<!-- SOLID CITY · part 2129 -->
  // trolley (animated)
      var tr = box(4,2,4,gold, cx,28,pz); tr.name='trolley'; tr.userData.cx=cx; tr.userData.pz=pz;
      box(0.35,12,0.35,darkM, cx,21,pz);
      box(7,1.2,3.5,gold, cx,14.5,pz); // spreader
      if (!window._hyperTrolleys) window._hyperTrolleys = [];
      window._hyperTrolleys.push(tr);
    });
  });

  // ---- CONTAINER STACKS on quay ----
  var ci = 0;
  for (var rx=-565; rx<=-490; rx+=16) {
    for (var rz=-125; rz<=125; rz+=22) {
      if (Math.abs(rz) < 30) continue; // working lane
      if ((rx+rz)%3 === 0) continue; // gaps
      var sh = 2 + (Math.abs(rx*7+rz*13) % 3); // 2-4 high
      for (var s2=0; s2<sh; s2++) {
        box(13,2.7,3,contCols[ci % contCols.length], rx, 3+s2*2.8, rz);
        ci++;
      }
      solid(rx,rz,13,3,0,3+sh*2.8);
    }
  }

  // ---- 2 CARGO SHIPS ----
  [[-80,-1],[80,1]].forEach(function(sp, si){
    var pz = sp[0], side = sp[1];
    var sz = pz + side*26;
    var sg = new T.Group(); sg.position.set(-640, 0, sz);
    var hullM = new T.MeshLambertMaterial({color: 0x2a3a4a});
    var hull = new T.Mesh(new T.BoxGeometry(72,9,17), hullM);
    hull.position.y = -2.5; sg.add(hull);
    var bow = new T.Mesh(new T.BoxGeometry(16,9,17), hullM);
    bow.position.set(42,-2.5,0); bow.rotation.y = 0.45; sg.add(bow);
    var stripeM = new T.MeshLambertMaterial({color: 0xc84a3a});
    var stripe = new T.Mesh(new T.BoxGeometry(72.5,1.2,17.5), stripeM);
    stripe.position.y = 0.5; sg.add(stripe);
    // deck containers
    for (var dx=-28; dx<=28; dx+=14) {
      for (var dz=-5.5; dz<=5.5; dz+=6) {
        var cm = contCols[Math.abs(dx+dz+si*7) % contCols.length];
        var cb = new T.Mesh(new T.BoxGeometry(12,2.7,5.2), cm);
        cb.position.set(dx, 3.4, dz); sg.add(cb);
        if ((dx+dz)%2===0) {
          var cb2 = new T.Mesh(new T.BoxGeometry(12,2.7,5.2), contCols[(Math.abs(dx*3+dz)+1)%5]);
          cb2.position.set(dx, 6.2, dz); sg.add(cb2);
        }
      }
    }
    // bridge tower
    var brM = new T.MeshLambertMaterial({color: 0xe8e8e8});
    var br = new T.Mesh(new T.BoxGeometry(10,16,14), brM);
    br.position.set(-30, 8, 0); sg.add(br);
    var brTop = new T.Mesh(new T.BoxGeometry(11,3,15), new T.MeshLambertMaterial({color: 0x2a4a6a}));
    brTop.position.set(-30, 17, 0); sg.add(brTop);
    // funnel
    var fun = new T.Mesh(new T.CylinderGeometry(2,2.5,8,10), stripeM);
    fun.position.set(-34, 20, 0); sg.add(fun);
    sg.name = 'cargoship';
    sg.userData.baseY = 0; sg.userData.ph = si*2.1;
    root.add(sg);
    solid(-640, sz, 72, 17, -7, 12);
    if (!window._hyperShips) window._hyperShips = [];
    window._hyperShips.push(sg);
  });

  // ---- HARBOR MASTER (real interior office) ----
  buildStore(T, root, foot, BM, {
    x:-500, z:100, ry:Math.PI/2, name:'HARBOR MASTER',
    fit:function(bx, sl, M){
      bx(6,1.1,2,M.counter, 0,0.55,-4); sl(0,-4,6,2,0,1.1);
      // chart wall
      bx(8,4,0.25,M.blueprint, 0,3.5,-6.7);
      bx(8.4,4.4,0.15,M.gold, 0,3.5,-6.8);
      // desks
      [[-4,0],[4,0]].forEach(function(p){
        bx(3,0.9,1.6,M.table, p[0],0.45,p[1]);
        bx(1.0,0.3,0.8,M.paper, p[0],1.05,p[1]);
        sl(p[0],p[1],3,1.6,0,1.2);
      });
      // radio desk with glowing console
      bx(4,1.0,1.4,M.register, 0,0.5,3.5);
      bx(3.6,0.7,0.2,M.glowA, 0,1.35,3.2);
      sl(0,3.5,4,1.4,0,1.7);
      // logbooks shelf
      bx(4,2.4,0.8,M.shelf, -6,1.2,4);
      for (var i=0;i<4;i++) bx(0.7,0.5,0.6,M.paper, -7.2+i*0.85,1.6,4);
      sl(-6,4,4,0.8,0,2.4);
    }
  });

  // ---- BREAKWATER ----
  var rockM = new T.MeshLambertMaterial({color: 0x3a3f45});
  for (var bz=-160; bz<=160; bz+=26) {
    var rk = new T.Mesh(new T.DodecahedronGeometry(7+((bz*13)%5+5)%5, 0), rockM);
    rk.position.set(-745 + ((bz*7)%9+9)%9 - 4, -3, bz);
    rk.rotation.set((bz%3), (bz%5), 0);
    root.add(rk);
  }

  // ---- LIGHTHOUSE ----
  var lhX = -630, lhZ = -165;
  var lhM = new T.MeshLambertMaterial({color: 0xe8e8e8});
  var redM = new T.MeshLambertMaterial({color: 0xc84a3a});
  var lht = new T.Mesh(new T.CylinderGeometry(4.5,6.5,38,12), lhM);
  lht.position.set(lhX, 19, lhZ); root.add(lht);
  for (var lsy=6; lsy<36; lsy+=10) {
    var st = new T.Mesh(new T.CylinderGeometry(4.9-(lsy/38)*2, 5.1-(lsy/38)*2, 3.4, 12), redM);
    st.position.set(lhX, lsy, lhZ); root.add(st);
  }
  var lampR = new T.Mesh(new T.CylinderGeometry(3,3,4,10), darkM);
  lampR.position.set(lhX, 40, lhZ); root.add(lampR);
  var lampB = new T.Mesh(new T.SphereGeometry(2.2,12,10), new T.MeshBasicMaterial({color: 0xffe8a0}));
  lampB.position.set(lhX, 40, lhZ); root.add(lampB);
  var beam = new T.Mesh(new T.CylinderGeometry(1.5,4,70,8,1,true),
    new T.MeshBasicMaterial({color: 0xffe8a0, transparent: true, opacity: 0.28, side: T.DoubleSide, depthWrite: false}));
  beam.position.set(lhX, 40, lhZ);
  beam.rotation.z = Math.PI/2;
  beam.name = 'lhbeam';
  root.add(beam);
  solid(lhX, lhZ, 13, 13, 0, 42);
  if (!window._hyperBeams) windo