<!-- SOLID CITY · part 3094 -->
e.add = function (geo, x, y, z, rx, ry, rz) {
  const T = this.T, g = geo.index ? geo.toNonIndexed() : geo;
  g.applyMatrix4(new T.Matrix4().compose(new T.Vector3(x || 0, y || 0, z || 0), new T.Quaternion().setFromEuler(new T.Euler(rx || 0, ry || 0, rz || 0)), new T.Vector3(1, 1, 1)));
  if (!g.attributes.uv) g.setAttribute('uv', new T.BufferAttribute(new Float32Array(g.attributes.position.count * 2), 2));
  this.parts.push(g); return this;
};
Merger.prototype.build = function () {
  const T = this.T; let n = 0; this.parts.forEach(function (p) { n += p.attributes.position.count; });
  const pos = new Float32Array(n * 3), nor = new Float32Array(n * 3), uv = new Float32Array(n * 2); let o = 0;
  this.parts.forEach(function (p) { const c = p.attributes.position.count; pos.set(p.attributes.position.array, o * 3); nor.set(p.attributes.normal.array, o * 3); uv.set(p.attributes.uv.array, o * 2); o += c; p.dispose(); });
  const g = new T.BufferGeometry();
  g.setAttribute('position', new T.BufferAttribute(pos, 3)); g.setAttribute('normal', new T.BufferAttribute(nor, 3)); g.setAttribute('uv', new T.BufferAttribute(uv, 2));
  g.computeBoundingSphere(); return g;
};

export function createProvoltaSanctuary(o) {
  const T = o.THREE, P = o.position || { x: 0, y: 0, z: 0 };
  const root = new T.Group(); root.name = 'provolta-sanctuary'; root.position.set(P.x, P.y, P.z);
  const foot = [];                                   // solid boxes, local: [cx, cz, w, d, y0, y1, rotY]
  const basalt = new Merger(T), stone = new Merger(T), crystal = new Merger(T), gold = new Merger(T), red = new Merger(T);

  // floor: a teal-stone dais (thin, walk-on) with a basalt rim of low curb stones
  stone.add(new T.CylinderGeometry(24, 24.4, 0.16, 48, 1), 0, 0.08, 0);
  stone.add(new T.CylinderGeometry(4.6, 4.6, 0.14, 32, 1), 0, 0.23, 0);                        // the oracle's step (centre)
  for (let i = 0; i < 24; i++) { const a = i / 24 * Math.PI * 2; if (Math.abs(Math.cos(a) + 1) < 0.08) continue;   // opening at the gate (west)
    basalt.add(new T.BoxGeometry(5.6, 0.45, 0.9), Math.cos(a) * 24.2, 0.22, Math.sin(a) * 24.2, 0, -a + Math.PI / 2, 0); }
  // gold inlay rings on the floor (thin, minor accent)
  gold.add(new T.TorusGeometry(4.8, 0.14, 4, 48), 0, 0.2, 0, Math.PI / 2, 0, 0);
  gold.add(new T.TorusGeometry(12.6, 0.14, 4, 64), 0, 0.18, 0, Math.PI / 2, 0, 0);

  // ring of 12 teal crystal pillars (hex prisms + tips) on basalt plinths with a red glyph gem
  const R = 16, H = [11.5, 10, 12.5, 9.5, 12, 10.5, 11, 9.8, 12.8, 10.2, 11.6, 10.8];
  for (let i = 0; i < 12; i++) {
    const a = (i + 0.5) / 12 * Math.PI * 2, x = Math.cos(a) * R, z = Math.sin(a) * R, h = H[i];
    basalt.add(new T.BoxGeometry(2.6, 1.0, 2.6), x, 0.5, z, 0, -a, 0);
    crystal.add(new T.CylinderGeometry(0.75, 0.95, h, 6, 1), x, 1.0 + h / 2, z, 0, a, 0);
    crystal.add(new T.ConeGeometry(0.75, 2.6, 6, 1), x, 1.0 + h + 1.3, z, 0, a, 0);
    red.add(new T.OctahedronGeometry(0.32, 0), x - Math.cos(a) * 1.35, 0.62, z - Math.sin(a) * 1.35);
    foot.push([x, z, 2.6, 2.6, 0, 1.0 + h + 2.6, 0]);
  }
  // the gold halo floating over the ring
  gold.add(new T.TorusGeometry(R, 0.28, 6, 72), 0, 13.2, 0, Math.PI / 2, 0, 0);

  // light pool: a ring of glowing water around the centre, four walkways (N, E, S, W)
  const poolTex = canvasTex(T, 256, 64, function (g, W, Hh) {
    const gr = g.createLinearGradient(0, 0, 0, Hh); gr.addColorStop(0, '#0a6f74'); gr.addColorStop(0.5, '#3de0e8'); gr.addColorStop(1, '#0a6f74');
    g.fillStyle = gr; g.fillRect(0, 0, W, Hh); g.strokeStyle = 'rgba(220,255,255,.55)'; g.lineWidth = 2;
    for (let k = 0; k < 9; k++) { g.beginPath(); for (let x = 0; x <= W; x += 8) g.lineTo(x, 8 + k * 6 + Math.sin(x / 18 + k) * 3); g.stroke(); }
  });
  poolTex.wrapS = poolTex.wrapT = T.RepeatWrapping; poolTex.repeat.set(4, 1);
  const pool = new Merger(T), gap = 0.2;
  for (let q = 0; q < 4; q++) pool.add(new T.RingGeometry(5.2, 9.2, 20, 1, q * Math.PI / 2 + gap, Math.PI / 2 - gap * 2), 0, 0.2, 0, -Math.PI / 2, 0, 0);
  basalt.add(new T.TorusGeometry(9.3, 0.22, 4, 64), 0, 0.2, 0, Math.PI / 2, 0, 0);            // basalt lip

  // the gate (west, facing the city): two tall crystals + gold lintel + the name plate
  [-4.2, 4.2].forEach(function (z) {
    basalt.add(new T.BoxGeometry(2.8, 1.2, 2.8), -24, 0.6, z);
    crystal.add(new T.CylinderGeometry(0.85, 1.05, 13, 6, 1), -24, 7.7, z);
    crystal.add(new T.ConeGeometry(0.85, 2.8, 6, 1), -24, 15.6, z);
    foot.push([-24, z, 2.8, 2.8, 0, 17, 0]);
  });
  gold.add(new T.BoxGeometry(1.4, 0.9, 11.6), -24, 13.4, 0);
  const signTex = canvasTex(T, 1024, 192, function (g, W, Hh) {
    g.fillStyle = '#071c1d'; g.fillRect(0, 0, W, Hh); g.strokeStyle = '#c99a3a'; g.lineWidth = 10; g.strokeRect(8, 8, W - 16, Hh - 16);
    g.textAlign = 'center'; g.textBaseline = 'middle'; g.fillStyle = '#7ff4f8'; g.font = '700 84px Georgia, serif'; g.fillText('PROVOLTA', W / 2, 78);
    g.fillStyle = '#