<!-- SAGA-SOLID · part 41 -->
y(14, 10, 2), darkMat);
      frame.position.set(x, 3, z - 14);
      scene.add(frame);
      /* Opening */
      var opening = new THREE.Mesh(new THREE.PlaneGeometry(10, 7),
        new THREE.MeshBasicMaterial({color: 0x000000}));
      opening.position.set(x, 3, z - 12.9);
      scene.add(opening);
      /* Warning lights */
      for(var l = -1; l <= 1; l++){
        var light = new THREE.Mesh(new THREE.SphereGeometry(0.5, 8, 6),
          new THREE.MeshBasicMaterial({color: 0xff0000}));
        light.position.set(x + l*6, 8.5, z - 12.8);
        scene.add(light);
      }
    }
    portal(150, -100);
    portal(-130, 180);
    portal(2050, 2000);
  }catch(e){ console.error(e); }
}
if(typeof buildFreight === 'function'){ try{ buildFreight(); }catch(e){ console.error(e); } }

/* DISTRICT CENTERS — plazas at the heart. 2026-10-04. */
function buildPlazas(){
  try{
    var stoneMat = new THREE.MeshStandardMaterial({color: 0x999988, roughness: 0.8});
    var goldMat = new THREE.MeshStandardMaterial({color: 0xd4a017, metalness: 0.6, roughness: 0.4});
    function plaza(x, z, r){
      /* Circular plaza */
      var pz = new THREE.Mesh(new THREE.CircleGeometry(r, 24), stoneMat);
      pz.rotation.x = -Math.PI/2;
      pz.position.set(x, 0.25, z);
      scene.add(pz);
      /* Central fountain */
      var base = new THREE.Mesh(new THREE.CylinderGeometry(4, 5, 2, 12), stoneMat);
      base.position.set(x, 1, z);
      scene.add(base);
      var water = new THREE.Mesh(new THREE.CylinderGeometry(3.5, 3.5, 0.5, 12),
        new THREE.MeshStandardMaterial({color: 0x0088cc, transparent: true, opacity: 0.7}));
      water.position.set(x, 2.2, z);
      scene.add(water);
      /* Obelisk */
      var ob = new THREE.Mesh(new THREE.BoxGeometry(2, 15, 2), goldMat);
      ob.position.set(x, 9, z);
      scene.add(ob);
      var tip = new THREE.Mesh(new THREE.ConeGeometry(1.5, 3, 4), goldMat);
      tip.position.set(x, 18, z);
      scene.add(tip);
    }
    plaza(100, -100, 30);   /* City */
    plaza(-80, 180, 25);    /* Village */
    plaza(2000, 2000, 35);  /* Ahupua'a 1 */
    plaza(0, 1500, 28);     /* Observatory */
  }catch(e){ console.error(e); }
}
if(typeof buildPlazas === 'function'){ try{ buildPlazas(); }catch(e){ console.error(e); } }

/* LAVA TUBES — underground in shield volcanoes (Hawaii). 2026-10-04. */
function buildLavaTubes(){
  try{
    var tubeMat = new THREE.MeshStandardMaterial({color: 0x1a1a1a, roughness: 1, side: THREE.BackSide});
    var glowMat = new THREE.MeshBasicMaterial({color: 0xff4400});
    function lavaTube(x, z, len, angle){
      /* Tube entrance — dark opening */
      var entrance = new THREE.Mesh(new THREE.CircleGeometry(8, 12), tubeMat);
      entrance.position.set(x, 4, z);
      entrance.rotation.y = angle;
      scene.add(entrance);
      /* Glow from inside */
      var glow = new THREE.Mesh(new THREE.CircleGeometry(6, 12), glowMat);
      glow.position.set(x + Math.sin(angle)*0.5, 3, z + Math.cos(angle)*0.5);
      glow.rotation.y = angle;
      scene.add(glow);
      /* Tube going in */
      var tube = new THREE.Mesh(new THREE.CylinderGeometry(8, 8, len, 12, 1, true), tubeMat);
      tube.rotation.x = Math.PI/2;
      tube.rotation.z = angle;
      tube.position.set(x + Math.sin(angle)*len/2, 4, z + Math.cos(angle)*len/2);
      scene.add(tube);
    }
    lavaTube(2000, 1850, 60, 0);
    lavaTube(-2000, 1850, 70, Math.PI/4);
    lavaTube(0, -2510, 65, Math.PI);
  }catch(e){ console.error(e); }
}
if(typeof buildLavaTubes === 'function'){ try{ buildLavaTubes(); }catch(e){ console.error(e); } }

/* ALLUVIAL FANS — sediment at canyon mouths. 2026-10-04. */
function buildFans(){
  try{
    var sedimentMat = new THREE.MeshStandardMaterial({color: 0xb09468, roughness: 1});
    function fan(x, z, r){
      /* Fan shape: half-cone spreading from canyon mouth */
      var fanMesh = new THREE.Mesh(new THREE.CylinderGeometry(r, r*0.3, 8, 16, 1, false, 0, Math.PI), sedimentMat);
      fanMesh.position.set(x, 2, z);
      fanMesh.scale.y = 0.5;
      scene.add(fanMesh);
      /* Braided channels */
      for(var c = 0; c < 5; c++){
        var ch = new THREE.Mesh(new THREE.PlaneGeometry(3, r*0.8),
          new THREE.MeshStandardMaterial({color: 0x8a7050, roughness: 1}));
        ch.rotation.x = -Math.PI/2;
        var ca = (c / 5) * Math.PI;
        ch.position.set(x + Math.cos(ca)*r*0.4, 4.2, z + Math.sin(ca)*r*0.4);
        ch.rotation.z = ca;
        scene.add(ch);
      }
    }
    fan(-1800, -3450, 80);  /* Canyon 1 mouth */
    fan(2200, 3450, 90);    /* Canyon 2 mouth */
    fan(-2800, -2700, 70);  /* Valley mouth */
  }catch(e){ console.error(e); }
}
if(typeof buildFans === 'function'){ try{ buildFans(); }catch(e){ console.error(e); } }

/* TRANSIT STATIONS — integrated into districts (Singapore model). 2026-10-04. */
function buildStations(){
  try{
    var steelMat = new THREE.MeshStandardMaterial({color: 0x888888, metalness: 0.7, roughness: 0.4}