{"parentUuid":null,"isSidechain":true,"promptId":"606b4c79-d3cd-4b0a-a2e5-8b38011359cb","agentId":"a9fd20a9d1d03f0e9","type":"user","message":{"role":"user","content":"I'm planning to recreate the Covalba \"Cool Roof solution\" page (live at https://www.covalba.fr/nos-solutions-cool-roof) inside this Next.js + headless WordPress repo, using the project's \"new DA\" (design direction / art direction) and reusing existing blocks/components.\n\nPlease explore and report back on TWO things:\n\nA) **The live page content** — Use WebFetch on https://www.covalba.fr/nos-solutions-cool-roof and summarize its full section-by-section structure: hero, headings, body copy, what blocks/sections it has (e.g. intro, benefits, how cool roof works, gallery, CTA, FAQ, etc.). Capture the actual French copy/headings so I know what content to seed. If the fetch is blocked, note that.\n\nB) **The repo's design system / \"new DA\"** — Explore the Next.js codebase for:\n   - The polished page templates and visual section components (e.g. SectorPageTemplate, product page components, hero components, CTA sections, stats/benefits sections). Memory notes that polished sector pages use `SectorPageTemplate` (FR) via a coded `SectorPageConfig` + `SECTOR_TEMPLATE_SLUGS` + `toSectorConfig`. Find these.\n   - What reusable visual section components exist that I could compose a cool roof page from (hero, feature grids, image+text, testimonials, CTA bands, FAQ, logos marquee, etc.). List each component, its file path, and the props it takes.\n   - The design tokens / color palette / typography that define the \"new DA\" (tailwind config, index.css, any DA docs under docs/contexte or elsewhere).\n   - How an existing well-designed page (e.g. an industrie page like cool roof industrie pharma/aéronautique, mentioned in recent commits) is composed — which components it uses. Look at recent commit 72f320f context.\n\nReport exact file paths (file:line). Be thorough on the component inventory since I'll reuse these. Read-only — do NOT modify anything."},"uuid":"76837989-40b8-49fd-8f18-79d4fa459963","timestamp":"2026-06-26T11:53:39.990Z","userType":"external","entrypoint":"cli","cwd":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale","sessionId":"c02b163b-170b-4cd3-a555-3613df5965a3","version":"2.1.193","gitBranch":"tom/validation-finale","slug":"plusieurs-chose-faire-crispy-axolotl"}
{"parentUuid":"76837989-40b8-49fd-8f18-79d4fa459963","isSidechain":true,"agentId":"a9fd20a9d1d03f0e9","attachment":{"type":"deferred_tools_delta","addedNames":["CronCreate","CronDelete","CronList","DesignSync","EnterWorktree","ExitWorktree","ListMcpResourcesTool","Monitor","PushNotification","ReadMcpResourceDirTool","ReadMcpResourceTool","RemoteTrigger","SendMessage","TaskCreate","TaskGet","TaskList","TaskStop","TaskUpdate","WebFetch","WebSearch","mcp__EstimanouContent__add_article_block","mcp__EstimanouContent__add_block","mcp__EstimanouContent__create_article","mcp__EstimanouContent__create_page","mcp__EstimanouContent__delete_article","mcp__EstimanouContent__delete_article_block","mcp__EstimanouContent__delete_block","mcp__EstimanouContent__get_article","mcp__EstimanouContent__get_city_page","mcp__EstimanouContent__get_page","mcp__EstimanouContent__list_articles","mcp__EstimanouContent__list_available_blocks","mcp__EstimanouContent__list_city_pages","mcp__EstimanouContent__list_pages","mcp__EstimanouContent__list_site_urls","mcp__EstimanouContent__reorder_article_blocks","mcp__EstimanouContent__reorder_blocks","mcp__EstimanouContent__replace_article_content","mcp__EstimanouContent__replace_city_seo_content","mcp__EstimanouContent__replace_page_layout","mcp__EstimanouContent__search_internal_links","mcp__EstimanouContent__update_article","mcp__EstimanouContent__update_article_block","mcp__EstimanouContent__update_block","mcp__EstimanouContent__update_city_page_content","mcp__claude_ai_Ahref__batch-analysis","mcp__claude_ai_Ahref__brand-radar-ai-responses","mcp__claude_ai_Ahref__brand-radar-ai-responses-entities","mcp__claude_ai_Ahref__brand-radar-cited-domains","mcp__claude_ai_Ahref__brand-radar-cited-domains-entities","mcp__claude_ai_Ahref__brand-radar-cited-pages","mcp__claude_ai_Ahref__brand-radar-cited-pages-entities","mcp__claude_ai_Ahref__brand-radar-impressions-history","mcp__claude_ai_Ahref__brand-radar-impressions-overview","mcp__claude_ai_Ahref__brand-radar-impressions-overview-entities","mcp__claude_ai_Ahref__brand-radar-mentions-history","mcp__claude_ai_Ahref__brand-radar-mentions-history-entities","mcp__claude_ai_Ahref__brand-radar-mentions-overview","mcp__claude_ai_Ahref__brand-radar-mentions-overview-entities","mcp__claude_ai_Ahref__brand-radar-sov-history","mcp__claude_ai_Ahref__brand-radar-sov-history-entities","mcp__claude_ai_Ahref__brand-radar-sov-overview","mcp__claude_ai_Ahref__brand-radar-sov-overview-entities","mcp__claude_ai_Ahref__doc","mcp__claude_ai_Ahref__gsc-anonymous-queries","mcp__claude_ai_Ahref__gsc-ctr-by-position","mcp__claude_ai_Ahref__gsc-keyword-history","mcp__claude_ai_Ahref__gsc-keywords","mcp__claude_ai_Ahref__gsc-metrics-by-country","mcp__claude_ai_Ahref__gsc-page-history","mcp__claude_ai_Ahref__gsc-pages","mcp__claude_ai_Ahref__gsc-pages-history","mcp__claude_ai_Ahref__gsc-performance-by-device","mcp__claude_ai_Ahref__gsc-performance-by-position","mcp__claude_ai_Ahref__gsc-performance-history","mcp__claude_ai_Ahref__gsc-positions-history","mcp__claude_ai_Ahref__keywords-explorer-matching-terms","mcp__claude_ai_Ahref__keywords-explorer-overview","mcp__claude_ai_Ahref__keywords-explorer-related-terms","mcp__claude_ai_Ahref__keywords-explorer-search-suggestions","mcp__claude_ai_Ahref__keywords-explorer-volume-by-country","mcp__claude_ai_Ahref__keywords-explorer-volume-history","mcp__claude_ai_Ahref__management-brand-radar-prompts","mcp__claude_ai_Ahref__management-brand-radar-reports","mcp__claude_ai_Ahref__management-keyword-list-keywords","mcp__claude_ai_Ahref__management-locations","mcp__claude_ai_Ahref__management-project-competitors","mcp__claude_ai_Ahref__management-project-keywords","mcp__claude_ai_Ahref__management-projects","mcp__claude_ai_Ahref__public-crawler-ip-ranges","mcp__claude_ai_Ahref__public-crawler-ips","mcp__claude_ai_Ahref__public-domain-rating-free","mcp__claude_ai_Ahref__rank-tracker-competitors-domains","mcp__claude_ai_Ahref__rank-tracker-competitors-overview","mcp__claude_ai_Ahref__rank-tracker-competitors-pages","mcp__claude_ai_Ahref__rank-tracker-competitors-stats","mcp__claude_ai_Ahref__rank-tracker-overview","mcp__claude_ai_Ahref__rank-tracker-serp-overview","mcp__claude_ai_Ahref__render-data-table","mcp__claude_ai_Ahref__render-scorecard","mcp__claude_ai_Ahref__render-time-series-chart","mcp__claude_ai_Ahref__serp-overview","mcp__claude_ai_Ahref__site-audit-issues","mcp__claude_ai_Ahref__site-audit-page-content","mcp__claude_ai_Ahref__site-audit-page-explorer","mcp__claude_ai_Ahref__site-audit-projects","mcp__claude_ai_Ahref__site-explorer-ai-responses-count","mcp__claude_ai_Ahref__site-explorer-all-backlinks","mcp__claude_ai_Ahref__site-explorer-anchors","mcp__claude_ai_Ahref__site-explorer-backlinks-stats","mcp__claude_ai_Ahref__site-explorer-broken-backlinks","mcp__claude_ai_Ahref__site-explorer-crawled-pages","mcp__claude_ai_Ahref__site-explorer-domain-rating","mcp__claude_ai_Ahref__site-explorer-domain-rating-history","mcp__claude_ai_Ahref__site-explorer-keywords-history","mcp__claude_ai_Ahref__site-explorer-linked-anchors-external","mcp__claude_ai_Ahref__site-explorer-linked-anchors-internal","mcp__claude_ai_Ahref__site-explorer-linked-domains","mcp__claude_ai_Ahref__site-explorer-metrics","mcp__claude_ai_Ahref__site-explorer-metrics-by-country","mcp__claude_ai_Ahref__site-explorer-metrics-history","mcp__claude_ai_Ahref__site-explorer-organic-competitors","mcp__claude_ai_Ahref__site-explorer-organic-keywords","mcp__claude_ai_Ahref__site-explorer-outlinks-stats","mcp__claude_ai_Ahref__site-explorer-pages-by-backlinks","mcp__claude_ai_Ahref__site-explorer-pages-by-internal-links","mcp__claude_ai_Ahref__site-explorer-pages-by-traffic","mcp__claude_ai_Ahref__site-explorer-pages-history","mcp__claude_ai_Ahref__site-explorer-paid-pages","mcp__claude_ai_Ahref__site-explorer-refdomains-history","mcp__claude_ai_Ahref__site-explorer-referring-domains","mcp__claude_ai_Ahref__site-explorer-top-pages","mcp__claude_ai_Ahref__site-explorer-total-search-volume-history","mcp__claude_ai_Ahref__site-explorer-url-rating-history","mcp__claude_ai_Ahref__social-media-activity-history","mcp__claude_ai_Ahref__social-media-authors","mcp__claude_ai_Ahref__social-media-channel-metrics","mcp__claude_ai_Ahref__social-media-channels","mcp__claude_ai_Ahref__social-media-post-metrics","mcp__claude_ai_Ahref__social-media-posts","mcp__claude_ai_Ahref__subscription-info-limits-and-usage","mcp__claude_ai_Ahref__web-analytics-browser-versions","mcp__claude_ai_Ahref__web-analytics-browser-versions-chart","mcp__claude_ai_Ahref__web-analytics-browsers","mcp__claude_ai_Ahref__web-analytics-browsers-chart","mcp__claude_ai_Ahref__web-analytics-chart","mcp__claude_ai_Ahref__web-analytics-cities","mcp__claude_ai_Ahref__web-analytics-cities-chart","mcp__claude_ai_Ahref__web-analytics-continents","mcp__claude_ai_Ahref__web-analytics-continents-chart","mcp__claude_ai_Ahref__web-analytics-countries","mcp__claude_ai_Ahref__web-analytics-countries-chart","mcp__claude_ai_Ahref__web-analytics-devices","mcp__claude_ai_Ahref__web-analytics-devices-chart","mcp__claude_ai_Ahref__web-analytics-entry-pages","mcp__claude_ai_Ahref__web-analytics-entry-pages-chart","mcp__claude_ai_Ahref__web-analytics-exit-pages","mcp__claude_ai_Ahref__web-analytics-exit-pages-chart","mcp__claude_ai_Ahref__web-analytics-languages","mcp__claude_ai_Ahref__web-analytics-languages-chart","mcp__claude_ai_Ahref__web-analytics-operating-systems","mcp__claude_ai_Ahref__web-analytics-operating-systems-chart","mcp__claude_ai_Ahref__web-analytics-operating-systems-versions","mcp__claude_ai_Ahref__web-analytics-operating-systems-versions-chart","mcp__claude_ai_Ahref__web-analytics-referrers","mcp__claude_ai_Ahref__web-analytics-referrers-chart","mcp__claude_ai_Ahref__web-analytics-source-channels","mcp__claude_ai_Ahref__web-analytics-source-channels-chart","mcp__claude_ai_Ahref__web-analytics-sources","mcp__claude_ai_Ahref__web-analytics-sources-chart","mcp__claude_ai_Ahref__web-analytics-stats","mcp__claude_ai_Ahref__web-analytics-top-pages","mcp__claude_ai_Ahref__web-analytics-top-pages-chart","mcp__claude_ai_Ahref__web-analytics-utm-params","mcp__claude_ai_Ahref__web-analytics-utm-params-chart","mcp__claude_ai_Canva__cancel-editing-transaction","mcp__claude_ai_Canva__comment-on-design","mcp__claude_ai_Canva__commit-editing-transaction","mcp__claude_ai_Canva__copy-design","mcp__claude_ai_Canva__create-brand-template-draft","mcp__claude_ai_Canva__create-design-from-brand-template","mcp__claude_ai_Canva__create-design-from-candidate","mcp__claude_ai_Canva__create-folder","mcp__claude_ai_Canva__export-design","mcp__claude_ai_Canva__generate-design","mcp__claude_ai_Canva__generate-design-structured","mcp__claude_ai_Canva__get-assets","mcp__claude_ai_Canva__get-brand-template-dataset","mcp__claude_ai_Canva__get-design","mcp__claude_ai_Canva__get-design-candidates","mcp__claude_ai_Canva__get-design-content","mcp__claude_ai_Canva__get-design-pages","mcp__claude_ai_Canva__get-design-thumbnail","mcp__claude_ai_Canva__get-export-formats","mcp__claude_ai_Canva__get-presenter-notes","mcp__claude_ai_Canva__help","mcp__claude_ai_Canva__import-design-from-url","mcp__claude_ai_Canva__list-brand-kits","mcp__claude_ai_Canva__list-comments","mcp__claude_ai_Canva__list-folder-items","mcp__claude_ai_Canva__list-replies","mcp__claude_ai_Canva__merge-designs","mcp__claude_ai_Canva__move-item-to-folder","mcp__claude_ai_Canva__perform-editing-operations","mcp__claude_ai_Canva__publish-brand-template","mcp__claude_ai_Canva__reply-to-comment","mcp__claude_ai_Canva__request-outline-review","mcp__claude_ai_Canva__resize-design","mcp__claude_ai_Canva__resolve-shortlink","mcp__claude_ai_Canva__search-brand-templates","mcp__claude_ai_Canva__search-designs","mcp__claude_ai_Canva__search-folders","mcp__claude_ai_Canva__start-editing-transaction","mcp__claude_ai_Canva__upload-asset-from-url","mcp__claude_ai_DATA_GOUV_FR__get_dataservice_info","mcp__claude_ai_DATA_GOUV_FR__get_dataservice_openapi_spec","mcp__claude_ai_DATA_GOUV_FR__get_dataset_info","mcp__claude_ai_DATA_GOUV_FR__get_metrics","mcp__claude_ai_DATA_GOUV_FR__get_resource_info","mcp__claude_ai_DATA_GOUV_FR__list_dataset_resources","mcp__claude_ai_DATA_GOUV_FR__query_resource_data","mcp__claude_ai_DATA_GOUV_FR__search_dataservices","mcp__claude_ai_DATA_GOUV_FR__search_datasets","mcp__claude_ai_DATA_GOUV_FR__search_organizations","mcp__claude_ai_Data_For_SEO__authenticate","mcp__claude_ai_Data_For_SEO__complete_authentication","mcp__claude_ai_Esteworld-Body__add_block","mcp__claude_ai_Esteworld-Body__delete_block","mcp__claude_ai_Esteworld-Body__find_esteworld_page","mcp__claude_ai_Esteworld-Body__fix_global_blocks","mcp__claude_ai_Esteworld-Body__get_block","mcp__claude_ai_Esteworld-Body__get_blocks_library","mcp__claude_ai_Esteworld-Body__get_breadcrumb","mcp__claude_ai_Esteworld-Body__get_fr_en_mapping","mcp__claude_ai_Esteworld-Body__get_internal_links","mcp__claude_ai_Esteworld-Body__get_internal_links_en","mcp__claude_ai_Esteworld-Body__get_maillage_rules","mcp__claude_ai_Esteworld-Body__get_page","mcp__claude_ai_Esteworld-Body__get_page_json","mcp__claude_ai_Esteworld-Body__get_page_status","mcp__claude_ai_Esteworld-Body__get_redirections","mcp__claude_ai_Esteworld-Body__get_section_content","mcp__claude_ai_Esteworld-Body__get_thematique_pages","mcp__claude_ai_Esteworld-Body__get_translation_languages","mcp__claude_ai_Esteworld-Body__list_pages","mcp__claude_ai_Esteworld-Body__list_pages_by_thematique","mcp__claude_ai_Esteworld-Body__list_pages_by_type","mcp__claude_ai_Esteworld-Body__list_pages_to_create","mcp__claude_ai_Esteworld-Body__list_pages_to_rewrite","mcp__claude_ai_Esteworld-Body__list_pages_with_esteworld","mcp__claude_ai_Esteworld-Body__list_pages_without_esteworld","mcp__claude_ai_Esteworld-Body__n8n_activate_workflow","mcp__claude_ai_Esteworld-Body__n8n_get_executions","mcp__claude_ai_Esteworld-Body__n8n_get_workflow","mcp__claude_ai_Esteworld-Body__n8n_list_workflows","mcp__claude_ai_Esteworld-Body__n8n_trigger_webhook","mcp__claude_ai_Esteworld-Body__preview_global_fixes","mcp__claude_ai_Esteworld-Body__reorder_blocks","mcp__claude_ai_Esteworld-Body__search_content","mcp__claude_ai_Esteworld-Body__search_links_by_keyword","mcp__claude_ai_Esteworld-Body__search_links_by_keyword_en","mcp__claude_ai_Esteworld-Body__submit_page","mcp__claude_ai_Esteworld-Body__submit_page_light","mcp__claude_ai_Esteworld-Body__translate_page","mcp__claude_ai_Esteworld-Body__update_block","mcp__claude_ai_Figma__add_code_connect_map","mcp__claude_ai_Figma__create_new_file","mcp__claude_ai_Figma__download_assets","mcp__claude_ai_Figma__export_video","mcp__claude_ai_Figma__generate_diagram","mcp__claude_ai_Figma__get_code_connect_map","mcp__claude_ai_Figma__get_code_connect_suggestions","mcp__claude_ai_Figma__get_context_for_code_connect","mcp__claude_ai_Figma__get_design_context","mcp__claude_ai_Figma__get_figjam","mcp__claude_ai_Figma__get_libraries","mcp__claude_ai_Figma__get_metadata","mcp__claude_ai_Figma__get_motion_context","mcp__claude_ai_Figma__get_screenshot","mcp__claude_ai_Figma__get_shader_effect","mcp__claude_ai_Figma__get_shader_fill","mcp__claude_ai_Figma__get_variable_defs","mcp__claude_ai_Figma__list_shader_effects","mcp__claude_ai_Figma__list_shader_fills","mcp__claude_ai_Figma__search_design_system","mcp__claude_ai_Figma__send_code_connect_mappings","mcp__claude_ai_Figma__upload_assets","mcp__claude_ai_Figma__use_figma","mcp__claude_ai_Figma__whoami","mcp__claude_ai_Gmail__create_draft","mcp__claude_ai_Gmail__create_label","mcp__claude_ai_Gmail__delete_label","mcp__claude_ai_Gmail__get_thread","mcp__claude_ai_Gmail__label_message","mcp__claude_ai_Gmail__label_thread","mcp__claude_ai_Gmail__list_drafts","mcp__claude_ai_Gmail__list_labels","mcp__claude_ai_Gmail__search_threads","mcp__claude_ai_Gmail__unlabel_message","mcp__claude_ai_Gmail__unlabel_thread","mcp__claude_ai_Gmail__update_label","mcp__claude_ai_Google_Calendar__create_event","mcp__claude_ai_Google_Calendar__delete_event","mcp__claude_ai_Google_Calendar__get_event","mcp__claude_ai_Google_Calendar__list_calendars","mcp__claude_ai_Google_Calendar__list_events","mcp__claude_ai_Google_Calendar__respond_to_event","mcp__claude_ai_Google_Calendar__suggest_time","mcp__claude_ai_Google_Calendar__update_event","mcp__claude_ai_Google_Drive__copy_file","mcp__claude_ai_Google_Drive__create_file","mcp__claude_ai_Google_Drive__download_file_content","mcp__claude_ai_Google_Drive__get_file_metadata","mcp__claude_ai_Google_Drive__get_file_permissions","mcp__claude_ai_Google_Drive__list_recent_files","mcp__claude_ai_Google_Drive__read_file_content","mcp__claude_ai_Google_Drive__search_files","mcp__claude_ai_SEMRush__backlink_research","mcp__claude_ai_SEMRush__execute_report","mcp__claude_ai_SEMRush__get_report_schema","mcp__claude_ai_SEMRush__keyword_research","mcp__claude_ai_SEMRush__organic_research","mcp__claude_ai_SEMRush__overview_research","mcp__claude_ai_SEMRush__projects_research","mcp__claude_ai_SEMRush__siteaudit_research","mcp__claude_ai_SEMRush__subdomain_research","mcp__claude_ai_SEMRush__subfolder_research","mcp__claude_ai_SEMRush__tracking_research","mcp__claude_ai_SEMRush__trends_research","mcp__claude_ai_SEMRush__url_research","mcp__claude_ai_Vercel__add_toolbar_reaction","mcp__claude_ai_Vercel__change_toolbar_thread_resolve_status","mcp__claude_ai_Vercel__check_domain_availability_and_price","mcp__claude_ai_Vercel__deploy_to_vercel","mcp__claude_ai_Vercel__edit_toolbar_message","mcp__claude_ai_Vercel__get_access_to_vercel_url","mcp__claude_ai_Vercel__get_deployment","mcp__claude_ai_Vercel__get_deployment_build_logs","mcp__claude_ai_Vercel__get_project","mcp__claude_ai_Vercel__get_runtime_errors","mcp__claude_ai_Vercel__get_runtime_logs","mcp__claude_ai_Vercel__get_toolbar_thread","mcp__claude_ai_Vercel__import-claude-design-from-url","mcp__claude_ai_Vercel__list_deployments","mcp__claude_ai_Vercel__list_projects","mcp__claude_ai_Vercel__list_teams","mcp__claude_ai_Vercel__list_toolbar_threads","mcp__claude_ai_Vercel__reply_to_toolbar_thread","mcp__claude_ai_Vercel__search_vercel_documentation","mcp__claude_ai_Vercel__web_fetch_vercel_url","mcp__gpt-image-2__continue_edit_session","mcp__gpt-image-2__edit_image","mcp__gpt-image-2__end_edit_session","mcp__gpt-image-2__generate_image","mcp__gpt-image-2__list_edit_sessions","mcp__gpt-image-2__start_edit_session","mcp__hostinger__DNS_deleteDNSRecordsV1","mcp__hostinger__DNS_getDNSRecordsV1","mcp__hostinger__DNS_getDNSSnapshotListV1","mcp__hostinger__DNS_getDNSSnapshotV1","mcp__hostinger__DNS_resetDNSRecordsV1","mcp__hostinger__DNS_restoreDNSSnapshotV1","mcp__hostinger__DNS_updateDNSRecordsV1","mcp__hostinger__DNS_validateDNSRecordsV1","mcp__hostinger__VPS_activateFirewallV1","mcp__hostinger__VPS_attachPublicKeyV1","mcp__hostinger__VPS_createFirewallRuleV1","mcp__hostinger__VPS_createNewFirewallV1","mcp__hostinger__VPS_createNewProjectV1","mcp__hostinger__VPS_createPTRRecordV1","mcp__hostinger__VPS_createPostInstallScriptV1","mcp__hostinger__VPS_createPublicKeyV1","mcp__hostinger__VPS_createSnapshotV1","mcp__hostinger__VPS_deactivateFirewallV1","mcp__hostinger__VPS_deleteFirewallRuleV1","mcp__hostinger__VPS_deleteFirewallV1","mcp__hostinger__VPS_deletePTRRecordV1","mcp__hostinger__VPS_deletePostInstallScriptV1","mcp__hostinger__VPS_deleteProjectV1","mcp__hostinger__VPS_deletePublicKeyV1","mcp__hostinger__VPS_deleteSnapshotV1","mcp__hostinger__VPS_getActionDetailsV1","mcp__hostinger__VPS_getActionsV1","mcp__hostinger__VPS_getAttachedPublicKeysV1","mcp__hostinger__VPS_getBackupsV1","mcp__hostinger__VPS_getDataCenterListV1","mcp__hostinger__VPS_getFirewallDetailsV1","mcp__hostinger__VPS_getFirewallListV1","mcp__hostinger__VPS_getMetricsV1","mcp__hostinger__VPS_getPostInstallScriptV1","mcp__hostinger__VPS_getPostInstallScriptsV1","mcp__hostinger__VPS_getProjectContainersV1","mcp__hostinger__VPS_getProjectContentsV1","mcp__hostinger__VPS_getProjectListV1","mcp__hostinger__VPS_getProjectLogsV1","mcp__hostinger__VPS_getPublicKeysV1","mcp__hostinger__VPS_getScanMetricsV1","mcp__hostinger__VPS_getSnapshotV1","mcp__hostinger__VPS_getTemplateDetailsV1","mcp__hostinger__VPS_getTemplatesV1","mcp__hostinger__VPS_getVirtualMachineDetailsV1","mcp__hostinger__VPS_getVirtualMachinesV1","mcp__hostinger__VPS_installMonarxV1","mcp__hostinger__VPS_purchaseNewVirtualMachineV1","mcp__hostinger__VPS_recreateVirtualMachineV1","mcp__hostinger__VPS_resetHostnameV1","mcp__hostinger__VPS_restartProjectV1","mcp__hostinger__VPS_restartVirtualMachineV1","mcp__hostinger__VPS_restoreBackupV1","mcp__hostinger__VPS_restoreSnapshotV1","mcp__hostinger__VPS_setHostnameV1","mcp__hostinger__VPS_setNameserversV1","mcp__hostinger__VPS_setPanelPasswordV1","mcp__hostinger__VPS_setRootPasswordV1","mcp__hostinger__VPS_setupPurchasedVirtualMachineV1","mcp__hostinger__VPS_startProjectV1","mcp__hostinger__VPS_startRecoveryModeV1","mcp__hostinger__VPS_startVirtualMachineV1","mcp__hostinger__VPS_stopProjectV1","mcp__hostinger__VPS_stopRecoveryModeV1","mcp__hostinger__VPS_stopVirtualMachineV1","mcp__hostinger__VPS_syncFirewallV1","mcp__hostinger__VPS_uninstallMonarxV1","mcp__hostinger__VPS_updateFirewallRuleV1","mcp__hostinger__VPS_updatePostInstallScriptV1","mcp__hostinger__VPS_updateProjectV1","mcp__hostinger__billing_deletePaymentMethodV1","mcp__hostinger__billing_disableAutoRenewalV1","mcp__hostinger__billing_enableAutoRenewalV1","mcp__hostinger__billing_getCatalogItemListV1","mcp__hostinger__billing_getPaymentMethodListV1","mcp__hostinger__billing_getSubscriptionListV1","mcp__hostinger__billing_setDefaultPaymentMethodV1","mcp__hostinger__domains_checkDomainAvailabilityV1","mcp__hostinger__domains_createDomainForwardingV1","mcp__hostinger__domains_createWHOISProfileV1","mcp__hostinger__domains_deleteDomainForwardingV1","mcp__hostinger__domains_deleteWHOISProfileV1","mcp__hostinger__domains_disableDomainLockV1","mcp__hostinger__domains_disablePrivacyProtectionV1","mcp__hostinger__domains_enableDomainLockV1","mcp__hostinger__domains_enablePrivacyProtectionV1","mcp__hostinger__domains_getDomainDetailsV1","mcp__hostinger__domains_getDomainForwardingV1","mcp__hostinger__domains_getDomainListV1","mcp__hostinger__domains_getWHOISProfileListV1","mcp__hostinger__domains_getWHOISProfileUsageV1","mcp__hostinger__domains_getWHOISProfileV1","mcp__hostinger__domains_purchaseNewDomainV1","mcp__hostinger__domains_updateDomainNameserversV1","mcp__hostinger__hosting_createAccountDatabaseV1","mcp__hostinger__hosting_createWebsiteParkedDomainV1","mcp__hostinger__hosting_createWebsiteSubdomainV1","mcp__hostinger__hosting_createWebsiteV1","mcp__hostinger__hosting_deleteAccountDatabaseV1","mcp__hostinger__hosting_deleteWebsiteParkedDomainV1","mcp__hostinger__hosting_deleteWebsiteSubdomainV1","mcp__hostinger__hosting_deployJsApplication","mcp__hostinger__hosting_deployStaticWebsite","mcp__hostinger__hosting_deployWordpressPlugin","mcp__hostinger__hosting_deployWordpressTheme","mcp__hostinger__hosting_generateAFreeSubdomainV1","mcp__hostinger__hosting_importWordpressWebsite","mcp__hostinger__hosting_installWordPressV1","mcp__hostinger__hosting_listAccountDatabasesV1","mcp__hostinger__hosting_listAvailableDatacentersV1","mcp__hostinger__hosting_listJsDeployments","mcp__hostinger__hosting_listOrdersV1","mcp__hostinger__hosting_listWebsiteParkedDomainsV1","mcp__hostinger__hosting_listWebsiteSubdomainsV1","mcp__hostinger__hosting_listWebsitesV1","mcp__hostinger__hosting_listWordPressInstallationsV1","mcp__hostinger__hosting_showJsDeploymentLogs","mcp__hostinger__hosting_verifyDomainOwnershipV1","mcp__hostinger__reach_createANewContactSegmentV1","mcp__hostinger__reach_createANewContactV1","mcp__hostinger__reach_createNewContactsV1","mcp__hostinger__reach_deleteAContactV1","mcp__hostinger__reach_getSegmentDetailsV1","mcp__hostinger__reach_listContactGroupsV1","mcp__hostinger__reach_listContactsV1","mcp__hostinger__reach_listProfilesV1","mcp__hostinger__reach_listSegmentContactsV1","mcp__hostinger__reach_listSegmentsV1","mcp__hostinger__v2_getDomainVerificationsDIRECT","mcp__n8n-mcp__get_node","mcp__n8n-mcp__get_template","mcp__n8n-mcp__n8n_audit_instance","mcp__n8n-mcp__n8n_autofix_workflow","mcp__n8n-mcp__n8n_create_workflow","mcp__n8n-mcp__n8n_delete_workflow","mcp__n8n-mcp__n8n_deploy_template","mcp__n8n-mcp__n8n_executions","mcp__n8n-mcp__n8n_generate_workflow","mcp__n8n-mcp__n8n_get_workflow","mcp__n8n-mcp__n8n_health_check","mcp__n8n-mcp__n8n_list_workflows","mcp__n8n-mcp__n8n_manage_credentials","mcp__n8n-mcp__n8n_manage_datatable","mcp__n8n-mcp__n8n_test_workflow","mcp__n8n-mcp__n8n_update_full_workflow","mcp__n8n-mcp__n8n_update_partial_workflow","mcp__n8n-mcp__n8n_validate_workflow","mcp__n8n-mcp__n8n_workflow_versions","mcp__n8n-mcp__search_nodes","mcp__n8n-mcp__search_templates","mcp__n8n-mcp__tools_documentation","mcp__n8n-mcp__validate_node","mcp__n8n-mcp__validate_workflow","mcp__nanobanana__generate_image","mcp__nanobanana__maintenance","mcp__nanobanana__show_output_stats","mcp__nanobanana__upload_file","mcp__plugin_vercel_vercel__authenticate","mcp__plugin_vercel_vercel__complete_authentication","mcp__refero__refero_get_flow","mcp__refero__refero_get_screen","mcp__refero__refero_get_screen_image","mcp__refero__refero_get_similar_screens","mcp__refero__refero_get_style","mcp__refero__refero_search_flows","mcp__refero__refero_search_screens","mcp__refero__refero_search_styles","mcp__semrush__authenticate","mcp__semrush__complete_authentication","mcp__stock-images-mcp__search_stock_images","mcp__trello__add_card_to_list","mcp__trello__add_checklist_item","mcp__trello__add_comment","mcp__trello__add_list_to_board","mcp__trello__archive_card","mcp__trello__archive_list","mcp__trello__assign_member_to_card","mcp__trello__attach_file_to_card","mcp__trello__attach_image_data_to_card","mcp__trello__attach_image_to_card","mcp__trello__create_board","mcp__trello__create_checklist","mcp__trello__create_label","mcp__trello__delete_comment","mcp__trello__delete_label","mcp__trello__find_checklist_items_by_description","mcp__trello__get_acceptance_criteria","mcp__trello__get_active_board_info","mcp__trello__get_board_labels","mcp__trello__get_board_members","mcp__trello__get_card","mcp__trello__get_card_comments","mcp__trello__get_card_history","mcp__trello__get_cards_by_list_id","mcp__trello__get_checklist_by_name","mcp__trello__get_checklist_items","mcp__trello__get_health","mcp__trello__get_health_detailed","mcp__trello__get_health_metadata","mcp__trello__get_health_performance","mcp__trello__get_lists","mcp__trello__get_my_cards","mcp__trello__get_recent_activity","mcp__trello__list_boards","mcp__trello__list_boards_in_workspace","mcp__trello__list_workspaces","mcp__trello__move_card","mcp__trello__perform_system_repair","mcp__trello__remove_member_from_card","mcp__trello__set_active_board","mcp__trello__set_active_workspace","mcp__trello__update_card_details","mcp__trello__update_checklist_item","mcp__trello__update_comment","mcp__trello__update_label"],"addedLines":["CronCreate","CronDelete","CronList","DesignSync","EnterWorktree","ExitWorktree","ListMcpResourcesTool","Monitor","PushNotification","ReadMcpResourceDirTool","ReadMcpResourceTool","RemoteTrigger","SendMessage","TaskCreate","TaskGet","TaskList","TaskStop","TaskUpdate","WebFetch","WebSearch","mcp__EstimanouContent__add_article_block","mcp__EstimanouContent__add_block","mcp__EstimanouContent__create_article","mcp__EstimanouContent__create_page","mcp__EstimanouContent__delete_article","mcp__EstimanouContent__delete_article_block","mcp__EstimanouContent__delete_block","mcp__EstimanouContent__get_article","mcp__EstimanouContent__get_city_page","mcp__EstimanouContent__get_page","mcp__EstimanouContent__list_articles","mcp__EstimanouContent__list_available_blocks","mcp__EstimanouContent__list_city_pages","mcp__EstimanouContent__list_pages","mcp__EstimanouContent__list_site_urls","mcp__EstimanouContent__reorder_article_blocks","mcp__EstimanouContent__reorder_blocks","mcp__EstimanouContent__replace_article_content","mcp__EstimanouContent__replace_city_seo_content","mcp__EstimanouContent__replace_page_layout","mcp__EstimanouContent__search_internal_links","mcp__EstimanouContent__update_article","mcp__EstimanouContent__update_article_block","mcp__EstimanouContent__update_block","mcp__EstimanouContent__update_city_page_content","mcp__claude_ai_Ahref__batch-analysis","mcp__claude_ai_Ahref__brand-radar-ai-responses","mcp__claude_ai_Ahref__brand-radar-ai-responses-entities","mcp__claude_ai_Ahref__brand-radar-cited-domains","mcp__claude_ai_Ahref__brand-radar-cited-domains-entities","mcp__claude_ai_Ahref__brand-radar-cited-pages","mcp__claude_ai_Ahref__brand-radar-cited-pages-entities","mcp__claude_ai_Ahref__brand-radar-impressions-history","mcp__claude_ai_Ahref__brand-radar-impressions-overview","mcp__claude_ai_Ahref__brand-radar-impressions-overview-entities","mcp__claude_ai_Ahref__brand-radar-mentions-history","mcp__claude_ai_Ahref__brand-radar-mentions-history-entities","mcp__claude_ai_Ahref__brand-radar-mentions-overview","mcp__claude_ai_Ahref__brand-radar-mentions-overview-entities","mcp__claude_ai_Ahref__brand-radar-sov-history","mcp__claude_ai_Ahref__brand-radar-sov-history-entities","mcp__claude_ai_Ahref__brand-radar-sov-overview","mcp__claude_ai_Ahref__brand-radar-sov-overview-entities","mcp__claude_ai_Ahref__doc","mcp__claude_ai_Ahref__gsc-anonymous-queries","mcp__claude_ai_Ahref__gsc-ctr-by-position","mcp__claude_ai_Ahref__gsc-keyword-history","mcp__claude_ai_Ahref__gsc-keywords","mcp__claude_ai_Ahref__gsc-metrics-by-country","mcp__claude_ai_Ahref__gsc-page-history","mcp__claude_ai_Ahref__gsc-pages","mcp__claude_ai_Ahref__gsc-pages-history","mcp__claude_ai_Ahref__gsc-performance-by-device","mcp__claude_ai_Ahref__gsc-performance-by-position","mcp__claude_ai_Ahref__gsc-performance-history","mcp__claude_ai_Ahref__gsc-positions-history","mcp__claude_ai_Ahref__keywords-explorer-matching-terms","mcp__claude_ai_Ahref__keywords-explorer-overview","mcp__claude_ai_Ahref__keywords-explorer-related-terms","mcp__claude_ai_Ahref__keywords-explorer-search-suggestions","mcp__claude_ai_Ahref__keywords-explorer-volume-by-country","mcp__claude_ai_Ahref__keywords-explorer-volume-history","mcp__claude_ai_Ahref__management-brand-radar-prompts","mcp__claude_ai_Ahref__management-brand-radar-reports","mcp__claude_ai_Ahref__management-keyword-list-keywords","mcp__claude_ai_Ahref__management-locations","mcp__claude_ai_Ahref__management-project-competitors","mcp__claude_ai_Ahref__management-project-keywords","mcp__claude_ai_Ahref__management-projects","mcp__claude_ai_Ahref__public-crawler-ip-ranges","mcp__claude_ai_Ahref__public-crawler-ips","mcp__claude_ai_Ahref__public-domain-rating-free","mcp__claude_ai_Ahref__rank-tracker-competitors-domains","mcp__claude_ai_Ahref__rank-tracker-competitors-overview","mcp__claude_ai_Ahref__rank-tracker-competitors-pages","mcp__claude_ai_Ahref__rank-tracker-competitors-stats","mcp__claude_ai_Ahref__rank-tracker-overview","mcp__claude_ai_Ahref__rank-tracker-serp-overview","mcp__claude_ai_Ahref__render-data-table","mcp__claude_ai_Ahref__render-scorecard","mcp__claude_ai_Ahref__render-time-series-chart","mcp__claude_ai_Ahref__serp-overview","mcp__claude_ai_Ahref__site-audit-issues","mcp__claude_ai_Ahref__site-audit-page-content","mcp__claude_ai_Ahref__site-audit-page-explorer","mcp__claude_ai_Ahref__site-audit-projects","mcp__claude_ai_Ahref__site-explorer-ai-responses-count","mcp__claude_ai_Ahref__site-explorer-all-backlinks","mcp__claude_ai_Ahref__site-explorer-anchors","mcp__claude_ai_Ahref__site-explorer-backlinks-stats","mcp__claude_ai_Ahref__site-explorer-broken-backlinks","mcp__claude_ai_Ahref__site-explorer-crawled-pages","mcp__claude_ai_Ahref__site-explorer-domain-rating","mcp__claude_ai_Ahref__site-explorer-domain-rating-history","mcp__claude_ai_Ahref__site-explorer-keywords-history","mcp__claude_ai_Ahref__site-explorer-linked-anchors-external","mcp__claude_ai_Ahref__site-explorer-linked-anchors-internal","mcp__claude_ai_Ahref__site-explorer-linked-domains","mcp__claude_ai_Ahref__site-explorer-metrics","mcp__claude_ai_Ahref__site-explorer-metrics-by-country","mcp__claude_ai_Ahref__site-explorer-metrics-history","mcp__claude_ai_Ahref__site-explorer-organic-competitors","mcp__claude_ai_Ahref__site-explorer-organic-keywords","mcp__claude_ai_Ahref__site-explorer-outlinks-stats","mcp__claude_ai_Ahref__site-explorer-pages-by-backlinks","mcp__claude_ai_Ahref__site-explorer-pages-by-internal-links","mcp__claude_ai_Ahref__site-explorer-pages-by-traffic","mcp__claude_ai_Ahref__site-explorer-pages-history","mcp__claude_ai_Ahref__site-explorer-paid-pages","mcp__claude_ai_Ahref__site-explorer-refdomains-history","mcp__claude_ai_Ahref__site-explorer-referring-domains","mcp__claude_ai_Ahref__site-explorer-top-pages","mcp__claude_ai_Ahref__site-explorer-total-search-volume-history","mcp__claude_ai_Ahref__site-explorer-url-rating-history","mcp__claude_ai_Ahref__social-media-activity-history","mcp__claude_ai_Ahref__social-media-authors","mcp__claude_ai_Ahref__social-media-channel-metrics","mcp__claude_ai_Ahref__social-media-channels","mcp__claude_ai_Ahref__social-media-post-metrics","mcp__claude_ai_Ahref__social-media-posts","mcp__claude_ai_Ahref__subscription-info-limits-and-usage","mcp__claude_ai_Ahref__web-analytics-browser-versions","mcp__claude_ai_Ahref__web-analytics-browser-versions-chart","mcp__claude_ai_Ahref__web-analytics-browsers","mcp__claude_ai_Ahref__web-analytics-browsers-chart","mcp__claude_ai_Ahref__web-analytics-chart","mcp__claude_ai_Ahref__web-analytics-cities","mcp__claude_ai_Ahref__web-analytics-cities-chart","mcp__claude_ai_Ahref__web-analytics-continents","mcp__claude_ai_Ahref__web-analytics-continents-chart","mcp__claude_ai_Ahref__web-analytics-countries","mcp__claude_ai_Ahref__web-analytics-countries-chart","mcp__claude_ai_Ahref__web-analytics-devices","mcp__claude_ai_Ahref__web-analytics-devices-chart","mcp__claude_ai_Ahref__web-analytics-entry-pages","mcp__claude_ai_Ahref__web-analytics-entry-pages-chart","mcp__claude_ai_Ahref__web-analytics-exit-pages","mcp__claude_ai_Ahref__web-analytics-exit-pages-chart","mcp__claude_ai_Ahref__web-analytics-languages","mcp__claude_ai_Ahref__web-analytics-languages-chart","mcp__claude_ai_Ahref__web-analytics-operating-systems","mcp__claude_ai_Ahref__web-analytics-operating-systems-chart","mcp__claude_ai_Ahref__web-analytics-operating-systems-versions","mcp__claude_ai_Ahref__web-analytics-operating-systems-versions-chart","mcp__claude_ai_Ahref__web-analytics-referrers","mcp__claude_ai_Ahref__web-analytics-referrers-chart","mcp__claude_ai_Ahref__web-analytics-source-channels","mcp__claude_ai_Ahref__web-analytics-source-channels-chart","mcp__claude_ai_Ahref__web-analytics-sources","mcp__claude_ai_Ahref__web-analytics-sources-chart","mcp__claude_ai_Ahref__web-analytics-stats","mcp__claude_ai_Ahref__web-analytics-top-pages","mcp__claude_ai_Ahref__web-analytics-top-pages-chart","mcp__claude_ai_Ahref__web-analytics-utm-params","mcp__claude_ai_Ahref__web-analytics-utm-params-chart","mcp__claude_ai_Canva__cancel-editing-transaction","mcp__claude_ai_Canva__comment-on-design","mcp__claude_ai_Canva__commit-editing-transaction","mcp__claude_ai_Canva__copy-design","mcp__claude_ai_Canva__create-brand-template-draft","mcp__claude_ai_Canva__create-design-from-brand-template","mcp__claude_ai_Canva__create-design-from-candidate","mcp__claude_ai_Canva__create-folder","mcp__claude_ai_Canva__export-design","mcp__claude_ai_Canva__generate-design","mcp__claude_ai_Canva__generate-design-structured","mcp__claude_ai_Canva__get-assets","mcp__claude_ai_Canva__get-brand-template-dataset","mcp__claude_ai_Canva__get-design","mcp__claude_ai_Canva__get-design-candidates","mcp__claude_ai_Canva__get-design-content","mcp__claude_ai_Canva__get-design-pages","mcp__claude_ai_Canva__get-design-thumbnail","mcp__claude_ai_Canva__get-export-formats","mcp__claude_ai_Canva__get-presenter-notes","mcp__claude_ai_Canva__help","mcp__claude_ai_Canva__import-design-from-url","mcp__claude_ai_Canva__list-brand-kits","mcp__claude_ai_Canva__list-comments","mcp__claude_ai_Canva__list-folder-items","mcp__claude_ai_Canva__list-replies","mcp__claude_ai_Canva__merge-designs","mcp__claude_ai_Canva__move-item-to-folder","mcp__claude_ai_Canva__perform-editing-operations","mcp__claude_ai_Canva__publish-brand-template","mcp__claude_ai_Canva__reply-to-comment","mcp__claude_ai_Canva__request-outline-review","mcp__claude_ai_Canva__resize-design","mcp__claude_ai_Canva__resolve-shortlink","mcp__claude_ai_Canva__search-brand-templates","mcp__claude_ai_Canva__search-designs","mcp__claude_ai_Canva__search-folders","mcp__claude_ai_Canva__start-editing-transaction","mcp__claude_ai_Canva__upload-asset-from-url","mcp__claude_ai_DATA_GOUV_FR__get_dataservice_info","mcp__claude_ai_DATA_GOUV_FR__get_dataservice_openapi_spec","mcp__claude_ai_DATA_GOUV_FR__get_dataset_info","mcp__claude_ai_DATA_GOUV_FR__get_metrics","mcp__claude_ai_DATA_GOUV_FR__get_resource_info","mcp__claude_ai_DATA_GOUV_FR__list_dataset_resources","mcp__claude_ai_DATA_GOUV_FR__query_resource_data","mcp__claude_ai_DATA_GOUV_FR__search_dataservices","mcp__claude_ai_DATA_GOUV_FR__search_datasets","mcp__claude_ai_DATA_GOUV_FR__search_organizations","mcp__claude_ai_Data_For_SEO__authenticate","mcp__claude_ai_Data_For_SEO__complete_authentication","mcp__claude_ai_Esteworld-Body__add_block","mcp__claude_ai_Esteworld-Body__delete_block","mcp__claude_ai_Esteworld-Body__find_esteworld_page","mcp__claude_ai_Esteworld-Body__fix_global_blocks","mcp__claude_ai_Esteworld-Body__get_block","mcp__claude_ai_Esteworld-Body__get_blocks_library","mcp__claude_ai_Esteworld-Body__get_breadcrumb","mcp__claude_ai_Esteworld-Body__get_fr_en_mapping","mcp__claude_ai_Esteworld-Body__get_internal_links","mcp__claude_ai_Esteworld-Body__get_internal_links_en","mcp__claude_ai_Esteworld-Body__get_maillage_rules","mcp__claude_ai_Esteworld-Body__get_page","mcp__claude_ai_Esteworld-Body__get_page_json","mcp__claude_ai_Esteworld-Body__get_page_status","mcp__claude_ai_Esteworld-Body__get_redirections","mcp__claude_ai_Esteworld-Body__get_section_content","mcp__claude_ai_Esteworld-Body__get_thematique_pages","mcp__claude_ai_Esteworld-Body__get_translation_languages","mcp__claude_ai_Esteworld-Body__list_pages","mcp__claude_ai_Esteworld-Body__list_pages_by_thematique","mcp__claude_ai_Esteworld-Body__list_pages_by_type","mcp__claude_ai_Esteworld-Body__list_pages_to_create","mcp__claude_ai_Esteworld-Body__list_pages_to_rewrite","mcp__claude_ai_Esteworld-Body__list_pages_with_esteworld","mcp__claude_ai_Esteworld-Body__list_pages_without_esteworld","mcp__claude_ai_Esteworld-Body__n8n_activate_workflow","mcp__claude_ai_Esteworld-Body__n8n_get_executions","mcp__claude_ai_Esteworld-Body__n8n_get_workflow","mcp__claude_ai_Esteworld-Body__n8n_list_workflows","mcp__claude_ai_Esteworld-Body__n8n_trigger_webhook","mcp__claude_ai_Esteworld-Body__preview_global_fixes","mcp__claude_ai_Esteworld-Body__reorder_blocks","mcp__claude_ai_Esteworld-Body__search_content","mcp__claude_ai_Esteworld-Body__search_links_by_keyword","mcp__claude_ai_Esteworld-Body__search_links_by_keyword_en","mcp__claude_ai_Esteworld-Body__submit_page","mcp__claude_ai_Esteworld-Body__submit_page_light","mcp__claude_ai_Esteworld-Body__translate_page","mcp__claude_ai_Esteworld-Body__update_block","mcp__claude_ai_Figma__add_code_connect_map","mcp__claude_ai_Figma__create_new_file","mcp__claude_ai_Figma__download_assets","mcp__claude_ai_Figma__export_video","mcp__claude_ai_Figma__generate_diagram","mcp__claude_ai_Figma__get_code_connect_map","mcp__claude_ai_Figma__get_code_connect_suggestions","mcp__claude_ai_Figma__get_context_for_code_connect","mcp__claude_ai_Figma__get_design_context","mcp__claude_ai_Figma__get_figjam","mcp__claude_ai_Figma__get_libraries","mcp__claude_ai_Figma__get_metadata","mcp__claude_ai_Figma__get_motion_context","mcp__claude_ai_Figma__get_screenshot","mcp__claude_ai_Figma__get_shader_effect","mcp__claude_ai_Figma__get_shader_fill","mcp__claude_ai_Figma__get_variable_defs","mcp__claude_ai_Figma__list_shader_effects","mcp__claude_ai_Figma__list_shader_fills","mcp__claude_ai_Figma__search_design_system","mcp__claude_ai_Figma__send_code_connect_mappings","mcp__claude_ai_Figma__upload_assets","mcp__claude_ai_Figma__use_figma","mcp__claude_ai_Figma__whoami","mcp__claude_ai_Gmail__create_draft","mcp__claude_ai_Gmail__create_label","mcp__claude_ai_Gmail__delete_label","mcp__claude_ai_Gmail__get_thread","mcp__claude_ai_Gmail__label_message","mcp__claude_ai_Gmail__label_thread","mcp__claude_ai_Gmail__list_drafts","mcp__claude_ai_Gmail__list_labels","mcp__claude_ai_Gmail__search_threads","mcp__claude_ai_Gmail__unlabel_message","mcp__claude_ai_Gmail__unlabel_thread","mcp__claude_ai_Gmail__update_label","mcp__claude_ai_Google_Calendar__create_event","mcp__claude_ai_Google_Calendar__delete_event","mcp__claude_ai_Google_Calendar__get_event","mcp__claude_ai_Google_Calendar__list_calendars","mcp__claude_ai_Google_Calendar__list_events","mcp__claude_ai_Google_Calendar__respond_to_event","mcp__claude_ai_Google_Calendar__suggest_time","mcp__claude_ai_Google_Calendar__update_event","mcp__claude_ai_Google_Drive__copy_file","mcp__claude_ai_Google_Drive__create_file","mcp__claude_ai_Google_Drive__download_file_content","mcp__claude_ai_Google_Drive__get_file_metadata","mcp__claude_ai_Google_Drive__get_file_permissions","mcp__claude_ai_Google_Drive__list_recent_files","mcp__claude_ai_Google_Drive__read_file_content","mcp__claude_ai_Google_Drive__search_files","mcp__claude_ai_SEMRush__backlink_research","mcp__claude_ai_SEMRush__execute_report","mcp__claude_ai_SEMRush__get_report_schema","mcp__claude_ai_SEMRush__keyword_research","mcp__claude_ai_SEMRush__organic_research","mcp__claude_ai_SEMRush__overview_research","mcp__claude_ai_SEMRush__projects_research","mcp__claude_ai_SEMRush__siteaudit_research","mcp__claude_ai_SEMRush__subdomain_research","mcp__claude_ai_SEMRush__subfolder_research","mcp__claude_ai_SEMRush__tracking_research","mcp__claude_ai_SEMRush__trends_research","mcp__claude_ai_SEMRush__url_research","mcp__claude_ai_Vercel__add_toolbar_reaction","mcp__claude_ai_Vercel__change_toolbar_thread_resolve_status","mcp__claude_ai_Vercel__check_domain_availability_and_price","mcp__claude_ai_Vercel__deploy_to_vercel","mcp__claude_ai_Vercel__edit_toolbar_message","mcp__claude_ai_Vercel__get_access_to_vercel_url","mcp__claude_ai_Vercel__get_deployment","mcp__claude_ai_Vercel__get_deployment_build_logs","mcp__claude_ai_Vercel__get_project","mcp__claude_ai_Vercel__get_runtime_errors","mcp__claude_ai_Vercel__get_runtime_logs","mcp__claude_ai_Vercel__get_toolbar_thread","mcp__claude_ai_Vercel__import-claude-design-from-url","mcp__claude_ai_Vercel__list_deployments","mcp__claude_ai_Vercel__list_projects","mcp__claude_ai_Vercel__list_teams","mcp__claude_ai_Vercel__list_toolbar_threads","mcp__claude_ai_Vercel__reply_to_toolbar_thread","mcp__claude_ai_Vercel__search_vercel_documentation","mcp__claude_ai_Vercel__web_fetch_vercel_url","mcp__gpt-image-2__continue_edit_session","mcp__gpt-image-2__edit_image","mcp__gpt-image-2__end_edit_session","mcp__gpt-image-2__generate_image","mcp__gpt-image-2__list_edit_sessions","mcp__gpt-image-2__start_edit_session","mcp__hostinger__DNS_deleteDNSRecordsV1","mcp__hostinger__DNS_getDNSRecordsV1","mcp__hostinger__DNS_getDNSSnapshotListV1","mcp__hostinger__DNS_getDNSSnapshotV1","mcp__hostinger__DNS_resetDNSRecordsV1","mcp__hostinger__DNS_restoreDNSSnapshotV1","mcp__hostinger__DNS_updateDNSRecordsV1","mcp__hostinger__DNS_validateDNSRecordsV1","mcp__hostinger__VPS_activateFirewallV1","mcp__hostinger__VPS_attachPublicKeyV1","mcp__hostinger__VPS_createFirewallRuleV1","mcp__hostinger__VPS_createNewFirewallV1","mcp__hostinger__VPS_createNewProjectV1","mcp__hostinger__VPS_createPTRRecordV1","mcp__hostinger__VPS_createPostInstallScriptV1","mcp__hostinger__VPS_createPublicKeyV1","mcp__hostinger__VPS_createSnapshotV1","mcp__hostinger__VPS_deactivateFirewallV1","mcp__hostinger__VPS_deleteFirewallRuleV1","mcp__hostinger__VPS_deleteFirewallV1","mcp__hostinger__VPS_deletePTRRecordV1","mcp__hostinger__VPS_deletePostInstallScriptV1","mcp__hostinger__VPS_deleteProjectV1","mcp__hostinger__VPS_deletePublicKeyV1","mcp__hostinger__VPS_deleteSnapshotV1","mcp__hostinger__VPS_getActionDetailsV1","mcp__hostinger__VPS_getActionsV1","mcp__hostinger__VPS_getAttachedPublicKeysV1","mcp__hostinger__VPS_getBackupsV1","mcp__hostinger__VPS_getDataCenterListV1","mcp__hostinger__VPS_getFirewallDetailsV1","mcp__hostinger__VPS_getFirewallListV1","mcp__hostinger__VPS_getMetricsV1","mcp__hostinger__VPS_getPostInstallScriptV1","mcp__hostinger__VPS_getPostInstallScriptsV1","mcp__hostinger__VPS_getProjectContainersV1","mcp__hostinger__VPS_getProjectContentsV1","mcp__hostinger__VPS_getProjectListV1","mcp__hostinger__VPS_getProjectLogsV1","mcp__hostinger__VPS_getPublicKeysV1","mcp__hostinger__VPS_getScanMetricsV1","mcp__hostinger__VPS_getSnapshotV1","mcp__hostinger__VPS_getTemplateDetailsV1","mcp__hostinger__VPS_getTemplatesV1","mcp__hostinger__VPS_getVirtualMachineDetailsV1","mcp__hostinger__VPS_getVirtualMachinesV1","mcp__hostinger__VPS_installMonarxV1","mcp__hostinger__VPS_purchaseNewVirtualMachineV1","mcp__hostinger__VPS_recreateVirtualMachineV1","mcp__hostinger__VPS_resetHostnameV1","mcp__hostinger__VPS_restartProjectV1","mcp__hostinger__VPS_restartVirtualMachineV1","mcp__hostinger__VPS_restoreBackupV1","mcp__hostinger__VPS_restoreSnapshotV1","mcp__hostinger__VPS_setHostnameV1","mcp__hostinger__VPS_setNameserversV1","mcp__hostinger__VPS_setPanelPasswordV1","mcp__hostinger__VPS_setRootPasswordV1","mcp__hostinger__VPS_setupPurchasedVirtualMachineV1","mcp__hostinger__VPS_startProjectV1","mcp__hostinger__VPS_startRecoveryModeV1","mcp__hostinger__VPS_startVirtualMachineV1","mcp__hostinger__VPS_stopProjectV1","mcp__hostinger__VPS_stopRecoveryModeV1","mcp__hostinger__VPS_stopVirtualMachineV1","mcp__hostinger__VPS_syncFirewallV1","mcp__hostinger__VPS_uninstallMonarxV1","mcp__hostinger__VPS_updateFirewallRuleV1","mcp__hostinger__VPS_updatePostInstallScriptV1","mcp__hostinger__VPS_updateProjectV1","mcp__hostinger__billing_deletePaymentMethodV1","mcp__hostinger__billing_disableAutoRenewalV1","mcp__hostinger__billing_enableAutoRenewalV1","mcp__hostinger__billing_getCatalogItemListV1","mcp__hostinger__billing_getPaymentMethodListV1","mcp__hostinger__billing_getSubscriptionListV1","mcp__hostinger__billing_setDefaultPaymentMethodV1","mcp__hostinger__domains_checkDomainAvailabilityV1","mcp__hostinger__domains_createDomainForwardingV1","mcp__hostinger__domains_createWHOISProfileV1","mcp__hostinger__domains_deleteDomainForwardingV1","mcp__hostinger__domains_deleteWHOISProfileV1","mcp__hostinger__domains_disableDomainLockV1","mcp__hostinger__domains_disablePrivacyProtectionV1","mcp__hostinger__domains_enableDomainLockV1","mcp__hostinger__domains_enablePrivacyProtectionV1","mcp__hostinger__domains_getDomainDetailsV1","mcp__hostinger__domains_getDomainForwardingV1","mcp__hostinger__domains_getDomainListV1","mcp__hostinger__domains_getWHOISProfileListV1","mcp__hostinger__domains_getWHOISProfileUsageV1","mcp__hostinger__domains_getWHOISProfileV1","mcp__hostinger__domains_purchaseNewDomainV1","mcp__hostinger__domains_updateDomainNameserversV1","mcp__hostinger__hosting_createAccountDatabaseV1","mcp__hostinger__hosting_createWebsiteParkedDomainV1","mcp__hostinger__hosting_createWebsiteSubdomainV1","mcp__hostinger__hosting_createWebsiteV1","mcp__hostinger__hosting_deleteAccountDatabaseV1","mcp__hostinger__hosting_deleteWebsiteParkedDomainV1","mcp__hostinger__hosting_deleteWebsiteSubdomainV1","mcp__hostinger__hosting_deployJsApplication","mcp__hostinger__hosting_deployStaticWebsite","mcp__hostinger__hosting_deployWordpressPlugin","mcp__hostinger__hosting_deployWordpressTheme","mcp__hostinger__hosting_generateAFreeSubdomainV1","mcp__hostinger__hosting_importWordpressWebsite","mcp__hostinger__hosting_installWordPressV1","mcp__hostinger__hosting_listAccountDatabasesV1","mcp__hostinger__hosting_listAvailableDatacentersV1","mcp__hostinger__hosting_listJsDeployments","mcp__hostinger__hosting_listOrdersV1","mcp__hostinger__hosting_listWebsiteParkedDomainsV1","mcp__hostinger__hosting_listWebsiteSubdomainsV1","mcp__hostinger__hosting_listWebsitesV1","mcp__hostinger__hosting_listWordPressInstallationsV1","mcp__hostinger__hosting_showJsDeploymentLogs","mcp__hostinger__hosting_verifyDomainOwnershipV1","mcp__hostinger__reach_createANewContactSegmentV1","mcp__hostinger__reach_createANewContactV1","mcp__hostinger__reach_createNewContactsV1","mcp__hostinger__reach_deleteAContactV1","mcp__hostinger__reach_getSegmentDetailsV1","mcp__hostinger__reach_listContactGroupsV1","mcp__hostinger__reach_listContactsV1","mcp__hostinger__reach_listProfilesV1","mcp__hostinger__reach_listSegmentContactsV1","mcp__hostinger__reach_listSegmentsV1","mcp__hostinger__v2_getDomainVerificationsDIRECT","mcp__n8n-mcp__get_node","mcp__n8n-mcp__get_template","mcp__n8n-mcp__n8n_audit_instance","mcp__n8n-mcp__n8n_autofix_workflow","mcp__n8n-mcp__n8n_create_workflow","mcp__n8n-mcp__n8n_delete_workflow","mcp__n8n-mcp__n8n_deploy_template","mcp__n8n-mcp__n8n_executions","mcp__n8n-mcp__n8n_generate_workflow","mcp__n8n-mcp__n8n_get_workflow","mcp__n8n-mcp__n8n_health_check","mcp__n8n-mcp__n8n_list_workflows","mcp__n8n-mcp__n8n_manage_credentials","mcp__n8n-mcp__n8n_manage_datatable","mcp__n8n-mcp__n8n_test_workflow","mcp__n8n-mcp__n8n_update_full_workflow","mcp__n8n-mcp__n8n_update_partial_workflow","mcp__n8n-mcp__n8n_validate_workflow","mcp__n8n-mcp__n8n_workflow_versions","mcp__n8n-mcp__search_nodes","mcp__n8n-mcp__search_templates","mcp__n8n-mcp__tools_documentation","mcp__n8n-mcp__validate_node","mcp__n8n-mcp__validate_workflow","mcp__nanobanana__generate_image","mcp__nanobanana__maintenance","mcp__nanobanana__show_output_stats","mcp__nanobanana__upload_file","mcp__plugin_vercel_vercel__authenticate","mcp__plugin_vercel_vercel__complete_authentication","mcp__refero__refero_get_flow","mcp__refero__refero_get_screen","mcp__refero__refero_get_screen_image","mcp__refero__refero_get_similar_screens","mcp__refero__refero_get_style","mcp__refero__refero_search_flows","mcp__refero__refero_search_screens","mcp__refero__refero_search_styles","mcp__semrush__authenticate","mcp__semrush__complete_authentication","mcp__stock-images-mcp__search_stock_images","mcp__trello__add_card_to_list","mcp__trello__add_checklist_item","mcp__trello__add_comment","mcp__trello__add_list_to_board","mcp__trello__archive_card","mcp__trello__archive_list","mcp__trello__assign_member_to_card","mcp__trello__attach_file_to_card","mcp__trello__attach_image_data_to_card","mcp__trello__attach_image_to_card","mcp__trello__create_board","mcp__trello__create_checklist","mcp__trello__create_label","mcp__trello__delete_comment","mcp__trello__delete_label","mcp__trello__find_checklist_items_by_description","mcp__trello__get_acceptance_criteria","mcp__trello__get_active_board_info","mcp__trello__get_board_labels","mcp__trello__get_board_members","mcp__trello__get_card","mcp__trello__get_card_comments","mcp__trello__get_card_history","mcp__trello__get_cards_by_list_id","mcp__trello__get_checklist_by_name","mcp__trello__get_checklist_items","mcp__trello__get_health","mcp__trello__get_health_detailed","mcp__trello__get_health_metadata","mcp__trello__get_health_performance","mcp__trello__get_lists","mcp__trello__get_my_cards","mcp__trello__get_recent_activity","mcp__trello__list_boards","mcp__trello__list_boards_in_workspace","mcp__trello__list_workspaces","mcp__trello__move_card","mcp__trello__perform_system_repair","mcp__trello__remove_member_from_card","mcp__trello__set_active_board","mcp__trello__set_active_workspace","mcp__trello__update_card_details","mcp__trello__update_checklist_item","mcp__trello__update_comment","mcp__trello__update_label"],"removedNames":[],"readdedNames":[]},"type":"attachment","uuid":"f4bcfc05-bf35-463c-b7bd-e699da93ea9f","timestamp":"2026-06-26T11:53:39.997Z","userType":"external","entrypoint":"cli","cwd":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale","sessionId":"c02b163b-170b-4cd3-a555-3613df5965a3","version":"2.1.193","gitBranch":"tom/validation-finale","slug":"plusieurs-chose-faire-crispy-axolotl"}
{"parentUuid":"f4bcfc05-bf35-463c-b7bd-e699da93ea9f","isSidechain":true,"agentId":"a9fd20a9d1d03f0e9","attachment":{"type":"skill_listing","content":"- adapt\n- agentmail\n- animate\n- arrange\n- audit\n- bolder\n- bun-to-next\n- clarify\n- colorize\n- critique\n- delight\n- design-taste-frontend: Anti-slop frontend skill for landing pages, portfolios, and redesigns. The agent reads the brief, infers the right design direction, and ships interfaces that do not look templated. Real design systems when applicable, audit-first on redesigns, strict pre-flight check.\n- distill\n- excalidraw-diagram: Create Excalidraw diagram JSON files that make visual arguments. Use when the user wants to visualize workflows, architectures, or concepts.\n- extract\n- feedbackpin: Fetch visual feedback tasks from FeedbackPin, resolve them by fixing the code, and report back via API\n- full-output-enforcement\n- gsap-core\n- gsap-frameworks\n- gsap-performance\n- gsap-plugins\n- gsap-react\n- gsap-scrolltrigger\n- gsap-timeline\n- gsap-utils\n- harden\n- high-end-visual-design\n- impeccable\n- industrial-brutalist-ui\n- minimalist-ui\n- netlify-cli: Déploie, gère et configure des sites Netlify depuis le terminal via le CLI officiel. Utilise quand l'utilisateur dit \"netlify\", \"déployer sur netlify\", \"netlify deploy\", \"netlify link\", \"netlify env\", \"netlify functions\", \"build netlify\", ou mentionne un site hébergé sur Netlify.\n- nextjs-wordpress-headless: Branche un projet Next.js (App Router) sur un WordPress headless auto-hébergé (Docker sur VPS Ubuntu, ACF PRO Flexible Content + WPGraphQL) avec un catalogue de blocks réorganisables, revalidation par tags et seed idempotent. Gère pages one-off, CPT, options globales, SEO.\n- normalize\n- onboard\n- optimize\n- overdrive\n- paf-site-magic\n- passmark\n- polish\n- quieter\n- redesign-existing-projects\n- refero-design\n- scheduled-actions\n- seo\n- seo-audit: Full website SEO audit with parallel subagent delegation. Crawls up to 500 pages, detects business type, delegates to 10 specialists (7 core + 3 conditional), generates health score. Use when user says \"audit\", \"full SEO check\", \"analyze my site\", or \"website health check\".\n- seo-backlinks\n- seo-competitor-pages\n- seo-content\n- seo-dataforseo\n- seo-firecrawl\n- seo-geo\n- seo-google\n- seo-hreflang\n- seo-image-gen\n- seo-images\n- seo-local\n- seo-maps\n- seo-page\n- seo-plan\n- seo-programmatic\n- seo-schema\n- seo-sitemap\n- seo-technical\n- shape\n- stitch-design-taste\n- typeset\n- handoff: Cree ou met a jour HANDOFF.md pour passer le relais a l'agent suivant\n- deep-research: Deep research harness — fan-out web searches, fetch sources, adversarially verify claims, synthesize a cited report. - When the user wants a deep, multi-source, fact-checked research report on any topic. BEFORE invoking, check if the question is specific enough to research directly — if underspecified (e.g., \"what car to buy\" without budget/use-case/region), ask 2-3 clarifying questions to narrow scope. Then pass the refined question as args, weaving the answers in.\n- vercel:bootstrap\n- vercel:deploy\n- vercel:env\n- vercel:marketplace\n- vercel:status\n- vercel:ai-gateway\n- vercel:ai-sdk\n- vercel:auth\n- vercel:bootstrap\n- vercel:chat-sdk\n- vercel:deployments-cicd\n- vercel:env-vars\n- vercel:knowledge-update\n- vercel:marketplace\n- vercel:microfrontends\n- vercel:next-cache-components\n- vercel:next-forge\n- vercel:next-upgrade\n- vercel:nextjs\n- vercel:react-best-practices\n- vercel:routing-middleware\n- vercel:runtime-cache\n- vercel:shadcn\n- vercel:turbopack\n- vercel:vercel-agent\n- vercel:vercel-cli\n- vercel:vercel-firewall\n- vercel:vercel-functions\n- vercel:vercel-sandbox\n- vercel:vercel-storage\n- vercel:verification\n- vercel:workflow: Vercel Workflow DevKit (WDK) expert guidance. Use when building durable workflows, long-running tasks, API routes or agents that need pause/resume, retries, step-based execution, or crash-safe orchestration with Vercel Workflow.\n- update-config: Use this skill to configure the Claude Code harness via settings.json. Automated behaviors (\"from now on when X\", \"each time X\", \"whenever X\", \"before/after X\") require hooks configured in settings.json - the harness executes these, not Claude, so memory/preferences cannot fulfill them. Also use for: permissions (\"allow X\", \"add permission\", \"move permission to\"), env vars (\"set X=Y\"), hook troubleshooting, or any changes to settings.json/settings.local.json files. Examples: \"allow npm commands\", \"add bq permission to global settings\", \"move permission to user settings\", \"set DEBUG=true\", \"when claude stops show X\". For simple settings like theme/model, suggest the /config command.\n- keybindings-help: Use when the user wants to customize keyboard shortcuts, rebind keys, add chord bindings, or modify ~/.claude/keybindings.json. Examples: \"rebind ctrl+s\", \"add a chord shortcut\", \"change the submit key\", \"customize keybindings\".\n- verify: Verify that a code change actually does what it's supposed to by running the app and observing behavior. Use when asked to verify a PR, confirm a fix works, test a change manually, check that a feature works, or validate local changes before pushing.\n- code-review: Review the current diff for correctness bugs and reuse/simplification/efficiency cleanups at the given effort level (low/medium: fewer, high-confidence findings; high→max: broader coverage, may include uncertain findings; ultra: deep multi-agent review in the cloud). Pass --comment to post findings as inline PR comments, or --fix to apply the findings to the working tree after the review.\n- simplify: Review the changed code for reuse, simplification, efficiency, and altitude cleanups, then apply the fixes. Quality only — it does not hunt for bugs; use /code-review for that.\n- fewer-permission-prompts: Scan your transcripts for common read-only Bash and MCP tool calls, then add a prioritized allowlist to project .claude/settings.json to reduce permission prompts.\n- loop: Run a prompt or slash command on a recurring interval (e.g. /loop 5m /foo). Omit the interval to let the model self-pace. - When the user wants to set up a recurring task, poll for status, or run something repeatedly on an interval (e.g. \"check the deploy every 5 minutes\", \"keep running /babysit-prs\"). Do NOT invoke for one-off tasks.\n- schedule: Create, update, list, or run scheduled cloud agents (routines) that execute on a cron schedule. - When the user wants to schedule a recurring cloud agent, set up automated tasks, create a cron job for Claude Code, or manage their scheduled agents/routines. Also use when the user wants a one-time scheduled run (\"run this once at 3pm\", \"remind me to check X tomorrow\").\n- claude-api: Reference for the Claude API / Anthropic SDK — model ids, pricing, params, streaming, tool use, MCP, agents, caching, token counting, model migration.\nTRIGGER — read BEFORE opening the target file; don't skip because it \"looks like a one-liner\" — whenever: the prompt names Claude/Anthropic in any form (Claude, Anthropic, Fable, Opus, Sonnet, Haiku, `anthropic`, `@anthropic-ai`, `claude-*`, `us.anthropic.*`, `[1m]`); the user asks about an LLM (pricing/model choice/limits/caching) — never answer from memory; OR the task is LLM-shaped with provider unstated (agent/MCP/tool-definition/multi-agent/RAG/LLM-judge/computer-use; generate/summarize/extract/classify/rewrite/converse over NL; debugging refusals/cutoffs/streaming/tool-calls/tokens).\nSKIP only when another provider is being worked on (overrides all triggers): OpenAI/GPT/Gemini/Llama/Mistral/Cohere/Ollama named in the query; OR `grep -rE 'openai|langchain_openai|google.generativeai|genai|mistralai|cohere|ollama'` over the project hits (run this grep FIRST if no provider named — don't Read the file).\n- run: Launch and drive this project's app to see a change working. Use when asked to run, start, or screenshot the app, or to confirm a change works in the real app (not just tests). First looks for a project skill that already covers launching the app; otherwise falls back to built-in patterns per project type (CLI, server, TUI, Electron, browser-driven, library).\n- init\n- review\n- security-review","skillCount":113,"isInitial":true,"names":["adapt","agentmail","animate","arrange","audit","bolder","bun-to-next","clarify","colorize","critique","delight","design-taste-frontend","distill","excalidraw-diagram","extract","feedbackpin","full-output-enforcement","gsap-core","gsap-frameworks","gsap-performance","gsap-plugins","gsap-react","gsap-scrolltrigger","gsap-timeline","gsap-utils","harden","high-end-visual-design","impeccable","industrial-brutalist-ui","minimalist-ui","netlify-cli","nextjs-wordpress-headless","normalize","onboard","optimize","overdrive","paf-site-magic","passmark","polish","quieter","redesign-existing-projects","refero-design","scheduled-actions","seo","seo-audit","seo-backlinks","seo-competitor-pages","seo-content","seo-dataforseo","seo-firecrawl","seo-geo","seo-google","seo-hreflang","seo-image-gen","seo-images","seo-local","seo-maps","seo-page","seo-plan","seo-programmatic","seo-schema","seo-sitemap","seo-technical","shape","stitch-design-taste","typeset","handoff","deep-research","vercel:bootstrap","vercel:deploy","vercel:env","vercel:marketplace","vercel:status","vercel:ai-gateway","vercel:ai-sdk","vercel:auth","vercel:bootstrap","vercel:chat-sdk","vercel:deployments-cicd","vercel:env-vars","vercel:knowledge-update","vercel:marketplace","vercel:microfrontends","vercel:next-cache-components","vercel:next-forge","vercel:next-upgrade","vercel:nextjs","vercel:react-best-practices","vercel:routing-middleware","vercel:runtime-cache","vercel:shadcn","vercel:turbopack","vercel:vercel-agent","vercel:vercel-cli","vercel:vercel-firewall","vercel:vercel-functions","vercel:vercel-sandbox","vercel:vercel-storage","vercel:verification","vercel:workflow","update-config","keybindings-help","verify","code-review","simplify","fewer-permission-prompts","loop","schedule","claude-api","run","init","review","security-review"]},"type":"attachment","uuid":"6a060806-cfd1-4e7b-9225-7179c8c59c07","timestamp":"2026-06-26T11:53:39.999Z","userType":"external","entrypoint":"cli","cwd":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale","sessionId":"c02b163b-170b-4cd3-a555-3613df5965a3","version":"2.1.193","gitBranch":"tom/validation-finale","slug":"plusieurs-chose-faire-crispy-axolotl"}
{"parentUuid":"6a060806-cfd1-4e7b-9225-7179c8c59c07","isSidechain":true,"agentId":"a9fd20a9d1d03f0e9","message":{"model":"claude-haiku-4-5-20251001","id":"msg_014ygHtiUYqrzdapq5HEZfSE","type":"message","role":"assistant","content":[{"type":"thinking","thinking":"","signature":"EpwKCm0IDxgCKkAx3YDkeUFd/DhsMcSOpGNMnAlV57dmBp8/jRH0lOJ1F6NLwuzvMdyaX96qdQ5CRrJx23XeW7kipZKrsg1j1D7+MhljbGF1ZGUtaGFpa3UtNC01LTIwMjUxMDAxOABCCHRoaW5raW5nEgwdfw+GIRiWFe0vNn0aDDZllwvrCxpMu7zxIiIwVWqzWtQQ93uxBCF8OemIk8eorNfaTKNU+11tpdPxJH4Wcqm4geNEK6TJXt/VPNQ/KtwIzRi7yVaLFsVGqgyXclkHWU4Y75c+PFynh11kwAoOC24ZyEDPPi3rmHeFFp+kWmy/JlcJ+Th+Wg8sUaiyY0WDI9pusbiAjCICFyOrl70hgA1KnZv/ine/Chah4ylHs5Z7TMm/RTFk0cI39MqQ8NzKanhSS6sQZa8S6rP84Jbf5iyHGl8TdNXbSaE13wJuOAlTskX+73NeMLjsg59Q7PKPCYlgvS3ylDEcwEUxCFmDbdDWx+OQi+kCgw/zf41DV26+4VnK2eKG/l103bLmHwTGHQ0dHzpcobWiKfCvRCq9ao9XMQNadvl/wIdWlT6fcJ9VXLzgV7MI1vji5LtChs0gk429HFJthdfhuYTUjDA4VqNYUWBQqEjTxMt42KleW6MT0qrPpeuiyZBzK74lcNlCtWM97JfiObvBG/Bp3LzcA2RNvgAotgoUlWzXwwnQ1D2ZTOLTd/zoSA8mhIrR/KdRc3GGEPAiOdajl7THR8wm+YZfC39sNvW04wDsk3MGkgd6+05fDvdKqFNiAvEWPdxGWFuRR9DuBc6QXXv/lV38sEwlqUt0I3F/avGrrhKpOO/g+E1YH+fS5/6oDQFvrr4xSJWuXSUdVigG8DvvDumY3QtxNXX7WXfwa6RcoqblCukmd8hIQqBFditKEGVAKe/JjWMLOpy7l4ep9iIY6wXsR5l2XGgrzO/twVBq0THIPh0zrjXVLhPgyGoEgFVesqIJ23kw8xIZRYZoaFLI/JdJTPZmvkyDsHp3dxaKFZZynIcY8mbOYIbtVqUIqCxJRKxk+m65IdX/OTPsMwOOtoENIdAPz8nAhBjoZcLgHWOuzubPpmgCT4y3dbbXOe9y7sXBvLNJugz1YTG++JpynyoTb9te0M8EHtHw8P6gIq178BXASRoko1VFLZmUKoMTS8mfWspQgpG6dnQpQ8GVHm+5KnZMgPqpZeOq3CUAh+nBj+yVzJw5s1Fiqujt47BTOb7nVCFkHuzQYlNDQdEvMBOecNVNHc4A2yxaMNYzoxB51IaGxdHdpDi2AGzA2YAP64tmT5uWruItbVZrJFXUGX9x9vu+oFs5MgNZ1woM9VZk1PkB0baLLQ86E9n6UfbnpQ2AMonMLMFbrZO6EUpRHpuh1yuEuGmCkwSwUfAEyBnDhgohVfjufG6MQAmG7hfT6vd38D9zo7lA2Noo1h0ge8hMu3cglt0HFu4PuxVUEXFeEyGxTzkZIfipCOv+6qMr2vu+V9Yy+MkqaakwX7ckVWirxqnKw7Vuje5OFEwb9mU3lje8Rx6CD1nkXu2O9cb69hezcy4EJc4dT5p1hDplUOQbdxj6TW2xXyMdDKhv+X6FKXLEwnhYkXOr45bPBS0sP7SGM9QuiXzLnVBg9OWnCsqZTI2KhdUR+v3q5Ha3m5CQL+dMkw7KC+2a36SZBpOJJUJilHv8nU211z1QNtsQhXgMa7CmGRvgIZT/26wSQRJRTRvxZvewLNUWDXsCaqv3GAE="}],"stop_reason":null,"stop_sequence":null,"stop_details":null,"usage":{"input_tokens":10,"cache_creation_input_tokens":19686,"cache_read_input_tokens":5973,"cache_creation":{"ephemeral_5m_input_tokens":19686,"ephemeral_1h_input_tokens":0},"output_tokens":1,"service_tier":"standard","inference_geo":"not_available"},"diagnostics":null},"requestId":"req_011CcRpqktL5EgifGpn2AVHZ","attributionAgent":"Explore","type":"assistant","uuid":"47f5ee2e-26f6-4db2-9006-881e0c72956c","timestamp":"2026-06-26T11:53:43.172Z","userType":"external","entrypoint":"cli","cwd":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale","sessionId":"c02b163b-170b-4cd3-a555-3613df5965a3","version":"2.1.193","gitBranch":"tom/validation-finale","slug":"plusieurs-chose-faire-crispy-axolotl"}
{"parentUuid":"47f5ee2e-26f6-4db2-9006-881e0c72956c","isSidechain":true,"agentId":"a9fd20a9d1d03f0e9","message":{"model":"claude-haiku-4-5-20251001","id":"msg_014ygHtiUYqrzdapq5HEZfSE","type":"message","role":"assistant","content":[{"type":"text","text":"I'll explore both the live page and the repo's design system. Let me start with parallel searches."}],"stop_reason":null,"stop_sequence":null,"stop_details":null,"usage":{"input_tokens":10,"cache_creation_input_tokens":19686,"cache_read_input_tokens":5973,"cache_creation":{"ephemeral_5m_input_tokens":19686,"ephemeral_1h_input_tokens":0},"output_tokens":1,"service_tier":"standard","inference_geo":"not_available"},"diagnostics":null},"requestId":"req_011CcRpqktL5EgifGpn2AVHZ","attributionAgent":"Explore","type":"assistant","uuid":"fe1742d4-d1b5-40e0-ae34-f6eb0a5ff5c4","timestamp":"2026-06-26T11:53:43.617Z","userType":"external","entrypoint":"cli","cwd":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale","sessionId":"c02b163b-170b-4cd3-a555-3613df5965a3","version":"2.1.193","gitBranch":"tom/validation-finale","slug":"plusieurs-chose-faire-crispy-axolotl"}
{"parentUuid":"fe1742d4-d1b5-40e0-ae34-f6eb0a5ff5c4","isSidechain":true,"agentId":"a9fd20a9d1d03f0e9","message":{"model":"claude-haiku-4-5-20251001","id":"msg_014ygHtiUYqrzdapq5HEZfSE","type":"message","role":"assistant","content":[{"type":"tool_use","id":"toolu_01UYBmJhDrNNDz7vDpWRQ7fS","name":"ToolSearch","input":{"query":"select:WebFetch","max_results":1},"caller":{"type":"direct"}}],"stop_reason":null,"stop_sequence":null,"stop_details":null,"usage":{"input_tokens":10,"cache_creation_input_tokens":19686,"cache_read_input_tokens":5973,"cache_creation":{"ephemeral_5m_input_tokens":19686,"ephemeral_1h_input_tokens":0},"output_tokens":1,"service_tier":"standard","inference_geo":"not_available"},"diagnostics":null},"requestId":"req_011CcRpqktL5EgifGpn2AVHZ","attributionAgent":"Explore","type":"assistant","uuid":"c37705dc-3896-41ab-a889-1d20a5195b24","timestamp":"2026-06-26T11:53:43.829Z","userType":"external","entrypoint":"cli","cwd":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale","sessionId":"c02b163b-170b-4cd3-a555-3613df5965a3","version":"2.1.193","gitBranch":"tom/validation-finale","slug":"plusieurs-chose-faire-crispy-axolotl"}
{"parentUuid":"c37705dc-3896-41ab-a889-1d20a5195b24","isSidechain":true,"promptId":"606b4c79-d3cd-4b0a-a2e5-8b38011359cb","agentId":"a9fd20a9d1d03f0e9","type":"user","message":{"role":"user","content":[{"type":"tool_result","tool_use_id":"toolu_01UYBmJhDrNNDz7vDpWRQ7fS","content":[{"type":"tool_reference","tool_name":"WebFetch"}]}]},"uuid":"1fbffae5-f90c-4940-a2f9-51f91e1a951e","timestamp":"2026-06-26T11:53:43.846Z","toolUseResult":{"matches":["WebFetch"],"query":"select:WebFetch","total_deferred_tools":571},"sourceToolAssistantUUID":"c37705dc-3896-41ab-a889-1d20a5195b24","userType":"external","entrypoint":"cli","cwd":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale","sessionId":"c02b163b-170b-4cd3-a555-3613df5965a3","version":"2.1.193","gitBranch":"tom/validation-finale","slug":"plusieurs-chose-faire-crispy-axolotl"}
{"parentUuid":"1fbffae5-f90c-4940-a2f9-51f91e1a951e","isSidechain":true,"agentId":"a9fd20a9d1d03f0e9","message":{"model":"claude-haiku-4-5-20251001","id":"msg_014ygHtiUYqrzdapq5HEZfSE","type":"message","role":"assistant","content":[{"type":"tool_use","id":"toolu_01LGyhvmyo6FCtdSnuXMBsQs","name":"Bash","input":{"command":"find /opt/projects/.covalba-next-wp-worktrees/tom-validation-finale -type f -name \"*.tsx\" -o -name \"*.ts\" | grep -i \"sector\\|template\\|page\" | head -20"},"caller":{"type":"direct"}}],"stop_reason":null,"stop_sequence":null,"stop_details":null,"usage":{"input_tokens":10,"cache_creation_input_tokens":19686,"cache_read_input_tokens":5973,"cache_creation":{"ephemeral_5m_input_tokens":19686,"ephemeral_1h_input_tokens":0},"output_tokens":1,"service_tier":"standard","inference_geo":"not_available"},"diagnostics":null},"requestId":"req_011CcRpqktL5EgifGpn2AVHZ","attributionAgent":"Explore","type":"assistant","uuid":"d7ac8413-475e-4215-b36c-9b4689d9a7df","timestamp":"2026-06-26T11:53:44.671Z","userType":"external","entrypoint":"cli","cwd":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale","sessionId":"c02b163b-170b-4cd3-a555-3613df5965a3","version":"2.1.193","gitBranch":"tom/validation-finale","slug":"plusieurs-chose-faire-crispy-axolotl"}
{"parentUuid":"d7ac8413-475e-4215-b36c-9b4689d9a7df","isSidechain":true,"promptId":"606b4c79-d3cd-4b0a-a2e5-8b38011359cb","agentId":"a9fd20a9d1d03f0e9","type":"user","message":{"role":"user","content":[{"tool_use_id":"toolu_01LGyhvmyo6FCtdSnuXMBsQs","type":"tool_result","content":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/app/page.tsx\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/src/data/roofPages.ts\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/src/data/sectorSeo.ts\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/src/lib/roofPageSeo.ts\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/src/components/SectorReferenceHighlights.tsx\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/src/components/SectorsGrid.tsx\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/src/components/MidPageForm.tsx\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/src/hooks/usePageMeta.ts\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/app/guides/page.tsx\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/app/presse/page.tsx\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/app/devenir-applicateur/page.tsx\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/app/guide-cool-roof/page.tsx\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/app/simulateur-economie-energie/page.tsx\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/app/qui-sommes-nous/page.tsx\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/app/diagnostic/page.tsx\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/app/references/page.tsx\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/app/[...slug]/page.tsx\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/app/contact/page.tsx\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/app/faq/page.tsx\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/app/nos-solutions-cool-roof/page.tsx","is_error":false}]},"uuid":"d6fb4ac1-45d7-4f8f-ba25-6046b8f67192","timestamp":"2026-06-26T11:53:44.762Z","toolUseResult":{"stdout":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/app/page.tsx\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/src/data/roofPages.ts\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/src/data/sectorSeo.ts\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/src/lib/roofPageSeo.ts\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/src/components/SectorReferenceHighlights.tsx\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/src/components/SectorsGrid.tsx\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/src/components/MidPageForm.tsx\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/src/hooks/usePageMeta.ts\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/app/guides/page.tsx\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/app/presse/page.tsx\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/app/devenir-applicateur/page.tsx\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/app/guide-cool-roof/page.tsx\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/app/simulateur-economie-energie/page.tsx\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/app/qui-sommes-nous/page.tsx\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/app/diagnostic/page.tsx\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/app/references/page.tsx\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/app/[...slug]/page.tsx\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/app/contact/page.tsx\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/app/faq/page.tsx\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/app/nos-solutions-cool-roof/page.tsx","stderr":"","interrupted":false,"isImage":false,"noOutputExpected":false},"sourceToolAssistantUUID":"d7ac8413-475e-4215-b36c-9b4689d9a7df","userType":"external","entrypoint":"cli","cwd":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale","sessionId":"c02b163b-170b-4cd3-a555-3613df5965a3","version":"2.1.193","gitBranch":"tom/validation-finale","slug":"plusieurs-chose-faire-crispy-axolotl"}
{"parentUuid":"d6fb4ac1-45d7-4f8f-ba25-6046b8f67192","isSidechain":true,"agentId":"a9fd20a9d1d03f0e9","message":{"model":"claude-haiku-4-5-20251001","id":"msg_014ygHtiUYqrzdapq5HEZfSE","type":"message","role":"assistant","content":[{"type":"tool_use","id":"toolu_01UKGKm1YoXZhM4E1E9iCV15","name":"Bash","input":{"command":"find /opt/projects/.covalba-next-wp-worktrees/tom-validation-finale -type f -path \"*/docs/contexte/*\" | head -20"},"caller":{"type":"direct"}}],"stop_reason":null,"stop_sequence":null,"stop_details":null,"usage":{"input_tokens":10,"cache_creation_input_tokens":19686,"cache_read_input_tokens":5973,"cache_creation":{"ephemeral_5m_input_tokens":19686,"ephemeral_1h_input_tokens":0},"output_tokens":1,"service_tier":"standard","inference_geo":"not_available"},"diagnostics":null},"requestId":"req_011CcRpqktL5EgifGpn2AVHZ","attributionAgent":"Explore","type":"assistant","uuid":"57dab537-531c-40f2-b8d0-e9a8e5ec58b6","timestamp":"2026-06-26T11:53:45.124Z","userType":"external","entrypoint":"cli","cwd":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale","sessionId":"c02b163b-170b-4cd3-a555-3613df5965a3","version":"2.1.193","gitBranch":"tom/validation-finale","slug":"plusieurs-chose-faire-crispy-axolotl"}
{"parentUuid":"57dab537-531c-40f2-b8d0-e9a8e5ec58b6","isSidechain":true,"promptId":"606b4c79-d3cd-4b0a-a2e5-8b38011359cb","agentId":"a9fd20a9d1d03f0e9","type":"user","message":{"role":"user","content":[{"tool_use_id":"toolu_01UKGKm1YoXZhM4E1E9iCV15","type":"tool_result","content":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/docs/contexte/climat-projections-giec.md\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/docs/contexte/marche.md\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/docs/contexte/README.md\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/docs/contexte/propale-seo.md\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/docs/contexte/cibles.md\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/docs/contexte/strategie.md\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/docs/contexte/objectifs-refonte.md\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/docs/contexte/concurrents.md\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/docs/contexte/entreprise.md\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/docs/contexte/transcripts/2026-04-15-call-covalba-reponses.md\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/docs/contexte/transcripts/README.md\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/docs/contexte/transcripts/2026-04-15-propale-seo.md\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/docs/contexte/transcripts/2026-04-15-brief-initial.md\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/docs/contexte/transcripts/2026-04-15-call-maxime-brut.md","is_error":false}]},"uuid":"dbb1b8af-6145-4ff4-a84b-e33bf188d5c3","timestamp":"2026-06-26T11:53:45.257Z","toolUseResult":{"stdout":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/docs/contexte/climat-projections-giec.md\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/docs/contexte/marche.md\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/docs/contexte/README.md\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/docs/contexte/propale-seo.md\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/docs/contexte/cibles.md\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/docs/contexte/strategie.md\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/docs/contexte/objectifs-refonte.md\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/docs/contexte/concurrents.md\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/docs/contexte/entreprise.md\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/docs/contexte/transcripts/2026-04-15-call-covalba-reponses.md\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/docs/contexte/transcripts/README.md\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/docs/contexte/transcripts/2026-04-15-propale-seo.md\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/docs/contexte/transcripts/2026-04-15-brief-initial.md\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/docs/contexte/transcripts/2026-04-15-call-maxime-brut.md","stderr":"","interrupted":false,"isImage":false,"noOutputExpected":false},"sourceToolAssistantUUID":"57dab537-531c-40f2-b8d0-e9a8e5ec58b6","userType":"external","entrypoint":"cli","cwd":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale","sessionId":"c02b163b-170b-4cd3-a555-3613df5965a3","version":"2.1.193","gitBranch":"tom/validation-finale","slug":"plusieurs-chose-faire-crispy-axolotl"}
{"parentUuid":"dbb1b8af-6145-4ff4-a84b-e33bf188d5c3","isSidechain":true,"agentId":"a9fd20a9d1d03f0e9","message":{"model":"claude-haiku-4-5-20251001","id":"msg_014ygHtiUYqrzdapq5HEZfSE","type":"message","role":"assistant","content":[{"type":"tool_use","id":"toolu_01Tnuch7ESadwb761wuRdgqc","name":"Bash","input":{"command":"git log --oneline -20 | grep -E \"72f320f|sector|cool|solution\""},"caller":{"type":"direct"}}],"stop_reason":null,"stop_sequence":null,"stop_details":null,"usage":{"input_tokens":10,"cache_creation_input_tokens":19686,"cache_read_input_tokens":5973,"cache_creation":{"ephemeral_5m_input_tokens":19686,"ephemeral_1h_input_tokens":0},"output_tokens":1,"service_tier":"standard","inference_geo":"not_available"},"diagnostics":null},"requestId":"req_011CcRpqktL5EgifGpn2AVHZ","attributionAgent":"Explore","type":"assistant","uuid":"9e70c462-579b-4078-94a7-7a8dfe341222","timestamp":"2026-06-26T11:53:45.350Z","userType":"external","entrypoint":"cli","cwd":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale","sessionId":"c02b163b-170b-4cd3-a555-3613df5965a3","version":"2.1.193","gitBranch":"tom/validation-finale","slug":"plusieurs-chose-faire-crispy-axolotl"}
{"parentUuid":"9e70c462-579b-4078-94a7-7a8dfe341222","isSidechain":true,"promptId":"606b4c79-d3cd-4b0a-a2e5-8b38011359cb","agentId":"a9fd20a9d1d03f0e9","type":"user","message":{"role":"user","content":[{"tool_use_id":"toolu_01Tnuch7ESadwb761wuRdgqc","type":"tool_result","content":"72f320f feat(industrie): pages cool roof industrie, pharma & aéronautique (FR/EN/ES) (#11)","is_error":false}]},"uuid":"78d53924-4736-4d8c-ac4a-ebe619991b9b","timestamp":"2026-06-26T11:53:45.449Z","toolUseResult":{"stdout":"72f320f feat(industrie): pages cool roof industrie, pharma & aéronautique (FR/EN/ES) (#11)","stderr":"","interrupted":false,"isImage":false,"noOutputExpected":false},"sourceToolAssistantUUID":"9e70c462-579b-4078-94a7-7a8dfe341222","userType":"external","entrypoint":"cli","cwd":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale","sessionId":"c02b163b-170b-4cd3-a555-3613df5965a3","version":"2.1.193","gitBranch":"tom/validation-finale","slug":"plusieurs-chose-faire-crispy-axolotl"}
{"parentUuid":"78d53924-4736-4d8c-ac4a-ebe619991b9b","isSidechain":true,"agentId":"a9fd20a9d1d03f0e9","message":{"model":"claude-haiku-4-5-20251001","id":"msg_01NCBtdQhJqLRj5jxmnWR7Xi","type":"message","role":"assistant","content":[{"type":"thinking","thinking":"","signature":"EooGCm0IDxgCKkB17SXXUoPXb2ME/a1tmPSL0wcRik1pAbzgxbPnzp51AQsvTVuYgxRtNIz4A0z3Fxb3uKluRRj4U6eWdaWwX+++MhljbGF1ZGUtaGFpa3UtNC01LTIwMjUxMDAxOABCCHRoaW5raW5nEgwmX+tqodvGkkxiubUaDM/ySSjg2pXjtRJEtCIwYM4rIKQziVw8EKDPlq1HcW6J9BiMSYUGp4LNlIqvh0HbdbTKVoNVnOtkWFXYcFNjKsoE0nEEBY3sobUV7M5Jz5TRbkz/5d5CfJahbEfWZAfa/fZwzhUooJgjtm2frQwedQj1Pd1QmqM5TCbGEMH2LVyTBPDISaIM7mIin5waRVrBxuF2WGkwjkW2a03q7kiP5U+o7qRr1w0IKcFvt2UhwS0YQNwh3AfDxmUUeCVDHcfrZhMQG7/wc7VCiLlkxXi5owatDA1Oqeid4vAUjbALLK+ldepGpYNWlfD8PVDHpyMJ5gA5sY2HNmz6vvB6vS6A+zO0SGOz6dpZCnjXVjSZiAu/3iTepmqLbqUi62SQ0aFP8O7bYU3maQmTMxooQluvnavGnoVaQz6wyoaXTmT3oNcO3a/w4aGwW5GxDKLaH7dCQAvWv01JqOlwfQ77lLdXDeuzVf0MUghr/Fyc2Yy4hk30HlS5r0gqyU6h3dK1ctlCNSBvrIMhTwGxmBSWRapAp8UTymd+esu57V4Ec2Xr5+yWV6xBc4N7ear01xM5Kqw5nIOahhGz/9LYWlrZFK6MPrNv9xibafD96eStDH926CeMiHlce9ClxQeiSL50D2VXOaMxCEL9EFJdYi5QrgRd0oAo6hApeXWKciea9qajWUYSl7HsDx/v+MYGdHNybL7rwdx7xdWwtSZrQyKbjH54A/6yE+aM25GFVKQe2rERhmjcaWfYbSAfqH4nySvTfMsTyrWHvz43BqfuHr/qJZtlMQXUD+3Wj9Jzs+azWf88qW7WxKAWdE87uNZp2bLpSTmT5+vmKjxdH7hRG9YfHf6NEm8jqIfmTLSRp/YAYBgB"}],"stop_reason":null,"stop_sequence":null,"stop_details":null,"usage":{"input_tokens":10,"cache_creation_input_tokens":3989,"cache_read_input_tokens":25659,"cache_creation":{"ephemeral_5m_input_tokens":3989,"ephemeral_1h_input_tokens":0},"output_tokens":3,"service_tier":"standard","inference_geo":"not_available"},"diagnostics":null},"requestId":"req_011CcRprACn6tagJKbhe18Ad","attributionAgent":"Explore","type":"assistant","uuid":"44be8713-e329-4de6-8883-bd48ae9f4432","timestamp":"2026-06-26T11:53:48.652Z","userType":"external","entrypoint":"cli","cwd":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale","sessionId":"c02b163b-170b-4cd3-a555-3613df5965a3","version":"2.1.193","gitBranch":"tom/validation-finale","slug":"plusieurs-chose-faire-crispy-axolotl"}
{"parentUuid":"44be8713-e329-4de6-8883-bd48ae9f4432","isSidechain":true,"agentId":"a9fd20a9d1d03f0e9","message":{"model":"claude-haiku-4-5-20251001","id":"msg_01NCBtdQhJqLRj5jxmnWR7Xi","type":"message","role":"assistant","content":[{"type":"tool_use","id":"toolu_016R1rdGiZYff8NQReYad9qP","name":"WebFetch","input":{"url":"https://www.covalba.fr/nos-solutions-cool-roof","prompt":"List the complete section-by-section structure of this page: hero, headings, body copy, images, blocks/sections (e.g., intro, benefits, how cool roof works, gallery, CTA, FAQ). Capture the actual French copy/headings."},"caller":{"type":"direct"}}],"stop_reason":null,"stop_sequence":null,"stop_details":null,"usage":{"input_tokens":10,"cache_creation_input_tokens":3989,"cache_read_input_tokens":25659,"cache_creation":{"ephemeral_5m_input_tokens":3989,"ephemeral_1h_input_tokens":0},"output_tokens":3,"service_tier":"standard","inference_geo":"not_available"},"diagnostics":null},"requestId":"req_011CcRprACn6tagJKbhe18Ad","attributionAgent":"Explore","type":"assistant","uuid":"b330ad12-d34f-4b89-b874-a41ee0442171","timestamp":"2026-06-26T11:53:49.760Z","userType":"external","entrypoint":"cli","cwd":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale","sessionId":"c02b163b-170b-4cd3-a555-3613df5965a3","version":"2.1.193","gitBranch":"tom/validation-finale","slug":"plusieurs-chose-faire-crispy-axolotl"}
{"parentUuid":"b330ad12-d34f-4b89-b874-a41ee0442171","isSidechain":true,"agentId":"a9fd20a9d1d03f0e9","message":{"model":"claude-haiku-4-5-20251001","id":"msg_01NCBtdQhJqLRj5jxmnWR7Xi","type":"message","role":"assistant","content":[{"type":"tool_use","id":"toolu_01ACBBcVaLVP5t78WvmmWKJW","name":"Bash","input":{"command":"git log --all --oneline -1 72f320f"},"caller":{"type":"direct"}}],"stop_reason":null,"stop_sequence":null,"stop_details":null,"usage":{"input_tokens":10,"cache_creation_input_tokens":3989,"cache_read_input_tokens":25659,"cache_creation":{"ephemeral_5m_input_tokens":3989,"ephemeral_1h_input_tokens":0},"output_tokens":3,"service_tier":"standard","inference_geo":"not_available"},"diagnostics":null},"requestId":"req_011CcRprACn6tagJKbhe18Ad","attributionAgent":"Explore","type":"assistant","uuid":"7c903854-6a67-46a6-b534-4bb89846c77e","timestamp":"2026-06-26T11:53:50.186Z","userType":"external","entrypoint":"cli","cwd":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale","sessionId":"c02b163b-170b-4cd3-a555-3613df5965a3","version":"2.1.193","gitBranch":"tom/validation-finale","slug":"plusieurs-chose-faire-crispy-axolotl"}
{"parentUuid":"7c903854-6a67-46a6-b534-4bb89846c77e","isSidechain":true,"promptId":"606b4c79-d3cd-4b0a-a2e5-8b38011359cb","agentId":"a9fd20a9d1d03f0e9","type":"user","message":{"role":"user","content":[{"tool_use_id":"toolu_01ACBBcVaLVP5t78WvmmWKJW","type":"tool_result","content":"ba0c49f fix: harden forms with Turnstile (#15)","is_error":false}]},"uuid":"45112b87-d92b-410a-acf9-cd224bb249e1","timestamp":"2026-06-26T11:53:50.259Z","toolUseResult":{"stdout":"ba0c49f fix: harden forms with Turnstile (#15)","stderr":"","interrupted":false,"isImage":false,"noOutputExpected":false},"sourceToolAssistantUUID":"7c903854-6a67-46a6-b534-4bb89846c77e","userType":"external","entrypoint":"cli","cwd":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale","sessionId":"c02b163b-170b-4cd3-a555-3613df5965a3","version":"2.1.193","gitBranch":"tom/validation-finale","slug":"plusieurs-chose-faire-crispy-axolotl"}
{"parentUuid":"45112b87-d92b-410a-acf9-cd224bb249e1","isSidechain":true,"agentId":"a9fd20a9d1d03f0e9","message":{"model":"claude-haiku-4-5-20251001","id":"msg_01NCBtdQhJqLRj5jxmnWR7Xi","type":"message","role":"assistant","content":[{"type":"tool_use","id":"toolu_01SXUeSzdsonuZL5hak3X4j2","name":"Read","input":{"file_path":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/app/nos-solutions-cool-roof/page.tsx"},"caller":{"type":"direct"}}],"stop_reason":null,"stop_sequence":null,"stop_details":null,"usage":{"input_tokens":10,"cache_creation_input_tokens":3989,"cache_read_input_tokens":25659,"cache_creation":{"ephemeral_5m_input_tokens":3989,"ephemeral_1h_input_tokens":0},"output_tokens":3,"service_tier":"standard","inference_geo":"not_available"},"diagnostics":null},"requestId":"req_011CcRprACn6tagJKbhe18Ad","attributionAgent":"Explore","type":"assistant","uuid":"73d752e9-bff4-4d86-91ae-9b2bf8929dbb","timestamp":"2026-06-26T11:53:50.841Z","userType":"external","entrypoint":"cli","cwd":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale","sessionId":"c02b163b-170b-4cd3-a555-3613df5965a3","version":"2.1.193","gitBranch":"tom/validation-finale","slug":"plusieurs-chose-faire-crispy-axolotl"}
{"parentUuid":"73d752e9-bff4-4d86-91ae-9b2bf8929dbb","isSidechain":true,"promptId":"606b4c79-d3cd-4b0a-a2e5-8b38011359cb","agentId":"a9fd20a9d1d03f0e9","type":"user","message":{"role":"user","content":[{"tool_use_id":"toolu_01SXUeSzdsonuZL5hak3X4j2","type":"tool_result","content":"1\timport type { Metadata } from \"next\";\n2\t\n3\timport Navbar from \"@/components/Navbar\";\n4\timport Footer from \"@/components/Footer\";\n5\timport StickyMobileCTA from \"@/components/StickyMobileCTA\";\n6\timport SolutionsGrid from \"@/components/SolutionsGrid\";\n7\timport JsonLd from \"@/components/seo/JsonLd\";\n8\timport { buildMetadata, SITE_URL } from \"@/lib/seo\";\n9\timport { breadcrumbJsonLd } from \"@/lib/wp/seoToMetadata\";\n10\t\n11\tconst PAGE_URL = `${SITE_URL}/nos-solutions-cool-roof`;\n12\t\n13\texport const metadata: Metadata = buildMetadata({\n14\t  title: \"Nos solutions cool roof - Covalba\",\n15\t  description:\n16\t    \"Découvrez les solutions cool roof Covalba pour toitures professionnelles : peinture réflective, étanchéité, anticorrosion et laque solaire.\",\n17\t  canonical: PAGE_URL,\n18\t});\n19\t\n20\texport default function Page() {\n21\t  return (\n22\t    <div className=\"min-h-screen bg-background\">\n23\t      <JsonLd\n24\t        id=\"solutions-cool-roof-breadcrumb-jsonld\"\n25\t        data={breadcrumbJsonLd([\n26\t          { name: \"Accueil\", url: `${SITE_URL}/` },\n27\t          { name: \"Nos solutions cool roof\", url: PAGE_URL },\n28\t        ])}\n29\t      />\n30\t      <Navbar />\n31\t      <main>\n32\t        <section className=\"relative overflow-hidden bg-navy pb-16 pt-28 text-white lg:pb-20 lg:pt-36\">\n33\t          <div className=\"absolute inset-0 opacity-40\">\n34\t            <img\n35\t              src=\"/images/qui-sommes-nous/hero-pulverisation.jpg\"\n36\t              alt=\"\"\n37\t              className=\"h-full w-full object-cover\"\n38\t              aria-hidden=\"true\"\n39\t            />\n40\t            <div className=\"absolute inset-0 bg-gradient-to-r from-navy via-navy/86 to-navy/46\" />\n41\t          </div>\n42\t          <div className=\"container relative z-10 mx-auto px-4 lg:px-8\">\n43\t            <p className=\"mb-5 font-body text-[10px] font-bold uppercase tracking-[0.24em] text-white/58\">\n44\t              Solutions cool roof\n45\t            </p>\n46\t            <h1 className=\"max-w-4xl font-satoshi text-5xl font-black leading-[0.96] tracking-tight md:text-6xl lg:text-7xl\">\n47\t              Un système adapté à chaque toiture professionnelle.\n48\t            </h1>\n49\t            <p className=\"mt-6 max-w-2xl font-body text-lg leading-relaxed text-white/72\">\n50\t              Covalba fabrique des revêtements réflectifs pour réduire la chaleur, protéger les supports et prolonger la durée de vie des toitures.\n51\t            </p>\n52\t          </div>\n53\t        </section>\n54\t        <SolutionsGrid />\n55\t      </main>\n56\t      <Footer />\n57\t      <StickyMobileCTA />\n58\t    </div>\n59\t  );\n60\t}\n61\t"}]},"uuid":"277d1d91-5a57-4864-97d4-eba79600c665","timestamp":"2026-06-26T11:53:50.866Z","toolUseResult":{"type":"text","file":{"filePath":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/app/nos-solutions-cool-roof/page.tsx","content":"import type { Metadata } from \"next\";\n\nimport Navbar from \"@/components/Navbar\";\nimport Footer from \"@/components/Footer\";\nimport StickyMobileCTA from \"@/components/StickyMobileCTA\";\nimport SolutionsGrid from \"@/components/SolutionsGrid\";\nimport JsonLd from \"@/components/seo/JsonLd\";\nimport { buildMetadata, SITE_URL } from \"@/lib/seo\";\nimport { breadcrumbJsonLd } from \"@/lib/wp/seoToMetadata\";\n\nconst PAGE_URL = `${SITE_URL}/nos-solutions-cool-roof`;\n\nexport const metadata: Metadata = buildMetadata({\n  title: \"Nos solutions cool roof - Covalba\",\n  description:\n    \"Découvrez les solutions cool roof Covalba pour toitures professionnelles : peinture réflective, étanchéité, anticorrosion et laque solaire.\",\n  canonical: PAGE_URL,\n});\n\nexport default function Page() {\n  return (\n    <div className=\"min-h-screen bg-background\">\n      <JsonLd\n        id=\"solutions-cool-roof-breadcrumb-jsonld\"\n        data={breadcrumbJsonLd([\n          { name: \"Accueil\", url: `${SITE_URL}/` },\n          { name: \"Nos solutions cool roof\", url: PAGE_URL },\n        ])}\n      />\n      <Navbar />\n      <main>\n        <section className=\"relative overflow-hidden bg-navy pb-16 pt-28 text-white lg:pb-20 lg:pt-36\">\n          <div className=\"absolute inset-0 opacity-40\">\n            <img\n              src=\"/images/qui-sommes-nous/hero-pulverisation.jpg\"\n              alt=\"\"\n              className=\"h-full w-full object-cover\"\n              aria-hidden=\"true\"\n            />\n            <div className=\"absolute inset-0 bg-gradient-to-r from-navy via-navy/86 to-navy/46\" />\n          </div>\n          <div className=\"container relative z-10 mx-auto px-4 lg:px-8\">\n            <p className=\"mb-5 font-body text-[10px] font-bold uppercase tracking-[0.24em] text-white/58\">\n              Solutions cool roof\n            </p>\n            <h1 className=\"max-w-4xl font-satoshi text-5xl font-black leading-[0.96] tracking-tight md:text-6xl lg:text-7xl\">\n              Un système adapté à chaque toiture professionnelle.\n            </h1>\n            <p className=\"mt-6 max-w-2xl font-body text-lg leading-relaxed text-white/72\">\n              Covalba fabrique des revêtements réflectifs pour réduire la chaleur, protéger les supports et prolonger la durée de vie des toitures.\n            </p>\n          </div>\n        </section>\n        <SolutionsGrid />\n      </main>\n      <Footer />\n      <StickyMobileCTA />\n    </div>\n  );\n}\n","numLines":61,"startLine":1,"totalLines":61}},"sourceToolAssistantUUID":"73d752e9-bff4-4d86-91ae-9b2bf8929dbb","userType":"external","entrypoint":"cli","cwd":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale","sessionId":"c02b163b-170b-4cd3-a555-3613df5965a3","version":"2.1.193","gitBranch":"tom/validation-finale","slug":"plusieurs-chose-faire-crispy-axolotl"}
{"parentUuid":"277d1d91-5a57-4864-97d4-eba79600c665","isSidechain":true,"agentId":"a9fd20a9d1d03f0e9","message":{"model":"claude-haiku-4-5-20251001","id":"msg_01NCBtdQhJqLRj5jxmnWR7Xi","type":"message","role":"assistant","content":[{"type":"tool_use","id":"toolu_016NPtt9wgcy5gpUpSw228hC","name":"Bash","input":{"command":"find /opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/src -type f -name \"*Sector*\" -o -name \"*Template*\" | grep -v node_modules"},"caller":{"type":"direct"}}],"stop_reason":"tool_use","stop_sequence":null,"stop_details":null,"usage":{"input_tokens":10,"cache_creation_input_tokens":3989,"cache_read_input_tokens":25659,"output_tokens":511,"server_tool_use":{"web_search_requests":0,"web_fetch_requests":0},"service_tier":"standard","cache_creation":{"ephemeral_1h_input_tokens":0,"ephemeral_5m_input_tokens":3989},"inference_geo":"not_available","iterations":[{"input_tokens":10,"output_tokens":511,"cache_read_input_tokens":25659,"cache_creation_input_tokens":3989,"cache_creation":{"ephemeral_5m_input_tokens":3989,"ephemeral_1h_input_tokens":0},"type":"message"}],"speed":"standard"},"diagnostics":null},"requestId":"req_011CcRprACn6tagJKbhe18Ad","attributionAgent":"Explore","type":"assistant","uuid":"5a9952f7-e91b-42a0-a213-1ed9e42e73d7","timestamp":"2026-06-26T11:53:51.134Z","userType":"external","entrypoint":"cli","cwd":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale","sessionId":"c02b163b-170b-4cd3-a555-3613df5965a3","version":"2.1.193","gitBranch":"tom/validation-finale","slug":"plusieurs-chose-faire-crispy-axolotl"}
{"parentUuid":"5a9952f7-e91b-42a0-a213-1ed9e42e73d7","isSidechain":true,"promptId":"606b4c79-d3cd-4b0a-a2e5-8b38011359cb","agentId":"a9fd20a9d1d03f0e9","type":"user","message":{"role":"user","content":[{"tool_use_id":"toolu_016NPtt9wgcy5gpUpSw228hC","type":"tool_result","content":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/src/components/SectorReferenceHighlights.tsx\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/src/components/SectorsGrid.tsx\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/src/lib/wp/toSectorConfig.ts\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/src/components/industries/SectorPageTemplate.tsx\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/src/components/roof/RoofPageTemplate.tsx\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/src/components/es/home/SectorsGridES.tsx\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/src/components/es/industries/SectorPageTemplateES.tsx\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/src/components/es/roof/RoofPageTemplateES.tsx\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/src/components/en/home/SectorsGridEN.tsx\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/src/components/en/industries/SectorPageTemplateEN.tsx\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/src/components/en/roof/RoofPageTemplateEN.tsx","is_error":false}]},"uuid":"312e15ec-aa63-4648-9287-5f7379e6d199","timestamp":"2026-06-26T11:53:51.207Z","toolUseResult":{"stdout":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/src/components/SectorReferenceHighlights.tsx\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/src/components/SectorsGrid.tsx\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/src/lib/wp/toSectorConfig.ts\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/src/components/industries/SectorPageTemplate.tsx\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/src/components/roof/RoofPageTemplate.tsx\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/src/components/es/home/SectorsGridES.tsx\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/src/components/es/industries/SectorPageTemplateES.tsx\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/src/components/es/roof/RoofPageTemplateES.tsx\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/src/components/en/home/SectorsGridEN.tsx\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/src/components/en/industries/SectorPageTemplateEN.tsx\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/src/components/en/roof/RoofPageTemplateEN.tsx","stderr":"","interrupted":false,"isImage":false,"noOutputExpected":false},"sourceToolAssistantUUID":"5a9952f7-e91b-42a0-a213-1ed9e42e73d7","userType":"external","entrypoint":"cli","cwd":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale","sessionId":"c02b163b-170b-4cd3-a555-3613df5965a3","version":"2.1.193","gitBranch":"tom/validation-finale","slug":"plusieurs-chose-faire-crispy-axolotl"}
{"parentUuid":"b330ad12-d34f-4b89-b874-a41ee0442171","isSidechain":true,"promptId":"606b4c79-d3cd-4b0a-a2e5-8b38011359cb","agentId":"a9fd20a9d1d03f0e9","type":"user","message":{"role":"user","content":[{"tool_use_id":"toolu_016R1rdGiZYff8NQReYad9qP","type":"tool_result","content":"# Covalba Website Structure Analysis\n\n## Page Sections (Top to Bottom)\n\n**1. Navigation Header**\n- Logo and main menu (Solutions, Vous êtes, Covalba)\n- Language selector (FR/EN/ES)\n- CTA buttons: \"Devenir applicateur,\" \"Demande de devis\"\n\n**2. Hero Section**\n- Headline: \"Décarbonnez votre activité grâce au cool roof\"\n- Subheading: \"La technologie cool roof au service des entreprises et de la planète\"\n- Illustrative diagrams (desktop and mobile versions)\n\n**3. Benefits Grid (6 cards)**\nCovering energy savings, storage optimization, workplace conditions, building preservation, customer experience, and environmental commitment\n\n**4. Services Section: \"Les services Covalba\"**\nThree subsections:\n- **Votre chantier** (three-step process from contact through project execution)\n- **Maintenance de votre toiture réfléchissante** (annual cleaning protocols)\n- **Monitoring de température** (pre/post measurement and reporting)\n\n**5. Product Showcase**\nFour product cards with images: CovaTherm 8/20, CovaSeal 20, CovaMetal 20, Laque solaire\n\n**6. Client Testimonials**\nThree quotes from satisfied customers (H. Lefort, Arnaud Gendre, Fabrice Hinschberger) with temperature/cost improvements\n\n**7. Case Study**\nAlbright project highlighting \"13°C en moins dans l'entrepôt\"\n\n**8. Sectoral Solutions (5 cards)**\nIndustry, Distribution, Logistics, Public Services, Tertiary\n\n**9. Downloadable Resource**\nWhitepaper: \"Le cool Roof, la solution pour diviser par [...]\"\n\n**10. Featured Product Spotlight**\nCovaTherm promotional section with CTA\n\n**11. Footer**\nCompany description, links organized by category (gammes, secteur, ressources), social media, copyright"}]},"uuid":"be9a8091-5144-4f77-9d71-32bd9aad074e","timestamp":"2026-06-26T11:53:56.731Z","toolUseResult":{"bytes":209247,"code":200,"codeText":"OK","result":"# Covalba Website Structure Analysis\n\n## Page Sections (Top to Bottom)\n\n**1. Navigation Header**\n- Logo and main menu (Solutions, Vous êtes, Covalba)\n- Language selector (FR/EN/ES)\n- CTA buttons: \"Devenir applicateur,\" \"Demande de devis\"\n\n**2. Hero Section**\n- Headline: \"Décarbonnez votre activité grâce au cool roof\"\n- Subheading: \"La technologie cool roof au service des entreprises et de la planète\"\n- Illustrative diagrams (desktop and mobile versions)\n\n**3. Benefits Grid (6 cards)**\nCovering energy savings, storage optimization, workplace conditions, building preservation, customer experience, and environmental commitment\n\n**4. Services Section: \"Les services Covalba\"**\nThree subsections:\n- **Votre chantier** (three-step process from contact through project execution)\n- **Maintenance de votre toiture réfléchissante** (annual cleaning protocols)\n- **Monitoring de température** (pre/post measurement and reporting)\n\n**5. Product Showcase**\nFour product cards with images: CovaTherm 8/20, CovaSeal 20, CovaMetal 20, Laque solaire\n\n**6. Client Testimonials**\nThree quotes from satisfied customers (H. Lefort, Arnaud Gendre, Fabrice Hinschberger) with temperature/cost improvements\n\n**7. Case Study**\nAlbright project highlighting \"13°C en moins dans l'entrepôt\"\n\n**8. Sectoral Solutions (5 cards)**\nIndustry, Distribution, Logistics, Public Services, Tertiary\n\n**9. Downloadable Resource**\nWhitepaper: \"Le cool Roof, la solution pour diviser par [...]\"\n\n**10. Featured Product Spotlight**\nCovaTherm promotional section with CTA\n\n**11. Footer**\nCompany description, links organized by category (gammes, secteur, ressources), social media, copyright","durationMs":6966,"url":"https://www.covalba.fr/nos-solutions-cool-roof"},"sourceToolAssistantUUID":"b330ad12-d34f-4b89-b874-a41ee0442171","userType":"external","entrypoint":"cli","cwd":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale","sessionId":"c02b163b-170b-4cd3-a555-3613df5965a3","version":"2.1.193","gitBranch":"tom/validation-finale","slug":"plusieurs-chose-faire-crispy-axolotl"}
{"parentUuid":"be9a8091-5144-4f77-9d71-32bd9aad074e","isSidechain":true,"agentId":"a9fd20a9d1d03f0e9","message":{"model":"claude-haiku-4-5-20251001","id":"msg_01P17KpgVc6gXuBji7BGvRzB","type":"message","role":"assistant","content":[{"type":"thinking","thinking":"","signature":"EuwGCm0IDxgCKkCraHgUfICAirTRaiDjVz4ztmi/maXyRVxKY2k2ZhEdOCFr0gDEn6s58bccp1hHrC4rYWfY8sC9Y0rF+C5NH1HRMhljbGF1ZGUtaGFpa3UtNC01LTIwMjUxMDAxOABCCHRoaW5raW5nEgxItS7K9ZTUlB1idsYaDD5RRRaQ5JuRjXafEyIwQRZx6LrkD9IvBzq+jk4NV2n4z2DiNZhTfeWIXDIeRuGiElyVpKGGOo+VxR29IgELKqwF3M+XKNQ32VyLhpM+cKcsBP9iX88DrJVJSFkn+0G5r4Z19a2UIDYVxCC7P0pFpDSdtMHFDE7NhZ63ojXP9cGEG1NDVZmrUupMxLiOBy06HQSYQPwhGElNbT+vVJW8a2udJ+EA6YEWsxub3Qu1SwR0tnM7SxJ98UZnY2W/ak6sZ37GyaRtIIS3sqiyjq27reyZ8uEgyZu30Gxa8V7olmTFUNEVsn1su7/qV9E9fuNjV+d3o5o1Up7epcwW6BqtVglrKtdMKq1h2slDuvHJe/dPIU14Hbgy7GqyBrOveab6PeyRJT5hLRmxZot0HZhsGmAkiCL3kSGVxfoEnp3Lnj4vIg7YyTFqYjrwZV8DcAlIMgcvANM5J2mseyBDLc1GnSQ6audqrE4v353CoOnNCgbkc5EJVRLV66afuB86VBJgKSVOjMWnwqtJKcdMAZcF8o+hWVQUgtb7C8B93A5ce0xjpoKHrOxCyt6FmkEzqtKtN9ooPP/a5ot82E3160y64kpMdqFN/zeQDNu6D/jdJTsvNEqklRfv63EJaDR1yN9eIyVnLhwtP4r+5cM915L47Uif9mf4oWXCyIDZMh0gJuJFjPBMJehOV5nwWtDq8cDQkQUWxhWosQBhlD7OAYlpfZp0CBhmnPw3IfUx4UMaOdWCdXwSw7Y5ksFyUNXMvpopYSce+skU0Yrj8Vay/BtKCDQ4UZuYrjuZNThI46jXw+d1aqEZxDb4Lapi0Ay+u1nHFw7zYsm9DfAiH/FgWj36Ej/lA9dMM9UYzzR5th9JXthXfzJtY93CwLjizNB3DImzgjkNMQJkEoQnm0j7ODIyO/2znJhZWsa4M0b8DLx6BS2X4fw4UzhpQ/pw7RYJ3EjYgNiUTjYihkp7sOuy+rDAhJC8pETFN/p0QMPKf4tNGAE="}],"stop_reason":null,"stop_sequence":null,"stop_details":null,"usage":{"input_tokens":1420,"cache_creation_input_tokens":1022,"cache_read_input_tokens":29648,"cache_creation":{"ephemeral_5m_input_tokens":1022,"ephemeral_1h_input_tokens":0},"output_tokens":1,"service_tier":"standard","inference_geo":"not_available"},"diagnostics":{"cache_miss_reason":{"type":"unavailable"}}},"requestId":"req_011CcRprzY8zCoPRf8AArPJY","attributionAgent":"Explore","type":"assistant","uuid":"b0c09f13-2ac8-48b1-aa39-cca5273552a4","timestamp":"2026-06-26T11:54:00.662Z","userType":"external","entrypoint":"cli","cwd":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale","sessionId":"c02b163b-170b-4cd3-a555-3613df5965a3","version":"2.1.193","gitBranch":"tom/validation-finale","slug":"plusieurs-chose-faire-crispy-axolotl"}
{"parentUuid":"b0c09f13-2ac8-48b1-aa39-cca5273552a4","isSidechain":true,"agentId":"a9fd20a9d1d03f0e9","message":{"model":"claude-haiku-4-5-20251001","id":"msg_01P17KpgVc6gXuBji7BGvRzB","type":"message","role":"assistant","content":[{"type":"tool_use","id":"toolu_01HaHSbUamF3EEXREQoKtq1c","name":"Read","input":{"file_path":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/src/components/industries/SectorPageTemplate.tsx"},"caller":{"type":"direct"}}],"stop_reason":null,"stop_sequence":null,"stop_details":null,"usage":{"input_tokens":1420,"cache_creation_input_tokens":1022,"cache_read_input_tokens":29648,"cache_creation":{"ephemeral_5m_input_tokens":1022,"ephemeral_1h_input_tokens":0},"output_tokens":1,"service_tier":"standard","inference_geo":"not_available"},"diagnostics":{"cache_miss_reason":{"type":"unavailable"}}},"requestId":"req_011CcRprzY8zCoPRf8AArPJY","attributionAgent":"Explore","type":"assistant","uuid":"f5cbadb7-c68b-4f81-a8b9-954662e93249","timestamp":"2026-06-26T11:54:00.867Z","userType":"external","entrypoint":"cli","cwd":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale","sessionId":"c02b163b-170b-4cd3-a555-3613df5965a3","version":"2.1.193","gitBranch":"tom/validation-finale","slug":"plusieurs-chose-faire-crispy-axolotl"}
{"parentUuid":"f5cbadb7-c68b-4f81-a8b9-954662e93249","isSidechain":true,"promptId":"606b4c79-d3cd-4b0a-a2e5-8b38011359cb","agentId":"a9fd20a9d1d03f0e9","type":"user","message":{"role":"user","content":[{"tool_use_id":"toolu_01HaHSbUamF3EEXREQoKtq1c","type":"tool_result","content":"1\t\"use client\";\n2\t\n3\timport { useState } from 'react';\n4\timport {\n5\t  ArrowRight,\n6\t  BadgeCheck,\n7\t  Building2,\n8\t  CalendarCheck,\n9\t  CalendarClock,\n10\t  Check,\n11\t  CheckCircle2,\n12\t  ClipboardCheck,\n13\t  HelpCircle,\n14\t  Play,\n15\t  Shield,\n16\t  Thermometer,\n17\t  TrendingDown,\n18\t  UsersRound,\n19\t  X,\n20\t  type LucideIcon,\n21\t} from 'lucide-react';\n22\timport { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from '@/components/ui/accordion';\n23\timport { Dialog, DialogContent } from '@/components/ui/dialog';\n24\timport ScrollReveal from '@/components/ScrollReveal';\n25\timport SectorReferenceHighlights from '@/components/SectorReferenceHighlights';\n26\timport WpImage from '@/components/ui/WpImage';\n27\timport type { ReferenceSector, ReferenceSectorSlug } from '@/data/references';\n28\timport classicRoofImage from '@/assets/industrie/logistique-solution-classic.webp';\n29\timport coolRoofImage from '@/assets/industrie/logistique-solution-coolroof.webp';\n30\t\n31\t// config.*.image sont des URL string (public /images via toSectorConfig, ou\n32\t// .src d'un import webp local en fallback). On les enveloppe en objet WpImage\n33\t// (dimensions inconnues -> mode fill, déjà utilisé pour ces fonds object-cover).\n34\tconst toFillImage = (src: string, alt = '') => ({\n35\t  sourceUrl: src,\n36\t  altText: alt,\n37\t  width: null,\n38\t  height: null,\n39\t});\n40\t\n41\ttype Logo = {\n42\t  name: string;\n43\t  url?: string;\n44\t};\n45\t\n46\ttype HeroStat = {\n47\t  icon: LucideIcon;\n48\t  value: string;\n49\t  label: string;\n50\t};\n51\t\n52\ttype Problem = {\n53\t  icon: LucideIcon;\n54\t  title: string;\n55\t  desc: string;\n56\t  image: string;\n57\t  alt: string;\n58\t};\n59\t\n60\ttype Benefit = {\n61\t  icon: LucideIcon;\n62\t  title: string;\n63\t  desc: string;\n64\t};\n65\t\n66\ttype Application = {\n67\t  icon: LucideIcon;\n68\t  label: string;\n69\t  title: string;\n70\t  desc: string;\n71\t  image: string;\n72\t};\n73\t\n74\ttype Figure = {\n75\t  icon: LucideIcon;\n76\t  value: string;\n77\t  label: string;\n78\t};\n79\t\n80\ttype CaseProof = {\n81\t  name: string;\n82\t  desc: string;\n83\t};\n84\t\n85\tconst referenceFilterBySectorSlug: Partial<Record<string, ReferenceSector>> = {\n86\t  industrie: 'Industrie',\n87\t  distribution: 'Distribution',\n88\t  logistique: 'Logistique',\n89\t  tertiaire: 'Tertiaire',\n90\t  collectivites: 'Collectivites',\n91\t  agricole: 'Agricole',\n92\t  erp: 'ERP',\n93\t};\n94\t\n95\ttype Faq = {\n96\t  q: string;\n97\t  a: string;\n98\t};\n99\t\n100\ttype SeoSection = {\n101\t  title: string;\n102\t  body: string;\n103\t};\n104\t\n105\ttype SpecialSection =\n106\t  | {\n107\t      kind: 'decret';\n108\t      eyebrow: string;\n109\t      title: string;\n110\t      intro: string;\n111\t      milestones: Array<{ value: string; label: string }>;\n112\t      points: string[];\n113\t      note: string;\n114\t      cta: string;\n115\t    }\n116\t  | {\n117\t      kind: 'funding';\n118\t      eyebrow: string;\n119\t      title: string;\n120\t      intro: string;\n121\t      points: Array<{ value: string; label: string }>;\n122\t      note: string;\n123\t      cta: string;\n124\t    };\n125\t\n126\texport type SectorPageConfig = {\n127\t  slug: string;\n128\t  title: string;\n129\t  description: string;\n130\t  canonicalPath: string;\n131\t  serviceName: string;\n132\t  serviceDescription: string;\n133\t  audience: string;\n134\t  reassurance?: string[];\n135\t  hero: {\n136\t    eyebrow: string;\n137\t    h1: string;\n138\t    sub: string;\n139\t    image: string;\n140\t    imageAlt: string;\n141\t    stats: HeroStat[];\n142\t    formTitle: string;\n143\t    formSubtitle: string;\n144\t    formFields: {\n145\t      typeLabel: string;\n146\t      typeOptions: string[];\n147\t      climateLabel: string;\n148\t      climateOptions: string[];\n149\t      yearLabel: string;\n150\t      microcopy: string;\n151\t      cta: string;\n152\t    };\n153\t  };\n154\t  logos: {\n155\t    title: string;\n156\t    items: Logo[];\n157\t  };\n158\t  problem: {\n159\t    eyebrow: string;\n160\t    title: string;\n161\t    mutedTitle: string;\n162\t    intro: string;\n163\t    transition: string;\n164\t    cards: Problem[];\n165\t  };\n166\t  solution: {\n167\t    eyebrow: string;\n168\t    title: string;\n169\t    mutedTitle: string;\n170\t    intro: string;\n171\t    points: string[];\n172\t    transition: string;\n173\t    beforeImage?: string;\n174\t    afterImage?: string;\n175\t  };\n176\t  durability: {\n177\t    title: string;\n178\t    mutedTitle?: string;\n179\t    intro: string;\n180\t    note: string;\n181\t    covalbaLabel: string;\n182\t  };\n183\t  special: SpecialSection;\n184\t  benefits: {\n185\t    eyebrow: string;\n186\t    title: string;\n187\t    desc: string;\n188\t    metric: string;\n189\t    metricLabel: string;\n190\t    image: string;\n191\t    imageAlt: string;\n192\t    cards: Benefit[];\n193\t    transition: string;\n194\t  };\n195\t  applications: {\n196\t    eyebrow: string;\n197\t    title: string;\n198\t    intro: string;\n199\t    cards: Application[];\n200\t    transition: string;\n201\t  };\n202\t  method: {\n203\t    eyebrow: string;\n204\t    title: string;\n205\t    mutedTitle: string;\n206\t    intro: string;\n207\t    steps: Array<{ title: string; text: string }>;\n208\t    duration: string;\n209\t  };\n210\t  proof: {\n211\t    eyebrow: string;\n212\t    title: string;\n213\t    mutedTitle: string;\n214\t    intro: string;\n215\t    figures: Figure[];\n216\t    cases?: CaseProof[];\n217\t    logos: Logo[];\n218\t    transition: string;\n219\t  };\n220\t  faq: {\n221\t    intro: string;\n222\t    items: Faq[];\n223\t  };\n224\t  finalCta: {\n225\t    eyebrow: string;\n226\t    title: string;\n227\t    desc: string;\n228\t    reassurances: string[];\n229\t  };\n230\t  seo: {\n231\t    eyebrow: string;\n232\t    title: string;\n233\t    intro: string;\n234\t    sections: SeoSection[];\n235\t    sources: string[];\n236\t  };\n237\t};\n238\t\n239\tconst ReassuranceBand = ({ items }: { items?: string[] }) => {\n240\t  if (!items?.length) return null;\n241\t\n242\t  return (\n243\t    <section className=\"border-y border-foreground/[0.06] bg-white py-4\">\n244\t      <div className=\"container mx-auto px-4 lg:px-8\">\n245\t        <ul className=\"flex flex-col items-start justify-center gap-3 font-body text-sm font-semibold text-foreground/62 sm:flex-row sm:flex-wrap sm:items-center sm:gap-x-6 sm:gap-y-2\">\n246\t          {items.map((item) => (\n247\t            <li key={item} className=\"flex items-center gap-2.5\">\n248\t              <CheckCircle2 className=\"h-4 w-4 shrink-0 text-teal-vivid\" strokeWidth={1.8} />\n249\t              <span>{item}</span>\n250\t            </li>\n251\t          ))}\n252\t        </ul>\n253\t      </div>\n254\t    </section>\n255\t  );\n256\t};\n257\t\n258\tconst inputClass =\n259\t  'w-full rounded-xl border border-white/[0.12] bg-white/[0.07] px-4 py-3 font-body text-sm text-white placeholder:text-white/40 transition-all duration-300 focus:border-white/25 focus:outline-none focus:ring-2 focus:ring-primary/50';\n260\t\n261\tconst selectClass =\n262\t  'w-full appearance-none rounded-xl border border-white/[0.12] bg-white/[0.07] px-4 py-3 font-body text-sm text-white transition-all duration-300 focus:border-white/25 focus:outline-none focus:ring-2 focus:ring-primary/50';\n263\t\n264\tconst lightFieldClass =\n265\t  'w-full rounded-xl border border-foreground/10 bg-white px-4 py-3 font-body text-sm text-foreground outline-none transition-all focus:border-teal-vivid/40 focus:ring-2 focus:ring-teal-vivid/15';\n266\t\n267\tconst SectorHero = ({ config }: { config: SectorPageConfig }) => {\n268\t  const [form, setForm] = useState({ type: '', climate: '', surface: '', year: '', email: '' });\n269\t  const [submitted, setSubmitted] = useState(false);\n270\t  const surfaceNum = parseFloat(form.surface) || 0;\n271\t  const estimMin = surfaceNum * 18;\n272\t  const estimMax = surfaceNum * 25;\n273\t  const fmt = (n: number) => new Intl.NumberFormat('fr-FR').format(n);\n274\t\n275\t  return (\n276\t    <section\n277\t      aria-labelledby={`${config.slug}-hero-title`}\n278\t      className=\"relative isolate flex min-h-[100svh] flex-col overflow-hidden bg-navy text-cream\"\n279\t    >\n280\t      <WpImage\n281\t        image={toFillImage(config.hero.image, config.hero.imageAlt)}\n282\t        fill\n283\t        priority\n284\t        sizes=\"100vw\"\n285\t        className=\"absolute inset-0 -z-10 size-full scale-[1.02] object-cover\"\n286\t      />\n287\t      <div\n288\t        aria-hidden=\"true\"\n289\t        className=\"absolute inset-0 -z-10 hidden bg-gradient-to-r from-navy/[0.92] via-navy/55 to-navy/25 lg:block\"\n290\t      />\n291\t      <div\n292\t        aria-hidden=\"true\"\n293\t        className=\"absolute inset-0 -z-10 bg-gradient-to-b from-navy/80 via-navy/22 to-navy/95 lg:hidden\"\n294\t      />\n295\t      <div\n296\t        aria-hidden=\"true\"\n297\t        className=\"absolute inset-x-0 bottom-0 -z-10 h-[28%] bg-gradient-to-t from-navy via-navy/85 to-transparent\"\n298\t      />\n299\t\n300\t      <div className=\"container relative z-10 mx-auto flex flex-1 items-center px-6 pb-10 pt-24 lg:px-12 lg:pb-16 lg:pt-28\">\n301\t        <div className=\"grid w-full grid-cols-1 items-center gap-10 lg:grid-cols-[55fr_45fr] lg:gap-12\">\n302\t          <div className=\"max-w-2xl space-y-6 lg:space-y-8\">\n303\t            {config.hero.eyebrow && (\n304\t              <div className=\"flex items-center gap-3\">\n305\t                <span className=\"h-px w-9 bg-teal-vivid\" aria-hidden=\"true\" />\n306\t                <span className=\"font-body text-[11px] font-semibold uppercase tracking-[0.22em] text-teal-vivid\">\n307\t                  {config.hero.eyebrow}\n308\t                </span>\n309\t              </div>\n310\t            )}\n311\t\n312\t            <h1\n313\t              id={`${config.slug}-hero-title`}\n314\t              className=\"font-satoshi font-bold leading-[1.02] text-white\"\n315\t              style={{ fontSize: 'clamp(2.25rem, 4.6vw, 4rem)', letterSpacing: '-0.03em' }}\n316\t            >\n317\t              {config.hero.h1}\n318\t            </h1>\n319\t\n320\t            <p\n321\t              className=\"max-w-xl font-satoshi font-medium leading-[1.3] text-cream/65\"\n322\t              style={{ fontSize: 'clamp(1rem, 1.5vw, 1.375rem)', letterSpacing: '-0.005em' }}\n323\t            >\n324\t              {config.hero.sub}\n325\t            </p>\n326\t\n327\t            <ul className=\"hidden gap-4 pt-1 sm:flex sm:flex-wrap lg:gap-6\" aria-label=\"Bénéfices clés\">\n328\t              {config.hero.stats.map((stat, index) => {\n329\t                const Icon = stat.icon;\n330\t                return (\n331\t                  <li\n332\t                    key={stat.label}\n333\t                    className={`flex items-start gap-3 ${\n334\t                      index !== 0 ? 'sm:border-l sm:border-white/10 sm:pl-6' : ''\n335\t                    }`}\n336\t                  >\n337\t                    <Icon className=\"mt-0.5 h-[18px] w-[18px] shrink-0 text-teal-vivid\" strokeWidth={1.5} />\n338\t                    <div className=\"leading-tight\">\n339\t                      <p className=\"font-satoshi text-[15px] font-bold text-white lg:text-base\">{stat.value}</p>\n340\t                      <p className=\"mt-1 font-body text-[12.5px] text-cream/55 lg:text-[13px]\">{stat.label}</p>\n341\t                    </div>\n342\t                  </li>\n343\t                );\n344\t              })}\n345\t            </ul>\n346\t          </div>\n347\t\n348\t          <div className=\"animate-hero-stats\">\n349\t            <div className=\"rounded-[1.5rem] border border-white/[0.08] bg-white/[0.04] p-1.5 backdrop-blur-sm\">\n350\t              <div className=\"rounded-[calc(1.5rem-6px)] border border-white/[0.06] bg-[#0b1a2b]/80 p-4 shadow-[inset_0_1px_1px_rgba(255,255,255,0.06)] backdrop-blur-xl lg:p-7\">\n351\t                {!submitted ? (\n352\t                  <>\n353\t                    <h2 className=\"mb-1 text-center font-satoshi text-xl font-bold text-white lg:text-2xl\">\n354\t                      {config.hero.formTitle}\n355\t                    </h2>\n356\t                    <p className=\"mb-4 text-center font-body text-[12px] text-white/50\">\n357\t                      {config.hero.formSubtitle}\n358\t                    </p>\n359\t                    <form\n360\t                      onSubmit={(event) => {\n361\t                        event.preventDefault();\n362\t                        setSubmitted(true);\n363\t                      }}\n364\t                      className=\"space-y-2.5 lg:space-y-3\"\n365\t                    >\n366\t                      <select\n367\t                        required\n368\t                        value={form.type}\n369\t                        onChange={(e) => setForm({ ...form, type: e.target.value })}\n370\t                        className={selectClass}\n371\t                      >\n372\t                        <option value=\"\" disabled className=\"bg-card text-foreground\">\n373\t                          {config.hero.formFields.typeLabel}\n374\t                        </option>\n375\t                        {config.hero.formFields.typeOptions.map((option) => (\n376\t                          <option key={option} value={option} className=\"bg-card text-foreground\">\n377\t                            {option}\n378\t                          </option>\n379\t                        ))}\n380\t                      </select>\n381\t                      <select\n382\t                        required\n383\t                        value={form.climate}\n384\t                        onChange={(e) => setForm({ ...form, climate: e.target.value })}\n385\t                        className={selectClass}\n386\t                      >\n387\t                        <option value=\"\" disabled className=\"bg-card text-foreground\">\n388\t                          {config.hero.formFields.climateLabel}\n389\t                        </option>\n390\t                        {config.hero.formFields.climateOptions.map((option) => (\n391\t                          <option key={option} value={option} className=\"bg-card text-foreground\">\n392\t                            {option}\n393\t                          </option>\n394\t                        ))}\n395\t                      </select>\n396\t                      <input\n397\t                        type=\"number\"\n398\t                        placeholder=\"Surface toiture (m²)\"\n399\t                        required\n400\t                        min=\"1\"\n401\t                        value={form.surface}\n402\t                        onChange={(e) => setForm({ ...form, surface: e.target.value })}\n403\t                        className={inputClass}\n404\t                      />\n405\t                      <input\n406\t                        type=\"number\"\n407\t                        placeholder={config.hero.formFields.yearLabel}\n408\t                        required\n409\t                        min=\"1900\"\n410\t                        value={form.year}\n411\t                        onChange={(e) => setForm({ ...form, year: e.target.value })}\n412\t                        className={inputClass}\n413\t                      />\n414\t                      <input\n415\t                        type=\"email\"\n416\t                        placeholder=\"Email professionnel\"\n417\t                        required\n418\t                        value={form.email}\n419\t                        onChange={(e) => setForm({ ...form, email: e.target.value })}\n420\t                        className={inputClass}\n421\t                      />\n422\t\n423\t                      <button\n424\t                        type=\"submit\"\n425\t                        className=\"group mt-1 flex w-full items-center justify-center gap-3 rounded-full cta-gradient py-3 font-semibold text-white active:scale-[0.98]\"\n426\t                      >\n427\t                        <span className=\"text-[15px]\">{config.hero.formFields.cta}</span>\n428\t                        <span className=\"flex h-8 w-8 items-center justify-center rounded-full bg-white/20 transition-transform duration-500 group-hover:translate-x-0.5\">\n429\t                          <ArrowRight className=\"h-4 w-4\" />\n430\t                        </span>\n431\t                      </button>\n432\t                    </form>\n433\t\n434\t                    <p className=\"mt-3 text-center font-body text-[11px] text-white/35\">\n435\t                      {config.hero.formFields.microcopy}\n436\t                    </p>\n437\t                  </>\n438\t                ) : (\n439\t                  <div className=\"py-4 text-center\">\n440\t                    <div className=\"mx-auto mb-4 flex h-12 w-12 items-center justify-center rounded-full bg-primary/20\">\n441\t                      <Shield className=\"h-6 w-6 text-primary\" />\n442\t                    </div>\n443\t                    <p className=\"mb-1 font-body text-sm text-white/60\">Budget indicatif pour {fmt(surfaceNum)} m²</p>\n444\t                    <p className=\"mb-4 font-satoshi text-2xl font-bold text-white\">\n445\t                      {fmt(estimMin)}€ - {fmt(estimMax)}€\n446\t                    </p>\n447\t                    <p className=\"mb-4 font-body text-[13px] text-white/50\">\n448\t                      Un conseiller vous contacte sous 24h avec un chiffrage détaillé.\n449\t                    </p>\n450\t                    <button\n451\t                      onClick={() => setSubmitted(false)}\n452\t                      className=\"font-body text-sm font-semibold text-primary hover:underline\"\n453\t                    >\n454\t                      Modifier ma demande\n455\t                    </button>\n456\t                  </div>\n457\t                )}\n458\t              </div>\n459\t            </div>\n460\t          </div>\n461\t        </div>\n462\t      </div>\n463\t\n464\t      <div className=\"relative z-10 mt-auto hidden lg:block\">\n465\t        <div className=\"border-t border-white/10 bg-navy/78 py-5 backdrop-blur-md\">\n466\t          <p className=\"mb-3 text-center font-body text-[10px] font-semibold uppercase tracking-[0.2em] text-white/35\">\n467\t            {config.logos.title}\n468\t          </p>\n469\t          <div className=\"mx-auto flex max-w-6xl flex-nowrap items-center justify-center gap-x-8 px-8 xl:gap-x-12\">\n470\t            {config.logos.items.map((logo) =>\n471\t              logo.url ? (\n472\t                <span key={logo.name} className=\"flex h-8 w-28 items-center justify-center\">\n473\t                  <img\n474\t                    src={logo.url}\n475\t                    alt={logo.name}\n476\t                    className=\"max-h-7 max-w-full object-contain opacity-45 transition-opacity duration-300 hover:opacity-75\"\n477\t                    style={{ filter: 'brightness(0) invert(1)' }}\n478\t                    loading=\"lazy\"\n479\t                    decoding=\"async\"\n480\t                  />\n481\t                </span>\n482\t              ) : (\n483\t                <span key={logo.name} className=\"flex h-8 w-28 items-center justify-center whitespace-nowrap font-satoshi text-base font-bold text-white/50 xl:text-lg\">\n484\t                  {logo.name}\n485\t                </span>\n486\t              )\n487\t            )}\n488\t          </div>\n489\t        </div>\n490\t      </div>\n491\t    </section>\n492\t  );\n493\t};\n494\t\n495\tconst ProblemSection = ({ config }: { config: SectorPageConfig }) => (\n496\t  <section className=\"relative overflow-hidden bg-cream py-20 lg:py-32\">\n497\t    <div className=\"container mx-auto px-4 lg:px-8\">\n498\t      <div className=\"mb-10 grid grid-cols-1 items-end gap-8 lg:mb-16 lg:grid-cols-[1.05fr_0.95fr] lg:gap-20\">\n499\t        <div className=\"space-y-6 lg:space-y-9\">\n500\t          <ScrollReveal>\n501\t            <div className=\"flex items-center gap-3\">\n502\t              <span className=\"h-px w-9 bg-terracotta/70\" aria-hidden=\"true\" />\n503\t              <span className=\"font-body text-[11px] font-bold uppercase tracking-[0.22em] text-terracotta-dark\">\n504\t                {config.problem.eyebrow}\n505\t              </span>\n506\t            </div>\n507\t          </ScrollReveal>\n508\t          <ScrollReveal>\n509\t            <h2\n510\t              className=\"font-satoshi font-bold text-foreground !leading-[1.05]\"\n511\t              style={{ fontSize: 'clamp(1.875rem, 3.6vw, 2.875rem)', letterSpacing: '-0.025em' }}\n512\t            >\n513\t              {config.problem.title}\n514\t              <br />\n515\t              <span className=\"text-foreground/40\">{config.problem.mutedTitle}</span>\n516\t            </h2>\n517\t          </ScrollReveal>\n518\t        </div>\n519\t        <ScrollReveal>\n520\t          <p className=\"max-w-[560px] font-body text-base leading-relaxed text-foreground/65 lg:ml-auto lg:text-[16px]\">\n521\t            {config.problem.intro}\n522\t          </p>\n523\t        </ScrollReveal>\n524\t      </div>\n525\t\n526\t      <ScrollReveal stagger>\n527\t        <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4 lg:gap-5 xl:gap-6\">\n528\t          {config.problem.cards.map((problem) => {\n529\t            const Icon = problem.icon;\n530\t            return (\n531\t              <article\n532\t                key={problem.title}\n533\t                className=\"group overflow-hidden rounded-2xl bg-white shadow-[0_18px_45px_-34px_hsl(var(--navy)/0.28)] ring-1 ring-foreground/[0.05]\"\n534\t              >\n535\t                <div className=\"relative aspect-[4/3] overflow-hidden bg-foreground/[0.04]\">\n536\t                  <WpImage\n537\t                    image={toFillImage(problem.image, problem.alt)}\n538\t                    fill\n539\t                    sizes=\"(min-width: 1024px) 25vw, (min-width: 640px) 50vw, 100vw\"\n540\t                    className=\"size-full object-cover\"\n541\t                  />\n542\t                  <div aria-hidden=\"true\" className=\"absolute inset-x-0 bottom-0 h-1/2 bg-gradient-to-t from-navy/45 to-transparent\" />\n543\t                  <span className=\"absolute left-4 top-4 flex h-10 w-10 items-center justify-center rounded-full bg-cream/90 text-terracotta-dark shadow-sm\">\n544\t                    <Icon className=\"h-5 w-5\" strokeWidth={1.7} />\n545\t                  </span>\n546\t                </div>\n547\t                <div className=\"px-6 py-7 lg:px-6 lg:py-8\">\n548\t                  <h3 className=\"mb-3 font-satoshi text-[18px] font-bold !leading-tight text-foreground lg:text-[19px]\">\n549\t                    {problem.title}\n550\t                  </h3>\n551\t                  <p className=\"font-body text-[14px] leading-relaxed text-foreground/62 lg:text-[14.5px]\">\n552\t                    {problem.desc}\n553\t                  </p>\n554\t                </div>\n555\t              </article>\n556\t            );\n557\t          })}\n558\t        </div>\n559\t      </ScrollReveal>\n560\t\n561\t      <ScrollReveal>\n562\t        {config.problem.transition && (\n563\t          <p className=\"mx-auto mt-10 max-w-3xl border-t border-foreground/10 pt-6 text-center font-body text-sm leading-relaxed text-foreground/58 lg:mt-14 lg:text-base\">\n564\t            {config.problem.transition}\n565\t          </p>\n566\t        )}\n567\t      </ScrollReveal>\n568\t    </div>\n569\t  </section>\n570\t);\n571\t\n572\tconst SolutionSection = ({ config }: { config: SectorPageConfig }) => (\n573\t  <section className=\"relative overflow-hidden bg-[#142333] py-20 text-white lg:py-32\">\n574\t    <div\n575\t      aria-hidden=\"true\"\n576\t      className=\"absolute inset-0 opacity-[0.55]\"\n577\t      style={{ backgroundImage: 'linear-gradient(115deg, rgba(255,255,255,0.055) 0 1px, transparent 1px 120px)' }}\n578\t    />\n579\t    <div className=\"container relative mx-auto px-4 lg:px-8\">\n580\t      <ScrollReveal>\n581\t        <div className=\"mx-auto mb-12 grid max-w-6xl grid-cols-1 items-end gap-8 lg:mb-16 lg:grid-cols-[0.88fr_1.12fr] lg:gap-16\">\n582\t          <div>\n583\t            <div className=\"mb-6 inline-flex items-center gap-3\">\n584\t              <span className=\"h-px w-8 bg-teal-vivid/70\" aria-hidden=\"true\" />\n585\t              <span className=\"font-body text-[11px] font-bold uppercase tracking-[0.22em] text-teal-vivid\">\n586\t                {config.solution.eyebrow}\n587\t              </span>\n588\t            </div>\n589\t            <h2\n590\t              className=\"font-satoshi font-bold !leading-[1.04] text-white\"\n591\t              style={{ fontSize: 'clamp(2rem, 3.4vw, 3rem)', letterSpacing: '-0.03em' }}\n592\t            >\n593\t              {config.solution.title}\n594\t              <br />\n595\t              <span className=\"text-white/45\">{config.solution.mutedTitle}</span>\n596\t            </h2>\n597\t          </div>\n598\t          <p className=\"max-w-2xl font-body text-base leading-relaxed text-white/74 lg:text-[17px]\">\n599\t            {config.solution.intro}\n600\t          </p>\n601\t        </div>\n602\t      </ScrollReveal>\n603\t\n604\t      <div className=\"grid grid-cols-1 gap-5 md:grid-cols-2 lg:gap-6\">\n605\t        {[\n606\t          {\n607\t            title: 'Toiture classique',\n608\t            image: config.solution.beforeImage ?? classicRoofImage.src,\n609\t            metric: \"jusqu'à 80°C\",\n610\t            metricLabel: 'en surface',\n611\t            points: ['Surface sombre', 'Absorbe la chaleur', 'Alourdit la climatisation'],\n612\t            cool: false,\n613\t          },\n614\t          {\n615\t            title: 'Toiture cool roof',\n616\t            image: config.solution.afterImage ?? coolRoofImage.src,\n617\t            metric: \"jusqu'à 90%\",\n618\t            metricLabel: 'du rayonnement réfléchi',\n619\t            points: ['Surface claire', 'Reste plus fraîche', 'Réduit la charge thermique'],\n620\t            cool: true,\n621\t          },\n622\t        ].map((item) => (\n623\t          <article key={item.title} className=\"overflow-hidden rounded-2xl border border-white/10 bg-white/[0.045]\">\n624\t            <div className=\"relative aspect-[1.1] overflow-hidden bg-[#0f1d2a] md:aspect-[1.18]\">\n625\t              <WpImage\n626\t                image={toFillImage(item.image, item.title)}\n627\t                fill\n628\t                sizes=\"(min-width: 768px) 50vw, 100vw\"\n629\t                className=\"size-full object-cover\"\n630\t              />\n631\t              <div aria-hidden=\"true\" className=\"absolute inset-x-0 bottom-0 h-2/3 bg-gradient-to-t from-[#142333] via-[#142333]/20 to-transparent\" />\n632\t            </div>\n633\t            <div className=\"p-5 lg:p-7\">\n634\t              <div className=\"mb-6 flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between\">\n635\t                <h3 className=\"font-satoshi text-xl font-bold !leading-tight text-white lg:text-2xl\">\n636\t                  {item.title}\n637\t                </h3>\n638\t                <div className={`shrink-0 rounded-xl border px-4 py-3 ${item.cool ? 'border-teal-vivid/18 bg-teal-vivid/10 text-teal-vivid' : 'border-terracotta/18 bg-terracotta/12 text-[#f0a084]'}`}>\n639\t                  <span className=\"block font-satoshi text-2xl font-bold leading-none lg:text-3xl\">{item.metric}</span>\n640\t                  <span className=\"mt-1 block font-body text-[10px] font-bold uppercase tracking-[0.14em] opacity-75\">\n641\t                    {item.metricLabel}\n642\t                  </span>\n643\t                </div>\n644\t              </div>\n645\t              <ul className=\"grid gap-2.5\">\n646\t                {item.points.map((point) => (\n647\t                  <li key={point} className=\"flex items-start gap-2.5\">\n648\t                    <CheckCircle2 className={`mt-0.5 h-4 w-4 shrink-0 ${item.cool ? 'text-teal-vivid' : 'text-[#f0a084]'}`} strokeWidth={2} />\n649\t                    <span className=\"font-body text-sm leading-relaxed text-white/66\">{point}</span>\n650\t                  </li>\n651\t                ))}\n652\t              </ul>\n653\t            </div>\n654\t          </article>\n655\t        ))}\n656\t      </div>\n657\t\n658\t      {(config.solution.points.length > 0 || config.solution.transition) && (\n659\t        <ScrollReveal>\n660\t          <div className=\"mx-auto mt-10 max-w-6xl lg:mt-14\">\n661\t            {config.solution.points.length > 0 && (\n662\t              <ul className=\"grid grid-cols-1 gap-3 md:grid-cols-4\">\n663\t                {config.solution.points.map((point) => (\n664\t                  <li key={point} className=\"flex items-center gap-3 rounded-xl border border-white/10 bg-white/[0.055] px-5 py-4\">\n665\t                    <span className=\"flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-teal-vivid/12\">\n666\t                      <Check className=\"h-4 w-4 text-teal-vivid\" strokeWidth={1.8} />\n667\t                    </span>\n668\t                    <span className=\"font-body text-sm font-semibold leading-snug text-white/78\">{point}</span>\n669\t                  </li>\n670\t                ))}\n671\t              </ul>\n672\t            )}\n673\t            {config.solution.transition && (\n674\t              <p className=\"mx-auto mt-8 max-w-2xl text-center font-body text-sm leading-relaxed text-white/52\">\n675\t                {config.solution.transition}\n676\t              </p>\n677\t            )}\n678\t          </div>\n679\t        </ScrollReveal>\n680\t      )}\n681\t    </div>\n682\t  </section>\n683\t);\n684\t\n685\tconst DurabilitySection = ({ config }: { config: SectorPageConfig }) => (\n686\t  <section className=\"relative overflow-hidden bg-[#F6FAFB] py-16 lg:py-28\">\n687\t    <div className=\"container mx-auto px-4 lg:px-8\">\n688\t      <ScrollReveal>\n689\t        <div className=\"mx-auto mb-12 max-w-2xl text-center lg:mb-16\">\n690\t          <p className=\"mb-5 font-body text-[10px] font-semibold uppercase tracking-[0.25em] text-primary/55\">\n691\t            Durabilité\n692\t          </p>\n693\t          <h2\n694\t            className=\"mb-5 font-satoshi font-bold text-foreground !leading-[1.05]\"\n695\t            style={{ fontSize: 'clamp(2rem, 3.2vw, 2.85rem)', letterSpacing: '-0.03em' }}\n696\t          >\n697\t            {config.durability.title}\n698\t            {config.durability.mutedTitle && (\n699\t              <>\n700\t                <br />\n701\t                <span className=\"text-foreground/35\">{config.durability.mutedTitle}</span>\n702\t              </>\n703\t            )}\n704\t          </h2>\n705\t          <p className=\"font-body text-base leading-relaxed text-foreground/62 lg:text-[17px]\">\n706\t            {config.durability.intro}\n707\t          </p>\n708\t        </div>\n709\t      </ScrollReveal>\n710\t\n711\t      <ScrollReveal>\n712\t        <div className=\"mx-auto grid max-w-5xl grid-cols-1 items-stretch gap-5 lg:grid-cols-2 lg:gap-0\">\n713\t          {[\n714\t            {\n715\t              title: 'Revêtement acrylique standard',\n716\t              subtitle: 'Prix bas à la pose',\n717\t              price: '~10 €',\n718\t              life: '2-5 ans',\n719\t              realCost: '25-30 €',\n720\t              covalba: false,\n721\t              points: ['Réflectivité qui baisse vite', 'Farinage et jaunissement', 'Réapplication plus fréquente'],\n722\t            },\n723\t            {\n724\t              title: 'Système polyuréthane Covalba',\n725\t              subtitle: config.durability.covalbaLabel,\n726\t              price: '18-20 €',\n727\t              life: '8-10 ans',\n728\t              realCost: '18-20 €',\n729\t              covalba: true,\n730\t              points: ['Résine polyuréthane durable', 'Vernis de finition anti-UV', 'Réflectivité conservée plus longtemps'],\n731\t            },\n732\t          ].map((option) => (\n733\t            <article\n734\t              key={option.title}\n735\t              className={`relative rounded-2xl px-7 py-9 shadow-[0_20px_60px_rgba(26,42,58,0.08)] lg:px-10 lg:py-12 ${\n736\t                option.covalba ? 'z-10 bg-foreground text-white lg:-ml-5 lg:scale-[1.03]' : 'bg-white text-foreground lg:scale-[0.97] lg:opacity-90'\n737\t              }`}\n738\t            >\n739\t              {option.covalba && (\n740\t                <span className=\"absolute -top-4 left-1/2 inline-flex -translate-x-1/2 items-center rounded-full bg-teal-vivid px-4 py-2 font-body text-[11px] font-bold uppercase tracking-[0.15em] text-white\">\n741\t                  Le choix durable\n742\t                </span>\n743\t              )}\n744\t              <h3 className=\"mb-2 font-satoshi text-2xl font-bold leading-tight lg:text-[1.7rem]\">{option.title}</h3>\n745\t              <p className={`mb-8 font-body text-sm ${option.covalba ? 'text-white/52' : 'text-foreground/50'}`}>\n746\t                {option.subtitle}\n747\t              </p>\n748\t              <div className=\"mb-8 grid grid-cols-3 gap-4\">\n749\t                {[\n750\t                  ['Prix au m²', option.price],\n751\t                  ['Tenue', option.life],\n752\t                  ['10 ans', option.realCost],\n753\t                ].map(([label, value]) => (\n754\t                  <div key={label}>\n755\t                    <p className={`mb-1 font-body text-[10px] uppercase tracking-widest ${option.covalba ? 'text-white/42' : 'text-foreground/38'}`}>\n756\t                      {label}\n757\t                    </p>\n758\t                    <p className={`font-satoshi text-2xl font-bold leading-none lg:text-3xl ${label === '10 ans' ? (option.covalba ? 'text-teal-vivid' : 'text-terracotta') : ''}`}>\n759\t                      {value}\n760\t                    </p>\n761\t                  </div>\n762\t                ))}\n763\t              </div>\n764\t              <ul className=\"space-y-3 border-t border-current/10 pt-7\">\n765\t                {option.points.map((point) => {\n766\t                  const Icon = option.covalba ? Check : X;\n767\t                  return (\n768\t                    <li key={point} className=\"flex items-start gap-2.5\">\n769\t                      <Icon className={`mt-0.5 h-4 w-4 shrink-0 ${option.covalba ? 'text-teal-vivid' : 'text-terracotta/70'}`} />\n770\t                      <span className={`font-body text-sm leading-relaxed ${option.covalba ? 'text-white/70' : 'text-foreground/60'}`}>\n771\t                        {point}\n772\t                      </span>\n773\t                    </li>\n774\t                  );\n775\t                })}\n776\t              </ul>\n777\t            </article>\n778\t          ))}\n779\t        </div>\n780\t      </ScrollReveal>\n781\t\n782\t      <ScrollReveal>\n783\t        <p className=\"mx-auto mt-10 max-w-3xl text-center font-body text-sm leading-relaxed text-foreground/55 lg:text-[15px]\">\n784\t          {config.durability.note}\n785\t        </p>\n786\t      </ScrollReveal>\n787\t    </div>\n788\t  </section>\n789\t);\n790\t\n791\tconst SpecialSection = ({ config }: { config: SectorPageConfig }) => {\n792\t  const [submitted, setSubmitted] = useState(false);\n793\t  const isFunding = config.special.kind === 'funding';\n794\t\n795\t  return (\n796\t    <section className=\"relative overflow-hidden bg-white py-16 lg:py-28\">\n797\t      <div className=\"container mx-auto px-4 lg:px-8\">\n798\t        <ScrollReveal>\n799\t          <div className=\"mx-auto mb-10 grid max-w-6xl grid-cols-1 items-end gap-7 lg:mb-14 lg:grid-cols-[0.9fr_1.1fr] lg:gap-16\">\n800\t            <div>\n801\t              <div className=\"mb-5 flex items-center gap-3\">\n802\t                <span className=\"h-px w-10 bg-teal-vivid\" aria-hidden=\"true\" />\n803\t                <span className=\"font-body text-[11px] font-bold uppercase tracking-[0.22em] text-teal-vivid\">\n804\t                  {config.special.eyebrow}\n805\t                </span>\n806\t              </div>\n807\t              <h2\n808\t                className=\"font-satoshi font-bold !leading-[1.04] text-foreground\"\n809\t                style={{ fontSize: 'clamp(1.95rem, 3vw, 2.75rem)', letterSpacing: '-0.03em' }}\n810\t              >\n811\t                {config.special.title}\n812\t              </h2>\n813\t            </div>\n814\t            <p className=\"max-w-2xl font-body text-base leading-relaxed text-foreground/68 lg:text-[16px]\">\n815\t              {config.special.intro}\n816\t            </p>\n817\t          </div>\n818\t        </ScrollReveal>\n819\t\n820\t        <div className=\"mx-auto grid max-w-6xl grid-cols-1 gap-5 lg:grid-cols-[0.82fr_1.18fr] lg:gap-7\">\n821\t          <ScrollReveal>\n822\t            <div className=\"h-full rounded-2xl bg-cream/70 p-6 ring-1 ring-foreground/[0.06] lg:p-7\">\n823\t              {!submitted ? (\n824\t                <>\n825\t                  <h3 className=\"mb-5 font-satoshi text-xl font-bold leading-tight text-foreground\">\n826\t                    {isFunding ? 'Vérifier mon éligibilité' : 'Estimer mon gain'}\n827\t                  </h3>\n828\t                  <form\n829\t                    className=\"grid gap-3\"\n830\t                    onSubmit={(event) => {\n831\t                      event.preventDefault();\n832\t                      setSubmitted(true);\n833\t                    }}\n834\t                  >\n835\t                    <select required className={lightFieldClass} defaultValue=\"\">\n836\t                      <option value=\"\" disabled>\n837\t                        Type de bâtiment\n838\t                      </option>\n839\t                      {config.hero.formFields.typeOptions.map((option) => (\n840\t                        <option key={option}>{option}</option>\n841\t                      ))}\n842\t                    </select>\n843\t                    <input required min=\"1\" type=\"number\" className={lightFieldClass} placeholder=\"Surface toiture (m²)\" />\n844\t                    <input required type=\"email\" className={lightFieldClass} placeholder=\"Email professionnel\" />\n845\t                    <button className=\"group mt-1 inline-flex items-center justify-center gap-2 rounded-full bg-teal-vivid py-2.5 pl-6 pr-2 font-semibold text-white\">\n846\t                      <span className=\"text-sm\">{config.special.cta}</span>\n847\t                      <span className=\"flex h-8 w-8 items-center justify-center rounded-full bg-white/20 transition-transform duration-500 group-hover:translate-x-0.5\">\n848\t                        <ArrowRight className=\"h-3.5 w-3.5\" />\n849\t                      </span>\n850\t                    </button>\n851\t                  </form>\n852\t                </>\n853\t              ) : (\n854\t                <div className=\"flex min-h-[260px] flex-col items-center justify-center text-center\">\n855\t                  <CheckCircle2 className=\"mb-4 h-12 w-12 text-teal-vivid\" strokeWidth={1.7} />\n856\t                  <h3 className=\"mb-3 font-satoshi text-2xl font-bold text-foreground\">Demande reçue.</h3>\n857\t                  <p className=\"max-w-sm font-body text-sm leading-relaxed text-foreground/62\">\n858\t                    Covalba revient vers vous avec une réponse personnalisée.\n859\t                  </p>\n860\t                </div>\n861\t              )}\n862\t            </div>\n863\t          </ScrollReveal>\n864\t\n865\t          <ScrollReveal>\n866\t            <div className=\"rounded-2xl bg-foreground p-6 text-white lg:p-8\">\n867\t              {config.special.kind === 'decret' ? (\n868\t                <div className=\"grid gap-4 sm:grid-cols-3\">\n869\t                  {config.special.milestones.map((milestone) => (\n870\t                    <div key={milestone.value} className=\"rounded-xl border border-white/10 bg-white/[0.04] p-5\">\n871\t                      <p className=\"font-satoshi text-4xl font-bold leading-none text-teal-vivid\">{milestone.value}</p>\n872\t                      <p className=\"mt-3 font-body text-sm text-white/62\">{milestone.label}</p>\n873\t                    </div>\n874\t                  ))}\n875\t                </div>\n876\t              ) : (\n877\t                <div className=\"grid gap-4 sm:grid-cols-2\">\n878\t                  {config.special.points.map((point) => (\n879\t                    <div key={point.label} className=\"rounded-xl border border-white/10 bg-white/[0.04] p-5\">\n880\t                      <p className=\"font-satoshi text-3xl font-bold leading-none text-teal-vivid\">{point.value}</p>\n881\t                      <p className=\"mt-3 font-body text-sm text-white/62\">{point.label}</p>\n882\t                    </div>\n883\t                  ))}\n884\t                </div>\n885\t              )}\n886\t              {config.special.kind === 'decret' && (\n887\t                <div className=\"mt-6 grid gap-3\">\n888\t                  {config.special.points.map((point) => (\n889\t                    <div key={point} className=\"flex items-start gap-3\">\n890\t                      <CheckCircle2 className=\"mt-0.5 h-4 w-4 shrink-0 text-teal-vivid\" />\n891\t                      <span className=\"font-body text-sm leading-relaxed text-white/68\">{point}</span>\n892\t                    </div>\n893\t                  ))}\n894\t                </div>\n895\t              )}\n896\t            </div>\n897\t            <p className=\"mt-5 rounded-2xl bg-cream/70 p-5 font-body text-xs leading-relaxed text-foreground/58 lg:text-[13px]\">\n898\t              {config.special.note}\n899\t            </p>\n900\t          </ScrollReveal>\n901\t        </div>\n902\t      </div>\n903\t    </section>\n904\t  );\n905\t};\n906\t\n907\tconst BenefitsSection = ({ config }: { config: SectorPageConfig }) => (\n908\t  <>\n909\t    <section className=\"relative overflow-hidden bg-cream pb-12 pt-16 lg:min-h-[640px] lg:pb-8 lg:pt-20\">\n910\t      <figure className=\"absolute right-0 top-0 hidden h-full min-h-[640px] w-[58vw] overflow-hidden lg:block\">\n911\t        <WpImage\n912\t          image={toFillImage(config.benefits.image)}\n913\t          alt=\"\"\n914\t          fill\n915\t          sizes=\"58vw\"\n916\t          className=\"size-full object-cover\"\n917\t        />\n918\t        <div aria-hidden=\"true\" className=\"absolute inset-y-0 left-0 w-[56%] bg-gradient-to-r from-cream via-cream/88 to-transparent\" />\n919\t      </figure>\n920\t      <div className=\"container relative z-10 mx-auto px-4 lg:px-8\">\n921\t        <ScrollReveal>\n922\t          <div className=\"max-w-[760px]\">\n923\t            <div className=\"mb-5 flex items-center gap-3 lg:mb-7\">\n924\t              <span className=\"h-px w-10 bg-primary/70\" aria-hidden=\"true\" />\n925\t              <span className=\"font-body text-[11px] font-bold uppercase tracking-[0.22em] text-primary\">\n926\t                {config.benefits.eyebrow}\n927\t              </span>\n928\t            </div>\n929\t            <h2\n930\t              className=\"mb-6 font-satoshi font-bold !leading-[1.04] text-foreground\"\n931\t              style={{ fontSize: 'clamp(2.15rem, 3vw, 3rem)' }}\n932\t            >\n933\t              {config.benefits.title}\n934\t            </h2>\n935\t            <p className=\"max-w-[540px] font-body text-base leading-relaxed text-foreground/72 lg:text-[16px]\">\n936\t              {config.benefits.desc}\n937\t            </p>\n938\t            <div className=\"relative z-10 mt-7 max-w-[540px] rounded-2xl bg-white/96 p-6 shadow-[0_22px_70px_-45px_hsl(var(--navy)/0.35)] ring-1 ring-foreground/[0.05]\">\n939\t              <div className=\"grid grid-cols-[48px_minmax(0,1fr)] items-center gap-5\">\n940\t                <Thermometer className=\"h-12 w-12 text-primary\" strokeWidth={1.55} />\n941\t                <div>\n942\t                  <p className=\"mb-3 font-body text-[11px] font-bold uppercase tracking-[0.22em] text-primary\">\n943\t                    Dès le premier été\n944\t                  </p>\n945\t                  <p className=\"font-satoshi text-[3.1rem] font-bold leading-[0.88] text-primary\">{config.benefits.metric}</p>\n946\t                  <p className=\"mt-2 font-satoshi text-xl font-bold leading-tight text-foreground\">{config.benefits.metricLabel}</p>\n947\t                </div>\n948\t              </div>\n949\t            </div>\n950\t          </div>\n951\t        </ScrollReveal>\n952\t      </div>\n953\t    </section>\n954\t\n955\t    <section className=\"relative overflow-hidden bg-white py-14\">\n956\t      <div className=\"container relative mx-auto px-4 lg:px-8\">\n957\t        <ScrollReveal stagger>\n958\t          <div className=\"grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-5 lg:gap-4\">\n959\t            {config.benefits.cards.map((benefit, index) => {\n960\t              const Icon = benefit.icon;\n961\t              return (\n962\t                <article key={benefit.title} className=\"min-h-[184px] rounded-2xl bg-cream/65 p-5 ring-1 ring-foreground/[0.05] lg:p-6\">\n963\t                  <div className=\"mb-7 flex h-11 w-11 items-center justify-center rounded-xl bg-white text-primary\">\n964\t                    <Icon className=\"h-5 w-5\" strokeWidth={1.55} />\n965\t                  </div>\n966\t                  <span className=\"mb-3 block font-body text-[11px] font-bold uppercase tracking-[0.18em] text-primary/70\">\n967\t                    0{index + 1}\n968\t                  </span>\n969\t                  <h3 className=\"font-satoshi text-lg font-bold leading-tight text-foreground lg:text-[19px]\">{benefit.title}</h3>\n970\t                  <p className=\"mt-2 font-body text-sm leading-snug text-foreground/62\">{benefit.desc}</p>\n971\t                </article>\n972\t              );\n973\t            })}\n974\t          </div>\n975\t        </ScrollReveal>\n976\t        <p className=\"mx-auto mt-10 max-w-2xl text-center font-body text-sm leading-relaxed text-foreground/54\">\n977\t          {config.benefits.transition}\n978\t        </p>\n979\t      </div>\n980\t    </section>\n981\t  </>\n982\t);\n983\t\n984\tconst ApplicationsSection = ({ config }: { config: SectorPageConfig }) => (\n985\t  <section className=\"relative overflow-hidden bg-cream py-16 lg:py-24\">\n986\t    <div className=\"container relative mx-auto px-4 lg:px-8\">\n987\t      <ScrollReveal>\n988\t        <div className=\"mx-auto mb-10 grid max-w-6xl grid-cols-1 gap-6 lg:mb-12 lg:grid-cols-[0.9fr_1.1fr] lg:items-end lg:gap-16\">\n989\t          <div>\n990\t            <div className=\"mb-5 flex items-center gap-3\">\n991\t              <span className=\"h-px w-10 bg-primary/70\" aria-hidden=\"true\" />\n992\t              <span className=\"font-body text-[11px] font-bold uppercase tracking-[0.22em] text-primary\">\n993\t                {config.applications.eyebrow}\n994\t              </span>\n995\t            </div>\n996\t            <h2\n997\t              className=\"font-satoshi font-bold !leading-[1.05] text-foreground\"\n998\t              style={{ fontSize: 'clamp(2rem, 3vw, 3rem)' }}\n999\t            >\n1000\t              {config.applications.title}\n1001\t            </h2>\n1002\t          </div>\n1003\t          <p className=\"max-w-[540px] border-l border-primary/30 pl-6 font-body text-base leading-relaxed text-foreground/68 lg:text-[16px]\">\n1004\t            {config.applications.intro}\n1005\t          </p>\n1006\t        </div>\n1007\t      </ScrollReveal>\n1008\t      <ScrollReveal stagger>\n1009\t        <div className=\"mx-auto grid max-w-6xl grid-cols-1 gap-4 lg:grid-cols-5 lg:gap-5\">\n1010\t          {config.applications.cards.map((card, index) => {\n1011\t            const Icon = card.icon;\n1012\t            return (\n1013\t              <article key={card.title} className=\"overflow-hidden rounded-2xl bg-white shadow-[0_16px_46px_-38px_hsl(var(--navy)/0.34)] ring-1 ring-foreground/[0.06]\">\n1014\t                <div className=\"relative aspect-[4/3] overflow-hidden bg-foreground/[0.04]\">\n1015\t                  <WpImage\n1016\t                    image={toFillImage(card.image)}\n1017\t                    alt=\"\"\n1018\t                    fill\n1019\t                    sizes=\"(min-width: 1024px) 20vw, 100vw\"\n1020\t                    className=\"size-full object-cover\"\n1021\t                  />\n1022\t                </div>\n1023\t                <div className=\"p-5\">\n1024\t                  <div className=\"mb-4 flex items-center justify-between gap-3\">\n1025\t                    <span className=\"inline-flex items-center gap-2 font-body text-[11px] font-bold uppercase tracking-[0.18em] text-primary\">\n1026\t                      <Icon className=\"h-5 w-5\" strokeWidth={1.55} />\n1027\t                      {card.label}\n1028\t                    </span>\n1029\t                    <span className=\"font-body text-xs font-bold text-foreground/22\">0{index + 1}</span>\n1030\t                  </div>\n1031\t                  <h3 className=\"font-satoshi text-xl font-bold leading-tight text-foreground\">{card.title}</h3>\n1032\t                  <p className=\"mt-2 font-body text-sm leading-snug text-foreground/60\">{card.desc}</p>\n1033\t                </div>\n1034\t              </article>\n1035\t            );\n1036\t          })}\n1037\t        </div>\n1038\t      </ScrollReveal>\n1039\t      {config.applications.transition && (\n1040\t        <p className=\"mx-auto mt-10 max-w-2xl text-center font-body text-sm leading-relaxed text-foreground/54\">\n1041\t          {config.applications.transition}\n1042\t        </p>\n1043\t      )}\n1044\t    </div>\n1045\t  </section>\n1046\t);\n1047\t\n1048\tconst MethodSection = ({ config }: { config: SectorPageConfig }) => {\n1049\t  const [videoOpen, setVideoOpen] = useState(false);\n1050\t  const icons = [ClipboardCheck, CalendarClock, Shield, TrendingDown];\n1051\t  return (\n1052\t    <section className=\"bg-white py-16 lg:py-32\">\n1053\t      <div className=\"container mx-auto px-4 lg:px-8\">\n1054\t        <div className=\"flex flex-col items-start gap-12 lg:flex-row lg:gap-20\">\n1055\t          <div className=\"lg:sticky lg:top-[120px] lg:w-[40%]\">\n1056\t            <ScrollReveal>\n1057\t              <p className=\"mb-6 font-body text-[10px] font-semibold uppercase tracking-[0.25em] text-primary/50\">\n1058\t                {config.method.eyebrow}\n1059\t              </p>\n1060\t              <h2\n1061\t                className=\"mb-6 font-satoshi text-3xl font-bold text-foreground !leading-[1.05] sm:text-4xl lg:text-[3rem]\"\n1062\t                style={{ letterSpacing: '-0.03em' }}\n1063\t              >\n1064\t                {config.method.title}\n1065\t                <span className=\"text-foreground/30\"> {config.method.mutedTitle}</span>\n1066\t              </h2>\n1067\t              <p className=\"mb-8 font-body text-base leading-relaxed text-muted-foreground lg:text-lg\">\n1068\t                {config.method.intro}\n1069\t              </p>\n1070\t              <button onClick={() => setVideoOpen(true)} className=\"group flex items-center gap-3 text-primary\">\n1071\t                <div className=\"flex h-12 w-12 items-center justify-center rounded-full bg-primary/10\">\n1072\t                  <Play className=\"h-5 w-5\" />\n1073\t                </div>\n1074\t                <span className=\"font-body text-sm font-semibold\">Voir un chantier en 2 minutes</span>\n1075\t              </button>\n1076\t            </ScrollReveal>\n1077\t          </div>\n1078\t          <div className=\"relative lg:w-[60%]\">\n1079\t            <div className=\"absolute bottom-4 left-5 top-4 w-px bg-gradient-to-b from-primary/25 via-primary/10 to-transparent lg:left-6\" />\n1080\t            {config.method.steps.map((step, index) => {\n1081\t              const Icon = icons[index] ?? ClipboardCheck;\n1082\t              return (\n1083\t                <ScrollReveal key={step.title}>\n1084\t                  <div className=\"group relative flex items-start gap-5 py-8 lg:gap-7 lg:py-10\">\n1085\t                    <div className=\"relative z-10 flex h-10 w-10 shrink-0 items-center justify-center rounded-full border border-primary/20 bg-primary/10 lg:h-12 lg:w-12\">\n1086\t                      <Icon className=\"h-4 w-4 text-primary lg:h-5 lg:w-5\" />\n1087\t                    </div>\n1088\t                    <div className=\"pt-1\">\n1089\t                      <span className=\"mb-2 block font-body text-xs font-bold uppercase tracking-widest text-primary/50\">\n1090\t                        Étape 0{index + 1}\n1091\t                      </span>\n1092\t                      <h3 className=\"mb-2 text-xl text-foreground lg:text-2xl\">{step.title}</h3>\n1093\t                      <p className=\"max-w-md font-body text-sm leading-relaxed text-muted-foreground lg:text-base\">{step.text}</p>\n1094\t                    </div>\n1095\t                  </div>\n1096\t                  {index < config.method.steps.length - 1 && <div className=\"ml-5 h-px bg-border lg:ml-6\" />}\n1097\t                </ScrollReveal>\n1098\t              );\n1099\t            })}\n1100\t            <p className=\"ml-16 mt-4 font-body text-xs font-medium text-muted-foreground/50 lg:ml-20\">\n1101\t              {config.method.duration}\n1102\t            </p>\n1103\t          </div>\n1104\t        </div>\n1105\t      </div>\n1106\t      <Dialog open={videoOpen} onOpenChange={setVideoOpen}>\n1107\t        <DialogContent className=\"max-w-4xl overflow-hidden border-none bg-black p-0\">\n1108\t          <div className=\"aspect-video\">\n1109\t            <iframe\n1110\t              src=\"https://www.youtube.com/embed/9HOB5OVH0Ac?autoplay=1\"\n1111\t              className=\"h-full w-full\"\n1112\t              allow=\"autoplay; encrypted-media\"\n1113\t              allowFullScreen\n1114\t              title=\"Covalba Cool Roof, un chantier en 2 minutes\"\n1115\t            />\n1116\t          </div>\n1117\t        </DialogContent>\n1118\t      </Dialog>\n1119\t    </section>\n1120\t  );\n1121\t};\n1122\t\n1123\tconst ProofSection = ({ config }: { config: SectorPageConfig }) => (\n1124\t  <section className=\"relative overflow-hidden bg-[#192A3A] py-24 lg:py-36\">\n1125\t    <div className=\"container relative mx-auto px-4 lg:px-8\">\n1126\t      <ScrollReveal>\n1127\t        <div className=\"mb-9 flex items-center gap-3 lg:mb-12\">\n1128\t          <span className=\"h-px w-12 bg-teal-vivid/70\" aria-hidden=\"true\" />\n1129\t          <span className=\"font-body text-[11px] font-bold uppercase tracking-[0.22em] text-teal-vivid\">\n1130\t            {config.proof.eyebrow}\n1131\t          </span>\n1132\t        </div>\n1133\t        <div className=\"mb-14 grid grid-cols-1 items-start gap-8 lg:mb-20 lg:grid-cols-[3fr_2fr] lg:gap-16\">\n1134\t          <h2\n1135\t            className=\"font-satoshi font-bold text-white !leading-[1.05]\"\n1136\t            style={{ fontSize: 'clamp(1.875rem, 3.8vw, 3rem)', letterSpacing: '-0.03em' }}\n1137\t          >\n1138\t            {config.proof.title}\n1139\t            <br />\n1140\t            <span className=\"text-teal-vivid\">{config.proof.mutedTitle}</span>\n1141\t          </h2>\n1142\t          <p className=\"max-w-[470px] font-body text-base leading-relaxed text-white/65 lg:mt-2 lg:text-[16px]\">\n1143\t            {config.proof.intro}\n1144\t          </p>\n1145\t        </div>\n1146\t      </ScrollReveal>\n1147\t      <ScrollReveal stagger>\n1148\t        <div className=\"mb-12 grid grid-cols-1 gap-4 md:grid-cols-3 lg:gap-5\">\n1149\t          {config.proof.figures.map((figure) => {\n1150\t            const Icon = figure.icon;\n1151\t            return (\n1152\t              <div key={figure.label} className=\"rounded-2xl border border-white/10 bg-white/[0.04] p-8 lg:p-9\">\n1153\t                <div className=\"mb-6 flex h-11 w-11 items-center justify-center rounded-full bg-teal-vivid/[0.12]\">\n1154\t                  <Icon className=\"h-5 w-5 text-teal-vivid\" strokeWidth={1.6} />\n1155\t                </div>\n1156\t                <p className=\"mb-3 font-satoshi text-4xl font-bold leading-none text-white\">{figure.value}</p>\n1157\t                <p className=\"font-body text-sm leading-relaxed text-white/60\">{figure.label}</p>\n1158\t              </div>\n1159\t            );\n1160\t          })}\n1161\t        </div>\n1162\t      </ScrollReveal>\n1163\t      <ScrollReveal>\n1164\t        <SectorReferenceHighlights\n1165\t          sector={config.slug as ReferenceSectorSlug}\n1166\t          referenceFilter={referenceFilterBySectorSlug[config.slug] ?? 'Tous'}\n1167\t          title=\"Des cas clients pour vous projeter.\"\n1168\t          variant=\"dark\"\n1169\t        />\n1170\t      </ScrollReveal>\n1171\t      {config.proof.cases && (\n1172\t        <div className=\"mb-12 grid gap-4 md:grid-cols-2\">\n1173\t          {config.proof.cases.map((item) => (\n1174\t            <div key={item.name} className=\"rounded-2xl border border-white/10 bg-white/[0.04] p-6\">\n1175\t              <h3 className=\"mb-2 font-satoshi text-xl font-bold text-white\">{item.name}</h3>\n1176\t              <p className=\"font-body text-sm leading-relaxed text-white/60\">{item.desc}</p>\n1177\t            </div>\n1178\t          ))}\n1179\t        </div>\n1180\t      )}\n1181\t      <div className=\"border-t border-white/10 pt-10\">\n1182\t        <div className=\"flex flex-wrap items-center justify-center gap-x-10 gap-y-7 lg:gap-x-14\">\n1183\t          {config.proof.logos.map((logo) =>\n1184\t            logo.url ? (\n1185\t              <span key={logo.name} className=\"flex h-8 w-28 items-center justify-center\">\n1186\t                <img\n1187\t                  src={logo.url}\n1188\t                  alt={logo.name}\n1189\t                  className=\"max-h-7 max-w-full object-contain opacity-45\"\n1190\t                  style={{ filter: 'brightness(0) invert(1)' }}\n1191\t                  loading=\"lazy\"\n1192\t                  decoding=\"async\"\n1193\t                />\n1194\t              </span>\n1195\t            ) : (\n1196\t              <span key={logo.name} className=\"flex h-8 w-28 items-center justify-center font-satoshi text-lg font-bold text-white/50\">{logo.name}</span>\n1197\t            )\n1198\t          )}\n1199\t        </div>\n1200\t        <p className=\"mx-auto mt-9 max-w-2xl text-center font-body text-sm leading-relaxed text-white/70\">\n1201\t          {config.proof.transition}\n1202\t        </p>\n1203\t      </div>\n1204\t    </div>\n1205\t  </section>\n1206\t);\n1207\t\n1208\tconst FaqSection = ({ config }: { config: SectorPageConfig }) => (\n1209\t  <section className=\"bg-cream py-20 lg:py-32\">\n1210\t    <div className=\"container mx-auto px-4 lg:px-8\">\n1211\t      <ScrollReveal>\n1212\t        <div className=\"grid items-start gap-10 lg:grid-cols-[0.85fr_1.15fr] lg:gap-16\">\n1213\t          <div className=\"lg:sticky lg:top-24\">\n1214\t            <div className=\"mb-5 flex items-center gap-3\">\n1215\t              <span className=\"h-px w-10 bg-primary/70\" aria-hidden=\"true\" />\n1216\t              <span className=\"font-body text-[11px] font-bold uppercase tracking-[0.22em] text-primary\">FAQ</span>\n1217\t            </div>\n1218\t            <h2 className=\"mb-5 font-satoshi font-bold text-foreground !leading-[1.05]\" style={{ fontSize: 'clamp(2rem, 3.3vw, 3rem)', letterSpacing: '-0.03em' }}>\n1219\t              Vos questions,\n1220\t              <br />\n1221\t              <span className=\"text-foreground/40\">nos réponses.</span>\n1222\t            </h2>\n1223\t            <p className=\"max-w-[420px] font-body text-base leading-relaxed text-foreground/65 lg:text-[15.5px]\">\n1224\t              {config.faq.intro}\n1225\t            </p>\n1226\t            <a href={`#contact-${config.slug}`} className=\"group mt-8 inline-flex items-center gap-2 text-sm font-semibold text-primary\">\n1227\t              Une autre question ? Parlons-en\n1228\t              <ArrowRight className=\"h-4 w-4\" />\n1229\t            </a>\n1230\t          </div>\n1231\t          <Accordion type=\"single\" collapsible className=\"space-y-3\">\n1232\t            {config.faq.items.map((faq, index) => (\n1233\t              <AccordionItem key={faq.q} value={`${config.slug}-faq-${index}`} className=\"rounded-xl border border-foreground/[0.06] bg-white px-5 shadow-[0_12px_34px_rgba(24,42,58,0.04)] lg:px-6\">\n1234\t                <AccordionTrigger className=\"py-5 text-left font-satoshi text-base font-bold text-foreground hover:no-underline lg:text-[17px]\">\n1235\t                  {faq.q}\n1236\t                </AccordionTrigger>\n1237\t                <AccordionContent className=\"pb-5 font-body text-[14.5px] leading-relaxed text-foreground/67 lg:text-[15px]\">\n1238\t                  {faq.a}\n1239\t                </AccordionContent>\n1240\t              </AccordionItem>\n1241\t            ))}\n1242\t          </Accordion>\n1243\t        </div>\n1244\t      </ScrollReveal>\n1245\t    </div>\n1246\t  </section>\n1247\t);\n1248\t\n1249\tconst FinalCta = ({ config }: { config: SectorPageConfig }) => (\n1250\t  <section id={`contact-${config.slug}`} className=\"overflow-hidden bg-[#182A3A] py-20 lg:py-32\">\n1251\t    <div className=\"container mx-auto px-4 lg:px-8\">\n1252\t      <ScrollReveal>\n1253\t        <div className=\"mx-auto max-w-4xl text-center\">\n1254\t          <div className=\"mb-6 inline-flex items-center gap-3\">\n1255\t            <span className=\"h-px w-8 bg-teal-vivid/70\" aria-hidden=\"true\" />\n1256\t            <span className=\"font-body text-[11px] font-bold uppercase tracking-[0.22em] text-teal-vivid\">\n1257\t              {config.finalCta.eyebrow}\n1258\t            </span>\n1259\t            <span className=\"h-px w-8 bg-teal-vivid/70\" aria-hidden=\"true\" />\n1260\t          </div>\n1261\t          <h2 className=\"mb-6 font-satoshi font-bold text-white !leading-[1.04]\" style={{ fontSize: 'clamp(2rem, 3.8vw, 3.5rem)', letterSpacing: '-0.03em' }}>\n1262\t            {config.finalCta.title}\n1263\t          </h2>\n1264\t          <p className=\"mx-auto mb-9 max-w-2xl font-body text-base leading-relaxed text-white/[0.72] lg:text-[17px]\">\n1265\t            {config.finalCta.desc}\n1266\t          </p>\n1267\t          <div className=\"flex flex-col items-stretch justify-center gap-3 sm:flex-row sm:items-center\">\n1268\t            <a href=\"/diagnostic\" className=\"group inline-flex items-center justify-center gap-2 rounded-full cta-gradient py-2.5 pl-6 pr-2 font-semibold text-white\">\n1269\t              <span className=\"text-sm\">Demander un devis</span>\n1270\t              <span className=\"flex h-8 w-8 items-center justify-center rounded-full bg-white/20\">\n1271\t                <ArrowRight className=\"h-3.5 w-3.5\" />\n1272\t              </span>\n1273\t            </a>\n1274\t            <a href=\"/diagnostic\" className=\"group inline-flex items-center justify-center gap-2 rounded-full border border-white/[0.22] py-2.5 pl-6 pr-2 font-semibold text-white/[0.88]\">\n1275\t              <span className=\"text-sm\">Parler à un expert</span>\n1276\t              <span className=\"flex h-8 w-8 items-center justify-center rounded-full bg-white/[0.12]\">\n1277\t                <ArrowRight className=\"h-3.5 w-3.5\" />\n1278\t              </span>\n1279\t            </a>\n1280\t          </div>\n1281\t        </div>\n1282\t      </ScrollReveal>\n1283\t      <ul className=\"mx-auto mt-12 grid max-w-3xl gap-3 sm:grid-cols-3\">\n1284\t        {config.finalCta.reassurances.map((item, index) => {\n1285\t          const icons = [CalendarCheck, BadgeCheck, Shield];\n1286\t          const Icon = icons[index] ?? BadgeCheck;\n1287\t          return (\n1288\t            <li key={item} className=\"flex items-center justify-center gap-2.5 rounded-lg border border-white/[0.12] bg-white/[0.045] px-4 py-3\">\n1289\t              <Icon className=\"h-4 w-4 shrink-0 text-teal-vivid\" strokeWidth={1.8} />\n1290\t              <span className=\"font-body text-sm text-white/[0.76]\">{item}</span>\n1291\t            </li>\n1292\t          );\n1293\t        })}\n1294\t      </ul>\n1295\t    </div>\n1296\t  </section>\n1297\t);\n1298\t\n1299\tconst SeoContent = ({ config }: { config: SectorPageConfig }) => (\n1300\t  <section className=\"bg-cream py-16 lg:py-28\">\n1301\t    <div className=\"container mx-auto px-4 lg:px-8\">\n1302\t      <div className=\"mx-auto max-w-5xl\">\n1303\t        <p className=\"mb-5 font-body text-[10px] font-semibold uppercase tracking-[0.25em] text-primary/55\">\n1304\t          {config.seo.eyebrow}\n1305\t        </p>\n1306\t        <h2 className=\"mb-5 font-satoshi text-3xl font-bold text-foreground !leading-[1.05] lg:text-5xl\">\n1307\t          {config.seo.title}\n1308\t        </h2>\n1309\t        <p className=\"mb-12 max-w-3xl font-body text-base leading-relaxed text-foreground/64\">\n1310\t          {config.seo.intro}\n1311\t        </p>\n1312\t        <div className=\"grid gap-10 md:grid-cols-2\">\n1313\t          {config.seo.sections.map((section) => (\n1314\t            <article key={section.title}>\n1315\t              <h3 className=\"mb-3 font-satoshi text-xl font-bold text-foreground\">{section.title}</h3>\n1316\t              <p className=\"font-body text-sm leading-relaxed text-foreground/68\">{section.body}</p>\n1317\t            </article>\n1318\t          ))}\n1319\t        </div>\n1320\t        <div className=\"mt-12 border-t border-foreground/10 pt-8\">\n1321\t          <p className=\"mb-4 font-body text-[11px] font-bold uppercase tracking-[0.18em] text-foreground/38\">Sources</p>\n1322\t          <ul className=\"grid gap-2 font-body text-xs leading-relaxed text-foreground/50 md:grid-cols-2\">\n1323\t            {config.seo.sources.map((source) => (\n1324\t              <li key={source}>{source}</li>\n1325\t            ))}\n1326\t          </ul>\n1327\t        </div>\n1328\t      </div>\n1329\t    </div>\n1330\t  </section>\n1331\t);\n1332\t\n1333\texport const SectorPageTemplate = ({ config }: { config: SectorPageConfig }) => (\n1334\t  <>\n1335\t    <SectorHero config={config} />\n1336\t    <ReassuranceBand items={config.reassurance} />\n1337\t    <ProblemSection config={config} />\n1338\t    <SolutionSection config={config} />\n1339\t    <DurabilitySection config={config} />\n1340\t    <SpecialSection config={config} />\n1341\t    <BenefitsSection config={config} />\n1342\t    <ApplicationsSection config={config} />\n1343\t    <MethodSection config={config} />\n1344\t    <ProofSection config={config} />\n1345\t    <FaqSection config={config} />\n1346\t    <FinalCta config={config} />\n1347\t    <SeoContent config={config} />\n1348\t  </>\n1349\t);\n1350\t\n1351\texport const defaultIcons = {\n1352\t  Building2,\n1353\t  HelpCircle,\n1354\t  Shield,\n1355\t  Thermometer,\n1356\t  TrendingDown,\n1357\t  UsersRound,\n1358\t};\n1359\t"}]},"uuid":"89755138-4122-49cb-bf8f-183dc50c44ca","timestamp":"2026-06-26T11:54:01.196Z","toolUseResult":{"type":"text","file":{"filePath":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/src/components/industries/SectorPageTemplate.tsx","content":"\"use client\";\n\nimport { useState } from 'react';\nimport {\n  ArrowRight,\n  BadgeCheck,\n  Building2,\n  CalendarCheck,\n  CalendarClock,\n  Check,\n  CheckCircle2,\n  ClipboardCheck,\n  HelpCircle,\n  Play,\n  Shield,\n  Thermometer,\n  TrendingDown,\n  UsersRound,\n  X,\n  type LucideIcon,\n} from 'lucide-react';\nimport { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from '@/components/ui/accordion';\nimport { Dialog, DialogContent } from '@/components/ui/dialog';\nimport ScrollReveal from '@/components/ScrollReveal';\nimport SectorReferenceHighlights from '@/components/SectorReferenceHighlights';\nimport WpImage from '@/components/ui/WpImage';\nimport type { ReferenceSector, ReferenceSectorSlug } from '@/data/references';\nimport classicRoofImage from '@/assets/industrie/logistique-solution-classic.webp';\nimport coolRoofImage from '@/assets/industrie/logistique-solution-coolroof.webp';\n\n// config.*.image sont des URL string (public /images via toSectorConfig, ou\n// .src d'un import webp local en fallback). On les enveloppe en objet WpImage\n// (dimensions inconnues -> mode fill, déjà utilisé pour ces fonds object-cover).\nconst toFillImage = (src: string, alt = '') => ({\n  sourceUrl: src,\n  altText: alt,\n  width: null,\n  height: null,\n});\n\ntype Logo = {\n  name: string;\n  url?: string;\n};\n\ntype HeroStat = {\n  icon: LucideIcon;\n  value: string;\n  label: string;\n};\n\ntype Problem = {\n  icon: LucideIcon;\n  title: string;\n  desc: string;\n  image: string;\n  alt: string;\n};\n\ntype Benefit = {\n  icon: LucideIcon;\n  title: string;\n  desc: string;\n};\n\ntype Application = {\n  icon: LucideIcon;\n  label: string;\n  title: string;\n  desc: string;\n  image: string;\n};\n\ntype Figure = {\n  icon: LucideIcon;\n  value: string;\n  label: string;\n};\n\ntype CaseProof = {\n  name: string;\n  desc: string;\n};\n\nconst referenceFilterBySectorSlug: Partial<Record<string, ReferenceSector>> = {\n  industrie: 'Industrie',\n  distribution: 'Distribution',\n  logistique: 'Logistique',\n  tertiaire: 'Tertiaire',\n  collectivites: 'Collectivites',\n  agricole: 'Agricole',\n  erp: 'ERP',\n};\n\ntype Faq = {\n  q: string;\n  a: string;\n};\n\ntype SeoSection = {\n  title: string;\n  body: string;\n};\n\ntype SpecialSection =\n  | {\n      kind: 'decret';\n      eyebrow: string;\n      title: string;\n      intro: string;\n      milestones: Array<{ value: string; label: string }>;\n      points: string[];\n      note: string;\n      cta: string;\n    }\n  | {\n      kind: 'funding';\n      eyebrow: string;\n      title: string;\n      intro: string;\n      points: Array<{ value: string; label: string }>;\n      note: string;\n      cta: string;\n    };\n\nexport type SectorPageConfig = {\n  slug: string;\n  title: string;\n  description: string;\n  canonicalPath: string;\n  serviceName: string;\n  serviceDescription: string;\n  audience: string;\n  reassurance?: string[];\n  hero: {\n    eyebrow: string;\n    h1: string;\n    sub: string;\n    image: string;\n    imageAlt: string;\n    stats: HeroStat[];\n    formTitle: string;\n    formSubtitle: string;\n    formFields: {\n      typeLabel: string;\n      typeOptions: string[];\n      climateLabel: string;\n      climateOptions: string[];\n      yearLabel: string;\n      microcopy: string;\n      cta: string;\n    };\n  };\n  logos: {\n    title: string;\n    items: Logo[];\n  };\n  problem: {\n    eyebrow: string;\n    title: string;\n    mutedTitle: string;\n    intro: string;\n    transition: string;\n    cards: Problem[];\n  };\n  solution: {\n    eyebrow: string;\n    title: string;\n    mutedTitle: string;\n    intro: string;\n    points: string[];\n    transition: string;\n    beforeImage?: string;\n    afterImage?: string;\n  };\n  durability: {\n    title: string;\n    mutedTitle?: string;\n    intro: string;\n    note: string;\n    covalbaLabel: string;\n  };\n  special: SpecialSection;\n  benefits: {\n    eyebrow: string;\n    title: string;\n    desc: string;\n    metric: string;\n    metricLabel: string;\n    image: string;\n    imageAlt: string;\n    cards: Benefit[];\n    transition: string;\n  };\n  applications: {\n    eyebrow: string;\n    title: string;\n    intro: string;\n    cards: Application[];\n    transition: string;\n  };\n  method: {\n    eyebrow: string;\n    title: string;\n    mutedTitle: string;\n    intro: string;\n    steps: Array<{ title: string; text: string }>;\n    duration: string;\n  };\n  proof: {\n    eyebrow: string;\n    title: string;\n    mutedTitle: string;\n    intro: string;\n    figures: Figure[];\n    cases?: CaseProof[];\n    logos: Logo[];\n    transition: string;\n  };\n  faq: {\n    intro: string;\n    items: Faq[];\n  };\n  finalCta: {\n    eyebrow: string;\n    title: string;\n    desc: string;\n    reassurances: string[];\n  };\n  seo: {\n    eyebrow: string;\n    title: string;\n    intro: string;\n    sections: SeoSection[];\n    sources: string[];\n  };\n};\n\nconst ReassuranceBand = ({ items }: { items?: string[] }) => {\n  if (!items?.length) return null;\n\n  return (\n    <section className=\"border-y border-foreground/[0.06] bg-white py-4\">\n      <div className=\"container mx-auto px-4 lg:px-8\">\n        <ul className=\"flex flex-col items-start justify-center gap-3 font-body text-sm font-semibold text-foreground/62 sm:flex-row sm:flex-wrap sm:items-center sm:gap-x-6 sm:gap-y-2\">\n          {items.map((item) => (\n            <li key={item} className=\"flex items-center gap-2.5\">\n              <CheckCircle2 className=\"h-4 w-4 shrink-0 text-teal-vivid\" strokeWidth={1.8} />\n              <span>{item}</span>\n            </li>\n          ))}\n        </ul>\n      </div>\n    </section>\n  );\n};\n\nconst inputClass =\n  'w-full rounded-xl border border-white/[0.12] bg-white/[0.07] px-4 py-3 font-body text-sm text-white placeholder:text-white/40 transition-all duration-300 focus:border-white/25 focus:outline-none focus:ring-2 focus:ring-primary/50';\n\nconst selectClass =\n  'w-full appearance-none rounded-xl border border-white/[0.12] bg-white/[0.07] px-4 py-3 font-body text-sm text-white transition-all duration-300 focus:border-white/25 focus:outline-none focus:ring-2 focus:ring-primary/50';\n\nconst lightFieldClass =\n  'w-full rounded-xl border border-foreground/10 bg-white px-4 py-3 font-body text-sm text-foreground outline-none transition-all focus:border-teal-vivid/40 focus:ring-2 focus:ring-teal-vivid/15';\n\nconst SectorHero = ({ config }: { config: SectorPageConfig }) => {\n  const [form, setForm] = useState({ type: '', climate: '', surface: '', year: '', email: '' });\n  const [submitted, setSubmitted] = useState(false);\n  const surfaceNum = parseFloat(form.surface) || 0;\n  const estimMin = surfaceNum * 18;\n  const estimMax = surfaceNum * 25;\n  const fmt = (n: number) => new Intl.NumberFormat('fr-FR').format(n);\n\n  return (\n    <section\n      aria-labelledby={`${config.slug}-hero-title`}\n      className=\"relative isolate flex min-h-[100svh] flex-col overflow-hidden bg-navy text-cream\"\n    >\n      <WpImage\n        image={toFillImage(config.hero.image, config.hero.imageAlt)}\n        fill\n        priority\n        sizes=\"100vw\"\n        className=\"absolute inset-0 -z-10 size-full scale-[1.02] object-cover\"\n      />\n      <div\n        aria-hidden=\"true\"\n        className=\"absolute inset-0 -z-10 hidden bg-gradient-to-r from-navy/[0.92] via-navy/55 to-navy/25 lg:block\"\n      />\n      <div\n        aria-hidden=\"true\"\n        className=\"absolute inset-0 -z-10 bg-gradient-to-b from-navy/80 via-navy/22 to-navy/95 lg:hidden\"\n      />\n      <div\n        aria-hidden=\"true\"\n        className=\"absolute inset-x-0 bottom-0 -z-10 h-[28%] bg-gradient-to-t from-navy via-navy/85 to-transparent\"\n      />\n\n      <div className=\"container relative z-10 mx-auto flex flex-1 items-center px-6 pb-10 pt-24 lg:px-12 lg:pb-16 lg:pt-28\">\n        <div className=\"grid w-full grid-cols-1 items-center gap-10 lg:grid-cols-[55fr_45fr] lg:gap-12\">\n          <div className=\"max-w-2xl space-y-6 lg:space-y-8\">\n            {config.hero.eyebrow && (\n              <div className=\"flex items-center gap-3\">\n                <span className=\"h-px w-9 bg-teal-vivid\" aria-hidden=\"true\" />\n                <span className=\"font-body text-[11px] font-semibold uppercase tracking-[0.22em] text-teal-vivid\">\n                  {config.hero.eyebrow}\n                </span>\n              </div>\n            )}\n\n            <h1\n              id={`${config.slug}-hero-title`}\n              className=\"font-satoshi font-bold leading-[1.02] text-white\"\n              style={{ fontSize: 'clamp(2.25rem, 4.6vw, 4rem)', letterSpacing: '-0.03em' }}\n            >\n              {config.hero.h1}\n            </h1>\n\n            <p\n              className=\"max-w-xl font-satoshi font-medium leading-[1.3] text-cream/65\"\n              style={{ fontSize: 'clamp(1rem, 1.5vw, 1.375rem)', letterSpacing: '-0.005em' }}\n            >\n              {config.hero.sub}\n            </p>\n\n            <ul className=\"hidden gap-4 pt-1 sm:flex sm:flex-wrap lg:gap-6\" aria-label=\"Bénéfices clés\">\n              {config.hero.stats.map((stat, index) => {\n                const Icon = stat.icon;\n                return (\n                  <li\n                    key={stat.label}\n                    className={`flex items-start gap-3 ${\n                      index !== 0 ? 'sm:border-l sm:border-white/10 sm:pl-6' : ''\n                    }`}\n                  >\n                    <Icon className=\"mt-0.5 h-[18px] w-[18px] shrink-0 text-teal-vivid\" strokeWidth={1.5} />\n                    <div className=\"leading-tight\">\n                      <p className=\"font-satoshi text-[15px] font-bold text-white lg:text-base\">{stat.value}</p>\n                      <p className=\"mt-1 font-body text-[12.5px] text-cream/55 lg:text-[13px]\">{stat.label}</p>\n                    </div>\n                  </li>\n                );\n              })}\n            </ul>\n          </div>\n\n          <div className=\"animate-hero-stats\">\n            <div className=\"rounded-[1.5rem] border border-white/[0.08] bg-white/[0.04] p-1.5 backdrop-blur-sm\">\n              <div className=\"rounded-[calc(1.5rem-6px)] border border-white/[0.06] bg-[#0b1a2b]/80 p-4 shadow-[inset_0_1px_1px_rgba(255,255,255,0.06)] backdrop-blur-xl lg:p-7\">\n                {!submitted ? (\n                  <>\n                    <h2 className=\"mb-1 text-center font-satoshi text-xl font-bold text-white lg:text-2xl\">\n                      {config.hero.formTitle}\n                    </h2>\n                    <p className=\"mb-4 text-center font-body text-[12px] text-white/50\">\n                      {config.hero.formSubtitle}\n                    </p>\n                    <form\n                      onSubmit={(event) => {\n                        event.preventDefault();\n                        setSubmitted(true);\n                      }}\n                      className=\"space-y-2.5 lg:space-y-3\"\n                    >\n                      <select\n                        required\n                        value={form.type}\n                        onChange={(e) => setForm({ ...form, type: e.target.value })}\n                        className={selectClass}\n                      >\n                        <option value=\"\" disabled className=\"bg-card text-foreground\">\n                          {config.hero.formFields.typeLabel}\n                        </option>\n                        {config.hero.formFields.typeOptions.map((option) => (\n                          <option key={option} value={option} className=\"bg-card text-foreground\">\n                            {option}\n                          </option>\n                        ))}\n                      </select>\n                      <select\n                        required\n                        value={form.climate}\n                        onChange={(e) => setForm({ ...form, climate: e.target.value })}\n                        className={selectClass}\n                      >\n                        <option value=\"\" disabled className=\"bg-card text-foreground\">\n                          {config.hero.formFields.climateLabel}\n                        </option>\n                        {config.hero.formFields.climateOptions.map((option) => (\n                          <option key={option} value={option} className=\"bg-card text-foreground\">\n                            {option}\n                          </option>\n                        ))}\n                      </select>\n                      <input\n                        type=\"number\"\n                        placeholder=\"Surface toiture (m²)\"\n                        required\n                        min=\"1\"\n                        value={form.surface}\n                        onChange={(e) => setForm({ ...form, surface: e.target.value })}\n                        className={inputClass}\n                      />\n                      <input\n                        type=\"number\"\n                        placeholder={config.hero.formFields.yearLabel}\n                        required\n                        min=\"1900\"\n                        value={form.year}\n                        onChange={(e) => setForm({ ...form, year: e.target.value })}\n                        className={inputClass}\n                      />\n                      <input\n                        type=\"email\"\n                        placeholder=\"Email professionnel\"\n                        required\n                        value={form.email}\n                        onChange={(e) => setForm({ ...form, email: e.target.value })}\n                        className={inputClass}\n                      />\n\n                      <button\n                        type=\"submit\"\n                        className=\"group mt-1 flex w-full items-center justify-center gap-3 rounded-full cta-gradient py-3 font-semibold text-white active:scale-[0.98]\"\n                      >\n                        <span className=\"text-[15px]\">{config.hero.formFields.cta}</span>\n                        <span className=\"flex h-8 w-8 items-center justify-center rounded-full bg-white/20 transition-transform duration-500 group-hover:translate-x-0.5\">\n                          <ArrowRight className=\"h-4 w-4\" />\n                        </span>\n                      </button>\n                    </form>\n\n                    <p className=\"mt-3 text-center font-body text-[11px] text-white/35\">\n                      {config.hero.formFields.microcopy}\n                    </p>\n                  </>\n                ) : (\n                  <div className=\"py-4 text-center\">\n                    <div className=\"mx-auto mb-4 flex h-12 w-12 items-center justify-center rounded-full bg-primary/20\">\n                      <Shield className=\"h-6 w-6 text-primary\" />\n                    </div>\n                    <p className=\"mb-1 font-body text-sm text-white/60\">Budget indicatif pour {fmt(surfaceNum)} m²</p>\n                    <p className=\"mb-4 font-satoshi text-2xl font-bold text-white\">\n                      {fmt(estimMin)}€ - {fmt(estimMax)}€\n                    </p>\n                    <p className=\"mb-4 font-body text-[13px] text-white/50\">\n                      Un conseiller vous contacte sous 24h avec un chiffrage détaillé.\n                    </p>\n                    <button\n                      onClick={() => setSubmitted(false)}\n                      className=\"font-body text-sm font-semibold text-primary hover:underline\"\n                    >\n                      Modifier ma demande\n                    </button>\n                  </div>\n                )}\n              </div>\n            </div>\n          </div>\n        </div>\n      </div>\n\n      <div className=\"relative z-10 mt-auto hidden lg:block\">\n        <div className=\"border-t border-white/10 bg-navy/78 py-5 backdrop-blur-md\">\n          <p className=\"mb-3 text-center font-body text-[10px] font-semibold uppercase tracking-[0.2em] text-white/35\">\n            {config.logos.title}\n          </p>\n          <div className=\"mx-auto flex max-w-6xl flex-nowrap items-center justify-center gap-x-8 px-8 xl:gap-x-12\">\n            {config.logos.items.map((logo) =>\n              logo.url ? (\n                <span key={logo.name} className=\"flex h-8 w-28 items-center justify-center\">\n                  <img\n                    src={logo.url}\n                    alt={logo.name}\n                    className=\"max-h-7 max-w-full object-contain opacity-45 transition-opacity duration-300 hover:opacity-75\"\n                    style={{ filter: 'brightness(0) invert(1)' }}\n                    loading=\"lazy\"\n                    decoding=\"async\"\n                  />\n                </span>\n              ) : (\n                <span key={logo.name} className=\"flex h-8 w-28 items-center justify-center whitespace-nowrap font-satoshi text-base font-bold text-white/50 xl:text-lg\">\n                  {logo.name}\n                </span>\n              )\n            )}\n          </div>\n        </div>\n      </div>\n    </section>\n  );\n};\n\nconst ProblemSection = ({ config }: { config: SectorPageConfig }) => (\n  <section className=\"relative overflow-hidden bg-cream py-20 lg:py-32\">\n    <div className=\"container mx-auto px-4 lg:px-8\">\n      <div className=\"mb-10 grid grid-cols-1 items-end gap-8 lg:mb-16 lg:grid-cols-[1.05fr_0.95fr] lg:gap-20\">\n        <div className=\"space-y-6 lg:space-y-9\">\n          <ScrollReveal>\n            <div className=\"flex items-center gap-3\">\n              <span className=\"h-px w-9 bg-terracotta/70\" aria-hidden=\"true\" />\n              <span className=\"font-body text-[11px] font-bold uppercase tracking-[0.22em] text-terracotta-dark\">\n                {config.problem.eyebrow}\n              </span>\n            </div>\n          </ScrollReveal>\n          <ScrollReveal>\n            <h2\n              className=\"font-satoshi font-bold text-foreground !leading-[1.05]\"\n              style={{ fontSize: 'clamp(1.875rem, 3.6vw, 2.875rem)', letterSpacing: '-0.025em' }}\n            >\n              {config.problem.title}\n              <br />\n              <span className=\"text-foreground/40\">{config.problem.mutedTitle}</span>\n            </h2>\n          </ScrollReveal>\n        </div>\n        <ScrollReveal>\n          <p className=\"max-w-[560px] font-body text-base leading-relaxed text-foreground/65 lg:ml-auto lg:text-[16px]\">\n            {config.problem.intro}\n          </p>\n        </ScrollReveal>\n      </div>\n\n      <ScrollReveal stagger>\n        <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4 lg:gap-5 xl:gap-6\">\n          {config.problem.cards.map((problem) => {\n            const Icon = problem.icon;\n            return (\n              <article\n                key={problem.title}\n                className=\"group overflow-hidden rounded-2xl bg-white shadow-[0_18px_45px_-34px_hsl(var(--navy)/0.28)] ring-1 ring-foreground/[0.05]\"\n              >\n                <div className=\"relative aspect-[4/3] overflow-hidden bg-foreground/[0.04]\">\n                  <WpImage\n                    image={toFillImage(problem.image, problem.alt)}\n                    fill\n                    sizes=\"(min-width: 1024px) 25vw, (min-width: 640px) 50vw, 100vw\"\n                    className=\"size-full object-cover\"\n                  />\n                  <div aria-hidden=\"true\" className=\"absolute inset-x-0 bottom-0 h-1/2 bg-gradient-to-t from-navy/45 to-transparent\" />\n                  <span className=\"absolute left-4 top-4 flex h-10 w-10 items-center justify-center rounded-full bg-cream/90 text-terracotta-dark shadow-sm\">\n                    <Icon className=\"h-5 w-5\" strokeWidth={1.7} />\n                  </span>\n                </div>\n                <div className=\"px-6 py-7 lg:px-6 lg:py-8\">\n                  <h3 className=\"mb-3 font-satoshi text-[18px] font-bold !leading-tight text-foreground lg:text-[19px]\">\n                    {problem.title}\n                  </h3>\n                  <p className=\"font-body text-[14px] leading-relaxed text-foreground/62 lg:text-[14.5px]\">\n                    {problem.desc}\n                  </p>\n                </div>\n              </article>\n            );\n          })}\n        </div>\n      </ScrollReveal>\n\n      <ScrollReveal>\n        {config.problem.transition && (\n          <p className=\"mx-auto mt-10 max-w-3xl border-t border-foreground/10 pt-6 text-center font-body text-sm leading-relaxed text-foreground/58 lg:mt-14 lg:text-base\">\n            {config.problem.transition}\n          </p>\n        )}\n      </ScrollReveal>\n    </div>\n  </section>\n);\n\nconst SolutionSection = ({ config }: { config: SectorPageConfig }) => (\n  <section className=\"relative overflow-hidden bg-[#142333] py-20 text-white lg:py-32\">\n    <div\n      aria-hidden=\"true\"\n      className=\"absolute inset-0 opacity-[0.55]\"\n      style={{ backgroundImage: 'linear-gradient(115deg, rgba(255,255,255,0.055) 0 1px, transparent 1px 120px)' }}\n    />\n    <div className=\"container relative mx-auto px-4 lg:px-8\">\n      <ScrollReveal>\n        <div className=\"mx-auto mb-12 grid max-w-6xl grid-cols-1 items-end gap-8 lg:mb-16 lg:grid-cols-[0.88fr_1.12fr] lg:gap-16\">\n          <div>\n            <div className=\"mb-6 inline-flex items-center gap-3\">\n              <span className=\"h-px w-8 bg-teal-vivid/70\" aria-hidden=\"true\" />\n              <span className=\"font-body text-[11px] font-bold uppercase tracking-[0.22em] text-teal-vivid\">\n                {config.solution.eyebrow}\n              </span>\n            </div>\n            <h2\n              className=\"font-satoshi font-bold !leading-[1.04] text-white\"\n              style={{ fontSize: 'clamp(2rem, 3.4vw, 3rem)', letterSpacing: '-0.03em' }}\n            >\n              {config.solution.title}\n              <br />\n              <span className=\"text-white/45\">{config.solution.mutedTitle}</span>\n            </h2>\n          </div>\n          <p className=\"max-w-2xl font-body text-base leading-relaxed text-white/74 lg:text-[17px]\">\n            {config.solution.intro}\n          </p>\n        </div>\n      </ScrollReveal>\n\n      <div className=\"grid grid-cols-1 gap-5 md:grid-cols-2 lg:gap-6\">\n        {[\n          {\n            title: 'Toiture classique',\n            image: config.solution.beforeImage ?? classicRoofImage.src,\n            metric: \"jusqu'à 80°C\",\n            metricLabel: 'en surface',\n            points: ['Surface sombre', 'Absorbe la chaleur', 'Alourdit la climatisation'],\n            cool: false,\n          },\n          {\n            title: 'Toiture cool roof',\n            image: config.solution.afterImage ?? coolRoofImage.src,\n            metric: \"jusqu'à 90%\",\n            metricLabel: 'du rayonnement réfléchi',\n            points: ['Surface claire', 'Reste plus fraîche', 'Réduit la charge thermique'],\n            cool: true,\n          },\n        ].map((item) => (\n          <article key={item.title} className=\"overflow-hidden rounded-2xl border border-white/10 bg-white/[0.045]\">\n            <div className=\"relative aspect-[1.1] overflow-hidden bg-[#0f1d2a] md:aspect-[1.18]\">\n              <WpImage\n                image={toFillImage(item.image, item.title)}\n                fill\n                sizes=\"(min-width: 768px) 50vw, 100vw\"\n                className=\"size-full object-cover\"\n              />\n              <div aria-hidden=\"true\" className=\"absolute inset-x-0 bottom-0 h-2/3 bg-gradient-to-t from-[#142333] via-[#142333]/20 to-transparent\" />\n            </div>\n            <div className=\"p-5 lg:p-7\">\n              <div className=\"mb-6 flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between\">\n                <h3 className=\"font-satoshi text-xl font-bold !leading-tight text-white lg:text-2xl\">\n                  {item.title}\n                </h3>\n                <div className={`shrink-0 rounded-xl border px-4 py-3 ${item.cool ? 'border-teal-vivid/18 bg-teal-vivid/10 text-teal-vivid' : 'border-terracotta/18 bg-terracotta/12 text-[#f0a084]'}`}>\n                  <span className=\"block font-satoshi text-2xl font-bold leading-none lg:text-3xl\">{item.metric}</span>\n                  <span className=\"mt-1 block font-body text-[10px] font-bold uppercase tracking-[0.14em] opacity-75\">\n                    {item.metricLabel}\n                  </span>\n                </div>\n              </div>\n              <ul className=\"grid gap-2.5\">\n                {item.points.map((point) => (\n                  <li key={point} className=\"flex items-start gap-2.5\">\n                    <CheckCircle2 className={`mt-0.5 h-4 w-4 shrink-0 ${item.cool ? 'text-teal-vivid' : 'text-[#f0a084]'}`} strokeWidth={2} />\n                    <span className=\"font-body text-sm leading-relaxed text-white/66\">{point}</span>\n                  </li>\n                ))}\n              </ul>\n            </div>\n          </article>\n        ))}\n      </div>\n\n      {(config.solution.points.length > 0 || config.solution.transition) && (\n        <ScrollReveal>\n          <div className=\"mx-auto mt-10 max-w-6xl lg:mt-14\">\n            {config.solution.points.length > 0 && (\n              <ul className=\"grid grid-cols-1 gap-3 md:grid-cols-4\">\n                {config.solution.points.map((point) => (\n                  <li key={point} className=\"flex items-center gap-3 rounded-xl border border-white/10 bg-white/[0.055] px-5 py-4\">\n                    <span className=\"flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-teal-vivid/12\">\n                      <Check className=\"h-4 w-4 text-teal-vivid\" strokeWidth={1.8} />\n                    </span>\n                    <span className=\"font-body text-sm font-semibold leading-snug text-white/78\">{point}</span>\n                  </li>\n                ))}\n              </ul>\n            )}\n            {config.solution.transition && (\n              <p className=\"mx-auto mt-8 max-w-2xl text-center font-body text-sm leading-relaxed text-white/52\">\n                {config.solution.transition}\n              </p>\n            )}\n          </div>\n        </ScrollReveal>\n      )}\n    </div>\n  </section>\n);\n\nconst DurabilitySection = ({ config }: { config: SectorPageConfig }) => (\n  <section className=\"relative overflow-hidden bg-[#F6FAFB] py-16 lg:py-28\">\n    <div className=\"container mx-auto px-4 lg:px-8\">\n      <ScrollReveal>\n        <div className=\"mx-auto mb-12 max-w-2xl text-center lg:mb-16\">\n          <p className=\"mb-5 font-body text-[10px] font-semibold uppercase tracking-[0.25em] text-primary/55\">\n            Durabilité\n          </p>\n          <h2\n            className=\"mb-5 font-satoshi font-bold text-foreground !leading-[1.05]\"\n            style={{ fontSize: 'clamp(2rem, 3.2vw, 2.85rem)', letterSpacing: '-0.03em' }}\n          >\n            {config.durability.title}\n            {config.durability.mutedTitle && (\n              <>\n                <br />\n                <span className=\"text-foreground/35\">{config.durability.mutedTitle}</span>\n              </>\n            )}\n          </h2>\n          <p className=\"font-body text-base leading-relaxed text-foreground/62 lg:text-[17px]\">\n            {config.durability.intro}\n          </p>\n        </div>\n      </ScrollReveal>\n\n      <ScrollReveal>\n        <div className=\"mx-auto grid max-w-5xl grid-cols-1 items-stretch gap-5 lg:grid-cols-2 lg:gap-0\">\n          {[\n            {\n              title: 'Revêtement acrylique standard',\n              subtitle: 'Prix bas à la pose',\n              price: '~10 €',\n              life: '2-5 ans',\n              realCost: '25-30 €',\n              covalba: false,\n              points: ['Réflectivité qui baisse vite', 'Farinage et jaunissement', 'Réapplication plus fréquente'],\n            },\n            {\n              title: 'Système polyuréthane Covalba',\n              subtitle: config.durability.covalbaLabel,\n              price: '18-20 €',\n              life: '8-10 ans',\n              realCost: '18-20 €',\n              covalba: true,\n              points: ['Résine polyuréthane durable', 'Vernis de finition anti-UV', 'Réflectivité conservée plus longtemps'],\n            },\n          ].map((option) => (\n            <article\n              key={option.title}\n              className={`relative rounded-2xl px-7 py-9 shadow-[0_20px_60px_rgba(26,42,58,0.08)] lg:px-10 lg:py-12 ${\n                option.covalba ? 'z-10 bg-foreground text-white lg:-ml-5 lg:scale-[1.03]' : 'bg-white text-foreground lg:scale-[0.97] lg:opacity-90'\n              }`}\n            >\n              {option.covalba && (\n                <span className=\"absolute -top-4 left-1/2 inline-flex -translate-x-1/2 items-center rounded-full bg-teal-vivid px-4 py-2 font-body text-[11px] font-bold uppercase tracking-[0.15em] text-white\">\n                  Le choix durable\n                </span>\n              )}\n              <h3 className=\"mb-2 font-satoshi text-2xl font-bold leading-tight lg:text-[1.7rem]\">{option.title}</h3>\n              <p className={`mb-8 font-body text-sm ${option.covalba ? 'text-white/52' : 'text-foreground/50'}`}>\n                {option.subtitle}\n              </p>\n              <div className=\"mb-8 grid grid-cols-3 gap-4\">\n                {[\n                  ['Prix au m²', option.price],\n                  ['Tenue', option.life],\n                  ['10 ans', option.realCost],\n                ].map(([label, value]) => (\n                  <div key={label}>\n                    <p className={`mb-1 font-body text-[10px] uppercase tracking-widest ${option.covalba ? 'text-white/42' : 'text-foreground/38'}`}>\n                      {label}\n                    </p>\n                    <p className={`font-satoshi text-2xl font-bold leading-none lg:text-3xl ${label === '10 ans' ? (option.covalba ? 'text-teal-vivid' : 'text-terracotta') : ''}`}>\n                      {value}\n                    </p>\n                  </div>\n                ))}\n              </div>\n              <ul className=\"space-y-3 border-t border-current/10 pt-7\">\n                {option.points.map((point) => {\n                  const Icon = option.covalba ? Check : X;\n                  return (\n                    <li key={point} className=\"flex items-start gap-2.5\">\n                      <Icon className={`mt-0.5 h-4 w-4 shrink-0 ${option.covalba ? 'text-teal-vivid' : 'text-terracotta/70'}`} />\n                      <span className={`font-body text-sm leading-relaxed ${option.covalba ? 'text-white/70' : 'text-foreground/60'}`}>\n                        {point}\n                      </span>\n                    </li>\n                  );\n                })}\n              </ul>\n            </article>\n          ))}\n        </div>\n      </ScrollReveal>\n\n      <ScrollReveal>\n        <p className=\"mx-auto mt-10 max-w-3xl text-center font-body text-sm leading-relaxed text-foreground/55 lg:text-[15px]\">\n          {config.durability.note}\n        </p>\n      </ScrollReveal>\n    </div>\n  </section>\n);\n\nconst SpecialSection = ({ config }: { config: SectorPageConfig }) => {\n  const [submitted, setSubmitted] = useState(false);\n  const isFunding = config.special.kind === 'funding';\n\n  return (\n    <section className=\"relative overflow-hidden bg-white py-16 lg:py-28\">\n      <div className=\"container mx-auto px-4 lg:px-8\">\n        <ScrollReveal>\n          <div className=\"mx-auto mb-10 grid max-w-6xl grid-cols-1 items-end gap-7 lg:mb-14 lg:grid-cols-[0.9fr_1.1fr] lg:gap-16\">\n            <div>\n              <div className=\"mb-5 flex items-center gap-3\">\n                <span className=\"h-px w-10 bg-teal-vivid\" aria-hidden=\"true\" />\n                <span className=\"font-body text-[11px] font-bold uppercase tracking-[0.22em] text-teal-vivid\">\n                  {config.special.eyebrow}\n                </span>\n              </div>\n              <h2\n                className=\"font-satoshi font-bold !leading-[1.04] text-foreground\"\n                style={{ fontSize: 'clamp(1.95rem, 3vw, 2.75rem)', letterSpacing: '-0.03em' }}\n              >\n                {config.special.title}\n              </h2>\n            </div>\n            <p className=\"max-w-2xl font-body text-base leading-relaxed text-foreground/68 lg:text-[16px]\">\n              {config.special.intro}\n            </p>\n          </div>\n        </ScrollReveal>\n\n        <div className=\"mx-auto grid max-w-6xl grid-cols-1 gap-5 lg:grid-cols-[0.82fr_1.18fr] lg:gap-7\">\n          <ScrollReveal>\n            <div className=\"h-full rounded-2xl bg-cream/70 p-6 ring-1 ring-foreground/[0.06] lg:p-7\">\n              {!submitted ? (\n                <>\n                  <h3 className=\"mb-5 font-satoshi text-xl font-bold leading-tight text-foreground\">\n                    {isFunding ? 'Vérifier mon éligibilité' : 'Estimer mon gain'}\n                  </h3>\n                  <form\n                    className=\"grid gap-3\"\n                    onSubmit={(event) => {\n                      event.preventDefault();\n                      setSubmitted(true);\n                    }}\n                  >\n                    <select required className={lightFieldClass} defaultValue=\"\">\n                      <option value=\"\" disabled>\n                        Type de bâtiment\n                      </option>\n                      {config.hero.formFields.typeOptions.map((option) => (\n                        <option key={option}>{option}</option>\n                      ))}\n                    </select>\n                    <input required min=\"1\" type=\"number\" className={lightFieldClass} placeholder=\"Surface toiture (m²)\" />\n                    <input required type=\"email\" className={lightFieldClass} placeholder=\"Email professionnel\" />\n                    <button className=\"group mt-1 inline-flex items-center justify-center gap-2 rounded-full bg-teal-vivid py-2.5 pl-6 pr-2 font-semibold text-white\">\n                      <span className=\"text-sm\">{config.special.cta}</span>\n                      <span className=\"flex h-8 w-8 items-center justify-center rounded-full bg-white/20 transition-transform duration-500 group-hover:translate-x-0.5\">\n                        <ArrowRight className=\"h-3.5 w-3.5\" />\n                      </span>\n                    </button>\n                  </form>\n                </>\n              ) : (\n                <div className=\"flex min-h-[260px] flex-col items-center justify-center text-center\">\n                  <CheckCircle2 className=\"mb-4 h-12 w-12 text-teal-vivid\" strokeWidth={1.7} />\n                  <h3 className=\"mb-3 font-satoshi text-2xl font-bold text-foreground\">Demande reçue.</h3>\n                  <p className=\"max-w-sm font-body text-sm leading-relaxed text-foreground/62\">\n                    Covalba revient vers vous avec une réponse personnalisée.\n                  </p>\n                </div>\n              )}\n            </div>\n          </ScrollReveal>\n\n          <ScrollReveal>\n            <div className=\"rounded-2xl bg-foreground p-6 text-white lg:p-8\">\n              {config.special.kind === 'decret' ? (\n                <div className=\"grid gap-4 sm:grid-cols-3\">\n                  {config.special.milestones.map((milestone) => (\n                    <div key={milestone.value} className=\"rounded-xl border border-white/10 bg-white/[0.04] p-5\">\n                      <p className=\"font-satoshi text-4xl font-bold leading-none text-teal-vivid\">{milestone.value}</p>\n                      <p className=\"mt-3 font-body text-sm text-white/62\">{milestone.label}</p>\n                    </div>\n                  ))}\n                </div>\n              ) : (\n                <div className=\"grid gap-4 sm:grid-cols-2\">\n                  {config.special.points.map((point) => (\n                    <div key={point.label} className=\"rounded-xl border border-white/10 bg-white/[0.04] p-5\">\n                      <p className=\"font-satoshi text-3xl font-bold leading-none text-teal-vivid\">{point.value}</p>\n                      <p className=\"mt-3 font-body text-sm text-white/62\">{point.label}</p>\n                    </div>\n                  ))}\n                </div>\n              )}\n              {config.special.kind === 'decret' && (\n                <div className=\"mt-6 grid gap-3\">\n                  {config.special.points.map((point) => (\n                    <div key={point} className=\"flex items-start gap-3\">\n                      <CheckCircle2 className=\"mt-0.5 h-4 w-4 shrink-0 text-teal-vivid\" />\n                      <span className=\"font-body text-sm leading-relaxed text-white/68\">{point}</span>\n                    </div>\n                  ))}\n                </div>\n              )}\n            </div>\n            <p className=\"mt-5 rounded-2xl bg-cream/70 p-5 font-body text-xs leading-relaxed text-foreground/58 lg:text-[13px]\">\n              {config.special.note}\n            </p>\n          </ScrollReveal>\n        </div>\n      </div>\n    </section>\n  );\n};\n\nconst BenefitsSection = ({ config }: { config: SectorPageConfig }) => (\n  <>\n    <section className=\"relative overflow-hidden bg-cream pb-12 pt-16 lg:min-h-[640px] lg:pb-8 lg:pt-20\">\n      <figure className=\"absolute right-0 top-0 hidden h-full min-h-[640px] w-[58vw] overflow-hidden lg:block\">\n        <WpImage\n          image={toFillImage(config.benefits.image)}\n          alt=\"\"\n          fill\n          sizes=\"58vw\"\n          className=\"size-full object-cover\"\n        />\n        <div aria-hidden=\"true\" className=\"absolute inset-y-0 left-0 w-[56%] bg-gradient-to-r from-cream via-cream/88 to-transparent\" />\n      </figure>\n      <div className=\"container relative z-10 mx-auto px-4 lg:px-8\">\n        <ScrollReveal>\n          <div className=\"max-w-[760px]\">\n            <div className=\"mb-5 flex items-center gap-3 lg:mb-7\">\n              <span className=\"h-px w-10 bg-primary/70\" aria-hidden=\"true\" />\n              <span className=\"font-body text-[11px] font-bold uppercase tracking-[0.22em] text-primary\">\n                {config.benefits.eyebrow}\n              </span>\n            </div>\n            <h2\n              className=\"mb-6 font-satoshi font-bold !leading-[1.04] text-foreground\"\n              style={{ fontSize: 'clamp(2.15rem, 3vw, 3rem)' }}\n            >\n              {config.benefits.title}\n            </h2>\n            <p className=\"max-w-[540px] font-body text-base leading-relaxed text-foreground/72 lg:text-[16px]\">\n              {config.benefits.desc}\n            </p>\n            <div className=\"relative z-10 mt-7 max-w-[540px] rounded-2xl bg-white/96 p-6 shadow-[0_22px_70px_-45px_hsl(var(--navy)/0.35)] ring-1 ring-foreground/[0.05]\">\n              <div className=\"grid grid-cols-[48px_minmax(0,1fr)] items-center gap-5\">\n                <Thermometer className=\"h-12 w-12 text-primary\" strokeWidth={1.55} />\n                <div>\n                  <p className=\"mb-3 font-body text-[11px] font-bold uppercase tracking-[0.22em] text-primary\">\n                    Dès le premier été\n                  </p>\n                  <p className=\"font-satoshi text-[3.1rem] font-bold leading-[0.88] text-primary\">{config.benefits.metric}</p>\n                  <p className=\"mt-2 font-satoshi text-xl font-bold leading-tight text-foreground\">{config.benefits.metricLabel}</p>\n                </div>\n              </div>\n            </div>\n          </div>\n        </ScrollReveal>\n      </div>\n    </section>\n\n    <section className=\"relative overflow-hidden bg-white py-14\">\n      <div className=\"container relative mx-auto px-4 lg:px-8\">\n        <ScrollReveal stagger>\n          <div className=\"grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-5 lg:gap-4\">\n            {config.benefits.cards.map((benefit, index) => {\n              const Icon = benefit.icon;\n              return (\n                <article key={benefit.title} className=\"min-h-[184px] rounded-2xl bg-cream/65 p-5 ring-1 ring-foreground/[0.05] lg:p-6\">\n                  <div className=\"mb-7 flex h-11 w-11 items-center justify-center rounded-xl bg-white text-primary\">\n                    <Icon className=\"h-5 w-5\" strokeWidth={1.55} />\n                  </div>\n                  <span className=\"mb-3 block font-body text-[11px] font-bold uppercase tracking-[0.18em] text-primary/70\">\n                    0{index + 1}\n                  </span>\n                  <h3 className=\"font-satoshi text-lg font-bold leading-tight text-foreground lg:text-[19px]\">{benefit.title}</h3>\n                  <p className=\"mt-2 font-body text-sm leading-snug text-foreground/62\">{benefit.desc}</p>\n                </article>\n              );\n            })}\n          </div>\n        </ScrollReveal>\n        <p className=\"mx-auto mt-10 max-w-2xl text-center font-body text-sm leading-relaxed text-foreground/54\">\n          {config.benefits.transition}\n        </p>\n      </div>\n    </section>\n  </>\n);\n\nconst ApplicationsSection = ({ config }: { config: SectorPageConfig }) => (\n  <section className=\"relative overflow-hidden bg-cream py-16 lg:py-24\">\n    <div className=\"container relative mx-auto px-4 lg:px-8\">\n      <ScrollReveal>\n        <div className=\"mx-auto mb-10 grid max-w-6xl grid-cols-1 gap-6 lg:mb-12 lg:grid-cols-[0.9fr_1.1fr] lg:items-end lg:gap-16\">\n          <div>\n            <div className=\"mb-5 flex items-center gap-3\">\n              <span className=\"h-px w-10 bg-primary/70\" aria-hidden=\"true\" />\n              <span className=\"font-body text-[11px] font-bold uppercase tracking-[0.22em] text-primary\">\n                {config.applications.eyebrow}\n              </span>\n            </div>\n            <h2\n              className=\"font-satoshi font-bold !leading-[1.05] text-foreground\"\n              style={{ fontSize: 'clamp(2rem, 3vw, 3rem)' }}\n            >\n              {config.applications.title}\n            </h2>\n          </div>\n          <p className=\"max-w-[540px] border-l border-primary/30 pl-6 font-body text-base leading-relaxed text-foreground/68 lg:text-[16px]\">\n            {config.applications.intro}\n          </p>\n        </div>\n      </ScrollReveal>\n      <ScrollReveal stagger>\n        <div className=\"mx-auto grid max-w-6xl grid-cols-1 gap-4 lg:grid-cols-5 lg:gap-5\">\n          {config.applications.cards.map((card, index) => {\n            const Icon = card.icon;\n            return (\n              <article key={card.title} className=\"overflow-hidden rounded-2xl bg-white shadow-[0_16px_46px_-38px_hsl(var(--navy)/0.34)] ring-1 ring-foreground/[0.06]\">\n                <div className=\"relative aspect-[4/3] overflow-hidden bg-foreground/[0.04]\">\n                  <WpImage\n                    image={toFillImage(card.image)}\n                    alt=\"\"\n                    fill\n                    sizes=\"(min-width: 1024px) 20vw, 100vw\"\n                    className=\"size-full object-cover\"\n                  />\n                </div>\n                <div className=\"p-5\">\n                  <div className=\"mb-4 flex items-center justify-between gap-3\">\n                    <span className=\"inline-flex items-center gap-2 font-body text-[11px] font-bold uppercase tracking-[0.18em] text-primary\">\n                      <Icon className=\"h-5 w-5\" strokeWidth={1.55} />\n                      {card.label}\n                    </span>\n                    <span className=\"font-body text-xs font-bold text-foreground/22\">0{index + 1}</span>\n                  </div>\n                  <h3 className=\"font-satoshi text-xl font-bold leading-tight text-foreground\">{card.title}</h3>\n                  <p className=\"mt-2 font-body text-sm leading-snug text-foreground/60\">{card.desc}</p>\n                </div>\n              </article>\n            );\n          })}\n        </div>\n      </ScrollReveal>\n      {config.applications.transition && (\n        <p className=\"mx-auto mt-10 max-w-2xl text-center font-body text-sm leading-relaxed text-foreground/54\">\n          {config.applications.transition}\n        </p>\n      )}\n    </div>\n  </section>\n);\n\nconst MethodSection = ({ config }: { config: SectorPageConfig }) => {\n  const [videoOpen, setVideoOpen] = useState(false);\n  const icons = [ClipboardCheck, CalendarClock, Shield, TrendingDown];\n  return (\n    <section className=\"bg-white py-16 lg:py-32\">\n      <div className=\"container mx-auto px-4 lg:px-8\">\n        <div className=\"flex flex-col items-start gap-12 lg:flex-row lg:gap-20\">\n          <div className=\"lg:sticky lg:top-[120px] lg:w-[40%]\">\n            <ScrollReveal>\n              <p className=\"mb-6 font-body text-[10px] font-semibold uppercase tracking-[0.25em] text-primary/50\">\n                {config.method.eyebrow}\n              </p>\n              <h2\n                className=\"mb-6 font-satoshi text-3xl font-bold text-foreground !leading-[1.05] sm:text-4xl lg:text-[3rem]\"\n                style={{ letterSpacing: '-0.03em' }}\n              >\n                {config.method.title}\n                <span className=\"text-foreground/30\"> {config.method.mutedTitle}</span>\n              </h2>\n              <p className=\"mb-8 font-body text-base leading-relaxed text-muted-foreground lg:text-lg\">\n                {config.method.intro}\n              </p>\n              <button onClick={() => setVideoOpen(true)} className=\"group flex items-center gap-3 text-primary\">\n                <div className=\"flex h-12 w-12 items-center justify-center rounded-full bg-primary/10\">\n                  <Play className=\"h-5 w-5\" />\n                </div>\n                <span className=\"font-body text-sm font-semibold\">Voir un chantier en 2 minutes</span>\n              </button>\n            </ScrollReveal>\n          </div>\n          <div className=\"relative lg:w-[60%]\">\n            <div className=\"absolute bottom-4 left-5 top-4 w-px bg-gradient-to-b from-primary/25 via-primary/10 to-transparent lg:left-6\" />\n            {config.method.steps.map((step, index) => {\n              const Icon = icons[index] ?? ClipboardCheck;\n              return (\n                <ScrollReveal key={step.title}>\n                  <div className=\"group relative flex items-start gap-5 py-8 lg:gap-7 lg:py-10\">\n                    <div className=\"relative z-10 flex h-10 w-10 shrink-0 items-center justify-center rounded-full border border-primary/20 bg-primary/10 lg:h-12 lg:w-12\">\n                      <Icon className=\"h-4 w-4 text-primary lg:h-5 lg:w-5\" />\n                    </div>\n                    <div className=\"pt-1\">\n                      <span className=\"mb-2 block font-body text-xs font-bold uppercase tracking-widest text-primary/50\">\n                        Étape 0{index + 1}\n                      </span>\n                      <h3 className=\"mb-2 text-xl text-foreground lg:text-2xl\">{step.title}</h3>\n                      <p className=\"max-w-md font-body text-sm leading-relaxed text-muted-foreground lg:text-base\">{step.text}</p>\n                    </div>\n                  </div>\n                  {index < config.method.steps.length - 1 && <div className=\"ml-5 h-px bg-border lg:ml-6\" />}\n                </ScrollReveal>\n              );\n            })}\n            <p className=\"ml-16 mt-4 font-body text-xs font-medium text-muted-foreground/50 lg:ml-20\">\n              {config.method.duration}\n            </p>\n          </div>\n        </div>\n      </div>\n      <Dialog open={videoOpen} onOpenChange={setVideoOpen}>\n        <DialogContent className=\"max-w-4xl overflow-hidden border-none bg-black p-0\">\n          <div className=\"aspect-video\">\n            <iframe\n              src=\"https://www.youtube.com/embed/9HOB5OVH0Ac?autoplay=1\"\n              className=\"h-full w-full\"\n              allow=\"autoplay; encrypted-media\"\n              allowFullScreen\n              title=\"Covalba Cool Roof, un chantier en 2 minutes\"\n            />\n          </div>\n        </DialogContent>\n      </Dialog>\n    </section>\n  );\n};\n\nconst ProofSection = ({ config }: { config: SectorPageConfig }) => (\n  <section className=\"relative overflow-hidden bg-[#192A3A] py-24 lg:py-36\">\n    <div className=\"container relative mx-auto px-4 lg:px-8\">\n      <ScrollReveal>\n        <div className=\"mb-9 flex items-center gap-3 lg:mb-12\">\n          <span className=\"h-px w-12 bg-teal-vivid/70\" aria-hidden=\"true\" />\n          <span className=\"font-body text-[11px] font-bold uppercase tracking-[0.22em] text-teal-vivid\">\n            {config.proof.eyebrow}\n          </span>\n        </div>\n        <div className=\"mb-14 grid grid-cols-1 items-start gap-8 lg:mb-20 lg:grid-cols-[3fr_2fr] lg:gap-16\">\n          <h2\n            className=\"font-satoshi font-bold text-white !leading-[1.05]\"\n            style={{ fontSize: 'clamp(1.875rem, 3.8vw, 3rem)', letterSpacing: '-0.03em' }}\n          >\n            {config.proof.title}\n            <br />\n            <span className=\"text-teal-vivid\">{config.proof.mutedTitle}</span>\n          </h2>\n          <p className=\"max-w-[470px] font-body text-base leading-relaxed text-white/65 lg:mt-2 lg:text-[16px]\">\n            {config.proof.intro}\n          </p>\n        </div>\n      </ScrollReveal>\n      <ScrollReveal stagger>\n        <div className=\"mb-12 grid grid-cols-1 gap-4 md:grid-cols-3 lg:gap-5\">\n          {config.proof.figures.map((figure) => {\n            const Icon = figure.icon;\n            return (\n              <div key={figure.label} className=\"rounded-2xl border border-white/10 bg-white/[0.04] p-8 lg:p-9\">\n                <div className=\"mb-6 flex h-11 w-11 items-center justify-center rounded-full bg-teal-vivid/[0.12]\">\n                  <Icon className=\"h-5 w-5 text-teal-vivid\" strokeWidth={1.6} />\n                </div>\n                <p className=\"mb-3 font-satoshi text-4xl font-bold leading-none text-white\">{figure.value}</p>\n                <p className=\"font-body text-sm leading-relaxed text-white/60\">{figure.label}</p>\n              </div>\n            );\n          })}\n        </div>\n      </ScrollReveal>\n      <ScrollReveal>\n        <SectorReferenceHighlights\n          sector={config.slug as ReferenceSectorSlug}\n          referenceFilter={referenceFilterBySectorSlug[config.slug] ?? 'Tous'}\n          title=\"Des cas clients pour vous projeter.\"\n          variant=\"dark\"\n        />\n      </ScrollReveal>\n      {config.proof.cases && (\n        <div className=\"mb-12 grid gap-4 md:grid-cols-2\">\n          {config.proof.cases.map((item) => (\n            <div key={item.name} className=\"rounded-2xl border border-white/10 bg-white/[0.04] p-6\">\n              <h3 className=\"mb-2 font-satoshi text-xl font-bold text-white\">{item.name}</h3>\n              <p className=\"font-body text-sm leading-relaxed text-white/60\">{item.desc}</p>\n            </div>\n          ))}\n        </div>\n      )}\n      <div className=\"border-t border-white/10 pt-10\">\n        <div className=\"flex flex-wrap items-center justify-center gap-x-10 gap-y-7 lg:gap-x-14\">\n          {config.proof.logos.map((logo) =>\n            logo.url ? (\n              <span key={logo.name} className=\"flex h-8 w-28 items-center justify-center\">\n                <img\n                  src={logo.url}\n                  alt={logo.name}\n                  className=\"max-h-7 max-w-full object-contain opacity-45\"\n                  style={{ filter: 'brightness(0) invert(1)' }}\n                  loading=\"lazy\"\n                  decoding=\"async\"\n                />\n              </span>\n            ) : (\n              <span key={logo.name} className=\"flex h-8 w-28 items-center justify-center font-satoshi text-lg font-bold text-white/50\">{logo.name}</span>\n            )\n          )}\n        </div>\n        <p className=\"mx-auto mt-9 max-w-2xl text-center font-body text-sm leading-relaxed text-white/70\">\n          {config.proof.transition}\n        </p>\n      </div>\n    </div>\n  </section>\n);\n\nconst FaqSection = ({ config }: { config: SectorPageConfig }) => (\n  <section className=\"bg-cream py-20 lg:py-32\">\n    <div className=\"container mx-auto px-4 lg:px-8\">\n      <ScrollReveal>\n        <div className=\"grid items-start gap-10 lg:grid-cols-[0.85fr_1.15fr] lg:gap-16\">\n          <div className=\"lg:sticky lg:top-24\">\n            <div className=\"mb-5 flex items-center gap-3\">\n              <span className=\"h-px w-10 bg-primary/70\" aria-hidden=\"true\" />\n              <span className=\"font-body text-[11px] font-bold uppercase tracking-[0.22em] text-primary\">FAQ</span>\n            </div>\n            <h2 className=\"mb-5 font-satoshi font-bold text-foreground !leading-[1.05]\" style={{ fontSize: 'clamp(2rem, 3.3vw, 3rem)', letterSpacing: '-0.03em' }}>\n              Vos questions,\n              <br />\n              <span className=\"text-foreground/40\">nos réponses.</span>\n            </h2>\n            <p className=\"max-w-[420px] font-body text-base leading-relaxed text-foreground/65 lg:text-[15.5px]\">\n              {config.faq.intro}\n            </p>\n            <a href={`#contact-${config.slug}`} className=\"group mt-8 inline-flex items-center gap-2 text-sm font-semibold text-primary\">\n              Une autre question ? Parlons-en\n              <ArrowRight className=\"h-4 w-4\" />\n            </a>\n          </div>\n          <Accordion type=\"single\" collapsible className=\"space-y-3\">\n            {config.faq.items.map((faq, index) => (\n              <AccordionItem key={faq.q} value={`${config.slug}-faq-${index}`} className=\"rounded-xl border border-foreground/[0.06] bg-white px-5 shadow-[0_12px_34px_rgba(24,42,58,0.04)] lg:px-6\">\n                <AccordionTrigger className=\"py-5 text-left font-satoshi text-base font-bold text-foreground hover:no-underline lg:text-[17px]\">\n                  {faq.q}\n                </AccordionTrigger>\n                <AccordionContent className=\"pb-5 font-body text-[14.5px] leading-relaxed text-foreground/67 lg:text-[15px]\">\n                  {faq.a}\n                </AccordionContent>\n              </AccordionItem>\n            ))}\n          </Accordion>\n        </div>\n      </ScrollReveal>\n    </div>\n  </section>\n);\n\nconst FinalCta = ({ config }: { config: SectorPageConfig }) => (\n  <section id={`contact-${config.slug}`} className=\"overflow-hidden bg-[#182A3A] py-20 lg:py-32\">\n    <div className=\"container mx-auto px-4 lg:px-8\">\n      <ScrollReveal>\n        <div className=\"mx-auto max-w-4xl text-center\">\n          <div className=\"mb-6 inline-flex items-center gap-3\">\n            <span className=\"h-px w-8 bg-teal-vivid/70\" aria-hidden=\"true\" />\n            <span className=\"font-body text-[11px] font-bold uppercase tracking-[0.22em] text-teal-vivid\">\n              {config.finalCta.eyebrow}\n            </span>\n            <span className=\"h-px w-8 bg-teal-vivid/70\" aria-hidden=\"true\" />\n          </div>\n          <h2 className=\"mb-6 font-satoshi font-bold text-white !leading-[1.04]\" style={{ fontSize: 'clamp(2rem, 3.8vw, 3.5rem)', letterSpacing: '-0.03em' }}>\n            {config.finalCta.title}\n          </h2>\n          <p className=\"mx-auto mb-9 max-w-2xl font-body text-base leading-relaxed text-white/[0.72] lg:text-[17px]\">\n            {config.finalCta.desc}\n          </p>\n          <div className=\"flex flex-col items-stretch justify-center gap-3 sm:flex-row sm:items-center\">\n            <a href=\"/diagnostic\" className=\"group inline-flex items-center justify-center gap-2 rounded-full cta-gradient py-2.5 pl-6 pr-2 font-semibold text-white\">\n              <span className=\"text-sm\">Demander un devis</span>\n              <span className=\"flex h-8 w-8 items-center justify-center rounded-full bg-white/20\">\n                <ArrowRight className=\"h-3.5 w-3.5\" />\n              </span>\n            </a>\n            <a href=\"/diagnostic\" className=\"group inline-flex items-center justify-center gap-2 rounded-full border border-white/[0.22] py-2.5 pl-6 pr-2 font-semibold text-white/[0.88]\">\n              <span className=\"text-sm\">Parler à un expert</span>\n              <span className=\"flex h-8 w-8 items-center justify-center rounded-full bg-white/[0.12]\">\n                <ArrowRight className=\"h-3.5 w-3.5\" />\n              </span>\n            </a>\n          </div>\n        </div>\n      </ScrollReveal>\n      <ul className=\"mx-auto mt-12 grid max-w-3xl gap-3 sm:grid-cols-3\">\n        {config.finalCta.reassurances.map((item, index) => {\n          const icons = [CalendarCheck, BadgeCheck, Shield];\n          const Icon = icons[index] ?? BadgeCheck;\n          return (\n            <li key={item} className=\"flex items-center justify-center gap-2.5 rounded-lg border border-white/[0.12] bg-white/[0.045] px-4 py-3\">\n              <Icon className=\"h-4 w-4 shrink-0 text-teal-vivid\" strokeWidth={1.8} />\n              <span className=\"font-body text-sm text-white/[0.76]\">{item}</span>\n            </li>\n          );\n        })}\n      </ul>\n    </div>\n  </section>\n);\n\nconst SeoContent = ({ config }: { config: SectorPageConfig }) => (\n  <section className=\"bg-cream py-16 lg:py-28\">\n    <div className=\"container mx-auto px-4 lg:px-8\">\n      <div className=\"mx-auto max-w-5xl\">\n        <p className=\"mb-5 font-body text-[10px] font-semibold uppercase tracking-[0.25em] text-primary/55\">\n          {config.seo.eyebrow}\n        </p>\n        <h2 className=\"mb-5 font-satoshi text-3xl font-bold text-foreground !leading-[1.05] lg:text-5xl\">\n          {config.seo.title}\n        </h2>\n        <p className=\"mb-12 max-w-3xl font-body text-base leading-relaxed text-foreground/64\">\n          {config.seo.intro}\n        </p>\n        <div className=\"grid gap-10 md:grid-cols-2\">\n          {config.seo.sections.map((section) => (\n            <article key={section.title}>\n              <h3 className=\"mb-3 font-satoshi text-xl font-bold text-foreground\">{section.title}</h3>\n              <p className=\"font-body text-sm leading-relaxed text-foreground/68\">{section.body}</p>\n            </article>\n          ))}\n        </div>\n        <div className=\"mt-12 border-t border-foreground/10 pt-8\">\n          <p className=\"mb-4 font-body text-[11px] font-bold uppercase tracking-[0.18em] text-foreground/38\">Sources</p>\n          <ul className=\"grid gap-2 font-body text-xs leading-relaxed text-foreground/50 md:grid-cols-2\">\n            {config.seo.sources.map((source) => (\n              <li key={source}>{source}</li>\n            ))}\n          </ul>\n        </div>\n      </div>\n    </div>\n  </section>\n);\n\nexport const SectorPageTemplate = ({ config }: { config: SectorPageConfig }) => (\n  <>\n    <SectorHero config={config} />\n    <ReassuranceBand items={config.reassurance} />\n    <ProblemSection config={config} />\n    <SolutionSection config={config} />\n    <DurabilitySection config={config} />\n    <SpecialSection config={config} />\n    <BenefitsSection config={config} />\n    <ApplicationsSection config={config} />\n    <MethodSection config={config} />\n    <ProofSection config={config} />\n    <FaqSection config={config} />\n    <FinalCta config={config} />\n    <SeoContent config={config} />\n  </>\n);\n\nexport const defaultIcons = {\n  Building2,\n  HelpCircle,\n  Shield,\n  Thermometer,\n  TrendingDown,\n  UsersRound,\n};\n","numLines":1359,"startLine":1,"totalLines":1359}},"sourceToolAssistantUUID":"f5cbadb7-c68b-4f81-a8b9-954662e93249","userType":"external","entrypoint":"cli","cwd":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale","sessionId":"c02b163b-170b-4cd3-a555-3613df5965a3","version":"2.1.193","gitBranch":"tom/validation-finale","slug":"plusieurs-chose-faire-crispy-axolotl"}
{"parentUuid":"89755138-4122-49cb-bf8f-183dc50c44ca","isSidechain":true,"agentId":"a9fd20a9d1d03f0e9","message":{"model":"claude-haiku-4-5-20251001","id":"msg_01P17KpgVc6gXuBji7BGvRzB","type":"message","role":"assistant","content":[{"type":"tool_use","id":"toolu_01WqmjDbToJMTbjxUYUNUnJM","name":"Read","input":{"file_path":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/src/components/roof/RoofPageTemplate.tsx"},"caller":{"type":"direct"}}],"stop_reason":null,"stop_sequence":null,"stop_details":null,"usage":{"input_tokens":1420,"cache_creation_input_tokens":1022,"cache_read_input_tokens":29648,"cache_creation":{"ephemeral_5m_input_tokens":1022,"ephemeral_1h_input_tokens":0},"output_tokens":1,"service_tier":"standard","inference_geo":"not_available"},"diagnostics":{"cache_miss_reason":{"type":"unavailable"}}},"requestId":"req_011CcRprzY8zCoPRf8AArPJY","attributionAgent":"Explore","type":"assistant","uuid":"8f17d4d8-7a84-4649-8408-707ea5473533","timestamp":"2026-06-26T11:54:01.336Z","userType":"external","entrypoint":"cli","cwd":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale","sessionId":"c02b163b-170b-4cd3-a555-3613df5965a3","version":"2.1.193","gitBranch":"tom/validation-finale","slug":"plusieurs-chose-faire-crispy-axolotl"}
{"parentUuid":"8f17d4d8-7a84-4649-8408-707ea5473533","isSidechain":true,"agentId":"a9fd20a9d1d03f0e9","message":{"model":"claude-haiku-4-5-20251001","id":"msg_01P17KpgVc6gXuBji7BGvRzB","type":"message","role":"assistant","content":[{"type":"tool_use","id":"toolu_01VoHyzwgyhPVTsBfzL1tcEP","name":"Read","input":{"file_path":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/src/lib/wp/toSectorConfig.ts"},"caller":{"type":"direct"}}],"stop_reason":null,"stop_sequence":null,"stop_details":null,"usage":{"input_tokens":1420,"cache_creation_input_tokens":1022,"cache_read_input_tokens":29648,"cache_creation":{"ephemeral_5m_input_tokens":1022,"ephemeral_1h_input_tokens":0},"output_tokens":1,"service_tier":"standard","inference_geo":"not_available"},"diagnostics":{"cache_miss_reason":{"type":"unavailable"}}},"requestId":"req_011CcRprzY8zCoPRf8AArPJY","attributionAgent":"Explore","type":"assistant","uuid":"25446ae3-3a19-48f1-9c8f-6017ca41d5a5","timestamp":"2026-06-26T11:54:01.543Z","userType":"external","entrypoint":"cli","cwd":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale","sessionId":"c02b163b-170b-4cd3-a555-3613df5965a3","version":"2.1.193","gitBranch":"tom/validation-finale","slug":"plusieurs-chose-faire-crispy-axolotl"}
{"parentUuid":"25446ae3-3a19-48f1-9c8f-6017ca41d5a5","isSidechain":true,"promptId":"606b4c79-d3cd-4b0a-a2e5-8b38011359cb","agentId":"a9fd20a9d1d03f0e9","type":"user","message":{"role":"user","content":[{"tool_use_id":"toolu_01VoHyzwgyhPVTsBfzL1tcEP","type":"tool_result","content":"1\t// Mapper inverse : reconstruit l'objet de config du SectorPageTemplate\n2\t// (Tertiaire / Collectivités / Agricole / ERP) depuis les sections WordPress\n3\t// du post `industrie`. Chaque champ est mappé avec fallback sur la config\n4\t// codée existante : valeur WP absente/vide => valeur du fallback (rendu\n5\t// identique au site pré-CMS).\n6\t//\n7\t// Matching des rows : par layout (suffixe `...XxxLayout` du __typename),\n8\t// dans l'ordre du flexible, avec les mêmes conventions que les seeds\n9\t// (wordpress/seed/content/industrie--{tertiaire,collectivites,agricole,erp}.json) :\n10\t//   hero → logos (bandeau hero) → grille_cards (problème) → texte_image (solution)\n11\t//   → tableau_comparatif (durabilité) → texte_image+cta (section spéciale)\n12\t//   → chiffres clair (bénéfices) → grille_cards sans badge (cards bénéfices)\n13\t//   → grille_cards (applications) → etapes (méthode) → chiffres sombre (preuves)\n14\t//   → references_grille → logos (preuves) → faq → cta (final) → contenu_seo.\n15\t// Quand un champ `origine` est posé sur une row, il sert d'indice prioritaire\n16\t// (valeur attendue : \"SectorPageTemplate\"), mais le matching reste par layout.\n17\t\n18\timport type { SectorPageConfig } from \"@/components/industries/SectorPageTemplate\";\n19\timport { arr, mapImage, parseAccent } from \"./mappers\";\n20\timport type {\n21\t  ChiffresBlock,\n22\t  CtaBlock,\n23\t  ContenuSeoBlock,\n24\t  EtapesBlock,\n25\t  FaqBlock,\n26\t  GrilleCardsBlock,\n27\t  HeroBlock,\n28\t  LogosBlock,\n29\t  TableauComparatifBlock,\n30\t  TexteImageBlock,\n31\t  WpSection,\n32\t} from \"./types\";\n33\t\n34\t// ---------------------------------------------------------------------------\n35\t// Petits utilitaires texte\n36\t// ---------------------------------------------------------------------------\n37\t\n38\t/**\n39\t * Décode les entités HTML courantes + la texturisation WordPress\n40\t * (wptexturize transforme `'` en `&rsquo;`, `\"` en `&ldquo;`/`&rdquo;`, etc.).\n41\t */\n42\tconst decode = (s: string): string =>\n43\t  s\n44\t    .replace(/&nbsp;|&#160;/g, \" \")\n45\t    .replace(/&lt;/g, \"<\")\n46\t    .replace(/&gt;/g, \">\")\n47\t    .replace(/&rsquo;|&lsquo;|&#821[67];|&#0?39;/g, \"'\")\n48\t    .replace(/&rdquo;|&ldquo;|&#822[01];|&quot;/g, '\"')\n49\t    .replace(/&ndash;|&#8211;/g, \"–\")\n50\t    .replace(/&mdash;|&#8212;/g, \"—\")\n51\t    .replace(/&hellip;|&#8230;/g, \"…\")\n52\t    .replace(/&amp;/g, \"&\");\n53\t\n54\t/** Texte brut d'un fragment HTML. */\n55\tconst text = (html?: string | null): string | undefined => {\n56\t  if (!html) return undefined;\n57\t  const t = decode(html.replace(/<[^>]+>/g, \"\")).trim();\n58\t  return t || undefined;\n59\t};\n60\t\n61\t/** Valeur string non vide ou undefined. */\n62\tconst val = (s?: string | null): string | undefined =>\n63\t  s && s.trim() ? s.trim() : undefined;\n64\t\n65\t/** Titre sans la convention `*accent*`. */\n66\tconst plain = (titre?: string | null): string | undefined =>\n67\t  titre ? val(titre.replace(/\\*/g, \"\")) : undefined;\n68\t\n69\t/**\n70\t * \"Tête *accentuée.*\" → { head: \"Tête\", muted: \"accentuée.\" }.\n71\t * Le template rend `{title}<br/><span muted>{mutedTitle}</span>`.\n72\t */\n73\tconst splitAccent = (\n74\t  titre?: string | null,\n75\t): { head?: string; muted?: string } => {\n76\t  if (!titre) return {};\n77\t  if (!titre.includes(\"*\")) return { head: plain(titre) };\n78\t  const segments = parseAccent(titre);\n79\t  const head = segments\n80\t    .filter((s) => !s.accent)\n81\t    .map((s) => s.text)\n82\t    .join(\"\")\n83\t    .trim();\n84\t  const muted = segments.find((s) => s.accent)?.text.trim();\n85\t  return { head: head || undefined, muted: muted || undefined };\n86\t};\n87\t\n88\t/** Contenus des <li> d'un HTML. */\n89\tconst liItems = (html?: string | null): string[] =>\n90\t  html ? [...html.matchAll(/<li[^>]*>([\\s\\S]*?)<\\/li>/g)].map((m) => m[1]) : [];\n91\t\n92\t/** \"<strong>valeur</strong> — label\" (ou sans tiret) → { value, label }. */\n93\tconst strongItem = (li: string): { value?: string; label?: string } => {\n94\t  const m = li.match(/<strong>([\\s\\S]*?)<\\/strong>\\s*(?:—\\s*)?([\\s\\S]*)/);\n95\t  if (!m) return { label: text(li) };\n96\t  return { value: text(m[1]), label: text(m[2]) };\n97\t};\n98\t\n99\t/** Paires <h3>titre</h3> suivi d'un <ul> (cartes solution). */\n100\tconst h3UlPairs = (html?: string | null): { title: string; points: string[] }[] =>\n101\t  html\n102\t    ? [...html.matchAll(/<h3[^>]*>([\\s\\S]*?)<\\/h3>\\s*<ul>([\\s\\S]*?)<\\/ul>/g)].map((m) => ({\n103\t        title: text(m[1]) ?? \"\",\n104\t        points: liItems(m[2]).map((li) => text(li) ?? \"\").filter(Boolean),\n105\t      }))\n106\t    : [];\n107\t\n108\t// ---------------------------------------------------------------------------\n109\t// Matching des sections par layout\n110\t// ---------------------------------------------------------------------------\n111\t\n112\tconst isLayout = (section: WpSection, suffix: string): boolean =>\n113\t  typeof section.__typename === \"string\" && section.__typename.endsWith(suffix);\n114\t\n115\t// ---------------------------------------------------------------------------\n116\t// Mapper principal\n117\t// ---------------------------------------------------------------------------\n118\t\n119\texport function toSectorConfig(\n120\t  sections: WpSection[] | null | undefined,\n121\t  fallback: SectorPageConfig,\n122\t): SectorPageConfig {\n123\t  // Copie profonde \"manuelle\" du fallback (les icônes Lucide sont des\n124\t  // fonctions : pas de structuredClone possible).\n125\t  const config: SectorPageConfig = {\n126\t    ...fallback,\n127\t    reassurance: fallback.reassurance ? [...fallback.reassurance] : undefined,\n128\t    hero: {\n129\t      ...fallback.hero,\n130\t      stats: fallback.hero.stats.map((s) => ({ ...s })),\n131\t      formFields: {\n132\t        ...fallback.hero.formFields,\n133\t        typeOptions: [...fallback.hero.formFields.typeOptions],\n134\t        climateOptions: [...fallback.hero.formFields.climateOptions],\n135\t      },\n136\t    },\n137\t    logos: { ...fallback.logos, items: fallback.logos.items.map((l) => ({ ...l })) },\n138\t    problem: { ...fallback.problem, cards: fallback.problem.cards.map((c) => ({ ...c })) },\n139\t    solution: { ...fallback.solution, points: [...fallback.solution.points] },\n140\t    durability: { ...fallback.durability },\n141\t    special:\n142\t      fallback.special.kind === \"decret\"\n143\t        ? {\n144\t            ...fallback.special,\n145\t            milestones: fallback.special.milestones.map((m) => ({ ...m })),\n146\t            points: [...fallback.special.points],\n147\t          }\n148\t        : {\n149\t            ...fallback.special,\n150\t            points: fallback.special.points.map((p) => ({ ...p })),\n151\t          },\n152\t    benefits: { ...fallback.benefits, cards: fallback.benefits.cards.map((c) => ({ ...c })) },\n153\t    applications: {\n154\t      ...fallback.applications,\n155\t      cards: fallback.applications.cards.map((c) => ({ ...c })),\n156\t    },\n157\t    method: { ...fallback.method, steps: fallback.method.steps.map((s) => ({ ...s })) },\n158\t    proof: {\n159\t      ...fallback.proof,\n160\t      figures: fallback.proof.figures.map((f) => ({ ...f })),\n161\t      cases: fallback.proof.cases?.map((c) => ({ ...c })),\n162\t      logos: fallback.proof.logos.map((l) => ({ ...l })),\n163\t    },\n164\t    faq: { ...fallback.faq, items: fallback.faq.items.map((i) => ({ ...i })) },\n165\t    finalCta: { ...fallback.finalCta, reassurances: [...fallback.finalCta.reassurances] },\n166\t    seo: {\n167\t      ...fallback.seo,\n168\t      sections: fallback.seo.sections.map((s) => ({ ...s })),\n169\t      sources: [...fallback.seo.sources],\n170\t    },\n171\t  };\n172\t\n173\t  if (!sections?.length) return config;\n174\t\n175\t  // -- Collecte par layout, dans l'ordre du flexible ------------------------\n176\t  const hero = sections.find((s) => isLayout(s, \"HeroLayout\")) as HeroBlock | undefined;\n177\t  const logosBlocks = sections.filter((s) => isLayout(s, \"LogosLayout\")) as LogosBlock[];\n178\t  const grilles = sections.filter((s) => isLayout(s, \"GrilleCardsLayout\")) as GrilleCardsBlock[];\n179\t  const texteImages = sections.filter((s) => isLayout(s, \"TexteImageLayout\")) as TexteImageBlock[];\n180\t  const chiffres = sections.filter((s) => isLayout(s, \"ChiffresLayout\")) as ChiffresBlock[];\n181\t  const tableaux = sections.filter((s) =>\n182\t    isLayout(s, \"TableauComparatifLayout\"),\n183\t  ) as TableauComparatifBlock[];\n184\t  const etapes = sections.find((s) => isLayout(s, \"EtapesLayout\")) as EtapesBlock | undefined;\n185\t  const faq = sections.find((s) => isLayout(s, \"FaqLayout\")) as FaqBlock | undefined;\n186\t  const cta = sections.find((s) => isLayout(s, \"CtaLayout\")) as CtaBlock | undefined;\n187\t  const seo = sections.find((s) => isLayout(s, \"ContenuSeoLayout\")) as\n188\t    | ContenuSeoBlock\n189\t    | undefined;\n190\t\n191\t  // grille_cards : problème (1re avec badge), cards bénéfices (1re sans\n192\t  // badge), applications (2e avec badge).\n193\t  const badged = grilles.filter((g) => val(g.entete?.badge));\n194\t  const problemBlock = badged[0];\n195\t  const applicationsBlock = badged[1];\n196\t  const benefitsCardsBlock = grilles.find((g) => !val(g.entete?.badge));\n197\t\n198\t  // texte_image : solution (sans CTA), section spéciale (avec CTA).\n199\t  const solutionBlock = texteImages.find((t) => !t.cta?.label);\n200\t  const specialBlock = texteImages.find((t) => Boolean(t.cta?.label));\n201\t\n202\t  // chiffres : bénéfices (clair), preuves (sombre).\n203\t  const benefitsMetricBlock = chiffres.find((c) => c.theme !== \"sombre\");\n204\t  const proofBlock = chiffres.find((c) => c.theme === \"sombre\");\n205\t\n206\t  const durabilityBlock = tableaux[0];\n207\t\n208\t  // -- HERO ------------------------------------------------------------------\n209\t  if (hero) {\n210\t    const img = mapImage(hero.image);\n211\t    config.hero.eyebrow = val(hero.eyebrow) ?? config.hero.eyebrow;\n212\t    config.hero.h1 = plain(hero.titre) ?? config.hero.h1;\n213\t    config.hero.sub = val(hero.lead) ?? config.hero.sub;\n214\t    if (img) {\n215\t      config.hero.image = img.sourceUrl;\n216\t      config.hero.imageAlt = img.altText || config.hero.imageAlt;\n217\t    }\n218\t    const stats = arr(hero.stats);\n219\t    if (stats.length) {\n220\t      config.hero.stats = config.hero.stats.map((s, i) => ({\n221\t        ...s,\n222\t        value: val(stats[i]?.value) ?? s.value,\n223\t        label: val(stats[i]?.label) ?? s.label,\n224\t      }));\n225\t    }\n226\t    config.hero.formFields.cta = val(hero.ctaPrimaire?.label) ?? config.hero.formFields.cta;\n227\t  }\n228\t\n229\t  // -- LOGOS (bandeau hero + bloc preuves) ------------------------------------\n230\t  // Image WP manquante (ex. SVG refusé à l'upload par WordPress) → on comble\n231\t  // avec l'URL du logo codé portant le même nom (deep-merge champ à champ).\n232\t  const mapLogos = (\n233\t    block: LogosBlock | undefined,\n234\t    fallbackItems: { name: string; url?: string }[],\n235\t  ) => {\n236\t    const items = arr(block?.logosCustom)\n237\t      .map((l) => {\n238\t        const img = mapImage(l.image);\n239\t        const name = l.nom ?? img?.altText ?? \"\";\n240\t        const fb = fallbackItems.find((f) => f.name === name);\n241\t        return { name, url: img?.sourceUrl ?? fb?.url };\n242\t      })\n243\t      .filter((l) => l.name);\n244\t    return items.length ? items : undefined;\n245\t  };\n246\t  const heroLogos = mapLogos(logosBlocks[0], fallback.logos.items);\n247\t  if (heroLogos) config.logos.items = heroLogos;\n248\t  config.logos.title = val(logosBlocks[0]?.entete?.titre) ?? config.logos.title;\n249\t  const proofLogos = mapLogos(logosBlocks[1], fallback.proof.logos);\n250\t  if (proofLogos) config.proof.logos = proofLogos;\n251\t\n252\t  // -- PROBLÈME ----------------------------------------------------------------\n253\t  if (problemBlock) {\n254\t    const { head, muted } = splitAccent(problemBlock.entete?.titre);\n255\t    config.problem.eyebrow = val(problemBlock.entete?.badge) ?? config.problem.eyebrow;\n256\t    config.problem.title = head ?? config.problem.title;\n257\t    config.problem.mutedTitle = muted ?? config.problem.mutedTitle;\n258\t    config.problem.intro = val(problemBlock.entete?.intro) ?? config.problem.intro;\n259\t    config.problem.transition = val(problemBlock.transition) ?? config.problem.transition;\n260\t    const cards = arr(problemBlock.cards);\n261\t    if (cards.length) {\n262\t      config.problem.cards = config.problem.cards.map((card, i) => {\n263\t        const c = cards[i];\n264\t        if (!c) return card;\n265\t        const img = mapImage(c.image);\n266\t        return {\n267\t          ...card,\n268\t          title: val(c.titre) ?? card.title,\n269\t          desc: val(c.texte) ?? card.desc,\n270\t          image: img?.sourceUrl ?? card.image,\n271\t          alt: img?.altText || card.alt,\n272\t        };\n273\t      });\n274\t    }\n275\t  }\n276\t\n277\t  // -- SOLUTION ------------------------------------------------------------------\n278\t  if (solutionBlock) {\n279\t    const { head, muted } = splitAccent(solutionBlock.entete?.titre);\n280\t    config.solution.eyebrow = val(solutionBlock.entete?.badge) ?? config.solution.eyebrow;\n281\t    config.solution.title = head ?? config.solution.title;\n282\t    config.solution.mutedTitle = muted ?? config.solution.mutedTitle;\n283\t    config.solution.intro = val(solutionBlock.entete?.intro) ?? config.solution.intro;\n284\t    const points = arr(solutionBlock.liste)\n285\t      .map((l) => val(l.texte))\n286\t      .filter((t): t is string => Boolean(t));\n287\t    if (points.length) config.solution.points = points;\n288\t    config.solution.transition = val(solutionBlock.note) ?? config.solution.transition;\n289\t    const img = mapImage(solutionBlock.image);\n290\t    if (img) config.solution.afterImage = img.sourceUrl;\n291\t  }\n292\t\n293\t  // -- DURABILITÉ ------------------------------------------------------------------\n294\t  if (durabilityBlock) {\n295\t    const { head, muted } = splitAccent(durabilityBlock.entete?.titre);\n296\t    config.durability.title = head ?? config.durability.title;\n297\t    if (muted) config.durability.mutedTitle = muted;\n298\t    config.durability.intro = val(durabilityBlock.entete?.intro) ?? config.durability.intro;\n299\t    config.durability.note = val(durabilityBlock.texteApres) ?? config.durability.note;\n300\t    const firstRow = arr(durabilityBlock.lignesComparatif)[0];\n301\t    const covalbaLabel = val(arr(firstRow?.cellules)[2]?.texte);\n302\t    config.durability.covalbaLabel = covalbaLabel ?? config.durability.covalbaLabel;\n303\t  }\n304\t\n305\t  // -- SECTION SPÉCIALE (décret / financement) ---------------------------------------\n306\t  if (specialBlock) {\n307\t    config.special.eyebrow = val(specialBlock.entete?.badge) ?? config.special.eyebrow;\n308\t    config.special.title = plain(specialBlock.entete?.titre) ?? config.special.title;\n309\t    config.special.intro = val(specialBlock.entete?.intro) ?? config.special.intro;\n310\t    config.special.note = val(specialBlock.note) ?? config.special.note;\n311\t    config.special.cta = val(specialBlock.cta?.label) ?? config.special.cta;\n312\t    const items = liItems(specialBlock.contenu).map(strongItem);\n313\t    if (config.special.kind === \"decret\") {\n314\t      const fbMilestones = fallback.special.kind === \"decret\" ? fallback.special.milestones : [];\n315\t      if (items.length) {\n316\t        config.special.milestones = items.map((it, i) => ({\n317\t          value: it.value ?? fbMilestones[i]?.value ?? \"\",\n318\t          label: it.label ?? fbMilestones[i]?.label ?? \"\",\n319\t        }));\n320\t      }\n321\t      const points = arr(specialBlock.liste)\n322\t        .map((l) => val(l.texte))\n323\t        .filter((t): t is string => Boolean(t));\n324\t      if (points.length) config.special.points = points;\n325\t    } else if (items.length) {\n326\t      const fbPoints = fallback.special.kind === \"funding\" ? fallback.special.points : [];\n327\t      config.special.points = items.map((it, i) => ({\n328\t        value: it.value ?? fbPoints[i]?.value ?? \"\",\n329\t        label: it.label ?? fbPoints[i]?.label ?? \"\",\n330\t      }));\n331\t    }\n332\t  }\n333\t\n334\t  // -- BÉNÉFICES (métrique + cartes) ---------------------------------------------------\n335\t  if (benefitsMetricBlock) {\n336\t    config.benefits.eyebrow = val(benefitsMetricBlock.entete?.badge) ?? config.benefits.eyebrow;\n337\t    config.benefits.title = plain(benefitsMetricBlock.entete?.titre) ?? config.benefits.title;\n338\t    config.benefits.desc = val(benefitsMetricBlock.entete?.intro) ?? config.benefits.desc;\n339\t    const figure = arr(benefitsMetricBlock.figures)[0];\n340\t    if (figure) {\n341\t      config.benefits.metric = val(figure.value) ?? config.benefits.metric;\n342\t      config.benefits.metricLabel = val(figure.label) ?? config.benefits.metricLabel;\n343\t    }\n344\t  }\n345\t  if (benefitsCardsBlock) {\n346\t    config.benefits.transition = val(benefitsCardsBlock.transition) ?? config.benefits.transition;\n347\t    const cards = arr(benefitsCardsBlock.cards);\n348\t    if (cards.length) {\n349\t      config.benefits.cards = config.benefits.cards.map((card, i) => {\n350\t        const c = cards[i];\n351\t        if (!c) return card;\n352\t        return {\n353\t          ...card,\n354\t          title: val(c.titre) ?? card.title,\n355\t          desc: val(c.texte) ?? card.desc,\n356\t        };\n357\t      });\n358\t    }\n359\t  }\n360\t\n361\t  // -- APPLICATIONS --------------------------------------------------------------------\n362\t  if (applicationsBlock) {\n363\t    config.applications.eyebrow =\n364\t      val(applicationsBlock.entete?.badge) ?? config.applications.eyebrow;\n365\t    config.applications.title = plain(applicationsBlock.entete?.titre) ?? config.applications.title;\n366\t    config.applications.intro = val(applicationsBlock.entete?.intro) ?? config.applications.intro;\n367\t    config.applications.transition =\n368\t      val(applicationsBlock.transition) ?? config.applications.transition;\n369\t    const cards = arr(applicationsBlock.cards);\n370\t    if (cards.length) {\n371\t      config.applications.cards = config.applications.cards.map((card, i) => {\n372\t        const c = cards[i];\n373\t        if (!c) return card;\n374\t        const img = mapImage(c.image);\n375\t        return {\n376\t          ...card,\n377\t          title: val(c.titre) ?? card.title,\n378\t          desc: val(c.texte) ?? card.desc,\n379\t          image: img?.sourceUrl ?? card.image,\n380\t        };\n381\t      });\n382\t    }\n383\t  }\n384\t\n385\t  // -- MÉTHODE ----------------------------------------------------------------------------\n386\t  if (etapes) {\n387\t    const { head, muted } = splitAccent(etapes.entete?.titre);\n388\t    config.method.eyebrow = val(etapes.entete?.badge) ?? config.method.eyebrow;\n389\t    config.method.title = head ?? config.method.title;\n390\t    config.method.mutedTitle = muted ?? config.method.mutedTitle;\n391\t    config.method.intro = val(etapes.entete?.intro) ?? config.method.intro;\n392\t    const steps = arr(etapes.etapes);\n393\t    if (steps.length) {\n394\t      config.method.steps = config.method.steps.map((step, i) => ({\n395\t        ...step,\n396\t        title: val(steps[i]?.titre) ?? step.title,\n397\t        text: val(steps[i]?.texte) ?? step.text,\n398\t      }));\n399\t    }\n400\t    config.method.duration = val(etapes.reassurance) ?? config.method.duration;\n401\t  }\n402\t\n403\t  // -- PREUVES ----------------------------------------------------------------------------\n404\t  if (proofBlock) {\n405\t    const { head, muted } = splitAccent(proofBlock.entete?.titre);\n406\t    config.proof.eyebrow = val(proofBlock.entete?.badge) ?? config.proof.eyebrow;\n407\t    config.proof.title = head ?? config.proof.title;\n408\t    config.proof.mutedTitle = muted ?? config.proof.mutedTitle;\n409\t    config.proof.intro = val(proofBlock.entete?.intro) ?? config.proof.intro;\n410\t    const figures = arr(proofBlock.figures);\n411\t    if (figures.length) {\n412\t      config.proof.figures = config.proof.figures.map((f, i) => ({\n413\t        ...f,\n414\t        value: val(figures[i]?.value) ?? f.value,\n415\t        label: val(figures[i]?.label) ?? f.label,\n416\t      }));\n417\t    }\n418\t  }\n419\t\n420\t  // -- FAQ ----------------------------------------------------------------------------------\n421\t  if (faq) {\n422\t    config.faq.intro = val(faq.entete?.intro) ?? config.faq.intro;\n423\t    const items = arr(faq.questions)\n424\t      .map((q) => ({ q: val(q.question) ?? \"\", a: text(q.reponse) ?? \"\" }))\n425\t      .filter((i) => i.q && i.a);\n426\t    if (items.length) config.faq.items = items;\n427\t  }\n428\t\n429\t  // -- CTA FINAL ------------------------------------------------------------------------------\n430\t  if (cta) {\n431\t    config.finalCta.title = plain(cta.titre) ?? config.finalCta.title;\n432\t    config.finalCta.desc = val(cta.texte) ?? config.finalCta.desc;\n433\t    const reassurances = arr(cta.reassurances)\n434\t      .map((r) => val(r.texte))\n435\t      .filter((t): t is string => Boolean(t));\n436\t    if (reassurances.length) config.finalCta.reassurances = reassurances;\n437\t  }\n438\t\n439\t  // -- CONTENU SEO ------------------------------------------------------------------------------\n440\t  if (seo) {\n441\t    const h2 = seo.intro?.match(/<h2[^>]*>([\\s\\S]*?)<\\/h2>/);\n442\t    const p = seo.intro?.match(/<p[^>]*>([\\s\\S]*?)<\\/p>/);\n443\t    config.seo.title = (h2 ? text(h2[1]) : undefined) ?? config.seo.title;\n444\t    config.seo.intro = (p ? text(p[1]) : undefined) ?? config.seo.intro;\n445\t    const secs = arr(seo.sections)\n446\t      .map((s) => ({ title: val(s.titre) ?? \"\", body: text(s.contenu) ?? \"\" }))\n447\t      .filter((s) => s.title && s.body);\n448\t    if (secs.length) config.seo.sections = secs;\n449\t    const sources = arr(seo.sources)\n450\t      .map((s) => val(s.label))\n451\t      .filter((t): t is string => Boolean(t));\n452\t    if (sources.length) config.seo.sources = sources;\n453\t  }\n454\t\n455\t  return config;\n456\t}\n457\t\n458\texport default toSectorConfig;\n459\t"}]},"uuid":"e5a02964-7638-4304-a1db-420947e3e6f4","timestamp":"2026-06-26T11:54:01.573Z","toolUseResult":{"type":"text","file":{"filePath":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/src/lib/wp/toSectorConfig.ts","content":"// Mapper inverse : reconstruit l'objet de config du SectorPageTemplate\n// (Tertiaire / Collectivités / Agricole / ERP) depuis les sections WordPress\n// du post `industrie`. Chaque champ est mappé avec fallback sur la config\n// codée existante : valeur WP absente/vide => valeur du fallback (rendu\n// identique au site pré-CMS).\n//\n// Matching des rows : par layout (suffixe `...XxxLayout` du __typename),\n// dans l'ordre du flexible, avec les mêmes conventions que les seeds\n// (wordpress/seed/content/industrie--{tertiaire,collectivites,agricole,erp}.json) :\n//   hero → logos (bandeau hero) → grille_cards (problème) → texte_image (solution)\n//   → tableau_comparatif (durabilité) → texte_image+cta (section spéciale)\n//   → chiffres clair (bénéfices) → grille_cards sans badge (cards bénéfices)\n//   → grille_cards (applications) → etapes (méthode) → chiffres sombre (preuves)\n//   → references_grille → logos (preuves) → faq → cta (final) → contenu_seo.\n// Quand un champ `origine` est posé sur une row, il sert d'indice prioritaire\n// (valeur attendue : \"SectorPageTemplate\"), mais le matching reste par layout.\n\nimport type { SectorPageConfig } from \"@/components/industries/SectorPageTemplate\";\nimport { arr, mapImage, parseAccent } from \"./mappers\";\nimport type {\n  ChiffresBlock,\n  CtaBlock,\n  ContenuSeoBlock,\n  EtapesBlock,\n  FaqBlock,\n  GrilleCardsBlock,\n  HeroBlock,\n  LogosBlock,\n  TableauComparatifBlock,\n  TexteImageBlock,\n  WpSection,\n} from \"./types\";\n\n// ---------------------------------------------------------------------------\n// Petits utilitaires texte\n// ---------------------------------------------------------------------------\n\n/**\n * Décode les entités HTML courantes + la texturisation WordPress\n * (wptexturize transforme `'` en `&rsquo;`, `\"` en `&ldquo;`/`&rdquo;`, etc.).\n */\nconst decode = (s: string): string =>\n  s\n    .replace(/&nbsp;|&#160;/g, \" \")\n    .replace(/&lt;/g, \"<\")\n    .replace(/&gt;/g, \">\")\n    .replace(/&rsquo;|&lsquo;|&#821[67];|&#0?39;/g, \"'\")\n    .replace(/&rdquo;|&ldquo;|&#822[01];|&quot;/g, '\"')\n    .replace(/&ndash;|&#8211;/g, \"–\")\n    .replace(/&mdash;|&#8212;/g, \"—\")\n    .replace(/&hellip;|&#8230;/g, \"…\")\n    .replace(/&amp;/g, \"&\");\n\n/** Texte brut d'un fragment HTML. */\nconst text = (html?: string | null): string | undefined => {\n  if (!html) return undefined;\n  const t = decode(html.replace(/<[^>]+>/g, \"\")).trim();\n  return t || undefined;\n};\n\n/** Valeur string non vide ou undefined. */\nconst val = (s?: string | null): string | undefined =>\n  s && s.trim() ? s.trim() : undefined;\n\n/** Titre sans la convention `*accent*`. */\nconst plain = (titre?: string | null): string | undefined =>\n  titre ? val(titre.replace(/\\*/g, \"\")) : undefined;\n\n/**\n * \"Tête *accentuée.*\" → { head: \"Tête\", muted: \"accentuée.\" }.\n * Le template rend `{title}<br/><span muted>{mutedTitle}</span>`.\n */\nconst splitAccent = (\n  titre?: string | null,\n): { head?: string; muted?: string } => {\n  if (!titre) return {};\n  if (!titre.includes(\"*\")) return { head: plain(titre) };\n  const segments = parseAccent(titre);\n  const head = segments\n    .filter((s) => !s.accent)\n    .map((s) => s.text)\n    .join(\"\")\n    .trim();\n  const muted = segments.find((s) => s.accent)?.text.trim();\n  return { head: head || undefined, muted: muted || undefined };\n};\n\n/** Contenus des <li> d'un HTML. */\nconst liItems = (html?: string | null): string[] =>\n  html ? [...html.matchAll(/<li[^>]*>([\\s\\S]*?)<\\/li>/g)].map((m) => m[1]) : [];\n\n/** \"<strong>valeur</strong> — label\" (ou sans tiret) → { value, label }. */\nconst strongItem = (li: string): { value?: string; label?: string } => {\n  const m = li.match(/<strong>([\\s\\S]*?)<\\/strong>\\s*(?:—\\s*)?([\\s\\S]*)/);\n  if (!m) return { label: text(li) };\n  return { value: text(m[1]), label: text(m[2]) };\n};\n\n/** Paires <h3>titre</h3> suivi d'un <ul> (cartes solution). */\nconst h3UlPairs = (html?: string | null): { title: string; points: string[] }[] =>\n  html\n    ? [...html.matchAll(/<h3[^>]*>([\\s\\S]*?)<\\/h3>\\s*<ul>([\\s\\S]*?)<\\/ul>/g)].map((m) => ({\n        title: text(m[1]) ?? \"\",\n        points: liItems(m[2]).map((li) => text(li) ?? \"\").filter(Boolean),\n      }))\n    : [];\n\n// ---------------------------------------------------------------------------\n// Matching des sections par layout\n// ---------------------------------------------------------------------------\n\nconst isLayout = (section: WpSection, suffix: string): boolean =>\n  typeof section.__typename === \"string\" && section.__typename.endsWith(suffix);\n\n// ---------------------------------------------------------------------------\n// Mapper principal\n// ---------------------------------------------------------------------------\n\nexport function toSectorConfig(\n  sections: WpSection[] | null | undefined,\n  fallback: SectorPageConfig,\n): SectorPageConfig {\n  // Copie profonde \"manuelle\" du fallback (les icônes Lucide sont des\n  // fonctions : pas de structuredClone possible).\n  const config: SectorPageConfig = {\n    ...fallback,\n    reassurance: fallback.reassurance ? [...fallback.reassurance] : undefined,\n    hero: {\n      ...fallback.hero,\n      stats: fallback.hero.stats.map((s) => ({ ...s })),\n      formFields: {\n        ...fallback.hero.formFields,\n        typeOptions: [...fallback.hero.formFields.typeOptions],\n        climateOptions: [...fallback.hero.formFields.climateOptions],\n      },\n    },\n    logos: { ...fallback.logos, items: fallback.logos.items.map((l) => ({ ...l })) },\n    problem: { ...fallback.problem, cards: fallback.problem.cards.map((c) => ({ ...c })) },\n    solution: { ...fallback.solution, points: [...fallback.solution.points] },\n    durability: { ...fallback.durability },\n    special:\n      fallback.special.kind === \"decret\"\n        ? {\n            ...fallback.special,\n            milestones: fallback.special.milestones.map((m) => ({ ...m })),\n            points: [...fallback.special.points],\n          }\n        : {\n            ...fallback.special,\n            points: fallback.special.points.map((p) => ({ ...p })),\n          },\n    benefits: { ...fallback.benefits, cards: fallback.benefits.cards.map((c) => ({ ...c })) },\n    applications: {\n      ...fallback.applications,\n      cards: fallback.applications.cards.map((c) => ({ ...c })),\n    },\n    method: { ...fallback.method, steps: fallback.method.steps.map((s) => ({ ...s })) },\n    proof: {\n      ...fallback.proof,\n      figures: fallback.proof.figures.map((f) => ({ ...f })),\n      cases: fallback.proof.cases?.map((c) => ({ ...c })),\n      logos: fallback.proof.logos.map((l) => ({ ...l })),\n    },\n    faq: { ...fallback.faq, items: fallback.faq.items.map((i) => ({ ...i })) },\n    finalCta: { ...fallback.finalCta, reassurances: [...fallback.finalCta.reassurances] },\n    seo: {\n      ...fallback.seo,\n      sections: fallback.seo.sections.map((s) => ({ ...s })),\n      sources: [...fallback.seo.sources],\n    },\n  };\n\n  if (!sections?.length) return config;\n\n  // -- Collecte par layout, dans l'ordre du flexible ------------------------\n  const hero = sections.find((s) => isLayout(s, \"HeroLayout\")) as HeroBlock | undefined;\n  const logosBlocks = sections.filter((s) => isLayout(s, \"LogosLayout\")) as LogosBlock[];\n  const grilles = sections.filter((s) => isLayout(s, \"GrilleCardsLayout\")) as GrilleCardsBlock[];\n  const texteImages = sections.filter((s) => isLayout(s, \"TexteImageLayout\")) as TexteImageBlock[];\n  const chiffres = sections.filter((s) => isLayout(s, \"ChiffresLayout\")) as ChiffresBlock[];\n  const tableaux = sections.filter((s) =>\n    isLayout(s, \"TableauComparatifLayout\"),\n  ) as TableauComparatifBlock[];\n  const etapes = sections.find((s) => isLayout(s, \"EtapesLayout\")) as EtapesBlock | undefined;\n  const faq = sections.find((s) => isLayout(s, \"FaqLayout\")) as FaqBlock | undefined;\n  const cta = sections.find((s) => isLayout(s, \"CtaLayout\")) as CtaBlock | undefined;\n  const seo = sections.find((s) => isLayout(s, \"ContenuSeoLayout\")) as\n    | ContenuSeoBlock\n    | undefined;\n\n  // grille_cards : problème (1re avec badge), cards bénéfices (1re sans\n  // badge), applications (2e avec badge).\n  const badged = grilles.filter((g) => val(g.entete?.badge));\n  const problemBlock = badged[0];\n  const applicationsBlock = badged[1];\n  const benefitsCardsBlock = grilles.find((g) => !val(g.entete?.badge));\n\n  // texte_image : solution (sans CTA), section spéciale (avec CTA).\n  const solutionBlock = texteImages.find((t) => !t.cta?.label);\n  const specialBlock = texteImages.find((t) => Boolean(t.cta?.label));\n\n  // chiffres : bénéfices (clair), preuves (sombre).\n  const benefitsMetricBlock = chiffres.find((c) => c.theme !== \"sombre\");\n  const proofBlock = chiffres.find((c) => c.theme === \"sombre\");\n\n  const durabilityBlock = tableaux[0];\n\n  // -- HERO ------------------------------------------------------------------\n  if (hero) {\n    const img = mapImage(hero.image);\n    config.hero.eyebrow = val(hero.eyebrow) ?? config.hero.eyebrow;\n    config.hero.h1 = plain(hero.titre) ?? config.hero.h1;\n    config.hero.sub = val(hero.lead) ?? config.hero.sub;\n    if (img) {\n      config.hero.image = img.sourceUrl;\n      config.hero.imageAlt = img.altText || config.hero.imageAlt;\n    }\n    const stats = arr(hero.stats);\n    if (stats.length) {\n      config.hero.stats = config.hero.stats.map((s, i) => ({\n        ...s,\n        value: val(stats[i]?.value) ?? s.value,\n        label: val(stats[i]?.label) ?? s.label,\n      }));\n    }\n    config.hero.formFields.cta = val(hero.ctaPrimaire?.label) ?? config.hero.formFields.cta;\n  }\n\n  // -- LOGOS (bandeau hero + bloc preuves) ------------------------------------\n  // Image WP manquante (ex. SVG refusé à l'upload par WordPress) → on comble\n  // avec l'URL du logo codé portant le même nom (deep-merge champ à champ).\n  const mapLogos = (\n    block: LogosBlock | undefined,\n    fallbackItems: { name: string; url?: string }[],\n  ) => {\n    const items = arr(block?.logosCustom)\n      .map((l) => {\n        const img = mapImage(l.image);\n        const name = l.nom ?? img?.altText ?? \"\";\n        const fb = fallbackItems.find((f) => f.name === name);\n        return { name, url: img?.sourceUrl ?? fb?.url };\n      })\n      .filter((l) => l.name);\n    return items.length ? items : undefined;\n  };\n  const heroLogos = mapLogos(logosBlocks[0], fallback.logos.items);\n  if (heroLogos) config.logos.items = heroLogos;\n  config.logos.title = val(logosBlocks[0]?.entete?.titre) ?? config.logos.title;\n  const proofLogos = mapLogos(logosBlocks[1], fallback.proof.logos);\n  if (proofLogos) config.proof.logos = proofLogos;\n\n  // -- PROBLÈME ----------------------------------------------------------------\n  if (problemBlock) {\n    const { head, muted } = splitAccent(problemBlock.entete?.titre);\n    config.problem.eyebrow = val(problemBlock.entete?.badge) ?? config.problem.eyebrow;\n    config.problem.title = head ?? config.problem.title;\n    config.problem.mutedTitle = muted ?? config.problem.mutedTitle;\n    config.problem.intro = val(problemBlock.entete?.intro) ?? config.problem.intro;\n    config.problem.transition = val(problemBlock.transition) ?? config.problem.transition;\n    const cards = arr(problemBlock.cards);\n    if (cards.length) {\n      config.problem.cards = config.problem.cards.map((card, i) => {\n        const c = cards[i];\n        if (!c) return card;\n        const img = mapImage(c.image);\n        return {\n          ...card,\n          title: val(c.titre) ?? card.title,\n          desc: val(c.texte) ?? card.desc,\n          image: img?.sourceUrl ?? card.image,\n          alt: img?.altText || card.alt,\n        };\n      });\n    }\n  }\n\n  // -- SOLUTION ------------------------------------------------------------------\n  if (solutionBlock) {\n    const { head, muted } = splitAccent(solutionBlock.entete?.titre);\n    config.solution.eyebrow = val(solutionBlock.entete?.badge) ?? config.solution.eyebrow;\n    config.solution.title = head ?? config.solution.title;\n    config.solution.mutedTitle = muted ?? config.solution.mutedTitle;\n    config.solution.intro = val(solutionBlock.entete?.intro) ?? config.solution.intro;\n    const points = arr(solutionBlock.liste)\n      .map((l) => val(l.texte))\n      .filter((t): t is string => Boolean(t));\n    if (points.length) config.solution.points = points;\n    config.solution.transition = val(solutionBlock.note) ?? config.solution.transition;\n    const img = mapImage(solutionBlock.image);\n    if (img) config.solution.afterImage = img.sourceUrl;\n  }\n\n  // -- DURABILITÉ ------------------------------------------------------------------\n  if (durabilityBlock) {\n    const { head, muted } = splitAccent(durabilityBlock.entete?.titre);\n    config.durability.title = head ?? config.durability.title;\n    if (muted) config.durability.mutedTitle = muted;\n    config.durability.intro = val(durabilityBlock.entete?.intro) ?? config.durability.intro;\n    config.durability.note = val(durabilityBlock.texteApres) ?? config.durability.note;\n    const firstRow = arr(durabilityBlock.lignesComparatif)[0];\n    const covalbaLabel = val(arr(firstRow?.cellules)[2]?.texte);\n    config.durability.covalbaLabel = covalbaLabel ?? config.durability.covalbaLabel;\n  }\n\n  // -- SECTION SPÉCIALE (décret / financement) ---------------------------------------\n  if (specialBlock) {\n    config.special.eyebrow = val(specialBlock.entete?.badge) ?? config.special.eyebrow;\n    config.special.title = plain(specialBlock.entete?.titre) ?? config.special.title;\n    config.special.intro = val(specialBlock.entete?.intro) ?? config.special.intro;\n    config.special.note = val(specialBlock.note) ?? config.special.note;\n    config.special.cta = val(specialBlock.cta?.label) ?? config.special.cta;\n    const items = liItems(specialBlock.contenu).map(strongItem);\n    if (config.special.kind === \"decret\") {\n      const fbMilestones = fallback.special.kind === \"decret\" ? fallback.special.milestones : [];\n      if (items.length) {\n        config.special.milestones = items.map((it, i) => ({\n          value: it.value ?? fbMilestones[i]?.value ?? \"\",\n          label: it.label ?? fbMilestones[i]?.label ?? \"\",\n        }));\n      }\n      const points = arr(specialBlock.liste)\n        .map((l) => val(l.texte))\n        .filter((t): t is string => Boolean(t));\n      if (points.length) config.special.points = points;\n    } else if (items.length) {\n      const fbPoints = fallback.special.kind === \"funding\" ? fallback.special.points : [];\n      config.special.points = items.map((it, i) => ({\n        value: it.value ?? fbPoints[i]?.value ?? \"\",\n        label: it.label ?? fbPoints[i]?.label ?? \"\",\n      }));\n    }\n  }\n\n  // -- BÉNÉFICES (métrique + cartes) ---------------------------------------------------\n  if (benefitsMetricBlock) {\n    config.benefits.eyebrow = val(benefitsMetricBlock.entete?.badge) ?? config.benefits.eyebrow;\n    config.benefits.title = plain(benefitsMetricBlock.entete?.titre) ?? config.benefits.title;\n    config.benefits.desc = val(benefitsMetricBlock.entete?.intro) ?? config.benefits.desc;\n    const figure = arr(benefitsMetricBlock.figures)[0];\n    if (figure) {\n      config.benefits.metric = val(figure.value) ?? config.benefits.metric;\n      config.benefits.metricLabel = val(figure.label) ?? config.benefits.metricLabel;\n    }\n  }\n  if (benefitsCardsBlock) {\n    config.benefits.transition = val(benefitsCardsBlock.transition) ?? config.benefits.transition;\n    const cards = arr(benefitsCardsBlock.cards);\n    if (cards.length) {\n      config.benefits.cards = config.benefits.cards.map((card, i) => {\n        const c = cards[i];\n        if (!c) return card;\n        return {\n          ...card,\n          title: val(c.titre) ?? card.title,\n          desc: val(c.texte) ?? card.desc,\n        };\n      });\n    }\n  }\n\n  // -- APPLICATIONS --------------------------------------------------------------------\n  if (applicationsBlock) {\n    config.applications.eyebrow =\n      val(applicationsBlock.entete?.badge) ?? config.applications.eyebrow;\n    config.applications.title = plain(applicationsBlock.entete?.titre) ?? config.applications.title;\n    config.applications.intro = val(applicationsBlock.entete?.intro) ?? config.applications.intro;\n    config.applications.transition =\n      val(applicationsBlock.transition) ?? config.applications.transition;\n    const cards = arr(applicationsBlock.cards);\n    if (cards.length) {\n      config.applications.cards = config.applications.cards.map((card, i) => {\n        const c = cards[i];\n        if (!c) return card;\n        const img = mapImage(c.image);\n        return {\n          ...card,\n          title: val(c.titre) ?? card.title,\n          desc: val(c.texte) ?? card.desc,\n          image: img?.sourceUrl ?? card.image,\n        };\n      });\n    }\n  }\n\n  // -- MÉTHODE ----------------------------------------------------------------------------\n  if (etapes) {\n    const { head, muted } = splitAccent(etapes.entete?.titre);\n    config.method.eyebrow = val(etapes.entete?.badge) ?? config.method.eyebrow;\n    config.method.title = head ?? config.method.title;\n    config.method.mutedTitle = muted ?? config.method.mutedTitle;\n    config.method.intro = val(etapes.entete?.intro) ?? config.method.intro;\n    const steps = arr(etapes.etapes);\n    if (steps.length) {\n      config.method.steps = config.method.steps.map((step, i) => ({\n        ...step,\n        title: val(steps[i]?.titre) ?? step.title,\n        text: val(steps[i]?.texte) ?? step.text,\n      }));\n    }\n    config.method.duration = val(etapes.reassurance) ?? config.method.duration;\n  }\n\n  // -- PREUVES ----------------------------------------------------------------------------\n  if (proofBlock) {\n    const { head, muted } = splitAccent(proofBlock.entete?.titre);\n    config.proof.eyebrow = val(proofBlock.entete?.badge) ?? config.proof.eyebrow;\n    config.proof.title = head ?? config.proof.title;\n    config.proof.mutedTitle = muted ?? config.proof.mutedTitle;\n    config.proof.intro = val(proofBlock.entete?.intro) ?? config.proof.intro;\n    const figures = arr(proofBlock.figures);\n    if (figures.length) {\n      config.proof.figures = config.proof.figures.map((f, i) => ({\n        ...f,\n        value: val(figures[i]?.value) ?? f.value,\n        label: val(figures[i]?.label) ?? f.label,\n      }));\n    }\n  }\n\n  // -- FAQ ----------------------------------------------------------------------------------\n  if (faq) {\n    config.faq.intro = val(faq.entete?.intro) ?? config.faq.intro;\n    const items = arr(faq.questions)\n      .map((q) => ({ q: val(q.question) ?? \"\", a: text(q.reponse) ?? \"\" }))\n      .filter((i) => i.q && i.a);\n    if (items.length) config.faq.items = items;\n  }\n\n  // -- CTA FINAL ------------------------------------------------------------------------------\n  if (cta) {\n    config.finalCta.title = plain(cta.titre) ?? config.finalCta.title;\n    config.finalCta.desc = val(cta.texte) ?? config.finalCta.desc;\n    const reassurances = arr(cta.reassurances)\n      .map((r) => val(r.texte))\n      .filter((t): t is string => Boolean(t));\n    if (reassurances.length) config.finalCta.reassurances = reassurances;\n  }\n\n  // -- CONTENU SEO ------------------------------------------------------------------------------\n  if (seo) {\n    const h2 = seo.intro?.match(/<h2[^>]*>([\\s\\S]*?)<\\/h2>/);\n    const p = seo.intro?.match(/<p[^>]*>([\\s\\S]*?)<\\/p>/);\n    config.seo.title = (h2 ? text(h2[1]) : undefined) ?? config.seo.title;\n    config.seo.intro = (p ? text(p[1]) : undefined) ?? config.seo.intro;\n    const secs = arr(seo.sections)\n      .map((s) => ({ title: val(s.titre) ?? \"\", body: text(s.contenu) ?? \"\" }))\n      .filter((s) => s.title && s.body);\n    if (secs.length) config.seo.sections = secs;\n    const sources = arr(seo.sources)\n      .map((s) => val(s.label))\n      .filter((t): t is string => Boolean(t));\n    if (sources.length) config.seo.sources = sources;\n  }\n\n  return config;\n}\n\nexport default toSectorConfig;\n","numLines":459,"startLine":1,"totalLines":459}},"sourceToolAssistantUUID":"25446ae3-3a19-48f1-9c8f-6017ca41d5a5","userType":"external","entrypoint":"cli","cwd":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale","sessionId":"c02b163b-170b-4cd3-a555-3613df5965a3","version":"2.1.193","gitBranch":"tom/validation-finale","slug":"plusieurs-chose-faire-crispy-axolotl"}
{"parentUuid":"e5a02964-7638-4304-a1db-420947e3e6f4","isSidechain":true,"agentId":"a9fd20a9d1d03f0e9","message":{"model":"claude-haiku-4-5-20251001","id":"msg_01P17KpgVc6gXuBji7BGvRzB","type":"message","role":"assistant","content":[{"type":"tool_use","id":"toolu_01QEDhESHxJmB7Ns6o761EQw","name":"Read","input":{"file_path":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/src/components/SolutionsGrid.tsx"},"caller":{"type":"direct"}}],"stop_reason":null,"stop_sequence":null,"stop_details":null,"usage":{"input_tokens":1420,"cache_creation_input_tokens":1022,"cache_read_input_tokens":29648,"cache_creation":{"ephemeral_5m_input_tokens":1022,"ephemeral_1h_input_tokens":0},"output_tokens":1,"service_tier":"standard","inference_geo":"not_available"},"diagnostics":{"cache_miss_reason":{"type":"unavailable"}}},"requestId":"req_011CcRprzY8zCoPRf8AArPJY","attributionAgent":"Explore","type":"assistant","uuid":"ac01d9c8-67cf-45d8-9670-36e04bcfcab3","timestamp":"2026-06-26T11:54:01.596Z","userType":"external","entrypoint":"cli","cwd":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale","sessionId":"c02b163b-170b-4cd3-a555-3613df5965a3","version":"2.1.193","gitBranch":"tom/validation-finale","slug":"plusieurs-chose-faire-crispy-axolotl"}
{"parentUuid":"ac01d9c8-67cf-45d8-9670-36e04bcfcab3","isSidechain":true,"promptId":"606b4c79-d3cd-4b0a-a2e5-8b38011359cb","agentId":"a9fd20a9d1d03f0e9","type":"user","message":{"role":"user","content":[{"tool_use_id":"toolu_01QEDhESHxJmB7Ns6o761EQw","type":"tool_result","content":"1\timport { Badge } from '@/components/ui/badge';\n2\timport { ArrowRight } from 'lucide-react';\n3\timport ScrollReveal from './ScrollReveal';\n4\t\n5\tconst products = [\n6\t  {\n7\t    name: 'CovaTherm 8 & 20',\n8\t    tagline: 'Le bouclier thermique de référence',\n9\t    description: 'Pour toitures plates et inclinées. Réfléchit 94% du rayonnement solaire. Version 20 avec protection anti-UV garantie 20 ans.',\n10\t    supports: 'Béton, bitume, EPDM, PVC',\n11\t    bg: 'bg-teal-light',\n12\t    image: 'https://covalba-admin.paf-studio.dev/wp-content/uploads/2026/06/vignette-covatherm.png',\n13\t    href: '/peinture-reflective-covatherm',\n14\t  },\n15\t  {\n16\t    name: 'CovaSeal',\n17\t    tagline: 'Étanchéité + réflexion en un produit',\n18\t    description: \"Membrane liquide qui étanchéifie et réfléchit en même temps. Application directe sur l'existant, sans dépose.\",\n19\t    supports: 'Béton, métal, bitume, membranes',\n20\t    bg: 'bg-[hsl(36,50%,95%)]',\n21\t    image: 'https://covalba-admin.paf-studio.dev/wp-content/uploads/2026/06/vignette-covaseal.png',\n22\t    href: '/covaseal',\n23\t  },\n24\t  {\n25\t    name: 'CovaMetal',\n26\t    tagline: 'Anticorrosion + cool roof pour métal',\n27\t    description: \"Traite la rouille et réfléchit le soleil en une seule intervention. Spécifique aux toitures métalliques dégradées.\",\n28\t    supports: 'Bac acier, zinc, tôle ondulée',\n29\t    bg: 'bg-[hsl(10,40%,95%)]',\n30\t    image: 'https://covalba-admin.paf-studio.dev/wp-content/uploads/2026/06/vignette-covametal.png',\n31\t    href: '/covametal',\n32\t  },\n33\t  {\n34\t    name: 'Laque solaire',\n35\t    tagline: 'Protection des surfaces vitrées',\n36\t    description: \"Réduit l'effet de serre sous les surfaces translucides tout en conservant la luminosité naturelle.\",\n37\t    supports: 'Polycarbonate, verre, PVC translucide',\n38\t    bg: 'bg-[hsl(200,40%,95%)]',\n39\t    image: 'https://covalba-admin.paf-studio.dev/wp-content/uploads/2026/06/vignette-covatherm.png',\n40\t    href: '/laque-solaire-covatherm-light',\n41\t  },\n42\t];\n43\t\n44\tconst SolutionsGrid = () => (\n45\t  <section className=\"py-20 lg:py-28 bg-offwhite\">\n46\t    <div className=\"container mx-auto px-4 lg:px-8\">\n47\t      <ScrollReveal>\n48\t        <div className=\"text-center mb-14\">\n49\t          <Badge className=\"mb-4 bg-teal-light text-primary border-primary/20\">Nos solutions</Badge>\n50\t          <h2 className=\"font-satoshi text-3xl lg:text-4xl font-bold text-foreground mb-3\">\n51\t            Un produit pour chaque type de toiture\n52\t          </h2>\n53\t          <p className=\"text-muted-foreground text-lg max-w-2xl mx-auto\">\n54\t            C'est pour ça qu'on est fabricant. Pas une peinture unique appliquée partout, mais un système spécifique pour chaque support.\n55\t          </p>\n56\t        </div>\n57\t      </ScrollReveal>\n58\t\n59\t      <ScrollReveal stagger>\n60\t        <div className=\"grid sm:grid-cols-2 lg:grid-cols-4 gap-6\">\n61\t          {products.map((p) => (\n62\t            <a key={p.name} href={p.href} className={`${p.bg} rounded-xl p-6 group hover:shadow-lg transition-all hover:-translate-y-1`}>\n63\t              <div className=\"aspect-square mb-5 flex items-center justify-center\">\n64\t                <img src={p.image} alt={p.name} className=\"w-3/4 object-contain group-hover:scale-105 transition-transform duration-300\" loading=\"lazy\" />\n65\t              </div>\n66\t              <h3 className=\"font-satoshi text-lg font-bold text-foreground mb-1\">{p.name}</h3>\n67\t              <p className=\"text-sm font-medium text-primary mb-3\">{p.tagline}</p>\n68\t              <p className=\"text-sm text-muted-foreground mb-3\">{p.description}</p>\n69\t              <p className=\"text-xs text-muted-foreground/70 mb-4\">Supports : {p.supports}</p>\n70\t              <span className=\"inline-flex items-center gap-1 text-sm font-semibold text-primary group-hover:gap-2 transition-all\">\n71\t                En savoir plus <ArrowRight className=\"w-4 h-4\" />\n72\t              </span>\n73\t            </a>\n74\t          ))}\n75\t        </div>\n76\t      </ScrollReveal>\n77\t\n78\t      <ScrollReveal>\n79\t        <div className=\"text-center mt-10\">\n80\t          <a href=\"/diagnostic\" className=\"inline-flex items-center gap-2 text-primary font-semibold hover:gap-3 transition-all\">\n81\t            Quel produit pour votre toiture ? <ArrowRight className=\"w-4 h-4\" />\n82\t          </a>\n83\t        </div>\n84\t      </ScrollReveal>\n85\t    </div>\n86\t  </section>\n87\t);\n88\t\n89\texport default SolutionsGrid;\n90\t"}]},"uuid":"0acbfab8-504a-4d0f-b16d-a843d175276f","timestamp":"2026-06-26T11:54:01.622Z","toolUseResult":{"type":"text","file":{"filePath":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/src/components/SolutionsGrid.tsx","content":"import { Badge } from '@/components/ui/badge';\nimport { ArrowRight } from 'lucide-react';\nimport ScrollReveal from './ScrollReveal';\n\nconst products = [\n  {\n    name: 'CovaTherm 8 & 20',\n    tagline: 'Le bouclier thermique de référence',\n    description: 'Pour toitures plates et inclinées. Réfléchit 94% du rayonnement solaire. Version 20 avec protection anti-UV garantie 20 ans.',\n    supports: 'Béton, bitume, EPDM, PVC',\n    bg: 'bg-teal-light',\n    image: 'https://covalba-admin.paf-studio.dev/wp-content/uploads/2026/06/vignette-covatherm.png',\n    href: '/peinture-reflective-covatherm',\n  },\n  {\n    name: 'CovaSeal',\n    tagline: 'Étanchéité + réflexion en un produit',\n    description: \"Membrane liquide qui étanchéifie et réfléchit en même temps. Application directe sur l'existant, sans dépose.\",\n    supports: 'Béton, métal, bitume, membranes',\n    bg: 'bg-[hsl(36,50%,95%)]',\n    image: 'https://covalba-admin.paf-studio.dev/wp-content/uploads/2026/06/vignette-covaseal.png',\n    href: '/covaseal',\n  },\n  {\n    name: 'CovaMetal',\n    tagline: 'Anticorrosion + cool roof pour métal',\n    description: \"Traite la rouille et réfléchit le soleil en une seule intervention. Spécifique aux toitures métalliques dégradées.\",\n    supports: 'Bac acier, zinc, tôle ondulée',\n    bg: 'bg-[hsl(10,40%,95%)]',\n    image: 'https://covalba-admin.paf-studio.dev/wp-content/uploads/2026/06/vignette-covametal.png',\n    href: '/covametal',\n  },\n  {\n    name: 'Laque solaire',\n    tagline: 'Protection des surfaces vitrées',\n    description: \"Réduit l'effet de serre sous les surfaces translucides tout en conservant la luminosité naturelle.\",\n    supports: 'Polycarbonate, verre, PVC translucide',\n    bg: 'bg-[hsl(200,40%,95%)]',\n    image: 'https://covalba-admin.paf-studio.dev/wp-content/uploads/2026/06/vignette-covatherm.png',\n    href: '/laque-solaire-covatherm-light',\n  },\n];\n\nconst SolutionsGrid = () => (\n  <section className=\"py-20 lg:py-28 bg-offwhite\">\n    <div className=\"container mx-auto px-4 lg:px-8\">\n      <ScrollReveal>\n        <div className=\"text-center mb-14\">\n          <Badge className=\"mb-4 bg-teal-light text-primary border-primary/20\">Nos solutions</Badge>\n          <h2 className=\"font-satoshi text-3xl lg:text-4xl font-bold text-foreground mb-3\">\n            Un produit pour chaque type de toiture\n          </h2>\n          <p className=\"text-muted-foreground text-lg max-w-2xl mx-auto\">\n            C'est pour ça qu'on est fabricant. Pas une peinture unique appliquée partout, mais un système spécifique pour chaque support.\n          </p>\n        </div>\n      </ScrollReveal>\n\n      <ScrollReveal stagger>\n        <div className=\"grid sm:grid-cols-2 lg:grid-cols-4 gap-6\">\n          {products.map((p) => (\n            <a key={p.name} href={p.href} className={`${p.bg} rounded-xl p-6 group hover:shadow-lg transition-all hover:-translate-y-1`}>\n              <div className=\"aspect-square mb-5 flex items-center justify-center\">\n                <img src={p.image} alt={p.name} className=\"w-3/4 object-contain group-hover:scale-105 transition-transform duration-300\" loading=\"lazy\" />\n              </div>\n              <h3 className=\"font-satoshi text-lg font-bold text-foreground mb-1\">{p.name}</h3>\n              <p className=\"text-sm font-medium text-primary mb-3\">{p.tagline}</p>\n              <p className=\"text-sm text-muted-foreground mb-3\">{p.description}</p>\n              <p className=\"text-xs text-muted-foreground/70 mb-4\">Supports : {p.supports}</p>\n              <span className=\"inline-flex items-center gap-1 text-sm font-semibold text-primary group-hover:gap-2 transition-all\">\n                En savoir plus <ArrowRight className=\"w-4 h-4\" />\n              </span>\n            </a>\n          ))}\n        </div>\n      </ScrollReveal>\n\n      <ScrollReveal>\n        <div className=\"text-center mt-10\">\n          <a href=\"/diagnostic\" className=\"inline-flex items-center gap-2 text-primary font-semibold hover:gap-3 transition-all\">\n            Quel produit pour votre toiture ? <ArrowRight className=\"w-4 h-4\" />\n          </a>\n        </div>\n      </ScrollReveal>\n    </div>\n  </section>\n);\n\nexport default SolutionsGrid;\n","numLines":90,"startLine":1,"totalLines":90}},"sourceToolAssistantUUID":"ac01d9c8-67cf-45d8-9670-36e04bcfcab3","userType":"external","entrypoint":"cli","cwd":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale","sessionId":"c02b163b-170b-4cd3-a555-3613df5965a3","version":"2.1.193","gitBranch":"tom/validation-finale","slug":"plusieurs-chose-faire-crispy-axolotl"}
{"parentUuid":"8f17d4d8-7a84-4649-8408-707ea5473533","isSidechain":true,"promptId":"606b4c79-d3cd-4b0a-a2e5-8b38011359cb","agentId":"a9fd20a9d1d03f0e9","type":"user","message":{"role":"user","content":[{"tool_use_id":"toolu_01WqmjDbToJMTbjxUYUNUnJM","type":"tool_result","content":"1\t\"use client\";\n2\t\n3\timport { useState } from 'react';\n4\timport {\n5\t  ArrowRight,\n6\t  BadgeCheck,\n7\t  CalendarClock,\n8\t  CalendarCheck,\n9\t  Check,\n10\t  CheckCircle2,\n11\t  ChevronDown,\n12\t  ClipboardCheck,\n13\t  Factory,\n14\t  HelpCircle,\n15\t  Play,\n16\t  ShieldCheck,\n17\t  ShieldAlert,\n18\t  Sparkles,\n19\t  SunMedium,\n20\t  Thermometer,\n21\t  TrendingDown,\n22\t  Users,\n23\t  Wrench,\n24\t  type LucideIcon,\n25\t} from 'lucide-react';\n26\t\n27\timport Footer from '@/components/Footer';\n28\timport Navbar from '@/components/Navbar';\n29\timport ScrollReveal from '@/components/ScrollReveal';\n30\timport StickyMobileCTA from '@/components/StickyMobileCTA';\n31\timport { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from '@/components/ui/accordion';\n32\timport { Dialog, DialogContent } from '@/components/ui/dialog';\n33\timport WpImage from '@/components/ui/WpImage';\n34\timport type { RoofPageData, TextCard } from '@/data/roofPages';\n35\timport coolRoofLayers from '@/assets/cool-roof-layers.webp';\n36\timport covaMetalProduct from '@/assets/produits/Covalba-CovaMetal20-Duo-Produit.webp';\n37\timport covaSealProduct from '@/assets/produits/Covalba-CovaSeal20-Duo-Produit.webp';\n38\timport covaTherm8Product from '@/assets/produits/Covalba-CovaTherm8-Produit.webp';\n39\timport covaTherm20Product from '@/assets/produits/Covalba-CovaTherm20-Produit.webp';\n40\t\n41\tinterface RoofPageTemplateProps {\n42\t  page: RoofPageData;\n43\t}\n44\t\n45\tconst cardIcons: LucideIcon[] = [SunMedium, Wrench, Factory, ShieldCheck];\n46\tconst methodIcons: LucideIcon[] = [ClipboardCheck, CalendarClock, ShieldCheck, TrendingDown];\n47\tconst proofIcons: LucideIcon[] = [Thermometer, ShieldCheck, BadgeCheck];\n48\tconst problemIcons: LucideIcon[] = [Users, SunMedium, ShieldAlert];\n49\t\n50\tconst logos = [\n51\t  { name: 'Continental', url: '/logos/logo-continental.svg' },\n52\t  { name: 'Thales', url: '/logos/logo-thales.svg' },\n53\t  { name: 'Nestlé', url: '/logos/logo-nestle.svg' },\n54\t  { name: 'SNCF', url: '/logos/logo-sncf.svg' },\n55\t  { name: 'Leclerc', url: '/logos/logo-leclerc.svg' },\n56\t  { name: 'Super U', url: '/logos/logo-super-u.svg' },\n57\t];\n58\t\n59\tconst displayCell = (value: string) => value.replace(/EUR/g, '€').replace(/m2/g, 'm²');\n60\t\n61\tconst formatCurrency = (value: number) =>\n62\t  `${new Intl.NumberFormat('fr-FR', { maximumFractionDigits: 0 }).format(Math.round(value))} €`;\n63\t\n64\tconst parsePricePerM2 = (value: string) => {\n65\t  const match = displayCell(value).match(/\\(([\\d,.]+)\\s*€\\/m²\\)/);\n66\t  if (!match) return null;\n67\t\n68\t  return Number.parseFloat(match[1].replace(',', '.'));\n69\t};\n70\t\n71\tconst getTreatmentRange = (page: RoofPageData, situation: string) => {\n72\t  const text = `${page.slug} ${situation}`.toLowerCase();\n73\t\n74\t  if (text.includes('covaseal') || text.includes('vieillissante') || text.includes('fuite')) {\n75\t    return { min: 28, max: 38, label: 'CovaSeal 20 estimatif' };\n76\t  }\n77\t\n78\t  if (text.includes('covametal') || text.includes('corrosion') || text.includes('tôle')) {\n79\t    return { min: 24, max: 32, label: 'CovaMetal 20 estimatif' };\n80\t  }\n81\t\n82\t  if (text.includes('fibrociment') || text.includes('plaques')) {\n83\t    return { min: 22, max: 28, label: 'CovaTherm support sensible' };\n84\t  }\n85\t\n86\t  return { min: 20, max: 25, label: 'CovaTherm estimatif' };\n87\t};\n88\t\n89\tconst getFallbackPricePerM2 = (option: string, optionIndex: number, treatmentMidpoint: number) => {\n90\t  const lower = option.toLowerCase();\n91\t\n92\t  if (optionIndex === 0) return treatmentMidpoint;\n93\t  if (lower.includes('anticorrosion simple')) return 16;\n94\t  if (lower.includes('remplacement')) return 120;\n95\t  if (lower.includes('membrane neuve')) return 90;\n96\t  if (lower.includes('isolation')) return 150;\n97\t\n98\t  return null;\n99\t};\n100\t\n101\tconst benefitImages = [\n102\t  '/images/toitures/benefit-confort.webp',\n103\t  '/images/toitures/benefit-protection-toiture.webp',\n104\t  '/images/toitures/benefit-clim.webp',\n105\t  '/images/toitures/benefit-chantier-evite.webp',\n106\t];\n107\t\n108\tconst feedbackRoofBenefitImages = [\n109\t  '/images/toitures/feedback-batiment-tempere.png',\n110\t  '/images/toitures/feedback-etancheite.png',\n111\t  '/images/toitures/feedback-economie-clim-1.png',\n112\t  '/images/toitures/feedback-economie-clim-3.png',\n113\t];\n114\t\n115\tconst getBenefitImage = (page: RoofPageData, benefit: TextCard, index: number) => {\n116\t  if (['membrane-bitumineuse', 'toiture-plate'].includes(page.slug)) {\n117\t    return feedbackRoofBenefitImages[index] ?? feedbackRoofBenefitImages[0];\n118\t  }\n119\t\n120\t  const text = `${benefit.title} ${benefit.text}`.toLowerCase();\n121\t\n122\t  if (page.slug === 'bac-acier' && (text.includes('tôle') || text.includes('corrosion'))) {\n123\t    return '/images/toitures/support-bac-acier-cool.webp';\n124\t  }\n125\t\n126\t  if (text.includes('facture') || text.includes('clim') || text.includes('froid')) {\n127\t    return '/images/toitures/benefit-clim.webp';\n128\t  }\n129\t\n130\t  if (text.includes('chantier') || text.includes('réfection') || text.includes('remplacement') || text.includes('dépose')) {\n131\t    return '/images/toitures/benefit-chantier-evite.webp';\n132\t  }\n133\t\n134\t  if (text.includes('protég') || text.includes('étanchéité') || text.includes('corrosion') || text.includes('durée')) {\n135\t    return '/images/toitures/benefit-protection-toiture.webp';\n136\t  }\n137\t\n138\t  return benefitImages[index] ?? benefitImages[0];\n139\t};\n140\t\n141\tconst supportVisuals: Record<string, { hot: string; cool: string; hotLabel: string; coolLabel: string }> = {\n142\t  'membrane-bitumineuse': {\n143\t    hot: '/images/toitures/support-bitume-chaud.webp',\n144\t    cool: '/images/toitures/feedback-economie-clim-2.png',\n145\t    hotLabel: 'Sans cool roof : membrane bitume en absorption',\n146\t    coolLabel: 'Avec cool roof : membrane réfléchissante',\n147\t  },\n148\t  'bac-acier': {\n149\t    hot: '/images/toitures/support-bac-acier-chaud.webp',\n150\t    cool: '/images/toitures/support-bac-acier-cool.webp',\n151\t    hotLabel: 'Sans cool roof : métal en surchauffe',\n152\t    coolLabel: 'Avec cool roof : bac acier réfléchi et protégé',\n153\t  },\n154\t  'toiture-plate': {\n155\t    hot: '/images/toitures/support-toiture-plate-chaud.webp',\n156\t    cool: '/images/toitures/feedback-economie-clim-2.png',\n157\t    hotLabel: 'Sans cool roof : terrasse en absorption',\n158\t    coolLabel: 'Avec cool roof : terrasse réfléchissante',\n159\t  },\n160\t  fibrociment: {\n161\t    hot: '/images/toitures/support-fibrociment-chaud.webp',\n162\t    cool: '/images/toitures/support-fibrociment-cool.webp',\n163\t    hotLabel: 'Sans cool roof : fibrociment en absorption',\n164\t    coolLabel: 'Avec cool roof : plaques protégées',\n165\t  },\n166\t  'tuiles-ciment': {\n167\t    hot: '/images/toitures/support-tuiles-ciment-chaud.webp',\n168\t    cool: '/images/toitures/support-tuiles-ciment-cool.webp',\n169\t    hotLabel: 'Sans cool roof : tuiles qui stockent la chaleur',\n170\t    coolLabel: 'Avec cool roof : tuiles réfléchissantes',\n171\t  },\n172\t};\n173\t\n174\tconst layerTitles = [\"Primaire d'accroche\", 'Résine réfléchissante', 'Vernis de protection'];\n175\t\n176\tconst layerColors = [\n177\t  {\n178\t    pill: 'bg-terracotta text-white',\n179\t    dot: 'bg-terracotta',\n180\t    chevron: 'text-terracotta',\n181\t  },\n182\t  {\n183\t    pill: 'bg-foreground text-white',\n184\t    dot: 'bg-foreground',\n185\t    chevron: 'text-foreground',\n186\t  },\n187\t  {\n188\t    pill: 'bg-primary text-white',\n189\t    dot: 'bg-primary',\n190\t    chevron: 'text-primary',\n191\t  },\n192\t];\n193\t\n194\tconst layerPositions = [\n195\t  { top: '56.7%', left: '36.5%' },\n196\t  { top: '48.2%', left: '36.5%' },\n197\t  { top: '36.3%', left: '35.6%' },\n198\t];\n199\t\n200\tconst getProblemTitle = (title: string) => {\n201\t  const map: Record<string, { strong: string; muted: string }> = {\n202\t    \"Une toiture bitume noire, c'est un radiateur posé sur votre bâtiment.\": {\n203\t      strong: 'Votre toiture chauffe.',\n204\t      muted: 'Votre bâtiment encaisse.',\n205\t    },\n206\t    'Le bac acier chauffe vite, rouille vite, et fatigue vite.': {\n207\t      strong: 'Le métal chauffe vite.',\n208\t      muted: 'La toiture fatigue aussi.',\n209\t    },\n210\t    'À plat, votre toiture prend le soleil toute la journée.': {\n211\t      strong: 'Votre terrasse prend tout.',\n212\t      muted: \"Chaleur, UV, étanchéité.\",\n213\t    },\n214\t    'Le fibrociment chauffe, vieillit, et coûte cher à déposer.': {\n215\t      strong: 'Le fibrociment chauffe.',\n216\t      muted: 'Le déposer coûte cher.',\n217\t    },\n218\t    'Des tuiles ciment foncées, des combles en surchauffe.': {\n219\t      strong: 'Les tuiles stockent la chaleur.',\n220\t      muted: 'Les combles la subissent.',\n221\t    },\n222\t  };\n223\t\n224\t  return map[title] ?? { strong: title, muted: '' };\n225\t};\n226\t\n227\tconst getLayerDescription = (index: number) => {\n228\t  if (index === 0) {\n229\t    return \"S'adapte au support existant. Chaque toiture a sa chimie, chaque chimie demande une préparation et une accroche adaptées.\";\n230\t  }\n231\t\n232\t  if (index === 1) {\n233\t    return \"C'est le coeur du système. La surface réfléchit le rayonnement solaire au lieu de l'absorber, donc la chaleur rentre moins dans le bâtiment.\";\n234\t  }\n235\t\n236\t  return \"Un top coat protège la résine des UV, de la pollution et du vieillissement prématuré pour conserver la performance dans le temps.\";\n237\t};\n238\t\n239\tconst getLayerExpert = (index: number) => {\n240\t  const notes = [\n241\t    \"Un primaire inadapté, c'est un système qui cloque et se décolle. Le support décide de tout.\",\n242\t    \"Le cool roof traite la cause : la toiture chauffe moins, donc le bâtiment reçoit moins de calories.\",\n243\t    \"La différence entre une peinture et un investissement, c'est la tenue dans le temps. La finition est là pour protéger la performance.\",\n244\t  ];\n245\t\n246\t  return notes[index] ?? notes[0];\n247\t};\n248\t\n249\tconst Label = ({ children, light = false }: { children: string; light?: boolean }) => (\n250\t  <div className=\"mb-5 flex items-center gap-3\">\n251\t    <span className={`h-px w-9 ${light ? 'bg-teal-vivid/70' : 'bg-primary/65'}`} aria-hidden=\"true\" />\n252\t    <span\n253\t      className={`font-body text-[11px] font-bold uppercase tracking-[0.22em] ${\n254\t        light ? 'text-teal-vivid' : 'text-primary'\n255\t      }`}\n256\t    >\n257\t      {children}\n258\t    </span>\n259\t  </div>\n260\t);\n261\t\n262\tconst PrimaryCTA = ({ label, href }: { label: string; href: string }) => (\n263\t  <a\n264\t    href={href}\n265\t    className=\"group inline-flex items-center justify-center gap-2 rounded-full cta-gradient py-2.5 pl-6 pr-2 font-semibold text-white\"\n266\t  >\n267\t    <span className=\"text-sm\">{label}</span>\n268\t    <span className=\"flex h-8 w-8 items-center justify-center rounded-full bg-white/20 transition-transform duration-500 group-hover:translate-x-0.5\">\n269\t      <ArrowRight className=\"h-3.5 w-3.5\" />\n270\t    </span>\n271\t  </a>\n272\t);\n273\t\n274\texport const RoofHero = ({ page }: { page: RoofPageData }) => {\n275\t  const [form, setForm] = useState({ climate: '', surface: '', email: '' });\n276\t  const [submitted, setSubmitted] = useState(false);\n277\t  const surfaceNum = parseFloat(form.surface) || 0;\n278\t  const estimate = surfaceNum ? `${new Intl.NumberFormat('fr-FR').format(surfaceNum * 22.5)} €` : '20-25 €/m²';\n279\t\n280\t  return (\n281\t    <section\n282\t      aria-labelledby={`${page.slug}-hero-title`}\n283\t      className=\"relative isolate flex min-h-[100svh] flex-col overflow-hidden bg-navy text-cream\"\n284\t    >\n285\t      <WpImage\n286\t        image={{ sourceUrl: page.heroImage, altText: page.heroImageAlt, width: null, height: null }}\n287\t        alt={page.heroImageAlt}\n288\t        fill\n289\t        priority\n290\t        className={`-z-10 size-full scale-[1.02] object-cover${\n291\t          page.slug === 'membrane-bitumineuse' ? ' object-[center_28%]' : ''\n292\t        }`}\n293\t      />\n294\t      <div\n295\t        aria-hidden=\"true\"\n296\t        className=\"absolute inset-0 -z-10 hidden bg-gradient-to-r from-navy/[0.94] via-navy/62 to-navy/25 lg:block\"\n297\t      />\n298\t      <div\n299\t        aria-hidden=\"true\"\n300\t        className={`absolute inset-0 -z-10 bg-gradient-to-b lg:hidden ${\n301\t          page.slug === 'membrane-bitumineuse'\n302\t            ? 'from-navy/92 via-navy/58 to-navy/96'\n303\t            : 'from-navy/84 via-navy/38 to-navy/96'\n304\t        }`}\n305\t      />\n306\t      <div aria-hidden=\"true\" className=\"absolute inset-x-0 bottom-0 -z-10 h-[28%] bg-gradient-to-t from-navy via-navy/85 to-transparent\" />\n307\t\n308\t      <div className=\"container relative z-10 mx-auto flex flex-1 items-center px-6 pb-10 pt-24 lg:px-12 lg:pb-16 lg:pt-28\">\n309\t        <div className=\"grid w-full grid-cols-1 items-center gap-10 lg:grid-cols-[55fr_45fr] lg:gap-12\">\n310\t          <div className=\"max-w-2xl space-y-6 lg:space-y-8\">\n311\t            <ScrollReveal>\n312\t              <nav className=\"flex items-center gap-2 font-body text-xs text-cream/50\">\n313\t                <a href=\"/\" className=\"transition-colors hover:text-cream/75\">Accueil</a>\n314\t                <span className=\"text-cream/28\">/</span>\n315\t                <span>Toitures</span>\n316\t                <span className=\"text-cream/28\">/</span>\n317\t                <span className=\"text-cream/78\">{page.breadcrumb}</span>\n318\t              </nav>\n319\t            </ScrollReveal>\n320\t\n321\t            <ScrollReveal>\n322\t              <h1\n323\t                id={`${page.slug}-hero-title`}\n324\t                className=\"font-satoshi font-bold leading-[1.02] text-white\"\n325\t                style={{ fontSize: 'clamp(2.25rem, 4.6vw, 4rem)', letterSpacing: '-0.03em' }}\n326\t              >\n327\t                {page.h1}\n328\t              </h1>\n329\t            </ScrollReveal>\n330\t\n331\t            <ScrollReveal>\n332\t              <p\n333\t                className=\"max-w-xl font-satoshi font-medium leading-[1.3] text-cream/66\"\n334\t                style={{ fontSize: 'clamp(1rem, 1.5vw, 1.375rem)', letterSpacing: '-0.005em' }}\n335\t              >\n336\t                {page.lead}\n337\t              </p>\n338\t            </ScrollReveal>\n339\t\n340\t            <ScrollReveal>\n341\t              <ul className=\"hidden gap-4 pt-1 sm:flex sm:flex-wrap lg:gap-6\" aria-label=\"Bénéfices clés\">\n342\t                {page.heroStats.map((stat, index) => {\n343\t                  const Icon = [Thermometer, ShieldCheck, TrendingDown][index] ?? BadgeCheck;\n344\t                  return (\n345\t                    <li\n346\t                      key={stat.label}\n347\t                      className={`flex items-start gap-3 ${index !== 0 ? 'sm:border-l sm:border-white/10 sm:pl-6' : ''}`}\n348\t                    >\n349\t                      <Icon className=\"mt-0.5 h-[18px] w-[18px] shrink-0 text-teal-vivid\" strokeWidth={1.5} />\n350\t                      <div className=\"leading-tight\">\n351\t                        <p className=\"font-satoshi text-[15px] font-bold text-white lg:text-base\">{stat.value}</p>\n352\t                        <p className=\"mt-1 font-body text-[12.5px] text-cream/55 lg:text-[13px]\">{stat.label}</p>\n353\t                      </div>\n354\t                    </li>\n355\t                  );\n356\t                })}\n357\t              </ul>\n358\t            </ScrollReveal>\n359\t          </div>\n360\t\n361\t          <ScrollReveal>\n362\t            <div className=\"rounded-[1.5rem] border border-white/[0.08] bg-white/[0.04] p-1.5 backdrop-blur-sm\">\n363\t              <div className=\"rounded-[calc(1.5rem-6px)] border border-white/[0.06] bg-[#0b1a2b]/80 p-4 shadow-[inset_0_1px_1px_rgba(255,255,255,0.06)] backdrop-blur-xl lg:p-7\">\n364\t                {!submitted ? (\n365\t                  <>\n366\t                    <h2 className=\"mb-1 text-center font-satoshi text-xl font-bold text-white lg:text-2xl\">\n367\t                      Estimez le gain possible\n368\t                    </h2>\n369\t                    <p className=\"mb-4 text-center font-body text-[12px] text-white/50\">\n370\t                      Réponse personnalisée sous 24h\n371\t                    </p>\n372\t                    <form\n373\t                      onSubmit={(event) => {\n374\t                        event.preventDefault();\n375\t                        setSubmitted(true);\n376\t                      }}\n377\t                      className=\"space-y-2.5 lg:space-y-3\"\n378\t                    >\n379\t                      <input\n380\t                        value={page.breadcrumb}\n381\t                        readOnly\n382\t                        className=\"w-full rounded-xl border border-white/[0.12] bg-white/[0.07] px-4 py-3 font-body text-sm text-white outline-none\"\n383\t                      />\n384\t                      <select\n385\t                        required\n386\t                        value={form.climate}\n387\t                        onChange={(e) => setForm({ ...form, climate: e.target.value })}\n388\t                        className=\"w-full appearance-none rounded-xl border border-white/[0.12] bg-white/[0.07] px-4 py-3 font-body text-sm text-white transition-all duration-300 focus:border-white/25 focus:outline-none focus:ring-2 focus:ring-primary/50\"\n389\t                      >\n390\t                        <option value=\"\" disabled className=\"bg-card text-foreground\">Bâtiment climatisé ?</option>\n391\t                        {['Oui', 'Non', 'Partiellement', 'À confirmer'].map((option) => (\n392\t                          <option key={option} value={option} className=\"bg-card text-foreground\">{option}</option>\n393\t                        ))}\n394\t                      </select>\n395\t                      <input\n396\t                        type=\"number\"\n397\t                        placeholder=\"Surface toiture (m²)\"\n398\t                        required\n399\t                        min=\"1\"\n400\t                        value={form.surface}\n401\t                        onChange={(e) => setForm({ ...form, surface: e.target.value })}\n402\t                        className=\"w-full rounded-xl border border-white/[0.12] bg-white/[0.07] px-4 py-3 font-body text-sm text-white placeholder:text-white/40 transition-all duration-300 focus:border-white/25 focus:outline-none focus:ring-2 focus:ring-primary/50\"\n403\t                      />\n404\t                      <input\n405\t                        type=\"email\"\n406\t                        placeholder=\"Email professionnel\"\n407\t                        required\n408\t                        value={form.email}\n409\t                        onChange={(e) => setForm({ ...form, email: e.target.value })}\n410\t                        className=\"w-full rounded-xl border border-white/[0.12] bg-white/[0.07] px-4 py-3 font-body text-sm text-white placeholder:text-white/40 transition-all duration-300 focus:border-white/25 focus:outline-none focus:ring-2 focus:ring-primary/50\"\n411\t                      />\n412\t\n413\t                      <button\n414\t                        type=\"submit\"\n415\t                        className=\"group mt-1 flex w-full items-center justify-center gap-3 rounded-full cta-gradient py-3 font-semibold text-white active:scale-[0.98]\"\n416\t                      >\n417\t                        <span className=\"text-[15px]\">Voir mon potentiel</span>\n418\t                        <span className=\"flex h-8 w-8 items-center justify-center rounded-full bg-white/20 transition-transform duration-500 group-hover:translate-x-0.5\">\n419\t                          <ArrowRight className=\"h-4 w-4\" />\n420\t                        </span>\n421\t                      </button>\n422\t                    </form>\n423\t\n424\t                    <p className=\"mt-3 text-center font-body text-[11px] text-white/35\">\n425\t                      Sans engagement · Étude adaptée au support\n426\t                    </p>\n427\t                  </>\n428\t                ) : (\n429\t                  <div className=\"py-4 text-center\">\n430\t                    <div className=\"mx-auto mb-4 flex h-12 w-12 items-center justify-center rounded-full bg-primary/20\">\n431\t                      <ShieldCheck className=\"h-6 w-6 text-primary\" />\n432\t                    </div>\n433\t                    <p className=\"mb-1 font-body text-sm text-white/60\">Base indicative pour {new Intl.NumberFormat('fr-FR').format(surfaceNum)} m²</p>\n434\t                    <p className=\"mb-4 font-satoshi text-2xl font-bold text-white\">{estimate}</p>\n435\t                    <p className=\"mb-4 font-body text-[13px] text-white/50\">\n436\t                      Un conseiller affine le chiffrage selon l'état réel de la toiture.\n437\t                    </p>\n438\t                    <button onClick={() => setSubmitted(false)} className=\"font-body text-sm font-semibold text-primary hover:underline\">\n439\t                      Modifier ma demande\n440\t                    </button>\n441\t                  </div>\n442\t                )}\n443\t              </div>\n444\t            </div>\n445\t          </ScrollReveal>\n446\t        </div>\n447\t      </div>\n448\t\n449\t      <div className=\"relative z-10 hidden border-t border-white/10 bg-navy/78 backdrop-blur-md lg:block\">\n450\t        <div className=\"container mx-auto flex items-center gap-8 px-12 py-5\">\n451\t          <p className=\"shrink-0 font-body text-[10px] font-semibold uppercase tracking-[0.24em] text-cream/45\">\n452\t            Ils nous font confiance\n453\t          </p>\n454\t          <div className=\"flex flex-1 items-center justify-between gap-8\">\n455\t            {logos.map((logo) => (\n456\t              <span key={logo.name} className=\"flex h-8 w-28 items-center justify-center\">\n457\t                <img\n458\t                  src={logo.url}\n459\t                  alt={logo.name}\n460\t                  className=\"max-h-7 max-w-full object-contain opacity-65 brightness-0 invert transition-opacity duration-300 hover:opacity-95\"\n461\t                  loading=\"eager\"\n462\t                  decoding=\"async\"\n463\t                />\n464\t              </span>\n465\t            ))}\n466\t          </div>\n467\t        </div>\n468\t      </div>\n469\t    </section>\n470\t  );\n471\t};\n472\t\n473\tconst ProblemSection = ({ page }: { page: RoofPageData }) => {\n474\t  const title = getProblemTitle(page.problem.title);\n475\t  const visual = supportVisuals[page.slug] ?? supportVisuals['membrane-bitumineuse'];\n476\t\n477\t  return (\n478\t    <section className=\"relative overflow-hidden bg-cream py-16 lg:py-36\">\n479\t      <div className=\"container relative mx-auto px-4 lg:px-8\">\n480\t        <ScrollReveal>\n481\t          <div className=\"mx-auto mb-14 max-w-3xl text-center lg:mb-20\">\n482\t            <h2\n483\t              className=\"font-satoshi text-3xl font-black text-foreground sm:text-4xl lg:text-[3rem]\"\n484\t              style={{ letterSpacing: '-0.03em', lineHeight: 1.05 }}\n485\t            >\n486\t              {title.strong}\n487\t              {title.muted && <span className=\"text-foreground/30\"> {title.muted}</span>}\n488\t            </h2>\n489\t          </div>\n490\t        </ScrollReveal>\n491\t\n492\t        <div className=\"grid grid-cols-1 items-center gap-12 lg:grid-cols-12 lg:gap-16\">\n493\t          <div className=\"order-2 lg:order-1 lg:col-span-5\">\n494\t            <ScrollReveal>\n495\t              <div className=\"relative\">\n496\t                <div className=\"pointer-events-none absolute -inset-8 rounded-[3rem] bg-[radial-gradient(ellipse_at_50%_50%,_hsl(var(--terracotta)/0.18)_0%,_transparent_65%)] blur-2xl\" />\n497\t                <div className=\"relative aspect-square overflow-hidden rounded-[2rem] bg-white shadow-[0_30px_80px_-15px_hsl(var(--terracotta-dark)/0.25),_0_10px_30px_-5px_hsl(var(--terracotta)/0.12)]\">\n498\t                  <WpImage\n499\t                    image={{ sourceUrl: visual.hot, altText: '', width: null, height: null }}\n500\t                    alt=\"\"\n501\t                    fill\n502\t                    className=\"h-full w-full object-contain p-4\"\n503\t                  />\n504\t                </div>\n505\t              </div>\n506\t              <p className=\"mt-4 text-center font-body text-[11px] uppercase tracking-wide text-terracotta/60\">\n507\t                {visual.hotLabel}\n508\t              </p>\n509\t            </ScrollReveal>\n510\t          </div>\n511\t\n512\t          <div className=\"order-1 lg:order-2 lg:col-span-7 lg:pl-12\">\n513\t            <ScrollReveal stagger>\n514\t              <div\n515\t                className=\"space-y-8 border-l-2 pl-8 lg:space-y-10 lg:pl-10\"\n516\t                style={{ borderImage: 'linear-gradient(to bottom, hsl(var(--terracotta)), hsl(var(--terracotta-dark))) 1' }}\n517\t              >\n518\t                {page.problem.cards.map((card, index) => {\n519\t                  const Icon = problemIcons[index] ?? HelpCircle;\n520\t                  return (\n521\t                    <div key={card.title}>\n522\t                      <div className=\"mb-2 flex items-center gap-3\">\n523\t                        <Icon className=\"h-5 w-5 text-terracotta\" strokeWidth={1.8} />\n524\t                        <h3\n525\t                          className=\"font-satoshi text-xl font-bold text-foreground lg:text-2xl\"\n526\t                          style={{ letterSpacing: '-0.02em', lineHeight: 1.2 }}\n527\t                        >\n528\t                          {card.title}\n529\t                        </h3>\n530\t                      </div>\n531\t                      <p className=\"font-body text-base leading-relaxed text-foreground/55\">{card.text}</p>\n532\t                    </div>\n533\t                  );\n534\t                })}\n535\t              </div>\n536\t            </ScrollReveal>\n537\t          </div>\n538\t        </div>\n539\t\n540\t        <div className=\"mt-20 grid grid-cols-1 items-center gap-12 lg:mt-28 lg:grid-cols-12 lg:gap-16\">\n541\t          <div className=\"order-2 lg:order-2 lg:col-span-5\">\n542\t            <ScrollReveal>\n543\t              <div className=\"relative\">\n544\t                <div className=\"pointer-events-none absolute -inset-8 rounded-[3rem] bg-[radial-gradient(ellipse_at_50%_50%,_rgba(32,150,140,0.18)_0%,_transparent_65%)] blur-2xl\" />\n545\t                <div className=\"relative aspect-square overflow-hidden rounded-[2rem] bg-white shadow-[0_30px_80px_-15px_rgba(20,120,110,0.20),_0_10px_30px_-5px_rgba(32,150,140,0.10)]\">\n546\t                  <WpImage\n547\t                    image={{ sourceUrl: visual.cool, altText: '', width: null, height: null }}\n548\t                    alt=\"\"\n549\t                    fill\n550\t                    className=\"h-full w-full object-contain p-4\"\n551\t                  />\n552\t                </div>\n553\t              </div>\n554\t              <p className=\"mt-4 text-center font-body text-[11px] uppercase tracking-wide text-primary/60\">\n555\t                {visual.coolLabel}\n556\t              </p>\n557\t            </ScrollReveal>\n558\t          </div>\n559\t\n560\t          <div className=\"order-1 lg:order-1 lg:col-span-7 lg:pr-12\">\n561\t            <ScrollReveal>\n562\t              <h3\n563\t                className=\"mb-8 max-w-xl font-satoshi text-3xl font-black text-foreground sm:text-4xl lg:text-[3rem]\"\n564\t                style={{ letterSpacing: '-0.03em', lineHeight: 1.05 }}\n565\t              >\n566\t                Le cool roof : une réponse concrète\n567\t                <span className=\"text-foreground/30\"> au problème de chaleur.</span>\n568\t              </h3>\n569\t              <p className=\"mb-8 max-w-lg font-body text-base leading-relaxed text-foreground/50\">\n570\t                Une surface claire renvoie le rayonnement solaire avant qu'il ne pénètre dans le bâtiment. La toiture chauffe moins, les derniers niveaux respirent, et le support subit moins d'UV et de chocs thermiques.\n571\t              </p>\n572\t              <PrimaryCTA label=\"Demander un devis\" href=\"/diagnostic\" />\n573\t            </ScrollReveal>\n574\t          </div>\n575\t        </div>\n576\t      </div>\n577\t    </section>\n578\t  );\n579\t};\n580\t\n581\tconst SolutionSection = ({ page }: { page: RoofPageData }) => {\n582\t  const [active, setActive] = useState(0);\n583\t\n584\t  return (\n585\t    <section className=\"relative bg-white\">\n586\t      <div className=\"container mx-auto px-4 lg:px-8\">\n587\t        <ScrollReveal>\n588\t          <div className=\"flex flex-col gap-8 pb-10 pt-16 lg:flex-row lg:items-end lg:gap-16 lg:pb-16 lg:pt-32\">\n589\t            <div className=\"lg:w-2/3\">\n590\t              <p className=\"mb-6 font-body text-[10px] font-semibold uppercase tracking-[0.25em] text-muted-foreground\">\n591\t                {page.solution.badge}\n592\t              </p>\n593\t              <h2\n594\t                className=\"font-satoshi text-3xl font-black text-foreground sm:text-4xl lg:text-[3rem]\"\n595\t                style={{ letterSpacing: '-0.03em', lineHeight: 1.05 }}\n596\t              >\n597\t                <span className=\"text-foreground/30\">Un système conçu pour </span>\n598\t                réfléchir, protéger et durer.\n599\t              </h2>\n600\t            </div>\n601\t            <div className=\"lg:w-1/3 lg:pb-1\">\n602\t              <p className=\"font-body text-base leading-relaxed text-foreground/52 lg:text-right lg:text-lg\">\n603\t                Un primaire, une résine, un vernis qui garantissent la performance de votre toiture dans le temps.\n604\t              </p>\n605\t              <div className=\"mt-5 flex lg:justify-end\">\n606\t                <PrimaryCTA label=\"Demander un devis\" href=\"/diagnostic\" />\n607\t              </div>\n608\t            </div>\n609\t          </div>\n610\t        </ScrollReveal>\n611\t\n612\t        <div className=\"flex flex-col gap-12 pb-24 lg:flex-row lg:gap-16 lg:pb-32\">\n613\t          <div className=\"overflow-hidden rounded-2xl shadow-[0_20px_60px_-15px_rgba(0,0,0,0.08)] lg:hidden\">\n614\t            <WpImage\n615\t              image={{\n616\t                sourceUrl: coolRoofLayers.src,\n617\t                altText: 'Coupe du système cool roof Covalba',\n618\t                width: coolRoofLayers.width,\n619\t                height: coolRoofLayers.height,\n620\t              }}\n621\t              alt=\"Coupe du système cool roof Covalba\"\n622\t              className=\"w-full\"\n623\t            />\n624\t          </div>\n625\t\n626\t          <div className=\"lg:w-1/2 lg:sticky lg:top-[20vh] lg:self-start\">\n627\t            {layerTitles.map((item, index) => {\n628\t              const isOpen = active === index;\n629\t              const colors = layerColors[index] ?? layerColors[0];\n630\t              return (\n631\t                <div key={item} className=\"border-b border-border last:border-b-0\">\n632\t                  <button\n633\t                    onClick={() => setActive(index)}\n634\t                    className=\"group flex w-full items-center gap-4 py-6 text-left\"\n635\t                  >\n636\t                    <span\n637\t                      className={`inline-flex h-8 w-8 shrink-0 items-center justify-center rounded-full font-body text-[11px] font-bold transition-all duration-300 ${\n638\t                        isOpen ? colors.pill : 'bg-muted text-muted-foreground'\n639\t                      }`}\n640\t                    >\n641\t                      0{index + 1}\n642\t                    </span>\n643\t                    <h3\n644\t                      className={`flex-1 font-satoshi text-xl font-bold transition-colors duration-300 lg:text-2xl ${\n645\t                        isOpen ? 'text-foreground' : 'text-foreground/50 group-hover:text-foreground/80'\n646\t                      }`}\n647\t                    >\n648\t                      {item}\n649\t                    </h3>\n650\t                    <ChevronDown\n651\t                      className={`h-5 w-5 shrink-0 transition-all duration-300 ${\n652\t                        isOpen ? `${colors.chevron} rotate-180` : 'text-foreground/25'\n653\t                      }`}\n654\t                      strokeWidth={2}\n655\t                    />\n656\t                  </button>\n657\t\n658\t                  <div\n659\t                    className={`grid transition-all duration-500 ${\n660\t                      isOpen ? 'grid-rows-[1fr] opacity-100' : 'grid-rows-[0fr] opacity-0'\n661\t                    }`}\n662\t                  >\n663\t                    <div className=\"overflow-hidden\">\n664\t                      <div className=\"pb-8 pl-6 lg:pl-12\">\n665\t                        <p className=\"mb-6 font-body text-base leading-relaxed text-foreground/65 lg:text-lg\">\n666\t                          {getLayerDescription(index)}\n667\t                        </p>\n668\t                        <div className=\"flex items-start gap-3 rounded-xl bg-foreground/[0.03] p-4\">\n669\t                          <div className=\"relative mt-0.5 h-9 w-9 shrink-0 overflow-hidden rounded-full\">\n670\t                            <WpImage\n671\t                              image={{\n672\t                                sourceUrl: '/maxime-bourassin.jpg',\n673\t                                altText: 'Maxime Bourassin, fondateur Covalba',\n674\t                                width: null,\n675\t                                height: null,\n676\t                              }}\n677\t                              alt=\"Maxime Bourassin, fondateur Covalba\"\n678\t                              fill\n679\t                              className=\"object-cover\"\n680\t                            />\n681\t                          </div>\n682\t                          <div>\n683\t                            <p className=\"font-body text-[15px] italic leading-relaxed text-foreground/65 lg:text-base\">\n684\t                              \"{getLayerExpert(index)}\"\n685\t                            </p>\n686\t                            <p className=\"mt-2 font-body text-xs font-semibold text-foreground/50\">\n687\t                              Maxime Bourassin, fondateur\n688\t                            </p>\n689\t                          </div>\n690\t                        </div>\n691\t                        {index === 0 && page.solution.note && (\n692\t                          <p className=\"mt-4 rounded-xl bg-primary/5 p-4 font-body text-sm leading-relaxed text-foreground/62\">\n693\t                            {page.solution.note}\n694\t                          </p>\n695\t                        )}\n696\t                      </div>\n697\t                    </div>\n698\t                  </div>\n699\t                </div>\n700\t              );\n701\t            })}\n702\t          </div>\n703\t\n704\t          <div className=\"hidden lg:block lg:w-1/2\">\n705\t            <div className=\"relative overflow-hidden rounded-2xl shadow-[0_30px_80px_-15px_rgba(0,0,0,0.08)]\">\n706\t              <WpImage\n707\t                image={{\n708\t                  sourceUrl: coolRoofLayers.src,\n709\t                  altText: 'Coupe du système cool roof Covalba',\n710\t                  width: coolRoofLayers.width,\n711\t                  height: coolRoofLayers.height,\n712\t                }}\n713\t                alt=\"Coupe du système cool roof Covalba\"\n714\t                className=\"w-full\"\n715\t              />\n716\t              {layerTitles.map((item, index) => {\n717\t                const pos = layerPositions[index];\n718\t                const colors = layerColors[index] ?? layerColors[0];\n719\t                const isActive = active === index;\n720\t                if (!pos) return null;\n721\t\n722\t                return (\n723\t                  <div key={item} className=\"absolute\" style={{ top: pos.top, left: pos.left }}>\n724\t                    <div\n725\t                      className={`absolute -translate-x-1/2 -translate-y-1/2 transition-all duration-500 ${\n726\t                        isActive ? 'scale-125' : 'scale-75 opacity-40'\n727\t                      }`}\n728\t                    >\n729\t                      <div\n730\t                        className={`h-3.5 w-3.5 rounded-full ${\n731\t                          isActive ? colors.dot : 'bg-foreground/20'\n732\t                        } shadow-lg ring-2 ring-white transition-colors duration-500`}\n733\t                      />\n734\t                      {isActive && (\n735\t                        <div className={`absolute inset-0 h-3.5 w-3.5 animate-ping rounded-full ${colors.dot} opacity-30`} />\n736\t                      )}\n737\t                    </div>\n738\t                    <div\n739\t                      className={`pointer-events-none absolute right-5 top-1/2 -translate-y-1/2 transition-all duration-500 ${\n740\t                        isActive ? 'translate-x-0 opacity-100' : 'translate-x-2 opacity-0'\n741\t                      }`}\n742\t                    >\n743\t                      <span className={`whitespace-nowrap rounded-full px-4 py-1.5 font-body text-[13px] font-bold shadow-lg ${colors.pill}`}>\n744\t                        {item}\n745\t                      </span>\n746\t                    </div>\n747\t                  </div>\n748\t                );\n749\t              })}\n750\t            </div>\n751\t          </div>\n752\t        </div>\n753\t      </div>\n754\t    </section>\n755\t  );\n756\t};\n757\t\n758\tconst BenefitsSection = ({ page }: { page: RoofPageData }) => (\n759\t  <section className=\"bg-white py-20 lg:py-32\">\n760\t    <div className=\"container mx-auto px-4 lg:px-8\">\n761\t      <ScrollReveal>\n762\t        <div className=\"mb-10 grid gap-8 lg:grid-cols-[0.82fr_1.18fr] lg:items-end lg:gap-14\">\n763\t          <div>\n764\t            <Label>{page.benefits.badge}</Label>\n765\t            <h2 className=\"font-satoshi text-3xl font-black leading-tight text-foreground sm:text-4xl lg:text-5xl\">\n766\t              {page.benefits.title}\n767\t            </h2>\n768\t          </div>\n769\t          <p className=\"max-w-xl border-l border-primary/30 pl-6 font-body text-base leading-relaxed text-foreground/62 lg:text-lg\">\n770\t            {page.benefits.featured}\n771\t          </p>\n772\t        </div>\n773\t      </ScrollReveal>\n774\t\n775\t      <ScrollReveal stagger>\n776\t        <div className=\"grid gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n777\t          {page.benefits.cards.map((benefit, index) => {\n778\t            const Icon = cardIcons[index] ?? Sparkles;\n779\t            return (\n780\t              <article\n781\t                key={benefit.title}\n782\t                className=\"group overflow-hidden rounded-2xl bg-cream ring-1 ring-foreground/[0.05] transition-all duration-500 hover:-translate-y-1 hover:shadow-[0_24px_70px_-48px_hsl(var(--navy)/0.45)]\"\n783\t              >\n784\t                <div className=\"relative aspect-[4/3] overflow-hidden bg-foreground/[0.04]\">\n785\t                  <WpImage\n786\t                    image={{ sourceUrl: getBenefitImage(page, benefit, index), altText: '', width: null, height: null }}\n787\t                    alt=\"\"\n788\t                    fill\n789\t                    className=\"h-full w-full object-cover transition-transform duration-700 group-hover:scale-[1.035]\"\n790\t                  />\n791\t                  <div className=\"absolute inset-x-0 bottom-0 h-20 bg-gradient-to-t from-cream to-transparent\" />\n792\t                </div>\n793\t                <div className=\"p-5 lg:p-6\">\n794\t                  <div className=\"mb-4 flex h-10 w-10 items-center justify-center rounded-xl bg-white text-primary shadow-[0_12px_30px_-24px_hsl(var(--navy)/0.35)]\">\n795\t                    <Icon className=\"h-5 w-5\" strokeWidth={1.7} />\n796\t                  </div>\n797\t                  <h3 className=\"font-satoshi text-lg font-bold leading-tight text-foreground\">{benefit.title}</h3>\n798\t                  <p className=\"mt-2 font-body text-sm leading-relaxed text-foreground/62\">{benefit.text}</p>\n799\t                </div>\n800\t              </article>\n801\t            );\n802\t          })}\n803\t        </div>\n804\t      </ScrollReveal>\n805\t    </div>\n806\t  </section>\n807\t);\n808\t\n809\tconst RoiOptionCards = ({\n810\t  page,\n811\t  surface,\n812\t  treatmentRange,\n813\t}: {\n814\t  page: RoofPageData;\n815\t  surface: number;\n816\t  treatmentRange: ReturnType<typeof getTreatmentRange>;\n817\t}) => {\n818\t  if (!page.roi.comparison) {\n819\t    return page.roi.afterComparison ? (\n820\t      <article className=\"rounded-2xl bg-white p-6 ring-1 ring-foreground/[0.06] lg:p-8\">\n821\t        <p className=\"font-body text-base leading-relaxed text-foreground/66 lg:text-lg\">\n822\t          {page.roi.afterComparison}\n823\t        </p>\n824\t      </article>\n825\t    ) : null;\n826\t  }\n827\t\n828\t  const options = page.roi.comparison.headers.slice(1);\n829\t  const rows = page.roi.comparison.rows;\n830\t  const investment = rows.find((row) => row[0].toLowerCase().includes('investissement'));\n831\t  const duration = rows.find((row) => row[0].toLowerCase().includes('dur'));\n832\t  const activity = rows.find((row) => row[0].toLowerCase().includes('activ'));\n833\t  const treatmentMidpoint = (treatmentRange.min + treatmentRange.max) / 2;\n834\t\n835\t  return (\n836\t    <div className=\"grid gap-4 lg:grid-cols-3\">\n837\t      {options.map((option, optionIndex) => {\n838\t        const isCovalba = optionIndex === 0;\n839\t        const rawInvestment = investment?.[optionIndex + 1] ?? '';\n840\t        const parsedPrice = parsePricePerM2(rawInvestment);\n841\t        const pricePerM2 = parsedPrice ?? getFallbackPricePerM2(option, optionIndex, treatmentMidpoint);\n842\t        const dynamicInvestment = pricePerM2 ? `~${formatCurrency(surface * pricePerM2)}` : displayCell(rawInvestment);\n843\t\n844\t        return (\n845\t          <article\n846\t            key={option}\n847\t            className={`rounded-2xl p-6 ring-1 ${\n848\t              isCovalba\n849\t                ? 'bg-[#142333] text-white ring-transparent'\n850\t                : 'bg-white text-foreground ring-foreground/[0.06]'\n851\t            }`}\n852\t          >\n853\t            <div className=\"mb-6 flex items-start justify-between gap-4\">\n854\t              <h3 className=\"font-satoshi text-xl font-black leading-tight\">{option}</h3>\n855\t              {isCovalba && (\n856\t                <span className=\"inline-flex h-7 w-7 shrink-0 items-center justify-center rounded-full bg-teal-vivid/15 text-teal-vivid\">\n857\t                  <Check className=\"h-4 w-4\" strokeWidth={2.4} />\n858\t                </span>\n859\t              )}\n860\t            </div>\n861\t            <p className={`font-satoshi text-3xl font-black leading-none ${isCovalba ? 'text-teal-vivid' : 'text-terracotta'}`}>\n862\t              {dynamicInvestment}\n863\t            </p>\n864\t            {pricePerM2 && (\n865\t              <p className={`mt-2 font-body text-xs font-semibold ${isCovalba ? 'text-white/45' : 'text-foreground/40'}`}>\n866\t                base {new Intl.NumberFormat('fr-FR').format(surface)} m² · {pricePerM2.toLocaleString('fr-FR')} €/m²\n867\t              </p>\n868\t            )}\n869\t            <dl className=\"mt-6 space-y-3 border-t border-current/10 pt-5\">\n870\t              {[duration, activity].filter(Boolean).map((row) => (\n871\t                <div key={row![0]} className=\"grid grid-cols-[0.75fr_1fr] gap-4\">\n872\t                  <dt className={`font-body text-xs font-bold uppercase tracking-[0.14em] ${isCovalba ? 'text-white/38' : 'text-foreground/35'}`}>\n873\t                    {displayCell(row![0])}\n874\t                  </dt>\n875\t                  <dd className={`font-body text-sm leading-relaxed ${isCovalba ? 'text-white/74' : 'text-foreground/62'}`}>\n876\t                    {displayCell(row![optionIndex + 1])}\n877\t                  </dd>\n878\t                </div>\n879\t              ))}\n880\t            </dl>\n881\t          </article>\n882\t        );\n883\t      })}\n884\t    </div>\n885\t  );\n886\t};\n887\t\n888\tconst ROICalculator = ({\n889\t  page,\n890\t  surface,\n891\t  selectedSituation,\n892\t  treatmentRange,\n893\t  onSurfaceChange,\n894\t  onSituationChange,\n895\t}: {\n896\t  page: RoofPageData;\n897\t  surface: number;\n898\t  selectedSituation: string;\n899\t  treatmentRange: ReturnType<typeof getTreatmentRange>;\n900\t  onSurfaceChange: (surface: number) => void;\n901\t  onSituationChange: (situation: string) => void;\n902\t}) => {\n903\t  const treatmentLow = surface * treatmentRange.min;\n904\t  const treatmentHigh = surface * treatmentRange.max;\n905\t  const referencePrice = selectedSituation.toLowerCase().includes('isolation') ? 150 : 90;\n906\t  const referenceCost = surface * referencePrice;\n907\t  const potentialGap = Math.max(referenceCost - treatmentHigh, 0);\n908\t\n909\t  return (\n910\t    <div className=\"mb-10 rounded-[2rem] bg-[#142333] p-5 text-white shadow-[0_34px_90px_-64px_hsl(var(--navy)/0.65)] lg:p-8\">\n911\t      <div className=\"grid gap-7 lg:grid-cols-[0.88fr_1.12fr] lg:items-end\">\n912\t        <div>\n913\t          <p className=\"font-body text-[10px] font-semibold uppercase tracking-[0.25em] text-teal-vivid/70\">\n914\t            Calculateur indicatif\n915\t          </p>\n916\t          <h3 className=\"mt-4 max-w-lg font-satoshi text-2xl font-black leading-tight lg:text-3xl\">\n917\t            Ajustez la surface et l'état de la toiture.\n918\t          </h3>\n919\t          <p className=\"mt-3 max-w-lg font-body text-sm leading-relaxed text-white/52\">\n920\t            Par défaut : 5 000 m², surface type d'un entrepôt ou bâtiment industriel à traiter.\n921\t          </p>\n922\t        </div>\n923\t\n924\t        <div className=\"grid gap-3 sm:grid-cols-[0.72fr_1.28fr]\">\n925\t          <label className=\"block\">\n926\t            <span className=\"mb-2 block font-body text-[11px] font-bold uppercase tracking-[0.16em] text-white/40\">\n927\t              Surface\n928\t            </span>\n929\t            <input\n930\t              type=\"number\"\n931\t              min={100}\n932\t              step={100}\n933\t              value={surface}\n934\t              onChange={(event) => onSurfaceChange(Math.max(100, Number(event.target.value) || 100))}\n935\t              className=\"h-12 w-full rounded-xl border border-white/10 bg-white/[0.07] px-4 font-body text-sm font-semibold text-white outline-none transition focus:border-teal-vivid/50 focus:ring-2 focus:ring-teal-vivid/20\"\n936\t              aria-label=\"Surface à traiter en mètres carrés\"\n937\t            />\n938\t          </label>\n939\t          <label className=\"block\">\n940\t            <span className=\"mb-2 block font-body text-[11px] font-bold uppercase tracking-[0.16em] text-white/40\">\n941\t              Situation\n942\t            </span>\n943\t            <select\n944\t              value={selectedSituation}\n945\t              onChange={(event) => onSituationChange(event.target.value)}\n946\t              className=\"h-12 w-full rounded-xl border border-white/10 bg-white/[0.07] px-4 font-body text-sm font-semibold text-white outline-none transition focus:border-teal-vivid/50 focus:ring-2 focus:ring-teal-vivid/20\"\n947\t              aria-label=\"Situation de la toiture\"\n948\t            >\n949\t              {page.roi.situation.rows.map((row) => (\n950\t                <option key={row[0]} value={row[0]} className=\"bg-card text-foreground\">\n951\t                  {row[0]}\n952\t                </option>\n953\t              ))}\n954\t            </select>\n955\t          </label>\n956\t        </div>\n957\t      </div>\n958\t\n959\t      <div className=\"mt-7 grid gap-3 md:grid-cols-3\">\n960\t        {[\n961\t          {\n962\t            label: treatmentRange.label,\n963\t            value: `${formatCurrency(treatmentLow)} - ${formatCurrency(treatmentHigh)}`,\n964\t            detail: `${treatmentRange.min}-${treatmentRange.max} €/m² selon préparation`,\n965\t            valueClass: 'text-teal-vivid',\n966\t          },\n967\t          {\n968\t            label: 'Réfection de référence',\n969\t            value: `~${formatCurrency(referenceCost)}`,\n970\t            detail: `${referencePrice} €/m², ordre de grandeur à comparer`,\n971\t            valueClass: 'text-terracotta',\n972\t          },\n973\t          {\n974\t            label: 'Écart potentiel',\n975\t            value: `jusqu'à ${formatCurrency(potentialGap)}`,\n976\t            detail: \"Investissement lourd évité ou repoussé si le support est viable\",\n977\t            valueClass: 'text-teal-vivid',\n978\t          },\n979\t        ].map((item) => (\n980\t          <article key={item.label} className=\"rounded-2xl bg-white/[0.07] p-5 ring-1 ring-white/10\">\n981\t            <p className=\"font-body text-[11px] font-bold uppercase tracking-[0.16em] text-white/38\">{item.label}</p>\n982\t            <p className={`mt-3 font-satoshi text-2xl font-black leading-tight ${item.valueClass}`}>{item.value}</p>\n983\t            <p className=\"mt-2 font-body text-xs leading-relaxed text-white/45\">{item.detail}</p>\n984\t          </article>\n985\t        ))}\n986\t      </div>\n987\t      <p className=\"mt-4 font-body text-xs leading-relaxed text-white/38\">\n988\t        Chiffrage indicatif : l'étude ajuste le prix selon l'accès, la préparation, les points singuliers et l'état réel du support.\n989\t      </p>\n990\t    </div>\n991\t  );\n992\t};\n993\t\n994\tconst getSituationImage = (recommendation: string) => {\n995\t  const lower = recommendation.toLowerCase();\n996\t  if (lower.includes('covametal')) return covaMetalProduct;\n997\t  if (lower.includes('covaseal')) return covaSealProduct;\n998\t  if (lower.includes('cova')) return covaTherm20Product;\n999\t  return covaTherm8Product;\n1000\t};\n1001\t\n1002\tconst SituationCards = ({ rows }: { rows: string[][] }) => (\n1003\t  <div className=\"grid gap-4 md:grid-cols-2\">\n1004\t    {rows.map((row) => (\n1005\t      <article key={row[0]} className=\"grid gap-4 rounded-2xl bg-white p-4 ring-1 ring-foreground/[0.06] sm:grid-cols-[128px_1fr] lg:grid-cols-[190px_1fr] lg:gap-5 lg:p-5\">\n1006\t        <div className=\"flex aspect-[4/3] items-center justify-center rounded-xl bg-gradient-to-br from-cream to-white p-4 shadow-[inset_0_1px_0_rgba(255,255,255,0.75),_0_18px_44px_-34px_hsl(var(--navy)/0.45)] ring-1 ring-foreground/[0.04] sm:aspect-square lg:p-6\">\n1007\t          {(() => {\n1008\t            const situationImg = getSituationImage(row[1]);\n1009\t            return (\n1010\t              <WpImage\n1011\t                image={{\n1012\t                  sourceUrl: situationImg.src,\n1013\t                  altText: '',\n1014\t                  width: situationImg.width,\n1015\t                  height: situationImg.height,\n1016\t                }}\n1017\t                alt=\"\"\n1018\t                className=\"max-h-full max-w-full object-contain\"\n1019\t              />\n1020\t            );\n1021\t          })()}\n1022\t        </div>\n1023\t        <div className=\"self-center\">\n1024\t          <p className=\"font-satoshi text-lg font-bold leading-tight text-foreground\">{row[0]}</p>\n1025\t          <p className=\"mt-2 font-body text-sm font-bold text-primary\">{row[1]}</p>\n1026\t          <p className=\"mt-2 font-body text-sm leading-relaxed text-foreground/58\">{row[2]}</p>\n1027\t        </div>\n1028\t      </article>\n1029\t    ))}\n1030\t  </div>\n1031\t);\n1032\t\n1033\tconst ROISection = ({ page }: { page: RoofPageData }) => {\n1034\t  const [surface, setSurface] = useState(5000);\n1035\t  const [selectedSituation, setSelectedSituation] = useState(page.roi.situation.rows[0]?.[0] ?? '');\n1036\t  const treatmentRange = getTreatmentRange(page, selectedSituation);\n1037\t\n1038\t  return (\n1039\t    <section className=\"bg-cream py-20 lg:py-32\">\n1040\t      <div className=\"container mx-auto px-4 lg:px-8\">\n1041\t      <ScrollReveal>\n1042\t        <div className=\"mx-auto mb-12 max-w-3xl text-center lg:mb-16\">\n1043\t          <div className=\"flex justify-center\">\n1044\t            <Label>{page.roi.badge}</Label>\n1045\t          </div>\n1046\t          <h2 className=\"font-satoshi text-3xl font-black leading-tight text-foreground sm:text-4xl lg:text-[3rem]\">\n1047\t            {page.roi.title}\n1048\t          </h2>\n1049\t          <p className=\"mx-auto mt-5 max-w-2xl font-body text-base leading-relaxed text-foreground/58 lg:text-lg\">\n1050\t            {page.roi.intro}\n1051\t          </p>\n1052\t        </div>\n1053\t      </ScrollReveal>\n1054\t\n1055\t      <ScrollReveal>\n1056\t        <div className=\"mb-12 grid gap-4 md:grid-cols-3\">\n1057\t          {[\n1058\t            ['20-25 €/m²', 'pour traiter et rafraîchir'],\n1059\t            ['8-10 ans', 'de réfection repoussée'],\n1060\t            ['0 arrêt', \"d'activité pendant le chantier\"],\n1061\t          ].map(([value, label]) => (\n1062\t            <article key={value} className=\"rounded-2xl bg-white p-6 text-center ring-1 ring-foreground/[0.06]\">\n1063\t              <p className=\"font-satoshi text-4xl font-black leading-none text-primary\">{value}</p>\n1064\t              <p className=\"mt-3 font-body text-sm font-semibold text-foreground/52\">{label}</p>\n1065\t            </article>\n1066\t          ))}\n1067\t        </div>\n1068\t      </ScrollReveal>\n1069\t\n1070\t      <ScrollReveal>\n1071\t        <div className=\"mb-8 max-w-2xl\">\n1072\t          <div>\n1073\t            <p className=\"font-body text-[10px] font-semibold uppercase tracking-[0.25em] text-primary/55\">\n1074\t              Comparer les options\n1075\t            </p>\n1076\t            <h3 className=\"mt-4 font-satoshi text-2xl font-black leading-tight text-foreground lg:text-3xl\">\n1077\t              Une lecture rapide du budget.\n1078\t            </h3>\n1079\t          </div>\n1080\t        </div>\n1081\t      </ScrollReveal>\n1082\t\n1083\t      <ScrollReveal>\n1084\t        <ROICalculator\n1085\t          page={page}\n1086\t          surface={surface}\n1087\t          selectedSituation={selectedSituation}\n1088\t          treatmentRange={treatmentRange}\n1089\t          onSurfaceChange={setSurface}\n1090\t          onSituationChange={setSelectedSituation}\n1091\t        />\n1092\t      </ScrollReveal>\n1093\t\n1094\t      <ScrollReveal>\n1095\t        <RoiOptionCards page={page} surface={surface} treatmentRange={treatmentRange} />\n1096\t        {page.roi.comparison && page.roi.afterComparison && (\n1097\t          <p className=\"mt-5 max-w-3xl font-body text-sm leading-relaxed text-foreground/52 lg:text-base\">\n1098\t            {page.roi.afterComparison}\n1099\t          </p>\n1100\t        )}\n1101\t      </ScrollReveal>\n1102\t\n1103\t      <ScrollReveal>\n1104\t        <div className=\"mt-16 rounded-[2rem] bg-white p-5 ring-1 ring-foreground/[0.06] lg:mt-20 lg:p-8\">\n1105\t          <div className=\"mb-6 flex flex-col gap-4 lg:flex-row lg:items-end lg:justify-between\">\n1106\t            <div>\n1107\t              <p className=\"font-body text-[10px] font-semibold uppercase tracking-[0.25em] text-primary/55\">\n1108\t                Décider selon l'état réel\n1109\t              </p>\n1110\t              <h3 className=\"mt-4 max-w-xl font-satoshi text-2xl font-black leading-tight text-foreground lg:text-3xl\">\n1111\t                Quelle solution pour votre toiture ?\n1112\t              </h3>\n1113\t            </div>\n1114\t            <PrimaryCTA label={page.roi.cta} href=\"/diagnostic\" />\n1115\t          </div>\n1116\t          <SituationCards rows={page.roi.situation.rows} />\n1117\t        </div>\n1118\t      </ScrollReveal>\n1119\t    </div>\n1120\t  </section>\n1121\t  );\n1122\t};\n1123\t\n1124\tconst DiagnosticCTA = ({ title, text }: { title: string; text: string }) => (\n1125\t  <section className=\"relative overflow-hidden bg-[#182A3A] py-14 text-white lg:py-20\">\n1126\t    <div\n1127\t      aria-hidden=\"true\"\n1128\t      className=\"absolute inset-0 opacity-35\"\n1129\t      style={{\n1130\t        backgroundImage:\n1131\t          'radial-gradient(circle at 16% 20%, rgba(83, 207, 166, 0.22), transparent 28%), linear-gradient(115deg, rgba(255,255,255,0.05) 0 1px, transparent 1px 120px)',\n1132\t      }}\n1133\t    />\n1134\t    <div className=\"container relative mx-auto px-4 lg:px-8\">\n1135\t      <ScrollReveal>\n1136\t        <div className=\"mx-auto grid max-w-5xl gap-7 lg:grid-cols-[1fr_auto] lg:items-center\">\n1137\t          <div>\n1138\t            <h2 className=\"font-satoshi text-2xl font-black leading-tight lg:text-4xl\">{title}</h2>\n1139\t            <p className=\"mt-3 max-w-2xl font-body text-sm leading-relaxed text-white/68 lg:text-base\">{text}</p>\n1140\t          </div>\n1141\t          <div className=\"flex flex-col gap-3 sm:flex-row lg:justify-end\">\n1142\t            <PrimaryCTA label=\"Demander un devis\" href=\"/diagnostic\" />\n1143\t          </div>\n1144\t        </div>\n1145\t      </ScrollReveal>\n1146\t    </div>\n1147\t  </section>\n1148\t);\n1149\t\n1150\tconst MethodSection = ({ page }: { page: RoofPageData }) => {\n1151\t  const [videoOpen, setVideoOpen] = useState(false);\n1152\t\n1153\t  return (\n1154\t    <section className=\"bg-white py-16 lg:py-32\">\n1155\t      <div className=\"container mx-auto px-4 lg:px-8\">\n1156\t        <div className=\"flex flex-col items-start gap-12 lg:flex-row lg:gap-20\">\n1157\t          <div className=\"lg:sticky lg:top-[120px] lg:w-[40%]\">\n1158\t            <ScrollReveal>\n1159\t              <p className=\"mb-6 font-body text-[10px] font-semibold uppercase tracking-[0.25em] text-primary/50\">\n1160\t                Le process\n1161\t              </p>\n1162\t              <h2\n1163\t                className=\"mb-6 font-satoshi text-3xl font-black text-foreground sm:text-4xl lg:text-[3rem]\"\n1164\t                style={{ letterSpacing: '-0.03em', lineHeight: 1.05 }}\n1165\t              >\n1166\t                4 étapes. Zéro interruption.\n1167\t                <span className=\"text-foreground/30\"> Zéro risque.</span>\n1168\t              </h2>\n1169\t              <p className=\"mb-8 font-body text-base leading-relaxed text-muted-foreground lg:text-lg\">\n1170\t                {page.method.reassurance}\n1171\t              </p>\n1172\t              <button\n1173\t                onClick={() => setVideoOpen(true)}\n1174\t                className=\"group flex items-center gap-3 text-primary transition-colors hover:text-primary\"\n1175\t              >\n1176\t                <span className=\"flex h-12 w-12 items-center justify-center rounded-full bg-primary/10 transition-colors group-hover:bg-primary/20\">\n1177\t                  <Play className=\"h-5 w-5\" />\n1178\t                </span>\n1179\t                <span className=\"font-body text-sm font-semibold\">Voir un chantier en 2 minutes</span>\n1180\t              </button>\n1181\t            </ScrollReveal>\n1182\t          </div>\n1183\t\n1184\t          <div className=\"relative lg:w-[60%]\">\n1185\t            <div className=\"absolute bottom-4 left-5 top-4 w-px bg-gradient-to-b from-primary/25 via-primary/10 to-transparent lg:left-6\" />\n1186\t            <div className=\"flex flex-col\">\n1187\t              {page.method.steps.map((step, index) => {\n1188\t                const Icon = methodIcons[index] ?? CheckCircle2;\n1189\t                return (\n1190\t                  <ScrollReveal key={step.title}>\n1191\t                    <div className=\"group relative flex items-start gap-5 py-8 lg:gap-7 lg:py-10\">\n1192\t                      <span className=\"relative z-10 flex h-10 w-10 shrink-0 items-center justify-center rounded-full border border-primary/20 bg-primary/10 transition-colors duration-500 group-hover:bg-primary/15 lg:h-12 lg:w-12\">\n1193\t                        <Icon className=\"h-4 w-4 text-primary lg:h-5 lg:w-5\" />\n1194\t                      </span>\n1195\t                      <div className=\"pt-1\">\n1196\t                        <span className=\"mb-2 block font-body text-xs font-bold uppercase tracking-widest text-primary/50\">\n1197\t                          Étape 0{index + 1}\n1198\t                        </span>\n1199\t                        <h3 className=\"mb-2 font-satoshi text-xl font-bold text-foreground lg:text-2xl\">\n1200\t                          {step.title}\n1201\t                        </h3>\n1202\t                        <p className=\"max-w-md font-body text-sm leading-relaxed text-muted-foreground lg:text-base\">\n1203\t                          {step.text}\n1204\t                        </p>\n1205\t                      </div>\n1206\t                    </div>\n1207\t                    {index < page.method.steps.length - 1 && <div className=\"ml-5 h-px bg-border lg:ml-6\" />}\n1208\t                  </ScrollReveal>\n1209\t                );\n1210\t              })}\n1211\t            </div>\n1212\t\n1213\t            <ScrollReveal>\n1214\t              <div className=\"ml-16 mt-4 lg:ml-20\">\n1215\t                <p className=\"font-body text-xs font-medium text-muted-foreground/50\">\n1216\t                  Durée moyenne : 3 jours · Sans arrêt d'activité\n1217\t                </p>\n1218\t              </div>\n1219\t            </ScrollReveal>\n1220\t          </div>\n1221\t        </div>\n1222\t      </div>\n1223\t\n1224\t      <Dialog open={videoOpen} onOpenChange={setVideoOpen}>\n1225\t        <DialogContent className=\"max-w-4xl overflow-hidden border-none bg-black p-0\">\n1226\t          <div className=\"aspect-video\">\n1227\t            <iframe\n1228\t              src=\"https://www.youtube.com/embed/9HOB5OVH0Ac?autoplay=1\"\n1229\t              className=\"h-full w-full\"\n1230\t              allow=\"autoplay; encrypted-media\"\n1231\t              allowFullScreen\n1232\t              title=\"Covalba Cool Roof, un chantier en 2 minutes\"\n1233\t            />\n1234\t          </div>\n1235\t        </DialogContent>\n1236\t      </Dialog>\n1237\t    </section>\n1238\t  );\n1239\t};\n1240\t\n1241\tconst ProofSection = ({ page }: { page: RoofPageData }) => (\n1242\t  <section className=\"bg-[#192A3A] py-20 text-white lg:py-32\">\n1243\t    <div className=\"container mx-auto px-4 lg:px-8\">\n1244\t      <ScrollReveal>\n1245\t        <div className=\"mb-12 grid gap-8 lg:grid-cols-[0.9fr_1.1fr] lg:items-end\">\n1246\t          <div>\n1247\t            <Label light>{page.proof.badge}</Label>\n1248\t            <h2 className=\"font-satoshi text-3xl font-black leading-tight sm:text-4xl lg:text-5xl\">{page.proof.title}</h2>\n1249\t          </div>\n1250\t          <p className=\"max-w-xl font-body text-base leading-relaxed text-white/62\">\n1251\t            Des chiffres de terrain à confirmer chantier par chantier, utilisés ici comme repères de performance.\n1252\t          </p>\n1253\t        </div>\n1254\t      </ScrollReveal>\n1255\t\n1256\t      <ScrollReveal stagger>\n1257\t        <div className=\"grid gap-4 md:grid-cols-3\">\n1258\t          {page.proof.figures.map((figure, index) => {\n1259\t            const Icon = proofIcons[index] ?? BadgeCheck;\n1260\t            return (\n1261\t              <article key={figure.value} className=\"rounded-2xl border border-white/10 bg-white/[0.045] p-7\">\n1262\t                <Icon className=\"mb-6 h-6 w-6 text-teal-vivid\" strokeWidth={1.7} />\n1263\t                <p className=\"font-satoshi text-3xl font-black leading-none text-white lg:text-4xl\">{figure.value}</p>\n1264\t                <p className=\"mt-3 font-body text-sm leading-relaxed text-white/60\">{figure.label}</p>\n1265\t              </article>\n1266\t            );\n1267\t          })}\n1268\t        </div>\n1269\t      </ScrollReveal>\n1270\t\n1271\t      <ScrollReveal>\n1272\t        <div className=\"mt-14 border-t border-white/10 pt-10\">\n1273\t          <p className=\"mb-8 text-center font-body text-[10px] font-bold uppercase tracking-[0.22em] text-white/42\">\n1274\t            Références clients\n1275\t          </p>\n1276\t          <div className=\"flex flex-wrap items-center justify-center gap-x-10 gap-y-7 lg:gap-x-14\">\n1277\t            {logos.map((logo) => (\n1278\t              <span key={logo.name} className=\"flex h-8 w-28 items-center justify-center\">\n1279\t                <img\n1280\t                  src={logo.url}\n1281\t                  alt={logo.name}\n1282\t                  className=\"max-h-7 max-w-full object-contain opacity-45 transition-opacity duration-300 hover:opacity-80\"\n1283\t                  style={{ filter: 'brightness(0) invert(1)' }}\n1284\t                  loading=\"lazy\"\n1285\t                />\n1286\t              </span>\n1287\t            ))}\n1288\t          </div>\n1289\t        </div>\n1290\t      </ScrollReveal>\n1291\t    </div>\n1292\t  </section>\n1293\t);\n1294\t\n1295\tconst FAQSection = ({ faq }: { faq: RoofPageData['faq'] }) => (\n1296\t  <section className=\"bg-cream py-20 lg:py-32\">\n1297\t    <div className=\"container mx-auto px-4 lg:px-8\">\n1298\t      <div className=\"grid gap-10 lg:grid-cols-[0.85fr_1.15fr] lg:gap-16\">\n1299\t        <ScrollReveal>\n1300\t          <div className=\"lg:sticky lg:top-24\">\n1301\t            <Label>FAQ</Label>\n1302\t            <h2 className=\"font-satoshi text-3xl font-black leading-tight text-foreground sm:text-4xl lg:text-5xl\">\n1303\t              Vos questions,\n1304\t              <br />\n1305\t              <span className=\"text-foreground/40\">nos réponses.</span>\n1306\t            </h2>\n1307\t            <a href=\"#contact\" className=\"group mt-8 inline-flex items-center gap-2 font-body text-sm font-semibold text-primary transition-all hover:gap-3\">\n1308\t              Une autre question ? Parlons-en\n1309\t              <ArrowRight className=\"h-4 w-4\" />\n1310\t            </a>\n1311\t          </div>\n1312\t        </ScrollReveal>\n1313\t\n1314\t        <ScrollReveal>\n1315\t          <Accordion type=\"single\" collapsible className=\"space-y-3\">\n1316\t            {faq.map((item, index) => (\n1317\t              <AccordionItem\n1318\t                key={item.q}\n1319\t                value={`roof-faq-${index}`}\n1320\t                className=\"rounded-xl border border-foreground/[0.06] bg-white px-5 shadow-[0_12px_34px_rgba(24,42,58,0.04)] data-[state=open]:border-primary/20 lg:px-6\"\n1321\t              >\n1322\t                <AccordionTrigger className=\"py-5 text-left font-satoshi text-base font-bold text-foreground hover:no-underline lg:text-[17px]\">\n1323\t                  {item.q}\n1324\t                </AccordionTrigger>\n1325\t                <AccordionContent className=\"pb-5 font-body text-[14.5px] leading-relaxed text-foreground/67 lg:text-[15px]\">\n1326\t                  {item.a}\n1327\t                </AccordionContent>\n1328\t              </AccordionItem>\n1329\t            ))}\n1330\t          </Accordion>\n1331\t        </ScrollReveal>\n1332\t      </div>\n1333\t    </div>\n1334\t  </section>\n1335\t);\n1336\t\n1337\tconst FinalCTA = ({ page }: { page: RoofPageData }) => (\n1338\t  <section id=\"contact\" className=\"overflow-hidden bg-[#182A3A] py-20 text-white lg:py-32\">\n1339\t    <div className=\"container mx-auto px-4 lg:px-8\">\n1340\t      <ScrollReveal>\n1341\t        <div className=\"mx-auto max-w-4xl text-center\">\n1342\t          <h2 className=\"font-satoshi text-3xl font-black leading-tight text-white sm:text-4xl lg:text-5xl\">\n1343\t            {page.finalCta.title}\n1344\t          </h2>\n1345\t          <p className=\"mx-auto mt-5 max-w-2xl font-body text-base leading-relaxed text-white/72 lg:text-lg\">\n1346\t            {page.finalCta.text}\n1347\t          </p>\n1348\t          <div className=\"mt-9 flex flex-col gap-3 sm:flex-row sm:justify-center\">\n1349\t            <PrimaryCTA label=\"Demander un devis\" href=\"/diagnostic\" />\n1350\t          </div>\n1351\t        </div>\n1352\t      </ScrollReveal>\n1353\t\n1354\t      <ScrollReveal>\n1355\t        <ul className=\"mx-auto mt-12 grid max-w-3xl gap-3 sm:grid-cols-3\">\n1356\t          {page.finalCta.reassurances.map((item) => (\n1357\t            <li key={item} className=\"flex items-center justify-center gap-2.5 rounded-lg border border-white/[0.12] bg-white/[0.045] px-4 py-3\">\n1358\t              <CalendarCheck className=\"h-4 w-4 shrink-0 text-teal-vivid\" strokeWidth={1.8} />\n1359\t              <span className=\"font-body text-sm text-white/[0.76]\">{item}</span>\n1360\t            </li>\n1361\t          ))}\n1362\t        </ul>\n1363\t      </ScrollReveal>\n1364\t    </div>\n1365\t  </section>\n1366\t);\n1367\t\n1368\tconst SEOContent = ({ page }: { page: RoofPageData }) => (\n1369\t  <section className=\"bg-white py-20 lg:py-28\">\n1370\t    <div className=\"container mx-auto px-4 lg:px-8\">\n1371\t      <ScrollReveal>\n1372\t        <article className=\"mx-auto max-w-3xl\">\n1373\t          <p className=\"mb-5 font-body text-[10px] font-bold uppercase tracking-[0.25em] text-primary/55\">\n1374\t            Guide support\n1375\t          </p>\n1376\t          <h2 className=\"font-satoshi text-3xl font-black leading-tight text-foreground lg:text-4xl\">\n1377\t            Tout comprendre sur le {page.eyebrow.toLowerCase()}.\n1378\t          </h2>\n1379\t          <p className=\"mt-6 font-body text-base leading-relaxed text-foreground/68 lg:text-lg\">\n1380\t            {page.seo.intro}\n1381\t          </p>\n1382\t\n1383\t          <div className=\"mt-10 space-y-9\">\n1384\t            {page.seo.sections.map((section) => (\n1385\t              <section key={section.title}>\n1386\t                <h3 className=\"font-satoshi text-2xl font-bold leading-tight text-foreground\">{section.title}</h3>\n1387\t                <p className=\"mt-3 font-body text-base leading-relaxed text-foreground/66\">{section.text}</p>\n1388\t              </section>\n1389\t            ))}\n1390\t          </div>\n1391\t\n1392\t          <div className=\"mt-12 rounded-2xl bg-cream p-6 ring-1 ring-foreground/[0.05]\">\n1393\t            <h3 className=\"font-satoshi text-lg font-bold text-foreground\">Sources</h3>\n1394\t            <ul className=\"mt-4 space-y-2\">\n1395\t              {page.seo.sources.map((source) => (\n1396\t                <li key={source.href}>\n1397\t                  <a href={source.href} className=\"font-body text-sm leading-relaxed text-primary underline-offset-4 hover:underline\" target=\"_blank\" rel=\"noreferrer\">\n1398\t                    {source.label}\n1399\t                  </a>\n1400\t                </li>\n1401\t              ))}\n1402\t            </ul>\n1403\t          </div>\n1404\t        </article>\n1405\t      </ScrollReveal>\n1406\t    </div>\n1407\t  </section>\n1408\t);\n1409\t\n1410\tconst RoofPageTemplate = ({ page }: RoofPageTemplateProps) => {\n1411\t  return (\n1412\t    <>\n1413\t      <Navbar />\n1414\t      <main>\n1415\t        <RoofHero page={page} />\n1416\t        <ProblemSection page={page} />\n1417\t        <SolutionSection page={page} />\n1418\t        <BenefitsSection page={page} />\n1419\t        <ROISection page={page} />\n1420\t        <DiagnosticCTA title={page.midCta.title} text={page.midCta.text} />\n1421\t        <MethodSection page={page} />\n1422\t        <ProofSection page={page} />\n1423\t        <FAQSection faq={page.faq} />\n1424\t        <FinalCTA page={page} />\n1425\t        <SEOContent page={page} />\n1426\t      </main>\n1427\t      <Footer />\n1428\t      <StickyMobileCTA />\n1429\t    </>\n1430\t  );\n1431\t};\n1432\t\n1433\texport default RoofPageTemplate;\n1434\t"}]},"uuid":"192a9da8-1fdd-4184-9fe8-aecaee068f67","timestamp":"2026-06-26T11:54:01.793Z","toolUseResult":{"type":"text","file":{"filePath":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/src/components/roof/RoofPageTemplate.tsx","content":"\"use client\";\n\nimport { useState } from 'react';\nimport {\n  ArrowRight,\n  BadgeCheck,\n  CalendarClock,\n  CalendarCheck,\n  Check,\n  CheckCircle2,\n  ChevronDown,\n  ClipboardCheck,\n  Factory,\n  HelpCircle,\n  Play,\n  ShieldCheck,\n  ShieldAlert,\n  Sparkles,\n  SunMedium,\n  Thermometer,\n  TrendingDown,\n  Users,\n  Wrench,\n  type LucideIcon,\n} from 'lucide-react';\n\nimport Footer from '@/components/Footer';\nimport Navbar from '@/components/Navbar';\nimport ScrollReveal from '@/components/ScrollReveal';\nimport StickyMobileCTA from '@/components/StickyMobileCTA';\nimport { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from '@/components/ui/accordion';\nimport { Dialog, DialogContent } from '@/components/ui/dialog';\nimport WpImage from '@/components/ui/WpImage';\nimport type { RoofPageData, TextCard } from '@/data/roofPages';\nimport coolRoofLayers from '@/assets/cool-roof-layers.webp';\nimport covaMetalProduct from '@/assets/produits/Covalba-CovaMetal20-Duo-Produit.webp';\nimport covaSealProduct from '@/assets/produits/Covalba-CovaSeal20-Duo-Produit.webp';\nimport covaTherm8Product from '@/assets/produits/Covalba-CovaTherm8-Produit.webp';\nimport covaTherm20Product from '@/assets/produits/Covalba-CovaTherm20-Produit.webp';\n\ninterface RoofPageTemplateProps {\n  page: RoofPageData;\n}\n\nconst cardIcons: LucideIcon[] = [SunMedium, Wrench, Factory, ShieldCheck];\nconst methodIcons: LucideIcon[] = [ClipboardCheck, CalendarClock, ShieldCheck, TrendingDown];\nconst proofIcons: LucideIcon[] = [Thermometer, ShieldCheck, BadgeCheck];\nconst problemIcons: LucideIcon[] = [Users, SunMedium, ShieldAlert];\n\nconst logos = [\n  { name: 'Continental', url: '/logos/logo-continental.svg' },\n  { name: 'Thales', url: '/logos/logo-thales.svg' },\n  { name: 'Nestlé', url: '/logos/logo-nestle.svg' },\n  { name: 'SNCF', url: '/logos/logo-sncf.svg' },\n  { name: 'Leclerc', url: '/logos/logo-leclerc.svg' },\n  { name: 'Super U', url: '/logos/logo-super-u.svg' },\n];\n\nconst displayCell = (value: string) => value.replace(/EUR/g, '€').replace(/m2/g, 'm²');\n\nconst formatCurrency = (value: number) =>\n  `${new Intl.NumberFormat('fr-FR', { maximumFractionDigits: 0 }).format(Math.round(value))} €`;\n\nconst parsePricePerM2 = (value: string) => {\n  const match = displayCell(value).match(/\\(([\\d,.]+)\\s*€\\/m²\\)/);\n  if (!match) return null;\n\n  return Number.parseFloat(match[1].replace(',', '.'));\n};\n\nconst getTreatmentRange = (page: RoofPageData, situation: string) => {\n  const text = `${page.slug} ${situation}`.toLowerCase();\n\n  if (text.includes('covaseal') || text.includes('vieillissante') || text.includes('fuite')) {\n    return { min: 28, max: 38, label: 'CovaSeal 20 estimatif' };\n  }\n\n  if (text.includes('covametal') || text.includes('corrosion') || text.includes('tôle')) {\n    return { min: 24, max: 32, label: 'CovaMetal 20 estimatif' };\n  }\n\n  if (text.includes('fibrociment') || text.includes('plaques')) {\n    return { min: 22, max: 28, label: 'CovaTherm support sensible' };\n  }\n\n  return { min: 20, max: 25, label: 'CovaTherm estimatif' };\n};\n\nconst getFallbackPricePerM2 = (option: string, optionIndex: number, treatmentMidpoint: number) => {\n  const lower = option.toLowerCase();\n\n  if (optionIndex === 0) return treatmentMidpoint;\n  if (lower.includes('anticorrosion simple')) return 16;\n  if (lower.includes('remplacement')) return 120;\n  if (lower.includes('membrane neuve')) return 90;\n  if (lower.includes('isolation')) return 150;\n\n  return null;\n};\n\nconst benefitImages = [\n  '/images/toitures/benefit-confort.webp',\n  '/images/toitures/benefit-protection-toiture.webp',\n  '/images/toitures/benefit-clim.webp',\n  '/images/toitures/benefit-chantier-evite.webp',\n];\n\nconst feedbackRoofBenefitImages = [\n  '/images/toitures/feedback-batiment-tempere.png',\n  '/images/toitures/feedback-etancheite.png',\n  '/images/toitures/feedback-economie-clim-1.png',\n  '/images/toitures/feedback-economie-clim-3.png',\n];\n\nconst getBenefitImage = (page: RoofPageData, benefit: TextCard, index: number) => {\n  if (['membrane-bitumineuse', 'toiture-plate'].includes(page.slug)) {\n    return feedbackRoofBenefitImages[index] ?? feedbackRoofBenefitImages[0];\n  }\n\n  const text = `${benefit.title} ${benefit.text}`.toLowerCase();\n\n  if (page.slug === 'bac-acier' && (text.includes('tôle') || text.includes('corrosion'))) {\n    return '/images/toitures/support-bac-acier-cool.webp';\n  }\n\n  if (text.includes('facture') || text.includes('clim') || text.includes('froid')) {\n    return '/images/toitures/benefit-clim.webp';\n  }\n\n  if (text.includes('chantier') || text.includes('réfection') || text.includes('remplacement') || text.includes('dépose')) {\n    return '/images/toitures/benefit-chantier-evite.webp';\n  }\n\n  if (text.includes('protég') || text.includes('étanchéité') || text.includes('corrosion') || text.includes('durée')) {\n    return '/images/toitures/benefit-protection-toiture.webp';\n  }\n\n  return benefitImages[index] ?? benefitImages[0];\n};\n\nconst supportVisuals: Record<string, { hot: string; cool: string; hotLabel: string; coolLabel: string }> = {\n  'membrane-bitumineuse': {\n    hot: '/images/toitures/support-bitume-chaud.webp',\n    cool: '/images/toitures/feedback-economie-clim-2.png',\n    hotLabel: 'Sans cool roof : membrane bitume en absorption',\n    coolLabel: 'Avec cool roof : membrane réfléchissante',\n  },\n  'bac-acier': {\n    hot: '/images/toitures/support-bac-acier-chaud.webp',\n    cool: '/images/toitures/support-bac-acier-cool.webp',\n    hotLabel: 'Sans cool roof : métal en surchauffe',\n    coolLabel: 'Avec cool roof : bac acier réfléchi et protégé',\n  },\n  'toiture-plate': {\n    hot: '/images/toitures/support-toiture-plate-chaud.webp',\n    cool: '/images/toitures/feedback-economie-clim-2.png',\n    hotLabel: 'Sans cool roof : terrasse en absorption',\n    coolLabel: 'Avec cool roof : terrasse réfléchissante',\n  },\n  fibrociment: {\n    hot: '/images/toitures/support-fibrociment-chaud.webp',\n    cool: '/images/toitures/support-fibrociment-cool.webp',\n    hotLabel: 'Sans cool roof : fibrociment en absorption',\n    coolLabel: 'Avec cool roof : plaques protégées',\n  },\n  'tuiles-ciment': {\n    hot: '/images/toitures/support-tuiles-ciment-chaud.webp',\n    cool: '/images/toitures/support-tuiles-ciment-cool.webp',\n    hotLabel: 'Sans cool roof : tuiles qui stockent la chaleur',\n    coolLabel: 'Avec cool roof : tuiles réfléchissantes',\n  },\n};\n\nconst layerTitles = [\"Primaire d'accroche\", 'Résine réfléchissante', 'Vernis de protection'];\n\nconst layerColors = [\n  {\n    pill: 'bg-terracotta text-white',\n    dot: 'bg-terracotta',\n    chevron: 'text-terracotta',\n  },\n  {\n    pill: 'bg-foreground text-white',\n    dot: 'bg-foreground',\n    chevron: 'text-foreground',\n  },\n  {\n    pill: 'bg-primary text-white',\n    dot: 'bg-primary',\n    chevron: 'text-primary',\n  },\n];\n\nconst layerPositions = [\n  { top: '56.7%', left: '36.5%' },\n  { top: '48.2%', left: '36.5%' },\n  { top: '36.3%', left: '35.6%' },\n];\n\nconst getProblemTitle = (title: string) => {\n  const map: Record<string, { strong: string; muted: string }> = {\n    \"Une toiture bitume noire, c'est un radiateur posé sur votre bâtiment.\": {\n      strong: 'Votre toiture chauffe.',\n      muted: 'Votre bâtiment encaisse.',\n    },\n    'Le bac acier chauffe vite, rouille vite, et fatigue vite.': {\n      strong: 'Le métal chauffe vite.',\n      muted: 'La toiture fatigue aussi.',\n    },\n    'À plat, votre toiture prend le soleil toute la journée.': {\n      strong: 'Votre terrasse prend tout.',\n      muted: \"Chaleur, UV, étanchéité.\",\n    },\n    'Le fibrociment chauffe, vieillit, et coûte cher à déposer.': {\n      strong: 'Le fibrociment chauffe.',\n      muted: 'Le déposer coûte cher.',\n    },\n    'Des tuiles ciment foncées, des combles en surchauffe.': {\n      strong: 'Les tuiles stockent la chaleur.',\n      muted: 'Les combles la subissent.',\n    },\n  };\n\n  return map[title] ?? { strong: title, muted: '' };\n};\n\nconst getLayerDescription = (index: number) => {\n  if (index === 0) {\n    return \"S'adapte au support existant. Chaque toiture a sa chimie, chaque chimie demande une préparation et une accroche adaptées.\";\n  }\n\n  if (index === 1) {\n    return \"C'est le coeur du système. La surface réfléchit le rayonnement solaire au lieu de l'absorber, donc la chaleur rentre moins dans le bâtiment.\";\n  }\n\n  return \"Un top coat protège la résine des UV, de la pollution et du vieillissement prématuré pour conserver la performance dans le temps.\";\n};\n\nconst getLayerExpert = (index: number) => {\n  const notes = [\n    \"Un primaire inadapté, c'est un système qui cloque et se décolle. Le support décide de tout.\",\n    \"Le cool roof traite la cause : la toiture chauffe moins, donc le bâtiment reçoit moins de calories.\",\n    \"La différence entre une peinture et un investissement, c'est la tenue dans le temps. La finition est là pour protéger la performance.\",\n  ];\n\n  return notes[index] ?? notes[0];\n};\n\nconst Label = ({ children, light = false }: { children: string; light?: boolean }) => (\n  <div className=\"mb-5 flex items-center gap-3\">\n    <span className={`h-px w-9 ${light ? 'bg-teal-vivid/70' : 'bg-primary/65'}`} aria-hidden=\"true\" />\n    <span\n      className={`font-body text-[11px] font-bold uppercase tracking-[0.22em] ${\n        light ? 'text-teal-vivid' : 'text-primary'\n      }`}\n    >\n      {children}\n    </span>\n  </div>\n);\n\nconst PrimaryCTA = ({ label, href }: { label: string; href: string }) => (\n  <a\n    href={href}\n    className=\"group inline-flex items-center justify-center gap-2 rounded-full cta-gradient py-2.5 pl-6 pr-2 font-semibold text-white\"\n  >\n    <span className=\"text-sm\">{label}</span>\n    <span className=\"flex h-8 w-8 items-center justify-center rounded-full bg-white/20 transition-transform duration-500 group-hover:translate-x-0.5\">\n      <ArrowRight className=\"h-3.5 w-3.5\" />\n    </span>\n  </a>\n);\n\nexport const RoofHero = ({ page }: { page: RoofPageData }) => {\n  const [form, setForm] = useState({ climate: '', surface: '', email: '' });\n  const [submitted, setSubmitted] = useState(false);\n  const surfaceNum = parseFloat(form.surface) || 0;\n  const estimate = surfaceNum ? `${new Intl.NumberFormat('fr-FR').format(surfaceNum * 22.5)} €` : '20-25 €/m²';\n\n  return (\n    <section\n      aria-labelledby={`${page.slug}-hero-title`}\n      className=\"relative isolate flex min-h-[100svh] flex-col overflow-hidden bg-navy text-cream\"\n    >\n      <WpImage\n        image={{ sourceUrl: page.heroImage, altText: page.heroImageAlt, width: null, height: null }}\n        alt={page.heroImageAlt}\n        fill\n        priority\n        className={`-z-10 size-full scale-[1.02] object-cover${\n          page.slug === 'membrane-bitumineuse' ? ' object-[center_28%]' : ''\n        }`}\n      />\n      <div\n        aria-hidden=\"true\"\n        className=\"absolute inset-0 -z-10 hidden bg-gradient-to-r from-navy/[0.94] via-navy/62 to-navy/25 lg:block\"\n      />\n      <div\n        aria-hidden=\"true\"\n        className={`absolute inset-0 -z-10 bg-gradient-to-b lg:hidden ${\n          page.slug === 'membrane-bitumineuse'\n            ? 'from-navy/92 via-navy/58 to-navy/96'\n            : 'from-navy/84 via-navy/38 to-navy/96'\n        }`}\n      />\n      <div aria-hidden=\"true\" className=\"absolute inset-x-0 bottom-0 -z-10 h-[28%] bg-gradient-to-t from-navy via-navy/85 to-transparent\" />\n\n      <div className=\"container relative z-10 mx-auto flex flex-1 items-center px-6 pb-10 pt-24 lg:px-12 lg:pb-16 lg:pt-28\">\n        <div className=\"grid w-full grid-cols-1 items-center gap-10 lg:grid-cols-[55fr_45fr] lg:gap-12\">\n          <div className=\"max-w-2xl space-y-6 lg:space-y-8\">\n            <ScrollReveal>\n              <nav className=\"flex items-center gap-2 font-body text-xs text-cream/50\">\n                <a href=\"/\" className=\"transition-colors hover:text-cream/75\">Accueil</a>\n                <span className=\"text-cream/28\">/</span>\n                <span>Toitures</span>\n                <span className=\"text-cream/28\">/</span>\n                <span className=\"text-cream/78\">{page.breadcrumb}</span>\n              </nav>\n            </ScrollReveal>\n\n            <ScrollReveal>\n              <h1\n                id={`${page.slug}-hero-title`}\n                className=\"font-satoshi font-bold leading-[1.02] text-white\"\n                style={{ fontSize: 'clamp(2.25rem, 4.6vw, 4rem)', letterSpacing: '-0.03em' }}\n              >\n                {page.h1}\n              </h1>\n            </ScrollReveal>\n\n            <ScrollReveal>\n              <p\n                className=\"max-w-xl font-satoshi font-medium leading-[1.3] text-cream/66\"\n                style={{ fontSize: 'clamp(1rem, 1.5vw, 1.375rem)', letterSpacing: '-0.005em' }}\n              >\n                {page.lead}\n              </p>\n            </ScrollReveal>\n\n            <ScrollReveal>\n              <ul className=\"hidden gap-4 pt-1 sm:flex sm:flex-wrap lg:gap-6\" aria-label=\"Bénéfices clés\">\n                {page.heroStats.map((stat, index) => {\n                  const Icon = [Thermometer, ShieldCheck, TrendingDown][index] ?? BadgeCheck;\n                  return (\n                    <li\n                      key={stat.label}\n                      className={`flex items-start gap-3 ${index !== 0 ? 'sm:border-l sm:border-white/10 sm:pl-6' : ''}`}\n                    >\n                      <Icon className=\"mt-0.5 h-[18px] w-[18px] shrink-0 text-teal-vivid\" strokeWidth={1.5} />\n                      <div className=\"leading-tight\">\n                        <p className=\"font-satoshi text-[15px] font-bold text-white lg:text-base\">{stat.value}</p>\n                        <p className=\"mt-1 font-body text-[12.5px] text-cream/55 lg:text-[13px]\">{stat.label}</p>\n                      </div>\n                    </li>\n                  );\n                })}\n              </ul>\n            </ScrollReveal>\n          </div>\n\n          <ScrollReveal>\n            <div className=\"rounded-[1.5rem] border border-white/[0.08] bg-white/[0.04] p-1.5 backdrop-blur-sm\">\n              <div className=\"rounded-[calc(1.5rem-6px)] border border-white/[0.06] bg-[#0b1a2b]/80 p-4 shadow-[inset_0_1px_1px_rgba(255,255,255,0.06)] backdrop-blur-xl lg:p-7\">\n                {!submitted ? (\n                  <>\n                    <h2 className=\"mb-1 text-center font-satoshi text-xl font-bold text-white lg:text-2xl\">\n                      Estimez le gain possible\n                    </h2>\n                    <p className=\"mb-4 text-center font-body text-[12px] text-white/50\">\n                      Réponse personnalisée sous 24h\n                    </p>\n                    <form\n                      onSubmit={(event) => {\n                        event.preventDefault();\n                        setSubmitted(true);\n                      }}\n                      className=\"space-y-2.5 lg:space-y-3\"\n                    >\n                      <input\n                        value={page.breadcrumb}\n                        readOnly\n                        className=\"w-full rounded-xl border border-white/[0.12] bg-white/[0.07] px-4 py-3 font-body text-sm text-white outline-none\"\n                      />\n                      <select\n                        required\n                        value={form.climate}\n                        onChange={(e) => setForm({ ...form, climate: e.target.value })}\n                        className=\"w-full appearance-none rounded-xl border border-white/[0.12] bg-white/[0.07] px-4 py-3 font-body text-sm text-white transition-all duration-300 focus:border-white/25 focus:outline-none focus:ring-2 focus:ring-primary/50\"\n                      >\n                        <option value=\"\" disabled className=\"bg-card text-foreground\">Bâtiment climatisé ?</option>\n                        {['Oui', 'Non', 'Partiellement', 'À confirmer'].map((option) => (\n                          <option key={option} value={option} className=\"bg-card text-foreground\">{option}</option>\n                        ))}\n                      </select>\n                      <input\n                        type=\"number\"\n                        placeholder=\"Surface toiture (m²)\"\n                        required\n                        min=\"1\"\n                        value={form.surface}\n                        onChange={(e) => setForm({ ...form, surface: e.target.value })}\n                        className=\"w-full rounded-xl border border-white/[0.12] bg-white/[0.07] px-4 py-3 font-body text-sm text-white placeholder:text-white/40 transition-all duration-300 focus:border-white/25 focus:outline-none focus:ring-2 focus:ring-primary/50\"\n                      />\n                      <input\n                        type=\"email\"\n                        placeholder=\"Email professionnel\"\n                        required\n                        value={form.email}\n                        onChange={(e) => setForm({ ...form, email: e.target.value })}\n                        className=\"w-full rounded-xl border border-white/[0.12] bg-white/[0.07] px-4 py-3 font-body text-sm text-white placeholder:text-white/40 transition-all duration-300 focus:border-white/25 focus:outline-none focus:ring-2 focus:ring-primary/50\"\n                      />\n\n                      <button\n                        type=\"submit\"\n                        className=\"group mt-1 flex w-full items-center justify-center gap-3 rounded-full cta-gradient py-3 font-semibold text-white active:scale-[0.98]\"\n                      >\n                        <span className=\"text-[15px]\">Voir mon potentiel</span>\n                        <span className=\"flex h-8 w-8 items-center justify-center rounded-full bg-white/20 transition-transform duration-500 group-hover:translate-x-0.5\">\n                          <ArrowRight className=\"h-4 w-4\" />\n                        </span>\n                      </button>\n                    </form>\n\n                    <p className=\"mt-3 text-center font-body text-[11px] text-white/35\">\n                      Sans engagement · Étude adaptée au support\n                    </p>\n                  </>\n                ) : (\n                  <div className=\"py-4 text-center\">\n                    <div className=\"mx-auto mb-4 flex h-12 w-12 items-center justify-center rounded-full bg-primary/20\">\n                      <ShieldCheck className=\"h-6 w-6 text-primary\" />\n                    </div>\n                    <p className=\"mb-1 font-body text-sm text-white/60\">Base indicative pour {new Intl.NumberFormat('fr-FR').format(surfaceNum)} m²</p>\n                    <p className=\"mb-4 font-satoshi text-2xl font-bold text-white\">{estimate}</p>\n                    <p className=\"mb-4 font-body text-[13px] text-white/50\">\n                      Un conseiller affine le chiffrage selon l'état réel de la toiture.\n                    </p>\n                    <button onClick={() => setSubmitted(false)} className=\"font-body text-sm font-semibold text-primary hover:underline\">\n                      Modifier ma demande\n                    </button>\n                  </div>\n                )}\n              </div>\n            </div>\n          </ScrollReveal>\n        </div>\n      </div>\n\n      <div className=\"relative z-10 hidden border-t border-white/10 bg-navy/78 backdrop-blur-md lg:block\">\n        <div className=\"container mx-auto flex items-center gap-8 px-12 py-5\">\n          <p className=\"shrink-0 font-body text-[10px] font-semibold uppercase tracking-[0.24em] text-cream/45\">\n            Ils nous font confiance\n          </p>\n          <div className=\"flex flex-1 items-center justify-between gap-8\">\n            {logos.map((logo) => (\n              <span key={logo.name} className=\"flex h-8 w-28 items-center justify-center\">\n                <img\n                  src={logo.url}\n                  alt={logo.name}\n                  className=\"max-h-7 max-w-full object-contain opacity-65 brightness-0 invert transition-opacity duration-300 hover:opacity-95\"\n                  loading=\"eager\"\n                  decoding=\"async\"\n                />\n              </span>\n            ))}\n          </div>\n        </div>\n      </div>\n    </section>\n  );\n};\n\nconst ProblemSection = ({ page }: { page: RoofPageData }) => {\n  const title = getProblemTitle(page.problem.title);\n  const visual = supportVisuals[page.slug] ?? supportVisuals['membrane-bitumineuse'];\n\n  return (\n    <section className=\"relative overflow-hidden bg-cream py-16 lg:py-36\">\n      <div className=\"container relative mx-auto px-4 lg:px-8\">\n        <ScrollReveal>\n          <div className=\"mx-auto mb-14 max-w-3xl text-center lg:mb-20\">\n            <h2\n              className=\"font-satoshi text-3xl font-black text-foreground sm:text-4xl lg:text-[3rem]\"\n              style={{ letterSpacing: '-0.03em', lineHeight: 1.05 }}\n            >\n              {title.strong}\n              {title.muted && <span className=\"text-foreground/30\"> {title.muted}</span>}\n            </h2>\n          </div>\n        </ScrollReveal>\n\n        <div className=\"grid grid-cols-1 items-center gap-12 lg:grid-cols-12 lg:gap-16\">\n          <div className=\"order-2 lg:order-1 lg:col-span-5\">\n            <ScrollReveal>\n              <div className=\"relative\">\n                <div className=\"pointer-events-none absolute -inset-8 rounded-[3rem] bg-[radial-gradient(ellipse_at_50%_50%,_hsl(var(--terracotta)/0.18)_0%,_transparent_65%)] blur-2xl\" />\n                <div className=\"relative aspect-square overflow-hidden rounded-[2rem] bg-white shadow-[0_30px_80px_-15px_hsl(var(--terracotta-dark)/0.25),_0_10px_30px_-5px_hsl(var(--terracotta)/0.12)]\">\n                  <WpImage\n                    image={{ sourceUrl: visual.hot, altText: '', width: null, height: null }}\n                    alt=\"\"\n                    fill\n                    className=\"h-full w-full object-contain p-4\"\n                  />\n                </div>\n              </div>\n              <p className=\"mt-4 text-center font-body text-[11px] uppercase tracking-wide text-terracotta/60\">\n                {visual.hotLabel}\n              </p>\n            </ScrollReveal>\n          </div>\n\n          <div className=\"order-1 lg:order-2 lg:col-span-7 lg:pl-12\">\n            <ScrollReveal stagger>\n              <div\n                className=\"space-y-8 border-l-2 pl-8 lg:space-y-10 lg:pl-10\"\n                style={{ borderImage: 'linear-gradient(to bottom, hsl(var(--terracotta)), hsl(var(--terracotta-dark))) 1' }}\n              >\n                {page.problem.cards.map((card, index) => {\n                  const Icon = problemIcons[index] ?? HelpCircle;\n                  return (\n                    <div key={card.title}>\n                      <div className=\"mb-2 flex items-center gap-3\">\n                        <Icon className=\"h-5 w-5 text-terracotta\" strokeWidth={1.8} />\n                        <h3\n                          className=\"font-satoshi text-xl font-bold text-foreground lg:text-2xl\"\n                          style={{ letterSpacing: '-0.02em', lineHeight: 1.2 }}\n                        >\n                          {card.title}\n                        </h3>\n                      </div>\n                      <p className=\"font-body text-base leading-relaxed text-foreground/55\">{card.text}</p>\n                    </div>\n                  );\n                })}\n              </div>\n            </ScrollReveal>\n          </div>\n        </div>\n\n        <div className=\"mt-20 grid grid-cols-1 items-center gap-12 lg:mt-28 lg:grid-cols-12 lg:gap-16\">\n          <div className=\"order-2 lg:order-2 lg:col-span-5\">\n            <ScrollReveal>\n              <div className=\"relative\">\n                <div className=\"pointer-events-none absolute -inset-8 rounded-[3rem] bg-[radial-gradient(ellipse_at_50%_50%,_rgba(32,150,140,0.18)_0%,_transparent_65%)] blur-2xl\" />\n                <div className=\"relative aspect-square overflow-hidden rounded-[2rem] bg-white shadow-[0_30px_80px_-15px_rgba(20,120,110,0.20),_0_10px_30px_-5px_rgba(32,150,140,0.10)]\">\n                  <WpImage\n                    image={{ sourceUrl: visual.cool, altText: '', width: null, height: null }}\n                    alt=\"\"\n                    fill\n                    className=\"h-full w-full object-contain p-4\"\n                  />\n                </div>\n              </div>\n              <p className=\"mt-4 text-center font-body text-[11px] uppercase tracking-wide text-primary/60\">\n                {visual.coolLabel}\n              </p>\n            </ScrollReveal>\n          </div>\n\n          <div className=\"order-1 lg:order-1 lg:col-span-7 lg:pr-12\">\n            <ScrollReveal>\n              <h3\n                className=\"mb-8 max-w-xl font-satoshi text-3xl font-black text-foreground sm:text-4xl lg:text-[3rem]\"\n                style={{ letterSpacing: '-0.03em', lineHeight: 1.05 }}\n              >\n                Le cool roof : une réponse concrète\n                <span className=\"text-foreground/30\"> au problème de chaleur.</span>\n              </h3>\n              <p className=\"mb-8 max-w-lg font-body text-base leading-relaxed text-foreground/50\">\n                Une surface claire renvoie le rayonnement solaire avant qu'il ne pénètre dans le bâtiment. La toiture chauffe moins, les derniers niveaux respirent, et le support subit moins d'UV et de chocs thermiques.\n              </p>\n              <PrimaryCTA label=\"Demander un devis\" href=\"/diagnostic\" />\n            </ScrollReveal>\n          </div>\n        </div>\n      </div>\n    </section>\n  );\n};\n\nconst SolutionSection = ({ page }: { page: RoofPageData }) => {\n  const [active, setActive] = useState(0);\n\n  return (\n    <section className=\"relative bg-white\">\n      <div className=\"container mx-auto px-4 lg:px-8\">\n        <ScrollReveal>\n          <div className=\"flex flex-col gap-8 pb-10 pt-16 lg:flex-row lg:items-end lg:gap-16 lg:pb-16 lg:pt-32\">\n            <div className=\"lg:w-2/3\">\n              <p className=\"mb-6 font-body text-[10px] font-semibold uppercase tracking-[0.25em] text-muted-foreground\">\n                {page.solution.badge}\n              </p>\n              <h2\n                className=\"font-satoshi text-3xl font-black text-foreground sm:text-4xl lg:text-[3rem]\"\n                style={{ letterSpacing: '-0.03em', lineHeight: 1.05 }}\n              >\n                <span className=\"text-foreground/30\">Un système conçu pour </span>\n                réfléchir, protéger et durer.\n              </h2>\n            </div>\n            <div className=\"lg:w-1/3 lg:pb-1\">\n              <p className=\"font-body text-base leading-relaxed text-foreground/52 lg:text-right lg:text-lg\">\n                Un primaire, une résine, un vernis qui garantissent la performance de votre toiture dans le temps.\n              </p>\n              <div className=\"mt-5 flex lg:justify-end\">\n                <PrimaryCTA label=\"Demander un devis\" href=\"/diagnostic\" />\n              </div>\n            </div>\n          </div>\n        </ScrollReveal>\n\n        <div className=\"flex flex-col gap-12 pb-24 lg:flex-row lg:gap-16 lg:pb-32\">\n          <div className=\"overflow-hidden rounded-2xl shadow-[0_20px_60px_-15px_rgba(0,0,0,0.08)] lg:hidden\">\n            <WpImage\n              image={{\n                sourceUrl: coolRoofLayers.src,\n                altText: 'Coupe du système cool roof Covalba',\n                width: coolRoofLayers.width,\n                height: coolRoofLayers.height,\n              }}\n              alt=\"Coupe du système cool roof Covalba\"\n              className=\"w-full\"\n            />\n          </div>\n\n          <div className=\"lg:w-1/2 lg:sticky lg:top-[20vh] lg:self-start\">\n            {layerTitles.map((item, index) => {\n              const isOpen = active === index;\n              const colors = layerColors[index] ?? layerColors[0];\n              return (\n                <div key={item} className=\"border-b border-border last:border-b-0\">\n                  <button\n                    onClick={() => setActive(index)}\n                    className=\"group flex w-full items-center gap-4 py-6 text-left\"\n                  >\n                    <span\n                      className={`inline-flex h-8 w-8 shrink-0 items-center justify-center rounded-full font-body text-[11px] font-bold transition-all duration-300 ${\n                        isOpen ? colors.pill : 'bg-muted text-muted-foreground'\n                      }`}\n                    >\n                      0{index + 1}\n                    </span>\n                    <h3\n                      className={`flex-1 font-satoshi text-xl font-bold transition-colors duration-300 lg:text-2xl ${\n                        isOpen ? 'text-foreground' : 'text-foreground/50 group-hover:text-foreground/80'\n                      }`}\n                    >\n                      {item}\n                    </h3>\n                    <ChevronDown\n                      className={`h-5 w-5 shrink-0 transition-all duration-300 ${\n                        isOpen ? `${colors.chevron} rotate-180` : 'text-foreground/25'\n                      }`}\n                      strokeWidth={2}\n                    />\n                  </button>\n\n                  <div\n                    className={`grid transition-all duration-500 ${\n                      isOpen ? 'grid-rows-[1fr] opacity-100' : 'grid-rows-[0fr] opacity-0'\n                    }`}\n                  >\n                    <div className=\"overflow-hidden\">\n                      <div className=\"pb-8 pl-6 lg:pl-12\">\n                        <p className=\"mb-6 font-body text-base leading-relaxed text-foreground/65 lg:text-lg\">\n                          {getLayerDescription(index)}\n                        </p>\n                        <div className=\"flex items-start gap-3 rounded-xl bg-foreground/[0.03] p-4\">\n                          <div className=\"relative mt-0.5 h-9 w-9 shrink-0 overflow-hidden rounded-full\">\n                            <WpImage\n                              image={{\n                                sourceUrl: '/maxime-bourassin.jpg',\n                                altText: 'Maxime Bourassin, fondateur Covalba',\n                                width: null,\n                                height: null,\n                              }}\n                              alt=\"Maxime Bourassin, fondateur Covalba\"\n                              fill\n                              className=\"object-cover\"\n                            />\n                          </div>\n                          <div>\n                            <p className=\"font-body text-[15px] italic leading-relaxed text-foreground/65 lg:text-base\">\n                              \"{getLayerExpert(index)}\"\n                            </p>\n                            <p className=\"mt-2 font-body text-xs font-semibold text-foreground/50\">\n                              Maxime Bourassin, fondateur\n                            </p>\n                          </div>\n                        </div>\n                        {index === 0 && page.solution.note && (\n                          <p className=\"mt-4 rounded-xl bg-primary/5 p-4 font-body text-sm leading-relaxed text-foreground/62\">\n                            {page.solution.note}\n                          </p>\n                        )}\n                      </div>\n                    </div>\n                  </div>\n                </div>\n              );\n            })}\n          </div>\n\n          <div className=\"hidden lg:block lg:w-1/2\">\n            <div className=\"relative overflow-hidden rounded-2xl shadow-[0_30px_80px_-15px_rgba(0,0,0,0.08)]\">\n              <WpImage\n                image={{\n                  sourceUrl: coolRoofLayers.src,\n                  altText: 'Coupe du système cool roof Covalba',\n                  width: coolRoofLayers.width,\n                  height: coolRoofLayers.height,\n                }}\n                alt=\"Coupe du système cool roof Covalba\"\n                className=\"w-full\"\n              />\n              {layerTitles.map((item, index) => {\n                const pos = layerPositions[index];\n                const colors = layerColors[index] ?? layerColors[0];\n                const isActive = active === index;\n                if (!pos) return null;\n\n                return (\n                  <div key={item} className=\"absolute\" style={{ top: pos.top, left: pos.left }}>\n                    <div\n                      className={`absolute -translate-x-1/2 -translate-y-1/2 transition-all duration-500 ${\n                        isActive ? 'scale-125' : 'scale-75 opacity-40'\n                      }`}\n                    >\n                      <div\n                        className={`h-3.5 w-3.5 rounded-full ${\n                          isActive ? colors.dot : 'bg-foreground/20'\n                        } shadow-lg ring-2 ring-white transition-colors duration-500`}\n                      />\n                      {isActive && (\n                        <div className={`absolute inset-0 h-3.5 w-3.5 animate-ping rounded-full ${colors.dot} opacity-30`} />\n                      )}\n                    </div>\n                    <div\n                      className={`pointer-events-none absolute right-5 top-1/2 -translate-y-1/2 transition-all duration-500 ${\n                        isActive ? 'translate-x-0 opacity-100' : 'translate-x-2 opacity-0'\n                      }`}\n                    >\n                      <span className={`whitespace-nowrap rounded-full px-4 py-1.5 font-body text-[13px] font-bold shadow-lg ${colors.pill}`}>\n                        {item}\n                      </span>\n                    </div>\n                  </div>\n                );\n              })}\n            </div>\n          </div>\n        </div>\n      </div>\n    </section>\n  );\n};\n\nconst BenefitsSection = ({ page }: { page: RoofPageData }) => (\n  <section className=\"bg-white py-20 lg:py-32\">\n    <div className=\"container mx-auto px-4 lg:px-8\">\n      <ScrollReveal>\n        <div className=\"mb-10 grid gap-8 lg:grid-cols-[0.82fr_1.18fr] lg:items-end lg:gap-14\">\n          <div>\n            <Label>{page.benefits.badge}</Label>\n            <h2 className=\"font-satoshi text-3xl font-black leading-tight text-foreground sm:text-4xl lg:text-5xl\">\n              {page.benefits.title}\n            </h2>\n          </div>\n          <p className=\"max-w-xl border-l border-primary/30 pl-6 font-body text-base leading-relaxed text-foreground/62 lg:text-lg\">\n            {page.benefits.featured}\n          </p>\n        </div>\n      </ScrollReveal>\n\n      <ScrollReveal stagger>\n        <div className=\"grid gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n          {page.benefits.cards.map((benefit, index) => {\n            const Icon = cardIcons[index] ?? Sparkles;\n            return (\n              <article\n                key={benefit.title}\n                className=\"group overflow-hidden rounded-2xl bg-cream ring-1 ring-foreground/[0.05] transition-all duration-500 hover:-translate-y-1 hover:shadow-[0_24px_70px_-48px_hsl(var(--navy)/0.45)]\"\n              >\n                <div className=\"relative aspect-[4/3] overflow-hidden bg-foreground/[0.04]\">\n                  <WpImage\n                    image={{ sourceUrl: getBenefitImage(page, benefit, index), altText: '', width: null, height: null }}\n                    alt=\"\"\n                    fill\n                    className=\"h-full w-full object-cover transition-transform duration-700 group-hover:scale-[1.035]\"\n                  />\n                  <div className=\"absolute inset-x-0 bottom-0 h-20 bg-gradient-to-t from-cream to-transparent\" />\n                </div>\n                <div className=\"p-5 lg:p-6\">\n                  <div className=\"mb-4 flex h-10 w-10 items-center justify-center rounded-xl bg-white text-primary shadow-[0_12px_30px_-24px_hsl(var(--navy)/0.35)]\">\n                    <Icon className=\"h-5 w-5\" strokeWidth={1.7} />\n                  </div>\n                  <h3 className=\"font-satoshi text-lg font-bold leading-tight text-foreground\">{benefit.title}</h3>\n                  <p className=\"mt-2 font-body text-sm leading-relaxed text-foreground/62\">{benefit.text}</p>\n                </div>\n              </article>\n            );\n          })}\n        </div>\n      </ScrollReveal>\n    </div>\n  </section>\n);\n\nconst RoiOptionCards = ({\n  page,\n  surface,\n  treatmentRange,\n}: {\n  page: RoofPageData;\n  surface: number;\n  treatmentRange: ReturnType<typeof getTreatmentRange>;\n}) => {\n  if (!page.roi.comparison) {\n    return page.roi.afterComparison ? (\n      <article className=\"rounded-2xl bg-white p-6 ring-1 ring-foreground/[0.06] lg:p-8\">\n        <p className=\"font-body text-base leading-relaxed text-foreground/66 lg:text-lg\">\n          {page.roi.afterComparison}\n        </p>\n      </article>\n    ) : null;\n  }\n\n  const options = page.roi.comparison.headers.slice(1);\n  const rows = page.roi.comparison.rows;\n  const investment = rows.find((row) => row[0].toLowerCase().includes('investissement'));\n  const duration = rows.find((row) => row[0].toLowerCase().includes('dur'));\n  const activity = rows.find((row) => row[0].toLowerCase().includes('activ'));\n  const treatmentMidpoint = (treatmentRange.min + treatmentRange.max) / 2;\n\n  return (\n    <div className=\"grid gap-4 lg:grid-cols-3\">\n      {options.map((option, optionIndex) => {\n        const isCovalba = optionIndex === 0;\n        const rawInvestment = investment?.[optionIndex + 1] ?? '';\n        const parsedPrice = parsePricePerM2(rawInvestment);\n        const pricePerM2 = parsedPrice ?? getFallbackPricePerM2(option, optionIndex, treatmentMidpoint);\n        const dynamicInvestment = pricePerM2 ? `~${formatCurrency(surface * pricePerM2)}` : displayCell(rawInvestment);\n\n        return (\n          <article\n            key={option}\n            className={`rounded-2xl p-6 ring-1 ${\n              isCovalba\n                ? 'bg-[#142333] text-white ring-transparent'\n                : 'bg-white text-foreground ring-foreground/[0.06]'\n            }`}\n          >\n            <div className=\"mb-6 flex items-start justify-between gap-4\">\n              <h3 className=\"font-satoshi text-xl font-black leading-tight\">{option}</h3>\n              {isCovalba && (\n                <span className=\"inline-flex h-7 w-7 shrink-0 items-center justify-center rounded-full bg-teal-vivid/15 text-teal-vivid\">\n                  <Check className=\"h-4 w-4\" strokeWidth={2.4} />\n                </span>\n              )}\n            </div>\n            <p className={`font-satoshi text-3xl font-black leading-none ${isCovalba ? 'text-teal-vivid' : 'text-terracotta'}`}>\n              {dynamicInvestment}\n            </p>\n            {pricePerM2 && (\n              <p className={`mt-2 font-body text-xs font-semibold ${isCovalba ? 'text-white/45' : 'text-foreground/40'}`}>\n                base {new Intl.NumberFormat('fr-FR').format(surface)} m² · {pricePerM2.toLocaleString('fr-FR')} €/m²\n              </p>\n            )}\n            <dl className=\"mt-6 space-y-3 border-t border-current/10 pt-5\">\n              {[duration, activity].filter(Boolean).map((row) => (\n                <div key={row![0]} className=\"grid grid-cols-[0.75fr_1fr] gap-4\">\n                  <dt className={`font-body text-xs font-bold uppercase tracking-[0.14em] ${isCovalba ? 'text-white/38' : 'text-foreground/35'}`}>\n                    {displayCell(row![0])}\n                  </dt>\n                  <dd className={`font-body text-sm leading-relaxed ${isCovalba ? 'text-white/74' : 'text-foreground/62'}`}>\n                    {displayCell(row![optionIndex + 1])}\n                  </dd>\n                </div>\n              ))}\n            </dl>\n          </article>\n        );\n      })}\n    </div>\n  );\n};\n\nconst ROICalculator = ({\n  page,\n  surface,\n  selectedSituation,\n  treatmentRange,\n  onSurfaceChange,\n  onSituationChange,\n}: {\n  page: RoofPageData;\n  surface: number;\n  selectedSituation: string;\n  treatmentRange: ReturnType<typeof getTreatmentRange>;\n  onSurfaceChange: (surface: number) => void;\n  onSituationChange: (situation: string) => void;\n}) => {\n  const treatmentLow = surface * treatmentRange.min;\n  const treatmentHigh = surface * treatmentRange.max;\n  const referencePrice = selectedSituation.toLowerCase().includes('isolation') ? 150 : 90;\n  const referenceCost = surface * referencePrice;\n  const potentialGap = Math.max(referenceCost - treatmentHigh, 0);\n\n  return (\n    <div className=\"mb-10 rounded-[2rem] bg-[#142333] p-5 text-white shadow-[0_34px_90px_-64px_hsl(var(--navy)/0.65)] lg:p-8\">\n      <div className=\"grid gap-7 lg:grid-cols-[0.88fr_1.12fr] lg:items-end\">\n        <div>\n          <p className=\"font-body text-[10px] font-semibold uppercase tracking-[0.25em] text-teal-vivid/70\">\n            Calculateur indicatif\n          </p>\n          <h3 className=\"mt-4 max-w-lg font-satoshi text-2xl font-black leading-tight lg:text-3xl\">\n            Ajustez la surface et l'état de la toiture.\n          </h3>\n          <p className=\"mt-3 max-w-lg font-body text-sm leading-relaxed text-white/52\">\n            Par défaut : 5 000 m², surface type d'un entrepôt ou bâtiment industriel à traiter.\n          </p>\n        </div>\n\n        <div className=\"grid gap-3 sm:grid-cols-[0.72fr_1.28fr]\">\n          <label className=\"block\">\n            <span className=\"mb-2 block font-body text-[11px] font-bold uppercase tracking-[0.16em] text-white/40\">\n              Surface\n            </span>\n            <input\n              type=\"number\"\n              min={100}\n              step={100}\n              value={surface}\n              onChange={(event) => onSurfaceChange(Math.max(100, Number(event.target.value) || 100))}\n              className=\"h-12 w-full rounded-xl border border-white/10 bg-white/[0.07] px-4 font-body text-sm font-semibold text-white outline-none transition focus:border-teal-vivid/50 focus:ring-2 focus:ring-teal-vivid/20\"\n              aria-label=\"Surface à traiter en mètres carrés\"\n            />\n          </label>\n          <label className=\"block\">\n            <span className=\"mb-2 block font-body text-[11px] font-bold uppercase tracking-[0.16em] text-white/40\">\n              Situation\n            </span>\n            <select\n              value={selectedSituation}\n              onChange={(event) => onSituationChange(event.target.value)}\n              className=\"h-12 w-full rounded-xl border border-white/10 bg-white/[0.07] px-4 font-body text-sm font-semibold text-white outline-none transition focus:border-teal-vivid/50 focus:ring-2 focus:ring-teal-vivid/20\"\n              aria-label=\"Situation de la toiture\"\n            >\n              {page.roi.situation.rows.map((row) => (\n                <option key={row[0]} value={row[0]} className=\"bg-card text-foreground\">\n                  {row[0]}\n                </option>\n              ))}\n            </select>\n          </label>\n        </div>\n      </div>\n\n      <div className=\"mt-7 grid gap-3 md:grid-cols-3\">\n        {[\n          {\n            label: treatmentRange.label,\n            value: `${formatCurrency(treatmentLow)} - ${formatCurrency(treatmentHigh)}`,\n            detail: `${treatmentRange.min}-${treatmentRange.max} €/m² selon préparation`,\n            valueClass: 'text-teal-vivid',\n          },\n          {\n            label: 'Réfection de référence',\n            value: `~${formatCurrency(referenceCost)}`,\n            detail: `${referencePrice} €/m², ordre de grandeur à comparer`,\n            valueClass: 'text-terracotta',\n          },\n          {\n            label: 'Écart potentiel',\n            value: `jusqu'à ${formatCurrency(potentialGap)}`,\n            detail: \"Investissement lourd évité ou repoussé si le support est viable\",\n            valueClass: 'text-teal-vivid',\n          },\n        ].map((item) => (\n          <article key={item.label} className=\"rounded-2xl bg-white/[0.07] p-5 ring-1 ring-white/10\">\n            <p className=\"font-body text-[11px] font-bold uppercase tracking-[0.16em] text-white/38\">{item.label}</p>\n            <p className={`mt-3 font-satoshi text-2xl font-black leading-tight ${item.valueClass}`}>{item.value}</p>\n            <p className=\"mt-2 font-body text-xs leading-relaxed text-white/45\">{item.detail}</p>\n          </article>\n        ))}\n      </div>\n      <p className=\"mt-4 font-body text-xs leading-relaxed text-white/38\">\n        Chiffrage indicatif : l'étude ajuste le prix selon l'accès, la préparation, les points singuliers et l'état réel du support.\n      </p>\n    </div>\n  );\n};\n\nconst getSituationImage = (recommendation: string) => {\n  const lower = recommendation.toLowerCase();\n  if (lower.includes('covametal')) return covaMetalProduct;\n  if (lower.includes('covaseal')) return covaSealProduct;\n  if (lower.includes('cova')) return covaTherm20Product;\n  return covaTherm8Product;\n};\n\nconst SituationCards = ({ rows }: { rows: string[][] }) => (\n  <div className=\"grid gap-4 md:grid-cols-2\">\n    {rows.map((row) => (\n      <article key={row[0]} className=\"grid gap-4 rounded-2xl bg-white p-4 ring-1 ring-foreground/[0.06] sm:grid-cols-[128px_1fr] lg:grid-cols-[190px_1fr] lg:gap-5 lg:p-5\">\n        <div className=\"flex aspect-[4/3] items-center justify-center rounded-xl bg-gradient-to-br from-cream to-white p-4 shadow-[inset_0_1px_0_rgba(255,255,255,0.75),_0_18px_44px_-34px_hsl(var(--navy)/0.45)] ring-1 ring-foreground/[0.04] sm:aspect-square lg:p-6\">\n          {(() => {\n            const situationImg = getSituationImage(row[1]);\n            return (\n              <WpImage\n                image={{\n                  sourceUrl: situationImg.src,\n                  altText: '',\n                  width: situationImg.width,\n                  height: situationImg.height,\n                }}\n                alt=\"\"\n                className=\"max-h-full max-w-full object-contain\"\n              />\n            );\n          })()}\n        </div>\n        <div className=\"self-center\">\n          <p className=\"font-satoshi text-lg font-bold leading-tight text-foreground\">{row[0]}</p>\n          <p className=\"mt-2 font-body text-sm font-bold text-primary\">{row[1]}</p>\n          <p className=\"mt-2 font-body text-sm leading-relaxed text-foreground/58\">{row[2]}</p>\n        </div>\n      </article>\n    ))}\n  </div>\n);\n\nconst ROISection = ({ page }: { page: RoofPageData }) => {\n  const [surface, setSurface] = useState(5000);\n  const [selectedSituation, setSelectedSituation] = useState(page.roi.situation.rows[0]?.[0] ?? '');\n  const treatmentRange = getTreatmentRange(page, selectedSituation);\n\n  return (\n    <section className=\"bg-cream py-20 lg:py-32\">\n      <div className=\"container mx-auto px-4 lg:px-8\">\n      <ScrollReveal>\n        <div className=\"mx-auto mb-12 max-w-3xl text-center lg:mb-16\">\n          <div className=\"flex justify-center\">\n            <Label>{page.roi.badge}</Label>\n          </div>\n          <h2 className=\"font-satoshi text-3xl font-black leading-tight text-foreground sm:text-4xl lg:text-[3rem]\">\n            {page.roi.title}\n          </h2>\n          <p className=\"mx-auto mt-5 max-w-2xl font-body text-base leading-relaxed text-foreground/58 lg:text-lg\">\n            {page.roi.intro}\n          </p>\n        </div>\n      </ScrollReveal>\n\n      <ScrollReveal>\n        <div className=\"mb-12 grid gap-4 md:grid-cols-3\">\n          {[\n            ['20-25 €/m²', 'pour traiter et rafraîchir'],\n            ['8-10 ans', 'de réfection repoussée'],\n            ['0 arrêt', \"d'activité pendant le chantier\"],\n          ].map(([value, label]) => (\n            <article key={value} className=\"rounded-2xl bg-white p-6 text-center ring-1 ring-foreground/[0.06]\">\n              <p className=\"font-satoshi text-4xl font-black leading-none text-primary\">{value}</p>\n              <p className=\"mt-3 font-body text-sm font-semibold text-foreground/52\">{label}</p>\n            </article>\n          ))}\n        </div>\n      </ScrollReveal>\n\n      <ScrollReveal>\n        <div className=\"mb-8 max-w-2xl\">\n          <div>\n            <p className=\"font-body text-[10px] font-semibold uppercase tracking-[0.25em] text-primary/55\">\n              Comparer les options\n            </p>\n            <h3 className=\"mt-4 font-satoshi text-2xl font-black leading-tight text-foreground lg:text-3xl\">\n              Une lecture rapide du budget.\n            </h3>\n          </div>\n        </div>\n      </ScrollReveal>\n\n      <ScrollReveal>\n        <ROICalculator\n          page={page}\n          surface={surface}\n          selectedSituation={selectedSituation}\n          treatmentRange={treatmentRange}\n          onSurfaceChange={setSurface}\n          onSituationChange={setSelectedSituation}\n        />\n      </ScrollReveal>\n\n      <ScrollReveal>\n        <RoiOptionCards page={page} surface={surface} treatmentRange={treatmentRange} />\n        {page.roi.comparison && page.roi.afterComparison && (\n          <p className=\"mt-5 max-w-3xl font-body text-sm leading-relaxed text-foreground/52 lg:text-base\">\n            {page.roi.afterComparison}\n          </p>\n        )}\n      </ScrollReveal>\n\n      <ScrollReveal>\n        <div className=\"mt-16 rounded-[2rem] bg-white p-5 ring-1 ring-foreground/[0.06] lg:mt-20 lg:p-8\">\n          <div className=\"mb-6 flex flex-col gap-4 lg:flex-row lg:items-end lg:justify-between\">\n            <div>\n              <p className=\"font-body text-[10px] font-semibold uppercase tracking-[0.25em] text-primary/55\">\n                Décider selon l'état réel\n              </p>\n              <h3 className=\"mt-4 max-w-xl font-satoshi text-2xl font-black leading-tight text-foreground lg:text-3xl\">\n                Quelle solution pour votre toiture ?\n              </h3>\n            </div>\n            <PrimaryCTA label={page.roi.cta} href=\"/diagnostic\" />\n          </div>\n          <SituationCards rows={page.roi.situation.rows} />\n        </div>\n      </ScrollReveal>\n    </div>\n  </section>\n  );\n};\n\nconst DiagnosticCTA = ({ title, text }: { title: string; text: string }) => (\n  <section className=\"relative overflow-hidden bg-[#182A3A] py-14 text-white lg:py-20\">\n    <div\n      aria-hidden=\"true\"\n      className=\"absolute inset-0 opacity-35\"\n      style={{\n        backgroundImage:\n          'radial-gradient(circle at 16% 20%, rgba(83, 207, 166, 0.22), transparent 28%), linear-gradient(115deg, rgba(255,255,255,0.05) 0 1px, transparent 1px 120px)',\n      }}\n    />\n    <div className=\"container relative mx-auto px-4 lg:px-8\">\n      <ScrollReveal>\n        <div className=\"mx-auto grid max-w-5xl gap-7 lg:grid-cols-[1fr_auto] lg:items-center\">\n          <div>\n            <h2 className=\"font-satoshi text-2xl font-black leading-tight lg:text-4xl\">{title}</h2>\n            <p className=\"mt-3 max-w-2xl font-body text-sm leading-relaxed text-white/68 lg:text-base\">{text}</p>\n          </div>\n          <div className=\"flex flex-col gap-3 sm:flex-row lg:justify-end\">\n            <PrimaryCTA label=\"Demander un devis\" href=\"/diagnostic\" />\n          </div>\n        </div>\n      </ScrollReveal>\n    </div>\n  </section>\n);\n\nconst MethodSection = ({ page }: { page: RoofPageData }) => {\n  const [videoOpen, setVideoOpen] = useState(false);\n\n  return (\n    <section className=\"bg-white py-16 lg:py-32\">\n      <div className=\"container mx-auto px-4 lg:px-8\">\n        <div className=\"flex flex-col items-start gap-12 lg:flex-row lg:gap-20\">\n          <div className=\"lg:sticky lg:top-[120px] lg:w-[40%]\">\n            <ScrollReveal>\n              <p className=\"mb-6 font-body text-[10px] font-semibold uppercase tracking-[0.25em] text-primary/50\">\n                Le process\n              </p>\n              <h2\n                className=\"mb-6 font-satoshi text-3xl font-black text-foreground sm:text-4xl lg:text-[3rem]\"\n                style={{ letterSpacing: '-0.03em', lineHeight: 1.05 }}\n              >\n                4 étapes. Zéro interruption.\n                <span className=\"text-foreground/30\"> Zéro risque.</span>\n              </h2>\n              <p className=\"mb-8 font-body text-base leading-relaxed text-muted-foreground lg:text-lg\">\n                {page.method.reassurance}\n              </p>\n              <button\n                onClick={() => setVideoOpen(true)}\n                className=\"group flex items-center gap-3 text-primary transition-colors hover:text-primary\"\n              >\n                <span className=\"flex h-12 w-12 items-center justify-center rounded-full bg-primary/10 transition-colors group-hover:bg-primary/20\">\n                  <Play className=\"h-5 w-5\" />\n                </span>\n                <span className=\"font-body text-sm font-semibold\">Voir un chantier en 2 minutes</span>\n              </button>\n            </ScrollReveal>\n          </div>\n\n          <div className=\"relative lg:w-[60%]\">\n            <div className=\"absolute bottom-4 left-5 top-4 w-px bg-gradient-to-b from-primary/25 via-primary/10 to-transparent lg:left-6\" />\n            <div className=\"flex flex-col\">\n              {page.method.steps.map((step, index) => {\n                const Icon = methodIcons[index] ?? CheckCircle2;\n                return (\n                  <ScrollReveal key={step.title}>\n                    <div className=\"group relative flex items-start gap-5 py-8 lg:gap-7 lg:py-10\">\n                      <span className=\"relative z-10 flex h-10 w-10 shrink-0 items-center justify-center rounded-full border border-primary/20 bg-primary/10 transition-colors duration-500 group-hover:bg-primary/15 lg:h-12 lg:w-12\">\n                        <Icon className=\"h-4 w-4 text-primary lg:h-5 lg:w-5\" />\n                      </span>\n                      <div className=\"pt-1\">\n                        <span className=\"mb-2 block font-body text-xs font-bold uppercase tracking-widest text-primary/50\">\n                          Étape 0{index + 1}\n                        </span>\n                        <h3 className=\"mb-2 font-satoshi text-xl font-bold text-foreground lg:text-2xl\">\n                          {step.title}\n                        </h3>\n                        <p className=\"max-w-md font-body text-sm leading-relaxed text-muted-foreground lg:text-base\">\n                          {step.text}\n                        </p>\n                      </div>\n                    </div>\n                    {index < page.method.steps.length - 1 && <div className=\"ml-5 h-px bg-border lg:ml-6\" />}\n                  </ScrollReveal>\n                );\n              })}\n            </div>\n\n            <ScrollReveal>\n              <div className=\"ml-16 mt-4 lg:ml-20\">\n                <p className=\"font-body text-xs font-medium text-muted-foreground/50\">\n                  Durée moyenne : 3 jours · Sans arrêt d'activité\n                </p>\n              </div>\n            </ScrollReveal>\n          </div>\n        </div>\n      </div>\n\n      <Dialog open={videoOpen} onOpenChange={setVideoOpen}>\n        <DialogContent className=\"max-w-4xl overflow-hidden border-none bg-black p-0\">\n          <div className=\"aspect-video\">\n            <iframe\n              src=\"https://www.youtube.com/embed/9HOB5OVH0Ac?autoplay=1\"\n              className=\"h-full w-full\"\n              allow=\"autoplay; encrypted-media\"\n              allowFullScreen\n              title=\"Covalba Cool Roof, un chantier en 2 minutes\"\n            />\n          </div>\n        </DialogContent>\n      </Dialog>\n    </section>\n  );\n};\n\nconst ProofSection = ({ page }: { page: RoofPageData }) => (\n  <section className=\"bg-[#192A3A] py-20 text-white lg:py-32\">\n    <div className=\"container mx-auto px-4 lg:px-8\">\n      <ScrollReveal>\n        <div className=\"mb-12 grid gap-8 lg:grid-cols-[0.9fr_1.1fr] lg:items-end\">\n          <div>\n            <Label light>{page.proof.badge}</Label>\n            <h2 className=\"font-satoshi text-3xl font-black leading-tight sm:text-4xl lg:text-5xl\">{page.proof.title}</h2>\n          </div>\n          <p className=\"max-w-xl font-body text-base leading-relaxed text-white/62\">\n            Des chiffres de terrain à confirmer chantier par chantier, utilisés ici comme repères de performance.\n          </p>\n        </div>\n      </ScrollReveal>\n\n      <ScrollReveal stagger>\n        <div className=\"grid gap-4 md:grid-cols-3\">\n          {page.proof.figures.map((figure, index) => {\n            const Icon = proofIcons[index] ?? BadgeCheck;\n            return (\n              <article key={figure.value} className=\"rounded-2xl border border-white/10 bg-white/[0.045] p-7\">\n                <Icon className=\"mb-6 h-6 w-6 text-teal-vivid\" strokeWidth={1.7} />\n                <p className=\"font-satoshi text-3xl font-black leading-none text-white lg:text-4xl\">{figure.value}</p>\n                <p className=\"mt-3 font-body text-sm leading-relaxed text-white/60\">{figure.label}</p>\n              </article>\n            );\n          })}\n        </div>\n      </ScrollReveal>\n\n      <ScrollReveal>\n        <div className=\"mt-14 border-t border-white/10 pt-10\">\n          <p className=\"mb-8 text-center font-body text-[10px] font-bold uppercase tracking-[0.22em] text-white/42\">\n            Références clients\n          </p>\n          <div className=\"flex flex-wrap items-center justify-center gap-x-10 gap-y-7 lg:gap-x-14\">\n            {logos.map((logo) => (\n              <span key={logo.name} className=\"flex h-8 w-28 items-center justify-center\">\n                <img\n                  src={logo.url}\n                  alt={logo.name}\n                  className=\"max-h-7 max-w-full object-contain opacity-45 transition-opacity duration-300 hover:opacity-80\"\n                  style={{ filter: 'brightness(0) invert(1)' }}\n                  loading=\"lazy\"\n                />\n              </span>\n            ))}\n          </div>\n        </div>\n      </ScrollReveal>\n    </div>\n  </section>\n);\n\nconst FAQSection = ({ faq }: { faq: RoofPageData['faq'] }) => (\n  <section className=\"bg-cream py-20 lg:py-32\">\n    <div className=\"container mx-auto px-4 lg:px-8\">\n      <div className=\"grid gap-10 lg:grid-cols-[0.85fr_1.15fr] lg:gap-16\">\n        <ScrollReveal>\n          <div className=\"lg:sticky lg:top-24\">\n            <Label>FAQ</Label>\n            <h2 className=\"font-satoshi text-3xl font-black leading-tight text-foreground sm:text-4xl lg:text-5xl\">\n              Vos questions,\n              <br />\n              <span className=\"text-foreground/40\">nos réponses.</span>\n            </h2>\n            <a href=\"#contact\" className=\"group mt-8 inline-flex items-center gap-2 font-body text-sm font-semibold text-primary transition-all hover:gap-3\">\n              Une autre question ? Parlons-en\n              <ArrowRight className=\"h-4 w-4\" />\n            </a>\n          </div>\n        </ScrollReveal>\n\n        <ScrollReveal>\n          <Accordion type=\"single\" collapsible className=\"space-y-3\">\n            {faq.map((item, index) => (\n              <AccordionItem\n                key={item.q}\n                value={`roof-faq-${index}`}\n                className=\"rounded-xl border border-foreground/[0.06] bg-white px-5 shadow-[0_12px_34px_rgba(24,42,58,0.04)] data-[state=open]:border-primary/20 lg:px-6\"\n              >\n                <AccordionTrigger className=\"py-5 text-left font-satoshi text-base font-bold text-foreground hover:no-underline lg:text-[17px]\">\n                  {item.q}\n                </AccordionTrigger>\n                <AccordionContent className=\"pb-5 font-body text-[14.5px] leading-relaxed text-foreground/67 lg:text-[15px]\">\n                  {item.a}\n                </AccordionContent>\n              </AccordionItem>\n            ))}\n          </Accordion>\n        </ScrollReveal>\n      </div>\n    </div>\n  </section>\n);\n\nconst FinalCTA = ({ page }: { page: RoofPageData }) => (\n  <section id=\"contact\" className=\"overflow-hidden bg-[#182A3A] py-20 text-white lg:py-32\">\n    <div className=\"container mx-auto px-4 lg:px-8\">\n      <ScrollReveal>\n        <div className=\"mx-auto max-w-4xl text-center\">\n          <h2 className=\"font-satoshi text-3xl font-black leading-tight text-white sm:text-4xl lg:text-5xl\">\n            {page.finalCta.title}\n          </h2>\n          <p className=\"mx-auto mt-5 max-w-2xl font-body text-base leading-relaxed text-white/72 lg:text-lg\">\n            {page.finalCta.text}\n          </p>\n          <div className=\"mt-9 flex flex-col gap-3 sm:flex-row sm:justify-center\">\n            <PrimaryCTA label=\"Demander un devis\" href=\"/diagnostic\" />\n          </div>\n        </div>\n      </ScrollReveal>\n\n      <ScrollReveal>\n        <ul className=\"mx-auto mt-12 grid max-w-3xl gap-3 sm:grid-cols-3\">\n          {page.finalCta.reassurances.map((item) => (\n            <li key={item} className=\"flex items-center justify-center gap-2.5 rounded-lg border border-white/[0.12] bg-white/[0.045] px-4 py-3\">\n              <CalendarCheck className=\"h-4 w-4 shrink-0 text-teal-vivid\" strokeWidth={1.8} />\n              <span className=\"font-body text-sm text-white/[0.76]\">{item}</span>\n            </li>\n          ))}\n        </ul>\n      </ScrollReveal>\n    </div>\n  </section>\n);\n\nconst SEOContent = ({ page }: { page: RoofPageData }) => (\n  <section className=\"bg-white py-20 lg:py-28\">\n    <div className=\"container mx-auto px-4 lg:px-8\">\n      <ScrollReveal>\n        <article className=\"mx-auto max-w-3xl\">\n          <p className=\"mb-5 font-body text-[10px] font-bold uppercase tracking-[0.25em] text-primary/55\">\n            Guide support\n          </p>\n          <h2 className=\"font-satoshi text-3xl font-black leading-tight text-foreground lg:text-4xl\">\n            Tout comprendre sur le {page.eyebrow.toLowerCase()}.\n          </h2>\n          <p className=\"mt-6 font-body text-base leading-relaxed text-foreground/68 lg:text-lg\">\n            {page.seo.intro}\n          </p>\n\n          <div className=\"mt-10 space-y-9\">\n            {page.seo.sections.map((section) => (\n              <section key={section.title}>\n                <h3 className=\"font-satoshi text-2xl font-bold leading-tight text-foreground\">{section.title}</h3>\n                <p className=\"mt-3 font-body text-base leading-relaxed text-foreground/66\">{section.text}</p>\n              </section>\n            ))}\n          </div>\n\n          <div className=\"mt-12 rounded-2xl bg-cream p-6 ring-1 ring-foreground/[0.05]\">\n            <h3 className=\"font-satoshi text-lg font-bold text-foreground\">Sources</h3>\n            <ul className=\"mt-4 space-y-2\">\n              {page.seo.sources.map((source) => (\n                <li key={source.href}>\n                  <a href={source.href} className=\"font-body text-sm leading-relaxed text-primary underline-offset-4 hover:underline\" target=\"_blank\" rel=\"noreferrer\">\n                    {source.label}\n                  </a>\n                </li>\n              ))}\n            </ul>\n          </div>\n        </article>\n      </ScrollReveal>\n    </div>\n  </section>\n);\n\nconst RoofPageTemplate = ({ page }: RoofPageTemplateProps) => {\n  return (\n    <>\n      <Navbar />\n      <main>\n        <RoofHero page={page} />\n        <ProblemSection page={page} />\n        <SolutionSection page={page} />\n        <BenefitsSection page={page} />\n        <ROISection page={page} />\n        <DiagnosticCTA title={page.midCta.title} text={page.midCta.text} />\n        <MethodSection page={page} />\n        <ProofSection page={page} />\n        <FAQSection faq={page.faq} />\n        <FinalCTA page={page} />\n        <SEOContent page={page} />\n      </main>\n      <Footer />\n      <StickyMobileCTA />\n    </>\n  );\n};\n\nexport default RoofPageTemplate;\n","numLines":1434,"startLine":1,"totalLines":1434}},"sourceToolAssistantUUID":"8f17d4d8-7a84-4649-8408-707ea5473533","userType":"external","entrypoint":"cli","cwd":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale","sessionId":"c02b163b-170b-4cd3-a555-3613df5965a3","version":"2.1.193","gitBranch":"tom/validation-finale","slug":"plusieurs-chose-faire-crispy-axolotl"}
{"parentUuid":"192a9da8-1fdd-4184-9fe8-aecaee068f67","isSidechain":true,"agentId":"a9fd20a9d1d03f0e9","message":{"model":"claude-haiku-4-5-20251001","id":"msg_01LZVU7NRHs6uXXYSFXzPWgy","type":"message","role":"assistant","content":[{"type":"thinking","thinking":"","signature":"EqcECm0IDxgCKkA5gbsJo4QRnQKISkIvC8B/AZpn9AMQMtXY8hS43rYbFJspt8xf+91e8eAMlnSHWPVJ899+sJR+8GaVp4ZaIWpvMhljbGF1ZGUtaGFpa3UtNC01LTIwMjUxMDAxOABCCHRoaW5raW5nEgxpPvhkf/MGkfn7+SsaDIS81L8cViG4FLS33CIwF/f+0itA6F4WjeMnH7Y6CjtOHZJcZNiY28MGOUshvVQ1+2xFg0HdehjK5rv0ALMHKucCzLqp8qbmcL4r6l4EVv8ePdSRTgZ+NFsE1TyQXos5jIcDz5x3cr/mFhn53FcMpszCcIYH0KCI4btUyepxfd/8KL2EMXMEWqIZlFEpQfOgiUrCEzQiaTeztI4sa0NdfqH8yt4sZHkm/St8Xy4PjYm/CPQeXc/AzvnHg41nfKoJtLbj4JtYmLvTqRDH6hsl6Jb13W+QPU8xhc4q+iEGU/MNizxQTVIUwYUQ2sFdFo2bLshyuJFOWj6uabQuhPcq2HCTDXkOUI7Rk9XLsYVRv10rDatQKNBsTr3dfbcbFVxLQj2oGbbUOMtyeGkjipKb/jORhEwmjU9LAUFoH79Ep7MahNkhg4GfLZS8aq6WZzKXJhdSriGB/i31HSuD6JvmZLHpwiSl5TZ2xYG8lO1BeZt/Ll5dhKSPmrHpUQ7iDG5BpFGCRe4nWKazzU8J8BvFB8Clb99XMLUY7eYNC3qcPDzD8YuOWP29LNsYAQ=="}],"stop_reason":null,"stop_sequence":null,"stop_details":null,"usage":{"input_tokens":9085,"cache_creation_input_tokens":47417,"cache_read_input_tokens":30670,"cache_creation":{"ephemeral_5m_input_tokens":47417,"ephemeral_1h_input_tokens":0},"output_tokens":1,"service_tier":"standard","inference_geo":"not_available"},"diagnostics":null},"requestId":"req_011CcRpsPQ4EGnDewxUU4CYJ","attributionAgent":"Explore","type":"assistant","uuid":"26af3cc6-4509-4b76-8d5b-a81d59937184","timestamp":"2026-06-26T11:54:05.206Z","userType":"external","entrypoint":"cli","cwd":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale","sessionId":"c02b163b-170b-4cd3-a555-3613df5965a3","version":"2.1.193","gitBranch":"tom/validation-finale","slug":"plusieurs-chose-faire-crispy-axolotl"}
{"parentUuid":"26af3cc6-4509-4b76-8d5b-a81d59937184","isSidechain":true,"agentId":"a9fd20a9d1d03f0e9","message":{"model":"claude-haiku-4-5-20251001","id":"msg_01LZVU7NRHs6uXXYSFXzPWgy","type":"message","role":"assistant","content":[{"type":"tool_use","id":"toolu_01DjSsqVuWrH24dyCpFrbZSu","name":"Read","input":{"file_path":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/tailwind.config.ts"},"caller":{"type":"direct"}}],"stop_reason":null,"stop_sequence":null,"stop_details":null,"usage":{"input_tokens":9085,"cache_creation_input_tokens":47417,"cache_read_input_tokens":30670,"cache_creation":{"ephemeral_5m_input_tokens":47417,"ephemeral_1h_input_tokens":0},"output_tokens":1,"service_tier":"standard","inference_geo":"not_available"},"diagnostics":null},"requestId":"req_011CcRpsPQ4EGnDewxUU4CYJ","attributionAgent":"Explore","type":"assistant","uuid":"4cc9bec5-a3eb-471a-a7fb-e22f07ba1959","timestamp":"2026-06-26T11:54:05.808Z","userType":"external","entrypoint":"cli","cwd":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale","sessionId":"c02b163b-170b-4cd3-a555-3613df5965a3","version":"2.1.193","gitBranch":"tom/validation-finale","slug":"plusieurs-chose-faire-crispy-axolotl"}
{"parentUuid":"4cc9bec5-a3eb-471a-a7fb-e22f07ba1959","isSidechain":true,"promptId":"606b4c79-d3cd-4b0a-a2e5-8b38011359cb","agentId":"a9fd20a9d1d03f0e9","type":"user","message":{"role":"user","content":[{"tool_use_id":"toolu_01DjSsqVuWrH24dyCpFrbZSu","type":"tool_result","content":"1\timport type { Config } from \"tailwindcss\";\n2\timport tailwindcssAnimate from \"tailwindcss-animate\";\n3\t\n4\texport default {\n5\t  darkMode: [\"class\"],\n6\t  content: [\"./pages/**/*.{ts,tsx}\", \"./components/**/*.{ts,tsx}\", \"./app/**/*.{ts,tsx}\", \"./src/**/*.{ts,tsx}\"],\n7\t  prefix: \"\",\n8\t  theme: {\n9\t    container: {\n10\t      center: true,\n11\t      padding: \"2rem\",\n12\t      screens: {\n13\t        \"xl\": \"1200px\",\n14\t        \"2xl\": \"1200px\",\n15\t      },\n16\t    },\n17\t    extend: {\n18\t      colors: {\n19\t        border: \"hsl(var(--border))\",\n20\t        input: \"hsl(var(--input))\",\n21\t        ring: \"hsl(var(--ring))\",\n22\t        background: \"hsl(var(--background))\",\n23\t        foreground: \"hsl(var(--foreground))\",\n24\t        primary: {\n25\t          DEFAULT: \"hsl(var(--primary))\",\n26\t          foreground: \"hsl(var(--primary-foreground))\",\n27\t        },\n28\t        secondary: {\n29\t          DEFAULT: \"hsl(var(--secondary))\",\n30\t          foreground: \"hsl(var(--secondary-foreground))\",\n31\t        },\n32\t        destructive: {\n33\t          DEFAULT: \"hsl(var(--destructive))\",\n34\t          foreground: \"hsl(var(--destructive-foreground))\",\n35\t        },\n36\t        muted: {\n37\t          DEFAULT: \"hsl(var(--muted))\",\n38\t          foreground: \"hsl(var(--muted-foreground))\",\n39\t        },\n40\t        accent: {\n41\t          DEFAULT: \"hsl(var(--accent))\",\n42\t          foreground: \"hsl(var(--accent-foreground))\",\n43\t        },\n44\t        popover: {\n45\t          DEFAULT: \"hsl(var(--popover))\",\n46\t          foreground: \"hsl(var(--popover-foreground))\",\n47\t        },\n48\t        card: {\n49\t          DEFAULT: \"hsl(var(--card))\",\n50\t          foreground: \"hsl(var(--card-foreground))\",\n51\t        },\n52\t        navy: {\n53\t          DEFAULT: \"hsl(var(--navy))\",\n54\t          light: \"hsl(var(--navy-light))\",\n55\t        },\n56\t        teal: {\n57\t          DEFAULT: \"hsl(var(--teal))\",\n58\t          light: \"hsl(var(--teal-light))\",\n59\t          dark: \"hsl(var(--teal-dark))\",\n60\t          vivid: \"hsl(var(--teal-vivid))\",\n61\t        },\n62\t        terracotta: {\n63\t          DEFAULT: \"hsl(var(--terracotta))\",\n64\t          dark: \"hsl(var(--terracotta-dark))\",\n65\t        },\n66\t        cream: \"hsl(var(--cream))\",\n67\t        offwhite: \"hsl(var(--offwhite))\",\n68\t        slate: \"hsl(var(--slate))\",\n69\t        sidebar: {\n70\t          DEFAULT: \"hsl(var(--sidebar-background))\",\n71\t          foreground: \"hsl(var(--sidebar-foreground))\",\n72\t          primary: \"hsl(var(--sidebar-primary))\",\n73\t          \"primary-foreground\": \"hsl(var(--sidebar-primary-foreground))\",\n74\t          accent: \"hsl(var(--sidebar-accent))\",\n75\t          \"accent-foreground\": \"hsl(var(--sidebar-accent-foreground))\",\n76\t          border: \"hsl(var(--sidebar-border))\",\n77\t          ring: \"hsl(var(--sidebar-ring))\",\n78\t        },\n79\t      },\n80\t      fontFamily: {\n81\t        satoshi: ['Satoshi', 'sans-serif'],\n82\t        body: ['var(--font-body)', 'Plus Jakarta Sans', 'sans-serif'],\n83\t        display: ['var(--font-display)', 'Space Grotesk', 'sans-serif'],\n84\t      },\n85\t      borderRadius: {\n86\t        lg: \"var(--radius)\",\n87\t        md: \"calc(var(--radius) - 2px)\",\n88\t        sm: \"calc(var(--radius) - 4px)\",\n89\t      },\n90\t      keyframes: {\n91\t        \"accordion-down\": {\n92\t          from: { height: \"0\" },\n93\t          to: { height: \"var(--radix-accordion-content-height)\" },\n94\t        },\n95\t        \"accordion-up\": {\n96\t          from: { height: \"var(--radix-accordion-content-height)\" },\n97\t          to: { height: \"0\" },\n98\t        },\n99\t      },\n100\t      animation: {\n101\t        \"accordion-down\": \"accordion-down 0.2s ease-out\",\n102\t        \"accordion-up\": \"accordion-up 0.2s ease-out\",\n103\t      },\n104\t    },\n105\t  },\n106\t  plugins: [tailwindcssAnimate],\n107\t} satisfies Config;\n108\t"}]},"uuid":"c6601cf7-4894-4e07-b5f8-43be652737c4","timestamp":"2026-06-26T11:54:05.833Z","toolUseResult":{"type":"text","file":{"filePath":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/tailwind.config.ts","content":"import type { Config } from \"tailwindcss\";\nimport tailwindcssAnimate from \"tailwindcss-animate\";\n\nexport default {\n  darkMode: [\"class\"],\n  content: [\"./pages/**/*.{ts,tsx}\", \"./components/**/*.{ts,tsx}\", \"./app/**/*.{ts,tsx}\", \"./src/**/*.{ts,tsx}\"],\n  prefix: \"\",\n  theme: {\n    container: {\n      center: true,\n      padding: \"2rem\",\n      screens: {\n        \"xl\": \"1200px\",\n        \"2xl\": \"1200px\",\n      },\n    },\n    extend: {\n      colors: {\n        border: \"hsl(var(--border))\",\n        input: \"hsl(var(--input))\",\n        ring: \"hsl(var(--ring))\",\n        background: \"hsl(var(--background))\",\n        foreground: \"hsl(var(--foreground))\",\n        primary: {\n          DEFAULT: \"hsl(var(--primary))\",\n          foreground: \"hsl(var(--primary-foreground))\",\n        },\n        secondary: {\n          DEFAULT: \"hsl(var(--secondary))\",\n          foreground: \"hsl(var(--secondary-foreground))\",\n        },\n        destructive: {\n          DEFAULT: \"hsl(var(--destructive))\",\n          foreground: \"hsl(var(--destructive-foreground))\",\n        },\n        muted: {\n          DEFAULT: \"hsl(var(--muted))\",\n          foreground: \"hsl(var(--muted-foreground))\",\n        },\n        accent: {\n          DEFAULT: \"hsl(var(--accent))\",\n          foreground: \"hsl(var(--accent-foreground))\",\n        },\n        popover: {\n          DEFAULT: \"hsl(var(--popover))\",\n          foreground: \"hsl(var(--popover-foreground))\",\n        },\n        card: {\n          DEFAULT: \"hsl(var(--card))\",\n          foreground: \"hsl(var(--card-foreground))\",\n        },\n        navy: {\n          DEFAULT: \"hsl(var(--navy))\",\n          light: \"hsl(var(--navy-light))\",\n        },\n        teal: {\n          DEFAULT: \"hsl(var(--teal))\",\n          light: \"hsl(var(--teal-light))\",\n          dark: \"hsl(var(--teal-dark))\",\n          vivid: \"hsl(var(--teal-vivid))\",\n        },\n        terracotta: {\n          DEFAULT: \"hsl(var(--terracotta))\",\n          dark: \"hsl(var(--terracotta-dark))\",\n        },\n        cream: \"hsl(var(--cream))\",\n        offwhite: \"hsl(var(--offwhite))\",\n        slate: \"hsl(var(--slate))\",\n        sidebar: {\n          DEFAULT: \"hsl(var(--sidebar-background))\",\n          foreground: \"hsl(var(--sidebar-foreground))\",\n          primary: \"hsl(var(--sidebar-primary))\",\n          \"primary-foreground\": \"hsl(var(--sidebar-primary-foreground))\",\n          accent: \"hsl(var(--sidebar-accent))\",\n          \"accent-foreground\": \"hsl(var(--sidebar-accent-foreground))\",\n          border: \"hsl(var(--sidebar-border))\",\n          ring: \"hsl(var(--sidebar-ring))\",\n        },\n      },\n      fontFamily: {\n        satoshi: ['Satoshi', 'sans-serif'],\n        body: ['var(--font-body)', 'Plus Jakarta Sans', 'sans-serif'],\n        display: ['var(--font-display)', 'Space Grotesk', 'sans-serif'],\n      },\n      borderRadius: {\n        lg: \"var(--radius)\",\n        md: \"calc(var(--radius) - 2px)\",\n        sm: \"calc(var(--radius) - 4px)\",\n      },\n      keyframes: {\n        \"accordion-down\": {\n          from: { height: \"0\" },\n          to: { height: \"var(--radix-accordion-content-height)\" },\n        },\n        \"accordion-up\": {\n          from: { height: \"var(--radix-accordion-content-height)\" },\n          to: { height: \"0\" },\n        },\n      },\n      animation: {\n        \"accordion-down\": \"accordion-down 0.2s ease-out\",\n        \"accordion-up\": \"accordion-up 0.2s ease-out\",\n      },\n    },\n  },\n  plugins: [tailwindcssAnimate],\n} satisfies Config;\n","numLines":108,"startLine":1,"totalLines":108}},"sourceToolAssistantUUID":"4cc9bec5-a3eb-471a-a7fb-e22f07ba1959","userType":"external","entrypoint":"cli","cwd":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale","sessionId":"c02b163b-170b-4cd3-a555-3613df5965a3","version":"2.1.193","gitBranch":"tom/validation-finale","slug":"plusieurs-chose-faire-crispy-axolotl"}
{"parentUuid":"c6601cf7-4894-4e07-b5f8-43be652737c4","isSidechain":true,"agentId":"a9fd20a9d1d03f0e9","message":{"model":"claude-haiku-4-5-20251001","id":"msg_01LZVU7NRHs6uXXYSFXzPWgy","type":"message","role":"assistant","content":[{"type":"tool_use","id":"toolu_01JPrySzx1LGdbHUmWYjNSgH","name":"Read","input":{"file_path":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/src/index.css","limit":100},"caller":{"type":"direct"}}],"stop_reason":null,"stop_sequence":null,"stop_details":null,"usage":{"input_tokens":9085,"cache_creation_input_tokens":47417,"cache_read_input_tokens":30670,"cache_creation":{"ephemeral_5m_input_tokens":47417,"ephemeral_1h_input_tokens":0},"output_tokens":1,"service_tier":"standard","inference_geo":"not_available"},"diagnostics":null},"requestId":"req_011CcRpsPQ4EGnDewxUU4CYJ","attributionAgent":"Explore","type":"assistant","uuid":"2ae58350-b89f-423d-a0a9-72c11c48162e","timestamp":"2026-06-26T11:54:06.023Z","userType":"external","entrypoint":"cli","cwd":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale","sessionId":"c02b163b-170b-4cd3-a555-3613df5965a3","version":"2.1.193","gitBranch":"tom/validation-finale","slug":"plusieurs-chose-faire-crispy-axolotl"}
{"parentUuid":"2ae58350-b89f-423d-a0a9-72c11c48162e","isSidechain":true,"promptId":"606b4c79-d3cd-4b0a-a2e5-8b38011359cb","agentId":"a9fd20a9d1d03f0e9","type":"user","message":{"role":"user","content":[{"tool_use_id":"toolu_01JPrySzx1LGdbHUmWYjNSgH","type":"tool_result","content":"1\t@tailwind base;\n2\t@tailwind components;\n3\t@tailwind utilities;\n4\t\n5\t@layer base {\n6\t  :root {\n7\t    /* Covalba Design System : Original palette */\n8\t    --background: 60 20% 97%;\n9\t    --foreground: 215 52% 12%;\n10\t\n11\t    --card: 0 0% 100%;\n12\t    --card-foreground: 215 52% 12%;\n13\t\n14\t    --popover: 0 0% 100%;\n15\t    --popover-foreground: 215 52% 12%;\n16\t\n17\t    --primary: 179 61% 26%;\n18\t    --primary-foreground: 0 0% 100%;\n19\t\n20\t    --secondary: 180 33% 93%;\n21\t    --secondary-foreground: 215 52% 12%;\n22\t\n23\t    --muted: 60 14% 96%;\n24\t    --muted-foreground: 216 12% 40%;\n25\t\n26\t    --accent: 36 68% 50%;\n27\t    --accent-foreground: 0 0% 100%;\n28\t\n29\t    --destructive: 10 55% 49%;\n30\t    --destructive-foreground: 0 0% 100%;\n31\t\n32\t    --border: 60 14% 92%;\n33\t    --input: 60 7% 83%;\n34\t    --ring: 179 61% 26%;\n35\t\n36\t    --radius: 0.75rem;\n37\t\n38\t    /* Custom tokens */\n39\t    --navy: 215 52% 12%;\n40\t    --navy-light: 214 33% 17%;\n41\t    --teal: 179 61% 26%;\n42\t    --teal-light: 180 33% 93%;\n43\t    --teal-dark: 179 61% 20%;\n44\t    --teal-vivid: 180 52% 45%; /* #3AADAD — highlight sur fond navy */\n45\t    --terracotta: 10 55% 49%;\n46\t    --terracotta-dark: 10 58% 41%;\n47\t    --cream: 60 20% 97%;\n48\t    --offwhite: 60 14% 96%;\n49\t    --slate: 216 12% 40%;\n50\t\n51\t    --sidebar-background: 0 0% 98%;\n52\t    --sidebar-foreground: 240 5.3% 26.1%;\n53\t    --sidebar-primary: 240 5.9% 10%;\n54\t    --sidebar-primary-foreground: 0 0% 98%;\n55\t    --sidebar-accent: 240 4.8% 95.9%;\n56\t    --sidebar-accent-foreground: 240 5.9% 10%;\n57\t    --sidebar-border: 220 13% 91%;\n58\t    --sidebar-ring: 217.2 91.2% 59.8%;\n59\t  }\n60\t}\n61\t\n62\t@layer base {\n63\t  * {\n64\t    @apply border-border;\n65\t  }\n66\t\n67\t  html {\n68\t    scroll-behavior: smooth;\n69\t  }\n70\t\n71\t  body {\n72\t    @apply bg-background text-foreground antialiased;\n73\t    font-family: var(--font-body), 'Plus Jakarta Sans', sans-serif;\n74\t  }\n75\t\n76\t  h1, h2, h3, h4, h5, h6 {\n77\t    font-family: 'Satoshi', sans-serif;\n78\t    text-wrap: balance;\n79\t  }\n80\t\n81\t  /* Focus ring */\n82\t  :focus-visible {\n83\t    outline: 2px solid hsl(var(--primary));\n84\t    outline-offset: 2px;\n85\t    border-radius: 4px;\n86\t  }\n87\t\n88\t  /* Skip to content */\n89\t  .skip-link {\n90\t    position: absolute;\n91\t    left: -9999px;\n92\t    z-index: 999;\n93\t    padding: 0.5rem 1rem;\n94\t    background: hsl(var(--primary));\n95\t    color: white;\n96\t    font-weight: 600;\n97\t    border-radius: 0 0 0.5rem 0;\n98\t  }\n99\t  .skip-link:focus {\n100\t    left: 0;"}]},"uuid":"435b4fbb-6da0-4cb7-a8d9-9870cc6c4a55","timestamp":"2026-06-26T11:54:06.047Z","toolUseResult":{"type":"text","file":{"filePath":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/src/index.css","content":"@tailwind base;\n@tailwind components;\n@tailwind utilities;\n\n@layer base {\n  :root {\n    /* Covalba Design System : Original palette */\n    --background: 60 20% 97%;\n    --foreground: 215 52% 12%;\n\n    --card: 0 0% 100%;\n    --card-foreground: 215 52% 12%;\n\n    --popover: 0 0% 100%;\n    --popover-foreground: 215 52% 12%;\n\n    --primary: 179 61% 26%;\n    --primary-foreground: 0 0% 100%;\n\n    --secondary: 180 33% 93%;\n    --secondary-foreground: 215 52% 12%;\n\n    --muted: 60 14% 96%;\n    --muted-foreground: 216 12% 40%;\n\n    --accent: 36 68% 50%;\n    --accent-foreground: 0 0% 100%;\n\n    --destructive: 10 55% 49%;\n    --destructive-foreground: 0 0% 100%;\n\n    --border: 60 14% 92%;\n    --input: 60 7% 83%;\n    --ring: 179 61% 26%;\n\n    --radius: 0.75rem;\n\n    /* Custom tokens */\n    --navy: 215 52% 12%;\n    --navy-light: 214 33% 17%;\n    --teal: 179 61% 26%;\n    --teal-light: 180 33% 93%;\n    --teal-dark: 179 61% 20%;\n    --teal-vivid: 180 52% 45%; /* #3AADAD — highlight sur fond navy */\n    --terracotta: 10 55% 49%;\n    --terracotta-dark: 10 58% 41%;\n    --cream: 60 20% 97%;\n    --offwhite: 60 14% 96%;\n    --slate: 216 12% 40%;\n\n    --sidebar-background: 0 0% 98%;\n    --sidebar-foreground: 240 5.3% 26.1%;\n    --sidebar-primary: 240 5.9% 10%;\n    --sidebar-primary-foreground: 0 0% 98%;\n    --sidebar-accent: 240 4.8% 95.9%;\n    --sidebar-accent-foreground: 240 5.9% 10%;\n    --sidebar-border: 220 13% 91%;\n    --sidebar-ring: 217.2 91.2% 59.8%;\n  }\n}\n\n@layer base {\n  * {\n    @apply border-border;\n  }\n\n  html {\n    scroll-behavior: smooth;\n  }\n\n  body {\n    @apply bg-background text-foreground antialiased;\n    font-family: var(--font-body), 'Plus Jakarta Sans', sans-serif;\n  }\n\n  h1, h2, h3, h4, h5, h6 {\n    font-family: 'Satoshi', sans-serif;\n    text-wrap: balance;\n  }\n\n  /* Focus ring */\n  :focus-visible {\n    outline: 2px solid hsl(var(--primary));\n    outline-offset: 2px;\n    border-radius: 4px;\n  }\n\n  /* Skip to content */\n  .skip-link {\n    position: absolute;\n    left: -9999px;\n    z-index: 999;\n    padding: 0.5rem 1rem;\n    background: hsl(var(--primary));\n    color: white;\n    font-weight: 600;\n    border-radius: 0 0 0.5rem 0;\n  }\n  .skip-link:focus {\n    left: 0;","numLines":100,"startLine":1,"totalLines":461}},"sourceToolAssistantUUID":"2ae58350-b89f-423d-a0a9-72c11c48162e","userType":"external","entrypoint":"cli","cwd":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale","sessionId":"c02b163b-170b-4cd3-a555-3613df5965a3","version":"2.1.193","gitBranch":"tom/validation-finale","slug":"plusieurs-chose-faire-crispy-axolotl"}
{"parentUuid":"435b4fbb-6da0-4cb7-a8d9-9870cc6c4a55","isSidechain":true,"agentId":"a9fd20a9d1d03f0e9","message":{"model":"claude-haiku-4-5-20251001","id":"msg_01LZVU7NRHs6uXXYSFXzPWgy","type":"message","role":"assistant","content":[{"type":"tool_use","id":"toolu_016HCS4Nf9tKhk8au5JBRZjA","name":"Bash","input":{"command":"find /opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/app -type f -name \"*.tsx\" | grep -i industrie | head -5"},"caller":{"type":"direct"}}],"stop_reason":null,"stop_sequence":null,"stop_details":null,"usage":{"input_tokens":9085,"cache_creation_input_tokens":47417,"cache_read_input_tokens":30670,"cache_creation":{"ephemeral_5m_input_tokens":47417,"ephemeral_1h_input_tokens":0},"output_tokens":1,"service_tier":"standard","inference_geo":"not_available"},"diagnostics":null},"requestId":"req_011CcRpsPQ4EGnDewxUU4CYJ","attributionAgent":"Explore","type":"assistant","uuid":"80160962-731c-478a-9fc0-3ebf90c85ce5","timestamp":"2026-06-26T11:54:06.471Z","userType":"external","entrypoint":"cli","cwd":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale","sessionId":"c02b163b-170b-4cd3-a555-3613df5965a3","version":"2.1.193","gitBranch":"tom/validation-finale","slug":"plusieurs-chose-faire-crispy-axolotl"}
{"parentUuid":"80160962-731c-478a-9fc0-3ebf90c85ce5","isSidechain":true,"promptId":"606b4c79-d3cd-4b0a-a2e5-8b38011359cb","agentId":"a9fd20a9d1d03f0e9","type":"user","message":{"role":"user","content":[{"tool_use_id":"toolu_016HCS4Nf9tKhk8au5JBRZjA","type":"tool_result","content":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/app/industries/[slug]/sector-view-client.tsx\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/app/industries/[slug]/page.tsx","is_error":false}]},"uuid":"c1e928d1-d58f-4c44-895b-61ad034eac9f","timestamp":"2026-06-26T11:54:06.555Z","toolUseResult":{"stdout":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/app/industries/[slug]/sector-view-client.tsx\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/app/industries/[slug]/page.tsx","stderr":"","interrupted":false,"isImage":false,"noOutputExpected":false},"sourceToolAssistantUUID":"80160962-731c-478a-9fc0-3ebf90c85ce5","userType":"external","entrypoint":"cli","cwd":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale","sessionId":"c02b163b-170b-4cd3-a555-3613df5965a3","version":"2.1.193","gitBranch":"tom/validation-finale","slug":"plusieurs-chose-faire-crispy-axolotl"}
{"parentUuid":"c1e928d1-d58f-4c44-895b-61ad034eac9f","isSidechain":true,"agentId":"a9fd20a9d1d03f0e9","message":{"model":"claude-haiku-4-5-20251001","id":"msg_01LZVU7NRHs6uXXYSFXzPWgy","type":"message","role":"assistant","content":[{"type":"tool_use","id":"toolu_014ug5tzoSNYK3biGTfANhJH","name":"Bash","input":{"command":"git log --all --pretty=format:\"%H %s\" | grep -i \"industrie\\|sector\\|pharma\\|aero\" | head -5"},"caller":{"type":"direct"}}],"stop_reason":"tool_use","stop_sequence":null,"stop_details":null,"usage":{"input_tokens":9085,"cache_creation_input_tokens":47417,"cache_read_input_tokens":30670,"output_tokens":410,"server_tool_use":{"web_search_requests":0,"web_fetch_requests":0},"service_tier":"standard","cache_creation":{"ephemeral_1h_input_tokens":0,"ephemeral_5m_input_tokens":47417},"inference_geo":"not_available","iterations":[{"input_tokens":9085,"output_tokens":410,"cache_read_input_tokens":30670,"cache_creation_input_tokens":47417,"cache_creation":{"ephemeral_5m_input_tokens":47417,"ephemeral_1h_input_tokens":0},"type":"message"}],"speed":"standard"},"diagnostics":null},"requestId":"req_011CcRpsPQ4EGnDewxUU4CYJ","attributionAgent":"Explore","type":"assistant","uuid":"6a6a1f23-d94e-4108-b299-7e7839b05198","timestamp":"2026-06-26T11:54:06.878Z","userType":"external","entrypoint":"cli","cwd":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale","sessionId":"c02b163b-170b-4cd3-a555-3613df5965a3","version":"2.1.193","gitBranch":"tom/validation-finale","slug":"plusieurs-chose-faire-crispy-axolotl"}
{"parentUuid":"6a6a1f23-d94e-4108-b299-7e7839b05198","isSidechain":true,"promptId":"606b4c79-d3cd-4b0a-a2e5-8b38011359cb","agentId":"a9fd20a9d1d03f0e9","type":"user","message":{"role":"user","content":[{"tool_use_id":"toolu_014ug5tzoSNYK3biGTfANhJH","type":"tool_result","content":"72f320f095bc309aa8ac717113e1c8e6c3248aed feat(industrie): pages cool roof industrie, pharma & aéronautique (FR/EN/ES) (#11)\ne3e93480eb4a1a8972ae824b4afcc3e4d20adb1c feat(industrie): render 3 sector pages with SectorPageTemplate (FR) + bespoke images\n81f6998c5ade71ca0cc02626b120fcd243d5e8a9 feat(industrie): add cool roof industry pillar + pharma & aerospace pages","is_error":false}]},"uuid":"ee37be13-e34f-4335-8ae2-948d0d224b56","timestamp":"2026-06-26T11:54:06.962Z","toolUseResult":{"stdout":"72f320f095bc309aa8ac717113e1c8e6c3248aed feat(industrie): pages cool roof industrie, pharma & aéronautique (FR/EN/ES) (#11)\ne3e93480eb4a1a8972ae824b4afcc3e4d20adb1c feat(industrie): render 3 sector pages with SectorPageTemplate (FR) + bespoke images\n81f6998c5ade71ca0cc02626b120fcd243d5e8a9 feat(industrie): add cool roof industry pillar + pharma & aerospace pages","stderr":"","interrupted":false,"isImage":false,"noOutputExpected":false},"sourceToolAssistantUUID":"6a6a1f23-d94e-4108-b299-7e7839b05198","userType":"external","entrypoint":"cli","cwd":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale","sessionId":"c02b163b-170b-4cd3-a555-3613df5965a3","version":"2.1.193","gitBranch":"tom/validation-finale","slug":"plusieurs-chose-faire-crispy-axolotl"}
{"parentUuid":"ee37be13-e34f-4335-8ae2-948d0d224b56","isSidechain":true,"agentId":"a9fd20a9d1d03f0e9","message":{"model":"claude-haiku-4-5-20251001","id":"msg_01GXrqru17a1CnXuMiBkNNGD","type":"message","role":"assistant","content":[{"type":"thinking","thinking":"","signature":"Et8CCm0IDxgCKkCLu3whEq0CQzXKa8sD7W3/VmYb06VXZtqqHIsTP5W8pa0Hzmm54QiEgzu/zbv8+TNYuawP/31YzKxryC8fsoHcMhljbGF1ZGUtaGFpa3UtNC01LTIwMjUxMDAxOABCCHRoaW5raW5nEgzD1qIMMy+tPunClDIaDNtrhlA6MtEjBnWWLyIwNzaqQli/iGOxMEg3/WhNMQ2Qr3t0c0R3hgF50bEFQLqIqr28eclDGoN0DbWC0QgnKp8Bo/TAw5xy0LxczyP7CXikR9poS9ksxFQPsuFhYyoi0Wu3a7BEDghZYBijqF0VdEiNODD2mvLm/6LTdZMRK3LAt4Zol1nexTq3T1XkeZlBuhe9hRVOFyFUIok2pfc0Ltw/hxjqWtUWQiq9SV7Og2fXiZLlSXlU2NUXETuY1Cw7/r3hkBBrYQIr/1fw3fsDJmyLeSHmVlm3GZDxFNtHXgYkGAE="}],"stop_reason":null,"stop_sequence":null,"stop_details":null,"usage":{"input_tokens":8,"cache_creation_input_tokens":12377,"cache_read_input_tokens":78087,"cache_creation":{"ephemeral_5m_input_tokens":12377,"ephemeral_1h_input_tokens":0},"output_tokens":1,"service_tier":"standard","inference_geo":"not_available"},"diagnostics":null},"requestId":"req_011CcRpskJAB9Wy9PSgAJWQ8","attributionAgent":"Explore","type":"assistant","uuid":"f224a709-6371-475e-8718-121f999dca18","timestamp":"2026-06-26T11:54:08.794Z","userType":"external","entrypoint":"cli","cwd":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale","sessionId":"c02b163b-170b-4cd3-a555-3613df5965a3","version":"2.1.193","gitBranch":"tom/validation-finale","slug":"plusieurs-chose-faire-crispy-axolotl"}
{"parentUuid":"f224a709-6371-475e-8718-121f999dca18","isSidechain":true,"agentId":"a9fd20a9d1d03f0e9","message":{"model":"claude-haiku-4-5-20251001","id":"msg_01GXrqru17a1CnXuMiBkNNGD","type":"message","role":"assistant","content":[{"type":"tool_use","id":"toolu_01JUHMEFGg3b44EkXTQ78sQX","name":"Read","input":{"file_path":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/app/industries/[slug]/page.tsx"},"caller":{"type":"direct"}}],"stop_reason":null,"stop_sequence":null,"stop_details":null,"usage":{"input_tokens":8,"cache_creation_input_tokens":12377,"cache_read_input_tokens":78087,"cache_creation":{"ephemeral_5m_input_tokens":12377,"ephemeral_1h_input_tokens":0},"output_tokens":1,"service_tier":"standard","inference_geo":"not_available"},"diagnostics":null},"requestId":"req_011CcRpskJAB9Wy9PSgAJWQ8","attributionAgent":"Explore","type":"assistant","uuid":"9c32b884-12d2-4eae-87bd-875e543cc766","timestamp":"2026-06-26T11:54:08.870Z","userType":"external","entrypoint":"cli","cwd":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale","sessionId":"c02b163b-170b-4cd3-a555-3613df5965a3","version":"2.1.193","gitBranch":"tom/validation-finale","slug":"plusieurs-chose-faire-crispy-axolotl"}
{"parentUuid":"9c32b884-12d2-4eae-87bd-875e543cc766","isSidechain":true,"promptId":"606b4c79-d3cd-4b0a-a2e5-8b38011359cb","agentId":"a9fd20a9d1d03f0e9","type":"user","message":{"role":"user","content":[{"tool_use_id":"toolu_01JUHMEFGg3b44EkXTQ78sQX","type":"tool_result","content":"1\timport type { Metadata } from \"next\";\n2\timport { notFound } from \"next/navigation\";\n3\t\n4\timport Navbar from \"@/components/Navbar\";\n5\timport Footer from \"@/components/Footer\";\n6\timport StickyMobileCTA from \"@/components/StickyMobileCTA\";\n7\timport JsonLd from \"@/components/seo/JsonLd\";\n8\timport { BlockRenderer } from \"@/components/blocks/BlockRenderer\";\n9\timport { industryCanonicalPath } from \"@/lib/frProdRoutes\";\n10\timport { SITE_URL } from \"@/lib/seo\";\n11\timport { getAllIndustrieSlugs, getIndustrie } from \"@/lib/wp/queries/industrie\";\n12\timport { breadcrumbJsonLd, wpSeoToMetadata } from \"@/lib/wp/seoToMetadata\";\n13\timport SectorView from \"./sector-view-client\";\n14\t\n15\t// Pages secteurs pilotées par WordPress (CPT `industrie`, rewrite /industries).\n16\t//\n17\t// Deux modes de rendu :\n18\t// - tertiaire / collectivites / agricole / erp : vue d'origine\n19\t//   (SectorPageTemplate) via toSectorConfig dans le wrapper client\n20\t//   sector-view-client.tsx (parité pixel avec les vues src/views/industries/*) ;\n21\t// - logistique / distribution et tout autre slug : BlockRenderer générique\n22\t//   (les adaptateurs origine font le travail).\n23\tconst SECTOR_TEMPLATE_SLUGS = [\"tertiaire\", \"collectivites\", \"agricole\", \"erp\", \"industrie\", \"pharmaceutique\", \"aeronautique\"];\n24\t\n25\texport const dynamicParams = true;\n26\t\n27\texport async function generateStaticParams() {\n28\t  const slugs = await getAllIndustrieSlugs();\n29\t  return slugs.map((slug) => ({ slug }));\n30\t}\n31\t\n32\texport async function generateMetadata({\n33\t  params,\n34\t}: {\n35\t  params: Promise<{ slug: string }>;\n36\t}): Promise<Metadata> {\n37\t  const { slug } = await params;\n38\t  const industrie = await getIndustrie(slug);\n39\t  if (!industrie) return {};\n40\t  const canonical = `${SITE_URL}${industryCanonicalPath(slug)}`;\n41\t\n42\t  return wpSeoToMetadata({ ...industrie.seo, canonical }, {\n43\t    title: industrie.title ?? undefined,\n44\t    canonical,\n45\t  });\n46\t}\n47\t\n48\texport default async function Page({\n49\t  params,\n50\t}: {\n51\t  params: Promise<{ slug: string }>;\n52\t}) {\n53\t  const { slug } = await params;\n54\t  const industrie = await getIndustrie(slug);\n55\t  if (!industrie) notFound();\n56\t  const pageUrl = `${SITE_URL}${industryCanonicalPath(slug)}`;\n57\t\n58\t  const breadcrumb = (\n59\t    <JsonLd\n60\t      id={`industrie-${slug}-breadcrumb-jsonld`}\n61\t      data={breadcrumbJsonLd([\n62\t        { name: \"Accueil\", url: `${SITE_URL}/` },\n63\t        { name: \"Industries\", url: `${SITE_URL}/industrie` },\n64\t        { name: industrie.title ?? slug, url: pageUrl },\n65\t      ])}\n66\t    />\n67\t  );\n68\t\n69\t  if (SECTOR_TEMPLATE_SLUGS.includes(slug)) {\n70\t    return (\n71\t      <>\n72\t        {breadcrumb}\n73\t        <SectorView slug={slug} sections={industrie.sections?.sections ?? null} />\n74\t      </>\n75\t    );\n76\t  }\n77\t\n78\t  return (\n79\t    <div className=\"min-h-screen bg-background\">\n80\t      {breadcrumb}\n81\t      <Navbar />\n82\t      <main>\n83\t        <BlockRenderer sections={industrie.sections?.sections} />\n84\t      </main>\n85\t      <Footer />\n86\t      <StickyMobileCTA />\n87\t    </div>\n88\t  );\n89\t}\n90\t"}]},"uuid":"e5d7bb1b-d1ae-434c-b214-1cbd785f422a","timestamp":"2026-06-26T11:54:08.905Z","toolUseResult":{"type":"text","file":{"filePath":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/app/industries/[slug]/page.tsx","content":"import type { Metadata } from \"next\";\nimport { notFound } from \"next/navigation\";\n\nimport Navbar from \"@/components/Navbar\";\nimport Footer from \"@/components/Footer\";\nimport StickyMobileCTA from \"@/components/StickyMobileCTA\";\nimport JsonLd from \"@/components/seo/JsonLd\";\nimport { BlockRenderer } from \"@/components/blocks/BlockRenderer\";\nimport { industryCanonicalPath } from \"@/lib/frProdRoutes\";\nimport { SITE_URL } from \"@/lib/seo\";\nimport { getAllIndustrieSlugs, getIndustrie } from \"@/lib/wp/queries/industrie\";\nimport { breadcrumbJsonLd, wpSeoToMetadata } from \"@/lib/wp/seoToMetadata\";\nimport SectorView from \"./sector-view-client\";\n\n// Pages secteurs pilotées par WordPress (CPT `industrie`, rewrite /industries).\n//\n// Deux modes de rendu :\n// - tertiaire / collectivites / agricole / erp : vue d'origine\n//   (SectorPageTemplate) via toSectorConfig dans le wrapper client\n//   sector-view-client.tsx (parité pixel avec les vues src/views/industries/*) ;\n// - logistique / distribution et tout autre slug : BlockRenderer générique\n//   (les adaptateurs origine font le travail).\nconst SECTOR_TEMPLATE_SLUGS = [\"tertiaire\", \"collectivites\", \"agricole\", \"erp\", \"industrie\", \"pharmaceutique\", \"aeronautique\"];\n\nexport const dynamicParams = true;\n\nexport async function generateStaticParams() {\n  const slugs = await getAllIndustrieSlugs();\n  return slugs.map((slug) => ({ slug }));\n}\n\nexport async function generateMetadata({\n  params,\n}: {\n  params: Promise<{ slug: string }>;\n}): Promise<Metadata> {\n  const { slug } = await params;\n  const industrie = await getIndustrie(slug);\n  if (!industrie) return {};\n  const canonical = `${SITE_URL}${industryCanonicalPath(slug)}`;\n\n  return wpSeoToMetadata({ ...industrie.seo, canonical }, {\n    title: industrie.title ?? undefined,\n    canonical,\n  });\n}\n\nexport default async function Page({\n  params,\n}: {\n  params: Promise<{ slug: string }>;\n}) {\n  const { slug } = await params;\n  const industrie = await getIndustrie(slug);\n  if (!industrie) notFound();\n  const pageUrl = `${SITE_URL}${industryCanonicalPath(slug)}`;\n\n  const breadcrumb = (\n    <JsonLd\n      id={`industrie-${slug}-breadcrumb-jsonld`}\n      data={breadcrumbJsonLd([\n        { name: \"Accueil\", url: `${SITE_URL}/` },\n        { name: \"Industries\", url: `${SITE_URL}/industrie` },\n        { name: industrie.title ?? slug, url: pageUrl },\n      ])}\n    />\n  );\n\n  if (SECTOR_TEMPLATE_SLUGS.includes(slug)) {\n    return (\n      <>\n        {breadcrumb}\n        <SectorView slug={slug} sections={industrie.sections?.sections ?? null} />\n      </>\n    );\n  }\n\n  return (\n    <div className=\"min-h-screen bg-background\">\n      {breadcrumb}\n      <Navbar />\n      <main>\n        <BlockRenderer sections={industrie.sections?.sections} />\n      </main>\n      <Footer />\n      <StickyMobileCTA />\n    </div>\n  );\n}\n","numLines":90,"startLine":1,"totalLines":90}},"sourceToolAssistantUUID":"9c32b884-12d2-4eae-87bd-875e543cc766","userType":"external","entrypoint":"cli","cwd":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale","sessionId":"c02b163b-170b-4cd3-a555-3613df5965a3","version":"2.1.193","gitBranch":"tom/validation-finale","slug":"plusieurs-chose-faire-crispy-axolotl"}
{"parentUuid":"e5d7bb1b-d1ae-434c-b214-1cbd785f422a","isSidechain":true,"agentId":"a9fd20a9d1d03f0e9","message":{"model":"claude-haiku-4-5-20251001","id":"msg_01GXrqru17a1CnXuMiBkNNGD","type":"message","role":"assistant","content":[{"type":"tool_use","id":"toolu_01CLYkG2CW9Jg62RrZwuuSJT","name":"Read","input":{"file_path":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/app/industries/[slug]/sector-view-client.tsx"},"caller":{"type":"direct"}}],"stop_reason":null,"stop_sequence":null,"stop_details":null,"usage":{"input_tokens":8,"cache_creation_input_tokens":12377,"cache_read_input_tokens":78087,"cache_creation":{"ephemeral_5m_input_tokens":12377,"ephemeral_1h_input_tokens":0},"output_tokens":1,"service_tier":"standard","inference_geo":"not_available"},"diagnostics":null},"requestId":"req_011CcRpskJAB9Wy9PSgAJWQ8","attributionAgent":"Explore","type":"assistant","uuid":"0c8eb683-07cb-4472-b953-4ee42954246e","timestamp":"2026-06-26T11:54:09.313Z","userType":"external","entrypoint":"cli","cwd":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale","sessionId":"c02b163b-170b-4cd3-a555-3613df5965a3","version":"2.1.193","gitBranch":"tom/validation-finale","slug":"plusieurs-chose-faire-crispy-axolotl"}
{"parentUuid":"0c8eb683-07cb-4472-b953-4ee42954246e","isSidechain":true,"promptId":"606b4c79-d3cd-4b0a-a2e5-8b38011359cb","agentId":"a9fd20a9d1d03f0e9","type":"user","message":{"role":"user","content":[{"tool_use_id":"toolu_01CLYkG2CW9Jg62RrZwuuSJT","type":"tool_result","content":"1\t\"use client\";\n2\t\n3\t// Wrapper client pour les secteurs disposant d'une vue d'origine\n4\t// (Tertiaire / Collectivités / Agricole / ERP) : reconstruit la config du\n5\t// SectorPageTemplate depuis les sections WP via toSectorConfig, avec la config\n6\t// codée d'origine en fallback champ à champ (parité pixel). Les configs vivent\n7\t// dans des modules \"use client\" : impossible de les importer côté serveur.\n8\t// La composition (Navbar / main / Footer / StickyMobileCTA) reproduit\n9\t// exactement celle des vues src/views/industries/*.\n10\t\n11\timport Navbar from \"@/components/Navbar\";\n12\timport Footer from \"@/components/Footer\";\n13\timport StickyMobileCTA from \"@/components/StickyMobileCTA\";\n14\timport {\n15\t  SectorPageTemplate,\n16\t  type SectorPageConfig,\n17\t} from \"@/components/industries/SectorPageTemplate\";\n18\timport { toSectorConfig } from \"@/lib/wp/toSectorConfig\";\n19\timport { config as agricoleConfig } from \"@/views/industries/Agricole\";\n20\timport { config as collectivitesConfig } from \"@/views/industries/Collectivites\";\n21\timport { config as erpConfig } from \"@/views/industries/ERP\";\n22\timport { config as tertiaireConfig } from \"@/views/industries/Tertiaire\";\n23\timport { config as industrieConfig } from \"@/views/industries/Industrie\";\n24\timport { config as pharmaceutiqueConfig } from \"@/views/industries/Pharmaceutique\";\n25\timport { config as aeronautiqueConfig } from \"@/views/industries/Aeronautique\";\n26\timport type { WpSection } from \"@/lib/wp/types\";\n27\t\n28\tconst CONFIGS: Record<string, SectorPageConfig> = {\n29\t  tertiaire: tertiaireConfig,\n30\t  collectivites: collectivitesConfig,\n31\t  agricole: agricoleConfig,\n32\t  erp: erpConfig,\n33\t  industrie: industrieConfig,\n34\t  pharmaceutique: pharmaceutiqueConfig,\n35\t  aeronautique: aeronautiqueConfig,\n36\t};\n37\t\n38\texport default function SectorView({\n39\t  slug,\n40\t  sections,\n41\t}: {\n42\t  slug: string;\n43\t  sections: WpSection[] | null;\n44\t}) {\n45\t  const fallback = CONFIGS[slug];\n46\t  if (!fallback) return null;\n47\t\n48\t  const config = toSectorConfig(sections, fallback);\n49\t\n50\t  return (\n51\t    <>\n52\t      <Navbar />\n53\t      <main>\n54\t        <SectorPageTemplate config={config} />\n55\t      </main>\n56\t      <Footer />\n57\t      <StickyMobileCTA />\n58\t    </>\n59\t  );\n60\t}\n61\t"}]},"uuid":"e7169508-f0aa-4fde-9a19-d50098810f47","timestamp":"2026-06-26T11:54:09.330Z","toolUseResult":{"type":"text","file":{"filePath":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/app/industries/[slug]/sector-view-client.tsx","content":"\"use client\";\n\n// Wrapper client pour les secteurs disposant d'une vue d'origine\n// (Tertiaire / Collectivités / Agricole / ERP) : reconstruit la config du\n// SectorPageTemplate depuis les sections WP via toSectorConfig, avec la config\n// codée d'origine en fallback champ à champ (parité pixel). Les configs vivent\n// dans des modules \"use client\" : impossible de les importer côté serveur.\n// La composition (Navbar / main / Footer / StickyMobileCTA) reproduit\n// exactement celle des vues src/views/industries/*.\n\nimport Navbar from \"@/components/Navbar\";\nimport Footer from \"@/components/Footer\";\nimport StickyMobileCTA from \"@/components/StickyMobileCTA\";\nimport {\n  SectorPageTemplate,\n  type SectorPageConfig,\n} from \"@/components/industries/SectorPageTemplate\";\nimport { toSectorConfig } from \"@/lib/wp/toSectorConfig\";\nimport { config as agricoleConfig } from \"@/views/industries/Agricole\";\nimport { config as collectivitesConfig } from \"@/views/industries/Collectivites\";\nimport { config as erpConfig } from \"@/views/industries/ERP\";\nimport { config as tertiaireConfig } from \"@/views/industries/Tertiaire\";\nimport { config as industrieConfig } from \"@/views/industries/Industrie\";\nimport { config as pharmaceutiqueConfig } from \"@/views/industries/Pharmaceutique\";\nimport { config as aeronautiqueConfig } from \"@/views/industries/Aeronautique\";\nimport type { WpSection } from \"@/lib/wp/types\";\n\nconst CONFIGS: Record<string, SectorPageConfig> = {\n  tertiaire: tertiaireConfig,\n  collectivites: collectivitesConfig,\n  agricole: agricoleConfig,\n  erp: erpConfig,\n  industrie: industrieConfig,\n  pharmaceutique: pharmaceutiqueConfig,\n  aeronautique: aeronautiqueConfig,\n};\n\nexport default function SectorView({\n  slug,\n  sections,\n}: {\n  slug: string;\n  sections: WpSection[] | null;\n}) {\n  const fallback = CONFIGS[slug];\n  if (!fallback) return null;\n\n  const config = toSectorConfig(sections, fallback);\n\n  return (\n    <>\n      <Navbar />\n      <main>\n        <SectorPageTemplate config={config} />\n      </main>\n      <Footer />\n      <StickyMobileCTA />\n    </>\n  );\n}\n","numLines":61,"startLine":1,"totalLines":61}},"sourceToolAssistantUUID":"0c8eb683-07cb-4472-b953-4ee42954246e","userType":"external","entrypoint":"cli","cwd":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale","sessionId":"c02b163b-170b-4cd3-a555-3613df5965a3","version":"2.1.193","gitBranch":"tom/validation-finale","slug":"plusieurs-chose-faire-crispy-axolotl"}
{"parentUuid":"e7169508-f0aa-4fde-9a19-d50098810f47","isSidechain":true,"agentId":"a9fd20a9d1d03f0e9","message":{"model":"claude-haiku-4-5-20251001","id":"msg_01GXrqru17a1CnXuMiBkNNGD","type":"message","role":"assistant","content":[{"type":"tool_use","id":"toolu_017yrqNN3PMoYS5Jw7KAg5UZ","name":"Bash","input":{"command":"git show 72f320f --stat | head -40"},"caller":{"type":"direct"}}],"stop_reason":null,"stop_sequence":null,"stop_details":null,"usage":{"input_tokens":8,"cache_creation_input_tokens":12377,"cache_read_input_tokens":78087,"cache_creation":{"ephemeral_5m_input_tokens":12377,"ephemeral_1h_input_tokens":0},"output_tokens":1,"service_tier":"standard","inference_geo":"not_available"},"diagnostics":null},"requestId":"req_011CcRpskJAB9Wy9PSgAJWQ8","attributionAgent":"Explore","type":"assistant","uuid":"7066b466-8e6d-43f4-82f7-1689f402f96e","timestamp":"2026-06-26T11:54:09.566Z","userType":"external","entrypoint":"cli","cwd":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale","sessionId":"c02b163b-170b-4cd3-a555-3613df5965a3","version":"2.1.193","gitBranch":"tom/validation-finale","slug":"plusieurs-chose-faire-crispy-axolotl"}
{"parentUuid":"7066b466-8e6d-43f4-82f7-1689f402f96e","isSidechain":true,"promptId":"606b4c79-d3cd-4b0a-a2e5-8b38011359cb","agentId":"a9fd20a9d1d03f0e9","type":"user","message":{"role":"user","content":[{"tool_use_id":"toolu_017yrqNN3PMoYS5Jw7KAg5UZ","type":"tool_result","content":"commit 72f320f095bc309aa8ac717113e1c8e6c3248aed\nAuthor: Tomassous-38 <assous.tom@gmail.com>\nDate:   Fri Jun 26 13:26:47 2026 +0200\n\n    feat(industrie): pages cool roof industrie, pharma & aéronautique (FR/EN/ES) (#11)\n    \n    * feat(industrie): add cool roof industry pillar + pharma & aerospace pages\n    \n    - Convert the /industrie hub into a proper `industrie` CPT page (FR/EN/ES),\n      SEO-optimised on \"cool roof pour bâtiments industriels\"\n    - Add two sector pages: pharmaceutical (/industries/pharmaceutique) and\n      aerospace (/industries/aeronautique), FR/EN/ES, generic BlockRenderer model\n    - Wire routing/i18n: frProdRoutes canonicals, resolve.ts FR_CONTENT,\n      routes.ts (sitemap), i18nRoutes triples, i18nNav sectors (FR/EN/ES)\n    - Add `pharmaceutique` + `aeronautique` secteur taxonomy terms (mu-plugin + SCHEMA)\n    - Remove legacy `page--industrie` (type page) + dedicated route/view/SEO data\n    - Add dedicated hero images (pharma, aerospace)\n    \n    Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\n    \n    * feat(industrie): render 3 sector pages with SectorPageTemplate (FR) + bespoke images\n    \n    The 3 industry pages now use the polished SectorPageTemplate model (like\n    agricole/erp/tertiaire) instead of the generic BlockRenderer, matching the\n    reference design exactly.\n    \n    - Add coded configs src/views/industries/{Industrie,Pharmaceutique,Aeronautique}.tsx\n      (full SectorPageConfig: hero lead-form, problem image cards, durability table,\n      funding section, benefits, applications, method, proof, FAQ, SEO)\n    - Add industrieSeo/pharmaSeo/aeronautiqueSeo to src/data/sectorSeo.ts\n    - Register slugs in SECTOR_TEMPLATE_SLUGS (app/industries/[slug] + app/[...slug])\n      and in CONFIGS (sector-view-client)\n    - Rewrite the 9 seeds (FR/EN/ES) to mirror the model (hero, logos, grille_cards,\n      texte_image, tableau_comparatif, chiffres, etapes, references_grille, faq, cta,\n      contenu_seo) with the generated image paths\n    - Generate 33 bespoke sector images (gpt-image-2): hero + 4 problem cards +\n      benefits + 5 application cards per page\n    \n    EN/ES keep the generic BlockRenderer render (site-wide architecture) with the\n    same content and images.","is_error":false}]},"uuid":"aa803bad-3222-4129-8cdb-14602a7528fb","timestamp":"2026-06-26T11:54:09.641Z","toolUseResult":{"stdout":"commit 72f320f095bc309aa8ac717113e1c8e6c3248aed\nAuthor: Tomassous-38 <assous.tom@gmail.com>\nDate:   Fri Jun 26 13:26:47 2026 +0200\n\n    feat(industrie): pages cool roof industrie, pharma & aéronautique (FR/EN/ES) (#11)\n    \n    * feat(industrie): add cool roof industry pillar + pharma & aerospace pages\n    \n    - Convert the /industrie hub into a proper `industrie` CPT page (FR/EN/ES),\n      SEO-optimised on \"cool roof pour bâtiments industriels\"\n    - Add two sector pages: pharmaceutical (/industries/pharmaceutique) and\n      aerospace (/industries/aeronautique), FR/EN/ES, generic BlockRenderer model\n    - Wire routing/i18n: frProdRoutes canonicals, resolve.ts FR_CONTENT,\n      routes.ts (sitemap), i18nRoutes triples, i18nNav sectors (FR/EN/ES)\n    - Add `pharmaceutique` + `aeronautique` secteur taxonomy terms (mu-plugin + SCHEMA)\n    - Remove legacy `page--industrie` (type page) + dedicated route/view/SEO data\n    - Add dedicated hero images (pharma, aerospace)\n    \n    Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\n    \n    * feat(industrie): render 3 sector pages with SectorPageTemplate (FR) + bespoke images\n    \n    The 3 industry pages now use the polished SectorPageTemplate model (like\n    agricole/erp/tertiaire) instead of the generic BlockRenderer, matching the\n    reference design exactly.\n    \n    - Add coded configs src/views/industries/{Industrie,Pharmaceutique,Aeronautique}.tsx\n      (full SectorPageConfig: hero lead-form, problem image cards, durability table,\n      funding section, benefits, applications, method, proof, FAQ, SEO)\n    - Add industrieSeo/pharmaSeo/aeronautiqueSeo to src/data/sectorSeo.ts\n    - Register slugs in SECTOR_TEMPLATE_SLUGS (app/industries/[slug] + app/[...slug])\n      and in CONFIGS (sector-view-client)\n    - Rewrite the 9 seeds (FR/EN/ES) to mirror the model (hero, logos, grille_cards,\n      texte_image, tableau_comparatif, chiffres, etapes, references_grille, faq, cta,\n      contenu_seo) with the generated image paths\n    - Generate 33 bespoke sector images (gpt-image-2): hero + 4 problem cards +\n      benefits + 5 application cards per page\n    \n    EN/ES keep the generic BlockRenderer render (site-wide architecture) with the\n    same content and images.","stderr":"","interrupted":false,"isImage":false,"noOutputExpected":false},"sourceToolAssistantUUID":"7066b466-8e6d-43f4-82f7-1689f402f96e","userType":"external","entrypoint":"cli","cwd":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale","sessionId":"c02b163b-170b-4cd3-a555-3613df5965a3","version":"2.1.193","gitBranch":"tom/validation-finale","slug":"plusieurs-chose-faire-crispy-axolotl"}
{"parentUuid":"aa803bad-3222-4129-8cdb-14602a7528fb","isSidechain":true,"agentId":"a9fd20a9d1d03f0e9","message":{"model":"claude-haiku-4-5-20251001","id":"msg_01GXrqru17a1CnXuMiBkNNGD","type":"message","role":"assistant","content":[{"type":"tool_use","id":"toolu_01LhJZpUKS8DpFmRoCLFPhYM","name":"Bash","input":{"command":"ls -la /opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/src/components/ | grep -i \"scroll\\|reveal\\|card\\|section\""},"caller":{"type":"direct"}}],"stop_reason":"tool_use","stop_sequence":null,"stop_details":null,"usage":{"input_tokens":8,"cache_creation_input_tokens":12377,"cache_read_input_tokens":78087,"output_tokens":330,"server_tool_use":{"web_search_requests":0,"web_fetch_requests":0},"service_tier":"standard","cache_creation":{"ephemeral_1h_input_tokens":0,"ephemeral_5m_input_tokens":12377},"inference_geo":"not_available","iterations":[{"input_tokens":8,"output_tokens":330,"cache_read_input_tokens":78087,"cache_creation_input_tokens":12377,"cache_creation":{"ephemeral_5m_input_tokens":12377,"ephemeral_1h_input_tokens":0},"type":"message"}],"speed":"standard"},"diagnostics":null},"requestId":"req_011CcRpskJAB9Wy9PSgAJWQ8","attributionAgent":"Explore","type":"assistant","uuid":"630bf263-88a2-425f-babf-fc6718784970","timestamp":"2026-06-26T11:54:09.773Z","userType":"external","entrypoint":"cli","cwd":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale","sessionId":"c02b163b-170b-4cd3-a555-3613df5965a3","version":"2.1.193","gitBranch":"tom/validation-finale","slug":"plusieurs-chose-faire-crispy-axolotl"}
{"parentUuid":"630bf263-88a2-425f-babf-fc6718784970","isSidechain":true,"promptId":"606b4c79-d3cd-4b0a-a2e5-8b38011359cb","agentId":"a9fd20a9d1d03f0e9","type":"user","message":{"role":"user","content":[{"tool_use_id":"toolu_01LhJZpUKS8DpFmRoCLFPhYM","type":"tool_result","content":"-rw-r--r--  1 dev dev  2944 Jun 26 11:46 ApplicatorsSection.tsx\n-rw-r--r--  1 dev dev  1463 Jun 26 11:46 CEESection.tsx\n-rw-r--r--  1 dev dev  3866 Jun 26 11:46 CTASection.tsx\n-rw-r--r--  1 dev dev 14590 Jun 26 11:46 ClimateScrollBlock.tsx\n-rw-r--r--  1 dev dev  4385 Jun 26 11:46 ConstatSection.tsx\n-rw-r--r--  1 dev dev  4526 Jun 26 11:46 CoolRoofExplainerSection.tsx\n-rw-r--r--  1 dev dev  5127 Jun 26 11:46 ExpertiseSection.tsx\n-rw-r--r--  1 dev dev  6342 Jun 26 11:46 IlotsChaleurSection.tsx\n-rw-r--r--  1 dev dev  4930 Jun 26 11:46 LocalIntroSection.tsx\n-rw-r--r--  1 dev dev  4836 Jun 26 11:46 LocalSolutionSection.tsx\n-rw-r--r--  1 dev dev  8770 Jun 26 11:46 MaillageInterneSection.tsx\n-rw-r--r--  1 dev dev 10402 Jun 26 11:46 NurturingPDFSection.tsx\n-rw-r--r--  1 dev dev  2881 Jun 26 11:46 PositionnementSection.tsx\n-rw-r--r--  1 dev dev  2274 Jun 26 11:46 PressSection.tsx\n-rw-r--r--  1 dev dev  2864 Jun 26 11:46 PrestationSecteursSection.tsx\n-rw-r--r--  1 dev dev 12084 Jun 26 11:46 PriceComparisonSection.tsx\n-rw-r--r--  1 dev dev  9234 Jun 26 11:46 PriceVSSection.tsx\n-rw-r--r--  1 dev dev  3200 Jun 26 11:46 ProblemSection.tsx\n-rw-r--r--  1 dev dev  7863 Jun 26 11:46 ProcessSection.tsx\n-rw-r--r--  1 dev dev  3203 Jun 26 11:46 RSESection.tsx\n-rw-r--r--  1 dev dev 11079 Jun 26 11:46 RoissyActivitiesSection.tsx\n-rw-r--r--  1 dev dev 10855 Jun 26 11:46 SEOContentSection.tsx\n-rw-r--r--  1 dev dev   568 Jun 26 11:46 ScrollReveal.tsx\n-rw-r--r--  1 dev dev 10463 Jun 26 11:46 SecteurIndustrielSection.tsx\n-rw-r--r--  1 dev dev  2698 Jun 26 11:46 SocialProofSection.tsx\n-rw-r--r--  1 dev dev  2911 Jun 26 11:46 SolutionSection.tsx\n-rw-r--r--  1 dev dev 13238 Jun 26 11:46 SystemSection.tsx\n-rw-r--r--  1 dev dev  3214 Jun 26 11:46 TypesToituresSection.tsx\n-rw-r--r--  1 dev dev   821 Jun 26 11:46 VideoSection.tsx\n-rw-r--r--  1 dev dev  3904 Jun 26 11:46 WinterObjectionSection.tsx\n-rw-r--r--  1 dev dev  4125 Jun 26 11:46 ZoneInterventionSection.tsx\n-rw-r--r--  1 dev dev  1919 Jun 26 11:46 climateScrollProjection.test.ts\n-rw-r--r--  1 dev dev  3823 Jun 26 11:46 climateScrollProjection.ts","is_error":false}]},"uuid":"44c734f6-c86a-4eb6-82a8-522ab0413cdd","timestamp":"2026-06-26T11:54:09.859Z","toolUseResult":{"stdout":"-rw-r--r--  1 dev dev  2944 Jun 26 11:46 ApplicatorsSection.tsx\n-rw-r--r--  1 dev dev  1463 Jun 26 11:46 CEESection.tsx\n-rw-r--r--  1 dev dev  3866 Jun 26 11:46 CTASection.tsx\n-rw-r--r--  1 dev dev 14590 Jun 26 11:46 ClimateScrollBlock.tsx\n-rw-r--r--  1 dev dev  4385 Jun 26 11:46 ConstatSection.tsx\n-rw-r--r--  1 dev dev  4526 Jun 26 11:46 CoolRoofExplainerSection.tsx\n-rw-r--r--  1 dev dev  5127 Jun 26 11:46 ExpertiseSection.tsx\n-rw-r--r--  1 dev dev  6342 Jun 26 11:46 IlotsChaleurSection.tsx\n-rw-r--r--  1 dev dev  4930 Jun 26 11:46 LocalIntroSection.tsx\n-rw-r--r--  1 dev dev  4836 Jun 26 11:46 LocalSolutionSection.tsx\n-rw-r--r--  1 dev dev  8770 Jun 26 11:46 MaillageInterneSection.tsx\n-rw-r--r--  1 dev dev 10402 Jun 26 11:46 NurturingPDFSection.tsx\n-rw-r--r--  1 dev dev  2881 Jun 26 11:46 PositionnementSection.tsx\n-rw-r--r--  1 dev dev  2274 Jun 26 11:46 PressSection.tsx\n-rw-r--r--  1 dev dev  2864 Jun 26 11:46 PrestationSecteursSection.tsx\n-rw-r--r--  1 dev dev 12084 Jun 26 11:46 PriceComparisonSection.tsx\n-rw-r--r--  1 dev dev  9234 Jun 26 11:46 PriceVSSection.tsx\n-rw-r--r--  1 dev dev  3200 Jun 26 11:46 ProblemSection.tsx\n-rw-r--r--  1 dev dev  7863 Jun 26 11:46 ProcessSection.tsx\n-rw-r--r--  1 dev dev  3203 Jun 26 11:46 RSESection.tsx\n-rw-r--r--  1 dev dev 11079 Jun 26 11:46 RoissyActivitiesSection.tsx\n-rw-r--r--  1 dev dev 10855 Jun 26 11:46 SEOContentSection.tsx\n-rw-r--r--  1 dev dev   568 Jun 26 11:46 ScrollReveal.tsx\n-rw-r--r--  1 dev dev 10463 Jun 26 11:46 SecteurIndustrielSection.tsx\n-rw-r--r--  1 dev dev  2698 Jun 26 11:46 SocialProofSection.tsx\n-rw-r--r--  1 dev dev  2911 Jun 26 11:46 SolutionSection.tsx\n-rw-r--r--  1 dev dev 13238 Jun 26 11:46 SystemSection.tsx\n-rw-r--r--  1 dev dev  3214 Jun 26 11:46 TypesToituresSection.tsx\n-rw-r--r--  1 dev dev   821 Jun 26 11:46 VideoSection.tsx\n-rw-r--r--  1 dev dev  3904 Jun 26 11:46 WinterObjectionSection.tsx\n-rw-r--r--  1 dev dev  4125 Jun 26 11:46 ZoneInterventionSection.tsx\n-rw-r--r--  1 dev dev  1919 Jun 26 11:46 climateScrollProjection.test.ts\n-rw-r--r--  1 dev dev  3823 Jun 26 11:46 climateScrollProjection.ts","stderr":"","interrupted":false,"isImage":false,"noOutputExpected":false},"sourceToolAssistantUUID":"630bf263-88a2-425f-babf-fc6718784970","userType":"external","entrypoint":"cli","cwd":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale","sessionId":"c02b163b-170b-4cd3-a555-3613df5965a3","version":"2.1.193","gitBranch":"tom/validation-finale","slug":"plusieurs-chose-faire-crispy-axolotl"}
{"parentUuid":"44c734f6-c86a-4eb6-82a8-522ab0413cdd","isSidechain":true,"agentId":"a9fd20a9d1d03f0e9","message":{"model":"claude-haiku-4-5-20251001","id":"msg_015muiZmvLZfUyNVs5o6EPhi","type":"message","role":"assistant","content":[{"type":"thinking","thinking":"","signature":"EogDCm0IDxgCKkBqNEBiKO6QLXVIettTZ5nq/fff+so+lLmB0V7tcOo8gPOddB5eLYyZ5NNYvU9CHrVSiqEcNHeTjc5VutQpt3VcMhljbGF1ZGUtaGFpa3UtNC01LTIwMjUxMDAxOABCCHRoaW5raW5nEgx6FdFMQg+kKCThSeUaDKmsDzM6ODbdjbSxqyIwFvMj2BARTgwb3tftg5YnQeDafOehMZeR4stgKFwdbn1qOzjO0M7NxmXn5NJzHCnfKsgB5jv66CjS2lzaXMLFqGMlnRu+sGvqS9GfTy84yGQ5V8sq7GPtcZnSXJ3frDB9+6Hzk1FyEjE0yw+alQZfQ5x+kbw/fTu2N5WXroSlUhl8BsHiJFhpMa3XhkchkjKeda+FqOBwMTLvjP3B1rDzhcN0KIxB/nKuBOPR/heHAobpairk6IwHHAsJZHISe42YWV2Q6xjRiflHQ4/xaz3Bfi90pXLjLbe704iWtr07xsjnHAWDcc8jJ2VXtajJa6K6fd9MC2qKOqWoio4YAQ=="}],"stop_reason":null,"stop_sequence":null,"stop_details":null,"usage":{"input_tokens":8,"cache_creation_input_tokens":4104,"cache_read_input_tokens":90464,"cache_creation":{"ephemeral_5m_input_tokens":4104,"ephemeral_1h_input_tokens":0},"output_tokens":3,"service_tier":"standard","inference_geo":"not_available"},"diagnostics":null},"requestId":"req_011CcRpsy5c5UF8SKdThMQSp","attributionAgent":"Explore","type":"assistant","uuid":"dba1de31-ddee-421c-b76c-693cd46acdb1","timestamp":"2026-06-26T11:54:11.456Z","userType":"external","entrypoint":"cli","cwd":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale","sessionId":"c02b163b-170b-4cd3-a555-3613df5965a3","version":"2.1.193","gitBranch":"tom/validation-finale","slug":"plusieurs-chose-faire-crispy-axolotl"}
{"parentUuid":"dba1de31-ddee-421c-b76c-693cd46acdb1","isSidechain":true,"agentId":"a9fd20a9d1d03f0e9","message":{"model":"claude-haiku-4-5-20251001","id":"msg_015muiZmvLZfUyNVs5o6EPhi","type":"message","role":"assistant","content":[{"type":"tool_use","id":"toolu_017Rcnn8Z5ddhNceBK5X2V3y","name":"Bash","input":{"command":"ls /opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/src/views/industries/ | head -20"},"caller":{"type":"direct"}}],"stop_reason":null,"stop_sequence":null,"stop_details":null,"usage":{"input_tokens":8,"cache_creation_input_tokens":4104,"cache_read_input_tokens":90464,"cache_creation":{"ephemeral_5m_input_tokens":4104,"ephemeral_1h_input_tokens":0},"output_tokens":3,"service_tier":"standard","inference_geo":"not_available"},"diagnostics":null},"requestId":"req_011CcRpsy5c5UF8SKdThMQSp","attributionAgent":"Explore","type":"assistant","uuid":"c928aff8-fd8a-40e7-bfbf-00508dcf7a64","timestamp":"2026-06-26T11:54:12.322Z","userType":"external","entrypoint":"cli","cwd":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale","sessionId":"c02b163b-170b-4cd3-a555-3613df5965a3","version":"2.1.193","gitBranch":"tom/validation-finale","slug":"plusieurs-chose-faire-crispy-axolotl"}
{"parentUuid":"c928aff8-fd8a-40e7-bfbf-00508dcf7a64","isSidechain":true,"promptId":"606b4c79-d3cd-4b0a-a2e5-8b38011359cb","agentId":"a9fd20a9d1d03f0e9","type":"user","message":{"role":"user","content":[{"tool_use_id":"toolu_017Rcnn8Z5ddhNceBK5X2V3y","type":"tool_result","content":"Aeronautique.tsx\nAgricole.test.tsx\nAgricole.tsx\nCollectivites.test.tsx\nCollectivites.tsx\nDistribution.test.tsx\nDistribution.tsx\nERP.test.tsx\nERP.tsx\nIndustrie.tsx\nLogistique.tsx\nPharmaceutique.tsx\nTertiaire.test.tsx\nTertiaire.tsx","is_error":false}]},"uuid":"77e25e39-5ab0-4f29-bfee-db3263aea54f","timestamp":"2026-06-26T11:54:12.371Z","toolUseResult":{"stdout":"Aeronautique.tsx\nAgricole.test.tsx\nAgricole.tsx\nCollectivites.test.tsx\nCollectivites.tsx\nDistribution.test.tsx\nDistribution.tsx\nERP.test.tsx\nERP.tsx\nIndustrie.tsx\nLogistique.tsx\nPharmaceutique.tsx\nTertiaire.test.tsx\nTertiaire.tsx","stderr":"","interrupted":false,"isImage":false,"noOutputExpected":false},"sourceToolAssistantUUID":"c928aff8-fd8a-40e7-bfbf-00508dcf7a64","userType":"external","entrypoint":"cli","cwd":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale","sessionId":"c02b163b-170b-4cd3-a555-3613df5965a3","version":"2.1.193","gitBranch":"tom/validation-finale","slug":"plusieurs-chose-faire-crispy-axolotl"}
{"parentUuid":"77e25e39-5ab0-4f29-bfee-db3263aea54f","isSidechain":true,"agentId":"a9fd20a9d1d03f0e9","message":{"model":"claude-haiku-4-5-20251001","id":"msg_015muiZmvLZfUyNVs5o6EPhi","type":"message","role":"assistant","content":[{"type":"tool_use","id":"toolu_01LKEmbYT2VbKbrtTLiJX38z","name":"Read","input":{"file_path":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/src/views/industries/Industrie.tsx","limit":150},"caller":{"type":"direct"}}],"stop_reason":null,"stop_sequence":null,"stop_details":null,"usage":{"input_tokens":8,"cache_creation_input_tokens":4104,"cache_read_input_tokens":90464,"cache_creation":{"ephemeral_5m_input_tokens":4104,"ephemeral_1h_input_tokens":0},"output_tokens":3,"service_tier":"standard","inference_geo":"not_available"},"diagnostics":null},"requestId":"req_011CcRpsy5c5UF8SKdThMQSp","attributionAgent":"Explore","type":"assistant","uuid":"362cd58d-27da-4d2e-bec2-21e32e8b6cc8","timestamp":"2026-06-26T11:54:12.772Z","userType":"external","entrypoint":"cli","cwd":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale","sessionId":"c02b163b-170b-4cd3-a555-3613df5965a3","version":"2.1.193","gitBranch":"tom/validation-finale","slug":"plusieurs-chose-faire-crispy-axolotl"}
{"parentUuid":"362cd58d-27da-4d2e-bec2-21e32e8b6cc8","isSidechain":true,"promptId":"606b4c79-d3cd-4b0a-a2e5-8b38011359cb","agentId":"a9fd20a9d1d03f0e9","type":"user","message":{"role":"user","content":[{"tool_use_id":"toolu_01LKEmbYT2VbKbrtTLiJX38z","type":"tool_result","content":"1\t\"use client\";\n2\t\n3\timport Navbar from '@/components/Navbar';\n4\timport Footer from '@/components/Footer';\n5\timport StickyMobileCTA from '@/components/StickyMobileCTA';\n6\timport { SectorPageTemplate, type SectorPageConfig } from '@/components/industries/SectorPageTemplate';\n7\timport { industrieSeo } from '@/data/sectorSeo';\n8\timport {\n9\t  BadgeCheck,\n10\t  Factory,\n11\t  FlaskConical,\n12\t  Flame,\n13\t  Gauge,\n14\t  Leaf,\n15\t  ShieldCheck,\n16\t  Snowflake,\n17\t  Thermometer,\n18\t  TrendingDown,\n19\t  UsersRound,\n20\t  Warehouse,\n21\t  Wrench,\n22\t  Zap,\n23\t} from 'lucide-react';\n24\t\n25\tconst img = (name: string) => `/images/industrie/${name}.webp`;\n26\t\n27\t// Exportée pour le wrapper client app/industries/[slug]/sector-view-client.tsx\n28\t// (fallback de toSectorConfig, rendu identique au modèle sectoriel).\n29\texport const config: SectorPageConfig = {\n30\t  ...industrieSeo,\n31\t  hero: {\n32\t    eyebrow: 'Cool roof bâtiment industriel',\n33\t    h1: 'Cool roof pour bâtiments industriels',\n34\t    sub: \"Réduisez la chaleur sous toiture, soulagez la climatisation et prolongez l'étanchéité — sans interrompre votre production.\",\n35\t    image: img('hero-batiment-industriel'),\n36\t    imageAlt: 'Bâtiment industriel avec toiture cool roof blanche réfléchissante',\n37\t    stats: [\n38\t      { icon: Thermometer, value: '-7 à -10°C', label: 'sous toiture' },\n39\t      { icon: Snowflake, value: 'jusqu’à -40%', label: 'de climatisation' },\n40\t      { icon: ShieldCheck, value: '+8 à 20 ans', label: 'd’étanchéité' },\n41\t    ],\n42\t    formTitle: 'Votre projet industriel',\n43\t    formSubtitle: 'Réponse personnalisée sous 48h',\n44\t    formFields: {\n45\t      typeLabel: 'Type de bâtiment',\n46\t      typeOptions: ['Usine de production', 'Agroalimentaire', 'Chimie / plasturgie', 'Hangar / entrepôt technique', 'Métallurgie', 'Autre'],\n47\t      climateLabel: 'Type de toiture',\n48\t      climateOptions: ['Membrane bitumineuse', 'Bac acier', 'EPDM / PVC', 'Fibrociment', 'À confirmer'],\n49\t      yearLabel: 'Année du bâtiment',\n50\t      microcopy: 'Étude technique offerte · Sans engagement',\n51\t      cta: 'Demander un devis',\n52\t    },\n53\t  },\n54\t  logos: {\n55\t    title: 'Des sites industriels nous font confiance',\n56\t    items: [\n57\t      { name: 'Continental' },\n58\t      { name: 'Thales' },\n59\t      { name: 'Nestlé' },\n60\t      { name: 'Servier' },\n61\t      { name: 'Somfy' },\n62\t    ],\n63\t  },\n64\t  problem: {\n65\t    eyebrow: 'Pourquoi agir',\n66\t    title: 'La chaleur pénalise',\n67\t    mutedTitle: 'directement vos bâtiments industriels.',\n68\t    intro:\n69\t      \"Sous une toiture exposée, la chaleur s'accumule, dégrade le confort de travail, sollicite les équipements et accélère le vieillissement de l'étanchéité.\",\n70\t    transition: 'La cause commune : une toiture sombre qui absorbe la chaleur au lieu de la renvoyer.',\n71\t    cards: [\n72\t      {\n73\t        icon: Thermometer,\n74\t        title: 'Confort de travail dégradé',\n75\t        desc: \"En atelier, les températures deviennent difficiles à supporter lors des pics de chaleur, avec un impact direct sur la productivité.\",\n76\t        image: img('problem-chaleur-atelier'),\n77\t        alt: 'Atelier industriel surchauffé en été',\n78\t      },\n79\t      {\n80\t        icon: Zap,\n81\t        title: 'Énergie en hausse',\n82\t        desc: 'Climatisation, ventilation et froid de process grimpent quand la toiture chauffe à 70-80°C.',\n83\t        image: img('problem-energie-toiture'),\n84\t        alt: 'Groupes de climatisation sur une toiture industrielle sombre',\n85\t      },\n86\t      {\n87\t        icon: Wrench,\n88\t        title: 'Équipements sur-sollicités',\n89\t        desc: 'Groupes froids, CTA et installations techniques tournent en surrégime et s’usent plus vite.',\n90\t        image: img('problem-equipements'),\n91\t        alt: 'Installation de froid de process industriel',\n92\t      },\n93\t      {\n94\t        icon: ShieldCheck,\n95\t        title: 'Étanchéité fragilisée',\n96\t        desc: \"Une toiture soumise aux UV et aux écarts thermiques vieillit plus vite : le remplacement approche.\",\n97\t        image: img('problem-etancheite'),\n98\t        alt: 'Étanchéité de toiture industrielle vieillissante',\n99\t      },\n100\t    ],\n101\t  },\n102\t  solution: {\n103\t    eyebrow: 'La solution Covalba',\n104\t    title: 'Votre toiture réfléchit',\n105\t    mutedTitle: 'au lieu de chauffer.',\n106\t    intro:\n107\t      \"Une toiture sombre absorbe le rayonnement et dépasse 70-80°C en surface. Le revêtement cool roof Covalba renvoie jusqu'à 90 % du rayonnement solaire : la toiture chauffe moins et transmet moins de chaleur au bâtiment.\",\n108\t    points: [\n109\t      'Solution passive, sans consommation d’énergie',\n110\t      'Posée depuis l’extérieur, sans arrêt de production',\n111\t      'Compatible bitume, bac acier, membrane, fibrociment',\n112\t      'Systèmes durables, 8 à 20 ans de tenue',\n113\t    ],\n114\t    transition: \"Reste la vraie question : combien coûte un revêtement s'il faut le refaire au bout de 2 à 5 ans ?\",\n115\t  },\n116\t  durability: {\n117\t    title: 'Le système Covalba',\n118\t    mutedTitle: 'tient plus longtemps sur vos toitures.',\n119\t    intro:\n120\t      \"Sur une toiture de plusieurs milliers de m², le prix au m² ne suffit pas : il faut compter la durée de vie, la réflectivité conservée et le risque de repasser trop tôt.\",\n121\t    note:\n122\t      'Les systèmes polyuréthane avec vernis de finition anti-UV sont conçus pour conserver leur performance 8 à 20 ans tout en protégeant la couverture.',\n123\t    covalbaLabel: 'Performance pensée dans la durée',\n124\t  },\n125\t  special: {\n126\t    kind: 'funding',\n127\t    eyebrow: 'Aides & financement',\n128\t    title: 'Des leviers peuvent financer une partie de vos travaux.',\n129\t    intro:\n130\t      \"Les bâtiments industriels ne relèvent pas de la prime CEE BAT-EN-112 (réservée au tertiaire commercial), mais d'autres dispositifs existent selon votre activité.\",\n131\t    points: [\n132\t      { value: 'Régions', label: 'aides à la rénovation et à la décarbonation selon votre région' },\n133\t      { value: 'ADEME', label: 'dispositifs liés à l’efficacité énergétique industrielle' },\n134\t      { value: '20-25 €/m²', label: 'contre 80 à 150 €/m² pour refaire l’étanchéité' },\n135\t      { value: 'ROI < 2 ans', label: 'sur les sites climatisés ou en froid de process' },\n136\t    ],\n137\t    note:\n138\t      \"Les leviers mobilisables dépendent de votre activité, de votre classification ICPE et de votre région. Covalba vous aide à les identifier avant devis.\",\n139\t    cta: 'Étudier mon financement',\n140\t  },\n141\t  benefits: {\n142\t    eyebrow: 'Ce que vous y gagnez',\n143\t    title: 'Moins de chaleur, plus de performance.',\n144\t    desc: \"Le cool roof agit sur la source de chaleur principale : la toiture. Les bénéfices se voient dès le premier été sur l'ambiance du bâtiment.\",\n145\t    metric: '-7 à -10°C',\n146\t    metricLabel: 'sous votre toiture',\n147\t    image: img('benefits-atelier-frais'),\n148\t    imageAlt: 'Atelier industriel moderne plus frais grâce au cool roof',\n149\t    transition: 'Au-delà du confort, voici comment le cool roof s’adapte à chaque type de site.',\n150\t    cards: ["}]},"uuid":"900d3816-9641-4e90-8978-463819a4e69c","timestamp":"2026-06-26T11:54:12.795Z","toolUseResult":{"type":"text","file":{"filePath":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/src/views/industries/Industrie.tsx","content":"\"use client\";\n\nimport Navbar from '@/components/Navbar';\nimport Footer from '@/components/Footer';\nimport StickyMobileCTA from '@/components/StickyMobileCTA';\nimport { SectorPageTemplate, type SectorPageConfig } from '@/components/industries/SectorPageTemplate';\nimport { industrieSeo } from '@/data/sectorSeo';\nimport {\n  BadgeCheck,\n  Factory,\n  FlaskConical,\n  Flame,\n  Gauge,\n  Leaf,\n  ShieldCheck,\n  Snowflake,\n  Thermometer,\n  TrendingDown,\n  UsersRound,\n  Warehouse,\n  Wrench,\n  Zap,\n} from 'lucide-react';\n\nconst img = (name: string) => `/images/industrie/${name}.webp`;\n\n// Exportée pour le wrapper client app/industries/[slug]/sector-view-client.tsx\n// (fallback de toSectorConfig, rendu identique au modèle sectoriel).\nexport const config: SectorPageConfig = {\n  ...industrieSeo,\n  hero: {\n    eyebrow: 'Cool roof bâtiment industriel',\n    h1: 'Cool roof pour bâtiments industriels',\n    sub: \"Réduisez la chaleur sous toiture, soulagez la climatisation et prolongez l'étanchéité — sans interrompre votre production.\",\n    image: img('hero-batiment-industriel'),\n    imageAlt: 'Bâtiment industriel avec toiture cool roof blanche réfléchissante',\n    stats: [\n      { icon: Thermometer, value: '-7 à -10°C', label: 'sous toiture' },\n      { icon: Snowflake, value: 'jusqu’à -40%', label: 'de climatisation' },\n      { icon: ShieldCheck, value: '+8 à 20 ans', label: 'd’étanchéité' },\n    ],\n    formTitle: 'Votre projet industriel',\n    formSubtitle: 'Réponse personnalisée sous 48h',\n    formFields: {\n      typeLabel: 'Type de bâtiment',\n      typeOptions: ['Usine de production', 'Agroalimentaire', 'Chimie / plasturgie', 'Hangar / entrepôt technique', 'Métallurgie', 'Autre'],\n      climateLabel: 'Type de toiture',\n      climateOptions: ['Membrane bitumineuse', 'Bac acier', 'EPDM / PVC', 'Fibrociment', 'À confirmer'],\n      yearLabel: 'Année du bâtiment',\n      microcopy: 'Étude technique offerte · Sans engagement',\n      cta: 'Demander un devis',\n    },\n  },\n  logos: {\n    title: 'Des sites industriels nous font confiance',\n    items: [\n      { name: 'Continental' },\n      { name: 'Thales' },\n      { name: 'Nestlé' },\n      { name: 'Servier' },\n      { name: 'Somfy' },\n    ],\n  },\n  problem: {\n    eyebrow: 'Pourquoi agir',\n    title: 'La chaleur pénalise',\n    mutedTitle: 'directement vos bâtiments industriels.',\n    intro:\n      \"Sous une toiture exposée, la chaleur s'accumule, dégrade le confort de travail, sollicite les équipements et accélère le vieillissement de l'étanchéité.\",\n    transition: 'La cause commune : une toiture sombre qui absorbe la chaleur au lieu de la renvoyer.',\n    cards: [\n      {\n        icon: Thermometer,\n        title: 'Confort de travail dégradé',\n        desc: \"En atelier, les températures deviennent difficiles à supporter lors des pics de chaleur, avec un impact direct sur la productivité.\",\n        image: img('problem-chaleur-atelier'),\n        alt: 'Atelier industriel surchauffé en été',\n      },\n      {\n        icon: Zap,\n        title: 'Énergie en hausse',\n        desc: 'Climatisation, ventilation et froid de process grimpent quand la toiture chauffe à 70-80°C.',\n        image: img('problem-energie-toiture'),\n        alt: 'Groupes de climatisation sur une toiture industrielle sombre',\n      },\n      {\n        icon: Wrench,\n        title: 'Équipements sur-sollicités',\n        desc: 'Groupes froids, CTA et installations techniques tournent en surrégime et s’usent plus vite.',\n        image: img('problem-equipements'),\n        alt: 'Installation de froid de process industriel',\n      },\n      {\n        icon: ShieldCheck,\n        title: 'Étanchéité fragilisée',\n        desc: \"Une toiture soumise aux UV et aux écarts thermiques vieillit plus vite : le remplacement approche.\",\n        image: img('problem-etancheite'),\n        alt: 'Étanchéité de toiture industrielle vieillissante',\n      },\n    ],\n  },\n  solution: {\n    eyebrow: 'La solution Covalba',\n    title: 'Votre toiture réfléchit',\n    mutedTitle: 'au lieu de chauffer.',\n    intro:\n      \"Une toiture sombre absorbe le rayonnement et dépasse 70-80°C en surface. Le revêtement cool roof Covalba renvoie jusqu'à 90 % du rayonnement solaire : la toiture chauffe moins et transmet moins de chaleur au bâtiment.\",\n    points: [\n      'Solution passive, sans consommation d’énergie',\n      'Posée depuis l’extérieur, sans arrêt de production',\n      'Compatible bitume, bac acier, membrane, fibrociment',\n      'Systèmes durables, 8 à 20 ans de tenue',\n    ],\n    transition: \"Reste la vraie question : combien coûte un revêtement s'il faut le refaire au bout de 2 à 5 ans ?\",\n  },\n  durability: {\n    title: 'Le système Covalba',\n    mutedTitle: 'tient plus longtemps sur vos toitures.',\n    intro:\n      \"Sur une toiture de plusieurs milliers de m², le prix au m² ne suffit pas : il faut compter la durée de vie, la réflectivité conservée et le risque de repasser trop tôt.\",\n    note:\n      'Les systèmes polyuréthane avec vernis de finition anti-UV sont conçus pour conserver leur performance 8 à 20 ans tout en protégeant la couverture.',\n    covalbaLabel: 'Performance pensée dans la durée',\n  },\n  special: {\n    kind: 'funding',\n    eyebrow: 'Aides & financement',\n    title: 'Des leviers peuvent financer une partie de vos travaux.',\n    intro:\n      \"Les bâtiments industriels ne relèvent pas de la prime CEE BAT-EN-112 (réservée au tertiaire commercial), mais d'autres dispositifs existent selon votre activité.\",\n    points: [\n      { value: 'Régions', label: 'aides à la rénovation et à la décarbonation selon votre région' },\n      { value: 'ADEME', label: 'dispositifs liés à l’efficacité énergétique industrielle' },\n      { value: '20-25 €/m²', label: 'contre 80 à 150 €/m² pour refaire l’étanchéité' },\n      { value: 'ROI < 2 ans', label: 'sur les sites climatisés ou en froid de process' },\n    ],\n    note:\n      \"Les leviers mobilisables dépendent de votre activité, de votre classification ICPE et de votre région. Covalba vous aide à les identifier avant devis.\",\n    cta: 'Étudier mon financement',\n  },\n  benefits: {\n    eyebrow: 'Ce que vous y gagnez',\n    title: 'Moins de chaleur, plus de performance.',\n    desc: \"Le cool roof agit sur la source de chaleur principale : la toiture. Les bénéfices se voient dès le premier été sur l'ambiance du bâtiment.\",\n    metric: '-7 à -10°C',\n    metricLabel: 'sous votre toiture',\n    image: img('benefits-atelier-frais'),\n    imageAlt: 'Atelier industriel moderne plus frais grâce au cool roof',\n    transition: 'Au-delà du confort, voici comment le cool roof s’adapte à chaque type de site.',\n    cards: [","numLines":150,"startLine":1,"totalLines":253}},"sourceToolAssistantUUID":"362cd58d-27da-4d2e-bec2-21e32e8b6cc8","userType":"external","entrypoint":"cli","cwd":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale","sessionId":"c02b163b-170b-4cd3-a555-3613df5965a3","version":"2.1.193","gitBranch":"tom/validation-finale","slug":"plusieurs-chose-faire-crispy-axolotl"}
{"parentUuid":"900d3816-9641-4e90-8978-463819a4e69c","isSidechain":true,"agentId":"a9fd20a9d1d03f0e9","message":{"model":"claude-haiku-4-5-20251001","id":"msg_015muiZmvLZfUyNVs5o6EPhi","type":"message","role":"assistant","content":[{"type":"tool_use","id":"toolu_01A7Wji829VF89umP6C28Yam","name":"Bash","input":{"command":"find /opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/src/components -type f -name \"*.tsx\" | grep -v \"en/\\|es/\" | head -30"},"caller":{"type":"direct"}}],"stop_reason":"tool_use","stop_sequence":null,"stop_details":null,"usage":{"input_tokens":8,"cache_creation_input_tokens":4104,"cache_read_input_tokens":90464,"output_tokens":303,"server_tool_use":{"web_search_requests":0,"web_fetch_requests":0},"service_tier":"standard","cache_creation":{"ephemeral_1h_input_tokens":0,"ephemeral_5m_input_tokens":4104},"inference_geo":"not_available","iterations":[{"input_tokens":8,"output_tokens":303,"cache_read_input_tokens":90464,"cache_creation_input_tokens":4104,"cache_creation":{"ephemeral_5m_input_tokens":4104,"ephemeral_1h_input_tokens":0},"type":"message"}],"speed":"standard"},"diagnostics":null},"requestId":"req_011CcRpsy5c5UF8SKdThMQSp","attributionAgent":"Explore","type":"assistant","uuid":"ed65923f-ee6b-442d-93d6-8f9760ffdd2e","timestamp":"2026-06-26T11:54:13.113Z","userType":"external","entrypoint":"cli","cwd":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale","sessionId":"c02b163b-170b-4cd3-a555-3613df5965a3","version":"2.1.193","gitBranch":"tom/validation-finale","slug":"plusieurs-chose-faire-crispy-axolotl"}
{"parentUuid":"ed65923f-ee6b-442d-93d6-8f9760ffdd2e","isSidechain":true,"promptId":"606b4c79-d3cd-4b0a-a2e5-8b38011359cb","agentId":"a9fd20a9d1d03f0e9","type":"user","message":{"role":"user","content":[{"tool_use_id":"toolu_01A7Wji829VF89umP6C28Yam","type":"tool_result","content":"(Bash completed with no output)","is_error":false}]},"uuid":"ff3e99de-0fc0-42c6-9348-2c4f01e8b2df","timestamp":"2026-06-26T11:54:13.185Z","toolUseResult":{"stdout":"","stderr":"","interrupted":false,"isImage":false,"noOutputExpected":false},"sourceToolAssistantUUID":"ed65923f-ee6b-442d-93d6-8f9760ffdd2e","userType":"external","entrypoint":"cli","cwd":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale","sessionId":"c02b163b-170b-4cd3-a555-3613df5965a3","version":"2.1.193","gitBranch":"tom/validation-finale","slug":"plusieurs-chose-faire-crispy-axolotl"}
{"parentUuid":"ff3e99de-0fc0-42c6-9348-2c4f01e8b2df","isSidechain":true,"agentId":"a9fd20a9d1d03f0e9","message":{"model":"claude-haiku-4-5-20251001","id":"msg_015aAga19KJCYD94rXrQu6rX","type":"message","role":"assistant","content":[{"type":"thinking","thinking":"","signature":"ErQDCm0IDxgCKkABmeR2rXQ/UnVnZ1tNhaYP6a86E3fkKr97Y9w9LT9icRHioJvNPsyC8rxfvKV7wCFptliGPCN98jgr6xC9k+1PMhljbGF1ZGUtaGFpa3UtNC01LTIwMjUxMDAxOABCCHRoaW5raW5nEgwj0eTRxA6eiTDRlywaDIVK0j66fqbEq0vCgCIwgLHPcd7sYvoRMs7HWzZIfntyro5LwJXh96Y9tOTAO2MEKwk6hadcjfvqRB069KMnKvQB2IOESJwEpmUb9EGEnEoVVT9gxlmnPEQvRJdupzzwWSGyWcPUl5IDHs6SfgHifNiPlOCKB8YRKk917KAO/BhVpEXL2YJ35l4XbY7CIgZ8P1ECuFA82sMRJUDe0jcNy3jwreOU5f411jMKPN+REzNaaKOo1kbem5+8xOmIr+Mqwg6pqiuePQlDygNNAEZTCLsW1RlHNh2BaV729F0vJFHJBjLBx51R+3RdCqA3OfOLzK+46yHx/tE38rjG/Ej26m57Pu0UZAO7FdHN5i7sS33DQcB5rh+IWwYhC3ZBgK+emDUA+bfT5mWgh4kCDHkKnh1fa/hgPxgB"}],"stop_reason":null,"stop_sequence":null,"stop_details":null,"usage":{"input_tokens":8,"cache_creation_input_tokens":3172,"cache_read_input_tokens":94568,"cache_creation":{"ephemeral_5m_input_tokens":3172,"ephemeral_1h_input_tokens":0},"output_tokens":1,"service_tier":"standard","inference_geo":"not_available"},"diagnostics":null},"requestId":"req_011CcRptD3FDCsmQoRzHqbhG","attributionAgent":"Explore","type":"assistant","uuid":"7d8b8010-b477-455e-baad-9bf1b49b8b4d","timestamp":"2026-06-26T11:54:15.064Z","userType":"external","entrypoint":"cli","cwd":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale","sessionId":"c02b163b-170b-4cd3-a555-3613df5965a3","version":"2.1.193","gitBranch":"tom/validation-finale","slug":"plusieurs-chose-faire-crispy-axolotl"}
{"parentUuid":"7d8b8010-b477-455e-baad-9bf1b49b8b4d","isSidechain":true,"agentId":"a9fd20a9d1d03f0e9","message":{"model":"claude-haiku-4-5-20251001","id":"msg_015aAga19KJCYD94rXrQu6rX","type":"message","role":"assistant","content":[{"type":"tool_use","id":"toolu_01Sznupkfzrrgtsnzt2fh65P","name":"Read","input":{"file_path":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/src/components/ScrollReveal.tsx"},"caller":{"type":"direct"}}],"stop_reason":null,"stop_sequence":null,"stop_details":null,"usage":{"input_tokens":8,"cache_creation_input_tokens":3172,"cache_read_input_tokens":94568,"cache_creation":{"ephemeral_5m_input_tokens":3172,"ephemeral_1h_input_tokens":0},"output_tokens":1,"service_tier":"standard","inference_geo":"not_available"},"diagnostics":null},"requestId":"req_011CcRptD3FDCsmQoRzHqbhG","attributionAgent":"Explore","type":"assistant","uuid":"a702535b-e3ab-4ff6-8f1d-f1e7b57886eb","timestamp":"2026-06-26T11:54:15.698Z","userType":"external","entrypoint":"cli","cwd":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale","sessionId":"c02b163b-170b-4cd3-a555-3613df5965a3","version":"2.1.193","gitBranch":"tom/validation-finale","slug":"plusieurs-chose-faire-crispy-axolotl"}
{"parentUuid":"a702535b-e3ab-4ff6-8f1d-f1e7b57886eb","isSidechain":true,"promptId":"606b4c79-d3cd-4b0a-a2e5-8b38011359cb","agentId":"a9fd20a9d1d03f0e9","type":"user","message":{"role":"user","content":[{"tool_use_id":"toolu_01Sznupkfzrrgtsnzt2fh65P","type":"tool_result","content":"1\t\"use client\";\n2\t\n3\timport { useInView } from '@/hooks/useInView';\n4\timport { ReactNode } from 'react';\n5\t\n6\tinterface ScrollRevealProps {\n7\t  children: ReactNode;\n8\t  className?: string;\n9\t  stagger?: boolean;\n10\t}\n11\t\n12\tconst ScrollReveal = ({ children, className = '', stagger = false }: ScrollRevealProps) => {\n13\t  const { ref, inView } = useInView({ threshold: 0.15 });\n14\t\n15\t  return (\n16\t    <div\n17\t      ref={ref}\n18\t      className={`${stagger ? 'stagger-children' : 'section-reveal'} ${inView ? 'in-view' : ''} ${className}`}\n19\t    >\n20\t      {children}\n21\t    </div>\n22\t  );\n23\t};\n24\t\n25\texport default ScrollReveal;\n26\t"}]},"uuid":"ad08bc2c-7051-4989-9db9-cb63a2e45166","timestamp":"2026-06-26T11:54:15.719Z","toolUseResult":{"type":"text","file":{"filePath":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/src/components/ScrollReveal.tsx","content":"\"use client\";\n\nimport { useInView } from '@/hooks/useInView';\nimport { ReactNode } from 'react';\n\ninterface ScrollRevealProps {\n  children: ReactNode;\n  className?: string;\n  stagger?: boolean;\n}\n\nconst ScrollReveal = ({ children, className = '', stagger = false }: ScrollRevealProps) => {\n  const { ref, inView } = useInView({ threshold: 0.15 });\n\n  return (\n    <div\n      ref={ref}\n      className={`${stagger ? 'stagger-children' : 'section-reveal'} ${inView ? 'in-view' : ''} ${className}`}\n    >\n      {children}\n    </div>\n  );\n};\n\nexport default ScrollReveal;\n","numLines":26,"startLine":1,"totalLines":26}},"sourceToolAssistantUUID":"a702535b-e3ab-4ff6-8f1d-f1e7b57886eb","userType":"external","entrypoint":"cli","cwd":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale","sessionId":"c02b163b-170b-4cd3-a555-3613df5965a3","version":"2.1.193","gitBranch":"tom/validation-finale","slug":"plusieurs-chose-faire-crispy-axolotl"}
{"parentUuid":"ad08bc2c-7051-4989-9db9-cb63a2e45166","isSidechain":true,"agentId":"a9fd20a9d1d03f0e9","message":{"model":"claude-haiku-4-5-20251001","id":"msg_015aAga19KJCYD94rXrQu6rX","type":"message","role":"assistant","content":[{"type":"tool_use","id":"toolu_015k57FkT5hzBFwyGR3gCt3a","name":"Bash","input":{"command":"find /opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/src/data -type f -name \"*.ts\" | head -10"},"caller":{"type":"direct"}}],"stop_reason":null,"stop_sequence":null,"stop_details":null,"usage":{"input_tokens":8,"cache_creation_input_tokens":3172,"cache_read_input_tokens":94568,"cache_creation":{"ephemeral_5m_input_tokens":3172,"ephemeral_1h_input_tokens":0},"output_tokens":1,"service_tier":"standard","inference_geo":"not_available"},"diagnostics":null},"requestId":"req_011CcRptD3FDCsmQoRzHqbhG","attributionAgent":"Explore","type":"assistant","uuid":"65b14fef-2e6c-4d02-96e1-aae28b5d6fc5","timestamp":"2026-06-26T11:54:16.182Z","userType":"external","entrypoint":"cli","cwd":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale","sessionId":"c02b163b-170b-4cd3-a555-3613df5965a3","version":"2.1.193","gitBranch":"tom/validation-finale","slug":"plusieurs-chose-faire-crispy-axolotl"}
{"parentUuid":"65b14fef-2e6c-4d02-96e1-aae28b5d6fc5","isSidechain":true,"promptId":"606b4c79-d3cd-4b0a-a2e5-8b38011359cb","agentId":"a9fd20a9d1d03f0e9","type":"user","message":{"role":"user","content":[{"tool_use_id":"toolu_015k57FkT5hzBFwyGR3gCt3a","type":"tool_result","content":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/src/data/references.ts\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/src/data/roofPages.ts\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/src/data/globalConfig.ts\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/src/data/mediaAssetReview.ts\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/src/data/zones.ts\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/src/data/sectorSeo.ts\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/src/data/climateProjections.ts\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/src/data/productFaqs.ts","is_error":false}]},"uuid":"15fab793-ddac-41f8-b26a-e1bd7198926e","timestamp":"2026-06-26T11:54:16.243Z","toolUseResult":{"stdout":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/src/data/references.ts\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/src/data/roofPages.ts\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/src/data/globalConfig.ts\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/src/data/mediaAssetReview.ts\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/src/data/zones.ts\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/src/data/sectorSeo.ts\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/src/data/climateProjections.ts\n/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/src/data/productFaqs.ts","stderr":"","interrupted":false,"isImage":false,"noOutputExpected":false},"sourceToolAssistantUUID":"65b14fef-2e6c-4d02-96e1-aae28b5d6fc5","userType":"external","entrypoint":"cli","cwd":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale","sessionId":"c02b163b-170b-4cd3-a555-3613df5965a3","version":"2.1.193","gitBranch":"tom/validation-finale","slug":"plusieurs-chose-faire-crispy-axolotl"}
{"parentUuid":"15fab793-ddac-41f8-b26a-e1bd7198926e","isSidechain":true,"agentId":"a9fd20a9d1d03f0e9","message":{"model":"claude-haiku-4-5-20251001","id":"msg_015aAga19KJCYD94rXrQu6rX","type":"message","role":"assistant","content":[{"type":"tool_use","id":"toolu_014Qp6pXipCbXJcj5JPTe4Q4","name":"Read","input":{"file_path":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/src/data/sectorSeo.ts","limit":80},"caller":{"type":"direct"}}],"stop_reason":null,"stop_sequence":null,"stop_details":null,"usage":{"input_tokens":8,"cache_creation_input_tokens":3172,"cache_read_input_tokens":94568,"cache_creation":{"ephemeral_5m_input_tokens":3172,"ephemeral_1h_input_tokens":0},"output_tokens":1,"service_tier":"standard","inference_geo":"not_available"},"diagnostics":null},"requestId":"req_011CcRptD3FDCsmQoRzHqbhG","attributionAgent":"Explore","type":"assistant","uuid":"b3e3d20e-93a4-4e12-8c10-1f6a9913c006","timestamp":"2026-06-26T11:54:16.405Z","userType":"external","entrypoint":"cli","cwd":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale","sessionId":"c02b163b-170b-4cd3-a555-3613df5965a3","version":"2.1.193","gitBranch":"tom/validation-finale","slug":"plusieurs-chose-faire-crispy-axolotl"}
{"parentUuid":"b3e3d20e-93a4-4e12-8c10-1f6a9913c006","isSidechain":true,"promptId":"606b4c79-d3cd-4b0a-a2e5-8b38011359cb","agentId":"a9fd20a9d1d03f0e9","type":"user","message":{"role":"user","content":[{"tool_use_id":"toolu_014Qp6pXipCbXJcj5JPTe4Q4","type":"tool_result","content":"1\t/**\n2\t * SEO des pages secteurs (template SectorPageTemplate) — données pures, partagées entre :\n3\t *   - les vues client (src/pages/industries/*) qui les spreadent dans leur config,\n4\t *   - les Server Components (app/industries/<slug>/page.tsx) pour metadata + JSON-LD.\n5\t */\n6\timport { SITE_URL } from '@/lib/seo';\n7\t\n8\texport interface SectorSeoConfig {\n9\t  slug: string;\n10\t  title: string;\n11\t  description: string;\n12\t  canonicalPath: string;\n13\t  serviceName: string;\n14\t  serviceDescription: string;\n15\t  audience: string;\n16\t}\n17\t\n18\texport const tertiaireSeo: SectorSeoConfig = {\n19\t  slug: 'tertiaire',\n20\t  title: 'Cool roof bureaux et tertiaire : -10°C, décret tertiaire | Covalba',\n21\t  description:\n22\t    \"Cool roof pour bureaux et bâtiments tertiaires : jusqu'à -10°C sous toiture et -20% de climatisation. Confort des équipes et levier décret tertiaire, sans gros travaux.\",\n23\t  canonicalPath: '/tertiaire',\n24\t  serviceName: 'Cool roof bureaux et bâtiment tertiaire',\n25\t  serviceDescription:\n26\t    'Solution cool roof pour bureaux, sièges sociaux, open spaces et bâtiments tertiaires existants : confort collaborateurs, climatisation soulagée et trajectoire décret tertiaire.',\n27\t  audience:\n28\t    'Directeurs immobiliers, facility managers, responsables services généraux, responsables RSE et QVT',\n29\t};\n30\t\n31\texport const collectivitesSeo: SectorSeoConfig = {\n32\t  slug: 'collectivites',\n33\t  title: 'Cool roof collectivité : -10°C, éligible Fonds Vert | Covalba',\n34\t  description:\n35\t    \"Cool roof pour écoles, gymnases et bâtiments publics : jusqu'à -10°C sous toiture, sans climatisation. Protégez vos usagers de la chaleur, éligible au Fonds Vert.\",\n36\t  canonicalPath: '/collectivité',\n37\t  serviceName: 'Cool roof collectivité et bâtiment public',\n38\t  serviceDescription:\n39\t    'Solution cool roof pour écoles, gymnases, EHPAD, mairies et bâtiments publics : confort d’été, Fonds Vert et intervention depuis l’extérieur.',\n40\t  audience:\n41\t    'Responsables services techniques, directeurs du patrimoine bâti, économes de flux et élus locaux',\n42\t};\n43\t\n44\texport const agricoleSeo: SectorSeoConfig = {\n45\t  slug: 'agricole',\n46\t  title: 'Cool roof bâtiment agricole : -10°C, bien-être animal',\n47\t  description:\n48\t    'Cool roof pour bâtiments agricoles et d’élevage : -8 à -10°C sous toiture, production et bien-être animal préservés. Compatible bac acier et fibrociment, éligible PCAE.',\n49\t  canonicalPath: '/industries/agricole',\n50\t  serviceName: 'Cool roof bâtiment agricole',\n51\t  serviceDescription:\n52\t    'Solution cool roof pour bâtiments agricoles, élevages, stabulations, hangars et stockages : confort animal, production préservée et éligibilité PCAE étudiée.',\n53\t  audience: 'Éleveurs, exploitants agricoles, responsables d’exploitation et coopératives',\n54\t};\n55\t\n56\texport const erpSeo: SectorSeoConfig = {\n57\t  slug: 'erp',\n58\t  title: 'Cool roof ERP : -10°C pour accueillir votre public au frais',\n59\t  description:\n60\t    'Cool roof pour établissements recevant du public : -8 à -10°C sous toiture, public au frais et climatisation soulagée, sans fermer. Hôtels, restaurants, salles, loisirs.',\n61\t  canonicalPath: '/industries/erp',\n62\t  serviceName: 'Cool roof ERP',\n63\t  serviceDescription:\n64\t    'Solution cool roof pour établissements recevant du public privés : hôtels, restaurants, salles de réception, cinémas, salles de sport, loisirs et lieux de culte.',\n65\t  audience: 'Exploitants, directeurs d’établissement, responsables patrimoine et techniques de groupes privés',\n66\t};\n67\t\n68\texport const industrieSeo: SectorSeoConfig = {\n69\t  slug: 'industrie',\n70\t  title: 'Cool roof pour bâtiments industriels : -8°C, coûts maîtrisés | Covalba',\n71\t  description:\n72\t    \"Cool roof pour bâtiments industriels : jusqu'à -8°C sous toiture, climatisation soulagée et étanchéité prolongée de 8 à 20 ans. Chantier sécurisé, sans arrêt de production.\",\n73\t  canonicalPath: '/industrie',\n74\t  serviceName: 'Cool roof bâtiment industriel',\n75\t  serviceDescription:\n76\t    \"Solution cool roof pour usines, sites de production, agroalimentaire et bâtiments industriels existants : confort de travail, climatisation soulagée et étanchéité prolongée.\",\n77\t  audience:\n78\t    \"Responsables maintenance, directeurs de site, responsables travaux et services généraux industriels\",\n79\t};\n80\t"}]},"uuid":"376a2fbc-1f96-4968-a94e-45414054158b","timestamp":"2026-06-26T11:54:16.429Z","toolUseResult":{"type":"text","file":{"filePath":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/src/data/sectorSeo.ts","content":"/**\n * SEO des pages secteurs (template SectorPageTemplate) — données pures, partagées entre :\n *   - les vues client (src/pages/industries/*) qui les spreadent dans leur config,\n *   - les Server Components (app/industries/<slug>/page.tsx) pour metadata + JSON-LD.\n */\nimport { SITE_URL } from '@/lib/seo';\n\nexport interface SectorSeoConfig {\n  slug: string;\n  title: string;\n  description: string;\n  canonicalPath: string;\n  serviceName: string;\n  serviceDescription: string;\n  audience: string;\n}\n\nexport const tertiaireSeo: SectorSeoConfig = {\n  slug: 'tertiaire',\n  title: 'Cool roof bureaux et tertiaire : -10°C, décret tertiaire | Covalba',\n  description:\n    \"Cool roof pour bureaux et bâtiments tertiaires : jusqu'à -10°C sous toiture et -20% de climatisation. Confort des équipes et levier décret tertiaire, sans gros travaux.\",\n  canonicalPath: '/tertiaire',\n  serviceName: 'Cool roof bureaux et bâtiment tertiaire',\n  serviceDescription:\n    'Solution cool roof pour bureaux, sièges sociaux, open spaces et bâtiments tertiaires existants : confort collaborateurs, climatisation soulagée et trajectoire décret tertiaire.',\n  audience:\n    'Directeurs immobiliers, facility managers, responsables services généraux, responsables RSE et QVT',\n};\n\nexport const collectivitesSeo: SectorSeoConfig = {\n  slug: 'collectivites',\n  title: 'Cool roof collectivité : -10°C, éligible Fonds Vert | Covalba',\n  description:\n    \"Cool roof pour écoles, gymnases et bâtiments publics : jusqu'à -10°C sous toiture, sans climatisation. Protégez vos usagers de la chaleur, éligible au Fonds Vert.\",\n  canonicalPath: '/collectivité',\n  serviceName: 'Cool roof collectivité et bâtiment public',\n  serviceDescription:\n    'Solution cool roof pour écoles, gymnases, EHPAD, mairies et bâtiments publics : confort d’été, Fonds Vert et intervention depuis l’extérieur.',\n  audience:\n    'Responsables services techniques, directeurs du patrimoine bâti, économes de flux et élus locaux',\n};\n\nexport const agricoleSeo: SectorSeoConfig = {\n  slug: 'agricole',\n  title: 'Cool roof bâtiment agricole : -10°C, bien-être animal',\n  description:\n    'Cool roof pour bâtiments agricoles et d’élevage : -8 à -10°C sous toiture, production et bien-être animal préservés. Compatible bac acier et fibrociment, éligible PCAE.',\n  canonicalPath: '/industries/agricole',\n  serviceName: 'Cool roof bâtiment agricole',\n  serviceDescription:\n    'Solution cool roof pour bâtiments agricoles, élevages, stabulations, hangars et stockages : confort animal, production préservée et éligibilité PCAE étudiée.',\n  audience: 'Éleveurs, exploitants agricoles, responsables d’exploitation et coopératives',\n};\n\nexport const erpSeo: SectorSeoConfig = {\n  slug: 'erp',\n  title: 'Cool roof ERP : -10°C pour accueillir votre public au frais',\n  description:\n    'Cool roof pour établissements recevant du public : -8 à -10°C sous toiture, public au frais et climatisation soulagée, sans fermer. Hôtels, restaurants, salles, loisirs.',\n  canonicalPath: '/industries/erp',\n  serviceName: 'Cool roof ERP',\n  serviceDescription:\n    'Solution cool roof pour établissements recevant du public privés : hôtels, restaurants, salles de réception, cinémas, salles de sport, loisirs et lieux de culte.',\n  audience: 'Exploitants, directeurs d’établissement, responsables patrimoine et techniques de groupes privés',\n};\n\nexport const industrieSeo: SectorSeoConfig = {\n  slug: 'industrie',\n  title: 'Cool roof pour bâtiments industriels : -8°C, coûts maîtrisés | Covalba',\n  description:\n    \"Cool roof pour bâtiments industriels : jusqu'à -8°C sous toiture, climatisation soulagée et étanchéité prolongée de 8 à 20 ans. Chantier sécurisé, sans arrêt de production.\",\n  canonicalPath: '/industrie',\n  serviceName: 'Cool roof bâtiment industriel',\n  serviceDescription:\n    \"Solution cool roof pour usines, sites de production, agroalimentaire et bâtiments industriels existants : confort de travail, climatisation soulagée et étanchéité prolongée.\",\n  audience:\n    \"Responsables maintenance, directeurs de site, responsables travaux et services généraux industriels\",\n};\n","numLines":80,"startLine":1,"totalLines":135}},"sourceToolAssistantUUID":"b3e3d20e-93a4-4e12-8c10-1f6a9913c006","userType":"external","entrypoint":"cli","cwd":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale","sessionId":"c02b163b-170b-4cd3-a555-3613df5965a3","version":"2.1.193","gitBranch":"tom/validation-finale","slug":"plusieurs-chose-faire-crispy-axolotl"}
{"parentUuid":"376a2fbc-1f96-4968-a94e-45414054158b","isSidechain":true,"agentId":"a9fd20a9d1d03f0e9","message":{"model":"claude-haiku-4-5-20251001","id":"msg_015gv5G3zu3MZnnBRrn3PnWf","type":"message","role":"assistant","content":[{"type":"thinking","thinking":"","signature":"EoMECm0IDxgCKkAwzRFWmCGzI7CryQ7xyFtHVoxy9iABeg5tYTMqpU6y2J1V7SPvJ4Kv3sBDi30jPTCW35sR5MXhdNEeifAxRmRuMhljbGF1ZGUtaGFpa3UtNC01LTIwMjUxMDAxOABCCHRoaW5raW5nEgzoqunzvVw9LWE/BsQaDI8zTOJV7vRXvR9iFSIw+jrRrNw6YXNqYnTS3XhvEo+bqsBC7u6U8psM0iI2ZJDtlwqKHPsIRUWLjjCttPX6KsMCgLyqtja107NZv0//S2RrvplT6c+TC3/4IKrYeUHU4Sx3vHOaPFrC12bQ2gHnAHP8YcDhPBaTpLpCDVY9/fS4CpXi0j+7OZQVOFJimb3mkUJhrNbihAADY7Dbtfr4J5r4xpa9PTb3IdfRVccIzlulR1E31HjaBO7A/fiTh76PrPM/POcEipl3G5sU9mE4Ny6tCV3NfhJel2buBpI2BQDX24wIbHHFC38zQfXOoeMZ9HwtLDs9uixF/Dw55mWTZ66cfOD3TrmSNS5XjvPKd2Boa3ryh1/ImdWG0G0+svBsn+k0nRhh2j9fak5FhslUN9cV3cAdTLuV4sow8Qf1NqUPMrp3txA6D1wnoLflauGywH1UzlhIJ4JJF676F4zGCM5wOX3ozToVGY6nvmCiYGfFPvKRdyKBk1Rwq5xtlUw73Z+e0YcYAQ=="}],"stop_reason":null,"stop_sequence":null,"stop_details":null,"usage":{"input_tokens":8,"cache_creation_input_tokens":2374,"cache_read_input_tokens":97740,"cache_creation":{"ephemeral_5m_input_tokens":2374,"ephemeral_1h_input_tokens":0},"output_tokens":1,"service_tier":"standard","inference_geo":"not_available"},"diagnostics":null},"requestId":"req_011CcRptTB3r1xd4dBVJ7uFo","attributionAgent":"Explore","type":"assistant","uuid":"4beff20b-5302-4ac3-940b-27d1bc520b4a","timestamp":"2026-06-26T11:54:18.381Z","userType":"external","entrypoint":"cli","cwd":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale","sessionId":"c02b163b-170b-4cd3-a555-3613df5965a3","version":"2.1.193","gitBranch":"tom/validation-finale","slug":"plusieurs-chose-faire-crispy-axolotl"}
{"parentUuid":"4beff20b-5302-4ac3-940b-27d1bc520b4a","isSidechain":true,"agentId":"a9fd20a9d1d03f0e9","message":{"model":"claude-haiku-4-5-20251001","id":"msg_015gv5G3zu3MZnnBRrn3PnWf","type":"message","role":"assistant","content":[{"type":"text","text":"Now I have comprehensive knowledge of both the live page and the repo's design system. Let me compile the report:\n\n---\n\n## A. LIVE PAGE STRUCTURE (covalba.fr/nos-solutions-cool-roof)\n\nThe WebFetch successfully captured the full section-by-section structure. Here's what the live page contains:\n\n### Sections (top to bottom):\n\n1. **Navigation Header** — Logo, menu, language selector, CTAs\n2. **Hero** — \"Décarbonnez votre activité grâce au cool roof\" + diagrams\n3. **Benefits Grid** — 6 cards covering energy savings, storage, workplace, preservation, customer experience, environmental impact\n4. **Services Section** — \"Les services Covalba\": \n   - Votre chantier (3-step process)\n   - Maintenance (annual cleaning)\n   - Monitoring (pre/post measurement)\n5. **Product Showcase** — 4 product cards (CovaTherm 8/20, CovaSeal 20, CovaMetal 20, Laque solaire)\n6. **Client Testimonials** — 3 customer quotes with temperature/cost improvements\n7. **Case Study** — Albright project (\"13°C en moins\")\n8. **Sectoral Solutions** — 5 industry cards (Industrie, Distribution, Logistique, Public Services, Tertiary)\n9. **Downloadable Resource** — Whitepaper CTA\n10. **Featured Product Spotlight** — CovaTherm promotional section\n11. **Footer**\n\n---\n\n## B. REPO DESIGN SYSTEM & REUSABLE COMPONENTS\n\n### 1. **Core Design Tokens (CSS Variables)**\n\n**File:** `/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/src/index.css`\n\n**Color Palette:**\n- `--navy: 215 52% 12%` (primary dark background)\n- `--teal-vivid: 180 52% 45%` (highlight accent on navy)\n- `--teal: 179 61% 26%` (primary teal)\n- `--teal-light: 180 33% 93%` (light teal background)\n- `--terracotta: 10 55% 49%` (warm accent for problems/issues)\n- `--terracotta-dark: 10 58% 41%`\n- `--cream: 60 20% 97%` (off-white, light sections)\n- `--foreground: 215 52% 12%` (text on light)\n- `--primary: 179 61% 26%` (teal, used for CTAs)\n\n**Typography:**\n- `font-satoshi` — Headings, bold statements (clamp sizes: 2.25rem to 7rem)\n- `font-body` — Regular text, smaller copy\n\n**Tailwind config:** `/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/tailwind.config.ts`\n\n---\n\n### 2. **Page Template Architecture: SectorPageTemplate**\n\n**Core file:** `/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/src/components/industries/SectorPageTemplate.tsx` (1,350 lines)\n\nThis is the **polished \"new DA\"** template. It's composed of ~13 exportable section components:\n\n| Component | Purpose | Key Props |\n|-----------|---------|-----------|\n| **SectorHero** | Navy hero with gradient overlay, left content + right form | `config.hero` (eyebrow, h1, sub, image, stats, form fields) |\n| **ReassuranceBand** | Horizontal strip with checkmark items | `config.reassurance[]` |\n| **ProblemSection** | Cream background, problem title + 4 card grid with images, left side visual | `config.problem` (eyebrow, title, mutedTitle, cards with icon+image+desc) |\n| **SolutionSection** | Dark (#142333) background, before/after comparison cards, solution points | `config.solution` (eyebrow, title, intro, points, images) |\n| **DurabilitySection** | Cream background, comparison table (Covalba vs competitors), pricing+durability metrics | `config.durability` (title, intro, note) |\n| **SpecialSection** | White, 2-column: form + milestones/points grid (décret/funding) | `config.special` (eyebrow, title, intro, form + milestones/points) |\n| **BenefitsSection** | Cream + white two-part: metric showcase (left image fade) + 5 benefits grid | `config.benefits` (eyebrow, title, metric, image, 5 cards) |\n| **ApplicationsSection** | Cream background, 5-column grid of application cards with images | `config.applications` (eyebrow, title, 5 cards with icon+image+desc) |\n| **MethodSection** | White, sticky left sidebar + 4-step timeline (right side) | `config.method` (eyebrow, title, 4 steps) |\n| **ProofSection** | Dark (#192A3A) navy, 3-column stat cards + reference logos grid + optional case studies | `config.proof` (eyebrow, title, figures, logos, cases) |\n| **FaqSection** | Cream background, sticky left + accordion (right) | `config.faq` (intro + FAQ items) |\n| **FinalCta** | Dark navy (#182A3A), centered CTA + reassurance pills | `config.finalCta` (title, desc, reassurances) |\n| **SeoContent** | White/cream, long-form SEO sections + sources | `config.seo` (title, intro, sections[], sources[]) |\n\n**Pattern:** Each section uses `ScrollReveal` wrapper for staggered reveal animations.\n\n---\n\n### 3. **Reusable Visual Section Components**\n\n| Component | Path | Purpose | Key Props |\n|-----------|------|---------|-----------|\n| **ScrollReveal** | `/src/components/ScrollReveal.tsx` | Scroll-triggered fade-in animation wrapper | `children`, `stagger`, `className` |\n| **WpImage** | `/src/components/ui/WpImage.tsx` | Next.js Image wrapper for WP media + fallback | `image` (sourceUrl, altText, width, height), `fill`, `priority`, `sizes`, `className` |\n| **SectorReferenceHighlights** | `/src/components/SectorReferenceHighlights.tsx` | Client testimonial/reference grid by sector filter | `sector`, `referenceFilter`, `title`, `variant` (light/dark) |\n| **MidPageForm** | `/src/components/MidPageForm.tsx` | Quick contact form (mid-page CTA) | TBD — check file |\n| **SolutionsGrid** | `/src/components/SolutionsGrid.tsx` | 4-column product card grid (CovaTherm, CovaSeal, CovaMetal, Laque) | Static product array, links to product pages |\n| **Navbar** | `/src/components/Navbar.tsx` | Header with logo, menu, i18n switcher | Global |\n| **Footer** | `/src/components/Footer.tsx` | Footer with links, copyright | Global |\n| **StickyMobileCTA** | `/src/components/StickyMobileCTA.tsx` | Sticky mobile action button | Global |\n| **Badge** | `/src/components/ui/badge.tsx` | Small label pill (teal-light background) | `children`, `className` |\n| **Accordion** | `/src/components/ui/accordion.tsx` | Radix accordion for FAQ | `type`, `collapsible` |\n| **Dialog** | `/src/components/ui/dialog.tsx` | Modal for video embeds | `open`, `onOpenChange` |\n\n---\n\n### 4. **RoofPageTemplate (Roof-Specific Pages)**\n\n**File:** `/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale/src/components/roof/RoofPageTemplate.tsx` (1,434 lines)\n\nTailored for individual roof support pages (membrane-bitumineuse, bac-acier, toiture-plate, fibrociment, tuiles-ciment). Similar structure to SectorPageTemplate but with:\n- **Interactive layer diagram** (cool roof cross-section with 3 layers, tap to reveal descriptions)\n- **ROI Calculator** — Dynamic surface input + situation selector → cost estimates\n- **Support visuals** — Before/after images for each roof type\n- **Method section** — 4-step process with video embed\n\n**Used by:** `/app/peinture-reflective-covatherm/page.tsx` and other roof type pages\n\n---\n\n### 5. **Type Definitions**\n\n**SectorPageConfig** (what you'll need to create):\n`/src/components/industries/SectorPageTemplate.tsx:126–237` defines the full structure:\n- `slug`, `title`, `description`, `canonicalPath`\n- `hero`, `logos`, `problem`, `solution`, `durability`, `special`, `benefits`, `applications`, `method`, `proof`, `faq`, `finalCta`, `seo`\n\n**File pattern for sector data:**\n- `/src/data/sectorSeo.ts` — SEO metadata (title, description, canonical, serviceName, audience)\n- `/src/views/industries/{SectorName}.tsx` — Full `SectorPageConfig` export + icon imports from `lucide-react`\n\nExample sectors (already built):\n- `/src/views/industries/Industrie.tsx`\n- `/src/views/industries/Pharmaceutique.tsx`\n- `/src/views/industries/Aeronautique.tsx`\n- `/src/views/industries/Tertiaire.tsx`\n- `/src/views/industries/Collectivites.tsx`\n- `/src/views/industries/Agricole.tsx`\n- `/src/views/industries/ERP.tsx`\n\n---\n\n### 6. **Data + Routing Integration**\n\n**SEO data registry:** `/src/data/sectorSeo.ts:1–80`\n- Exports `industrieSeo`, `pharmaceutiqueSeo`, `aeronautiqueSeo`, `tertiaireSeo`, etc. (each a `SectorSeoConfig`)\n\n**Routing + Slug Registry:** `/app/industries/[slug]/page.tsx:23`\n```tsx\nconst SECTOR_TEMPLATE_SLUGS = [\"tertiaire\", \"collectivites\", \"agricole\", \"erp\", \"industrie\", \"pharmaceutique\", \"aeronautique\"];\n```\n\n**Wrapper client component:** `/app/industries/[slug]/sector-view-client.tsx`\n- Maps slug → `CONFIGS` dict → fallback config → passes to `toSectorConfig()` (merges WP data) → renders `SectorPageTemplate`\n\n---\n\n### 7. **WordPress → Config Mapper**\n\n**File:** `/src/lib/wp/toSectorConfig.ts` (459 lines)\n\nMaps WordPress flexible content blocks back to `SectorPageConfig` with coded fallback:\n- Matches blocks by layout suffix (e.g., `HeroLayout`, `GrilleCardsLayout`, `TexteImageLayout`)\n- Decodes HTML entities, splits accented text (`*muted*` pattern)\n- Extracts images, lists, and form fields\n- If WP data missing, falls back to coded config (ensures pixel parity)\n\n**Key block types matched:**\n- `HeroLayout`, `LogosLayout`, `GrilleCardsLayout`, `TexteImageLayout`, `TableauComparatifLayout`, `ChiffresLayout`, `EtapesLayout`, `FaqLayout`, `CtaLayout`, `ContenuSeoLayout`\n\n---\n\n### 8. **Recent Commit (72f320f) — Industry Sector Pages**\n\n**Commit:** 72f320f095bc309aa8ac717113e1c8e6c3248aed\n\nAdded **3 industry sector pages** using `SectorPageTemplate`:\n- `/industries/industrie` (Cool roof industrial buildings)\n- `/industries/pharmaceutique` (Pharma sector)\n- `/industries/aeronautique` (Aerospace sector)\n\nEach includes:\n- Coded `SectorPageConfig` in `/src/views/industries/{Name}.tsx`\n- SEO entry in `/src/data/sectorSeo.ts`\n- 33 bespoke GPT-image-2 generated images (hero + problem cards + benefits + application cards per page)\n- 9 WordPress seed JSON files (FR/EN/ES) with block structure matching the template\n\n---\n\n### 9. **Image Hosting & Asset Convention**\n\n**Public images:** `/public/images/industrie/{name}.webp` (committed, served directly)\n\n**Generated images** (from commit 72f320f):\n- `hero-batiment-industriel.webp`\n- `problem-chaleur-atelier.webp`, `problem-energie-toiture.webp`, `problem-equipements.webp`, `problem-etancheite.webp`\n- `benefits-atelier-frais.webp`\n- 5x application images (e.g., `app-usine-production.webp`)\n\n**Current pattern:** Image paths are hardcoded in config as:\n```tsx\nconst img = (name: string) => `/images/industrie/${name}.webp`;\n```\n\n---\n\n### 10. **Existing Component Inventory (Reusable Page Sections)**\n\nAll these live in `/src/components/` and can be reused:\n\n**Pre-built sections:**\n- `ApplicatorsSection.tsx` — Lists applicator firms\n- `PriceVSSection.tsx` — Price comparison table\n- `PriceComparisonSection.tsx` — Detailed comparison grid\n- `ProcessSection.tsx` — 4-step process timeline\n- `ExpertiseSection.tsx` — Expertise cards\n- `LocalSolutionSection.tsx` — Geographic/local targeting\n- `SEOContentSection.tsx` — Long-form SEO content + sources\n- `SystemSection.tsx` — Layered system explanation (like cool roof 3-layer diagram)\n\n**Global sections:**\n- `Navbar.tsx` — Header (navy with lightBg variant)\n- `Footer.tsx` — Footer with link organization\n- `StickyMobileCTA.tsx` — Mobile action button overlay\n\n---\n\n## SUMMARY: How to Build Cool Roof Solution Page\n\n### Option A: **Quick approach** — Reuse SolutionsGrid\nModify `/app/nos-solutions-cool-roof/page.tsx` to import and compose existing components:\n- Keep existing hero + SolutionsGrid\n- Add problem/benefits sections from RoofPageTemplate or sector pages\n- Link to individual product pages\n\n### Option B: **Polished approach** — Create a custom \"product-family\" config\nBuild a hybrid template (cross between `SectorPageTemplate` + `RoofPageTemplate`) that:\n1. Opens with a **sectoral hero** (choice of industry → drill-down)\n2. Shows the **4 products** as featured cards\n3. Displays **benefits** (thermal, durability, sustainability)\n4. Ends with **case studies** + **CTA**\n\nThis would reuse:\n- `/src/components/ScrollReveal.tsx`\n- `/src/components/SolutionsGrid.tsx` (or new product variant)\n- `/src/components/SectorReferenceHighlights.tsx` (for case studies)\n- Color tokens from `src/index.css`\n- Typography + spacing from Tailwind config + `font-satoshi` / `font-body`\n\n**Absolute paths to copy for component structure:**\n- Template pattern: `/src/components/industries/SectorPageTemplate.tsx:1–1350`\n- Data pattern: `/src/views/industries/Industrie.tsx` (full config example)\n- SEO pattern: `/src/data/sectorSeo.ts` (add entry for cool-roof-solutions)\n- Router integration: `/app/industries/[slug]/sector-view-client.tsx` (adapt for your route)"}],"stop_reason":"end_turn","stop_sequence":null,"stop_details":null,"usage":{"input_tokens":8,"cache_creation_input_tokens":2374,"cache_read_input_tokens":97740,"output_tokens":3970,"server_tool_use":{"web_search_requests":0,"web_fetch_requests":0},"service_tier":"standard","cache_creation":{"ephemeral_1h_input_tokens":0,"ephemeral_5m_input_tokens":2374},"inference_geo":"not_available","iterations":[{"input_tokens":8,"output_tokens":3970,"cache_read_input_tokens":97740,"cache_creation_input_tokens":2374,"cache_creation":{"ephemeral_5m_input_tokens":2374,"ephemeral_1h_input_tokens":0},"type":"message"}],"speed":"standard"},"diagnostics":null},"requestId":"req_011CcRptTB3r1xd4dBVJ7uFo","attributionAgent":"Explore","type":"assistant","uuid":"64af43bd-3902-4cb5-bbe7-066c5f92bb8c","timestamp":"2026-06-26T11:54:58.342Z","userType":"external","entrypoint":"cli","cwd":"/opt/projects/.covalba-next-wp-worktrees/tom-validation-finale","sessionId":"c02b163b-170b-4cd3-a555-3613df5965a3","version":"2.1.193","gitBranch":"tom/validation-finale","slug":"plusieurs-chose-faire-crispy-axolotl"}
