+ КСИТ-цель {farTarget.toFixed(1)} · регламент-дефолт, источник НСПД ·
+ масса генеративная (этажи/секции/время — исследовательские вводные)
+
+
+
+ );
+}
diff --git a/frontend/src/components/site-finder/ptica/massing/MassingViewer.tsx b/frontend/src/components/site-finder/ptica/massing/MassingViewer.tsx
new file mode 100644
index 00000000..84c4333c
--- /dev/null
+++ b/frontend/src/components/site-finder/ptica/massing/MassingViewer.tsx
@@ -0,0 +1,35 @@
+"use client";
+
+/**
+ * MassingViewer — the only entry point the drawer imports for the 3D massing
+ * sandbox. Loads MassingScene (Three.js) client-side only via
+ * `dynamic(ssr:false)` so WebGL/Three.js never run on the server, with a dark
+ * skeleton while the chunk loads. The drawer gates its children behind
+ * `{open && ...}`, so the scene mounts on open and the MassingScene effect
+ * cleanup disposes the renderer/scene on close.
+ */
+
+import dynamic from "next/dynamic";
+
+import styles from "@/app/site-finder/analysis/[cad]/ptica/ptica.module.css";
+import type { MassingSceneProps } from "@/components/site-finder/ptica/massing/MassingScene";
+
+const MassingScene = dynamic(
+ () => import("@/components/site-finder/ptica/massing/MassingScene"),
+ {
+ ssr: false,
+ loading: () => (
+