<!-- SAGA2 · part 61 -->
=st.id) return false;
  st.active=false; st.dx=0; st.dy=0;
  vis.setLive(false); vis.setKnob(0,0);
  // glide back to infinity rest position
  var cx2 = window.innerWidth/2 + (vis===visR?52:-52);
  vis.base.style.left=(cx2-48)+'px';
  vis.base.style.top='';
  vis.base.style.bottom='70px';
  return true;
}
document.addEventListener('touchstart',function(e){
  // ignore touches on buttons (clear cache etc)
  if(e.target && (e.target.tagName==='BUTTON'||e.target.closest('button'))) return;
  for(var i=0;i<e.changedTouches.length;i++){
    var t=e.changedTouches[i];
    if(t.clientX < window.innerWidth*0.5 && !stickL.active){
      stickTouchStart(stickL, visL, t);
      e.preventDefault();
    } else if(t.clientX >= window.innerWidth*0.5 && !stickR.active){
      stickR.px=t.clientX; stickR.py=t.clientY;
      stickTouchStart(stickR, visR, t);
      e.preventDefault();
    }
  }
},{passive:false});
var pinchDist = 0;
document.addEventListener('touchmove',function(e){
  // PINCH TO ZOOM
  if(e.touches.length===2){
    var dx = e.touches[0].clientX - e.touches[1].clientX;
    var dy = e.touches[0].clientY - e.touches[1].clientY;
    var d = Math.sqrt(dx*dx+dy*dy);
    if(pinchDist>0){
      var zoom = (d - pinchDist)*0.1;
      // move camera forward/back along view direction
      var dir = new THREE.Vector3();
      camera.getWorldDirection(dir);
      camera.position.addScaledVector(dir, zoom);
    }
    pinchDist = d;
    e.preventDefault();
    return;
  }
  pinchDist = 0;
  for(var i=0;i<e.changedTouches.length;i++){
    var t=e.changedTouches[i];
    if(stickL.active&&t.identifier===stickL.id){ stickTouchMove(stickL,visL,t,false); e.preventDefault(); }
    if(stickR.active&&t.identifier===stickR.id){ stickTouchMove(stickR,visR,t,true); e.preventDefault(); }
  }
},{passive:false});
function endTouch2(e){
  for(var i=0;i<e.changedTouches.length;i++){
    stickTouchEnd(stickL,visL,e.changedTouches[i]);
    stickTouchEnd(stickR,visR,e.changedTouches[i]);
  }
}
window.addEventListener('touchend',endTouch2);
window.addEventListener('touchcancel',endTouch2);
var clock=new THREE.Clock();

// ===== HUMAN CYBORG MASTERPIECE — smooth face, circuit intaglio =====
var avatarGrp = null;
var avatarVisor = null;
var avatarCannonL = null, avatarCannonR = null;
var avatarGrp = null;
var avatarCannonL = null, avatarCannonR = null;
var avatarVisor = null;
function buildAvatar(){
  if(avatarGrp) return;
  avatarGrp = new THREE.Group();

  // ===== INTAGLIO MATERIALS =====
  var lnCyan = new THREE.LineBasicMaterial({color:0x77eeff, transparent:true, opacity:0.6, blending:THREE.AdditiveBlending});
  var lnGold = new THREE.LineBasicMaterial({color:0xffd766, transparent:true, opacity:0.9, blending:THREE.AdditiveBlending});
  var lnDim = new THREE.LineBasicMaterial({color:0x3388aa, transparent:true, opacity:0.5, blending:THREE.AdditiveBlending});
  var lnWhite = new THREE.LineBasicMaterial({color:0xccf6ff, transparent:true, opacity:0.7, blending:THREE.AdditiveBlending});
  avatarGrp.userData.lineMats = [lnCyan, lnGold, lnDim, lnWhite];
  var lnSteel = new THREE.LineBasicMaterial({color:0xaaccdd, transparent:true, opacity:1.0});
  var lnChrome = new THREE.LineBasicMaterial({color:0xffffff, transparent:true, opacity:1.0});
  var lnBlack = new THREE.LineBasicMaterial({color:0x222233, transparent:true, opacity:1.0});
  function drawDark(pts, mat, parent){
    for(var w=0; w<16; w++){
      var ox=(Math.random()-0.5)*0.3, oy=(Math.random()-0.5)*0.3;
      var ptw = pts.map(function(p){ return new THREE.Vector3(p.x+ox, p.y+oy, p.z); });
      (parent||avatarGrp).add(new THREE.Line(new THREE.BufferGeometry().setFromPoints(ptw), mat));
    }
  }
  function draw(pts, mat, parent){
    // 20-WAY — twenty lines, micro-offsets, blended into pure light
    for(var w=0; w<8; w++){
      var ox = (Math.random()-0.5)*0.6, oy = (Math.random()-0.5)*0.6, oz = (Math.random()-0.5)*0.2;
      var ptw = pts.map(function(p){ return new THREE.Vector3(p.x+ox, p.y+oy, p.z+oz); });
      var gw = new THREE.BufferGeometry().setFromPoints(ptw);
      (parent||avatarGrp).add(new THREE.Line(gw, mat||lnCyan));
    }
  }

  // ===== HEAD — contour lines on ellipsoid (rx=5.7, ry=6.94, rz=6.08) =====
  var headGrp = new THREE.Group();
  function headPt(theta, phi, out){
    var r = 1.02+(out||0);
    return new THREE.Vector3(
      5.7*r*Math.sin(theta)*Math.cos(phi),
      6.94*r*Math.sin(phi),
      6.08*r*Math.cos(theta)*Math.cos(phi)
    );
  }
  // FACE SURFACE — carved: front 120° left void for the human face (King's order)
  for(var fs=0; fs<24; fs+=2){
    var fy = 6-fs*0.7;
    // back arc (skip face region)
    var fpts1=[], fpts2=[];
    for(var fi=0;fi<=24;fi++){ var fan=fi/24*Math.PI*2;
      var ffr = 4.5+Math.sin(fs*0.5)*0.25;
      var pt = new THREE.Vector3(Math.cos(fan)*ffr, fy, 2+Math.sin(fan)*ffr*0.85);
      // face is front (fan near PI/2); carve it out
      var dFan = Math.abs(fan - Math.PI/2);
      if(dFan > 1.05