<!-- SOLID CITY · part 65 -->
nd the map we have here, and let the roads travel to them").
   An expansion of the EXISTING capital in the same world coordinates: 8 campuses on a ring ~1.18 km from the Forum Plaza,
   on the island side (north round to south-east; the west is the coast). Every campus is joined to the city by a paved radial
   road from the city edge, and all campuses by the University Ring boulevard. Loaded BEFORE city.js:
   - city.js heightAt()/groundAt() flatten a road bed and the campus pads to city level (flatW),
   - hyper.js marks roads + pads walkable in its A* grid (walk) so AI Drive and citizens follow the roads,
   - campus.js draws the roads, halls, sign posts and the catalog / library UI. Plain data + math, no THREE. */
(function () {
'use strict';
var D2R = Math.PI / 180, RING = 1180, PAD = 92, ROAD = 6.5, GATE_R = 770;
var CAMPUS = [
  { id: 'sciences',    name: 'Sciences',                                 short: 'SCIENCES',    deg: -100, hall: 'observatory' },
  { id: 'mathcs',      name: 'Mathematics & Computer Science / AI',      short: 'MATH \u00b7 CS \u00b7 AI', deg: -70, gdeg: -1.5, hall: 'ziggurat' },
  { id: 'engineering', name: 'Engineering & Architecture',               short: 'ENGINEERING', deg: -40,  gdeg: 6, hall: 'truss' },
  { id: 'arts',        name: 'Arts & Music',                             short: 'ARTS & MUSIC', deg: -10, gdeg: 4.5, hall: 'shell' },
  { id: 'humanities',  name: 'Humanities',                               short: 'HUMANITIES',  deg: 20,   hall: 'temple' },
  { id: 'medicine',    name: 'Medicine & Health',                        short: 'MEDICINE',    deg: 50,   gdeg: 0.5, hall: 'cross' },
  { id: 'social',      name: 'Social Sciences, Law & Economics',         short: 'LAW \u00b7 ECON', deg: 80, hall: 'rotunda' },
  { id: 'business',    name: 'Business & Communications',                short: 'BUSINESS \u00b7 COMMS', deg: 110, gdeg: -9, hall: 'towers' }
];
CAMPUS.forEach(function (c) {
  var a = c.deg * D2R, ca = Math.cos(a), sa = Math.sin(a);
  c.x = Math.round(ca * RING); c.z = Math.round(sa * RING);
  var ga = (c.deg + (c.gdeg || 0)) * D2R;                              // gate angle: nudged to a clear gap in the edge skyline
  c.gate = { x: Math.cos(ga) * GATE_R, z: Math.sin(ga) * GATE_R };    // where the radial road leaves the city
  c.front = { x: ca * (RING - 62), z: sa * (RING - 62) };              // the hall's forecourt (faces the city)
  c.face = Math.atan2(-ca, -sa);                                       // rotation.y so local +z points back to the city
  c.radial = [c.gate, { x: ca * (RING - PAD + 4), z: sa * (RING - PAD + 4) }];
});
var A0 = CAMPUS[0].deg * D2R, A1 = CAMPUS[CAMPUS.length - 1].deg * D2R;
function segD(px, pz, a, b) { var dx = b.x - a.x, dz = b.z - a.z, l = dx * dx + dz * dz, t = l ? ((px - a.x) * dx + (pz - a.z) * dz) / l : 0; t = t < 0 ? 0 : t > 1 ? 1 : t; return Math.hypot(px - a.x - dx * t, pz - a.z - dz * t); }
/* distance (m) from (x,z) to the nearest road centre-line / campus pad edge (<= 0 inside a pad) */
function dist(x, z) {
  var r = Math.sqrt(x * x + z * z); if (r < 700 || r > RING + PAD + 420) return 1e9;
  var best = 1e9, i, c, ang = Math.atan2(z, x);
  for (i = 0; i < CAMPUS.length; i++) {
    c = CAMPUS[i];
    var dp = Math.hypot(x - c.x, z - c.z) - PAD; if (dp < best) best = dp;
    var dr = segD(x, z, c.radial[0], c.radial[1]); if (dr < best) best = dr;
  }
  if (ang >= A0 && ang <= A1) { var dg = Math.abs(r - RING); if (dg < best) best = dg; }    // the University Ring
  return best;
}
/* terrain flatten weight 0..1 for heightAt: flat 22 m either side of a road (pads +8), smooth 150 m shoulder */
function flatW(x, z) { var d = dist(x, z); if (d >= 172) return 0; if (d <= 22) return 1; var t = (d - 22) / 150; return 1 - t * t * (3 - 2 * t); }
/* walkable for the Hyper A* grid (outside the city disc): the paved roads and the campus pads */
function walk(x, z) { return dist(x, z) <= ROAD; }
function nameAt(x, z) {
  for (var i = 0; i < CAMPUS.length; i++) { var c = CAMPUS[i]; if (Math.hypot(x - c.x, z - c.z) < PAD + 40) return c.short + ' CAMPUS'; }
  var r = Math.hypot(x, z); if (r > 790 && dist(x, z) < 30) return 'UNIVERSITY ROAD';
  return '';
}
window.CampusMap = { CAMPUS: CAMPUS, RING: RING, PAD: PAD, ROAD: ROAD, GATE_R: GATE_R, A0: A0, A1: A1, dist: dist, flatW: flatW, walk: walk, nameAt: nameAt,
  get: function (id) { for (var i = 0; i < CAMPUS.length; i++) if (CAMPUS[i].id === id) return CAMPUS[i]; return null; } };
})();


===== FILE: public/city/campus.js =====
/* SOLID CITY UNIVERSITY — stage 1 (2026-10-10, the King: "Build a bigger map ... where humans and AI can create their own libraries";
   "Expand the map we have here, and let the roads travel to them").
   The capital grows outward in the SAME world: 8 campuses on a ring (campus-map.js), paved lit roads from the existing districts
   out to every campus and the University Ring boulevard between them. city.js flattens the road be