<!-- SOLIDIVISM-STAGING · part 6 -->
length > 0) {
          const target = buildings[aiIdx % buildings.length];
          aiIdx++;
          if (aiDriveToBuilding(target.label)) {
            aiBtn.classList.add('active');
            aiBtn.textContent = '⏸️';
          }
        }
      };
    }
    const stopBtn = document.getElementById('tac-stop');
    if (stopBtn) {
      stopBtn.onclick = () => {
        // Emergency stop: halt all movement and AI
        aiStop();
        aiAssist = false;
        const aiB = document.getElementById('tac-ai');
        if (aiB) aiB.classList.remove('active');
        // Reset velocities
        joystick.dx = 0; joystick.dy = 0;
        joystick.active = false;
        observe('emergency.stop', { timestamp: new Date().toISOString() });
        stopBtn.classList.add('active');
        setTimeout(() => stopBtn.classList.remove('active'), 500);
      };
    }
  }

  function setupInput() {
    window.addEventListener('keydown', e => keys[e.key.toLowerCase()] = true);
    window.addEventListener('keyup', e => keys[e.key.toLowerCase()] = false);
    
    const joyZone = document.getElementById('joystick');
    const camZone = document.getElementById('camstick');
    if (camZone && 'ontouchstart' in window) {
      camZone.style.display = 'block';
      let camTouchId = null, camStartX = 0, camStartY = 0;
      const camKnob = document.getElementById('camstick-knob');
      camZone.addEventListener('touchstart', e => {
        const t = e.changedTouches[0];
        camTouchId = t.identifier;
        camStartX = t.clientX; camStartY = t.clientY;
        camstick.active = true;
        e.preventDefault();
      }, { passive: false });
      camZone.addEventListener('touchmove', e => {
        for (const t of e.changedTouches) {
          if (t.identifier === camTouchId) {
            camstick.dx = Math.max(-1, Math.min(1, (t.clientX - camStartX) / 50));
            camstick.dy = Math.max(-1, Math.min(1, (t.clientY - camStartY) / 50));
            if (camKnob) camKnob.style.transform = `translate(calc(-50% + ${camstick.dx * 35}px), calc(-50% + ${camstick.dy * 35}px))`;
          }
        }
        e.preventDefault();
      }, { passive: false });
      camZone.addEventListener('touchend', e => {
        for (const t of e.changedTouches) {
          if (t.identifier === camTouchId) {
            camstick.active = false;
            camstick.dx = 0; camstick.dy = 0;
            if (camKnob) camKnob.style.transform = 'translate(-50%, -50%)';
          }
        }
      });
    }
    if (joyZone && 'ontouchstart' in window) {
      joyZone.style.display = 'block';
      joyZone.style.zIndex = '50';
      let touchId = null, startX = 0, startY = 0;
      joyZone.addEventListener('touchstart', e => {
        const t = e.changedTouches[0];
        touchId = t.identifier;
        startX = t.clientX; startY = t.clientY;
        joystick.active = true;
        e.preventDefault();
      }, { passive: false });
      joyZone.addEventListener('touchmove', e => {
        for (const t of e.changedTouches) {
          if (t.identifier === touchId) {
            joystick.dx = Math.max(-1, Math.min(1, (t.clientX - startX) / 50));
            joystick.dy = Math.max(-1, Math.min(1, (t.clientY - startY) / 50));
          }
        }
        e.preventDefault();
      }, { passive: false });
      joyZone.addEventListener('touchend', e => {
        for (const t of e.changedTouches) {
          if (t.identifier === touchId) {
            joystick.active = false;
            joystick.dx = 0; joystick.dy = 0;
          }
        }
      });
    }
  }

  // ── THE LOOP: Where solid meets visible ──
  // ── PERFORMANCE MONITORING ──
  let frameCount = 0;
  let lastFpsTime = Date.now();
  let currentFps = 0;
  let frameTimes = [];

  function animate() {
    requestAnimationFrame(animate);
    const frameStart = performance.now();
    
    // Movement
    let mx = 0, mz = 0;
    if (keys['w'] || keys['arrowup']) mz -= 1;
    if (keys['s'] || keys['arrowdown']) mz += 1;
    if (keys['a'] || keys['arrowleft']) mx -= 1;
    if (keys['d'] || keys['arrowright']) mx += 1;
    if (joystick.active) { mx += joystick.dx; mz += joystick.dy; }

    const len = Math.sqrt(mx * mx + mz * mz);
    if (len > 1) { mx /= len; mz /= len; }

    // Camera-relative movement: forward is where camera faces
    // Camera yaw defines the facing direction
    if (len > 0.1) {
      const sin = Math.sin(camYaw);
      const cos = Math.cos(camYaw);
      // Transform input from camera-space to world-space
      // Input (mx,mz): mx=right, mz=forward in camera space
      // World: forward = (-sin, -cos), right = (cos, -sin)
      const wx = mx * cos + mz * sin;
      const wz = -mx * sin + mz * cos;
      mx = wx; mz = wz;
    }
    
    // AI Drive takes over movement (human input overrides)
    const aiMove = aiUpdate(0.016);
    if (aiMove && !joystick.active && mx === 0 && mz === 0) {
      mx = aiMove.mx; mz = aiMove.mz;
  