<!-- SOLID-PLAYTIME · part 186 -->
ow.invState?window.invState.held:null; }catch(e){ return null; }
}
function heldCount(){
  var k=heldKey(); if(!k) return 0;
  if(k==='console') return 1;
  try{ return (window.invState.counts[k]||0); }catch(e){ return 0; }
}
function parseKey(k){ var p=k.split('-'); return {variant:p[0],shape:p.slice(1).join('-')}; }
function snap(v){ return Math.round(v/CELL)*CELL; }
/* occupancy = top surface per cell: blocks may stack, never interpenetrate */
var cellTop={};
function pieceTop(shape){
  if(shape==='pillar') return 3.9;
  if(shape==='wall') return 3.0;
  if(shape==='roof') return 1.3;
  if(shape==='arch') return 3.7;
  if(shape==='column') return 4.9;
  if(shape==='stairs') return 1.8;
  if(shape==='platform') return 1.15;
  if(shape==='fence') return 1.1;
  if(shape==='beam') return 0.5;
  if(shape==='step') return 0.5;
  if(shape==='foundation') return 0.4;
  return 0.25;
}
function cellTaken(x,z,y){
  var t=cellTop[x+','+z];
  if(t===undefined) return false;
  return y<t-0.05;
}
function markCell(x,z,y,shape){ cellTop[x+','+z]=y+pieceTop(shape); }

function refreshGhost(){
  if(!ghost||!ghostCell) return;
  var hk=heldKey();
  var gy=groundY(ghostCell.x,ghostCell.z);
  ghostOK=!!hk&&heldCount()>0&&!cellTaken(ghostCell.x,ghostCell.z,gy);
  var gmat=ghostOK?(hk==='console'?ghostMatGold:ghostMatOK):ghostMatBad;
  ghost.traverse(function(o){ if(o.isMesh) o.material=gmat; });
}
function moveGhostTo(wx,wz){
  var hk=heldKey();
  if(ghost) Kt.scene.remove(ghost);
  ghost=null; ghostCell=null;
  if(!hk) return;
  var ps=parseKey(hk);
  ghost=(hk==='console'&&window.consoleGhostMesh)?window.consoleGhostMesh():buildPiece(ps.shape);
  ghostCell={x:snap(wx),z:snap(wz)};
  ghost.position.set(ghostCell.x,groundY(ghostCell.x,ghostCell.z)+0.02,ghostCell.z);
  ghost.rotation.y=ghostRot;
  Kt.scene.add(ghost);
  try{ if(window.consoleAim) window.consoleAim(ghostCell.x,ghostCell.z,hk); }catch(e){}
  refreshGhost();
}
function doPlace(){
  if(!buildOn||!ghost||!ghostCell) { toast('TAP THE GROUND TO AIM','#888'); return; }
  refreshGhost();
  if(!ghostOK){
    if(!heldKey()) toast('PICK A MATERIAL IN ITEMS FIRST','#ff5544');
    else if(heldCount()<=0) toast('NONE LEFT — HARVEST MORE','#ff5544');
    else toast('CELL OCCUPIED','#ff5544');
    return;
  }
  var hk=heldKey(), ps=parseKey(hk);
  var y=groundY(ghostCell.x,ghostCell.z);
  var justPlaced=spawnBlock(ps.shape,ps.variant,ghostCell.x,y,ghostCell.z,ghostRot);
  if(hk==='console'){
    try{
      for(var cpi=placed.length-1;cpi>=0;cpi--){ if(placed[cpi].mesh===justPlaced){ placed.splice(cpi,1); break; } }
      Kt.scene.remove(justPlaced);
      saveBuilds();
      if(window.deployConsole) window.deployConsole(ghostCell.x,y,ghostCell.z,ghostRot);
    }catch(de){}
  }else{
    try{if(window.syncPlaceBlock)window.syncPlaceBlock({shape:ps.shape,variant:ps.variant,x:ghostCell.x,y:y,z:ghostCell.z,rot:ghostRot});}catch(se){}
    sessionPlaced.push({shape:ps.shape,variant:ps.variant});
    try{
      window.invState.counts[hk]--;
      localStorage.setItem('solid-inv-v1',JSON.stringify({counts:window.invState.counts,equipped:window.invState.equipped,held:window.invState.held}));
    }catch(e){}
  }
  try{ Kt.burst(ghostCell.x,y+1.5,ghostCell.z,VCOLOR[ps.variant]); }catch(e2){}
  saveBuilds();
  if(hk!=='console') toast('PLACED '+ps.variant.toUpperCase()+' '+ps.shape.toUpperCase(),VCSS[ps.variant]);
  refreshGhost();
}

/* ============ tap-to-aim overlay ============ */
var rayc=new T.Raycaster(), ndc=new T.Vector2(), groundPlane=new T.Plane(new T.Vector3(0,1,0),0), hitP=new T.Vector3();
function onTap(e){
  if(!buildOn) return;
  try{ if(heldKey()==='console') return; }catch(e){}
  var cx=(e.clientX!==undefined)?e.clientX:(e.touches&&e.touches[0]?e.touches[0].clientX:0);
  var cy=(e.clientY!==undefined)?e.clientY:(e.touches&&e.touches[0]?e.touches[0].clientY:0);
  ndc.x=(cx/window.innerWidth)*2-1; ndc.y=-(cy/window.innerHeight)*2+1;
  try{
    rayc.setFromCamera(ndc,Kt.camera);
    if(rayc.ray.intersectPlane(groundPlane,hitP)) moveGhostTo(hitP.x,hitP.z);
  }catch(err){}
}

/* ============ build bar ============ */
function mkBtn(label,fn,primary){
  var b=document.createElement('button');
  b.className='igl-btn';
  var tx=document.createElement('span'); tx.className='igl-text'; tx.textContent=label;
  b.appendChild(tx);
  b.style.cssText+=';padding:10px 12px;font-size:11px;min-width:0;';
  if(primary) b.style.cssText+=';border:2px solid #ffd700 !important;';
  b.addEventListener('click',function(e){ e.stopPropagation(); fn(); });
  return b;
}
function setBuild(on){
  buildOn=on;
  if(on){
    gridH=new T.GridHelper(CELL*GRIDSZ,GRIDSZ,0xffd700,0x7a5fd0);
    gridH.material.transparent=true; gridH.material.opacity=0.5;
    Kt.scene.add(gridH);
    tapLayer=document.createElement('div');
    tapLayer.style.cssText='position:fixed;inset:0;z-index:9990;';
    tapLayer.addEventListener('pointerup',onTap);
    document.body.appendChild(tapLayer