diff --git a/frontend/src/app/site-finder/analysis/[cad]/ptica/PticaPageContent.tsx b/frontend/src/app/site-finder/analysis/[cad]/ptica/PticaPageContent.tsx
index 684b1d61..7c08a200 100644
--- a/frontend/src/app/site-finder/analysis/[cad]/ptica/PticaPageContent.tsx
+++ b/frontend/src/app/site-finder/analysis/[cad]/ptica/PticaPageContent.tsx
@@ -33,6 +33,8 @@ import { PticaShell } from "@/components/site-finder/ptica/PticaShell";
import type { PticaTab } from "@/components/site-finder/ptica/PticaShell";
import { PticaHero } from "@/components/site-finder/ptica/PticaHero";
import { DevelopmentScan } from "@/components/site-finder/ptica/DevelopmentScan";
+import { PticaLowerGrid } from "@/components/site-finder/ptica/cockpit/PticaLowerGrid";
+import { PticaBottomGrid } from "@/components/site-finder/ptica/cockpit/PticaBottomGrid";
import { PticaScenarios } from "@/components/site-finder/ptica/scenarios/PticaScenarios";
import { PticaReports } from "@/components/site-finder/ptica/reports/PticaReports";
import { PticaCompare } from "@/components/site-finder/ptica/compare/PticaCompare";
@@ -146,6 +148,16 @@ export function PticaPageContent({ cad }: Props) {
analysis={analysis}
onOpenDrawer={handleOpenDrawer}
/>
+
+
>
)}
{tab === "scenarios" && (
diff --git a/frontend/src/app/site-finder/analysis/[cad]/ptica/ptica.module.css b/frontend/src/app/site-finder/analysis/[cad]/ptica/ptica.module.css
index 58f46369..157f0a78 100644
--- a/frontend/src/app/site-finder/analysis/[cad]/ptica/ptica.module.css
+++ b/frontend/src/app/site-finder/analysis/[cad]/ptica/ptica.module.css
@@ -656,7 +656,7 @@
}
.scanGrid {
display: grid;
- grid-template-columns: repeat(4, 1fr);
+ grid-template-columns: repeat(7, 1fr);
gap: 10px;
}
.scanCard {
@@ -1879,7 +1879,11 @@
}
@media (max-width: 1200px) {
.scanGrid {
- grid-template-columns: repeat(2, 1fr);
+ grid-template-columns: repeat(3, 1fr);
+ }
+ .lowerGrid,
+ .bottomGrid {
+ grid-template-columns: 1fr 1fr;
}
.forecastGrid,
.reportGrid {
@@ -1894,7 +1898,9 @@
display: none;
}
.hero,
- .scanGrid {
+ .scanGrid,
+ .lowerGrid,
+ .bottomGrid {
grid-template-columns: 1fr;
}
.scorePanel {
@@ -2167,3 +2173,309 @@
border-radius: 999px;
backdrop-filter: blur(6px);
}
+
+/* ===================== LOWER GRID (cockpit) =====================
+ Ported from prototype .lower-grid: ОКС · Development Potential ·
+ Recommended Product · Инсоляционная матрица. */
+.lowerGrid {
+ display: grid;
+ grid-template-columns: 1.05fr 1.05fr 1.15fr 0.95fr;
+ gap: 10px;
+}
+
+/* shared detail-btn that needs top separation inside flow cards */
+.detailBtnSpaced {
+ margin-top: 10px;
+ align-self: flex-start;
+}
+
+/* ОКС — isometric building visual + empty-state */
+.isoBox {
+ height: 84px;
+ display: grid;
+ place-items: center;
+ margin: 2px 0 10px;
+}
+.isoBox svg {
+ width: 100%;
+ height: 100%;
+}
+.isoFaceLeft {
+ fill: rgba(210, 101, 91, 0.22);
+ stroke: var(--accent-red);
+ stroke-width: 1;
+}
+.isoFaceTop {
+ fill: rgba(210, 101, 91, 0.13);
+ stroke: var(--accent-red);
+ stroke-width: 1;
+}
+.isoFaceRight {
+ fill: rgba(210, 101, 91, 0.3);
+ stroke: var(--accent-red);
+ stroke-width: 1;
+}
+
+/* Development Potential — metric tiles */
+.potentialGrid {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: 9px;
+ margin-bottom: 10px;
+}
+/* grid-item wrapper (label + value stack); min-width:0 stops long values
+ blowing out the grid track. */
+.metric {
+ min-width: 0;
+}
+.metricLabel {
+ font-size: 8.5px;
+ text-transform: uppercase;
+ letter-spacing: 0.06em;
+ color: var(--text-soft);
+ margin-bottom: 2px;
+}
+.metricValue {
+ font-size: 17px;
+ font-weight: 600;
+ color: var(--text-strong);
+}
+.metricValueLg {
+ font-size: 22px;
+}
+.metricValuePlaceholder {
+ color: var(--text-soft);
+ font-weight: 500;
+}
+.metricUnit {
+ font-size: 10px;
+ color: var(--text-muted);
+ margin-left: 3px;
+}
+
+/* Recommended Product — mix-bar head (квартирография / доля) */
+.mixHead {
+ display: flex;
+ justify-content: space-between;
+ font-size: 8.5px;
+ text-transform: uppercase;
+ letter-spacing: 0.06em;
+ color: var(--text-soft);
+ margin-bottom: 8px;
+}
+
+/* Инсоляционная матрица — faint preview massing + ПРЕВЬЮ placeholder */
+.isoBoxPreview {
+ height: 74px;
+ display: grid;
+ place-items: center;
+ margin: 2px 0 10px;
+ opacity: 0.55;
+}
+.isoBoxPreview svg {
+ width: 100%;
+ height: 100%;
+}
+.isoPreviewLeft {
+ fill: rgba(150, 192, 214, 0.1);
+ stroke: var(--border-strong);
+ stroke-width: 1;
+}
+.isoPreviewTop {
+ fill: rgba(150, 192, 214, 0.06);
+ stroke: var(--border-strong);
+ stroke-width: 1;
+}
+.isoPreviewRight {
+ fill: rgba(150, 192, 214, 0.14);
+ stroke: var(--border-strong);
+ stroke-width: 1;
+}
+.isoPreviewEdge {
+ stroke: var(--border);
+ stroke-width: 0.6;
+}
+.placeholder {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ text-align: center;
+ gap: 8px;
+}
+.placeholderSoon {
+ font-size: 22px;
+ letter-spacing: 0.12em;
+ color: var(--text-soft);
+ font-weight: 600;
+}
+.placeholder p {
+ font-size: 10px;
+ color: var(--text-soft);
+ margin: 0;
+ max-width: 180px;
+}
+
+/* ===================== BOTTOM GRID (cockpit) =====================
+ Ported from prototype .bottom-grid: Investment Clearance · Buy Signal ·
+ Legal Status · Site Verdict. */
+.bottomGrid {
+ display: grid;
+ grid-template-columns: 1.5fr 0.62fr 0.86fr 1.2fr;
+ gap: 10px;
+}
+
+/* Investment Clearance — bignum row */
+.bignumRow {
+ display: grid;
+ grid-template-columns: repeat(5, 1fr);
+ gap: 8px;
+}
+.bignum {
+ min-width: 0;
+}
+.bignumLabel {
+ font-size: 8.5px;
+ text-transform: uppercase;
+ letter-spacing: 0.06em;
+ color: var(--text-soft);
+ margin-bottom: 4px;
+}
+.bignumValue {
+ font-size: 30px;
+ font-weight: 500;
+ letter-spacing: 0.01em;
+ color: var(--text-strong);
+ line-height: 1;
+}
+.bignumValuePlaceholder {
+ color: var(--text-soft);
+}
+.bignumUnit {
+ display: block;
+ font-size: 9px;
+ color: var(--text-muted);
+ margin-top: 4px;
+ text-transform: uppercase;
+ letter-spacing: 0.05em;
+}
+.bignumCaption {
+ margin: 12px 0 0;
+ font-size: 9px;
+ text-transform: uppercase;
+ letter-spacing: 0.06em;
+ color: var(--text-soft);
+}
+
+/* Buy Signal — centered gauge */
+.buySignalCard {
+ display: grid;
+ place-items: center;
+}
+.buySignalTitle {
+ align-self: flex-start;
+}
+
+/* Legal Status — Нет/значение grid */
+.legalGrid {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: var(--line);
+ background: var(--border-faint);
+ border: var(--line) solid var(--border-faint);
+ border-radius: var(--radius-sm);
+ overflow: hidden;
+}
+.legalCell {
+ background: var(--surface-2);
+ padding: 9px 11px;
+}
+.legalKey {
+ display: block;
+ font-size: 8.5px;
+ text-transform: uppercase;
+ letter-spacing: 0.07em;
+ color: var(--text-soft);
+ margin-bottom: 3px;
+}
+.legalValue {
+ font-size: 12.5px;
+ font-weight: 600;
+ color: var(--text);
+}
+.legalValuePlaceholder {
+ color: var(--text-soft);
+ font-weight: 500;
+}
+
+/* Site Verdict — headline plaque + checklist */
+.verdictCard {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ gap: 10px;
+ text-align: center;
+}
+.verdictSplit {
+ display: grid;
+ grid-template-columns: auto 1fr;
+ gap: 18px;
+ align-items: center;
+}
+.verdictLead {
+ text-align: center;
+}
+.verdictLeadLabel {
+ font-size: 9px;
+ text-transform: uppercase;
+ letter-spacing: 0.12em;
+ color: var(--text-soft);
+ margin-bottom: 6px;
+}
+.verdictWord {
+ font-size: 30px;
+ font-weight: 700;
+ letter-spacing: 0.18em;
+ text-transform: uppercase;
+ text-shadow: 0 0 22px var(--glow);
+}
+.verdictWordGood {
+ color: var(--accent-green);
+}
+.verdictWordWarn {
+ color: var(--accent-yellow);
+}
+.verdictWordBad {
+ color: var(--accent-red);
+}
+.checklist {
+ display: grid;
+ gap: 8px;
+ text-align: left;
+}
+.checkItem {
+ display: flex;
+ align-items: flex-start;
+ gap: 9px;
+ font-size: 10.5px;
+ text-transform: uppercase;
+ letter-spacing: 0.03em;
+ color: var(--text-muted);
+}
+.checkIc {
+ width: 16px;
+ height: 16px;
+ flex: none;
+}
+.checkItemOk .checkIc {
+ color: var(--accent-green);
+ border: var(--line-strong) solid currentColor;
+ border-radius: 50%;
+ padding: 2px;
+}
+.checkItemWarn .checkIc {
+ color: var(--accent-yellow);
+}
+.checkItemBad .checkIc {
+ color: var(--accent-red);
+}
diff --git a/frontend/src/components/site-finder/ptica/BuildabilityGauge.tsx b/frontend/src/components/site-finder/ptica/BuildabilityGauge.tsx
index 1bf46eb2..714bc38b 100644
--- a/frontend/src/components/site-finder/ptica/BuildabilityGauge.tsx
+++ b/frontend/src/components/site-finder/ptica/BuildabilityGauge.tsx
@@ -41,9 +41,11 @@ export function BuildabilityGauge({ gauge, title }: Props) {
return (
-
- {title}
-
+ {title && (
+
+ {title}
+
+ )}