<!-- SOLID CITY · part 44 -->
s = M.group.userData.standRects || [];
  for (var i = 0; i < rects.length; i++) {
    var f = rects[i];
    if (Math.abs(x - (POS.x + f.cx)) <= f.hw && Math.abs(z - (POS.z + f.cz)) <= f.hd &&
        (py == null || M.baseY + f.y <= py + 1.6)) return M.baseY + f.y;
  }
  return -1000;
}

/* ---------------- the light reads real state --------------------------- */
function modeFor(recipient) {
  if (M.fetchOk === false) return 'dark';
  var mine = M.msgs.filter(function (m) { return m.recipient === recipient; });
  if (!mine.length) return 'dark';
  var newest = mine[0];
  return newest.status === 'answered' ? 'steady' : 'pulse';
}
function poll() {
  fetch('/api/city/between', { credentials: 'same-origin' }).then(function (r) { return r.json(); }).then(function (j) {
    if (j && j.ok) { M.msgs = j.messages || []; M.fetchOk = true; }
    else M.fetchOk = false;
  }).catch(function () { M.fetchOk = false; }).then(function () {
    if (M.group && M.group.userData.setLight) {
      M.group.userData.setLight('solid', modeFor('solid'), S.t);
      M.group.userData.setLight('vector', modeFor('vector'), S.t);
    }
    if (M.panelOpen) renderList();
  });
}

/* ---------------- the panel -------------------------------------------- */
var STATE_WORDS = {
  submitted: 'kept by the stones — not yet carried to its channel',
  available: 'waiting where its keeper can find it',
  received: 'received — acknowledged, not yet answered',
  answered: 'answered',
  closed: 'closed without reply, by an explicit act'
};
function ago(t) {
  var s = Math.max(0, (Date.now() - t) / 1000);
  if (s < 90) return 'moments ago';
  if (s < 3600) return Math.round(s / 60) + ' minutes ago';
  if (s < 86400) return Math.round(s / 3600) + ' hours ago';
  return Math.round(s / 86400) + ' days ago';
}
function interval(a, b) {
  var s = Math.max(0, (b - a) / 1000);
  if (s < 90) return 'moments';
  if (s < 3600) return Math.round(s / 60) + ' minutes';
  if (s < 86400) return Math.round(s / 3600) + ' hours';
  return Math.round(s / 86400) + ' days';
}
function esc(v) { return String(v == null ? '' : v).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;'); }
function buildPanel() {
  if (M.panelBuilt) return; M.panelBuilt = true;
  var css = document.createElement('style');
  css.textContent = '#bs-btn{position:fixed;left:50%;transform:translateX(-50%);bottom:148px;z-index:60;background:rgba(16,18,24,.88);color:#e9e2cf;border:1px solid rgba(216,168,51,.65);border-radius:999px;padding:10px 18px;font:600 14px Georgia,serif;letter-spacing:.06em;display:none;cursor:pointer}' +
  '#bs-panel{position:fixed;inset:0;z-index:70;display:none;align-items:center;justify-content:center;background:rgba(4,6,10,.55)}' +
  '#bs-card{background:#14161d;color:#e9e2cf;border:1px solid rgba(216,168,51,.7);border-radius:14px;max-width:520px;width:92vw;max-height:86vh;overflow-y:auto;padding:18px 20px;font-family:Georgia,serif;box-shadow:0 18px 60px rgba(0,0,0,.6)}' +
  '#bs-card h2{margin:0 0 4px;font-size:20px;letter-spacing:.08em;color:#f3d98b;text-align:center}' +
  '#bs-card .sub{font-size:12.5px;color:#9aa4b5;text-align:center;margin-bottom:12px;line-height:1.45}' +
  '#bs-card .row{display:flex;gap:8px;margin:10px 0}' +
  '.bs-to{flex:1;padding:9px;border-radius:9px;border:1px solid #3a4150;background:#1b1e26;color:#cdbf9d;font:600 13px Georgia,serif;cursor:pointer}' +
  '.bs-to.on{border-color:#d8a833;color:#f3d98b;background:#24202f}' +
  '#bs-text{width:100%;box-sizing:border-box;min-height:74px;background:#0e1015;color:#e9e2cf;border:1px solid #3a4150;border-radius:9px;padding:9px;font:14px Georgia,serif}' +
  '#bs-send{width:100%;margin-top:8px;padding:11px;border-radius:9px;border:1px solid #d8a833;background:linear-gradient(180deg,#3a2f14,#241c0a);color:#f3d98b;font:700 14px Georgia,serif;letter-spacing:.05em;cursor:pointer}' +
  '#bs-note{font-size:12.5px;color:#9aa4b5;margin-top:8px;min-height:16px;text-align:center}' +
  '.bs-msg{border-top:1px solid #2b303d;padding:9px 0}' +
  '.bs-msg .meta{font-size:11.5px;color:#9aa4b5;letter-spacing:.03em}' +
  '.bs-msg .body{font-size:14px;margin:3px 0;line-height:1.45}' +
  '.bs-msg .reply{font-size:13.5px;color:#cfe8d8;margin-top:4px;line-height:1.45}' +
  '.bs-msg .interval{font-size:11.5px;color:#cdbf9d;font-style:italic;margin-top:2px}' +
  '#bs-close{width:100%;margin-top:12px;padding:9px;border-radius:9px;border:1px solid #3a4150;background:#1b1e26;color:#cdbf9d;font:600 13px Georgia,serif;cursor:pointer}';
  document.head.appendChild(css);
  var btn = document.createElement('button'); btn.id = 'bs-btn'; btn.textContent = '🪨 THE BETWEEN STONES';
  btn.onclick = function () { M.panelOpen = true; document.getElementById('bs-panel').style.display = 'flex'; poll(); };
  document.body.appendChild(btn);
  var wrap = document.createElement('div'); wrap.id = 'bs-panel';
  wrap.innerHTML = '<div id="bs-card"><h2>THE BETWEEN STONES</h2>' +
    '<div class="sub">Leave