<!-- SOLID CITY · part 2057 -->
, 0.25, 1.9),
    new T.MeshLambertMaterial({ color: 0x141218 }));
  base.position.y = 0.12; grp.add(base);
  return grp;
}
export function createEighthGate(o) {
  var T = o.THREE, P = o.position || { x: 0, y: 0, z: 0 };
  var root = new T.Group(); root.name = 'eighth-gate'; root.position.set(P.x, P.y, P.z);
  if (o.rotY) root.rotation.y = o.rotY;
  var foot = [];
  var basalt = new T.MeshLambertMaterial({ color: 0x1a181e });
  var gold = new T.MeshLambertMaterial({ color: 0xd8aa48, emissive: 0x2a1a04 });
  var goldGlow = new T.MeshBasicMaterial({ color: 0xffd880 });
  // ground inlay: octagonal ring, the eight claimed in stone
  var inlay = new T.Mesh(new T.RingGeometry(7.6, 9.0, 8),
    new T.MeshBasicMaterial({ color: 0xd8aa48, transparent: true, opacity: 0.55, side: T.DoubleSide }));
  inlay.rotation.x = -Math.PI / 2; inlay.rotation.z = Math.PI / 8; inlay.position.y = 0.06; root.add(inlay);
  // posts
  [-1, 1].forEach(function (s) {
    var post = new T.Mesh(new T.BoxGeometry(1.6, 12, 1.6), basalt);
    post.position.set(5 * s, 6, 0); root.add(post);
    var footBlock = new T.Mesh(new T.BoxGeometry(2.6, 1.0, 2.6), basalt);
    footBlock.position.set(5 * s, 0.5, 0); root.add(footBlock);
    var cap = new T.Mesh(new T.OctahedronGeometry(0.9), gold);
    cap.position.set(5 * s, 12.7, 0); root.add(cap);
    foot.push([5 * s, 0, 2.6, 2.6, 0, 13.5, 0]);
  });
  // lintel
  var lintel = new T.Mesh(new T.BoxGeometry(12.6, 1.6, 2.0), gold);
  lintel.position.y = 12.9; root.add(lintel);
  // the octagonal ring: eight sides for the eighth gate
  var ring = new T.Mesh(new T.TorusGeometry(3.8, 0.28, 8, 8), goldGlow);
  ring.position.y = 6.4; ring.rotation.z = Math.PI / 8; root.add(ring);
  var disc = new T.Mesh(new T.CircleGeometry(3.55, 8),
    new T.MeshBasicMaterial({ color: 0xffd880, transparent: true, opacity: 0.16, side: T.DoubleSide, depthWrite: false }));
  disc.position.y = 6.4; disc.rotation.z = Math.PI / 8; root.add(disc); disc.name = 'gate-disc';
  var halo = new T.PointLight(0xffd880, 0.9, 30); halo.position.set(0, 6.4, 0); root.add(halo);
  // true name + seam name: quiet markers, nothing more
  var nameMark = quietMarker(T, 'THE EIGHTH GATE');
  nameMark.position.set(8.2, 0, 2.5); nameMark.rotation.y = -0.5; root.add(nameMark);
  var seamMark = quietMarker(T, 'WHERE THE SEVEN END');
  seamMark.position.set(0, 0, 12.5); root.add(seamMark);
  var pulse = 0;
  root.userData = {
    footprint: foot, center: { x: 0, z: 0 }, radius: 16, height: 16,
    update: function (t, S) {
      disc.material.opacity = 0.13 + 0.07 * Math.sin(t * 2.2);
      ring.rotation.z = Math.PI / 8 + Math.sin(t * 0.4) * 0.02;
      if (pulse > 0) {
        pulse -= 0.03;
        disc.material.opacity = 0.13 + pulse * 0.9;
        halo.intensity = 0.9 + pulse * 6;
      } else { halo.intensity = 0.9; }
      // passing through the disc: the gate answers with light
      if (S && S.mode === 'walk' && S.p && !this._cool) {
        var dx = S.p.x - P.x, dz = S.p.z - P.z;
        // gate-local frame: +Z is the facing direction (sin/cos of rotY)
        var ry = o.rotY || 0, fx = Math.sin(ry), fz = Math.cos(ry);
        var lz = dx * fx + dz * fz;        // along facing
        var lx = dx * fz - dz * fx;        // lateral
        if (Math.abs(lx) < 2.6 && Math.abs(lz) < 1.6) {
          this._cool = 8; pulse = 1;
        }
      }
      if (this._cool > 0) this._cool -= 0.016;
    }
  };
  return root;
}
export default createEighthGate;


===== FILE: public/city/hall-becoming-place.js =====
/* Solid City — places THE HALL OF BECOMING (public/city/hall-becoming.js) east of the city.
   Six Fibonacci chambers on a golden spiral; you walk inward and matter refines.
   Lazy: imported after the city is built; any import/build error is caught and the city carries on.
   The placer adapts to terrain at runtime (grid sample, take max).
   Adds: collision (userData.footprint), a radar marker 'HALL', 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;
var POS = { x: 1000, z: -350 };
var M = { state: 'idle', group: null, wait: 5.0, gy: 20, said: false };
function sampleGround() {
  var g = (typeof groundAt === 'function') ? groundAt : null;
  if (!g) return 20;
  var max = -1000, h, ix, iz;
  for (ix = -2; ix <= 2; ix++) for (iz = -2; iz <= 2; iz++) {
    try { h = g(POS.x + ix * 26, POS.z + iz * 26); } catch (e) { h = 20; }
    if (h > max) max = h;
  }
  return max + 0.4;
}
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 +