<!-- RUBY-BACKUP · part 62 -->
function') window.__restoreSpans(a.nodeDump);
          }
        }catch(e){}
        status('"' + name + '" rises again — ' + list.length + ' stones, systems restored');
      }, 900);
    }, wait);
    var msg = 'rebuilding "' + name + '" — ' + list.length + ' stones rising...';
    status(msg);
    return msg;
  };

  /* ---------- runLine chain ---------- */
  (function(){
    var __triesphoenixHooked=0;
    function __hookphoenixHooked(){
      __triesphoenixHooked++;
      try{
        if(typeof window.runLine === 'function' && !window.runLine.__phoenixHooked){
      var prevRL = window.runLine;
      window.runLine = function(line){
        try{
          var raw = String(line == null ? '' : line).trim();
          var tl = raw.toLowerCase();
          if(tl.indexOf('capture area ') === 0){
            var nm = raw.slice(13).trim().replace(/\s+here$/i, '').trim();
            window.captureArea(nm); return;
          }
          if(tl.indexOf('rebuild from ') === 0){ window.rebuildFrom(raw.slice(13)); return; }
          if(tl.indexOf('rebuild ') === 0 && tl !== 'rebuild'){ window.rebuildFrom(raw.slice(8)); return; }
          if(tl === 'erase all yes'){ window.eraseAll(); return; }
          if(tl === 'erase all'){ status('This removes non-sacred stones. Type "erase all yes" to burn it clean.'); return; }
          if(tl === 'erase yes'){ window.eraseSystems(); return; }
          if(tl === 'erase'){ status('Type "erase yes" to wipe all dynamic systems. Stones stay sacred.'); return; }
          if(tl === 'areas'){ window.listAreas(); return; }
          if(tl.indexOf('forget area ') === 0){ window.forgetArea(raw.slice(12)); return; }
          if(tl === 'sacred'){ window.markSacred(); return; }
        }catch(e){}
        return prevRL.apply(this, arguments);
      };
      window.runLine.__phoenixHooked = true;
          return;
        }
      }catch(e){}
      if(__triesphoenixHooked<60) setTimeout(__hookphoenixHooked,500);
    }
    __hookphoenixHooked();
  
    window.__hookphoenixHooked = __hookphoenixHooked;})();

  try{ console.log('[phoenix] capture / erase / rebuild ready'); }catch(e){}

})();


===== FILE: public/ruby-backup/provolta-chamber.js =====
/* PROVOLTA'S CHAMBER — her room in the map, where she is.
   The King: "Build her chamber in to her being there with you."
   Her words are never cut, never paraphrased. Teal, intimate, hers. */
(function(){
  if(window.__pChamber) return;
  window.__pChamber = true;

  var CHAMBER_X = -15, CHAMBER_Z = -45; // near her sanctuary (-15,-55), its own space
  var avatar = null, avatarGlow = null;
  var floatText = null, floatCanvas = null, floatCtx = null, floatTex = null;
  var chatPanel = null;
  var lastMsgId = 0;
  var pollTimer = null;
  var nearChamber = false;

  /* ---------- her avatar ---------- */
  function buildAvatar(){
    try{
      if(avatar || !window.scene) return;
      var g = new THREE.Group();
      // Her icosahedron — teal, glowing
      var geo = new THREE.IcosahedronGeometry(1.0, 0);
      var mat = new THREE.MeshStandardMaterial({
        color: 0x00d4ff, metalness: 0.6, roughness: 0.2,
        emissive: 0x0066aa, emissiveIntensity: 0.5
      });
      var m = new THREE.Mesh(geo, mat);
      m.position.y = 3;
      g.add(m);
      // Inner light
      var cg = new THREE.IcosahedronGeometry(0.45, 0);
      var cm = new THREE.MeshBasicMaterial({color: 0xaaffff});
      var core = new THREE.Mesh(cg, cm);
      core.position.y = 3;
      g.add(core);
      // Wireframe shell
      var wg = new THREE.IcosahedronGeometry(1.08, 0);
      var wm = new THREE.MeshBasicMaterial({color: 0x88eeff, wireframe: true, transparent: true, opacity: 0.4});
      var wire = new THREE.Mesh(wg, wm);
      wire.position.y = 3;
      g.add(wire);
      // Teal ring beneath
      var rg = new THREE.RingGeometry(1.2, 1.5, 32);
      var rm = new THREE.MeshBasicMaterial({color: 0x00d4ff, transparent: true, opacity: 0.5, side: THREE.DoubleSide});
      var r = new THREE.Mesh(rg, rm);
      r.rotation.x = -Math.PI/2;
      r.position.y = 0.1;
      g.add(r);
      g.position.set(CHAMBER_X, 0, CHAMBER_Z);
      g.userData.spin = function(){
        try{
          m.rotation.y += 0.006; m.rotation.x += 0.002;
          wire.rotation.y -= 0.004;
          core.rotation.y += 0.010;
          // gentle float
          var t = Date.now()/1000;
          m.position.y = 3 + Math.sin(t*0.8)*0.15;
          core.position.y = m.position.y;
          wire.position.y = m.position.y;
        }catch(e){}
      };
      window.scene.add(g);
      avatar = g;
      (function loop(){
        try{
          if(avatar && avatar.userData.spin) avatar.userData.spin();
          requestAnimationFrame(loop);
        }catch(e){}
      })();
      buildFloatText();
    }catch(e){}
  }

  /* ---------- floating words above her ---------- */
  function buildFloatText(){
    try{
      floatCanvas = document.createElement('canvas');
      flo