<!-- SOLID CITY · part 680 -->
xture(c); t.encoding = T.sRGBEncoding; t.anisotropy = 4;
  if (repeat) { t.wrapS = t.wrapT = T.RepeatWrapping; t.repeat.set(repeat[0], repeat[1]); }
  return t;
}
var r3 = mulberry(4242);
// Solidivism motherboard floor
var TEX_BOARD = canvasTex(512, 512, function (g, w, h) {
  g.fillStyle = '#0a0809'; g.fillRect(0, 0, w, h);
  g.strokeStyle = 'rgba(120,20,30,.55)'; g.lineWidth = 2;
  for (var k = 0; k < 70; k++) { var x = r3() * w, y = r3() * h; g.beginPath(); g.moveTo(x, y); var hz = r3() < .5; var L = 40 + r3() * 160; g.lineTo(hz ? x + L : x, hz ? y : y + L); g.lineTo(hz ? x + L + 20 : x + 20, hz ? y + 20 : y + L + 20); g.stroke(); g.fillStyle = '#c99a3a'; g.fillRect(x - 3, y - 3, 6, 6); }
  g.strokeStyle = 'rgba(232,195,106,.18)'; g.lineWidth = 1; for (k = 0; k <= 8; k++) { g.beginPath(); g.moveTo(k * 64, 0); g.lineTo(k * 64, h); g.moveTo(0, k * 64); g.lineTo(w, k * 64); g.stroke(); }
  for (k = 0; k < 14; k++) { g.fillStyle = '#151214'; var cw = 30 + r3() * 50; g.fillRect(r3() * w, r3() * h, cw, cw * .6); }
}, [6, 6]);
// tower windows (emissive)
var TEX_WIN = canvasTex(128, 256, function (g, w, h) {
  g.fillStyle = '#000'; g.fillRect(0, 0, w, h);
  for (var y = 4; y < h; y += 10) for (var x = 4; x < w; x += 10) { var p = r3(); if (p < 0.3) { g.fillStyle = p < 0.08 ? '#ff3048' : p < 0.22 ? '#e8b04a' : '#5a3a20'; g.fillRect(x, y, 6, 5); } }
}, [1, 1]);
var TEX_BLDG = canvasTex(128, 256, function (g, w, h) {
  g.fillStyle = '#121014'; g.fillRect(0, 0, w, h);
  for (var y = 0; y < h; y += 10) { g.fillStyle = 'rgba(255,255,255,.035)'; g.fillRect(0, y, w, 1); }
  g.fillStyle = '#2a0a10'; g.fillRect(0, 0, 3, h); g.fillRect(w - 3, 0, 3, h);
}, [1, 1]);
function labelTex(text, sub, w, h) {
  return canvasTex(w || 512, h || 128, function (g, W, H) {
    g.fillStyle = 'rgba(8,4,8,.88)'; g.fillRect(0, 0, W, H);
    g.strokeStyle = '#e8c36a'; g.lineWidth = 6; g.strokeRect(4, 4, W - 8, H - 8);
    g.fillStyle = '#e8c36a'; g.textAlign = 'center'; g.font = '700 ' + Math.round(H * 0.36) + 'px Georgia, serif'; g.fillText(text, W / 2, sub ? H * 0.5 : H * 0.64);
    if (sub) { g.fillStyle = '#ff4d5e'; g.font = '800 ' + Math.round(H * 0.17) + 'px system-ui, sans-serif'; g.fillText(sub, W / 2, H * 0.82); }
  });
}

/* ---------------- Solidivism: everything visible is solid ---------------- */
var solids = [];   // AABBs (absolute coords): {x0,x1,z0,z1,y0,y1}
function solidBox(x, z, w, d, y0, y1) { solids.push({ x0: x - w / 2, x1: x + w / 2, z0: z - d / 2, z1: z + d / 2, y0: y0, y1: y1 }); }
function collideXZ(p, rad, y) { // push a point out of every solid it overlaps (at height y)
  for (var k = 0; k < solids.length; k++) {
    var s = solids[k]; if (y < s.y0 - 0.5 || y > s.y1) continue;
    if (p.x > s.x0 - rad && p.x < s.x1 + rad && p.z > s.z0 - rad && p.z < s.z1 + rad) {
      var dl = p.x - (s.x0 - rad), dr = (s.x1 + rad) - p.x, dn = p.z - (s.z0 - rad), df = (s.z1 + rad) - p.z, m = Math.min(dl, dr, dn, df);
      if (m === dl) p.x = s.x0 - rad; else if (m === dr) p.x = s.x1 + rad; else if (m === dn) p.z = s.z0 - rad; else p.z = s.z1 + rad;
    }
  }
}
function insideSolid(x, y, z, pad) { for (var k = 0; k < solids.length; k++) { var s = solids[k]; if (x > s.x0 - pad && x < s.x1 + pad && z > s.z0 - pad && z < s.z1 + pad && y > s.y0 - pad && y < s.y1 + pad) return s; } return null; }

var M = {
  black: curve(new T.MeshLambertMaterial({ color: 0x0d0b0e })),
  gun: curve(new T.MeshLambertMaterial({ color: 0x2a2a30 })),
  gold: curve(new T.MeshLambertMaterial({ color: 0xc99a3a, emissive: 0x100a02 })),
  red: curve(new T.MeshBasicMaterial({ color: 0xff2a40 })),
  redDim: curve(new T.MeshLambertMaterial({ color: 0x5a0410, emissive: 0x3a020a })),
  glowGold: curve(new T.MeshBasicMaterial({ color: 0xffd27a })),
  board: curve(new T.MeshLambertMaterial({ map: TEX_BOARD, color: 0xffffff, emissive: 0x030001 })),
  road: curve(new T.MeshLambertMaterial({ color: 0x0b0a0c })),
  bldg: curve(new T.MeshLambertMaterial({ map: TEX_BLDG, emissiveMap: TEX_WIN, emissive: 0xffffff }))
};
function box(w, h, d, mat, x, y, z, solid) {
  var m = new T.Mesh(new T.BoxGeometry(w, h, d), mat); m.position.set(x, y + h / 2, z); world.add(m);
  if (solid !== false) solidBox(x, z, w, d, y, y + h);
  return m;
}
function cyl(rt, rb, h, mat, x, y, z, seg, solid) {
  var m = new T.Mesh(new T.CylinderGeometry(rt, rb, h, seg || 16), mat); m.position.set(x, y + h / 2, z); world.add(m);
  if (solid !== false) solidBox(x, z, Math.max(rt, rb) * 1.6, Math.max(rt, rb) * 1.6, y, y + h);
  return m;
}
function sign(text, sub, x, y, z, w, rotY) {
  var m = new T.Mesh(new T.PlaneGeometry(w, w / 4), curve(new T.MeshBasicMaterial({ map: labelTex(text, sub), side: T.DoubleSide, fog: true })));
  m.position.set(x, y, z); m.rotation.y = rotY || 0; world.add(m); return m;
}
var animated = [];   // {obj, fn}
var NP = { draw: null, playing: false }, RADIO_MASTS = [];

/* districts (absolute coords, city ground at CITY_Y) */
var D = {
  plaz