<!-- SOLID CITY · part 3638 -->
 T.BoxGeometry(w[2], 1.1, w[3] + 0.6), basaltMat);
      curb.position.set(w[0], 0.55, w[1]); g.add(curb);
    });
    // fire pit
    var pit = new T.Mesh(new T.CylinderGeometry(2.6, 3, 1.2, 12), basaltMat);
    pit.position.y = 0.6; g.add(pit);
    var flame = new T.Mesh(new T.ConeGeometry(1.6, 4.2, 10),
      new T.MeshBasicMaterial({ color: C.fire, transparent: true, opacity: 0.9 }));
    flame.position.y = 3.4; flame.name = 'flame'; g.add(flame);
    var fireLight = new T.PointLight(0xff9a40, 2.2, 70); fireLight.position.y = 5; g.add(fireLight);
    g.userData.fireLight = fireLight; g.userData.flame = flame;
    // log benches around the fire
    for (var b = 0; b < 6; b++) {
      var ba = (b / 6) * Math.PI * 2 + 0.26;
      var bench = new T.Mesh(new T.CylinderGeometry(0.5, 0.5, 4.4, 8), woodDarkMat);
      bench.rotation.z = Math.PI / 2; bench.rotation.y = -ba;
      bench.position.set(Math.cos(ba) * 6.4, 0.9, Math.sin(ba) * 6.4); g.add(bench);
    }
    g.position.set(cx, ty, cz);
    root.add(g);
    root.userData.hale = g;
    haleRef.g = g;
    foot.push([cx - W/2, cz - D/2, 1.2, D, ty, ty + PH, 0]); foot.push([cx + W/2, cz - D/2, 1.2, D, ty, ty + PH, 0]);
    foot.push([cx, cz, 5.4, 5.4, ty, ty + 2, 0]);  // fire pit
  })();

  // ---------- lookout (Terrace C, northwest edge — faces the city) ----------
  (function () {
    // city is at ~(0,0); village at (2000,2000) → city dir ≈ (-0.707,-0.707); local NW edge
    var lx = -38, lz = 108, ty = -36;
    var deck = new T.Mesh(new T.BoxGeometry(16, 1.2, 10), woodMat);
    deck.position.set(lx, ty + 2.6, lz); root.add(deck);
    // posts + railing on the view side
    for (var i = -2; i <= 2; i++) {
      var pr = new T.Mesh(new T.CylinderGeometry(0.22, 0.22, 2.6, 6), woodDarkMat);
      pr.position.set(lx + i * 3.4 - 1.2, ty + 4.4, lz - 4.6); root.add(pr);
    }
    var rail = new T.Mesh(new T.BoxGeometry(16, 0.25, 0.25), woodDarkMat);
    rail.position.set(lx - 1.2, ty + 5.6, lz - 4.6); root.add(rail);
    // support poles down the slope
    [[-6, -3], [6, -3], [-6, 3], [6, 3]].forEach(function (p) {
      var pole = new T.Mesh(new T.CylinderGeometry(0.35, 0.35, 9, 6), woodDarkMat);
      pole.position.set(lx + p[0], ty - 1.5, lz + p[1]); root.add(pole);
    });
    // a small warm lantern on the rail
    var lant = new T.Mesh(new T.SphereGeometry(0.5, 8, 6), winMat);
    lant.position.set(lx - 1.2, ty + 6.3, lz - 4.6); root.add(lant);
    foot.push([lx, lz, 16, 10, ty, ty + 3.2, 0]);
  })();

  // ---------- GIANT TREES — the King's wish: 25-40 m ancients ----------
  // Two kinds: tall kine-pine (layered cones) and broad ohia (sphere canopy).
  // Seeded scatter, clustered, never in a grid, kept off terraces and road.
  var trees = [];
  function pineTree(x, z, ty, h) {
    var g = new T.Group();
    var trunkH = h * 0.32, trunkR = 1.1 + h * 0.022;
    var trunk = new T.Mesh(new T.CylinderGeometry(trunkR * 0.75, trunkR, trunkH, 8), trunkMat);
    trunk.position.y = trunkH / 2; g.add(trunk);
    var layers = 4, ch = h * 0.72, baseR = h * 0.20;
    for (var i = 0; i < layers; i++) {
      var lr = baseR * (1 - i / (layers + 0.6)), lh = ch / layers * 1.5;
      var cone = new T.Mesh(new T.ConeGeometry(lr, lh, 9), i % 2 ? leafDeepMat : leafMat);
      cone.position.y = trunkH + ch * (i + 0.7) / layers; g.add(cone);
    }
    g.position.set(x, ty, z);
    g.rotation.y = R() * Math.PI * 2;
    root.add(g); trees.push(g);
    foot.push([x, z, trunkR * 2.6, trunkR * 2.6, ty, ty + trunkH, 0]);
  }
  function ohiaTree(x, z, ty, h) {
    var g = new T.Group();
    var trunkH = h * 0.30, trunkR = 1.3 + h * 0.024;
    var trunk = new T.Mesh(new T.CylinderGeometry(trunkR * 0.7, trunkR, trunkH, 8), trunkMat);
    trunk.position.y = trunkH / 2; g.add(trunk);
    var n = 3, cr = h * 0.22;
    for (var i = 0; i < n; i++) {
      var s = new T.Mesh(new T.SphereGeometry(cr * (1 - i * 0.18), 10, 8), i % 2 ? leafMat : leafDeepMat);
      s.position.set((R() - 0.5) * cr * 0.9, trunkH + cr * 0.75 + i * cr * 0.55, (R() - 0.5) * cr * 0.9);
      s.scale.y = 0.82; g.add(s);
    }
    g.position.set(x, ty, z);
    root.add(g); trees.push(g);
    foot.push([x, z, trunkR * 2.6, trunkR * 2.6, ty, ty + trunkH, 0]);
  }
  // scatter: ring r=130..300 around village center, plus groves between terraces
  var placed = 0, guard = 0;
  function clearOf(x, z) {
    // keep off terraces (r 60 + margin) and the road corridor
    for (var i = 0; i < TER.length; i++) {
      if (Math.hypot(x - TER[i].x, z - TER[i].z) < TER[i].r + 14) return false;
    }
    return true;
  }
  while (placed < 96 && guard++ < 900) {
    var a = R() * Math.PI * 2, rr = 130 + R() * 170;
    var tx = Math.cos(a) * rr, tz = Math.sin(a) * rr;
    if (!clearOf(tx, tz)) continue;
    // the Bore's corridor: keep the tunnel's perfect line clear (bore tie-in, 2026-10-11)
    // nudges consume no RNG — the forest is otherwise exactly as the King saw it
    if (Math.abs(tx) < 18 && 