diff --git a/funciones.php b/funciones.php
index be87111..e7847dc 100755
--- a/funciones.php
+++ b/funciones.php
@@ -1,6 +1,39 @@
require_once CMS_VIEWER_LIB;
+/**
+ * ¿Esta copia de la web corre en Forge (local o test) o en producción?
+ *
+ * La señal es la PRESENCIA del `.acai` en la raíz: Forge lo escribe en cada copia
+ * local, y NUNCA viaja a producción — está en el `exclude` del manifest de
+ * push-core y fuera de la allowlist del sync per-web (verificado 2026-09-01).
+ *
+ * Se detecta LOCAL de forma explícita y todo lo demás se trata como producción,
+ * no al revés: si la señal fallara, el comportamiento seguro es el de producción
+ * (respetar `pagina_publicada`). Asumir local ante la duda podría dejar visible
+ * una web sin terminar.
+ *
+ * POR QUÉ VIVE AQUÍ y no en otro sitio, que costó tres intentos:
+ * - NO en `cms/`: esa carpeta se sobrescribe al actualizar el core desde el CMS
+ * legacy y el cambio se perdería.
+ * - NO en `lib/variables.php`: ese fichero viaja en el sync PER-WEB (es el único
+ * de raíz que lo hace), así que la copia de cada web manda y puede quedarse
+ * vieja o divergir. Una función del núcleo no puede vivir en un fichero que
+ * cada web sobrescribe.
+ * - NO en un plugin (`TokenGuard::isLocalTest()` hace esto mismo): el núcleo no
+ * debe depender de que un plugin esté presente y cargado, y `builder_saas`
+ * publica solo al editarlo.
+ * `funciones.php` es CORE (viaja en el manifest de push-core, como `header.php`)
+ * y lo carga todo el front antes de usarlo.
+ */
+function esEntornoLocal() {
+ static $local = null;
+ if ($local === null) {
+ $local = is_file(dirname(__FILE__) . "/.acai");
+ }
+ return $local;
+}
+
// VARIABLES RELACIONADAS CON LA EXTRACCION DE CSS
$contadorImagenes = 0;
$modulosCargados = array();
diff --git a/header.php b/header.php
index de3f6d9..6c2a87e 100755
--- a/header.php
+++ b/header.php
@@ -56,23 +56,36 @@ $config_header = array(
'alternate' => @$alternate
);
-if (1){
-
- if (@$customCode) echo modulo('custom-header',$config_header); else echo tpl('cabecera',$config_header);
-}else{
- if (!isset($_SESSION["pruebas"])){
- die(tpl('mantenimiento',$config_header));
-
- }else{
- if (@$customCode) echo modulo('custom-header',$config_header); else echo tpl('cabecera',$config_header);
- if (isset($_SESSION["pruebas"])){
- if ($configuracionRecord["pagina_publicada"]==0){
- ?>
-
SITIO EN PRUEBAS
-
- }
- }
+// Quien ve la web y quien ve la pagina de mantenimiento.
+//
+// En LOCAL/TEST (Forge) siempre se ve la web: ahi no existe el concepto de
+// "publicada" ni el modo `?pruebas`, que son solo de produccion.
+//
+// En PRODUCCION:
+// - publicada -> se ve
+// - sin publicar + ?pruebas -> se ve, con el cartel rojo
+// - sin publicar + visitante -> pagina de mantenimiento
+//
+// Antes esto era un `if (1)` hardcodeado que se saltaba la comprobacion entera,
+// con una copia `header.php.prod` que comentaba esas lineas para produccion. La
+// copia estaba MAL: al comentar el `if(1){...}else{`, el cuerpo del else pasaba a
+// ejecutarse siempre y un visitante normal de una web PUBLICADA recibia
+// `die(mantenimiento)`. Nadie lo vio porque ese fichero solo corria en
+// produccion. Con la condicion en tiempo de ejecucion el camino de produccion se
+// prueba en local tocando la señal.
+$verLaWeb = esEntornoLocal()
+ || @$configuracionRecord["pagina_publicada"]
+ || isset($_SESSION["pruebas"]);
+
+if ($verLaWeb) {
+ if (@$customCode) echo modulo('custom-header',$config_header); else echo tpl('cabecera',$config_header);
+ // Aviso solo cuando de verdad estas mirando algo sin publicar (prod + pruebas).
+ if (!esEntornoLocal() && isset($_SESSION["pruebas"]) && @$configuracionRecord["pagina_publicada"] == 0) {
+ ?>
+ SITIO EN PRUEBAS
+
}
-
+} else {
+ die(tpl('mantenimiento',$config_header));
}
?>
diff --git a/header.php.prod b/header.php.prod
deleted file mode 100755
index ddd7050..0000000
--- a/header.php.prod
+++ /dev/null
@@ -1,78 +0,0 @@
-
-require_once ("sesion.php");
-if (isset($_GET["pruebas"])) $_SESSION["pruebas"]=true;
-
-require_once "funciones.php";
-if (!isset($current)) $current=0;
-
-if (HAY_TIENDA) {
- $categorias = CocoDB::get("categorias_productos", "parentNum=0", "siblingOrder ASC", null, ["ignoreSchema" => true]);
-}
-
-$idiomas = dame_idiomas();
-
-$idiomaSeleccionado = "Español";
-
-foreach ($idiomas as $idioma):
-
- if ($idioma["valor"]=="/".@$_REQUEST["idioma"]) $idiomaSeleccionado=$idioma["idioma"];
-endforeach;
-
-$apartadoCesta = CocoDB::get("apartados", "controlador='cesta.php'", null, 1, ["ignoreSchema" => true]);
-$apartadoCesta = @$apartadoCesta[0];
-
-$apartadoFavoritos = CocoDB::get("apartados", "controlador='favoritos.php'", null, 1, ["ignoreSchema" => true]);
-$apartadoFavoritos = @$apartadoFavoritos[0];
-
-$apartadoLogin = CocoDB::get("apartados", "controlador='login.php'", null, 1, ["ignoreSchema" => true]);
-$apartadoLogin = @$apartadoLogin[0];
-
-$apartadoRegistro = CocoDB::get("apartados", "controlador='registro.php'", null, 1, ["ignoreSchema" => true]);
-$apartadoRegistro = @$apartadoRegistro[0];
-
-$alternate = dame_alternates($_SERVER["REQUEST_URI"]);
-
-$config_header = array(
- 'titulo_de_pagina' => $configuracionRecord["titulo_de_pagina"],
- 'categorias' => @$categorias,
- 'pagina_publicada' => $configuracionRecord["pagina_publicada"],
- 'current' => $current,
- 'portada' => @$portada,
- 'index' => @$index,
- 'configuracionRecord' => $configuracionRecord,
- 'configuracionTienda' => $configuracionTienda,
- 'meta_descripcion' => $configuracionRecord["metatag_descripcion"],
- 'meta_palabras' => @$configuracionRecord["metatag_palabras"],
- 'otros_metas' => @$otros_metas,
- 'color_base' => @$color_base,
- 'categorias' => @$categorias,
- 'idiomas' => @$idiomas,
- 'idiomaSeleccionado'=> @$idiomaSeleccionado,
- 'apartadoCesta' => @$apartadoCesta,
- 'apartadoFavoritos' => @$apartadoFavoritos,
- 'apartadoLogin' => @$apartadoLogin,
- 'apartadoRegistro' => @$apartadoRegistro,
- 'sitebuilder' => @$apartado["plantilla_sitebuilder"],
- 'alternate' => @$alternate
- );
-
-#if (1){
-
-# if (@$customCode) echo modulo('custom-header',$config_header); else echo tpl('cabecera',$config_header);
-#}else{
- if (!isset($_SESSION["pruebas"])){
- die(tpl('mantenimiento',$config_header));
-
- }else{
- if (@$customCode) echo modulo('custom-header',$config_header); else echo tpl('cabecera',$config_header);
- if (isset($_SESSION["pruebas"])){
- if ($configuracionRecord["pagina_publicada"]==0){
- ?>
- SITIO EN PRUEBAS
-
- }
- }
- }
-
-#}
-?>