<?php
/**
 * Instalación pendiente: no servir el escritorio hasta que exista install.lock.
 * Fuerza al asistente en /install/ aunque el usuario abra la URL del inicio.
 */
require_once __DIR__ . '/includes/install_public.php';
if (!antara_install_is_locked()) {
    $to = antara_install_base_url();
    if (!headers_sent()) {
        header('Location: ' . $to, true, 302);
        header('Cache-Control: no-store, no-cache, must-revalidate');
    } else {
        echo '<script>location.replace(' . json_encode($to, JSON_UNESCAPED_SLASHES | JSON_HEX_TAG | JSON_HEX_AMP) . ');</script>';
    }
    exit;
}

require __DIR__ . '/core/auth/guard.php';
require __DIR__ . '/includes/bootstrap.php';
require_once __DIR__ . '/includes/user_settings_helpers.php';
if (AntaraSession::isLoggedIn()) {
    $__profileUid = grid_user_settings_session_user_id();
    if ($__profileUid !== null) {
        $settings = grid_settings_merged_for_user($settings, $__profileUid);
    }
}
require __DIR__ . '/includes/api.php';

$gridAdminUsersUrl = rtrim($baseUrl, '/') . '/admin/users/';
$gridAuthApiUrl = rtrim($baseUrl, '/') . '/core/auth/api.php';
$gridLoginUrl = rtrim($baseUrl, '/') . '/login/';
$gridUserLoggedIn = AntaraSession::isLoggedIn();

$gridSessionUserDisplayName = '';
$gridSessionUserAvatarSrc = '';
$gridSessionUserInitial = '';
$gridSessionUserId = '';
$gridSessionUserOrgLine = '';
$gridProf = '';
$gridSessionUserMediaFrame = null;
if ($gridUserLoggedIn) {
    require_once __DIR__ . '/core/auth/profile_image.php';
    $gridSessionUser = AntaraSession::user();
    if ($gridSessionUser && !empty($gridSessionUser['id'])) {
        try {
            $gridSessionUserFresh = AntaraStore::findUserById($gridSessionUser['id']);
            if ($gridSessionUserFresh) {
                $gridSessionUser = $gridSessionUserFresh;
            }
        } catch (\Throwable $e) {
            // Mantener datos de sesión si el vault no está disponible.
        }
        $gridSessionUserDisplayName = trim((string)($gridSessionUser['username'] ?? ''));
        if ($gridSessionUserDisplayName === '') {
            $gridSessionUserDisplayName = trim((string)($gridSessionUser['email'] ?? ''));
        }
        if (($settings['deploymentKind'] ?? '') === 'company') {
            require_once __DIR__ . '/includes/org_structure_helpers.php';
            $gridOrgLabels = antara_org_resolve_labels(
                $settings,
                (string) ($gridSessionUser['branchId'] ?? ''),
                (string) ($gridSessionUser['departmentId'] ?? ''),
                (string) ($gridSessionUser['positionId'] ?? '')
            );
            $gridOrgParts = array_filter([
                $gridOrgLabels['department'] ?? '',
                $gridOrgLabels['position'] ?? '',
                $gridOrgLabels['branch'] ?? '',
            ], static fn($v) => trim((string) $v) !== '');
            $gridSessionUserOrgLine = implode(' · ', $gridOrgParts);
        }
        $gridProf = antara_user_profile_image_rel($gridSessionUser);
        if ($gridProf !== null && $gridProf !== '') {
            if (preg_match('#^https?://#i', $gridProf)) {
                $gridSessionUserAvatarSrc = $gridProf;
            } else {
                $relPath = $gridProf[0] === '/' ? $gridProf : '/' . $gridProf;
                $diskPath = dirname(__DIR__) . str_replace('/', DIRECTORY_SEPARATOR, $relPath);
                $avatarBust = is_file($diskPath) ? (string) filemtime($diskPath) : (string) time();
                $gridSessionUserAvatarSrc = rtrim($baseUrl, '/') . $relPath . '?v=' . rawurlencode($avatarBust);
            }
        }
        $gridSessionUserInitial = strtoupper(substr($gridSessionUserDisplayName !== '' ? $gridSessionUserDisplayName : '?', 0, 1));
        $gridSessionUserId = (string)($gridSessionUser['id'] ?? '');
        $gridSessionUserMediaFrame = isset($gridSessionUser['profileMediaFrame']) && is_array($gridSessionUser['profileMediaFrame'])
            ? $gridSessionUser['profileMediaFrame']
            : null;
    }
}

$gridHasSuperAdminUser = false;
try {
    $gridHasSuperAdminUser = AntaraStore::hasActiveSuperAdmin();
} catch (\Throwable $e) {
    $gridHasSuperAdminUser = false;
}

$gridSinapsysLogoRel = '';
$gridSinapsysLogoAlt = 'SINAPSYS DEVOPS SA DE CV.';
$gridClienteLogoRel = '';
$gridClienteLogoAlt = 'Quadrata — licenciamiento';
$gridClienteLogoIsVideo = false;
$gridClienteLogoMediaFrame = null;
$gridClienteLogoKind = null;
$__logoDir = __DIR__ . DIRECTORY_SEPARATOR . 'logos_sinapsys';
$__pngList = [];
if (is_dir($__logoDir)) {
    $__glob = glob($__logoDir . DIRECTORY_SEPARATOR . '*.png');
    if (is_array($__glob) && $__glob !== []) {
        natsort($__glob);
        $__pngList = $__glob;
    }
}
$__cfgLogo = isset($settings['clientLogoRel']) ? trim((string) $settings['clientLogoRel']) : '';
if ($__cfgLogo !== '' && strpos($__cfgLogo, '..') === false && preg_match('#^logos_sinapsys/[^/\\\\]+$#i', $__cfgLogo)) {
    $__cfgLogoFs = __DIR__ . DIRECTORY_SEPARATOR . str_replace(['/', '\\'], DIRECTORY_SEPARATOR, ltrim($__cfgLogo, '/'));
    if (is_file($__cfgLogoFs)) {
        $gridClienteLogoRel = str_replace('\\', '/', $__cfgLogo);
        $ext = strtolower((string) pathinfo($__cfgLogoFs, PATHINFO_EXTENSION));
        $gridClienteLogoIsVideo = in_array($ext, ['mp4', 'webm', 'mov', 'ogg'], true);
        $gridClienteLogoKind = $gridClienteLogoIsVideo ? 'video' : (strtolower($ext) === 'gif' ? 'gif' : 'image');
    }
}
if (isset($settings['clientLogoMediaFrame']) && is_array($settings['clientLogoMediaFrame'])) {
    require_once __DIR__ . '/core/auth/profile_image_ops.php';
    $gridClienteLogoMediaFrame = antara_user_profile_media_frame_normalize($settings['clientLogoMediaFrame']);
}
if ($gridClienteLogoRel === '') {
    $__logoClienteGlob = is_dir($__logoDir) ? (glob($__logoDir . DIRECTORY_SEPARATOR . 'logo_cliente.*') ?: []) : [];
    foreach ($__logoClienteGlob as $__lcPath) {
        if (is_file($__lcPath)) {
            $gridClienteLogoRel = 'logos_sinapsys/' . basename($__lcPath);
            $ext = strtolower((string) pathinfo($__lcPath, PATHINFO_EXTENSION));
            $gridClienteLogoIsVideo = in_array($ext, ['mp4', 'webm', 'mov', 'ogg'], true);
            $gridClienteLogoKind = $gridClienteLogoIsVideo ? 'video' : (strtolower($ext) === 'gif' ? 'gif' : 'image');
            break;
        }
    }
}
foreach ($__pngList as $__pngPath) {
    $__bn = basename($__pngPath);
    if (stripos($__bn, 'logo_cliente') !== 0) {
        $gridSinapsysLogoRel = 'logos_sinapsys/' . $__bn;
        break;
    }
}

$gridCreditsLogoIsCliente = ($gridClienteLogoRel !== '');

/**
 * Cache-busting automático para assets (CSS/JS).
 * Usa filemtime para cambiar ?v= cuando el archivo cambia.
 */
function grid_asset_url(string $relPath): string {
    $relPath = ltrim($relPath, '/');
    $full = __DIR__ . DIRECTORY_SEPARATOR . str_replace(['/', '\\'], DIRECTORY_SEPARATOR, $relPath);
    $v = @filemtime($full);
    if (!$v) $v = time();
    $url = $relPath . '?v=' . rawurlencode((string)$v);
    return htmlspecialchars($url, ENT_QUOTES, 'UTF-8');
}

/** Nombre visible de categoría (string legacy u objeto con name). */
function grid_category_display_name($cat): string {
    if (is_string($cat)) {
        return $cat;
    }
    if (is_array($cat) && isset($cat['name'])) {
        return (string) $cat['name'];
    }
    return '';
}
?>
<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=yes, interactive-widget=overlays-content">
    <title>Escritorio de Aplicaciones</title>
    <link rel="stylesheet" href="<?php echo grid_asset_url('assets/vendor/font-awesome/css/all.min.css'); ?>">
    <link rel="stylesheet" href="<?php echo grid_asset_url('assets/css/main.css'); ?>">
    <link rel="stylesheet" href="<?php echo grid_asset_url('assets/css/app-dialog.css'); ?>">
    <link rel="stylesheet" href="<?php echo grid_asset_url('assets/css/os-shell.css'); ?>">
    <link rel="stylesheet" href="<?php echo grid_asset_url('assets/css/tooltips.css'); ?>">
    <link rel="stylesheet" href="<?php echo grid_asset_url('modules/css/auth.css'); ?>">
    <?php if ($gridUserLoggedIn): ?>
    <?php require_once __DIR__ . '/includes/vendor_assets.php'; ?>
    <link rel="stylesheet" href="<?php echo grid_asset_url(ANTARA_VENDOR_CROPPER_CSS); ?>">
    <link rel="stylesheet" href="<?php echo grid_asset_url('assets/auth/image_editor.css'); ?>">
    <?php endif; ?>
    <?php
    require_once __DIR__ . '/includes/pwa_manifest.php';
    foreach (grid_pwa_head_meta_lines($settings, $baseUrl) as $_pwaLine) {
        echo $_pwaLine . "\n    ";
    }
    ?>
</head>
<body lang="<?php echo htmlspecialchars($settings['appLocale'] ?? 'es'); ?>" class="<?php echo htmlspecialchars($settings['selectedTheme'] ?? 'neumorphism'); ?> <?php echo (isMobile() && !($settings['mobileDesktopMode'] ?? false)) ? 'mobile-mode' : ''; ?> <?php echo (isMobile() && ($settings['mobileDesktopMode'] ?? false)) ? 'mobile-pc-mode' : ''; ?> taskbar-<?php echo htmlspecialchars($settings['taskbarPosition'] ?? 'bottom'); ?>">
    <svg aria-hidden="true" width="0" height="0" style="position:absolute;overflow:hidden">
        <defs>
            <filter id="ac3d-crystal-displace" x="-18%" y="-18%" width="136%" height="136%" color-interpolation-filters="sRGB">
                <feTurbulence type="fractalNoise" baseFrequency="0.013" numOctaves="3" seed="17" result="ac3dNoise"/>
                <feDisplacementMap id="ac3d-displace-map" in="SourceGraphic" in2="ac3dNoise" scale="28" xChannelSelector="R" yChannelSelector="G"/>
            </filter>
        </defs>
    </svg>
    <div id="ac3dDistortLayer" class="ac3d-distort-layer" hidden aria-hidden="true"></div>
    <?php
    $jsonFlags = JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT;
    echo "<script>let _phpSettings = " . json_encode($settings, $jsonFlags) . ";</script>\n";
    echo "<script>const BASE_URL = " . json_encode($baseUrl, $jsonFlags) . ";</script>\n";
    echo "<script>window.GRID_AUTH = " . json_encode([
        'apiUrl' => $gridAuthApiUrl,
        'loginUrl' => $gridLoginUrl,
        'adminUrl' => $gridAdminUsersUrl,
        'csrf' => $gridUserLoggedIn ? AntaraCsrf::token() : '',
    ], $jsonFlags) . ";</script>\n";
    if ($gridSessionUserId !== '') {
        echo "<script>window.GRID_SESSION_USER = " . json_encode([
            'id' => $gridSessionUserId,
            'profileImageRel' => $gridProf ?? '',
            'profileMediaFrame' => $gridSessionUserMediaFrame ?? null,
            'initial' => $gridSessionUserInitial,
        ], $jsonFlags) . ";</script>\n";
    }
    echo "<script>const IS_MOBILE = " . json_encode(isMobile(), $jsonFlags) . ";</script>\n";
    echo "<script>const GRID_SETTINGS_RECOVERY_ALERT = " . json_encode(!empty($gridSettingsRecoveryAlert), $jsonFlags) . ";</script>\n";
    echo "<script>const GRID_SETTINGS_PERSIST_FAILED = " . json_encode(!empty($gridSettingsPersistFailed), $jsonFlags) . ";</script>\n";
    // Zoom se maneja por-dispositivo en localStorage (ver main.js).
    echo "<script>const SAVED_IFRAME_ZOOM = " . json_encode(1, $jsonFlags) . ";</script>\n";
    require_once __DIR__ . '/includes/flexia_instance.php';
    antara_flexia_emit_instance_script();
    echo '<script src="' . grid_asset_url('assets/js/flexia_instance_guard.js') . '"></script>' . "\n";
    ?>

    <div class="topbar">
        <div class="filter-container">
            <select id="categoryFilter">
                <option value="">Todas las categorías</option>
                <?php 
                $categories = $settings['categories'] ?? ['General'];
                foreach ($categories as $cat):
                    $catName = grid_category_display_name($cat);
                    if ($catName !== 'General'):
                ?>
                        <option value="<?php echo htmlspecialchars($catName, ENT_QUOTES, 'UTF-8'); ?>"><?php echo htmlspecialchars($catName, ENT_QUOTES, 'UTF-8'); ?></option>
                <?php 
                    endif;
                endforeach; 
                ?>
            </select>
        </div>
        <div class="search-container">
            <input type="text" id="searchInput" placeholder="Buscar apps...">
            <span class="search-clear" id="searchClear" onclick="clearSearch()">&times;</span>
            <div class="zoom-controls">
                <button class="action-btn" id="zoomOutBtn" title="Alejar"><i class="fas fa-search-minus"></i></button>
                <button class="action-btn" id="zoomInBtn" title="Acercar"><i class="fas fa-search-plus"></i></button>
                <button class="action-btn" id="fullscreenBtn" title="Pantalla completa"><i class="fas fa-expand"></i></button>
            </div>
            <button class="action-btn" id="muteToggle" title="Activar/desactivar sonido" style="display: none;"><i class="fas fa-volume-mute"></i></button>
            <button class="action-btn" id="youtubeLinkBtn" title="Abrir video actual en YouTube" style="display: none;"><i class="fab fa-youtube"></i></button>
        </div>
    </div>

    <!-- Escritorio principal -->
    <div class="grid-container" id="appGrid"></div>
    
    <!-- Accesos directos del escritorio -->
    <div class="desktop-shortcuts" id="desktopShortcuts"></div>

    <!-- Menú inicio Web OS (overlay) -->
    <div class="windows-menu-backdrop" id="windowsMenuBackdrop"></div>
    <div id="windowsMenu" class="windows-menu os-shell" role="dialog" aria-modal="true" aria-label="Menú de aplicaciones">
        <div class="os-shell__head">
            <div class="os-shell__head-mobile-start">
                <div class="os-mobile-widget-chip" data-os-widget-key="spotify" title="Arrastrar para reordenar">
                    <button type="button" class="os-spotify-mobile-open" id="osSpotifyMobileOpen" aria-label="Spotify" title="Spotify">
                        <i class="fab fa-spotify" aria-hidden="true"></i><span class="os-spotify-mobile-open__label">Spotify</span>
                    </button>
                </div>
                <div class="os-mobile-widget-chip" data-os-widget-key="system" title="Arrastrar para reordenar">
                    <button type="button" class="os-system-mobile-open" id="osSystemMobileOpen" aria-label="Estado del sistema" title="Estado del sistema">
                        <i class="fas fa-server" aria-hidden="true"></i><span class="os-system-mobile-open__label">Sistema</span>
                    </button>
                </div>
                <div class="os-mobile-widget-chip" data-os-widget-key="weather" title="Arrastrar para reordenar">
                    <button type="button" class="os-weather-mobile-open" id="osWeatherMobileOpen" aria-label="Clima y ubicación" title="Clima y ubicación">
                        <i class="fas fa-cloud-sun" aria-hidden="true"></i><span class="os-weather-mobile-open__label">Clima</span>
                    </button>
                </div>
                <div class="os-mobile-widget-chip" data-os-widget-key="notes" title="Arrastrar para reordenar">
                    <button type="button" class="os-notes-mobile-open" id="osNotesMobileOpen" aria-label="Notas rápidas" title="Notas rápidas">
                        <i class="fas fa-sticky-note" aria-hidden="true"></i><span class="os-notes-mobile-open__label">Notas</span>
                    </button>
                </div>
                <div class="os-mobile-widget-chip" data-os-widget-key="media" title="Arrastrar para reordenar">
                    <button type="button" class="os-media-mobile-open" id="osMediaMobileOpen" aria-label="Galería de medios" title="Galería de medios">
                        <i class="fas fa-images" aria-hidden="true"></i><span class="os-media-mobile-open__label">Galería</span>
                    </button>
                </div>
            </div>
            <button type="button" class="windows-menu-close" id="windowsMenuClose" aria-label="Cerrar menú"><i class="fas fa-times"></i></button>
        </div>
        <div class="os-shell__body">
            <aside class="windows-menu-categories os-shell__sidebar" aria-label="Categorías">
                <?php if ($gridUserLoggedIn && $gridSessionUserDisplayName !== ''): ?>
                <div class="windows-menu-user" id="windowsMenuUser" aria-label="Usuario">
                    <div class="windows-menu-user__avatar-wrap" data-antara-profile-wrap="<?php echo htmlspecialchars($gridSessionUserId, ENT_QUOTES, 'UTF-8'); ?>">
                        <img class="windows-menu-user__avatar" data-antara-profile-img src="<?php echo $gridSessionUserAvatarSrc !== '' ? htmlspecialchars($gridSessionUserAvatarSrc, ENT_QUOTES, 'UTF-8') : ''; ?>" alt="" loading="lazy" decoding="async" <?php echo $gridSessionUserAvatarSrc === '' ? 'hidden' : ''; ?> />
                        <span class="windows-menu-user__avatar windows-menu-user__avatar--placeholder" data-antara-profile-ph aria-hidden="true" <?php echo $gridSessionUserAvatarSrc !== '' ? 'hidden' : ''; ?>><?php echo htmlspecialchars($gridSessionUserInitial, ENT_QUOTES, 'UTF-8'); ?></span>
                    </div>
                    <p class="windows-menu-user__name"><?php echo htmlspecialchars($gridSessionUserDisplayName, ENT_QUOTES, 'UTF-8'); ?></p>
                    <?php if ($gridSessionUserOrgLine !== ''): ?>
                    <p class="windows-menu-user__org"><?php echo htmlspecialchars($gridSessionUserOrgLine, ENT_QUOTES, 'UTF-8'); ?></p>
                    <?php endif; ?>
                </div>
                <?php endif; ?>
                <div class="windows-search-wrap">
                    <input type="text" id="windowsSearch" placeholder="Buscar en el menú..." autocomplete="off">
                    <span class="windows-search-clear" id="windowsSearchClear" title="Limpiar búsqueda" aria-label="Limpiar búsqueda">&times;</span>
                </div>
                <ul id="windowsCategoryList">
                    <li id="allCategoriesOption" data-category="all" tabindex="0">
                        <span class="os-cat-icon"><i class="fas fa-th-large" aria-hidden="true"></i></span>
                        <span class="os-cat-label">Todas las categorías</span>
                    </li>
                </ul>
            </aside>
            <main class="windows-menu-apps os-shell__main" id="windowsAppsContainer" aria-label="Aplicaciones"></main>
            <aside id="osWidgetPanel" class="os-shell__widgets" aria-label="Widgets">
                <section class="os-widget os-spotify-widget os-spotify-widget--desktop" id="osWidgetSpotify" aria-labelledby="osWidgetSpotifyTitle" data-os-widget-key="spotify">
                    <div class="os-widget-spotify__head" title="Clic para plegar; mantén pulsado y arrastra para reordenar">
                        <h3 class="os-widget__title" id="osWidgetSpotifyTitle">
                            <span class="os-widget__title-icon" aria-hidden="true"><i class="fab fa-spotify"></i></span>
                            <span class="os-widget__title-text">Spotify</span>
                        </h3>
                        <button type="button" class="os-widget-spotify-toggle" id="osWidgetSpotifyToggle" aria-expanded="true" aria-controls="osWidgetSpotifyBody" title="Minimizar sección">
                            <i class="fas fa-chevron-up" aria-hidden="true"></i>
                        </button>
                    </div>
                    <div id="osWidgetSpotifyBody" class="os-widget-spotify__body">
                        <div class="os-spotify-panel" id="osSpotifyPanel" aria-live="polite"></div>
                    </div>
                </section>
                <section class="os-widget" id="osWidgetSystem" aria-labelledby="osWidgetSystemTitle" data-os-widget-key="system">
                    <div class="os-widget-system__head" title="Clic para plegar; mantén pulsado y arrastra para reordenar">
                        <h3 class="os-widget__title" id="osWidgetSystemTitle">
                            <span class="os-widget__title-icon" aria-hidden="true"><i class="fas fa-server"></i></span>
                            <span class="os-widget__title-text">Estado del sistema</span>
                        </h3>
                        <button type="button" class="os-widget-system-toggle" id="osWidgetSystemToggle" aria-expanded="true" aria-controls="osWidgetSystemBody" title="Minimizar sección">
                            <i class="fas fa-chevron-up" aria-hidden="true"></i>
                        </button>
                    </div>
                    <div id="osWidgetSystemBody" class="os-widget-system__body">
                        <div id="osSystemEnvPill" class="os-env-pill"></div>
                        <div id="osSystemMeta" class="os-env-meta"></div>
                        <div id="osSystemMeters"></div>
                    </div>
                </section>
                <section class="os-widget os-weather-widget os-weather-widget--desktop" id="osWidgetWeather" aria-labelledby="osWidgetWeatherTitle" data-os-widget-key="weather">
                    <div class="os-widget-weather__head" title="Clic para plegar; mantén pulsado y arrastra para reordenar">
                        <h3 class="os-widget__title" id="osWidgetWeatherTitle">
                            <span class="os-widget__title-icon" aria-hidden="true"><i class="fas fa-cloud-sun"></i></span>
                            <span class="os-widget__title-text">Clima y ubicación</span>
                        </h3>
                        <button type="button" class="os-widget-weather-toggle" id="osWidgetWeatherToggle" aria-expanded="true" aria-controls="osWidgetWeatherBody" title="Minimizar sección">
                            <i class="fas fa-chevron-up" aria-hidden="true"></i>
                        </button>
                    </div>
                    <div id="osWidgetWeatherBody" class="os-widget-weather__body">
                        <div class="os-weather-panel" id="osWeatherPanel" aria-live="polite">
                            <div class="os-weather-map-head">
                                <div class="os-weather-map" id="osWeatherMap" hidden>
                                    <iframe id="osWeatherMapFrame" class="os-weather-map__frame" title="Mapa de ubicación" loading="lazy" referrerpolicy="no-referrer-when-downgrade"></iframe>
                                </div>
                                <a class="os-weather-map-link" id="osWeatherMapLink" href="#" target="_blank" rel="noopener noreferrer" hidden>Abrir en mapa</a>
                            </div>
                            <div class="os-weather-main">
                                <span class="os-weather-icon" id="osWeatherIcon" aria-hidden="true"><i class="fas fa-spinner fa-spin"></i></span>
                                <span class="os-weather-temp" id="osWeatherTemp">—</span>
                            </div>
                            <p class="os-weather-place" id="osWeatherPlace">Obteniendo ubicación…</p>
                            <dl class="os-weather-meta">
                                <div class="os-weather-meta__row">
                                    <dt>Humedad</dt>
                                    <dd id="osWeatherHumidity">—</dd>
                                </div>
                                <div class="os-weather-meta__row">
                                    <dt>Viento</dt>
                                    <dd id="osWeatherWind">—</dd>
                                </div>
                            </dl>
                        </div>
                        <p class="os-weather-updated" id="osWeatherUpdated" hidden></p>
                        <button type="button" class="os-weather-refresh" id="osWeatherRefresh" title="Actualizar clima">Actualizar</button>
                    </div>
                </section>
                <section class="os-widget os-notes-widget os-notes-widget--desktop" id="osWidgetNotes" aria-labelledby="osWidgetNotesTitle" data-os-widget-key="notes">
                    <div class="os-widget-notes__head" title="Clic para plegar; mantén pulsado y arrastra para reordenar">
                        <h3 class="os-widget__title" id="osWidgetNotesTitle">
                            <span class="os-widget__title-icon" aria-hidden="true"><i class="fas fa-sticky-note"></i></span>
                            <span class="os-widget__title-text">Notas rápidas</span>
                        </h3>
                        <button type="button" class="os-widget-notes-toggle" id="osWidgetNotesToggle" aria-expanded="true" aria-controls="osWidgetNotesBody" title="Minimizar sección">
                            <i class="fas fa-chevron-up" aria-hidden="true"></i>
                        </button>
                    </div>
                    <div id="osWidgetNotesBody" class="os-widget-notes__body">
                        <div class="os-notes-search-wrap">
                            <i class="fas fa-search os-notes-search-icon" aria-hidden="true"></i>
                            <input type="search" class="os-notes-search" id="osNotesSearch" placeholder="Buscar en notas…" autocomplete="off" aria-label="Buscar en notas">
                        </div>
                        <p class="os-notes-counter" id="osNotesCounter" aria-live="polite"></p>
                        <div class="os-notes-carousel-wrap">
                            <div class="os-notes-carousel" id="osNotesCarousel"></div>
                            <div class="os-notes-nav-row" role="group" aria-label="Navegación y notas">
                                <button type="button" class="os-notes-nav" id="osNotesPrev" aria-label="Nota anterior"><i class="fas fa-chevron-left" aria-hidden="true"></i></button>
                                <button type="button" class="os-notes-add" id="osNotesAdd">+ Añadir nota</button>
                                <button type="button" class="os-notes-nav" id="osNotesNext" aria-label="Nota siguiente"><i class="fas fa-chevron-right" aria-hidden="true"></i></button>
                            </div>
                        </div>
                    </div>
                </section>
                <section class="os-widget os-media-widget os-media-widget--desktop" id="osWidgetMedia" aria-labelledby="osWidgetMediaTitle" data-os-widget-key="media">
                    <div class="os-widget-media__head" title="Clic para plegar; mantén pulsado y arrastra para reordenar">
                        <h3 class="os-widget__title" id="osWidgetMediaTitle">
                            <span class="os-widget__title-icon" aria-hidden="true"><i class="fas fa-images"></i></span>
                            <span class="os-widget__title-text">Galería de medios</span>
                        </h3>
                        <button type="button" class="os-widget-media-toggle" id="osWidgetMediaToggle" aria-expanded="true" aria-controls="osWidgetMediaBody" title="Minimizar sección">
                            <i class="fas fa-chevron-up" aria-hidden="true"></i>
                        </button>
                    </div>
                    <div id="osWidgetMediaBody" class="os-widget-media__body">
                        <div class="os-media-slider-wrap">
                            <p class="os-notes-counter os-media-slider-counter" id="osMediaSliderCounter" aria-live="polite"></p>
                            <div class="os-media-slider-viewport" id="osMediaSliderViewport">
                                <div class="os-media-slider-main" id="osMediaSliderMain" role="img" aria-live="polite"></div>
                            </div>
                            <div class="os-media-slider-thumbs" id="osMediaSliderThumbs" role="tablist" aria-label="Miniaturas"></div>
                            <div class="os-notes-nav-row" role="group" aria-label="Navegación y galería">
                                <button type="button" class="os-notes-nav" id="osMediaSliderPrev" aria-label="Anterior" title="Anterior"><i class="fas fa-chevron-left" aria-hidden="true"></i></button>
                                <button type="button" class="os-notes-add" id="osMediaSliderAdd">+ Añadir</button>
                                <button type="button" class="os-notes-nav" id="osMediaSliderNext" aria-label="Siguiente" title="Siguiente"><i class="fas fa-chevron-right" aria-hidden="true"></i></button>
                                <button type="button" class="os-notes-nav os-media-slider-trash" id="osMediaSliderTrash" aria-label="Quitar medio" title="Quitar del slider"><i class="fas fa-trash" aria-hidden="true"></i></button>
                            </div>
                            <input type="file" id="osMediaSliderUpload" accept="image/*,video/*" multiple hidden>
                        </div>
                    </div>
                </section>
            </aside>
        </div>
        <div class="windows-menu-footer" id="windowsMenuFooter" role="region" aria-label="Sesión">
            <div class="windows-menu-footer__title">Sesión y administración</div>
            <a class="windows-menu-footer__link js-admin-users-window" id="windowsMenuAdminLink" href="<?php echo htmlspecialchars($gridAdminUsersUrl, ENT_QUOTES, 'UTF-8'); ?>">Panel de usuarios y acceso</a>
            <?php if ($gridUserLoggedIn): ?>
            <button type="button" class="windows-menu-footer__btn" id="windowsMenuLogoutBtn">Cerrar sesión</button>
            <?php endif; ?>
        </div>
    </div>

    <!-- Barra de tareas estilo Windows -->
    <div id="taskbar" class="taskbar">
        <button class="start-button" id="startButton">
            <?php if (!empty($settings['startButtonIcon'])): ?>
                <img src="<?php echo htmlspecialchars($settings['startButtonIcon']); ?>" alt="inicio">
            <?php else: ?>
                <i class="fas fa-th" aria-hidden="true"></i>
            <?php endif; ?>
        </button>
        <div class="recycle-bin" id="recycleBin" title="Papelera de reciclaje">
            <i class="fas fa-trash"></i>
        </div>
        <div class="windows-mosaic-btn" id="windowsMosaicBtn" title="Ventanas en mosaico" role="button" tabindex="0" aria-label="Ventanas en mosaico">
            <i class="fas fa-th-large"></i>
        </div>
        <div class="mobile-app-hub-btn" id="mobileAppHubBtn" title="Apps ancladas y abiertas" role="button" tabindex="0" aria-label="Apps ancladas y abiertas">
            <i class="fas fa-layer-group"></i>
            <span class="hub-count" id="mobileAppHubCount">0</span>
        </div>
        <div class="taskbar-strip" id="taskbarStrip">
            <div class="pinned-apps" id="pinnedAppsContainer"></div>
            <div class="taskbar-apps" id="taskbarAppsContainer"></div>
        </div>
        <div class="taskbar-spotify-quick taskbar-spotify-quick--extended" id="taskbarSpotifyQuick" hidden role="group" aria-label="Spotify en reproducción"></div>
        <div class="taskbar-tray-zone" id="taskbarTrayZone">
            <div class="taskbar-tray" id="taskbarTray" aria-label="Estado de red y energía">
                <span class="taskbar-tray__item" id="taskbarTrayNet" title="Red"><i class="fas fa-wifi" aria-hidden="true"></i></span>
                <span class="taskbar-tray__item" id="taskbarTrayBat" title="Batería" hidden><i class="fas fa-battery-full" aria-hidden="true"></i></span>
            </div>
        </div>
        <div class="clock" id="clock"></div>
    </div>
    <div class="mobile-app-hub-backdrop" id="mobileAppHubBackdrop" aria-hidden="true">
        <div class="mobile-app-hub-panel" id="mobileAppHubPanel">
            <button type="button" class="mobile-app-hub-close mobile-app-hub-close--corner" id="mobileAppHubCloseBtn" aria-label="Cerrar"><i class="fas fa-times" aria-hidden="true"></i></button>
            <div class="mobile-app-hub-head">
                <div class="mobile-app-hub-title">Aplicaciones</div>
            </div>
            <div class="mobile-app-hub-section mobile-app-hub-section--open" id="mobileAppHubSectionOpen">
                <h4>Abiertas</h4>
                <div class="mobile-app-hub-strip mobile-app-hub-strip--open">
                    <div class="mobile-app-hub-grid mobile-app-hub-grid--open" id="mobileAppHubOpen"></div>
                </div>
            </div>
            <div class="mobile-app-hub-section mobile-app-hub-section--pinned" id="mobileAppHubSectionPinned">
                <h4>Ancladas</h4>
                <div class="mobile-app-hub-strip mobile-app-hub-strip--pinned">
                    <div class="mobile-app-hub-grid mobile-app-hub-grid--pinned" id="mobileAppHubPinned"></div>
                </div>
            </div>
            <div class="mobile-app-hub-section mobile-app-hub-section--session" id="mobileAppHubSectionSession" role="region" aria-label="Sesión">
                <h4>Sesión</h4>
                <div class="mobile-app-hub-session-actions">
                    <a class="mobile-app-hub-session-link js-admin-users-window" id="mobileAppHubAdminLink" href="<?php echo htmlspecialchars($gridAdminUsersUrl, ENT_QUOTES, 'UTF-8'); ?>">Administración</a>
                    <?php if ($gridUserLoggedIn): ?>
                    <button type="button" class="mobile-app-hub-session-logout" id="mobileAppHubLogoutBtn">Cerrar sesión</button>
                    <?php endif; ?>
                </div>
            </div>
        </div>
    </div>
    
    <div class="spotify-quick-mobile-fab spotify-quick-mobile-fab--extended" id="spotifyQuickMobileFab" hidden role="group" aria-label="Spotify en reproducción"></div>
    <button class="add-app-btn" id="addAppFloatBtn" title="Agregar aplicación">+</button>
    <button class="config-btn" id="configBtn" title="Configuración">⚙️</button>
    
    <div class="f2-hint" id="f2Hint">F2: Editar seleccionada | Enter: Abrir | Supr: Eliminar | ESC: Cerrar | Flechas: Navegar</div>
    
    <div class="strip-menu-backdrop" id="stripMenuBackdrop"></div>
    
    <!-- Menú contextual de escritorio -->
    <div class="strip-menu" id="desktopStripMenu">
        <button type="button" class="strip-menu-link" id="desktopAddAppBtn"><i class="fas fa-plus"></i> Agregar aplicación</button>
        <button type="button" class="strip-menu-link" id="desktopNextWallpaperBtn" style="display: none;"><i class="fas fa-images"></i> <span id="desktopNextWallpaperLabel"></span></button>
        <button type="button" class="strip-menu-link" id="desktopConfigBtn"><i class="fas fa-cog"></i> Configuración</button>
        <a class="strip-menu-link js-admin-users-window" id="desktopStripAdminLink" href="<?php echo htmlspecialchars($gridAdminUsersUrl, ENT_QUOTES, 'UTF-8'); ?>"><i class="fas fa-user-shield"></i> Usuarios y acceso</a>
        <?php if ($gridUserLoggedIn): ?>
        <button type="button" class="strip-menu-link" id="desktopStripLogoutBtn"><i class="fas fa-sign-out-alt"></i> Cerrar sesión</button>
        <?php endif; ?>
    </div>

    <!-- Modal para agregar/editar app -->
    <div id="addAppModal" class="modal">
        <div class="modal-content">
            <span class="close" onclick="document.getElementById('addAppModal').style.display='none'; document.body.classList.remove('modal-open');">&times;</span>
            <h2 id="modalTitle">Agregar Aplicación</h2>
            <form id="appForm">
                <div id="iconGridPreview">
                    <img id="iconPreviewImg" src="">
                </div>
                <label for="appIcon">Icono:</label>
                <input type="file" id="appIcon" accept="image/*" onchange="previewIcon(this)">
                <label for="appTitle">Título:</label>
                <input type="text" id="appTitle" required>
                <div class="action-type-selector">
                    <label>
                        <input type="radio" name="actionType" value="link" checked> Enlace
                    </label>
                    <label>
                        <input type="radio" name="actionType" value="file"> Archivo
                    </label>
                </div>
                <div id="linkTargetSelector" style="margin-bottom: 12px;">
                    <label>Abrir enlace en:</label>
                    <div style="display: flex; gap: 15px; flex-wrap: wrap;">
                        <label>
                            <input type="radio" name="linkTarget" value="_self"> Misma pestaña
                        </label>
                        <label>
                            <input type="radio" name="linkTarget" value="_blank" checked> Nueva pestaña
                        </label>
                        <label>
                            <input type="radio" name="linkTarget" value="window"> Ventana (iframe modal)
                        </label>
                    </div>
                </div>
                <div id="linkInput">
                    <label for="appLink">Enlace:</label>
                    <div class="input-with-preview">
                        <input type="url" id="appLink" placeholder="https://ejemplo.com">
                        <button type="button" class="preview-btn" id="previewLinkBtn" onclick="previewCurrentLink()" style="display: none;">Ver</button>
                    </div>
                </div>
                <div id="fileInput" style="display: none;">
                    <label for="appFile">Archivo:</label>
                    <input type="file" id="appFile" accept=".pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.txt,.jpg,.jpeg,.png,.gif,.mp3,.mp4,.webm,.ogg,.wav">
                    <div id="currentFileInfo" class="file-info" style="display: none;">
                        <span id="currentFileName"></span>
                    </div>
                </div>
                <div class="category-form">
                    <div>
                        <input type="text" id="appCategoryFilter" placeholder="Filtrar categorías...">
                        <select id="appCategory" required>
                            <option value="General">General</option>
                            <?php 
                            $categories = $settings['categories'] ?? ['General'];
                            foreach ($categories as $cat): 
                                if ($cat !== 'General'): 
                            ?>
                                    <option value="<?php echo htmlspecialchars($cat); ?>"><?php echo htmlspecialchars($cat); ?></option>
                            <?php 
                                endif;
                            endforeach; 
                            ?>
                        </select>
                    </div>
                    <button type="button" id="addCategoryBtn">+</button>
                </div>
                <label for="appDescription">Descripción:</label>
                <textarea id="appDescription" rows="4"></textarea>
                
                <div style="margin: 10px 0;">
                    <label>
                        <input type="checkbox" id="showInGrid" checked> Mostrar en el escritorio
                    </label>
                </div>
                
                <div style="display: flex; justify-content: space-between; margin-top: 10px; gap: 10px; flex-wrap: wrap;">
                    <button type="button" id="cancelAddAppBtn">Cancelar</button>
                    <button type="submit">Guardar</button>
                </div>
                <button type="button" id="deleteBtn" style="display: none;"><i class="fas fa-trash-alt"></i> Desinstalar</button>
            </form>
        </div>
    </div>

    <div id="addCategoryModal" class="modal">
        <div class="modal-content">
            <span class="close" onclick="document.getElementById('addCategoryModal').style.display='none'; document.body.classList.remove('modal-open');">&times;</span>
            <h2>Agregar Categoría</h2>
            <form id="categoryForm">
                <label for="categoryName">Nombre de la categoría:</label>
                <input type="text" id="categoryName" required>
                <label for="categoryDescription">Descripción (opcional):</label>
                <textarea id="categoryDescription" rows="2" placeholder="Breve descripción"></textarea>
                <label for="categoryColor">Color de acento:</label>
                <input type="color" id="categoryColor" value="#38bdf8">
                <label for="categoryIconClass" style="display:block;margin-top:10px;">Icono</label>
                <select id="categoryIconClass" class="os-category-icon-select" aria-label="Icono de categoría"></select>
                <div class="os-cat-preview" id="categoryPreviewModal">
                    <div class="os-cat-preview__icon" id="categoryPreviewIcon"><i class="fas fa-folder"></i></div>
                    <div>
                        <strong id="categoryPreviewName">Vista previa</strong>
                        <div id="categoryPreviewDesc" style="font-size:12px;opacity:.75;margin-top:4px;"></div>
                    </div>
                </div>
                <div style="display: flex; justify-content: space-between; margin-top: 10px; gap: 10px;">
                    <button type="button" id="cancelCategoryBtn">Cancelar</button>
                    <button type="submit">Guardar Categoría</button>
                </div>
            </form>
        </div>
    </div>

    <div id="editCategoryIconModal" class="modal" style="display:none;">
        <div class="modal-content" style="max-width:380px;">
            <span class="close" id="editCategoryIconModalCloseX">&times;</span>
            <h3>Icono y color</h3>
            <p id="editCategoryIconModalCategoryLabel" style="margin:0 0 12px;font-size:14px;opacity:0.88;"></p>
            <label for="editCategoryIconSelect">Icono</label>
            <select id="editCategoryIconSelect" class="os-category-icon-select" aria-label="Icono de categoría"></select>
            <label for="editCategoryIconColor" style="display:block;margin-top:12px;">Color de acento</label>
            <input type="color" id="editCategoryIconColor" value="#38bdf8" style="width:100%;height:40px;border:none;padding:0;margin-top:4px;">
            <div style="display:flex;gap:10px;margin-top:16px;flex-wrap:wrap;justify-content:flex-end;">
                <button type="button" id="editCategoryIconCancelBtn">Cancelar</button>
                <button type="button" id="editCategoryIconSaveBtn">Guardar</button>
            </div>
        </div>
    </div>

    <div id="configModal" class="modal">
        <div class="modal-content">
            <span class="close" onclick="document.getElementById('configModal').style.display='none'; document.body.classList.remove('modal-open');">&times;</span>
            <h2>Configuración</h2>
            <div class="tabs">
                <div class="tab active" data-tab="background">Fondo</div>
                <div class="tab" data-tab="categories">Categorías</div>
                <div class="tab" data-tab="themes">Temas</div>
                <div class="tab" data-tab="desktopMode">Modo escritorio</div>
                <div class="tab" data-tab="security">Seguridad</div>
                <div class="tab" id="explorerStorageTabBtn" data-tab="explorerStorage">Caché y papelera</div>
                <div class="tab" id="explorerCustomizationTabBtn" data-tab="explorerCustomization">Explorador (avanzado)</div>
                <div class="tab" id="diskRecoveryTabBtn" data-tab="diskRecovery">Archivos en disco</div>
                <div class="tab" id="integrationsTabBtn" data-tab="integrations">Integraciones</div>
                <div class="tab" id="systemCreditsTabBtn" data-tab="systemCredits">Créditos y hosting</div>
            </div>
            <div id="backgroundTab" class="tab-content active">
                <form id="configForm" onsubmit="event.preventDefault();">
                    <div class="background-option">
                        <label>
                            <input type="radio" name="backgroundType" value="youtube" id="useYoutube" <?php echo ($settings['backgroundType'] ?? 'file') == 'youtube' ? 'checked' : ''; ?>> Video de YouTube
                        </label>
                        <label>
                            <input type="radio" name="backgroundType" value="file" id="useFile" <?php echo ($settings['backgroundType'] ?? 'file') == 'file' ? 'checked' : ''; ?>> Archivo local único
                        </label>
                        <label>
                            <input type="radio" name="backgroundType" value="images" id="useImages" <?php echo ($settings['backgroundType'] ?? 'file') == 'images' ? 'checked' : ''; ?>> Múltiples imágenes
                        </label>
                        <label>
                            <input type="radio" name="backgroundType" value="videos" id="useVideos" <?php echo ($settings['backgroundType'] ?? 'file') == 'videos' ? 'checked' : ''; ?>> Múltiples videos
                        </label>
                    </div>
                    
                    <!-- YouTube -->
                    <div id="youtubeInputGroup" class="input-group" style="display: <?php echo ($settings['backgroundType'] ?? 'file') == 'youtube' ? 'block' : 'none'; ?>;">
                        <div class="youtube-field">
                            <label for="youtubeLink">YouTube PC/Tablet (único):</label>
                            <input type="text" id="youtubeLink" placeholder="https://youtube.com/watch?v=... o /shorts/..." value="<?php echo htmlspecialchars($settings['youtubeBackground'] ?? ''); ?>">
                        </div>
                        <div class="youtube-field">
                            <label for="youtubeLinkMobile">YouTube Móvil (único):</label>
                            <input type="text" id="youtubeLinkMobile" placeholder="https://youtube.com/shorts/... o watch?v=..." value="<?php echo htmlspecialchars($settings['youtubeBackgroundMobile'] ?? ''); ?>">
                        </div>
                        
                        <div class="sub-tabs">
                            <button type="button" class="sub-tab active" data-subtab="single">Video único</button>
                            <button type="button" class="sub-tab" data-subtab="playlist">Lista de videos</button>
                        </div>
                        <div id="youtubeSingle" class="sub-tab-content active"></div>
                        <div id="youtubePlaylist" class="sub-tab-content">
                            <h4>Videos PC</h4>
                            <div id="youtubePlaylistPCContainer" class="media-list"></div>
                            <div class="add-url-form">
                                <input type="url" id="newYoutubePC" placeholder="watch, shorts o youtu.be">
                                <button type="button" onclick="addYoutubeUrl('pc')">Añadir</button>
                            </div>
                            <h4>Videos Móvil</h4>
                            <div id="youtubePlaylistMobileContainer" class="media-list"></div>
                            <div class="add-url-form">
                                <input type="url" id="newYoutubeMobile" placeholder="watch, shorts o youtu.be">
                                <button type="button" onclick="addYoutubeUrl('mobile')">Añadir</button>
                            </div>
                            <div>
                                <label>
                                    <input type="checkbox" id="usePlaylist" <?php echo !empty($settings['usePlaylist']) ? 'checked' : ''; ?>>
                                    Usar lista (el video único se agrega automáticamente)
                                </label>
                            </div>
                            <div class="play-mode-options">
                                <label><input type="radio" name="youtubePlayMode" value="random" <?php echo ($settings['youtubePlayMode'] ?? 'random') == 'random' ? 'checked' : ''; ?>> Aleatorio</label>
                                <label><input type="radio" name="youtubePlayMode" value="sequential" <?php echo ($settings['youtubePlayMode'] ?? 'random') == 'sequential' ? 'checked' : ''; ?>> Secuencial</label>
                            </div>
                        </div>
                    </div>
                    
                    <!-- Archivo local único -->
                    <div id="fileInputGroup" class="input-group" style="display: <?php echo ($settings['backgroundType'] ?? 'file') == 'file' ? 'flex' : 'none'; ?>;">
                        <label for="bgFile">Archivo local:</label>
                        <input type="file" id="bgFile" accept="image/*,video/*,.webp,.mp4,.webm,.ogg">
                        <div id="bgUploadProgress">
                            <div><div id="bgProgressBar"></div></div>
                            <div id="bgProgressLabel">0%</div>
                        </div>
                    </div>
                    
                    <!-- Múltiples imágenes -->
                    <div id="imagesInputGroup" class="input-group" style="display: <?php echo ($settings['backgroundType'] ?? 'file') == 'images' ? 'block' : 'none'; ?>;">
                        <label for="imageFiles">Seleccionar imágenes (múltiples):</label>
                        <input type="file" id="imageFiles" accept="image/*" multiple>
                        <div id="imageListContainer" class="media-list"></div>
                        <div>
                            <label><input type="checkbox" id="slideshowEnabled" <?php echo !empty($settings['slideshowEnabled']) ? 'checked' : ''; ?>> Pase de diapositivas</label>
                        </div>
                        <div id="slideshowIntervalGroup" style="margin-top:10px; display:<?php echo !empty($settings['slideshowEnabled']) ? 'block' : 'none'; ?>;">
                            <label for="slideshowInterval">Intervalo (seg):</label>
                            <input type="number" id="slideshowInterval" min="1" value="<?php echo $settings['slideshowInterval'] ?? 5; ?>">
                        </div>
                    </div>
                    
                    <!-- Múltiples videos -->
                    <div id="videosInputGroup" class="input-group" style="display: <?php echo ($settings['backgroundType'] ?? 'file') == 'videos' ? 'block' : 'none'; ?>;">
                        <label for="videoFiles">Seleccionar videos (múltiples):</label>
                        <input type="file" id="videoFiles" accept="video/*" multiple>
                        <div id="videoListContainer" class="media-list"></div>
                        <div class="play-mode-options">
                            <label><input type="radio" name="videoPlayMode" value="random" <?php echo ($settings['videoPlayMode'] ?? 'random') == 'random' ? 'checked' : ''; ?>> Aleatorio</label>
                            <label><input type="radio" name="videoPlayMode" value="sequential" <?php echo ($settings['videoPlayMode'] ?? 'random') == 'sequential' ? 'checked' : ''; ?>> Secuencial</label>
                            <label><input type="radio" name="videoPlayMode" value="loop" <?php echo ($settings['videoPlayMode'] ?? 'random') == 'loop' ? 'checked' : ''; ?>> Loop (un solo video)</label>
                        </div>
                    </div>
                    
                    <div id="previewContainer"></div>
                    <div id="youtubeFeedback"></div>
                    <label for="mosaicColor">Color de mosaicos:</label>
                    <input type="color" id="mosaicColor" value="<?php echo htmlspecialchars($settings['mosaicColor'] ?? '#000000'); ?>">
                    <div style="display: flex; gap: 10px; margin-top: 10px; flex-wrap: wrap;">
                        <button type="button" onclick="applyBackgroundSettings()" style="flex:1;">Aplicar</button>
                        <button type="button" id="resetBackgroundBtn" style="flex:1;">Restablecer</button>
                    </div>
                </form>
            </div>
            <div id="categoriesTab" class="tab-content">
                <h3>Gestionar Categorías</h3>
                <ul id="categoryList"></ul>
                <form id="addCategoryForm" onsubmit="event.preventDefault(); addNewCategory();">
                    <input type="text" id="newCategoryName" placeholder="Nueva categoría" required>
                    <textarea id="newCategoryDescription" rows="2" placeholder="Descripción (opcional)" style="width:100%;margin-top:8px;"></textarea>
                    <div style="display:flex;gap:12px;align-items:center;margin-top:8px;flex-wrap:wrap;">
                        <label for="newCategoryColor">Color</label>
                        <input type="color" id="newCategoryColor" value="#38bdf8">
                    </div>
                    <label for="newCategoryIconClass" style="display:block;margin-top:10px;">Icono</label>
                    <select id="newCategoryIconClass" class="os-category-icon-select" aria-label="Icono de categoría"></select>
                    <button type="submit" style="margin-top:8px;">Añadir</button>
                </form>
            </div>
            <div id="themesTab" class="tab-content">
                <h3>Seleccionar Tema</h3>
                <select id="themeSelect">
                    <option value="neumorphism" <?php echo ($settings['selectedTheme'] ?? 'neumorphism') == 'neumorphism' ? 'selected' : ''; ?>>Neumorfismo</option>
                    <option value="glassmorphism" <?php echo ($settings['selectedTheme'] ?? '') == 'glassmorphism' ? 'selected' : ''; ?>>Glassmorfismo</option>
                    <option value="skeuomorphism" <?php echo ($settings['selectedTheme'] ?? '') == 'skeuomorphism' ? 'selected' : ''; ?>>Skeuomorfismo</option>
                    <option value="flat" <?php echo ($settings['selectedTheme'] ?? '') == 'flat' ? 'selected' : ''; ?>>Diseño Plano</option>
                    <option value="material" <?php echo ($settings['selectedTheme'] ?? '') == 'material' ? 'selected' : ''; ?>>Diseño Material</option>
                    <option value="brutalism" <?php echo ($settings['selectedTheme'] ?? '') == 'brutalism' ? 'selected' : ''; ?>>Diseño Brutalista</option>
                    <option value="retro" <?php echo ($settings['selectedTheme'] ?? '') == 'retro' ? 'selected' : ''; ?>>Diseño Retro</option>
                    <option value="dark" <?php echo ($settings['selectedTheme'] ?? '') == 'dark' ? 'selected' : ''; ?>>Modo Oscuro</option>
                    <option value="minimalism" <?php echo ($settings['selectedTheme'] ?? '') == 'minimalism' ? 'selected' : ''; ?>>Diseño Minimalista</option>
                    <option value="morphing" <?php echo ($settings['selectedTheme'] ?? '') == 'morphing' ? 'selected' : ''; ?>>Diseño Morphing</option>
                    <option value="isometric" <?php echo ($settings['selectedTheme'] ?? '') == 'isometric' ? 'selected' : ''; ?>>Diseño Isométrico</option>
                    <option value="cyberpunk" <?php echo ($settings['selectedTheme'] ?? '') == 'cyberpunk' ? 'selected' : ''; ?>>Diseño Retro Futurista</option>
                    <option value="gradient" <?php echo ($settings['selectedTheme'] ?? '') == 'gradient' ? 'selected' : ''; ?>>Diseño en Gradientes</option>
                    <option value="glassgradient" <?php echo ($settings['selectedTheme'] ?? '') == 'glassgradient' ? 'selected' : ''; ?>>Aurora cristal (vidrio + gradiente)</option>
                    <option value="auroracrystal3d" <?php echo ($settings['selectedTheme'] ?? '') == 'auroracrystal3d' ? 'selected' : ''; ?>>Aurora cristal 3D (blur + deformación)</option>
                    <option value="card" <?php echo ($settings['selectedTheme'] ?? '') == 'card' ? 'selected' : ''; ?>>Diseño de Cartas</option>
                    <option value="typography" <?php echo ($settings['selectedTheme'] ?? '') == 'typography' ? 'selected' : ''; ?>>Diseño de Tipografía Audaz</option>
                </select>
                <br><br>
                <label for="fontSelect">Fuente:</label>
                <select id="fontSelect">
                    <option value="Arial, sans-serif" <?php echo ($settings['selectedFont'] ?? '') == 'Arial, sans-serif' ? 'selected' : ''; ?>>Arial</option>
                    <option value="Helvetica, sans-serif" <?php echo ($settings['selectedFont'] ?? '') == 'Helvetica, sans-serif' ? 'selected' : ''; ?>>Helvetica</option>
                    <option value="Georgia, serif" <?php echo ($settings['selectedFont'] ?? '') == 'Georgia, serif' ? 'selected' : ''; ?>>Georgia</option>
                    <option value="'Times New Roman', serif" <?php echo ($settings['selectedFont'] ?? '') == "'Times New Roman', serif" ? 'selected' : ''; ?>>Times New Roman</option>
                    <option value="'Courier New', monospace" <?php echo ($settings['selectedFont'] ?? '') == "'Courier New', monospace" ? 'selected' : ''; ?>>Courier New</option>
                    <option value="Verdana, sans-serif" <?php echo ($settings['selectedFont'] ?? '') == 'Verdana, sans-serif' ? 'selected' : ''; ?>>Verdana</option>
                    <option value="'Trebuchet MS', sans-serif" <?php echo ($settings['selectedFont'] ?? '') == "'Trebuchet MS', sans-serif" ? 'selected' : ''; ?>>Trebuchet MS</option>
                    <option value="Impact, sans-serif" <?php echo ($settings['selectedFont'] ?? '') == 'Impact, sans-serif' ? 'selected' : ''; ?>>Impact</option>
                    <option value="'Arial Black', sans-serif" <?php echo ($settings['selectedFont'] ?? '') == "'Arial Black', sans-serif" ? 'selected' : ''; ?>>Arial Black</option>
                    <option value="'Palatino Linotype', serif" <?php echo ($settings['selectedFont'] ?? '') == "'Palatino Linotype', serif" ? 'selected' : ''; ?>>Palatino Linotype</option>
                    <option value="'Lucida Sans Unicode', sans-serif" <?php echo ($settings['selectedFont'] ?? '') == "'Lucida Sans Unicode', sans-serif" ? 'selected' : ''; ?>>Lucida Sans Unicode</option>
                    <option value="Tahoma, sans-serif" <?php echo ($settings['selectedFont'] ?? '') == 'Tahoma, sans-serif' ? 'selected' : ''; ?>>Tahoma</option>
                    <option value="'Century Gothic', sans-serif" <?php echo ($settings['selectedFont'] ?? '') == "'Century Gothic', sans-serif" ? 'selected' : ''; ?>>Century Gothic</option>
                    <option value="'Lucida Console', monospace" <?php echo ($settings['selectedFont'] ?? '') == "'Lucida Console', monospace" ? 'selected' : ''; ?>>Lucida Console</option>
                    <option value="'Franklin Gothic Medium', sans-serif" <?php echo ($settings['selectedFont'] ?? '') == "'Franklin Gothic Medium', sans-serif" ? 'selected' : ''; ?>>Franklin Gothic Medium</option>
                </select>
                <br><br>
                <label for="fontSizeInput">Tamaño fuente (px):</label>
                <?php
                $fontSizeInputVal = preg_replace('/\D/', '', (string)($settings['selectedFontSize'] ?? '16'));
                if ($fontSizeInputVal === '') {
                    $fontSizeInputVal = '16';
                }
                ?>
                <input type="number" id="fontSizeInput" min="8" max="72" value="<?php echo htmlspecialchars($fontSizeInputVal); ?>">
                <br><br>
                <label for="textColorPicker">Color texto:</label>
                <input type="color" id="textColorPicker" value="<?php echo htmlspecialchars($settings['textColor'] ?? '#000000'); ?>">
                <br><br>
                <label for="gridTextColorPicker">Color texto del escritorio:</label>
                <input type="color" id="gridTextColorPicker" value="<?php echo htmlspecialchars($settings['gridTextColor'] ?? '#000000'); ?>">
                <br><br>
                <label for="appLocaleSelect">Idioma / Language / Langue:</label>
                <select id="appLocaleSelect">
                    <?php $al = $settings['appLocale'] ?? 'es'; ?>
                    <option value="es" <?php echo $al === 'es' ? 'selected' : ''; ?>>Español</option>
                    <option value="en" <?php echo $al === 'en' ? 'selected' : ''; ?>>English</option>
                    <option value="fr" <?php echo $al === 'fr' ? 'selected' : ''; ?>>Français</option>
                    <option value="de" <?php echo $al === 'de' ? 'selected' : ''; ?>>Deutsch</option>
                    <option value="pt" <?php echo $al === 'pt' ? 'selected' : ''; ?>>Português</option>
                    <option value="it" <?php echo $al === 'it' ? 'selected' : ''; ?>>Italiano</option>
                    <option value="ru" <?php echo $al === 'ru' ? 'selected' : ''; ?>>Русский</option>
                    <option value="zh" <?php echo $al === 'zh' ? 'selected' : ''; ?>>中文</option>
                    <option value="ja" <?php echo $al === 'ja' ? 'selected' : ''; ?>>日本語</option>
                    <option value="ko" <?php echo $al === 'ko' ? 'selected' : ''; ?>>한국어</option>
                    <option value="ar" <?php echo $al === 'ar' ? 'selected' : ''; ?>>العربية</option>
                    <option value="hi" <?php echo $al === 'hi' ? 'selected' : ''; ?>>हिन्दी</option>
                </select>
                <h4 class="theme-palette-title">Paleta del tema (por tema)</h4>
                <p class="theme-palette-hint">Elige un tema arriba y ajusta sus colores (incluidos los del explorador de archivos al final de cada tema); se guardan al pulsar Aplicar.</p>
                <div id="themePalettePanel" class="theme-palette-panel" aria-live="polite"></div>
                <div class="theme-actions">
                    <div id="themePreviewNotice" class="theme-preview-notice"><i class="fas fa-eye"></i> Vista previa</div>
                    <button type="button" id="restoreThemeBtn" class="restore-theme-btn" style="display:none;">Restaurar</button>
                    <button type="button" id="applyThemeBtn" class="apply-theme-btn">Aplicar</button>
                </div>
                <div style="display:flex; gap:10px; margin-top:10px; flex-wrap:wrap; align-items:center;">
                    <button type="button" id="openExplorerThemeModalBtn"><i class="fas fa-cog"></i> Personalizar explorador</button>
                </div>
            </div>
            <div id="desktopModeTab" class="tab-content">
                <h3>Modo de escritorio</h3>
                <p>Solo aplica en PC. En móvil siempre se usa el escritorio clásico a menos que actives la opción.</p>
                <label>
                    <input type="radio" name="desktopMode" value="grid" <?php echo ($settings['desktopMode'] ?? 'grid') == 'grid' ? 'checked' : ''; ?>> Escritorio clásico
                </label>
                <br>
                <label>
                    <input type="radio" name="desktopMode" value="windows" <?php echo ($settings['desktopMode'] ?? 'grid') == 'windows' ? 'checked' : ''; ?>> Modo Windows (con menú)
                </label>
                <br><br>
                <h4>Experiencia en móvil</h4>
                <label>
                    <input type="checkbox" id="mobileDesktopMode" <?php echo !empty($settings['mobileDesktopMode']) ? 'checked' : ''; ?>> Activar experiencia tipo PC en móvil (experimental)
                </label>
                <p style="font-size: 12px; color: gray;">Al activar esta opción, en dispositivos móviles se mostrará la barra de tareas (siempre inferior) y menú tipo Windows.</p>
                <br><br>
                <h4>Posición de la barra de tareas (solo PC)</h4>
                <label>
                    <input type="radio" name="taskbarPosition" value="bottom" <?php echo ($settings['taskbarPosition'] ?? 'bottom') == 'bottom' ? 'checked' : ''; ?>> Inferior
                </label>
                <label>
                    <input type="radio" name="taskbarPosition" value="top" <?php echo ($settings['taskbarPosition'] ?? 'bottom') == 'top' ? 'checked' : ''; ?>> Superior
                </label>
                <label>
                    <input type="radio" name="taskbarPosition" value="left" <?php echo ($settings['taskbarPosition'] ?? 'bottom') == 'left' ? 'checked' : ''; ?>> Izquierda
                </label>
                <label>
                    <input type="radio" name="taskbarPosition" value="right" <?php echo ($settings['taskbarPosition'] ?? 'bottom') == 'right' ? 'checked' : ''; ?>> Derecha
                </label>
                <br><br>
                <h4>Apariencia de iconos</h4>
                <label>
                    <input type="checkbox" id="showTypeBadge" <?php echo !empty($settings['showTypeBadge']) ? 'checked' : ''; ?>> Mostrar indicador de tipo
                </label>
                <br>
                <label>Modo de indicador:</label><br>
                <label>
                    <input type="radio" name="typeBadgeMode" value="icon" <?php echo ($settings['typeBadgeMode'] ?? 'icon') == 'icon' ? 'checked' : ''; ?>> Icono
                </label>
                <label>
                    <input type="radio" name="typeBadgeMode" value="text" <?php echo ($settings['typeBadgeMode'] ?? 'icon') == 'text' ? 'checked' : ''; ?>> Texto
                </label>
                <br><br>
                <h4>Icono del botón de inicio</h4>
                <div id="startButtonPreview">
                    <?php if (!empty($settings['startButtonIcon'])): ?>
                        <img src="<?php echo htmlspecialchars($settings['startButtonIcon']); ?>" alt="" class="config-start-icon-preview">
                    <?php endif; ?>
                </div>
                <input type="file" id="startButtonIcon" accept="image/*,image/gif,.gif">
                <button type="button" onclick="uploadStartIcon()">Subir icono</button>
                <button type="button" id="removeStartIconBtn" onclick="removeStartIcon()" <?php echo empty($settings['startButtonIcon']) ? 'style="display:none"' : ''; ?>>Eliminar icono</button>
                <br><br>
                <button type="button" onclick="applyDesktopMode()">Guardar configuración</button>
            </div>
            <div id="securityTab" class="tab-content">
                <h3>Seguridad</h3>

                <div class="config-admin-auth-hint" style="margin-bottom:1.25rem; padding:12px 14px; border-radius:10px; background:rgba(0,114,255,0.12); border:1px solid rgba(0,242,255,0.28);">
                    <h4 style="margin:0 0 8px 0; font-size:1rem;">Usuarios y acceso al escritorio</h4>
                    <p style="margin:0; color:rgba(232,244,255,0.88); font-size:0.9rem; line-height:1.5;">
                        La <strong>lista de usuarios</strong>, contraseñas, passkeys y la <strong>configuración de acceso</strong>
                        (login obligatorio, registro público, WebAuthn) están en el panel de administración, no en estas pestañas de apariencia.
                    </p>
                    <p style="margin:12px 0 0 0;">
                        <a href="<?php echo htmlspecialchars($gridAdminUsersUrl, ENT_QUOTES, 'UTF-8'); ?>" class="config-admin-auth-hint__link js-admin-users-window" style="display:inline-block; padding:10px 16px; border-radius:8px; text-decoration:none; font-weight:600; font-size:0.88rem; letter-spacing:0.04em; background:linear-gradient(95deg,#7000ff,#0072ff 55%,#00f2ff); color:#fff; box-shadow:0 0 16px rgba(0,114,255,0.35);">Abrir panel de usuarios y acceso</a>
                    </p>
                </div>

                <label>
                    <input type="checkbox" id="inspectBlock" <?php echo !empty($settings['inspectBlock']) ? 'checked' : ''; ?>> Bloquear inspección de código
                </label>
                <br><br>
                <button type="button" onclick="saveSecuritySettings()">Guardar</button>

                <hr style="border:none; border-top:1px solid rgba(255,255,255,0.18); margin:18px 0;">

                <h4 id="backupLogsTitle">Backup y logs</h4>
                <div style="display:flex; gap:10px; flex-wrap:wrap; align-items:center; margin-top:10px;">
                    <button type="button" id="exportBackupBtn">Descargar ZIP</button>
                    <input type="file" id="importBackupZipInput" accept=".zip" style="flex:1; min-width:220px;">
                    <button type="button" id="importBackupBtn">Subir ZIP</button>
                </div>

                <?php if (!empty($gridHasSuperAdminUser)): ?>
                <hr style="border:none; border-top:1px solid rgba(255,255,255,0.18); margin:18px 0;">

                <div class="flexia-format-reinstall">
                    <h4 id="formatReinstallTitle" class="flexia-format-reinstall__heading">Formateo y reinstalación</h4>
                    <p id="formatReinstallHint" class="flexia-format-reinstall__hint muted" style="font-size:0.88rem; line-height:1.45; color:rgba(232,244,255,0.82); margin:0 auto 14px; max-width:42rem;"></p>
                    <div class="flexia-format-reinstall__toggle-row">
                        <label class="flexia-ios-toggle-label" for="formatModeCheckbox">
                            <span id="formatModeLabel" class="flexia-ios-toggle-label__text"></span>
                            <span class="flexia-ios-toggle">
                                <input type="checkbox" id="formatModeCheckbox" class="flexia-ios-toggle__input">
                                <span class="flexia-ios-toggle__track"></span>
                            </span>
                        </label>
                    </div>
                    <div class="flexia-format-reinstall__btn-wrap">
                        <button type="button" id="formatLaunchInstallBtn" class="apply-theme-btn flexia-format-reinstall__btn" disabled></button>
                    </div>
                </div>
                <?php endif; ?>

                <div style="margin-top:18px;">
                    <h4 id="openingsHistoryTitle" style="margin-top:0;">Historial de aperturas</h4>
                    <div style="display:flex; gap:10px; flex-wrap:wrap; align-items:center; margin-top:10px;">
                        <button type="button" id="refreshLogBtn">Actualizar log</button>
                        <button type="button" id="clearLogBtn">Eliminar historial</button>
                        <button type="button" id="rotateLogBtn">Crear log nuevo</button>
                    </div>
                    <textarea id="activityLogBox" readonly style="width:100%; height:220px; margin-top:12px;"></textarea>
                </div>
            </div>
            <div id="explorerStorageTab" class="tab-content">
                <h3 id="explorerStorageTitle">Explorador: caché remota y papelera</h3>
                <div class="explorer-storage-charts explorer-storage-charts--top">
                    <div class="explorer-storage-chart-block explorer-storage-chart-block--pie">
                        <div id="explorerStoragePieLabel" class="explorer-storage-chart-label"></div>
                        <canvas id="explorerStoragePieCanvas" width="760" height="460"></canvas>
                        <div id="explorerStoragePieLegend" class="explorer-storage-legend explorer-storage-legend--chart"></div>
                    </div>
                    <div class="explorer-storage-chart-block explorer-storage-chart-block--disk">
                        <div id="explorerStorageBarLabel" class="explorer-storage-chart-label"></div>
                        <canvas id="explorerStorageDiskCanvas" width="760" height="190"></canvas>
                    </div>
                </div>
                <p id="explorerStorageEnv" class="explorer-storage-env" aria-live="polite"></p>
                <div id="explorerStorageStats" class="explorer-storage-stats"></div>
                <div class="explorer-storage-shortcuts" role="group" aria-labelledby="explorerStorageShortcutsHint">
                    <p id="explorerStorageShortcutsHint" class="explorer-storage-shortcuts-hint"></p>
                    <div class="explorer-storage-shortcuts-row">
                        <button type="button" id="explorerStorageOpenFilesBtn" class="explorer-storage-shortcut-btn"><i class="fas fa-folder-open" aria-hidden="true"></i> <span id="explorerStorageOpenFilesBtnLabel"></span></button>
                        <button type="button" id="explorerStorageOpenCacheBtn" class="explorer-storage-shortcut-btn"><i class="fas fa-database" aria-hidden="true"></i> <span id="explorerStorageOpenCacheBtnLabel"></span></button>
                        <button type="button" id="explorerStorageOpenTrashBtn" class="explorer-storage-shortcut-btn"><i class="fas fa-trash-restore" aria-hidden="true"></i> <span id="explorerStorageOpenTrashBtnLabel"></span></button>
                    </div>
                </div>
                <div class="explorer-storage-actions">
                    <button type="button" id="explorerEmptyRemoteCacheBtn"></button>
                    <button type="button" id="explorerEmptyTrashFromConfigBtn"></button>
                    <button type="button" id="explorerStorageRefreshBtn"></button>
                    <button type="button" id="gridClearAssetCacheBtn">Borrar caché de CSS/JS</button>
                </div>
            </div>
            <div id="explorerCustomizationTab" class="tab-content">
                <h3>Personalización del explorador</h3>
                <p class="explorer-cust-hint">Misma configuración que en el explorador (iconos, vista previa de carpetas, fondo multimedia del panel). Se guarda en <code>config/explorer_customization.json</code>.</p>
                <div class="explorer-cust-config-grid">
                    <label for="ecfgExplorerTheme">Tema lógico</label>
                    <select id="ecfgExplorerTheme">
                        <option value="default">Predeterminado</option>
                        <option value="glass-dark">Glass oscuro</option>
                        <option value="corporate">Empresarial</option>
                        <option value="minimal">Minimalista</option>
                    </select>
                    <label for="ecfgViewMode">Vista por defecto</label>
                    <select id="ecfgViewMode">
                        <option value="icons_sm">Iconos pequeños</option>
                        <option value="icons_md">Iconos medianos</option>
                        <option value="icons_lg">Iconos grandes</option>
                        <option value="icons_xl">Iconos extra grandes</option>
                        <option value="list">Lista</option>
                        <option value="details">Detalle</option>
                        <option value="tiles">Tarjetas</option>
                    </select>
                    <label for="ecfgIconSize">Tamaño icono (global)</label>
                    <select id="ecfgIconSize">
                        <option value="small">Pequeño</option>
                        <option value="medium">Mediano</option>
                        <option value="large">Grande</option>
                        <option value="xlarge">Extra grande</option>
                    </select>
                    <label for="ecfgDefaultFolderIcon">Icono carpeta (clase FA o <code>media/...</code>)</label>
                    <input type="text" id="ecfgDefaultFolderIcon" class="wide-input" placeholder="fas fa-folder">
                    <label for="ecfgDefaultPreview">Preview carpeta por defecto</label>
                    <select id="ecfgDefaultPreview">
                        <option value="none">Ninguno</option>
                        <option value="image">Imagen</option>
                        <option value="gif">GIF</option>
                        <option value="video">Vídeo</option>
                    </select>
                    <label><input type="checkbox" id="ecfgAllowGif" checked> Permitir GIF en previews</label>
                    <span></span>
                    <label><input type="checkbox" id="ecfgAllowVideo" checked> Permitir vídeo en previews</label>
                    <span></span>
                    <label for="ecfgChromeType">Fondo del panel del explorador</label>
                    <select id="ecfgChromeType">
                        <option value="none">Ninguno</option>
                        <option value="solid">Color sólido</option>
                        <option value="image">Imagen</option>
                        <option value="gif">GIF</option>
                        <option value="video">Vídeo (silenciado)</option>
                    </select>
                    <label for="ecfgChromeColor">Color (si sólido)</label>
                    <input type="color" id="ecfgChromeColor" value="#000000">
                    <label for="ecfgChromeSrc">Ruta <code>media/explorer/...</code></label>
                    <input type="text" id="ecfgChromeSrc" class="wide-input" placeholder="media/explorer/customization/backgrounds/...">
                    <span></span>
                    <div class="explorer-cust-upload-row">
                        <input type="file" id="ecfgChromeFile" accept="image/*,video/mp4,video/webm,.gif">
                        <button type="button" id="ecfgChromeUploadBtn">Subir y asignar</button>
                    </div>
                </div>
                <p class="explorer-cust-hint">La paleta de colores del explorador (barra, árbol, tarjetas) sigue en <strong>Temas</strong> → «Personalizar explorador».</p>
                <div id="explorerSharedSpacesConfig" class="explorer-shared-spaces-config" style="margin-top:1.25rem;padding-top:1rem;border-top:1px solid rgba(255,255,255,.12);">
                    <h4 style="margin:0 0 .5rem;">Espacios compartidos del explorador</h4>
                    <p class="explorer-cust-hint" style="margin:0 0 .75rem;">El <strong>espacio comunitario</strong> usa <code>media/explorer/files/</code> (visible para todos salvo exclusiones). Cada departamento tiene su carpeta en <code>media/explorer/departments/{id}/files/</code>.</p>
                    <div class="explorer-cust-config-grid">
                        <label><input type="checkbox" id="essCommunityEnabled" checked> Espacio comunitario activo (global)</label>
                        <span></span>
                        <label><input type="checkbox" id="essDepartmentsEnabled" checked> Carpetas por departamento activas (global)</label>
                        <span></span>
                        <label for="essCommunityHiddenUsers">Ocultar comunitario a usuarios (IDs, uno por línea)</label>
                        <textarea id="essCommunityHiddenUsers" class="wide-input" rows="3" placeholder="uuid-usuario-1"></textarea>
                        <label for="essDepartmentsHiddenUsers">Ocultar departamentos a usuarios (IDs, uno por línea)</label>
                        <textarea id="essDepartmentsHiddenUsers" class="wide-input" rows="3" placeholder="uuid-usuario-2"></textarea>
                    </div>
                    <button type="button" id="essSharedSpacesSaveBtn" class="apply-theme-btn" style="margin-top:.75rem;">Guardar espacios compartidos</button>
                    <p id="essSharedSpacesStatus" class="muted" style="min-height:1.2em;margin-top:.5rem;" aria-live="polite"></p>
                </div>
                <button type="button" id="explorerCustConfigSaveBtn" class="apply-theme-btn">Guardar personalización del explorador</button>
            </div>
            <div id="diskRecoveryTab" class="tab-content">
                <?php if (!empty($gridHasSuperAdminUser)): ?>
                <div class="flexia-format-reinstall flexia-format-reinstall--disk">
                    <h4 id="diskRecoveryFormatTitle" class="flexia-format-reinstall__heading"></h4>
                    <p id="diskRecoveryFormatHint" class="flexia-format-reinstall__hint muted" style="font-size:0.88rem;line-height:1.45;margin:0 auto 14px;max-width:42rem;"></p>
                    <div class="flexia-format-reinstall__toggle-row">
                        <label class="flexia-ios-toggle-label" for="diskRecoveryFormatModeCheckbox">
                            <span id="diskRecoveryFormatModeLabel" class="flexia-ios-toggle-label__text"></span>
                            <span class="flexia-ios-toggle">
                                <input type="checkbox" id="diskRecoveryFormatModeCheckbox" class="flexia-ios-toggle__input">
                                <span class="flexia-ios-toggle__track"></span>
                            </span>
                        </label>
                    </div>
                    <div class="flexia-format-reinstall__btn-wrap">
                        <button type="button" id="diskRecoveryFormatLaunchBtn" class="apply-theme-btn flexia-format-reinstall__btn" disabled></button>
                    </div>
                    <p class="muted flexia-format-reinstall__crosshint" style="font-size:0.82rem;margin:10px 0 0;line-height:1.4;" id="diskRecoveryFormatCrossHint"></p>
                </div>
                <?php endif; ?>
            </div>
            <div id="integrationsTab" class="tab-content">
                <h3>Integraciones con servicios externos</h3>
                <p class="muted" style="font-size:0.88rem;line-height:1.5;margin:0 0 18px;">
                    Conecta Flexia con servicios de terceros. Cada usuario inicia sesión en su propia cuenta desde el widget; aquí solo se configura la app a nivel de instalación.
                </p>

                <section class="integration-card" data-integration="spotify">
                    <header class="integration-card__head">
                        <span class="integration-card__icon" style="background:#1db954;"><i class="fab fa-spotify" aria-hidden="true"></i></span>
                        <div class="integration-card__title-wrap">
                            <h4 class="integration-card__title">Spotify</h4>
                            <p class="integration-card__subtitle muted">Reproductor integrado en el menú inicio (requiere Spotify Premium).</p>
                        </div>
                        <span class="integration-card__status integration-card__status--idle" id="spotifyIntegrationStatus" aria-live="polite">No configurada</span>
                    </header>

                    <div class="integration-card__setup" id="spotifyIntegrationSetup">
                        <div id="spotifyIntegrationSetupQuestion">
                            <p class="integration-card__setup-question">¿Ya tienes un Client ID de Spotify?</p>
                            <div class="integration-card__setup-choices" role="group" aria-label="¿Ya tienes Client ID?">
                                <button type="button" class="integration-card__setup-choice" id="spotifyHasClientIdYes">Sí, ya tengo uno</button>
                                <button type="button" class="integration-card__setup-choice integration-card__setup-choice--secondary" id="spotifyHasClientIdNo">No, necesito crear una app</button>
                            </div>
                        </div>

                        <div class="integration-card__setup-path" id="spotifySetupExistingPath" hidden>
                            <p class="integration-card__setup-path-lead">Abre el <a href="https://developer.spotify.com/dashboard" target="_blank" rel="noopener noreferrer">dashboard de desarrolladores de Spotify</a>, elige tu app y copia el <strong>Client ID</strong>.</p>
                            <p class="muted integration-card__note">Comprueba que la <strong>Redirect URI</strong> de tu app coincida exactamente con la URL que aparece más abajo.</p>
                            <div class="integration-card__setup-path-actions">
                                <a href="https://developer.spotify.com/dashboard" target="_blank" rel="noopener noreferrer" class="integration-card__setup-link-btn">Abrir dashboard de Spotify</a>
                                <button type="button" class="integration-card__setup-back" id="spotifySetupBackFromExisting">Volver</button>
                            </div>
                        </div>

                        <div class="integration-card__setup-path" id="spotifySetupNewPath" hidden>
                            <details class="integration-card__howto" id="spotifyIntegrationHowto" open>
                                <summary>Cómo conectar (3 pasos)</summary>
                                <ol class="integration-card__steps">
                                    <li>Abre el <a href="https://developer.spotify.com/dashboard" target="_blank" rel="noopener noreferrer">dashboard de desarrolladores de Spotify</a> e inicia sesión con tu cuenta.</li>
                                    <li>Pulsa <a href="https://developer.spotify.com/dashboard/create" target="_blank" rel="noopener noreferrer"><strong>Create app</strong></a> en el dashboard. Pon cualquier nombre y descripción. En <strong>Redirect URI</strong> pega <em>exactamente</em> la URL que aparece más abajo.</li>
                                    <li>Una vez creada, abre la app, copia el <strong>Client ID</strong> y pégalo aquí. Guarda y listo.</li>
                                </ol>
                                <p class="muted integration-card__note">No se pide Client Secret: Flexia usa OAuth con PKCE. Requiere <strong>Spotify Premium</strong>. Tras cambios de permisos (me gusta, añadir a playlist), pulsa <strong>Desconectar</strong> en el widget y <strong>Probar conexión</strong> de nuevo.</p>
                            </details>
                            <button type="button" class="integration-card__setup-back" id="spotifySetupBackFromNew">Volver</button>
                        </div>
                    </div>

                    <div class="integration-card__field">
                        <label for="spotifyClientId">Client ID</label>
                        <input type="text" id="spotifyClientId" autocomplete="off" spellcheck="false"
                               placeholder="Pega aquí el Client ID de tu app de Spotify">
                    </div>

                    <div class="integration-card__field">
                        <label for="spotifyRedirectUri">Redirect URI <span class="muted">(copia esto en el dashboard de Spotify)</span></label>
                        <div class="integration-card__copyrow">
                            <input type="text" id="spotifyRedirectUri" readonly>
                            <button type="button" class="integration-card__copy-btn" id="spotifyRedirectUriCopyBtn" title="Copiar al portapapeles">
                                <i class="fas fa-copy" aria-hidden="true"></i>
                            </button>
                        </div>
                    </div>

                    <div class="integration-card__actions">
                        <button type="button" class="apply-theme-btn" id="spotifyIntegrationSaveBtn">Guardar</button>
                        <button type="button" id="spotifyIntegrationTestBtn" disabled>Probar conexión</button>
                    </div>

                    <p class="integration-card__msg" id="spotifyIntegrationMsg" aria-live="polite"></p>
                </section>
            </div>
            <div id="systemCreditsTab" class="tab-content">
                <div class="system-credits">
                    <?php if ($gridSinapsysLogoRel !== ''): ?>
                    <div class="system-credits-logo-wrap">
                        <img class="system-credits-logo" src="<?php echo grid_asset_url($gridSinapsysLogoRel); ?>" alt="<?php echo htmlspecialchars($gridSinapsysLogoAlt, ENT_QUOTES, 'UTF-8'); ?>">
                    </div>
                    <?php endif; ?>
                    <div class="system-credits-license">
                        <h3 id="systemCreditsMainTitle"></h3>
                        <p id="systemCreditsOwnerLine" class="system-credits-owner"></p>
                        <?php if ($gridCreditsLogoIsCliente): ?>
                        <div class="system-credits-license-logo-row">
                            <div class="system-credits-license-logo-ring" data-antara-client-logo-wrap data-client-logo-frame="<?php echo htmlspecialchars(json_encode($gridClienteLogoMediaFrame, JSON_UNESCAPED_UNICODE), ENT_QUOTES, 'UTF-8'); ?>">
                                <img class="system-credits-license-logo" data-antara-profile-img src="<?php echo grid_asset_url($gridClienteLogoRel); ?>" alt="<?php echo htmlspecialchars($gridClienteLogoAlt, ENT_QUOTES, 'UTF-8'); ?>" <?php echo ($gridClienteLogoKind === 'video') ? 'hidden' : ''; ?>>
                                <span class="system-credits-license-logo-ph" data-antara-profile-ph aria-hidden="true" hidden>L</span>
                            </div>
                        </div>
                        <?php elseif ($gridSinapsysLogoRel === '' && $gridClienteLogoRel === ''): ?>
                        <p class="system-credits-logo-missing system-credits-logo-missing--license" id="systemCreditsLogoMissing"></p>
                        <?php endif; ?>
                    </div>
                    <div class="system-credits-notice">
                        <h4 id="systemCreditsPrivacyTitle"></h4>
                        <p id="systemCreditsPrivacyText"></p>
                    </div>
                    <h4 id="systemCreditsHostingHeading"></h4>
                    <p id="systemCreditsHostingStatus" class="system-credits-hosting-status" aria-live="polite"></p>
                    <dl id="systemCreditsHostingDl" class="system-credits-dl"></dl>
                    <p id="systemCreditsTrafficNote" class="muted system-credits-traffic-note" style="font-size:0.82rem;line-height:1.45;margin:8px 0 0;"></p>
                </div>
            </div>
        </div>
    </div>

    <!-- Renombrar archivo/carpeta (explorador) -->
    <div id="explorerRenameModal" class="modal explorer-rename-modal" aria-hidden="true">
        <div class="modal-content explorer-rename-modal-content">
            <button type="button" class="close explorer-rename-modal-close" id="explorerRenameModalCloseX" aria-label="Cerrar">&times;</button>
            <div class="explorer-rename-modal-head">
                <div class="explorer-rename-modal-icon-ring" aria-hidden="true">
                    <i id="explorerRenameModalIcon" class="fas fa-file-alt"></i>
                </div>
                <div class="explorer-rename-modal-titles">
                    <h2 id="explorerRenameModalTitle">Renombrar</h2>
                    <p id="explorerRenameModalHint" class="explorer-rename-modal-hint"></p>
                </div>
            </div>
            <div class="explorer-rename-modal-body">
                <div id="explorerRenameFolderBlock" class="explorer-rename-block" style="display:none;">
                    <label id="explorerRenameFolderLabel" for="explorerRenameFolderInput"></label>
                    <input type="text" id="explorerRenameFolderInput" class="explorer-rename-input explorer-rename-input-full" autocomplete="off" spellcheck="false">
                </div>
                <div id="explorerRenameFileBlock" class="explorer-rename-block">
                    <label id="explorerRenameBaseLabel" for="explorerRenameBase"></label>
                    <div class="explorer-rename-split" role="group" aria-labelledby="explorerRenameBaseLabel">
                        <input type="text" id="explorerRenameBase" class="explorer-rename-input explorer-rename-input-base" autocomplete="off" spellcheck="false">
                        <span class="explorer-rename-dot" aria-hidden="true">.</span>
                        <input type="text" id="explorerRenameExt" class="explorer-rename-input explorer-rename-input-ext" autocomplete="off" spellcheck="false" maxlength="32">
                    </div>
                    <p id="explorerRenameExtHelp" class="explorer-rename-help"></p>
                </div>
                <div class="explorer-rename-preview">
                    <span id="explorerRenamePreviewLabel"></span>
                    <code id="explorerRenamePreviewValue" dir="ltr"></code>
                </div>
            </div>
            <div class="explorer-rename-modal-actions">
                <button type="button" id="explorerRenameModalCancel" class="explorer-rename-btn explorer-rename-btn-cancel"></button>
                <button type="button" id="explorerRenameModalSave" class="explorer-rename-btn explorer-rename-btn-save"></button>
            </div>
        </div>
    </div>

    <!-- Conflicto de nombre (copiar/pegar / remoto) -->
    <div id="explorerConflictModal" class="modal explorer-conflict-modal" aria-hidden="true">
        <div class="modal-content explorer-conflict-modal-content">
            <button type="button" class="close explorer-conflict-modal-close" id="explorerConflictModalCloseX" aria-label="Cerrar">&times;</button>
            <div class="explorer-conflict-modal-head">
                <div class="explorer-conflict-modal-icon-ring" aria-hidden="true">
                    <i class="fas fa-clone"></i>
                </div>
                <div class="explorer-conflict-modal-titles">
                    <h2 id="explorerConflictModalTitle"></h2>
                    <p id="explorerConflictModalMessage" class="explorer-conflict-modal-message"></p>
                </div>
            </div>
            <div class="explorer-conflict-modal-body">
                <label class="explorer-conflict-apply-all">
                    <input type="checkbox" id="explorerConflictApplyAll" />
                    <span id="explorerConflictApplyAllLabel"></span>
                </label>
                <div id="explorerConflictModalMain" class="explorer-conflict-modal-actions">
                    <button type="button" id="explorerConflictBtnReplace" class="explorer-conflict-btn explorer-conflict-btn-danger"></button>
                    <button type="button" id="explorerConflictBtnMerge" class="explorer-conflict-btn explorer-conflict-btn-primary" style="display:none;"></button>
                    <button type="button" id="explorerConflictBtnRename" class="explorer-conflict-btn explorer-conflict-btn-primary"></button>
                    <button type="button" id="explorerConflictBtnSkip" class="explorer-conflict-btn"></button>
                    <button type="button" id="explorerConflictBtnCancel" class="explorer-conflict-btn explorer-conflict-btn-muted"></button>
                </div>
                <div id="explorerConflictModalRename" class="explorer-conflict-rename-panel" style="display:none;">
                    <label id="explorerConflictNewNameLabel" for="explorerConflictNewNameInput"></label>
                    <input type="text" id="explorerConflictNewNameInput" class="explorer-rename-input explorer-rename-input-full" autocomplete="off" spellcheck="false" />
                    <div class="explorer-conflict-rename-actions">
                        <button type="button" id="explorerConflictBtnRenameBack" class="explorer-conflict-btn explorer-conflict-btn-muted"></button>
                        <button type="button" id="explorerConflictBtnRenameOk" class="explorer-conflict-btn explorer-conflict-btn-primary"></button>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <!-- Carpeta creada: entrar o permanecer -->
    <div id="explorerNewFolderChoiceModal" class="modal explorer-conflict-modal" aria-hidden="true">
        <div class="modal-content explorer-conflict-modal-content">
            <button type="button" class="close explorer-conflict-modal-close" id="explorerNewFolderChoiceModalCloseX" aria-label="Cerrar">&times;</button>
            <div class="explorer-conflict-modal-head">
                <div class="explorer-conflict-modal-icon-ring" aria-hidden="true">
                    <i class="fas fa-folder-plus"></i>
                </div>
                <div class="explorer-conflict-modal-titles">
                    <h2 id="explorerNewFolderChoiceModalTitle"></h2>
                    <p id="explorerNewFolderChoiceModalMessage" class="explorer-conflict-modal-message"></p>
                </div>
            </div>
            <div class="explorer-conflict-modal-body">
                <div class="explorer-conflict-modal-actions">
                    <button type="button" id="explorerNewFolderChoiceBtnEnter" class="explorer-conflict-btn explorer-conflict-btn-primary"></button>
                    <button type="button" id="explorerNewFolderChoiceBtnStay" class="explorer-conflict-btn explorer-conflict-btn-muted"></button>
                </div>
            </div>
        </div>
    </div>

    <!-- Personalización visual del explorador -->
    <div id="explorerThemeModal" class="modal explorer-theme-modal" aria-hidden="true">
        <div class="modal-content explorer-theme-modal-content">
            <button type="button" class="close explorer-theme-modal-close" id="explorerThemeModalCloseX" aria-label="Cerrar">&times;</button>
            <h2 id="explorerThemeModalTitle">Personalizar explorador</h2>
            <p class="explorer-theme-modal-hint">Cambia colores y transparencia del explorador (panel, árbol, barra y tarjetas). Se aplican al instante y se guardan al pulsar Guardar.</p>

            <div class="explorer-theme-grid">
                <div class="explorer-theme-field">
                    <label for="explorerThemeMainBg">Fondo principal</label>
                    <div class="explorer-theme-row">
                        <input type="color" id="explorerThemeMainBg">
                        <input type="range" id="explorerThemeMainAlpha" min="0" max="100" value="100">
                        <span id="explorerThemeMainAlphaLabel" class="explorer-theme-alpha-label">100%</span>
                    </div>
                </div>
                <div class="explorer-theme-field">
                    <label for="explorerThemeSidebarBg">Panel lateral</label>
                    <div class="explorer-theme-row">
                        <input type="color" id="explorerThemeSidebarBg">
                        <input type="range" id="explorerThemeSidebarAlpha" min="0" max="100" value="100">
                        <span id="explorerThemeSidebarAlphaLabel" class="explorer-theme-alpha-label">100%</span>
                    </div>
                </div>
                <div class="explorer-theme-field">
                    <label for="explorerThemeTreeBg">Árbol (fondo)</label>
                    <div class="explorer-theme-row">
                        <input type="color" id="explorerThemeTreeBg">
                        <input type="range" id="explorerThemeTreeAlpha" min="0" max="100" value="100">
                        <span id="explorerThemeTreeAlphaLabel" class="explorer-theme-alpha-label">100%</span>
                    </div>
                </div>
                <div class="explorer-theme-field">
                    <label for="explorerThemeToolbarBg">Barra (fondo)</label>
                    <div class="explorer-theme-row">
                        <input type="color" id="explorerThemeToolbarBg">
                        <input type="range" id="explorerThemeToolbarAlpha" min="0" max="100" value="100">
                        <span id="explorerThemeToolbarAlphaLabel" class="explorer-theme-alpha-label">100%</span>
                    </div>
                </div>
                <div class="explorer-theme-field">
                    <label for="explorerThemeText">Texto principal</label>
                    <input type="color" id="explorerThemeText">
                </div>
                <div class="explorer-theme-field">
                    <label for="explorerThemeMuted">Texto secundario</label>
                    <input type="color" id="explorerThemeMuted">
                </div>
                <div class="explorer-theme-field">
                    <label for="explorerThemeAccent">Acento</label>
                    <input type="color" id="explorerThemeAccent">
                </div>
                <div class="explorer-theme-field">
                    <label for="explorerThemeBorder">Bordes</label>
                    <input type="color" id="explorerThemeBorder">
                </div>
                <div class="explorer-theme-field">
                    <label for="explorerThemeInputBg">Búsqueda / inputs</label>
                    <div class="explorer-theme-row">
                        <input type="color" id="explorerThemeInputBg">
                        <input type="range" id="explorerThemeInputAlpha" min="0" max="100" value="100">
                        <span id="explorerThemeInputAlphaLabel" class="explorer-theme-alpha-label">100%</span>
                    </div>
                </div>
                <div class="explorer-theme-field">
                    <label for="explorerThemeItemBg">Tarjetas de ítems</label>
                    <div class="explorer-theme-row">
                        <input type="color" id="explorerThemeItemBg">
                        <input type="range" id="explorerThemeItemAlpha" min="0" max="100" value="100">
                        <span id="explorerThemeItemAlphaLabel" class="explorer-theme-alpha-label">100%</span>
                    </div>
                </div>
            </div>

            <div class="explorer-theme-actions">
                <button type="button" id="explorerThemeResetBtn">Restaurar</button>
                <button type="button" id="explorerThemeSaveBtn">Guardar</button>
            </div>
        </div>
    </div>

    <div id="explorerToolbarCustModal" class="modal explorer-toolbar-cust-modal" style="display:none;" aria-hidden="true" role="dialog">
        <div class="modal-content explorer-toolbar-cust-modal-content">
            <button type="button" class="close" id="explorerToolbarCustModalClose" aria-label="Cerrar">&times;</button>
            <h2>Fondo del explorador</h2>
            <p class="explorer-cust-hint">Imagen, GIF o vídeo detrás del contenido (sin sonido). Opcional: abre la paleta de colores para barra y tarjetas.</p>
            <label for="explorerToolbarCustChromeType">Tipo</label>
            <select id="explorerToolbarCustChromeType">
                <option value="none">Ninguno</option>
                <option value="solid">Color sólido</option>
                <option value="image">Imagen</option>
                <option value="gif">GIF</option>
                <option value="video">Vídeo</option>
            </select>
            <label for="explorerToolbarCustChromeColor">Color</label>
            <input type="color" id="explorerToolbarCustChromeColor" value="#0f172a">
            <label for="explorerToolbarCustChromeSrc">Ruta guardada</label>
            <input type="text" id="explorerToolbarCustChromeSrc" class="wide-input" placeholder="media/explorer/customization/...">
            <div class="explorer-cust-upload-row" style="margin-top:10px;">
                <input type="file" id="explorerToolbarCustFile" accept="image/*,video/mp4,video/webm,.gif">
                <button type="button" id="explorerToolbarCustUploadBtn">Subir</button>
            </div>
            <div style="display:flex;gap:10px;margin-top:14px;flex-wrap:wrap;">
                <button type="button" id="explorerToolbarCustOpenPaletteBtn" class="explorer-rename-btn explorer-rename-btn-cancel">Paleta de colores…</button>
                <button type="button" id="explorerToolbarCustModalSave" class="explorer-rename-btn explorer-rename-btn-save">Guardar fondo</button>
                <button type="button" id="explorerToolbarCustModalCancel" class="explorer-rename-btn explorer-rename-btn-cancel">Cerrar</button>
            </div>
        </div>
    </div>

    <div id="explorerCustModal" class="modal explorer-cust-modal" style="display:none;" aria-hidden="true" role="dialog">
        <div class="modal-content explorer-cust-modal-content">
            <button type="button" class="close" id="explorerCustModalClose" aria-label="Cerrar">&times;</button>
            <h2 id="explorerCustModalTitle">Personalizar</h2>
            <div class="explorer-cust-modal-grid">
                <label for="explorerCustIcon">Icono (clase FA o <code>media/...</code>)</label>
                <input type="text" id="explorerCustIcon" class="wide-input" placeholder="fas fa-folder">
                <label for="explorerCustColor">Color acento</label>
                <input type="color" id="explorerCustColor" value="#000000">
                <div id="explorerCustRowPreview" class="explorer-cust-span2">
                    <label for="explorerCustPreviewType">Vista previa carpeta</label>
                    <select id="explorerCustPreviewType">
                        <option value="none">Ninguna</option>
                        <option value="image">Imagen</option>
                        <option value="gif">GIF</option>
                        <option value="video">Vídeo</option>
                    </select>
                    <label for="explorerCustPreviewSrc">Ruta preview</label>
                    <input type="text" id="explorerCustPreviewSrc" class="wide-input" placeholder="media/explorer/customization/previews/...">
                    <input type="file" id="explorerCustPreviewFile" accept="image/*,video/mp4,video/webm,.gif" style="margin-top:6px;">
                    <button type="button" id="explorerCustUploadPreviewBtn" class="explorer-rename-btn explorer-rename-btn-cancel" style="margin-top:6px;">Subir preview</button>
                </div>
                <div id="explorerCustRowBg" class="explorer-cust-span2">
                    <label for="explorerCustBg">Fondo de esta carpeta (ruta)</label>
                    <input type="text" id="explorerCustBg" class="wide-input" placeholder="media/explorer/customization/backgrounds/...">
                </div>
                <div id="explorerCustRowViewMode" class="explorer-cust-span2">
                    <label for="explorerCustViewMode">Vista preferida (opcional)</label>
                    <input type="text" id="explorerCustViewMode" class="wide-input" placeholder="icons_md, list, details…">
                </div>
                <div id="explorerCustRowCard" class="explorer-cust-span2" style="display:none;">
                    <label for="explorerCustCardStyle">Estilo tarjeta (archivo)</label>
                    <input type="text" id="explorerCustCardStyle" class="wide-input" placeholder="compact, outline…">
                </div>
            </div>
            <div style="display:flex;gap:10px;margin-top:14px;flex-wrap:wrap;">
                <button type="button" id="explorerCustModalSave" class="explorer-rename-btn explorer-rename-btn-save">Guardar</button>
                <button type="button" id="explorerCustModalReset" class="explorer-rename-btn explorer-rename-btn-cancel">Restaurar</button>
                <button type="button" id="explorerCustModalCancel" class="explorer-rename-btn explorer-rename-btn-cancel">Cancelar</button>
            </div>
        </div>
    </div>

    <!-- Modal para la papelera -->
    <div id="recycleBinModal" class="modal">
        <div class="modal-content recycle-bin-modal-content">
            <span class="close" onclick="document.getElementById('recycleBinModal').style.display='none'; document.body.classList.remove('modal-open');">&times;</span>
            <div class="recycle-bin-modal-header">
                <h2 id="recycleBinModalTitle">Papelera de reciclaje</h2>
                <button type="button" id="emptyTrashBtnTop" class="empty-trash-btn" onclick="emptyTrash()">Vaciar papelera</button>
            </div>
            <div id="trashItems" class="trash-items"></div>
            <div class="recycle-bin-modal-footer">
                <button type="button" id="emptyTrashBtn" class="empty-trash-btn" onclick="emptyTrash()">Vaciar papelera</button>
            </div>
        </div>
    </div>

    <!-- Modal de mosaico de ventanas -->
    <div id="windowsMosaicModal" class="modal">
        <div class="modal-content windows-mosaic-modal-content">
            <span class="close" onclick="document.getElementById('windowsMosaicModal').style.display='none'; document.body.classList.remove('modal-open');">&times;</span>
            <h2 id="windowsMosaicTitle">Ventanas abiertas</h2>
            <div id="windowsMosaicGrid" class="windows-mosaic-grid" aria-live="polite"></div>
            <div class="windows-mosaic-actions">
                <button id="closeAllWindowsBtn" type="button">Cerrar todo</button>
            </div>
        </div>
    </div>

    <!-- Notas rápidas (móvil / pantalla estrecha): modal independiente -->
    <div id="osNotesMobileModal" class="modal os-notes-mobile-modal" role="dialog" aria-modal="true" aria-labelledby="osNotesMobileTitle" style="display: none;">
        <div class="modal-content os-notes-mobile-modal__content">
            <div class="os-mobile-modal__head">
                <h2 id="osNotesMobileTitle" class="os-mobile-modal__title">
                    <span class="os-widget__title-icon" aria-hidden="true"><i class="fas fa-sticky-note"></i></span>
                    <span class="os-widget__title-text">Notas rápidas</span>
                </h2>
                <button type="button" class="close os-mobile-modal__close" id="osNotesMobileClose" title="Cerrar" aria-label="Cerrar"><span aria-hidden="true">&times;</span></button>
            </div>
            <div class="os-notes-search-wrap">
                <i class="fas fa-search os-notes-search-icon" aria-hidden="true"></i>
                <input type="search" class="os-notes-search" id="osNotesSearchMobile" placeholder="Buscar en notas…" autocomplete="off" aria-label="Buscar en notas">
            </div>
            <p class="os-notes-counter" id="osNotesCounterMobile" aria-live="polite"></p>
            <div class="os-notes-carousel-wrap">
                <div class="os-notes-carousel" id="osNotesCarouselMobile"></div>
                <div class="os-notes-nav-row" role="group" aria-label="Navegación y notas">
                    <button type="button" class="os-notes-nav" id="osNotesPrevMobile" aria-label="Nota anterior"><i class="fas fa-chevron-left" aria-hidden="true"></i></button>
                    <button type="button" class="os-notes-add" id="osNotesAddMobile">+ Añadir nota</button>
                    <button type="button" class="os-notes-nav" id="osNotesNextMobile" aria-label="Nota siguiente"><i class="fas fa-chevron-right" aria-hidden="true"></i></button>
                </div>
            </div>
        </div>
    </div>

    <!-- Clima y ubicación (móvil): mismo patrón que notas -->
    <div id="osWeatherMobileModal" class="modal os-weather-mobile-modal" role="dialog" aria-modal="true" aria-labelledby="osWeatherMobileTitle" style="display: none;">
        <div class="modal-content os-weather-mobile-modal__content">
            <div class="os-mobile-modal__head">
                <h2 id="osWeatherMobileTitle" class="os-mobile-modal__title">
                    <span class="os-widget__title-icon" aria-hidden="true"><i class="fas fa-cloud-sun"></i></span>
                    <span class="os-widget__title-text">Clima y ubicación</span>
                </h2>
                <button type="button" class="close os-mobile-modal__close" id="osWeatherMobileClose" title="Cerrar" aria-label="Cerrar"><span aria-hidden="true">&times;</span></button>
            </div>
            <div class="os-weather-panel" id="osWeatherPanelMobile" aria-live="polite">
                <div class="os-weather-map-head">
                    <div class="os-weather-map" id="osWeatherMapMobile" hidden>
                        <iframe id="osWeatherMapFrameMobile" class="os-weather-map__frame" title="Mapa de ubicación" loading="lazy" referrerpolicy="no-referrer-when-downgrade"></iframe>
                    </div>
                    <a class="os-weather-map-link" id="osWeatherMapLinkMobile" href="#" target="_blank" rel="noopener noreferrer" hidden>Abrir en mapa</a>
                </div>
                <div class="os-weather-main">
                    <span class="os-weather-icon" id="osWeatherIconMobile" aria-hidden="true"><i class="fas fa-spinner fa-spin"></i></span>
                    <span class="os-weather-temp" id="osWeatherTempMobile">—</span>
                </div>
                <p class="os-weather-place" id="osWeatherPlaceMobile">Obteniendo ubicación…</p>
                <dl class="os-weather-meta">
                    <div class="os-weather-meta__row">
                        <dt>Humedad</dt>
                        <dd id="osWeatherHumidityMobile">—</dd>
                    </div>
                    <div class="os-weather-meta__row">
                        <dt>Viento</dt>
                        <dd id="osWeatherWindMobile">—</dd>
                    </div>
                </dl>
            </div>
            <p class="os-weather-updated" id="osWeatherUpdatedMobile" hidden></p>
            <button type="button" class="os-weather-refresh" id="osWeatherRefreshMobile" title="Actualizar clima">Actualizar</button>
        </div>
    </div>

    <!-- Estado del sistema (móvil): mismo patrón que notas -->
    <div id="osSystemMobileModal" class="modal os-system-mobile-modal" role="dialog" aria-modal="true" aria-labelledby="osSystemMobileTitle" style="display: none;">
        <div class="modal-content os-system-mobile-modal__content">
            <div class="os-mobile-modal__head">
                <h2 id="osSystemMobileTitle" class="os-mobile-modal__title">
                    <span class="os-widget__title-icon" aria-hidden="true"><i class="fas fa-server"></i></span>
                    <span class="os-widget__title-text">Estado del sistema</span>
                </h2>
                <button type="button" class="close os-mobile-modal__close" id="osSystemMobileClose" title="Cerrar" aria-label="Cerrar"><span aria-hidden="true">&times;</span></button>
            </div>
            <div class="os-widget os-widget--system-modal" id="osWidgetSystemMobile">
                <div id="osSystemEnvPillMobile" class="os-env-pill"></div>
                <div id="osSystemMetaMobile" class="os-env-meta"></div>
                <div id="osSystemMetersMobile"></div>
            </div>
        </div>
    </div>

    <!-- Galería de medios (móvil): mismo patrón que notas -->
    <div id="osMediaMobileModal" class="modal os-media-mobile-modal" role="dialog" aria-modal="true" aria-labelledby="osMediaMobileTitle" style="display: none;">
        <div class="modal-content os-media-mobile-modal__content">
            <div class="os-mobile-modal__head">
                <h2 id="osMediaMobileTitle" class="os-mobile-modal__title">
                    <span class="os-widget__title-icon" aria-hidden="true"><i class="fas fa-images"></i></span>
                    <span class="os-widget__title-text">Galería de medios</span>
                </h2>
                <button type="button" class="close os-mobile-modal__close" id="osMediaMobileClose" title="Cerrar" aria-label="Cerrar"><span aria-hidden="true">&times;</span></button>
            </div>
            <div class="os-media-slider-wrap">
                <p class="os-notes-counter os-media-slider-counter" id="osMediaSliderCounterMobile" aria-live="polite"></p>
                <div class="os-media-slider-viewport" id="osMediaSliderViewportMobile">
                    <div class="os-media-slider-main" id="osMediaSliderMainMobile" role="img" aria-live="polite"></div>
                </div>
                <div class="os-media-slider-thumbs" id="osMediaSliderThumbsMobile" role="tablist" aria-label="Miniaturas"></div>
                <div class="os-notes-nav-row" role="group" aria-label="Navegación y galería">
                    <button type="button" class="os-notes-nav" id="osMediaSliderPrevMobile" aria-label="Anterior" title="Anterior"><i class="fas fa-chevron-left" aria-hidden="true"></i></button>
                    <button type="button" class="os-notes-add" id="osMediaSliderAddMobile">+ Añadir</button>
                    <button type="button" class="os-notes-nav" id="osMediaSliderNextMobile" aria-label="Siguiente" title="Siguiente"><i class="fas fa-chevron-right" aria-hidden="true"></i></button>
                    <button type="button" class="os-notes-nav os-media-slider-trash" id="osMediaSliderTrashMobile" aria-label="Quitar medio" title="Quitar del slider"><i class="fas fa-trash" aria-hidden="true"></i></button>
                </div>
                <input type="file" id="osMediaSliderUploadMobile" accept="image/*,video/*" multiple hidden>
            </div>
        </div>
    </div>

    <!-- Spotify (móvil): mismo patrón que clima/notas -->
    <div id="osSpotifyMobileModal" class="modal os-spotify-mobile-modal" role="dialog" aria-modal="true" aria-labelledby="osSpotifyMobileTitle" style="display: none;">
        <div class="modal-content os-spotify-mobile-modal__content">
            <div class="os-mobile-modal__head">
                <h2 id="osSpotifyMobileTitle" class="os-mobile-modal__title">
                    <span class="os-widget__title-icon" aria-hidden="true"><i class="fab fa-spotify"></i></span>
                    <span class="os-widget__title-text">Spotify</span>
                </h2>
                <button type="button" class="close os-mobile-modal__close" id="osSpotifyMobileClose" title="Cerrar" aria-label="Cerrar"><span aria-hidden="true">&times;</span></button>
            </div>
            <div class="os-spotify-panel" id="osSpotifyPanelMobile" aria-live="polite"></div>
        </div>
    </div>

    <div class="strip-menu" id="stripMenu">
        <button type="button" class="strip-menu-link" id="editAppBtn"><i class="fas fa-edit"></i> Editar App</button>
        <button type="button" class="strip-menu-link" id="toggleGridBtn" style="display: none;"><i class="fas fa-eye"></i> Añadir/Quitar del escritorio</button>
        <button type="button" class="strip-menu-link" id="pinToTaskbarBtn" style="display: none;"><i class="fas fa-star"></i> Anclar a la barra de tareas</button>
        <button type="button" class="strip-menu-link delete-app-btn" id="deleteAppBtn"><i class="fas fa-trash"></i> Desinstalar</button>
        <button type="button" class="strip-menu-link" id="folderOpenBtn" style="display: none;"><i class="fas fa-folder-open"></i> Abrir carpeta</button>
        <button type="button" class="strip-menu-link" id="folderInfoBtn" style="display: none;"><i class="fas fa-info-circle"></i> Información</button>
        <button type="button" class="strip-menu-link" id="folderRenameBtn" style="display: none;"><i class="fas fa-i-cursor"></i> Renombrar carpeta</button>
        <button type="button" class="strip-menu-link" id="folderColorBtn" style="display: none;"><i class="fas fa-palette"></i> Cambiar color</button>
        <button type="button" class="strip-menu-link" id="folderDeleteBtn" style="display: none;"><i class="fas fa-trash"></i> Eliminar carpeta</button>
    </div>

    <div id="launcherFolderModal" class="modal launcher-folder-modal" style="display:none" aria-modal="true" role="dialog" aria-labelledby="launcherFolderModalTitle">
        <div class="modal-content launcher-folder-modal-content">
            <span class="close" id="launcherFolderModalClose" title="Cerrar">&times;</span>
            <h2 id="launcherFolderModalTitle">Carpeta</h2>
            <div id="launcherFolderGrid" class="grid-container launcher-folder-inner-grid"></div>
        </div>
    </div>

    <div id="previewModal" class="modal">
        <div class="window-frame" id="previewWindowFrame">
            <div class="window-titlebar" id="previewWindowTitlebar">
                <div class="window-title">
                    <img id="previewModalIcon" src="" alt="preview" onerror="this.style.display='none'">
                    <span id="previewModalTitle">Previsualización</span>
                </div>
                <div class="window-controls">
                    <button class="maximize-btn" id="previewMaximizeBtn" title="Maximizar/Restaurar"><i class="fas fa-window-restore"></i></button>
                    <button class="zoom-in-btn" id="previewZoomInBtn" title="Acercar imagen"><i class="fas fa-search-plus"></i></button>
                    <button class="zoom-out-btn" id="previewZoomOutBtn" title="Alejar imagen"><i class="fas fa-search-minus"></i></button>
                    <button class="zoom-reset-btn" id="previewZoomResetBtn" title="Restaurar zoom"><i class="fas fa-undo"></i></button>
                    <button class="external-btn" id="previewExternalBtn" title="Abrir en nueva pestaña"><i class="fas fa-external-link-alt"></i></button>
                    <button class="close-btn" id="previewCloseBtn" title="Cerrar"><i class="fas fa-times"></i></button>
                </div>
            </div>
            <div class="window-content">
                <div id="previewContent"></div>
                <div id="previewActions">
                    <button id="shareBtn">Compartir</button>
                    <button id="downloadBtn">Descargar</button>
                    <button id="previewPrintBtn" type="button" style="display:none;">Imprimir</button>
                </div>
            </div>
            <div class="window-resize-handle" id="previewResizeHandle"></div>
        </div>
    </div>

    <script type="text/javascript" src="<?php echo grid_asset_url('assets/js/clock-format.js'); ?>"></script>
    <script type="text/javascript" src="<?php echo grid_asset_url('assets/js/app-dialog.js'); ?>"></script>
    <script type="text/javascript" src="<?php echo grid_asset_url('assets/auth/auth_tab_sync.js'); ?>"></script>
    <?php if ($gridUserLoggedIn): ?>
    <script>
    window.ANTARA_AUTH_TAB_SYNC_CFG = {
      listenLogin: false,
      listenLogout: true,
      loginUrl: <?php echo json_encode($gridLoginUrl, JSON_UNESCAPED_SLASHES); ?>
    };
    if (window.AntaraAuthTabSync && typeof window.AntaraAuthTabSync.init === 'function') {
      window.AntaraAuthTabSync.init(window.ANTARA_AUTH_TAB_SYNC_CFG);
    }
    </script>
    <?php endif; ?>
    <script type="text/javascript" src="<?php echo grid_asset_url('assets/auth/profile_image_sync.js'); ?>"></script>
    <script>
    (function () {
      var u = window.GRID_SESSION_USER;
      var sync = window.AntaraProfileImageSync;
      if (u && u.id && sync && typeof sync.init === 'function') {
        sync.init({
          sessionUserId: u.id,
          projectBase: typeof BASE_URL === 'string' ? BASE_URL : '',
          initial: u.initial || '?',
        });
        if (u.profileImageRel) {
          sync.apply(u.id, u.profileImageRel, {
            projectBase: typeof BASE_URL === 'string' ? BASE_URL : '',
            initial: u.initial || '?',
            mediaFrame: u.profileMediaFrame || null,
            skipPublish: true,
          });
        }
      }
    })();
    </script>
    <?php if ($gridUserLoggedIn): ?>
    <?php require __DIR__ . '/admin/_image_editor_dialog.php'; ?>
    <dialog class="profile-self-dialog" id="profile-self-dialog" aria-labelledby="profile-self-title">
      <div class="profile-self-dialog__inner">
        <h3 id="profile-self-title">Tu foto de perfil</h3>
        <p class="profile-self-dialog__lead">Imagen con recorte, o GIF/vídeo con encuadre circular.</p>
        <input type="file" id="profile-self-file" accept="image/png,image/jpeg,image/webp,image/gif,video/mp4,video/webm,video/ogg" hidden />
        <input type="hidden" id="profile-self-source" value="original" />
        <div class="profile-self-dialog__actions">
          <button type="button" class="btn btn-secondary-wizardish" id="profile-self-gallery">Galería</button>
          <button type="button" class="btn btn-secondary-wizardish" id="profile-self-camera">Cámara</button>
        </div>
        <p class="feedback" id="profile-self-feedback" role="status"></p>
        <div class="profile-self-dialog__foot">
          <button type="button" class="btn btn-text-wizardish" id="profile-self-clear">Quitar</button>
          <button type="button" class="btn btn-ghost" id="profile-self-cancel">Cancelar</button>
          <button type="button" class="btn btn-primary" id="profile-self-save">Guardar</button>
        </div>
      </div>
    </dialog>
    <script type="text/javascript" src="<?php echo grid_asset_url(ANTARA_VENDOR_CROPPER_JS); ?>" defer></script>
    <script type="text/javascript" src="<?php echo grid_asset_url('assets/auth/avatar_square_crop.js'); ?>" defer></script>
    <script type="text/javascript" src="<?php echo grid_asset_url('assets/js/install_image_picker.js'); ?>" defer></script>
    <script type="text/javascript" src="<?php echo grid_asset_url('assets/auth/profile_self.js'); ?>" defer></script>
    <?php endif; ?>
    <script type="text/javascript" src="<?php echo grid_asset_url('assets/js/launcher/layout-model.js'); ?>"></script>
    <script type="text/javascript" src="<?php echo grid_asset_url('assets/js/launcher/folder-service.js'); ?>"></script>
    <script type="text/javascript" src="<?php echo grid_asset_url('assets/js/launcher/grid-drag.js'); ?>"></script>
    <script type="text/javascript" src="<?php echo grid_asset_url('assets/js/launcher/pointer-interaction.js'); ?>"></script>
    <script type="text/javascript" src="<?php echo grid_asset_url('assets/js/launcher/context-target.js'); ?>"></script>
    <script type="text/javascript" src="<?php echo grid_asset_url('assets/js/launcher/grid-integration.js'); ?>"></script>
    <script type="text/javascript" src="<?php echo grid_asset_url('assets/js/explorer-customization.js'); ?>"></script>
    <script type="text/javascript" src="<?php echo grid_asset_url('assets/js/explorer-shared-spaces.js'); ?>"></script>
    <script type="text/javascript" src="<?php echo grid_asset_url('assets/js/youtube-url.js'); ?>"></script>
    <script type="text/javascript" src="<?php echo grid_asset_url('assets/js/tooltips.js'); ?>"></script>
    <script type="text/javascript" src="<?php echo grid_asset_url('assets/js/main.js'); ?>"></script>
    <script type="text/javascript" src="<?php echo grid_asset_url('assets/js/os-shell.js'); ?>"></script>
</body>
</html>

