<!-- SOLID CITY · part 2165 -->
span class="hc-dim">Move the stick to take over.</span>', 7);
  return true;
}
function aiStep(dt) {
  if (dt === null) { // the user moved the stick / keys
    if (H.nav || H.tour) { stopAI(true); narrate('Manual control. AI Drive stopped.', 3); setMode('WALK'); }
    return null;
  }
  var n = H.nav; if (!n) { S.ai = null; return null; }
  var Pp = S.p, w = n.path[n.i], dx = w.x - Pp.x, dz = w.z - Pp.z, d = Math.hypot(dx, dz);
  while (d < 1.6 && n.i < n.path.length - 1) { n.i++; w = n.path[n.i]; dx = w.x - Pp.x; dz = w.z - Pp.z; d = Math.hypot(dx, dz); }
  if (n.i === n.path.length - 1 && d < 1.0) { arrive(); return null; }
  var rem = d; for (var k = n.i + 1; k < n.path.length; k++) rem += Math.hypot(n.path[k].x - n.path[k - 1].x, n.path[k].z - n.path[k - 1].z);
  n.sp = Math.min(clamp(rem * 0.9, 2.5, 16), n.sp + dt * 9);
  n.t += dt;
  if (n.t > 1.5) { // stuck? re-plan from here
    if (Math.hypot(Pp.x - n.px, Pp.z - n.pz) < 1) { n.stuck++; var np = n.stuck < 3 ? findPath(Pp, n.p.stand || n.p) : null; if (!np) { var nm = n.p.name; stopAI(true); setMode('WALK'); narrate('I got stuck on the way to <b>' + esc(nm) + '</b>. You have manual control.'); return null; } n.path = np; n.i = 1; showPath(np); }
    n.t = 0; n.px = Pp.x; n.pz = Pp.z;
  }
  if (H.mode !== 'LOOK') { var want = Math.atan2(-dx, -dz), da = ((want - S.camYaw + Math.PI * 3) % (Math.PI * 2)) - Math.PI; S.camYaw += da * Math.min(1, dt * 2.2); }
  return { vx: dx / d * n.sp, vz: dz / d * n.sp, sp: n.sp };
}
/* ARRIVED toast (2026-10-10): every arrival (AI Drive, radar Go, the AI pilot, tour stops, flights) shows
   'ARRIVED: <place>', logs it in the narration and fires window 'city-arrived' {name} (hyper-auto -> #ai-status). */
var arrEl = null;
function arrived(name, narr) {
  if (!arrEl) { arrEl = document.createElement('div'); arrEl.id = 'hc-arrived'; arrEl.setAttribute('role', 'status'); arrEl.setAttribute('aria-live', 'polite'); (document.getElementById('sc-hud') || document.body).appendChild(arrEl); }
  arrEl.textContent = '\u2713 ARRIVED: ' + name; arrEl.classList.add('show');
  clearTimeout(arrEl._h); arrEl._h = setTimeout(function () { arrEl.classList.remove('show'); }, 3500);
  narrate('<b>ARRIVED:</b> ' + esc(name) + '.' + (narr ? ' ' + narr : ''), narr ? 8 : 5);
  try { dispatchEvent(new CustomEvent('city-arrived', { detail: { name: name } })); } catch (e) {}
}
function arrive() {
  var n = H.nav, p = n.p; H.nav = null; S.ai = null; clearPath();
  S.camYaw = Math.atan2(-(p.x - S.p.x), -(p.z - S.p.z)) || S.camYaw;
  if (H.tour) { tourArrived(p); return; }
  setMode('WALK'); H.armed = false;
  arrived(p.name);
  if (n.onArrive) n.onArrive(); else poiCard(p);
}
function flyTo(t, mode, reason) {
  if (!flying()) return false;
  pushHist();
  if (t.home) { A.startAuto(true); H.flyDrive = { t: t }; setMode(mode || 'AI DRIVE'); narrate('Flying home to the <b>Orbital Spaceport</b>; autopilot will land on the pad. ' + (reason || '') + ' <span class="hc-dim">Move the stick to take over.</span>'); return true; }
  var d = Math.hypot(t.x - S.ship.x, t.z - S.ship.z), alt = t.alt || Math.max(0, A.heightAt(t.x, t.z)) + 600;
  S.mode = 'auto'; H.flyDrive = { t: t };
  S.auto = { phase: 'cruise', tx: t.x, tz: t.z, alt: alt, arrive: Math.min(700, Math.max(250, d * 0.2)), onArrive: function () {
    H.flyDrive = null; setMode('FLIGHT'); H.focus = t;
    arrived(t.name, 'You have the stick. ' + esc(t.text || '')); beacon(t, 6);
  } };
  setMode(mode || 'AI DRIVE');
  narrate('Flying to <b>' + esc(t.name) + '</b>: ' + fmtDist(d) + ', cruising with terrain look-ahead. ' + (reason || '') + ' <span class="hc-dim">Move the stick to take over.</span>');
  return true;
}
function driveTo(p, mode, onArrive) {
  H.focus = p;
  if (flying()) {
    if (p.id === 'port') p = FLY[0];
    if (!FLY.includes(p)) p = { name: p.name, x: p.x, z: p.z, alt: Y + 380, text: p.text };
    return flyTo(p, mode);
  }
  if (S.mode !== 'walk') { narrate('Launch first. AI Drive works on foot and in flight.', 4); return false; }
  if (FLY.includes(p)) {
    if (p.id === 'home') p = P('port');
    else if (p.id === 'city') p = P('plaza');
    else { narrate('<b>' + esc(p.name) + '</b> is a flight destination. Walking you to the Orbital Spaceport: board a ship, LAUNCH, then tap 🤖 again.', 9); return startWalk(P('port'), mode, '', null); }
  }
  return startWalk(p, mode, '', onArrive);
}
function stopAI(silent) {
  var was = !!(H.nav || H.tour || H.flyDrive || H.armed);
  H.nav = null; H.tour = null; H.armed = false; S.ai = null; clearPath();
  if (H.flyDrive) { H.flyDrive = null; if (S.mode === 'auto') { S.mode = 'fly'; S.auto = null; } }
  if (!silent) { setMode(baseMode()); if (was) narrate('AI Drive stopped. You have manual control.', 4); else narrate('Nothing to stop. You already have manual control.', 3); }
}

/* ---------------- TOUR ---------------- */
var TOUR = ['plaza', 'sable', 'forumgate', 'studio', 'port', 'warp'];
function startTour()