'Entraînez-vous comme vous opérez.', "PROSERVE\u{2122} is the modular XR training platform engineered for European security forces. Real recoil, autonomous AI, sovereign by design \u{2014} from solo officer to full academy." => "PROSERVE\u{2122} est la plateforme XR modulaire conçue pour les forces de sécurité européennes. Recul réel, IA autonome, souveraineté native \u{2014} de l'agent seul à l'académie complète.", // 3 pillars row 'Three certainties' => 'Trois certitudes', 'A platform engineered around three commitments.' => 'Une plateforme construite autour de trois engagements.', 'Operational reality' => 'Réalité opérationnelle', 'Real recoil. Real weapons. Real consequences. AI civilians and adversaries that perceive and decide. No two drills play out the same way.' => "Recul réel. Vraies armes. Conséquences réelles. Civils et adversaires IA qui perçoivent et décident. Aucun exercice ne se joue deux fois pareil.", 'Modular by design' => 'Modulaire par conception', 'From 9 m\u{B2} solo to 900 m\u{B2} academy, same software, same scenarios, same instructor tools. Your investment scales with you.' => "De 9 m\u{B2} solo à 900 m\u{B2} académie, même logiciel, mêmes scénarios, mêmes outils instructeur. Votre investissement évolue avec vous.", 'Sovereign & secure' => 'Souverain & sécurisé', 'Designed and produced in France. Operates fully offline. No data leaves your network. GDPR-native by default.' => "Conçu et produit en France. Fonctionne entièrement hors ligne. Aucune donnée ne quitte votre réseau. RGPD-natif par défaut.", // Industries teaser 'Who we serve' => 'Qui nous servons', 'Built for those who carry the weight.' => 'Conçu pour celles et ceux qui en portent le poids.', // Solutions teaser 'The PROSERVE platform' => 'La plateforme PROSERVE', 'Pick the configuration that fits your unit.' => 'Choisissez la configuration adaptée à votre unité.', // Numbers band 'By the numbers' => 'En chiffres', '10 years of XR R&D focused on security forces.' => "10 ans de R&D XR consacrés aux forces de sécurité.", '10 years' => '10 ans', 'XR R&D for security forces' => 'R&D XR pour les forces de sécurité', '11 environments' => '11 environnements', 'Validated training contexts' => 'Contextes d\'entraînement validés', '50+ scenarios' => '50+ scénarios', 'Updated four times a year' => 'Mis à jour quatre fois par an', 'GDPR-native' => 'RGPD-natif', 'Fully offline operation' => 'Fonctionnement entièrement hors ligne', // Why Asterion teaser 'Why teams choose Asterion' => 'Pourquoi les équipes choisissent Asterion', 'A platform built around the operator. Not the other way around.' => "Une plateforme construite autour de l'opérateur. Pas l'inverse.", "Founded in 2016 to solve one specific problem: security forces need more repetition than the ranges, ammunition budgets, and exercise calendars allow. Ten years later, our platform does exactly that \u{2014} at every scale, in every environment, for every role." => "Fondée en 2016 pour résoudre un problème précis : les forces de sécurité ont besoin de plus de répétition que ce que les stands, budgets munitions et calendriers d'exercice permettent. Dix ans plus tard, notre plateforme fait exactement cela \u{2014} à toute échelle, dans tout environnement, pour tout rôle.", 'Read the full story' => 'Lire l\'histoire complète', // Customers teaser 'Trusted by units across Europe' => 'Choisi par des unités en Europe', 'Real deployments. Measured results.' => 'Déploiements réels. Résultats mesurés.', "From national police academies to special tactical units, PROSERVE is in active service \u{2014} with measurable impact on training volume, tactical accuracy, and operator confidence." => "Des écoles nationales de police aux unités tactiques spéciales, PROSERVE est en service actif \u{2014} avec un impact mesurable sur le volume d'entraînement, la précision tactique et la confiance des opérateurs.", 'See customer stories' => 'Voir les retours clients', // Final closer (separate from shared closer because we override copy) 'Ready to see PROSERVE in action?' => 'Prêt à voir PROSERVE en action ?', 'Schedule a tailored demo or request a Test & Evaluation Kit.' => 'Réservez une démo personnalisée ou demandez un kit Test & Evaluation.', ]); }); /* ----------------------------------------------------------------- URL trigger ----------------------------------------------------------------- */ add_action('template_redirect', function () { if (empty($_GET['av_generate_home'])) return; if (! in_array($_SERVER['SERVER_NAME'] ?? '', ['localhost', '127.0.0.1'], true)) wp_die('localhost only'); // Ensure home page exists (slug 'home') AND is set as WP static front page $home = get_page_by_path('home'); if (! $home) { $home_id = wp_insert_post([ 'post_type' => 'page', 'post_title' => 'Home', 'post_name' => 'home', 'post_parent' => 0, 'post_status' => 'publish', 'post_content' => '', ]); $action = 'created'; } else { $home_id = $home->ID; $action = 'updated'; } // Set as WP static front page update_option('show_on_front', 'page'); update_option('page_on_front', $home_id); $elements = av_build_home_elements(); $write = av_write_bricks_page_elements($home_id, $elements); header('Content-Type: text/plain; charset=utf-8'); echo "Home page #$home_id ($action) — " . count($elements) . " elements (json={$write['json_len']}, stored={$write['stored_len']})\n"; echo "show_on_front = page, page_on_front = $home_id\n"; echo "Visit / to see the home.\n"; exit; }); /* ----------------------------------------------------------------- HOME PAGE BUILDER ----------------------------------------------------------------- */ function av_build_home_elements() { $els = []; // 1. HERO — full-bleed cinematic video background + overlay text $els = array_merge($els, av_build_home_video_hero()); // 2. THREE PILLARS — 3-card grid (count===3 → 33% each, clean row of 3) $els = array_merge($els, av_build_cards_section('homep', 0, [ 'eyebrow' => 'Three certainties', 'title' => 'A platform engineered around three commitments.', 'items' => [ ['title' => 'Operational reality', 'body' => 'Real recoil. Real weapons. Real consequences. AI civilians and adversaries that perceive and decide. No two drills play out the same way.'], ['title' => 'Modular by design', 'body' => "From 9 m\u{B2} solo to 900 m\u{B2} academy, same software, same scenarios, same instructor tools. Your investment scales with you."], ['title' => 'Sovereign & secure', 'body' => 'Designed and produced in France. Operates fully offline. No data leaves your network. GDPR-native by default.'], ], ], 'var(--color-bg-subtle)')); // 3. INDUSTRIES — 4 cards linking to /industries/* $industries_cards = [ 'eyebrow' => 'Who we serve', 'title' => 'Built for those who carry the weight.', 'items' => [ ['title' => 'Police', 'body' => "National & Municipal \u{2014} Police training, when the schedule won't bend."], ['title' => 'Special Forces', 'body' => "Tactical units \u{2014} Special forces train differently. Their simulation should, too."], ['title' => 'Military', 'body' => "Armed forces \u{2014} Military VR training. Sovereign. Modular. Field-deployable."], ['title' => 'Firefighters', 'body' => "Emergency services \u{2014} Train the worst day. Safely. Repeatedly."], ], ]; $els = array_merge($els, av_build_cards_section('homei', 1, $industries_cards, 'var(--color-bg-default)')); // Append "Learn more →" link in each industry card $industry_slugs = ['police', 'special-forces', 'military', 'firefighters']; foreach ($industry_slugs as $i => $slug) { $kid = "khomeic1x{$i}"; $lid = "lnhomeic1x{$i}"; $els[] = av_text_link($lid, $kid, "Learn more \u{2192}", "/industries/$slug/"); foreach ($els as &$el) { if (($el['id'] ?? '') === $kid) { $el['children'][] = $lid; } } unset($el); } // 4. SOLUTIONS — 4 cards linking to /solutions/* $solutions_cards = [ 'eyebrow' => 'The PROSERVE platform', 'title' => 'Pick the configuration that fits your unit.', 'items' => [ ['title' => 'MY PROSERVE', 'body' => "Solo training \u{2014} Your first range, in a mini-case."], ['title' => 'PROSERVE FLEX', 'body' => "Team training \u{B7} 1 to 5 \u{2014} Your team, in the same scenario, on any flat surface."], ['title' => 'PROSERVE ACADEMY', 'body' => "Unit training \u{B7} 1 to 16 \u{2014} The full training centre, in your facility."], ['title' => 'PROSERVE+', 'body' => "Customization & options \u{2014} When the catalog doesn't fit your mission."], ], ]; $els = array_merge($els, av_build_cards_section('homes', 2, $solutions_cards, 'var(--color-bg-subtle)')); $solution_slugs = ['my-proserve', 'proserve-flex', 'proserve-academy', 'customization']; foreach ($solution_slugs as $i => $slug) { $kid = "khomesc2x{$i}"; $lid = "lnhomesc2x{$i}"; $els[] = av_text_link($lid, $kid, "Learn more \u{2192}", "/solutions/$slug/"); foreach ($els as &$el) { if (($el['id'] ?? '') === $kid) { $el['children'][] = $lid; } } unset($el); } // 5. NUMBERS BAND — 4-card grid stats $els = array_merge($els, av_build_cards_section('homen', 3, [ 'eyebrow' => 'By the numbers', 'title' => '10 years of XR R&D focused on security forces.', 'items' => [ ['title' => '10 years', 'body' => 'XR R&D for security forces'], ['title' => '11 environments', 'body' => 'Validated training contexts'], ['title' => '50+ scenarios', 'body' => 'Updated four times a year'], ['title' => 'GDPR-native', 'body' => 'Fully offline operation'], ], ], 'var(--color-bg-default)')); // 6. WHY ASTERION teaser — prose with CTA $els = array_merge($els, av_build_cta_section('homew', 4, [ 'eyebrow' => 'Why teams choose Asterion', 'title' => 'A platform built around the operator. Not the other way around.', 'body' => "Founded in 2016 to solve one specific problem: security forces need more repetition than the ranges, ammunition budgets, and exercise calendars allow. Ten years later, our platform does exactly that \u{2014} at every scale, in every environment, for every role.", 'ctas' => [ ['label' => 'Read the full story', 'href' => '/why-asterion/', 'variant' => 'secondary'], ], ], 'var(--color-bg-subtle)')); // 7. CUSTOMERS teaser $els = array_merge($els, av_build_cta_section('homec', 5, [ 'eyebrow' => 'Trusted by units across Europe', 'title' => 'Real deployments. Measured results.', 'body' => "From national police academies to special tactical units, PROSERVE is in active service \u{2014} with measurable impact on training volume, tactical accuracy, and operator confidence.", 'ctas' => [ ['label' => 'See customer stories', 'href' => '/customers/', 'variant' => 'secondary'], ], ], 'var(--color-bg-default)')); // 8. CLOSER CTA — full navy with custom copy $els = array_merge($els, av_build_home_closer_cta()); return $els; } /** * Cinematic full-bleed hero with background video + dark overlay + light text. * Video URL is read from the WP option `av_home_hero_video_url`. If empty, * the hero falls back to a solid navy background (no video) — the layout and * text stay identical so the page renders cleanly even without a video. * * To set the video URL : * 1. Upload your MP4 to WP Admin → Media Library * 2. Copy the file URL * 3. Run /?av_set_home_video= (see av-set-home-video.php mu-plugin) * or update_option('av_home_hero_video_url', '') via WP CLI / DB * 4. Re-run /?av_generate_home=1 */ function av_build_home_video_hero() { $video_url = (string) get_option('av_home_hero_video_url', ''); $sid = 'hhomesc'; $oct = 'hhomeoc'; $nrr = 'hhomenr'; $eybId = 'hhomeeb'; $h1Id = 'hhomeh1'; $ledId = 'hhomeld'; $rowId = 'hhomerw'; // Background settings : video if URL configured, otherwise navy color. if ($video_url !== '') { $section_background = [ 'videoUrl' => $video_url, 'videoScale' => 'cover', // fill the section, crop if needed 'videoAspectRatio' => '16/9', 'overlay' => [ 'color' => ['raw' => 'rgba(11, 31, 58, 0.6)'], // navy 60% — readability ], 'color' => ['raw' => 'var(--color-brand-navy)'], // fallback while video loads ]; } else { $section_background = ['color' => av_color('var(--color-brand-navy)')]; } $els = []; // SECTION — full-bleed, 100vh tall, content vertically centered. // Using min-height (not fixed height) so content can still extend if needed. // 100dvh fallback handles mobile address bar collapse correctly (newer browsers). $els[] = [ 'id' => $sid, 'name' => 'section', 'parent' => 0, 'children' => [$oct], 'settings' => [ '_padding' => av_sp('2rem', '0', '2rem', '0'), // breathing room at top/bottom '_heightMin' => '100vh', // full viewport height '_justifyContent' => 'center', // vertical centering (flex-column) '_background' => $section_background, '_position' => 'relative', '_overflow' => 'hidden', '_cssCustom' => '%root% { min-height: 100vh; min-height: 100dvh; }', ], ]; // OUTER CONTAINER — 1280 max-width, no horizontal centering of inner $els[] = [ 'id' => $oct, 'name' => 'container', 'parent' => $sid, 'children' => [$nrr], 'settings' => [ '_direction' => 'column', '_widthMax' => '1280px', '_width' => '100%', '_padding' => av_sp('0', '1.5rem', '0', '1.5rem'), '_padding:mobile_landscape' => av_sp('0', '1rem', '0', '1rem'), '_alignItems' => 'flex-start', '_position' => 'relative', '_zIndex' => '2', // above the video overlay ], ]; // NARRATIVE INNER — 800 max-width, light text $els[] = [ 'id' => $nrr, 'name' => 'container', 'parent' => $oct, 'children' => [$h1Id, $ledId, $rowId], 'settings' => [ '_direction' => 'column', '_widthMax' => '800px', '_widthMin' => '0', '_width' => '100%', '_margin' => av_sp('0', 'auto', '0', '0'), '_padding' => av_sp('0', '0', '0', '0'), '_rowGap' => '1.5rem', ], ]; // H1 — large, white, tactical $els[] = [ 'id' => $h1Id, 'name' => 'heading', 'parent' => $nrr, 'children' => [], 'settings' => [ 'tag' => 'h1', 'text' => 'Train like you operate.', '_typography' => [ 'color' => av_color('var(--color-text-on-dark)'), 'font-weight' => '800', 'font-size' => '3.5rem', 'line-height' => '1.1', 'letter-spacing'=> '-0.02em', ], '_typography:tablet_portrait' => ['font-size' => '2.75rem'], '_typography:mobile_landscape' => ['font-size' => '2.25rem'], '_typography:mobile_portrait' => ['font-size' => '1.875rem'], ], ]; // LEAD — muted-white $els[] = av_text( $ledId, $nrr, "PROSERVE\u{2122} is the modular XR training platform engineered for European security forces. Real recoil, autonomous AI, sovereign by design \u{2014} from solo officer to full academy.", 'rgba(255, 255, 255, 0.85)', '1.25rem', '1.55' ); // CTA row $b1 = 'hhomeb0'; $b2 = 'hhomeb1'; $els[] = [ 'id' => $rowId, 'name' => 'container', 'parent' => $nrr, 'children' => [$b1, $b2], 'settings' => [ '_direction' => 'row', '_columnGap' => '1rem', '_rowGap' => '1rem', '_flexWrap' => 'wrap', '_width' => '100%', '_padding' => av_sp('1rem', '0', '0', '0'), ], ]; $els[] = av_button($b1, $rowId, 'Book a demo', '/request-demo/', 'gold'); $els[] = av_button($b2, $rowId, 'Request a T&E Kit', '/request-te-kit/', 'outline-on-dark'); return $els; } function av_build_home_closer_cta() { $sid = "schmhc"; $oct = "ochmhc"; $nrr = "nrhmhc"; $eyb = "ebhmhc"; $hId = "h2hmhc"; $led = "ldhmhc"; $row = "rwhmhc"; $b1 = "b1hmhc"; $b2 = "b2hmhc"; return [ [ 'id' => $sid, 'name' => 'section', 'parent' => 0, 'children' => [$oct], 'settings' => array_merge(av_section_padding_responsive(), [ '_background' => ['color' => av_color('var(--color-brand-navy)')], ]), ], [ 'id' => $oct, 'name' => 'container', 'parent' => $sid, 'children' => [$nrr], 'settings' => [ '_direction' => 'column', '_widthMax' => '1280px', '_width' => '100%', '_padding' => av_sp('0', '1.5rem', '0', '1.5rem'), '_padding:mobile_landscape' => av_sp('0', '1rem', '0', '1rem'), '_alignItems' => 'flex-start', ], ], [ 'id' => $nrr, 'name' => 'container', 'parent' => $oct, 'children' => [$eyb, $hId, $led, $row], 'settings' => [ '_direction' => 'column', '_widthMax' => '800px', '_widthMin' => '0', '_width' => '100%', '_margin' => av_sp('0', 'auto', '0', '0'), '_padding' => av_sp('0', '0', '0', '0'), '_rowGap' => '1.25rem', ], ], av_eyebrow($eyb, $nrr, 'Ready to see PROSERVE in action?'), av_heading($hId, $nrr, 'h2', 'Schedule a tailored demo or request a Test & Evaluation Kit.', 'var(--color-text-on-dark)'), av_text($led, $nrr, "Book 30 minutes with our team. We'll bring the kit. You bring the doctrine.", 'var(--color-text-on-dark)', '1.125rem', '1.55'), [ 'id' => $row, 'name' => 'container', 'parent' => $nrr, 'children' => [$b1, $b2], 'settings' => [ '_direction' => 'row', '_columnGap' => '1rem', '_rowGap' => '1rem', '_flexWrap' => 'wrap', '_widthMin' => '0', '_width' => '100%', '_padding' => av_sp('0.5rem', '0', '0', '0'), ], ], av_button($b1, $row, 'Book a Demo', '/request-demo/', 'gold'), av_button($b2, $row, 'Request a T&E Kit', '/request-te-kit/', 'outline-on-dark'), ]; }