+ {/* Summary */}
+
+
+ {counts.yes + counts.partial} of {threatVectors.length} vectors covered
+
+
+
+
+ {counts.yes} secured
+
+
+
+ {counts.partial} in progress
+
+
+
+ {counts.no} gaps
+
+
+
+
+ {/* SVG Radial Map */}
+
+
+
+
+ {/* Mobile list fallback */}
+
+ {threatVectors.map((v) => {
+ const state = posture[v.id] || "no";
+ const sev = severityMeta[v.severity];
+ return (
+
handleSelect(v.id)}
+ >
+
{
+ e.stopPropagation();
+ handleToggle(v.id);
+ }}
+ >
+ {checkMarks[state]}
+
+
{v.title}
+
+ {sev.label}
+
+
+ );
+ })}
+
+
+ {/* Detail Card */}
+ {selectedVector && (
+
handleSetPosture(selectedVector.id, state)}
+ onClose={() => setSelected(null)}
+ />
+ )}
+
+ );
+}
+
+function DetailCard({
+ vector,
+ state,
+ onSetState,
+ onClose,
+}: {
+ vector: ThreatVector;
+ state: PostureState;
+ onSetState: (state: PostureState) => void;
+ onClose: () => void;
+}) {
+ const sev = severityMeta[vector.severity];
+
+ return (
+