<!-- SOLID CITY · part 2500 -->
=== THE REJECTION + THE PORTS (the King's word,
   * 2026-10-14 ~01:48): "Reject the mountain roads entirely —
   * build the ports, terraces where the land demands." We had
   * started building on a flaw — lines drawn before the land
   * was read — and it morphed through two nights of lessons.
   * So the six mountain roads NEVER RISE: no ribbons, no banks,
   * no junction discs, no lamps along them, no road bodies, no
   * SOLID Bridge, and no driveways running to roads that do
   * not exist. The smith still SURVEYS the alignments inside
   * this factory — the houses were placed against that survey
   * and houses do not move — but the survey is a memory now,
   * not a build. What rises instead: SPACESHIP PORTS at the
   * settlements — level stone discs with a gold ring and a
   * beacon, standing on natural flat ground where the survey
   * found it, and standing as fill TERRACES where the land
   * demanded. The ports are the way between places now. */
  var ROADS_REJECTED = true;
  var ports = [];
  var PORT_SITES = [
    { name: 'GATE ROAD PORT', x: 650, z: -1265, y: 34.8, kind: 'natural' },
    { name: 'SHOULDER BENCHES PORT', x: 890, z: -1850, y: 88.14, kind: 'natural' },
    { name: 'WESTERN HEIGHTS PORT', x: 780, z: -1865, y: 84.32, kind: 'natural' },
    { name: 'NORTH BENCHES PORT', x: 665, z: -2060, y: 73.0, kind: 'natural' },
    { name: 'WESTERN BENCHES PORT', x: -365, z: -1075, y: 14.13, kind: 'natural' },
    { name: 'SOUTHERN BENCHES PORT', x: -490, z: -1165, y: 9.16, kind: 'natural' },
    { name: 'BRAID HEAD PORT', x: 890, z: -1345, y: 146.09, kind: 'terrace' },
    { name: 'EASTERN BENCHES PORT', x: 1045, z: -1635, y: 124.58, kind: 'terrace' },
    { name: 'HIGH BENCHES PORT', x: 1205, z: -1560, y: 179.33, kind: 'terrace' },
    { name: 'SUMMIT PORT', x: 1299, z: -1591, y: 198.95, kind: 'terrace' },
    { name: 'FAR NORTH PORT', x: 515, z: -2360, y: 15.29, kind: 'terrace' },
    { name: 'HALL OF BECOMING PORT', x: 1055, z: -295, y: 155.91, kind: 'terrace' },
    { name: 'KAUHALE MAUNA PORT', x: 2035, z: 1995, y: 263.33, kind: 'terrace' },
    { name: 'THE GAP PORT', x: 2059, z: 1870, y: 301.59, kind: 'terrace' }
  ];
  function buildPorts() {
    PORT_SITES.forEach(function (P) {
      var SEG = 24, ctr = [P.x, P.y, P.z], rim = [], k;
      for (k = 0; k < SEG; k++) { var an = k / SEG * Math.PI * 2; rim.push([P.x + Math.cos(an) * 10, P.y, P.z + Math.sin(an) * 10]); }
      var S = { pos: [], nor: [] }, SK = { pos: [], nor: [] }, GL = { pos: [], nor: [] };
      for (k = 0; k < SEG; k++) {
        var r1 = rim[k], r2 = rim[(k + 1) % SEG];
        triPush(S, ctr, r1, r2);
        standTris.push(ctr[0], ctr[1], ctr[2], r1[0], r1[1], r1[2], r2[0], r2[1], r2[2]);
        var d1 = [r1[0], groundAt(r1[0], r1[2]) - 0.4, r1[2]], d2 = [r2[0], groundAt(r2[0], r2[2]) - 0.4, r2[2]];
        triPush(SK, r1, r2, d2); triPush(SK, r1, d2, d1);
        var a1 = k / SEG * Math.PI * 2, a2 = (k + 1) / SEG * Math.PI * 2;
        var g1 = [P.x + Math.cos(a1) * 8.55, P.y + 0.02, P.z + Math.sin(a1) * 8.55], g2 = [P.x + Math.cos(a2) * 8.55, P.y + 0.02, P.z + Math.sin(a2) * 8.55];
        var g3 = [P.x + Math.cos(a2) * 9.0, P.y + 0.02, P.z + Math.sin(a2) * 9.0], g4 = [P.x + Math.cos(a1) * 9.0, P.y + 0.02, P.z + Math.sin(a1) * 9.0];
        triPush(GL, g1, g2, g3); triPush(GL, g1, g3, g4);
      }
      pourSurf(S, solid, C.stone);
      pourSurf(SK, solid, C.stoneDark);
      pourSurf(GL, glowB, 0xd8a833);
      // the beacon: one lamp standing on the pad's north rim
      var bx = P.x, bz = P.z - 10.8;
      BASE = M4(bx, P.y - 0.1, bz, 0, 0, 0);
      streetLight();
      BASE = new T.Matrix4();
      foot.push([bx, bz, 0.3, 0.3, P.y - 0.1, P.y + 5.2, 0]);
      foot.push([P.x, P.z, 20, 20, P.y - 6, P.y, 0]);
      ports.push({ name: P.name, x: P.x, z: P.z, y: P.y, kind: P.kind });
    });
  }
  // a junction APRON: a fan whose rim is stitched to the roads
  // themselves — each rim point takes its height from the nearest
  // stations' own planes (grade along, bank across), the highest
  // claim winning, as the world's standing law also takes the
  // highest — so the apron meets every road on that road's own
  // terms, and its skirts fall to the land. A disc planed from one
  // station is a table wherever the host's own surface curves;
  // an apron stitched to all the roads is a junction.
  function apronAt(x, z, host) {
    if (ROADS_REJECTED) return;   // THE REJECTION: no junction discs rise
    var S = { pos: [], nor: [] }, SEG = 20, fr = 7.0, ctr = [x, host.y + 0.03, z];
    var all = [];
    for (var rn in smithRoads) all = all.concat(smithRoads[rn].stations);
    function heightAt(px, pz) {
      var best = null, wsum = 0, ysum = 0;
      for (var q = 0; q < all.length; q++) {
        var s2 = all[q], dx = px - s2.x, dz = pz - s2.z;
        var dd = dx * dx + dz * dz;
        if (dd > 100) continue;
        var y = s2.y + s2.grade * (dx * s2.fx + dz * s2.fz) 