<!-- SOLID CITY · part 3727 -->
'ai',latency:+latency.toFixed(2),epoch});updateStations();},72);}
  command(name,owner,epoch,fn,id){const t=this.tasks[name];id=id||name+'-'+owner+'-'+epoch+'-'+Math.random();if(!this.connected){this.emit('command_rejected',{task:name,reason:'operator disconnected',epoch});return false;}if(this.seen.has(id)){this.emit('command_rejected',{task:name,reason:'duplicate command',epoch});return false;}this.seen.add(id);if(this.queue.length>48){this.emit('command_rejected',{task:name,reason:'queue overloaded',epoch});return false;}if(!t||t.owner!==owner||t.epoch!==epoch){this.emit('command_rejected',{task:name,reason:'stale ownership epoch',epoch,current:t?t.epoch:null});return false;}this.queue.push(id);try{fn();this.emit('command_accepted',{task:name,owner,epoch});}finally{this.queue.shift();}return true;}
  advisory(task,text){this.emit('advisory',{task,text});}
}

const canvas=document.getElementById('game'),ctx=canvas.getContext('2d');
const $=id=>document.getElementById(id);let dpr=1,W=800,H=560,last=0,raf=0,running=false,paused=false,ended=false;
let ship,enemies=[],shells=[],enemyShots=[],particles=[],stars=[],events=[],eventSeq=0,wave=1,nextSpawn=0,aiTick=0,adviceTick=0,missionStart=0;
let rngSeed=92811;
function rand(){rngSeed=(rngSeed*1664525+1013904223)>>>0;return rngSeed/4294967296;}
function emit(type,data){events.push({id:++eventSeq,type,time:performance.now(),mission:missionStart?performance.now()-missionStart:0,...(data||{})});if(events.length>1000)events.shift();if(type==='advisory')$('advisoryText').textContent=data.text;if(type==='command_rejected')showWarning('SIGNAL GUARD · '+data.reason.toUpperCase());renderOwnership();}
let coordination=new ControlCoordination(['nav','batteryA','batteryB','defense'],emit);
function reset(){
  rngSeed=92811;events=[];eventSeq=0;coordination=new ControlCoordination(['nav','batteryA','batteryB','defense'],emit);
  ship={x:.5,y:.74,vx:0,vy:0,hull:100,shield:100,shieldFace:'front',progress:0,targetA:0,targetB:0,navInput:0,boost:false,defCooldown:0};
  enemies=[];shells=[];enemyShots=[];particles=[];wave=1;nextSpawn=.4;aiTick=0;adviceTick=0;ended=false;paused=false;missionStart=performance.now();
  for(let i=0;i<110;i++)stars[i]={x:rand(),y:rand(),z:.25+rand()*.75};
  ['nav','batteryA','batteryB','defense'].forEach(n=>emit('ownership',{task:n,owner:'ai',epoch:1}));
  updateStations();updateHUD();
}
function resize(){const r=canvas.getBoundingClientRect();dpr=Math.min(devicePixelRatio||1,2);W=Math.max(320,r.width);H=Math.max(250,r.height);canvas.width=Math.round(W*dpr);canvas.height=Math.round(H*dpr);ctx.setTransform(dpr,0,0,dpr,0,0);}
function spawnEnemy(kind){const side=rand()<.5?-1:1;const e={id:'E'+Math.floor(rand()*99999),kind:kind||((wave>2&&rand()<.22)?'cruiser':'fighter'),x:.15+rand()*.7,y:-.08-rand()*.2,vx:(rand()-.5)*.05,vy:.045+rand()*.025,hp:kind==='cruiser'?80:((wave>2&&rand()<.22)?80:28),maxHp:0,fire:.7+rand()*1.2,dead:false,side};e.maxHp=e.hp;enemies.push(e);emit('threat_detected',{threat:e.id,kind:e.kind,wave});}
function claim(station){if(coordination.tasks[station].owner==='human')return;coordination.claim(station);updateStations();showWarning(stationLabel(station)+' · YOU HAVE CONTROL',false);}
function release(station){coordination.release(station);updateStations();$('handoffText').textContent='Safe handoff in progress · interruptible by your touch';}
function stationLabel(n){return {nav:'NAVIGATION',batteryA:'BATTERY A',batteryB:'BATTERY B',defense:'DEFENSE'}[n];}
function updateStations(){document.querySelectorAll('.station').forEach(el=>{const n=el.dataset.station,t=coordination.tasks[n];el.dataset.owner=t.owner;el.querySelector('.owner').textContent=t.owner==='human'?'YOU':(t.status==='HANDOFF'?'HANDOFF':'AI CREW');});renderOwnership();}
function renderOwnership(){const vals=Object.values(coordination.tasks),h=vals.filter(t=>t.owner==='human').length;$('ownershipSummary').textContent='YOU '+h+' · AI '+(4-h);const rejected=events.filter(e=>e.type==='command_rejected').length;$('signalText').textContent=coordination.connected?(rejected?'GUARD ACTIVE · '+rejected+' REJECTED':'LINK VERIFIED · LOCAL'):'LINK LOST';}
function showWarning(text,hazard=true){const el=$('warning');el.textContent=text;el.classList.add('show');clearTimeout(showWarning.t);showWarning.t=setTimeout(()=>el.classList.remove('show'),hazard?1600:900);}
function humanCommand(station,fn){const t=coordination.tasks[station];if(t.owner!=='human')claim(station);else if(t.status==='HANDOFF'){t.epoch++;t.status='ACTIVE';emit('command_rejected',{task:station,reason:'handoff interrupted by human input',epoch:t.epoch});updateStations();}const now=coordination.tasks[station];return coordination.command(station,'human',now.epoch,fn,'H-'+station+'-'+performance.now());}
function fireBattery(name,owner){const t=coordination.tasks[name];if(t.owner!==owner)return;const live=enemies.filter(e=>!e.dead);if(!live.length)return;const selected=name==='batteryA'?ship