<!-- SOLID CITY · part 2832 -->
k] = extra[k]; return new T.MeshLambertMaterial(p); }
  function sway(mat, base) {
    mat.onBeforeCompile = function (sh) {
      sh.uniforms.uTime = uTime;
      sh.vertexShader = 'uniform float uTime;\n' + sh.vertexShader.replace('#include <begin_vertex>', '#include <begin_vertex>\n#ifdef USE_INSTANCING\n vec4 ipos = instanceMatrix * vec4(0.0, 0.0, 0.0, 1.0);\n float swy = sin(uTime * 1.7 + ipos.x * 0.35 + ipos.z * 0.41) * 0.055 * (position.y + ' + base + ');\n transformed.x += swy; transformed.z += swy * 0.6;\n#endif');
    };
    mat.customProgramCacheKey = function () { return 'nature-sway-' + base; };
    return mat;
  }
  function greens(c, base, spread) { var g = base + CR() * spread; c.setHSL(0.26 + CR() * 0.05, 0.5, g); }

  /* ——— STONES: crystallized, jittered in the bake ——— */
  var stoneGeo = new T.IcosahedronGeometry(1, 1);
  (function () { var p = stoneGeo.attributes.position, v = new T.Vector3(), jr = mulberry(777); for (var i = 0; i < p.count; i++) { v.fromBufferAttribute(p, i); var s = 0.78 + jr() * 0.45; p.setXYZ(i, v.x * s, v.y * s * 0.82, v.z * s); } stoneGeo.computeVertexNormals(); })();
  var stones = scatter(hiTier ? 850 : 500, function (x, z, h) { if (h < 2.2) return null; return { x: x, z: z, y: h, ry: R() * 6.28, s: 0.25 + Math.pow(R(), 2.2) * 1.6 }; });
  counts.stones = stones.length; note('stones', stones);
  instanced('stones', stoneGeo, lambert(0xffffff, { flatShading: true }), stones,
    function (d, p) { d.position.set(p.x, p.y + p.s * 0.18, p.z); d.rotation.set(0, p.ry, 0); d.scale.set(p.s, p.s * 0.8, p.s); },
    function (c) { var g = 0.34 + CR() * 0.22; c.setRGB(g, g * 1.01, g * 1.07); });

  /* ——— GRASS: meadow-clustered, wind in its bones ——— */
  var meadowC = []; for (var ci = 0; ci < 70; ci++) meadowC.push({ x: -3200 + R() * 6400, z: -3300 + R() * 6600 });
  function meadowy(x, z) { for (var i = 0; i < meadowC.length; i++) { var dx = x - meadowC[i].x, dz = z - meadowC[i].z; if (dx * dx + dz * dz < 900) return true; } return false; }
  var grassGeo = new T.ConeGeometry(0.17, 0.6, 5); grassGeo.translate(0, 0.28, 0);
  var grass = scatter(hiTier ? 6500 : 2600, function (x, z, h) {
    if (h < 2.5 || h > 140 || slope(x, z, h) > 0.55) return null;
    if (!meadowy(x, z) && R() > 0.30) return null;
    return { x: x, z: z, y: h, ry: R() * 6.28, s: 0.7 + R() * 0.9 };
  });
  counts.grass = grass.length; note('grass', grass);
  instanced('grass', grassGeo, sway(lambert(0xffffff), '0.0'), grass,
    function (d, p) { d.position.set(p.x, p.y - 0.03, p.z); d.rotation.set(0, p.ry, 0); d.scale.setScalar(p.s); },
    function (c) { greens(c, 0.20, 0.16); });

  /* ——— FLOWERS: stems in the wind, heads of colour ——— */
  var flowers = scatter(hiTier ? 850 : 380, function (x, z, h) {
    if (h < 2.5 || h > 120 || slope(x, z, h) > 0.5) return null;
    if (!meadowy(x, z) && R() > 0.45) return null;
    return { x: x, z: z, y: h, ry: R() * 6.28, s: 0.8 + R() * 0.5 };
  });
  counts.flowers = flowers.length; note('flowers', flowers);
  var stemGeo = new T.CylinderGeometry(0.012, 0.02, 0.34, 5); stemGeo.translate(0, 0.17, 0);
  instanced('flower-stems', stemGeo, sway(lambert(0x3d6b2f), '0.0'), flowers,
    function (d, p) { d.position.set(p.x, p.y - 0.02, p.z); d.rotation.set(0, p.ry, 0); d.scale.setScalar(p.s); }, null);
  var headGeo = new T.IcosahedronGeometry(0.06, 0);
  var PALETTE = [0xd84a5a, 0xe8b13c, 0x9a6ae0, 0xf2ead8, 0xe07ab0, 0xe2703a];
  instanced('flower-heads', headGeo, sway(lambert(0xffffff), '0.36'), flowers,
    function (d, p) { d.position.set(p.x, p.y + 0.36 * p.s, p.z); d.rotation.set(0, p.ry, 0); d.scale.setScalar(p.s); },
    function (c) { c.setHex(PALETTE[Math.floor(CR() * PALETTE.length)]); });

  /* ——— BUSHES: squashed crystal blobs of green ——— */
  var bushGeo = new T.IcosahedronGeometry(1, 1); bushGeo.scale(1, 0.62, 1);
  var bushes = scatter(hiTier ? 480 : 260, function (x, z, h) { if (h < 2.5 || h > 170 || slope(x, z, h) > 0.85) return null; return { x: x, z: z, y: h, ry: R() * 6.28, s: 0.5 + R() * 1.1 }; });
  counts.bushes = bushes.length; note('bushes', bushes);
  instanced('bushes', bushGeo, lambert(0xffffff, { flatShading: true }), bushes,
    function (d, p) { d.position.set(p.x, p.y + p.s * 0.3, p.z); d.rotation.set(0, p.ry, 0); d.scale.setScalar(p.s); },
    function (c) { greens(c, 0.16, 0.12); });

  /* ——— PALMS: leaning trunks, umbrella crowns ——— */
  var palmTrunkGeo = new T.CylinderGeometry(0.13, 0.24, 4.6, 6); palmTrunkGeo.translate(0, 2.3, 0);
  var palmCrownGeo = new T.IcosahedronGeometry(1.7, 0); palmCrownGeo.scale(1.25, 0.34, 1.25);
  var palms = scatter(hiTier ? 110 : 60, function (x, z, h) { if (h < 2.5 || h > 70 || slope(x, z, h) > 0.6) return null; return { x: x, z: z, y: h, ry: R() * 6.28, s: 0.9 + R() * 0.5, la: R() * 6.28, ll: 0.05 + R() * 0.13 }; });
  counts.palms = palms.length; note('palms', palms);
  var trunkMat = lambert(0x6e5136);
  instanced('palm-trunks', palmTrunkGeo, trunkMat