<!-- SOLID CITY · part 2107 -->
      bx(3,0.14,1,M.strip, 0,6.5,0);
      fxCounter(bx,sl,M,0,5,5);
    }},
    {x:-18,z:130,ry:Math.PI,name:'SALT & SMOKE',fit:function(bx,sl){
      fxCounter(bx,sl,M,0,-4.5,10);
      for(var i=0;i<4;i++) bx(1.2,0.4,0.8,foodCols[(i+1)%5], -3.5+i*2.2,1.4,-4.5);
      tableSet(bx,sl,-4,2); tableSet(bx,sl,4,2);
      bx(8,2.5,0.4,M.shelf, 0,3,-6.5); // kitchen back
    }},
    {x:7,z:130,ry:Math.PI,name:'THE LENS',fit:function(bx,sl){
      [-4,0,4].forEach(function(px){
        bx(3,2.2,0.9,M.shelf, px,1.1,-4);
        bx(0.9,0.6,0.6,M.register, px,2.35,-4);
        var lens=new T.Mesh(new T.CylinderGeometry(0.22,0.22,0.3,10),M.glowA);
        // cylinder via box approx
        bx(0.44,0.44,0.3,M.glowA, px,2.35,-3.5);
        sl(px,-4,3,0.9,0,2.2);
      });
      bx(6,3,0.25,M.glowB, 0,3.5,5); // poster wall near front
      fxCounter(bx,sl,M,-5,4.5,4);
    }},
    {x:60,z:75,ry:0,name:'PETAL & STONE',fit:function(bx,sl){
      flowerStand(bx,sl,-5,-2); flowerStand(bx,sl,0,-2); flowerStand(bx,sl,5,-2);
      flowerStand(bx,sl,-2.5,2); flowerStand(bx,sl,2.5,2);
      fxCounter(bx,sl,M,0,5,6);
    }},
    {x:82,z:75,ry:0,name:'THE DEEP CUT',fit:function(bx,sl){
      [-4,0,4].forEach(function(px){
        bx(1.1,0.7,1.1,M.chair, px,0.35,0);
        bx(1.1,1.0,0.18,M.caseGlass, px,1.9,-0.8); // mirror
        bx(0.9,0.25,0.9,M.chair, px,0.85,0);
        sl(px,0,1.2,1.2,0,1.0);
      });
      bx(8,2.4,0.3,M.caseGlass, 0,2.8,-6.5); // mirror wall
      fxCounter(bx,sl,M,5.5,4.5,4);
    }},
    {x:104,z:75,ry:0,name:'COPPER KETTLE',fit:function(bx,sl){
      [[-4,-2],[0,-2],[4,-2],[-2,2],[2,2]].forEach(function(p){
        bx(1.6,0.35,1.6,M.table, p[0],0.18,p[1]);
        bx(0.7,0.5,0.7,M.chair, p[0],0.25,p[1]+1.2);
        sl(p[0],p[1],1.6,2.4,0,0.5);
      });
      fxCounter(bx,sl,M,0,5,8);
      for(var i=0;i<4;i++) bx(0.4,0.5,0.4,M.register, -3+i*2,1.45,5); // kettles
      fxShelf(bx,sl,M,-6,-5,4,prodCols);
    }},
    {x:126,z:75,ry:0,name:'INK & IRON',fit:function(bx,sl){
      fxShelf(bx,sl,M,-5,-4,6,bookCols); fxShelf(bx,sl,M,2,-4,6,prodCols);
      bx(5,0.9,2.4,M.table, 0,0.45,1.5);
      for(var i=0;i<4;i++) bx(0.8,0.25,1.1,bookCols[i%6], -1.8+i*1.2,1.0,1.5);
      sl(0,1.5,5,2.4,0,1.1);
      fxCounter(bx,sl,M,5.5,4.5,4);
    }},
    {x:-30,z:110,ry:0,name:'THE QUIET PAGE',fit:function(bx,sl){
      [-6,-2,2,6].forEach(function(px){ fxShelf(bx,sl,M,px,-3,3,bookCols); });
      tableSet(bx,sl,0,3);
      fxCounter(bx,sl,M,-5.5,4.5,4);
    }}
  ];
  stores.forEach(function(s){ buildStore(T, root, foot, M, s); });

  // ---- shopping street furniture: benches + planters along the east row ----
  var benchM=new T.MeshLambertMaterial({color:0x6a5a40});
  var leafM=new T.MeshLambertMaterial({color:0x2e6a34});
  [48,70,92,114].forEach(function(bx){
    var b=new T.Mesh(new T.BoxGeometry(3,0.5,1.2),benchM);
    b.position.set(bx,0.6,62); root.add(b);
    foot.push([bx,62,3,1.2,0,0.9,0]);
    var pl=new T.Mesh(new T.BoxGeometry(2,1.6,2),benchM);
    pl.position.set(bx,0.8,88); root.add(pl);
    var lf=new T.Mesh(new T.SphereGeometry(1.4,8,6),leafM);
    lf.position.set(bx,2.4,88); root.add(lf);
    foot.push([bx,88,2,2,0,1.6,0]);
  });
  // west store bench + planter
  var b2=new T.Mesh(new T.BoxGeometry(3,0.5,1.2),benchM);
  b2.position.set(-70,0.6,72); root.add(b2); foot.push([-70,72,3,1.2,0,0.9,0]);
}

/* WESTERN EXPANSION — massive skyline + real harbor (2026-10-11)
 * The King's words: "stretch it the direction away from the city so we have
 * a massive sky line with a real shipping dock port harbor."
 * - West podium extension (x -470..-210)
 * - 12 more megatowers (240-400m) with portholes — a wall of towers
 * - 6 businesses (bank, shipping, law, restaurant/bar, news, architect)
 * - Real harbor: quay, 3 cargo piers, 6 gantry cranes, container stacks,
 *   2 cargo ships, harbor master (real interior), breakwater, lighthouse, buoys
 */
function westTower(T, root, foot, M, x, z, h, tp, R, lift) {
  lift = lift || 0;
  var g = new T.Group(); g.position.set(x, lift, z);
  var w = 20 + R() * 18, d = 20 + R() * 18;
  var mat = R() < 0.5 ? M.glassA : M.glassB;
  var hw;
  if (tp === 0) {
    var nd = new T.Mesh(new T.CylinderGeometry(w*0.28, w*0.55, h, 8), mat);
    nd.position.y = h/2; g.add(nd);
    var tip = new T.Mesh(new T.CylinderGeometry(0.8, 2.5, 26, 6), M.gold);
    tip.position.y = h+13; g.add(tip);
    hw = w*0.62;
    foot.push([x, z, w*1.24, w*1.24, lift, h+26+lift, 0]);
  } else if (tp === 1) {
    var PHI = 1.6180339887;
    var b1 = new T.Mesh(new T.BoxGeometry(w, h*0.55, d), mat); b1.position.y = h*0.275; g.add(b1);
    var w2 = w/PHI, d2 = d/PHI;
    var b2 = new T.Mesh(new T.BoxGeometry(w2, h*0.3, d2), mat); b2.position.set(0, h*0.55+h*0.15, 0); g.add(b2);
    var b3 = new T.Mesh(new T.BoxGeometry(w2/PHI, h*0.15, d2/PHI), M.gold);
    b3.position.set(0, h*0.85+h*0.075, 0); g.add(b3);
    hw = Math.max(w, d)*0.52;
    foot.push([x, z, Math.max(w,d)*1.04,