<!-- SOLID CITY · part 3045 -->

      }
    }
    function edgePt(s, side, out, lift) {
      var d = s.hw + out;
      return [s.x + s.Rx * side * d, s.y + s.Ry * side * d + (lift || 0), s.z + s.Rz * side * d];
    }
    /* THE DRAPE (the finish that answers the fins): the old bank
     * marched outward up to fourteen metres hunting for the land and,
     * not finding it, pinned its foot in the air — 3,152 sail
     * triangles by the census, floating up to thirteen metres above
     * the slope. The drape instead walks a short profile out from
     * the edge and MEETS the land: at each step its height is the
     * land itself, clamped between a falling repose (0.62) and a
     * rising cut (0.95); once it reaches the land it follows it,
     * tucked a quarter-metre under. If the land falls away faster
     * than repose for a full bench depth (3.4 m), the profile
     * becomes a benched shoulder, descending gently — a retaining
     * line at the road's own edge, never a sheet hung in the air.
     * The whole profile spans at most 6.3 m from the edge. */
    function drapeFrom(e, dirx, dirz) {
      var pts = [e], met = false;
      for (var k = 1; k <= 6; k++) {
        var d = 1.05 * k;
        var px = e[0] + dirx * d, pz = e[2] + dirz * d;
        var land = groundAt(px, pz) - 0.25;
        var y;
        if (met) y = land;
        else {
          y = Math.max(e[1] - 0.62 * d, Math.min(land, e[1] + 0.95 * d));
          var bench = e[1] - 3.4 - 0.25 * Math.max(0, d - 5.48);
          if (y < bench) y = bench;
          if (y === land) met = true;
        }
        pts.push([px, y, pz]);
      }
      return { pts: pts, met: met };
    }
    var drapeCacheL = [], drapeCacheR = [];
    for (i = 0; i < N - 1; i++) {
      var A = st[i], B = st[i + 1];
      quad(ribbon, A.L, B.L, B.R, A.R); standQuad(stand, A.L, B.L, B.R, A.R);
      /* curbs: a top ribbon and an outer face, both edges; the top stands */
      var sides = [-1, 1];
      for (var q = 0; q < 2; q++) {
        var sd = sides[q], curb = sd < 0 ? curbL : curbR, gold = sd < 0 ? goldL : goldR;
        var out0 = 0.32, lift0 = 0.0;
        if (spec.furniture === 'bench') {
          /* THE BENCH KIT (the King's photographs): a dirt shoulder on
           * both edges — the carriageway's own ground, stood on like
           * the road — and on the DOWNHILL edge a guardrail: posts and
           * a silver rail over the drop. No curb, no gold: those are
           * street furniture, and this is a mountain. */
          out0 = 0.95; lift0 = 0.015;
          var sho = sd < 0 ? shoL : shoR;
          var hA0 = edgePt(A, sd, 0.02, 0.015), hA1 = edgePt(A, sd, 0.95, 0.015);
          var hB0 = edgePt(B, sd, 0.02, 0.015), hB1 = edgePt(B, sd, 0.95, 0.015);
          quad(sho, hA0, hB0, hB1, hA1); standQuad(stand, hA0, hB0, hB1, hA1);
          if (sd === -upSide) {
            var rAl = edgePt(A, sd, 0.62, 0.38), rAh = edgePt(A, sd, 0.62, 0.66);
            var rBl = edgePt(B, sd, 0.62, 0.38), rBh = edgePt(B, sd, 0.62, 0.66);
            quad(rail, rAl, rBl, rBh, rAh, [sd * A.rx, sd * A.rz]);
            quad(rail, rBl, rAl, rAh, rBh, [sd * A.rx, sd * A.rz]);
            var tA0 = edgePt(A, sd, 0.56, 0.66), tA1 = edgePt(A, sd, 0.68, 0.66);
            var tB0 = edgePt(B, sd, 0.56, 0.66), tB1 = edgePt(B, sd, 0.68, 0.66);
            quad(rail, tA0, tB0, tB1, tA1);
            if (i % 2 === 0) {
              var pb = edgePt(A, sd, 0.62, 0.0), py0 = pb[1] - 0.06, py1 = pb[1] + 0.60;
              var pc = function (dx, dz, y) { return [pb[0] + A.rx * dx + A.fx * dz, y, pb[2] + A.rz * dx + A.fz * dz]; };
              var p00 = pc(-0.09, -0.09, py0), p10 = pc(0.09, -0.09, py0), p11 = pc(0.09, 0.09, py0), p01 = pc(-0.09, 0.09, py0);
              var p00t = pc(-0.09, -0.09, py1), p10t = pc(0.09, -0.09, py1), p11t = pc(0.09, 0.09, py1), p01t = pc(-0.09, 0.09, py1);
              quad(posts, p00, p10, p10t, p00t); quad(posts, p10, p11, p11t, p10t);
              quad(posts, p11, p01, p01t, p11t); quad(posts, p01, p00, p00t, p01t);
              quad(posts, p00t, p10t, p11t, p01t);
            }
          }
        } else {
        var cA0 = edgePt(A, sd, 0.02, 0.02), cA1 = edgePt(A, sd, 0.32, 0.15);
        var cB0 = edgePt(B, sd, 0.02, 0.02), cB1 = edgePt(B, sd, 0.32, 0.15);
        quad(curb, cA0, cB0, cB1, cA1); standQuad(stand, cA0, cB0, cB1, cA1);
        var fA = [cA1[0], cA1[1] - 0.19, cA1[2]], fB = [cB1[0], cB1[1] - 0.19, cB1[2]];
        quad(curb, cA1, cB1, fB, fA, [sd * A.rx, sd * A.rz]);
        var gA0 = edgePt(A, sd, 0.05, 0.157), gA1 = edgePt(A, sd, 0.13, 0.157);
        var gB0 = edgePt(B, sd, 0.05, 0.157), gB1 = edgePt(B, sd, 0.13, 0.157);
        quad(gold, gA0, gB0, gB1, gA1);
        /* the sidewalk, on the uphill side: from the curb's outer edge */
        if (walkSide === sd) {
          var wA0 = edgePt(A, sd, 0.32, 0.14), wA1 = edgePt(A, sd, 1.95, 0.14);
          var wB0 = edgePt(B, sd, 0.32, 0.14), wB1 = edgePt(B, sd, 1.95, 