<!-- SOLID CITY · part 3413 -->
 || 1; s.connect(fl); s.start(t, Math.random()); s.stop(t + dur + 0.05); return fl; };
  const osc = (type, f0, f1, dur) => { const o = C.createOscillator(); o.type = type; o.frequency.setValueAtTime(f0, t); o.frequency.exponentialRampToValueAtTime(f1, t + dur); o.start(t); o.stop(t + dur + 0.05); return o; };
  if (kind === 'laser') env(osc('square', 1500 + Math.random() * 200, 180, 0.12), 0.004, 0.11, 0.08);
  else if (kind === 'boom') { env(noise(1.1, 'lowpass', 900), 0.005, 1.0, 0.9); env(osc('sine', 120, 30, 0.6), 0.005, 0.55, 0.7); }
  else if (kind === 'bigboom') { env(noise(2.2, 'lowpass', 600), 0.01, 2.1, 1.0); env(osc('sine', 80, 20, 1.4), 0.01, 1.3, 0.9); }
  else if (kind === 'hit') env(noise(0.25, 'bandpass', 2200, 2), 0.003, 0.2, 0.5);
  else if (kind === 'ouch') { env(osc('sawtooth', 220, 60, 0.35), 0.005, 0.32, 0.35); env(noise(0.3, 'lowpass', 500), 0.005, 0.28, 0.6); }
  else if (kind === 'zap') env(osc('sine', 600, 900, 0.18), 0.01, 0.16, 0.12);
  else if (kind === 'boost') { env(noise(0.9, 'bandpass', 1400, 0.8), 0.08, 0.8, 0.45); env(osc('sawtooth', 90, 260, 0.7), 0.05, 0.6, 0.12); }
  else if (kind === 'beep') env(osc('square', 880, 880, 0.12), 0.005, 0.12, 0.12);
  else if (kind === 'go') { env(osc('square', 1320, 1320, 0.4), 0.005, 0.4, 0.14); env(noise(2.5, 'lowpass', 400), 0.3, 2.2, 0.9); }
  else if (kind === 'chime') { [523, 659, 784, 1046].forEach((f, i) => { const o = C.createOscillator(); o.type = 'triangle'; o.frequency.value = f; const g = C.createGain(); g.gain.setValueAtTime(0.0001, t + i * 0.12); g.gain.exponentialRampToValueAtTime(0.16, t + i * 0.12 + 0.02); g.gain.exponentialRampToValueAtTime(0.0001, t + i * 0.12 + 0.6); o.connect(g); g.connect(AU.master); o.start(t + i * 0.12); o.stop(t + i * 0.12 + 0.7); }); }
  else if (kind === 'alarm') env(osc('square', 660, 440, 0.25), 0.005, 0.24, 0.08);
}
function setMuted(m) { AU.muted = m; try { localStorage.setItem('space-muted', m ? '1' : '0'); } catch (e) { /* private mode */ } if (AU.master) AU.master.gain.value = m ? 0 : 0.55; $('h-mute').textContent = m ? '🔇' : '🔊'; $('h-mute').setAttribute('aria-label', m ? 'Sound off' : 'Sound on'); }

/* ======================= GAME STATE ======================= */
const S = {
  phase: 'loading', t: 0, phaseT: 0, runT: 0, running: false,
  pos: new V3(0, SHIP_REST, 0), yaw: PAD_HEADING, pitch: 0, roll: 0, speed: 0, vUp: 0,
  boostMeter: 1, boosting: false, boostLock: 0, shields: 100, invuln: 0, slowT: 0, sinceHit: 9,
  kills: 0, hits: 0, wave: 0, waveT: 0, topSpeed: 0, heat: 0, checkpoint: null, fireCd: 0, gun: 0,
  lock: null, shake: 0, hurt: 0, fov: 68, cloudFx: 0, landing: null, homeShown: false, result: null, saved: null, board: null, shots: 0
};
const input = { x: 0, y: 0, firing: false, boosting: false, fire: false, boost: false, stickX: 0, stickY: 0, keys: {}, mouse: null, mouseAim: !IS_TOUCH, mouseFire: false };
const bot = { on: false, god: false };
const camState = { pos: new V3(0, 8, 24), look: new V3(), init: false };
function forward(out, yaw = S.yaw, pitch = S.pitch) { return out.set(-Math.sin(yaw) * Math.cos(pitch), Math.sin(pitch), -Math.cos(yaw) * Math.cos(pitch)); }
const shipQ = new THREE.Quaternion(), eul = new THREE.Euler(0, 0, 0, 'YXZ');

/* ======================= HUD ======================= */
const H = {}; ['h-obj', 'h-time', 'h-kills', 'h-shield', 'h-boost', 'h-spd', 'h-alt', 'h-banner', 'h-bt', 'h-bs', 'h-lock', 'h-hurt', 'h-cloud', 'h-heat', 'h-mother', 'h-mbar', 'h-reticle', 'b-fire', 'b-boost', 'b-launch', 'h-count', 'h-perf', 'h-markers', 'stick', 'h-speedo', 'h-arc'].forEach((id) => { H[id] = $(id); });
let bannerT = 0;
function banner(title, sub, dur = 3) { H['h-bt'].textContent = title; H['h-bs'].textContent = sub || ''; H['h-banner'].hidden = false; H['h-banner'].classList.remove('show'); void H['h-banner'].offsetWidth; H['h-banner'].classList.add('show'); bannerT = dur; }
const markers = []; for (let i = 0; i < 8; i++) { const d = document.createElement('div'); d.className = 'mk'; d.hidden = true; H['h-markers'].appendChild(d); markers.push(d); }
const fmtT = (s) => { const m = Math.floor(s / 60), r = s - m * 60; return m + ':' + (r < 10 ? '0' : '') + r.toFixed(1); };
const lastHud = {};
function setText(el, key, v) { if (lastHud[key] !== v) { lastHud[key] = v; el.textContent = v; } }

/* ======================= INPUT ======================= */
(function stickInput() {
  const st = H.stick, knob = st.querySelector('i'); let id = null, cx = 0, cy = 0;
  function set(x, y) { const r = st.getBoundingClientRect().width * 0.4, d = Math.hypot(x, y); if (d > r) { x *= r / d; y *= r / d; } knob.style.transform = `translate(${x}px,${y}px)`; input.stickX = x / r; input.stickY = -y / r; }
  st.addEventListener('pointerdown', (e) => { id = e.pointerId; try { st.setPointerCapture(id); } catch (er) { /* older iOS */ } const r = st.getBoundingClientRect(); cx = r.left + r.width / 2; cy = r.top + r.height / 2; set(e.clientX - cx, e