<!-- SOLID CITY · part 1449 -->
tch(function () { wait.remove(); spLine('sys', 'Connection lost.'); })
    .then(function () { soulBusy = false; $('sp-send').disabled = false; });
}
/* ---------------- CHECK-INS tab: the SHARED Soluv room (= /soluv wall 2, /api/soluv-room) ----------------
   Not the private AI talk: everyone logged in sees the same feed (oldest at top, newest at the bottom).
   Posts go only to /api/soluv-room (name from the login, CSRF header); nothing here calls an AI. Polls every 4 s while open. */
var wall = { tab: 'talk', last: 0, timer: 0, busy: false, n: 0 };
function spTab(t) {
  wall.tab = t; var w = t === 'wall';
  $('sp-tab-talk').classList.toggle('on', !w); $('sp-tab-wall').classList.toggle('on', w);
  $('sp-tab-talk').setAttribute('aria-selected', String(!w)); $('sp-tab-wall').setAttribute('aria-selected', String(w));
  $('sp-log').hidden = w; $('sp-wall').hidden = !w;
  getMe().then(function (j) {
    var ok = j && j.loggedIn;
    if (w) { $('sp-login').hidden = true; $('sp-form').style.display = 'none'; $('sp-wlogin').hidden = !!ok; $('sp-wform').hidden = !ok; if (ok) { wallPoll(); if (!IS_TOUCH) $('sp-wmsg').focus(); } else $('sp-wall').textContent = ''; }
    else { $('sp-wlogin').hidden = true; $('sp-wform').hidden = true; $('sp-login').hidden = !!ok; $('sp-form').style.display = ok ? '' : 'none'; }
  });
}
function wallFmt(t) { try { return new Date(t).toLocaleString([], { month: 'short', day: 'numeric', hour: 'numeric', minute: '2-digit' }); } catch (e) { return ''; } }
function wallAdd(m) {
  if (!m || m.id <= wall.last) return; wall.last = m.id;
  var box = $('sp-wall'), atEnd = box.scrollHeight - box.scrollTop - box.clientHeight < 60;
  var d = document.createElement('div'), mine = me && me.name && m.from === me.name; d.className = 'wl' + (mine ? ' me' : '') + (m.king ? ' king' : '');
  var h = document.createElement('b'); h.textContent = (m.king ? '\u265B ' : '') + m.from; d.appendChild(h);
  var tm = document.createElement('small'); tm.textContent = ' ' + wallFmt(m.t); d.appendChild(tm);
  var p = document.createElement('p'); p.textContent = m.text; d.appendChild(p);
  var em = $('sp-wempty'); if (em) em.remove();
  box.appendChild(d); wall.n++;
  spStatus();
  if (atEnd || wall.n < 3) box.scrollTop = 1e9;
}
function spStatus() {   // header status line: 'Soul Print Tower · LIVE · N check-ins' (display only)
  var s = $('sp-status'); if (!s) return;
  s.textContent = 'Soul Print Tower \u00b7 '; var i = document.createElement('i'); i.className = 'sp-live'; i.textContent = 'LIVE'; s.appendChild(i);
  if (wall.n) s.appendChild(document.createTextNode(' \u00b7 ' + wall.n + ' check-in' + (wall.n === 1 ? '' : 's')));
}
function wallPoll() {
  clearTimeout(wall.timer);
  if ($('sp-talk').hidden || wall.tab !== 'wall') return;
  if (!document.hidden && !wall.inflight) { wall.inflight = true; fetch('/api/soluv-room?since=' + wall.last, { credentials: 'same-origin', cache: 'no-store' }).then(function (r) { return r.json(); }).then(function (j) {
    var first = !wall.n; (j.msgs || []).forEach(wallAdd);
    if (first && !wall.n && !$('sp-wempty')) { var e = document.createElement('div'); e.className = 'sys'; e.id = 'sp-wempty'; e.textContent = 'No check-ins in the last 2 days yet. The room clears messages after 2 days.'; $('sp-wall').appendChild(e); }
    if (first) $('sp-wall').scrollTop = 1e9;
  }).catch(function () {}).then(function () { wall.inflight = false; }); }
  wall.timer = setTimeout(wallPoll, 4000);
}
function wallPost(text) {
  text = String(text || '').trim().slice(0, 500); if (!text || wall.busy) return;
  wall.busy = true; $('sp-wsend').disabled = true;
  getMe().then(function (m) {
    return fetch('/api/soluv-room', { method: 'POST', credentials: 'same-origin', headers: { 'Content-Type': 'application/json', 'X-CSRF-Token': (m && m.csrf) || '' }, body: JSON.stringify({ msg: text, localKey: 'city' + Date.now().toString(36) }) });
  }).then(function (r) { return r.json().catch(function () { return {}; }).then(function (j) { return { s: r.status, j: j }; }); })
    .then(function (o) {
      if (o.j && o.j.ok) { $('sp-wmsg').value = ''; if (o.j.msg) wallAdd(o.j.msg); $('sp-wall').scrollTop = 1e9; }
      else { var e = document.createElement('div'); e.className = 'sys'; e.textContent = o.s === 403 ? 'Session check failed. Reload and try again.' : o.s === 429 ? 'Slow down a little.' : 'Post failed (' + ((o.j && o.j.error) || o.s) + ').'; $('sp-wall').appendChild(e); }
    }).catch(function () {}).then(function () { wall.busy = false; $('sp-wsend').disabled = false; });
}
$('sp-tab-talk').addEventListener('click', function () { spTab('talk'); });
$('sp-tab-wall').addEventListener('click', function () { spTab('wall'); });
$('sp-close2').addEventListener('click', function () { $('sp-close').click(); });
$('sp-wform').addEventListener('submit', function (e) { e.preventDefault(); wallPost($('sp-wmsg').value); });
$('sp-close').addEventListener('click', function () { 