<!-- SAGA-SOLID · part 65 -->
continue;
            mm.getWorldPosition(_v3);
            var mdx = kingPos.x - _v3.x;
            var mdz = kingPos.z - _v3.z;
            var mdist = Math.sqrt(mdx*mdx + mdz*mdz);
            /* Approximate mountain radius from geometry */
            var mr = 50; /* Default */
            if(mm.geometry && mm.geometry.boundingBox){
              var bb = mm.geometry.boundingBox;
              mr = Math.max(bb.max.x - bb.min.x, bb.max.z - bb.min.z) / 2 * mm.scale.x;
            }
            var mtop = _v3.y + (mm.geometry.boundingBox ? (mm.geometry.boundingBox.max.y - mm.geometry.boundingBox.min.y) * mm.scale.y : 50);
            /* If inside mountain horizontally and below top, push out */
            if(mdist < mr && kingPos.y < mtop){
              var pushAng = Math.atan2(mdz, mdx);
              kingPos.x = _v3.x + Math.cos(pushAng) * (mr + 2);
              kingPos.z = _v3.z + Math.sin(pushAng) * (mr + 2);
              /* If near top, allow standing on it */
              if(kingPos.y > mtop - 10){
                kingPos.y = mtop;
              }
            }
          }
        }
        lastDX = _fvx * 0.16;
        lastDZ = _fvz * 0.16;
      }
      if(typeof playerBody !== 'undefined' && playerBody){
        playerBody.rotation.x = _fdy < -0.99 ? -0.3 : 0;
        /* 5. Turn smoothing — character rotates toward movement, never snaps */
        var mvx = _fvx, mvz = _fvz;
        if(Math.sqrt(mvx*mvx + mvz*mvz) > 0.5){
          var desired = Math.atan2(mvx, mvz);
          var cur = playerBody.rotation.y || 0;
          var diff = desired - cur;
          while(diff > Math.PI) diff -= Math.PI*2;
          while(diff < -Math.PI) diff += Math.PI*2;
          playerBody.rotation.y = cur + diff * 0.15;
        }
      }
      if(typeof kingPos !== 'undefined' && kingPos && kingPos.y <= 0.55 && typeof camPitch !== 'undefined' && !window._camActive){
        camPitch += (0.35 - camPitch) * 0.05;
      }
    }catch(e){}
  }, 16);
}
makeStick('left:20px;bottom:100px;', function(dx, dy){
  /* GTA-STYLE INPUT PIPELINE — deadzone -> curve -> camera-relative -> desired velocity */
  _fdy = dy;
  /* 1. Radial deadzone */
  var mag = Math.sqrt(dx*dx + dy*dy);
  var DEAD = 0.18;
  if(mag < DEAD){ dx = 0; dy = 0; mag = 0; }
  else {
    /* 2. Response curve (gamma 1.5) — precision at center, full at edge */
    var norm = Math.min(1, (mag - DEAD) / (1 - DEAD));
    var curved = Math.pow(norm, 1.5);
    var s = curved / (mag || 1);
    dx *= s; dy *= s; mag = curved;
  }
    /* V202 SHADOW INTENT — processed human input, NO movement authority */
    if(window.ACTOR_RUNTIME){ if(!ActorRuntime.ai.active) ActorRuntime.submitIntent("human",{moveX:dx,moveZ:-dy}); ActorRuntime.locomotion.requestedMode=moveMode; }
  if(moveMode === "fly" && dy < -0.99){
    var upAmt = (-dy - 0.99) * 100.0;
    if(upAmt > 1) upAmt = 1;
    _ftvy = upAmt * 12.0;
    /* Fly FORWARD at run speed — keep horizontal, don't kill it */
    if(camYaw !== _fyaw){ _fyaw = camYaw; _fcos = Math.cos(camYaw); _fsin = Math.sin(camYaw); }
    var fsp = 12.0;
    _ftvx = (_fsin * dx - _fcos * 1.0) * fsp;
    _ftvz = (-_fcos * dx - _fsin * 1.0) * fsp;
  } else {
    if(camYaw !== _fyaw){ _fyaw = camYaw; _fcos = Math.cos(camYaw); _fsin = Math.sin(camYaw); }
    var sp = 12.0, ndy = -dy;
    /* 3. Camera-relative direction */
    _ftvx = (_fsin * dx - _fcos * ndy) * sp;
    _ftvz = (-_fcos * dx - _fsin * ndy) * sp;
    _ftvy = 0;
    if(moveMode === "fly" && kingPos.y > 0.6 && dy > 0.95) _ftvy = -8.0;
  }
});

/* RIGHT stick — aims the camera (cannon fires where it faces) */
/* ===== THE CAMERA HAND — v82, one lightning ===== */
function aimCamera(dx, dy){
  window._camActive = (Math.abs(dx) > 0.05 || Math.abs(dy) > 0.05);
  clearTimeout(window._camIdleT);
  window._camIdleT = setTimeout(function(){ window._camActive = false; }, 500);
  if(window._freecam){
    var _fwd = new THREE.Vector3();
    camera.getWorldDirection(_fwd);
    camera.position.addScaledVector(_fwd, -dy * 2);
    var _right = new THREE.Vector3().crossVectors(_fwd, camera.up).normalize();
    camera.position.addScaledVector(_right, dx * 2);
  } else {
    camYaw -= dx * 0.04;
    camPitch = Math.max(-1.5, Math.min(1.4, camPitch + dy * 0.025));
  }
}
makeStick('right:20px;bottom:190px;', aimCamera);


/* ===== BUTTON WALL — 56 tappable buttons in 3D ===== */
var buttonWall = null;
var wallButtons = [];
function buildButtonWall(){
  if(buttonWall) scene.remove(buttonWall);
  wallButtons = [];
  buttonWall = new THREE.Group();
  /* Build 10 units ahead — you place it by where you stand */
  var wx = kingPos.x - Math.cos(camYaw) * 10;
  var wz = kingPos.z - Math.sin(camYaw) * 10;
  var wy = 25;
  say('wall placed where you stand');
  
  /* Wall: dark panel with gold trim, at Practice District */
  var wallGeo = new THREE.BoxGeometry(60, 40, 2);
  var wallMat = new THREE.MeshStandardMaterial({ color: 0x0b0906, roughness: 0.8 });
  var wall = new THREE.M