<!-- SOLID CITY · part 3686 -->
inZ:-1265,maxZ:-510, anchor:[-917,-765]},
  {id:5, name:'Quiet Precision', band:'east', minX:-871.25,maxX:-800,minZ:-1265,maxZ:-510, anchor:[-848,-985]}, // anchor re-sited by Solid's survey: the drawn anchor stood on the high shoulder (14-17 m); this ground is verified shelf (7.9 m)
  {id:6, name:'South Connection', band:'south', minX:-1465,maxX:-1090,minZ:-615,maxZ:-457.5, anchor:[-1126,-578]}, // anchor re-sited by Solid's survey: the drawn anchor stood inside the South Lot; this ground is verified clear (8.9 m)
  {id:7, name:'Southern Landscape', band:'south', minX:-1465,maxX:-1090,minZ:-457.5,maxZ:-300, anchor:[-1190,-390]}
]);
const ROADS = {
  2:[[-1075,-900],[-1058,-878],[-1024,-844]],
  3:[[-1008,-839],[-980,-819],[-951,-789]],
  4:[[-936,-785],[-913,-761],[-880,-730]],
  5:[[-866,-1060],[-848,-985],[-822,-918]], // route re-surveyed by Solid: the drawn line climbed the high shoulder (14.2-17.1 m) and the land refused every stone; this line walks the ward's low northern shelf (5.8-10.2 m), band-verified clear
  6:[[-1136,-602],[-1126,-572],[-1118,-540]], // route re-surveyed by Solid: the drawn line ran through the South Lot and across the Long Road; this line is the true South Connection — from the podium's south-east shoulder down to the Long Road's north verge, band-verified clear
  7:[[-1215,-437],[-1190,-395],[-1160,-350]]
};
function ctx({THREE,groundAt,isAllowed},ward) {
  if(!THREE || typeof groundAt!=='function' || typeof isAllowed!=='function')
    throw Error('THREE, groundAt and verified isAllowed(x,z) required');
  const within=(x,z)=>x>=ward.minX && x<ward.maxX && z>=ward.minZ && z<ward.maxZ;
  const safe=(x,z)=>within(x,z) && isAllowed(x,z)===true;
  return {THREE,groundAt,safe};
}
function diskSafe(safe,x,z,r) {
  for(let j=0;j<16;j++) {const a=j*Math.PI/8;if(!safe(x+Math.cos(a)*r,z+Math.sin(a)*r))return false;}
  return safe(x,z);
}
function material(T,color) {return new T.MeshLambertMaterial({color,side:T.DoubleSide});}
function cube(T,group,mat,x,y,z,w,h,d) {
  const m=new T.Mesh(new T.BoxGeometry(w,h,d),mat);m.position.set(x,y,z);m.receiveShadow=true;group.add(m);return m;
}
function cylinder(T,group,mat,x,y,z,rTop,rBottom,height,sides=7) {
  const m=new T.Mesh(new T.CylinderGeometry(rTop,rBottom,height,sides),mat);
  m.position.set(x,y,z);group.add(m);return m;
}
function signTexture(T,label) {
  if(typeof document==='undefined') throw Error('Canvas is required to create ward sign texture in the browser');
  const canvas=document.createElement('canvas');canvas.width=512;canvas.height=192;
  const c=canvas.getContext('2d');
  c.fillStyle='#171b24';c.fillRect(0,0,512,192);
  c.strokeStyle='#d8b566';c.lineWidth=14;c.strokeRect(9,9,494,174);
  c.fillStyle='#f3d88c';c.textAlign='center';c.textBaseline='middle';
  c.font='bold 91px Georgia, serif';c.fillText(label,256,98);
  const tex=new T.CanvasTexture(canvas);tex.colorSpace=T.SRGBColorSpace;
  return tex;
}
// Roadside sign, board lies in XY plane, front points toward +Z.
// Placement requires all post/board footprint samples to be allowed.
export function createWardSign({THREE,groundAt,isAllowed},id,x,z,heading=0) {
  if(!WARDS.some(w=>w.id===id)) throw Error('Unknown ward');
  if(!THREE||typeof groundAt!=='function'||typeof isAllowed!=='function') throw Error('Missing dependencies');
  const g=new THREE.Group();g.name=`WARD ${id} sign`;
  const gold=material(THREE,0xc5a25a),post=material(THREE,0x504b43);
  const board=new THREE.Mesh(new THREE.PlaneGeometry(4.4,1.55),
    new THREE.MeshBasicMaterial({map:signTexture(THREE,`WARD ${id}`),side:THREE.DoubleSide}));
  board.position.set(0,2.3,0.02);g.add(board);
  // THE BATTENING (2026-10-14): the board was a single DoubleSide
  // plane — from one travel direction the ward's name read
  // MIRRORED. A twin board now faces the other way (the first-ward
  // sign's pattern), so the name reads true from both approaches.
  const boardBack=new THREE.Mesh(board.geometry,board.material);
  boardBack.position.set(0,2.3,-0.02);boardBack.rotation.y=Math.PI;g.add(boardBack);
  // Simple gold border as physical frame; two posts below.
  cube(THREE,g,gold,0,3.105,0,4.55,.11,.12);
  cube(THREE,g,gold,0,1.495,0,4.55,.11,.12);
  for(const px of [-2.24,2.24]) {
    cube(THREE,g,gold,px,2.30,0,.11,1.72,.12);
    const [wx,wz]=[x+Math.cos(heading)*px,z-Math.sin(heading)*px];
    // Base at local 0, adapt each post to the actual terrain elevation.
    const relative=groundAt(wx,wz)-groundAt(x,z);
    cube(THREE,g,post,px,.80+relative/2,0,.16,1.60+Math.abs(relative),.16);
  }
  g.position.set(x,groundAt(x,z)+.03,z);g.rotation.y=heading;
  g.userData={ward:id,label:`WARD ${id}`,kind:'roadside-sign'};
  return g;
}
function addSign(args,ward,group,safe) {
  const [ax,az]=ward.anchor;
  // Search for a safe roadside location; never silently place on protected land.
  const offsets=[[0,6],[0,-6],[6,0],[-6,0],[9,9],[-9,-9],[14,0],[-14,0]];
  for(const [dx,dz] of offsets) {
  