///... by default — using it on $illu would // strip every SVG element and leave only the blue container. $svg_allowed = array( 'svg' => array( 'viewbox' => true, 'xmlns' => true, 'fill' => true, 'width' => true, 'height' => true, 'class' => true ), 'g' => array( 'fill' => true, 'stroke' => true, 'stroke-width' => true, 'transform' => true, 'opacity' => true ), 'path' => array( 'd' => true, 'fill' => true, 'stroke' => true, 'stroke-width' => true, 'stroke-linecap' => true, 'stroke-linejoin' => true, 'opacity' => true ), 'rect' => array( 'x' => true, 'y' => true, 'width' => true, 'height' => true, 'rx' => true, 'ry' => true, 'fill' => true, 'stroke' => true, 'stroke-width' => true, 'opacity' => true ), 'circle' => array( 'cx' => true, 'cy' => true, 'r' => true, 'fill' => true, 'stroke' => true, 'stroke-width' => true, 'opacity' => true ), 'ellipse' => array( 'cx' => true, 'cy' => true, 'rx' => true, 'ry' => true, 'fill' => true, 'stroke' => true, 'stroke-width' => true, 'opacity' => true ), 'line' => array( 'x1' => true, 'y1' => true, 'x2' => true, 'y2' => true, 'stroke' => true, 'stroke-width' => true, 'stroke-linecap' => true, 'opacity' => true ), 'polyline' => array( 'points' => true, 'fill' => true, 'stroke' => true, 'stroke-width' => true, 'stroke-linecap' => true, 'stroke-linejoin' => true ), 'polygon' => array( 'points' => true, 'fill' => true, 'stroke' => true, 'stroke-width' => true ), 'text' => array( 'x' => true, 'y' => true, 'fill' => true, 'font-size' => true, 'font-family' => true, 'text-anchor' => true ), 'defs' => array(), 'lineargradient' => array( 'id' => true, 'x1' => true, 'y1' => true, 'x2' => true, 'y2' => true, 'gradientunits' => true ), 'radialgradient' => array( 'id' => true, 'cx' => true, 'cy' => true, 'r' => true ), 'stop' => array( 'offset' => true, 'stop-color' => true, 'stop-opacity' => true ), ); echo '
'; echo ''; echo '
'; echo '

' . esc_html( $title ) . '

'; echo '

' . wp_kses_post( $subtitle ) . '

'; echo '
'; if ( $actions_html !== '' ) { echo '
' . wp_kses_post( $actions_html ) . '
'; } echo '
'; // If a hub stashed its navigation for this request, render it // right below the header so the tabs sit inside the content. // The HTML is already fully escaped by render_hub_nav(). if ( class_exists( 'FLINK_Admin' ) && ! empty( FLINK_Admin::$pending_hubnav ) ) { echo wp_kses( FLINK_Admin::$pending_hubnav, FLINK_Admin::admin_kses_allowed() ); FLINK_Admin::$pending_hubnav = ''; // consume once, so it appears only under the first header on the page } } /** * SVG illustrations — one per major page. * * Design language for the whole set: * - 64×64 viewBox so each fits the 96×96 container at 2/3 size * - Same primary blue (#2563eb), light blue accents * - Same accent ambers/greens for "highlight" elements * - Conceptual not literal — communicates the page's role * in 2 seconds without a label */ private static function get_illustration( $key ) { $illustrations = array( // ── Bases de conocimiento: stacked cards + AI sparkle ────── 'kb' => ' ', // ── Páginas pilar: hub & spokes (one big circle with smaller satellites) ── 'pilares' => ' ', // ── Reglas de enlazado: word with arrow becoming a link ───── 'reglas' => ' ', // ── Enlazado semántico: brain-like network of related nodes ─ 'semantic' => ' ', // ── Mapa de enlaces / Actividad: bar chart with sparkline ─── 'exitos' => ' ', // ── Ajustes: gear with subtle accents ─────────────────────── 'ajustes' => ' ', // ── Herramientas: wrench + screwdriver crossed ────────────── 'herramientas' => ' ', // ── Crear contenido: document + AI sparkle ────────────────── 'content' => ' ', // ── Crear imágenes: image frame + sparkle ────────────────── 'images' => ' ', // ── Traducciones: globe with arrows ───────────────────────── 'translation' => ' A 文 ', // ── Automatizaciones: clock with circular arrow ──────────── 'pipeline' => ' ', // ── URLs excluidas: shield with crossed circle ────────────── 'exclusiones' => ' ', // ── Actividad / Log: timeline with dots ───────────────────── 'actividad' => ' ', ); return $illustrations[ $key ] ?? ''; } /** * Inject the shared CSS for the illustrated header. Pages call * Returns the page-header CSS as a string so callers can attach it * via wp_add_inline_style(). This is the WordPress.org-compliant way * to ship inline styles. */ public static function get_styles() { return ' .ilph-hd{ display:flex;align-items:center;justify-content:space-between;gap:24px; margin:0 0 22px;flex-wrap:wrap; } .ilph-hd-illu{ flex-shrink:0;width:96px;height:96px; display:flex;align-items:center;justify-content:center; background:linear-gradient(135deg, #eef2ff 0%, #dbeafe 100%); border:1px solid #e0e7ff; border-radius:18px; } .ilph-hd-illu svg{width:64px;height:64px;display:block;} .ilph-hd-text{flex:1;min-width:240px;} .ilph-title{ font-size:28px !important;font-weight:700 !important; letter-spacing:-.03em !important;line-height:1.1 !important; color:var(--ds-ink, #0f1419) !important;margin:0 0 6px !important; } .ilph-sub{ font-size:15px !important;color:var(--ds-ink3, #6b7280) !important; margin:0 !important;line-height:1.5 !important; } .ilph-hd-actions{display:flex;gap:8px;flex-shrink:0;align-items:center;flex-wrap:wrap;} @media (max-width:720px){ .ilph-hd-illu{width:72px;height:72px;border-radius:14px;} .ilph-hd-illu svg{width:48px;height:48px;} .ilph-title{font-size:24px !important;} .ilph-sub{font-size:14px !important;} } '; } }