<!-- RUBY-BACKUP · part 444 -->
="color:#00ffff;font-weight:bold;font-size:18px;">SPACE MISSION '+m.id+' 🚀</div><div style="margin-top:8px;font-style:italic;">'+m.text+'</div><div style="margin-top:6px;font-size:13px;color:#aaa;">'+m.detail+'</div>';
  document.body.appendChild(div);
  codeStatus('space mission '+m.id+' — '+m.text);
}
/* THE RICH STRANGER — once in a lifetime, after months */
function checkStrangerEligibility(){
  try{
    var firstPlay = localStorage.getItem('ruby-first-play');
    var strangerSeen = localStorage.getItem('ruby-stranger-seen');
    if(!firstPlay){
      localStorage.setItem('ruby-first-play', Date.now().toString());
      return false;
    }
    if(strangerSeen) return false; /* once in a lifetime */
    var monthsPlayed = (Date.now() - parseInt(firstPlay)) / (30*24*60*60*1000);
    /* appears after 2+ months, or very rarely before */
    if(monthsPlayed >= 2) return true;
    if(Math.random() < 0.001) return true; /* 0.1% chance — a miracle */
    return false;
  }catch(e){ return false; }
}
var STRANGER = null;
function buildRichStranger(x, y, z){
  var g = new THREE.Group();
  /* wealthy — gold, elegant */
  var skin = new THREE.MeshStandardMaterial({color: 0xd4a574, roughness: 0.4});
  var gold = new THREE.MeshStandardMaterial({color: 0xffd700, metalness: 0.9, roughness: 0.2});
  var suit = new THREE.MeshStandardMaterial({color: 0x1a1a2a, roughness: 0.3});
  var head = new THREE.Mesh(new THREE.SphereGeometry(0.15, 20, 20), skin);
  head.position.y = 1.6; g.add(head);
  /* kind, tired eyes — has seen much */
  [-1,1].forEach(function(s){
    var eye = new THREE.Mesh(new THREE.SphereGeometry(0.022, 10, 10),
      new THREE.MeshStandardMaterial({color: 0x3a2a1a}));
    eye.position.set(0.08, 1.62, s*0.06); g.add(eye);
  });
  /* gray hair — distinguished */
  var hair = new THREE.Mesh(new THREE.SphereGeometry(0.155, 16, 16, 0, Math.PI*2, 0, Math.PI*0.5),
    new THREE.MeshStandardMaterial({color: 0xaaaaaa, roughness: 0.8}));
  hair.position.y = 1.62; g.add(hair);
  /* elegant suit */
  var body = new THREE.Mesh(new THREE.CylinderGeometry(0.18, 0.22, 1.0, 14), suit);
  body.position.y = 1.0; g.add(body);
  /* gold watch — glints */
  var watch = new THREE.Mesh(new THREE.CylinderGeometry(0.04, 0.04, 0.02, 10), gold);
  watch.position.set(0, 0.9, 0.22); watch.rotation.x = Math.PI/2;
  g.add(watch);
  /* gold cane */
  var cane = new THREE.Mesh(new THREE.CylinderGeometry(0.02, 0.02, 1.1, 8), gold);
  cane.position.set(0, 0.55, 0.28); g.add(cane);
  var caneTop = new THREE.Mesh(new THREE.SphereGeometry(0.04, 10, 10), gold);
  caneTop.position.set(0, 1.12, 0.28); g.add(caneTop);
  [-1,1].forEach(function(s){
    var leg = new THREE.Mesh(new THREE.CylinderGeometry(0.07, 0.06, 0.6, 8), suit);
    leg.position.set(0, 0.3, s*0.1); g.add(leg);
    var shoe = new THREE.Mesh(new THREE.BoxGeometry(0.2, 0.08, 0.1), gold);
    shoe.position.set(0.05, 0.04, s*0.1); g.add(shoe);
  });
  /* aura — subtle gold */
  var aura = new THREE.Mesh(new THREE.SphereGeometry(0.8, 16, 16),
    new THREE.MeshBasicMaterial({color: 0xffd700, transparent: true, opacity: 0.08}));
  aura.position.y = 1.0; g.add(aura);
  g.position.set(x, y, z);
  /* his story */
  var story = [
    'I have traveled 40 years.',
    'I have everything. Except one thing.',
    'Will you help me find it?',
    'It is not gold. It is not land.',
    'It is a moment. Like this one.'
  ];
  var sIdx = 0;
  var sCv = document.createElement('canvas');
  sCv.width = 512; sCv.height = 80;
  var sCtx = sCv.getContext('2d');
  var sTex = new THREE.CanvasTexture(sCv);
  var sBubble = new THREE.Mesh(new THREE.PlaneGeometry(2.8, 0.44),
    new THREE.MeshBasicMaterial({map: sTex, transparent: true}));
  sBubble.position.set(0, 2.2, 0);
  g.add(sBubble);
  function drawStory(){
    sCtx.clearRect(0, 0, 512, 80);
    sCtx.fillStyle = 'rgba(30,25,10,0.95)';
    sCtx.fillRect(0, 0, 512, 80);
    sCtx.strokeStyle = '#ffd700'; sCtx.lineWidth = 3;
    sCtx.strokeRect(4, 4, 504, 72);
    sCtx.fillStyle = '#ffd700'; sCtx.font = 'italic 20px Georgia'; sCtx.textAlign = 'center';
    sCtx.fillText(story[sIdx], 256, 48);
    sTex.needsUpdate = true;
    sIdx = (sIdx+1) % story.length;
  }
  drawStory();
  var storyTimer = setInterval(drawStory, 5000);
  g.userData.storyTimer = storyTimer;
  /* he waits. He is patient. */
  var t = 0;
  var anim = setInterval(function(){
    t += 0.02;
    aura.material.opacity = 0.06 + Math.sin(t*2)*0.03;
    watch.rotation.y += 0.05; /* glinting */
  }, 50);
  g.userData.anim = anim;
  return g;
}
function summonStranger(){
  if(typeof scene==='undefined' || typeof mePos==='undefined') return;
  if(!checkStrangerEligibility()){
    codeStatus('the stranger has not come yet. Keep playing. He comes once.');
    return;
  }
  if(STRANGER){
    try{ scene.remove(STRANGER); }catch(e){}
  }
  /* appears at the plaza — the heart */
  var x = mePos.x*0.13, z = mePos.z*0.13;
  STRANGER = buildRichStranger(x+5, 0, z+5);
  scene