1/* ============================================================ 2 MONOCHROAM â shared chrome + interactions 3 ============================================================ */ 4(function(){ 5 "use strict"; 6 7 /* ---------- brand assets ---------- */ 8 function logoMark(cls){ 9 return '<svg viewBox="0 0 40 40" class="mark '+(cls||'')+'" aria-hidden="true">'+ 10 '<circle cx="19" cy="20.5" r="16.4" fill="none" stroke="currentColor" stroke-width="3"/>'+ 11 '<circle cx="19" cy="20.5" r="8.4" fill="currentColor"/>'+ 12 '<circle cx="19" cy="20.5" r="3.5" fill="#08080a"/>'+ 13 '<circle cx="33.2" cy="7.2" r="4.4" fill="#ff3b30"/>'+ 14 '</svg>'; 15 } 16 var LOGO_SRC='https://lirp.cdn-website.com/beb2a5ff/dms3rep/multi/opt/Logo_Monochroam_white-1920w.png'; 17 function logo(extra){ 18 var sm=(extra||'').indexOf('logo--sm')>=0; 19 return '<a href="index.html" class="logo '+(extra||'')+'" aria-label="Monochroam home">'+ 20 '<img class="logo-img" src="'+LOGO_SRC+'" alt="Monochroam" style="height:'+(sm?'24px':'30px')+';width:auto;display:block">'+ 21 '</a>'; 22 } 23 24 var NAV = [ 25 ['hosts.html','Hosts'], 26 ['studio.html','Studio'], 27 ['refer.html','Free credits'], 28 ['faq.html','FAQ'], 29 ['contact.html','Contact'] 30 ]; 31 32 /* ---------- header ---------- */ 33 function buildHeader(page){ 34 var links = NAV.map(function(n){ 35 var active = n[0].indexOf(page)===0 && page ? ' class="active"' : ''; 36 return '<a href="'+n[0]+'"'+active+'>'+n[1]+'</a>'; 37 }).join(''); 38 return ''+ 39 '<div class="wrap">'+ 40 logo()+ 41 '<nav class="nav" id="nav">'+links+'</nav>'+ 42 '<div class="header-cta">'+ 43 '<a href="index.html#get-app" class="btn btn--sm">Get the app</a>'+ 44 '<button class="nav-toggle" id="navToggle" aria-label="Menu" aria-expanded="false">'+ 45 '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 6h18M3 12h18M3 18h18"/></svg>'+ 46 '</button>'+ 47 '</div>'+ 48 '</div>'; 49 } 50 51 /* ---------- footer ---------- */ 52 var iconMail='<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><rect x="3" y="5" width="18" height="14" rx="2"/><path d="m3 7 9 6 9-6"/></svg>'; 53 var iconIg='<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><rect x="3" y="3" width="18" height="18" rx="5"/><circle cx="12" cy="12" r="4"/><circle cx="17.5" cy="6.5" r="1" fill="currentColor" stroke="none"/></svg>'; 54 var iconTk='<svg viewBox="0 0 24 24" fill="currentColor"><path d="M16.5 5.6a4.3 4.3 0 0 1-2.7-1.6v8.9a5 5 0 1 1-5-5c.3 0 .5 0 .8.1v2.6a2.4 2.4 0 1 0 1.7 2.3V2h2.5a4.3 4.3 0 0 0 2.7 3.6z"/></svg>'; 55 56 function buildFooter(){ 57 return ''+ 58 '<div class="wrap">'+ 59 '<div class="footer-grid">'+ 60 '<div class="footer-col footer-brand">'+ 61 logo('logo--sm')+ 62 '<p class="muted" style="font-size:.95rem;max-width:30ch;margin-bottom:18px">Curated photography sessions & studio spaces for the spotlight-worthy.</p>'+ 63 '<div class="socials">'+ 64 '<a class="soc" href="contact.html" aria-label="Email">'+iconMail+'</a>'+ 65 '<a class="soc" href="#" aria-label="Instagram">'+iconIg+'</a>'+ 66 '<a class="soc" href="#" aria-label="TikTok">'+iconTk+'</a>'+ 67 '</div>'+ 68 '</div>'+ 69 '<div class="footer-col">'+ 70 '<h4>Company</h4>'+ 71 '<ul>'+ 72 '<li><a href="meet-the-hosts.html">Meet the hosts</a></li>'+ 73 '<li><a href="#">Terms & Conditions</a></li>'+ 74 '<li><a href="#">Cancellation policy</a></li>'+ 75 '<li><a href="#">Accessibility</a></li>'+ 76 '<li><a href="#">Privacy</a></li>'+ 77 '</ul>'+ 78 '</div>'+ 79 '<div class="footer-col">'+ 80 '<h4>Community</h4>'+ 81 '<ul>'+ 82 '<li><a href="studio.html">Studio</a></li>'+ 83 '<li><a href="meet-the-hosts.html">Hosts</a></li>'+ 84 '<li><a href="contact.html">Contact</a></li>'+ 85 '<li><a href="faq.html">FAQ</a></li>'+ 86 '</ul>'+ 87 '</div>'+ 88 '<div class="footer-col">'+ 89 '<h4>Stay in the loop</h4>'+ 90 '<p class="muted" style="font-size:.95rem;margin-bottom:16px">New drops, sessions & member perks â straight to your inbox.</p>'+ 91 '<form class="news" data-newsletter novalidate>'+ 92 '<div class="inline-form">'+ 93 '<input class="input" type="email" placeholder="[email protected]" aria-label="Email" required>'+ 94 '<button class="btn" type="submit">Subscribe</button>'+ 95 '</div>'+ 96 '<p class="field-msg" data-msg></p>'+ 97 '</form>'+ 98 '</div>'+ 99 '</div>'+ 100 '<div class="footer-bottom">'+ 101 '<p>© 2026 Monochroam LP. All rights reserved.</p>'+ 102 '<div class="mini-nav"><a href="#">Terms</a><a href="#">Privacy</a><a href="#">Cookies</a></div>'+ 103 '</div>'+ 104 '</div>'; 105 } 106 107 /* ---------- mount chrome ---------- */ 108 function mount(){ 109 var body = document.body; 110 var page = body.getAttribute('data-page')||''; 111 var header = document.querySelector('[data-site-header]'); 112 if(header){ header.className='site-header'; header.innerHTML=buildHeader(page); } 113 var footer = document.querySelector('[data-site-footer]'); 114 if(footer){ footer.className='site-footer'; footer.innerHTML=buildFooter(); } 115 116 // header scroll state 117 var onScroll=function(){ if(header) header.classList.toggle('is-scrolled', window.scrollY>12); }; 118 onScroll(); window.addEventListener('scroll',onScroll,{passive:true}); 119 120 // mobile nav
121 var nav=document.getElementById('nav'), toggle=document.getElementById('navToggle'); 122 if(toggle){ 123 toggle.addEventListener('click',function(){ 124 var open=nav.classList.toggle('is-open'); 125 header.classList.toggle('menu-open',open); 126 toggle.setAttribute('aria-expanded',open); 127 }); 128 nav.querySelectorAll('a').forEach(function(a){a.addEventListener('click',function(){ 129 nav.classList.remove('is-open');header.classList.remove('menu-open'); 130 });}); 131 } 132 } 133 134 /* ---------- reveals ---------- */ 135 function reveals(){ 136 var els=[].slice.call(document.querySelectorAll('.reveal')); 137 // auto-stagger groups 138 document.querySelectorAll('[data-stagger]').forEach(function(g){ 139 var step=parseInt(g.getAttribute('data-stagger'),10)||90; 140 [].slice.call(g.children).forEach(function(c,i){ if(c.classList.contains('reveal')) c.style.setProperty('--d',(i*step)+'ms'); }); 141 }); 142 if(!els.length) return; 143 function check(){ 144 var vh=window.innerHeight||document.documentElement.clientHeight; 145 els=els.filter(function(e){ 146 var r=e.getBoundingClientRect(); 147 if(r.top<vh*0.92 && r.bottom>-40){ e.classList.add('in'); return false; } 148 return true; 149 }); 150 } 151 check(); 152 requestAnimationFrame(check); 153 window.addEventListener('scroll',check,{passive:true}); 154 window.addEventListener('resize',check); 155 // safety net: if the animation timeline is frozen (hidden/throttled tab), 156 // never leave content hidden â force the visible end-state. 157 setTimeout(function(){ 158 if(document.timeline && document.timeline.currentTime===0){ 159 var st=document.createElement('style'); 160 st.id='reveal-fallback'; 161 st.textContent='.reveal{opacity:1!important;animation:none!important}'; 162 document.head.appendChild(st); 163 } 164 els.forEach(function(e){e.classList.add('in');}); 165 },1400); 166 } 167 168 /* ---------- accordions ---------- */ 169 function accordions(){ 170 document.querySelectorAll('[data-acc]').forEach(function(group){ 171 var single=group.hasAttribute('data-acc-single'); 172 group.querySelectorAll('.acc').forEach(function(acc){ 173 var head=acc.querySelector('.acc-head'); 174 head.addEventListener('click',function(){ 175 var willOpen=!acc.classList.contains('open'); 176 if(single) group.querySelectorAll('.acc.open').forEach(function(o){o.classList.remove('open');}); 177 acc.classList.toggle('open',willOpen); 178 }); 179 }); 180 }); 181 } 182 183 /* ---------- count-up ---------- */ 184 function counters(){ 185 var nums=[].slice.call(document.querySelectorAll('[data-count]')); 186 if(!nums.length) return; 187 function run(el){ 188 var end=parseFloat(el.getAttribute('data-count')), suf=el.getAttribute('data-suffix')||'', dec=(end%1!==0)?1:0, t0=null, dur=1400; 189 function step(t){ if(!t0)t0=t; var p=Math.min((t-t0)/dur,1); var e2=1-Math.pow(1-p,3); 190 el.textContent=(end*e2).toFixed(dec).replace(/\B(?=(\d{3})+(?!\d))/g,',')+suf; if(p<1)requestAnimationFrame(step); } 191 requestAnimationFrame(step); 192 } 193 function check(){ 194 var vh=window.innerHeight||document.documentElement.clientHeight; 195 nums=nums.filter(function(el){ 196 var r=el.getBoundingClientRect(); 197 if(r.top<vh*0.9 && r.bottom>0){ run(el); return false; } 198 return true; 199 }); 200 } 201 check(); 202 window.addEventListener('scroll',check,{passive:true}); 203 setTimeout(function(){nums.forEach(run);},2600); 204 } 205 206 /* ---------- tilt ---------- */ 207 function tilt(){ 208 if(matchMedia('(hover:none)').matches) return; 209 document.querySelectorAll('[data-tilt]').forEach(function(el){ 210 var max=6; 211 el.addEventListener('mousemove',function(e){ 212 if(document.documentElement.dataset.motion==='off') return; 213 var r=el.getBoundingClientRect(), x=(e.clientX-r.left)/r.width-.5, y=(e.clientY-r.top)/r.height-.5; 214 el.style.transform='perspective(900px) rotateY('+(x*max)+'deg) rotateX('+(-y*max)+'deg) translateY(-4px)'; 215 }); 216 el.addEventListener('mouseleave',function(){el.style.transform='';}); 217 }); 218 } 219
220 /* ---------- 3D tilt + glare (cards) ---------- */ 221 function tilt3d(root){ 222 if(matchMedia('(hover:none)').matches||matchMedia('(prefers-reduced-motion:reduce)').matches) return; 223 (root||document).querySelectorAll('[data-tilt3d]').forEach(function(el){ 224 if(el.__t3d) return; el.__t3d=true; 225 var max=parseFloat(el.getAttribute('data-tilt3d'))||10, raf; 226 var glare=el.querySelector('.tilt-glare'); 227 if(!glare){glare=document.createElement('span');glare.className='tilt-glare';el.appendChild(glare);} 228 el.addEventListener('pointermove',function(e){ 229 if(document.documentElement.dataset.motion==='off')return; 230 var r=el.getBoundingClientRect(); 231 var px=(e.clientX-r.left)/r.width, py=(e.clientY-r.top)/r.height; 232 cancelAnimationFrame(raf); 233 raf=requestAnimationFrame(function(){ 234 el.classList.add('is-tilting'); 235 el.style.setProperty('--tly',((px-0.5)*max).toFixed(2)+'deg'); 236 el.style.setProperty('--tlx',((0.5-py)*max).toFixed(2)+'deg'); 237 el.style.setProperty('--gx',(px*100).toFixed(1)+'%'); 238 el.style.setProperty('--gy',(py*100).toFixed(1)+'%'); 239 }); 240 }); 241 el.addEventListener('pointerleave',function(){ 242 el.classList.remove('is-tilting'); 243 el.style.setProperty('--tly','0deg'); 244 el.style.setProperty('--tlx','0deg'); 245 }); 246 }); 247 } 248 249 /* ---------- forms ---------- */ 250 function isEmail(v){return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(v);} 251 function forms(){ 252 // newsletter (footer + inline) 253 document.querySelectorAll('[data-newsletter]').forEach(function(f){ 254 f.addEventListener('submit',function(e){ 255 e.preventDefault(); 256 var inp=f.querySelector('input[type=email]'), msg=f.querySelector('[data-msg]'); 257 if(!isEmail(inp.value)){inp.classList.add('invalid');if(msg){msg.style.color='var(--red)';msg.textContent='Enter a valid email.';}return;} 258 inp.classList.remove('invalid'); 259 if(msg){msg.style.color='var(--green)';msg.textContent='You\u2019re in. Welcome to the spotlight. â¦';} 260 f.querySelector('button').textContent='Subscribed â'; 261 inp.value='';inp.disabled=true; 262 }); 263 }); 264 // generic validated forms 265 document.querySelectorAll('[data-validate]').forEach(function(f){ 266 f.addEventListener('submit',function(e){ 267 e.preventDefault();var ok=true; 268 f.querySelectorAll('[required]').forEach(function(inp){ 269 var bad = !inp.value.trim() || (inp.type==='email' && !isEmail(inp.value)); 270 inp.classList.toggle('invalid',bad); if(bad)ok=false; 271 }); 272 var msg=f.querySelector('[data-form-msg]'); 273 if(!ok){if(msg){msg.style.color='var(--red)';msg.textContent='Please fill in the highlighted fields.';}return;} 274 var btn=f.querySelector('button[type=submit]'); 275 var done=function(){ 276 if(msg){msg.style.color='var(--green)';msg.textContent='Sent! We\u2019ll be in touch soon. â¦';} 277 if(btn){btn.textContent='Sent â';btn.disabled=true;} 278 f.querySelectorAll('.input').forEach(function(i){i.value='';i.disabled=true;}); 279 }; 280 var inbox=f.getAttribute('data-contact'); 281 if(!inbox){done();return;} 282 // relay the message to the inbox via formsubmit.co (static site â no server of our own) 283 var data={_subject:'New message from monochroam.com',_template:'table'}; 284 f.querySelectorAll('input[name],textarea[name]').forEach(function(inp){ 285 if(inp.type==='radio'&&!inp.checked)return; 286 data[inp.name]=inp.value; 287 }); 288 if(btn){btn.textContent='Sending\u2026';btn.disabled=true;} 289 fetch('https://formsubmit.co/ajax/'+inbox,{ 290 method:'POST', 291 headers:{'Content-Type':'application/json','Accept':'application/json'}, 292 body:JSON.stringify(data) 293 }).then(function(r){ 294 if(!r.ok)throw new Error('bad status'); 295 return r.json(); 296 }).then(done).catch(function(){ 297 if(btn){btn.innerHTML='Send message <span class="arrow">\u2192</span>';btn.disabled=false;} 298 if(msg){msg.style.color='var(--red)';msg.textContent='Couldn\u2019t send right now \u2014 please email [email protected] directly.';} 299 }); 300 }); 301 }); 302 // clear invalid on type 303 document.addEventListener('input',function(e){ if(e.target.classList&&e.target.classList.contains('invalid'))e.target.classList.remove('invalid'); }); 304 } 305 306 /* ---------- hero parallax ---------- */ 307 var pxEls=[], pxBound=false; 308 function parallaxCollect(root){ 309 (root||document).querySelectorAll('[data-parallax]').forEach(function(el){ 310 if(pxEls.indexOf(el)<0) pxEls.push(el); 311 }); 312 } 313 function parallax(){ 314 parallaxCollect(document); 315 if(pxBound) return; pxBound=true; 316 window.addEventListener('scroll',function(){ 317 if(document.documentElement.dataset.motion==='off')return; 318 var y=window.scrollY;
319 pxEls.forEach(function(el){var s=parseFloat(el.getAttribute('data-parallax'))||.15;el.style.transform='translateY('+(y*s)+'px)';}); 320 },{passive:true}); 321 } 322 323 /* ---------- public: bind behaviours on dynamically added content ---------- */ 324 window.MC={ 325 enhance:function(root){ tilt3d(root); parallaxCollect(root); } 326 }; 327 328 /* ---------- TWEAKS ---------- */ 329 var ACCENTS={ 330 violet:['#6c4df6','#8a72ff'], 331 indigo:['#4f46e5','#7c79ff'], 332 orange:['#ff5e2c','#ff8a5c'], 333 green:['#1fb36b','#3fd98c'] 334 }; 335 var MOTION=['off','subtle','lively','maximal']; 336 function applyMotion(v){ 337 document.documentElement.dataset.motion=v; 338 var scale = v==='maximal'?1.2:(v==='lively'?1:(v==='subtle'?0.7:0)); 339 document.documentElement.style.setProperty('--motion-scale', scale||0.0001); 340 } 341 function applyAccent(k){ 342 var a=ACCENTS[k]||ACCENTS.violet, r=document.documentElement.style; 343 r.setProperty('--violet',a[0]); r.setProperty('--violet-bright',a[1]); 344 } 345 function getState(){ 346 var m=localStorage.getItem('mc_motion')||'maximal'; 347 var a=localStorage.getItem('mc_accent')||'violet'; 348 return {motion:m,accent:a}; 349 } 350 function tweaks(){ 351 var s=getState(); applyMotion(s.motion); applyAccent(s.accent); 352 353 var panel=document.createElement('div'); 354 panel.id='tweaks-panel'; 355 panel.style.cssText='position:fixed;right:18px;bottom:18px;z-index:9999;width:264px;background:rgba(15,15,19,.96);backdrop-filter:blur(14px);border:1px solid var(--border-strong);border-radius:18px;padding:18px;display:none;font-family:var(--font-body);box-shadow:0 24px 60px -20px rgba(0,0,0,.8)'; 356 panel.innerHTML= 357 '<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:14px">'+ 358 '<strong style="font-family:var(--font-display);text-transform:uppercase;letter-spacing:.04em;font-size:.95rem">Tweaks</strong>'+ 359 '<button id="tw-close" aria-label="Close" style="background:none;border:0;color:var(--text-dim);font-size:20px;line-height:1;cursor:pointer">Ã</button>'+ 360 '</div>'+ 361 '<div style="font-size:.74rem;letter-spacing:.14em;text-transform:uppercase;color:var(--text-faint);margin-bottom:8px;font-weight:700">Motion</div>'+ 362 '<div id="tw-motion" style="display:grid;grid-template-columns:repeat(2,1fr);gap:6px;margin-bottom:18px"></div>'+ 363 '<div style="font-size:.74rem;letter-spacing:.14em;text-transform:uppercase;color:var(--text-faint);margin-bottom:8px;font-weight:700">Accent</div>'+ 364 '<div id="tw-accent" style="display:flex;gap:10px"></div>'; 365 document.body.appendChild(panel); 366 367 function seg(host,opts,current,onpick){ 368 host.innerHTML=''; 369 opts.forEach(function(o){ 370 var b=document.createElement('button'); 371 b.textContent=o[0].toUpperCase()+o.slice(1); 372 b.style.cssText='padding:8px 6px;border-radius:9px;border:1px solid '+(o===current?'var(--violet-bright)':'var(--border)')+';background:'+(o===current?'var(--violet-soft)':'transparent')+';color:'+(o===current?'#fff':'var(--text-dim)')+';font-size:.82rem;font-weight:600;cursor:pointer;font-family:inherit;transition:.15s'; 373 b.onclick=function(){onpick(o);}; 374 host.appendChild(b); 375 }); 376 } 377 function swatches(host,current,onpick){ 378 host.innerHTML=''; 379 Object.keys(ACCENTS).forEach(function(k){ 380 var b=document.createElement('button'); 381 b.setAttribute('aria-label',k); 382 b.style.cssText='width:38px;height:38px;border-radius:11px;cursor:pointer;background:linear-gradient(135deg,'+ACCENTS[k][0]+','+ACCENTS[k][1]+');border:2px solid '+(k===current?'#fff':'transparent')+';box-shadow:0 0 0 1px var(--border)'; 383 b.onclick=function(){onpick(k);}; 384 host.appendChild(b); 385 }); 386 } 387 function render(){ 388 var st=getState(); 389 seg(panel.querySelector('#tw-motion'),MOTION,st.motion,function(v){localStorage.setItem('mc_motion',v);applyMotion(v);post();render();}); 390 swatches(panel.querySelector('#tw-accent'),st.accent,function(k){localStorage.setItem('mc_accent',k);applyAccent(k);post();render();}); 391 } 392 function post(){
393 try{var st=getState();window.parent.postMessage({type:'__edit_mode_set_keys',edits:{motion:st.motion,accent:st.accent}},'*');}catch(e){} 394 } 395 render(); 396 397 panel.querySelector('#tw-close').onclick=function(){ 398 panel.style.display='none'; 399 try{window.parent.postMessage({type:'__edit_mode_dismissed'},'*');}catch(e){} 400 }; 401 window.addEventListener('message',function(e){ 402 var t=e.data&&e.data.type; 403 if(t==='__activate_edit_mode'){panel.style.display='block';render();} 404 else if(t==='__deactivate_edit_mode'){panel.style.display='none';} 405 }); 406 try{window.parent.postMessage({type:'__edit_mode_available'},'*');}catch(e){} 407 } 408 409 /* ---------- boot ---------- */ 410 function init(){ mount();reveals();accordions();counters();tilt();tilt3d();forms();parallax();tweaks(); } 411 if(document.readyState==='loading') document.addEventListener('DOMContentLoaded',init); else init(); 412})();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.