<!-- SOLID CITY · part 3400 -->
100% - 28px));box-sizing:border-box;padding:18px 16px 16px;border-radius:16px;text-align:center;',
' background:radial-gradient(circle at 50% 0%,rgba(120,40,200,.55),rgba(8,4,16,.96) 70%);border:1px solid #b46bff;color:#efe6ff;font:14px/1.4 system-ui,sans-serif;box-shadow:0 0 40px rgba(150,80,255,.45)}',
'#wh-prompt[hidden]{display:none}',
'#wh-prompt .wh-sw{font-size:40px;line-height:1;display:inline-block;animation:whspin 2.4s linear infinite}',
'@keyframes whspin{to{transform:rotate(360deg)}}',
'#wh-prompt h3{margin:8px 0 4px;font:900 19px system-ui,sans-serif;letter-spacing:.06em;color:#fff}',
'#wh-prompt p{margin:0 0 14px;color:#cdbff0;font-size:13px}',
'#wh-prompt .wh-b{display:grid;grid-template-columns:1fr 1fr;gap:10px}',
'#wh-prompt .wh-b a,#wh-prompt .wh-b button{min-height:52px;border-radius:12px;font:900 15px system-ui,sans-serif;letter-spacing:.12em;display:flex;align-items:center;justify-content:center;text-decoration:none;cursor:pointer;box-sizing:border-box}',
'#wh-play{border:2px solid #e8c36a;background:linear-gradient(180deg,#9a4dff,#3d1080);color:#fff;box-shadow:0 0 16px rgba(160,90,255,.6)}',
'#wh-no{border:1px solid #6b5aa0;background:rgba(0,0,0,.45);color:#d8ccff}'
].join('\n');
document.head.appendChild(css);

/* ---------- 1. SPACE MISSION button ---------- */
function addButton() {
  var ex = $('space-btn'), dock0 = $('sc-dock'); if (ex) { if (dock0 && ex.parentNode !== dock0) { ex.className = ''; dock0.appendChild(ex); } return; }
  var a = document.createElement('a'); a.id = 'space-btn'; a.href = URL_SPACE + '?from=city';
  a.setAttribute('aria-label', 'Space Mission'); a.title = 'Space Mission: fly, shoot the alien fleet, come home and park';
  a.innerHTML = '<span class="sb-i">\uD83D\uDE80</span><span class="sb-t">SPACE</span><span class="sb-t2"> MISSION</span>';
  var dock = $('sc-dock');
  if (dock) dock.appendChild(a); else { a.className = 'sb-float'; (document.getElementById('sc-hud') || document.body).appendChild(a); }
}

/* ---------- 3. citizen chip ---------- */
function watchChips() {
  var chips = $('cz-chips'); if (!chips || chips.__space) return; chips.__space = true;
  function fix() {
    var nm = ($('cz-name') && $('cz-name').textContent || '').trim();
    var mine = chips.querySelector('.cz-space');
    if (!CHIP_FOR[nm]) { if (mine) mine.remove(); return; }
    if (mine || !chips.children.length) return;
    var b = document.createElement('button'); b.type = 'button'; b.className = 'cz-space';
    b.textContent = '\uD83D\uDE80 Play the space mission';
    b.addEventListener('click', function () { location.href = URL_SPACE + '?from=hangar'; });
    chips.insertBefore(b, chips.firstChild);
  }
  new MutationObserver(fix).observe(chips, { childList: true });
  fix();
}

/* ---------- 3D helpers ---------- */
function glowTex(r, g, b) {
  var c = document.createElement('canvas'); c.width = c.height = 64; var x = c.getContext('2d');
  var gr = x.createRadialGradient(32, 32, 0, 32, 32, 32);
  gr.addColorStop(0, 'rgba(' + r + ',' + g + ',' + b + ',1)'); gr.addColorStop(0.4, 'rgba(' + r + ',' + g + ',' + b + ',.35)'); gr.addColorStop(1, 'rgba(' + r + ',' + g + ',' + b + ',0)');
  x.fillStyle = gr; x.fillRect(0, 0, 64, 64); return c;
}

function build(A) {
  var T = A.T, world = A.world, curve = A.curve;
  var CURV = (0.5 / A.R_PLANET).toExponential(6);
  var VS = 'varying vec2 vUv; void main(){ vUv = uv; vec4 wp = modelMatrix * vec4(position,1.0); vec2 cd = wp.xz - cameraPosition.xz; wp.y -= dot(cd,cd) * ' + CURV + '; gl_Position = projectionMatrix * viewMatrix * wp; }';

  /* ---- 2. Hangar launch pad ---- */
  var py = A.groundAt(PADP.x, PADP.z);
  var pad = new T.Group(); pad.position.set(PADP.x, py, PADP.z); pad.name = 'space-pad';
  var padMat = new T.ShaderMaterial({ uniforms: { uT: { value: 0 } }, transparent: true, depthWrite: false, vertexShader: VS,
    fragmentShader: 'uniform float uT; varying vec2 vUv; void main(){ vec2 p = vUv*2.0-1.0; float r = length(p); if (r > 1.0) discard;' +
      ' float ring = smoothstep(.05,0.,abs(r-.93)) + smoothstep(.04,0.,abs(r-.62))*.8 + smoothstep(.03,0.,abs(r-fract(uT*.35)))*.6;' +
      ' float a = atan(p.y,p.x); float h = step(.5, fract(a*3.0/3.14159 + uT*.2)) * smoothstep(.04,0.,abs(r-.78));' +
      ' float H = (smoothstep(.05,0.,abs(abs(p.x)-.22))*step(abs(p.y),.34)) + smoothstep(.05,0.,abs(p.y))*step(abs(p.x),.22);' +
      ' vec3 c = vec3(1.0,.62,.18)*(ring+h) + vec3(1.0,.85,.5)*H; float al = clamp(ring+h+H,0.,1.)*.95 + .18*(1.0-r);' +
      ' gl_FragColor = vec4(c + vec3(.25,.05,.02), al); }' });
  var disc = new T.Mesh(new T.PlaneGeometry(26, 26), padMat); disc.rotation.x = -Math.PI / 2; disc.position.y = 0.12; disc.renderOrder = 2; pad.add(disc);
  var base = new T.Mesh(new T.CylinderGeometry(13.4, 13.8, 0.25, 40), curve(new T.MeshLambertMaterial({ color: 0x1a1216 }))); base.position.y = 0.02; pad.add(base);
  var beamMat = new T.ShaderMaterial({ uniforms: { uT: { value: 0 } }, tra