<!-- SOLID CITY · part 3718 -->
s*.56);ctx.lineTo(ms*.72,ms*.8);ctx.closePath();ctx.fill();ctx.stroke();
  ctx.fillStyle='#7a5c14';ctx.fillRect(-ms*.18,-ms*.55,ms*.36,ms*.65);
  ctx.globalAlpha=s.phase==='stillness'?.25:1;
  ctx.fillStyle='#ffd166';[-.55,-.3,.3,.55].forEach(q=>{ctx.fillRect(q*ms,-ms*.05,3,8);});
  ctx.globalAlpha=1;
  ctx.strokeStyle='rgba(20,12,4,.85)';ctx.lineWidth=2;
  for(let c=0;c<3-s.rings;c++){
    ctx.beginPath();let cx=-ms*.6+c*ms*.18,cy=-ms*.9;ctx.moveTo(cx,cy);
    for(let k=0;k<5;k++){cx+=(rand()-.5)*ms*.5;cy+=ms*.38;ctx.lineTo(cx,cy);}
    ctx.stroke();
  }
  ctx.restore();ctx.restore();
}
/* Test/dev handle for the summit: read-only state plus the same entry
   points the buttons call. Harmless in production. */
window.__warshipSummit=Object.freeze({
  state:()=>summit?{phase:summit.phase,rings:summit.rings,returned:summit.returned,shieldsDown:summit.shieldsDown,aiSync:summit.aiSync,dropVisible:$('dropBtn')?!$('dropBtn').hidden:null,shipY:+ship.y.toFixed(3),shield:Math.round(ship.shield),hull:Math.round(ship.hull)}:null,
  ended:()=>ended,
  types:()=>events.map(e=>e.type),
  fire:(n,o)=>fireBattery(n,o),
  drop:()=>{if(coordination.tasks.defense.owner!=='human')coordination.claim('defense');dropShields();},
  damage:(n,src)=>damageShip(n,src||'test','front'),
  setProgress:p=>{ship.progress=p;},
  setHull:h=>{ship.hull=h;}
});
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;gameClock=0;missionStart=performance.now();
  summit=null;const db=$('dropBtn');if(db)db.hidden=true;const ot=$('objectiveTitle');if(ot)ot.textContent='Reach Meridian Gate';
  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(summit&&!summit.mirrorGone&&summit.phase!=='ascent'&&summit.phase!=='done'){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,mirror:true,x:ship.x,y:ship.y-.035,tx:summ