<!-- SOLID CITY · part 2527 -->
 = [];   // {x, z, ry, name}
  /* the built centreline as true segments (consecutive stations of
   * one road stand metres apart; the jump between roads is wide) —
   * the measure the Verge Law judges by, because on hairpin ground
   * a distance to the nearest station POINT can read clear while
   * the neighbouring leg's SEGMENT passes through the same ground. */
  var VERGE_SEGS = null;
  function segDistToRoad(x, z) {
    if (!VERGE_SEGS) {
      VERGE_SEGS = [];
      for (var vi = 0; vi < roadPts.length - 1; vi++) { var va = roadPts[vi], vb = roadPts[vi + 1]; if (Math.hypot(vb[0] - va[0], vb[1] - va[1]) < 4) VERGE_SEGS.push([va, vb]); }
    }
    var bd = 1e12, bx = x, bz = z;
    for (var i = 0; i < VERGE_SEGS.length; i++) {
      var a = VERGE_SEGS[i][0], b = VERGE_SEGS[i][1];
      var dx = b[0] - a[0], dz = b[1] - a[1], L2 = dx * dx + dz * dz;
      var t = L2 ? ((x - a[0]) * dx + (z - a[1]) * dz) / L2 : 0; t = Math.max(0, Math.min(1, t));
      var px = a[0] + dx * t, pz = a[1] + dz * t, d = Math.hypot(x - px, z - pz);
      if (d < bd) { bd = d; bx = px; bz = pz; }
    }
    return { d: bd, x: bx, z: bz };
  }
  function plateFor(name, x, z) {
    var rp = nearestRoad(x, z);
    /* THE VERGE LAW FOR SIGNS (the King's report, 2026-10-13 ~23:12:
     * "trees and signs in the middle — I can't move up or down with
     * that"). A cluster's centre is a survey idea, and several sit
     * ON the road's own line — a plate planted there stands in the
     * carriageway (the Eastern Benches plate measured 0.6 m from
     * the centreline). So the plate walks out to the verge: at
     * least 7.5 m from every built centreline segment, toward its
     * own cluster's nearest home — ground the siting law already
     * keeps clear — still facing the road it names. Plates already
     * clear stand where they were planted. No seed is drawn here;
     * the census of homes cannot shift. */
    if (segDistToRoad(x, z).d < 7.5) {
      var hb = null, hd = 1e12;
      homes.forEach(function (h) { var dd = Math.hypot(h.x - x, h.z - z); if (dd < hd) { hd = dd; hb = h; } });
      var ux, uz;
      if (hb) { ux = hb.x - rp.x; uz = hb.z - rp.z; } else { ux = x - rp.x; uz = z - rp.z; }
      var ul = Math.hypot(ux, uz); if (ul < 0.01) { ux = 1; uz = 0; ul = 1; }
      ux /= ul; uz /= ul;
      var D = 7.5;
      x = rp.x + ux * D; z = rp.z + uz * D;
      while (segDistToRoad(x, z).d < 7.5 && D < 44) { D += 0.5; x = rp.x + ux * D; z = rp.z + uz * D; }
      rp = nearestRoad(x, z);
    }
    plates.push({ x: x, z: z, ry: faceAngle(x, z, rp.x, rp.z), name: name });
  }
  function compound(cx, cz, name, mainStyle, satStyles, opts) {
    opts = opts || {};
    var main = findSpot(cx, cz, 45, 13);
    if (!main) return 0;
    var rp = nearestRoad(main[0], main[1]);
    var mrec = buildHome(mainStyle, main[0], main[1], faceAngle(main[0], main[1], rp.x, rp.z), 1.12, 'full');
    placed.push([main[0], main[1], 17]);
    serveHome(mrec, rp);
    var count = 1;
    for (var i = 0; i < satStyles.length; i++) {
      var a = (i / satStyles.length) * Math.PI * 2 + R() * 0.8;
      var sx = cx + Math.cos(a) * (opts.ring || 30), sz = cz + Math.sin(a) * (opts.ring || 30);
      var sp = findSpot(sx, sz, 30, 11);
      if (!sp) continue;
      var srec = buildHome(satStyles[i], sp[0], sp[1], faceAngle(sp[0], sp[1], cx, cz), 0.82 + R() * 0.2, i === 0 ? 'full' : 'simple');
      placed.push([sp[0], sp[1], 15]);
      // satellites share the compound's parking — a path of yellow stones to the yard instead of a second drive
      var fx = Math.sin(srec.ry), fz = Math.cos(srec.ry), frontL = srec.padCz + srec.padD / 2;
      steppedPath(sp[0] + fx * (frontL + 1), sp[1] + fz * (frontL + 1), cx, cz, 1.6, C.path, 2.6);
      srec.door = [sp[0] + fx * (frontL + 0.9), sp[1] + fz * (frontL + 0.9)];
      count++;
    }
    // the shared yard: a great monkeypod, taro at the low side, lava-rock edging
    /* THE VERGE LAW FOR THE YARD (same report, same hour): the yard
     * was planted at the raw centre too — at the Eastern Benches
     * its monkeypod stood 0.6 m from the centreline, a tree in the
     * middle of the road. The yard now steps away from the road
     * until its heart is 11 m clear (the monkeypod's canopy then
     * overhangs grass, not carriageway), keeping its taro beside
     * it. The same seeds are drawn; only the ground moves. */
    var yardX = cx, yardZ = cz;
    if (segDistToRoad(cx, cz).d < 11) {
      var yrp = nearestRoad(cx, cz);
      var yux = mrec.x - yrp.x, yuz = mrec.z - yrp.z, yul = Math.hypot(yux, yuz);
      if (yul < 0.01) { yux = 1; yuz = 0; yul = 1; }
      yux /= yul; yuz /= yul;
      var ySteps = 0;
      while (segDistToRoad(yardX, yardZ).d < 11 && ySteps < 72) { yardX += yux * 0.5; yardZ += yuz * 0.5; ySteps++; }
    }
    plantAt(yardX, yardZ, function () { monkeypod(1.25); });
    var taroX = yardX + (R() - 0.5) * 16, taroZ = yardZ + (R() - 0.5) * 16;
    if (s