<!-- SOLID CITY · part 3448 -->
:Math.random()*6.28})}
    if(elapsed>=nextAdvisoryAt){nextAdvisoryAt=elapsed+6;autoAdvisory()}}else if(elapsed>=nextAdvisoryAt){nextAdvisoryAt=elapsed+6;summitAdvisory()}
    if(active===0){if(summit)finishSummit(false,'fell');else finish(false)}else if(progress>=100&&!summit)beginSummit();
    updateHUD();
  }
  function announce(t){document.getElementById('advisory').textContent=t}
  function autoAdvisory(){var active=drones.filter(function(d){return d.status==='ACTIVE'}).length,human=drones.filter(function(d){return d.owner==='HUMAN'&&d.status==='ACTIVE'}).length;if(active<9)announce('Integrity falling. REGROUP can recover disabled drones.');else if(debris.length>12)announce('Hazard density high. Recommend SCATTER or SWEEP. Advisory only.');else if(human)announce(human+' human-held drone'+(human===1?' remains':'s remain')+' outside AI group orders.');else announce('AI sub-commanders executing '+activeOrder+'. All control channels stable.')}
  function finish(success){if(!running)return;running=false;paused=false;pauseBtn.hidden=true;pauseScreen.hidden=true;app.inert=false;document.getElementById('debriefTitle').textContent=success?'Lane secured.':'Swarm lost.';document.getElementById('debriefCopy').textContent=success?'The convoy reached the exit vector under coordinated protection.':'No active drones remain to protect the convoy.';document.getElementById('finalTime').textContent=nowStamp();document.getElementById('finalClear').textContent=count('CLEARED');document.getElementById('finalLost').textContent=count('LOST');debrief.hidden=false;addEvent(success?'COMPLETE':'FAILED','MISSION',success?'Convoy reached exit vector':'All drones disabled')}
  /* ================= SUMMIT: THE COALESCENCE =================
     Twelve drones. Twelve faces. One body.
     At progress 100 the debris field answers a single gravity and fuses
     into one core. The swarm must close a perfect dodecahedron around it
     (one drone per face — the icosahedron's 12 vertices, pure golden ratio),
     hold it under strain, then choose: collapse as one, or hold the cage.
     The many, made one. Mathematically. */
  var PHI=1.6180339887;
  var summit=null;
  function summitIcoVerts(){var v=[],s=[1,-1],i,j;for(i=0;i<2;i++)for(j=0;j<2;j++)v.push([0,s[i],s[j]*PHI]);for(i=0;i<2;i++)for(j=0;j<2;j++)v.push([s[i],s[j]*PHI,0]);for(i=0;i<2;i++)for(j=0;j<2;j++)v.push([s[i]*PHI,0,s[j]]);return v}
  function summitDodecaVerts(){var v=[],s=[1,-1],i,j,k,q=1/PHI;for(i=0;i<2;i++)for(j=0;j<2;j++)for(k=0;k<2;k++)v.push([s[i],s[j],s[k]]);for(i=0;i<2;i++)for(j=0;j<2;j++)v.push([0,s[i]*PHI,s[j]*q]);for(i=0;i<2;i++)for(j=0;j<2;j++)v.push([s[i]*q,0,s[j]*PHI]);for(i=0;i<2;i++)for(j=0;j<2;j++)v.push([s[i]*PHI,s[j]*q,0]);return v}
  function summitDot(a,b){return a[0]*b[0]+a[1]*b[1]+a[2]*b[2]}
  function summitNorm(p){var l=Math.hypot(p[0],p[1],p[2])||1;return [p[0]/l,p[1]/l,p[2]/l]}
  function summitFaces(ico,dod){
    return ico.map(function(c){
      var n=summitNorm(c);
      var ds=dod.map(function(p,i){return {i:i,d:summitDot(p,n)}});
      ds.sort(function(a,b){return b.d-a.d});
      var top=ds[0].d;
      return ds.filter(function(o){return Math.abs(o.d-top)<1e-9}).map(function(o){return o.i});
    });
  }
  function summitEdges(ico){
    var n=ico.map(summitNorm),e=[],a,b,d,best=1e9;
    for(a=0;a<12;a++)for(b=a+1;b<12;b++){d=Math.hypot(n[a][0]-n[b][0],n[a][1]-n[b][1],n[a][2]-n[b][2]);if(d<best)best=d}
    for(a=0;a<12;a++)for(b=a+1;b<12;b++){d=Math.hypot(n[a][0]-n[b][0],n[a][1]-n[b][1],n[a][2]-n[b][2]);if(Math.abs(d-best)<1e-9)e.push([a,b])}
    return e;
  }
  function summitProject(x,y,z,rot){
    var c=Math.cos(rot),s=Math.sin(rot);
    var x1=x*c+z*s,z1=-x*s+z*c,y1=y;
    var t=0.42,ct=Math.cos(t),st=Math.sin(t);
    return [x1,y1*ct-z1*st];
  }
  function summitLatticeR(){
    if(!summit)return 0.16;
    if(summit.phase==='collapse')return Math.max(0,0.16*(1-summit.collapseT/6.18));
    return 0.16;
  }
  function summitStationField(){
    var out=[],R=summitLatticeR(),asp=canvasW/Math.max(1,canvasH);
    for(var i=0;i<12;i++){
      var p=summitProject(summit.icoN[i][0],summit.icoN[i][1],summit.icoN[i][2],summit.rot);
      out.push({x:summit.core.x+p[0]*R,y:summit.core.y+p[1]*R*asp});
    }
    return out;
  }
  function heldCount(){if(!summit)return 0;var n=0,i;for(i=0;i<12;i++)if(summit.heldBy[i])n++;return n}
  function humanHeldCount(){return drones.filter(function(d){return d.owner==='HUMAN'&&d.status==='ACTIVE'}).length}
  function droneName(id){var d=drones.filter(function(x){return x.id===id})[0];return d?d.name:'D-??'}
  function beginSummit(){
    if(summit)return;
    var ico=summitIcoVerts(),dod=summitDodecaVerts();
    var icoN=ico.map(summitNorm),dodN=dod.map(summitNorm);
    var faces=summitFaces(ico,dod);
    var ap=summitDot(dodN[faces[0][0]],icoN[0]);
    summit={phase:'coalesce',t:0,rot:0,charge:0,integrity:100,clearance:0,collapseT:0,collapseFlash:0,
      choice:null,surgeT:0,breachT