<!-- SOLID CITY · part 2090 -->
f (inside && S.p.y > M.gy + f.y - 3 && M.gy + f.y > best) best = M.gy + f.y;
  }
  return best;
}
function actHere(x, z) {
  if (M.state !== 'ready' || !M.group) return null;
  try { return M.group.userData.actHere(x, z); } catch (e) { return null; }
}
function boardElevator() {
  if (M.state !== 'ready' || !M.group) return;
  try { M.group.userData.boardElevator(S.p.x, S.p.z); } catch (e) {}
}
window.CityHyperCity = { update: update, radar: radar, pos: POS, standY: standY, actHere: actHere, boardElevator: boardElevator, state: function () { return M.state; } };
})();


===== FILE: public/city/hyper-city.js =====
/* SOLID CITY — HYPER CITY (2026-10-11, by order of the King)
 * "You going to build a hyper building city here"
 * A district of futuristic megatowers on the west coast: 24 towers 150-400m,
 * the Hyper Spire (460m), street grid, central plaza, waterfront promenade.
 * Design law: science grown into beautiful art — golden-ratio setbacks,
 * symmetrical crowns, the skyline a composition.
 * True names: THE HYPER CITY (district), THE HYPER SPIRE.
 * Self-contained ES module. Local frame: +X = east (city side), -X = west (ocean).
 */
function mulberry(a){return function(){a|=0;a=a+0x6D2B79F5|0;var t=Math.imul(a^a>>>15,1|a);t=t+Math.imul(t^t>>>7,61|t)^t;return((t^t>>>14)>>>0)/4294967296;};}
function textPlate(T, text, w){
  var c=document.createElement('canvas');c.width=512;c.height=128;
  var g=c.getContext('2d');
  g.fillStyle='#101418';g.fillRect(0,0,512,128);
  g.strokeStyle='#d8aa48';g.lineWidth=5;g.strokeRect(7,7,498,114);
  g.fillStyle='#e8c86a';g.textAlign='center';g.textBaseline='middle';
  g.font='bold 46px Georgia,serif';g.fillText(text,256,66);
  var t=new T.CanvasTexture(c);t.encoding=T.sRGBEncoding;t.anisotropy=4;return t;
}
function quietMarker(T,text){
  var grp=new T.Group();
  var stone=new T.Mesh(new T.BoxGeometry(4.4,0.6,2.2),new T.MeshLambertMaterial({color:0x1e2228}));
  stone.position.y=0.65;stone.rotation.x=-0.45;grp.add(stone);
  /* THE BATTENING (2026-10-14): the face was 4.0x1.0 at (0,0.88,0.52) — inside the stone (0.57 along the normal vs its 1.10 front). Now a fitted plaque (2.32x0.58, the plate's own aspect) PROUD at 1.13; sampler-verified 0 of 7 points inside. */
  var face=new T.Mesh(new T.PlaneGeometry(2.32,0.58),new T.MeshBasicMaterial({map:textPlate(T,text)}));
  face.position.set(0,1.142,1.018);face.rotation.x=-0.45;grp.add(face);
  var base=new T.Mesh(new T.BoxGeometry(4.6,0.3,2.4),new T.MeshLambertMaterial({color:0x14171c}));
  base.position.y=0.15;grp.add(base);
  return grp;
}
// glass facade texture: daytime reflective blue-glass with window grid
function facadeTex(T, tint){
  var c=document.createElement('canvas');c.width=128;c.height=256;
  var g=c.getContext('2d');
  var gr=g.createLinearGradient(0,0,0,256);
  gr.addColorStop(0,'#9fc4e8');gr.addColorStop(0.5,'#7aa8d8');gr.addColorStop(1,'#5a88c0');
  g.fillStyle=gr;g.fillRect(0,0,128,256);
  g.fillStyle=tint||'rgba(20,40,70,0.55)';
  for(var y=6;y<256;y+=14)for(var x=4;x<128;x+=12){ g.fillRect(x,y,8,9); }
  g.fillStyle='rgba(255,255,255,0.25)';
  for(var y2=6;y2<256;y2+=14)for(var x2=4;x2<128;x2+=12){ g.fillRect(x2,y2,8,2); }
  var t=new T.CanvasTexture(c);t.encoding=T.sRGBEncoding;
  t.wrapS=t.wrapT=T.RepeatWrapping;return t;
}
/* Interior podium builder for Hyper City — adds REAL building interiors.
 * Appended to hyper-city.js. Builds 3 podium+tower structures:
 * - Spire podium (cylindrical, 70m dia, 95m tall): lobby, 4 floors, observatory
 * - 2 tower podiums (box, 50x50m, 60m tall): lobby, 3 floors, roof deck
 * Each with: doors, lobby fit-out, elevator (rideable), rooms, roof.
 */
/* Interior podium builder v2 — TWO REAL FLOORS, then portholes.
 * The King's refinement: "I just need the first 2 floors for the buildings
 * the rest will be port holes aka portals."
 * - Floor 1 (lobby): REAL — doors, columns, desk, full fit-out
 * - Floor 2: REAL — corridors, offices/rooms
 * - Roof/Observatory: REAL deck
 * - Above: porthole discs (glowing portals) on the facade, wormhole aesthetic
 */
function buildInteriorPodium(T, root, foot, elevators, standFloors, o) {
  var R = o.R;
  var glassA = o.glassA, gold = o.gold, steel = o.steel;
  var deckM = new T.MeshLambertMaterial({ color: 0x2c313a });
  var wallM = new T.MeshLambertMaterial({ color: 0x3a4048 });
  var floorM = new T.MeshLambertMaterial({ color: 0x4a5058 });
  var deskM = new T.MeshLambertMaterial({ color: 0x6a5a40 });
  var partM = new T.MeshLambertMaterial({ color: 0x8a8a90 });
  var ceilM = new T.MeshLambertMaterial({ color: 0x2a2e34 });
  var g = new T.Group();
  g.position.set(o.x, 0, o.z);
  var isCyl = !!o.cyl;
  var W = o.w, D = o.d, H = o.h;
  var floors = o.floors; // [0, floor2Y, roofY]
  var i, j;

  function box(w, h, d, mat, x, y, z, ry) {
    var m = new T.Mesh(new T.BoxGeometry(w, h, d), mat);
    m.position.set(x, y, z); if (ry) m.rotation.y = ry;
    g.add(m); return m;
  }
  function solid(cx, cz, 