.wrap{position:relative;width:94%;height:82%;display:flex;gap:6%}
.tile{position:relative;flex:1;border:1px solid var(--line);border-radius:12px;background:var(--surface);display:grid;place-items:center;cursor:pointer;padding:0}
.tag{position:absolute;top:8px;left:10px;font:700 10px/1 monospace;color:var(--muted)}
.dot{width:22%;aspect-ratio:1;border-radius:50%;background:var(--line)}
.dot.go{background:var(--accent-3)}
.tile.bad .dot.go{background:var(--accent-2)}
const good = document.getElementById('good');
const bad = document.getElementById('bad');
const gdot = document.getElementById('gdot');
const bdot = document.getElementById('bdot');
function beep(ctx, t, freq) {
const osc = ctx.createOscillator();
const gain = ctx.createGain();
osc.type = 'sine';
osc.frequency.value = freq;
gain.gain.setValueAtTime(0, t);
gain.gain.linearRampToValueAtTime(0.13, t + 0.01);
gain.gain.exponentialRampToValueAtTime(0.0001, t + 0.13);
osc.connect(gain).connect(ctx.destination);
osc.start(t);
osc.stop(t + 0.14);
}
function trigger(el, dot, delayMs, playSound) {
el.style.transform = 'scale(.97)';
setTimeout(() => { el.style.transform = ''; }, 90);
setTimeout(() => {
dot.classList.add('go');
setTimeout(() => dot.classList.remove('go'), 160);
if (playSound) {
const ctx = new (window.AudioContext || window.webkitAudioContext)();
beep(ctx, ctx.currentTime, delayMs === 0 ? 660 : 330);
setTimeout(() => ctx.close(), 300);
}
}, delayMs);
}
let cycle = 0;
setInterval(() => {
cycle++;
if (cycle % 2) trigger(good, gdot, 0, false); else trigger(bad, bdot, 500, false);
}, 2000);
good.addEventListener('click', () => trigger(good, gdot, 0, true));
bad.addEventListener('click', () => trigger(bad, bdot, 500, true));