// 432 Bleu — Box Office · background atmosphere + HUD chrome
// Concentric resonance rings, perspective floor, scanlines, vignettes.
// `intensity` 0..1 scales ring/scanline opacity. `accent` is the active neon hex.
function Atmosphere({ accent, intensity = 0.7 }) {
const ringOpacity = 0.05 + intensity * 0.22;
const scanOpacity = 0.015 + intensity * 0.05;
return (
{/* base radial */}
{/* concentric resonance rings */}
{/* perspective floor */}
{/* color vignettes */}
{/* scanlines */}
);
}
// HUD corner brackets + persistent status rails.
function Hud({ accent, shows }) {
const [display, setDisplay] = React.useState('');
const [live, setLive] = React.useState(false);
React.useEffect(() => {
const next = shows
.filter(s => s.status !== 'sold-out')
.map(s => ({ ...s, _d: new Date(s.dateISO) }))
.filter(s => s._d > new Date())
.sort((a, b) => a._d - b._d)[0];
if (!next) { setDisplay('NO UPCOMING SHOWS'); return; }
function tick() {
const now = new Date();
const doorsTarget = next.doorsISO ? new Date(next.doorsISO) : next._d;
const diffToShow = next._d - now;
const diffToDoors = doorsTarget - now;
if (diffToShow <= 0) {
setLive(true);
setDisplay('');
return;
}
if (diffToDoors <= 0 && next.doorsISO) {
setLive(false);
setDisplay(`DOORS OPEN · SHOW @ ${next.timeLabel}`);
return;
}
setLive(false);
const diff = diffToDoors;
const d = Math.floor(diff / 86400000);
const h = Math.floor((diff % 86400000) / 3600000);
const m = Math.floor((diff % 3600000) / 60000);
const s = Math.floor((diff % 60000) / 1000);
if (d > 0) {
setDisplay(`${next.artist} · ${d}D ${String(h).padStart(2,'0')}H ${String(m).padStart(2,'0')}M`);
} else {
setDisplay(`${next.artist} · ${String(h).padStart(2,'0')}:${String(m).padStart(2,'0')}:${String(s).padStart(2,'0')}`);
}
}
tick();
const id = setInterval(tick, 1000);
return () => clearInterval(id);
}, [shows]);
return (
<>
{[[0, 0], [1, 0]].map(([x, y], i) => (
))}
432.BLEU · BOX OFFICE
{live ? '● LIVE' : `▷ NEXT · ${display}`}
>
);
}
Object.assign(window, { Atmosphere, Hud });