<!-- SOLID CITY · part 2876 -->
52;
            limbs[0].rotation.x = sw; limbs[3].rotation.x = sw;
            limbs[1].rotation.x = -sw; limbs[2].rotation.x = -sw;
          }
          var hi = w.g.userData.heroInner;
          if (hi && hi.userData.update) hi.userData.update(dt, t + w.phase);
          if (w.kind === 'forge') w.g.rotation.z = Math.sin(w.phase) * 0.028;
        }
        for (i = 0; i < standers.length; i++) {
          var s = standers[i];
          s.g.rotation.y = s.face + Math.sin(t * 0.3 + s.phase) * 0.13;
          if (s.kind === 'shade') s.g.position.y = s.baseY + 0.12 + 0.05 * Math.sin(t * 1.3 + s.phase);
          var sh = s.g.userData.heroInner;
          if (sh && sh.userData.update) sh.userData.update(dt, t + s.phase);
        }
      }
    };
    return group;
  }

  return { createPopulation: createPopulation };
});


===== FILE: public/city/portrait.css =====
/* portrait.css: the King's rule that no city overlay may run past a phone screen (320-430px portrait, landscape,
   notch and home-bar safe areas). Loaded LAST; "html body" + !important outranks the <style> blocks modules inject. */
html,body{max-width:100%;overflow:hidden}
html body #sc{overflow:clip}
/* the renderer sizes the drawing buffer only; the canvas always takes the real viewport (iOS can report a stale innerWidth) */
html body #sc-gl{width:100% !important;height:100% !important}

/* every overlay: border-box, never wider than the screen minus a gutter, long words wrap */
html body #uni-panel,html body .sc-talk,html body .mp-panel,html body #hc-card,html body .w-pick,html body .rf-pick,html body .fg-sheet,
html body .fg-pop,html body #ai-panel,html body #pd-panel,html body .sc-portal,html body #hc-narration,html body #bk-book{
  box-sizing:border-box;max-width:calc(100vw - 16px - env(safe-area-inset-left) - env(safe-area-inset-right)) !important;overflow-wrap:anywhere;word-break:normal}
html body #bk-book{max-width:100vw !important}
html body #uni-panel *,html body #bk-reader *{box-sizing:border-box;max-width:100%}
html body #uni-panel .u-tabs,html body #uni-panel .u-row{flex-wrap:wrap}
html body #uni-panel .u-tabs button{flex:1 1 auto}
html body .sc-talk input,html body .sc-talk textarea,html body .mp-panel input,html body .w-pick input,html body .fg-sheet input,html body .fg-sheet textarea{max-width:100%;box-sizing:border-box}
html body .w-pick-h{position:sticky;top:-14px;z-index:2;background:#0a070b}
/* notch side in landscape */
html body #uni-panel{left:calc(12px + env(safe-area-inset-left))}
html body .mp-panel{left:calc(8px + env(safe-area-inset-left))}
html body #ai-panel{left:calc(8px + env(safe-area-inset-left))}

/* touch: every close button is a 44px target */
@media (max-width:600px),(pointer:coarse){
  html body #uni-panel .u-x,html body #bk-x,html body .mp-x,html body #sc-hud .hc-x,html body .w-x,html body #rf-x,html body .fg-x,
  html body #cz-close,html body #sp-close,html body #pd-x,html body #t-close,html body #p-close,html body #w-res-x{min-width:44px !important;min-height:44px !important;flex-shrink:0}
  html body .mp-x{flex:0 0 44px}
}

/* portrait phones: panels become bottom sheets with an 8px gutter, internal scroll, home-bar padding */
@media (max-width:600px){
  html body #uni-panel,html body .mp-panel,html body .w-pick,html body .rf-pick,html body .fg-sheet,html body .sc-talk{
    left:0 !important;right:0 !important;margin:0 auto !important;width:min(calc(100vw - 16px), 560px) !important;
    top:auto !important;bottom:0 !important;transform:none !important;border-radius:16px 16px 0 0 !important;border-width:2px 2px 0 !important}
  html body #uni-panel,html body .mp-panel{height:72vh !important;height:72dvh !important;max-height:calc(100% - 100px - env(safe-area-inset-top)) !important}
  html body .w-pick,html body .rf-pick,html body .fg-sheet{max-height:min(78vh, calc(100% - 100px - env(safe-area-inset-top))) !important;
    padding-bottom:calc(12px + env(safe-area-inset-bottom)) !important;overflow-y:auto !important;overflow-x:hidden !important}
  html body .sc-talk{max-height:min(66vh, calc(100% - 100px - env(safe-area-inset-top))) !important}
  html body #hc-card{left:calc(8px + env(safe-area-inset-left)) !important;max-width:calc(100vw - 16px) !important;box-sizing:border-box}
}
/* landscape phones: little height, so panels use the full height and step clear of the notch */
@media (max-height:500px) and (min-width:601px){
  html body #uni-panel{top:calc(8px + env(safe-area-inset-top)) !important;bottom:calc(8px + env(safe-area-inset-bottom)) !important;z-index:26}
  html body .mp-panel{top:calc(60px + env(safe-area-inset-top)) !important;bottom:calc(8px + env(safe-area-inset-bottom)) !important;height:auto !important}
  html body .w-pick{max-height:calc(100vh - 16px) !important}
  html body .sc-talk{left:calc(8px + env(safe-area-inset-left)) !important;right:calc(8px + env(safe-area-inset-right)) !important;max-height:80vh !important}
}


===== FILE: public/city/provolta-a