<!-- SOLID CITY · part 3606 -->
bled: false, curveSegments: 40 });
    geo.translate(0, 0, -0.7 * scale);
    return new T.Mesh(geo, stoneMat);
  }
  var i, z;
  for (i = 0; i < 21; i++) {
    z = -(i + 0.5) * (BORE_LEN / 21);
    var arch = archRing(1);
    arch.position.set(0, 6 * PHI, z);
    root.add(arch);
    // gold keystone at the visible crown
    var key = new T.Mesh(new T.BoxGeometry(1.1, 1.6, 1.7), goldBasic);
    key.position.set(0, 6 * PHI + 6 * PHI + 0.5, z);
    root.add(key);
  }

  // ---------- Fibonacci light bands ----------
  var bands = fibBands(), bandLights = [];
  bands.forEach(function (d, bi) {
    var bz = -d, last = bi === bands.length - 1;
    var bw = last ? 1.4 : 0.55, bh = last ? 0.35 : 0.18;
    // ceiling strip (just under the ceiling) + wall strips (proud of the walls)
    var cs = new T.Mesh(new T.BoxGeometry(BORE_W + 1.6, bh, bw), last ? goldGlow : goldBasic);
    cs.position.set(0, WALL_H - 0.9, bz); root.add(cs);
    [-1, 1].forEach(function (s) {
      var ws = new T.Mesh(new T.BoxGeometry(bh, WALL_H - 2, bw), last ? goldGlow : goldBasic);
      ws.position.set(s * (BORE_W / 2 - 0.1), (WALL_H - 2) / 2, bz); root.add(ws);
    });
    if (bi % 2 === 0 || last) {
      var pl = new T.PointLight(0xffd9a0, last ? 2.2 : 1.15, last ? 120 : 55);
      pl.position.set(0, 13, bz); root.add(pl); bandLights.push(pl);
    }
  });
  // the promise: a point of light at the far end, visible from the mouth
  var promise = new T.Mesh(new T.SphereGeometry(1.6, 12, 10), new T.MeshBasicMaterial({ color: 0xfff4d6 }));
  promise.position.set(0, 10, -BORE_LEN + 4); root.add(promise);
  var promiseGlow = new T.PointLight(0xfff0d0, 2.0, 90);
  promiseGlow.position.set(0, 10, -BORE_LEN + 6); root.add(promiseGlow);

  // ---------- THE MOUTH: grand portal + mountain teeth + its true name ----------
  var mouth = archRing(1.45);
  mouth.position.set(0, 6 * PHI * 1.45, 1.2); root.add(mouth);
  var mkey = new T.Mesh(new T.BoxGeometry(1.6, 2.2, 2.2), goldBasic);
  mkey.position.set(0, 6 * PHI * 1.45 + 7.5 * PHI * 1.45 - 0.5, 1.2); root.add(mkey);
  [-1, 1].forEach(function (s) {
    var py = new T.Mesh(new T.BoxGeometry(4, 26, 4), basaltMat);
    py.position.set(s * 13.5, 11, 2); root.add(py);
    foot.push([s * 13.5, 2, 4, 4, 0, 24, 0]);
    var cap = new T.Mesh(new T.BoxGeometry(5, 1.2, 5), stoneMat);
    cap.position.set(s * 13.5, 24.5, 2); root.add(cap);
  });
  // mountain teeth around the mouth: the bore begins inside the mountain
  for (i = 0; i < 9; i++) {
    var a = (i / 9) * Math.PI * 2, rr = 22 + R() * 10;
    if (Math.abs(a - Math.PI / 2) < 0.5) continue; // keep the approach open
    var h = 20 + R() * 22;
    var tooth = new T.Mesh(new T.ConeGeometry(6 + R() * 5, h, 7), basaltMat);
    tooth.position.set(Math.cos(a) * rr, h / 2 - 3, 4 + Math.sin(a) * rr * 0.7);
    tooth.rotation.y = R() * 3; root.add(tooth);
    foot.push([Math.cos(a) * rr, 4 + Math.sin(a) * rr * 0.7, 9, 9, 0, h - 4, 0]);
  }
  // rock spine along the exposed upper tube
  for (i = 0; i < 14; i++) {
    var sz2 = -25 - i * 28 - R() * 14, sx = (R() < 0.5 ? -1 : 1) * (9 + R() * 6);
    var rh = 12 + R() * 20;
    var spine = new T.Mesh(new T.ConeGeometry(5 + R() * 4, rh, 6), basaltMat);
    spine.position.set(sx, WALL_H + rh / 2 - 4, sz2); root.add(spine);
  }
  // its true name, set in stone — one quiet marker
  var mouthPlaque = namePlaque(T, 'THE MOUTH', 7, stoneMat);
  mouthPlaque.position.set(17.5, 3.2, 6); mouthPlaque.rotation.y = -0.5; root.add(mouthPlaque);
  foot.push([17.5, 6, 2, 2, 0, 5, 0]);

  // ---------- the road flows in: connector path from the village switchback ----------
  // village road ends at tunnel-local (-36, 35); the path curves to the mouth (0, 2)
  var roadC0 = new T.Color(0x4a3f30), roadC1 = new T.Color(0x1e1c22), tmpC = new T.Color();
  var pts = [[-36, 35], [-26, 27], [-15, 18], [-6, 9], [0, 2.5]];
  for (i = 0; i < pts.length - 1; i++) {
    var p0 = pts[i], p1 = pts[i + 1];
    var len = Math.hypot(p1[0] - p0[0], p1[1] - p0[1]);
    tmpC.copy(roadC0).lerp(roadC1, (i + 1) / (pts.length - 1)); // road-brown becoming bore-stone
    var seg = new T.Mesh(new T.BoxGeometry(len + 1.5, 0.55, 7.5),
      new T.MeshLambertMaterial({ color: tmpC.getHex() }));
    seg.position.set((p0[0] + p1[0]) / 2, -0.28, (p0[1] + p1[1]) / 2);
    seg.rotation.y = -Math.atan2(p1[1] - p0[1], p1[0] - p0[0]);
    root.add(seg);
  }
  // two small guide stones where the village road becomes the Bore
  [[-33, 32], [-3, 5.5]].forEach(function (gp, gi) {
    var gs = new T.Mesh(new T.BoxGeometry(1.1, 2.6, 1.1), stoneMat);
    gs.position.set(gp[0] + (gi ? 4.4 : -4.4), 1.3, gp[1]); root.add(gs);
    var gt = new T.Mesh(new T.BoxGeometry(1.3, 0.35, 1.3), goldBasic);
    gt.position.set(gp[0] + (gi ? 4.4 : -4.4), 2.75, gp[1]); root.add(gt);
  });

  var flames = [];
  root.userData = {
    footprint: foot, walls: walls, center: { x: 0, z: -BORE_LEN / 2 }, radius: BORE_LEN / 2 + 40,
    length: BORE_LEN,
    update: fu