<!-- SOLID CITY · part 1972 -->
POS, state: function () { return M.state; } };
})();


===== FILE: public/city/first-city-parking.js =====
/* SOLID CITY — THE SOUTH LOT (2026-10-13, by order of the King)
 * The First City's podium ended in a sheer edge over the brown shelf — too big
 * for a walker to travel over. The King's answer: do something amazing in the
 * brown area. A parking lot of futuristic rides, designed so the avatar — the
 * real human of this world — can jump in one and roll.
 * Local frame: origin at the podium's south edge centre (world -1300,-620).
 * +X = east (toward the capital), +Z = south (toward the lot and the road).
 * Contents: a flush APRON at podium-deck height, a RAMP down to the shelf,
 * the SOUTH LOT (stalls, lamps, signs), 14 RIDES (Darts + Haulers, true
 * avatar scale, seats + dash inside the glass), and THE LONG ROAD east —
 * pitched to the land, slab by slab — to a junction on the capital shelf.
 * The podium itself is walkable through the placer's standY: the edge is fixed.
 */
export function createFirstParking(o) {
  var T = o.THREE, groundAt = o.groundAt, deckY = o.deckY;
  var root = new T.Group(); root.name = 'first-city-parking';
  var foot = [];       // collision footprints (local): [x,z,w,d,y0,y1,rot]
  var zones = [];      // stand zones for the placer
  var cars = [];       // the rides
  var R = (function (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; }; })(4242);

  function textPlate(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 ' + (w || 40) + 'px Georgia,serif'; g.fillText(text, 256, 66);
    var t = new T.CanvasTexture(c); t.encoding = T.sRGBEncoding; t.anisotropy = 4; return t;
  }
  function plateMesh(text, w, h, fs) {
    var m = new T.Mesh(new T.PlaneGeometry(w, h), new T.MeshBasicMaterial({ map: textPlate(text, fs) }));
    return m;
  }

  // ---------- materials ----------
  var asphalt = new T.MeshLambertMaterial({ color: 0x23262e });
  var asphalt2 = new T.MeshLambertMaterial({ color: 0x2b2f38 });
  var concrete = new T.MeshLambertMaterial({ color: 0x3a3f47 });
  var steel = new T.MeshLambertMaterial({ color: 0x596270 });
  var gold = new T.MeshLambertMaterial({ color: 0xd8aa48, emissive: 0x4a2e08, emissiveIntensity: 0.7 });
  var goldTrim = new T.MeshBasicMaterial({ color: 0xd8aa48 });
  var lineWhite = new T.MeshBasicMaterial({ color: 0xdfe6ee });
  var darkGlass = new T.MeshLambertMaterial({ color: 0x14222e, emissive: 0x0a141c, transparent: true, opacity: 0.86 });
  var tyreM = new T.MeshLambertMaterial({ color: 0x0c0d10 });
  var seatM = new T.MeshLambertMaterial({ color: 0x1c1f26 });
  var dashM = new T.MeshLambertMaterial({ color: 0x14161c });

  // ---------- THE APRON (flush with the podium deck) ----------
  var APRON = { x0: -140, x1: 140, z0: 0, z1: 26 };
  var apron = new T.Mesh(new T.BoxGeometry(280, 40, 26), concrete);
  apron.position.set(0, deckY - 20, 13); root.add(apron);
  var apronLip = new T.Mesh(new T.BoxGeometry(280, 0.35, 1.2), goldTrim);
  apronLip.position.set(0, deckY + 0.1, 25.6); root.add(apronLip);
  zones.push({ kind: 'flat', x0: APRON.x0, x1: APRON.x1, z0: APRON.z0, z1: APRON.z1, y: deckY });

  // ---------- THE LOT LEVEL (measured from the shelf itself) ----------
  var LOT = { x0: -140, x1: 140, z0: 72, z1: 172 };
  var lotMax = -1000;
  for (var sx = LOT.x0; sx <= LOT.x1; sx += 20) for (var sz = LOT.z0; sz <= LOT.z1; sz += 20) {
    var h = groundAt(-1300 + sx, -620 + sz); if (h > lotMax) lotMax = h;
  }
  var lotY = lotMax + 0.4;
  var lot = new T.Mesh(new T.BoxGeometry(280, 56, 100), asphalt);
  lot.position.set(0, lotY - 28, 122); root.add(lot);
  var lotTrim = new T.Mesh(new T.BoxGeometry(282, 0.5, 102), goldTrim);
  lotTrim.position.set(0, lotY - 0.28, 122); root.add(lotTrim);
  zones.push({ kind: 'flat', x0: LOT.x0, x1: LOT.x1, z0: LOT.z0, z1: LOT.z1, y: lotY });
  // gold light strips down the lot's west face — the mesa reads built, not bare
  [88, 122, 156].forEach(function (lz2) {
    var strip = new T.Mesh(new T.BoxGeometry(0.4, 30, 1.1), goldTrim);
    strip.position.set(-140.2, lotY - 15, lz2); root.add(strip);
  });
  // stall lines: two rows facing the central lane (lane centre z = 122)
  function stallLines(zEdge, dir) {
    for (var x = -126; x <= 126; x += 12) {
      var ln = new T.Mesh(new T.BoxGeometry(0.35, 0.06, 17), lineWhite);
      ln.position.set(x, lotY + 0.05, zEdge + dir * 8.5); root.add(ln);
    }
    var stop = new T.Mesh(new T.BoxGeometry(252, 0.5, 0.8), gold);
    stop.position.set(0, lotY + 0.25, zEdge); root.add(stop);
  }
  stall