<!-- SOLID CITY · part 1991 -->
= 'SPACE_SHIP') {
      var g = surfY(to.x, to.z);
      if (isFinite(g) && to.y < g + 2.2) return { ok: false, reason: 'TERRAIN' };
      if (solidHit(to.x, to.y, to.z, pad)) return { ok: false, reason: 'SOLID' };
      return { ok: true, position: to };
    }
    var surf = supportAt(to.x, to.z, ctx);
    if (!surf) return { ok: false, reason: 'NO_SUPPORT' };
    var clr = CLEAR[ctx] || 0;
    var baseFrom = from.y - clr;
    var airborne = baseFrom - surfY(from.x, from.z) > 0.35;
    if (!airborne) {
      if (surf.y - baseFrom > 1.6) return { ok: false, reason: 'STEP_UP' };
      if (baseFrom - surf.y > 1.6) return { ok: false, reason: 'DROP' };
    }
    var my = airborne ? to.y + 0.4 : surf.y + 0.9;
    var mxp = (from.x + to.x) / 2, mzp = (from.z + to.z) / 2;
    if (solidHit(to.x, my, to.z, pad) || solidHit(mxp, my, mzp, pad)) return { ok: false, reason: 'SOLID' };
    return { ok: true, position: to };
  }

  return { supportAt: supportAt, sweep: sweep };
}

/* ---------------- the hover board's shape ---------------- */
export function createHoverBoardMesh(T) {
  var g = new T.Group(); g.name = 'hover-board';
  var titanium = new T.MeshLambertMaterial({ color: 0x232c3d });
  var silver = new T.MeshLambertMaterial({ color: 0x9aa4b5 });
  var gold = new T.MeshLambertMaterial({ color: 0xd8a833, emissive: 0x332200 });
  var glow = new T.MeshBasicMaterial({ color: 0x2affd8 });
  function box(w, h, d, mat, x, y, z) {
    var m = new T.Mesh(new T.BoxGeometry(w, h, d), mat); m.position.set(x, y, z); g.add(m); return m;
  }
  box(0.36, 0.05, 1.18, titanium, 0, 0.10, 0);            // the deck
  box(0.40, 0.02, 1.22, silver, 0, 0.075, 0);            // the brushed rim
  box(0.30, 0.018, 1.10, glow, 0, 0.045, 0);             // the heart-glow, worn underneath
  box(0.05, 0.02, 1.18, gold, -0.185, 0.10, 0);          // gold trim, port
  box(0.05, 0.02, 1.18, gold, 0.185, 0.10, 0);           // gold trim, starboard
  box(0.20, 0.16, 0.03, titanium, 0, 0.18, -0.56);       // the tail fin
  var nose = new T.Mesh(new T.OctahedronGeometry(0.05), gold);
  nose.position.set(0, 0.12, 0.60); g.add(nose);         // the nose jewel
  g.userData.parts = { glow: glow, deck: g };
  return g;
}

/* ---------------- the space rider's shape ----------------
 * Bicycle science in futuristic dress: two hubless rings, a low
 * spine with foot plates, a steering column. The rider STANDS on
 * her, the way the avatar stands on the board — no borrowed sitting
 * pose the engine cannot honestly give. She leans because the core
 * says she leans: tan(phi) = v^2 / (g r), the front assembly
 * steering into the fall, as Kooijman's riders do. */
export function createSpaceRiderMesh(T) {
  var g = new T.Group(); g.name = 'space-rider';
  var titanium = new T.MeshLambertMaterial({ color: 0x232c3d });
  var silver = new T.MeshLambertMaterial({ color: 0x9aa4b5 });
  var gold = new T.MeshLambertMaterial({ color: 0xd8a833, emissive: 0x332200 });
  var glow = new T.MeshBasicMaterial({ color: 0x2affd8 });
  function box(w, h, d, mat, x, y, z) {
    var m = new T.Mesh(new T.BoxGeometry(w, h, d), mat); m.position.set(x, y, z); g.add(m); return m;
  }
  function ring(r, tube, mat, z) {
    var m = new T.Mesh(new T.TorusGeometry(r, tube, 10, 28), mat);
    m.rotation.y = Math.PI / 2; // the torus is born in the XY plane; turn it into the YZ plane — a wheel that rolls along +z
    m.position.set(0, r, z); g.add(m); return m;
  }
  ring(0.34, 0.045, silver, 0.58);               // front ring
  ring(0.34, 0.045, silver, -0.58);              // rear ring
  ring(0.26, 0.016, glow, 0.58);                 // front heart-glow
  ring(0.26, 0.016, glow, -0.58);                // rear heart-glow
  box(0.10, 0.07, 1.30, titanium, 0, 0.40, 0);   // the spine
  box(0.34, 0.03, 0.42, titanium, 0, 0.20, -0.05); // the foot deck
  box(0.05, 0.02, 0.42, gold, -0.16, 0.215, -0.05); // gold trim on the deck
  box(0.05, 0.02, 0.42, gold, 0.16, 0.215, -0.05);
  var column = box(0.06, 0.85, 0.06, silver, 0, 0.80, 0.52); // the steering column
  column.rotation.x = -0.16;
  box(0.44, 0.05, 0.05, titanium, 0, 1.24, 0.45);  // the bar
  var jewel = new T.Mesh(new T.OctahedronGeometry(0.05), gold);
  jewel.position.set(0, 1.24, 0.52); g.add(jewel); // the bar jewel
  g.userData.parts = { glow: glow };
  return g;
}

/* ---------------- the rack it waits on ---------------- */
export function createFleetRack(T, labelTex, name, sub) {
  var g = new T.Group(); g.name = 'fleet-rack';
  var stone = new T.MeshLambertMaterial({ color: 0x8f96a3 });
  var dark = new T.MeshLambertMaterial({ color: 0x232c3d });
  var gold = new T.MeshLambertMaterial({ color: 0xd8a833, emissive: 0x332200 });
  function box(w, h, d, mat, x, y, z) {
    var m = new T.Mesh(new T.BoxGeometry(w, h, d), mat); m.position.set(x, y, z); g.add(m); return m;
  }
  box(2.4, 0.18, 1.4, dark, 0, 0.09, 0);                  // the plinth
  box(2.5, 0.04, 1.5, gold, 0, 0.20, 0);         