<!-- NEW4 — TEST 4 · THE QUILT · part 443 -->
/ 2); wg.translate(L.x, 0.6, L.z); waterGeos.push(wg);
  }
  if (bankGeos.length) { const m = new THREE.Mesh(mergeGeometries(bankGeos), new THREE.MeshLambertMaterial({ color: 0x6b6257 })); m.name = 'BANKS'; group.add(m); }
  if (waterGeos.length) { const m = new THREE.Mesh(mergeGeometries(waterGeos), new THREE.MeshLambertMaterial({ color: 0x2f6db3 })); m.name = 'WATER'; group.add(m); }
  // bridges + streets
  const streetGeos = [], deckGeos = [], pierGeos = [], railGeos = [];
  const deckProfileAt = (dk, x, z) => {
    const ux = x - dk.cx, uz = z - dk.cz; const u = ux * dk.dx + uz * dk.dz, v = -ux * dk.dz + uz * dk.dx;
    const half = dk.len / 2, RAMP = 15;
    if (Math.abs(v) > dk.wid / 2 + 0.6 || Math.abs(u) > half + RAMP) return 0;
    if (Math.abs(u) <= half) return 4.5;
    return 4.5 * (1 - (Math.abs(u) - half) / RAMP);
  };
  for (const s of MAP.streets) {
    const dx = s.b[0] - s.a[0], dz = s.b[1] - s.a[1], len = Math.hypot(dx, dz), ux = dx / len, uz = dz / len;
    const ang = Math.atan2(dx, dz);
    const sg = new THREE.BoxGeometry(s.w, 0.12, len); sg.applyMatrix4(new THREE.Matrix4().compose(new THREE.Vector3((s.a[0] + s.b[0]) / 2, 0.37, (s.a[1] + s.b[1]) / 2), new THREE.Quaternion().setFromEuler(new THREE.Euler(0, ang, 0)), new THREE.Vector3(1, 1, 1)));
    streetGeos.push(sg);
    // sample for water crossings
    let runStart = -1; const runs = [];
    for (let d = 0; d <= len; d += 2) { const x = s.a[0] + ux * d, z = s.a[1] + uz * d; const wet = inWater(x, z); if (wet && runStart < 0) runStart = d; if ((!wet || d >= len - 2) && runStart >= 0) { runs.push([runStart, d]); runStart = -1; } }
    for (const [d0, d1] of runs) {
      if (d1 - d0 < 8) continue;
      const cx = s.a[0] + ux * (d0 + d1) / 2, cz = s.a[1] + uz * (d0 + d1) / 2;
      const dk = { cx, cz, dx: ux, dz: uz, len: (d1 - d0), wid: s.w }; decks.push(dk); counts.bridges++;
      const dg = new THREE.BoxGeometry(s.w, 0.7, (d1 - d0) + 8); dg.applyMatrix4(new THREE.Matrix4().compose(new THREE.Vector3(cx, 4.15, cz), new THREE.Quaternion().setFromEuler(new THREE.Euler(0, ang, 0)), new THREE.Vector3(1, 1, 1)));
      deckGeos.push(dg);
      for (const sgn of [-1, 1]) { // ramps
        const rl = 15, rcx = cx + ux * sgn * ((d1 - d0) / 2 + 4 + rl / 2 - 1), rcz = cz + uz * sgn * ((d1 - d0) / 2 + 4 + rl / 2 - 1);
        const rg = new THREE.BoxGeometry(s.w, 0.5, rl);
        const m = new THREE.Matrix4().compose(new THREE.Vector3(rcx, 2.15, rcz), new THREE.Quaternion().setFromEuler(new THREE.Euler(0, ang, 0)).multiply(new THREE.Quaternion().setFromEuler(new THREE.Euler(sgn * Math.atan2(4.3, rl), 0, 0))), new THREE.Vector3(1, 1, 1));
        rg.applyMatrix4(m); deckGeos.push(rg);
        const r1 = new THREE.BoxGeometry(0.5, 0.9, (d1 - d0) + 8); // rails follow deck only
        r1.applyMatrix4(new THREE.Matrix4().compose(new THREE.Vector3(cx - uz * (s.w / 2 - 0.4), 5.1, cz + ux * (s.w / 2 - 0.4)), new THREE.Quaternion().setFromEuler(new THREE.Euler(0, ang, 0)), new THREE.Vector3(1, 1, 1)));
        const r2 = new THREE.BoxGeometry(0.5, 0.9, (d1 - d0) + 8);
        r2.applyMatrix4(new THREE.Matrix4().compose(new THREE.Vector3(cx + uz * (s.w / 2 - 0.4), 5.1, cz - ux * (s.w / 2 - 0.4)), new THREE.Quaternion().setFromEuler(new THREE.Euler(0, ang, 0)), new THREE.Vector3(1, 1, 1)));
        if (sgn < 0) { railGeos.push(r1, r2); }
      }
      for (let d = d0 + 6; d < d1 - 3; d += 15) { const px = s.a[0] + ux * d, pz = s.a[1] + uz * d; const pg = new THREE.CylinderGeometry(1.2, 1.4, 4.4, 8); pg.translate(px, 2.2, pz); pierGeos.push(pg); }
    }
  }
  if (streetGeos.length) { const m = new THREE.Mesh(mergeGeometries(streetGeos), new THREE.MeshLambertMaterial({ color: 0x33373c })); m.name = 'STREETS'; group.add(m); }
  if (deckGeos.length) { const m = new THREE.Mesh(mergeGeometries(deckGeos), new THREE.MeshLambertMaterial({ color: 0x4a4d52 })); m.name = 'BRIDGES'; group.add(m); }
  if (pierGeos.length) { const m = new THREE.Mesh(mergeGeometries(pierGeos), new THREE.MeshLambertMaterial({ color: 0x5a5d60 })); m.name = 'PIERS'; group.add(m); }
  if (railGeos.length) { const m = new THREE.Mesh(mergeGeometries(railGeos), new THREE.MeshLambertMaterial({ color: 0x8a8d90 })); m.name = 'RAILS'; group.add(m); }
  // ---------- region kits ----------
  const buckets = new Map();
  const bucket = (color) => { if (!buckets.has(color)) buckets.set(color, []); return buckets.get(color); };
  const treeGeos = [], trunkGeos = [];
  const tree = (x, z, s) => { trunkGeos.push(new THREE.CylinderGeometry(0.22 * s, 0.3 * s, 2.2 * s, 5).applyMatrix4(M4(THREE, x, 1.1 * s, z))); treeGeos.push(new THREE.ConeGeometry(1.9 * s, 5.2 * s, 7).applyMatrix4(M4(THREE, x, 2.2 * s + 2.6 * s, z))); counts.trees++; };
  const WALLS = [0xe8e2d4, 0xdfe5ea, 0xf0e0cc, 0xd8e2d0, 0xead9d9, 0xf3ead9], ROOFS = [0x6b5a4a, 0x596066, 0x746052, 0x4f5a60];
  for (const R of MAP.regions) {
    const rnd = mulberry32(R.seed || 7);
    if (R.kind 