<!-- RUBY-BACKUP · part 46 -->
  if(gDown('m',e.clientX,e.clientY)){ e.preventDefault(); e.stopPropagation(); }
      window._grandMouse=true;
    },{capture:true});
    window.addEventListener('mousemove',function(e){
      if(!window._grandMouse) return;
      if(gMove('m',e.clientX,e.clientY)){ e.preventDefault(); e.stopPropagation(); }
    },{capture:true});
    window.addEventListener('mouseup',function(e){
      if(window._grandMouse){ gUp('m'); window._grandMouse=false; }
    },{capture:true});
  }
  try{ initSpanTaps(); }catch(e){}
  /* codes: wrap runLine (grand-rigging -> rigging -> pulley-lab -> rope-deform -> original) */
  (function(){
    var __triesgr=0;
    function __hookgr(){
      __triesgr++;
      try{
        if(typeof window.runLine!=='function'||window.runLine.__grHooked){ if(__triesgr<60) setTimeout(__hookgr,500); return; }
    var orig=window.runLine;
    window.runLine=function(line){
      var tl=String(line==null?'':line).trim().toLowerCase();
      if(tl==='compound'){ buildCompound(); return; }
      if(tl==='uncompound'){ killMachines('compound'); status('compound gone'); return; }
      if(tl==='counterweight'){ buildCounterweight(); return; }
      if(tl==='unweight'){ killMachines('counterweight'); status('counterweight gone'); return; }
      if(tl==='winch'){ buildWinch(); return; }
      if(tl==='unwinch'){ killMachines('winch'); status('winch gone'); return; }
      if(tl==='gearlink'){ buildGearlink(); return; }
      if(tl==='ungear'){ killMachines('gearlink'); status('gear link gone'); return; }
      if(tl==='lever'){ buildLever(); return; }
      if(tl==='unlever'){ killMachines('lever'); status('lever gone'); return; }
      if(tl==='spring'){ buildSpring(); return; }
      if(tl==='unspring'){ killMachines('spring'); status('spring gone'); return; }
      if(tl==='span'){ armSpan(); return; }
      if(tl==='unspan'){ unspanAll(); return; }
      if(tl==='codex'){ openCodex(); return; }
      if(tl==='closecodex'){ closeCodex(); return; }
      if(typeof orig==='function') return orig(line);
    };
    window.runLine.__grHooked=true;
      }catch(e){}
      if(__triesgr<60) setTimeout(__hookgr,500);
    }
    __hookgr();
  })();
}
if(document.readyState==='loading'){
  document.addEventListener('DOMContentLoaded',initGrand);
}else{ initGrand(); }

})();


===== FILE: public/ruby-backup/hook-manager.js =====
/* HOOK MANAGER — one script to bind them all.
   The King: "How do we fix it?" — Ten files try to hook window.runLine at load time
   and miss because runLine doesn't exist yet. This manager loads LAST, waits for
   runLine, then attaches every hook in the correct order. The map heals itself. */
(function(){
  if(window.__hookManager) return;
  window.__hookManager = true;

  // Registry: each system registers its hook function here
  window.__hookRegistry = window.__hookRegistry || [];

  window.registerHook = function(name, fn){
    try{
      // Don't double-register
      for(var i=0;i<window.__hookRegistry.length;i++){
        if(window.__hookRegistry[i].name === name) return;
      }
      window.__hookRegistry.push({name: name, fn: fn});
    }catch(e){}
  };

  // The manager: wait for runLine, then fire all hooks in order
  function fireHooks(){
    var fired = 0;
    for(var i=0;i<window.__hookRegistry.length;i++){
      try{
        var h = window.__hookRegistry[i];
        var flag = '__' + h.name + 'Hooked';
        if(window.runLine && !window.runLine[flag]){
          h.fn();
          fired++;
        }
      }catch(e){}
    }
    return fired;
  }

  function waitForRunLine(){
    var tries = 0;
    function attempt(){
      tries++;
      try{
        if(typeof window.runLine === 'function'){
          var n = fireHooks();
          try{ fireLegacyHooks(); }catch(e){}
          // Keep trying for late registrants (up to 30s)
          if(tries < 60){
            setTimeout(function(){
              try{ fireHooks(); }catch(e){}
              if(tries < 60) setTimeout(attempt, 500);
            }, 500);
          }
          return;
        }
      }catch(e){}
      if(tries < 120) setTimeout(attempt, 500);
    }
    setTimeout(attempt, 500);
  }

  // Also fire on demand
  window.fireAllHooks = fireHooks;

  /* Legacy hook functions — each file's own hook, called by the manager.
     These existed but their retry loops were broken. The manager calls them. */
  function fireLegacyHooks(){
    var fns = [
      '__hookseedHooked', '__hookphoenixHooked', '__hooksalvageHooked', '__hooksnapHooked'
    ];
    for(var i=0;i<fns.length;i++){
      try{
        if(typeof window[fns[i]] === 'function') window[fns[i]]();
      }catch(e){}
    }
    /* Inline-hook files: trigger their IIFE hooks by re-dispatching */
    try{
      if(typeof window.__doBuilderHook === 'function') window.__doBuilderHook();
    }catch(e){}
  }
  window.fireLegacyHooks = fireLegacyHooks;

  if(document.readyState === 'complete'){
    waitForRunLine();
  } else {
    windo