<!-- SOLID CITY · part 37 -->
Width = 6; g.strokeRect(0, 0, 512, 512);
  });
  floorTex.wrapS = floorTex.wrapT = THREE.RepeatWrapping; floorTex.repeat.set(6, 6);
  var floor = new THREE.Mesh(new THREE.PlaneGeometry(44, 44),
    new THREE.MeshLambertMaterial({ map: floorTex }));
  floor.rotation.x = -Math.PI / 2; scene.add(floor);

  // Walls
  var wallMat = new THREE.MeshLambertMaterial({ color: 0x1b2129 });
  function wall(w, h, x, y, z, ry) {
    var m = new THREE.Mesh(new THREE.PlaneGeometry(w, h), wallMat);
    m.position.set(x, y, z); m.rotation.y = ry; scene.add(m); return m;
  }
  wall(44, 14, 0, 7, 22, Math.PI);        // south (behind start)
  wall(44, 14, -22, 7, 0, Math.PI / 2);   // west
  wall(44, 14, 22, 7, 0, -Math.PI / 2);    // east
  // North wall = viewport frame; window opening shows space
  wall(44, 14, 0, 7, -22, 0);

  // Viewport: starfield plane just outside north wall + window cutout illusion
  var starGeo = new THREE.BufferGeometry();
  var sp = [];
  for (var i = 0; i < 900; i++) {
    sp.push((Math.random() - 0.5) * 160, Math.random() * 70 - 8, -60 - Math.random() * 40);
  }
  starGeo.setAttribute('position', new THREE.Float32BufferAttribute(sp, 3));
  starPts = new THREE.Points(starGeo, new THREE.PointsMaterial({ color: 0xcfe8ff, size: 0.7 }));
  scene.add(starPts);
  // Window frame (gold) over the wall
  var frameMat = new THREE.MeshLambertMaterial({ color: 0xd8aa48, emissive: 0x2a1a04 });
  var winW = 30, winH = 8, winY = 7;
  [[0, winY + winH / 2, winW + 1, 1], [0, winY - winH / 2, winW + 1, 1]].forEach(function (b) {
    var m = new THREE.Mesh(new THREE.BoxGeometry(b[2], b[3], 0.6), frameMat);
    m.position.set(b[0], b[1], -21.7); scene.add(m);
  });
  [[-winW / 2, 0], [winW / 2, 0]].forEach(function (s) {
    var m = new THREE.Mesh(new THREE.BoxGeometry(1, winH + 1, 0.6), frameMat);
    m.position.set(s[0], winY, -21.7); scene.add(m);
  });
  // Dark glass tint inside frame (mostly transparent so stars show)
  var glass = new THREE.Mesh(new THREE.PlaneGeometry(winW, winH),
    new THREE.MeshBasicMaterial({ color: 0x060b12, transparent: true, opacity: 0.25 }));
  glass.position.set(0, winY, -21.8); scene.add(glass);

  // Ceiling + light strips
  var ceil = new THREE.Mesh(new THREE.PlaneGeometry(44, 44),
    new THREE.MeshLambertMaterial({ color: 0x10141a }));
  ceil.rotation.x = Math.PI / 2; ceil.position.y = 14; scene.add(ceil);
  var stripMat = new THREE.MeshBasicMaterial({ color: 0xbfe9f2 });
  for (var sxi = -1; sxi <= 1; sxi++) {
    var strip = new THREE.Mesh(new THREE.BoxGeometry(30, 0.15, 1.2), stripMat);
    strip.position.set(0, 13.8, sxi * 10); scene.add(strip);
  }
  var dl = new THREE.DirectionalLight(0xcfe8ff, 0.5); dl.position.set(6, 12, 8); scene.add(dl);

  buildConsoles();
  addEventListener('resize', function () {
    camera.aspect = innerWidth / innerHeight; camera.updateProjectionMatrix();
    renderer.setSize(innerWidth, innerHeight);
  });
}

function drawScreen(taskId) {
  var c = consoles[taskId]; if (!c) return;
  var g = c.screenCtx, s = SYS[taskId];
  g.fillStyle = '#06131d'; g.fillRect(0, 0, 256, 160);
  g.fillStyle = '#d8aa48'; g.font = 'bold 26px monospace'; g.textAlign = 'center';
  g.fillText(s.label, 128, 40);
  g.fillStyle = DMG_CSS[s.dmg]; g.font = 'bold 30px monospace';
  g.fillText(DMG_NAMES[s.dmg], 128, 88);
  // damage pips
  for (var i = 0; i < 3; i++) {
    g.fillStyle = i < s.dmg ? DMG_CSS[s.dmg] : '#1d2b34';
    g.fillRect(48 + i * 56, 112, 44, 20);
  }
  c.screenTex.needsUpdate = true;
}

function buildConsoles() {
  var defs = [
    { id: 'propulsion', x: -13, z: -8, ry: 0.5, accent: 0xff7a3c },
    { id: 'shielding',  x: 13,  z: -8, ry: -0.5, accent: 0x23c7d9 },
    { id: 'comms',      x: 0,   z: 12, ry: Math.PI, accent: 0xf2ad42 }
  ];
  defs.forEach(function (d) {
    var grp = new THREE.Group(); grp.position.set(d.x, 0, d.z); grp.rotation.y = d.ry;
    var ped = new THREE.Mesh(new THREE.BoxGeometry(2.4, 1.15, 1.1),
      new THREE.MeshLambertMaterial({ color: 0x232b34 }));
    ped.position.y = 0.575; grp.add(ped);
    var scr = new THREE.Mesh(new THREE.PlaneGeometry(2.0, 1.25),
      new THREE.MeshBasicMaterial({ map: null }));
    // create screen texture via drawScreen
    var c = document.createElement('canvas'); c.width = 256; c.height = 160;
    var tex = new THREE.CanvasTexture(c); tex.encoding = THREE.sRGBEncoding;
    scr.material.map = tex;
    scr.position.set(0, 1.75, 0.15); scr.rotation.x = -0.28; grp.add(scr);
    var ring = new THREE.Mesh(new THREE.TorusGeometry(0.85, 0.09, 10, 40),
      new THREE.MeshBasicMaterial({ color: DMG_COLORS[0] }));
    ring.position.set(0, 2.9, 0); grp.add(ring);
    var lamp = new THREE.PointLight(d.accent, 0.7, 12); lamp.position.set(0, 3.2, 0); grp.add(lamp);
    // generous invisible hit box for tapping
    var hit = new THREE.Mesh(new THREE.BoxGeometry(3.4, 3.6, 2.6),
      new THREE.MeshBasicMaterial({ visible: false }));
    hit.position.y = 1.8; hit.userData.taskId = d