<!-- SOLID CITY · part 2994 -->
sU.rx * (hw + 1.2), sU.z + sU.rz * (hw + 1.2));
      var uLg = groundAt(sU.x - sU.rx * (hw + 1.2), sU.z - sU.rz * (hw + 1.2));
      upScore += (uRg - uLg);
    }
    var upSide = upScore >= 0 ? 1 : -1;

    /* the profile: keyed to the uphill edge, floored by the surface.
     * desired: the uphill edge sits a hair under its own ground (the
     * dirt meets the road), and the surface rises from that edge
     * toward the centre at a civil cross slope. The floor's law is
     * stated where it is computed (v3, below). */
    /* the cross-section is read through a median first: a rib that
     * crosses the line for ONE station is a feature of the land, not
     * an order to the road — the road answers the land's grain, and
     * the rib's corner is dressed by the cut bank where it stands.
     * The floor (v3) swears two things only: the centre is never
     * buried, and no edge may drag the whole surface more than
     * 1.35 m above the centre for its own sake. */
    var rawC = [], rawL = [], rawR = [];
    for (i = 0; i < N; i++) {
      var s0 = st[i];
      rawC.push(groundAt(s0.x, s0.z));
      rawL.push(groundAt(s0.x - s0.rx * hw, s0.z - s0.rz * hw));
      rawR.push(groundAt(s0.x + s0.rx * hw, s0.z + s0.rz * hw));
      s0.gC = rawC[i];
    }
    function med3(arr, j) {
      var a = arr[Math.max(0, j - 1)], b = arr[j], c = arr[Math.min(N - 1, j + 1)];
      return a + b + c - Math.min(a, b, c) - Math.max(a, b, c);
    }
    var prof = [], floorY = [];
    for (i = 0; i < N; i++) {
      var s = st[i];
      var gC = med3(rawC, i);
      var gL = med3(rawL, i), gR = med3(rawR, i);
      var crossMax = Math.max(gL, gC, gR);
      var gUp = upSide > 0 ? gR : gL;
      var sCross = Math.max(-0.04, Math.min(0.10, (gC - gUp) / hw));
      var want = gUp - 0.06 + hw * sCross;
      if (want > gC + 1.05) want = gC + 1.05;        // never fill the centre higher
      prof.push(want);
      floorY.push(Math.max(gC + 0.06, Math.min(crossMax - 0.30, gC + 1.35)));
      s.crossMax = crossMax; s.gUp = gUp;
    }
    /* The envelope survives as the profile's SAFETY NET (it is
     * called again below and inside the host-plane blend): the
     * profile never sinks under its floor and never grades beyond
     * the cap; its passes only ever RAISE — a limiter that could
     * also lower would drag the surface under the floor it was
     * sworn to keep (the first build's burial was that crime). */
    for (i = 0; i < N; i++) if (prof[i] < floorY[i]) prof[i] = floorY[i];
    function envelope() {
      var i2;
      for (i2 = 1; i2 < N; i2++) { var d = st[i2].ds || stepM; var need = prof[i2 - 1] - gradeCap * d; if (prof[i2] < need) prof[i2] = need; }
      for (i2 = N - 2; i2 >= 0; i2--) { var d2 = st[i2 + 1].ds || stepM; var need2 = prof[i2 + 1] - gradeCap * d2; if (prof[i2] < need2) prof[i2] = need2; }
    }
    /* THE VERTICAL ALIGNMENT — the corridor's second element
     * chain, in the vertical plane (the curriculum's discipline
     * 2). The design profile is a chain of GRADE SEGMENTS through
     * PVIs — points of vertical intersection — joined by PARABOLIC
     * vertical curves: y = yPVC + gIn·t + (gOut−gIn)·t²/(2L), the
     * curve's length from its rate L = K·A (K = 6 m per percent of
     * grade change, A the grades' difference). PVIs stand about
     * twelve metres apart on the terrain's demand (the floored
     * want computed above); the pins are the chain's two ends,
     * exact by construction; the chain is grade-limited by raising
     * the low end of any over-cap segment, the envelope's own
     * discipline, before a single parabola is drawn. What the
     * parabolas cannot honour — a floor that fights back — the
     * envelope below re-proves, as it always has. */
    (function verticalAlign() {
      var arcS = [0];
      for (var vi2 = 1; vi2 < N; vi2++) arcS.push(arcS[vi2 - 1] + (st[vi2].ds || stepM));
      var pIdx = [0];
      for (vi2 = 1; vi2 < N - 1; vi2++) if (arcS[vi2] - arcS[pIdx[pIdx.length - 1]] >= 12) pIdx.push(vi2);
      pIdx.push(N - 1);
      var m = pIdx.length, H = pIdx.map(function (ix) { return prof[ix]; });
      if (spec.pinStartY != null) H[0] = spec.pinStartY;
      if (spec.pinEndY != null) H[m - 1] = spec.pinEndY;
      for (var lp = 0; lp < 3; lp++) {
        for (var j = 0; j < m - 1; j++) {
          var dS = arcS[pIdx[j + 1]] - arcS[pIdx[j]];
          if (H[j + 1] < H[j] - gradeCap * dS && j + 1 < m - 1) H[j + 1] = H[j] - gradeCap * dS;
        }
        for (j = m - 1; j > 0; j--) {
          var dS2 = arcS[pIdx[j]] - arcS[pIdx[j - 1]];
          if (H[j - 1] < H[j] - gradeCap * dS2 && j - 1 > 0) H[j - 1] = H[j] - gradeCap * dS2;
        }
      }
      var segG = [], segL = [];
      for (j = 0; j < m - 1; j++) { segL.push(arcS[pIdx[j + 1]] - arcS[pIdx[j]]); segG.push((H[j + 1] - H[j]) / Math.max(segL[j], 0.01)); }
      var curves = [];
      for (j = 1; j < m - 1; j++) {
        var Apc = Math.abs(segG[j] -