<!-- SOLID CITY · part 2951 -->
false }, { y: topY + SKY_LIFT, sky: true }].forEach(function (spec) {
      var g = mod.createRingCity({ THREE: A.T, center: POS, topY: spec.y, sky: spec.sky, dense: spec.sky, beautify: !spec.sky });
      A.world.add(g);
      (g.userData.footprint || []).forEach(addFootprint);
      M.cities.push({ group: g, port: g.userData.port || null, sky: spec.sky, landingSent: false });
    });
    M.state = 'ready';
    hyperStops();
  } catch (e) { M.state = 'idle'; }
}
function standY(x, z, py) {
  if (M.state !== 'ready') return -1000;
  var gate = (S && S.drive) ? 1.6 : 0.45;
  var best = -1000;
  for (var ci = 0; ci < M.cities.length; ci++) {
    var ud = M.cities[ci].group.userData;
    var rects = ud.standRects || [];
    for (var i = 0; i < rects.length; i++) {
      var r = rects[i], dx = x - r.cx, dz = z - r.cz;
      var lx = dx * r.tx + dz * r.tz, lz = dx * r.rx + dz * r.rz;
      if (Math.abs(lx) <= r.hw && Math.abs(lz) <= r.hd) {
        if (py == null || r.y <= py + gate) { if (r.y > best) best = r.y; }
      }
    }
    if (ud.glassFloor) {
      var dd = Math.hypot(x - POS.x, z - POS.z);
      if (dd <= 545 && (py == null || ud.topY <= py + gate)) { if (ud.topY > best) best = ud.topY; }
    }
    var p = M.cities[ci].port;
    if (p) {
      var pd = Math.hypot(x - p.x, z - p.z);
      if (pd <= p.r && (py == null || p.y <= py + gate)) { if (p.y > best) best = p.y; }
    }
  }
  return best;
}
function update(dt) {
  if (M.state === 'idle') {
    M.wait -= dt;
    var tReady = !!(window.CityAncestorRoads && CityAncestorRoads.state && CityAncestorRoads.state() === 'ready');
    if (M.wait <= 0 && A.isBuilt() && tReady) build();
    return;
  }
  if (M.state !== 'ready') return;
  M.cities.forEach(function (ct) {
    if (ct.group.userData.update) try { ct.group.userData.update(dt, S.t); } catch (e) {}
    if (!ct.landingSent && ct.port && window.CitySkyTrain && CitySkyTrain.addLanding) {
      ct.landingSent = !!CitySkyTrain.addLanding({ id: ct.sky ? 'sky-ring-port' : 'ring-city-port', name: ct.sky ? 'SKY RING PORT' : 'RING CITY PORT', x: ct.port.x, z: ct.port.z, gy: ct.port.y, grand: false });
    }
  });
}
window.CityRingCity = { update: update, standY: standY, state: function () { return M.state; },
  group: function () { return M.cities.length ? M.cities[0].group : null; },
  skyGroup: function () { var s = M.cities.filter(function (c) { return c.sky; }); return s.length ? s[0].group : null; },
  cities: function () { return M.cities; } };
})();


===== FILE: public/city/ring-city-place.js.bak-all-20261014 =====
/* Solid City — places THE RING CITY OF THE ANCESTORS
 * (public/city/ring-city.js) on the Ancestral Roads terrace,
 * and its SKY TWIN above it.
 * "Build the city on these rings — fill this terrace." — the
 * King, 2026-10-14; and then: "Build another in the sky above
 * it — glass floor to see it from below."
 * The placer waits for the terrace itself, takes its height
 * from the terrace's own law (CityAncestorRoads.topY), lays
 * the ground city in the bands between the roads, and raises
 * the twin 140 metres above it on a glass floor with a gold-
 * ringed keel. Standing hooks (CityRingCity.standY) serve
 * both cities and were added to updateWalk and standingAt in
 * the same breath, as the Law of the Two Lists commands. */
(function () {
'use strict';
if (!window.SC || !SC.api) return;
var A = SC.api, S = A.S;
var POS = { x: 0, z: -1600 };
var SKY_LIFT = 140;
var M = { state: 'idle', wait: 4.2, cities: [] };
function addFootprint(b) {
  /* the factory's frame runs local X along the tangent
   * (-sin a, cos a) and local Z along the radius (cos a, sin a) */
  var tx = -Math.sin(b.a), tz = Math.cos(b.a), rx = Math.cos(b.a), rz = Math.sin(b.a);
  var nx = Math.max(1, Math.ceil(b.w / 2.5)), nz = Math.max(1, Math.ceil(b.d / 2.5));
  var cw = b.w / nx, cd = b.d / nz;
  for (var i = 0; i < nx; i++) for (var j = 0; j < nz; j++) {
    var ox = -b.w / 2 + cw * (i + 0.5), oz = -b.d / 2 + cd * (j + 0.5);
    var cx = b.x + tx * ox + rx * oz, cz = b.z + tz * ox + rz * oz;
    var hx = cw / 2 * Math.abs(tx) + cd / 2 * Math.abs(rx), hz = cw / 2 * Math.abs(tz) + cd / 2 * Math.abs(rz);
    A.solids.push({ x0: cx - hx, x1: cx + hx, z0: cz - hz, z1: cz + hz, y0: b.y0, y1: b.y1, ringCity: true });
  }
}
function hyperStop(id, name, short, x, z, standX, standZ, alias, text) {
  var H = window.CityHyper; if (!H || !H.pois) return;
  if (H.pois.some(function (p) { return p.id === id; })) return;
  H.pois.push({ id: id, name: name, short: short, x: x, z: z, stand: { x: standX, z: standZ }, alias: alias, text: text });
  if (H.regrid) H.regrid();
}
function hyperStops() {
  hyperStop('ring-city', 'THE RING CITY OF THE ANCESTORS', 'RING CITY', POS.x, POS.z, POS.x, POS.z + 470,
    'ring city ancestors terrace rings houses hotels mansions market',
    'The city the Ancestral Roads were drawn for, raised by the King\'s word on October 14, 2026: houses, pavilions, gardens and