<?php
/**
 * Plugin Name: Fe Adulta — Homepage
 * Description: Portada con selección editorial via ACF.
 * Version: 1.4
 */

// ── Flush rewrite rules una sola vez tras cambios de configuración ────────
add_action('init', function() {
    if (get_option('fea_flush_needed')) {
        flush_rewrite_rules(true);
        delete_option('fea_flush_needed');
    }
});

// ── Portada multilingüe: sirve la página traducida en el home de cada idioma ──
// Polylang free no traduce page_on_front automáticamente.
// Este hook intercepta el query del home de idioma y carga la página correcta.
add_action('pre_get_posts', function(WP_Query $query) {
    if (!$query->is_main_query()) return;
    if (!function_exists('pll_current_language') || !function_exists('pll_get_post')) return;

    // Solo actuar cuando WP cree que está en el home/front page
    if (!$query->is_home() && !$query->is_front_page()) return;

    $lang = pll_current_language();
    if (!$lang || $lang === 'es') return;

    $translated_id = pll_get_post(26542, $lang);
    if (!$translated_id) return;

    // Forzar carga de la página traducida como si fuera la portada estática
    $query->set('page_id', $translated_id);
    $query->set('post_type', 'page');
    $query->is_home       = false;
    $query->is_front_page = true;
    $query->is_singular   = true;
    $query->is_page       = true;
}, 1);

// ── Multimedia: 30 entradas por página en su archivo (#63) ──
add_action('pre_get_posts', function(WP_Query $query) {
    if (is_admin() || !$query->is_main_query()) return;
    if ($query->is_category('multimedia')) {
        $query->set('posts_per_page', 30);
    }
});

// ── Tablón de anuncios (#97): ocultar del listado los anuncios de más de 12 meses ──
// Ventana móvil, no destructiva: los posts siguen publicados/accesibles por URL; solo
// se excluyen del archivo de la categoría para que el Tablón no parezca desactualizado.
// Cubre las 5 categorías Polylang (ES + en/fr/it/pt).
add_action('pre_get_posts', function(WP_Query $query) {
    if (is_admin() || !$query->is_main_query()) return;
    if ($query->is_category(['tablon-de-anuncios', 'tablon-de-anuncios-en',
        'tablon-de-anuncios-fr', 'tablon-de-anuncios-it', 'tablon-de-anuncios-pt'])) {
        $query->set('date_query', [[
            'after'     => date('Y-m-d', strtotime('-12 months')),
            'inclusive' => true,
        ]]);
    }
});

// ── Normalizar títulos (TODO CAPS legacy → frase) en todo el front #63 #73 ──
// Mismo criterio que la portada (fea_title). Cubre listados/búsqueda/home, el artículo
// (single), el <title>/SEO y los feeds. El wp-admin se deja SIN tocar para que el editor
// vea el dato real (en mayúsculas) al editar.
add_filter('the_title', function($title, $post_id = 0) {
    if (is_admin() || !function_exists('fea_title')) return $title;
    // Artículo individual: solo el título del propio post mostrado (no widgets/relacionados).
    if (is_singular()) {
        if (in_the_loop() || (int) $post_id === (int) get_queried_object_id()) {
            return fea_title($title);
        }
        return $title;
    }
    // Listados (incluida portada) dentro del loop.
    if ((is_archive() || is_search() || is_home() || is_front_page()) && in_the_loop()) {
        return fea_title($title);
    }
    return $title;
}, 20, 2);

// <title> del documento — núcleo WP (cuando Yoast no lo sobrescribe).
add_filter('document_title_parts', function($parts) {
    if (is_admin() || !function_exists('fea_title')) return $parts;
    if (!empty($parts['title'])) $parts['title'] = fea_title($parts['title']);
    return $parts;
}, 20);

// <title>/OG/Twitter vía Yoast: normaliza solo la porción del título del post.
$fea_seo_title = function($title) {
    if (is_admin() || !is_singular() || !function_exists('fea_title')) return $title;
    $raw = get_post_field('post_title', get_queried_object_id());
    if ($raw && mb_strpos($title, $raw) !== false) {
        $title = str_replace($raw, fea_title($raw), $title);
    }
    return $title;
};
add_filter('wpseo_title', $fea_seo_title, 20);
add_filter('wpseo_opengraph_title', $fea_seo_title, 20);
add_filter('wpseo_twitter_title', $fea_seo_title, 20);

// Título del item en feeds RSS.
add_filter('the_title_rss', function($title) {
    return function_exists('fea_title') ? fea_title($title) : $title;
}, 20);

// Asegura que option_page_on_front devuelve la página traducida al idioma actual
// (necesario para is_front_page() y para que el template FSE lo reconozca)
add_filter('option_page_on_front', function($value) {
    if (!function_exists('pll_current_language') || !function_exists('pll_get_post')) return $value;
    static $running = false;
    if ($running) return $value; // evitar recursión
    $running = true;
    $lang = pll_current_language();
    $running = false;
    if (!$lang || $lang === 'es') return $value;
    $translated = pll_get_post((int) $value, $lang);
    return $translated ?: $value;
});

// ── Traducir links de categoría "Esta semana" / "Semana pasada" al idioma actual ─
// Las categorías traducidas EN/FR/IT/PT dan 404 (bug WP_Tax_Query AND 0=1 con Polylang).
// Solución: redirigir ES cat URL → post traducido directamente (no a la categoría).
// Para "Otras semanas" (cartas-de-otras-semanas, count=729): se deja como está.
add_action('wp_footer', function() {
    if (!function_exists('pll_current_language') || !function_exists('pll_get_post')) return;
    $lang = pll_current_language();
    if (!$lang || $lang === 'es') return;

    global $wpdb;
    $map = [];

    // Categorías de carta única (count=1) → redirigir al post traducido
    $single_carta_cats = [
        'cartasemana'       => 6,
        'carta-semana-pasada' => 22,
    ];
    foreach ($single_carta_cats as $slug => $es_cat_id) {
        // term_taxonomy_id de la categoría ES (bypassa Polylang)
        $tt_id = (int) $wpdb->get_var($wpdb->prepare(
            "SELECT term_taxonomy_id FROM {$wpdb->term_taxonomy}
             WHERE term_id=%d AND taxonomy='category'", $es_cat_id
        ));
        if (!$tt_id) continue;
        // Post ES más reciente en esa categoría
        $es_post_id = (int) $wpdb->get_var($wpdb->prepare(
            "SELECT p.ID FROM {$wpdb->posts} p
             JOIN {$wpdb->term_relationships} tr ON p.ID=tr.object_id
             WHERE tr.term_taxonomy_id=%d AND p.post_status='publish'
             ORDER BY p.post_date DESC LIMIT 1", $tt_id
        ));
        if (!$es_post_id) continue;
        // Post traducido
        $trans_id = pll_get_post($es_post_id, $lang);
        if (!$trans_id) continue;
        $trans_url = get_permalink($trans_id);
        if ($trans_url) {
            $map[home_url('/category/' . $slug . '/')] = $trans_url;
        }
    }
    if (empty($map)) return;
    ?>
    <script>
    (function(){
        var map = <?php echo json_encode($map); ?>;
        document.querySelectorAll('a[href]').forEach(function(a){
            var clean = a.href.split('?')[0];
            if (map[clean]) a.href = map[clean];
        });
    })();
    </script>
    <?php
}, 25);

// ── Foto de perfil de autor via ACF (campo en perfil de usuario) ──────────
add_action('acf/init', function() {
    if (!function_exists('acf_add_local_field_group')) return;
    acf_add_local_field_group([
        'key'    => 'group_user_foto_perfil',
        'title'  => 'Foto de perfil',
        'fields' => [[
            'key'           => 'field_user_foto_perfil',
            'label'         => 'Foto',
            'name'          => 'foto_perfil',
            'type'          => 'image',
            'instructions'  => 'Sube una foto cuadrada del autor (mínimo 100×100px).',
            'return_format' => 'url',
            'preview_size'  => 'thumbnail',
            'upload_folder' => 'autores',
        ]],
        'location' => [[
            ['param' => 'user_form', 'operator' => '==', 'value' => 'all'],
        ]],
    ]);
});

// Usar la foto del autor en lugar del Gravatar cuando existe
// Lee el attachment ID guardado en el meta 'foto_perfil' (campo ACF)
add_filter('get_avatar_url', function($url, $id_or_email, $args) {
    $user_id = null;
    if (is_numeric($id_or_email))            $user_id = (int) $id_or_email;
    elseif ($id_or_email instanceof WP_User) $user_id = $id_or_email->ID;
    elseif (is_string($id_or_email)) {
        $user = get_user_by('email', $id_or_email);
        if ($user) $user_id = $user->ID;
    }
    if (!$user_id) return $url;
    $attach_id = get_user_meta($user_id, 'foto_perfil', true);
    if ($attach_id) {
        $foto = wp_get_attachment_image_url((int) $attach_id, 'full');
        if ($foto) return $foto;
    }
    return $url;
}, 10, 3);

// ── Ordenar por fecha los resultados del buscador ACF en campos de portada ─
add_filter('acf/fields/relationship/query/key=field_portada_articulos', function($args) {
    $args['orderby'] = 'date';
    $args['order']   = 'DESC';
    return $args;
});
add_filter('acf/fields/relationship/query/key=field_portada_multimedia', function($args) {
    $args['orderby'] = 'date';
    $args['order']   = 'DESC';
    return $args;
});

// ── Campos ACF para la portada ────────────────────────────────────────────
add_action('acf/init', function() {
    if (!function_exists('acf_add_local_field_group')) return;

    $front_page_id = (int) get_option('page_on_front');

    acf_add_local_field_group([
        'key'    => 'group_portada_fea',
        'title'  => 'Contenido de la portada',
        'fields' => [
            [
                'key'           => 'field_portada_articulos',
                'label'         => 'Artículos seleccionados',
                'name'          => 'portada_articulos',
                'type'          => 'relationship',
                'instructions'  => 'Elige los artículos que aparecerán en la portada esta semana (máx. 9). Puedes buscar por título.',
                'post_type'     => ['post'],
                'post_status'   => ['publish', 'draft'],
                'filters'       => ['search', 'taxonomy'],
                'elements'      => ['featured_image'],
                'min'           => 0,
                'max'           => 9,
                'return_format' => 'object',
                'query_args'    => ['orderby' => 'date', 'order' => 'DESC'],
            ],
            [
                'key'           => 'field_portada_multimedia',
                'label'         => 'Multimedia seleccionado',
                'name'          => 'portada_multimedia',
                'type'          => 'relationship',
                'instructions'  => 'Elige los vídeos o audios para la portada (máx. 4).',
                'post_type'     => ['post'],
                'post_status'   => ['publish', 'draft'],
                'filters'       => ['search'],
                'elements'      => ['featured_image'],
                'min'           => 0,
                'max'           => 4,
                'return_format' => 'object',
                'query_args'    => ['orderby' => 'date', 'order' => 'DESC'],
            ],
        ],
        'location' => [[
            ['param' => 'page', 'operator' => '==', 'value' => (string) $front_page_id],
        ]],
        'position'      => 'normal',
        'style'         => 'default',
        'label_placement' => 'top',
    ]);
});

// ── Selector de idioma (dropdown con bandera + 2 letras) ─────────────────
add_action('wp_head', function() {
    if (!function_exists('pll_the_languages')) return;
    ?>
    <style>
    #fea-lang-switcher {
        position: relative;
        display: inline-flex;
        align-items: center;
        font-family: inherit;
        z-index: 9999;
    }
    #fea-lang-btn {
        display: inline-flex;
        align-items: center;
        gap: 5px;
        background: none;
        border: 1px solid rgba(0,0,0,0.25);
        border-radius: 5px;
        padding: 4px 9px;
        cursor: pointer;
        font-size: 0.82rem;
        font-weight: 700;
        color: inherit;
        line-height: 1.4;
        white-space: nowrap;
    }
    #fea-lang-btn:hover { background: rgba(0,0,0,0.06); }
    #fea-lang-btn .arrow { font-size: 0.6rem; opacity: 0.6; }
    #fea-lang-dropdown {
        display: none;
        position: absolute;
        top: calc(100% + 4px);
        right: 0;
        background: #fff;
        border: 1px solid #ddd;
        border-radius: 7px;
        box-shadow: 0 6px 16px rgba(0,0,0,0.13);
        min-width: 90px;
        padding: 4px 0;
        list-style: none;
        margin: 0;
    }
    #fea-lang-switcher.open #fea-lang-dropdown { display: block; }
    #fea-lang-dropdown li { margin: 0; padding: 0; }
    #fea-lang-dropdown a {
        display: flex;
        align-items: center;
        gap: 7px;
        padding: 7px 14px;
        font-size: 0.82rem;
        font-weight: 600;
        text-decoration: none;
        color: #222;
        white-space: nowrap;
    }
    #fea-lang-dropdown a:hover { background: #f5f5f5; }
    #fea-lang-dropdown a[aria-current] { font-weight: 700; color: #000; background: #efefef; }
    #fea-lang-dropdown a.fea-lang-untrans { opacity: 0.45; }
    #fea-lang-dropdown a.fea-lang-untrans::after { content: "·"; margin-left: 4px; opacity: 0.7; }
    </style>
    <?php
});

add_action('wp_footer', function() {
    if (!function_exists('pll_the_languages')) return;

    $flags = ['es' => '🇪🇸', 'en' => '🇬🇧', 'fr' => '🇫🇷', 'it' => '🇮🇹', 'pt' => '🇵🇹'];

    $langs = pll_the_languages(['raw' => 1, 'hide_if_no_translation' => 0]);
    if (!$langs) return;

    $current = array_filter($langs, fn($l) => $l['current_lang']);
    $current = $current ? array_values($current)[0] : null;
    $cur_slug  = $current ? $current['slug'] : 'es';
    $cur_flag  = $flags[$cur_slug] ?? '🌐';
    $cur_code  = strtoupper($cur_slug);

    $items = '';
    foreach ($langs as $l) {
        $flag = $flags[$l['slug']] ?? '🌐';
        $code = strtoupper($l['slug']);
        $cur  = $l['current_lang'] ? ' aria-current="true"' : '';
        // Marcar los idiomas SIN traducción de esta página (Polylang enlaza al inicio del
        // idioma): se atenúan y avisan, para no hacer creer que traducen el contenido actual.
        $notr = !empty($l['no_translation']) && empty($l['current_lang']);
        $cls  = $notr ? ' class="fea-lang-untrans"' : '';
        $ttl  = $notr ? ' title="Esta página no está traducida — irás al inicio en ' . esc_attr($code) . '"' : '';
        $items .= '<li><a href="' . esc_url($l['url']) . '"' . $cur . $cls . $ttl . '>' . $flag . ' ' . $code . '</a></li>';
    }
    ?>
    <div id="fea-lang-switcher" role="navigation" aria-label="Idioma / Language">
        <button id="fea-lang-btn" aria-haspopup="listbox" aria-expanded="false"
                onclick="var s=this.closest('#fea-lang-switcher'),o=s.classList.toggle('open');this.setAttribute('aria-expanded',o)">
            <?= $cur_flag ?> <?= $cur_code ?> <span class="arrow">▼</span>
        </button>
        <ul id="fea-lang-dropdown" role="listbox"><?= $items ?></ul>
    </div>
    <script>
    (function() {
        var sw = document.getElementById('fea-lang-switcher');
        if (!sw) return;
        // Cerrar al clicar fuera
        document.addEventListener('click', function(e) {
            if (!sw.contains(e.target)) {
                sw.classList.remove('open');
                document.getElementById('fea-lang-btn').setAttribute('aria-expanded', 'false');
            }
        });
        // Inyectar en el nav principal del header
        function inject() {
            // Buscar la barra de navegación principal (primer nivel dentro del header)
            var header = document.querySelector('header.wp-block-template-part');
            if (!header) header = document.querySelector('header');
            if (!header) return;
            // Buscar el div/group que contiene el menú de navegación
            var navGroup = header.querySelector('.wp-block-navigation__container');
            if (!navGroup) navGroup = header.querySelector('nav');
            if (!navGroup) {
                // Fallback: poner en el header con posición absoluta
                header.style.position = 'relative';
                sw.style.cssText = 'position:absolute;top:50%;right:1.5rem;transform:translateY(-50%);';
                header.appendChild(sw);
                return;
            }
            // Crear li wrapper para el nav
            var li = document.createElement('li');
            li.className = 'wp-block-navigation-item';
            li.style.cssText = 'display:flex;align-items:center;margin-left:0.5rem;';
            li.appendChild(sw);
            // Insertar DESPUÉS del buscador (si existe)
            var searchItem = navGroup.querySelector('.wp-block-search');
            if (searchItem) {
                // Subir hasta el li/div hermano directo del navGroup
                var anchor = searchItem;
                while (anchor.parentNode && anchor.parentNode !== navGroup) {
                    anchor = anchor.parentNode;
                }
                anchor.parentNode.insertBefore(li, anchor.nextSibling);
            } else {
                navGroup.appendChild(li);
            }
        }
        if (document.readyState === 'loading') {
            document.addEventListener('DOMContentLoaded', inject);
        } else {
            inject();
        }
    })();
    </script>
    <?php
}, 20);

// ── Centrar bloque slider+librería (header template, todas las páginas) ───
add_action('wp_head', function() {
    ?>
    <style>
    /* El bloque de columnas con el slider usa márgenes negativos del FSE
       que lo desplazan. Lo forzamos a centrar con max-width explícito. */
    .wp-block-columns:has(.wp-block-nextend-smartslider3) {
        max-width: min(var(--wp--style--global--wide-size, 1340px), 100%);
        margin-left: auto !important;
        margin-right: auto !important;
        box-sizing: border-box;
        padding-left: var(--wp--preset--spacing--30);
        padding-right: var(--wp--preset--spacing--30);
    }

    /* Ocultar columna librería en tablet */
    @media (max-width: 900px) {
        .fea-slider-block .wp-block-column:last-child {
            display: none !important;
        }
    }

    /* Ocultar slider en móvil (banner superior sigue visible) */
    @media (max-width: 600px) {
        .fea-slider-block {
            display: none !important;
        }
    }

    /* Buscador del header: reducir altura */
    .wp-block-search__input {
        padding-top: 0.25rem !important;
        padding-bottom: 0.25rem !important;
        line-height: 1.3 !important;
    }
    .wp-block-search__button {
        padding-top: 0.25rem !important;
        padding-bottom: 0.25rem !important;
    }
    </style>
    <?php
});

// ── Estilos ───────────────────────────────────────────────────────────────
add_action('wp_head', function() {
    if (!fea_is_front_page()) return;
    ?>
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
    <link href="https://fonts.googleapis.com/css2?family=Fraunces:opsz,wght@9..144,400;9..144,600;9..144,700&display=swap" rel="stylesheet">
    <style>
    /* ── Hero: Carta (izq) + Carrusel (der) en banda beige full-width ── */
    .fea-hero-band { max-width: none !important; width: 100vw; margin-left: calc(50% - 50vw) !important; margin-right: calc(50% - 50vw) !important; background: linear-gradient(180deg, #efe9e1, #f4f0ea); border-bottom: 1px solid #e4ddd1; margin-bottom: 3rem; }
    .fea-hero-inner { max-width: 1180px; margin: 0 auto; padding: 2.75rem 28px; display: grid; grid-template-columns: minmax(260px, 400px) minmax(0, 1fr); gap: 2.5rem; align-items: center; }
    .fea-hero-text { min-width: 0; }
    .fea-hero-link { display: block; text-decoration: none; color: inherit; }
    .fea-hero-link:hover .fea-hero-title { text-decoration: underline; text-underline-offset: 4px; }
    .fea-section-label { display: inline-block; font-size: 0.72rem; font-weight: 700; letter-spacing: 0.18em; text-transform: uppercase; color: #8b1a2e; margin-bottom: 0.7rem; }
    .fea-hero-title { font-family: 'Fraunces', Georgia, serif; font-size: clamp(2rem, 3.4vw, 3rem); font-weight: 600; line-height: 1.08; letter-spacing: -0.01em; margin: 0 0 1rem; color: #2a2320; }
    .fea-hero-meta { display: flex; align-items: center; gap: 0.5rem; font-size: 0.875rem; color: #6f655c; }
    .fea-hero-cta { display: inline-block; margin-top: 1.25rem; background: #8b1a2e; color: #fff; font-weight: 600; font-size: 0.92rem; padding: 0.7rem 1.4rem; border-radius: 8px; }
    .fea-hero-slider { min-width: 0; overflow: hidden; }
    .fea-hero-slider .n2-ss-align { max-width: 100% !important; width: 100% !important; }
    @media (max-width: 860px) { .fea-hero-inner { grid-template-columns: 1fr; gap: 1.75rem; } }

    /* Ancho de las secciones de portada: contenedor centrado (aire a los lados) */
    body.home .fea-section, .fea-front .fea-section { max-width: 1180px !important; margin-left: auto !important; margin-right: auto !important; }

    /* ── Secciones — dirección "Cálido editorial" (Mockup A, #57) ── */
    .fea-section { margin-bottom: 3.75rem; padding-top: 0.5rem; }
    .fea-section-title { display: flex; align-items: center; gap: 1rem; font-family: 'Fraunces', Georgia, serif; font-size: 1.65rem; font-weight: 600; letter-spacing: -0.01em; text-transform: none; color: #2a2320; margin: 0 0 1.6rem; padding: 0; border: 0; }
    .fea-section-title::after { content: ''; display: inline-block; flex: 0 0 46px; height: 3px; background: #8b1a2e; border-radius: 2px; }
    .fea-section-head { display: flex; align-items: center; gap: 1rem; margin-bottom: 1.6rem; }
    .fea-section-head .fea-section-title { flex: 1 1 auto; min-width: 0; margin-bottom: 0; }
    .fea-section-more { flex: 0 0 auto; color: #8b1a2e; font-size: 0.86rem; font-weight: 700; text-decoration: none; white-space: nowrap; }
    .fea-section-more:hover { text-decoration: underline; text-underline-offset: 3px; }
    @media (max-width: 480px) {
        .fea-section-head { gap: 0.65rem; }
        .fea-section-head .fea-section-title { font-size: 1.45rem; gap: 0.65rem; }
        .fea-section-head .fea-section-title::after { flex-basis: 28px; }
        .fea-section-more { font-size: 0.8rem; }
    }

    .fea-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1.6rem; }
    @media (max-width: 980px) { .fea-grid { grid-template-columns: repeat(3, 1fr); } }
    @media (max-width: 680px)  { .fea-grid { grid-template-columns: 1fr 1fr; } }
    @media (max-width: 420px)  { .fea-grid { grid-template-columns: 1fr; } }

    .fea-card { background: #fff; border: 1px solid #efe7d8; border-radius: 14px; padding: 1.5rem 1rem; text-align: center; transition: transform .18s ease, box-shadow .18s ease; }
    .fea-card:hover { transform: translateY(-5px); box-shadow: 0 18px 36px -20px rgba(42,35,32,.45); }
    /* Ocultar visualmente el texto de accesibilidad del Smart Slider (nombres de fichero con guiones bajos) */
    .n2-ss-slide--focus { position: absolute !important; width: 1px !important; height: 1px !important; padding: 0 !important; margin: -1px !important; overflow: hidden !important; clip: rect(0,0,0,0) !important; white-space: nowrap !important; border: 0 !important; }
    .fea-card-avatar-link { display: block; }
    .fea-card-avatar { box-shadow: 0 0 0 3px #f7ecd9, 0 0 0 4px #e7d7bb; transition: transform .2s ease; }
    .fea-card:hover .fea-card-avatar { transform: scale(1.05); }
    .fea-card-author { color: #8b1a2e; font-weight: 600; font-size: 0.9rem; margin: 0.95rem 0 0.5rem; line-height: 1.25; }
    .fea-card-title { font-size: 0.98rem; font-weight: 600; line-height: 1.32; margin: 0; }
    .fea-card-title a { text-decoration: none; color: #2a2320; }
    .fea-card-title a:hover { text-decoration: underline; text-underline-offset: 3px; }

    /* ── Footer portada: contener anchos, aire a los lados (no entre medias) ── */
    /* Reduce el espaciado preset 80 (enorme) solo dentro del footer, sin tocar listas */
    .fea-footer-portada { max-width: 1180px; margin-left: auto; margin-right: auto; --wp--preset--spacing--80: 3rem; }
    /* Las 3 imágenes (Librería / Noticias / Portal-EFFA): columnas iguales, aires iguales */
    .fea-footer-portada .wp-block-columns { max-width: 900px; margin-left: auto; margin-right: auto; gap: 2.5rem !important; align-items: start; justify-content: center; }
    .fea-footer-portada .wp-block-columns .wp-block-column { flex: 1 1 0 !important; width: auto !important; min-width: 0; display: flex; flex-direction: column; align-items: center; text-align: center; }
    .fea-footer-portada .wp-block-columns .wp-block-column img { max-width: 100%; width: auto; height: auto; margin-left: auto; margin-right: auto; }
    /* Las columnas de enlaces: centrarlas (aire a los lados, no entre medias) */
    .fea-footer-portada .wp-block-group.is-content-justification-space-between { justify-content: center !important; gap: 3.5rem !important; }
    </style>
    <?php
});

// ── Slider del hero a prueba de fuego: llena la columna y, si es más estrecha
//    que el ancho base del slider (Smart Slider no baja de él), lo escala con transform ──
add_action('wp_footer', function() {
    if (!fea_is_front_page()) return;
    ?>
    <script>
    (function () {
        var els = function () {
            return {
                c: document.querySelector('.fea-hero-slider'),
                s: document.querySelector('.fea-hero-slider .n2-ss-slider')
            };
        };
        var lastW = -1, busy = false, raf = 0;
        function apply() {
            var e = els();
            if (!e.c || !e.s) return;
            // reset para medir el tamaño natural que decide Smart Slider
            e.s.style.transform = '';
            e.s.style.transformOrigin = '';
            e.c.style.height = '';
            // que Smart Slider recalcule (crece hasta llenar la columna si cabe)
            busy = true; window.dispatchEvent(new Event('resize')); busy = false;
            requestAnimationFrame(function () {
                var avail = e.c.clientWidth;
                var rect  = e.s.getBoundingClientRect();
                if (rect.width > avail + 1) {           // columna más estrecha que el slider → escalar
                    var k = avail / rect.width;
                    e.s.style.transformOrigin = 'top left';
                    e.s.style.transform = 'scale(' + k + ')';
                    e.c.style.height = Math.round(rect.height * k) + 'px';
                }
            });
        }
        function schedule() { cancelAnimationFrame(raf); raf = requestAnimationFrame(apply); }
        function onChange(force) {
            if (busy) return;
            var c = els().c; if (!c) return;
            var w = c.clientWidth;
            if (!force && w === lastW) return;          // solo reaccionar a cambios de ANCHO (evita bucle por la altura)
            lastW = w; schedule();
        }
        window.addEventListener('load', function () { onChange(true); setTimeout(function(){onChange(true);}, 300); setTimeout(function(){onChange(true);}, 800); });
        window.addEventListener('resize', function () { onChange(false); });
        if ('ResizeObserver' in window) {
            var c = els().c;
            if (c) new ResizeObserver(function () { onChange(false); }).observe(c);
        }
    })();
    </script>
    <?php
}, 99);

// ── Estilos para listados/archivos (categoría, autor, fecha, búsqueda) #63 ──
add_action('wp_head', function() {
    if (is_admin() || fea_is_front_page()) return;
    if (!(is_archive() || is_search() || is_home())) return;
    ?>
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link href="https://fonts.googleapis.com/css2?family=Fraunces:opsz,wght@9..144,400;9..144,600;9..144,700&display=swap" rel="stylesheet">
    <style>
    /* Título del archivo: serif con barra granate (coherente con la portada) */
    .wp-block-query-title { font-family: 'Fraunces', Georgia, serif !important; font-weight: 600 !important; color: #2a2320 !important; letter-spacing: -0.01em; display: flex; align-items: center; gap: 1rem; }
    .wp-block-query-title::after { content: ''; flex: 0 0 46px; height: 3px; background: #8b1a2e; border-radius: 2px; }
    /* Anchura coherente con la portada */
    .wp-block-query.alignwide { max-width: 1180px !important; margin-left: auto !important; margin-right: auto !important; }
    /* Grid de tarjetas */
    .fea-archive-grid { display: grid !important; grid-template-columns: repeat(3, 1fr) !important; gap: 1.5rem !important; }
    @media (max-width: 900px) { .fea-archive-grid { grid-template-columns: repeat(2, 1fr) !important; } }
    @media (max-width: 560px) { .fea-archive-grid { grid-template-columns: 1fr !important; } }
    .fea-archive-card { background: #fff; border: 1px solid #efe7d8; border-radius: 14px; padding: 1.4rem 1.3rem; height: 100%; display: flex; flex-direction: column; transition: transform .18s ease, box-shadow .18s ease; }
    .fea-archive-card:hover { transform: translateY(-4px); box-shadow: 0 18px 36px -20px rgba(42,35,32,.45); }
    .fea-archive-title { margin: 0 !important; }
    .fea-archive-title a { font-family: 'Fraunces', Georgia, serif; font-weight: 600; color: #2a2320; text-decoration: none; line-height: 1.25; }
    .fea-archive-card:hover .fea-archive-title a { color: #8b1a2e; }
    .fea-archive-date { margin: 0.45rem 0 0 !important; }
    .fea-archive-date a, .fea-archive-date { color: #8b1a2e !important; font-weight: 600; text-decoration: none; }
    .fea-archive-excerpt { margin: 0.6rem 0 0 !important; color: #6f655c; font-size: 0.92rem; line-height: 1.45; }
    .fea-archive-excerpt a { display: none; }
    </style>
    <?php
});


// ── Ocultar título de página en todas las portadas ────────────────────────
add_action('wp_head', function() {
    if (!fea_is_front_page()) return;
    echo '<style>.wp-block-post-title { display:none !important; }</style>';
}, 20);

// ── H1 semántico oculto para páginas sin título visible ───────────────────
add_action('wp_head', function() {
    ?>
    <style>
    .fea-sr-only {
        position: absolute !important;
        width: 1px !important;
        height: 1px !important;
        padding: 0 !important;
        margin: -1px !important;
        overflow: hidden !important;
        clip: rect(0, 0, 0, 0) !important;
        clip-path: inset(50%) !important;
        white-space: nowrap !important;
        border: 0 !important;
    }
    </style>
    <?php
}, 20);

add_filter('the_content', function($content) {
    if (is_admin() || !is_main_query() || !in_the_loop()) return $content;
    if (preg_match('/<h1\b/i', $content)) return $content;

    $title = '';
    if (fea_is_front_page()) {
        $title = get_bloginfo('name') ?: 'Fe Adulta';
    } elseif (fea_is_escuela_page()) {
        $title = 'Escuela de Formación en Fe Adulta';
    }

    if (!$title) return $content;

    return '<h1 class="fea-sr-only fea-page-h1">' . esc_html($title) . '</h1>' . $content;
}, 5);

// ── Título <title> para páginas sin post_title propio (Escuela) ───────────
add_filter('document_title_parts', function($parts) {
    if (fea_is_escuela_page()) {
        $parts['title'] = 'Escuela de Formación en Fe Adulta';
    }
    return $parts;
});

// ── Ocultar metadatos de post en páginas estáticas ────────────────────────
add_action('wp_head', function() {
    if (!fea_hide_static_meta()) return;
    ?>
    <style>
    .wp-block-group:has(> .wp-block-avatar):has(.wp-block-post-author-name),
    .wp-block-post-author-name,
    .wp-block-post-terms.taxonomy-category {
        display: none !important;
    }
    </style>
    <?php
}, 20);

// ── Byline personalizado en artículos individuales ────────────────────────

// ── Byline personalizado: se gestiona desde el template FSE (ID 42359) ────
// El template wp_template 'single' ya contiene wp:avatar + wp:post-author-name
// + wp:post-terms. Este hook solo añade los estilos necesarios.
add_action('astra_single_header_bottom', function() {
    if (!is_single()) return;

    $author_id   = (int) get_the_author_meta('ID');
    $author_name = get_the_author_meta('display_name');
    $avatar_url  = get_avatar_url($author_id, ['size' => 48]);
    $author_url  = get_author_posts_url($author_id);

    $cat_str = '';
    $cats = get_the_category();
    if ($cats) {
        $cat_url = get_category_link($cats[0]->term_id);
        $cat_str = '<a href="' . esc_url($cat_url) . '" class="fea-byline-cat">'
                 . esc_html($cats[0]->name) . '</a>';
    }

    echo '<div class="fea-byline">'
       . '<a href="' . esc_url($author_url) . '" class="fea-byline-avatar-link">'
       . '<img src="' . esc_url($avatar_url) . '" alt="' . esc_attr($author_name) . '" width="48" height="48" class="fea-byline-avatar">'
       . '</a>'
       . '<div class="fea-byline-info">'
       . '<a href="' . esc_url($author_url) . '" class="fea-byline-name">' . esc_html($author_name) . '</a>'
       . $cat_str
       . '</div>'
       . '</div>';
});

add_action('wp_head', function() {
    if (!is_single()) return;
    ?>
    <style>
    .fea-byline { display: flex; align-items: center; gap: 0.75rem; margin-top: 0.75rem; }
    .fea-byline-avatar-link { flex-shrink: 0; }
    .fea-byline-avatar { border-radius: 50%; display: block; }
    .fea-byline-info { display: flex; flex-direction: column; gap: 0.2rem; }
    .fea-byline-name { font-size: 0.9rem; font-weight: 600; color: #222; text-decoration: none; }
    .fea-byline-name:hover { text-decoration: underline; }
    .fea-byline-cat { font-size: 0.78rem; color: #888; text-decoration: none; }
    .fea-byline-cat:hover { text-decoration: underline; color: #555; }
    .wp-block-group:has(> .wp-block-avatar):has(.wp-block-post-author-name) {
        align-items: center;
        gap: 0.7rem;
    }
    .wp-block-group:has(> .wp-block-avatar):has(.wp-block-post-author-name) > .wp-block-avatar {
        flex: 0 0 54px;
    }
    .wp-block-group:has(> .wp-block-avatar):has(.wp-block-post-author-name) > .wp-block-avatar img {
        width: 54px !important;
        height: 54px !important;
    }
    .fea-post-date-inline {
        font-size: 0.74rem;
        line-height: 1.2;
        color: #888;
        margin-top: 0.08rem;
    }
    .fea-post-date-inline time { white-space: nowrap; }
    @media (max-width: 720px) {
        .wp-block-group:has(> .wp-block-avatar):has(.wp-block-post-author-name) > .wp-block-avatar {
            flex-basis: 50px;
        }
        .wp-block-group:has(> .wp-block-avatar):has(.wp-block-post-author-name) > .wp-block-avatar img {
            width: 50px !important;
            height: 50px !important;
        }
    }
    </style>
    <?php
});

add_filter('render_block_core/post-terms', function($block_content, $block) {
    if (!is_single() || get_post_type() !== 'post') return $block_content;

    $taxonomy = $block['attrs']['term'] ?? '';
    if ($taxonomy !== 'category') return $block_content;
    if (strpos($block_content, 'fea-post-date-inline') !== false) return $block_content;

    $date_attr = esc_attr(get_the_date('c'));
    $date_text = esc_html(ucfirst(wp_date(get_option('date_format'), get_post_timestamp())));
    if ($date_text === '') return $block_content;

    return $block_content
        . '<div class="fea-post-date-inline"><time datetime="' . $date_attr . '">' . $date_text . '</time></div>';
}, 10, 2);

// ── Helpers ───────────────────────────────────────────────────────────────
function fea_title(string $title): string {
    $lower = mb_strtolower($title, 'UTF-8');
    $out   = mb_strtoupper(mb_substr($lower, 0, 1, 'UTF-8'), 'UTF-8') . mb_substr($lower, 1, null, 'UTF-8');
    // Capitalizar también la primera letra tras separadores de cláusula (citas bíblicas
    // dobles "Isaías 5,1 / Filipenses 4,6", subtítulos "Título: Subtítulo", ¿…?, ¡…!).
    $out = preg_replace_callback('/([\/:¿¡] *)(\p{Ll})/u', function ($m) {
        return $m[1] . mb_strtoupper($m[2], 'UTF-8');
    }, $out);
    $out = fea_recapitalizar_nombres_propios($out);
    return $out;
}

/**
 * Nombres propios (personas, lugares, "Dios"/"Papa") que deben mantener mayúscula
 * inicial en los títulos de portada. Los títulos originales se guardan en MAYÚSCULAS
 * y fea_title() los minusculiza salvo la primera letra, así que esta señal se pierde
 * para cualquier nombre propio que no sea la primera palabra del título. Añadir aquí
 * cuando una carta nueva mencione un nombre que salga mal capitalizado en portada.
 * Ver issue rafa/feadulta#160.
 */
function fea_nombres_propios(): array {
    return [
        'Aguirre', 'Crepin', 'Monga', 'Papa', 'Lampedusa', 'Europa', 'España', 'Dios',
    ];
}

function fea_recapitalizar_nombres_propios(string $texto): string {
    static $regex = null, $map = null;
    if ($regex === null) {
        $nombres = fea_nombres_propios();
        usort($nombres, fn($a, $b) => mb_strlen($b, 'UTF-8') - mb_strlen($a, 'UTF-8'));
        $alt = implode('|', array_map(fn($n) => preg_quote($n, '/'), $nombres));
        $regex = '/(?<![\p{L}])(' . $alt . ')(?![\p{L}])/iu';
        $map = [];
        foreach ($nombres as $n) $map[mb_strtolower($n, 'UTF-8')] = $n;
    }
    return preg_replace_callback($regex, function ($m) use ($map) {
        $k = mb_strtolower($m[1], 'UTF-8');
        return $map[$k] ?? $m[1];
    }, $texto);
}

/** Lista de libros bíblicos (para avatar genérico de lecturas/eucaristías). #61 */
function fea_libros_biblicos(): array {
    return [
        'Nuevo Testamento','Antiguo Testamento',
        'Génesis','Éxodo','Levítico','Números','Deuteronomio','Josué','Jueces','Rut',
        'Samuel','Reyes','Crónicas','Esdras','Nehemías','Tobías','Judit','Ester','Macabeos',
        'Job','Salmos','Salmo','Proverbios','Eclesiastés','Cantar','Sabiduría','Eclesiástico','Sirácide',
        'Isaías','Jeremías','Lamentaciones','Baruc','Ezequiel','Daniel',
        'Oseas','Joel','Amós','Abdías','Jonás','Miqueas','Nahúm','Habacuc','Sofonías','Ageo','Zacarías','Malaquías',
        'Hechos','Romanos','Corintios','Gálatas','Efesios','Filipenses','Colosenses','Tesalonicenses',
        'Timoteo','Tito','Filemón','Hebreos','Santiago','Pedro','Judas','Apocalipsis',
    ];
}

/** Devuelve la abreviatura del evangelista si el texto es una cita de evangelio, o ''. #61 */
function fea_evangelista_de_texto(string $txt): string {
    if (preg_match('/^\s*(Mateo|Mt|Marcos|Mc|Lucas|Lc|Juan|Jn)\b\.?\s*\d/iu', $txt, $m)) {
        $k = mb_strtolower($m[1], 'UTF-8');
        $map = ['mateo'=>'mateo-angel','mt'=>'mateo-angel','marcos'=>'marcos-leon','mc'=>'marcos-leon',
                'lucas'=>'lucas-toro','lc'=>'lucas-toro','juan'=>'juan-aguila','jn'=>'juan-aguila'];
        return $map[$k] ?? '';
    }
    return '';
}

/** Devuelve 'antiguo-testamento' / 'nuevo-testamento' si el texto es esa firma, o ''. #66 */
function fea_testamento_de_texto(string $txt): string {
    $t = mb_strtolower(trim($txt), 'UTF-8');
    if ($t === 'antiguo testamento') return 'antiguo-testamento';
    if ($t === 'nuevo testamento')   return 'nuevo-testamento';
    return '';
}

/** True si el texto empieza por un libro bíblico (cita) o es el nombre de un libro. #61 */
function fea_es_libro_biblico(string $txt): bool {
    $txt = trim($txt);
    foreach (fea_libros_biblicos() as $libro) {
        if (mb_strtolower($txt, 'UTF-8') === mb_strtolower($libro, 'UTF-8')) return true;
        if (preg_match('/^' . preg_quote($libro, '/') . '\b/iu', $txt)) return true;
    }
    return false;
}

/**
 * URL del avatar para un post de portada/listado. #61
 * - Citas de evangelio (Mt/Mc/Lc/Jn + número) → símbolo del evangelista.
 * - Lecturas/eucaristías firmadas por un libro bíblico → Biblia.
 * - Resto → avatar real del autor.
 */
function fea_avatar_url(object $post, int $size, int $author_id, string $author_name): string {
    $base  = content_url('uploads/avatares/evangelistas/');
    // Solo la LECTURA en sí (cuyo título es la cita, p.ej. "Mateo 9, 36") lleva símbolo de
    // evangelista; los comentaristas humanos conservan su avatar aunque comenten ese evangelio.
    $title = (string) $post->post_title;
    // Las traducciones tienen el título en su idioma (Matteo, Geremia, Romani…) que no
    // reconocemos. Usamos el título del ORIGINAL ES, donde sí detectamos el libro → la
    // traducción hereda el mismo símbolo que el ES (#135).
    if (function_exists('pll_get_post_language') && pll_get_post_language($post->ID) !== 'es') {
        $es = function_exists('pll_get_post') ? pll_get_post($post->ID, 'es') : 0;
        if ($es) {
            $esp = get_post($es);
            if ($esp) $title = (string) $esp->post_title;
        }
    }
    if ($ev = fea_evangelista_de_texto($title)) return $base . $ev . '.svg';
    // "Antiguo Testamento" / "Nuevo Testamento" llevan símbolo propio (no el genérico). #66
    if ($t = fea_testamento_de_texto($title) ?: fea_testamento_de_texto($author_name)) return $base . $t . '.svg';
    if (fea_es_libro_biblico($title) || fea_es_libro_biblico($author_name)) return $base . 'biblia.svg';
    return get_avatar_url($author_id, ['size' => $size, 'default' => 'identicon']);
}

function fea_card(object $post): string {
    $author_id   = $post->post_author;
    $author_name = get_the_author_meta('display_name', $author_id);
    $avatar_url  = fea_avatar_url($post, 96, (int) $author_id, (string) $author_name);
    $url         = get_permalink($post->ID);
    $title       = fea_title($post->post_title);
    return '<article class="fea-card">'
        . '<a href="' . esc_url($url) . '" class="fea-card-avatar-link" aria-label="' . esc_attr($author_name) . '">'
        . '<span class="fea-card-avatar" style="display:block;width:84px;height:84px;border-radius:50%;overflow:hidden;margin:0 auto;">'
        . '<img src="' . esc_url($avatar_url) . '" alt="' . esc_attr($author_name) . '" width="84" height="84" class="fea-avatar" style="width:100%;height:100%;object-fit:cover;display:block;" loading="lazy">'
        . '</span>'
        . '</a>'
        . '<div class="fea-card-author">' . esc_html($author_name) . '</div>'
        . '<h3 class="fea-card-title"><a href="' . esc_url($url) . '">' . esc_html($title) . '</a></h3>'
        . '</article>';
}

/** IDs de las páginas de portada en todos los idiomas. */
function fea_front_page_ids(): array {
    return [26542, 42756, 42757, 42758, 43889]; // ES=26542, PT=42756, IT=42757, FR=42758, EN=43889 (FR/PT corregidos #75)
}

/** True si la página actual es alguna de las portadas (multilingüe). */
function fea_is_front_page(): bool {
    if (is_front_page()) return true;
    $id = get_queried_object_id();
    return $id && in_array($id, fea_front_page_ids(), true);
}

/** True para la landing de Escuela, que no muestra título visible. */
function fea_is_escuela_page(): bool {
    if (!is_page()) return false;
    $page = get_queried_object();
    return $page instanceof WP_Post && $page->post_name === 'escuela';
}

/** True para contenidos importados que funcionan como páginas institucionales. */
function fea_hide_static_meta(): bool {
    if (is_admin() || fea_is_front_page()) return false;

    $post = get_queried_object();
    if (!$post instanceof WP_Post) return false;

    if ($post->post_type === 'page') return true;

    $slugs = [
        'colaboradores',
        'contactar',
        'multimedia',
        'ayuda',
        'video-tutorial',
        'como-usar-el-buscador-avanzado',
        'portal',
        'paraponeraldialafe',
        'alta',
        'alta-en-effa',
        'regala',
        'catalogo-de-publicaciones-2018',
        'nueva-politica-de-privacidad',
    ];

    return in_array($post->post_name, $slugs, true);
}

/** Devuelve el idioma actual de Polylang, o 'es' si no está activo. */
function fea_current_lang(): string {
    return (function_exists('pll_current_language') ? pll_current_language() : null) ?: 'es';
}

/** Etiquetas de sección traducidas por idioma. */
function fea_labels(): array {
    $all = [
        'es' => [
            'carta'      => 'Carta de la semana',
            'evangelio'  => 'Comentarios al evangelio',
            'articulos'  => 'Artículos de esta semana',
            'eucaristia' => 'Para una eucaristía más participativa',
            'multimedia' => 'Multimedia',
        ],
        'en' => [
            'carta'      => 'Letter of the week',
            'evangelio'  => 'Gospel commentary',
            'articulos'  => 'Articles of the week',
            'eucaristia' => 'For a more participatory Eucharist',
            'multimedia' => 'Multimedia',
        ],
        'fr' => [
            'carta'      => 'Lettre de la semaine',
            'evangelio'  => 'Commentaires de l\'évangile',
            'articulos'  => 'Articles de la semaine',
            'eucaristia' => 'Pour une eucharistie plus participative',
            'multimedia' => 'Multimédia',
        ],
        'it' => [
            'carta'      => 'Lettera della settimana',
            'evangelio'  => 'Commenti al vangelo',
            'articulos'  => 'Articoli della settimana',
            'eucaristia' => 'Per una eucaristia più partecipativa',
            'multimedia' => 'Multimedia',
        ],
        'pt' => [
            'carta'      => 'Carta da semana',
            'evangelio'  => 'Comentários ao evangelho',
            'articulos'  => 'Artigos da semana',
            'eucaristia' => 'Para uma eucaristia mais participativa',
            'multimedia' => 'Multimédia',
        ],
    ];
    return $all[fea_current_lang()] ?? $all['es'];
}

/**
 * ID de la página de portada para el idioma actual.
 */
function fea_front_page_id(): int {
    $es_front = 26542;
    $lang = fea_current_lang();
    if ($lang === 'es') return $es_front;
    if (function_exists('pll_get_post')) {
        $translated = pll_get_post($es_front, $lang);
        if ($translated) return (int) $translated;
    }
    return $es_front;
}

/**
 * Traduce un term_id de categoría ES al idioma actual.
 * Si no hay traducción disponible, devuelve el ID original.
 */
function fea_cat(int $es_cat_id): int {
    $lang = fea_current_lang();
    if ($lang === 'es') return $es_cat_id;
    if (function_exists('pll_get_term')) {
        $translated = pll_get_term($es_cat_id, $lang);
        if ($translated) return (int) $translated;
    }
    return $es_cat_id;
}

// ── Enlace "Evangelio del día · fecha" ────────────────────────────────────
// Píldora discreta, estilo "fecha con contenido", a la página del Evangelio de
// cada día. Se inserta dentro del hero de la carta (portada). Multiidioma.
function fea_eed_link_html() {
    $tz   = new DateTimeZone('Europe/Madrid');
    $now  = new DateTimeImmutable('now', $tz);
    $d    = (int) $now->format('j');
    $m    = (int) $now->format('n');
    $lang = function_exists('fea_current_lang') ? fea_current_lang() : 'es';

    $LBL = ['es'=>'Evangelio del día','en'=>'Gospel of the day','fr'=>'Évangile du jour','it'=>'Vangelo del giorno','pt'=>'Evangelho do dia'];
    $MES = [
        'es'=>[1=>'enero','febrero','marzo','abril','mayo','junio','julio','agosto','septiembre','octubre','noviembre','diciembre'],
        'en'=>[1=>'January','February','March','April','May','June','July','August','September','October','November','December'],
        'fr'=>[1=>'janvier','février','mars','avril','mai','juin','juillet','août','septembre','octobre','novembre','décembre'],
        'it'=>[1=>'gennaio','febbraio','marzo','aprile','maggio','giugno','luglio','agosto','settembre','ottobre','novembre','dicembre'],
        'pt'=>[1=>'janeiro','fevereiro','março','abril','maio','junho','julho','agosto','setembro','outubro','novembro','dezembro'],
    ];
    $L   = isset($MES[$lang]) ? $lang : 'es';
    $mes = $MES[$L][$m];
    if      ($L === 'es' || $L === 'pt') $fecha = $d . ' de ' . $mes;
    elseif  ($L === 'en')                $fecha = $mes . ' ' . $d;
    else                                 $fecha = $d . ' ' . $mes; // fr, it

    // get_posts usa suppress_filters=true → Polylang no filtra y siempre
    // devuelve la página ES. Resolvemos la traducción del idioma actual.
    $pg  = get_posts(['name'=>'evangelio-de-cada-dia','post_type'=>'post','post_status'=>'publish','numberposts'=>1]);
    $pid = $pg ? (int) $pg[0]->ID : 0;
    if ($pid && $lang !== 'es' && function_exists('pll_get_post')) {
        $tr = pll_get_post($pid, $lang);
        if ($tr) $pid = (int) $tr;
    }
    $url = $pid ? get_permalink($pid) : home_url('/evangelio-de-cada-dia/');

    $css = '<style>'
        . '.fea-eed-link{margin:1.6rem 0 0}'
        . '.fea-eed-link a{display:inline-flex;align-items:center;gap:.5rem;color:#8b1a2e;text-decoration:none;font-size:.92rem;line-height:1}'
        . '.fea-eed-link a:hover{text-decoration:underline;text-underline-offset:3px}'
        . '.fea-eed-link .lbl{font-weight:700}'
        . '.fea-eed-link .sep{color:#caa9b0}'
        . '.fea-eed-link .fecha{color:#6f655c}'
        . '.fea-eed-link .arrow{color:#8b1a2e;font-weight:700}'
        . '</style>';

    return $css . '<div class="fea-eed-link"><a href="' . esc_url($url) . '">'
        . '<span class="lbl">' . esc_html($LBL[$L]) . '</span>'
        . '<span class="sep">·</span>'
        . '<span class="fecha">' . esc_html($fecha) . '</span>'
        . '<span class="arrow">&rsaquo;</span></a></div>';
}

// ── Shortcode: [fea_carta_semana_hero] ────────────────────────────────────
add_shortcode('fea_carta_semana_hero', function() {
    $lang   = fea_current_lang();
    $labels = fea_labels();

    $cartas = get_posts([
        'posts_per_page' => 1,
        'category__in'   => [fea_cat(6)],
        'post_status'    => 'publish',
        'orderby'        => 'date',
        'order'          => 'DESC',
    ]);
    if (!$cartas) return '';

    $c           = $cartas[0];
    $url         = get_permalink($c->ID);
    $fecha       = date_i18n('j F Y', strtotime($c->post_date));
    $author_name = get_the_author_meta('display_name', $c->post_author);
    $avatar_url  = get_avatar_url($c->post_author, ['size' => 32, 'default' => 'identicon']);
    $slider      = do_shortcode('[smartslider3 slider="2"]');

    return '<section class="fea-hero-band"><div class="fea-hero-inner">'
        . '<div class="fea-hero-text">'
        . '<a href="' . esc_url($url) . '" class="fea-hero-link">'
        . '<span class="fea-section-label">' . esc_html($labels['carta']) . '</span>'
        . '<h2 class="fea-hero-title">' . esc_html(fea_title($c->post_title)) . '</h2>'
        . '<div class="fea-hero-meta">'
        . '<img src="' . esc_url($avatar_url) . '" alt="' . esc_attr($author_name) . '" width="32" height="32" class="fea-avatar" style="width:32px;height:32px;border-radius:50%;object-fit:cover;">'
        . '<span>' . esc_html($author_name) . ' · ' . $fecha . '</span>'
        . '</div>'
        . '<span class="fea-hero-cta">' . esc_html($labels['carta'] ? 'Leer la carta' : 'Leer la carta') . ' →</span>'
        . '</a>'
        . fea_eed_link_html()
        . '</div>'
        . '<div class="fea-hero-slider">' . $slider . '</div>'
        . '</div></section>';
});

// ── Shortcode: [fea_articulos_semana] ─────────────────────────────────────
// Fuente principal: links de la sección "Artículos seleccionados" de la carta vigente.
// Fallbacks: ACF portada_articulos → últimos por categoría.
add_shortcode('fea_articulos_semana', function($atts) {
    $lang   = fea_current_lang();
    $labels = fea_labels();
    $atts   = shortcode_atts(['titulo' => $labels['articulos']], $atts);
    $page   = fea_front_page_id();

    // 1) Fuente principal: sección "Artículos seleccionados" de la carta vigente
    $posts = function_exists('fea_carta_section_posts') ? fea_carta_section_posts('articulos', $lang) : [];

    // 2) Fallback ACF (solo ES)
    if (empty($posts) && $lang === 'es' && function_exists('get_field')) {
        $seleccion = get_field('portada_articulos', $page) ?: [];
        foreach ($seleccion as $p) {
            if ($p->post_status === 'publish') $posts[] = $p;
        }
    }

    // 3) Fallback: últimos artículos en el idioma actual
    if (empty($posts)) {
        $posts = get_posts([
            'posts_per_page'   => 9,
            'category__in'     => [fea_cat(1650)],
            'category__not_in' => array_map('fea_cat', [6, 21, 22, 23, 26, 58, 40, 1645, 1646, 1647, 1648, 1649, 1651, 1652]),
            'post_status'      => 'publish',
            'orderby'          => 'date',
            'order'            => 'DESC',
        ]);
    }
    if (!$posts) return '';

    $html = '<section class="fea-section">'
          . '<h2 class="fea-section-title">' . esc_html($atts['titulo']) . '</h2>'
          . '<div class="fea-grid">';
    foreach ($posts as $post) $html .= fea_card($post);
    return $html . '</div></section>';
});

// ── Shortcode: [fea_evangelio] ────────────────────────────────────────────
// Fuente principal: sección "Evangelio y comentarios" de la carta vigente.
// Fallback: editorial cat 1646 + comentarios cat 1647 por fecha.
add_shortcode('fea_evangelio', function($atts) {
    $lang   = fea_current_lang();
    $labels = fea_labels();
    $atts   = shortcode_atts(['titulo' => $labels['evangelio']], $atts);

    $posts = function_exists('fea_carta_section_posts') ? fea_carta_section_posts('evangelio', $lang) : [];

    if (empty($posts)) {
        $editorial = get_posts([
            'posts_per_page' => 1,
            'category__in'   => [fea_cat(1646)],
            'post_status'    => 'publish',
            'orderby'        => 'date',
            'order'          => 'DESC',
        ]);
        $comentarios = get_posts([
            'posts_per_page'   => 6,
            'category__in'     => [fea_cat(1647)],
            'category__not_in' => [fea_cat(1646)],
            'post_status'      => 'publish',
            'orderby'          => 'date',
            'order'            => 'DESC',
        ]);
        $posts = array_merge($editorial, $comentarios);
    }
    if (!$posts) return '';

    $html = '<section class="fea-section">'
          . '<h2 class="fea-section-title">' . esc_html($atts['titulo']) . '</h2>'
          . '<div class="fea-grid">';
    foreach ($posts as $post) $html .= fea_card($post);
    return $html . '</div></section>';
});

// ── Shortcode: [fea_evangelio_diario] ─────────────────────────────────────
// "El Evangelio de cada día": dos devocionales diarios indexados por día del año.
//   · A la fuente cada día (texto, Fray Marcos)  → categoría term_id 14
//   · Otro evangelio es posible (vídeo YouTube)   → categoría term_id 15
// El texto de Fray Marcos se resuelve contra el calendario litúrgico versionado
// (fecha ISO -> book_index), no por el título civil heredado de Joomla. Se muestra
// el de HOY (zona horaria del sitio) o el día indicado por ?fed=M-D, con pestañas para
// que el usuario elija formato y navegación día anterior / siguiente.
// Contenido solo en ES (devocional sin traducción) → categorías 14/15 fijas.
add_shortcode('fea_evangelio_diario', function($atts) {
    $MESES = [1=>'enero',2=>'febrero',3=>'marzo',4=>'abril',5=>'mayo',6=>'junio',
              7=>'julio',8=>'agosto',9=>'septiembre',10=>'octubre',11=>'noviembre',12=>'diciembre'];
    // Día litúrgico de referencia: España (la web es ES); el servidor va en UTC.
    $tz = new DateTimeZone('Europe/Madrid');
    $now = new DateTimeImmutable('now', $tz);
    $m = (int) $now->format('n');
    $d = (int) $now->format('j');
    if (!empty($_GET['fed']) && preg_match('/^(\d{1,2})-(\d{1,2})$/', $_GET['fed'], $mm)) {
        $gm = (int) $mm[1]; $gd = (int) $mm[2];
        if ($gm >= 1 && $gm <= 12 && $gd >= 1 && $gd <= 31) { $m = $gm; $d = $gd; }
    }
    $date = $now->setDate((int) $now->format('Y'), $m, $d);
    $calendar_path = defined('FEA_EVANGELIO_CALENDAR_PATH')
        ? FEA_EVANGELIO_CALENDAR_PATH
        : WP_CONTENT_DIR . '/fea-data/calendario-liturgico-2026-2040.json';
    $calendar = is_readable($calendar_path)
        ? json_decode((string) file_get_contents($calendar_path), true)
        : null;
    $book_index = (int) ($calendar['dates'][$date->format('Y-m-d')]['book_index'] ?? 0);

    $find_text = function($index) {
        global $wpdb;
        if ($index < 1) return null;
        $id = $wpdb->get_var($wpdb->prepare(
            "SELECT p.ID FROM {$wpdb->posts} p
             JOIN {$wpdb->postmeta} pm ON pm.post_id = p.ID
             WHERE pm.meta_key = '_fea_book_index' AND pm.meta_value = %d
               AND p.post_type = 'post' AND p.post_status = 'publish'
             ORDER BY p.ID ASC LIMIT 1",
            $index));
        return $id ? get_post((int) $id) : null;
    };
    $texto = $find_text($book_index);
    // El vídeo queda deliberadamente con el índice civil heredado: su catálogo
    // no forma parte de la migración litúrgica de #20.
    $titulo_dia = $d . ' ' . $MESES[$m];
    $find_video = function() use ($titulo_dia) {
        global $wpdb;
        $id = $wpdb->get_var($wpdb->prepare(
            "SELECT p.ID FROM {$wpdb->posts} p
             JOIN {$wpdb->term_relationships} tr ON tr.object_id = p.ID
             JOIN {$wpdb->term_taxonomy} tt ON tt.term_taxonomy_id = tr.term_taxonomy_id
             WHERE tt.taxonomy = 'category' AND tt.term_id = 15
               AND p.post_type = 'post' AND p.post_status = 'publish'
               AND LOWER(TRIM(p.post_title)) = %s
             ORDER BY p.ID ASC LIMIT 1", $titulo_dia));
        return $id ? get_post((int) $id) : null;
    };
    $video = $find_video();
    // Hasta que el importador instale el JSON y reindexe, conservar el contenido
    // civil heredado evita dejar la pestaña de texto en blanco durante el despliegue.
    if (!$texto && !$book_index) {
        $legacy_text = function() use ($titulo_dia) {
            global $wpdb;
            $id = $wpdb->get_var($wpdb->prepare(
                "SELECT p.ID FROM {$wpdb->posts} p
                 JOIN {$wpdb->term_relationships} tr ON tr.object_id = p.ID
                 JOIN {$wpdb->term_taxonomy} tt ON tt.term_taxonomy_id = tr.term_taxonomy_id
                 WHERE tt.taxonomy = 'category' AND tt.term_id = 14
                   AND p.post_type = 'post' AND p.post_status = 'publish'
                   AND LOWER(TRIM(p.post_title)) = %s
                 ORDER BY p.ID ASC LIMIT 1", $titulo_dia));
            return $id ? get_post((int) $id) : null;
        };
        $texto = $legacy_text();
    }

    // navegación por día del calendario (año irrelevante; usamos un año bisiesto fijo)
    $base = get_permalink();
    $cur  = DateTimeImmutable::createFromFormat('!Y-n-j', '2024-' . $m . '-' . $d, $tz);
    $prev = $cur->modify('-1 day');
    $next = $cur->modify('+1 day');
    $lbl  = function($dt) use ($MESES) { return ((int)$dt->format('j')) . ' ' . substr($MESES[(int)$dt->format('n')], 0, 3); };
    $href = function($dt) use ($base) { return esc_url(add_query_arg('fed', $dt->format('n') . '-' . $dt->format('j'), $base)); };

    $render = function($post, $tipo) {
        if (!$post) {
            return '<p class="fea-eed-empty">No hay ' . ($tipo === 'video' ? 'vídeo' : 'texto') . ' disponible para este día.</p>';
        }
        $c = apply_filters('the_content', $post->post_content);
        return '<div class="fea-eed-art">' . $c . '</div>';
    };

    $css = '<style>'
        . '.fea-eed{max-width:760px;margin:0 auto}'
        . '.fea-eed-head{display:flex;align-items:center;justify-content:space-between;gap:.5rem;margin:.2rem 0 1.1rem}'
        . '.fea-eed-date{font-size:1.15rem;color:#8b1a2e;margin:0;text-align:center;flex:1}'
        . '.fea-eed-nav{white-space:nowrap;color:#8b1a2e;text-decoration:none;font-weight:600;font-size:.9rem;padding:.3rem .6rem;border:1px solid #e2cdd2;border-radius:8px}'
        . '.fea-eed-nav:hover{background:#faf3f4}'
        . '.fea-eed-tabs input{position:absolute;opacity:0;pointer-events:none}'
        . '.fea-eed-labels{display:flex;gap:.5rem;border-bottom:2px solid #e2cdd2;margin-bottom:1.2rem}'
        . '.fea-eed-labels label{flex:1;text-align:center;cursor:pointer;padding:.6rem 1rem;font-weight:700;color:#888;border:2px solid transparent;border-bottom:none;border-radius:8px 8px 0 0;margin-bottom:-2px}'
        . '#fed-texto:checked~.fea-eed-labels label[for=fed-texto],'
        . '#fed-video:checked~.fea-eed-labels label[for=fed-video]{color:#8b1a2e;border-color:#e2cdd2;background:#faf3f4}'
        . '.fea-eed-panel{display:none}'
        . '#fed-texto:checked~.fea-eed-panel-texto{display:block}'
        . '#fed-video:checked~.fea-eed-panel-video{display:block}'
        . '.fea-eed-art iframe{max-width:100%}'
        . '.fea-eed-panel-video .fea-eed-art iframe{width:100%;max-width:600px;height:auto;aspect-ratio:16/9;display:block;margin:0 auto}'
        . '.fea-eed-art h1{font-size:1.4rem;line-height:1.3;text-align:center}'
        . '.fea-eed-empty{color:#888;font-style:italic;text-align:center;padding:1.5rem}'
        . '.wp-block-post-title{text-align:center}'
        . '</style>';

    $h  = $css . '<div class="fea-eed">';
    $h .= '<div class="fea-eed-head">'
        . '<a class="fea-eed-nav" href="' . $href($prev) . '">&lsaquo; ' . esc_html($lbl($prev)) . '</a>'
        . '<h2 class="fea-eed-date">' . esc_html($d . ' de ' . $MESES[$m]) . '</h2>'
        . '<a class="fea-eed-nav" href="' . $href($next) . '">' . esc_html($lbl($next)) . ' &rsaquo;</a>'
        . '</div>';
    $h .= '<div class="fea-eed-tabs">'
        . '<input type="radio" name="fed-tab" id="fed-texto" checked>'
        . '<input type="radio" name="fed-tab" id="fed-video">'
        . '<div class="fea-eed-labels">'
        . '<label for="fed-texto">A la fuente cada día</label>'
        . '<label for="fed-video">Otro evangelio es posible (vídeo)</label>'
        . '</div>'
        . '<div class="fea-eed-panel fea-eed-panel-texto">' . $render($texto, 'texto') . '</div>'
        . '<div class="fea-eed-panel fea-eed-panel-video">' . $render($video, 'video') . '</div>'
        . '</div></div>';
    return $h;
});

// ── Shortcode: [fea_eucaristia] ───────────────────────────────────────────
// Fuente principal: sección "Para unas eucaristías más participativas" de la carta.
// Fallback: cat 1648 por fecha.
add_shortcode('fea_eucaristia', function($atts) {
    $lang   = fea_current_lang();
    $labels = fea_labels();
    $atts   = shortcode_atts(['titulo' => $labels['eucaristia']], $atts);

    $posts = function_exists('fea_carta_section_posts') ? fea_carta_section_posts('eucaristia', $lang) : [];

    if (empty($posts)) {
        $posts = get_posts([
            'posts_per_page' => 6,
            'category__in'   => [fea_cat(1648)],
            'post_status'    => 'publish',
            'orderby'        => 'date',
            'order'          => 'DESC',
        ]);
    }
    if (!$posts) return '';

    $html = '<section class="fea-section">'
          . '<h2 class="fea-section-title">' . esc_html($atts['titulo']) . '</h2>'
          . '<div class="fea-grid">';
    foreach ($posts as $post) $html .= fea_card($post);
    return $html . '</div></section>';
});

// ── Shortcode: [fea_multimedia] ───────────────────────────────────────────
// Fuente principal: sección "Material multimedia" de la carta vigente.
// Fallbacks: ACF portada_multimedia → últimos por categoría.
add_shortcode('fea_multimedia', function($atts) {
    $lang   = fea_current_lang();
    // Multimedia es contenido ES y externo (sin traducir) → solo se muestra en
    // español de momento; en otros idiomas la sección se oculta (#135).
    if ($lang !== 'es') return '';
    $labels = fea_labels();
    $atts   = shortcode_atts(['titulo' => $labels['multimedia']], $atts);
    $page   = fea_front_page_id();
    $more_labels = [
        'es' => 'Ver más',
        'en' => 'View all',
        'fr' => 'Voir plus',
        'it' => 'Vedi tutto',
        'pt' => 'Ver mais',
    ];
    $more_label = $more_labels[$lang] ?? $more_labels['es'];
    $index_id   = 18977;
    if ($lang !== 'es' && function_exists('pll_get_post')) {
        $translated_index = (int) pll_get_post($index_id, $lang);
        if ($translated_index) $index_id = $translated_index;
    }
    $index_url = get_permalink($index_id);

    $posts = function_exists('fea_carta_section_posts') ? fea_carta_section_posts('multimedia', $lang) : [];

    if (empty($posts) && $lang === 'es' && function_exists('get_field')) {
        $seleccion = get_field('portada_multimedia', $page) ?: [];
        foreach ($seleccion as $p) {
            if ($p->post_status === 'publish') $posts[] = $p;
        }
    }

    if (empty($posts)) {
        $posts = get_posts([
            'posts_per_page' => 4,
            'category__in'   => array_map('fea_cat', [1649, 26, 58]),
            'post_status'    => 'publish',
            'orderby'        => 'date',
            'order'          => 'DESC',
        ]);
    }
    if (!$posts) return '';

    $html = '<section class="fea-section">'
          . '<div class="fea-section-head">'
          . '<h2 class="fea-section-title">' . esc_html($atts['titulo']) . '</h2>'
          . ($index_url ? '<a class="fea-section-more" href="' . esc_url($index_url) . '">'
              . esc_html($more_label) . ' <span aria-hidden="true">→</span></a>' : '')
          . '</div>'
          . '<div class="fea-grid">';
    foreach ($posts as $post) $html .= fea_card($post);
    return $html . '</div></section>';
});

// ── Shortcode: [fea_noticia_centro] — bloque central del footer (Noticias) ───
add_shortcode('fea_noticia_centro', function() {
    $uploads  = wp_upload_dir()['baseurl'];
    $cat_url  = get_category_link(fea_cat(41));
    $latest   = get_posts([
        'posts_per_page' => 1,
        'category__in'   => [fea_cat(41)],
        'post_status'    => 'publish',
        'orderby'        => 'date',
        'order'          => 'DESC',
    ]);
    $title = !empty($latest) ? fea_title($latest[0]->post_title) : '';
    $url   = !empty($latest) ? get_permalink($latest[0]->ID) : $cat_url;

    $html  = '<a href="' . esc_url($cat_url) . '">';
    $html .= '<img src="' . esc_url($uploads . '/recursos/noticias_2025.jpg') . '" '
           . 'alt="Noticias de alcance" width="300" height="340" '
           . 'style="display:block;margin:0 auto;" />';
    $html .= '</a>';
    if ($title) {
        $html .= '<p style="text-align:center;margin-top:0.5rem;font-size:0.85rem;font-weight:600;line-height:1.3;">'
               . '<a href="' . esc_url($url) . '" style="color:#0000cc;">'
               . esc_html($title) . '</a></p>';
    }
    return $html;
});

// ── Reescribir links internos al idioma activo (Polylang) ─────────────────
add_filter('the_content', function($content) {
    if (!function_exists('pll_current_language') || !function_exists('pll_get_post')) return $content;
    $lang = pll_current_language();
    if (!$lang || $lang === 'es') return $content;
    // Los archivos de cartas pueden contener cientos de enlaces. Resolver cada uno
    // con url_to_postid() en un listado agota memoria; la reescritura solo aporta
    // valor al mostrar el contenido completo de una entrada o página.
    if (!is_singular()) return $content;

    return preg_replace_callback(
        '/<a\s([^>]*\s)?href=["\']([^"\']+)["\']([^>]*)>/i',
        function($m) use ($lang) {
            $href = $m[2];
            $home = home_url();
            if (strpos($href, $home) === false) return $m[0];

            $post_id = url_to_postid($href);
            if (!$post_id) return $m[0];

            $translated_id = pll_get_post($post_id, $lang);
            if (!$translated_id || $translated_id === $post_id) return $m[0];

            $new_url = get_permalink($translated_id);
            if (!$new_url) return $m[0];

            return str_replace($href, $new_url, $m[0]);
        },
        $content
    );
}, 20);

// ── Ordenar categoría Evangelios y Comentarios por título ASC ─────────────
add_action('pre_get_posts', function($query) {
    if ($query->is_main_query() && $query->is_category('evangelios-y-comentarios')) {
        $query->set('orderby', 'title');
        $query->set('order', 'ASC');
    }
});


// ── Acordeón de versículos en posts de Evangelios y Comentarios ───────────
add_action('wp_footer', function() {
    if (!is_single()) return;
    global $post;
    if (!has_category('evangelios-y-comentarios', $post)) return;
    ?>
    <style>
    .versiculo-group { margin: 0.5em 0; }
    .versiculo-toggle {
        display: flex; align-items: center; gap: 10px;
        cursor: default; margin: 0.8em 0 0;
    }
    .versiculo-toggle .v-icon {
        display: inline-flex; align-items: center; justify-content: center;
        width: 22px; height: 22px; min-width: 22px; border-radius: 50%;
        background: #c8860a; color: white; font-size: 18px; line-height: 1;
        cursor: pointer; user-select: none; font-weight: bold;
        transition: background 0.15s;
    }
    .versiculo-group.open .v-icon { background: #6b3080; }
    .v-icon::after { content: '+'; }
    .versiculo-group.open .v-icon::after { content: '\2212'; }
    .versiculo-body { display: none; padding-left: 4px; }
    .versiculo-group.open .versiculo-body { display: block; }
    </style>
    <script>
    document.addEventListener('DOMContentLoaded', function() {
        var content = document.querySelector('.wp-block-post-content, .entry-content');
        if (!content) return;

        var verseRe = /^(JUAN|LUCAS|MARCOS|MATEO)\s+\d/i;

        function isVerse(el) {
            if (el.tagName !== 'P') return false;
            var links = el.querySelectorAll('a');
            if (links.length !== 1) return false;
            return verseRe.test(el.textContent.trim());
        }

        var children = Array.from(content.children);
        var i = 0;
        while (i < children.length) {
            var child = children[i];
            if (isVerse(child)) {
                var group = document.createElement('div');
                group.className = 'versiculo-group';

                var header = document.createElement('div');
                header.className = 'versiculo-toggle';

                var icon = document.createElement('span');
                icon.className = 'v-icon';

                var link = child.querySelector('a').cloneNode(true);
                header.appendChild(icon);
                header.appendChild(link);
                group.appendChild(header);

                var body = document.createElement('div');
                body.className = 'versiculo-body';

                child.parentNode.insertBefore(group, child);
                child.remove();
                i++;

                while (i < children.length && !isVerse(children[i])) {
                    body.appendChild(children[i]);
                    i++;
                }

                group.appendChild(body);

                icon.addEventListener('click', function() {
                    this.closest('.versiculo-group').classList.toggle('open');
                });
            } else {
                i++;
            }
        }
    });
    </script>
    <?php
}, 30);

// ── Avatares en artículos de versículos (Evangelios y Comentarios) ─────────
add_action('wp_footer', function() {
    if (!is_single()) return;
    global $post, $wpdb;
    if (!has_category('evangelios-y-comentarios', $post)) return;

    // Extraer todos los slugs de links internos del contenido
    preg_match_all('/<a\s[^>]*href=["\']([^"\']+)["\']/', $post->post_content, $m);
    $slugs = [];
    foreach ($m[1] as $url) {
        $slug = basename(rtrim(parse_url($url, PHP_URL_PATH), '/'));
        if ($slug) {
            $slugs[] = $slug;
        }
    }
    $slugs = array_values(array_unique(array_filter($slugs)));
    if (empty($slugs)) return;

    // Una sola query: slug → author_id
    $ph   = implode(',', array_fill(0, count($slugs), '%s'));
    $rows = $wpdb->get_results(
        $wpdb->prepare(
            "SELECT post_name, post_author FROM {$wpdb->posts}
             WHERE post_name IN ($ph) AND post_status IN ('publish','draft') AND post_type='post'",
            $slugs
        )
    );

    // Construir mapa slug → avatar_url (reutilizando cache de autor)
    $author_cache = [];
    $avatar_map   = [];
    foreach ($rows as $row) {
        $aid = (int) $row->post_author;
        if (!isset($author_cache[$aid])) {
            $user = get_userdata($aid);
            $author_cache[$aid] = ['src' => get_avatar_url($aid, ['size' => 40, 'default' => 'identicon']), 'name' => $user ? $user->display_name : ''];
        }
        if ($author_cache[$aid]) {
            $avatar_map[$row->post_name] = $author_cache[$aid];
        }
    }
    if (empty($avatar_map)) return;
    ?>
    <style>
    .versiculo-body ul { padding-left: 0; list-style: none; }
    .versiculo-body li { display: flex; align-items: center; gap: 7px; margin-bottom: 4px; }
    .fea-li-avatar { width: 24px; height: 24px; border-radius: 50%; object-fit: cover; flex-shrink: 0; }
    .transl-toggle { font-size: 11px; color: #888; cursor: pointer; margin-left: 6px; user-select: none; white-space: nowrap; flex-shrink: 0; }
    .transl-toggle:hover { color: #777; }
    .transl-block { display: none; margin: 2px 0 6px 32px; font-size: 11px; line-height: 1.8; }
    .transl-block.open { display: block; }
    .transl-block a { color: #aaa; display: block; }
    .transl-block a:hover { color: #555; }
    </style>
    <script>
    (function() {
        var map = <?php echo json_encode($avatar_map); ?>;
        function slug(url) {
            return url.replace(/\/$/, '').split('/').pop().split('?')[0].split('#')[0];
        }
        document.addEventListener('DOMContentLoaded', function() {
            document.querySelectorAll('.versiculo-body li').forEach(function(li) {
                var a = li.querySelector('a');
                if (!a) return;
                var entry = map[slug(a.href)];
                if (!entry) return;
                var img = document.createElement('img');
                img.src = entry.src;
                img.title = entry.name;
                img.alt = '';
                img.className = 'fea-li-avatar';
                li.insertBefore(img, li.firstChild);
            });

            // Colapsar traducciones (p margin-left:90px) bajo "(…)"
            document.querySelectorAll('.versiculo-body').forEach(function(body) {
                Array.from(body.children).forEach(function(el) {
                    if (el.tagName !== 'P') return;
                    var ml = parseInt(el.style.marginLeft || '0');
                    if (ml < 60) return;
                    var prev = el.previousElementSibling;
                    while (prev && prev.tagName !== 'UL') prev = prev.previousElementSibling;
                    if (!prev) return;
                    var lis = prev.querySelectorAll('li');
                    if (!lis.length) return;
                    var lastLi = lis[lis.length - 1];
                    el.classList.add('transl-block');
                    var btn = document.createElement('span');
                    btn.className = 'transl-toggle';
                    btn.textContent = 'Otros idiomas (\u2026)';
                    lastLi.appendChild(btn);
                    btn.addEventListener('click', function(e) {
                        e.stopPropagation();
                        el.classList.toggle('open');
                    });
                });
            });
        });
    })();
    </script>
    <?php
}, 31);


// ── Shortcodes lista de autores ────────────────────────────────────────────

// IDs excluidos: Fe Adulta (1,890), Ediciones Feadulta (1540), José Chicharro (1049)
if (!defined('FEA_AUTORES_EXCLUIR')) define('FEA_AUTORES_EXCLUIR', [1, 890, 1049, 1540]);
if (!defined('FEA_LANG_ES_TTID'))   define('FEA_LANG_ES_TTID',   1404);

function fea_autores_query($min_count = 0, $extra_exclude = []) {
    global $wpdb;
    $excl   = implode(',', array_merge(FEA_AUTORES_EXCLUIR, $extra_exclude));
    $ttid   = FEA_LANG_ES_TTID;
    $having = $min_count > 0 ? "HAVING cnt >= $min_count" : '';
    $order  = $min_count > 0 ? 'cnt DESC' : 'u.display_name ASC';
    return $wpdb->get_results("
        SELECT u.ID, u.display_name, COUNT(*) as cnt
        FROM {$wpdb->posts} p
        JOIN {$wpdb->term_relationships} tr ON tr.object_id = p.ID
        JOIN {$wpdb->users} u ON u.ID = p.post_author
        WHERE p.post_type = 'post'
          AND p.post_status = 'publish'
          AND tr.term_taxonomy_id = $ttid
          AND u.ID NOT IN ($excl)
        GROUP BY p.post_author
        $having
        ORDER BY $order
    ");
}

function fea_autores_html($rows, $show_count = false, $extra_class = "") {
    $extra = $extra_class ? ' ' . $extra_class : '';
    $out = '<ul class="fea-autores-lista' . $extra . '" style="list-style:none;padding-left:0;">';
    foreach ($rows as $r) {
        $url    = esc_url(get_author_posts_url($r->ID));
        $name   = esc_html($r->display_name);
        $avatar = esc_url(get_avatar_url($r->ID, ['size' => 40, 'default' => 'identicon']));
        $cnt    = $show_count ? ' <span class="fea-autor-cnt">(' . $r->cnt . ')</span>' : '';
        $out   .= '<li><span style="display:inline-block;width:40px;height:40px;min-width:40px;border-radius:50%;overflow:hidden;flex-shrink:0;"><img src="' . $avatar . '" width="40" height="40" alt="" loading="lazy" style="width:40px;height:40px;object-fit:cover;display:block;"></span>&nbsp;&nbsp;<a href="' . $url . '">' . $name . '</a>' . $cnt . '</li>';
    }
    $out .= '</ul>';
    return $out;
}

add_shortcode('fea_autores_habituales', function() {
    $rows = fea_autores_query(30, [948, 1048]);
    if (empty($rows)) return '<p>No hay datos disponibles.</p>';
    $n   = count($rows);
    $out = '<details class="fea-autores-section"><summary class="fea-autores-summary">Autores habituales <span class="fea-autor-cnt">(' . $n . ' autores)</span></summary>';
    $out .= fea_autores_html($rows, true);
    $out .= '</details>';
    return $out;
});

add_shortcode('fea_autores_completo', function() {
    $rows = fea_autores_query(0);
    if (empty($rows)) return '<p>No hay datos disponibles.</p>';
    $n   = count($rows);
    $out = '<details class="fea-autores-section"><summary class="fea-autores-summary">Lista completa por orden alfabético <span class="fea-autor-cnt">(' . $n . ' autores)</span></summary>';
    $out .= fea_autores_html($rows, false, 'fea-autores-completo');
    $out .= '</details>';
    return $out;
});

add_action('wp_head', function() {
    if (!is_page('autores-lista')) return;
    ?>
    <style>
    .fea-autores-section { margin-bottom: 1.5em; }
    .fea-autores-summary {
        font-size: 1.3rem; font-weight: 600; cursor: pointer;
        padding: 0.5em 0; list-style: none;
        display: flex; align-items: center; gap: 0.5em;
        border-bottom: 2px solid #046bd2; margin-bottom: 0.8em;
        user-select: none;
    }
    .fea-autores-summary::-webkit-details-marker { display: none; }
    .fea-autores-summary::before {
        content: "\25B6"; font-size: 0.75em; color: #046bd2;
        transition: transform 0.2s; display: inline-block;
    }
    details[open] > .fea-autores-summary::before { transform: rotate(90deg); }
    .fea-autores-lista { list-style: none; padding: 0; margin: 0.5em 0 1em; }
    .fea-autores-lista li {
        display: flex; align-items: center; gap: 12px;
        padding: 3px 0; border-bottom: 1px solid #f5f5f5;
    }
    .fea-autores-lista li img.fea-autor-avatar {
        width: 40px; height: 40px; min-width: 40px;
        border-radius: 50%; clip-path: circle(50%);
        object-fit: cover; display: block; flex-shrink: 0;
    }
    .fea-autor-cnt { color: #888; font-size: 0.85em; }
    .fea-autores-completo { column-count: 3; column-gap: 2em; }
    .fea-autores-completo li { break-inside: avoid; }
    @media (max-width: 700px) { .fea-autores-completo { column-count: 2; } }
    @media (max-width: 480px) { .fea-autores-completo { column-count: 1; } }
    </style>
    <?php
}, 20);

// ── Aumentar posts por página en archivos de autor ─────────────────────────
add_action('pre_get_posts', function($query) {
    if ($query->is_main_query() && $query->is_author()) {
        $query->set('posts_per_page', 30);
    }
});

// ── Shortcodes EFFA (Escuela de Formación en Fe Adulta) ────────────────────

// Sección de vídeos (subpáginas): thumbnail YT o primera imagen del contenido
add_shortcode('effa_seccion', function($atts) {
    $atts = shortcode_atts(['cat' => '', 'num' => -1], $atts);
    if (!$atts['cat']) return '';

    $posts = get_posts([
        'numberposts'   => (int) $atts['num'],
        'category_name' => $atts['cat'],
        'post_status'   => 'publish',
        'orderby'       => 'meta_value',
        'meta_key'      => '_effa_joomla_alias',
        'order'         => 'ASC',
    ]);

    if (!$posts) return '<p>No hay contenido en esta sección todavía.</p>';

    $items = [];
    foreach ($posts as $p) {
        $url   = get_permalink($p->ID);
        $thumb = get_the_post_thumbnail_url($p->ID, 'medium');
        if (!$thumb && preg_match('~youtube\.com/watch\?v=([a-zA-Z0-9_-]+)~', $p->post_content, $m)) {
            $thumb = 'https://img.youtube.com/vi/' . $m[1] . '/mqdefault.jpg';
        }
        if (!$thumb && preg_match('~<img[^>]+src="([^"]+)"~', $p->post_content, $mi)) {
            $thumb = $mi[1];
        }
        $cell  = '<td style="width:25%;padding:6px;vertical-align:top;">';
        $cell .= '<a href="' . esc_url($url) . '" style="text-decoration:none;color:inherit;display:block;">';
        if ($thumb) $cell .= '<img src="' . esc_url($thumb) . '" style="width:100%;height:auto;display:block;border-radius:4px;">';
        $cell .= '<strong style="display:block;font-size:0.85rem;margin-top:5px;color:#222;">' . esc_html(fea_title($p->post_title)) . '</strong>';
        $cell .= '</a>';
        $cell .= '</td>';
        $items[] = $cell;
    }

    $html = '<table class="effa-proyecto-table" style="width:100%;border-collapse:collapse;table-layout:fixed;">';
    foreach (array_chunk($items, 4) as $row) {
        while (count($row) < 4) $row[] = '<td></td>';
        $html .= '<tr>' . implode('', $row) . '</tr>';
    }
    $html .= '</table>';
    return $html;
});

// Hub del proyecto (8 artículos de presentación): primera imagen + extracto
add_shortcode('effa_proyecto', function() {
    $posts = get_posts([
        'numberposts'   => -1,
        'category_name' => 'proyecat',
        'post_status'   => 'publish',
        'orderby'       => 'name',
        'order'         => 'ASC',
    ]);
    if (!$posts) return '';

    $items = [];
    foreach ($posts as $p) {
        $url    = get_permalink($p->ID);
        preg_match('~<img[^>]+src="([^"]+)"~', $p->post_content, $mi);
        $thumb   = $mi[1] ?? '';
        $text    = trim(preg_replace('/\s+/', ' ', wp_strip_all_tags($p->post_content)));
        $excerpt = wp_trim_words($text, 12, '…');

        $cell  = '<td style="width:25%;padding:6px;vertical-align:top;">';
        $cell .= '<a href="' . esc_url($url) . '" style="text-decoration:none;color:inherit;display:block;">';
        if ($thumb) $cell .= '<img src="' . esc_url($thumb) . '" style="width:100%;height:auto;display:block;border-radius:4px;">';
        $cell .= '<strong style="display:block;font-size:0.85rem;margin-top:5px;color:#222;">' . esc_html(fea_title($p->post_title)) . '</strong>';
        $cell .= '</a>';
        $cell .= '<span style="display:block;font-size:0.75rem;color:#666;margin-top:3px;line-height:1.3;">' . esc_html($excerpt) . '</span>';
        $cell .= '</td>';
        $items[] = $cell;
    }

    $html = '<table class="effa-proyecto-table" style="width:100%;border-collapse:collapse;table-layout:fixed;">';
    foreach (array_chunk($items, 4) as $row) {
        while (count($row) < 4) $row[] = '<td></td>';
        $html .= '<tr>' . implode('', $row) . '</tr>';
    }
    $html .= '</table>';
    return $html;
});

// CSS EFFA (tabs nav, logo, CTA, cards)
add_action('wp_head', function() {
    global $post;
    if (!$post || (strpos($post->post_content, 'effa_') === false && strpos($post->post_name ?? '', 'effa') === false)) return;
    ?>
    <style>
    .effa-logo { display: block; margin: 0 auto 1rem; max-width: 200px; }
    .effa-intro { text-align: center; margin-bottom: 1.5rem; }
    .effa-nav { display: flex; flex-wrap: wrap; gap: 0.5rem; margin: 1.5rem 0 2rem; padding: 0 0 1rem; list-style: none; border-bottom: 2px solid #e5e5e5; }
    .effa-nav li { list-style: none; }
    .effa-nav a { display: inline-block; padding: 0.35em 1em; border: 1px solid #ccc; border-radius: 999px; font-size: 0.85rem; text-decoration: none; color: #444; transition: background 0.15s, color 0.15s, border-color 0.15s; }
    .effa-nav a:hover, .effa-nav a.active { background: #E89A1A; color: #fff; border-color: #E89A1A; }
    .effa-cta-wrap { text-align: center; margin: 2rem 0 1rem; }
    .effa-cta { display: inline-block; padding: 0.6em 1.8em; background: #E89A1A; color: #fff; border-radius: 999px; text-decoration: none; font-weight: 700; font-size: 1rem; }
    .effa-cta:hover { background: #c97d10; color: #fff; }
    /* Tarjetas EFFA: reflota de 4 columnas a 2 en movil */
    @media (max-width: 600px) {
        .effa-proyecto-table tr { display: flex; flex-wrap: wrap; }
        .effa-proyecto-table td { width: 50% !important; box-sizing: border-box; }
        .effa-proyecto-table td:empty { display: none; }
    }
    </style>
    <?php
}, 20);

// ── Índice dinámico de evangelio por libro ─────────────────────────────────

// "Jn 4, 5-42" → "jn-4-5-42"  (anchor ID format)
function fea_cita_to_anchor(string $cita): string {
    return strtolower(preg_replace('/[,\.\s]+/', '-', trim($cita)));
}

// Parse "Jn 4, 5-42" → [4, 5] for numeric sorting
function fea_cita_sort_key(string $cita): array {
    preg_match('/(\d+),\s*(\d+)/', $cita, $m);
    return [(int)($m[1] ?? 0), (int)($m[2] ?? 0)];
}

add_shortcode('fea_citas_evangelio', function($atts) {
    $atts  = shortcode_atts(['libro' => 'Jn'], $atts);
    $libro = preg_replace('/[^A-Za-z]/', '', $atts['libro']); // sanitize
    global $wpdb;
    $cat_com = 1647;

    // One query: all posts + author + avatar email in this book
    $rows = $wpdb->get_results($wpdb->prepare(
        "SELECT p.ID, p.post_title, p.post_author,
                pm.meta_value  AS cita,
                u.display_name AS autor_name,
                u.user_email   AS autor_email
         FROM {$wpdb->posts} p
         JOIN {$wpdb->postmeta} pm  ON pm.post_id = p.ID AND pm.meta_key = '_cita_evangelio'
         JOIN {$wpdb->term_relationships} tr ON tr.object_id = p.ID
         JOIN {$wpdb->term_taxonomy} tt ON tt.term_taxonomy_id = tr.term_taxonomy_id AND tt.term_id = %d
         JOIN {$wpdb->users} u ON u.ID = p.post_author
         WHERE p.post_status = 'publish'
           AND pm.meta_value LIKE %s
         ORDER BY pm.meta_value, p.post_date ASC",
        $cat_com, $libro . ' %'
    ));

    if (empty($rows)) return '<p>No hay comentarios para este evangelio.</p>';

    // Group by cita
    $groups = [];
    foreach ($rows as $r) $groups[$r->cita][] = $r;

    // Sort groups numerically by chapter, then verse
    uksort($groups, function($a, $b) {
        [$ca, $va] = fea_cita_sort_key($a);
        [$cb, $vb] = fea_cita_sort_key($b);
        return $ca !== $cb ? $ca - $cb : $va - $vb;
    });

    // Avatar URL by email (Gravatar, with fallback)
    $avatar_cache = [];
    $avatar_url = function(string $email, int $id) use (&$avatar_cache): string {
        if (!isset($avatar_cache[$id])) {
            $url = get_avatar_url($id, ['size' => 40, 'default' => 'mystery']);
            $avatar_cache[$id] = $url ?: 'https://www.gravatar.com/avatar/' . md5(strtolower(trim($email))) . '?s=40&d=mystery';
        }
        return $avatar_cache[$id];
    };

    $html = '<div class="fea-indice-evangelio">';

    foreach ($groups as $cita => $posts) {
        $n      = count($posts);
        $anchor = fea_cita_to_anchor($cita);
        $html .= '<details class="fea-cita-group" id="' . esc_attr($anchor) . '">';
        $html .= '<summary class="fea-cita-summary">'
               . '<span class="fea-cita-ref">' . esc_html($cita) . '</span>'
               . ' <span class="fea-cita-count">' . $n . ' comentario' . ($n !== 1 ? 's' : '') . '</span>'
               . '</summary>';
        $html .= '<ul class="fea-cita-lista">';
        foreach ($posts as $p) {
            $av  = $avatar_url($p->autor_email, $p->post_author);
            $html .= '<li class="fea-cita-item">'
                   . '<span class="fea-cita-avatar">'
                   . '<img src="' . esc_url($av) . '" width="40" height="40" alt="" loading="lazy">'
                   . '</span>'
                   . '<span class="fea-cita-meta">'
                   . '<a href="' . esc_url(get_permalink($p->ID)) . '">' . esc_html(fea_title($p->post_title)) . '</a>'
                   . '<span class="fea-cita-autor">' . esc_html($p->autor_name) . '</span>'
                   . '</span>'
                   . '</li>';
        }
        $html .= '</ul></details>';
    }

    $html .= '</div>';
    return $html;
});

add_action('wp_head', function() {
    global $post;
    if (!$post || !has_shortcode($post->post_content, 'fea_citas_evangelio')) return;
    ?>
    <style>
    .fea-indice-evangelio { margin: 1.5rem 0; }

    .fea-cita-group {
        border-bottom: 1px solid #e5e5e5;
        padding: 0;
    }
    .fea-cita-summary {
        display: flex;
        align-items: baseline;
        gap: 0.6rem;
        padding: 0.75rem 0.5rem;
        cursor: pointer;
        list-style: none;
        user-select: none;
    }
    .fea-cita-summary::-webkit-details-marker { display: none; }
    .fea-cita-summary::before {
        content: '›';
        font-size: 1.1rem;
        color: #046bd2;
        transition: transform 0.15s;
        display: inline-block;
        flex-shrink: 0;
    }
    .fea-cita-group[open] > .fea-cita-summary::before { transform: rotate(90deg); }
    .fea-cita-ref {
        font-weight: 700;
        font-size: 0.95rem;
    }
    .fea-cita-count {
        font-size: 0.8rem;
        color: #888;
    }

    .fea-cita-lista {
        list-style: none;
        padding: 0 0 0.75rem 1.5rem;
        margin: 0;
        display: flex;
        flex-direction: column;
        gap: 0.5rem;
    }
    .fea-cita-item {
        display: flex;
        align-items: center;
        gap: 0.75rem;
    }
    .fea-cita-avatar {
        display: inline-block;
        width: 40px; height: 40px; min-width: 40px;
        border-radius: 50%;
        overflow: hidden;
        flex-shrink: 0;
    }
    .fea-cita-avatar img {
        width: 40px; height: 40px;
        object-fit: cover; display: block;
    }
    .fea-cita-meta {
        display: flex;
        flex-direction: column;
        gap: 0.1rem;
        line-height: 1.3;
    }
    .fea-cita-meta a { font-size: 0.9rem; }
    .fea-cita-autor {
        font-size: 0.78rem;
        color: #888;
    }
    </style>
    <?php
}, 20);

// ── Pie de comentario: carta, cita evangelio, otros comentarios ────────────

// Add id anchors to verse headings in the 4 gospel index pages
add_filter('the_content', function($content) {
    global $post;
    $index_ids = [17874, 17881, 17882, 17883];
    if (!isset($post->ID) || !in_array($post->ID, $index_ids)) return $content;

    $bookmap = ['JUAN'=>'Jn','LUCAS'=>'Lc','MARCOS'=>'Mc','MATEO'=>'Mt'];

    return preg_replace_callback(
        '~<p([^>]*)>\s*(<a[^>]*>)\s*((JUAN|LUCAS|MARCOS|MATEO)\s+(\d+),\s*([\d\-–\s]+))\s*(</a>)\s*</p>~i',
        function($m) use ($bookmap) {
            $abbr   = $bookmap[strtoupper($m[4])] ?? '';
            if (!$abbr) return $m[0];
            $anchor = strtolower($abbr . '-' . $m[5] . '-' . preg_replace('/[\s–\-]+/', '-', trim($m[6])));
            $anchor = rtrim($anchor, '-');
            return '<p' . $m[1] . ' id="' . $anchor . '">' . $m[2] . $m[3] . $m[7] . '</p>';
        },
        $content
    );
}, 9); // priority 9 so it runs before the_content shortcode processing

add_filter('the_content', function($content) {
    if (!is_single()) return $content;
    global $post;
    if (!in_category('comentarios-al-evangelio', $post)) return $content;

    $carta_id = function_exists('fea_evangelio_comment_meta')
        ? fea_evangelio_comment_meta($post->ID, '_carta_id')
        : get_post_meta($post->ID, '_carta_id', true);
    $cita = function_exists('fea_evangelio_comment_meta')
        ? fea_evangelio_comment_meta($post->ID, '_cita_evangelio')
        : get_post_meta($post->ID, '_cita_evangelio', true);

    if (!$carta_id && !$cita) return $content;

    $html  = '<div class="fea-com-footer">';

    // --- Carta de la semana ---
    if ($carta_id) {
        $carta = get_post($carta_id);
        if ($carta && $carta->post_status === 'publish') {
            $fecha = date_i18n('j F Y', strtotime($carta->post_date));
            $html .= '<div class="fea-com-row fea-com-carta">'
                   . '<span class="fea-com-label">Carta de la semana</span>'
                   . '<a href="' . esc_url(get_permalink($carta_id)) . '">'
                   . esc_html(fea_title($carta->post_title))
                   . ' <span class="fea-com-fecha">(' . $fecha . ')</span>'
                   . '</a>'
                   . '</div>';
        }
    }

    // --- Otros comentarios de esta misma cita ---
    if ($cita) {
        $others = get_posts([
            'post_type'      => 'post',
            'post_status'    => 'publish',
            'posts_per_page' => 30,
            'post__not_in'   => [$post->ID],
            'category_name'  => 'comentarios-al-evangelio',
            'meta_key'       => '_cita_evangelio',
            'meta_value'     => $cita,
            'orderby'        => 'date',
            'order'          => 'ASC',
        ]);

        if (!empty($others)) {
            $html .= '<div class="fea-com-row fea-com-otros">'
                   . '<span class="fea-com-label">Otros comentarios sobre ' . esc_html($cita) . '</span>'
                   . '<ul class="fea-com-lista">';
            foreach ($others as $o) {
                $html .= '<li><a href="' . esc_url(get_permalink($o->ID)) . '">'
                       . esc_html(fea_title($o->post_title)) . '</a></li>';
            }
            $html .= '</ul></div>';
        }
    }

    $html .= '</div>'; // .fea-com-footer
    return $content . $html;
});

add_action('wp_head', function() {
    if (!is_single()) return;
    global $post;
    if (!$post || !in_category('comentarios-al-evangelio', $post)) return;
    ?>
    <style>
    .fea-com-footer {
        margin-top: 2.5rem;
        padding-top: 1.5rem;
        border-top: 2px solid #e5e5e5;
        font-size: 0.9rem;
    }
    .fea-com-row {
        display: flex;
        flex-wrap: wrap;
        gap: 0.4rem 0.8rem;
        align-items: baseline;
        margin-bottom: 1rem;
    }
    .fea-com-label {
        font-weight: 700;
        color: #555;
        white-space: nowrap;
        flex-shrink: 0;
    }
    .fea-com-label::after { content: ':'; margin-right: 0.2em; }
    .fea-com-fecha { color: #888; font-size: 0.85em; }
    .fea-com-lista {
        list-style: none;
        padding: 0;
        margin: 0.3rem 0 0;
        display: flex;
        flex-wrap: wrap;
        gap: 0.3rem 0;
        flex-direction: column;
    }
    .fea-com-lista li::before {
        content: '›';
        margin-right: 0.4em;
        color: #046bd2;
    }
    .fea-com-otros .fea-com-label { display: block; margin-bottom: 0.4rem; }
    .fea-com-otros { flex-direction: column; align-items: flex-start; }
    </style>
    <?php
}, 20);
