<!-- SAGA-STAGING · part 65 -->

    e.stopPropagation(); e.preventDefault();
    for(var k=0; k<e.changedTouches.length; k++){
      var t = e.changedTouches[k];
      if(t.identifier === touchId) setKnob(t.clientX - cx, t.clientY - cy);
    }
  }, {passive:false});
  base.addEventListener('touchend', function(e){
    e.stopPropagation();
    for(var k=0; k<e.changedTouches.length; k++){
      if(e.changedTouches[k].identifier === touchId){
        touchId = null;
        knob.style.transform = 'translate(0,0)';
        onMove(0, 0);
      }
    }
  }, {passive:true});
  return base;
}

/* LEFT stick — moves the king */
var lastDX = 0, lastDZ = 0, walkPhase = 0;
/* Fast flight state - hoisted */
var _fvx = 0, _fvy = 0, _fvz = 0;
var _ftvx = 0, _ftvy = 0, _ftvz = 0;
/* V219: dedicated movement-loop timestamp for AI_GUARDED delta-time (not shared with hyperMove/ShadowMotion) */
var _moveLoopLastT = (typeof performance !== 'undefined' && performance.now) ? performance.now() : Date.now();
var _fcos = 1, _fsin = 0, _fyaw = 999;
var _fdy = 0;
/* Continuous movement loop - runs even when finger holds still */
if(!window._moveLoop){
  window._moveLoop = true;
  setInterval(function(){
    try{
      /* V219: measured delta-seconds; timestamp updates even on early return so no stale dt on mode switch */
      var _v219now = (typeof performance !== 'undefined' && performance.now) ? performance.now() : Date.now();
      var _dtMove = Math.min(Math.max((_v219now - _moveLoopLastT) / 1000, 0), 0.05);
      _moveLoopLastT = _v219now;
      if(hyperMove.enabled) return;
      /* 4. Acceleration/deceleration — fast to start, weighty to stop */
      var ax = Math.abs(_ftvx) > Math.abs(_fvx) ? 0.22 : 0.12;
      var az = Math.abs(_ftvz) > Math.abs(_fvz) ? 0.22 : 0.12;
      _fvx += (_ftvx - _fvx) * ax;
      _fvz += (_ftvz - _fvz) * az;
      _fvy += (_ftvy - _fvy) * 0.18;
      if(typeof kingPos !== 'undefined' && kingPos){
        var _aiLive=window.ACTOR_RUNTIME&&ActorRuntime.authority==="ai_guarded"&&ActorRuntime.ai.active;
        if(_aiLive){
          var _sv=ActorRuntime.safetySupervisor,_sm=ActorRuntime.shadowMotion;
          if(_sv&&_sv.permit&&_sm){
            /* V219: delta-time integration — velocity (u/s) x measured seconds */
            var _aidx = _sm.velocity.x * _dtMove, _aidz = _sm.velocity.z * _dtMove;
            kingPos.x += _aidx;
            kingPos.z += _aidz;
            lastDX = _aidx;
            lastDZ = _aidz;
          }
        }else{
          kingPos.x += _fvx * 0.16;
          kingPos.z += _fvz * 0.16;
          var ny = kingPos.y + _fvy * 0.16;
          kingPos.y = ny < 0.5 ? 0.5 : ny;
        }
        /* MOUNTAIN COLLISION — push out of solid terrain */
        if(window._mountains && window._mountains.length){
          var _v3 = new THREE.Vector3();
          for(var mi = 0; mi < window._mountains.length; mi++){
            var mm = window._mountains[mi];
            if(!mm.userData.isSolidTerrain) 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;', fun