<!-- SOLID CITY · part 3675 -->
 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 k in LINK_MID) blip(LINK_MID[k].x, LINK_MID[k].z, '#ffd27a', 3, '');
  blip(-1127, -524, '#ffd27a', 3, '');
  blip(-912, -768, '#ffd27a', 3, '');
}
function update(dt) {
  if (!H.houses.length) return;
  var dx = S.p.x - H.housePos.x, dz = S.p.z - H.housePos.z;
  if (!H.saidHouse && dx * dx + dz * dz < 150 * 150) {
    H.saidHouse = true;
    A.help('🏠 THE PILOT HOUSE — the nation\'s first dwelling, in Ward 2. Its door is glass; walk in, stand on its floor, examine its foundations. Nine more lawful houses now stand beside it.', 8);
  }
  for (var w in STREET) {
    if (H.saidStreet[w]) continue;
    var st = STREET[w], sx = S.p.x - st.x, sz = S.p.z - st.z;
    if (sx * sx + sz * sz < 130 * 130) { H.saidStreet[w] = true; A.help(st.line || ('🏘 ' + st.name + ' STREET — dwellings of the nation stand along this path, each founded on sampled ground, each floor under standing law.'), 7); }
  }
  var clx = S.p.x + 912, clz = S.p.z + 768;
  if (!H.saidClimb && clx * clx + clz * clz < 90 * 90) { H.saidClimb = true; A.help('🧗 THE CLIMB — the completed W4–W5 high road: 248 surveyed metres under their own permission class, three resting turns, cresting where Ward 4\'s own path touches the high ground.', 7); }
  var w6x = S.p.x + 1127, w6z = S.p.z + 524;
  if (!H.saidW6 && w6x * w6x + w6z * w6z < 70 * 70) { H.saidW6 = true; A.help('🛤 THE WARD 6 LINK — the South Ward touches the Long Road here, on a surveyed line, at the corridor\'s edge.', 7); }
  for (var k in LINK_MID) {
    if (H.saidJoin[k]) continue;
    var m = LINK_MID[k], jx = S.p.x - m.x, jz = S.p.z - m.z;
    if (jx * jx + jz * jz < 60 * 60) { H.saidJoin[k] = true; A.help('🛤 A join in the nation\'s road — the wards are one network here. This link was measured to three hundredths of a millimetre of its constructed surface.', 7); }
  }
}
function wallSolids(house) {
  var mesh = house.mesh, st = house.stand;
  var c = Math.cos(mesh.rotation.y), s = Math.sin(mesh.rotation.y);
  (house.solids.source || []).forEach(function (w) {
    var p = w.geometry.parameters, ly = w.position.y;
    if (p.height < 1 && ly > st.center[1] + 2) return; // the lintel — above the door, no standing law
    var len = Math.max(p.width, p.depth), dep = Math.min(p.width, p.depth);
    var n = Math.max(1, Math.ceil(len / 0.9)), cw = len / n;
    var hx = cw / 2 * Math.abs(c) + dep / 2 * Math.abs(s), hz = cw / 2 * Math.abs(s) + dep / 2 * Math.abs(c);
    for (var i = 0; i < n; i++) {
      var off = -len / 2 + cw * (i + 0.5);
      var lx = w.position.x + (p.width >= p.depth ? off : 0), lz = w.position.z + (p.width >= p.de