// PEN Landing — Header, Hero, and App composition.
const { useState: useStateA, useEffect: useEffectA } = React;
// ────────────────────────────────────────────────────────────────────
// Status bar (top strip)
// ────────────────────────────────────────────────────────────────────
function StatusBar({ copy }) {
const [time, setTime] = useStateA(() => fmtClock());
useEffectA(() => {
const t = setInterval(() => setTime(fmtClock()), 1000);
return () => clearInterval(t);
}, []);
return (
{copy.uptime}
{copy.coords}
{copy.live}
·
{time}
);
}
function fmtClock() {
const options = {
timeZone: "America/Lima",
hour: "2-digit",
minute: "2-digit",
second: "2-digit",
hour12: false
};
const formatter = new Intl.DateTimeFormat("es-PE", options);
return `${formatter.format(new Date())} PET`;
}
function pad(n) {return String(n).padStart(2, "0");}
// ────────────────────────────────────────────────────────────────────
// Header
// ────────────────────────────────────────────────────────────────────
function Header({ copy, onCta, onNav }) {
const handleNav = (e, sec) => {
e.preventDefault();
onNav("landing", sec);
};
return (
);
}
// ────────────────────────────────────────────────────────────────────
// Hero — left: copy + stats; right: live console
// ────────────────────────────────────────────────────────────────────
function Hero({ copy, consoleCopy, onCta }) {
return (
{copy.eyebrow}
{copy.h1Top}
{copy.h1Bottom}
{copy.sub}
{copy.ctaSub}
{[copy.stat1, copy.stat2, copy.stat3].map((s, i) =>
{s.label}
{s.value}
{s.foot}
)}
{copy.stat4 && (
{copy.stat4.label}
{copy.stat4.foot}
)}
);
}
// ────────────────────────────────────────────────────────────────────
// Toast — "Demo solicitada" feedback when CTA pressed
// ────────────────────────────────────────────────────────────────────
function Toast({ toast }) {
if (!toast) return null;
return (
● {toast.head}
{toast.body}
);
}
// ────────────────────────────────────────────────────────────────────
// App
// ────────────────────────────────────────────────────────────────────
const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
"lang": "es",
"glow": 0.55,
"gridDensity": 0.04,
"accentVariant": "neon"
} /*EDITMODE-END*/;
function App() {
const [tweaks, setTweak] = useTweaks(TWEAK_DEFAULTS);
const copy = PEN_COPY[tweaks.lang] || PEN_COPY.es;
const [toast, setToast] = useStateA(null);
const [view, setView] = useStateA("landing");
const [showModal, setShowModal] = useStateA(false);
const navigateTo = (v, secId = null) => {
setView(v);
// Dynamic SEO Title and Description updates for SPA
try {
const metaDesc = document.querySelector('meta[name="description"]');
if (v === "landing") {
document.title = "PEN — Tu perímetro, monitoreado 24/7.";
if (metaDesc) metaDesc.setAttribute("content", "PEN Security - Auditoría de ciberseguridad, monitoreo activo de hosts y continuidad de negocio 24/7 en el Perú. Protege tu empresa contra ransomware, phishing y fugas de datos.");
} else if (v === "about") {
document.title = "Sobre PEN — Ciberseguridad y continuidad para la empresa peruana";
if (metaDesc) metaDesc.setAttribute("content", "Conoce quiénes somos en PEN Security. Nuestra misión, visión y pilares operativos para proteger la infraestructura digital en Lima, Perú.");
} else if (v === "blog") {
document.title = "Blog Técnico — Artículos y Amenazas de Ciberseguridad en el Perú";
if (metaDesc) metaDesc.setAttribute("content", "Análisis técnicos, guías de configuración y mejores prácticas de seguridad informática escritas por los especialistas de PEN Security.");
} else if (v === "contact") {
document.title = "Contacto — Hablemos de tu ciberseguridad | PEN Security";
if (metaDesc) metaDesc.setAttribute("content", "Solicita tu diagnóstico de ciberseguridad gratuito. Ponte en contacto directo con nuestros analistas en Surquillo, Lima.");
} else if (v === "platforms") {
document.title = "Plataformas de Seguridad Integradas | PEN Security";
if (metaDesc) metaDesc.setAttribute("content", "Conoce las plataformas líderes que integramos en PEN: Fortinet Firewalls, CrowdStrike EDR, SentinelOne XDR, Veeam Backup y Microsoft Defender.");
} else if (v === "crm") {
document.title = "Admin CRM Dashboard | PEN Security";
if (metaDesc) metaDesc.setAttribute("content", "Sistema de gestión interna de leads y solicitudes.");
}
} catch (e) {
console.warn("Fallo al actualizar metadatos SEO dinámicos:", e);
}
if (secId) {
setTimeout(() => {
const idStr = secId.toLowerCase().replace(/[^a-z0-9]+/g, "-");
const el = document.getElementById(idStr) || document.getElementById(secId);
if (el) el.scrollIntoView({ behavior: "smooth" });
}, 150);
} else {
window.scrollTo({ top: 0, behavior: "smooth" });
}
};
// Apply glow + grid CSS vars
useEffectA(() => {
const r = document.documentElement;
r.style.setProperty("--pen-glow-strength", tweaks.glow);
r.style.setProperty("--pen-grid-opacity", tweaks.gridDensity);
const accentMap = {
neon: "#00FF7A",
mint: "#B0FFD9",
cyber: "#7FE9FF"
};
r.style.setProperty("--pen-accent", accentMap[tweaks.accentVariant] || accentMap.neon);
// Also push to neon token for full effect
if (tweaks.accentVariant === "cyber") {
r.style.setProperty("--pen-neon", "#7FE9FF");
r.style.setProperty("--accent", "#7FE9FF");
r.style.setProperty("--pen-line", "rgba(127,233,255,0.16)");
r.style.setProperty("--pen-line-strong", "rgba(127,233,255,0.34)");
} else {
r.style.setProperty("--pen-neon", "#00FF7A");
r.style.setProperty("--accent", "#00FF7A");
r.style.setProperty("--pen-line", "rgba(0,255,122,0.14)");
r.style.setProperty("--pen-line-strong", "rgba(0,255,122,0.32)");
}
}, [tweaks.glow, tweaks.gridDensity, tweaks.accentVariant]);
useEffectA(() => {
const handleOpen = () => setShowModal(true);
window.addEventListener("open-diagnostic-modal", handleOpen);
return () => window.removeEventListener("open-diagnostic-modal", handleOpen);
}, []);
const onCta = () => {
setShowModal(true);
};
return (
{view === "landing" && (
<>
>
)}
{view === "about" && (
navigateTo("landing")} />
)}
{view === "blog" && (
navigateTo("landing")} />
)}
{view === "contact" && (
navigateTo("landing")} />
)}
{view === "platforms" && (
navigateTo("landing")} />
)}
{view === "crm" && (
navigateTo("landing")} />
)}
setShowModal(false)} />
setTweak("lang", v)}
options={[
{ value: "es", label: "Español" },
{ value: "en", label: "English" }]
} />
setTweak("glow", v)} />
setTweak("gridDensity", v)} />
setTweak("accentVariant", v)}
options={[
{ value: "neon", label: "Neon" },
{ value: "mint", label: "Mint" },
{ value: "cyber", label: "Cyber" }]
} />
);
}
ReactDOM.createRoot(document.getElementById("root")).render();