<!-- SOLID CITY · part 2054 -->
2.6, 1.6);
  var beamCapGeo = new T.BoxGeometry(20.2, 0.7, 2.2);
  [1.9, -1.9].forEach(function (pz) {
    var beam = new T.Mesh(beamGeo, goldMat); beam.position.set(0, 22.5, pz); root.add(beam);
    var bcap = new T.Mesh(beamCapGeo, basaltMat); bcap.position.set(0, 24.1, pz); root.add(bcap);
  });
  // Gold trim line glowing under the beams
  var trim = new T.Mesh(new T.BoxGeometry(19.4, 0.25, 4.4), glowGoldMat); trim.position.set(0, 21.05, 0); root.add(trim);

  // Twin gold braziers atop the pillars, flames rising between the beams
  var flames = [];
  [-7, 7].forEach(function (px, k) {
    var bowl = new T.Mesh(new T.CylinderGeometry(1.3, 0.8, 0.9, 16), goldMat);
    bowl.position.set(px, 22.0, 0); root.add(bowl);
    var rim = new T.Mesh(new T.TorusGeometry(1.3, 0.12, 6, 24), glowGoldMat);
    rim.rotation.x = Math.PI / 2; rim.position.set(px, 22.45, 0); root.add(rim);
    var flame = new T.Mesh(new T.ConeGeometry(0.85, 2.8, 12), flameMat);
    flame.position.set(px, 23.9, 0); flame.userData.phase = k * 2.1; root.add(flame); flames.push(flame);
    var core = new T.Mesh(new T.ConeGeometry(0.4, 1.6, 10), flameCoreMat);
    core.position.set(px, 23.3, 0); core.userData.phase = k * 2.1 + 0.7; root.add(core); flames.push(core);
  });
  // ONE warm light for the whole gate
  var light = new T.PointLight(0xff9a30, 1.2, 70, 1.6); light.position.set(0, 24, 0); root.add(light);

  // Name plate — dark basalt, gold border, Georgia serif — on both faces
  function plateTexture(text) {
    var c = document.createElement('canvas'); c.width = 1024; c.height = 128;
    var g = c.getContext('2d');
    g.fillStyle = '#141114'; g.fillRect(0, 0, 1024, 128);
    g.strokeStyle = '#d8aa48'; g.lineWidth = 6; g.strokeRect(6, 6, 1012, 116);
    g.fillStyle = '#d8aa48'; g.textAlign = 'center'; g.textBaseline = 'middle';
    var fs = 56; g.font = 'bold ' + fs + 'px Georgia, serif';
    while (g.measureText(text).width > 940 && fs > 20) { fs -= 2; g.font = 'bold ' + fs + 'px Georgia, serif'; }
    g.fillText(text, 512, 66);
    var t = new T.CanvasTexture(c); t.encoding = T.sRGBEncoding; t.anisotropy = 4; return t;
  }
  var plateMat = new T.MeshBasicMaterial({ map: plateTexture('GATE OF THE ANCESTORS') });
  var plateGeo = new T.PlaneGeometry(16, 2);
  var plateN = new T.Mesh(plateGeo, plateMat); plateN.position.set(0, 22.5, 2.75); root.add(plateN);
  var plateS = new T.Mesh(plateGeo, plateMat); plateS.position.set(0, 22.5, -2.75); plateS.rotation.y = Math.PI; root.add(plateS);

  root.userData = {
    footprint: foot, center: { x: 0, z: 0 }, radius: 14, height: 26,
    update: function (t) {
      for (var i = 0; i < flames.length; i++) {
        var f = flames[i], ph = f.userData.phase;
        f.scale.set(1 + Math.sin(t * 7 + ph) * 0.12, 1 + Math.sin(t * 9 + ph) * 0.18, 1 + Math.cos(t * 8 + ph) * 0.12);
      }
      light.intensity = 1.2 + Math.sin(t * 11) * 0.22;
    }
  };
  return root;
}
export default createGateAncestors;


===== FILE: public/city/gate-eighth-place.js =====
/* Solid City — places THE EIGHTH GATE (public/city/gate-eighth.js) southwest of the hangar hub.
   The seven game-gates ring the hub in seven directions; the eighth direction stood open.
   Lazy: imported after the city is built; any import/build error is caught and the city carries on.
   Adds: collision (userData.footprint), a radar marker 'VIII', a Hyper Controller stop,
   and a Watch (GRAND TOUR) caption. */
(function () {
'use strict';
if (!window.SC || !SC.api) return;
var A = SC.api, S = A.S, Y0 = A.CITY_Y;
var POS = { x: -584, z: 294 };
var HUB = { x: -540, z: 250 };
var ROTY = Math.atan2(HUB.x - POS.x, HUB.z - POS.z); // face the hub
var M = { state: 'idle', group: null, wait: 4.0, said: false };
function addBox(cx, cz, w, d, rot, y0, y1) {
  var nx = Math.max(1, Math.ceil(w / 2.5)), nz = Math.max(1, Math.ceil(d / 2.5)), cw = w / nx, cd = d / nz, c = Math.cos(rot), s = Math.sin(rot);
  var hx = cw / 2 * Math.abs(c) + cd / 2 * Math.abs(s), hz = cw / 2 * Math.abs(s) + cd / 2 * Math.abs(c);
  for (var i = 0; i < nx; i++) for (var j = 0; j < nz; j++) {
    var ox = -w / 2 + cw * (i + 0.5), oz = -d / 2 + cd * (j + 0.5), lx = cx + ox * c + oz * s, lz = cz - ox * s + oz * c;
    A.solids.push({ x0: POS.x + lx - hx, x1: POS.x + lx + hx, z0: POS.z + lz - hz, z1: POS.z + lz + hz, y0: Y0 + y0, y1: Y0 + y1, eighthGate: true });
  }
}
function collide(ud) { (ud.footprint || []).forEach(function (b) { addBox(b[0], b[1], b[2], b[3], b[6] || 0, b[4], b[5]); }); }
function hyperStop() {
  var H = window.CityHyper; if (!H || !H.pois || H.pois.some(function (p) { return p.id === 'eighth-gate'; })) return;
  H.pois.push({ id: 'eighth-gate', name: 'The Eighth Gate', short: 'VIII', x: POS.x, z: POS.z, stand: { x: POS.x + 20, z: POS.z - 20 },
    alias: 'eighth gate 8th viii southwest hangar',
    text: 'The eighth gate, southwest of the hangar: seven gates ring the hub in seven directions, and this one closes the ring. Gold, not