<!-- SOLID CITY · part 2456 -->
.group.position.y = 0.35; b.vel.y = Math.abs(b.vel.y) * 0.5; }
  }
  function makeLanding(kind) {
    return {
      next: kind === 'branch' ? ['PERCHED', 'FLIGHT'] : (kind === 'surface' ? ['SURFACE_REST', 'FLIGHT'] : ['GROUND_IDLE', 'FLIGHT']),
      enter: function (b) {
        var c = destPoint(b).clone();
        b.landContact = c;
        var from = b.group.position.clone();
        var dir = c.clone().sub(from); dir.y = 0;
        if (dir.lengthSq() < 0.01) dir.set(Math.sin(b.heading), 0, Math.cos(b.heading));
        dir.normalize();
        b.landDir = dir;
        b.landStage = c.clone().addScaledVector(dir, -3.1); b.landStage.y = c.y + (kind === 'ground' ? 1.25 : 0.85);
        b.setPhase('approach');
      },
      update: function (b, dt) {
        var F = b.species.flight;
        if (b.phase === 'approach') {
          // abort if the surface was taken while we approached
          if (kind !== 'ground' && b.dest.surface.occupiedBy && b.dest.surface.occupiedBy !== b) {
            b.memory.blocked[b.dest.surface.id] = b.time + 20;
            b.history.push({ kind: 'abort', state: b.state, t: b.time });
            b.dest = b.journeyDest && b.journeyDest.kind ? b.journeyDest : { kind: 'ground', spot: b.world.spotById('near-meadow') };
            b.setState('FLIGHT'); return;
          }
          var d = b.loco.steerFlight(dt, b.landStage, { speed: F.approachSpeed * 1.9, turnMul: 1.5 });
          b.pose.foldTarget = 1; b.pose.flapActive = true; b.pose.flapRateMul = 0.8; b.pose.glide = false;
          b.pose.legMode = b.group.position.distanceTo(b.landStage) < 2.6 ? 'extend' : 'tucked';
          b.flapMode = 'flap';
          if (d < 0.55) {
            b.setPhase('flare');
            b.flareFrom = b.group.position.clone();
            var dd = b.flareFrom.distanceTo(b.landContact);
            b.flareDur = clamp(dd / (F.approachSpeed * 0.85), 0.45, 1.15);
          }
        } else if (b.phase === 'flare') {
          var k = clamp(b.phaseT / b.flareDur, 0, 1), e = ease(k);
          var prev = b.group.position.clone();
          b.group.position.lerpVectors(b.flareFrom, b.landContact, e);
          b.vel.copy(b.group.position.clone().sub(prev).divideScalar(Math.max(dt, 0.001)));
          b.speed = b.vel.length();
          b.heading = Math.atan2(b.landDir.x, b.landDir.z);
          b.pitch = lerp(0.35, 0, e);                    // braking flare eases level
          b.pose.flapActive = true; b.pose.flapRateMul = 0.55; b.pose.flapAmp = 1.2; // deep braking strokes
          b.pose.legMode = 'extend';
          b.pose.tailPitch = 0.45 * (1 - e);
          if (k >= 1) { b.group.position.copy(b.landContact); b.setPhase('contact'); }
        } else if (b.phase === 'contact') {
          b.pose.flapActive = false; b.pose.legMode = kind === 'branch' ? 'grip' : 'stand';
          b.pose.bodyPitch = 0.05;
          if (b.phaseT > 0.14) b.setPhase('balance');
        } else if (b.phase === 'balance') {
          b.pose.tailPitch = Math.sin(b.phaseT * 9) * 0.22 * (1 - b.phaseT / 0.5);  // tail dips, settling
          b.pose.bodyPitch = Math.sin(b.phaseT * 7) * 0.03 * (1 - b.phaseT / 0.5);
          if (b.phaseT > 0.5) b.setPhase('fold');
        } else if (b.phase === 'fold') {
          b.pose.foldTarget = 0;
          b.pose.tailPitch = 0;
          if (b.anim.fold < 0.06 || b.phaseT > 0.8) {
            b.setPhase(null);
            if (kind === 'branch') { b.surface = b.dest.surface; b.surface.occupiedBy = b; b.setState('PERCHED'); }
            else if (kind === 'surface') { b.surface = b.dest.surface; b.surface.occupiedBy = b; b.setState('SURFACE_REST'); }
            else { b.spotId = b.dest.spot.id; b.setState('GROUND_IDLE'); }
          }
        }
      }
    };
  }

  var PARAKEET_FSM = {
    PERCHED: {
      next: ['TAKEOFF', 'ALERT'],
      update: function (b, dt) { restPoseCommon(b, 'grip'); b.pose.tailBase = 0.30; b.scanUpdate(dt); }
    },
    SURFACE_REST: {
      next: ['TAKEOFF', 'ALERT'],
      enter: function (b) { b.restT = 0; b.stepT = 2 + b.rng() * 3; b.stepTarget = null; },
      update: function (b, dt) {
        restPoseCommon(b, 'stand'); b.pose.tailBase = 0.18;
        b.scanUpdate(dt, true);
        if (b.rng() < dt * 0.12) b.pose.headPitch = 0.55;        // peer over the edge
        // REPOSITION: turn on the spot, sometimes a shuffle-step across the top
        b.stepT -= dt;
        if (b.stepT <= 0) {
          b.stepT = 2.5 + b.rng() * 3.5;
          b.targetHeading = b.heading + (b.rng() * 2 - 1) * 1.5;
          if (b.surface && b.surface.radius > 0.5 && b.rng() < 0.6) {
            var off = (b.rng() - 0.5) * b.surface.radius * 0.7;
            b.stepTarget = V3(b.surface.center.x + Math.sin(b.targetHeading) * off, b.surface.center.y, b.surface.center.z + Math.cos(b.targetHeading) * off);
          }
        }
        if (b.targetHeading != null) b.heading = angLerp(b.heading, b.targetHeading, clamp(dt * 3, 0, 1));
        