<!-- RUBY-BACKUP · part 32 -->
.style.background = '#d8a920';
            installBtn.style.borderColor = '#ffe27a';
          } else {
            installBtn.style.color = '#8a6a1c'; installBtn.style.background = 'transparent';
            installBtn.style.borderColor = '#8a6a1c';
          }
        }catch(e){}
      }
      function tapInstall(e){
        try{ if(e){ e.preventDefault(); e.stopPropagation(); } }catch(x){}
        installMode = !installMode;
        paintInstall();
        try{
          if(typeof codeStatus==='function')
            codeStatus(installMode ? 'INSTALL on — tap a code, then tap a block' : '');
        }catch(e){}
      }
      if(installBtn){
        installBtn.addEventListener('touchstart', tapInstall, {passive:false});
        installBtn.addEventListener('mousedown', tapInstall);
      }
      // Row taps
      var rows = el.querySelectorAll('.cps-row');
      for(var k=0;k<rows.length;k++){
        (function(row){
          var fired = false;
          function go(e){
            if(fired) return; fired = true;
            try{ if(e){ e.preventDefault(); e.stopPropagation(); } }catch(x){}
            var si = parseInt(row.getAttribute('data-sec'),10);
            var ci = parseInt(row.getAttribute('data-idx'),10);
            var cd = SECTIONS[si].codes[ci];
            if(installMode){
              if(cd.arg){ fired = false; promptArgInstall(si, cd, row); return; }
              window.armInstall(cd.code, cd.why);
              return;
            }
            if(cd.arg){ fired = false; promptArg(si, cd, row); return; }
            closeScroll();
            setTimeout(function(){ runCode(cd.code); }, 320);
          }
          row.addEventListener('touchstart', go, {passive:false});
          row.addEventListener('mousedown', go);
        })(rows[k]);
      }
      void el.offsetHeight;
      el.style.maxHeight = mh + 'px';
      try{ if(typeof codeStatus==='function') codeStatus('the pyramid speaks — choose'); }catch(e){}
    }catch(e){ closeScroll(); }
  }


  /* ============ CODE INSTALLATION — the pyramid is the source ============
     The King: "Have an option to install codes to other blocks from this pyramid."
     Codes flow from the pyramid into the world, block by block. */

  window.__installed = window.__installed || {};   // nodeId -> [code strings]
  window.__installArmed = null;                    // {code, why} when armed
  window.__uninstallArmed = false;

  var INSTALL_KEY = 'ruby-installed-v1';

  function saveInstalled(){
    try{ localStorage.setItem(INSTALL_KEY, JSON.stringify(window.__installed)); }catch(e){}
  }
  function loadInstalled(){
    try{
      var d = JSON.parse(localStorage.getItem(INSTALL_KEY)||'{}');
      if(d && typeof d==='object') window.__installed = d;
    }catch(e){}
  }

  /* Gold sigil marking a code-bearer */
  function addSigil(nodeId){
    try{
      var rec = (window.__nodeMap||{})[nodeId];
      if(!rec || !rec.obj) return;
      var obj = rec.obj;
      if(obj.userData.__sigil) return; // already marked
      var g = new THREE.OctahedronGeometry(0.35);
      var m = new THREE.MeshBasicMaterial({color:0xffd700});
      var s = new THREE.Mesh(g, m);
      // Place above the block
      var p = new THREE.Vector3(); obj.getWorldPosition(p);
      // Find block height roughly via bounding box
      try{
        var bb = new THREE.Box3().setFromObject(obj);
        var sz = new THREE.Vector3(); bb.getSize(sz);
        s.position.set(0, sz.y/2 + 0.6, 0);
      }catch(e){ s.position.set(0, 1.5, 0); }
      obj.add(s);
      obj.userData.__sigil = s;
      // Gentle spin
      (function spin(){
        try{
          if(!s.parent) return;
          s.rotation.y += 0.03;
          requestAnimationFrame(spin);
        }catch(e){}
      })();
    }catch(e){}
  }
  function removeSigil(nodeId){
    try{
      var rec = (window.__nodeMap||{})[nodeId];
      if(rec && rec.obj && rec.obj.userData.__sigil){
        var s = rec.obj.userData.__sigil;
        if(s.parent) s.parent.remove(s);
        delete rec.obj.userData.__sigil;
      }
    }catch(e){}
  }

  /* Restore sigils for all installed blocks on load */
  function restoreSigils(){
    try{
      for(var nid in window.__installed){
        if(window.__installed[nid] && window.__installed[nid].length) addSigil(nid);
      }
    }catch(e){}
  }

  window.installCodeOn = function(nodeId, code){
    try{
      window.__installed[nodeId] = window.__installed[nodeId] || [];
      if(window.__installed[nodeId].indexOf(code) < 0){
        window.__installed[nodeId].push(code);
        saveInstalled();
        addSigil(nodeId);
        return true;
      }
      return false; // already there
    }catch(e){ return false; }
  };

  window.uninstallCodesOn = function(nodeId){
    try{
      delete window.__installed[nodeId];
      saveInstalled();
      removeSigil(nodeId);
      return true;
    }catch(e){ return false; }
  };

  window.installedOn = function(nodeId){
    try{ ret