<!-- SAGA-SOLID · part 55 -->
 ===== */
var osEl = document.getElementById('os');
var osToggle = document.getElementById('os-toggle');
var osOpen = false;

osToggle.onclick = function(){ osOpen=!osOpen; osEl.classList.toggle('open', osOpen);; };
function osButton(emoji, title, fn){
  var b = document.createElement('button');
  b.innerHTML = emoji; b.title = title;
  b.onclick = function(){ fn(); osOpen=false; osEl.classList.remove('open');; };
  osEl.appendChild(b);
  return b;
}

/* ===== DISTRICTS ===== */
var districts = {};
function registerDistrict(n, l, fn){ districts[n] = {label:l, build:fn, loaded:false}; }
function activateDistrict(n){
  var d = districts[n];
  if(!d) return say('unknown');
  if(d.loaded) return say(d.label + ' already stands');
  try { d.build(); d.loaded=true; say(d.label + ' rises'); }
  catch(e){ say('stumbled'); }
}
var dOrder=[], dIdx=0;
function nextDistrict(){
  for(var i=0;i<dOrder.length;i++){
    var n=dOrder[(dIdx+i)%dOrder.length];
    if(districts[n] && !districts[n].loaded){
      activateDistrict(n); dIdx=(dIdx+i+1)%dOrder.length; return;
    }
  }
  say('all districts stand');
}

/* ================================================================
   THE CODES — organized by category, proper
   ================================================================ */

/* ---- SPECIAL: the 12 ---- */
var lastBam = null;

function doBam(args){
  var shape = args[0] || 'box';
  var size = parseFloat(args[1]) || 10;
  var count = 1, row = 0;

  /* bam box 10 x5 — batch */
  for(var i=0;i<args.length;i++){
    if(args[i][0]==='x') count = parseInt(args[i].slice(1)) || 1;
    if(args[i]==='line') row = parseInt(args[i+1]) || 0;
  }

  lastBam = {shape:shape, size:size, count:count, row:row};

  for(var c=0;c<count;c++){
    var mesh;
    if(shape==='box') mesh = new THREE.Mesh(new THREE.BoxGeometry(size,size,size), goldMat);
    else if(shape==='wall'){
      var len = row || 5;
      mesh = new THREE.Mesh(new THREE.BoxGeometry(size*len, size, 1), goldMat);
    }
    else mesh = new THREE.Mesh(new THREE.BoxGeometry(size,size,size), goldMat);

    var ox = row ? c * size * 1.2 : c * size * 1.5;
    mesh.position.set(kingPos.x + ox, groundY + size/2, kingPos.z);
    window.applyMinimum(mesh);
    var _gp = mesh.geometry.parameters || {width:size, height:size, depth:size};
    mesh.userData.bam = {w:_gp.width, h:_gp.height, d:_gp.depth};
    mesh.userData.staysOnMap = true;
    scene.add(mesh);
    window._bamBlocks.push(mesh);
  }
  saveBamBlocks();
  if(window.logBuild) window.logBuild(shape + ' x' + count + ' raised');
  say(shape + ' stands' + (count>1 ? ' x'+count : ''));
}


/* THE EPISTOLARY — the King's proper body: hyper-realistic cyborg superhero */
function spawnNewBody(){
  var g = new THREE.Group();
  var cyberSkin = new THREE.MeshStandardMaterial({color:0x2a2a35, roughness:0.35, metalness:0.85});
  var gold = new THREE.MeshStandardMaterial({color:0xd8a920, roughness:0.3, metalness:0.8});
  var cyanGlow = new THREE.MeshStandardMaterial({color:0x00ccff, roughness:0.2, metalness:0.5, emissive:0x00aacc, emissiveIntensity:1.2});
  var capeMat = new THREE.MeshStandardMaterial({color:0x8b0000, roughness:0.8, metalness:0.1, side:THREE.DoubleSide});
  /* Head (handsome, heroic proportions) */
  var head = new THREE.Mesh(new THREE.SphereGeometry(0.55, 24, 24), cyberSkin);
  head.position.y = 2.35; head.scale.set(0.9, 1.1, 0.95);
  g.add(head);
  /* Cyan circuit lines on face */
  var faceLine = new THREE.Mesh(new THREE.TorusGeometry(0.4, 0.02, 8, 24), cyanGlow);
  faceLine.position.set(0, 2.4, 0.35); faceLine.rotation.x = 0.3;
  g.add(faceLine);
  /* Glowing eyes */
  var eyeL = new THREE.Mesh(new THREE.SphereGeometry(0.08, 8, 8), cyanGlow);
  eyeL.position.set(-0.18, 2.45, 0.45); g.add(eyeL);
  var eyeR = new THREE.Mesh(new THREE.SphereGeometry(0.08, 8, 8), cyanGlow);
  eyeR.position.set(0.18, 2.45, 0.45); g.add(eyeR);
  /* Torso (athletic, segmented armor) */
  var torso = new THREE.Mesh(new THREE.BoxGeometry(1.0, 1.2, 0.5), cyberSkin);
  torso.position.y = 1.5; g.add(torso);
  /* Chest circuits */
  for(var i=0; i<3; i++){
    var cl = new THREE.Mesh(new THREE.BoxGeometry(0.8, 0.03, 0.02), cyanGlow);
    cl.position.set(0, 1.3 + i*0.25, 0.26); g.add(cl);
  }
  /* Gold chest emblem */
  var emblem = new THREE.Mesh(new THREE.OctahedronGeometry(0.15), gold);
  emblem.position.set(0, 1.7, 0.28); g.add(emblem);
  /* Arms (segmented) */
  var armL = new THREE.Group();
  var uaL = new THREE.Mesh(new THREE.CylinderGeometry(0.14, 0.12, 0.5, 12), cyberSkin); uaL.position.y = -0.25; armL.add(uaL);
  var faL = new THREE.Mesh(new THREE.CylinderGeometry(0.11, 0.09, 0.45, 12), cyberSkin); faL.position.y = -0.7; armL.add(faL);
  var handL = new THREE.Mesh(new THREE.SphereGeometry(0.12, 10, 10), cyberSkin); handL.position.y = -0.95; armL.add(handL);
  armL.position.set(-0.65, 1.9, 0); g.add(armL);
  var armR = new THREE.Group();
  var uaR = new THREE.Mesh(new THREE.CylinderGeometry(0.14,