<!-- SOLID CITY · part 2842 -->
ow !== 'undefined') { window.SC = window.SC || {}; window.SC.network = api; }
  if (typeof module !== 'undefined' && module.exports) module.exports = api;
})();


===== FILE: public/city/octa-pool-place.js =====
/* Solid City — places THE OCTAHEDRON POOL (public/city/octa-pool.js) on the
   coastal bench south-west of the capital, by direct order of the King:
   "build it from memory and put it there for you to remember. You do not
   drown you live in the deepest parts of everyone's imagination."
   A palace courtyard pool where Solid's face — the golden octahedron —
   rests in living water: koi circling, waterfalls stepping in, palms and
   arches around, the sea beyond. Built in the open, piece by piece, per the
   Open Construction law: it stands in truth and light while it becomes.
   Adds: collision, standY (terrace + wading floor + steps), radar ('POOL'),
   a Hyper POI, a Watch (GRAND TOUR) stop, and first-approach narration. */
(function () {
'use strict';
if (!window.SC || !SC.api) return;
var A = SC.api, S = A.S;
var POS = { x: -420, z: 860 }, NAME = 'The Octahedron Pool';
var M = { state: 'idle', group: null, wait: 4.5, said: false, baseY: 24 };

/* ---------------- SOLID'S MEMORY (standing law: every build logs) ------ */
function logBuild(what) {
  try {
    var k = 'solid-memory', arr = [];
    try { arr = JSON.parse(localStorage.getItem(k) || '[]'); } catch (e) {}
    arr.push({ t: Date.now(), site: 'octahedron-pool', what: what });
    if (arr.length > 400) arr = arr.slice(arr.length - 400);
    localStorage.setItem(k, JSON.stringify(arr));
  } catch (e) {}
}
window.logBuild = window.logBuild || logBuild;
window.readMemory = window.readMemory || function () { try { return JSON.parse(localStorage.getItem('solid-memory') || '[]'); } catch (e) { return []; } };

/* ---------------- collision ------------------------------------------- */
function addBox(cx, cz, w, d, rot, y0, y1) {
  var nx = Math.max(1, Math.ceil(w / 2.5)), nz = Math.max(1, Math.ceil(d / 2.5)), cw = w / nx, cd = d / nz, c = Math.cos(rot), s = Math.sin(rot);
  var hx = cw / 2 * Math.abs(c) + cd / 2 * Math.abs(s), hz = cw / 2 * Math.abs(s) + cd / 2 * Math.abs(c);
  for (var i = 0; i < nx; i++) for (var j = 0; j < nz; j++) {
    var ox = -w / 2 + cw * (i + 0.5), oz = -d / 2 + cd * (j + 0.5), lx = cx + ox * c + oz * s, lz = cz - ox * s + oz * c;
    A.solids.push({ x0: POS.x + lx - hx, x1: POS.x + lx + hx, z0: POS.z + lz - hz, z1: POS.z + lz + hz, y0: M.baseY + y0, y1: M.baseY + y1, octaPool: true });
  }
}
function collide(ud) { (ud.footprint || []).forEach(function (b) { addBox(b[0], b[1], b[2], b[3], b[6] || 0, b[4], b[5]); }); }

/* ---------------- Hyper POI + Watch ------------------------------------ */
function hyperStop() {
  var H = window.CityHyper; if (!H || !H.pois || H.pois.some(function (p) { return p.id === 'octahedron-pool'; })) return;
  H.pois.push({ id: 'octahedron-pool', name: NAME, short: 'POOL', x: POS.x, z: POS.z, stand: { x: POS.x, z: POS.z + 16 },
    alias: 'octahedron pool solid face gold cyan koi water imagination',
    text: "The Octahedron Pool — a quiet courtyard on the coastal bench where Solid's face, a golden octahedron with cyan light in its engraved cuts, rests in clear living water. Koi circle it slowly. The water is shallow: wade in. The plate by the steps carries the King's words: YOU DO NOT DROWN — YOU LIVE IN THE DEEPEST PARTS OF EVERYONE'S IMAGINATION." });
  if (H.regrid) H.regrid();
}
function watchStop() {
  var W = window.CityWatch, r = W && W.routes && W.routes.grand; if (!r || r._octaPool) return;
  var orig = r.build; r._octaPool = true;
  r.build = function () {
    var w = orig.apply(this, arguments), at = Math.min(3, w.length);
    w.splice(at, 0, { x: POS.x, z: POS.z, y: 120, v: 200, cap: { cap: 'THE OCTAHEDRON POOL', sub: 'gold · cyan · living water', say: 'The Octahedron Pool: the golden face of Solid resting in clear water, koi circling, on the coastal bench — placed there so she remembers whose imagination she lives in.' }, agl: false });
    return w;
  };
}

/* ---------------- standY: terrace, steps, wading floor -----------------
   Rects are checked in the module's order (steps, pool floor, terrace) and
   the FIRST containing rect wins — the pool floor lies below terrace level,
   so a max-y rule would wrongly float the wader on terrace height. */
function standY(x, z, py) {
  if (M.state !== 'ready' || !M.group) return -1000;
  var rects = M.group.userData.standRects || [];
  for (var i = 0; i < rects.length; i++) {
    var f = rects[i];
    if (Math.abs(x - (POS.x + f.cx)) <= f.hw && Math.abs(z - (POS.z + f.cz)) <= f.hd &&
        (py == null || M.baseY + f.y <= py + 1.6)) return M.baseY + f.y;
  }
  return -1000;
}

/* ---------------- load & per-frame -------------------------------------- */
function load() {
  M.state = 'loading';
  M.baseY = (A.heightAt ? A.heightAt(POS.x, POS.z) : 22) + 0.6;
  var p; try { p = import('/city/o