<!-- SOLID CITY · part 3399 -->
Math.abs(rc(r-y.yaw))+Math.abs(a-y.pitch)}};if(e==="battle"){let n=Hn.filter(s=>s.alive).sort((s,r)=>s.pos.distanceToSquared(y.pos)-r.pos.distanceToSquared(y.pos))[0];if(n){let s=t(Ot.copy(n.pos).addScaledVector(n.vel,n.pos.distanceTo(y.pos)/1600));i.fire=s.err<.45&&s.d<1500,i.boost=s.d>1100&&y.boostMeter>.3}}else if(e==="return"){let n=Math.hypot(y.pos.x,y.pos.z);t(Ot.set(0,Math.min(y.pos.y,380+n*.12),0)),i.boost=y.boostMeter>.3&&vs(y.pos.y)<1500}return i}var bt={show:gr.has("perf"),frames:[],fps:60,lastAdj:0,log:[],tier:2,sumMs:0,n:0};bt.show&&(Ne["h-perf"].hidden=!1);function vy(i){if(i-bt.lastAdj<1500||bt.frames.length<40)return;bt.lastAdj=i;let e=bt.frames.slice(-60),t=e.reduce((r,a)=>r+a,0)/e.length,n=1e3/t;if(bt.fps=n,gr.get("dpr"))return;let s=!1;n<47&&Rn>Uf?(Rn=Math.max(Uf,Rn-(n<35?.2:.1)),s=!0):n<40&&bt.tier>0?(bt.tier--,Of.mesh.geometry.instanceCount=Math.round(Of.n*(bt.tier?.65:.4)),ic.visible=bt.tier>0,s=!0):n>58.5&&Rn<ru-.01&&(Rn=Math.min(ru,Rn+.1),s=!0),s&&(zn.setPixelRatio(Rn),xr(),bt.log.push({t:Math.round(y.t),fps:Math.round(n),pr:+Rn.toFixed(2),tier:bt.tier}),bt.log.length>40&&bt.log.shift())}var tc=0,pp=1;function mp(i){requestAnimationFrame(mp),tc||(tc=i);let e=i-tc;if(tc=i,document.hidden)return;bt.frames.push(e),bt.frames.length>240&&bt.frames.shift(),y.running&&y.t>2&&(bt.sumMs+=e,bt.n++);let t=Math.min(e/1e3,.05);if(y.running)for(let n=0;n<pp;n++)Jv(t);zn.render(et,Mt),vy(i)}async function yy(){hr(.62,"Building the island\u2026"),await $l(),Uv(),hr(.7,"Raising the capital\u2026"),await $l(),Fv(),Ov(),hr(.78,"Fuelling your ship\u2026"),await $l(),zv(),Hv(),hr(.86,"Compiling shaders\u2026"),await $l(),ap(),y.running=!1,hp(.016),fp(.016);let i=["scout","circler","diver","mother"].map(e=>tp(e));i.forEach((e,t)=>{e.mesh.position.set(t*20-30,10,-40)}),oc(new $e(0,10,-40),.01),np(Ti);try{zn.compile(et,Mt)}catch{}zn.render(et,Mt),i.forEach(e=>{et.remove(e.mesh),e.hull.dispose()}),sp(ct.muted),jn("pad"),y.running=!0,requestAnimationFrame(mp),hr(1,"Ready")}window.__spaceStart=function(){_c(),Lt("hud").hidden=!1,_u()};window.SPACE={state:y,aliens:Hn,input:Oe,bot:Pa,pad:ln,stats(){let i=bt.frames.slice().sort((t,n)=>t-n),e=i.reduce((t,n)=>t+n,0)/(i.length||1);return{fps:1e3/e,avgMs:e,p95Ms:i[Math.floor(i.length*.95)]||0,worstMs:i[i.length-1]||0,runAvgFps:bt.n?1e3/(bt.sumMs/bt.n):0,pixelRatio:Rn,tier:bt.tier,calls:zn.info.render.calls,tris:zn.info.render.triangles,adapt:bt.log.slice(),touch:Qn,mobile:Qt}},test:{autopilot(i=!0,e=!1){Pa.on=i,Pa.god=e},speed(i){pp=ht(i|0,1,8)},launch:xc,reset:_u,phase:()=>y.phase,alt:()=>vs(y.pos.y)}};yy().catch(i=>{hr(1,"Error: "+(i&&i.message)),console.error(i)});
/*! Bundled license information:

three/build/three.core.js:
three/build/three.module.js:
  (**
   * @license
   * Copyright 2010-2026 Three.js Authors
   * SPDX-License-Identifier: MIT
   *)
*/


===== FILE: public/city/space/src/city-link.js =====
/* Solid City -> SPACE MISSION entry points (additive only; uses window.SC.api, never edits city internals).
   - SPACE MISSION button in the bottom dock (#sc-dock)
   - Hangar launch pad at (-307, 410) with a portal card -> /city/space/
   - "Play the space mission" chip in the talk panel of King Playa, Solid and Provolta
   - WORMHOLE portal at (-280, 560): swirling 3D portal, collision pylons, radar blip, Hyper Controller stop,
     "Enter the wormhole? PLAY / NOT NOW" prompt on foot or in flight
   - ?at=hangar | ?at=wormhole arrival when coming back from the level */
(function () {
'use strict';
var URL_SPACE = '/city/space/';
var PADP = { x: -307, z: 410 }, WH = { x: -280, z: 560 }, WH_R = 11, WH_H = 13.5;
var CHIP_FOR = { 'KING PLAYA': 1, 'SOLID': 1, 'PROVOLTA': 1 };
function $(id) { return document.getElementById(id); }

/* ---------- styles ---------- */
var css = document.createElement('style'); css.id = 'space-link-css';
css.textContent = [
'#space-btn{min-height:44px;min-width:44px;padding:0 14px;border-radius:22px;border:1px solid #ff9a3c;background:linear-gradient(180deg,rgba(227,18,44,.92),rgba(90,4,16,.92));color:#fff;font:900 12px system-ui,sans-serif;letter-spacing:.1em;display:inline-flex;align-items:center;justify-content:center;gap:6px;text-decoration:none;box-sizing:border-box;box-shadow:0 0 12px rgba(255,120,40,.45);white-space:nowrap}',
'#space-btn .sb-i{font-size:17px;line-height:1}',
'#space-btn:hover{box-shadow:0 0 18px rgba(255,150,60,.75)}',
'#space-btn.sb-float{position:absolute;z-index:13;right:calc(10px + env(safe-area-inset-right));bottom:calc(16px + env(safe-area-inset-bottom))}',
'@media (max-width:600px){#space-btn{padding:0 12px}#space-btn .sb-t2{display:none}}',
'@media (min-width:601px) and (max-height:500px){#space-btn .sb-t2{display:none}}',
'.cz-chips button.cz-space{height:44px;border-color:#ff9a3c;background:linear-gradient(180deg,#e3122c,#7d0614);color:#fff;font-weight:800}',
'#wh-prompt{position:fixed;z-index:60;left:50%;top:50%;transform:translate(-50%,-50%);width:min(360px,calc(