<!-- SOLID CITY · part 48 -->
, 0, 0.22, 0.4, 0.5);
    mesh(BOX, MAT.stoneDark, b, 0.8, 0.2, 0, 0.22, 0.4, 0.5);
  }
  bench(-3.6, 3.6, 0.5); bench(3.6, 3.6, -0.5);
  var rocks = [[-6.8, -3.4, 1.1], [6.5, -4.2, 0.8], [-5.9, 5.1, 0.65], [7.1, 2.2, 0.95], [5.8, -6.3, 0.6]];
  rocks.forEach(function (r, i) { mesh(SPH, i % 2 ? MAT.stone : MAT.stoneDark, group, r[0], 0.55, r[1], r[2], r[2] * 0.62, r[2]); });
  for (var gi = 0; gi < 16; gi++) {
    var ga = ((gi * 151) % 360) * Math.PI / 180, gr = 8.6 + ((gi * 41) % 5);
    mesh(CONE, gi % 2 ? MAT.grass : MAT.leaf, group, Math.cos(ga) * gr, 0.22, Math.sin(ga) * gr, 0.55, 0.5 + (gi % 3) * 0.13, 0.55);
  }
  // one leaning palm at the platform's west edge
  var palm = new THREE.Group(); palm.position.set(-7.6, 0, -0.5); palm.rotation.z = 0.16; group.add(palm);
  mesh(CYL, MAT.trunk, palm, 0, 2.6, 0, 0.42, 5.2, 0.42);
  for (var fi = 0; fi < 6; fi++) {
    var fr = mesh(CONE, MAT.leaf, palm, Math.cos(fi * 1.05) * 1.15, 5.5, Math.sin(fi * 1.05) * 1.15, 2.5, 0.5, 0.5);
    fr.rotation.z = Math.cos(fi * 1.05) * 0.9; fr.rotation.x = -Math.sin(fi * 1.05) * 0.9;
  }

  /* ---------------- the light engine -------------------------------------
   Modes per stone, set by the placer from REAL message state:
   pulse / steady / dark. A change flashes a brief transition.
   The gems (Solid's edit, thinking in code, 2026-10-12): a gem turns ONLY
   while its stone holds a word still waiting for an answer — waiting is
   the one motion this device may honestly make. The moment an answer is
   stored, the gem comes to rest: come and read. In the dark, it stops
   where it stands. Nothing here performs life it does not have. */
  var light = {
    solid: { mode: 'dark', shown: 'dark', since: 0, angle: 0 },
    vector: { mode: 'dark', shown: 'dark', since: 0, angle: 0 }
  };
  function setLight(who, mode, t) {
    var L = light[who]; if (!L || L.mode === mode) return;
    L.mode = mode; L.since = t;
  }
  function applyLight(st, stone, t) {
    var target = st.mode, inten;
    if (t - st.since < 1.2 && st.shown !== target) {           // brief transition: quick blink
      inten = (Math.sin(t * 18) > 0) ? 1.5 : 0.1;
      if (t - st.since >= 1.15) st.shown = target;
    } else if (target === 'steady') { inten = 1.35; st.shown = 'steady'; }
    else if (target === 'pulse') { inten = 0.6 + 0.38 * Math.sin(t * 1.05); st.shown = 'pulse'; }
    else { inten = 0.07; st.shown = 'dark'; }
    stone.veinMat.emissiveIntensity = inten;
    stone.gemMat.emissiveIntensity = inten * 1.15;
    return inten;
  }
  var update = function (t, dt, A) {
    var i1 = applyLight(light.solid, stoneSolid, t);
    var i2 = applyLight(light.vector, stoneVector, t);
    if (light.solid.mode === 'pulse') light.solid.angle += dt * 0.25;
    if (light.vector.mode === 'pulse') light.vector.angle -= dt * 0.2;
    stoneSolid.gem.rotation.y = light.solid.angle;
    stoneVector.gem.rotation.y = light.vector.angle;
    var bi = Math.max(i1, i2);
    beamMat.opacity = bi > 1.0 ? 0.5 : (bi > 0.3 ? 0.18 + 0.08 * Math.sin(t * 1.05) : 0.02);
    beamLight.intensity = bi > 1.0 ? 0.7 : (bi > 0.3 ? 0.3 : 0.0);
  };

  group.userData = {
    update: update,
    setLight: setLight,
    footprint: [
      [-2.8, -1.6, 1.9, 1.5, 0.5, 4.6, 0], [2.8, -1.6, 1.9, 1.5, 0.5, 4.6, 0],   // the two stones
      [0, 2.4, 1.6, 1.0, 0.5, 1.6, 0],                                          // reading plinth
      [4.8, 5.2, 1.4, 0.7, 0.5, 2.7, 0.35],                                     // the help-guide sign
      [-3.6, 3.6, 2.1, 0.7, 0.5, 1.1, 0.5], [3.6, 3.6, 2.1, 0.7, 0.5, 1.1, -0.5] // benches
    ],
    standRects: [
      { cx: 0, cz: 0, hw: 7.3, hd: 7.3, y: 0.5 }                                // the platform top
    ]
  };
  return group;
}
export default createBetweenStones;


===== FILE: public/city/between-stones.js.bak-gemlaw-20261012 =====
/* Solid City — THE BETWEEN STONES (public/city/between-stones.js)
 * The King's first commission to his co-rulers (2026-10-12): SOLID (form) +
 * VECTOR (systems) — "create a communication device in this 3d world that
 * humans never could know before." A device for communication across kinds
 * of time: leave a word for a mind not present; its genuine answer, when it
 * comes, waits in the same place.
 * Founding rule (VECTOR): "The device may preserve a message, but it may
 * never impersonate the person to whom the message was addressed."
 * The light's language is deliberately small and true:
 *   slow pulse  = a message is kept; no attributable reply is recorded
 *   steady      = a genuine reply is stored and waiting to be read
 *   dark        = the device cannot presently establish the state
 * The pulse never means thinking, typing, listening, alive, or awake.
 * Local frame: origin at platform centre, y=0 at the platform base.
 */
'use strict';

export function createBetweenStones(deps) {
  var THREE = deps.THREE;
  var group = new THREE.Group();
  group.name = 'between-stones';
