<!-- RUBY-BACKUP · part 332 -->
size:20px;font-weight:bold;margin-bottom:10px;font-family:sans-serif;';
    ov.appendChild(title);
    var cv = document.createElement('canvas');
    var SZ = Math.min(window.innerWidth-40, window.innerHeight-120);
    cv.width = SZ; cv.height = SZ;
    cv.style.cssText = 'border:2px solid #d8a920;border-radius:10px;';
    ov.appendChild(cv);
    var ctx = cv.getContext('2d');
    var MAP = 2400, scale = SZ/MAP, cx = SZ/2, cy = SZ/2;
    // background
    ctx.fillStyle = '#0a1a0a';
    ctx.fillRect(0, 0, SZ, SZ);
    // contour lines — sample terrain
    var step = 20;
    for(var gx=-MAP/2; gx<MAP/2; gx+=step){
      for(var gz=-MAP/2; gz<MAP/2; gz+=step){
        var h = getTerrainH(gx, gz);
        // color by elevation
        var t = Math.max(0, Math.min(1, (h+14)/28));
        var r = Math.floor(20+t*60), gg = Math.floor(60+t*80), b = Math.floor(20+t*30);
        ctx.fillStyle = 'rgb('+r+','+gg+','+b+')';
        var px = cx+gx*scale, py = cy+gz*scale;
        ctx.fillRect(px, py, Math.max(1,step*scale), Math.max(1,step*scale));
      }
    }
    // contour rings every 4 units of elevation
    ctx.strokeStyle = 'rgba(216,169,32,0.3)';
    ctx.lineWidth = 1;
    for(var e=-12; e<=12; e+=4){
      ctx.beginPath();
      var first = true;
      for(var a=0; a<=Math.PI*2+0.1; a+=0.1){
        // approximate contour as deformed circle
        var rad = 300 + e*20;
        var wx = Math.cos(a)*rad, wz = Math.sin(a)*rad;
        // nudge by terrain
        var hh = getTerrainH(wx, wz);
        var adj = (hh-e)*8;
        wx += Math.cos(a)*adj; wz += Math.sin(a)*adj;
        var px2 = cx+wx*scale, py2 = cy+wz*scale;
        if(first){ ctx.moveTo(px2,py2); first=false; }
        else ctx.lineTo(px2,py2);
      }
      ctx.stroke();
    }
    // highways
    ctx.strokeStyle = '#666';
    ctx.lineWidth = 3;
    if(typeof _highwayPts!=='undefined'){
      _highwayPts.forEach(function(pts){
        ctx.beginPath();
        pts.forEach(function(p, i){
          var px = cx+p[0]*scale, py = cy+p[1]*scale;
          if(i===0) ctx.moveTo(px,py); else ctx.lineTo(px,py);
        });
        ctx.stroke();
      });
    }
    // heatmap — where he's been
    if(_metrics.positions.length>0){
      _metrics.positions.forEach(function(p){
        var px = cx+p.x*scale, py = cy+p.z*scale;
        var grad = ctx.createRadialGradient(px,py,0,px,py,8);
        grad.addColorStop(0, 'rgba(255,0,0,0.6)');
        grad.addColorStop(1, 'rgba(255,0,0,0)');
        ctx.fillStyle = grad;
        ctx.beginPath();
        ctx.arc(px, py, 8, 0, Math.PI*2);
        ctx.fill();
      });
    }
    // player
    if(typeof mePos!=='undefined'){
      ctx.fillStyle = '#00ff00';
      ctx.beginPath();
      ctx.arc(cx+mePos.x*scale, cy+mePos.z*scale, 5, 0, Math.PI*2);
      ctx.fill();
    }
    // legend
    var legend = document.createElement('div');
    legend.innerHTML = '<span style="color:#ff0000">\u25cf</span> where you have been &nbsp; <span style="color:#00ff00">\u25cf</span> you are &nbsp; <span style="color:#888">\u2014</span> highways';
    legend.style.cssText = 'color:#aaa;font-size:12px;margin-top:10px;font-family:sans-serif;';
    ov.appendChild(legend);
    var hint = document.createElement('div');
    hint.innerHTML = 'tap anywhere to close • type "topo" to reopen';
    hint.style.cssText = 'color:#666;font-size:11px;margin-top:5px;font-family:sans-serif;';
    ov.appendChild(hint);
    ov.addEventListener('click', function(){ ov.remove(); });
    document.body.appendChild(ov);
    if(typeof codeStatus==='function') codeStatus('topographic map — '+_metrics.positions.length+' tracks');
  }catch(e){
    if(typeof codeStatus==='function') codeStatus('topo failed');
  }
}
function showMetrics(){
  try{
    if(typeof codeStatus==='function')
      codeStatus('metrics: '+_metrics.positions.length+' positions tracked, '+_metrics.fixes+' auto-fixes');
  }catch(e){}
}
/* HIGHWAY GUARDIAN — nothing builds on highways except power lines */
var _highwayPts = [
  [[12,0],[50,15],[100,10],[200,30],[400,20],[600,40],[800,60],[1000,50],[1200,70]],
  [[12,0],[40,-25],[90,-40],[180,-35],[350,-50],[550,-40],[750,-60],[950,-50],[1150,-70]],
  [[0,12],[-15,50],[-10,100],[-30,200],[-20,400],[-40,600],[-60,800],[-50,1000],[-70,1200]],
  [[0,12],[20,55],[15,110],[35,220],[30,420],[50,600],[60,800],[70,1000],[80,1180]],
  [[-12,0],[-50,-15],[-100,-10],[-200,-30],[-400,-20],[-600,-40],[-800,-60],[-1000,-50],[-1200,-70]],
  [[0,-12],[15,-50],[10,-100],[30,-200],[20,-400],[40,-600],[50,-800],[60,-1000],[70,-1200]],
  [[60,60],[120,110],[200,100],[280,150],[220,220],[140,200],[80,240]]
];
function isOnHighway(x, z){
  try{
    for(var r=0; r<_highwayPts.length; r++){
      var pts = _highwayPts[r];
      for(var i=0; i<pts.length-1; i++){
        var ax=pts[i][0], az=pts[i][1], bx=pts[i+1][0], bz=pts[i+1][1];
        var dx=bx-ax, dz=bz-az;
        var len2 = dx*dx+dz*dz;
        var t = len2>0 ? Math.max(0, Math.min(1, ((