<!-- SOLID CITY · part 2918 -->
,W,H);g.addColorStop(0,'#06151e');g.addColorStop(1,'#02070c');ctx.fillStyle=g;ctx.fillRect(0,0,W,H);
    drawStars();drawGate();state.hazards.forEach(drawHazard);state.debris.forEach(drawDebris);state.pods.forEach(drawPod);state.enemies.forEach(drawEnemy);state.shots.forEach(drawShot);drawShip();
  }
  function drawStars(){ctx.save();for(let i=0;i<90;i++){const x=(i*113)%W,y=(i*67)%H,a=.2+(i%5)*.12;ctx.fillStyle='rgba(177,230,239,'+a+')';ctx.fillRect(x,y,i%13===0?2:1,i%13===0?2:1)}ctx.restore()}
  function drawGate(){const g=state.gate;ctx.save();ctx.translate(g.x,g.y);ctx.strokeStyle='#57e7ff';ctx.lineWidth=6;ctx.shadowColor='#32d9ff';ctx.shadowBlur=22;ctx.beginPath();ctx.arc(0,0,g.r,-1.2,1.2);ctx.stroke();ctx.beginPath();ctx.arc(0,0,g.r,1.94,4.34);ctx.stroke();ctx.shadowBlur=0;ctx.fillStyle='#b8f7ff';ctx.font='700 13px "Arial Narrow"';ctx.textAlign='center';ctx.fillText('RESCUE GATE',0,-g.r-12);ctx.restore()}
  function drawHazard(h){ctx.save();ctx.translate(h.x,h.y);ctx.rotate(h.spin);ctx.strokeStyle='rgba(255,99,117,.48)';ctx.fillStyle='rgba(255,70,92,.05)';ctx.lineWidth=2;ctx.setLineDash([8,8]);ctx.beginPath();ctx.arc(0,0,h.r,0,Math.PI*2);ctx.fill();ctx.stroke();ctx.setLineDash([]);for(let i=0;i<3;i++){ctx.rotate(2.094);ctx.fillStyle='rgba(255,99,117,.28)';ctx.beginPath();ctx.moveTo(0,-8);ctx.lineTo(10,-h.r*.72);ctx.lineTo(-10,-h.r*.72);ctx.closePath();ctx.fill()}ctx.restore()}
  function drawDebris(d){ctx.save();ctx.translate(d.x,d.y);ctx.fillStyle='#59666b';ctx.strokeStyle='#8d9da3';ctx.beginPath();for(let i=0;i<7;i++){const a=i/7*Math.PI*2,r=d.r*(.7+((i*3)%5)/10);const x=Math.cos(a)*r,y=Math.sin(a)*r;i?ctx.lineTo(x,y):ctx.moveTo(x,y)}ctx.closePath();ctx.fill();ctx.stroke();ctx.restore()}
  function drawPod(p){if(p.status==='rescued'||p.status==='lost')return;ctx.save();ctx.translate(p.x,p.y);const cargo=p.status==='cargo';ctx.strokeStyle=p.hp<42?'#ff6375':'#ffc857';ctx.fillStyle='#1e3037';ctx.lineWidth=3;ctx.shadowColor=ctx.strokeStyle;ctx.shadowBlur=10;ctx.beginPath();ctx.roundRect(-14,-9,28,18,8);ctx.fill();ctx.stroke();ctx.shadowBlur=0;if(!cargo){ctx.globalAlpha=.32;ctx.beginPath();ctx.arc(0,0,48,0,Math.PI*2);ctx.stroke();ctx.globalAlpha=1;ctx.fillStyle='#eefcff';ctx.font='600 11px system-ui';ctx.textAlign='center';ctx.fillText(p.id+' · '+Math.ceil(p.hp)+'%',0,-56);if(p.stabilize>0){ctx.fillStyle='rgba(0,0,0,.7)';ctx.fillRect(-28,18,56,5);ctx.fillStyle='#ffc857';ctx.fillRect(-28,18,56*(p.stabilize/100),5)}}ctx.restore()}
  function drawEnemy(e){ctx.save();ctx.translate(e.x,e.y);ctx.rotate(Math.PI);ctx.fillStyle='#b72a42';ctx.strokeStyle='#ff8290';ctx.lineWidth=2;ctx.beginPath();ctx.moveTo(18,0);ctx.lineTo(-11,-9);ctx.lineTo(-5,0);ctx.lineTo(-11,9);ctx.closePath();ctx.fill();ctx.stroke();ctx.restore()}
  function drawShot(s){ctx.save();ctx.fillStyle='#72f7ff';ctx.shadowColor='#72f7ff';ctx.shadowBlur=9;ctx.beginPath();ctx.arc(s.x,s.y,3,0,Math.PI*2);ctx.fill();ctx.restore()}
  function drawShip(){const s=state.ship;ctx.save();ctx.translate(s.x,s.y);ctx.rotate(s.angle);ctx.fillStyle='#d4eef2';ctx.strokeStyle='#42dce5';ctx.lineWidth=2;ctx.shadowColor='#42dce5';ctx.shadowBlur=10;ctx.beginPath();ctx.moveTo(22,0);ctx.lineTo(-13,-13);ctx.lineTo(-8,-4);ctx.lineTo(-19,0);ctx.lineTo(-8,4);ctx.lineTo(-13,13);ctx.closePath();ctx.fill();ctx.stroke();ctx.shadowBlur=0;ctx.fillStyle='#ffc857';ctx.fillRect(-18,-3,7,6);if(s.pulse>0){ctx.strokeStyle='rgba(87,231,255,'+(.25+s.pulse/2)+')';ctx.beginPath();ctx.arc(0,0,32+s.pulse*10,0,Math.PI*2);ctx.stroke()}ctx.restore()}

  function updateUI(){
    const s=state.ship,p=s.cargo;$('#shipVal').textContent=Math.ceil(s.hp)+'%';$('#shipBar').style.width=s.hp+'%';$('#shieldVal').textContent=Math.ceil(s.shield)+'%';$('#shieldBar').style.width=s.shield+'%';$('#shipMeter').classList.toggle('danger',s.hp<35);
    $('#podVal').textContent=p?Math.ceil(p.hp)+'%':'None';$('#podBar').style.width=p?p.hp+'%':'0%';$('#rescuedCount').textContent=state.rescued;$('#remainingCount').textContent=state.pods.filter(x=>x.status==='adrift'||x.status==='cargo').length;$('#riskCount').textContent=state.risk;$('#lostCount').textContent=state.lost;
    let obj;if(p)obj='Escort '+p.id+' safely to the blue rescue gate.';else{const n=nearestPod();obj=n?'Approach '+n.id+', stabilize the pod, then extract.':'Return to the rescue gate.'}$('#objective').textContent=obj;
  }
  function derived(){
    const of=t=>events.filter(e=>e.type===t), lat=of('handoff').map(e=>e.data.latency).sort((a,b)=>a-b);return{rescued:of('rescue').length,lost:of('lost').length,human:of('extraction').filter(e=>e.data.owner==='human').length,ai:of('extraction').filter(e=>e.data.owner==='ai').length,intercepts:of('interception').length,handoffs:of('handoff').length,rejected:of('rejected').length,repairs:of('repair').length,events:events.filter(e=>['handoff','rejected','interception','extraction','repair'].includes(e.type)).length,latency:lat.length?lat[Math.floor(lat.length/2)]:null};
  }
  function 