links / conversor.html
minispace's picture
Optimize and sanitize public codebase: remove all comments, explanatory notes, backend training data, and verify security isolation
9b14626
Raw History Blame Contribute Delete
31 kB
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="Conversor de Divisas en Vivo - Dólar Argentina por NEO STUDIO.">
<title>Conversor de Divisas | NEO STUDIO</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Outfit:wght@600;700;800&family=Plus+Jakarta+Sans:wght@500;600;700&family=JetBrains+Mono:wght@600;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="styles.css"> <style>
.app-download-divider {
border: none;
border-top: 1px solid rgba(255, 255, 255, 0.15);
margin: 40px auto 24px auto;
width: 100%;
max-width: 580px;
}
.download-bar-container {
margin-bottom: 30px;
display: flex;
flex-direction: column;
align-items: center;
gap: 10px;
}
.download-bar-label {
font-size: 0.78rem;
font-weight: 700;
color: #94a3b8;
letter-spacing: 0.5px;
text-transform: uppercase;
}
.download-bar-buttons {
display: flex;
align-items: center;
justify-content: center;
gap: 12px;
flex-wrap: wrap;
}
.btn-download {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 6px;
font-size: 0.85rem;
font-weight: 700;
padding: 10px 20px;
border-radius: 12px;
text-decoration: none;
transition: all 0.2s ease;
}
.btn-download-macos {
background: #0071e3;
color: #ffffff;
border: none;
box-shadow: 0 4px 14px rgba(0, 113, 227, 0.4);
}
.btn-download-macos:hover {
background: #005bb5;
transform: translateY(-2px);
}
.btn-download-disabled {
background: rgba(255, 255, 255, 0.06);
color: #64748b;
border: 1px solid rgba(255, 255, 255, 0.1);
cursor: not-allowed;
opacity: 0.6;
}
.mac-window {
width: 100%;
max-width: 580px;
margin: 0 auto;
background: rgba(15, 23, 42, 0.85);
backdrop-filter: blur(16px);
border: 1px solid rgba(255, 255, 255, 0.12);
border-radius: 20px;
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.6);
overflow: hidden;
}
.mac-titlebar {
display: flex;
align-items: center;
justify-content: space-between;
padding: 14px 18px;
background: rgba(255, 255, 255, 0.04);
border-bottom: 1px solid rgba(255, 255, 255, 0.08);
}
.mac-dots {
display: flex;
gap: 8px;
}
.mac-dot {
width: 12px;
height: 12px;
border-radius: 50%;
}
.dot-red { background: #ff5f56; border: 1px solid #e0443e; }
.dot-yellow { background: #ffbd2e; border: 1px solid #dea123; }
.dot-green { background: #27c93f; border: 1px solid #1aab29; }
.mac-window-title {
font-size: 0.82rem;
font-weight: 700;
color: var(--text-secondary);
letter-spacing: 0.5px;
}
.mac-content {
padding: 24px;
display: flex;
flex-direction: column;
gap: 20px;
}
.rate-selector-pills {
display: flex;
gap: 8px;
overflow-x: auto;
padding-bottom: 6px;
scrollbar-width: thin;
}
.rate-pill {
background: rgba(255, 255, 255, 0.06);
border: 1px solid rgba(255, 255, 255, 0.1);
color: var(--text-secondary);
padding: 7px 14px;
border-radius: 20px;
font-size: 0.8rem;
font-weight: 700;
cursor: pointer;
white-space: nowrap;
transition: all 0.2s ease;
}
.rate-pill:hover {
background: rgba(255, 255, 255, 0.12);
color: #ffffff;
}
.rate-pill.active {
background: linear-gradient(135deg, #10b981 0%, #059669 100%);
border-color: #34d399;
color: #ffffff;
box-shadow: 0 4px 12px rgba(16, 185, 129, 0.3);
}
.converter-box {
background: rgba(30, 41, 59, 0.6);
border: 1px solid rgba(255, 255, 255, 0.08);
border-radius: 16px;
padding: 20px;
display: flex;
flex-direction: column;
gap: 14px;
}
.currency-input-group {
display: flex;
flex-direction: column;
gap: 6px;
}
.currency-label-row {
display: flex;
justify-content: space-between;
align-items: center;
font-size: 0.8rem;
font-weight: 700;
color: var(--text-secondary);
}
.input-wrapper {
position: relative;
display: flex;
align-items: center;
}
.currency-symbol {
position: absolute;
left: 16px;
font-family: 'JetBrains Mono', monospace;
font-size: 1.1rem;
font-weight: 700;
color: #34d399;
}
.currency-input {
width: 100%;
background: rgba(15, 23, 42, 0.7);
border: 1.5px solid rgba(255, 255, 255, 0.12);
border-radius: 12px;
padding: 14px 44px 14px 44px;
font-family: 'JetBrains Mono', monospace;
font-size: 1.25rem;
font-weight: 700;
color: #ffffff;
outline: none;
transition: all 0.2s ease;
}
.currency-input:focus {
border-color: #34d399;
box-shadow: 0 0 0 3px rgba(52, 211, 153, 0.2);
}
.currency-badge {
position: absolute;
right: 14px;
font-size: 0.75rem;
font-weight: 800;
padding: 4px 8px;
border-radius: 6px;
background: rgba(255, 255, 255, 0.1);
color: #ffffff;
}
.swap-divider {
display: flex;
align-items: center;
justify-content: space-between;
padding: 4px 0;
}
.swap-btn {
background: rgba(255, 255, 255, 0.08);
border: 1px solid rgba(255, 255, 255, 0.15);
color: #ffffff;
width: 40px;
height: 40px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
transition: all 0.2s ease;
margin: 0 auto;
}
.swap-btn:hover {
background: rgba(52, 211, 153, 0.2);
border-color: #34d399;
transform: rotate(180deg);
}
.rate-info-text {
font-size: 0.8rem;
color: var(--text-secondary);
font-weight: 600;
text-align: center;
}
.presets-row {
display: flex;
gap: 8px;
justify-content: center;
}
.preset-btn {
background: rgba(255, 255, 255, 0.06);
border: 1px solid rgba(255, 255, 255, 0.1);
color: #ffffff;
padding: 6px 12px;
border-radius: 10px;
font-size: 0.78rem;
font-weight: 700;
cursor: pointer;
transition: all 0.2s ease;
}
.preset-btn:hover {
background: rgba(52, 211, 153, 0.2);
border-color: #34d399;
}
.rates-grid-title {
font-size: 0.88rem;
font-weight: 700;
color: var(--text-secondary);
display: flex;
justify-content: space-between;
align-items: center;
}
.rates-table {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
gap: 10px;
}
.rate-card-item {
background: rgba(15, 23, 42, 0.6);
border: 1px solid rgba(255, 255, 255, 0.08);
border-radius: 12px;
padding: 10px 12px;
display: flex;
flex-direction: column;
gap: 4px;
}
.rate-card-name {
font-size: 0.75rem;
font-weight: 700;
color: #94a3b8;
}
.rate-card-values {
display: flex;
justify-content: space-between;
font-family: 'JetBrains Mono', monospace;
font-size: 0.85rem;
font-weight: 700;
}
.compra-val { color: #34d399; }
.venta-val { color: #38bdf8; }
.custom-rate-box {
display: flex;
align-items: center;
gap: 10px;
background: rgba(255, 255, 255, 0.04);
padding: 10px 14px;
border-radius: 12px;
border: 1px solid rgba(255, 255, 255, 0.1);
}
.custom-rate-input {
background: transparent;
border: none;
color: #ffffff;
font-family: 'JetBrains Mono', monospace;
font-weight: 700;
outline: none;
width: 100px;
}
img, svg, logo-img, .product-img, .modal-img, .thumb-img {
-webkit-user-drag: none !important;
user-drag: none !important;
-webkit-touch-callout: none !important;
user-select: none !important;
pointer-events: auto !important;
}
:root {
--font-size-h1: clamp(1.3rem, 4.5vw + 0.5rem, 2.4rem);
--font-size-h2: clamp(1.1rem, 3.5vw + 0.4rem, 1.8rem);
--font-size-h3: clamp(0.95rem, 2.5vw + 0.3rem, 1.3rem);
--font-size-hero: clamp(1.4rem, 5vw + 0.4rem, 2.5rem);
--font-size-modal: clamp(1.15rem, 3.5vw + 0.4rem, 1.6rem);
}
h1, .main-title, .hero-text h1 {
font-size: var(--font-size-hero) !important;
line-height: 1.2 !important;
word-break: break-word !important;
overflow-wrap: break-word !important;
}
h2, .section-heading h2, .catalog-title, .dash-title, .form-title {
font-size: var(--font-size-h2) !important;
line-height: 1.25 !important;
word-break: break-word !important;
}
h3, .card-title {
font-size: var(--font-size-h3) !important;
line-height: 1.3 !important;
word-break: break-word !important;
}
.modal-title {
font-size: var(--font-size-modal) !important;
line-height: 1.2 !important;
}
@media (max-width: 768px) {
.top-bar {
font-size: 0.72rem !important;
padding: 6px 10px !important;
}
.store-header, .header-inner, .page-header {
padding: 10px 14px !important;
gap: 10px !important;
}
.header-inner {
display: flex !important;
flex-wrap: wrap !important;
justify-content: space-between !important;
align-items: center !important;
}
.nav-left {
gap: 8px !important;
flex-shrink: 0;
}
.logo-img, .brand-logo-text {
height: 38px !important;
font-size: 1.2rem !important;
}
.search-bar {
order: 3 !important;
width: 100% !important;
max-width: 100% !important;
margin-top: 4px !important;
}
.controls-right {
order: 2 !important;
gap: 6px !important;
}
.back-link, .back-button {
padding: 4px 10px !important;
font-size: 0.78rem !important;
}
.live-rate-badge, .location-badge, .lang-switch-btn {
font-size: 0.7rem !important;
padding: 4px 8px !important;
}
.hero-banner {
padding: 20px 16px !important;
border-radius: 16px !important;
margin-bottom: 20px !important;
}
.modal-content {
max-height: 92vh !important;
overflow-y: auto !important;
border-radius: 18px !important;
}
.modal-details {
padding: 18px !important;
}
.product-card {
border-radius: 14px !important;
}
}
@media (max-width: 480px) {
.hero-text h1, .main-title {
font-size: 1.3rem !important;
}
.card-body {
padding: 12px !important;
}
}
.logo-mask-wrapper,
.stand-logo-wrapper,
.interactive-vector-wrapper {
top: 50% !important;
left: 50% !important;
transform: translate(-50%, -50%) !important;
}
.cube-beat .cube-bg {
background-position: center center !important;
}
@media (max-width: 768px) {
.cubes-grid {
gap: 18px !important;
}
.cube-card {
aspect-ratio: 1 / 1.30 !important;
padding: 18px 14px 16px 14px !important;
transition: transform 0.4s cubic-bezier(0.2, 0.8, 0.2, 1),
aspect-ratio 0.4s cubic-bezier(0.2, 0.8, 0.2, 1),
box-shadow 0.4s ease !important;
display: flex !important;
flex-direction: column !important;
justify-content: space-between !important;
}
.cube-card:hover, .cube-card:active {
aspect-ratio: 1 / 1.35 !important;
transform: translateY(-4px) scale(1.01) !important;
}
.cube-header {
position: relative !important;
z-index: 10 !important;
}
.cube-footer {
position: relative !important;
z-index: 10 !important;
margin-top: auto !important;
}
.cube-title {
font-size: clamp(1.1rem, 4vw, 1.35rem) !important;
line-height: 1.2 !important;
text-shadow: 0 2px 8px rgba(0,0,0,0.85) !important;
}
}
.cubes-grid {
display: grid !important;
grid-template-columns: repeat(2, 1fr) !important;
gap: 16px !important;
width: 100% !important;
max-width: 480px !important;
margin: 0 auto !important;
}
@media (max-width: 768px) {
.cubes-grid {
max-width: 360px !important;
gap: 14px !important;
}
}
.copyright a {
color: #38bdf8 !important;
text-decoration: none !important;
font-weight: 700 !important;
transition: color 0.2s ease;
}
.copyright a:hover {
color: #8b5cf6 !important;
text-decoration: underline !important;
}
.page-loader {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background: #090d16;
z-index: 99999;
display: flex;
align-items: center;
justify-content: center;
transition: opacity 0.35s cubic-bezier(0.2, 0.8, 0.2, 1), visibility 0.35s ease;
opacity: 1;
visibility: visible;
}
.page-loader.loaded {
opacity: 0;
visibility: hidden;
pointer-events: none;
}
.loader-spinner {
width: 42px;
height: 42px;
border: 3.5px solid rgba(255, 255, 255, 0.12);
border-top-color: #38bdf8;
border-radius: 50%;
animation: loaderSpin 0.75s infinite linear;
}
@keyframes loaderSpin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
:root {
--font-size-h1: clamp(1.3rem, 4.5vw + 0.5rem, 2.4rem);
--font-size-h2: clamp(1.1rem, 3.5vw + 0.4rem, 1.8rem);
--font-size-h3: clamp(0.95rem, 2.5vw + 0.3rem, 1.3rem);
--font-size-hero: clamp(1.4rem, 5vw + 0.4rem, 2.5rem);
--font-size-modal: clamp(1.15rem, 3.5vw + 0.4rem, 1.6rem);
}
h1, .main-title, .hero-text h1 {
font-size: var(--font-size-hero) !important;
line-height: 1.2 !important;
word-break: break-word !important;
overflow-wrap: break-word !important;
}
h2, .section-heading h2, .catalog-title, .dash-title, .form-title {
font-size: var(--font-size-h2) !important;
line-height: 1.25 !important;
word-break: break-word !important;
}
h3, .card-title {
font-size: var(--font-size-h3) !important;
line-height: 1.3 !important;
word-break: break-word !important;
}
.modal-title {
font-size: var(--font-size-modal) !important;
line-height: 1.2 !important;
}
@media (max-width: 768px) {
.top-bar {
font-size: 0.72rem !important;
padding: 6px 10px !important;
}
.store-header, .header-inner, .page-header {
padding: 10px 14px !important;
gap: 10px !important;
}
.header-inner {
display: flex !important;
flex-wrap: wrap !important;
justify-content: space-between !important;
align-items: center !important;
}
.nav-left {
gap: 8px !important;
flex-shrink: 0;
}
.logo-img, .brand-logo-text {
height: 38px !important;
font-size: 1.2rem !important;
}
.search-bar {
order: 3 !important;
width: 100% !important;
max-width: 100% !important;
margin-top: 4px !important;
}
.controls-right {
order: 2 !important;
gap: 6px !important;
}
.back-link, .back-button {
padding: 4px 10px !important;
font-size: 0.78rem !important;
}
.live-rate-badge, .location-badge, .lang-switch-btn {
font-size: 0.7rem !important;
padding: 4px 8px !important;
}
.hero-banner {
padding: 20px 16px !important;
border-radius: 16px !important;
margin-bottom: 20px !important;
}
.modal-content {
max-height: 92vh !important;
overflow-y: auto !important;
border-radius: 18px !important;
}
.modal-details {
padding: 18px !important;
}
.product-card {
border-radius: 14px !important;
}
}
@media (max-width: 480px) {
.hero-text h1, .main-title {
font-size: 1.3rem !important;
}
.card-body {
padding: 12px !important;
}
}
.logo-mask-wrapper,
.stand-logo-wrapper,
.interactive-vector-wrapper {
top: 50% !important;
left: 50% !important;
transform: translate(-50%, -50%) !important;
}
.cube-beat .cube-bg {
background-position: center center !important;
}
@media (max-width: 768px) {
.cubes-grid {
gap: 18px !important;
}
.cube-card {
aspect-ratio: 1 / 1.30 !important;
padding: 18px 14px 16px 14px !important;
transition: transform 0.4s cubic-bezier(0.2, 0.8, 0.2, 1),
aspect-ratio 0.4s cubic-bezier(0.2, 0.8, 0.2, 1),
box-shadow 0.4s ease !important;
display: flex !important;
flex-direction: column !important;
justify-content: space-between !important;
}
.cube-card:hover, .cube-card:active {
aspect-ratio: 1 / 1.35 !important;
transform: translateY(-4px) scale(1.01) !important;
}
.cube-header {
position: relative !important;
z-index: 10 !important;
}
.cube-footer {
position: relative !important;
z-index: 10 !important;
margin-top: auto !important;
}
.cube-title {
font-size: clamp(1.1rem, 4vw, 1.35rem) !important;
line-height: 1.2 !important;
text-shadow: 0 2px 8px rgba(0,0,0,0.85) !important;
}
}
.cubes-grid {
display: grid !important;
grid-template-columns: repeat(2, 1fr) !important;
gap: 16px !important;
width: 100% !important;
max-width: 480px !important;
margin: 0 auto !important;
}
@media (max-width: 768px) {
.cubes-grid {
max-width: 360px !important;
gap: 14px !important;
}
}
.copyright a {
color: #38bdf8 !important;
text-decoration: none !important;
font-weight: 700 !important;
transition: color 0.2s ease;
}
.copyright a:hover {
color: #8b5cf6 !important;
text-decoration: underline !important;
}
</style>
</head>
<body>
<div style="background:#0f172a;padding:10px 20px"><a href="index.html" style="color:#94a3b8;text-decoration:none;font-weight:700;font-size:.9rem">← Inicio</a></div>
<div id="pageLoader" class="page-loader">
<div class="loader-spinner"></div>
</div>
<div class="bg-radial bg-radial-1"></div>
<div class="bg-radial bg-radial-2"></div>
<div class="bg-grid"></div>
<div class="container page-container">
<header class="page-header">
<a href="interactive.html" class="back-button">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5">
<path d="M19 12H5M12 19l-7-7 7-7"/>
</svg>
<span>Volver</span>
</a>
</header>
<main class="mac-window">
<div class="mac-titlebar">
<div class="mac-dots">
<div class="mac-dot dot-red"></div>
<div class="mac-dot dot-yellow"></div>
<div class="mac-dot dot-green"></div>
</div>
<span class="mac-window-title">ConversorDolar.app — Web Edition</span>
<span id="lastUpdated" style="font-size: 0.72rem; color: #94a3b8;">Cargando...</span>
</div>
<div class="mac-content">
<div class="rate-selector-pills" id="pillsContainer">
<button class="rate-pill active" onclick="selectRate('blueVenta', this)">Blue Venta</button>
<button class="rate-pill" onclick="selectRate('blueCompra', this)">Blue Compra</button>
<button class="rate-pill" onclick="selectRate('mep', this)">MEP</button>
<button class="rate-pill" onclick="selectRate('ccl', this)">CCL</button>
<button class="rate-pill" onclick="selectRate('oficialVenta', this)">Oficial</button>
<button class="rate-pill" onclick="selectRate('tarjeta', this)">Tarjeta</button>
<button class="rate-pill" onclick="selectRate('cripto', this)">Cripto</button>
<button class="rate-pill" onclick="selectRate('custom', this)">Personalizado</button>
</div>
<div id="customRateRow" class="custom-rate-box" style="display: none;">
<span style="font-size: 0.8rem; color: #94a3b8; font-weight: 700;">Cotización Personalizada: $</span>
<input type="number" id="customRateInput" class="custom-rate-input" placeholder="1350" oninput="onCustomRateChange()">
</div>
<div class="converter-box">
<div class="currency-input-group">
<div class="currency-label-row">
<span id="topLabel">Dólares Estadounidenses</span>
<span>Monto</span>
</div>
<div class="input-wrapper">
<span class="currency-symbol" id="topSymbol">U$S</span>
<input type="text" id="topInput" class="currency-input" value="100" oninput="onTopInput()">
<span class="currency-badge" id="topBadge">USD</span>
</div>
</div>
<div class="swap-divider">
<div class="rate-info-text" id="activeRateText">Cotización: 1 USD = $1.350,00 ARS</div>
<button class="swap-btn" onclick="toggleSwap()" title="Intercambiar Monedas">
<svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2.5">
<path d="M7 16V4m0 0L3 8m4-4l4 4m6 0v12m0 0l4-4m-4 4l-4-4"/>
</svg>
</button>
</div>
<div class="currency-input-group">
<div class="currency-label-row">
<span id="bottomLabel">Pesos Argentinos</span>
<span>Resultado</span>
</div>
<div class="input-wrapper">
<span class="currency-symbol" id="bottomSymbol">$</span>
<input type="text" id="bottomInput" class="currency-input" placeholder="0,00" oninput="onBottomInput()">
<span class="currency-badge" id="bottomBadge">ARS</span>
</div>
</div>
<div class="presets-row">
<button class="preset-btn" onclick="setPreset(10)">$10 USD</button>
<button class="preset-btn" onclick="setPreset(50)">$50 USD</button>
<button class="preset-btn" onclick="setPreset(100)">$100 USD</button>
<button class="preset-btn" onclick="setPreset(500)">$500 USD</button>
<button class="preset-btn" onclick="setPreset(1000)">$1000 USD</button>
</div>
</div>
<div class="rates-grid-title">
<span>Cotizaciones en Vivo (dolarapi.com)</span>
<button onclick="fetchRates()" style="background: none; border: none; color: #34d399; cursor: pointer; font-size: 0.8rem; font-weight: 700;">🔄 Actualizar</button>
</div>
<div class="rates-table" id="ratesTable">
</div>
</div>
</main>
<footer class="site-footer">
<p class="copyright">Sitio creado con Neo Studio</p>
</footer>
</div>
<script id="script-ajuste-de-textos">
(function ajusteDeTextos() {
function adaptTextAndHeaders() {
const width = window.innerWidth;
document.documentElement.style.setProperty('--window-width', width + 'px');
const headings = document.querySelectorAll('.hero-text h1, .main-title, .modal-title, .section-heading h2');
headings.forEach(h => {
if (width < 500) {
h.style.letterSpacing = '-0.3px';
} else {
h.style.letterSpacing = 'normal';
}
});
}
window.addEventListener('resize', adaptTextAndHeaders);
window.addEventListener('orientationchange', adaptTextAndHeaders);
document.addEventListener('DOMContentLoaded', adaptTextAndHeaders);
adaptTextAndHeaders();
})();
</script>
<script>
document.addEventListener('dragstart', function(e) {
if (e.target.tagName === 'IMG' || e.target.tagName === 'SVG' || e.target.closest('img')) {
e.preventDefault();
}
});
</script>
<script>
(function() {
function hideLoaderNow() {
var loader = document.getElementById('pageLoader');
if (loader) {
loader.style.opacity = '0';
loader.style.visibility = 'hidden';
loader.style.pointerEvents = 'none';
if (loader.parentNode) loader.parentNode.removeChild(loader);
}
}
if (document.readyState === 'interactive' || document.readyState === 'complete') {
hideLoaderNow();
} else {
document.addEventListener('DOMContentLoaded', hideLoaderNow);
window.addEventListener('load', hideLoaderNow);
}
setTimeout(hideLoaderNow, 250);
})();
</script>
<script>
(function() {
setTimeout(function() {
try {
const pageName = document.title || window.location.pathname;
const startTime = Date.now();
const dateStr = new Date().toLocaleDateString('es-AR', { day: '2-digit', month: 'long', year: 'numeric' });
const timeStr = new Date().toLocaleTimeString('es-AR', { hour: '2-digit', minute: '2-digit', second: '2-digit' });
const userAgent = navigator.userAgent;
let deviceStr = 'Desktop';
if (/Mobi|Android|iPhone|iPad/i.test(userAgent)) deviceStr = 'Móvil / Celular';
let currentRecordIndex = -1;
function saveVisit(ip, city, country, flag) {
let logs = JSON.parse(localStorage.getItem('site_visitor_history') || '[]');
const visitRecord = {
id: Date.now(),
date: dateStr,
time: timeStr,
page: pageName,
ip: ip || 'Desconocida',
city: city || 'Desconocida',
country: country || 'Desconocido',
flag: flag || '🌐',
device: deviceStr,
durationSec: 1
};
logs.push(visitRecord);
if (logs.length > 500) logs = logs.slice(-500);
localStorage.setItem('site_visitor_history', JSON.stringify(logs));
currentRecordIndex = logs.length - 1;
}
fetch('https://ipapi.co/json/', { signal: AbortSignal.timeout(2000) })
.then(res => res.json())
.then(data => {
saveVisit(data.ip, data.city, data.country_name, data.country_code ? String.fromCodePoint(...[...data.country_code.toUpperCase()].map(c => 127397 + c.charCodeAt())) : '🌐');
})
.catch(() => {
saveVisit('Oculta', 'Local', 'Argentina', '🇦🇷');
});
setInterval(() => {
if (currentRecordIndex < 0) return;
const elapsed = Math.round((Date.now() - startTime) / 1000);
let logs = JSON.parse(localStorage.getItem('site_visitor_history') || '[]');
if (logs[currentRecordIndex]) {
logs[currentRecordIndex].durationSec = elapsed;
localStorage.setItem('site_visitor_history', JSON.stringify(logs));
}
}, 3000);
} catch(e) {}
}, 100);
})();
</script>
<script>
document.addEventListener('contextmenu', function(e) { e.preventDefault(); });
document.addEventListener('keydown', function(e) {
if (e.keyCode === 123 ||
(e.ctrlKey && e.shiftKey && (e.keyCode === 73 || e.keyCode === 74 || e.keyCode === 67)) ||
(e.ctrlKey && (e.keyCode === 85 || e.keyCode === 83)) ||
(e.metaKey && e.altKey && (e.keyCode === 73 || e.keyCode === 74)) ||
(e.metaKey && (e.keyCode === 85 || e.keyCode === 83))) {
e.preventDefault();
return false;
}
});
document.addEventListener('dragstart', function(e) { e.preventDefault(); });
</script>
</body>
</html>