H hide cursor · L replay intro · F fool dialog · C crash/reboot · X clear · E scanlines · F11 fullscreen
`
${t.d}${t.m}
${t.name}${t.loc}
${t.btns.map(b=>`
${b[0]}`).join('')}
`).join('');
return `
Tour Dates
${rows}
${socialsRow()}`;
},
after(win){
// load Bandsintown standalone widget; hide static fallback once it renders
if(!document.getElementById('bit-script')){
const s=document.createElement('script'); s.id='bit-script';
s.src='https://widgetv3.bandsintown.com/main.min.js'; s.charset='utf-8'; s.async=true;
document.body.appendChild(s);
}
const fb=win.querySelector('#tour-fallback');
let tries=0; const iv=setInterval(()=>{
tries++;
const w=win.querySelector('#bit-widget');
if(w && w.querySelector('iframe, .bit-widget')){ if(fb) fb.style.display='none'; clearInterval(iv); }
if(tries>20) clearInterval(iv); // ~10s; keep fallback if it never loads
},500);
}
},
contact: {
title:"Contact",
w:560, h:400,
body(){
return `CONTACT
${socialsRow()}`;
}
},
goodgrief: {
title:"good grief!",
w:380, h:540,
body(){
return `
Listen to good grief!
on all streaming services
Listen Here
${socialsRow()}
`;
}
},
};
function openWindow(key){
const def=WINDOWS[key]; if(!def) return;
let win=document.getElementById('cwin-'+key);
if(win){ win.style.zIndex=++z; return; }
const ww=Math.min(def.w, innerWidth-40), wh=Math.min(def.h, innerHeight-90);
win=el(``);
winLayer.appendChild(win); win.style.zIndex=++z;
win.querySelector('.cbody').innerHTML=def.body();
cwinDraggable(win);
win.querySelector('.ctl').addEventListener('click',e=>{ e.stopPropagation();
// closing a page-window returns to Home URL (so the URL stays truthful)
if(PAGE===key && PAGE!=='home'){ go('home'); } else { win.remove(); }
});
if(def.after) def.after(win);
}
function cwinDraggable(win){
const bar=win.querySelector('.ctitle');
win.addEventListener('mousedown',()=>{ win.style.zIndex=++z; });
bar.addEventListener('mousedown',e=>{
const r=win.getBoundingClientRect(); const ox=e.clientX-r.left, oy=e.clientY-r.top; win.style.transform='none'; win.style.left=r.left+'px'; win.style.top=r.top+'px';
function move(ev){ win.style.left=(ev.clientX-ox)+'px'; win.style.top=(ev.clientY-oy)+'px'; }
function up(){ document.removeEventListener('mousemove',move); document.removeEventListener('mouseup',up); }
document.addEventListener('mousemove',move); document.addEventListener('mouseup',up);
});
}
/* navigate to a real page (separate URLs for SEO) */
function go(act){
if(act==='store'){ window.open(CONFIG.links.store,'_blank','noopener'); return; }
if(isMobile()) closeMobileTray(); // a dock tap exits the clown flow before navigating
if(act==='home'){ document.querySelectorAll('.cwin,.foolwin,.popwin').forEach(n=>n.remove()); playLoading(); return; }
if(act==='tour'){ openWindow('tour'); return; }
if(act==='contact'){ openWindow('contact'); return; }
if(act==='goodgrief'){ openWindow('goodgrief'); return; } // album opens inline on any page
if(act==='miles'){
// Miles the Clown = the Feed-the-Clown game (insWin + gameWin on desktop;
// opens into the scroll tray on mobile so it fits a phone screen).
if(isMobile()){ mobileTray(); startGame.skipInstructions=true; startGame(); startGame.skipInstructions=false; intoTray('gameWin'); }
else { startGame(); }
return;
}
if(act==='pool'){ openWindow('pool'); return; }
}
/* folder icons: single-click selects, double-click opens (Mac style) */
(function initIcons(){
const icons=document.querySelectorAll('#icons .dicon');
icons.forEach(ic=>{
ic.addEventListener('click',e=>{ e.stopPropagation(); if(isMobile()){ go(ic.dataset.act); return; } icons.forEach(o=>o.classList.remove('sel')); ic.classList.add('sel'); });
ic.addEventListener('dblclick',e=>{ e.stopPropagation(); go(ic.dataset.act); });
});
document.getElementById('desktop').addEventListener('click',()=> icons.forEach(o=>o.classList.remove('sel')));
// Mobile: the "Done" chip is the way out of the tray now that the dock is hidden.
const tx=document.getElementById('trayExit');
if(tx) tx.addEventListener('click',e=>{ e.stopPropagation(); closeMobileTray(); });
})();
/* ---------- keys ---------- */
document.addEventListener('keydown',e=>{
// don't hijack single-key shortcuts while typing in the license name field
const t=e.target; if(t && (t.tagName==='INPUT'||t.tagName==='TEXTAREA'||t.isContentEditable)) return;
const k=e.key.toLowerCase();
if(k==='h') body.classList.toggle('hide-cursor');
else if(k==='e') body.classList.toggle('no-scan');
else if(k==='l') playLoading();
else if(k==='f' && PAGE==='home') showFool();
else if(k==='c') doCrash(); // crash/reboot preserved on the C key
else if(k==='x') clearClowns();
});
/* ---------- start: boot intro ----------
Home (index.html) plays the full boot sequence EVERY load.
Inner pages (tour/contact) skip straight to the desktop so
navigation stays instant. */
if(CONFIG.loading.autoplay && PAGE==='home'){
playLoading();
} else {
body.classList.remove('intro'); loadingEl.style.display='none';
revealDesktop(); // inner pages: straight to desktop + open this page's window
}