<!-- SOLIDABILITY-WORLD · part 58 -->
  container.addEventListener('click', e => {
      handleTap(e.clientX, e.clientY);
    });

    function handleTap(clientX, clientY) {
      const camera = SWEngine.getCamera();
      const scene = SWEngine.getScene();
      if (!camera || !scene) return;

      // Convert to normalized device coordinates
      const rect = container.getBoundingClientRect();
      tapPoint.x = ((clientX - rect.left) / rect.width) * 2 - 1;
      tapPoint.y = -((clientY - rect.top) / rect.height) * 2 + 1;

      raycaster.setFromCamera(tapPoint, camera);
      const intersects = raycaster.intersectObjects(scene.children, false);

      for (const hit of intersects) {
        const room = hit.object.userData.room;
        if (room) {
          // Highlight the selected building
          highlightBuilding(hit.object, room);

          // Human Intervention: pause movement and inspect
          // Works during WALK, AI DRIVE, or any mode
          if (typeof SWIntervene !== 'undefined') {
            SWIntervene.intervene(room, hit.object.userData.isDoor ? 'door' : 'wall');
          } else {
            // Fallback: just show glass
            SWGlass.show(room);
          }
          return;
        }
      }
    }

    // Highlight selected building
    let highlighted = null;
    function highlightBuilding(mesh, room) {
      // Remove previous highlight
      if (highlighted) {
        highlighted.material.emissive.setHex(0x000000);
        highlighted = null;
      }
      if (mesh.material && mesh.material.emissive) {
        mesh.material.emissive.setHex(0x003333);
        highlighted = mesh;
        // Clear after 3 seconds
        setTimeout(() => {
          if (highlighted === mesh) {
            mesh.material.emissive.setHex(0x000000);
            highlighted = null;
          }
        }, 3000);
      }
    }
  }

  function getLayout() { return layout; }

  // Heat modes (per GPT-6): CHANGE, RUNTIME, RISK — never conflated
  // CHANGE HEAT: file modification recency (observed from filesystem)
  // RUNTIME HEAT: measured execution activity (UNKNOWN — no telemetry)
  // RISK HEAT: diagnostic findings (inferred from analysis)
  let heatMode = null; // null, 'change', 'runtime', 'risk'

  function cycleHeatMode() {
    const modes = [null, 'change', 'risk']; // 'runtime' excluded: no data
    const idx = modes.indexOf(heatMode);
    heatMode = modes[(idx + 1) % modes.length];
    applyHeatColors();
    return heatMode;
  }

  function getHeatMode() { return heatMode; }

  function heatColorFor(room) {
    if (heatMode === 'change') {
      // CHANGE HEAT: modification recency (OBSERVED from mtime)
      const ageDays = room.age_days;
      if (ageDays == null || ageDays < 0) return 0x1a1a1a;
      if (ageDays < 1) return 0xff2222;
      if (ageDays < 7) return 0xcc1a1a;
      if (ageDays < 30) return 0x771111;
      if (ageDays < 90) return 0x331111;
      return 0x0d0d0d;
    }
    if (heatMode === 'risk') {
      // RISK HEAT: diagnostic risk (INFERRED from complexity + test coverage)
      const cx = room.complexity || 0;
      const tested = room.has_test;
      if (cx > 1000 && !tested) return 0xff2222;  // critical: complex + untested
      if (cx > 500 && !tested) return 0xcc4400;   // high: complex + untested
      if (cx > 200 && !tested) return 0x774400;   // moderate
      if (cx > 1000) return 0x441111;             // complex but tested
      return 0x0d0d0d;                            // low risk: black
    }
    return 0x6688aa; // default
  }

  function heatLabel() {
    if (heatMode === 'change') return 'CHANGE HEAT (file modification recency)';
    if (heatMode === 'risk') return 'RISK HEAT (complexity + test coverage)';
    return null;
  }

  function applyHeatColors() {
    const scene = SWEngine.getScene();
    if (!scene) return;
    const districtColors = { 'public': 0x4488ff, '(root)': 0xffd700, 'lib': 0x00ffcc };
    scene.traverse(obj => {
      if (obj.userData && obj.userData.room && !obj.userData.isDoor) {
        const room = obj.userData.room;
        if (!obj.material || !obj.material.color) return;
        if (heatMode) {
          obj.material.color.setHex(heatColorFor(room));
          const glow = heatMode === 'change' ? room.age_days < 7
            : (room.complexity > 500 && !room.has_test);
          if (obj.material.emissive) {
            obj.material.emissive.setHex(glow ? 0x550000 : 0x000000);
          }
        } else {
          obj.material.color.setHex(districtColors[room.district] || 0x6688aa);
          if (obj.material.emissive) obj.material.emissive.setHex(0x000000);
        }
      }
    });
  }

  return { build, buildFull, buildPublic, update, getLayout, checkCollision, getColliders: () => colliders, cycleHeatMode, getHeatMode, heatLabel };
})();


===== FILE: public/solidability-world/js/three.min.js =====
/**
 * @license
 * Copyright 2010-2021 Three.js Authors
 * SPDX-License-Identifier: MIT
 */
!function(t,e){"object