<!-- SOLID CITY · part 3737 -->
h.hypot(e.x-s.x,e.y-s.y)<(e.kind==='cruiser'?.045:.028));if(e)hitEnemy(e,10,s);});
  enemyShots.forEach(p=>{p.x+=p.vx*dt;p.y+=p.vy*dt;p.life-=dt;if(Math.hypot(p.x-ship.x,p.y-ship.y)<.035){p.life=0;damageShip(8,'enemy projectile');}});
  particles.forEach(p=>{p.x+=p.vx*dt;p.y+=p.vy*dt;p.vx*=.97;p.vy*=.97;p.life-=dt;});
  enemies=enemies.filter(e=>!e.dead&&e.y<1.05);shells=shells.filter(s=>!s.hit&&s.life>0);enemyShots=enemyShots.filter(p=>p.life>0&&p.y<1.1);particles=particles.filter(p=>p.life>0);
  ai(dt);adviceTick-=dt;if(adviceTick<=0){adviceTick=4.5;const human=Object.entries(coordination.tasks).filter(x=>x[1].owner==='human').map(x=>stationLabel(x[0]));const msg=human.length?'Holding '+(4-human.length)+' stations. Your '+human.join(' + ')+' commands remain isolated.':(enemyShots.length?'Incoming fire tracked. Defense is screening the ship.':'All stations coordinated. Route to Meridian Gate remains clear.');coordination.advisory('crew',msg);}
  if(enemyShots.some(p=>Math.hypot(p.x-ship.x,p.y-ship.y)<.18))showWarning('INCOMING · DEFENSE RECOMMENDS EVASION');
  updateHUD();if(ship.progress>=1)finish(true);
}
function draw(){ctx.clearRect(0,0,W,H);const grd=ctx.createLinearGradient(0,0,0,H);grd.addColorStop(0,'#02070c');grd.addColorStop(1,'#0a1c27');ctx.fillStyle=grd;ctx.fillRect(0,0,W,H);
  ctx.fillStyle='#d9f5ff';stars.forEach(s=>{ctx.globalAlpha=.25+s.z*.65;ctx.fillRect(s.x*W,s.y*H,Math.max(1,s.z*1.7),Math.max(1,s.z*3.2));});ctx.globalAlpha=1;
  const gateY=(.08+ship.progress*.03)*H;ctx.strokeStyle='rgba(35,199,217,.28)';ctx.lineWidth=2;ctx.beginPath();ctx.arc(W*.5,gateY,W*(.07+ship.progress*.02),0,Math.PI*2);ctx.stroke();ctx.fillStyle='rgba(35,199,217,.12)';ctx.beginPath();ctx.arc(W*.5,gateY,W*.04,0,Math.PI*2);ctx.fill();
  enemyShots.forEach(p=>{ctx.strokeStyle='#ff674e';ctx.lineWidth=2;ctx.beginPath();ctx.moveTo(p.x*W,p.y*H);ctx.lineTo((p.x-p.vx*.06)*W,(p.y-p.vy*.06)*H);ctx.stroke();});
  shells.forEach(s=>{ctx.strokeStyle=s.battery==='batteryA'?'#59eaff':'#ffd166';ctx.lineWidth=2;ctx.beginPath();ctx.moveTo(s.x*W,s.y*H);ctx.lineTo((s.x-(s.tx-s.x)*.08)*W,(s.y-(s.ty-s.y)*.08)*H);ctx.stroke();});
  enemies.forEach(e=>drawEnemy(e));drawShip();particles.forEach(drawParticle);
  const humanTargets=['batteryA','batteryB'].filter(n=>coordination.tasks[n].owner==='human');humanTargets.forEach(n=>{const live=enemies.filter(e=>!e.dead),idx=n==='batteryA'?ship.targetA:ship.targetB,e=live[idx%live.length];if(e){ctx.strokeStyle=n==='batteryA'?'#59eaff':'#ffd166';ctx.lineWidth=1;ctx.setLineDash([5,5]);ctx.beginPath();ctx.arc(e.x*W,e.y*H,24,0,Math.PI*2);ctx.stroke();ctx.setLineDash([]);}});
}
function drawEnemy(e){const x=e.x*W,y=e.y*H,s=e.kind==='cruiser'?18:11;ctx.save();ctx.translate(x,y);ctx.fillStyle=e.kind==='cruiser'?'#c6503d':'#8f4051';ctx.strokeStyle='#ff9b78';ctx.lineWidth=1.5;ctx.beginPath();ctx.moveTo(0,s);ctx.lineTo(-s*.8,-s*.7);ctx.lineTo(0,-s*.25);ctx.lineTo(s*.8,-s*.7);ctx.closePath();ctx.fill();ctx.stroke();ctx.restore();ctx.fillStyle='rgba(0,0,0,.7)';ctx.fillRect(x-18,y-s-9,36,3);ctx.fillStyle='#ff6358';ctx.fillRect(x-18,y-s-9,36*Math.max(0,e.hp/e.maxHp),3);}
function drawShip(){const x=ship.x*W,y=ship.y*H,s=Math.max(22,Math.min(34,W*.035));ctx.save();ctx.translate(x,y);ctx.fillStyle='rgba(35,199,217,'+(0.12+ship.shield/450)+')';ctx.strokeStyle='#36d9e8';ctx.lineWidth=2;ctx.beginPath();const a=ship.shieldFace==='left'?Math.PI*.55:ship.shieldFace==='right'?-Math.PI*.05:Math.PI*1.05;ctx.arc(0,0,s*1.7,a,a+Math.PI*.9);ctx.stroke();ctx.fillStyle='#b9d5df';ctx.strokeStyle='#effcff';ctx.lineWidth=1.5;ctx.beginPath();ctx.moveTo(0,-s*1.25);ctx.lineTo(-s*.72,s*.8);ctx.lineTo(-s*.28,s*.56);ctx.lineTo(0,s*.9);ctx.lineTo(s*.28,s*.56);ctx.lineTo(s*.72,s*.8);ctx.closePath();ctx.fill();ctx.stroke();ctx.fillStyle='#0c5967';ctx.fillRect(-s*.18,-s*.55,s*.36,s*.65);ctx.fillStyle='#58e5ef';ctx.fillRect(-s*.45,s*.65,s*.22,s*.22);ctx.fillRect(s*.23,s*.65,s*.22,s*.22);ctx.fillStyle='#ffbd59';[-.55,-.3,.3,.55].forEach(q=>{ctx.fillRect(q*s,-s*.05,3,8)});ctx.restore();}
function drawParticle(p){const a=Math.max(0,p.life/p.max);ctx.globalAlpha=a;ctx.fillStyle=p.type==='boom'?'#ff8a3d':p.type==='muzzle'?'#7bf5ff':'#ffd27b';ctx.beginPath();ctx.arc(p.x*W,p.y*H,(p.type==='boom'?10:4)*(1-a*.3),0,Math.PI*2);ctx.fill();ctx.globalAlpha=1;}
function updateHUD(){$('progressBar').style.width=(ship.progress*100).toFixed(1)+'%';$('rangeText').textContent=Math.max(0,Math.round(8000*(1-ship.progress))).toLocaleString()+' KM';$('hullBar').style.width=Math.max(0,ship.hull)+'%';$('hullText').textContent=Math.max(0,Math.round(ship.hull))+'%';$('shieldBar').style.width=Math.max(0,ship.shield)+'%';$('shieldText').textContent=Math.max(0,Math.round(ship.shield))+'%';$('waveChip').textContent='WAVE '+wave+' · CONTACTS '+enemies.length;}
function loop(t){const dt=Math.min(.034,(t-last)/1000||.016);last=t;update(dt);draw();raf=requestAnimationFrame(loop);}
function finish(win){if(ended)return;ended=true;running=false;emi