<!-- SOLID CITY · part 1980 -->
;
const lerp = (a,b,t)=>a+(b-a)*t;
const approach = (a,b,step)=>a+clamp(b-a,-step,step);
const decay = (k,dt)=>Math.exp(-k*dt);
const len2 = (x,z)=>Math.hypot(x,z);
const forward = yaw=>({x:Math.sin(yaw),z:Math.cos(yaw)});
const right = yaw=>({x:Math.cos(yaw),z:-Math.sin(yaw)});
const copy = p=>({x:p.x,y:p.y,z:p.z});
const finite = (...xs)=>xs.every(Number.isFinite);
const shape = x=>{x=clamp(x,-1,1);const a=Math.abs(x);return a<.1?0:Math.sign(x)*Math.pow((a-.1)/.9,1.4);};
function requireWorld(world){
  if(typeof world?.supportAt!=='function'||typeof world?.sweep!=='function')
    throw new Error('REJECT: authoritative supportAt and sweep required');
}
/* supportAt(x,z,context) -> {y, normal:{x,y,z}, kind, id, canSupport:true}
 * or null. MUST resolve overlapping support layers for the craft and trajectory.
 * sweep(from,to,radius,context) -> {ok:true,position?} or {ok:false,reason}.
 * These are mandatory engine adapters; their correctness is UNVERIFIED here.
 */
function sample(world,x,z,context){
  const h=world.supportAt(x,z,context);
  if(!h||h.canSupport!==true||!finite(h.y,h.normal?.x,h.normal?.y,h.normal?.z)||h.normal.y<=0)
    return null;
  return h;
}
function move(world,s,to,radius,context){
  if(!finite(to.x,to.y,to.z))return {accepted:false,reason:'NONFINITE_POSITION'};
  const hit=world.sweep(s.pos,to,radius,context);
  if(!hit||hit.ok!==true)return {accepted:false,reason:hit?.reason||'COLLISION_UNVERIFIED'};
  s.pos=copy(hit.position||to);return {accepted:true};
}
function groundedPose(world,s,clearance,context){
  const f=forward(s.yaw),r=right(s.yaw);
  const a=sample(world,s.pos.x+f.x*.65,s.pos.z+f.z*.65,context);
  const b=sample(world,s.pos.x-f.x*.65,s.pos.z-f.z*.65,context);
  if(!a||!b||a.id!==b.id)return null;
  const y=(a.y+b.y)/2;
  return {y:y+clearance,normal:{x:(a.normal.x+b.normal.x)/2,y:(a.normal.y+b.normal.y)/2,z:(a.normal.z+b.normal.z)/2},rise:a.y-b.y,id:a.id};
}
export function createGroundRide(pos,yaw=0){return {type:'GROUND_RIDE',pos:copy(pos),yaw,v:0,lat:0,steer:0,grounded:true,mode:'DRIVE',pitch:0,roll:0};}
export function stepGroundRide(s,input,world,dt=CRAFT_STEP){
  requireWorld(world);if(s.mode==='BLOCKED')return {accepted:false,reason:'BLOCKED'};
  const x=shape(input.x||0),y=shape(input.y||0),f=forward(s.yaw),r=right(s.yaw);
  const maxSteer=lerp(.55,.17,clamp(Math.abs(s.v)/26,0,1));
  s.steer=approach(s.steer,x*maxSteer,(Math.abs(x)<.01?4.5:3)*dt);
  let a=0;
  if(y>.01)a=s.v<0?10*y:10*y*Math.max(0,1-(Math.max(0,s.v)/26)**2);
  else if(y<-.01)a=s.v>.3?12*y:6*y;
  else if(Math.abs(s.v)>.001)a=-Math.sign(s.v)*(1+.015*Math.abs(s.v));
  const ground=groundedPose(world,s,.45,'GROUND_RIDE');
  if(!ground)return {accepted:false,reason:'SUPPORT_MISSING_OR_LAYER_MISMATCH'};
  a-=9.81*ground.rise/1.3; // approximate slope projection: START, axle probe spacing 1.3 m
  const old=s.v;s.v=clamp(s.v+a*dt,-8,26);
  if(old>0&&s.v<0&&y<0)s.v=0; // brake must not silently become reverse
  if(Math.abs(s.v)<.1&&Math.abs(y)<.01)s.v=0;
  let omega=s.v/2.7*Math.tan(s.steer);
  omega=clamp(omega,-12/Math.max(Math.abs(s.v),3),12/Math.max(Math.abs(s.v),3));
  if(s.v===0)omega=0;
  s.yaw+=omega*dt;
  s.lat*=decay(8,dt);
  const nf=forward(s.yaw),nr=right(s.yaw);
  const to={x:s.pos.x+(nf.x*s.v+nr.x*s.lat)*dt,y:ground.y,z:s.pos.z+(nf.z*s.v+nr.z*s.lat)*dt};
  const hit=move(world,s,to,1.1,'GROUND_RIDE');if(!hit.accepted){s.v=0;return hit;}
  const after=groundedPose(world,s,.45,'GROUND_RIDE');
  if(!after)return {accepted:false,reason:'EXITED_AUTHORIZED_SUPPORT',needsRecovery:true};
  s.pos.y=after.y;s.pitch=Math.atan2(after.rise,1.3);
  return {accepted:true,groundId:after.id,speed:s.v,steer:s.steer};
}
export function createHoverBoard(pos,yaw=0){return {type:'HOVER_BOARD',pos:copy(pos),yaw,vx:0,vy:0,vz:0,mode:'RIDE',cooldown:0,roll:0};}
export function stepHoverBoard(s,input,world,dt=CRAFT_STEP){
  requireWorld(world);const x=shape(input.x||0),y=shape(input.y||0);
  s.cooldown=Math.max(0,s.cooldown-dt);
  const f=forward(s.yaw),speed=len2(s.vx,s.vz);
  if(s.mode==='RIDE'){
    const h=groundedPose(world,s,.08,'HOVER_BOARD');
    if(!h)return {accepted:false,reason:'NO_BOARD_SUPPORT'};
    const n=h.normal;
    s.vx+=(-20*n.y*n.x)*dt;s.vz+=(-20*n.y*n.z)*dt; // gravity projected to tangent x/z
    if(y>.1&&s.cooldown===0&&speed<6){const push=1.4*(1-speed/6);s.vx+=f.x*push;s.vz+=f.z*push;s.cooldown=.45;}
    if(y<-.1){const drop=Math.min(speed,6*(-y)*dt);if(speed>1e-5){s.vx-=s.vx/speed*drop;s.vz-=s.vz/speed*drop;}}
    const v=len2(s.vx,s.vz),drag=Math.max(0,1-(.25/Math.max(v,.25)+.015*v)*dt);
    s.vx*=drag;s.vz*=drag;
    const yawRate=x*lerp(2.2,1,clamp(v/10,0,1));s.yaw+=yawRate*dt;
    s.roll=-x*clamp(v/8,0,1)*28*PI/180;
    if(input.jump===true){s.mode='AIR';s.vy=5.2;}
    else s.pos.y=h.y;
  }
  if(s.mode==='AIR'){
    s.vy-=20*dt;s.yaw+=x*.7*dt;
  }
  const to={x:s.pos.x+s.vx*dt,y:s.pos.y+s.vy*dt,z:s.pos.z+s.vz*dt};
  const hit=move(world,s,to,.45,'HOVE