<!-- SOLID CITY · part 2454 -->
 + 0.22 : this.species.size.lengthM * 0.5;
  };
  BirdEntity.prototype.placeOnSurface = function (surface, heading) {
    this.group.position.copy(surface.center);
    this.heading = heading || 0;
    this.surface = surface; surface.occupiedBy = this;
    this.memory.lastSurfaceId = surface.id;
    this.forceState(this.species.id === 'dodo' ? 'REST' : (surface.kind === 'branch' ? 'PERCHED' : 'SURFACE_REST'));
  };
  BirdEntity.prototype.placeOnGround = function (x, z, heading) {
    this.group.position.set(x, 0, z);
    this.heading = heading || 0;
    this.forceState(this.species.capabilities.canFly ? 'GROUND_IDLE' : 'REST');
  };
  BirdEntity.prototype.forceState = function (name) {
    this.state = name; this.phase = null; this.phaseT = 0; this.stateT = 0; this.dwell = 0;
    var st = this.fsm[name];
    if (st && st.enter) st.enter(this);
  };
  BirdEntity.prototype.setState = function (name) {
    if (name === this.state) return;
    var table = this.fsm[this.state];
    if (this.state && table && table.next.indexOf(name) < 0) {
      throw new Error(this.species.id + ': illegal transition ' + this.state + ' -> ' + name);
    }
    var from = this.state;
    if (from && this.fsm[from] && this.fsm[from].exit) this.fsm[from].exit(this);
    this.state = name; this.phase = null; this.phaseT = 0; this.stateT = 0;
    this.history.push({ kind: 'state', from: from, to: name, t: this.time });
    var st = this.fsm[name];
    if (st && st.enter) st.enter(this);
  };
  BirdEntity.prototype.setPhase = function (name) {
    if (this.phase === name) return;
    this.phase = name; this.phaseT = 0;
    this.history.push({ kind: 'phase', state: this.state, phase: name, t: this.time });
  };
  BirdEntity.prototype.releaseSurface = function () {
    if (this.surface) { this.surface.occupiedBy = null; this.memory.lastSurfaceId = this.surface.id; this.surface = null; }
  };
  BirdEntity.prototype.scanUpdate = function (dt, wide) {
    this.scanT -= dt;
    if (this.scanT <= 0) {
      this.scanT = 1.1 + this.rng() * 2.2;
      this.scanYaw = (this.rng() * 2 - 1) * (wide ? 1.25 : 0.95);
      this.scanPitch = (this.rng() * 0.55 - 0.12);
    }
    this.pose.headYaw = this.scanYaw;
    this.pose.headPitch = this.scanPitch;
  };
  BirdEntity.prototype.update = function (dt, ctx) {
    ctx = ctx || {};
    this.time += dt; this.stateT += dt; this.phaseT += dt;
    if (this.state === 'PERCHED' || this.state === 'SURFACE_REST' || this.state === 'GROUND_IDLE' || this.state === 'REST') this.dwell += dt; else this.dwell = 0;
    if (ctx.playerPos) this.lastPlayerPos = ctx.playerPos;
    this.behavior.update(dt, ctx);
    var st = this.fsm[this.state];
    if (st && st.update) st.update(this, dt, ctx);
    if (this.state === 'FLIGHT' && this.flapMode === 'glide') this.glideSeconds += dt;
    this.anim.update(dt, this.time);
    if (this.anim.fold > 0.12 && this.anim.fold < 0.88) this.foldMidFrames++;
    // orientation: yaw, then pitch (nose), then bank — flight reads as flight
    this.group.rotation.order = 'YXZ';
    this.group.rotation.y = this.heading;
    var inFlight = (this.state === 'FLIGHT' || this.state === 'TAKEOFF' || this.phase === 'flare' || this.phase === 'approach');
    this.group.rotation.x = inFlight ? -this.pitch * 0.8 : 0;
    this.group.rotation.z = inFlight ? -(this.bank || 0) : 0;
  };
  BirdEntity.prototype.setLOD = function (level) {
    this.lodLevel = level;
    if (!this.detail) return;
    var i;
    for (i = 0; i < this.detail.hi.length; i++) this.detail.hi[i].visible = level >= 2;
    for (i = 0; i < this.detail.mid.length; i++) this.detail.mid[i].visible = level >= 1;
  };
  function lodForDistance(effectiveDist) { return effectiveDist < 9 ? 2 : (effectiveDist < 26 ? 1 : 0); }

  /* ---------- shared state helpers ---------- */
  function restPoseCommon(b, legMode) {
    b.pose.foldTarget = 0; b.pose.flapActive = false; b.pose.glide = false;
    b.pose.legMode = legMode; b.pose.gaitSpeed = 0;
    b.pose.bodyPitch = Math.sin(b.time * 0.9) * 0.008; // alive, not statuesque
    b.pose.tailPitch = Math.sin(b.time * 0.7 + 1) * 0.05;
  }
  function destPoint(b) {
    if (!b.dest) return null;
    return b.dest.kind === 'surface' ? b.dest.surface.center : b.dest.spot.pos;
  }
  function takeoffEnter(b) {
    b.setPhase(b.surface ? 'look' : 'alert');
    b.pose.legMode = b.surface ? (b.surface.kind === 'branch' ? 'grip' : 'stand') : 'stand';
  }
  function takeoffUpdate(b, dt) {
    var F = b.species.flight;
    var dp = destPoint(b);
    var destHeading = dp ? Math.atan2(dp.x - b.group.position.x, dp.z - b.group.position.z) : b.heading;
    b.pose.headYaw = clamp(angDiff(b.heading, destHeading), -1.2, 1.2);
    b.pose.headPitch = -0.05;
    if (b.phase === 'look' || b.phase === 'alert') {
      b.pose.foldTarget = 0.06;
      if (b.phaseT > 0.38) b.setPhase('crouch');
    } else if (b.phase === 'crouch') {
      b.pose.bodyPitch = 0.16;                       // visible pre