<!-- SAGA-SOLID · part 66 -->
esh(wallGeo, wallMat);
  wall.position.set(wx, wy, wz);
  buttonWall.add(wall);
  
  /* Gold trim */
  var trimGeo = new THREE.BoxGeometry(62, 42, 1);
  var trimMat = new THREE.MeshStandardMaterial({ color: 0xd8a920, roughness: 0.3, metalness: 0.8 });
  var trim = new THREE.Mesh(trimGeo, trimMat);
  trim.position.set(wx, wy, wz + 0.5);
  buttonWall.add(trim);
  
  /* Title */
  var titleCanvas = document.createElement('canvas');
  titleCanvas.width = 1024; titleCanvas.height = 128;
  var tctx = titleCanvas.getContext('2d');
  tctx.fillStyle = '#0b0906'; tctx.fillRect(0,0,1024,128);
  tctx.fillStyle = '#ffd700'; tctx.font = '64px Georgia';
  tctx.textAlign = 'center'; tctx.fillText('C O D E R S 1 0 0', 512, 84);
  var titleTex = new THREE.CanvasTexture(titleCanvas);
  var titleMat = new THREE.MeshBasicMaterial({ map: titleTex, transparent: true });
  var titleMesh = new THREE.Mesh(new THREE.PlaneGeometry(40, 5), titleMat);
  titleMesh.position.set(wx, wy + 18, wz + 1.5);
  buttonWall.add(titleMesh);
  
  /* 56 buttons: 7 columns x 8 rows */
  var loader = new THREE.TextureLoader();
  var cols = 7, rows = 8;
  var btnSize = 6, gap = 1.5;
  var startX = wx - (cols * (btnSize + gap)) / 2 + btnSize/2;
  var startY = wy + 12;
  
  BTNS.forEach(function(b, i){
    var col = i % cols;
    var row = Math.floor(i / cols);
    var x = startX + col * (btnSize + gap);
    var y = startY - row * (btnSize + gap);
    
    var tex = loader.load('/coders100/buttons/' + b[0] + '.webp');
    tex.minFilter = THREE.LinearMipmapLinearFilter;
    tex.magFilter = THREE.LinearFilter;
    tex.anisotropy = renderer.capabilities.getMaxAnisotropy();
    var mat = new THREE.MeshBasicMaterial({ map: tex, transparent: true });
    var mesh = new THREE.Mesh(new THREE.PlaneGeometry(btnSize, btnSize), mat);
    mesh.position.set(x, y, wz + 1.5);
    mesh.userData.buttonIndex = i;
    mesh.userData.buttonFn = b[2];
    mesh.userData.buttonName = b[1];
    buttonWall.add(mesh);
    wallButtons.push(mesh);
  });
  
  /* Face the player */
  buttonWall.rotation.y = -camYaw + Math.PI;
  scene.add(buttonWall);
  say('button wall built — 56 buttons, tap to press');
}

/* Raycast tapping for wall buttons */
var raycaster = new THREE.Raycaster();
var tapPos = new THREE.Vector2();
function onWallTap(event){
  if(!buttonWall) return;
  var rect = renderer.domElement.getBoundingClientRect();
  tapPos.x = ((event.clientX - rect.left) / rect.width) * 2 - 1;
  tapPos.y = -((event.clientY - rect.top) / rect.height) * 2 + 1;
  raycaster.setFromCamera(tapPos, camera);
  var hits = raycaster.intersectObjects(wallButtons);
  if(hits.length > 0){
    var btn = hits[0].object;
    /* Press animation: scale down briefly */
    btn.scale.set(0.85, 0.85, 1);
    setTimeout(function(){ btn.scale.set(1, 1, 1); }, 150);
    /* Do the task */
    say('pressed: ' + btn.userData.buttonName);
    btn.userData.buttonFn();
  }
}
/* Attach tap listener */
if(typeof renderer !== 'undefined' && renderer.domElement){
  renderer.domElement.addEventListener('click', onWallTap);
}

/* ===== PRACTICE DISTRICT ===== */
registerDistrict('practice', 'Practice District', function(){
  var CX=600, CZ=600, PHI=1.6180339887;
  var entry=new THREE.Mesh(new THREE.CircleGeometry(20,24), goldMat);
  entry.rotation.x=-Math.PI/2; entry.position.set(CX,0.3,CZ+60); scene.add(entry);
  var green=new THREE.Mesh(new THREE.CircleGeometry(30,24),
    new THREE.MeshStandardMaterial({color:0x2d6a2d,roughness:0.9}));
  green.rotation.x=-Math.PI/2; green.position.set(CX,0.3,CZ); scene.add(green);
  var pad=new THREE.Mesh(new THREE.CircleGeometry(25,24), goldMat);
  pad.rotation.x=-Math.PI/2; pad.position.set(CX,0.3,CZ-62); scene.add(pad);
  var r1=new THREE.Mesh(new THREE.BoxGeometry(6,0.5,40), roadMat);
  r1.position.set(CX,0.5,CZ+30); scene.add(r1);
  var r2=new THREE.Mesh(new THREE.BoxGeometry(6,0.5,37), roadMat);
  r2.position.set(CX,0.5,CZ-31); scene.add(r2);
  var tg=new THREE.MeshStandardMaterial({color:0xffd700,emissive:0xffd700,emissiveIntensity:0.7,roughness:0.3,metalness:0.6});
  var pw=16,ph=26,pyy=0;
  for(var i=0;i<4;i++){
    var t=new THREE.Mesh(new THREE.BoxGeometry(pw,ph,pw), tg);
    t.position.set(CX,pyy+ph/2,CZ-62); window.applyMinimum(t); scene.add(t);
    pyy+=ph; pw/=PHI; ph/=PHI;
  }
  for(var p=0;p<6;p++){
    var a=(p/6)*Math.PI*2;
    var post=new THREE.Mesh(new THREE.CylinderGeometry(0.8,1,12,8), goldMat);
    post.position.set(CX+Math.cos(a)*10,6,CZ+Math.sin(a)*10);
    window.applyMinimum(post); scene.add(post);
  }
  var roof=new THREE.Mesh(new THREE.ConeGeometry(14,8,6), goldMat);
  roof.position.set(CX,16,CZ); window.applyMinimum(roof); scene.add(roof);
});
dOrder.push('practice');

/* ===== LOOP ===== */

/* 1. AUTO-SWIM — water zones, auto-enter/exit like Genshin */
var waterBodies = [
  {x: 100, z: 100, r: 30, surfaceY: 0.5},
  {x: -80, z: 60, r: 25, surfaceY: 0.5}
];
function waterAt(x, z){
  for(var i=0; i<waterBodies.length; i++){
   