<!-- SOLID CITY · part 3647 -->
o VECTOR's Triangle-and-Seam
 * Auditor (an on-demand royal instrument) can ask whether the
 * constructed triangles agree with the registry. For box slabs the
 * standing face is the top: probes landing on any other face are
 * answered null — they are not standing probes, and the instrument's
 * reader says so plainly rather than crying mismatch. */
function regAudit(name, mesh, standAt, kind, expectedUp) {
  if (!mesh) return;
  (window.SC.auditables = window.SC.auditables || []).push({ name: name, mesh: mesh, standAt: standAt || null, kind: kind || 'surface', expectedUp: expectedUp !== false });
}
function topAware(target) {
  return function (x, z, refY) { return (refY != null && Math.abs(refY - target) <= 0.05) ? target : null; };
}
function ribbonStand(tris) {
  var ix = indexTris(tris);
  return function (x, z) { return triHeightIx(ix, x, z); };
}

function localUV(st, x, z) {
  var du = x - st.center[0], dv = z - st.center[2];
  return [du * st.ux + dv * st.uz, du * st.vx + dv * st.vz];
}
/* The joins' designer delivered their standing surfaces as raw triangle
 * geometry — "VISUAL GEOMETRY ONLY until stand/collision registry
 * integrated" — so this placer performs the integration he specified:
 * the exact triangles of each connector answer standY by barycentric
 * height, the same mathematics his measureConnector proves them by. */
function triHeight(tris, x, z) {
  // each tri: [ax, ay, az, bx, by, bz, cx, cy, cz] in world coordinates
  for (var i = 0; i < tris.length; i++) {
    var t = tris[i];
    var den = (t[5] - t[8]) * (t[0] - t[6]) + (t[6] - t[3]) * (t[2] - t[8]);
    if (Math.abs(den) < 1e-10) continue;
    var u = ((t[5] - t[8]) * (x - t[6]) + (t[6] - t[3]) * (z - t[8])) / den;
    var v = ((t[8] - t[2]) * (x - t[6]) + (t[0] - t[6]) * (z - t[8])) / den;
    var w = 1 - u - v;
    if (Math.min(u, v, w) < -1e-7) continue;
    return u * t[1] + v * t[4] + w * t[7];
  }
  return null;
}
/* THE SPATIAL INDEX (ladder stage 3, 2026-10-13): triHeight's full scan
 * answered every standing query by walking every triangle of every
 * join. The index buckets each join's triangles by their bounding boxes
 * on a 16 m grid; a query visits only its own cell's candidates, in
 * original registration order — the first containing triangle it finds
 * is the very one the full scan would return. Same barycentric rule,
 * same selection, same answers; the scan is now proportional to the
 * neighbourhood, not the nation. */
function indexTris(tris) {
  var cells = {};
  for (var i = 0; i < tris.length; i++) {
    var t = tris[i];
    var x0 = Math.floor(Math.min(t[0], t[3], t[6]) / 16), x1 = Math.floor(Math.max(t[0], t[3], t[6]) / 16);
    var z0 = Math.floor(Math.min(t[2], t[5], t[8]) / 16), z1 = Math.floor(Math.max(t[2], t[5], t[8]) / 16);
    for (var cx = x0; cx <= x1; cx++) for (var cz = z0; cz <= z1; cz++) {
      var k = cx + ',' + cz;
      (cells[k] = cells[k] || []).push(i);
    }
  }
  return { tris: tris, cells: cells };
}
function triHeightIx(ix, x, z) {
  if (!ix) return null;
  var cand = ix.cells[Math.floor(x / 16) + ',' + Math.floor(z / 16)];
  if (!cand) return null;
  var tris = ix.tris;
  for (var n = 0; n < cand.length; n++) {
    var t = tris[cand[n]];
    var den = (t[5] - t[8]) * (t[0] - t[6]) + (t[6] - t[3]) * (t[2] - t[8]);
    if (Math.abs(den) < 1e-10) continue;
    var u = ((t[5] - t[8]) * (x - t[6]) + (t[6] - t[3]) * (z - t[8])) / den;
    var v = ((t[8] - t[2]) * (x - t[6]) + (t[0] - t[6]) * (z - t[8])) / den;
    var w = 1 - u - v;
    if (Math.min(u, v, w) < -1e-7) continue;
    return u * t[1] + v * t[4] + w * t[7];
  }
  return null;
}
function extractTris(geo) {
  var pos = geo.getAttribute('position'), idx = geo.getIndex(), tris = [];
  var n = idx ? idx.count : pos.count;
  for (var i = 0; i + 2 < n; i += 3) {
    var tri = [];
    for (var k = 0; k < 3; k++) {
      var vi = idx ? idx.getX(i + k) : i + k;
      tri.push(pos.getX(vi), pos.getY(vi), pos.getZ(vi));
    }
    tris.push(tri);
  }
  return tris;
}
function standY(x, z, py) {
  var best = -1000;
  for (var h = 0; h < H.houses.length; h++) {
    var hs = H.houses[h], st = hs.stand, uv = localUV(st, x, z), floor = st.center[1];
    var cand = [];
    if (Math.abs(uv[0]) <= 4 && Math.abs(uv[1]) <= 5) cand.push(floor);
    if (hs.roofTop && Math.abs(uv[0]) <= 4.35 && Math.abs(uv[1]) <= 5.35) cand.push(hs.roofTop);
    for (var i = 0; i < cand.length; i++) if ((py == null || cand[i] <= py + 1.6) && cand[i] > best) best = cand[i];
  }
  for (var j = 0; j < H.joins.length; j++) {
    var y = triHeightIx(H.joinIx[j], x, z);
    if (y != null && (py == null || y <= py + 1.6) && y > best) best = y;
  }
  return best;
}
function radar(rg, blip, flying) {
  if (!H.houses.length) return;
  blip(H.housePos.x, H.housePos.z, '#ffd27a', flying ? 3 : 6, flying ? '' : 'PILOT HOUSE');
  for (var h = 1; h < H.houses.length; h++) blip(H.houses[h].cx, H.houses[h].cz, '#ffd27a', 3, '');
  for (var 