<!-- SOLID CITY · part 2794 -->
 (gz0 + gz1) / 2, ang, rx, 0);
            box(solid, 7.6, 0.22, run + 1.6, 0, 0, 0, C.road);
            standQuad((gx0 + gx1) / 2, (ga + gb) / 2 + 0.1, (gz0 + gz1) / 2, ang, rx, 7.6, run + 1.6, 0.11);
            if (j % 2 === 0 && s2 === 0) box(solid, 0.35, 0.05, 2.2, 0, 0.14, 0, C.path);   // center dash
            BASE = new T.Matrix4();
          }
        }
      }
    });
    // street lights along the roads, alternating sides — set PERPENDICULAR
    // to the road's own direction (the old x-only offset dropped 33 of 56
    // lamps into the carriageway on the east-west runs; the King found them
    // there, 2026-10-13). Every pole also enters the collision registry:
    // a lamp at the verge is a post, not a ghost.
    for (var k = 6; k < roadPts.length; k += 9) {
      var p = roadPts[k], side = (k % 18 === 6) ? 1 : -1;
      var pa = roadPts[Math.max(0, k - 1)], pb = roadPts[Math.min(roadPts.length - 1, k + 1)];
      var dx = pb[0] - pa[0], dz = pb[1] - pa[1], dl = Math.hypot(dx, dz) || 1;
      var lx = p[0] + side * (dz / dl) * 5.2, lz = p[1] + side * (-dx / dl) * 5.2;
      var ly = groundAt(lx, lz);
      BASE = M4(lx, ly - 0.1, lz, R() * 3, 0, 0);
      streetLight();
      BASE = new T.Matrix4();
      foot.push([lx, lz, 0.3, 0.3, ly - 0.1, ly + 5.1, 0]);
    }
  }
  /* ================= THE RIM STEP DEMONSTRATION (2026-10-13) =================
   * One pitch of the twisted Road B, built by the Road Smith as an
   * isolated demonstration under the King's authorization. The old
   * roads stand untouched beside it; nothing re-sites, nothing moves.
   * THE SWITCH: RIMSTEP_DEMO is the rollback — set it false (or pass
   * { rimStepDemo: false } to the factory) and the district is
   * exactly as it was, byte for byte in every registry that matters.
   * The line: surveyed, not merely designed — the lower-bench
   * traverse, then the riser pitch to the upper bench above High
   * Benches, threaded around the as-sited homes (the design's own
   * tail ran through two of them; the survey caught it first).
   * Furniture is THE BENCH (the King's photographs): dirt shoulders,
   * the cut bank on the uphill side, a guardrail over the drop. */
  var RIMSTEP_DEMO = true;
  function buildRimStepDemo() {
    var smith = createRoadSmith({ groundAt: groundAt });
    var built = smith.buildRoad({
      points: [[1162, -1546], [1185, -1545], [1208, -1543.5], [1228, -1544], [1243, -1545], [1256, -1546.5], [1263, -1547.9]],
      width: 7.6, furniture: 'bench'
    });
    var IDM = new T.Matrix4();
    function pour(surf, color) {
      if (!surf.pos.length) return;
      var g = new T.BufferGeometry();
      g.setAttribute('position', new T.Float32BufferAttribute(surf.pos, 3));
      g.setAttribute('normal', new T.Float32BufferAttribute(surf.nor, 3));
      solid.add(g, IDM, color);
    }
    pour(built.ribbon, C.road);
    pour(built.shoL, C.soil); pour(built.shoR, C.soil);
    pour(built.skirtL, C.stone); pour(built.skirtR, C.stone);
    pour(built.fans, C.conc);
    pour(built.rail, 0x9aa4b5);
    pour(built.posts, C.stoneDark);
    for (var i = 0; i < built.standTris.length; i++) standTris.push(built.standTris[i]);
  }

  function nearestRoad(x, z) {
    var best = null, bd = 1e12;
    for (var i = 0; i < roadPts.length; i++) {
      var dx = roadPts[i][0] - x, dz = roadPts[i][1] - z, dd = dx * dx + dz * dz;
      if (dd < bd) { bd = dd; best = roadPts[i]; }
    }
    return { x: best[0], z: best[1], dist: Math.sqrt(bd) };
  }
  function steppedPath(x0, z0, x1, z1, wdt, col, stepLen) {
    var len = Math.hypot(x1 - x0, z1 - z0), n = Math.max(1, Math.round(len / stepLen)), ang = Math.atan2(x1 - x0, z1 - z0), run = len / n;
    for (var j = 0; j < n; j++) {
      var t = (j + 0.5) / n, px = x0 + (x1 - x0) * t, pz = z0 + (z1 - z0) * t;
      // THE ONE ROAD reaches the driveways too: each stone pitches between
      // the same sampled ends its neighbours use — a path of ramps that
      // follow the land, not a staircase dropped on it.
      var ga = groundAt(x0 + (x1 - x0) * (j / n), z0 + (z1 - z0) * (j / n));
      var gb = groundAt(x0 + (x1 - x0) * ((j + 1) / n), z0 + (z1 - z0) * ((j + 1) / n));
      var rx = -Math.atan2(gb - ga, run);   // pitch truth (2026-10-13): atan2, as above
      BASE = M4(px, (ga + gb) / 2 + 0.08, pz, ang, rx, 0);
      box(solid, wdt, 0.18, stepLen + 0.7, 0, 0, 0, col);
      standQuad(px, (ga + gb) / 2 + 0.08, pz, ang, rx, wdt, stepLen + 0.7, 0.09);
      BASE = new T.Matrix4();
    }
  }

  /* ================= SITING — the placement law, enforced ================= */
  var EXCLUDE = [   // [x, z, radius] — structures and ground that stay untouched
    [0, -1600, 578],      // THE ANCESTRAL ROADS terrace (platform r=560)
    [0, -3200, 430],      // Imperial Colosseum
    [0, 0, 1060],         // the capital
    [0, -950, 205],       // Gate of Ancestors
    [450, -1150, 205],    // Compass Meridian
    [750, -1600, 255],    // Over