From b75b1e76a439268ad1785f129357bbd688d197be Mon Sep 17 00:00:00 2001 From: Abraham Date: Wed, 9 Sep 2026 17:37:17 +0200 Subject: [PATCH] Subir archivos a "/" --- icons8-brain-connections-64.png | Bin 0 -> 3009 bytes icons8-brain-connections-96.png | Bin 0 -> 5130 bytes index.html | 129 +++++++ script.js | 587 ++++++++++++++++++++++++++++++++ styles.css | 421 +++++++++++++++++++++++ 5 files changed, 1137 insertions(+) create mode 100644 icons8-brain-connections-64.png create mode 100644 icons8-brain-connections-96.png create mode 100644 index.html create mode 100644 script.js create mode 100644 styles.css diff --git a/icons8-brain-connections-64.png b/icons8-brain-connections-64.png new file mode 100644 index 0000000000000000000000000000000000000000..8f7bee3c7cbfe1bc9a7f4eff3929d242366cead9 GIT binary patch literal 3009 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 DTKvUW literal 0 HcmV?d00001 diff --git a/icons8-brain-connections-96.png b/icons8-brain-connections-96.png new file mode 100644 index 0000000000000000000000000000000000000000..ae672c91e8db231981a463c98bb3fdc14031613b GIT binary patch literal 5130 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 + + + + + + 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; + } +}