<!-- SOLID CITY · part 2048 -->
 lx - hx, x1: POS.x + lx + hx, z0: POS.z + lz - hz, z1: POS.z + lz + hz, y0: M.gy + y0, y1: M.gy + y1, foundry: 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 === 'foundry'; })) return;
  H.pois.push({ id: 'foundry', name: 'The Foundry', short: 'FOUNDRY', x: POS.x, z: POS.z, stand: { x: POS.x + 56, z: POS.z },
    alias: 'foundry forge making ships crucible molten',
    text: 'The Foundry, west of the city: where ships and structures are born. Twelve pillars, eight molten channels, the crucible at the center \u2014 and it hums.' });
  if (H.regrid) H.regrid();
}
function watchStop() {
  var W = window.CityWatch, r = W && W.routes && W.routes.grand; if (!r || r._foundry) return;
  var orig = r.build; r._foundry = true;
  r.build = function () {
    var w = orig.apply(this, arguments);
    w.push({ x: POS.x + 110, z: POS.z - 40, y: M.gy + 120, v: 170, cap: { cap: 'THE FOUNDRY', sub: 'Where the city\u2019s ships are born \u00b7 west of the city', say: 'The Foundry: crucible, molten channels, ship-frames on trestles. It hums.' }, agl: false });
    return w;
  };
}
function load() {
  M.state = 'loading';
  M.gy = sampleGround();
  var p; try { p = import('/city/foundry.js?v=20261011d'); } catch (e) { p = Promise.reject(e); }
  p.then(function (mod) {
    var make = mod.createFoundry || mod.default;
    var g = make({ THREE: A.T, position: { x: POS.x, y: M.gy, z: POS.z } });
    A.world.add(g); M.group = g; M.state = 'ready';
    collide(g.userData || {}); hyperStop(); watchStop();
  }).catch(function (e) { M.state = 'failed'; try { console.warn('[city] Foundry skipped:', e && e.message); } catch (x) {} });
}
function update(dt) {
  if (M.state === 'idle') { if (A.isBuilt && !A.isBuilt()) return; M.wait -= dt; if (M.wait <= 0) load(); return; }
  if (M.state !== 'ready' || document.hidden) return;
  var c = A.camera.position, d = Math.hypot(c.x + A.origin.x - POS.x, c.z + A.origin.z - POS.z);
  M.group.visible = d < 6000;
  if (d < 1500 && M.group.userData.update) try { M.group.userData.update(S.t, dt); } catch (e) {}
  if (S.mode === 'walk') {
    var pd = Math.hypot(S.p.x - POS.x, S.p.z - POS.z);
    if (pd < 60 && !M.said) { M.said = true; if (window.CityHyper && CityHyper.narrate) CityHyper.narrate('<b>The Foundry</b>: where the city\u2019s ships are born. Mind the channels \u2014 listen for the hum.', 9); }
    else if (pd > 200) M.said = false;
  }
}
function radar(g, blip, fl) { if (M.state === 'ready') blip(POS.x, POS.z, '#ff7a2a', fl ? 3 : 5, fl ? '' : 'FOUNDRY'); }
window.CityFoundry = { update: update, radar: radar, pos: POS, state: function () { return M.state; } };
})();


===== FILE: public/city/foundry.js =====
/* SOLID CITY — THE FOUNDRY (2026-10-11, Royal Decree city expansion)
 * Where the city's ships and structures are born. Industrial-sacred.
 * Twelve basalt pillars in dodecagonal ring; eight molten channels radiate from
 * the central crucible in 8-fold symmetry; chains hang from the ring beam;
 * three ship-frames rise on trestles, unfinished; embers climb forever.
 * It hums: the crucible light breathes at 0.9 rad/s, the channels flow.
 * True name: THE FOUNDRY. Seam: THE YARD EDGE.
 * Self-contained ES module. Local frame: +X = east (the city side).
 */
function textPlate(T, text) {
  var c = document.createElement('canvas'); c.width = 512; c.height = 128;
  var g = c.getContext('2d');
  g.fillStyle = '#17141a'; g.fillRect(0, 0, 512, 128);
  g.strokeStyle = '#8a6a30'; g.lineWidth = 4; g.strokeRect(8, 8, 496, 112);
  g.fillStyle = '#d8c690'; g.textAlign = 'center'; g.textBaseline = 'middle';
  g.font = 'bold 44px Georgia, serif'; g.fillText(text, 256, 66);
  var t = new T.CanvasTexture(c); t.encoding = T.sRGBEncoding; t.anisotropy = 4; return t;
}
function quietMarker(T, text) {
  var grp = new T.Group();
  var stone = new T.Mesh(new T.BoxGeometry(3.4, 0.5, 1.7),
    new T.MeshLambertMaterial({ color: 0x1e1b22 }));
  stone.position.y = 0.55; stone.rotation.x = -0.5; grp.add(stone);
  /* THE BATTENING (2026-10-14): the face was 3.1 x 0.78 at
   * (0, 0.72, 0.42) — measured inside the stone (0.45 along the
   * face normal vs the stone's 0.85 front): the middle of the
   * name was entombed. Now a fitted plaque in the plate's own
   * aspect, PROUD of the front face (0.87; sampler-verified
   * 0 of 7 points inside the stone). */
  var face = new T.Mesh(new T.PlaneGeometry(1.92, 0.48),
    new T.MeshBasicMaterial({ map: textPlate(T, text), transparent: false }));
  face.position.set(0, 0.984, 0.754); face.rotation.x = -0.5; grp.add(face);
  var base = new T.Mesh(new T.BoxGeometry(3.6, 0.25, 1.9),
    new T.MeshLambertMaterial({ color: 0x141218 }));
  base.position.y = 0.12; grp.add(base);
  return grp;
}
export function createFoundry(o) {
  var T = o.TH