<!-- RUBY-BACKUP · part 141 -->
scale.x;
    m.geometry.dispose();
  }
  return shapeK1[shape];
}
var shapeBtn = document.getElementById('shape-btn');
var shapePanel = document.getElementById('shapepanel');
if(!shapeBtn){
  shapeBtn = document.createElement('button');
  shapeBtn.id = 'shape-btn';
  shapeBtn.style.display = 'none';
  document.body.appendChild(shapeBtn);
}
SHAPE_ORDER.forEach(function(k){
  var b = document.createElement('button');
  var base = shapeBase(k), ghostly = shapeIsGhost(k);
  var letter = SHAPE_CODES[base]||'?';
  b.innerHTML = (ghostly ? ghostIcon(SHAPE_ICONS[base]) : SHAPE_ICONS[base]) +
    '<div style="font-size:9px;color:#e8c34a;line-height:1.3;">'+(ghostly?letter.toUpperCase():letter)+'</div>';
  b.setAttribute('aria-label', shapeLabel(k));
  b.dataset.shape = k;
  b.addEventListener('click', function(e){ e.stopPropagation(); setShape(k); });
  if(shapePanel) shapePanel.appendChild(b);
});
function paintShapeUI(){
  var base = shapeBase(curShapeKey), ghostly = shapeIsGhost(curShapeKey);
  shapeBtn.innerHTML = ghostly ? ghostIcon(SHAPE_ICONS[base]) : SHAPE_ICONS[base];
  if(!shapePanel) return;
  var kids = shapePanel.children;
  for(var i=0;i<kids.length;i++) kids[i].classList.toggle('sel', kids[i].dataset.shape===curShapeKey);
}
function closeShapePanel(){ if(shapePanel) shapePanel.classList.remove('open'); }
function setShape(k){
  curShapeKey = k;
  paintShapeUI();
  closeShapePanel();
  refreshGhost();
}
shapeBtn.addEventListener('click', function(e){
  e.stopPropagation();
  renderPanel.classList.remove('open');
  if(shapePanel) shapePanel.classList.toggle('open');
});
paintShapeUI();

/* ---- create / shrink modes ---- */
var mode = 'create';
var btnCreate = document.getElementById('mode-create');
var btnDelete = document.getElementById('mode-delete');
function setMode(m){
  mode = m;
  if(btnCreate) btnCreate.classList.toggle('on', m==='create');
  if(btnDelete) btnDelete.classList.toggle('on', m==='delete');
  ghost.visible = false;
}
if(btnCreate) btnCreate.addEventListener('click', function(){ setMode('create'); });
if(btnDelete) btnDelete.addEventListener('click', function(){ setMode('delete'); });

/* ---- walk: a body, not a camera ---- */
(function(){ var w=document.getElementById('walk-btn'); if(w) w.addEventListener('click', function(){ setWalk(!WALK); }); })();
/* ---- our keyboard: one dock for chat and codes ---- */
var KB = {page:'abc', shift:false, sys:false};
var KB_TARGET = 'chat';
function kbUse(which){ KB_TARGET = which; KB.page='abc'; KB.shift=false; paintKB(); }
/* Quick-keys: each keyboard button runs a game code — Solid mapped them */
var QUICK_KEYS = {
  'w':'walk', 'n':'new', 'l':'land', 'f':'floor', 'u':'union',
  'b':'b1', 'd':'dawn', 'c':'clouds', 'r':'rain', 'm':'mirror',
  'g':'wall', 'h':'home', 's':'seams', 'k':'king', 'v':'visit'
};
var QUICK_MODE = false;
function kbQuickToggle(){ QUICK_MODE = !QUICK_MODE; codeStatus(QUICK_MODE ? 'quick-keys on — tap a letter to run its code' : 'quick-keys off — tap to type'); }
function syncDock(){
  var any = chatOpen || codeOpen;
  document.getElementById('dock').classList.toggle('open', any);
  document.getElementById('chatrow').classList.toggle('open', chatOpen);
  var kb = document.getElementById('kb');
  if(kb) kb.style.display = any ? '' : 'none';
  document.body.classList.toggle('chatting', any);
  document.body.classList.toggle('codemode', codeOpen);
  document.body.classList.toggle('kbopen', any);
  /* move the menu above the keyboard */
  if(any) hideFloatButtons(); else showFloatButtons();
}
var KB_ROWS = {
  abc:[['q','w','e','r','t','y','u','i','o','p'],
       ['a','s','d','f','g','h','j','k','l'],
       ['sh','z','x','c','v','b','n','m','bk'],
       ['cp','ps','pg','sp','go']],
  num:[['1','2','3','4','5','6','7','8','9','0'],
       ['-','/',':',';','(',')','$','&','@'],
       ['#','.',',','?','!','_',"'",'%','bk'],
       ['cp','ps','pg','sp','go']]
};
function kbLabel(k){
  if(k==='sh') return KB.shift ? '&#8681;' : '&#8679;';
  if(k==='bk') return '&#9003;';
  if(k==='sp') return 'space';
  if(k==='cp') return '&#10697;';
  if(k==='ps') return 'paste';
  if(k==='go') return '&#9650;';
  if(k==='pg') return KB.page==='abc' ? '?123' : 'ABC';
  return KB.shift ? k.toUpperCase() : k;
}
function paintKB(){
  var kb = document.getElementById('kb');
  if(!kb) return;
  kb.innerHTML = '';
  KB_ROWS[KB.page].forEach(function(row){
    var r = document.createElement('div');
    r.className = 'kbrow';
    row.forEach(function(k){
      var b = document.createElement('button');
      b.className = 'kbkey' + ((k==='sp')?' wide':((k==='go')?' go':((k==='sh'||k==='bk'||k==='pg')?' fn':'')));
      b.innerHTML = kbLabel(k);
      b.setAttribute('data-k', k);
      b.addEventListener('pointerdown', function(e){ e.preventDefault(); kbTap(k, b); });
      r.appendChild(b);
    });
    kb.appendChild(r);
  });
}
function copyText(v){
  function fallback(){
    try{
      var ta = document.createEl