<!-- SOLID CITY · part 3641 -->
g r=70..135
    var a2 = R() * Math.PI * 2, rr2 = 70 + R() * 65;
    var tx2 = Math.cos(a2) * rr2, tz2 = Math.sin(a2) * rr2;
    if (!clearOf(tx2, tz2)) continue;
    if (Math.abs(tx2) < 18 && tz2 < -100 && tz2 > -340) continue;   // bore corridor stays clear
    var h2 = 22 + R() * 14, ty2 = -18 - R() * 28;
    if (R() < 0.55) pineTree(tx2, tz2, ty2, h2); else ohiaTree(tx2, tz2, ty2, h2);
    placed2++;
  }
  [[-120, -60], [120, -40], [-110, 90], [110, 110]].forEach(function (gv) {   // 4 dense groves
    for (var gi = 0; gi < 11; gi++) {
      var gx = gv[0] + (R() - 0.5) * 46, gz = gv[1] + (R() - 0.5) * 46;
      if (!clearOf(gx, gz)) continue;
      if (Math.abs(gx) < 18 && gz < -100 && gz > -340) continue;
      var gh = 24 + R() * 13, gy2 = -18 - R() * 26;
      if (R() < 0.55) pineTree(gx, gz, gy2, gh); else ohiaTree(gx, gz, gy2, gh);
    }
  });
  // saplings among the ancients (20)
  for (var spi = 0; spi < 20; spi++) {
    var sa = R() * Math.PI * 2, sr = 75 + R() * 120;
    var sx = Math.cos(sa) * sr, sz = Math.sin(sa) * sr;
    if (!clearOf(sx, sz)) continue;
    var sh = 6 + R() * 5, sy = -18 - R() * 24;
    var sap = new T.Mesh(new T.ConeGeometry(1.6 + sh * 0.06, sh * 0.8, 7), leafMat);
    sap.position.set(sx, sy + sh * 0.4, sz); root.add(sap);
    var str = new T.Mesh(new T.CylinderGeometry(0.25, 0.35, sh * 0.35, 6), trunkMat);
    str.position.set(sx, sy + sh * 0.17, sz); root.add(str);
    foot.push([sx, sz, 1.2, 1.2, sy, sy + sh * 0.35, 0]);
  }
  // fallen logs (8)
  for (var fli = 0; fli < 8; fli++) {
    var fa = R() * Math.PI * 2, fr = 85 + R() * 110;
    var fx2 = Math.cos(fa) * fr, fz2 = Math.sin(fa) * fr;
    if (!clearOf(fx2, fz2)) continue;
    var fl2 = 7 + R() * 5, fy2 = -18 - R() * 24;
    var log = new T.Mesh(new T.CylinderGeometry(0.7, 0.9, fl2, 8), trunkMat);
    log.rotation.z = Math.PI / 2; log.rotation.y = R() * Math.PI;
    log.position.set(fx2, fy2 + 0.8, fz2); root.add(log);
    foot.push([fx2, fz2, fl2, 2, fy2, fy2 + 1.8, 0]);
  }

  // ---------- boulders: basalt bones of the mountain (24) ----------
  for (var bi = 0; bi < 24; bi++) {
    var ba2 = R() * Math.PI * 2, br2 = 65 + R() * 150;
    var bx = Math.cos(ba2) * br2, bz = Math.sin(ba2) * br2;
    if (!clearOf(bx, bz)) continue;
    if (Math.abs(bx) < 20 && bz < -95 && bz > -345) continue;
    var bs = 1.5 + R() * 3.2, by = -16 - R() * 26;
    var rock = new T.Mesh(new T.DodecahedronGeometry(bs, 0), basaltMat);
    rock.position.set(bx, by + bs * 0.55, bz);
    rock.rotation.set(R() * 3, R() * 3, R() * 3); root.add(rock);
    foot.push([bx, bz, bs * 1.7, bs * 1.7, by, by + bs * 1.5, 0]);
  }

  // ---------- bushes and ferns (48) ----------
  for (var ui = 0; ui < 48; ui++) {
    var ua = R() * Math.PI * 2, ur = 62 + R() * 120;
    var ux = Math.cos(ua) * ur, uz = Math.sin(ua) * ur;
    if (!clearOf(ux, uz)) continue;
    var us = 0.8 + R() * 1.4, uy = -16 - R() * 22;
    var bush;
    if (R() < 0.5) { bush = new T.Mesh(new T.SphereGeometry(us, 8, 6), leafDeepMat); }
    else { bush = new T.Mesh(new T.ConeGeometry(us * 0.9, us * 1.6, 7), leafMat); }
    bush.position.set(ux, uy + us * 0.7, uz); root.add(bush);
    // bushes are soft: small solid core only
    foot.push([ux, uz, us, us, uy, uy + us, 0]);
  }

  // ---------- stone paths connecting the clusters ----------
  var pathMat = new T.MeshLambertMaterial({ color: 0x4f463c });
  function stonePath(pts) {
    for (var i = 0; i < pts.length - 1; i++) {
      var A0 = pts[i], B0 = pts[i + 1];
      var segs = Math.ceil(Math.hypot(B0[0] - A0[0], B0[1] - A0[1]) / 4);
      for (var k = 0; k < segs; k++) {
        var px = A0[0] + (B0[0] - A0[0]) * (k + 0.5) / segs + (R() - 0.5) * 1.2;
        var pz = A0[1] + (B0[1] - A0[1]) * (k + 0.5) / segs + (R() - 0.5) * 1.2;
        var py = A0[2] + (B0[2] - A0[2]) * (k + 0.5) / segs;
        var slab = new T.Mesh(new T.CylinderGeometry(1.5 + R() * 0.5, 1.7 + R() * 0.5, 0.5, 7), pathMat);
        slab.position.set(px, py + 0.9, pz); slab.rotation.y = R() * 3; root.add(slab);
      }
    }
  }
  stonePath([[-40, -70, 0], [-20, -60, 0], [0, -62, 0], [20, -60, 0], [40, -70, 0]]);       // A west-east
  stonePath([[-56, 14, -18], [-38, 18, -18], [-28, -12, -18], [-8, 26, -18], [8, -22, -18]]); // B west loop
  stonePath([[34, 4, -18], [56, 12, -18], [62, -18, -18], [45, -25, -18]]);                  // B east
  stonePath([[-30, 72, -36], [-12, 108, -36], [-2, 120, -36], [6, 66, -36], [28, 112, -36]]); // C loop
  stonePath([[90, 20, -20], [100, 40, -22], [85, 55, -22]]);                                // eastern grove

  // ---------- rope fences along terrace edges (with collision) ----------
  function ropeFence(x1, z1, y1, x2, z2, y2) {
    var len = Math.hypot(x2 - x1, z2 - z1), n = Math.max(2, Math.round(len / 7));
    var tops = [];
    for (var i = 0; i <= n; i++) {
      var px = x1 + (x2 - x1) * i / n, pz = z1 + (z2 - z1) * i / n, py = y1 + (y2 - y1) * i / n;
      var post = new T.M