<!-- SAGA-SOLID · part 59 -->
:0,
    moveZ:0,
    lookX:0,
    lookY:0,
    magnitude:0,
    jump:false,
    ascend:false,
    descend:false,
    interact:false,
    sequence:0,
    timestamp:0
  },
  locomotion:{
    mode:"still",
    requestedMode:"still",
    capabilities:{walk:true,run:true,jump:true,fly:true,swim:true,vehicle:true},
    velocity:new THREE.Vector3(0,0,0),
    desiredVelocity:new THREE.Vector3(0,0,0),
    grounded:false,
    surface:null,
    slope:0,
    verticalVelocity:0
  },
  physics:{
    gravity:30,
    walkSpeed:12,
    runSpeed:20,
    flySpeed:12,
    acceleration:28,
    braking:36,
    rootClearance:0.37,
    maxSlope:50,
    stepHeight:0.6,
    coyoteMs:120,
    jumpBufferMs:140
  },
  safety:{
    lastSafe:new THREE.Vector3(),
    hasLastSafe:false,
    killY:-500,
    recovering:false
  },
  ai:{
    allowed:true,
    active:false,
    agentId:null,
    goal:null,
    target:null,
    control:"none"
  },
  debug:{
    shadow:true,
    ticks:0,
    lastError:null
  }
};
ActorRuntime.submitIntent=function(source,intent){
  if(source!=="human" && source!=="ai") return false;
  if(source==="ai" && !ActorRuntime.ai.allowed) return false;
  if(!intent || typeof intent!=="object") return false;
  var I=ActorRuntime.input;
  I.owner=source;
  I.source=source==="ai"?"agent":"controls";
  if(Number.isFinite(intent.moveX)) I.moveX=Math.max(-1,Math.min(1,intent.moveX));
  if(Number.isFinite(intent.moveZ)) I.moveZ=Math.max(-1,Math.min(1,intent.moveZ));
  I.magnitude=Math.min(1,Math.sqrt(I.moveX*I.moveX+I.moveZ*I.moveZ));
  I.jump=!!intent.jump;
  I.ascend=!!intent.ascend;
  I.descend=!!intent.descend;
  I.interact=!!intent.interact;
  I.sequence++;
  I.timestamp=performance.now();
  return true;
};
ActorRuntime.releaseAI=function(){
  ActorRuntime.ai.active=false;
  ActorRuntime.ai.agentId=null;
  ActorRuntime.ai.goal=null;
  ActorRuntime.ai.target=null;
  ActorRuntime.ai.control="none";
  ActorRuntime.input.owner="human";
};
window.ACTOR_RUNTIME=ActorRuntime;

/* ===== ACTOR MOBILE DEBUG — v203 ===== */
ActorRuntime.debug.mobile=false;
ActorRuntime.debugElement=null;
ActorRuntime.toggleDebug=function(){
  ActorRuntime.debug.mobile=!ActorRuntime.debug.mobile;
  if(!ActorRuntime.debugElement){
    var d=document.createElement("div");
    d.id="actor-runtime-debug";
    d.style.cssText="position:fixed;top:62px;left:8px;z-index:999999;background:rgba(0,0,0,.82);color:#fff;border:1px solid rgba(255,255,255,.35);border-radius:8px;padding:8px 10px;font:11px/1.35 monospace;white-space:pre;pointer-events:none;max-width:calc(100vw - 16px)";
    document.body.appendChild(d);
    ActorRuntime.debugElement=d;
  }
  ActorRuntime.debugElement.style.display=ActorRuntime.debug.mobile?"block":"none";
};
ActorRuntime.updateDebug=function(){
  if(!ActorRuntime.debug.mobile||!ActorRuntime.debugElement||ActorRuntime.debug.showingTest||ActorRuntime.debug.shadowLiveDisplay)return;
  var I=ActorRuntime.input,L=ActorRuntime.locomotion,A=ActorRuntime.ai;
  ActorRuntime.debugElement.textContent=
    "ACTOR RUNTIME v"+ActorRuntime.version+"  SHADOW\n"+
    "AUTHORITY  "+String(ActorRuntime.authority).toUpperCase()+"\n"+
    "OWNER      "+String(I.owner).toUpperCase()+"\n"+
    "MODE       "+String(L.requestedMode).toUpperCase()+"\n"+
    "STICK      "+I.moveX.toFixed(2)+" / "+I.moveZ.toFixed(2)+"\n"+
    "MAG        "+I.magnitude.toFixed(2)+"\n"+
    "SEQUENCE   "+I.sequence+"\n"+
    "AI         "+(A.allowed?(A.active?"ACTIVE":"READY"):"LOCKED")+"\n"+
    "CONTROL    "+(ActorRuntime.enabled?"LIVE":"SAFE / SHADOW");
};
setInterval(function(){try{ActorRuntime.updateDebug();}catch(e){}},100);
window.ACTOR_RUNTIME=ActorRuntime;

/* ===== VIRTUAL CONTROLLER TEST — v204 ===== */
ActorRuntime.runControllerTest=function(){
  ActorRuntime.debug.showingTest=true;
  var R=ActorRuntime,results=[],startSeq=R.input.sequence;
  var startPos=(typeof kingPos!=="undefined"&&kingPos)?kingPos.clone():null;
  function test(name,ok){results.push({name:name,pass:!!ok});}
  function send(v){return R.submitIntent("ai",v);}

  var oldEnabled=R.enabled,oldAuthority=R.authority;
  R.enabled=false;
  R.authority="legacy";

  test("AI INTENT API",send({moveX:0,moveZ:0}));
  send({moveX:0,moveZ:1});
  test("FORWARD",R.input.moveX===0&&R.input.moveZ===1);
  send({moveX:0,moveZ:-1});
  test("BACKWARD",R.input.moveX===0&&R.input.moveZ===-1);
  send({moveX:-1,moveZ:0});
  test("LEFT",R.input.moveX===-1&&R.input.moveZ===0);
  send({moveX:1,moveZ:0});
  test("RIGHT",R.input.moveX===1&&R.input.moveZ===0);
  send({moveX:9,moveZ:-9});
  test("CLAMP",R.input.moveX===1&&R.input.moveZ===-1&&R.input.magnitude===1);
  send({moveX:.5,moveZ:.5});
  test("DIAGONAL",Math.abs(R.input.magnitude-Math.sqrt(.5))<.001);
  test("AI OWNER",R.input.owner==="ai");
  test("SEQUENCE",R.input.sequence>startSeq);

  R.submitIntent("human",{moveX:0,moveZ:0});
  test("HUMAN TAKEOVER",R.input.owner==="human"&&R.input.magnitude===0);

  var unchanged=true;
  if(startPos&&ki