<!-- SOLID CITY · part 3696 -->
ning(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&&!warden)return;const selected=name==='batteryA'?ship.targetA:ship.targetB;const target=live.length?live[selected%live.length]:{id:'WARDEN',x:.5,y:.16};if(!target)return;const epoch=t.epoch,id='salvo-'+name+'-'+Math.floor(performance.now());coordination.command(name,owner,epoch,()=>{
    const offsets=[-10,-3,3,10];offsets.forEach((o,i)=>{shells.push({battery:name,owner,x:ship.x,y:ship.y-.035,tx:target.x,ty:target.y,target:target.id,life:1.4,offset:o/W,hit:false});emit('shot',{battery:name,owner,target:target.id,shell:i+1});});
    emit('salvo',{battery:name,owner,target:target.id});if(warden&&warden.stage==='synchronize')wardenSalvo(name,owner);for(let i=0;i<12;i++)particle(ship.x+(name==='batteryA'?-.018:.018),ship.y-.03,'muzzle');
  },id);
}
function cycleTarget(name){const live=enemies.filter(e=>!e.dead);if(!live.length)return;if(name==='batteryA')ship.targetA=(ship.targetA+1)%live.length;else ship.targetB=(ship.targetB+1)%live.length;emit('target_selected',{battery:name,owner:'human',target:live[name==='batteryA'?ship.targetA:ship.targetB].id});}
function particle(x,y,type){particles.push({x,y,vx:(rand()-.5)*.14,vy:(rand()-.5)*.14,life:type==='boom'?1.2:.45,max:type==='boom'?1.2:.45,type});}
function hitEnemy(e,damage,s){e.hp-=damage;s.hit=true;emit('hit',{battery:s.battery,owner:s.owner,target:e.id,damage});for(let i=0;i<8;i++)particle(e.x,e.y,'hit');if(e.hp<=0&&!e.dead){e.dead=true;emit('threat_destroyed',{threat:e.id,battery:s.battery,owner:s.owner,kind:e.kind});for(let i=0;i<38;i++)particle(e.x,e.y,'boom');}}
const SHIELD_STRONG=.8,SHIELD_WEAK=.2;
function shieldProtection(facing,impactFace){return facing===impactFace?SHIELD_STRONG:SHIELD_WEAK;}
function projectileImpactFace(p){if(Math.abs(p.vx)>Math.abs(p.vy)*.55)return p.vx>0?'left':'right';return 'front';}
function relativeImpactFace(x){if(x<ship.x-.035)return 'left';if(x>ship.x+.035)return 'right';return 'front';}
function updateDefenseStatus(){
  const face=ship.shieldFace||'front',other=face==='front'?'sides':'other arcs',charge=Math.max(0,Math.round(ship.shield));
  $('defenseStatus').textContent=charge>0?'Facing '+face.toUpperCase()+' · rated 80% '+face+' / 20% '+other+' · charge '+charge+'%':'Facing '+face.toUpperCase()+' · 0% effective · shield empty';
  document.querySelectorAll('[data-station="defense"] [data-action^="shield"]').forEach(btn=>{const active=btn.dataset.action.toLowerCase()==='shield'+face;btn.classList.toggle('active',active);btn.setAttribute('aria-pressed',String(active));});
}
function damageShip(amount,source,impactFace){
  impactFace=impactFace||'front';
  const protection=shieldProtection(ship.shieldFace,impactFace),shieldAvailable=ship.shield>0;let absorbed=0;
  if(shieldAvailable){absorbed=Math.min(ship.shield,amount*protection);ship.shield-=absorbed;}
  const hull=Math.max(0,amount-absorbed);ship.hull-=hull;
  const absorbedPct=amount?Math.round(absorbed/amount*100):0;
  emit('damage_taken',{amount:+hull.toFixed(1),absorbed:+absorbed.toFixed(1),source,impactFace,shieldFace:ship.shieldFace,rating:+(protection*100).toFixed(0),absorbedPct});
  showWarning(shieldAvailable?impactFace.toUpperCase()+' IMPACT · '+absorbedPct+'% ABSORBED':impactFace.toUpperCa