<!-- SOLID CITY · part 3157 -->
() * 0.6, false);
    }
    for (var lz = 1425; lz <= 1530; lz += 35) { lamp(GAL.x - 8.2, galleryFloorY(lz), lz, 0.85); lamp(GAL.x + 8.2, galleryFloorY(lz), lz, 0.85); }
  })();
  function shop(x, z, ry, title) {
    var F = H(x, z);
    var g2 = new T.Group(); g2.position.set(x, F, z); g2.rotation.y = ry; group.add(g2);
    function LB(w, h, d, lx, ly, lz, mat) { var m = new T.Mesh(new T.BoxGeometry(w, h, d), mat); m.position.set(lx, ly, lz); m.frustumCulled = false; g2.add(m); return m; }
    var stoneM = new T.MeshLambertMaterial({ color: C.stone }), darkM = new T.MeshLambertMaterial({ color: C.stoneDark });
    LB(7.4, 3.6, 0.8, 0, 1.8, -1.5, stoneM);
    LB(7.4, 1.1, 1.1, 0, 0.55, 0.6, darkM);
    LB(8.2, 0.3, 4.6, 0, 3.85, -0.2, darkM);
    [-3.8, 3.8].forEach(function (lx) { LB(0.3, 3.9, 0.3, lx, 1.95, 1.6, stoneM); });
    for (var vi = 0; vi < 6; vi++) {
      var v = new T.Mesh(new T.BoxGeometry(0.5, 0.8, 0.5), new T.MeshBasicMaterial({ color: vi % 2 ? C.vialG : C.vialR }));
      v.position.set(-2.7 + vi * 1.08, 2.5, -1.45); v.frustumCulled = false; g2.add(v);
      var v2 = new T.Mesh(new T.BoxGeometry(0.42, 0.65, 0.42), new T.MeshBasicMaterial({ color: vi % 2 ? C.lamp : C.win }));
      v2.position.set(-2.7 + vi * 1.08, 1.35, -1.45); v2.frustumCulled = false; g2.add(v2);
    }
    sign(x + Math.sin(ry) * 0, F + 5.6, z, ry, 7.6, 1.5, [title, 'HEALTH · SAFETY · PROVISIONS'], 92, 0);
    footprints.push({ x: x, z: z, w: 8.4, d: 4.6, a: ry, y0: F, y1: F + 4 });
  }
  shop(2586, 1404, Math.PI, 'REPLENISHMENTS');
  shop(2614, 1536, 0, 'REPLENISHMENTS');
  (function midway() {
    var z = 1470, F = galleryFloorY(z);
    marbleDisc(GAL.x, F, z, 13.5, marbleRed, 2);
    var geo = new T.CylinderGeometry(13.5, 13.5, 17, opts.texTier === 'lo' ? 14 : 22, 2, true, Math.PI / 2, Math.PI); geo.rotateX(Math.PI / 2);
    if (HEIGHT) displace(geo, 3, 1, 0.5);
    var sh = new T.Mesh(geo, lavaTex ? lavaMat(3, 1, T.DoubleSide) : new T.MeshLambertMaterial({ color: C.basalt, side: T.DoubleSide }));
    sh.position.set(GAL.x, F + 1.1, z); sh.frustumCulled = false; group.add(sh);
    formation(GAL.x - 6, F + 13.4, z - 3, 1.2, true); formation(GAL.x + 7, F + 13.4, z + 4, 1.1, true);
    formation(GAL.x - 11.5, F, z + 6, 1.1, false); formation(GAL.x + 11.8, F, z - 5, 1.2, false);
    shop(2590.5, z, Math.PI / 2, 'THE MIDWAY SHOP');
    lamp(GAL.x + 10.5, F, z - 8, 1); lamp(GAL.x + 10.5, F, z + 8, 1);
  })();
  /* city name signs at the gallery mouths — read both ways */
  sign(2613, A_C.f + 4.6, 1410, Math.PI * 0.94, 8.6, 1.6, ['THE SERVITUDE', 'THE FIRST HOLLOW'], 96, 4.6);
  sign(2587, B_C.f + 4.6, 1530, Math.PI * 0.06, 8.6, 1.6, ['THE SERVITUDE', 'THE DEEP HOLLOW'], 96, 4.6);

  /* ================= THE ENTREE =================
   * The gate in the First Hollow's south-western face: two
   * towers, a lintel, and the name of the place lettered
   * PROUD over the way in — with a lamp-lit shelf running
   * out to the brow of the mountain. */
  (function buildGate() {
    var u = { x: -0.7071, z: 0.7071 }, perp = { x: 0.7071, z: 0.7071 };
    var G = { x: A_C.x + u.x * 150, z: A_C.z + u.z * 150 }, F = A_C.f;
    var ry = Math.atan2(u.x, u.z);
    [-9.5, 9.5].forEach(function (off) {
      var tx = G.x + perp.x * off, tz = G.z + perp.z * off;
      box(solid, 3.4, 17, 3.4, mat4(tx, F + 8.5, tz, 0, ry, 0), C.stone);
      box(solid, 4.4, 1, 4.4, mat4(tx, F + 17.4, tz, 0, ry, 0), C.stoneDark);
      sph(glow, 0.55, mat4(tx, F + 18.3, tz, 0, 0, 0), C.lamp);
      footprints.push({ x: tx, z: tz, w: 4, d: 4, a: ry, y0: F, y1: F + 17.9 });
    });
    box(solid, 22.5, 2.8, 3.8, mat4(G.x, F + 15.4, G.z, 0, ry, 0), C.stoneDark);
    box(glow, 22.5, 0.4, 0.5, mat4(G.x + u.x * 1.95, F + 13.85, G.z + u.z * 1.95, 0, ry, 0), C.gold);
    sign(G.x + u.x * 2.15, F + 15.4, G.z + u.z * 2.15, ry, 13, 2.1, ['THE SERVITUDE'], 120, 0);
    /* the shelf processional: gold edges + lamps to the brow */
    for (var s2 = 158; s2 <= 242; s2 += 21) {
      var px = A_C.x + u.x * s2, pz = A_C.z + u.z * s2, py = H(px, pz);
      [-13, 13].forEach(function (off) { box(glow, 0.5, 0.25, 19, mat4(px + perp.x * off, py + 0.2, pz + perp.z * off, 0, ry, 0), C.gold); });
      if ((s2 - 158) % 42 === 0) { lamp(px + perp.x * 11, py, pz + perp.z * 11, 1); lamp(px - perp.x * 11, py, pz - perp.z * 11, 1); }
    }
  })();

  group.add(solid.build(new T.MeshLambertMaterial({ vertexColors: true })));
  group.add(glow.build(new T.MeshBasicMaterial({ vertexColors: true })));
  if (glassB.n) group.add(glassB.build(new T.MeshLambertMaterial({ vertexColors: true, transparent: true, opacity: 0.6 })));
  group.userData = {
    footprints: footprints, layers: layers,
    centers: { a: A_C, b: B_C }, gallery: GAL,
    texTier: opts.texTier || null,
    molded: molded,
    counts: { footprints: footprints.length, layers: layers.length },
    update: function (dt, t) {
      t = t || 0;
      crystals.forEach(function (c, i) { c.rotation.y = 