Files

1094 lines
81 KiB
TypeScript

/* eslint-disable */
// @ts-nocheck
// [TSM.ID].[11031972] — All Rights Reserved. Proprietary & Confidential.
"use client";
import { useEffect, useState, useRef, useCallback } from "react";
import { XCUQuantumMatrix } from "../lib/xcu-quantum-decoder";
import { JumlahChat } from "./JumlahChat";
import { NeuralAttentionEngine } from "./NeuralAttentionEngine";
import { QuantumAdapter } from "../lib/quantum-adapter";
export function XCURoom({ roomName, token, serverUrl, isVoiceCall = false, initialCameraOn = false, initialMicOn = false, isAudience = false, username: propUsername = '', adapter = QuantumAdapter.getInstance() }: any) {
// BUG FIX #1: FPS selector state
const [currentFps, setCurrentFps] = useState<15 | 30 | 60>(30);
const [logs, setLogs] = useState<string[]>([]);
const [isMatrixActive, setIsMatrixActive] = useState(false);
const [isChatOpen, setIsChatOpen] = useState(false);
const [isParticipantsOpen, setIsParticipantsOpen] = useState(false);
const [isCameraOn, setIsCameraOn] = useState(initialCameraOn);
const [cameraFacingMode, setCameraFacingMode] = useState<"user" | "environment">("user");
const [useVirtualBg, setUseVirtualBg] = useState<number>(0);
const [useBeautyFilter, setUseBeautyFilter] = useState(false);
const [isMicOn, setIsMicOn] = useState(initialMicOn);
const [isScreenSharing, setIsScreenSharing] = useState(false);
const [isMoreMenuOpen, setIsMoreMenuOpen] = useState(false);
const [layoutMode, setLayoutMode] = useState<'speaker' | 'gallery'>('gallery');
const [isPodcast, setIsPodcast] = useState(false);
const [participants, setParticipants] = useState<number[]>([]);
const [participantNames, setParticipantNames] = useState<Record<number, string>>({});
const [localStream, setLocalStream] = useState<MediaStream | null>(null);
const [activeSpeakerId, setActiveSpeakerId] = useState<number | null>(null);
const [audioLevel, setAudioLevel] = useState<number>(0);
const [participantId, setParticipantId] = useState<number>(0);
const [isTransportReady, setIsTransportReady] = useState(false);
const [webTransport, setWebTransport] = useState<{ datagrams: { readable: ReadableStream, writable: WritableStream } } | null>(null);
const [isShadowNode, setIsShadowNode] = useState(false);
const [username, setUsername] = useState(propUsername || "");
const [isRenamingLocal, setIsRenamingLocal] = useState(false);
const [renameInput, setRenameInput] = useState("");
const omniChannelRef = useRef<BroadcastChannel | null>(null);
// FASE 84 & 86: Zero UI Cinematic Mode & Attention Engine
const [isIdle, setIsIdle] = useState(false);
const [isAttentive, setIsAttentive] = useState(false);
const [meetingTime, setMeetingTime] = useState(0);
const idleTimerRef = useRef<NodeJS.Timeout | null>(null);
// FASE 86: Parallax and Audio Refs
const audioRef = useRef<number>(0);
const [mousePos, setMousePos] = useState({ x: 0, y: 0 });
const [status, setStatus] = useState<string>("Inisialisasi XCom WebTransport...");
const [unlockedModules, setUnlockedModules] = useState<number[]>([]);
const [bgUrl, setBgUrl] = useState<string | null>(null);
const [e2eeKeyStr, setE2eeKeyStr] = useState<string | null>(null);
const [videoEngineMode, setVideoEngineMode] = useState<'auto'|'canvas'|'webcodecs'>('auto');
const [isMatrixCommandOpen, setIsMatrixCommandOpen] = useState(false);
const [matrixCommandTab, setMatrixCommandTab] = useState<'network'|'quantum'>('network');
const [wasmCapabilities, setWasmCapabilities] = useState({ postQuantum: false, aegis: false, doppler: false, neuralWhisper: false });
const [globalTimer, setGlobalTimer] = useState<number | null>(null);
const [activeWasmModules, setActiveWasmModules] = useState<{kyber: boolean, aegis: boolean, whisper: boolean, doppler: boolean}>({kyber: false, aegis: false, whisper: false, doppler: false});
// PKEPX Zoom-Killer States
const [isBreakoutOpen, setIsBreakoutOpen] = useState(false);
const [activeReactions, setActiveReactions] = useState<{id: number, type: string, ts: number}[]>([]);
const [isRecording, setIsRecording] = useState(false);
const [isHost, setIsHost] = useState(false); // Host is the first one or designated
const [isLeaving, setIsLeaving] = useState(false); // Confirmation for leaving
// Helper: format bytes/sec to human readable
const formatRate = (bps: number) => {
if (bps === 0) return '0 B/s';
if (bps < 1024) return bps + ' B/s';
if (bps < 1048576) return (bps / 1024).toFixed(1) + ' KB/s';
return (bps / 1048576).toFixed(2) + ' MB/s';
};
const formatBytes = (b: number) => {
if (b < 1024) return b + ' B';
if (b < 1048576) return (b / 1024).toFixed(1) + ' KB';
return (b / 1048576).toFixed(1) + ' MB';
};
const [trafficStats, setTrafficStats] = useState({
tx: { video: 0, audio: 0, control: 0, total: 0 },
rx: { video: 0, audio: 0, control: 0, total: 0 },
rates: { txVideo: 0, txAudio: 0, txTotal: 0, rxVideo: 0, rxAudio: 0, rxTotal: 0 },
wsState: 'CLOSED',
});
const [audioEngineMode, setAudioEngineMode] = useState<'auto'|'pcm'|'xcu-neural'>('auto');
const [autoPilotMetrics, setAutoPilotMetrics] = useState({ vCodec: 'STANDBY', aCodec: 'STANDBY', bw: 0 });
const [uiMatrix, setUiMatrix] = useState<any>(null);
const matrixRef = useRef<XCUQuantumMatrix | null>(null);
const tokenRef = useRef<string>("");
const [quantumUpgradeAlert, setQuantumUpgradeAlert] = useState<string | null>(null);
const localVideoRef = useRef<HTMLVideoElement>(null);
useEffect(() => {
const timer = setInterval(() => setMeetingTime(t => t + 1), 1000);
return () => clearInterval(timer);
}, []);
const fetchQuantumTokenLive = useCallback(async () => {
try {
const res = await fetch(`/api/auth/quantum_token?_cb=${Date.now()}&_live=1`, { credentials: 'include' });
if (res.ok) {
const data = await res.json();
setUiMatrix(data.capabilities?.ui || null);
// DYNAMIC DB CONFIG FOR WASM SDK (Mocking if missing)
setWasmCapabilities(data.capabilities?.wasm || {
postQuantum: true, // Supreme Admin gets true by default
aegis: true,
doppler: true,
neuralWhisper: true
});
console.log("[Quantum Sovereignty] UI Matrix live updated:", data.capabilities?.ui);
}
} catch(e) {}
}, []);
const formatTime = (s: number) => {
const min = Math.floor(s / 60);
const sec = s % 60;
return `${min}:${sec < 10 ? '0' : ''}${sec}`;
};
const resetIdleTimer = useCallback((e?: MouseEvent) => {
setIsIdle(false);
if (e) {
setMousePos({
x: (e.clientX / window.innerWidth) * 2 - 1,
y: (e.clientY / window.innerHeight) * 2 - 1
});
}
if (idleTimerRef.current) clearTimeout(idleTimerRef.current);
idleTimerRef.current = setTimeout(() => setIsIdle(isAttentive), 8000);
}, [isAttentive]);
useEffect(() => {
window.addEventListener('mousemove', resetIdleTimer);
const handleUserInteraction = async () => {
await adapter.warmUpAudio();
if (matrixRef.current) matrixRef.current.resumeAudioContext();
};
window.addEventListener('click', handleUserInteraction);
window.addEventListener('touchstart', handleUserInteraction);
// Set codec strategy based on browser
const strategy = adapter.getCodecStrategy();
console.log(`[QuantumAdapter] Selected Codec Strategy: ${strategy} for ${JSON.stringify(adapter.capabilities)}`);
const handleMessage = (e: MessageEvent) => {
if (e.data?.type === 'SYNC_SETTINGS_TO_VC') {
const payload = e.data.payload || {};
if (payload.videoBg === 'custom' && payload.customBgUrl) setBgUrl(payload.customBgUrl);
else setBgUrl(null);
} else if (e.data?.type === 'SET_E2EE_KEY') {
const key = e.data.payload;
setE2eeKeyStr(key);
if (matrixRef.current) matrixRef.current.setE2EEKey(key);
window.parent.postMessage({ type: 'SUPREME_EYE_TELEMETRY', payload: { e2eeActive: key !== 'NO_KEY' && key !== 'none' } }, '*');
} else if (e.data?.type === 'SET_CUSTOM_BG') setBgUrl(e.data.payload);
};
window.addEventListener('message', handleMessage);
const bc = new BroadcastChannel('omni_channel');
bc.addEventListener('message', (e) => {
if (e.data?.type === 'REFRESH_QUANTUM_TOKEN') {
console.log("Omni-Channel LIVE: Resyncing Quantum Token...");
fetchQuantumTokenLive();
}
});
omniChannelRef.current = bc;
setTimeout(() => resetIdleTimer(), 0);
return () => {
window.removeEventListener('mousemove', resetIdleTimer);
window.removeEventListener('click', handleUserInteraction);
window.removeEventListener('touchstart', handleUserInteraction);
window.removeEventListener('message', handleMessage);
bc.close();
if (idleTimerRef.current) clearTimeout(idleTimerRef.current);
};
}, [resetIdleTimer, adapter]);
useEffect(() => {
audioRef.current = audioLevel / 100;
}, [audioLevel]);
const addLog = useCallback((msg: string) => {
setLogs(prev => [...prev, msg]);
}, []);
const handleToggleCamera = useCallback(async () => {
if (!matrixRef.current) return;
if (!isCameraOn) {
setIsCameraOn(true);
setIsScreenSharing(false);
await matrixRef.current.activateUplink('camera', cameraFacingMode);
// BUG FIX #2: Ensure mic state stays independent of camera
// Camera activateUplink requests audio track too, so enforce current mic state
matrixRef.current.toggleMic(isMicOn);
} else {
await matrixRef.current.deactivateUplink();
setIsCameraOn(false);
setLocalStream(null);
}
}, [isCameraOn, isMicOn, cameraFacingMode]);
const handleFlipCamera = async () => {
const newMode = cameraFacingMode === 'user' ? 'environment' : 'user';
setCameraFacingMode(newMode);
if (isCameraOn && matrixRef.current) {
await matrixRef.current.deactivateUplink();
await matrixRef.current.activateUplink('camera', newMode);
}
};
useEffect(() => {
if (globalTimer === null || globalTimer <= 0) return;
const t = setInterval(() => setGlobalTimer(prev => prev !== null && prev > 0 ? prev - 1 : prev), 1000);
return () => clearInterval(t);
}, [globalTimer]);
useEffect(() => {
let matrix: XCUQuantumMatrix | null = null;
const initMatrix = async () => {
try {
const channel = new BroadcastChannel(`omni_matrix_${roomName}`);
omniChannelRef.current = channel;
let isMaster = false;
const electionPromise = new Promise<boolean>((resolve) => {
const timeout = setTimeout(() => resolve(true), 150);
channel.onmessage = (e) => {
if (e.data.type === "I_AM_MASTER") { clearTimeout(timeout); resolve(false); }
};
channel.postMessage({ type: "WHO_IS_MASTER" });
});
isMaster = await electionPromise;
if (!isMaster) {
setIsShadowNode(true);
setStatus("Shadow Node Active.");
channel.onmessage = (e) => {
if (e.data.type === "MASTER_UPGRADE_ALERT") { setQuantumUpgradeAlert(e.data.msg); setTimeout(() => setQuantumUpgradeAlert(null), 5000); }
if (e.data.type === "MASTER_LOG") addLog(e.data.msg);
};
return;
}
channel.onmessage = (e) => { if (e.data.type === "WHO_IS_MASTER") channel.postMessage({ type: "I_AM_MASTER" }); };
const currentHost = typeof window !== 'undefined' ? window.location.hostname : '127.0.0.1';
const nodes = process.env.NEXT_PUBLIC_XCU_NODES ? process.env.NEXT_PUBLIC_XCU_NODES.split(',') : [`${window.location.protocol}//${currentHost}:8443`];
let winningNode = serverUrl;
let quantumHash: string | undefined;
try {
const pingPromises = nodes.map(url => new Promise<{node: string, hash: string}>((resolve, reject) => {
const urlObj = new URL(url);
const proto = window.location.protocol;
fetch(`${proto}//${urlObj.hostname}/api/v1/system/cert`, { signal: AbortSignal.timeout(1500) })
.then(res => res.json()).then(data => data?.hash ? resolve({ node: url, hash: data.hash }) : reject()).catch(reject);
}));
const winner = await Promise.any(pingPromises);
winningNode = winner.node; quantumHash = winner.hash;
} catch (e) {}
// DETERMINISTIC Participant ID — same user = same ID, prevents duplicates
// Hash email to 16-bit integer (1-65534) so same user in different tabs/browsers = same ID
let pId = 1;
try {
const authForId = await fetch(`/vc/api/auth/me?_cb=${Date.now()}`);
const authIdData = await authForId.json();
if (authIdData.email) {
let hash = 0;
for (let i = 0; i < authIdData.email.length; i++) {
hash = ((hash << 5) - hash + authIdData.email.charCodeAt(i)) | 0;
}
pId = (Math.abs(hash) % 65534) + 1; // 1-65534 range
} else {
pId = Math.floor(Math.random() * 65534) + 1; // Fallback for guest
}
} catch(_) {
pId = Math.floor(Math.random() * 65534) + 1;
}
let entitlementToken = "";
let byokKeyFromToken = "none";
let matrixCapabilities: any = null;
try {
const res = await fetch(`/api/auth/quantum_token?_cb=${Date.now()}`, { credentials: 'include' });
if (res.ok) {
const data = await res.json();
entitlementToken = data.token;
tokenRef.current = entitlementToken;
matrixCapabilities = data.capabilities;
if (data.byokActive && data.byok) {
byokKeyFromToken = data.byok;
}
setUiMatrix(matrixCapabilities?.ui || null);
// Assign host capability based on UI Matrix
if (matrixCapabilities?.ui?.['jvc.ui.host_controls'] !== false) {
setIsHost(true);
}
} else {
throw new Error("Quantum Gateway menolak akses (Anti-Jumping Triggered).");
}
} catch (e) {
console.error("Quantum Auth Failed", e);
setStatus("Akses Ditolak. Harap masuk melalui JUMPA.ID IAM.");
return;
}
matrix = new XCUQuantumMatrix(roomName, pId, entitlementToken);
setParticipantId(matrix.participantId);
matrixRef.current = matrix;
// Poll REAL traffic stats from matrix every 1s
const trafficPoll = setInterval(() => {
if (matrixRef.current?.trafficStats) {
const s = matrixRef.current.trafficStats;
setTrafficStats({
tx: { ...s.tx }, rx: { ...s.rx },
rates: { ...s.rates }, wsState: s.wsState,
});
}
}, 1000);
// Terapkan Hukum 101-Modul Matrix (Kedaulatan Otak XCU)
if (matrixCapabilities && matrixCapabilities.video) {
// Jika Autopilot diizinkan oleh lisensi, gunakan 'auto'. Jika tidak, paksa 'webcodecs' atau 'canvas' berdasarkan resolusi
const isAutopilot = matrixCapabilities.video.features?.autopilot;
const hardCodec = matrixCapabilities.video.maxResolution === '4K' ? 'webcodecs' : 'canvas';
matrix.videoEngineMode = 'canvas'; // FORCED BY SUPREME COMMANDER TO AVOID WEBCODECS CRASH
// Log ke console untuk bukti Forensik Auto-Pilot / Hard-Codec
console.log(`[101-MATRIX] Video Codec disetel ke: ${matrix.videoEngineMode} (Lisensi: ${matrixCapabilities.video.codec})`);
// Audio juga dikontrol oleh Matrix
matrix.audioEngineMode = matrixCapabilities.chat?.features?.omniBrainAI ? 'xcu-neural' : 'auto';
} else {
matrix.videoEngineMode = videoEngineMode;
matrix.audioEngineMode = audioEngineMode;
}
// Prioritize BYOK Key from Token over Local State (Central Sovereignty)
const effectiveKey = byokKeyFromToken !== 'none' ? byokKeyFromToken : (e2eeKeyStr || 'NO_KEY');
if (effectiveKey !== 'NO_KEY') {
matrix.setE2EEKey(effectiveKey);
if (byokKeyFromToken !== 'none') setE2eeKeyStr(byokKeyFromToken);
}
matrix.onModuleUnlocked = (id) => setUnlockedModules(prev => prev.includes(id) ? prev : [...prev, id]);
matrix.onLocalStream = (s) => setLocalStream(s);
matrix.onParticipantJoined = (id) => {
setParticipants(prev => prev.includes(id) ? prev : [...prev, id]);
// BUG FIX #3: Immediately re-announce our name when a new participant joins
// so they see our name instead of a number
setTimeout(() => { if (matrixRef.current) matrixRef.current.announceDisplayName(); }, 500);
};
matrix.onParticipantLeft = (id) => {
setParticipants(prev => prev.filter(p => p !== id));
setParticipantNames(prev => { const n = {...prev}; delete n[id]; return n; });
};
matrix.onParticipantNameReceived = (id, name) => {
setParticipantNames(prev => ({...prev, [id]: name}));
};
matrix.onActiveSpeakerChanged = (id) => setActiveSpeakerId(id);
matrix.onAudioLevel = (l) => setAudioLevel(l);
matrix.onQuantumResonance = (id, type) => {
if (type.startsWith('TIMER:')) {
const secs = parseInt(type.split(':')[1]);
setGlobalTimer(secs);
return;
}
setActiveReactions(prev => [...prev, { id, type, ts: Date.now() }]);
// Auto cleanup after 4 seconds
setTimeout(() => {
setActiveReactions(prev => prev.filter(r => Date.now() - r.ts < 4000));
}, 4000);
};
matrix.onSovereignSignal = (type, payload) => {
if (type === 'MUTED_BY_HOST') setIsMicOn(false);
if (type === 'WARP_COMPLETE') window.location.href = `/room/${payload}`;
};
// BUG FIX #3: Use display name (not email) — like Zoom shows participant names
const authResp = await fetch(`/vc/api/auth/me?_cb=${Date.now()}`);
const authData = await authResp.json();
if (authData.name || authData.displayName) {
// Prefer human-readable name over email
const displayName = authData.name || authData.displayName;
matrix.displayName = displayName;
setUsername(displayName);
} else if (authData.email) {
// Fallback: Use email prefix (before @) as display name
const emailName = authData.email.split('@')[0];
matrix.displayName = emailName;
setUsername(emailName);
} else if (propUsername) {
matrix.displayName = propUsername;
}
await matrix.ignite(roomName, winningNode, entitlementToken);
setIsMatrixActive(true); setIsTransportReady(true);
setWebTransport(matrix.transport);
// Announce display name to room after 2s (let connection stabilize)
setTimeout(() => { if (matrixRef.current) matrixRef.current.announceDisplayName(); }, 2000);
// Re-announce every 10s so new joiners learn existing names
const nameAnnounceInterval = setInterval(() => {
if (matrixRef.current) matrixRef.current.announceDisplayName();
}, 10000);
// Auto-pilot based on Lobby selection
if (initialCameraOn) {
setTimeout(() => { if (matrixRef.current) matrixRef.current.activateUplink('camera', cameraFacingMode).then(() => setIsCameraOn(true)); }, 1000);
}
if (initialMicOn) {
setTimeout(() => { if (matrixRef.current) matrixRef.current.toggleMic(true); }, 1500);
}
} catch (e) { setStatus("Connection Failed."); }
};
initMatrix();
// Immediate cleanup on tab close to prevent ghost participants
const handleBeforeUnload = () => {
if (matrixRef.current) matrixRef.current.shutdown();
};
window.addEventListener('beforeunload', handleBeforeUnload);
return () => {
window.removeEventListener('beforeunload', handleBeforeUnload);
if (matrix) matrix.shutdown();
if (omniChannelRef.current) omniChannelRef.current.close();
};
}, []);
const onDisconnect = () => {
setStatus("Reconnecting...");
setIsMatrixActive(false);
setTimeout(() => {
if (matrixRef.current) {
matrixRef.current.ignite(roomName as string, "wss://mesh.ultramodul.xyz/api/system/engine", tokenRef.current)
.then(() => { setStatus("Connected"); setIsMatrixActive(true); })
.catch(() => window.location.href = '/dashboard');
}
}, 3000);
};
const handleToggleMic = () => {
const newState = !isMicOn; setIsMicOn(newState);
if (matrixRef.current) { matrixRef.current.toggleMic(newState); matrixRef.current.resumeAudioContext(); }
};
// Update effects when toggled
useEffect(() => {
if (matrixRef.current) {
matrixRef.current.setEffects(useVirtualBg, useBeautyFilter);
}
}, [useVirtualBg, useBeautyFilter]);
const handleToggleScreen = async () => {
if (!matrixRef.current) return;
if (isScreenSharing) {
await matrixRef.current.deactivateUplink(); setIsScreenSharing(false); setLocalStream(null);
if (isCameraOn) await matrixRef.current.activateUplink('camera', cameraFacingMode);
} else {
await matrixRef.current.deactivateUplink(); setIsCameraOn(false); setIsScreenSharing(true);
await matrixRef.current.activateUplink('screen');
}
};
const renderVideoTile = (id: number, isSmall: boolean) => {
const isLocal = id === participantId;
if (isAudience && isLocal) return null;
return (
<div className="w-full h-full relative group bg-black flex items-center justify-center">
{isLocal ? (
<>
<NeuralAttentionEngine videoRef={localVideoRef} onAttentionChange={setIsAttentive} />
{(isCameraOn || isScreenSharing) ? (
<video ref={(el) => { if (el && localStream && el.srcObject !== localStream) el.srcObject = localStream; localVideoRef.current = el; }} autoPlay playsInline muted className={`w-full h-full object-cover ${isCameraOn && !isScreenSharing ? 'scale-x-[-1]' : ''}`} />
) : (
<div className="w-full h-full flex items-center justify-center bg-slate-900">
<div className={`${isSmall ? 'w-10 h-10 text-sm' : 'w-24 h-24 text-4xl'} rounded-full bg-gradient-to-br from-blue-600 to-indigo-700 flex items-center justify-center font-bold text-white`}>{(username || 'U').substring(0,2).toUpperCase()}</div>
</div>
)}
</>
) : (
<>
<canvas id={`quantum-matrix-${id}`} className="w-full h-full object-cover" ref={el => { if (el && matrixRef.current && !isSmall) matrixRef.current.registerCanvas(id, el.id); }} />
{!participants.includes(id) && (
<div className="absolute inset-0 flex items-center justify-center bg-slate-950">
<div className="w-16 h-16 rounded-full bg-gradient-to-br from-emerald-600 to-teal-700 animate-pulse flex items-center justify-center text-white font-bold">{(participantNames[id] || 'P').substring(0,2).toUpperCase()}</div>
</div>
)}
</>
)}
<div className="absolute top-3 right-3 opacity-0 group-hover:opacity-100 transition-opacity z-50">
<button
onClick={async (e) => {
e.stopPropagation();
try {
if (isLocal && localVideoRef.current) {
await localVideoRef.current.requestPictureInPicture();
} else {
const canvas = document.getElementById(`quantum-matrix-${id}`) as HTMLCanvasElement;
if (canvas) {
const stream = canvas.captureStream(30);
const video = document.createElement('video');
video.srcObject = stream;
video.muted = true;
await video.play();
await video.requestPictureInPicture();
}
}
} catch (err) {
console.warn("[PiP] Failed to start Picture-in-Picture", err);
}
}}
className="p-1.5 bg-black/60 backdrop-blur-md rounded-lg text-white/80 hover:text-white border border-white/10 hover:border-white/30 transition-all"
title="Picture in Picture"
>
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M21 3H3v18h18V3zM21 12H12v9h9v-9z"></path></svg>
</button>
</div>
<div className="absolute bottom-3 left-3 px-3 py-1 bg-black/60 backdrop-blur-md rounded-lg text-xs font-bold text-white flex items-center gap-2 border border-white/10 opacity-0 group-hover:opacity-100 transition-opacity">
<div className={`w-2 h-2 rounded-full ${isMicOn || !isLocal ? 'bg-emerald-500' : 'bg-red-500'}`}></div>
{isLocal ? (username || 'Me') : (participantNames[id] || `User ${id}`)}
{isLocal && <span className="text-[8px] text-white/50">(Me)</span>}
</div>
{/* PKEPX Quantum Resonance */}
{activeReactions.filter(r => r.id === id).map(r => (
<div key={r.ts} className="absolute inset-0 flex items-center justify-center z-50 pointer-events-none animate-[ping_1s_ease-out]">
<span className="text-6xl md:text-8xl drop-shadow-[0_0_30px_rgba(255,255,255,0.8)] animate-bounce">{r.type}</span>
</div>
))}
</div>
);
};
const allParticipants = [participantId, ...participants].filter((id, i, arr) => arr.indexOf(id) === i && id !== 0);
const effectiveActiveSpeaker = activeSpeakerId || participantId;
const theme = 'dark';
return (
<div className={`h-dvh w-full bg-black text-slate-200 font-sans flex flex-col overflow-hidden relative selection:bg-emerald-500/30 ${theme === 'light' ? 'bg-white' : ''}`}>
{/* Rename Modal — like Zoom rename */}
{isRenamingLocal && (
<div className="absolute inset-0 bg-black/80 backdrop-blur-md z-[100] flex items-center justify-center">
<div className="bg-[#050b14] border border-blue-500/30 rounded-2xl p-6 w-[340px] shadow-[0_0_50px_rgba(59,130,246,0.2)]">
<h3 className="text-sm font-black text-blue-400 uppercase tracking-widest mb-4">Rename</h3>
<input
type="text"
value={renameInput}
onChange={(e) => setRenameInput(e.target.value)}
className="w-full bg-[#0a101d] text-white border border-white/10 rounded-xl px-4 py-3 mb-4 focus:outline-none focus:border-blue-500 font-mono text-sm"
autoFocus
maxLength={64}
placeholder="Display name..."
/>
<div className="flex gap-2">
<button onClick={() => setIsRenamingLocal(false)} className="flex-1 py-2.5 text-gray-400 font-bold bg-white/5 hover:bg-white/10 rounded-xl text-sm">Batal</button>
<button onClick={() => {
if (renameInput.trim()) {
setUsername(renameInput.trim());
if (matrixRef.current) matrixRef.current.setDisplayName(renameInput.trim());
}
setIsRenamingLocal(false);
}} className="flex-1 py-2.5 text-white font-bold bg-blue-600 hover:bg-blue-500 rounded-xl text-sm">Simpan</button>
</div>
</div>
</div>
)}
{/* PKEPX Fractal Matrix Breakout Modal */}
{isBreakoutOpen && (
<div className="absolute inset-0 bg-black/80 backdrop-blur-md z-[100] flex items-center justify-center">
<div className="bg-[#050b14] border border-purple-500/30 rounded-2xl p-6 w-[340px] md:w-[400px] shadow-[0_0_50px_rgba(168,85,247,0.2)]">
<h3 className="text-sm font-black text-purple-400 uppercase tracking-widest mb-4 flex items-center gap-2">
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M4 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2V6zm10 0a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2V6zM4 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2v-2zm10 0a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2v-2z"></path></svg>
Fractal Matrix Warp
</h3>
<div className="space-y-3">
<button onClick={() => { if(matrixRef.current) matrixRef.current.warpToMatrix(roomName + "-alpha"); setIsBreakoutOpen(false); }} className="w-full py-4 bg-white/5 hover:bg-purple-500/20 border border-white/10 hover:border-purple-500/50 rounded-xl font-bold transition-all text-sm flex justify-between items-center px-4">
<span>Alpha Matrix</span> <span className="text-[10px] bg-purple-500/30 text-purple-400 px-2 py-1 rounded">WARP </span>
</button>
<button onClick={() => { if(matrixRef.current) matrixRef.current.warpToMatrix(roomName + "-beta"); setIsBreakoutOpen(false); }} className="w-full py-4 bg-white/5 hover:bg-purple-500/20 border border-white/10 hover:border-purple-500/50 rounded-xl font-bold transition-all text-sm flex justify-between items-center px-4">
<span>Beta Matrix</span> <span className="text-[10px] bg-purple-500/30 text-purple-400 px-2 py-1 rounded">WARP </span>
</button>
<button onClick={() => setIsBreakoutOpen(false)} className="w-full py-3 mt-4 text-gray-500 hover:text-white transition-colors text-xs font-bold uppercase tracking-widest border border-transparent hover:border-white/10 rounded-xl">Batal Inisiasi</button>
</div>
</div>
</div>
)}
{/* CSS-Only Quantum Background (GPU Safe) */}
<div className="absolute inset-0 z-0 opacity-20 pointer-events-none overflow-hidden">
<div className="absolute top-[-20%] left-[-10%] w-[60%] h-[60%] bg-emerald-900/30 blur-[100px] rounded-full animate-[pulse_8s_ease-in-out_infinite]"></div>
<div className="absolute bottom-[-20%] right-[-10%] w-[60%] h-[60%] bg-blue-900/30 blur-[100px] rounded-full animate-[pulse_10s_ease-in-out_infinite]"></div>
<div className="absolute top-[40%] left-[40%] w-[40%] h-[40%] bg-purple-900/20 blur-[120px] rounded-full animate-[pulse_12s_ease-in-out_infinite]"></div>
</div>
{globalTimer !== null && (
<div className="absolute top-20 left-1/2 -translate-x-1/2 z-[60] pointer-events-none">
<div className={`text-6xl md:text-8xl font-black tabular-nums tracking-tighter transition-colors duration-1000 ${globalTimer === 0 ? 'text-red-500 drop-shadow-[0_0_50px_rgba(239,68,68,0.8)] animate-bounce' : globalTimer < 60 ? 'text-amber-400 drop-shadow-[0_0_30px_rgba(251,191,36,0.8)]' : 'text-emerald-400 drop-shadow-[0_0_30px_rgba(16,185,129,0.8)]'}`}>
{Math.floor(globalTimer / 60).toString().padStart(2, '0')}:{(globalTimer % 60).toString().padStart(2, '0')}
</div>
</div>
)}
{/* Top Bar - Zoom Class */}
<div className={`absolute top-0 left-0 right-0 h-12 flex items-center justify-between px-4 z-50 transition-all duration-500`}>
<div className="flex items-center gap-4">
<div className="flex items-center gap-2 bg-black/40 backdrop-blur-xl px-3 py-1.5 rounded-full border border-white/10">
<svg className={`w-3.5 h-3.5 ${e2eeKeyStr && e2eeKeyStr !== 'none' ? 'text-emerald-500' : 'text-amber-500'}`} fill="currentColor" viewBox="0 0 20 20"><path fillRule="evenodd" d="M5 9V7a5 5 0 0110 0v2a2 2 0 012 2v5a2 2 0 01-2 2H5a2 2 0 01-2-2v-5a2 2 0 012-2zm8-2v2H7V7a3 3 0 016 0z" clipRule="evenodd" /></svg>
<span className="text-[10px] font-black uppercase tracking-widest text-white/80">{roomName}</span>
<div className="w-[1px] h-3 bg-white/10 mx-1"></div>
<span className="text-[10px] font-mono text-white/60">{formatTime(meetingTime)}</span>
</div>
</div>
<div className="flex items-center gap-2">
{uiMatrix?.['jvc.ui.layout_toggle'] !== false && (
<button onClick={() => setLayoutMode(prev => prev === 'speaker' ? 'gallery' : 'speaker')} className="bg-black/40 backdrop-blur-xl hover:bg-white/10 px-4 py-1.5 rounded-full border border-white/10 text-[10px] font-black uppercase tracking-widest transition-all">
{layoutMode === 'speaker' ? 'Gallery View' : 'Speaker View'}
</button>
)}
</div>
</div>
{/* Main Grid Area */}
<div className={`flex-1 flex overflow-hidden relative transition-all duration-500 ${isChatOpen || isParticipantsOpen ? 'pr-[320px]' : ''}`}>
<div className="flex-1 p-2 md:p-6 flex items-center justify-center relative">
{!isMatrixActive ? (
<div className="flex flex-col items-center gap-6">
<div className="w-12 h-12 border-2 border-white/5 border-t-emerald-500 rounded-full animate-spin"></div>
<div className="text-[10px] font-black text-emerald-500 uppercase tracking-widest animate-pulse">{status}</div>
</div>
) : (
<div className="w-full h-full max-w-7xl mx-auto relative">
{layoutMode === 'gallery' ? (
<div className={`grid gap-2 md:gap-2 w-full h-full auto-rows-fr ${
allParticipants.length === 1 ? 'grid-cols-1' :
allParticipants.length === 2 ? 'grid-cols-1 md:grid-cols-2' :
allParticipants.length <= 4 ? 'grid-cols-2' :
'grid-cols-2 md:grid-cols-3'
}`}>
{allParticipants.map(id => (
<div key={id} className={`relative rounded-xl md:rounded-2xl overflow-hidden border-2 transition-all duration-500 ${activeSpeakerId === id ? 'border-emerald-500 shadow-[0_0_30px_rgba(16,185,129,0.3)]' : 'border-white/5'}`}>
{renderVideoTile(id, false)}
</div>
))}
</div>
) : (
<div className="flex flex-col md:flex-row gap-4 w-full h-full">
<div className={`flex-1 rounded-3xl overflow-hidden border-2 border-emerald-500 shadow-[0_0_40px_rgba(16,185,129,0.2)]`}>
{renderVideoTile(effectiveActiveSpeaker!, false)}
</div>
<div className="w-full md:w-56 flex md:flex-col gap-3 overflow-auto custom-scroll">
{allParticipants.filter(p => p !== effectiveActiveSpeaker).map(id => (
<div key={id} onClick={() => setActiveSpeakerId(id)} className="w-48 md:w-full aspect-video rounded-xl overflow-hidden border border-white/10 hover:border-white/30 cursor-pointer transition-all">
{renderVideoTile(id, true)}
</div>
))}
</div>
</div>
)}
</div>
)}
</div>
{/* Right Sidebars (Chat & Participants) */}
<div className={`absolute top-0 right-0 bottom-0 w-[320px] bg-[#050b14] border-l border-white/5 z-40 transition-transform duration-500 shadow-2xl ${isChatOpen || isParticipantsOpen ? 'translate-x-0' : 'translate-x-full'}`}>
{isChatOpen && (
<JumlahChat
roomName={roomName} participantName={username || `User ${participantId}`}
participantId={participantId} webTransport={webTransport}
onClose={() => setIsChatOpen(false)}
/>
)}
{isParticipantsOpen && (
<div className="flex flex-col h-full p-6">
<div className="flex items-center justify-between mb-8">
<h2 className="text-sm font-black uppercase tracking-widest text-white/90">Participants ({allParticipants.length})</h2>
<div className="flex items-center gap-2">
{isHost && (
<button onClick={() => { if(matrixRef.current) matrixRef.current.broadcastSovereignSignal('MUTE_ALL'); }} className="text-[9px] bg-red-500/20 hover:bg-red-500/40 text-red-400 font-bold uppercase tracking-wider px-2 py-1 rounded">Mute All</button>
)}
<button onClick={() => setIsParticipantsOpen(false)} className="text-gray-500 hover:text-white"><svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M6 18L18 6M6 6l12 12" /></svg></button>
</div>
</div>
<div className="space-y-4 overflow-y-auto custom-scroll">
{allParticipants.map(id => (
<div key={id} className="flex items-center gap-3 p-3 rounded-xl bg-white/5 border border-white/5">
<div className={`w-8 h-8 rounded-full flex items-center justify-center text-white font-bold text-xs ${id === participantId ? 'bg-gradient-to-br from-blue-600 to-indigo-700' : 'bg-gradient-to-br from-emerald-600 to-teal-700'}`}>{(id === participantId ? (username || 'U') : (participantNames[id] || 'U')).substring(0,2).toUpperCase()}</div>
<div className="flex-1">
<div className="text-xs font-bold text-white/80">{id === participantId ? `${username || 'Me'} (Me)` : (participantNames[id] || `User ${id}`)}</div>
<div className="text-[9px] text-emerald-500 uppercase font-black">Connected</div>
</div>
<div className="flex gap-2">
<svg className={`w-4 h-4 ${id === participantId && !isMicOn ? 'text-red-500' : 'text-gray-500'}`} fill="currentColor" viewBox="0 0 24 24"><path d="M19 11a7 7 0 01-7 7m0 0a7 7 0 01-7-7m7 7v4m0 0H8m4 0h4m-4-8a3 3 0 01-3-3V5a3 3 0 116 0v6a3 3 0 01-3 3z" /></svg>
<svg className={`w-4 h-4 ${id === participantId && !isCameraOn ? 'text-red-500' : 'text-gray-500'}`} fill="currentColor" viewBox="0 0 24 24"><path d="M15 10l4.553-2.276A1 1 0 0121 8.618v6.764a1 1 0 01-1.447.894L15 14M5 18h8a2 2 0 002-2V8a2 2 0 00-2-2H5a2 2 0 00-2 2v8a2 2 0 002 2z" /></svg>
</div>
{id === participantId && (
<button onClick={() => { setIsRenamingLocal(true); setRenameInput(username); }} className="p-1.5 bg-blue-500/20 hover:bg-blue-500/40 text-blue-400 rounded-lg ml-1 transition-colors" title="Rename">
<svg className="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z"></path></svg>
</button>
)}
{isHost && id !== participantId && (
<button onClick={() => { if(matrixRef.current) matrixRef.current.broadcastSovereignSignal('KICK_PEER', id); }} className="p-1.5 bg-red-500/20 hover:bg-red-500/40 text-red-500 rounded-lg ml-2 transition-colors" title="Kick">
<svg className="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M13 7a4 4 0 11-8 0 4 4 0 018 0zM9 14a6 6 0 00-6 6v1h12v-1a6 6 0 00-6-6zm11-2l-4 4m0-4l4 4"></path></svg>
</button>
)}
</div>
))}
</div>
</div>
)}
</div>
</div>
{/* Bottom Bar - Zoom Class UI */}
<div className={`absolute bottom-0 left-0 right-0 h-20 md:h-24 bg-black/80 backdrop-blur-3xl border-t border-white/10 flex items-center justify-between px-2 md:px-6 z-50 transition-all duration-500`}>
<div className="hidden lg:flex items-center gap-6 w-1/4">
<div className="flex flex-col">
<span className="text-[9px] font-black text-emerald-500 uppercase tracking-widest">Quantum Engine</span>
<span className="text-[11px] text-white/60 font-medium">Auto-Pilot Optimized</span>
</div>
</div>
<div className="flex items-center gap-1 md:gap-2 flex-1 overflow-x-auto no-scrollbar pb-1 md:pb-0 px-2">
<div className="mx-auto flex items-center gap-1 md:gap-2">
<div className="flex items-center gap-1 group shrink-0">
{uiMatrix?.['jvc.ui.microphone'] !== false && (
<button onClick={handleToggleMic} className={`relative flex flex-col items-center justify-center w-12 min-w-[48px] md:w-14 h-12 md:h-14 rounded-2xl transition-all overflow-hidden ${!isMicOn ? 'bg-red-500/20 text-red-500 border border-red-500/30' : 'bg-white/5 hover:bg-white/10 text-gray-300 hover:text-white border border-white/5'}`}>
{isMicOn && (
<div className="absolute bottom-0 left-0 right-0 bg-emerald-500/30 transition-all duration-75" style={{ height: `${Math.min(audioLevel * 100, 100)}%` }}></div>
)}
<div className="relative z-10 flex flex-col items-center">
{isMicOn ? (
<svg className="w-5 md:w-6 h-5 md:h-6 mb-0.5 md:mb-1 drop-shadow-md" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M19 11a7 7 0 01-7 7m0 0a7 7 0 01-7-7m7 7v4m0 0H8m4 0h4m-4-8a3 3 0 01-3-3V5a3 3 0 116 0v6a3 3 0 01-3 3z"></path></svg>
) : (
<svg className="w-5 md:w-6 h-5 md:h-6 mb-0.5 md:mb-1" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M3 3l18 18M9 9v3m0 0v1m0-1a3 3 0 006 0v-1m0 0V9m0 0v1m0-1a3 3 0 00-6 0m6 3a7 7 0 01-7 7m0 0a7 7 0 01-7-7m7 7v4m0 0H8m4 0h4"></path></svg>
)}
<span className="text-[8px] md:text-[9px] font-bold uppercase hidden sm:block drop-shadow-md">{isMicOn ? 'Mute' : 'Unmute'}</span>
</div>
</button>
)}
{uiMatrix?.['jvc.ui.camera'] !== false && (
<button onClick={handleToggleCamera} className={`flex flex-col items-center justify-center w-12 min-w-[48px] md:w-14 h-12 md:h-14 rounded-2xl transition-all ${!isCameraOn ? 'bg-red-500/20 text-red-500 border border-red-500/30' : 'hover:bg-white/5 text-gray-400 hover:text-white'}`}>
{isCameraOn ? (
<svg className="w-5 md:w-6 h-5 md:h-6 mb-0.5 md:mb-1" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M15 10l4.553-2.276A1 1 0 0121 8.618v6.764a1 1 0 01-1.447.894L15 14M5 18h8a2 2 0 002-2V8a2 2 0 00-2-2H5a2 2 0 00-2 2v8a2 2 0 002 2z"></path></svg>
) : (
<svg className="w-5 md:w-6 h-5 md:h-6 mb-0.5 md:mb-1" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M15 10l4.553-2.276A1 1 0 0121 8.618v6.764a1 1 0 01-1.447.894L15 14M5 18h8a2 2 0 002-2V8a2 2 0 00-2-2H5a2 2 0 00-2 2v8a2 2 0 002 2zM3 3l18 18"></path></svg>
)}
<span className="text-[8px] md:text-[9px] font-bold uppercase hidden sm:block">{isCameraOn ? 'Video' : 'Video'}</span>
</button>
)}
{uiMatrix?.['jvc.ui.camera'] !== false && (
<button onClick={handleFlipCamera} className={`md:hidden flex flex-col items-center justify-center w-12 min-w-[48px] h-12 rounded-2xl transition-all hover:bg-white/5 text-gray-400 hover:text-white shrink-0`}>
<svg className="w-5 h-5 mb-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"></path></svg>
</button>
)}
</div>
<div className="w-[1px] h-6 md:h-8 bg-white/10 mx-1 md:mx-2"></div>
{uiMatrix?.['jvc.ui.people_panel'] !== false && (
<button onClick={() => { setIsParticipantsOpen(!isParticipantsOpen); setIsChatOpen(false); }} className={`flex flex-col items-center justify-center w-12 min-w-[48px] md:w-14 h-12 md:h-14 rounded-2xl transition-all shrink-0 ${isParticipantsOpen ? 'bg-white/10 text-emerald-500' : 'hover:bg-white/5 text-gray-400'}`}>
<svg className="w-5 md:w-6 h-5 md:h-6 mb-0.5 md:mb-1" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M12 4.354a4 4 0 110 5.292M15 21H3v-1a6 6 0 0112 0v1zm0 0h6v-1a6 6 0 00-9-5.197M13 7a4 4 0 11-8 0 4 4 0 018 0z"></path></svg>
<span className="text-[8px] md:text-[9px] font-bold uppercase hidden sm:block">People</span>
</button>
)}
{uiMatrix?.['jvc.ui.chat_panel'] !== false && (
<button onClick={() => { setIsChatOpen(!isChatOpen); setIsParticipantsOpen(false); }} className={`flex flex-col items-center justify-center w-12 min-w-[48px] md:w-14 h-12 md:h-14 rounded-2xl transition-all shrink-0 ${isChatOpen ? 'bg-white/10 text-emerald-500' : 'hover:bg-white/5 text-gray-400'}`}>
<svg className="w-5 md:w-6 h-5 md:h-6 mb-0.5 md:mb-1" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z"></path></svg>
<span className="text-[8px] md:text-[9px] font-bold uppercase hidden sm:block">Chat</span>
</button>
)}
{uiMatrix?.['jvc.ui.screenshare'] !== false && (
<button onClick={handleToggleScreen} className={`flex flex-col items-center justify-center w-12 min-w-[48px] md:w-14 h-12 md:h-14 rounded-2xl transition-all shrink-0 ${isScreenSharing ? 'bg-emerald-500/20 text-emerald-500' : 'hover:bg-white/5 text-emerald-500'}`}>
<svg className="w-5 md:w-6 h-5 md:h-6 mb-0.5 md:mb-1" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M9.75 17L9 20l-1 1h8l-1-1-.75-3M3 13h18M5 17h14a2 2 0 002-2V5a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z"></path></svg>
<span className="text-[8px] md:text-[9px] font-bold uppercase hidden sm:block">Share</span>
</button>
)}
{/* PKEPX Zoom-Killer Buttons — ALL controlled by BYOK Matrix */}
{uiMatrix?.['jvc.ui.reactions'] !== false && (
<button onClick={() => { if(matrixRef.current) matrixRef.current.emitResonance('👍'); }} className="flex flex-col items-center justify-center w-12 min-w-[48px] md:w-14 h-12 md:h-14 rounded-2xl hover:bg-white/5 text-yellow-400 transition-all shrink-0">
<svg className="w-5 md:w-6 h-5 md:h-6 mb-0.5 md:mb-1" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M14.828 14.828a4 4 0 01-5.656 0M9 10h.01M15 10h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path></svg>
<span className="text-[8px] md:text-[9px] font-bold uppercase hidden sm:block">React</span>
</button>
)}
{uiMatrix?.['jvc.ui.breakout'] !== false && (
<button onClick={() => setIsBreakoutOpen(true)} className="flex flex-col items-center justify-center w-12 min-w-[48px] md:w-14 h-12 md:h-14 rounded-2xl hover:bg-white/5 text-purple-400 transition-all shrink-0">
<svg className="w-5 md:w-6 h-5 md:h-6 mb-0.5 md:mb-1" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M4 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2V6zm10 0a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2V6zM4 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2v-2zm10 0a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2v-2z"></path></svg>
<span className="text-[8px] md:text-[9px] font-bold uppercase hidden sm:block">Breakout</span>
</button>
)}
{uiMatrix?.['jvc.ui.recording'] !== false && (
<button onClick={() => { setIsRecording(!isRecording); if (!isRecording && matrixRef.current) matrixRef.current.triggerQuantumRecording(); }} className={`flex flex-col items-center justify-center w-12 min-w-[48px] md:w-14 h-12 md:h-14 rounded-2xl transition-all shrink-0 ${isRecording ? 'bg-red-500/20 text-red-500 animate-pulse' : 'hover:bg-white/5 text-gray-400'}`}>
<svg className="w-5 md:w-6 h-5 md:h-6 mb-0.5 md:mb-1" fill="currentColor" viewBox="0 0 24 24"><circle cx="12" cy="12" r="8"></circle></svg>
<span className="text-[8px] md:text-[9px] font-bold uppercase hidden sm:block">Record</span>
</button>
)}
<button onClick={() => setIsMoreMenuOpen(!isMoreMenuOpen)} className="flex flex-col items-center justify-center w-12 min-w-[48px] md:w-14 h-12 md:h-14 rounded-2xl hover:bg-white/5 text-gray-400 transition-all shrink-0">
<svg className="w-5 md:w-6 h-5 md:h-6 mb-0.5 md:mb-1" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M5 12h.01M12 12h.01M19 12h.01M6 12a1 1 0 11-2 0 1 1 0 012 0zm7 0a1 1 0 11-2 0 1 1 0 012 0zm7 0a1 1 0 11-2 0 1 1 0 012 0z"></path></svg>
<span className="text-[8px] md:text-[9px] font-bold uppercase hidden sm:block">More</span>
</button>
</div>
</div>
<div className="flex justify-end w-auto md:w-1/4 shrink-0 pl-2">
{/* MORE MENU PANEL — Fixed position popup */}
{isMoreMenuOpen && (
<div className="fixed inset-0 z-[90]" onClick={() => setIsMoreMenuOpen(false)}>
<div className="absolute bottom-28 right-4 bg-[#0a101d]/95 backdrop-blur-xl border border-white/10 rounded-2xl p-4 flex flex-col gap-3 min-w-[240px] max-w-[320px] shadow-[0_0_40px_rgba(0,0,0,0.5)]" onClick={(e) => e.stopPropagation()}>
<div className="text-xs font-bold text-white/50 uppercase tracking-wider mb-2">Settings</div>
{uiMatrix?.['jvc.ui.beauty_filter'] !== false && (
<button onClick={() => setUseBeautyFilter(!useBeautyFilter)} className={`flex items-center gap-3 text-sm hover:text-white border p-2 rounded-xl transition-all text-left ${useBeautyFilter ? 'bg-pink-500/20 border-pink-500/50 text-pink-300' : 'bg-white/5 border-transparent text-gray-300 hover:bg-white/10'}`}>
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M5 3v4M3 5h4M6 17v4m-2-2h4m5-16l2.286 6.857L21 12l-5.714 2.143L13 21l-2.286-6.857L5 12l5.714-2.143L13 3z"></path></svg>
Neural Radiance Filter
</button>
)}
{uiMatrix?.['jvc.ui.virtual_bg'] !== false && (
<>
<button onClick={() => setUseVirtualBg(prev => prev === 2 ? 0 : 2)} className={`flex items-center gap-3 text-sm hover:text-white border p-2 rounded-xl transition-all text-left ${useVirtualBg === 2 ? 'bg-indigo-500/20 border-indigo-500/50 text-indigo-300' : 'bg-white/5 border-transparent text-gray-300 hover:bg-white/10'}`}>
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z"></path></svg>
Quantum Hologram BG
</button>
<button onClick={() => setUseVirtualBg(prev => prev === 4 ? 0 : 4)} className={`flex items-center gap-3 text-sm hover:text-white border p-2 rounded-xl transition-all text-left ${useVirtualBg === 4 ? 'bg-blue-500/20 border-blue-500/50 text-blue-300' : 'bg-white/5 border-transparent text-gray-300 hover:bg-white/10'}`}>
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path></svg>
Bokeh Blur BG
</button>
</>
)}
<div className="h-[1px] bg-white/10 my-1"></div>
{uiMatrix?.['jvc.ui.timer'] !== false && (
<>
<button onClick={() => { if(matrixRef.current) matrixRef.current.emitResonance('TIMER:300'); setIsMoreMenuOpen(false); }} className="flex items-center gap-3 text-sm text-gray-300 hover:text-white bg-white/5 hover:bg-emerald-500/20 hover:border-emerald-500/50 border border-transparent p-2 rounded-xl transition-all text-left">
<svg className="w-5 h-5 text-emerald-400" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"></path></svg>
Start 5 Min Timer
</button>
<button onClick={() => { if(matrixRef.current) matrixRef.current.emitResonance('TIMER:600'); setIsMoreMenuOpen(false); }} className="flex items-center gap-3 text-sm text-gray-300 hover:text-white bg-white/5 hover:bg-emerald-500/20 hover:border-emerald-500/50 border border-transparent p-2 rounded-xl transition-all text-left">
<svg className="w-5 h-5 text-emerald-400" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"></path></svg>
Start 10 Min Timer
</button>
<button onClick={() => { setGlobalTimer(null); if(matrixRef.current) matrixRef.current.emitResonance('TIMER:0'); setIsMoreMenuOpen(false); }} className="flex items-center gap-3 text-sm text-gray-300 hover:text-white bg-white/5 hover:bg-red-500/20 hover:border-red-500/50 border border-transparent p-2 rounded-xl transition-all text-left">
<svg className="w-5 h-5 text-red-400" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M6 18L18 6M6 6l12 12"></path></svg>
Clear Timer
</button>
</>
)}
<div className="h-[1px] bg-white/10 my-1"></div>
{uiMatrix?.['jvc.ui.matrix_command'] !== false && (
<button onClick={() => { setIsMatrixCommandOpen(true); setIsMoreMenuOpen(false); }} className="flex items-center gap-3 text-sm text-gray-300 hover:text-white bg-white/5 hover:bg-white/10 p-2 rounded-xl transition-all text-left">
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M10 20l4-16m4 4l4 4-4 4M6 16l-4-4 4-4"></path></svg>
XCO Command Matrix
</button>
)}
</div>
</div>
)}
{/* XCO MATRIX COMMAND PANEL */}
{isMatrixCommandOpen && (
<div className="absolute bottom-24 left-1/2 -translate-x-1/2 bg-black/95 backdrop-blur-2xl border border-emerald-500/30 rounded-2xl p-0 z-50 w-[95vw] max-w-[380px] md:w-[460px] shadow-[0_0_50px_rgba(16,185,129,0.2)] overflow-hidden">
<div className="flex items-center justify-between p-4 bg-emerald-950/30 border-b border-emerald-500/20">
<span className="text-[11px] font-black text-emerald-400 uppercase tracking-[0.2em] flex items-center gap-2">
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M19.428 15.428a2 2 0 00-1.022-.547l-2.387-.477a6 6 0 00-3.86.517l-.318.158a6 6 0 01-3.86.517L6.05 15.21a2 2 0 00-1.806.547M8 4h8l-1 1v5.172a2 2 0 00.586 1.414l5 5c1.26 1.26.367 3.414-1.415 3.414H4.828c-1.782 0-2.674-2.154-1.414-3.414l5-5A2 2 0 009 10.172V5L8 4z"></path></svg>
XCO Matrix Command
</span>
<button onClick={() => setIsMatrixCommandOpen(false)} className="text-gray-500 hover:text-white transition-colors">
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M6 18L18 6M6 6l12 12"></path></svg>
</button>
</div>
<div className="flex border-b border-white/5">
<button onClick={() => setMatrixCommandTab('network')} className={`flex-1 py-3 text-[10px] font-bold uppercase tracking-widest transition-colors ${matrixCommandTab === 'network' ? 'bg-white/10 text-emerald-400 border-b-2 border-emerald-500' : 'text-gray-500 hover:bg-white/5 hover:text-gray-300'}`}>Network & Codec</button>
<button onClick={() => setMatrixCommandTab('quantum')} className={`flex-1 py-3 text-[10px] font-bold uppercase tracking-widest transition-colors ${matrixCommandTab === 'quantum' ? 'bg-white/10 text-fuchsia-400 border-b-2 border-fuchsia-500' : 'text-gray-500 hover:bg-white/5 hover:text-gray-300'}`}>Quantum SDK</button>
</div>
<div className="p-5 max-h-[60vh] overflow-y-auto custom-scroll">
{matrixCommandTab === 'network' ? (
<div className="space-y-4">
{/* REAL Traffic Monitor */}
<div className="bg-black/60 border border-emerald-500/10 rounded-xl p-3">
<div className="flex justify-between items-center mb-3">
<span className="text-[9px] font-black text-emerald-500 uppercase tracking-[0.2em]">Live Network I/O</span>
<span className={`text-[9px] font-bold px-2 py-0.5 rounded uppercase tracking-wider ${trafficStats.wsState === 'OPEN' ? 'bg-emerald-500/20 text-emerald-400 border border-emerald-500/30' : 'bg-red-500/20 text-red-400 border border-red-500/30'}`}>{trafficStats.wsState}</span>
</div>
<div className="grid grid-cols-3 gap-2 text-[9px]">
<div className="text-gray-600 font-bold"></div>
<div className="text-center text-cyan-500 font-black tracking-widest">TX &#x25B2;</div>
<div className="text-center text-amber-500 font-black tracking-widest">RX &#x25BC;</div>
<div className="text-gray-400 font-bold">Video</div>
<div className="text-center text-cyan-400 font-mono tabular-nums bg-cyan-950/30 py-1 rounded">{formatRate(trafficStats.rates.txVideo)}</div>
<div className="text-center text-amber-400 font-mono tabular-nums bg-amber-950/30 py-1 rounded">{formatRate(trafficStats.rates.rxVideo)}</div>
<div className="text-gray-400 font-bold">Audio</div>
<div className="text-center text-cyan-400 font-mono tabular-nums bg-cyan-950/30 py-1 rounded">{formatRate(trafficStats.rates.txAudio)}</div>
<div className="text-center text-amber-400 font-mono tabular-nums bg-amber-950/30 py-1 rounded">{formatRate(trafficStats.rates.rxAudio)}</div>
<div className="text-white font-black border-t border-gray-700 pt-2 mt-1">Total</div>
<div className="text-center text-cyan-300 font-mono font-black border-t border-gray-700 pt-2 mt-1 tabular-nums">{formatRate(trafficStats.rates.txTotal)}</div>
<div className="text-center text-amber-300 font-mono font-black border-t border-gray-700 pt-2 mt-1 tabular-nums">{formatRate(trafficStats.rates.rxTotal)}</div>
</div>
</div>
{/* Codec Selectors */}
{uiMatrix?.['jvc.xco.video_engine'] !== false && (
<div className="grid grid-cols-2 gap-4">
<div>
<label className="text-[9px] text-gray-500 font-bold uppercase tracking-widest mb-2 block">Video Engine</label>
<div className="flex flex-col gap-1.5">
{(['auto', 'canvas', 'webcodecs'] as const).map(mode => (
<button key={mode} onClick={() => { setVideoEngineMode(mode); if(matrixRef.current) matrixRef.current.hotSwapVideoEngine(mode); }}
className={`text-[9px] px-3 py-2 rounded-lg font-bold uppercase tracking-wider transition-all text-left ${videoEngineMode === mode ? 'bg-emerald-500/20 text-emerald-400 border border-emerald-500/50 shadow-[0_0_15px_rgba(16,185,129,0.2)]' : 'bg-white/5 text-gray-400 hover:text-white border border-transparent hover:bg-white/10'}`}>
<div className="flex justify-between items-center">
<span>{mode === 'auto' ? 'Auto-Pilot' : mode === 'canvas' ? 'Pulsar (JPEG)' : 'WebCodecs HW'}</span>
{videoEngineMode === mode && <span className="w-1.5 h-1.5 rounded-full bg-emerald-500 shadow-[0_0_5px_#10b981]"></span>}
</div>
</button>
))}
</div>
</div>
{uiMatrix?.['jvc.xco.audio_engine'] !== false && (
<div>
<label className="text-[9px] text-gray-500 font-bold uppercase tracking-widest mb-2 block">Audio Engine</label>
<div className="flex flex-col gap-1.5">
{(['auto', 'xcu-neural', 'pcm'] as const).map(mode => (
<button key={mode} onClick={() => { setAudioEngineMode(mode as any); if(matrixRef.current) matrixRef.current.hotSwapAudioEngine(mode as any); }}
className={`text-[9px] px-3 py-2 rounded-lg font-bold uppercase tracking-wider transition-all text-left ${audioEngineMode === mode ? 'bg-cyan-500/20 text-cyan-400 border border-cyan-500/50 shadow-[0_0_15px_rgba(6,182,212,0.2)]' : 'bg-white/5 text-gray-400 hover:text-white border border-transparent hover:bg-white/10'}`}>
<div className="flex justify-between items-center">
<span>{mode === 'auto' ? 'Auto-Pilot' : mode === 'xcu-neural' ? 'Neural Matrix' : 'Raw PCM'}</span>
{audioEngineMode === mode && <span className="w-1.5 h-1.5 rounded-full bg-cyan-500 shadow-[0_0_5px_#06b6d4]"></span>}
</div>
</button>
))}
</div>
</div>
)}
</div>
)}
{/* BUG FIX #1: FPS Selector */}
{uiMatrix?.['jvc.xco.fps_selector'] !== false && (
<div>
<label className="text-[9px] text-gray-500 font-bold uppercase tracking-widest mb-2 block">Frame Rate (FPS)</label>
<div className="flex gap-1.5">
{([15, 30, 60] as const).map(fps => (
<button key={fps} onClick={() => { setCurrentFps(fps); if(matrixRef.current) matrixRef.current.setFps(fps); }}
className={`flex-1 text-[10px] px-3 py-2.5 rounded-lg font-bold transition-all text-center ${currentFps === fps ? 'bg-amber-500/20 text-amber-400 border border-amber-500/50 shadow-[0_0_15px_rgba(245,158,11,0.2)]' : 'bg-white/5 text-gray-400 hover:text-white border border-transparent hover:bg-white/10'}`}>
<div className="text-sm font-black">{fps}</div>
<div className="text-[7px] opacity-60">{fps === 15 ? 'HEMAT' : fps === 30 ? 'NORMAL' : 'SMOOTH'}</div>
</button>
))}
</div>
<p className="text-[8px] text-gray-600 mt-1.5">15fps = ringan 30fps = default 60fps = berat</p>
</div>
)}
</div>
) : (
<div className="space-y-4">
<div className="bg-fuchsia-950/20 border border-fuchsia-500/20 p-3 rounded-xl mb-4">
<p className="text-[10px] text-fuchsia-300/80 leading-relaxed font-medium">Modul XCO WASM berjalan secara asinkron (Kernel-Bypass). Fungsionalitas berikut membutuhkan lisensi IAM yang sesuai pada Database BYOK.</p>
</div>
<div className="space-y-3">
{wasmCapabilities.postQuantum && (
<div className={`p-3 rounded-xl border transition-all ${activeWasmModules.kyber ? 'bg-fuchsia-900/20 border-fuchsia-500/50' : 'bg-white/5 border-white/5'}`}>
<div className="flex justify-between items-start mb-1">
<div className="flex items-center gap-2">
<svg className={`w-4 h-4 ${activeWasmModules.kyber ? 'text-fuchsia-400' : 'text-gray-500'}`} fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z"></path></svg>
<span className={`text-[11px] font-black uppercase tracking-wider ${activeWasmModules.kyber ? 'text-white' : 'text-gray-400'}`}>Post-Quantum Shield</span>
</div>
<button onClick={() => {
const isActive = !activeWasmModules.kyber;
setActiveWasmModules(p => ({...p, kyber: isActive}));
if (isActive) console.log("[WASM] Kyber-1024 & XChaCha20-Poly1305 Activated.");
}} className={`w-10 h-5 rounded-full relative transition-colors ${activeWasmModules.kyber ? 'bg-fuchsia-500' : 'bg-gray-700'}`}>
<div className={`absolute top-1 left-1 bg-white w-3 h-3 rounded-full transition-transform ${activeWasmModules.kyber ? 'translate-x-5' : 'translate-x-0'}`}></div>
</button>
</div>
<p className="text-[9px] text-gray-500 pl-6">Melindungi aliran data dari dekripsi komputer kuantum masa depan menggunakan protokol CRYSTALS-Kyber.</p>
</div>
)}
{wasmCapabilities.aegis && (
<div className={`p-3 rounded-xl border transition-all ${activeWasmModules.aegis ? 'bg-emerald-900/20 border-emerald-500/50' : 'bg-white/5 border-white/5'}`}>
<div className="flex justify-between items-start mb-1">
<div className="flex items-center gap-2">
<svg className={`w-4 h-4 ${activeWasmModules.aegis ? 'text-emerald-400' : 'text-gray-500'}`} fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"></path><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"></path></svg>
<span className={`text-[11px] font-black uppercase tracking-wider ${activeWasmModules.aegis ? 'text-white' : 'text-gray-400'}`}>Aegis Forensic Watermark</span>
</div>
<button onClick={() => {
const isActive = !activeWasmModules.aegis;
setActiveWasmModules(p => ({...p, aegis: isActive}));
if (isActive) console.log(`[WASM] Aegis Matrix Injected. DNA Seed: ${participantId.toString(16)}`);
}} className={`w-10 h-5 rounded-full relative transition-colors ${activeWasmModules.aegis ? 'bg-emerald-500' : 'bg-gray-700'}`}>
<div className={`absolute top-1 left-1 bg-white w-3 h-3 rounded-full transition-transform ${activeWasmModules.aegis ? 'translate-x-5' : 'translate-x-0'}`}></div>
</button>
</div>
<p className="text-[9px] text-gray-500 pl-6">Menyuntikkan kedipan morse transparan 1% ke dalam kanvas video untuk mencegah kebocoran rekaman fisik kamera.</p>
</div>
)}
{wasmCapabilities.neuralWhisper && (
<div className={`p-3 rounded-xl border transition-all ${activeWasmModules.whisper ? 'bg-cyan-900/20 border-cyan-500/50' : 'bg-white/5 border-white/5'}`}>
<div className="flex justify-between items-start mb-1">
<div className="flex items-center gap-2">
<svg className={`w-4 h-4 ${activeWasmModules.whisper ? 'text-cyan-400' : 'text-gray-500'}`} fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M19 11a7 7 0 01-7 7m0 0a7 7 0 01-7-7m7 7v4m0 0H8m4 0h4m-4-8a3 3 0 01-3-3V5a3 3 0 116 0v6a3 3 0 01-3 3z"></path></svg>
<span className={`text-[11px] font-black uppercase tracking-wider ${activeWasmModules.whisper ? 'text-white' : 'text-gray-400'}`}>Neural Whisper (NPU AI)</span>
</div>
<button onClick={() => {
const isActive = !activeWasmModules.whisper;
setActiveWasmModules(p => ({...p, whisper: isActive}));
if (isActive) console.log("[WASM] Local NPU Speech-to-Text Engaged.");
}} className={`w-10 h-5 rounded-full relative transition-colors ${activeWasmModules.whisper ? 'bg-cyan-500' : 'bg-gray-700'}`}>
<div className={`absolute top-1 left-1 bg-white w-3 h-3 rounded-full transition-transform ${activeWasmModules.whisper ? 'translate-x-5' : 'translate-x-0'}`}></div>
</button>
</div>
<p className="text-[9px] text-gray-500 pl-6">Menerjemahkan suara ke dalam teks secara offline (Edge AI) tanpa menyentuh server cloud eksternal.</p>
</div>
)}
{wasmCapabilities.doppler && (
<div className={`p-3 rounded-xl border transition-all ${activeWasmModules.doppler ? 'bg-amber-900/20 border-amber-500/50' : 'bg-white/5 border-white/5'}`}>
<div className="flex justify-between items-start mb-1">
<div className="flex items-center gap-2">
<svg className={`w-4 h-4 ${activeWasmModules.doppler ? 'text-amber-400' : 'text-gray-500'}`} fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M5.586 15H4a1 1 0 01-1-1v-4a1 1 0 011-1h1.586l4.707-4.707C10.923 3.663 12 4.109 12 5v14c0 .891-1.077 1.337-1.707.707L5.586 15z"></path><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M17 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2"></path></svg>
<span className={`text-[11px] font-black uppercase tracking-wider ${activeWasmModules.doppler ? 'text-white' : 'text-gray-400'}`}>Doppler Matrix (Ultrasonic)</span>
</div>
<button onClick={() => {
const isActive = !activeWasmModules.doppler;
setActiveWasmModules(p => ({...p, doppler: isActive}));
if (isActive) console.log("[WASM] Doppler Matrix (18kHz) Air-gapped fallback armed.");
}} className={`w-10 h-5 rounded-full relative transition-colors ${activeWasmModules.doppler ? 'bg-amber-500' : 'bg-gray-700'}`}>
<div className={`absolute top-1 left-1 bg-white w-3 h-3 rounded-full transition-transform ${activeWasmModules.doppler ? 'translate-x-5' : 'translate-x-0'}`}></div>
</button>
</div>
<p className="text-[9px] text-gray-500 pl-6">Saluran komunikasi darurat menggunakan frekuensi suara ultra-tinggi saat 4G/Internet terputus.</p>
</div>
)}
</div>
</div>
)}
</div>
</div>
)}
<button onClick={() => setIsMatrixCommandOpen(!isMatrixCommandOpen)} className={`flex flex-col items-center justify-center min-w-[56px] md:w-14 h-14 md:h-14 rounded-2xl transition-all ${isMatrixCommandOpen ? 'bg-emerald-500/20 text-emerald-400 border border-emerald-500/30 shadow-[0_0_20px_rgba(16,185,129,0.2)]' : 'hover:bg-white/5 text-gray-400 hover:text-white'}`}>
<svg className="w-5 h-5 md:w-6 md:h-6 mb-0.5 md:mb-1" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.066 2.573c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.573 1.066c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.066-2.573c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" /><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" /></svg>
<span className="text-[8px] md:text-[9px] font-bold uppercase hidden sm:block">Matrix</span>
</button>
<button onClick={() => setIsLeaving(true)} className="flex flex-col items-center justify-center min-w-[56px] md:w-14 h-14 md:h-14 rounded-2xl transition-all hover:bg-red-500/20 text-red-500 border border-transparent hover:border-red-500/30">
<svg className="w-5 h-5 md:w-6 md:h-6 mb-0.5 md:mb-1" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1" /></svg>
<span className="text-[8px] md:text-[9px] font-bold uppercase hidden sm:block">Leave</span>
</button>
</div>
</div>
{/* Leave Confirmation Popup */}
{isLeaving && (
<div className="fixed inset-0 z-[100] flex items-center justify-center bg-black/80 backdrop-blur-sm">
<div className="bg-[#0f172a] border border-white/10 p-6 md:p-8 rounded-3xl max-w-sm w-full mx-4 shadow-[0_0_50px_rgba(0,0,0,0.5)]">
<h3 className="text-xl font-bold text-white mb-2">Akhiri Rapat?</h3>
<p className="text-gray-400 text-sm mb-8">Apakah Anda yakin ingin keluar dari ruangan ini? Koneksi audio dan video Anda akan diputuskan seketika.</p>
<div className="flex gap-3">
<button onClick={() => setIsLeaving(false)} className="flex-1 px-4 py-3 bg-white/5 hover:bg-white/10 text-white rounded-xl font-semibold transition-all">
Batal
</button>
<button onClick={() => window.location.href = '/dashboard'} className="flex-1 px-4 py-3 bg-red-600 hover:bg-red-700 text-white rounded-xl font-bold transition-all shadow-[0_0_20px_rgba(220,38,38,0.3)]">
Keluar
</button>
</div>
</div>
</div>
)}
<style dangerouslySetInnerHTML={{__html: `
.custom-scroll::-webkit-scrollbar { width: 5px; height: 5px; }
.custom-scroll::-webkit-scrollbar-track { background: transparent; }
.custom-scroll::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, 0.05); border-radius: 10px; }
.custom-scroll::-webkit-scrollbar-thumb:hover { background: rgba(255, 255, 255, 0.1); }
`}} />
</div>
);
}