<!-- RUBY-BACKUP · part 61 -->
]).filter(function(pr){
      var a = Math.round(pr[0].x*10)/10 + ',' + Math.round(pr[0].z*10)/10;
      var b = Math.round(pr[1].x*10)/10 + ',' + Math.round(pr[1].z*10)/10;
      return pos[a] && pos[b];
    });
    var spans = (full.spans || []).filter(function(sp){ return inR(sp.ax, sp.az) && inR(sp.bx, sp.bz); });
    return {v:1, t:Date.now(), nodes:nodes, portals:portals, network:null, spans:spans};
  }

  window.captureArea = function(name){
    name = cleanName(name);
    if(!name) return 'name it — capture area <name>';
    var pp = playerPos();
    var stonesArr = captureStones(pp.x, pp.z, RADIUS);
    var dump = areaNodeDump(pp.x, pp.z, RADIUS);
    var areas = loadAreas();
    areas[name] = {t: Date.now(), cx: Math.round(pp.x*10)/10, cz: Math.round(pp.z*10)/10,
                   radius: RADIUS, stones: stonesArr, nodeDump: dump};
    saveAreas(areas);
    var msg = 'area "' + name + '" captured — ' + stonesArr.length + ' stones, ' +
              dump.nodes.length + ' nodes, ' + dump.spans.length + ' spans';
    status(msg);
    return msg;
  };

  window.listAreas = function(){
    var areas = loadAreas(), names = Object.keys(areas);
    if(!names.length){ status('no captured areas'); return 'no captured areas'; }
    var lines = names.map(function(n){ return '"' + n + '" — ' + ageStr(areas[n].t) + ', ' + (areas[n].stones||[]).length + ' stones'; });
    var out = lines.join('\n');
    status(names.length + ' captured areas');
    try{ console.log('[areas]\n' + out); }catch(e){}
    return out;
  };

  window.forgetArea = function(name){
    name = cleanName(name);
    var areas = loadAreas();
    if(!areas[name]) return 'no area "' + name + '"';
    delete areas[name];
    saveAreas(areas);
    status('forgotten area "' + name + '"');
    return 'forgotten';
  };

  /* ---------- erase ---------- */
  window.eraseSystems = function(){
    try{ if(typeof window.__clearDynamic === 'function') window.__clearDynamic(); }catch(e){}
    /* also forget the autoload memory so systems don't resurrect on reload */
    try{ if(typeof window.forgetNodes === 'function') window.forgetNodes(); }catch(e){}
    var msg = 'systems erased — modes, ropes, spans, network gone. stones stand sacred.';
    status(msg);
    return msg;
  };

  window.eraseAll = function(){
    var nStones = 0, nFill = 0;
    try{
      /* pass 1: identify sacred */
      var ch = (typeof stones !== 'undefined' && stones.children) ? stones.children : [];
      var sacredSet = {};
      for(var i=0;i<ch.length;i++){ if(isSacred(ch[i])) sacredSet[i] = true; }
      /* pass 2: remove non-sacred stones (fillers go unless near sacred) */
      for(var j=ch.length-1;j>=0;j--){
        var g = ch[j], u = g.userData || {};
        if(sacredSet[j]) continue;
        if(u.filler){
          var nearSacred = false;
          for(var k in sacredSet){
            var sg = ch[k];
            if(sg && Math.hypot(g.position.x-sg.position.x, g.position.z-sg.position.z) < 3){ nearSacred = true; break; }
          }
          if(nearSacred) continue;
          nFill++;
        } else {
          if(!u.stone) continue;
          nStones++;
        }
        try{ stones.remove(g); }catch(e){}
      }
      try{ if(typeof save === 'function') save(); }catch(e){}
      try{ if(typeof broadcastWatch === 'function') broadcastWatch(); }catch(e){}
    }catch(e){}
    window.eraseSystems();
    var msg = 'burned clean — ' + nStones + ' stones, ' + nFill + ' fillers removed. sacred stands.';
    try{ if(typeof codeStatus === 'function') codeStatus(msg); }catch(e){}
    return msg;
  };

  /* ---------- rebuild ---------- */
  function stoneAtSafe(x, z, y){
    try{ if(typeof stoneAt === 'function') return !!stoneAt(x, z, y || 0); }catch(e){}
    return false;
  }

  window.rebuildFrom = function(name){
    name = cleanName(name);
    var areas = loadAreas();
    var a = areas[name];
    if(!a) return 'no area "' + name + '" — capture it first';
    var list = a.stones || [];
    /* raise the stones, staggered — nothing teleports */
    for(var i=0;i<list.length;i++){
      (function(e, idx){
        setTimeout(function(){
          try{
            if(stoneAtSafe(e.x, e.z, e.y)) return; /* already standing — never alter */
            if(typeof placeStone === 'function'){
              var g = placeStone(e.x, e.z, e.r, e.s, false, true, e.y || 0, !!e.land);
              if(g && e.sacred) g.userData.sacred = true;
            }
          }catch(ex){}
        }, idx * 120);
      })(list[i], i);
    }
    /* after the stones rise: stamp, then return the systems */
    var wait = list.length * 120 + 800;
    setTimeout(function(){
      try{ if(typeof window.stampAllNodes === 'function') window.stampAllNodes(); }catch(e){}
      setTimeout(function(){
        try{
          if(a.nodeDump){
            if(typeof window.__restoreNodes === 'function') window.__restoreNodes(a.nodeDump);
            if(typeof window.__restoreSpans === '