<!-- RUBY-BACKUP · part 126 -->

    var tw = parseFloat(_dimsInputs.w.value);
    var th = parseFloat(_dimsInputs.h.value);
    var td = parseFloat(_dimsInputs.d.value);
    if(!(tw > 0 && th > 0 && td > 0)) return;
    var box = new THREE.Box3().setFromObject(SELECTED_PART);
    var cs = box.getSize(new THREE.Vector3());
    var cur = SELECTED_PART.scale;
    /* avoid divide by zero on first drag */
    if(cs.x < 0.001 || cs.y < 0.001 || cs.z < 0.001) return;
    var nsx = cur.x * (tw / cs.x);
    var nsy = cur.y * (th / cs.y);
    var nsz = cur.z * (td / cs.z);
    /* clamp to sane */
    nsx = Math.max(0.01, Math.min(10, nsx));
    nsy = Math.max(0.01, Math.min(10, nsy));
    nsz = Math.max(0.01, Math.min(10, nsz));
    SELECTED_PART.scale.set(nsx, nsy, nsz);
    /* the law: never beyond her height */
    if(enforceHeightLaw()){
      codeStatus('held at her measure — no part bigger than she is');
    }
  }catch(e){}
}
function hideDimsPanel(){
  if(_dimsPanel){
    try{ _dimsPanel.remove(); }catch(e){}
    _dimsPanel = null;
    _dimsInputs = {};
  }
}
function applyDimsToSelected(){
  if(!SELECTED_PART){ codeStatus('select a part first'); return; }
  try{
    var tw = parseFloat(_dimsInputs.w.value);
    var th = parseFloat(_dimsInputs.h.value);
    var td = parseFloat(_dimsInputs.d.value);
    if(!(tw > 0 && th > 0 && td > 0)){ codeStatus('enter positive numbers'); return; }
    /* measure current */
    var box = new THREE.Box3().setFromObject(SELECTED_PART);
    var cs = box.getSize(new THREE.Vector3());
    /* scale to target — account for current scale */
    var cur = SELECTED_PART.scale;
    var nsx = cur.x * (tw / cs.x);
    var nsy = cur.y * (th / cs.y);
    var nsz = cur.z * (td / cs.z);
    SELECTED_PART.scale.set(nsx, nsy, nsz);
    codeStatus('set to ' + tw.toFixed(2) + ' x ' + th.toFixed(2) + ' x ' + td.toFixed(2));
  }catch(e){ codeStatus('could not apply: ' + e.message); }
}
function setSelectMode(on){
  SELECT_MODE = on;
  codeStatus(on ? 'tap a part to select it' : 'selection off');
  if(!on){ try{ hideDimsPanel(); }catch(e){} }
  if(!on && SELECTED_PART){
    try{
      if(_origEmissive) SELECTED_PART.material.emissive.copy(_origEmissive);
      else SELECTED_PART.material.emissive.set(0x000000);
    }catch(e){}
    SELECTED_PART = null;
  }
}
function selectPart(obj){
  /* clear old */
  if(SELECTED_PART){
    try{
      if(_origEmissive) SELECTED_PART.material.emissive.copy(_origEmissive);
      else SELECTED_PART.material.emissive.set(0x000000);
    }catch(e){}
  }
  SELECTED_PART = obj;
  try{
    _origEmissive = obj.material.emissive ? obj.material.emissive.clone() : null;
    if(!obj.material.emissive) obj.material.emissive = new THREE.Color(0x000000);
    obj.material.emissive.set(0x336699);
    obj.material.emissiveIntensity = 0.8;
    obj.material.needsUpdate = true;
  }catch(e){}
  /* report + dimension inputs */
  var name = obj.name || 'unnamed';
  try{
    var box = new THREE.Box3().setFromObject(obj);
    var s = box.getSize(new THREE.Vector3());
    codeStatus('selected: ' + name);
    showDimsPanel(name, s.x, s.y, s.z);
  }catch(e){
    codeStatus('selected: ' + name);
  }
}
/* hook into the tap handler — if select mode is on, pick the part */
var _origTapHandler = null;
function enablePartSelection(){
  /* find the canvas tap — we add our own listener */
  try{
    var cv = document.querySelector('canvas');
    if(!cv || cv._selectHook) return;
    cv._selectHook = true;
    cv.addEventListener('click', function(e){
      if(!SELECT_MODE) return;
      try{
        var rect = cv.getBoundingClientRect();
        var mx = ((e.clientX - rect.left) / rect.width) * 2 - 1;
        var my = -((e.clientY - rect.top) / rect.height) * 2 + 1;
        var ray = new THREE.Raycaster();
        ray.setFromCamera({x: mx, y: my}, camera);
        var targets = [];
        if(DISSECT_GROUP) targets.push(DISSECT_GROUP);
        if(TABLE_BODIES) targets.push(TABLE_BODIES);
        if(PROVOLTA_MODEL) targets.push(PROVOLTA_MODEL);
        if(typeof stones!=='undefined') targets.push(stones);
        if(typeof RUBY_HANDLES!=='undefined' && RUBY_HANDLES) targets.push(RUBY_HANDLES);
        var hits = ray.intersectObjects(targets, true);
        if(hits.length > 0){
          var obj = hits[0].object;
          /* ruby handle clicked — anchor/unanchor */
          if(obj.userData && obj.userData.isRubyHandle){
            if(typeof toggleRubyAnchor!=='undefined') toggleRubyAnchor(obj);
            return;
          }
          /* tap carried block to set it down */
          if(typeof CARRIED_BLOCK!=='undefined' && CARRIED_BLOCK && obj === CARRIED_BLOCK){
            if(typeof dropCarriedBlock==='function') dropCarriedBlock();
            return;
          }
          /* engage with PROVOLTA — you must come to her, she knows you */
          try{
            var isHer = false;
            var p = obj;
            while(p){
              if(p === PROVOLTA_MODEL){ isHer = true; break; }
   