<!-- SOLID CITY · part 3207 -->
oute.stops;
    if (tr.mode === 'dwell') {
      tr.dwellT -= dt; tr.v = 0;
      if (tr.dwellT <= 0) {
        var nxt = tr.stopIdx + tr.dir;
        if (nxt < 0 || nxt >= stops.length) { tr.dir = -tr.dir; nxt = tr.stopIdx + tr.dir; }
        tr.stopIdx = nxt; tr.mode = 'run';
      }
    } else {
      var target = stops[tr.stopIdx], dStop = (target.s - tr.s) * tr.dir;
      if (dStop <= 0.05) {
        tr.s = target.s; tr.mode = 'dwell'; tr.dwellT = 4; tr.station = target.station;
      } else {
        var vT = dStop > 120 ? 26 : Math.max(0.5, 26 * dStop / 120);
        tr.v += Math.max(-3.8 * dt, Math.min(3.0 * dt, vT - tr.v));
        tr.s += tr.v * dt * tr.dir;
        if ((target.s - tr.s) * tr.dir < 0) tr.s = target.s;
      }
    }
    placeTrain(tr, dt);
  }

  /* ================= SHUTTLES =================
   * Small craft hopping port to port on their own business:
   * climb, cruise, descend, hover a while beside the disc,
   * and away again. The sky's ordinary errands. */
  function buildShuttle() {
    var g = new T.Group();
    var hull = new T.Mesh(new T.SphereGeometry(1.6, 12, 8), MAT.titanium); hull.scale.set(1, 0.55, 2.2); hull.position.y = 0.4; g.add(hull);
    var dome = new T.Mesh(new T.SphereGeometry(0.95, 10, 6), MAT.glass); dome.scale.set(1, 0.6, 1.4); dome.position.set(0, 0.95, 0.7); g.add(dome);
    g.add(box(1.9, 0.14, 3.4, MAT.gold, 0, -0.25, 0));
    g.add(box(0.3, 0.3, 0.3, MAT.white, 0, 0.5, 3.55));
    g.add(box(0.3, 0.3, 0.3, MAT.red, 0, 0.5, -3.55));
    return g;
  }
  var shuttles = [];
  for (var si = 0; si < 6; si++) {
    var sh = { mesh: buildShuttle(), mode: 'hover', t: 2 + si * 5, at: STATIONS[1 + (si * 3) % 16], from: null, to: null, ph: 0, laneY: 0, x: 0, y: -1000, z: 0, yaw: 0 };
    sh.x = sh.at.x + 14; sh.z = sh.at.z; sh.y = sh.at.gy + 12;
    group.add(sh.mesh); shuttles.push(sh);
  }
  function pickDest(notId) {
    var c = LANDINGS.filter(function (s) { return s.id !== notId; });
    return c[Math.floor(Math.random() * c.length)];
  }
  function stepShuttle(sh, dt) {
    sh.t -= dt;
    if (sh.mode === 'hover') {
      sh.y = sh.at.gy + 12 + Math.sin(perfNow * 0.9 + sh.x) * 0.3;
      if (sh.t <= 0) { sh.from = sh.at; sh.to = pickDest(sh.at.id); var mx = -1e12; for (var i = 0; i <= 10; i++) { var gx = sh.from.x + (sh.to.x - sh.from.x) * i / 10, gz = sh.from.z + (sh.to.z - sh.from.z) * i / 10, gg = heightAt(gx, gz); if (gg > mx) mx = gg; } sh.laneY = Math.min(398, Math.max(sh.from.gy, sh.to.gy) + 48, mx + 42); sh.mode = 'go'; }
    } else {
      var tx = sh.to.x + 14, tz = sh.to.z, ty = sh.to.gy + 12;
      var dx = tx - sh.x, dz = tz - sh.z, dh = Math.hypot(dx, dz);
      var desY = dh > 90 ? sh.laneY : ty;
      var vy = Math.max(-9, Math.min(9, (desY - sh.y) * 0.8));
      sh.y += vy * dt;
      if (dh > 1) {
        var sp = 36, step = Math.min(dh, sp * dt);
        sh.x += dx / dh * step; sh.z += dz / dh * step;
        var wantYaw = Math.atan2(dx, dz), dy = wantYaw - sh.yaw;
        while (dy > Math.PI) dy -= Math.PI * 2; while (dy < -Math.PI) dy += Math.PI * 2;
        sh.yaw += dy * Math.min(1, dt * 2.2);
      }
      if (dh < 2 && Math.abs(sh.y - ty) < 1.2) { sh.at = sh.to; sh.mode = 'hover'; sh.t = 5 + Math.random() * 6; }
    }
    sh.mesh.position.set(sh.x, sh.y, sh.z);
    sh.mesh.rotation.set(0, sh.yaw, 0);
  }

  /* ================= HOUSE CRAFT =================
   * The grand households keep a little ship on their own port,
   * and it LANDS there — the King marked the pleasure of it
   * with his own eyes (~02:07): "a space ship lands and
   * departs — I like that little cool design." So each hotel
   * and mansion's craft lifts off its disc, flies a visit to
   * another landing, hovers a while in the traffic, comes
   * home, and settles back onto its own stone. The hillside
   * contributing to the sky, as he ordered. */
  var houseCraft = [];
  EXTRA.filter(function (p) { return p.grand; }).forEach(function (home, ci) {
    var m = buildShuttle(); m.scale.setScalar(0.9); group.add(m);
    houseCraft.push({ mesh: m, home: home, mode: 'parked', t: 14 + ci * 17, x: home.x + 4.5, y: home.gy + 0.55, z: home.z + 2, yaw: ci * 1.3, dest: null });
  });
  function stepCraft(cr, dt) {
    cr.t -= dt;
    if (cr.mode === 'parked') {
      if (cr.t <= 0) { cr.dest = pickDest(cr.home.id); cr.mode = 'rise'; }
    } else if (cr.mode === 'rise') {
      cr.y += 5.5 * dt;
      if (cr.y >= cr.home.gy + 16) cr.mode = 'go';
    } else if (cr.mode === 'go') {
      var laneY = Math.min(398, Math.max(cr.home.gy, cr.dest.gy) + 46);
      var rem = flyToward(cr, cr.dest.x + 14, laneY, cr.dest.z, 42, dt);
      if (rem < 30) { flyToward(cr, cr.dest.x + 14, cr.dest.gy + 12, cr.dest.z, 20, dt); if (rem < 3) { cr.mode = 'visit'; cr.t = 6; } }
    } else if (cr.mode === 'visit') {
      cr.y = cr.dest.gy + 12 + Math.sin(perfNow * 0.85 + cr.x) * 0.3;
      if (cr.t <= 0) cr.mode = 'back';
    } else if (cr.mode === 'back') {
