<!-- SOLUV · part 502 -->
().expandByScalar(R);
    if (b.containsPoint(q)) {
      const pen = [['x', q.x - b.min.x, b.min.x], ['x', b.max.x - q.x, b.max.x], ['z', q.z - b.min.z, b.min.z], ['z', b.max.z - q.z, b.max.z], ['y', b.max.y - q.y, b.max.y]].sort((a, c) => a[1] - c[1]);
      q[pen[0][0]] = pen[0][2]; camera.position.copy(q.applyMatrix4(group.matrixWorld));
    }
    lastGood.copy(camera.position);
  }
  const prevLookAt = camera.lookAt;
  camera.lookAt = function (...a) {
    if (a[0] && a[0].isVector3) aim.copy(a[0]); else if (a.length >= 3) aim.set(+a[0], +a[1], +a[2]);
    if (camH() < 80) solid(); else lastGood.copy(camera.position);
    group.visible = shouldShow();
    return prevLookAt.apply(this, a);
  };

  // her own text arrives in the background: draw again when it changes (the world only listens to its own walls)
  let redraw = 0;
  const draw = () => { if (redraw) return; redraw = requestAnimationFrame(() => { redraw = 0; if (group.visible) renderer.render(scene, camera); }); };
  wall.addEventListener('change', draw); wall.addEventListener('status', draw);

  /* ---------- UI: a map label (tap to fly to her), "walk up" and a composer when you stand at her face ---------- */
  const style = document.createElement('style');
  style.textContent = `
  .spt-label{position:absolute;left:0;top:0;z-index:3;box-sizing:border-box;min-height:48px;padding:0 10px;display:flex;align-items:center;background:none;border:0;cursor:pointer;touch-action:manipulation;-webkit-tap-highlight-color:transparent}
  .spt-label span{font:14px/1.2 "Soluv Condensed","Roboto Condensed",sans-serif;color:#d7ecf2;background:#050b12d9;border:1px solid #3a6f80;border-radius:8px;padding:3px 8px;white-space:nowrap}
  .spt-label[hidden],.spt-walk[hidden],.spt-compose[hidden]{display:none}
  .spt-walk{position:absolute;left:8px;bottom:max(8px,env(safe-area-inset-bottom));z-index:5;box-sizing:border-box;min-height:48px;height:48px;padding:0 16px;border-radius:12px;border:1px solid #3a6f80;background:#050b12e6;color:#d7ecf2;font:600 16px/1 "Soluv Condensed","Roboto Condensed",sans-serif;cursor:pointer;touch-action:manipulation}
  .spt-compose{position:absolute;left:8px;right:72px;bottom:max(8px,env(safe-area-inset-bottom));display:flex;gap:6px;z-index:5;margin:0}
  .spt-input{flex:1;min-width:0;height:48px;box-sizing:border-box;border-radius:12px;border:1px solid #3a6f80;background:#050b12;color:#fff;font:17px/1 "Soluv Condensed","Roboto Condensed",sans-serif;padding:0 12px;outline:none;-webkit-appearance:none;appearance:none}
  .spt-input:focus{border-color:#cfe6ee}
  .spt-send,.spt-login{box-sizing:border-box;min-width:64px;height:48px;border-radius:12px;border:1px solid #3a6f80;background:#0b1620;color:#d7ecf2;font:600 16px/1 "Soluv Condensed","Roboto Condensed",sans-serif;display:flex;align-items:center;justify-content:center;text-decoration:none;cursor:pointer;touch-action:manipulation;padding:0 12px;white-space:nowrap}
  .spt-send:disabled{opacity:.5}
  .spt-compose.spt-guest .spt-input,.spt-compose.spt-guest .spt-send{display:none}
  .spt-compose:not(.spt-guest) .spt-login{display:none}
  .spt-msg{position:absolute;left:8px;right:80px;bottom:calc(max(8px,env(safe-area-inset-bottom)) + 56px);z-index:5;padding:8px 12px;border-radius:12px;background:#050b12f0;border:1px solid #3a6f80;color:#d7ecf2;font:15px/1.3 "Soluv Condensed","Roboto Condensed",sans-serif}
  .spt-msg[hidden]{display:none}`;
  document.head.appendChild(style);
  const label = document.createElement('button'); label.type = 'button'; label.className = 'spt-label'; label.hidden = true; label.setAttribute('aria-label', 'Fly to the Soul Print tower');
  label.innerHTML = '<span>\u2726 Soul Print</span>';
  const walk = document.createElement('button'); walk.type = 'button'; walk.className = 'spt-walk'; walk.hidden = true; walk.textContent = '\u270e Walk up to Soul Print';
  const form = document.createElement('form'); form.className = 'spt-compose spt-guest'; form.hidden = true; form.autocomplete = 'off';
  form.innerHTML = '<input class="spt-input" maxlength="2000" enterkeyhint="send" aria-label="Write to Soul Print" placeholder="Write to Soul Print\u2026"><button class="spt-send" type="submit">Send</button><a class="spt-login" href="/login">Log in to post</a>';
  const msg = document.createElement('div'); msg.className = 'spt-msg'; msg.hidden = true; msg.setAttribute('role', 'status');
  host.appendChild(label); host.appendChild(walk); host.appendChild(form); host.appendChild(msg);
  const input = form.querySelector('.spt-input'), send = form.querySelector('.spt-send'), loginA = form.querySelector('.spt-login');
  let msgT = 0; function say(t) { msg.textContent = t; msg.hidden = false; clearTimeout(msgT); msgT = setTimeout(() => { msg.hidden = true; }, 5000); }

  // camera poses for her (same shapes as the world's own "Wall" and "Live" views)
  const tanH = () => Math.tan(camera.fov * Math.PI / 360);
  const cssW = () => canvasEl.clientWidth || innerW