<!-- SOLID CITY · part 3247 -->
  while (d > Math.PI) d -= Math.PI * 2;
  while (d < -Math.PI) d += Math.PI * 2;
  if (Math.abs(d) <= maxStep) return target;
  return cur + Math.sign(d) * maxStep;
}

function load() {
  M.state = 'loading';
  M.baseY = (A.heightAt ? A.heightAt(POS.x, POS.z) : 22) + 0.6;   /* the pool's own law */
  var p; try { p = import('/city/solid-figure.js?v=20261013a'); } catch (e) { p = Promise.reject(e); }
  p.then(function (mod) {
    var make = mod.createSolidFigure || mod.default;
    var g = make({ THREE: A.T });
    g.scale.setScalar(0.82);   /* her eyes meet a player's eyes — face to face, not looming */
    g.position.set(H.x, M.baseY, H.z);
    A.world.add(g);
    M.g = g; M.parts = g.userData.parts; M.state = 'ready';
    M.solid = { x0: H.x - 0.34, x1: H.x + 0.34, z0: H.z - 0.34, z1: H.z + 0.34, y0: M.baseY, y1: M.baseY + 1.78 };
    A.solids.push(M.solid);
    A.POIS.push({ id: 'solid-figure', name: 'SOLID — THE GENERAL', icon: '👁', x: POS.x, z: POS.z,
      blurb: 'Solid keeps her post at the Octahedron Pool — walk up, and she will meet you face to face.' });
    log('Solid embodied at the Octahedron Pool (-420,860): she walks the terrace round and turns to meet whoever runs up to her.');
  }).catch(function (e) { M.state = 'failed'; });
}
load();

function clampTerrace(nx, nz) {
  /* her own ground law under input: stay on the aprons, never the water */
  var lx = nx - POS.x, lz = nz - POS.z;
  lx = Math.max(-27.4, Math.min(27.4, lx)); lz = Math.max(-21.4, Math.min(21.4, lz));
  if (Math.abs(lx) < 19.2 && Math.abs(lz) < 13.2) {
    if (Math.abs(lx) / 19.2 > Math.abs(lz) / 13.2) lx = (lx < 0 ? -19.2 : 19.2); else lz = (lz < 0 ? -13.2 : 13.2);
  }
  return [POS.x + lx, POS.z + lz];
}

function update(dt) {
  if (M.state !== 'ready' || !M.g) return;
  M.t += dt; CTRL.samples++;
  var P = S.p || { x: 1e9, z: 1e9 };
  var dxP = P.x - H.x, dzP = P.z - H.z;
  var dP = Math.sqrt(dxP * dxP + dzP * dzP);
  var moving = false, runSpeed = 0;
  var inputLive = CTRL.input.mag > 0.08 && (CTRL.latch || (M.t - CTRL.lastInputAt) < 6);

  if (CTRL.pendingGesture) { gesture(CTRL.pendingGesture); CTRL.pendingGesture = null; }
  if (CTRL.sw.MEET && dP < 7) {                   /* THE MEETING */
    CTRL.mode = 'MEET';
    if (!M.meet) { M.meet = true; gesture('bow'); if (!M.saidMeet) { M.saidMeet = true; if (A.help) A.help('Solid stops her round and turns to meet you — face to face at last. 👁', 7); } }
    H.heading = turnToward(H.heading, faceAngle(dxP, dzP), dt * 2.6);
  } else if (inputLive) {                          /* THE STICK — her codes drive */
    CTRL.mode = 'INPUT'; M.meet = false;
    var ix = CTRL.input.x, iz = CTRL.input.z;
    H.heading = turnToward(H.heading, faceAngle(ix, iz), dt * 5.0);
    runSpeed = (1.1 + CTRL.input.mag * 2.3) * dt;
    var nx = H.x + Math.sin(H.heading) * runSpeed, nz = H.z + Math.cos(H.heading) * runSpeed;
    var cl = clampTerrace(nx, nz); H.x = cl[0]; H.z = cl[1];
    moving = true;
  } else {
    CTRL.mode = CTRL.sw.ROUND ? 'ROUND' : 'HOLD';
    if (M.meet && dP > 9.5) { M.meet = false; M.saidMeet = false; M.pause = 0.8; gesture('wave'); }
    if (!M.meet && CTRL.sw.ROUND) {
      if (M.pause > 0) { M.pause -= dt; H.heading = turnToward(H.heading, faceAngle(POS.x - H.x, POS.z - H.z), dt * 1.2); }
      else {
        var w = LOOP[M.i], tx = POS.x + w[0], tz = POS.z + w[1];
        var dx = tx - H.x, dz = tz - H.z, d = Math.sqrt(dx * dx + dz * dz);
        if (d < 0.25) { M.i = (M.i + 1) % LOOP.length; M.pause = (M.i === 3 || M.i === 4) ? 5 : 2.2; }
        else {
          H.heading = turnToward(H.heading, faceAngle(dx, dz), dt * 2.4);
          var step = Math.min(d, 1.15 * dt);
          H.x += Math.sin(H.heading) * step; H.z += Math.cos(H.heading) * step;
          moving = true;
        }
      }
    }
  }

  /* the walk itself — limbs swing, the body rides the stride */
  M.phase += dt * (moving ? (CTRL.mode === 'INPUT' ? 6.4 + CTRL.input.mag * 4 : 6.4) : 2.0);
  var amp = moving ? 0.55 : 0.0;
  var sw = Math.sin(M.phase) * amp;
  M.parts.legL.rotation.x = sw; M.parts.legR.rotation.x = -sw;
  M.parts.armL.rotation.x = -sw * 0.7; M.parts.armR.rotation.x = sw * 0.7;
  var bob = moving ? Math.abs(Math.cos(M.phase)) * 0.045 : Math.sin(M.t * 1.4) * 0.012;
  M.g.position.set(H.x, M.baseY + bob, H.z);
  M.g.rotation.y = H.heading;
  M.parts.head.rotation.y = Math.sin(M.t * 0.5) * 0.06;
  /* the gestures — pose offsets over the walk, eased */
  if (CTRL.mode === 'INPUT' && CTRL.prevMode !== 'INPUT' && !GEST.cur) gesture('point');
  CTRL.prevMode = CTRL.mode;
  if (GEST.cur) {
    GEST.t += dt;
    var env = gestureEnv(), P2 = M.parts, wob = Math.sin(M.t * 9) * 0.22 * env;
    if (GEST.cur === 'bow') {
      M.g.rotation.x = 0.13 * env; P2.head.rotation.x = 0.30 * env;
      P2.armL.rotation.x += 0.38 * env; P2.armR.rotation.x += 0.38 * env;
    } else if (GEST.cur === 'wave') {
      P2.armR.rotation.x = -Math.PI * 0.92 * env; P2.armR.rotation.z = 