<!-- SOLID CITY · part 1797 -->
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); } 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>Meridian\u2019s Compass</b>: a star-chart plaza in naval blue and gold, with a bearing stone at its heart. Discipline under pressure.', 8); }
    else if (pd > 150) M.said = false;
  }
}
function radar(g, blip, fl) { if (M.state === 'ready') blip(POS.x, POS.z, '#2a6a9a', fl ? 3 : 5, fl ? '' : 'COMPASS'); }
window.CityCompassMeridian = { update: update, radar: radar, pos: POS, state: function () { return M.state; }, group: function () { return M.group; } };
})();


===== FILE: public/city/compass-meridian.js =====
/* SOLID CITY — MERIDIAN'S COMPASS (2026-10-11, Builder B)
 * Star-chart plaza NE of the Ancestral Roads. Circular walkable stone dais,
 * 8-point compass-rose inlay (deep blue + gold on dark), central bearing
 * obelisk (~8m). Meridian's discipline: blue naval grids.
 * Local frame: ground at y = 0. Self-contained ES module.
 *
 *   import { createCompassMeridian } from '/city/compass-meridian.js';
 *   const g = createCompassMeridian({ THREE, position: {x, y, z} });
 *   // g.userData: footprint, update(t)
 */
export function createCompassMeridian(o) {
  var T = o.THREE, P = o.position || { x: 0, y: 0, z: 0 };
  var root = new T.Group(); root.name = 'compass-meridian'; root.position.set(P.x, P.y, P.z);
  var foot = [];
  var C = { gold: 0xd8aa48, blue: 0x2a6a9a, basalt: 0x141114, stone: 0x1e1a20 };

  // Dais: thin walkable stone disc — no blocker footprint
  var dais = new T.Mesh(new T.CylinderGeometry(15, 15.5, 0.15, 56), new T.MeshLambertMaterial({ color: C.stone }));
  dais.position.y = 0.075; root.add(dais);
  var rim = new T.Mesh(new T.TorusGeometry(15, 0.14, 4, 72), new T.MeshBasicMaterial({ color: C.gold }));
  rim.rotation.x = Math.PI / 2; rim.position.y = 0.16; root.add(rim);

  // Compass rose: canvas inlay, 8-point rose in blue and gold, naval grid rings
  var roseTex = (function () {
    var c = document.createElement('canvas'); c.width = c.height = 512;
    var g = c.getContext('2d'), cx = 256, cy = 256, k, a;
    g.strokeStyle = 'rgba(42,106,154,0.4)'; g.lineWidth = 1.5;
    [60, 120, 180].forEach(function (r) { g.beginPath(); g.arc(cx, cy, r, 0, Math.PI * 2); g.stroke(); });
    for (k = 0; k < 8; k++) {
      a = k * Math.PI / 4;
      g.beginPath(); g.moveTo(cx + Math.cos(a) * 30, cy + Math.sin(a) * 30);
      g.lineTo(cx + Math.cos(a) * 205, cy + Math.sin(a) * 205); g.stroke();
    }
    for (k = 0; k < 8; k++) {
      a = k * Math.PI / 4 - Math.PI / 2;
      var len = (k % 2 === 0) ? 220 : 158, half = (k % 2 === 0) ? 24 : 17;
      var tx = cx + Math.cos(a) * len, ty = cy + Math.sin(a) * len;
      var ox = Math.cos(a + Math.PI / 2) * half, oy = Math.sin(a + Math.PI / 2) * half;
      g.fillStyle = (k % 2 === 0) ? '#d8aa48' : '#2a6a9a';
      g.beginPath(); g.moveTo(tx, ty); g.lineTo(cx + ox, cy + oy); g.lineTo(cx - ox, cy - oy); g.closePath(); g.fill();
      g.fillStyle = 'rgba(20,17,20,0.45)';
      g.beginPath(); g.moveTo(tx, ty); g.lineTo(cx, cy); g.lineTo(cx - ox, cy - oy); g.closePath(); g.fill();
    }
    g.fillStyle = '#d8aa48'; g.beginPath(); g.arc(cx, cy, 20, 0, Math.PI * 2); g.fill();
    g.fillStyle = '#141114'; g.beginPath(); g.arc(cx, cy, 11, 0, Math.PI * 2); g.fill();
    g.fillStyle = '#d8aa48'; g.font = 'bold 30px Georgia, serif'; g.textAlign = 'center'; g.textBaseline = 'middle';
    var L = ['N', 'E', 'S', 'W'];
    for (k = 0; k < 4; k++) { a = k * Math.PI / 2 - Math.PI / 2; g.fillText(L[k], cx + Math.cos(a) * 240, cy + Math.sin(a) * 240); }
    var t = new T.CanvasTexture(c); t.anisotropy = 4; return t;
  })();
  var roseG = new T.Group(); roseG.rotation.y = Math.PI; root.add(roseG); // N points map-north (+Z)
  var rose = new T.Mesh(new T.PlaneGeometry(27, 27), new T.MeshBasicMaterial({ map: roseTex, transparent: true, depthWrite: false }));
  rose.rotation.x = -Math.PI / 2; rose.position.y = 0.17; roseG.add(rose);

  // Central bearing obelisk (~8m): basalt shaft, blue cap, slow bearing needle
  var plinth = new T.Mesh(new T.CylinderGeometry(2.4, 2.9, 0.5, 4), new T.MeshLambertMaterial({ color: C.basalt }));
  plinth.rotation.y = Math.PI / 4; plinth.position.y = 0.25; root.add(plinth);
  var shaft = new T.Mesh(new T.CylinderGeometry(0.85, 1.35, 8, 4), new T.MeshLambertMaterial({ color: C.stone }));
  shaft.rotation.y = Math.PI / 4; shaft.position.y = 4.5; root.add(shaft);
  var collar = new T.Mesh(new T.TorusGeometry(1.55, 0.07, 6, 48), new T.MeshBasicMaterial({ color: C.blue }));
  collar.rotation.x = Math.PI / 2; collar.position.y = 1.1; root.add(collar);
  var cap = new T.Mesh(new T.ConeGeometry(0.85, 1.1, 4), new T.MeshBasicMaterial({ color: C.blue }));
  cap.rotation.y = Math