{"id":13580,"date":"2026-04-27T11:49:28","date_gmt":"2026-04-27T11:49:28","guid":{"rendered":"https:\/\/africaresearchconnects.com\/rrat-synthese\/"},"modified":"2026-04-27T11:49:45","modified_gmt":"2026-04-27T11:49:45","slug":"rrat-synthese","status":"publish","type":"page","link":"https:\/\/africaresearchconnects.com\/fr\/rrat-synthese\/","title":{"rendered":"RRAT Synth\u00e8se"},"content":{"rendered":"<div id=\"rrat-synthesis\" class=\"ar-page-container arc-rrat-public\">\n\n\t<!-- Toolbar (hidden in print) -->\n\t<div class=\"rrat-syn-toolbar no-print\">\n\n\t\t<div class=\"rrat-syn-toolbar-head\">\n\t\t\t<div class=\"rrat-syn-toolbar-title\">\n\t\t\t\t<i class=\"fas fa-compass\"><\/i>\n\t\t\t\t<span>Build a synthesis<\/span>\n\t\t\t<\/div>\n\t\t\t<div class=\"rrat-syn-toolbar-hint\">\n\t\t\t\tPick a scope, refine the picker that appears, and click <strong>Generate<\/strong>.\n\t\t\t<\/div>\n\t\t<\/div>\n\n\t\t<!-- Scope chips: one-click selection of analytical lens. -->\n\t\t<div class=\"rrat-syn-scope-chips\" id=\"syn-scope-chips\" role=\"tablist\" aria-label=\"Synthesis scope\">\n\t\t\t<button type=\"button\" class=\"rrat-syn-chip-btn is-active\" data-scope=\"continental\">\n\t\t\t\t<i class=\"fas fa-globe-africa\"><\/i> Continental\n\t\t\t<\/button>\n\t\t\t<button type=\"button\" class=\"rrat-syn-chip-btn\" data-scope=\"multi\">\n\t\t\t\t<i class=\"fas fa-trophy\"><\/i> Top-N comparison\n\t\t\t<\/button>\n\t\t\t<button type=\"button\" class=\"rrat-syn-chip-btn\" data-scope=\"countries\">\n\t\t\t\t<i class=\"fas fa-flag\"><\/i> Specific countries\n\t\t\t<\/button>\n\t\t\t<button type=\"button\" class=\"rrat-syn-chip-btn\" data-scope=\"region\">\n\t\t\t\t<i class=\"fas fa-map\"><\/i> Region\n\t\t\t<\/button>\n\t\t\t<button type=\"button\" class=\"rrat-syn-chip-btn\" data-scope=\"sector\">\n\t\t\t\t<i class=\"fas fa-university\"><\/i> Sector\n\t\t\t<\/button>\n\t\t\t<button type=\"button\" class=\"rrat-syn-chip-btn\" data-scope=\"country\">\n\t\t\t\t<i class=\"fas fa-map-marker-alt\"><\/i> Single country\n\t\t\t<\/button>\n\t\t\t<button type=\"button\" class=\"rrat-syn-chip-btn\" data-scope=\"institution\">\n\t\t\t\t<i class=\"fas fa-building\"><\/i> Single institution\n\t\t\t<\/button>\n\t\t\t<button type=\"button\" class=\"rrat-syn-chip-btn\" data-scope=\"institutions\">\n\t\t\t\t<i class=\"fas fa-city\"><\/i> Compare institutions\n\t\t\t<\/button>\n\t\t<\/div>\n\n\t\t<!-- Hidden state-bearer; the chip-row above flips this value. -->\n\t\t<input type=\"hidden\" id=\"syn-scope\" value=\"continental\">\n\n\t\t<!-- Contextual picker rows \u2014 one shows per scope. -->\n\t\t<div class=\"rrat-syn-pickers\">\n\n\t\t\t<!-- Continental: nothing to configure. -->\n\t\t\t<div class=\"rrat-syn-picker\" data-for=\"continental\">\n\t\t\t\t<div class=\"rrat-syn-picker-note\">\n\t\t\t\t\t<i class=\"fas fa-info-circle\"><\/i>\n\t\t\t\t\tSynthesise across <strong>every published RRAT submission<\/strong>, all African countries pooled.\n\t\t\t\t<\/div>\n\t\t\t<\/div>\n\n\t\t\t<!-- Top-N: number picker for how many countries by submission volume. -->\n\t\t\t<div class=\"rrat-syn-picker\" data-for=\"multi\" style=\"display:none;\">\n\t\t\t\t<label class=\"rrat-syn-field\">\n\t\t\t\t\t<span class=\"rrat-syn-field-label\">Compare top<\/span>\n\t\t\t\t\t<select id=\"syn-topn\" class=\"rrat-syn-input\">\n\t\t\t\t\t\t<option value=\"3\">3 countries<\/option>\n\t\t\t\t\t\t<option value=\"4\" selected>4 countries<\/option>\n\t\t\t\t\t\t<option value=\"5\">5 countries<\/option>\n\t\t\t\t\t\t<option value=\"6\">6 countries<\/option>\n\t\t\t\t\t\t<option value=\"8\">8 countries<\/option>\n\t\t\t\t\t<\/select>\n\t\t\t\t<\/label>\n\t\t\t\t<div class=\"rrat-syn-picker-note\">\n\t\t\t\t\tRanked by published submission volume, highest first.\n\t\t\t\t<\/div>\n\t\t\t<\/div>\n\n\t\t\t<!-- Specific countries: rich multi-picker with Select All \/ region \/ search. -->\n\t\t\t<div class=\"rrat-syn-picker\" data-for=\"countries\" style=\"display:none;\">\n\t\t\t\t<div class=\"rrat-syn-multipick\" data-target=\"countries\">\n\t\t\t\t\t<div class=\"rrat-syn-multipick-head\">\n\t\t\t\t\t\t<input type=\"search\" class=\"rrat-syn-multipick-search\" id=\"syn-countries-search\" placeholder=\"Search countries\u2026\" autocomplete=\"off\">\n\t\t\t\t\t\t<div class=\"rrat-syn-multipick-actions\">\n\t\t\t\t\t\t\t<button type=\"button\" class=\"rrat-syn-mp-btn\" data-mp-action=\"all\">\n\t\t\t\t\t\t\t\t<i class=\"fas fa-check-double\"><\/i> Select all\n\t\t\t\t\t\t\t<\/button>\n\t\t\t\t\t\t\t<button type=\"button\" class=\"rrat-syn-mp-btn\" data-mp-action=\"clear\">\n\t\t\t\t\t\t\t\t<i class=\"fas fa-eraser\"><\/i> Clear\n\t\t\t\t\t\t\t<\/button>\n\t\t\t\t\t\t\t<div class=\"rrat-syn-mp-region\">\n\t\t\t\t\t\t\t\t<button type=\"button\" class=\"rrat-syn-mp-btn rrat-syn-mp-region-trigger\">\n\t\t\t\t\t\t\t\t\t<i class=\"fas fa-map\"><\/i> Pick by region <i class=\"fas fa-caret-down\"><\/i>\n\t\t\t\t\t\t\t\t<\/button>\n\t\t\t\t\t\t\t\t<div class=\"rrat-syn-mp-region-menu\" hidden><\/div>\n\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t\t<div class=\"rrat-syn-multipick-list\" id=\"syn-countries-list\"><\/div>\n\t\t\t\t\t<div class=\"rrat-syn-multipick-footer\">\n\t\t\t\t\t\t<span class=\"rrat-syn-mp-count\"><strong id=\"syn-countries-count\">0<\/strong> selected <span class=\"rrat-syn-mp-cap\">(max 12)<\/span><\/span>\n\t\t\t\t\t\t<div class=\"rrat-syn-mp-chips\" id=\"syn-countries-chips\"><\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t<\/div>\n\n\t\t\t<!-- Region: single-select region picker. -->\n\t\t\t<div class=\"rrat-syn-picker\" data-for=\"region\" style=\"display:none;\">\n\t\t\t\t<label class=\"rrat-syn-field\">\n\t\t\t\t\t<span class=\"rrat-syn-field-label\">Region<\/span>\n\t\t\t\t\t<select id=\"syn-region\" class=\"rrat-syn-input\">\n\t\t\t\t\t\t<option value=\"\">Select a region\u2026<\/option>\n\t\t\t\t\t<\/select>\n\t\t\t\t<\/label>\n\t\t\t\t<div class=\"rrat-syn-picker-note\">\n\t\t\t\t\tSynthesis is reduced to countries with submissions in this region.\n\t\t\t\t<\/div>\n\t\t\t<\/div>\n\n\t\t\t<!-- Sector: single-select. -->\n\t\t\t<div class=\"rrat-syn-picker\" data-for=\"sector\" style=\"display:none;\">\n\t\t\t\t<label class=\"rrat-syn-field\">\n\t\t\t\t\t<span class=\"rrat-syn-field-label\">Sector<\/span>\n\t\t\t\t\t<select id=\"syn-sector\" class=\"rrat-syn-input\">\n\t\t\t\t\t\t<option value=\"University\">University<\/option>\n\t\t\t\t\t\t<option value=\"Research Institute\">Research Institute<\/option>\n\t\t\t\t\t\t<option value=\"Other\">Other<\/option>\n\t\t\t\t\t<\/select>\n\t\t\t\t<\/label>\n\t\t\t<\/div>\n\n\t\t\t<!-- Single country: searchable select. -->\n\t\t\t<div class=\"rrat-syn-picker\" data-for=\"country\" style=\"display:none;\">\n\t\t\t\t<label class=\"rrat-syn-field\">\n\t\t\t\t\t<span class=\"rrat-syn-field-label\">Country<\/span>\n\t\t\t\t\t<select id=\"syn-country\" class=\"rrat-syn-input\">\n\t\t\t\t\t\t<option value=\"\">Select a country\u2026<\/option>\n\t\t\t\t\t<\/select>\n\t\t\t\t<\/label>\n\t\t\t<\/div>\n\n\t\t\t<!-- Single institution: typeahead. -->\n\t\t\t<div class=\"rrat-syn-picker\" data-for=\"institution\" style=\"display:none;\">\n\t\t\t\t<label class=\"rrat-syn-field rrat-syn-field-wide\">\n\t\t\t\t\t<span class=\"rrat-syn-field-label\">Institution<\/span>\n\t\t\t\t\t<input type=\"search\" id=\"syn-inst-search-single\" class=\"rrat-syn-input\" placeholder=\"Type an institution name\u2026\" autocomplete=\"off\">\n\t\t\t\t<\/label>\n\t\t\t\t<div class=\"rrat-syn-inst-results\" id=\"syn-inst-results-single\"><\/div>\n\t\t\t\t<div class=\"rrat-syn-inst-selected\" id=\"syn-inst-selected-single\"><\/div>\n\t\t\t<\/div>\n\n\t\t\t<!-- Multi institutions: typeahead with chip list + Clear. -->\n\t\t\t<div class=\"rrat-syn-picker\" data-for=\"institutions\" style=\"display:none;\">\n\t\t\t\t<label class=\"rrat-syn-field rrat-syn-field-wide\">\n\t\t\t\t\t<span class=\"rrat-syn-field-label\">Institutions <small>(up to 12)<\/small><\/span>\n\t\t\t\t\t<input type=\"search\" id=\"syn-inst-search-multi\" class=\"rrat-syn-input\" placeholder=\"Type to find institutions to compare\u2026\" autocomplete=\"off\">\n\t\t\t\t<\/label>\n\t\t\t\t<div class=\"rrat-syn-inst-results\" id=\"syn-inst-results-multi\"><\/div>\n\t\t\t\t<div class=\"rrat-syn-inst-selected-head\">\n\t\t\t\t\t<span class=\"rrat-syn-mp-count\"><strong id=\"syn-inst-count\">0<\/strong> selected <span class=\"rrat-syn-mp-cap\">(max 12)<\/span><\/span>\n\t\t\t\t\t<button type=\"button\" class=\"rrat-syn-mp-btn\" id=\"syn-inst-clear\">\n\t\t\t\t\t\t<i class=\"fas fa-eraser\"><\/i> Clear all\n\t\t\t\t\t<\/button>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"rrat-syn-inst-selected\" id=\"syn-inst-selected-multi\"><\/div>\n\t\t\t<\/div>\n\n\t\t<\/div>\n\n\t\t<!-- Secondary filter row + actions. -->\n\t\t<div class=\"rrat-syn-secondary\">\n\t\t\t<label class=\"rrat-syn-field\">\n\t\t\t\t<span class=\"rrat-syn-field-label\">\n\t\t\t\t\tFocus dimension\n\t\t\t\t\t<span class=\"rrat-syn-field-hint\">optional<\/span>\n\t\t\t\t<\/span>\n\t\t\t\t<select id=\"syn-dimension\" class=\"rrat-syn-input\">\n\t\t\t\t\t<option value=\"\">\u2014 All dimensions \u2014<\/option>\n\t\t\t\t<\/select>\n\t\t\t<\/label>\n\n\t\t\t<div class=\"rrat-syn-actions\">\n\t\t\t\t<button id=\"syn-regenerate\" class=\"rrat-btn rrat-btn-outline\" style=\"display:none;\" title=\"Bypass the AI cache and re-call OpenAI\">\n\t\t\t\t\t<i class=\"fas fa-magic\"><\/i> Regenerate\n\t\t\t\t<\/button>\n\t\t\t\t<button id=\"syn-print\" class=\"rrat-btn rrat-btn-outline\">\n\t\t\t\t\t<i class=\"fas fa-file-pdf\"><\/i> Print \/ PDF\n\t\t\t\t<\/button>\n\t\t\t\t<button id=\"syn-refresh\" class=\"rrat-btn rrat-btn-primary\">\n\t\t\t\t\t<i class=\"fas fa-bolt\"><\/i> Generate\n\t\t\t\t<\/button>\n\t\t\t<\/div>\n\t\t<\/div>\n\n\t<\/div>\n\n\t<!-- AI error banner (admin only) -->\n\t<div id=\"syn-ai-error\" class=\"rrat-syn-ai-error no-print\" style=\"display:none;\"><\/div>\n\n\t<!-- Cover banner \u2014 title\/subtitle from AI; strip + meta deterministic -->\n\t<header class=\"rrat-syn-cover\">\n\t\t<div class=\"rrat-syn-cover-tag\" id=\"syn-cover-tag\">RRAT Continental Assessment Programme<\/div>\n\t\t<h1 class=\"rrat-syn-cover-title\" id=\"syn-cover-title\">Research Readiness Synthesis<\/h1>\n\t\t<div class=\"rrat-syn-cover-sub\" id=\"syn-cover-sub\">Generating live from RRAT data\u2026<\/div>\n\t\t<div class=\"rrat-syn-cover-meta\" id=\"syn-cover-meta\"><\/div>\n\t\t<div class=\"rrat-syn-cover-cache no-print\" id=\"syn-cover-cache\" style=\"display:none;\"><\/div>\n\n\t\t<!--\n\t\t\tAssessment call-to-action, inside the cover masthead.\n\t\t\tTwo constraints drove this position. It must sit OUTSIDE #syn-body,\n\t\t\twhich ships display:none and is only revealed once the synthesis AJAX\n\t\t\tresolves \u2014 and whose error paths call .html() on it, which would\n\t\t\tdestroy the link outright. And it must be above the fold: the toolbar\n\t\t\tplus cover run roughly 600-700px, so anything below the banner needs\n\t\t\tscrolling on a 1080p screen. In the masthead it is on screen at first\n\t\t\tpaint, before the report generates, and survives a failed load.\n\t\t-->\n\t\t<div class=\"rrat-syn-cta rrat-syn-cta-cover\">\n\t\t\t<div class=\"rrat-syn-cta-body\">\n\t\t\t\t<div class=\"rrat-syn-cta-title\">Is your institution missing from this synthesis?<\/div>\n\t\t\t\t<p class=\"rrat-syn-cta-text\">This report is generated live from submitted RRAT assessments \u2014 adding yours brings it into the evidence base.<\/p>\n\t\t\t<\/div>\n\t\t\t<a class=\"rrat-btn rrat-syn-cta-btn rrat-syn-cta-btn-oncover\" href=\"https:\/\/africaresearchconnects.com\/fr\/research-readiness-assessment\/\">\n\t\t\t\t<i class=\"fas fa-clipboard-check\"><\/i> Complete the Assessment\n\t\t\t<\/a>\n\t\t<\/div>\n\n\t\t<div class=\"rrat-syn-cover-strip\" id=\"syn-cover-strip\"><\/div>\n\t<\/header>\n\n\t<div id=\"syn-loading\" class=\"rrat-syn-loading\">\n\t\t<i class=\"fas fa-spinner fa-spin\"><\/i> Computing synthesis\u2026\n\t<\/div>\n\n\t<div id=\"syn-body\" style=\"display:none;\">\n\n\t\t\t\t<div class=\"arc-ai-notice\" role=\"note\" aria-label=\"AI-generated content notice\">\n\t\t\t<div class=\"arc-ai-notice-head\">\n\t\t\t\t<span class=\"arc-ai-notice-icon\" aria-hidden=\"true\">\n\t\t\t\t\t<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M12 2v4\"\/><path d=\"M12 18v4\"\/><path d=\"m4.93 4.93 2.83 2.83\"\/><path d=\"m16.24 16.24 2.83 2.83\"\/><path d=\"M2 12h4\"\/><path d=\"M18 12h4\"\/><path d=\"m4.93 19.07 2.83-2.83\"\/><path d=\"m16.24 7.76 2.83-2.83\"\/><\/svg>\n\t\t\t\t<\/span>\n\t\t\t\t<strong class=\"arc-ai-notice-label\">AI-generated content<\/strong>\n\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t\t\t<div class=\"arc-ai-notice-body\">Generated from RRAT survey submissions in the selected scope. <span class=\"arc-ai-notice-verify\">Verify against the source before citing.<\/span><\/div>\n\t\t\t\t\t<\/div>\n\t\t\n\t\t<section class=\"rrat-syn-section\" id=\"syn-execsec\">\n\t\t\t<h2 class=\"rrat-syn-h2\">The Evidence Base<\/h2>\n\t\t\t<div class=\"rrat-syn-stats\" id=\"syn-stats\"><\/div>\n\t\t\t<div class=\"rrat-syn-narrative rrat-syn-narrative-lead\" id=\"syn-background-context\"><\/div>\n\t\t\t<div class=\"rrat-syn-narrative\" id=\"syn-exec-summary\"><\/div>\n\t\t\t<div class=\"rrat-syn-insight\" id=\"syn-headline-insight\"><\/div>\n\t\t<\/section>\n\n\t\t<section class=\"rrat-syn-section\" id=\"syn-matrixsec\">\n\t\t\t<h2 class=\"rrat-syn-h2\" id=\"syn-matrix-title\">Continental Capacity Matrix<\/h2>\n\t\t\t<p class=\"rrat-syn-lead\">Average readiness score by capacity domain, per <span id=\"syn-entity-noun\">country<\/span> in scope. Scores expressed as percentage of maximum (0\u2013100). Heat colouring: <span class=\"rrat-syn-chip ok\">\u226570%<\/span> <span class=\"rrat-syn-chip mid\">40\u201369%<\/span> <span class=\"rrat-syn-chip low\">&lt;40%<\/span><\/p>\n\t\t\t<div id=\"syn-matrix\" class=\"rrat-syn-table-wrap\"><\/div>\n\t\t\t<div class=\"rrat-syn-narrative\" id=\"syn-matrix-narrative\"><\/div>\n\t\t<\/section>\n\n\t\t<section class=\"rrat-syn-section\" id=\"syn-comparative-sec\" style=\"display:none;\">\n\t\t\t<h2 class=\"rrat-syn-h2\">Comparative Lens<\/h2>\n\t\t\t<p class=\"rrat-syn-lead\">Who is leading, who is lagging, and which clusters emerge once the matrix is read horizontally rather than vertically.<\/p>\n\t\t\t<div class=\"rrat-syn-narrative rrat-syn-narrative-prose\" id=\"syn-comparative-lens\"><\/div>\n\t\t<\/section>\n\n\t\t<section class=\"rrat-syn-section\" id=\"syn-regional-sec\" style=\"display:none;\">\n\t\t\t<h2 class=\"rrat-syn-h2\">Regional Distribution<\/h2>\n\t\t\t<p class=\"rrat-syn-lead\">Where are the continent's capacity gaps geographically concentrated? Each row is a UN Africa region; each column a capacity domain. The <strong>Gap<\/strong> column shows the spread (best \u2212 worst region) per domain \u2014 high values flag dimensions where the regional disparity is widest.<\/p>\n\t\t\t<div id=\"syn-regional\" class=\"rrat-syn-table-wrap\"><\/div>\n\t\t\t<div class=\"rrat-syn-narrative\" id=\"syn-regional-narrative\"><\/div>\n\t\t<\/section>\n\n\t\t<section class=\"rrat-syn-section\" id=\"syn-sectorsec\">\n\t\t\t<h2 class=\"rrat-syn-h2\">Sector Disaggregation<\/h2>\n\t\t\t<p class=\"rrat-syn-lead\">Universities, research institutes, and other organisations carry different roles in the research-to-impact pipeline. Their capacity profiles diverge accordingly.<\/p>\n\t\t\t<div id=\"syn-sectors\" class=\"rrat-syn-table-wrap\"><\/div>\n\t\t\t<div class=\"rrat-syn-narrative\" id=\"syn-sector-narrative\"><\/div>\n\t\t<\/section>\n\n\t\t<section class=\"rrat-syn-section\">\n\t\t\t<h2 class=\"rrat-syn-h2\" id=\"syn-profiles-title\">Profiles<\/h2>\n\t\t\t<p class=\"rrat-syn-lead\">Composite readiness score, top three strengths, three highest-leverage gaps, and a narrative read for each entity in scope.<\/p>\n\t\t\t<div id=\"syn-profiles\" class=\"rrat-syn-profiles\"><\/div>\n\t\t<\/section>\n\n\t\t<section class=\"rrat-syn-section\" id=\"syn-deepreads-sec\" style=\"display:none;\">\n\t\t\t<h2 class=\"rrat-syn-h2\">Indicator Deep-Reads<\/h2>\n\t\t\t<p class=\"rrat-syn-lead\">A handful of binary indicators carry outsized strategic weight. These are the readings worth pausing on.<\/p>\n\t\t\t<div id=\"syn-deepreads\" class=\"rrat-syn-deepreads\"><\/div>\n\t\t<\/section>\n\n\t\t<section class=\"rrat-syn-section\">\n\t\t\t<h2 class=\"rrat-syn-h2\">Innovation Readiness Tiers<\/h2>\n\t\t\t<p class=\"rrat-syn-lead\">Institutions classified by composite score and the two highest-leverage governance dimensions (ethics + grants management). Listings show up to 12 institutions per tier.<\/p>\n\t\t\t<div class=\"rrat-syn-narrative\" id=\"syn-tier-narrative\"><\/div>\n\t\t\t<div id=\"syn-tiers\" class=\"rrat-syn-tiers\"><\/div>\n\t\t<\/section>\n\n\t\t<section class=\"rrat-syn-section\" id=\"syn-riskopp-sec\" style=\"display:none;\">\n\t\t\t<h2 class=\"rrat-syn-h2\">Risks &amp; Opportunities<\/h2>\n\t\t\t<p class=\"rrat-syn-lead\">Structural risks that could undermine readiness investments, alongside the asymmetric opportunities visible in the data.<\/p>\n\t\t\t<div class=\"rrat-syn-riskopp\" id=\"syn-riskopp\"><\/div>\n\t\t<\/section>\n\n\t\t<section class=\"rrat-syn-section\" id=\"syn-recsec\" style=\"display:none;\">\n\t\t\t<h2 class=\"rrat-syn-h2\">Strategic Recommendations<\/h2>\n\t\t\t<p class=\"rrat-syn-lead\">Concrete actions, each grounded in a specific gap and routed to a realistic owner with a timeline.<\/p>\n\t\t\t<div id=\"syn-recs\" class=\"rrat-syn-recs\"><\/div>\n\t\t<\/section>\n\n\t\t<section class=\"rrat-syn-section\" id=\"syn-briefs-sec\" style=\"display:none;\">\n\t\t\t<h2 class=\"rrat-syn-h2\">Audience Briefs<\/h2>\n\t\t\t<p class=\"rrat-syn-lead\">The same evidence, framed for the two audiences who can act on it.<\/p>\n\t\t\t<div class=\"rrat-syn-briefs\">\n\t\t\t\t<div class=\"rrat-syn-brief rrat-syn-brief-policy\" id=\"syn-brief-policy-card\" style=\"display:none;\">\n\t\t\t\t\t<div class=\"rrat-syn-brief-tag\"><i class=\"fas fa-landmark\"><\/i> Policy brief<\/div>\n\t\t\t\t\t<div class=\"rrat-syn-brief-body\" id=\"syn-policy-brief\"><\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"rrat-syn-brief rrat-syn-brief-funder\" id=\"syn-brief-funder-card\" style=\"display:none;\">\n\t\t\t\t\t<div class=\"rrat-syn-brief-tag\"><i class=\"fas fa-hand-holding-usd\"><\/i> Funder brief<\/div>\n\t\t\t\t\t<div class=\"rrat-syn-brief-body\" id=\"syn-funder-brief\"><\/div>\n\t\t\t\t<\/div>\n\t\t\t<\/div>\n\t\t<\/section>\n\n\t\t<section class=\"rrat-syn-section\" id=\"syn-further-sec\" style=\"display:none;\">\n\t\t\t<h2 class=\"rrat-syn-h2\">Areas for Further Research<\/h2>\n\t\t\t<p class=\"rrat-syn-lead\">Open questions and knowledge gaps that the current dataset surfaces but cannot yet answer.<\/p>\n\t\t\t<ul id=\"syn-further\" class=\"rrat-syn-further\"><\/ul>\n\t\t<\/section>\n\n\t\t<section class=\"rrat-syn-section page-break-before\">\n\t\t\t<h2 class=\"rrat-syn-h2\">Annex \u2014 Indicator Reference<\/h2>\n\t\t\t<p class=\"rrat-syn-lead\">Per-domain breakdown of binary indicators. Percentages report the share of institutions answering \"Yes\" \u2014 non-responses and \"I don't know\" included in the denominator.<\/p>\n\t\t\t<div id=\"syn-annex\"><\/div>\n\t\t<\/section>\n\n\t\t<footer class=\"rrat-syn-footer\">\n\t\t\t<div>Generated <span id=\"syn-gen-time\"><\/span> from live RRAT data. <span id=\"syn-gen-source\"><\/span><span id=\"syn-ai-status\"><\/span><\/div>\n\t\t<\/footer>\n\n\t<\/div>\n<\/div>\n\n<script>\n(function($) {\n\t'use strict';\n\n\t\/\/ Picker reference data, inlined from PHP at render time so the toolbar\n\t\/\/ is fully usable before the AI-bearing initial AJAX returns.\n\tvar REGION_MAP    = {\"Northern Africa\":[\"Algeria\",\"Egypt\",\"Libya\",\"Morocco\",\"Sudan\",\"Tunisia\",\"Western Sahara\"],\"Western Africa\":[\"Benin\",\"Burkina Faso\",\"Cabo Verde\",\"Cape Verde\",\"C\\u00f4te d'Ivoire\",\"Cote d'Ivoire\",\"Gambia\",\"Ghana\",\"Guinea\",\"Guinea-Bissau\",\"Liberia\",\"Mali\",\"Mauritania\",\"Niger\",\"Nigeria\",\"Senegal\",\"Sierra Leone\",\"Togo\"],\"Central Africa\":[\"Cameroon\",\"Central African Republic\",\"Chad\",\"Republic of the Congo\",\"Congo\",\"Democratic Republic of the Congo\",\"DRC\",\"Equatorial Guinea\",\"Gabon\",\"S\\u00e3o Tom\\u00e9 and Pr\\u00edncipe\",\"Sao Tome and Principe\"],\"Eastern Africa\":[\"Burundi\",\"Comoros\",\"Djibouti\",\"Eritrea\",\"Ethiopia\",\"Kenya\",\"Madagascar\",\"Malawi\",\"Mauritius\",\"Mozambique\",\"Rwanda\",\"Seychelles\",\"Somalia\",\"South Sudan\",\"Tanzania\",\"United Republic of Tanzania\",\"Uganda\",\"Zambia\",\"Zimbabwe\"],\"Southern Africa\":[\"Botswana\",\"Eswatini\",\"Swaziland\",\"Lesotho\",\"Namibia\",\"South Africa\"]};\n\tvar DOMAIN_LABELS = {\"demographics\":\"Demographics\",\"institution_profile\":\"Institution Profile\",\"infrastructure\":\"Infrastructure\",\"human_resources\":\"Human Resources\",\"research_output\":\"Research Output\",\"education_training\":\"Education & Training\",\"ethics_governance\":\"Ethics & Governance\",\"grants_finance\":\"Grants & Finance\",\"policy_engagement\":\"Policy Engagement\",\"ict_digital\":\"ICT & Digital\",\"awards_collaborations\":\"Awards & Collaborations\"};\n\tvar ALL_COUNTRIES = [{\"name\":\"Nigeria\",\"n\":212},{\"name\":\"Kenya\",\"n\":155},{\"name\":\"Ethiopia\",\"n\":122},{\"name\":\"Uganda\",\"n\":61},{\"name\":\"Tanzania\",\"n\":44},{\"name\":\"Zambia\",\"n\":40},{\"name\":\"Ghana\",\"n\":35},{\"name\":\"South Africa\",\"n\":34},{\"name\":\"Burkina Faso\",\"n\":30},{\"name\":\"Zimbabwe\",\"n\":26},{\"name\":\"Rwanda\",\"n\":24},{\"name\":\"Sierra Leone\",\"n\":18},{\"name\":\"DR Congo\",\"n\":17},{\"name\":\"Benin\",\"n\":17},{\"name\":\"Cameroon\",\"n\":15},{\"name\":\"Somalia\",\"n\":14},{\"name\":\"Malawi\",\"n\":11},{\"name\":\"Guinea\",\"n\":10},{\"name\":\"Tunisia\",\"n\":9},{\"name\":\"Senegal\",\"n\":9},{\"name\":\"Burundi\",\"n\":8},{\"name\":\"Egypt\",\"n\":7},{\"name\":\"Algeria\",\"n\":6},{\"name\":\"Gabon\",\"n\":6},{\"name\":\"Madagascar\",\"n\":6},{\"name\":\"Botswana\",\"n\":6},{\"name\":\"Mozambique\",\"n\":5},{\"name\":\"Namibia\",\"n\":5},{\"name\":\"South Sudan\",\"n\":5},{\"name\":\"Sudan\",\"n\":5},{\"name\":\"Liberia\",\"n\":5},{\"name\":\"Gambia\",\"n\":4},{\"name\":\"Mali\",\"n\":4},{\"name\":\"Morocco\",\"n\":4},{\"name\":\"C\\u00f4te d'Ivoire\",\"n\":4},{\"name\":\"Niger\",\"n\":3},{\"name\":\"Togo\",\"n\":2},{\"name\":\"Cabo Verde\",\"n\":2},{\"name\":\"Chad\",\"n\":2},{\"name\":\"Angola\",\"n\":2},{\"name\":\"Libya\",\"n\":1},{\"name\":\"Djibouti\",\"n\":1},{\"name\":\"Lesotho\",\"n\":1},{\"name\":\"Guinea-Bissau\",\"n\":1},{\"name\":\"Eswatini\",\"n\":1},{\"name\":\"Seychelles\",\"n\":1},{\"name\":\"Mauritius\",\"n\":1}];\n\n\t\/\/ State for the rich multi-pickers. Native <select multiple> is replaced\n\t\/\/ by checkbox lists with search + Select All \/ Region \/ Clear affordances\n\t\/\/ so users see what they're doing.\n\tvar state = {\n\t\tscope: 'continental',\n\t\tcountries: [],\n\t\tcountriesAll: ALL_COUNTRIES.slice(),\n\t\tinstitutionsSingle: null,\n\t\tinstitutionsMulti: []\n\t};\n\n\t$(document).ready(function () {\n\t\tbindUI();\n\t\t\/\/ Populate the toolbar's reference pickers before the first AJAX returns.\n\t\tseedPickersFromInline();\n\t\tbootstrap();\n\t});\n\n\tfunction seedPickersFromInline() {\n\t\t\/\/ Single country picker.\n\t\tvar $cSingle = $('#syn-country');\n\t\tALL_COUNTRIES.forEach(function (c) {\n\t\t\t$cSingle.append('<option value=\"' + esc(c.name) + '\">' + esc(c.name) + ' (' + c.n + ')<\/option>');\n\t\t});\n\n\t\t\/\/ Region picker.\n\t\tvar $r = $('#syn-region');\n\t\tObject.keys(REGION_MAP).forEach(function (region) {\n\t\t\t$r.append('<option value=\"' + esc(region) + '\">' + esc(region) + '<\/option>');\n\t\t});\n\n\t\t\/\/ Dimension focus picker.\n\t\tvar $dim = $('#syn-dimension');\n\t\tObject.keys(DOMAIN_LABELS).forEach(function (k) {\n\t\t\tif (k === 'demographics') return;\n\t\t\t$dim.append('<option value=\"' + esc(k) + '\">' + esc(DOMAIN_LABELS[k]) + '<\/option>');\n\t\t});\n\n\t\t\/\/ Countries multi-picker list + region submenu.\n\t\trenderCountriesList();\n\t\tvar menuHtml = Object.keys(REGION_MAP).map(function (region) {\n\t\t\tvar available = REGION_MAP[region].filter(function (n) {\n\t\t\t\treturn ALL_COUNTRIES.some(function (c) { return c.name === n; });\n\t\t\t});\n\t\t\treturn '<button type=\"button\" class=\"rrat-syn-mp-region-item\" data-region=\"' + esc(region) + '\">'\n\t\t\t\t+ esc(region) + ' <small>(' + available.length + ')<\/small><\/button>';\n\t\t}).join('');\n\t\t$('.rrat-syn-mp-region-menu').html(menuHtml);\n\t}\n\n\tfunction bindUI() {\n\t\t\/\/ Scope chip selection \u2014 flips hidden #syn-scope + reveals the matching picker.\n\t\t$('#syn-scope-chips').on('click', '.rrat-syn-chip-btn', function () {\n\t\t\tvar scope = $(this).data('scope');\n\t\t\t$('#syn-scope-chips .rrat-syn-chip-btn').removeClass('is-active');\n\t\t\t$(this).addClass('is-active');\n\t\t\t$('#syn-scope').val(scope);\n\t\t\tstate.scope = scope;\n\t\t\t$('.rrat-syn-picker').hide();\n\t\t\t$('.rrat-syn-picker[data-for=\"' + scope + '\"]').show();\n\t\t});\n\n\t\t\/\/ Multi-picker for countries.\n\t\t$('#syn-countries-search').on('input', renderCountriesList);\n\t\t$('.rrat-syn-multipick[data-target=\"countries\"]').on('click', '[data-mp-action=\"all\"]', function () {\n\t\t\t\/\/ Select up to the cap (12). If user has a search filter active,\n\t\t\t\/\/ only the filtered subset is added.\n\t\t\tvar q = ($('#syn-countries-search').val() || '').toLowerCase();\n\t\t\tvar pool = state.countriesAll.filter(function (c) { return c.name.toLowerCase().indexOf(q) !== -1; });\n\t\t\tpool.forEach(function (c) {\n\t\t\t\tif (state.countries.length >= 12) return;\n\t\t\t\tif (state.countries.indexOf(c.name) === -1) state.countries.push(c.name);\n\t\t\t});\n\t\t\trenderCountriesList();\n\t\t\trenderCountriesSelected();\n\t\t});\n\t\t$('.rrat-syn-multipick[data-target=\"countries\"]').on('click', '[data-mp-action=\"clear\"]', function () {\n\t\t\tstate.countries = [];\n\t\t\trenderCountriesList();\n\t\t\trenderCountriesSelected();\n\t\t});\n\t\t$('.rrat-syn-mp-region-trigger').on('click', function (e) {\n\t\t\te.stopPropagation();\n\t\t\t$('.rrat-syn-mp-region-menu').prop('hidden', function (_, v) { return !v; });\n\t\t});\n\t\t$(document).on('click', function () { $('.rrat-syn-mp-region-menu').prop('hidden', true); });\n\t\t$('.rrat-syn-mp-region-menu').on('click', '[data-region]', function (e) {\n\t\t\te.stopPropagation();\n\t\t\tvar region = $(this).data('region');\n\t\t\tvar members = (REGION_MAP[region] || []);\n\t\t\tvar availableNames = state.countriesAll.map(function (c) { return c.name; });\n\t\t\tvar present = members.filter(function (m) { return availableNames.indexOf(m) !== -1; });\n\t\t\tpresent.forEach(function (n) {\n\t\t\t\tif (state.countries.length >= 12) return;\n\t\t\t\tif (state.countries.indexOf(n) === -1) state.countries.push(n);\n\t\t\t});\n\t\t\t$('.rrat-syn-mp-region-menu').prop('hidden', true);\n\t\t\trenderCountriesList();\n\t\t\trenderCountriesSelected();\n\t\t});\n\t\t$('#syn-countries-list').on('change', 'input[type=\"checkbox\"]', function () {\n\t\t\tvar name = $(this).val();\n\t\t\tif (this.checked) {\n\t\t\t\tif (state.countries.length >= 12) {\n\t\t\t\t\tthis.checked = false;\n\t\t\t\t\tflashCap('You can compare up to 12 countries at a time.');\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (state.countries.indexOf(name) === -1) state.countries.push(name);\n\t\t\t} else {\n\t\t\t\tstate.countries = state.countries.filter(function (n) { return n !== name; });\n\t\t\t}\n\t\t\trenderCountriesSelected();\n\t\t});\n\t\t$('#syn-countries-chips').on('click', '.rrat-syn-chip-x', function () {\n\t\t\tvar name = $(this).data('name');\n\t\t\tstate.countries = state.countries.filter(function (n) { return n !== name; });\n\t\t\t$('#syn-countries-list input[value=\"' + cssEscape(name) + '\"]').prop('checked', false);\n\t\t\trenderCountriesSelected();\n\t\t});\n\n\t\t\/\/ Single + multi institution typeaheads.\n\t\tbindInstitutionTypeahead('#syn-inst-search-single', '#syn-inst-results-single', 'single');\n\t\tbindInstitutionTypeahead('#syn-inst-search-multi',  '#syn-inst-results-multi',  'multi');\n\t\t$('#syn-inst-clear').on('click', function () {\n\t\t\tstate.institutionsMulti = [];\n\t\t\trenderInstitutionsSelected('multi');\n\t\t});\n\n\t\t\/\/ Action buttons.\n\t\t$('#syn-refresh').on('click', function () { loadAndRender(false); });\n\t\t$('#syn-regenerate').on('click', function () { loadAndRender(true); });\n\t\t$('#syn-print').on('click', function () { window.print(); });\n\t}\n\n\tfunction bindInstitutionTypeahead(searchSel, resultsSel, kind) {\n\t\tvar debounce = null;\n\t\t$(searchSel).on('input', function () {\n\t\t\tvar q = $(this).val();\n\t\t\tclearTimeout(debounce);\n\t\t\tif (q.length < 2) { $(resultsSel).empty(); return; }\n\t\t\tdebounce = setTimeout(function () {\n\t\t\t\t$.get(arcRratPublic.ajaxUrl, { action: 'arc_rrat_synthesis_institutions', q: q, limit: 15 }, function (res) {\n\t\t\t\t\tif (!res.success) return;\n\t\t\t\t\tvar html = res.data.results.map(function (r) {\n\t\t\t\t\t\treturn '<div class=\"rrat-syn-inst-result\" data-id=\"' + r.id + '\" data-name=\"' + esc(r.name) + '\" data-country=\"' + esc(r.country || '') + '\">'\n\t\t\t\t\t\t\t+ '<strong>' + esc(r.name) + '<\/strong>'\n\t\t\t\t\t\t\t+ ' <span class=\"rrat-syn-inst-country\">' + esc(r.country || '') + '<\/span>'\n\t\t\t\t\t\t\t+ (r.composite != null ? ' <span class=\"rrat-syn-inst-comp\">' + Math.round(r.composite) + '%<\/span>' : '')\n\t\t\t\t\t\t\t+ '<\/div>';\n\t\t\t\t\t}).join('');\n\t\t\t\t\t$(resultsSel).html(html || '<div class=\"rrat-syn-inst-noresults\">No matches.<\/div>');\n\t\t\t\t});\n\t\t\t}, 220);\n\t\t});\n\t\t$(resultsSel).on('click', '.rrat-syn-inst-result', function () {\n\t\t\tvar rec = { id: $(this).data('id'), name: $(this).data('name'), country: $(this).data('country') };\n\t\t\tif (kind === 'single') {\n\t\t\t\tstate.institutionsSingle = rec;\n\t\t\t} else {\n\t\t\t\tif (state.institutionsMulti.some(function (r) { return r.id === rec.id; })) return;\n\t\t\t\tif (state.institutionsMulti.length >= 12) { flashCap('Maximum 12 institutions per synthesis.'); return; }\n\t\t\t\tstate.institutionsMulti.push(rec);\n\t\t\t}\n\t\t\t$(searchSel).val('');\n\t\t\t$(resultsSel).empty();\n\t\t\trenderInstitutionsSelected(kind);\n\t\t});\n\t\t\/\/ Remove from chip list.\n\t\t$('#syn-inst-selected-' + kind).on('click', '.rrat-syn-chip-x', function () {\n\t\t\tvar id = $(this).data('id');\n\t\t\tif (kind === 'single') {\n\t\t\t\tstate.institutionsSingle = null;\n\t\t\t} else {\n\t\t\t\tstate.institutionsMulti = state.institutionsMulti.filter(function (r) { return r.id !== id; });\n\t\t\t}\n\t\t\trenderInstitutionsSelected(kind);\n\t\t});\n\t}\n\n\tfunction renderInstitutionsSelected(kind) {\n\t\tif (kind === 'single') {\n\t\t\tvar r = state.institutionsSingle;\n\t\t\tvar html = r\n\t\t\t\t? '<span class=\"rrat-syn-inst-tag\">' + esc(r.name) + ' <small>(' + esc(r.country || '') + ')<\/small>'\n\t\t\t\t\t+ ' <button type=\"button\" class=\"rrat-syn-chip-x\" data-id=\"' + r.id + '\" aria-label=\"Remove\">\u00d7<\/button><\/span>'\n\t\t\t\t: '';\n\t\t\t$('#syn-inst-selected-single').html(html);\n\t\t} else {\n\t\t\tvar html = state.institutionsMulti.map(function (r) {\n\t\t\t\treturn '<span class=\"rrat-syn-inst-tag\">' + esc(r.name) + ' <small>(' + esc(r.country || '') + ')<\/small>'\n\t\t\t\t\t+ ' <button type=\"button\" class=\"rrat-syn-chip-x\" data-id=\"' + r.id + '\" aria-label=\"Remove\">\u00d7<\/button><\/span>';\n\t\t\t}).join('');\n\t\t\t$('#syn-inst-selected-multi').html(html);\n\t\t\t$('#syn-inst-count').text(state.institutionsMulti.length);\n\t\t}\n\t}\n\n\tfunction renderCountriesList() {\n\t\tvar q = ($('#syn-countries-search').val() || '').toLowerCase();\n\t\tvar filtered = state.countriesAll.filter(function (c) {\n\t\t\treturn !q || c.name.toLowerCase().indexOf(q) !== -1;\n\t\t});\n\t\tif (!filtered.length) {\n\t\t\t$('#syn-countries-list').html('<div class=\"rrat-syn-mp-empty\">No countries match \"' + esc(q) + '\".<\/div>');\n\t\t\treturn;\n\t\t}\n\t\tvar html = filtered.map(function (c) {\n\t\t\tvar checked = state.countries.indexOf(c.name) !== -1 ? 'checked' : '';\n\t\t\treturn '<label class=\"rrat-syn-mp-item\">'\n\t\t\t\t+ '<input type=\"checkbox\" value=\"' + esc(c.name) + '\" ' + checked + '>'\n\t\t\t\t+ '<span class=\"rrat-syn-mp-item-name\">' + esc(c.name) + '<\/span>'\n\t\t\t\t+ '<span class=\"rrat-syn-mp-item-n\">' + c.n + '<\/span>'\n\t\t\t\t+ '<\/label>';\n\t\t}).join('');\n\t\t$('#syn-countries-list').html(html);\n\t}\n\n\tfunction renderCountriesSelected() {\n\t\t$('#syn-countries-count').text(state.countries.length);\n\t\tvar html = state.countries.map(function (n) {\n\t\t\treturn '<span class=\"rrat-syn-chip-tag\">' + esc(n)\n\t\t\t\t+ ' <button type=\"button\" class=\"rrat-syn-chip-x\" data-name=\"' + esc(n) + '\" aria-label=\"Remove\">\u00d7<\/button><\/span>';\n\t\t}).join('');\n\t\t$('#syn-countries-chips').html(html);\n\t}\n\n\tfunction flashCap(msg) {\n\t\tvar $b = $('<div class=\"rrat-syn-flash\">').text(msg);\n\t\t$('.rrat-syn-toolbar').append($b);\n\t\tsetTimeout(function () { $b.fadeOut(300, function () { $(this).remove(); }); }, 2200);\n\t}\n\n\tfunction cssEscape(s) {\n\t\t\/\/ Minimal \u2014 country names don't contain quotes, but be safe.\n\t\treturn String(s).replace(\/\"\/g, '\\\\\"');\n\t}\n\n\tfunction bootstrap() {\n\t\t\/\/ Initial render \u2014 uses the synthesis_data endpoint to also pull\n\t\t\/\/ the country and region reference lists in one round trip.\n\t\tloadAndRender(false);\n\t}\n\n\tfunction loadAndRender(regenerate) {\n\t\tvar scope = state.scope;\n\t\tvar params = { action: 'arc_rrat_synthesis_data', scope: scope };\n\n\t\tif (scope === 'multi')        params.top_n           = $('#syn-topn').val();\n\t\tif (scope === 'country')      params.country         = $('#syn-country').val();\n\t\tif (scope === 'countries')    params.countries       = state.countries.join(',');\n\t\tif (scope === 'region')       params.region          = $('#syn-region').val();\n\t\tif (scope === 'sector')       params.sector          = $('#syn-sector').val();\n\t\tif (scope === 'institution')  params.institution_id  = (state.institutionsSingle || {}).id || '';\n\t\tif (scope === 'institutions') params.institution_ids = state.institutionsMulti.map(function (r) { return r.id; }).join(',');\n\t\tvar dim = $('#syn-dimension').val();\n\t\tif (dim) params.dimension_focus = dim;\n\t\tif (regenerate) params.regenerate = 1;\n\n\t\t\/\/ Friendly validation.\n\t\tif (scope === 'countries' && state.countries.length === 0) {\n\t\t\talert('Please select at least one country.');\n\t\t\treturn;\n\t\t}\n\t\tif (scope === 'country' && !params.country) {\n\t\t\talert('Please select a country.');\n\t\t\treturn;\n\t\t}\n\t\tif (scope === 'region' && !params.region) {\n\t\t\talert('Please select a region.');\n\t\t\treturn;\n\t\t}\n\t\tif (scope === 'institution' && !params.institution_id) {\n\t\t\talert('Please select an institution.');\n\t\t\treturn;\n\t\t}\n\t\tif (scope === 'institutions' && !params.institution_ids) {\n\t\t\talert('Please select at least one institution.');\n\t\t\treturn;\n\t\t}\n\n\t\t$('#syn-body').hide();\n\t\t$('#syn-ai-error').hide().empty();\n\t\t$('#syn-loading').show();\n\n\t\t$.get(arcRratPublic.ajaxUrl, params, function (res) {\n\t\t\t$('#syn-loading').hide();\n\t\t\tif (!res.success) {\n\t\t\t\t$('#syn-body').show().html('<div class=\"rrat-syn-error\">Failed to load: ' + (res.data || 'unknown error') + '<\/div>');\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tpopulatePickers(res.data);\n\t\t\trenderAll(res.data);\n\t\t\t$('#syn-body').show();\n\t\t}).fail(function () {\n\t\t\t$('#syn-loading').hide();\n\t\t\t$('#syn-body').show().html('<div class=\"rrat-syn-error\">Network error \u2014 check connection and reload.<\/div>');\n\t\t});\n\t}\n\n\tfunction populatePickers(d) {\n\t\t\/\/ Reference pickers (countries, regions, dimensions) are already\n\t\t\/\/ populated from inlined PHP data on document.ready. The server\n\t\t\/\/ response only needs to flip the admin-only regenerate button.\n\t\t$('#syn-regenerate').toggle(!!d.can_regenerate);\n\t}\n\n\tfunction renderAll(d) {\n\t\trenderAiErrorBanner(d);\n\t\trenderCover(d);\n\t\trenderStats(d);\n\t\trenderBackgroundContext(d);\n\t\trenderExecSummary(d);\n\t\trenderHeadlineInsight(d);\n\t\trenderMatrix(d);\n\t\trenderMatrixNarrative(d);\n\t\trenderComparativeLens(d);\n\t\trenderRegional(d);\n\t\trenderSectors(d);\n\t\trenderSectorNarrative(d);\n\t\trenderProfiles(d);\n\t\trenderIndicatorDeepReads(d);\n\t\trenderTierNarrative(d);\n\t\trenderTiers(d);\n\t\trenderRiskOpportunity(d);\n\t\trenderRecommendations(d);\n\t\trenderAudienceBriefs(d);\n\t\trenderFurtherResearch(d);\n\t\trenderAnnex(d);\n\t\trenderFooter(d);\n\t\t\/\/ After layout settles, decide which table-wraps need the \"\u2192 Scroll\"\n\t\t\/\/ affordance. Without this the fade + hint always show; we only want\n\t\t\/\/ them when content actually overflows the visible width.\n\t\tsetTimeout(decorateScrollableTables, 50);\n\t}\n\n\tfunction decorateScrollableTables() {\n\t\t$('#rrat-synthesis .rrat-syn-table-wrap').each(function () {\n\t\t\tvar el = this;\n\t\t\tvar overflows = el.scrollWidth > el.clientWidth + 1;\n\t\t\t$(el).toggleClass('has-overflow', overflows);\n\t\t\tif (!overflows) return;\n\t\t\t\/\/ Track right-edge state so we can hide the fade once user has\n\t\t\t\/\/ scrolled all the way over \u2014 feels finished, not nagged.\n\t\t\tvar onScroll = function () {\n\t\t\t\tvar atEnd = (el.scrollLeft + el.clientWidth) >= (el.scrollWidth - 2);\n\t\t\t\t$(el).toggleClass('is-scrolled-right', atEnd);\n\t\t\t};\n\t\t\tel.addEventListener('scroll', onScroll, { passive: true });\n\t\t\tonScroll();\n\t\t});\n\t}\n\n\t\/\/ Re-evaluate when the window resizes \u2014 narrowing the window can make a\n\t\/\/ previously-fitting table start overflowing, and vice versa.\n\t$(window).on('resize', function () {\n\t\tclearTimeout(window._rratResizeTimer);\n\t\twindow._rratResizeTimer = setTimeout(decorateScrollableTables, 120);\n\t});\n\n\tfunction ai(d) { return (d && d.ai) || {}; }\n\n\tfunction renderAiErrorBanner(d) {\n\t\tvar $b = $('#syn-ai-error');\n\t\tif (d.ai_error && d.can_regenerate) {\n\t\t\t$b.html('<strong>AI synthesis failed.<\/strong> Falling back to deterministic narrative. '\n\t\t\t\t+ '<br><small>' + esc(d.ai_error) + '<\/small> '\n\t\t\t\t+ '<a href=\"#\" id=\"syn-ai-retry\">Retry<\/a>').show();\n\t\t\t$('#syn-ai-retry').on('click', function (e) { e.preventDefault(); loadAndRender(true); });\n\t\t} else {\n\t\t\t$b.hide();\n\t\t}\n\t}\n\n\tfunction renderCover(d) {\n\t\tvar aiData = ai(d);\n\t\tvar now = new Date();\n\t\tvar monthYear = now.toLocaleDateString('en-US', { month: 'long', year: 'numeric' });\n\t\t$('#syn-cover-tag').text(monthYear + ' \u00b7 ARC \u00b7 RRAT Assessment');\n\n\t\tvar title;\n\t\tif (aiData.cover_title) {\n\t\t\ttitle = aiData.cover_title;\n\t\t} else if (d.scope === 'country' && d.countries && d.countries.length === 1) {\n\t\t\ttitle = d.countries[0] + ' \u2014 Research Readiness Profile';\n\t\t} else if (d.scope === 'continental') {\n\t\t\ttitle = 'Africa Research Readiness \u2014 Continental Synthesis';\n\t\t} else if (d.scope === 'institution' || d.scope === 'institutions') {\n\t\t\ttitle = (d.entities && d.entities.length === 1)\n\t\t\t\t? d.entities[0] + ' \u2014 Institutional Readiness Profile'\n\t\t\t\t: d.entities.length + '-Institution Comparative Synthesis';\n\t\t} else if (d.scope === 'region') {\n\t\t\ttitle = (d.scope_meta && d.scope_meta.region ? d.scope_meta.region : 'Region') + ' \u2014 Research Readiness Synthesis';\n\t\t} else if (d.scope === 'sector') {\n\t\t\ttitle = (d.scope_meta && d.scope_meta.sector ? d.scope_meta.sector : 'Sector') + ' Sector \u2014 Research Readiness Synthesis';\n\t\t} else {\n\t\t\ttitle = (d.countries && d.countries.length ? d.countries.length + '-Country' : 'Multi-country') + ' Research Readiness Synthesis';\n\t\t}\n\t\t$('#syn-cover-title').text(title);\n\n\t\tvar sub = aiData.cover_subtitle || d.scope_label || '';\n\t\t$('#syn-cover-sub').text(sub);\n\n\t\tvar meta = d.exec.submissions.toLocaleString() + ' respondents \u00b7 ' +\n\t\t\td.exec.institutions.toLocaleString() + ' institutions \u00b7 ' +\n\t\t\td.exec.dimensions + ' capacity domains \u00b7 ' +\n\t\t\td.exec.sectors + ' sectors';\n\t\tif (d.dimension_focus) {\n\t\t\tmeta += ' \u00b7 focus: ' + (d.domain_labels[d.dimension_focus] || d.dimension_focus);\n\t\t}\n\t\t$('#syn-cover-meta').text(meta);\n\n\t\tvar topDim = strongestDimension(d);\n\t\tvar weakDim = weakestDimension(d);\n\t\tvar leadEntity = Object.keys(d.entity_composite || {})[0];\n\t\tvar leadComp = leadEntity ? d.entity_composite[leadEntity] : null;\n\t\tvar stripItems = [];\n\t\tif (leadEntity && leadComp != null) stripItems.push({ v: Math.round(leadComp) + '%', l: leadEntity + ' \u2014 highest composite' });\n\t\tif (topDim) stripItems.push({ v: Math.round(topDim.avg) + '%', l: 'Strongest: ' + topDim.label });\n\t\tif (weakDim) stripItems.push({ v: Math.round(weakDim.avg) + '%', l: 'Weakest: ' + weakDim.label });\n\n\t\t$('#syn-cover-strip').html(stripItems.map(function (s) {\n\t\t\treturn '<div class=\"rrat-syn-cover-stat\"><div class=\"v\">' + s.v + '<\/div><div class=\"l\">' + esc(s.l) + '<\/div><\/div>';\n\t\t}).join(''));\n\n\t\tvar entityNoun = d.entity_kind === 'institution' ? 'institution' : (d.entity_kind === 'sector' ? 'sector' : 'country');\n\t\t$('#syn-entity-noun').text(entityNoun);\n\t\t$('#syn-matrix-title').text(d.entity_kind === 'institution' ? 'Institutional Capacity Matrix' : 'Capacity Matrix');\n\t\t$('#syn-profiles-title').text(d.entity_kind === 'institution' ? 'Institutional Profiles' : 'Country Profiles');\n\n\t\t\/\/ Cache visibility badge \u2014 shows the user that subsequent loads of\n\t\t\/\/ this same scope (with unchanged data) don't burn AI cycles.\n\t\tvar $cache = $('#syn-cover-cache');\n\t\tif (d.ai && !d.ai_error && d.ai_generated_at) {\n\t\t\tvar when = formatCacheTimestamp(d.ai_generated_at);\n\t\t\tvar label = d.ai_cached\n\t\t\t\t? '<i class=\"fas fa-bolt\"><\/i> Cached &middot; first generated ' + esc(when) + '. Regenerates only when new RRAT data arrives.'\n\t\t\t\t: '<i class=\"fas fa-magic\"><\/i> Generated just now &middot; future loads of this scope will reuse this result until new data lands.';\n\t\t\t$cache.html(label).show();\n\t\t} else {\n\t\t\t$cache.hide().empty();\n\t\t}\n\t}\n\n\tfunction formatCacheTimestamp(mysqlTs) {\n\t\t\/\/ MySQL DATETIME \"YYYY-MM-DD HH:MM:SS\" \u2014 convert to a relative + absolute label.\n\t\tif (!mysqlTs) return '';\n\t\tvar d = new Date(mysqlTs.replace(' ', 'T') + 'Z');\n\t\tif (isNaN(d.getTime())) return mysqlTs;\n\t\tvar nowMs = Date.now();\n\t\tvar diffSec = Math.max(0, Math.round((nowMs - d.getTime()) \/ 1000));\n\t\tvar rel;\n\t\tif (diffSec < 60)        rel = 'just now';\n\t\telse if (diffSec < 3600) rel = Math.floor(diffSec \/ 60) + ' min ago';\n\t\telse if (diffSec < 86400) rel = Math.floor(diffSec \/ 3600) + ' h ago';\n\t\telse if (diffSec < 604800) rel = Math.floor(diffSec \/ 86400) + ' d ago';\n\t\telse rel = d.toLocaleDateString();\n\t\treturn rel + ' (' + d.toLocaleString() + ')';\n\t}\n\n\tfunction renderStats(d) {\n\t\tvar stats = [\n\t\t\t{ v: d.exec.submissions, l: 'Respondents' },\n\t\t\t{ v: d.exec.institutions, l: 'Institutions' },\n\t\t\t{ v: d.exec.countries, l: 'Countries' },\n\t\t\t{ v: d.exec.dimensions, l: 'Capacity domains' },\n\t\t\t{ v: d.exec.sectors, l: 'Institutional sectors' }\n\t\t];\n\t\tvar html = stats.map(function (s) {\n\t\t\treturn '<div class=\"rrat-syn-stat\"><div class=\"rrat-syn-stat-v\">' + (s.v || 0).toLocaleString() + '<\/div><div class=\"rrat-syn-stat-l\">' + s.l + '<\/div><\/div>';\n\t\t}).join('');\n\t\t$('#syn-stats').html(html);\n\t}\n\n\tfunction renderBackgroundContext(d) {\n\t\tvar t = ai(d).background_context;\n\t\t$('#syn-background-context').text(t || '');\n\t}\n\n\tfunction renderExecSummary(d) {\n\t\tvar t = ai(d).executive_summary;\n\t\t$('#syn-exec-summary').text(t || '');\n\t}\n\n\tfunction renderHeadlineInsight(d) {\n\t\tvar t = ai(d).headline_insight;\n\t\tif (t) { $('#syn-headline-insight').html('<strong>Headline.<\/strong> ' + esc(t)); return; }\n\n\t\tvar pairs = dimensionAverages(d);\n\t\tif (!pairs.length) return;\n\t\tvar top = pairs[0], bot = pairs[pairs.length - 1];\n\t\t$('#syn-headline-insight').html(\n\t\t\t'<strong>The conversion gap.<\/strong> Strongest dimension is <strong>' +\n\t\t\tesc(top.label) + ' (' + Math.round(top.avg) + '%)<\/strong>; weakest is <strong>' + esc(bot.label) +\n\t\t\t' (' + Math.round(bot.avg) + '%)<\/strong>. A <strong>' + Math.round(top.avg - bot.avg) +\n\t\t\t'-percentage-point spread<\/strong> between research activity and the infrastructure that converts it into visible, fundable output.'\n\t\t);\n\t}\n\n\tfunction renderMatrixNarrative(d) {\n\t\t$('#syn-matrix-narrative').text(ai(d).matrix_narrative || '');\n\t}\n\n\tfunction renderComparativeLens(d) {\n\t\tvar t = ai(d).comparative_lens;\n\t\tif (!t) { $('#syn-comparative-sec').hide(); return; }\n\t\t$('#syn-comparative-lens').text(t);\n\t\t$('#syn-comparative-sec').show();\n\t}\n\n\tfunction renderSectorNarrative(d) {\n\t\t$('#syn-sector-narrative').text(ai(d).sector_narrative || '');\n\t\tvar hasData = d.sectors && Object.keys(d.sectors).length > 0;\n\t\t$('#syn-sectorsec').toggle(!!hasData);\n\t}\n\n\tfunction renderIndicatorDeepReads(d) {\n\t\tvar reads = ai(d).indicator_deep_reads;\n\t\tif (!Array.isArray(reads) || reads.length === 0) { $('#syn-deepreads-sec').hide(); return; }\n\t\tvar html = reads.map(function (r) {\n\t\t\treturn '<article class=\"rrat-syn-deepread\">'\n\t\t\t\t+ '<header class=\"rrat-syn-deepread-head\">'\n\t\t\t\t+ '<h3>' + esc(r.finding_label || r.variable_name || 'Indicator') + '<\/h3>'\n\t\t\t\t+ (r.variable_name ? '<code class=\"rrat-syn-deepread-var\">' + esc(r.variable_name) + '<\/code>' : '')\n\t\t\t\t+ '<\/header>'\n\t\t\t\t+ (r.interpretation ? '<p class=\"rrat-syn-deepread-body\">' + esc(r.interpretation) + '<\/p>' : '')\n\t\t\t\t+ (r.what_it_means ? '<p class=\"rrat-syn-deepread-implication\"><strong>What it means.<\/strong> ' + esc(r.what_it_means) + '<\/p>' : '')\n\t\t\t\t+ '<\/article>';\n\t\t}).join('');\n\t\t$('#syn-deepreads').html(html);\n\t\t$('#syn-deepreads-sec').show();\n\t}\n\n\tfunction renderTierNarrative(d) {\n\t\t$('#syn-tier-narrative').text(ai(d).tier_narrative || '');\n\t}\n\n\tfunction renderRiskOpportunity(d) {\n\t\tvar ro = ai(d).risk_opportunity;\n\t\tif (!ro || (!Array.isArray(ro.risks) && !Array.isArray(ro.opportunities))) {\n\t\t\t$('#syn-riskopp-sec').hide();\n\t\t\treturn;\n\t\t}\n\t\tvar risks = (ro.risks || []).map(function (r) {\n\t\t\tvar sev = (r.severity || 'medium').toLowerCase();\n\t\t\treturn '<li class=\"rrat-syn-ro-item rrat-syn-ro-sev-' + esc(sev) + '\">'\n\t\t\t\t+ '<div class=\"rrat-syn-ro-tag\">' + esc(sev) + ' severity<\/div>'\n\t\t\t\t+ '<h4>' + esc(r.title || '') + '<\/h4>'\n\t\t\t\t+ (r.detail ? '<p>' + esc(r.detail) + '<\/p>' : '')\n\t\t\t\t+ '<\/li>';\n\t\t}).join('');\n\t\tvar opps = (ro.opportunities || []).map(function (o) {\n\t\t\tvar lev = (o.leverage || 'medium').toLowerCase();\n\t\t\treturn '<li class=\"rrat-syn-ro-item rrat-syn-ro-lev-' + esc(lev) + '\">'\n\t\t\t\t+ '<div class=\"rrat-syn-ro-tag\">' + esc(lev) + ' leverage<\/div>'\n\t\t\t\t+ '<h4>' + esc(o.title || '') + '<\/h4>'\n\t\t\t\t+ (o.detail ? '<p>' + esc(o.detail) + '<\/p>' : '')\n\t\t\t\t+ '<\/li>';\n\t\t}).join('');\n\t\tvar html = '';\n\t\tif (risks) {\n\t\t\thtml += '<div class=\"rrat-syn-ro-col rrat-syn-ro-col-risks\">'\n\t\t\t\t+ '<h3><i class=\"fas fa-exclamation-triangle\"><\/i> Risks<\/h3>'\n\t\t\t\t+ '<ul>' + risks + '<\/ul><\/div>';\n\t\t}\n\t\tif (opps) {\n\t\t\thtml += '<div class=\"rrat-syn-ro-col rrat-syn-ro-col-opps\">'\n\t\t\t\t+ '<h3><i class=\"fas fa-lightbulb\"><\/i> Opportunities<\/h3>'\n\t\t\t\t+ '<ul>' + opps + '<\/ul><\/div>';\n\t\t}\n\t\t$('#syn-riskopp').html(html);\n\t\t$('#syn-riskopp-sec').show();\n\t}\n\n\tfunction renderRecommendations(d) {\n\t\tvar aiD = ai(d);\n\t\tvar recs = aiD.strategic_recommendations || aiD.recommendations;  \/\/ v2 + v1 fallback\n\t\tif (!recs || !recs.length) { $('#syn-recsec').hide(); return; }\n\n\t\tvar html;\n\t\tif (typeof recs[0] === 'string') {\n\t\t\t\/\/ v1-style array of strings.\n\t\t\thtml = '<ol class=\"rrat-syn-recs-legacy\">'\n\t\t\t\t+ recs.map(function (r) { return '<li>' + esc(r) + '<\/li>'; }).join('')\n\t\t\t\t+ '<\/ol>';\n\t\t} else {\n\t\t\t\/\/ v2-style structured objects.\n\t\t\thtml = recs.map(function (r, i) {\n\t\t\t\treturn '<article class=\"rrat-syn-rec\">'\n\t\t\t\t\t+ '<div class=\"rrat-syn-rec-num\">' + (i + 1) + '<\/div>'\n\t\t\t\t\t+ '<div class=\"rrat-syn-rec-body\">'\n\t\t\t\t\t+ '<h3 class=\"rrat-syn-rec-action\">' + esc(r.action || '') + '<\/h3>'\n\t\t\t\t\t+ (r.rationale ? '<p class=\"rrat-syn-rec-rationale\">' + esc(r.rationale) + '<\/p>' : '')\n\t\t\t\t\t+ '<div class=\"rrat-syn-rec-meta\">'\n\t\t\t\t\t+ (r.owner    ? '<span class=\"rrat-syn-rec-pill\"><i class=\"fas fa-user-shield\"><\/i> '   + esc(r.owner)    + '<\/span>' : '')\n\t\t\t\t\t+ (r.timeline ? '<span class=\"rrat-syn-rec-pill\"><i class=\"far fa-clock\"><\/i> '         + esc(r.timeline) + '<\/span>' : '')\n\t\t\t\t\t+ '<\/div>'\n\t\t\t\t\t+ '<\/div><\/article>';\n\t\t\t}).join('');\n\t\t}\n\t\t$('#syn-recs').html(html);\n\t\t$('#syn-recsec').show();\n\t}\n\n\tfunction renderAudienceBriefs(d) {\n\t\tvar aiD = ai(d);\n\t\tvar anyShown = false;\n\t\tif (aiD.policy_brief) {\n\t\t\t$('#syn-policy-brief').text(aiD.policy_brief);\n\t\t\t$('#syn-brief-policy-card').show();\n\t\t\tanyShown = true;\n\t\t} else {\n\t\t\t$('#syn-brief-policy-card').hide();\n\t\t}\n\t\tif (aiD.funder_brief) {\n\t\t\t$('#syn-funder-brief').text(aiD.funder_brief);\n\t\t\t$('#syn-brief-funder-card').show();\n\t\t\tanyShown = true;\n\t\t} else {\n\t\t\t$('#syn-brief-funder-card').hide();\n\t\t}\n\t\t$('#syn-briefs-sec').toggle(anyShown);\n\t}\n\n\tfunction renderFurtherResearch(d) {\n\t\tvar items = ai(d).further_research;\n\t\tif (!Array.isArray(items) || items.length === 0) { $('#syn-further-sec').hide(); return; }\n\t\t$('#syn-further').html(items.map(function (s) { return '<li>' + esc(s) + '<\/li>'; }).join(''));\n\t\t$('#syn-further-sec').show();\n\t}\n\n\tfunction renderFooter(d) {\n\t\tvar now = new Date();\n\t\t$('#syn-gen-time').text(now.toLocaleString());\n\t\t$('#syn-gen-source').text('Computed from ' + d.exec.submissions.toLocaleString() + ' published submissions.');\n\t\tif (d.ai && !d.ai_error) {\n\t\t\t$('#syn-ai-status').text(d.ai_cached ? ' Narrative cached.' : ' Narrative generated by OpenAI.');\n\t\t} else if (d.ai_error) {\n\t\t\t$('#syn-ai-status').text(' Narrative: deterministic fallback (AI unavailable).');\n\t\t} else {\n\t\t\t$('#syn-ai-status').text('');\n\t\t}\n\t}\n\n\tfunction strongestDimension(d) { var p = dimensionAverages(d); return p.length ? p[0] : null; }\n\tfunction weakestDimension(d)   { var p = dimensionAverages(d); return p.length ? p[p.length - 1] : null; }\n\n\tfunction dimensionAverages(d) {\n\t\tvar avg = {};\n\t\tObject.keys(d.matrix || {}).forEach(function (en) {\n\t\t\tObject.keys(d.matrix[en]).forEach(function (dim) {\n\t\t\t\tif (!avg[dim]) avg[dim] = { s: 0, n: 0 };\n\t\t\t\tavg[dim].s += d.matrix[en][dim];\n\t\t\t\tavg[dim].n++;\n\t\t\t});\n\t\t});\n\t\treturn Object.keys(avg).map(function (dim) {\n\t\t\treturn { dim: dim, label: d.domain_labels[dim] || dim, avg: avg[dim].s \/ avg[dim].n };\n\t\t}).sort(function (a, b) { return b.avg - a.avg; });\n\t}\n\n\tfunction renderMatrix(d) {\n\t\tvar entities = Object.keys(d.entity_composite || {});\n\t\tvar dims = orderedDimensions(d);\n\t\tvar showGapCol = entities.length > 1;\n\n\t\tvar entityHeader = d.entity_kind === 'institution' ? 'Institution' : (d.entity_kind === 'sector' ? 'Sector' : 'Country');\n\t\tvar html = '<table class=\"rrat-syn-table\"><thead><tr><th>' + entityHeader + '<\/th>';\n\t\tdims.forEach(function (dim) { html += '<th>' + esc(d.domain_labels[dim] || dim) + '<\/th>'; });\n\t\thtml += '<th class=\"composite\">Composite<\/th>';\n\t\t\/\/ Per-entity gap (spread across dims) \u2014 surfaces \"uneven profile\" entities.\n\t\thtml += '<th class=\"rrat-syn-gap-col\" title=\"Spread between this entity\\'s strongest and weakest dimension\">Profile gap<\/th>';\n\t\thtml += '<\/tr><\/thead><tbody>';\n\n\t\tentities.forEach(function (en) {\n\t\t\thtml += '<tr><th class=\"country-cell\">' + esc(en) + '<\/th>';\n\t\t\tvar rowVals = [];\n\t\t\tdims.forEach(function (dim) {\n\t\t\t\tvar pct = (d.matrix[en] || {})[dim];\n\t\t\t\tif (pct != null) rowVals.push(pct);\n\t\t\t\thtml += cellHeat(pct);\n\t\t\t});\n\t\t\tvar comp = d.entity_composite[en];\n\t\t\thtml += '<td class=\"composite ' + heatClass(comp) + '\"><strong>' + (comp != null ? Math.round(comp) + '%' : '\u2014') + '<\/strong><\/td>';\n\t\t\thtml += gapCell(rowVals);\n\t\t\thtml += '<\/tr>';\n\t\t});\n\n\t\tif (showGapCol) {\n\t\t\t\/\/ Cross-entity gap per dimension \u2014 \"where the continent disagrees\".\n\t\t\thtml += '<tr class=\"mean-row\"><th>Scope mean<\/th>';\n\t\t\tvar dimMeans = [];\n\t\t\tdims.forEach(function (dim) {\n\t\t\t\tvar sum = 0, n = 0;\n\t\t\t\tentities.forEach(function (en) {\n\t\t\t\t\tvar v = (d.matrix[en] || {})[dim];\n\t\t\t\t\tif (v != null) { sum += v; n++; }\n\t\t\t\t});\n\t\t\t\tvar m = n ? sum \/ n : null;\n\t\t\t\tif (m != null) dimMeans.push(m);\n\t\t\t\thtml += cellHeat(m);\n\t\t\t});\n\t\t\tvar allComp = entities.reduce(function (s, en) { return s + (d.entity_composite[en] || 0); }, 0);\n\t\t\thtml += '<td class=\"composite ' + heatClass(allComp \/ entities.length) + '\"><strong>' + Math.round(allComp \/ entities.length) + '%<\/strong><\/td>';\n\t\t\thtml += gapCell(dimMeans);\n\t\t\thtml += '<\/tr>';\n\n\t\t\thtml += '<tr class=\"mean-row rrat-syn-gap-row\"><th title=\"Spread (max \u2212 min) across entities for each dimension\">Gap across ' + (d.entity_kind === 'institution' ? 'institutions' : (d.entity_kind === 'sector' ? 'sectors' : 'countries')) + '<\/th>';\n\t\t\tdims.forEach(function (dim) {\n\t\t\t\tvar vals = [];\n\t\t\t\tentities.forEach(function (en) {\n\t\t\t\t\tvar v = (d.matrix[en] || {})[dim];\n\t\t\t\t\tif (v != null) vals.push(v);\n\t\t\t\t});\n\t\t\t\thtml += gapCellInline(vals);\n\t\t\t});\n\t\t\thtml += '<td class=\"composite na\">\u2014<\/td><td class=\"na\">\u2014<\/td><\/tr>';\n\t\t}\n\n\t\tif (d.entity_kind === 'institution' && d.baselines) {\n\t\t\t['national', 'continental'].forEach(function (key) {\n\t\t\t\tvar row = d.baselines[key];\n\t\t\t\tif (!row || !Object.keys(row).length) return;\n\t\t\t\thtml += '<tr class=\"mean-row\"><th>' + (key === 'national' ? 'National avg' : 'Continental avg') + '<\/th>';\n\t\t\t\tvar sum = 0, n = 0;\n\t\t\t\tvar rowVals = [];\n\t\t\t\tdims.forEach(function (dim) {\n\t\t\t\t\tvar v = row[dim];\n\t\t\t\t\thtml += cellHeat(v != null ? v : null);\n\t\t\t\t\tif (v != null) { sum += v; n++; rowVals.push(v); }\n\t\t\t\t});\n\t\t\t\thtml += '<td class=\"composite ' + heatClass(n ? sum \/ n : null) + '\"><strong>' + (n ? Math.round(sum \/ n) + '%' : '\u2014') + '<\/strong><\/td>';\n\t\t\t\thtml += gapCell(rowVals);\n\t\t\t\thtml += '<\/tr>';\n\t\t\t});\n\t\t}\n\n\t\thtml += '<\/tbody><\/table>';\n\t\t$('#syn-matrix').html(html);\n\t}\n\n\t\/\/ Render a Gap cell from an array of percentages: max \u2212 min, with a heat\n\t\/\/ class that flags wide spreads. Empty array \u2192 '\u2014'.\n\tfunction gapCell(vals) {\n\t\tif (!vals || vals.length < 2) return '<td class=\"rrat-syn-gap-cell na\">\u2014<\/td>';\n\t\tvar spread = Math.max.apply(null, vals) - Math.min.apply(null, vals);\n\t\treturn '<td class=\"rrat-syn-gap-cell ' + gapHeatClass(spread) + '\"><strong>' + Math.round(spread) + 'pp<\/strong><\/td>';\n\t}\n\tfunction gapCellInline(vals) {\n\t\tif (!vals || vals.length < 2) return '<td class=\"na\">\u2014<\/td>';\n\t\tvar spread = Math.max.apply(null, vals) - Math.min.apply(null, vals);\n\t\treturn '<td class=\"rrat-syn-gap-cell ' + gapHeatClass(spread) + '\"><strong>' + Math.round(spread) + 'pp<\/strong><\/td>';\n\t}\n\tfunction gapHeatClass(spread) {\n\t\t\/\/ Smaller gap = more uniform (good); larger gap = more uneven (notable).\n\t\tif (spread == null) return 'na';\n\t\tif (spread < 15) return 'gap-tight';\n\t\tif (spread < 30) return 'gap-mid';\n\t\treturn 'gap-wide';\n\t}\n\n\tfunction renderRegional(d) {\n\t\tvar regions = d.regions || {};\n\t\tvar regionKeys = Object.keys(regions);\n\t\t\/\/ Only render when scope spans \u22652 regions \u2014 for single-country or\n\t\t\/\/ single-region scopes the section adds no signal.\n\t\tif (regionKeys.length < 2) { $('#syn-regional-sec').hide(); return; }\n\n\t\t\/\/ Order regions in the conventional north-to-south arrangement when\n\t\t\/\/ possible (matches the dictionary). Any not-known just appends.\n\t\tvar regionOrder = ['Northern Africa', 'Western Africa', 'Central Africa', 'Eastern Africa', 'Southern Africa'];\n\t\tregionKeys.sort(function (a, b) {\n\t\t\tvar ai = regionOrder.indexOf(a), bi = regionOrder.indexOf(b);\n\t\t\tif (ai === -1 && bi === -1) return a.localeCompare(b);\n\t\t\tif (ai === -1) return 1;\n\t\t\tif (bi === -1) return -1;\n\t\t\treturn ai - bi;\n\t\t});\n\n\t\tvar dims = orderedDimensions(d);\n\n\t\tvar html = '<table class=\"rrat-syn-table\"><thead><tr><th>Region<\/th><th>Countries<\/th>';\n\t\tdims.forEach(function (dim) { html += '<th>' + esc(d.domain_labels[dim] || dim) + '<\/th>'; });\n\t\thtml += '<th class=\"composite\">Region avg<\/th>';\n\t\thtml += '<th class=\"rrat-syn-gap-col\" title=\"Spread between this region\\'s strongest and weakest domain\">Domain spread<\/th>';\n\t\thtml += '<\/tr><\/thead><tbody>';\n\n\t\tregionKeys.forEach(function (rg) {\n\t\t\tvar data = regions[rg];\n\t\t\tvar rowVals = [];\n\t\t\thtml += '<tr><th class=\"country-cell\">' + esc(rg) + '<\/th>';\n\t\t\thtml += '<td><em>' + (data.n_countries || 0) + ' (' + (data.n_submissions || 0) + ' sub' + (data.n_submissions === 1 ? '' : 's') + ')<\/em><\/td>';\n\t\t\tdims.forEach(function (dim) {\n\t\t\t\tvar pct = (data.dimensions || {})[dim];\n\t\t\t\tif (pct != null) rowVals.push(pct);\n\t\t\t\thtml += cellHeat(pct);\n\t\t\t});\n\t\t\tvar avg = rowVals.length ? rowVals.reduce(function (s, x) { return s + x; }, 0) \/ rowVals.length : null;\n\t\t\thtml += '<td class=\"composite ' + heatClass(avg) + '\"><strong>' + (avg != null ? Math.round(avg) + '%' : '\u2014') + '<\/strong><\/td>';\n\t\t\thtml += gapCell(rowVals);\n\t\t\thtml += '<\/tr>';\n\t\t});\n\n\t\t\/\/ Cross-region gap row \u2014 for each dimension, max(region) \u2212 min(region).\n\t\t\/\/ This is the headline \"where is the continent most uneven?\" view.\n\t\thtml += '<tr class=\"mean-row rrat-syn-gap-row\"><th>Inter-regional gap<\/th><td class=\"na\">\u2014<\/td>';\n\t\tdims.forEach(function (dim) {\n\t\t\tvar vals = [];\n\t\t\tregionKeys.forEach(function (rg) {\n\t\t\t\tvar v = (regions[rg].dimensions || {})[dim];\n\t\t\t\tif (v != null) vals.push(v);\n\t\t\t});\n\t\t\thtml += gapCellInline(vals);\n\t\t});\n\t\thtml += '<td class=\"composite na\">\u2014<\/td><td class=\"na\">\u2014<\/td><\/tr>';\n\n\t\thtml += '<\/tbody><\/table>';\n\t\t$('#syn-regional').html(html);\n\t\t\/\/ Optional AI commentary slot \u2014 the prompt may emit `regional_narrative` later.\n\t\t$('#syn-regional-narrative').text((ai(d).regional_narrative) || '');\n\t\t$('#syn-regional-sec').show();\n\t}\n\n\tfunction renderSectors(d) {\n\t\tvar sectorOrder = ['University', 'Research Institute', 'Other'];\n\t\tvar dims = orderedDimensions(d);\n\t\tvar html = '<table class=\"rrat-syn-table\"><thead><tr><th>Sector<\/th><th>n<\/th>';\n\t\tdims.forEach(function (dim) { html += '<th>' + esc(d.domain_labels[dim] || dim) + '<\/th>'; });\n\t\thtml += '<\/tr><\/thead><tbody>';\n\t\tsectorOrder.forEach(function (sec) {\n\t\t\tvar row = d.sectors[sec];\n\t\t\tif (!row) return;\n\t\t\tvar anyDim = Object.keys(row)[0];\n\t\t\tvar n = anyDim ? row[anyDim].n : 0;\n\t\t\thtml += '<tr><th>' + esc(sec) + '<\/th><td><em>' + n + '<\/em><\/td>';\n\t\t\tdims.forEach(function (dim) { html += cellHeat(row[dim] ? row[dim].pct : null); });\n\t\t\thtml += '<\/tr>';\n\t\t});\n\t\thtml += '<\/tbody><\/table>';\n\t\t$('#syn-sectors').html(html);\n\t}\n\n\tfunction renderProfiles(d) {\n\t\tvar profiles = d.entity_profiles || [];\n\t\tvar aiProfiles = ai(d).entity_profiles || {};\n\t\tvar html = '';\n\t\tprofiles.forEach(function (cp) {\n\t\t\tvar commentary = aiProfiles[cp.entity] || '';\n\t\t\thtml += '<div class=\"rrat-syn-profile\">';\n\t\t\thtml += '<div class=\"rrat-syn-profile-head\">';\n\t\t\thtml += '<div><h3>' + esc(cp.entity) + '<\/h3><div class=\"rrat-syn-profile-meta\">' +\n\t\t\t\t(cp.kind === 'institution' ? 'institution' : cp.n + ' submission' + (cp.n === 1 ? '' : 's')) +\n\t\t\t\t' \u00b7 composite <strong>' + Math.round(cp.composite) + '%<\/strong><\/div><\/div>';\n\t\t\thtml += '<div class=\"rrat-syn-rcmm-badge ' + heatClass(cp.composite) + '\">' + Math.round(cp.composite) + '<\/div>';\n\t\t\thtml += '<\/div>';\n\t\t\tif (commentary) {\n\t\t\t\thtml += '<div class=\"rrat-syn-profile-commentary\">' + esc(commentary) + '<\/div>';\n\t\t\t}\n\t\t\thtml += '<div class=\"rrat-syn-profile-cols\">';\n\t\t\thtml += '<div><h4>Strengths<\/h4><ul>';\n\t\t\tcp.strengths.forEach(function (s) { html += '<li><strong>' + Math.round(s.pct) + '%<\/strong> \u2014 ' + esc(s.label) + '<\/li>'; });\n\t\t\thtml += '<\/ul><\/div>';\n\t\t\thtml += '<div><h4>Highest-leverage gaps<\/h4><ul>';\n\t\t\tcp.gaps.forEach(function (g) { html += '<li><strong>' + Math.round(g.pct) + '%<\/strong> \u2014 ' + esc(g.label) + '<\/li>'; });\n\t\t\thtml += '<\/ul><\/div>';\n\t\t\thtml += '<\/div><\/div>';\n\t\t});\n\t\t$('#syn-profiles').html(html);\n\t}\n\n\tfunction renderTiers(d) {\n\t\tvar aiDescs = ai(d).tier_descriptions || {};\n\t\tvar html = '';\n\t\tObject.keys(d.tiers).forEach(function (key, i) {\n\t\t\tvar tier = d.tiers[key];\n\t\t\thtml += '<div class=\"rrat-syn-tier tier-' + (i + 1) + '\">';\n\t\t\thtml += '<div class=\"rrat-syn-tier-head\"><h3>Tier ' + (i + 1) + ' \u2014 ' + esc(tier.label) + '<\/h3>';\n\t\t\thtml += '<div class=\"rrat-syn-tier-count\">' + tier.count + ' institutions<\/div><\/div>';\n\t\t\thtml += '<div class=\"rrat-syn-tier-criteria\">' + esc(tier.criteria) + '<\/div>';\n\t\t\tif (aiDescs[key]) html += '<div class=\"rrat-syn-tier-desc\">' + esc(aiDescs[key]) + '<\/div>';\n\t\t\tif (tier.institutions.length) {\n\t\t\t\thtml += '<table class=\"rrat-syn-tier-table\"><thead><tr><th>Institution<\/th><th>Country<\/th><th>Sector<\/th><th>Composite<\/th><th>Ethics<\/th><th>Grants<\/th><\/tr><\/thead><tbody>';\n\t\t\t\ttier.institutions.forEach(function (r) {\n\t\t\t\t\thtml += '<tr>';\n\t\t\t\t\thtml += '<td>' + esc(r.institute_name || '\u2014') + '<\/td>';\n\t\t\t\t\thtml += '<td>' + esc(r.country_name || '\u2014') + '<\/td>';\n\t\t\t\t\thtml += '<td>' + esc(r.institute_type || '\u2014') + '<\/td>';\n\t\t\t\t\thtml += '<td><strong>' + (r.composite != null ? Math.round(r.composite) : '\u2014') + '%<\/strong><\/td>';\n\t\t\t\t\thtml += '<td>' + (r.ethics_pct != null ? Math.round(r.ethics_pct) + '%' : '\u2014') + '<\/td>';\n\t\t\t\t\thtml += '<td>' + (r.grants_pct != null ? Math.round(r.grants_pct) + '%' : '\u2014') + '<\/td>';\n\t\t\t\t\thtml += '<\/tr>';\n\t\t\t\t});\n\t\t\t\thtml += '<\/tbody><\/table>';\n\t\t\t\tif (tier.count > tier.institutions.length) {\n\t\t\t\t\thtml += '<div class=\"rrat-syn-tier-more\">+' + (tier.count - tier.institutions.length) + ' more not shown<\/div>';\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\thtml += '<div class=\"rrat-syn-tier-empty\">No institutions in this tier within the current scope.<\/div>';\n\t\t\t}\n\t\t\thtml += '<\/div>';\n\t\t});\n\t\t$('#syn-tiers').html(html);\n\t}\n\n\tfunction renderAnnex(d) {\n\t\tvar aiAssess = ai(d).annex_assessments || {};\n\t\tvar html = '';\n\t\tvar domainKeys = orderedDimensions(d);\n\t\tdomainKeys.forEach(function (dom) {\n\t\t\tvar indicators = (d.annex || {})[dom];\n\t\t\tif (!indicators || !indicators.length) return;\n\n\t\t\thtml += '<div class=\"rrat-syn-annex-block page-break-inside-avoid\"><h3>' + esc(d.domain_labels[dom] || dom) + '<\/h3>';\n\t\t\t\/\/ Wrap in table-wrap so wide annex tables scroll horizontally rather\n\t\t\t\/\/ than overflowing the page width. The CSS adds a fade + \"Scroll \u2192\"\n\t\t\t\/\/ affordance when the wrap detects overflow at layout time.\n\t\t\thtml += '<div class=\"rrat-syn-table-wrap\">';\n\t\t\thtml += '<table class=\"rrat-syn-table rrat-syn-annex-table\"><thead><tr>';\n\t\t\thtml += '<th>Indicator<\/th>';\n\t\t\t(d.countries || []).forEach(function (c) { html += '<th>' + esc(c) + '<\/th>'; });\n\t\t\thtml += '<th>Overall<\/th>';\n\t\t\t\/\/ Gap column \u2014 max \u2212 min across the in-scope countries, in\n\t\t\t\/\/ percentage-points. Hidden when scope has <2 countries (would\n\t\t\t\/\/ always read 0pp, providing no signal).\n\t\t\tvar showAnnexGap = (d.countries || []).length > 1;\n\t\t\tif (showAnnexGap) {\n\t\t\t\thtml += '<th class=\"rrat-syn-gap-col\" title=\"Spread between the country with the highest \\'Yes\\' share and the lowest, in percentage points\">Gap<\/th>';\n\t\t\t}\n\t\t\thtml += '<th class=\"rrat-syn-assessment-col\">Assessment<\/th><\/tr><\/thead><tbody>';\n\n\t\t\tindicators.forEach(function (ind) {\n\t\t\t\tvar assessment = aiAssess[ind.variable_name] || ind.assessment || '';\n\t\t\t\tvar vals = [];\n\t\t\t\thtml += '<tr><td class=\"rrat-syn-indicator-cell\" title=\"' + esc(ind.label) + '\">' + esc(ind.finding_label) + '<\/td>';\n\t\t\t\t(d.countries || []).forEach(function (c) {\n\t\t\t\t\tvar bc = ind.by_country[c];\n\t\t\t\t\tif (bc && bc.pct != null) vals.push(bc.pct);\n\t\t\t\t\thtml += bc ? cellPct(bc.pct) : '<td class=\"na\">\u2014<\/td>';\n\t\t\t\t});\n\t\t\t\thtml += '<td class=\"overall\"><strong>' + (ind.overall_pct != null ? ind.overall_pct + '%' : '\u2014') + '<\/strong><\/td>';\n\t\t\t\tif (showAnnexGap) html += gapCellInline(vals);\n\t\t\t\thtml += '<td class=\"rrat-syn-assessment\">' + esc(assessment) + '<\/td><\/tr>';\n\t\t\t});\n\n\t\t\thtml += '<\/tbody><\/table><\/div><\/div>';\n\t\t});\n\t\t$('#syn-annex').html(html);\n\t}\n\n\tfunction orderedDimensions(d) {\n\t\tvar avg = {};\n\t\tObject.keys(d.matrix || {}).forEach(function (en) {\n\t\t\tObject.keys(d.matrix[en]).forEach(function (dim) {\n\t\t\t\tif (!avg[dim]) avg[dim] = { s: 0, n: 0 };\n\t\t\t\tavg[dim].s += d.matrix[en][dim];\n\t\t\t\tavg[dim].n++;\n\t\t\t});\n\t\t});\n\t\treturn Object.keys(avg).sort(function (a, b) { return (avg[b].s \/ avg[b].n) - (avg[a].s \/ avg[a].n); });\n\t}\n\n\tfunction heatClass(pct) {\n\t\tif (pct == null) return 'na';\n\t\tif (pct >= 70) return 'ok';\n\t\tif (pct >= 40) return 'mid';\n\t\treturn 'low';\n\t}\n\tfunction cellHeat(pct) {\n\t\tif (pct == null) return '<td class=\"na\">\u2014<\/td>';\n\t\treturn '<td class=\"' + heatClass(pct) + '\">' + Math.round(pct) + '%<\/td>';\n\t}\n\tfunction cellPct(pct) {\n\t\tif (pct == null) return '<td class=\"na\">\u2014<\/td>';\n\t\tvar cls = pct >= 70 ? 'ok' : (pct >= 40 ? 'mid' : 'low');\n\t\treturn '<td class=\"' + cls + '\">' + pct + '%<\/td>';\n\t}\n\tfunction esc(s) {\n\t\tif (s == null) return '';\n\t\treturn $('<div>').text(String(s)).html();\n\t}\n\n})(jQuery);\n<\/script>\n\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n","protected":false},"excerpt":{"rendered":"","protected":false},"author":1848,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"_acf_changed":false,"_bbp_topic_count":0,"_bbp_reply_count":0,"_bbp_total_topic_count":0,"_bbp_total_reply_count":0,"_bbp_voice_count":0,"_bbp_anonymous_reply_count":0,"_bbp_topic_count_hidden":0,"_bbp_reply_count_hidden":0,"_bbp_forum_subforum_count":0,"footnotes":""},"class_list":["post-13580","page","type-page","status-publish","hentry"],"acf":[],"_links":{"self":[{"href":"https:\/\/africaresearchconnects.com\/fr\/wp-json\/wp\/v2\/pages\/13580","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/africaresearchconnects.com\/fr\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/africaresearchconnects.com\/fr\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/africaresearchconnects.com\/fr\/wp-json\/wp\/v2\/users\/1848"}],"replies":[{"embeddable":true,"href":"https:\/\/africaresearchconnects.com\/fr\/wp-json\/wp\/v2\/comments?post=13580"}],"version-history":[{"count":1,"href":"https:\/\/africaresearchconnects.com\/fr\/wp-json\/wp\/v2\/pages\/13580\/revisions"}],"predecessor-version":[{"id":13581,"href":"https:\/\/africaresearchconnects.com\/fr\/wp-json\/wp\/v2\/pages\/13580\/revisions\/13581"}],"wp:attachment":[{"href":"https:\/\/africaresearchconnects.com\/fr\/wp-json\/wp\/v2\/media?parent=13580"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}