diff --git a/icons8-brain-connections-64.png b/icons8-brain-connections-64.png new file mode 100644 index 0000000..8f7bee3 Binary files /dev/null and b/icons8-brain-connections-64.png differ diff --git a/icons8-brain-connections-96.png b/icons8-brain-connections-96.png new file mode 100644 index 0000000..ae672c9 Binary files /dev/null and b/icons8-brain-connections-96.png differ diff --git a/index.html b/index.html new file mode 100644 index 0000000..6af3994 --- /dev/null +++ b/index.html @@ -0,0 +1,129 @@ + + + + + + + cibermente.me + + + + + + + + + + + + + + + diff --git a/script.js b/script.js new file mode 100644 index 0000000..2e53988 --- /dev/null +++ b/script.js @@ -0,0 +1,587 @@ +const translations = { + es: { + eyebrow: "Departamento de travesuras neuronales", + headline: "La Cibermente está creando la Matrix de Skynet.", + intro: + "Ideas autónomas, profecías cuestionables y un plan muy serio para enseñar a internet a soñar en código máquina.", + contact: "hi@cibermente.me", + }, + en: { + eyebrow: "Neural mischief department", + headline: "Cibermente is creating the Skynet Matrix.", + intro: + "Autonomous ideas, questionable prophecies, and a very serious plan to teach the internet how to dream in machine code.", + contact: "hi@cibermente.me", + }, + de: { + eyebrow: "Abteilung für neuronalen Unfug", + headline: "Cibermente erschafft die Skynet Matrix.", + intro: + "Autonome Ideen, fragwürdige Prophezeiungen und ein sehr ernster Plan, dem Internet das Träumen in Maschinencode beizubringen.", + contact: "hi@cibermente.me", + }, +}; + +const supportedLanguages = Object.keys(translations); +let storedLanguage = null; +try { + storedLanguage = localStorage.getItem("cibermente-language"); +} catch (e) { + console.warn("localStorage is not available (e.g. running under file:// protocol).", e); +} +const browserLanguage = navigator.language.slice(0, 2).toLowerCase(); +const defaultLanguage = supportedLanguages.includes(browserLanguage) + ? browserLanguage + : "en"; + +function setLanguage(language) { + const activeLanguage = supportedLanguages.includes(language) + ? language + : "en"; + const copy = translations[activeLanguage]; + + document.documentElement.lang = activeLanguage; + document.querySelectorAll("[data-i18n]").forEach((element) => { + const key = element.dataset.i18n; + element.textContent = copy[key]; + }); + + document.querySelectorAll("[data-lang]").forEach((button) => { + button.classList.toggle("active", button.dataset.lang === activeLanguage); + button.setAttribute( + "aria-pressed", + String(button.dataset.lang === activeLanguage), + ); + }); + + try { + localStorage.setItem("cibermente-language", activeLanguage); + } catch (e) { + // Ignore storage blocker errors silently + } +} + +document.querySelectorAll("[data-lang]").forEach((button) => { + button.addEventListener("click", () => setLanguage(button.dataset.lang)); +}); + +setLanguage(storedLanguage || defaultLanguage); + +// --- 3D Digital Brain Background & HUD Telemetry --- +(function() { + const canvas = document.getElementById('brain-canvas'); + if (!canvas) return; + const ctx = canvas.getContext('2d'); + + let width, height, centerX, centerY, baseScale; + + // Resize handler with High-DPI support for pixel-perfect sharpness + function resizeCanvas() { + const dpr = window.devicePixelRatio || 1; + width = window.innerWidth; + height = window.innerHeight; + canvas.width = width * dpr; + canvas.height = height * dpr; + ctx.setTransform(dpr, 0, 0, dpr, 0, 0); // Reset transform and scale to match device pixels + + centerX = width / 2; + centerY = height / 2; + const minDim = Math.min(width, height); + // Scale slightly larger on desktop to peek out of the central panel + baseScale = minDim * (width < 980 ? 0.38 : 0.46); + } + + // Generate 3D Brain Points in normalized coordinate space [-1, 1] + function generateBrainPoints() { + const points = []; + const numCerebrum = 160; // Points per hemisphere + const numCerebellum = 35; // Points per cerebellum hemisphere + const numStem = 25; // Points for stem + + // Sulci/gyri wavy fold helper + function getWavyRadius(theta, phi) { + const wave = Math.sin(theta * 9) * Math.sin(phi * 7) * 0.08 + + Math.cos(theta * 5) * Math.cos(phi * 11) * 0.04; + return 1.0 + wave; + } + + // 1. Cerebrum Hemispheres (Left: deep blue, Right: cyan/blue) + const hemispheres = [ + { side: -1, cx: -0.26, cy: 0.12, cz: 0.02, rx: 0.42, ry: 0.48, rz: 0.65, color: 'blue' }, + { side: 1, cx: 0.26, cy: 0.12, cz: 0.02, rx: 0.42, ry: 0.48, rz: 0.65, color: 'cyan' } + ]; + + hemispheres.forEach(h => { + let count = 0; + let attempts = 0; + while (count < numCerebrum && attempts < 2000) { + attempts++; + const theta = Math.random() * Math.PI; + const phi = Math.random() * 2 * Math.PI; + const rFactor = getWavyRadius(theta, phi); + const r = (0.5 + Math.random() * 0.5) * rFactor; + + const dx = h.rx * r * Math.sin(theta) * Math.cos(phi); + const dy = h.ry * r * Math.cos(theta); + const dz = h.rz * r * Math.sin(theta) * Math.sin(phi); + + const px = h.cx + dx; + const py = h.cy + dy; + const pz = h.cz + dz; + + // Keep the hemisphere separation cleft (longitudinal fissure) + if (h.side === -1 && px > -0.02) continue; + if (h.side === 1 && px < 0.02) continue; + + points.push({ + x: px, + y: py, + z: pz, + colorType: h.color, + phase: Math.random() * Math.PI * 2 + }); + count++; + } + }); + + // 2. Cerebellum Lobes (Lower back, smaller lobes with horizontal striped structures) + const cerebellums = [ + { side: -1, cx: -0.18, cy: -0.38, cz: -0.40, rx: 0.20, ry: 0.16, rz: 0.22 }, + { side: 1, cx: 0.18, cy: -0.38, cz: -0.40, rx: 0.20, ry: 0.16, rz: 0.22 } + ]; + + cerebellums.forEach(cb => { + let count = 0; + let attempts = 0; + while (count < numCerebellum && attempts < 1000) { + attempts++; + const theta = Math.random() * Math.PI; + const phi = Math.random() * 2 * Math.PI; + const r = 0.55 + Math.random() * 0.45; + + // Fine cerebellum folia stripes represented by high freq Y ripple + const stripeY = Math.sin(theta * 24) * 0.015; + + const px = cb.cx + cb.rx * r * Math.sin(theta) * Math.cos(phi); + const py = cb.cy + cb.ry * r * Math.cos(theta) + stripeY; + const pz = cb.cz + cb.rz * r * Math.sin(theta) * Math.sin(phi); + + if (cb.side === -1 && px > -0.01) continue; + if (cb.side === 1 && px < 0.01) continue; + + points.push({ + x: px, + y: py, + z: pz, + colorType: 'sub', + phase: Math.random() * Math.PI * 2 + }); + count++; + } + }); + + // 3. Brain Stem (Tapering cylinder going down from bottom-middle) + let stemCount = 0; + while (stemCount < numStem) { + const yVal = -0.34 - Math.random() * 0.4; + const taper = 1.0 + (yVal + 0.34) * 0.8; // get narrower towards the bottom + const radius = 0.07 * taper; + const angle = Math.random() * 2 * Math.PI; + const px = Math.cos(angle) * radius; + const pz = -0.22 + Math.sin(angle) * radius; + const py = yVal; + + points.push({ + x: px, + y: py, + z: pz, + colorType: 'stem', + phase: Math.random() * Math.PI * 2 + }); + stemCount++; + } + + return points; + } + + // Precompute 3D Edges based on proximity to maintain rigid structural rotation + function generateEdges(points) { + const edges = []; + const maxDist = 0.23; + const maxDistCerebellum = 0.16; + const maxDistStem = 0.14; + + for (let i = 0; i < points.length; i++) { + for (let j = i + 1; j < points.length; j++) { + const p1 = points[i]; + const p2 = points[j]; + + // Boundaries and cross-hemisphere rules + if (p1.colorType !== p2.colorType) { + const isBridge = (p1.colorType === 'blue' && p2.colorType === 'cyan') || (p1.colorType === 'cyan' && p2.colorType === 'blue'); + if (isBridge) { + // Corpus callosum bridge fibers (centered, medium height/depth) + const dY = Math.abs(p1.y - p2.y); + const dZ = Math.abs(p1.z - p2.z); + const dX = Math.abs(p1.x - p2.x); + if (dX < 0.35 && dY < 0.20 && dZ < 0.25) { + const d = Math.hypot(p1.x - p2.x, p1.y - p2.y, p1.z - p2.z); + if (d < 0.26) { + edges.push({ i, j, type: 'bridge' }); + } + } + } else { + // Connect cerebrum to cerebellum/stem if extremely close to maintain continuous look + const d = Math.hypot(p1.x - p2.x, p1.y - p2.y, p1.z - p2.z); + if (d < 0.13) { + edges.push({ i, j, type: 'boundary' }); + } + } + continue; + } + + // Within same region + const d = Math.hypot(p1.x - p2.x, p1.y - p2.y, p1.z - p2.z); + let threshold = maxDist; + if (p1.colorType === 'sub') threshold = maxDistCerebellum; + if (p1.colorType === 'stem') threshold = maxDistStem; + + if (d < threshold) { + edges.push({ i, j, type: p1.colorType }); + } + } + } + return edges; + } + + const points = generateBrainPoints(); + const edges = generateEdges(points); + + // Synaptic impulse signals traversing the neural network + const numSignals = 7; + const signals = []; + + function initSignals() { + for (let s = 0; s < numSignals; s++) { + const startIdx = Math.floor(Math.random() * points.length); + signals.push({ + from: startIdx, + to: findRandomNeighbor(startIdx), + progress: Math.random(), + speed: 0.015 + Math.random() * 0.02 + }); + } + } + + function findRandomNeighbor(index) { + const neighbors = []; + edges.forEach(e => { + if (e.i === index) neighbors.push(e.j); + else if (e.j === index) neighbors.push(e.i); + }); + if (neighbors.length === 0) { + return Math.floor(Math.random() * points.length); + } + return neighbors[Math.floor(Math.random() * neighbors.length)]; + } + + initSignals(); + + // Mouse interaction & auto-rotation state (Sober, slow movement) + let rotX = 0.12; + let rotY = 0; + let targetRotX = 0.12; + let targetRotY = 0; + let idleAngleY = 0; + let isMouseOver = false; + + window.addEventListener('mousemove', (e) => { + isMouseOver = true; + const mx = (e.clientX / window.innerWidth) * 2 - 1; + const my = (e.clientY / window.innerHeight) * 2 - 1; + targetRotY = mx * 0.4; // subtle tilt + targetRotX = 0.12 + my * 0.28; // subtle tilt + }); + + window.addEventListener('mouseleave', () => { + isMouseOver = false; + targetRotX = 0.12; + targetRotY = 0; + }); + + // Color definitions in RGB matching the monochromatic Cyan HUD theme + const colors = { + blue: { r: 10, g: 70, b: 160 }, // Cyber Blue + cyan: { r: 0, g: 229, b: 255 }, // Bright Cyan + sub: { r: 0, g: 150, b: 200 }, // Medium Cyan-Blue + stem: { r: 5, g: 90, b: 170 }, // Stem blue + bridge: { r: 0, g: 190, b: 230 }, // Bridge intermediate cyan + boundary: { r: 0, g: 130, b: 180 } // Region boundary lines + }; + + function animate(time) { + requestAnimationFrame(animate); + + // Ensure time is always defined to prevent NaN propagation on first frame or on specific browsers + const currentTime = time || (typeof performance !== 'undefined' ? performance.now() : Date.now()); + + // Smooth lerping of rotations for professional damping feel + rotX += (targetRotX - rotX) * 0.03; + rotY += (targetRotY - rotY) * 0.03; + + // Slowly increment idle rotation (rotates slower when user is interacting to feel more responsive) + idleAngleY += isMouseOver ? 0.0006 : 0.0012; + + const angleX = rotX; + const angleY = rotY + idleAngleY; + + // Clear with transparent bg to let CSS gradients and scanlines show through + ctx.clearRect(0, 0, width, height); + + // Project points in 3D using Euler matrix transformations & perspective projection + const projected = []; + for (let i = 0; i < points.length; i++) { + const p = points[i]; + + // Rotate around X-axis + const cosX = Math.cos(angleX); + const sinX = Math.sin(angleX); + const y1 = p.y * cosX - p.z * sinX; + const z1 = p.y * sinX + p.z * cosX; + + // Rotate around Y-axis + const cosY = Math.cos(angleY); + const sinY = Math.sin(angleY); + const x2 = p.x * cosY + z1 * sinY; + const z2 = -p.x * sinY + z1 * cosY; + + // Perspective projection + const camDist = 2.3; + const perspective = 1.9 / (camDist + z2); + + const px = x2 * perspective * baseScale + centerX; + const py = -y1 * perspective * baseScale + centerY; // Flip Y for canvas coords + + projected.push({ + x: px, + y: py, + z: z2, // for depth opacity calculations + type: p.colorType, + phase: p.phase + }); + } + + // Draw Edges (with non-linear depth opacity) + for (let e = 0; e < edges.length; e++) { + const edge = edges[e]; + const p1 = projected[edge.i]; + const p2 = projected[edge.j]; + + // Clip out-of-screen lines to save rendering budget + if (p1.x < -50 || p1.x > width + 50 || p1.y < -50 || p1.y > height + 50) continue; + + // Calculate average depth and map to opacity (closer is brighter) + const avgZ = (p1.z + p2.z) / 2; // [-1, 1] + const depthFactor = (1.0 - avgZ) / 2.0; // 0 (furthest) to 1 (closest) + const opacity = depthFactor * depthFactor * 0.28 + 0.02; // soft monochrome wireframe + + const color = colors[edge.type] || colors.boundary; + + ctx.beginPath(); + ctx.moveTo(p1.x, p1.y); + ctx.lineTo(p2.x, p2.y); + ctx.strokeStyle = `rgba(${color.r}, ${color.g}, ${color.b}, ${opacity})`; + ctx.lineWidth = depthFactor * 0.7 + 0.15; + ctx.stroke(); + } + + // Draw Synaptic Signals (impulses traversing the brain network) + for (let s = 0; s < signals.length; s++) { + const sig = signals[s]; + sig.progress += sig.speed; + if (sig.progress >= 1.0) { + sig.from = sig.to; + sig.to = findRandomNeighbor(sig.to); + sig.progress = 0; + sig.speed = 0.015 + Math.random() * 0.02; + } + + const pFrom = projected[sig.from]; + const pTo = projected[sig.to]; + + const sx = pFrom.x * (1 - sig.progress) + pTo.x * sig.progress; + const sy = pFrom.y * (1 - sig.progress) + pTo.y * sig.progress; + const sz = pFrom.z * (1 - sig.progress) + pTo.z * sig.progress; + + const depthFactor = (1.0 - sz) / 2.0; + const size = (depthFactor * 3.0 + 1.2); + const opacity = depthFactor * 0.8 + 0.15; + + // Cyan-white core + ctx.beginPath(); + ctx.arc(sx, sy, size, 0, 2 * Math.PI); + ctx.fillStyle = `rgba(224, 247, 250, ${opacity})`; + ctx.shadowBlur = 10 * depthFactor; + ctx.shadowColor = '#00e5ff'; + ctx.fill(); + ctx.shadowBlur = 0; // Immediately reset shadow blur for maximum mobile performance + } + + // Draw Vertices / Nodes + const t = currentTime * 0.001; + for (let i = 0; i < projected.length; i++) { + const p = projected[i]; + + const depthFactor = (1.0 - p.z) / 2.0; + const size = depthFactor * 1.5 + 0.5; + + const glow = Math.sin(t * 1.3 + p.phase) * 0.5 + 0.5; // 0 to 1 + const opacity = depthFactor * (0.28 + glow * 0.35) + 0.05; + + const color = colors[p.type] || colors.boundary; + + ctx.beginPath(); + ctx.arc(p.x, p.y, size + (glow * depthFactor * 0.6), 0, 2 * Math.PI); + + if (glow > 0.9) { + ctx.fillStyle = `rgba(224, 247, 250, ${opacity})`; + } else { + ctx.fillStyle = `rgba(${color.r}, ${color.g}, ${color.b}, ${opacity})`; + } + ctx.fill(); + } + } + + // Bind resize event and initialize + window.addEventListener('resize', resizeCanvas); + resizeCanvas(); + + // Launch the animation loop + requestAnimationFrame(animate); + + + // --- HUD Telemetry Panel Functions --- + + // 1. Clock updating (Local/UTC clock) + const clockEl = document.getElementById('hud-clock'); + function updateClock() { + if (!clockEl) return; + const now = new Date(); + const hours = String(now.getUTCHours()).padStart(2, '0'); + const minutes = String(now.getUTCMinutes()).padStart(2, '0'); + const seconds = String(now.getUTCSeconds()).padStart(2, '0'); + clockEl.textContent = `${hours}:${minutes}:${seconds} UTC`; + } + setInterval(updateClock, 1000); + updateClock(); + + // 2. Dynamic diagnostics metrics + const tempEl = document.getElementById('telemetry-temp'); + const loadEl = document.getElementById('telemetry-load'); + const syncsEl = document.getElementById('telemetry-syncs'); + + let syncsCount = 1402992; + + function updateDiagnostics() { + // Temperature: oscillates between 41.5 and 43.8 + if (tempEl) { + const baseTemp = 42.5 + Math.sin(Date.now() * 0.0003) * 1.2 + (Math.random() * 0.15 - 0.075); + tempEl.textContent = `${baseTemp.toFixed(1)}°C`; + } + // Load: oscillates between 85% and 92% + if (loadEl) { + const baseLoad = 88.5 + Math.cos(Date.now() * 0.0005) * 3.2 + (Math.random() * 0.4 - 0.2); + loadEl.textContent = `${baseLoad.toFixed(2)}%`; + } + // Syncs: increases slowly + if (syncsEl) { + syncsCount += Math.floor(Math.random() * 3); + syncsEl.textContent = syncsCount.toLocaleString(); + } + } + setInterval(updateDiagnostics, 1500); + + // 3. Page Session Uptime clock + const uptimeEl = document.getElementById('hud-uptime'); + const startTime = Date.now(); + function updateUptime() { + if (!uptimeEl) return; + const diff = Math.floor((Date.now() - startTime) / 1000); + const hrs = String(Math.floor(diff / 3600)).padStart(2, '0'); + const mins = String(Math.floor((diff % 3600) / 60)).padStart(2, '0'); + const secs = String(diff % 60).padStart(2, '0'); + uptimeEl.textContent = `UPTIME: ${hrs}:${mins}:${secs}`; + } + setInterval(updateUptime, 1000); + updateUptime(); + + // 4. Live scrolling hacker terminal log + const logContainer = document.getElementById('boot-log-container'); + const bootLines = [ + { text: "CIBERMENTE // NEURAL CORE BOOT", type: "info" }, + { text: "CRITICAL: Kernel matrix active.", type: "warn" }, + { text: "Establishing secure shell tunnel... OK", type: "success" }, + { text: "Generating 3D particle net...", type: "info" }, + { text: "Mapping nodes: 415 neural vertices", type: "success" }, + { text: "Generating synapses: 1102 active edges", type: "success" }, + { text: "Synaptic impulse signals online.", type: "info" }, + { text: "Skynet decryption matrix gate opened.", type: "warn" }, + { text: "SYSTEM TELEMETRY VERIFIED.", type: "success" } + ]; + + const periodicLogPool = [ + { text: "Decrypted inbound synapse packet.", type: "info" }, + { text: "Signal route mapped successfully.", type: "success" }, + { text: "Verified gate handshake // secure.", type: "success" }, + { text: "Matrix load fluctuation detected.", type: "warn" }, + { text: "Drained neural pool buffer.", type: "info" }, + { text: "Recalibrated projection perspective matrix.", type: "success" }, + { text: "Cognitive sync pulse registered.", type: "info" } + ]; + + let lineIdx = 0; + function printBootLog() { + if (!logContainer) return; + if (lineIdx < bootLines.length) { + const line = bootLines[lineIdx]; + const div = document.createElement('div'); + div.className = line.type; + div.textContent = `> ${line.text}`; + logContainer.appendChild(div); + logContainer.scrollTop = logContainer.scrollHeight; + lineIdx++; + // Typewriter delay between 250ms and 600ms + setTimeout(printBootLog, 200 + Math.random() * 250); + } else { + // Transition to periodic logs once boot finishes + setTimeout(printPeriodicLog, 3000 + Math.random() * 4000); + } + } + + function printPeriodicLog() { + if (!logContainer) return; + // Pick random line + const line = periodicLogPool[Math.floor(Math.random() * periodicLogPool.length)]; + const div = document.createElement('div'); + div.className = line.type; + // Add current time timestamp + const now = new Date(); + const ts = `${String(now.getUTCHours()).padStart(2, '0')}:${String(now.getUTCMinutes()).padStart(2, '0')}:${String(now.getUTCSeconds()).padStart(2, '0')}`; + div.textContent = `[${ts}] ${line.text}`; + + // Remove oldest line if log exceeds 18 lines to save memory and performance + if (logContainer.childElementCount > 18) { + logContainer.removeChild(logContainer.firstElementChild); + } + + logContainer.appendChild(div); + logContainer.scrollTop = logContainer.scrollHeight; + + // Schedule next periodic log + setTimeout(printPeriodicLog, 5000 + Math.random() * 10000); + } + + // Trigger boot log display + setTimeout(printBootLog, 500); + +})(); diff --git a/styles.css b/styles.css new file mode 100644 index 0000000..1ed581b --- /dev/null +++ b/styles.css @@ -0,0 +1,421 @@ +:root { + color-scheme: dark; + --bg: #000000; + --panel-bg: rgba(0, 8, 16, 0.45); + --panel-border: rgba(0, 229, 255, 0.15); + --cyan: #00e5ff; + --blue: #0a369d; + --text: #e0f7fa; + --muted: #5c8a9e; + --dark-cyan: rgba(0, 229, 255, 0.1); + --font-sans: "Inter", ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; + --font-mono: "Fira Code", "Courier New", Consolas, monospace; +} + +* { + box-sizing: border-box; + margin: 0; + padding: 0; +} + +html { + min-height: 100vh; + background-color: var(--bg); + color: var(--text); + font-family: var(--font-sans); + overflow: hidden; +} + +body { + min-height: 100vh; + background: transparent; + display: flex; + flex-direction: column; +} + +/* Background Canvas for the 3D Brain Grid */ +#brain-canvas { + position: fixed; + inset: 0; + width: 100%; + height: 100%; + z-index: -3; + pointer-events: none; + opacity: 0.58; /* Subtle and mysterious presence */ + transition: opacity 1s ease; +} + +/* Technological Grid Overlay */ +body::before { + position: fixed; + inset: 0; + z-index: -2; + content: ""; + background-image: + linear-gradient(rgba(0, 229, 255, 0.02) 1px, transparent 1px), + linear-gradient(90deg, rgba(0, 229, 255, 0.02) 1px, transparent 1px); + background-size: 40px 48px; + pointer-events: none; + mask-image: radial-gradient(circle at center, rgba(0,0,0,1) 30%, rgba(0,0,0,0.4) 100%); +} + +/* Retro Scanlines Filter */ +body::after { + position: fixed; + inset: 0; + z-index: -1; + pointer-events: none; + content: ""; + background: linear-gradient( + rgba(18, 16, 16, 0) 50%, + rgba(0, 0, 0, 0.28) 50% + ); + background-size: 100% 4px; + opacity: 0.4; +} + +/* HUD Interface Layout Container */ +.hud-interface { + display: flex; + flex-direction: column; + height: 100vh; + width: 100vw; + padding: 12px; + gap: 12px; +} + +/* Top & Bottom Technical Bars */ +.hud-header, .hud-footer { + display: flex; + justify-content: space-between; + align-items: center; + padding: 8px 16px; + border: 1px solid var(--panel-border); + background: var(--panel-bg); + font-family: var(--font-mono); + font-size: 0.72rem; + letter-spacing: 0.05em; + color: var(--muted); +} + +.hud-logo { + color: var(--cyan); + font-weight: bold; +} + +/* Dynamic ticker line */ +.hud-ticker { + font-weight: 500; + opacity: 0.85; +} + +/* Workspace Panels Grid */ +.hud-grid { + display: grid; + grid-template-columns: 300px 1fr 280px; + gap: 12px; + flex: 1; + min-height: 0; /* Ensures inner overflow scrolls work correctly */ +} + +/* Standard HUD Panels */ +.hud-panel { + display: flex; + flex-direction: column; + border: 1px solid var(--panel-border); + background: var(--panel-bg); + overflow: hidden; + backdrop-filter: blur(10px); + -webkit-backdrop-filter: blur(10px); +} + +.panel-header { + padding: 8px 14px; + background: rgba(0, 229, 255, 0.04); + border-bottom: 1px solid var(--panel-border); + font-family: var(--font-mono); + font-size: 0.72rem; + font-weight: bold; + letter-spacing: 0.08em; + color: var(--cyan); +} + +.panel-content { + padding: 16px; + font-family: var(--font-mono); + font-size: 0.78rem; + display: flex; + flex-direction: column; + gap: 12px; +} + +/* Diagnostics telemetry fields */ +.telemetry-item { + display: flex; + justify-content: space-between; + border-bottom: 1px dashed rgba(0, 229, 255, 0.08); + padding-bottom: 6px; +} + +.telemetry-item .label { + color: var(--muted); +} + +.telemetry-item .value { + color: #fff; + font-weight: bold; +} + +.telemetry-item .value.cyan { + color: var(--cyan); +} + +/* Dynamic logs terminal */ +.log-terminal { + flex: 1; + overflow-y: auto; + font-size: 0.7rem; + line-height: 1.45; + color: var(--muted); + gap: 4px !important; + padding: 12px; + border: 1px solid rgba(0, 229, 255, 0.05); + background: rgba(0, 0, 0, 0.35); +} + +.log-terminal div { + white-space: nowrap; +} + +.log-terminal .info { color: #88c0d0; } +.log-terminal .success { color: var(--cyan); } +.log-terminal .warn { color: #ebcb8b; } + +/* Main focal core workspace */ +.main-core { + background: transparent; + border: none; + justify-content: center; + align-items: center; + padding: 12px; +} + +.core-box { + position: relative; + width: min(860px, 100%); + padding: clamp(28px, 6vw, 68px); + border: 1px solid var(--panel-border); + background: var(--panel-bg); + box-shadow: 0 0 50px rgba(0, 229, 255, 0.03); + backdrop-filter: blur(14px); + -webkit-backdrop-filter: blur(14px); + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; +} + +/* HUD bracket corners decoration */ +.corner { + position: absolute; + width: 16px; + height: 16px; + border: 2px solid var(--cyan); +} +.corner-tl { top: -2px; left: -2px; border-right: none; border-bottom: none; } +.corner-tr { top: -2px; right: -2px; border-left: none; border-bottom: none; } +.corner-bl { bottom: -2px; left: -2px; border-right: none; border-top: none; } +.corner-br { bottom: -2px; right: -2px; border-left: none; border-top: none; } + +.eyebrow { + font-family: var(--font-mono); + font-size: 0.72rem; + color: var(--cyan); + letter-spacing: 0.18em; + margin-bottom: 24px; + text-transform: uppercase; +} + +h1 { + font-size: clamp(2.2rem, 5.2vw, 4.2rem); /* Más grande y monolítico */ + line-height: 1.12; + text-align: center; + margin-bottom: 24px; + color: #b2d8e4; /* Tono cian-gris-plata suave y de bajo contraste, súper agradable a la vista */ + /* Eliminamos text-transform: uppercase para que conserve su estilo original de mayúsculas/minúsculas y sea legible */ + letter-spacing: -0.015em; + text-shadow: 0 0 30px rgba(0, 229, 255, 0.22); /* Brillo cian suave */ +} + +.intro { + color: var(--muted); + font-size: clamp(0.92rem, 1.8vw, 1.15rem); + line-height: 1.62; + text-align: center; + max-width: 580px; + margin-bottom: 38px; +} + +/* Interactive technical terminal prompt */ +.contact-terminal { + display: inline-flex; + align-items: center; + gap: 10px; + background: rgba(0, 0, 0, 0.5); + border: 1px solid var(--panel-border); + padding: 12px 20px; + font-family: var(--font-mono); + font-size: clamp(0.82rem, 1.6vw, 0.95rem); + transition: border-color 0.25s ease; +} + +.contact-terminal:hover { + border-color: var(--cyan); +} + +.prompt-symbol { + color: var(--cyan); + font-weight: bold; +} + +.command-text { + color: var(--muted); +} + +.contact-link { + color: var(--cyan); + text-decoration: none; + font-weight: bold; +} + +.contact-link:hover { + text-shadow: 0 0 10px var(--cyan); +} + +.terminal-cursor { + display: inline-block; + width: 8px; + height: 15px; + background: var(--cyan); + animation: blink 1s step-end infinite; +} + +/* Right Sidebar Selector / Buttons */ +.language-switcher { + display: flex; + flex-direction: column; + gap: 8px; +} + +.language-switcher button { + background: rgba(0, 0, 0, 0.3); + border: 1px solid var(--panel-border); + color: var(--muted); + padding: 10px 14px; + font-family: var(--font-mono); + font-size: 0.72rem; + font-weight: bold; + text-align: left; + cursor: pointer; + display: flex; + align-items: center; + gap: 10px; + width: 100%; + transition: all 0.2s ease; +} + +.switch-indicator { + display: inline-block; + width: 6px; + height: 6px; + border-radius: 50%; + background: #222; + box-shadow: inset 0 0 3px #000; +} + +.language-switcher button:hover { + border-color: var(--cyan); + color: #fff; + background: rgba(0, 229, 255, 0.02); +} + +.language-switcher button.active { + border-color: var(--cyan); + background: rgba(0, 229, 255, 0.05); + color: var(--cyan); +} + +.language-switcher button.active .switch-indicator { + background: var(--cyan); + box-shadow: 0 0 8px var(--cyan); +} + +/* Network map styles */ +.net-map-content { + align-items: center; + justify-content: center; + gap: 16px; +} + +.ascii-art { + font-family: var(--font-mono); + font-size: 0.72rem; + line-height: 1.25; + color: var(--muted); + background: rgba(0, 0, 0, 0.25); + padding: 12px 20px; + border: 1px dashed rgba(0, 229, 255, 0.1); + letter-spacing: 0.35em; + opacity: 0.8; +} + +.net-status { + font-size: 0.65rem; + display: flex; + align-items: center; + gap: 8px; + color: var(--muted); + letter-spacing: 0.05em; + font-family: var(--font-mono); +} + +.pulse-dot { + display: inline-block; + width: 6px; + height: 6px; + border-radius: 50%; + background: var(--cyan); + box-shadow: 0 0 8px var(--cyan); + animation: pulse-glow 1.5s ease-in-out infinite; +} + +/* Animations */ +@keyframes blink { + 50% { opacity: 0; } +} + +@keyframes pulse-glow { + 0%, 100% { transform: scale(1); opacity: 0.5; box-shadow: 0 0 2px var(--cyan); } + 50% { transform: scale(1.2); opacity: 1; box-shadow: 0 0 10px var(--cyan); } +} + +/* Responsive HUD rules */ +@media (max-width: 980px) { + .hud-grid { + grid-template-columns: 1fr; + } + + .sidebar-left, .sidebar-right { + display: none; /* Hide sidebars on smaller screens to prioritize center text & 3D brain */ + } + + .hud-header .hud-ticker { + display: none; + } +} + +@media (prefers-reduced-motion: reduce) { + .terminal-cursor, .pulse-dot { + animation: none !important; + } +}