{"id":14338,"date":"2026-09-26T17:51:14","date_gmt":"2026-09-26T15:51:14","guid":{"rendered":"https:\/\/geopard.tech\/?page_id=14338"},"modified":"2026-10-12T15:54:37","modified_gmt":"2026-10-12T13:54:37","slug":"%d1%8d%d0%bb%d1%8c-%d0%bd%d0%b8%d0%bd%d1%8c%d0%be-%d3%99%d1%81%d0%b5%d1%80%d1%96","status":"publish","type":"page","link":"https:\/\/geopard.tech\/kz\/el-nino-impact\/","title":{"rendered":"\u042d\u043b\u044c-\u041d\u0438\u043d\u044c\u043e \u0436\u04d9\u043d\u0435 \u043c\u0443\u0441\u0441\u043e\u043d \u04d9\u0441\u0435\u0440\u0456\u043d\u0456\u04a3 \u0441\u0438\u043c\u0443\u043b\u044f\u0442\u043e\u0440\u044b"},"content":{"rendered":"\n<div class=\"gp-eni\" id=\"gp-eni\" data-theme=\"light\" data-phase=\"elnino\">\n<style>\n\/* ===== theme chrome (rule 7). Header + footer kept; only the duplicate WP page\n   title (a bare h1 in #simple_page > .container) is hidden. Same full-page\n   takeover as \/global-crop-calendar\/. ===== *\/\n#simple_page > .container > h1{display:none !important}\n#simple_page > .container{width:auto !important;max-width:none !important;margin:0 !important;padding:0 !important}\n#simple_page{padding:0 !important}\n\n\/* Roboto at first paint and at every weight (rule 24), from fonts.wp.com. *\/\n@font-face{font-family:\"Roboto\";font-style:normal;font-weight:100 900;font-display:swap;src:url(https:\/\/fonts.wp.com\/s\/roboto\/v51\/KFO7CnqEu92Fr1ME7kSn66aGLdTylUAMa3KUBHMdazTgWw.woff2) format(\"woff2\");unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF}\n@font-face{font-family:\"Roboto\";font-style:normal;font-weight:100 900;font-display:swap;src:url(https:\/\/fonts.wp.com\/s\/roboto\/v51\/KFO7CnqEu92Fr1ME7kSn66aGLdTylUAMa3yUBHMdazQ.woff2) format(\"woff2\");unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}\n\n\/* ===== ENI:CSS START: every rule scoped under .gp-eni (rule 5), light only (rule 11) ===== *\/\n.gp-eni{\n  --f:\"Roboto\",-apple-system,\"Segoe UI\",Helvetica,Arial,sans-serif;\n  --ink:#212121; --dim:#4c6066; --dim2:#708086;\n  --accent:#145328; --accent-mid:#15701e; --accent-soft:#1b7a2a; --orange:#f76a0c;\n  --bg:#fafbf4; --panel:#ffffff; --panel2:#f4f7ea; --line:#e3e7da; --line2:#d6e2c5;\n  --r-panel:8px; --r-card:6px; --r-ctl:4px; --r-bar:2px;\n  \/* map *\/\n  --sea:#f2f6ea; --grat:#dde5d2; --land0:#e0e7d6; --land0s:#fafbf5;\n  \/* rainfall anomaly ramp, drier to wetter, seven steps (semantic, this tool only) *\/\n  --dry3:#8a5a2b; --dry2:#b98a55; --dry1:#dfc9a4; --wet1:#aac8d8; --wet2:#5f9fbe; --wet3:#2c6d96;\n  color:var(--ink);background:var(--bg);font-family:var(--f);\n  font-size:16px;line-height:1.55;font-variant-numeric:tabular-nums;position:relative;overflow-x:clip;\n}\n.gp-eni *{box-sizing:border-box}\n.gp-eni h1,.gp-eni h2,.gp-eni h3,.gp-eni h4{font-family:var(--f);font-weight:700;line-height:1.16;margin:0;color:var(--ink)}\n.gp-eni p{margin:0}\n.gp-eni a{color:var(--accent-mid)}\n.gp-eni section{position:relative;max-width:1480px;margin:0 auto;padding:36px 28px}\n.gp-eni .eni-prose{max-width:1000px}\n.gp-eni .eni-h2{font-size:clamp(1.5rem,2.4vw,2.1rem);font-weight:700;text-wrap:balance}\n.gp-eni .eni-lede{color:var(--dim);font-size:1.05rem;line-height:1.65}\n\n\/* hero: a div, never a bare header tag (rule 5b). Centred (rule 14). *\/\n.gp-eni .eni-hero{text-align:center;padding:30px 28px 0;max-width:1480px;margin:0 auto}\n.gp-eni .eni-hero h1{font-size:clamp(2rem,4vw,3.1rem);letter-spacing:-.015em;margin:0 auto;max-width:820px;text-wrap:balance}\n.gp-eni .eni-hero-sub{font-size:clamp(1.3rem,2.4vw,1.85rem);font-weight:700;color:var(--accent-mid);margin:6px auto 0;max-width:820px;text-wrap:balance}\n.gp-eni .eni-hero .eni-lede{max-width:780px;margin:14px auto 0}\n\n\/* status card + controls *\/\n.gp-eni .eni-tool{padding-top:22px}\n.gp-eni .eni-state{display:flex;flex-wrap:wrap;align-items:center;gap:10px 22px;background:var(--panel);border:1px solid var(--line2);border-radius:var(--r-panel);padding:14px 18px}\n.gp-eni .eni-state b{font-weight:700}\n.gp-eni .eni-state .eni-state-k{font-size:.78rem;font-weight:700;letter-spacing:.07em;text-transform:uppercase;color:var(--dim2)}\n.gp-eni .eni-state .eni-state-v{font-size:1.02rem}\n.gp-eni .eni-state .eni-state-src{color:var(--dim2);font-size:.86rem;margin-left:auto}\n.gp-eni .eni-state .eni-state-stale{flex:1 1 100%;color:var(--dim2);font-size:.86rem}\n.gp-eni .eni-state .eni-state-obs{flex:1 1 100%;color:var(--dim2);font-size:.8rem}\n.gp-eni .eni-state .eni-state-row{flex:1 1 100%;border-top:1px solid var(--line);padding-top:10px}\n.gp-eni .eni-state .eni-state-ol{display:inline-block;margin-right:18px;font-size:.95rem}\n.gp-eni .eni-controls{margin-top:12px;background:var(--panel);border:1px solid var(--line);border-radius:var(--r-panel);padding:14px 18px}\n.gp-eni .eni-ctl{display:flex;flex-wrap:wrap;align-items:center;gap:10px 18px}\n.gp-eni .eni-ctl + .eni-ctl{margin-top:12px;padding-top:12px;border-top:1px solid var(--line)}\n.gp-eni .eni-ctl-lab{flex:0 0 auto;font-size:.78rem;font-weight:700;letter-spacing:.07em;text-transform:uppercase;color:var(--dim2);width:84px}\n.gp-eni .eni-chips{display:flex;flex-wrap:wrap;gap:6px;flex:1 1 auto;min-width:0}\n.gp-eni .eni-chip{display:inline-flex;align-items:center;gap:7px;min-height:38px;padding:0 13px;border:1px solid var(--line2);background:var(--panel);color:var(--ink);\n  font-family:var(--f);font-size:.92rem;font-weight:400;border-radius:var(--r-ctl);cursor:pointer;transition:border-color .12s,background .12s,color .12s}\n.gp-eni .eni-chip:hover{border-color:var(--accent-soft);color:var(--accent-mid)}\n.gp-eni .eni-chip[aria-pressed=\"true\"]{background:var(--accent);border-color:var(--accent);color:#fff}\n.gp-eni .eni-chip small{color:var(--dim2);font-size:.82rem}\n.gp-eni .eni-chip[aria-pressed=\"true\"] small{color:rgba(255,255,255,.8)}\n.gp-eni select.eni-select{min-height:38px;padding:0 10px;border:1px solid var(--line2);border-radius:var(--r-ctl);background:var(--panel);color:var(--ink);font-family:var(--f);font-size:.95rem;max-width:100%}\n\n\/* stage: map beside the region panel *\/\n.gp-eni .eni-stage{display:grid;grid-template-columns:minmax(0,1.5fr) minmax(340px,1fr);gap:18px;align-items:start;padding-top:0}\n.gp-eni .eni-pane{background:var(--panel);border:1px solid var(--line);border-radius:var(--r-panel);min-width:0}\n.gp-eni .eni-panehead{display:flex;align-items:baseline;justify-content:space-between;gap:10px;flex-wrap:wrap;padding:14px 18px;border-bottom:1px solid var(--line)}\n.gp-eni .eni-panehead h2{font-size:1.06rem}\n.gp-eni .eni-panehead p{font-size:.86rem;color:var(--dim2)}\n.gp-eni .eni-mapwrap{position:relative;padding:8px 10px 10px}\n.gp-eni .eni-map{display:block;width:100%;height:auto;aspect-ratio:2.2165;touch-action:manipulation}\n.gp-eni .eni-map .sea{fill:var(--sea);stroke:var(--line2);stroke-width:1;vector-effect:non-scaling-stroke}\n.gp-eni .eni-map .grat{fill:none;stroke:var(--grat);stroke-width:.7;vector-effect:non-scaling-stroke}\n.gp-eni .eni-map path.c{fill:var(--land0);stroke:var(--land0s);stroke-width:.6;vector-effect:non-scaling-stroke}\n\/* two-pass region draw: path.rg-edge (below, stroke only, pointer-events:none)\n   carries every region's outline; path.rg (above, same ring data, fill only)\n   covers the inner half of every INTERNAL admin border the edge pass draws,\n   leaving only the region's true outer perimeter haloed -- so a 24-state\n   Brazil or a 7-country Sahel reads as one area, not a scatter of borders.\n   The edge pass can't receive hover\/focus itself (pointer-events:none), so\n   is-hover\/is-focus are mirrored onto it from the fill pass by JS (buildMap \/\n   the mouseover\/focusin handlers below); is-sel and low are model state,\n   mirrored the same way from paintMap. *\/\n.gp-eni .eni-map path.rg-edge{fill:none;stroke:#fff;stroke-width:1.1;vector-effect:non-scaling-stroke;pointer-events:none;transition:stroke .18s}\n.gp-eni .eni-map path.rg-edge.low{stroke-dasharray:3 2}\n\/* no reliable ENSO signal (phase 2, task 3): a SOLID, distinctly-coloured\n   outline -- never the low-confidence dashed white line above, which reads as\n   \"a real anomaly we are just less sure of\" rather than \"no anomaly exists to\n   read here\". Colour reused from the existing --dim2 token (rule 24: no new\n   hex), same one the low-confidence badge already uses. *\/\n.gp-eni .eni-map path.rg-edge.nosig{stroke:var(--dim2);stroke-width:1.4;stroke-dasharray:none}\n.gp-eni .eni-map path.rg-edge.is-hover{stroke:var(--ink)}\n.gp-eni .eni-map path.rg-edge.fc{stroke:var(--ink);stroke-width:2}\n.gp-eni .eni-map path.rg-edge.is-sel{stroke:var(--ink);stroke-width:2}\n.gp-eni .eni-map path.rg-edge.is-focus{stroke:var(--ink);stroke-width:3;stroke-dasharray:none}\n\/* hairline stroke in the fill's OWN colour (set from JS, paintMap, so it can\n   never be a fixed CSS colour): adjacent admin1 units are simplified\n   independently by build-regions.js, so a sub-pixel sliver of the basemap\n   can show through between two units of the SAME region (seen on Brazil\n   South and Australia's multi-state fills). A same-colour hairline along\n   every sub-path closes that gap without drawing a visible border -- the\n   two-pass rg-edge\/rg split above still owns all VISIBLE outlines. *\/\n.gp-eni .eni-map path.rg{fill-opacity:.88;cursor:pointer;transition:fill .18s;stroke-width:.6;vector-effect:non-scaling-stroke}\n.gp-eni .eni-map path.rg.low{fill-opacity:.55}\n\/* no-signal fill is a hatch pattern (defined once in <defs>, see buildMap),\n   not a rainfall-ramp colour -- fill-opacity stays at 1 so the pattern itself\n   (already a mix of --land0 and --dim2) reads clearly instead of washing out. *\/\n.gp-eni .eni-map path.rg.nosig{fill-opacity:1}\n.gp-eni .eni-map path.rg:focus{outline:none}\n.gp-eni .eni-map text.lb{font-family:var(--f);font-size:9px;font-weight:700;fill:var(--ink);pointer-events:none;paint-order:stroke;stroke:#fff;stroke-width:2.5px;stroke-linejoin:round}\n.gp-eni .eni-legend{display:flex;flex-wrap:wrap;align-items:center;gap:8px 14px;padding:10px 18px 14px;font-size:.84rem;color:var(--dim)}\n.gp-eni .eni-legend i{display:inline-block;width:14px;height:10px;border-radius:var(--r-bar);vertical-align:-1px;margin-right:5px}\n.gp-eni .eni-legend .low{background:var(--wet1);opacity:.55;border:1px dashed var(--ink)}\n\/* legend key for a no reliable signal region (phase 2, task 3): a diagonal\n   hatch (repeating-linear-gradient, since this swatch is an HTML <i>, not the\n   SVG the map itself uses) echoes the map's own hatch fill, distinct from the\n   low-confidence swatch above (solid tint, dashed border). *\/\n.gp-eni .eni-legend .fc{background:var(--land0);border:2px solid var(--ink)}\n.gp-eni .eni-legend .nosig{background:repeating-linear-gradient(45deg,var(--land0) 0 2px,var(--dim2) 2px 3px);border:1px solid var(--dim2)}\n\/* mobile pan hint (rule 9 deviation, see the tool rules \"The map on a phone\"): shown only inside the max-width:820px block below *\/\n.gp-eni .eni-maphint{display:none;margin:8px 0 0;padding:0 16px;font-size:.82rem;color:var(--dim2)}\n\n\/* region panel *\/\n.gp-eni .eni-panel{padding:16px 18px}\n.gp-eni .eni-tiles{display:grid;grid-template-columns:repeat(4,1fr);gap:8px}\n.gp-eni .eni-tiles.five{grid-template-columns:repeat(auto-fit,minmax(120px,1fr))}\n.gp-eni .eni-tile{min-width:0}\n.gp-eni .eni-view{margin-bottom:10px}\n.gp-eni .eni-tile small{display:block;color:var(--dim2);font-size:.8rem;margin-top:2px}\n.gp-eni .eni-tile{background:var(--panel2);border:1px solid var(--line);border-radius:var(--r-card);padding:10px 12px;min-height:44px}\n.gp-eni .eni-tile .k{display:block;font-size:.75rem;font-weight:700;letter-spacing:.07em;text-transform:uppercase;color:var(--dim2)}\n.gp-eni .eni-tile .v{display:block;font-size:1.05rem;font-weight:700;margin-top:2px}\n.gp-eni .eni-tile .v.dry{color:var(--dry3)} .gp-eni .eni-tile .v.wet{color:var(--wet3)}\n\/* no reliable ENSO signal (phase 2, task 3): the Rain\/Temperature tiles read\n   \"No signal\" text instead of a \"+0%\"\/\"+0.0\u00b0C\" figure -- a real zero would\n   misread as \"confirmed no change\" rather than \"not a number we have\". *\/\n.gp-eni .eni-tile .v.nosig{color:var(--dim2);font-size:.92rem}\n.gp-eni .eni-badge{display:inline-block;padding:2px 8px;border-radius:var(--r-ctl);font-size:.78rem;font-weight:700;border:1px solid var(--line2);background:var(--panel)}\n.gp-eni .eni-badge.high{color:var(--accent-mid)} .gp-eni .eni-badge.medium{color:#8a6d1f} .gp-eni .eni-badge.low{color:var(--dim2)}\n.gp-eni .eni-badge.nosig{color:var(--dim2)}\n.gp-eni .eni-mech{margin-top:10px;color:var(--dim);font-size:.92rem}\n.gp-eni .eni-sub{margin-top:16px;font-size:.78rem;font-weight:700;letter-spacing:.07em;text-transform:uppercase;color:var(--dim2)}\n.gp-eni .eni-crops{list-style:none;margin:8px 0 0;padding:0}\n.gp-eni .eni-crops li{display:flex;flex-wrap:wrap;gap:4px 10px;align-items:baseline;padding:7px 0;border-top:1px solid var(--line);font-size:.92rem}\n.gp-eni .eni-crops li:first-child{border-top:0}\n.gp-eni .eni-crops b{font-weight:700;min-width:120px}\n.gp-eni .eni-crops .yr{font-weight:700;padding:0 6px;border-radius:var(--r-ctl);background:var(--panel2)}\n.gp-eni .eni-crops .yr.neg{color:var(--orange)} .gp-eni .eni-crops .yr.pos{color:var(--accent-mid)}\n.gp-eni .eni-crops small{color:var(--dim);flex:1 1 100%}\n.gp-eni .eni-bars{margin-top:8px}\n.gp-eni .eni-bar{display:grid;grid-template-columns:minmax(120px,.9fr) minmax(0,1.6fr) 34px;align-items:center;gap:10px;min-height:32px;font-size:.92rem}\n.gp-eni .eni-bar .tr{position:relative;height:12px;background:var(--panel2);border-radius:var(--r-bar)}\n.gp-eni .eni-bar .tr::before{content:\"\";position:absolute;left:50%;top:-3px;bottom:-3px;width:1px;background:var(--line2)}\n.gp-eni .eni-bar .fl{position:absolute;top:0;height:100%;border-radius:var(--r-bar);background:var(--accent)}\n.gp-eni .eni-bar .fl.neg{background:var(--orange)}\n.gp-eni .eni-bar .ix{font-weight:700;text-align:right}\n.gp-eni .eni-bar .ix.neg{color:var(--orange)} .gp-eni .eni-bar .ix.pos{color:var(--accent-mid)}\n\/* keyboard focus for the three [data-tip] surfaces that carried no tabindex\n   (Task 11 QA): a tile, a yield-band glyph or a demand bar hands its full\n   reason to the tooltip on mouseover\/touchstart via the shared [data-tip]\n   delegation, but with no tabindex a keyboard-only sighted user tabbed\n   straight past all three -- confirmed live, the map's 14 regions were\n   followed immediately by the mechanism paragraph's citation links, never\n   by a tile or a bar. outline (not stroke, these are HTML not SVG) matches\n   the heatmap header\/row focus-visible colour for one consistent ring. *\/\n.gp-eni .eni-tile:focus-visible,.gp-eni .eni-crops .yr:focus-visible,.gp-eni .eni-bar:focus-visible{outline:2px solid var(--accent-mid);outline-offset:2px}\n\/* visually hidden but readable by assistive tech -- a bare <div> is not\n   guaranteed to expose aria-label (it carries no ARIA role a screen reader\n   treats as nameable), and bare punctuation (\"--\", \"+\") in a yield band is\n   often skipped or misread, so both get the FULL sentence as real text\n   content here instead, with the visible glyph marked aria-hidden next to\n   it (see the demand-bar and yield-band markup in renderPanel). *\/\n.gp-eni .eni-sr{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}\n\n\/* playbook *\/\n.gp-eni .eni-play{display:grid;grid-template-columns:repeat(3,1fr);gap:14px;margin-top:14px}\n.gp-eni .eni-col{background:var(--panel);border:1px solid var(--line);border-radius:var(--r-card);padding:14px 16px}\n.gp-eni .eni-col h3{font-size:.9rem;letter-spacing:.06em;text-transform:uppercase}\n.gp-eni .eni-col.push h3{color:var(--accent-mid)} .gp-eni .eni-col.pull h3{color:var(--orange)} .gp-eni .eni-col.hold h3{color:var(--dim2)}\n.gp-eni .eni-col ul{list-style:none;margin:8px 0 0;padding:0}\n.gp-eni .eni-col li{padding:8px 0;border-top:1px solid var(--line);font-size:.92rem}\n.gp-eni .eni-col li:first-child{border-top:0}\n.gp-eni .eni-col li b{display:block;font-weight:700}\n.gp-eni .eni-col li span{color:var(--dim)}\n.gp-eni .eni-col li small{display:block;color:var(--dim2);margin-top:2px}\n.gp-eni .eni-col .none{color:var(--dim2);font-size:.9rem;margin-top:8px}\n.gp-eni .eni-msg{margin-top:14px;background:var(--panel2);border:1px solid var(--line);border-radius:var(--r-card);padding:14px 16px}\n.gp-eni .eni-msg h3{font-size:.9rem;letter-spacing:.06em;text-transform:uppercase;color:var(--dim2)}\n.gp-eni .eni-msg p{margin-top:8px;font-size:.98rem}\n.gp-eni .eni-watch{margin-top:14px}\n.gp-eni .eni-watch ul{margin:8px 0 0;padding-left:18px;color:var(--dim);font-size:.92rem}\n.gp-eni .eni-actions{display:flex;flex-wrap:wrap;gap:10px;margin-top:14px}\n.gp-eni .eni-btn2{display:inline-flex;align-items:center;min-height:44px;padding:0 18px;border:1px solid var(--accent);border-radius:var(--r-ctl);background:var(--accent);color:#fff;font-family:var(--f);font-size:.95rem;cursor:pointer}\n.gp-eni .eni-btn2.ghost{background:var(--panel);color:var(--accent)}\n.gp-eni .eni-neutral{margin-top:14px;color:var(--dim);background:var(--panel);border:1px solid var(--line);border-radius:var(--r-card);padding:16px}\n\n\/* portfolio heatmap *\/\n.gp-eni .eni-heatscroll{overflow-x:auto;margin-top:14px;border:1px solid var(--line);border-radius:var(--r-panel);background:var(--panel)}\n.gp-eni table.eni-heat{border-collapse:collapse;width:100%;min-width:760px;font-size:.9rem}\n.gp-eni table.eni-heat th,.gp-eni table.eni-heat td{padding:8px 10px;border-bottom:1px solid var(--line);text-align:center}\n.gp-eni table.eni-heat th{font-weight:700;color:var(--dim);background:var(--panel2);cursor:pointer;white-space:nowrap}\n.gp-eni table.eni-heat th[aria-sort]{color:var(--accent-mid)}\n.gp-eni table.eni-heat td:first-child,.gp-eni table.eni-heat th:first-child{text-align:left;position:sticky;left:0;background:var(--panel);font-weight:700}\n.gp-eni table.eni-heat td i{display:inline-block;min-width:34px;padding:3px 0;border-radius:var(--r-ctl);font-style:normal;font-weight:700;color:#fff}\n.gp-eni table.eni-heat td i.p3{background:var(--accent)} .gp-eni table.eni-heat td i.p2{background:var(--accent-mid)} .gp-eni table.eni-heat td i.p1{background:#a0d468;color:var(--ink)}\n.gp-eni table.eni-heat td i.z{background:var(--panel2);color:var(--dim2)}\n.gp-eni table.eni-heat td i.n1{background:#f6c9a8;color:var(--ink)} .gp-eni table.eni-heat td i.n2{background:#f79a52;color:var(--ink)} .gp-eni table.eni-heat td i.n3{background:var(--orange)}\n\/* no reliable ENSO signal (phase 2, task 3): ONE muted band across every\n   category column, not eight \"0\" cells -- eight zeros reads as \"checked,\n   nothing moves\"; one hatched band reads as \"not measured here\". Echoes the\n   map's own hatch treatment (repeating-linear-gradient, since this is an\n   HTML td, not SVG). *\/\n.gp-eni table.eni-heat td.nosig{background:repeating-linear-gradient(45deg,var(--panel2) 0 6px,var(--panel) 6px 12px);color:var(--dim2);font-weight:700;text-align:center}\n.gp-eni table.eni-heat tr.is-sel td,.gp-eni table.eni-heat tr.is-sel th{background:var(--panel2)}\n\/* selecting a no-signal region on the heatmap must not erase its hatch --\n   tr.is-sel td above and td.nosig earlier both carry the SAME specificity\n   (0,3,2 vs 0,3,3 -- td.nosig loses), so a selected no-signal row silently\n   fell back to a flat tint, reading as less distinct than an unselected one.\n   One more class in the selector (0,4,3) wins cleanly, no !important. *\/\n.gp-eni table.eni-heat tr.is-sel td.nosig{background:repeating-linear-gradient(45deg,var(--panel2) 0 6px,var(--panel) 6px 12px)}\n\/* sort headers are real <button>s so a keyboard user gets Enter\/Space for\n   free (see the JS comment above renderHeat -- the map task's role=\"img\" on\n   an SVG container silently stripped 14 path buttons from assistive tech,\n   so this table uses native interactive elements instead of a role bolted\n   onto a non-interactive one). aria-sort's colour comes from the existing\n   th[aria-sort] rule above via color:inherit, so the active header does not\n   need its own colour declaration here. *\/\n.gp-eni table.eni-heat th[data-col]{padding:0}\n.gp-eni table.eni-heat th[data-col] button{all:unset;display:block;box-sizing:border-box;width:100%;padding:8px 10px;cursor:pointer;font:inherit;font-weight:700;color:inherit;text-align:center}\n.gp-eni table.eni-heat th[data-col] button:focus-visible{outline:2px solid var(--accent-mid);outline-offset:-2px}\n\/* rows have no native interactive equivalent to a <button>, so they get\n   tabindex + a keydown handler (Enter\/Space) mirroring the map's path.rg\n   pattern, while keeping the tr's native row role intact for a screen\n   reader's own table navigation. *\/\n.gp-eni table.eni-heat tbody tr{cursor:pointer}\n.gp-eni table.eni-heat tbody tr:hover td,.gp-eni table.eni-heat tbody tr:hover th{background:var(--panel2)}\n.gp-eni table.eni-heat tbody tr:focus-visible{outline:2px solid var(--accent-mid);outline-offset:-2px}\n\n\/* server-rendered summary (crawlers, no-JS) *\/\n.gp-eni .eni-rows{margin-top:14px;overflow-x:auto}\n.gp-eni table.eni-rows-t{border-collapse:collapse;width:100%;min-width:720px;font-size:.9rem}\n.gp-eni table.eni-rows-t th,.gp-eni table.eni-rows-t td{padding:8px 10px;border-bottom:1px solid var(--line);text-align:left;vertical-align:top}\n.gp-eni table.eni-rows-t th{color:var(--dim);background:var(--panel2)}\n\n\/* tooltip: floats above the page, so a shadow is allowed (allowShadow in tests) *\/\n.gp-eni .eni-tip{position:fixed;z-index:80;max-width:300px;padding:7px 10px;border-radius:var(--r-ctl);background:#14251a;color:#fff;\n  font-family:var(--f);font-size:.83rem;line-height:1.45;pointer-events:none;opacity:0;transition:opacity .1s;box-shadow:0 6px 22px rgba(0,0,0,.24)}\n.gp-eni .eni-tip.is-on{opacity:1}\n.gp-eni .eni-tip b{display:block;font-weight:700}\n.gp-eni .eni-tip span{display:block;text-decoration:none;color:#b9d5bd}\n\n\/* prose, cards, CTA, FAQ *\/\n.gp-eni .eni-cards{display:grid;grid-template-columns:repeat(3,1fr);gap:14px;margin-top:16px}\n.gp-eni .eni-card{background:var(--panel);border:1px solid var(--line);border-radius:var(--r-card);padding:16px 18px}\n.gp-eni .eni-card h3{font-size:1rem}\n.gp-eni .eni-card p{margin-top:6px;color:var(--dim);font-size:.94rem}\n.gp-eni .eni-cta{background:var(--accent);border-radius:var(--r-panel);padding:38px 40px;text-align:center;color:#fff}\n.gp-eni .eni-cta h2{color:#fff;font-size:clamp(1.5rem,2.6vw,2.1rem);max-width:760px;margin:0 auto;text-wrap:balance}\n.gp-eni .eni-cta p{color:rgba(255,255,255,.9);max-width:720px;margin:14px auto 0;font-size:1.02rem;line-height:1.65}\n.gp-eni .eni-form{margin-top:26px;text-align:left}\n.gp-eni .eni-form-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:12px 14px}\n.gp-eni .eni-f{display:flex;flex-direction:column;gap:5px;color:#fff;font-size:.9rem}\n.gp-eni .eni-f-wide{grid-column:1 \/ -1}\n.gp-eni .eni-f input,.gp-eni .eni-f select,.gp-eni .eni-f textarea{min-height:44px;padding:9px 12px;border:1px solid rgba(255,255,255,.55);border-radius:var(--r-ctl);background:#fff;color:var(--ink);font-family:var(--f);font-size:1rem;width:100%}\n.gp-eni .eni-f textarea{min-height:110px;resize:vertical}\n.gp-eni .eni-f input:focus-visible,.gp-eni .eni-f select:focus-visible,.gp-eni .eni-f textarea:focus-visible{outline:2px solid #fff;outline-offset:2px}\n.gp-eni .eni-f .is-bad{border:2px solid var(--orange)}\n.gp-eni .eni-f-row{display:grid;grid-template-columns:1fr 130px;gap:8px}\n.gp-eni .eni-form-actions{margin-top:16px;display:flex;flex-wrap:wrap;align-items:center;gap:12px 18px}\n.gp-eni .eni-form-msg{margin:12px 0 0;color:#fff;font-size:.95rem}\n.gp-eni .eni-form-msg.ok{font-weight:700}\n.gp-eni .eni-form-fallback{margin:12px 0 0;color:#fff;font-size:.95rem}\n.gp-eni .eni-form-fallback a{color:#fff}\n.gp-eni .eni-form-note{margin:14px 0 0;color:rgba(255,255,255,.85);font-size:.86rem;max-width:none}\n.gp-eni .eni-form-note a{color:#fff}\n.gp-eni [hidden]{display:none !important}\n.gp-eni .eni-btn{display:inline-flex;align-items:center;min-height:48px;padding:0 26px;border-radius:var(--r-ctl);background:#fff;color:var(--accent);font-family:var(--f);font-weight:400;font-size:1rem;text-decoration:none}\n.gp-eni .eni-btn:hover{background:#eef4e4;color:var(--accent)}\n.gp-eni .eni-btn-ghost{display:inline-flex;align-items:center;min-height:48px;padding:0 24px;border-radius:var(--r-ctl);border:1.5px solid rgba(255,255,255,.55);color:#fff;font-family:var(--f);font-weight:400;font-size:1rem;text-decoration:none}\n.gp-eni .eni-btn-ghost:hover{border-color:#fff;color:#fff;background:rgba(255,255,255,.1)}\n.gp-eni .eni-faq{margin-top:22px}\n.gp-eni .eni-faq details{background:var(--panel);border:1px solid var(--line);border-radius:var(--r-card);margin-top:10px}\n.gp-eni .eni-faq summary{cursor:pointer;padding:14px 16px;font-weight:700;min-height:44px}\n.gp-eni .eni-faq .a{padding:0 16px 14px;color:var(--dim)}\n.gp-eni .eni-ai{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:14px;background:var(--panel);border:1px solid var(--line2);border-radius:var(--r-panel);padding:22px 26px}\n.gp-eni .eni-ai h2{font-size:1.2rem}\n.gp-eni .eni-ai p{color:var(--dim);margin-top:4px}\n\n\/* widescreen pass (rule 13) *\/\n@media (min-width:1200px){\n  .gp-eni .eni-stage{grid-template-columns:minmax(0,1.6fr) minmax(380px,1fr)}\n}\n\/* tablet + phone (rule 9) *\/\n@media (max-width:820px){\n  .gp-eni section{padding:26px 16px}\n  .gp-eni .eni-hero{padding:22px 16px 0}\n  .gp-eni .eni-state .eni-state-src{margin-left:0;flex:1 1 100%}\n  .gp-eni .eni-state-ol{display:block;margin-right:0}\n  .gp-eni .eni-ctl-lab{width:auto;flex:0 0 auto;font-size:.75rem}\n  .gp-eni .eni-chip{min-height:44px;font-size:.9rem;padding:0 12px}\n  .gp-eni select.eni-select{min-height:44px;font-size:1rem;flex:1 1 100%}\n  .gp-eni .eni-stage{grid-template-columns:1fr}\n  .gp-eni .eni-mapwrap{padding:0}\n  .gp-eni .eni-map{border-top:1px solid var(--line)}\n  \/* Rule 9 names a min-height:62vh map; a world map letterboxes instead of\n     filling at phone widths (preserveAspectRatio keeps the whole 2.2:1 frame\n     visible either way), so this tool deviates: a deliberate horizontal\n     scroll container at a fixed, usable pixel width instead. See the tool rules\n     \"The map on a phone\". *\/\n  .gp-eni .eni-mapscroll{overflow-x:auto;-webkit-overflow-scrolling:touch}\n  .gp-eni .eni-map{min-width:660px}\n  .gp-eni .eni-map text.lb{font-size:13px;stroke-width:3.6px}\n  .gp-eni .eni-maphint{display:block}\n  .gp-eni .eni-tiles{grid-template-columns:repeat(2,1fr)}\n  .gp-eni .eni-tiles.five{grid-template-columns:repeat(2,1fr)}\n  .gp-eni .eni-play{grid-template-columns:1fr}\n  .gp-eni .eni-cards{grid-template-columns:1fr}\n  .gp-eni .eni-cta{padding:28px 20px}\n  .gp-eni .eni-form-grid{grid-template-columns:1fr}\n  .gp-eni .eni-f-row{grid-template-columns:1fr}\n  .gp-eni .eni-btn2{min-height:44px}\n  .gp-eni table.eni-heat th,.gp-eni table.eni-heat td{padding:14px 10px}\n  .gp-eni table.eni-heat th[data-col] button{min-height:44px;padding:14px 10px}\n}\n@media (max-width:480px){\n  .gp-eni .eni-hero h1{font-size:1.85rem}\n  .gp-eni .eni-hero-sub{font-size:1.2rem}\n  .gp-eni .eni-chips{gap:5px}\n  .gp-eni .eni-chip{font-size:.86rem;padding:0 10px}\n  .gp-eni .eni-bar{grid-template-columns:minmax(100px,1fr) minmax(0,1.3fr) 30px}\n  \/* phone fold (Task 11): the Outlook sentence (a live the agency advisory,\n     often 5-6 lines at this width) was the tallest single block in the\n     status card, pushing the map to ~954px on a 812px-tall viewport --\n     over a full extra screen of scrolling before any map pixel is\n     visible. Clamped to 2 lines (full sentence stays in the DOM for a\n     screen reader; \"source\" link two lines below already carries the\n     citation). Combined with tighter status\/control padding on phones\n     only, this brings the map to ~810px -- at the fold, not past it. *\/\n  .gp-eni .eni-state-v{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;overflow:hidden}\n  \/* same fold budget, second claim on it (2026-09-26): the observed-index\n     line carries TWO values and a season since the agency split the official and\n     legacy indices, where it used to carry one short number. At this width\n     the full sentence runs ~5 lines. Clamped to 3, which is where both\n     values and the date of the switch sit; the explanatory tail is written\n     last precisely so it is what a clamp takes, and the whole sentence\n     stays in the DOM for a screen reader. *\/\n  .gp-eni .eni-state-obs{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:3;overflow:hidden}\n  .gp-eni .eni-state,.gp-eni .eni-controls{padding:11px 14px}\n  .gp-eni .eni-ctl + .eni-ctl{margin-top:8px;padding-top:8px}\n}\n\n\/* print: the playbook one-pager (nothing leaves the browser). This\n   stylesheet is correctly scoped under .gp-eni (rule 5) and can therefore\n   never reach outside it to hide the theme's own sticky header, mega menu\n   or footer -- there is no selector this file could write that would touch\n   them. The escape hatch (2026-09-26 review) is promoting .gp-eni ITSELF to\n   a full-bleed layer for print: taken out of normal document flow and\n   pinned over the whole print area, so the surrounding chrome (still\n   present in the DOM, never touched, impossible to touch) ends up behind\n   the printed page instead of printing alongside or above it. Every OTHER\n   section still hides the normal way. The region panel (anomaly numbers,\n   crops under the season, demand bars) now stays VISIBLE: hiding the whole\n   .eni-stage used to take the panel down with the map, leaving a sheet of\n   push\/hold\/pull-back advice with none of the numbers behind it -- not\n   worth printing. Only the map SIDE of the stage (:first-child of the two\n   .eni-pane columns) is hidden, not the stage itself.\n\n   ABSOLUTE, not FIXED (Task 11 browser QA, found via an actual printed PDF,\n   not just a computed-style check): `position:fixed` in Chrome's print\/PDF\n   engine repeats the fixed box at the same top-left spot on EVERY page --\n   correct for a one-page-tall region (what this was tested against), but\n   the panel + playbook for almost any region is 2-3 printed pages, so page\n   2 and 3 rendered the SAME page-1 content stamped over the actually-\n   flowing playbook underneath it, both illegible. `position:absolute` with\n   the same top:0;left:0;right:0 anchors identically to the page's top-left\n   for page 1 (no positioned ancestor sits between <body> and .gp-eni on\n   this page, so the containing block is the same initial containing block\n   fixed would have used) and keeps the same z-index stacking over the\n   theme chrome, but is NOT re-painted per page, so page 2+ simply continues\n   the box's own normal flow. Verified: printing a region whose playbook\n   spans 3 pages now shows the panel on page 1 and the playbook flowing\n   cleanly across pages 2-3, no duplication. *\/\n@media print{\n  .gp-eni{position:absolute;top:0;left:0;right:0;width:100%;height:auto;z-index:999999999;background:#fff}\n  .gp-eni .eni-hero,.gp-eni .eni-tool,.gp-eni .eni-heat-sec,.gp-eni .eni-rows-sec,.gp-eni .eni-method,.gp-eni .eni-cta-sec,.gp-eni .eni-faq-sec,.gp-eni .eni-ai-sec,.gp-eni .eni-actions{display:none !important}\n  .gp-eni .eni-stage > .eni-pane:first-child{display:none !important}\n  .gp-eni .eni-play{grid-template-columns:repeat(3,1fr)}\n}\n@media (prefers-reduced-motion:reduce){ .gp-eni *{transition:none !important} }\n\/* ---- margin reclaim (the factory rules, rule 33) \u2500 the site's Additional CSS sets margins on BARE\n   TAGS with !important (li{margin-bottom:10px}, h1{margin:20px 0}, h3{margin:15px 0}, plus ol and\n   hr). Scoping cannot beat !important, so the margins this embed declares above were silently not\n   being applied on the live page. Those global rules are load-bearing for posts and the homepage\n   (measured 2026-10-12: stripping the li one moves 141 of 202 list items on a post, the h3 one\n   moves 3 of 6 headings on the homepage), so they stay and the embed re-asserts its own spacing\n   here. ONLY the margins this tool actually declares are reclaimed: tags it never specified keep\n   whatever the site gives them, because that is the spacing it was designed against. ---- *\/\n.gp-eni h1,.gp-eni h2,.gp-eni h3,.gp-eni h4{margin:0 !important}\n.gp-eni .eni-hero h1{margin:0 auto !important}\n\/* ===== ENI:CSS END ===== *\/\n<\/style>\n\n<div class=\"eni-hero\">\n  <h1>El Ni&ntilde;o and Monsoon Impact Simulator<\/h1>\n  <h2 class=\"eni-hero-sub\">Where the 2026-27 El Ni&ntilde;o and the monsoon outlook move crop stress and input demand<\/h2>\n  <p class=\"eni-lede\">Pick an ENSO phase and a region: typical rainfall anomaly, crops under stress, input demand shift, and a push, hold or pull-back playbook. In your browser, no signup.<\/p>\n<\/div>\n\n<section class=\"eni-tool\" id=\"eni-tool\">\n  <div class=\"eni-state\" id=\"eni-state\"><\/div>\n  <div class=\"eni-controls\" id=\"eni-controls\"><\/div>\n<\/section>\n\n<section class=\"eni-stage\" id=\"eni-stage\">\n  <div class=\"eni-pane\">\n    <div class=\"eni-panehead\">\n      <h2 id=\"eni-map-h\">Where the season moves<\/h2>\n      <p id=\"eni-map-sub\">Regions coloured by the typical rainfall anomaly. Hover, tap or focus for the numbers; click or press Enter to select.<\/p>\n    <\/div>\n    <div class=\"eni-mapwrap\">\n      <div class=\"eni-mapscroll\">\n        <svg class=\"eni-map\" id=\"eni-map\" role=\"group\" aria-labelledby=\"eni-map-h eni-map-sub\" preserveAspectRatio=\"xMidYMid meet\"><\/svg>\n      <\/div>\n      <p class=\"eni-maphint\" id=\"eni-maphint\">Map pans sideways to show every region. Use the Region dropdown above to select without panning.<\/p>\n    <\/div>\n    <div class=\"eni-legend\" id=\"eni-legend\"><\/div>\n  <\/div>\n  <div class=\"eni-pane\">\n    <div class=\"eni-panehead\">\n      <h2 id=\"eni-panel-h\">Region<\/h2>\n      <p id=\"eni-panel-sub\">Typical anomaly, crops under stress, demand shift by category.<\/p>\n    <\/div>\n    <div class=\"eni-panel\" id=\"eni-panel\"><\/div>\n  <\/div>\n<\/section>\n<section class=\"eni-play-sec\" id=\"eni-play-sec\">\n  <div class=\"eni-prose\">\n    <h2 class=\"eni-h2\" id=\"eni-play-h\">Playbook<\/h2>\n    <p class=\"eni-lede\" id=\"eni-play-sub\">What to push, hold and pull back in this region for the season, and the line to give distributors.<\/p>\n  <\/div>\n  <div id=\"eni-play\"><\/div>\n<\/section>\n<section class=\"eni-heat-sec\" id=\"eni-heat-sec\">\n  <div class=\"eni-prose\">\n    <h2 class=\"eni-h2\">Portfolio view<\/h2>\n    <p class=\"eni-lede\" id=\"eni-heat-sub\">Every region against every category for the phase and strength you picked. Sort a column to see where a product line moves most.<\/p>\n  <\/div>\n  <div class=\"eni-heatscroll\" id=\"eni-heat\"><\/div>\n<\/section>\n<section class=\"eni-rows-sec\" id=\"eni-rows-sec\">\n  <div class=\"eni-rows\">\n<!-- ENI-ROWS BEGIN -->\n<h2 class=\"eni-h2\">Region summary, historic El Ni\u00f1o<\/h2>\n<table class=\"eni-rows-t\"><thead><tr><th scope=\"col\">Region<\/th><th scope=\"col\">Rain<\/th><th scope=\"col\">Temperature<\/th><th scope=\"col\">Months<\/th><th scope=\"col\">Confidence<\/th><th scope=\"col\">Top demand shifts<\/th><\/tr><\/thead><tbody>\n<tr class=\"eni-row\" data-region=\"in-monsoon\"><td>India: Indo-Gangetic Plain and Deccan (monsoon outlook)<\/td><td>-25%<\/td><td>+0.6\u00b0C<\/td><td>Oct to Dec<\/td><td>medium<\/td><td class=\"eni-row-top\">+3 Biostimulants and anti-stress; -2 Fungicides; +2 Insecticides<\/td><\/tr>\n<tr class=\"eni-row\" data-region=\"pk-indus\"><td>Pakistan: Indus Plain (monsoon outlook)<\/td><td>-7%<\/td><td>+0.6\u00b0C<\/td><td>Oct to Dec<\/td><td>low<\/td><td class=\"eni-row-top\">+2 Biostimulants and anti-stress; -1 Fungicides; +1 Insecticides<\/td><\/tr>\n<tr class=\"eni-row\" data-region=\"sea-rice-palm\"><td>Southeast Asia: rice and oil palm belts<\/td><td>-31%<\/td><td>+1.0\u00b0C<\/td><td>Jul to Dec<\/td><td>high<\/td><td class=\"eni-row-top\">-3 Fungicides; +3 Insecticides; +3 Biostimulants and anti-stress<\/td><\/tr>\n<tr class=\"eni-row\" data-region=\"ph-monsoon\"><td>Philippines: Luzon and Visayas rice and corn (seasonal outlook)<\/td><td>-39%<\/td><td>+0.6\u00b0C<\/td><td>Oct to Dec<\/td><td>high<\/td><td class=\"eni-row-top\">+3 Biostimulants and anti-stress; -2 Fungicides; +2 Insecticides<\/td><\/tr>\n<tr class=\"eni-row\" data-region=\"au-winter-crop\"><td>Australia: WA wheat belt, eastern wheat belt and Queensland<\/td><td>-25%<\/td><td>+1.0\u00b0C<\/td><td>Jun to Nov<\/td><td>high<\/td><td class=\"eni-row-top\">-3 Fungicides; +3 Insecticides; +3 Biostimulants and anti-stress<\/td><\/tr>\n<tr class=\"eni-row\" data-region=\"saf-summer\"><td>Southern Africa: Highveld, Zambia, Zimbabwe, Mozambique<\/td><td>-31%<\/td><td>+1.3\u00b0C<\/td><td>Nov to Mar<\/td><td>high<\/td><td class=\"eni-row-top\">-3 Fungicides; +3 Insecticides; +3 Biostimulants and anti-stress<\/td><\/tr>\n<tr class=\"eni-row\" data-region=\"eaf-short-rains\"><td>East Africa: Kenya and Ethiopian highlands<\/td><td>+38%<\/td><td>+0.6\u00b0C<\/td><td>Oct to Dec<\/td><td>high<\/td><td class=\"eni-row-top\">+3 Fungicides; +2 Herbicides; +2 Seed treatment<\/td><\/tr>\n<tr class=\"eni-row\" data-region=\"sahel\"><td>Sahel and West African savanna<\/td><td>-19%<\/td><td>+0.6\u00b0C<\/td><td>Jul to Sep<\/td><td>medium<\/td><td class=\"eni-row-top\">+3 Biostimulants and anti-stress; +3 Short-cycle and tolerant seed; -2 Fungicides<\/td><\/tr>\n<tr class=\"eni-row\" data-region=\"cam-dry-corridor\"><td>Central America Dry Corridor and Mexico<\/td><td>-31%<\/td><td>+1.1\u00b0C<\/td><td>May to Oct<\/td><td>high<\/td><td class=\"eni-row-top\">-3 Fungicides; +3 Insecticides; +3 Biostimulants and anti-stress<\/td><\/tr>\n<tr class=\"eni-row\" data-region=\"and-north\"><td>Colombia and Venezuela<\/td><td>-31%<\/td><td>+1.0\u00b0C<\/td><td>Dec to Mar<\/td><td>high<\/td><td class=\"eni-row-top\">-3 Fungicides; +3 Insecticides; +3 Biostimulants and anti-stress<\/td><\/tr>\n<tr class=\"eni-row\" data-region=\"br-centre-north\"><td>Brazil centre-north: Cerrado, MATOPIBA, Sert\u00e3o and Bahia<\/td><td>-19%<\/td><td>+1.3\u00b0C<\/td><td>Sep to Feb<\/td><td>medium<\/td><td class=\"eni-row-top\">+3 Biostimulants and anti-stress; +3 Short-cycle and tolerant seed; -2 Fungicides<\/td><\/tr>\n<tr class=\"eni-row\" data-region=\"br-south\"><td>Brazil south: Paran\u00e1, Santa Catarina, Rio Grande do Sul<\/td><td>+38%<\/td><td>+0.4\u00b0C<\/td><td>Sep to Feb<\/td><td>high<\/td><td class=\"eni-row-top\">+3 Fungicides; +2 Herbicides; +2 Seed treatment<\/td><\/tr>\n<tr class=\"eni-row\" data-region=\"plata-pampas\"><td>Argentina, Uruguay and Paraguay: the Pampas<\/td><td>+31%<\/td><td>+0.3\u00b0C<\/td><td>Oct to Mar<\/td><td>high<\/td><td class=\"eni-row-top\">+3 Fungicides; +2 Herbicides; +2 Seed treatment<\/td><\/tr>\n<tr class=\"eni-row\" data-region=\"us-south-west\"><td>US southern tier, Delta and California<\/td><td>+25%<\/td><td>-0.4\u00b0C<\/td><td>Dec to Mar<\/td><td>medium<\/td><td class=\"eni-row-top\">+3 Fungicides; +2 Herbicides; +2 Seed treatment<\/td><\/tr>\n<tr class=\"eni-row\" data-region=\"pe-ec-coast\"><td>Peru and Ecuador coast<\/td><td>+188%<\/td><td>+1.9\u00b0C<\/td><td>Dec to Apr<\/td><td>high<\/td><td class=\"eni-row-top\">+3 Fungicides; +3 Herbicides; +3 Seed treatment<\/td><\/tr>\n<tr class=\"eni-row\" data-region=\"ca-prairies\"><td>Canada: Alberta, Saskatchewan and Manitoba<\/td><td>-25%<\/td><td>+1.5\u00b0C<\/td><td>Dec to Apr<\/td><td>medium<\/td><td class=\"eni-row-top\">-3 Fungicides; +3 Insecticides; +3 Biostimulants and anti-stress<\/td><\/tr>\n<tr class=\"eni-row\" data-region=\"cn-yangtze\"><td>China: Yangtze basin (Hubei, Hunan, Jiangxi, Anhui, Jiangsu, Zhejiang, Sichuan)<\/td><td>+38%<\/td><td>+0.5\u00b0C<\/td><td>Jun to Aug<\/td><td>medium<\/td><td class=\"eni-row-top\">+3 Fungicides; +2 Herbicides; +2 Seed treatment<\/td><\/tr>\n<tr class=\"eni-row\" data-region=\"cn-north-plain\"><td>China: North Plain (Hebei, Henan, Shandong, Shanxi, Shaanxi)<\/td><td>-25%<\/td><td>+0.6\u00b0C<\/td><td>Oct to Mar<\/td><td>medium<\/td><td class=\"eni-row-top\">+3 Biostimulants and anti-stress; +3 Short-cycle and tolerant seed; -2 Fungicides<\/td><\/tr>\n<tr class=\"eni-row\" data-region=\"cl-central\"><td>Chile: central valley<\/td><td>+50%<\/td><td>+0.4\u00b0C<\/td><td>Jun to Oct<\/td><td>medium<\/td><td class=\"eni-row-top\">+3 Fungicides; +2 Herbicides; +2 Seed treatment<\/td><\/tr>\n<tr class=\"eni-row\" data-region=\"nz-crop\"><td>New Zealand<\/td><td>-25%<\/td><td>+0.8\u00b0C<\/td><td>Nov to Mar<\/td><td>medium<\/td><td class=\"eni-row-top\">-3 Fungicides; +3 Insecticides; +3 Biostimulants and anti-stress<\/td><\/tr>\n<tr class=\"eni-row\" data-region=\"med-west\"><td>Western Mediterranean: Spain, Portugal and Italy<\/td><td>+23%<\/td><td>-0.3\u00b0C<\/td><td>Nov to Feb<\/td><td>low<\/td><td class=\"eni-row-top\">+3 Fungicides; +2 Herbicides; +2 Seed treatment<\/td><\/tr>\n<tr class=\"eni-row\" data-region=\"ua-black-sea\"><td>Ukraine and the Black Sea<\/td><td>no signal<\/td><td>no signal<\/td><td>Apr to Sep<\/td><td>low<\/td><td class=\"eni-row-top\">no reliable ENSO signal here<\/td><\/tr>\n<tr class=\"eni-row\" data-region=\"eu-central\"><td>Central Europe: Poland, Czechia, Slovakia, Hungary, Romania and Bulgaria<\/td><td>no signal<\/td><td>no signal<\/td><td>Mar to Aug<\/td><td>low<\/td><td class=\"eni-row-top\">no reliable ENSO signal here<\/td><\/tr>\n<tr class=\"eni-row\" data-region=\"eu-west\"><td>Western and northern Europe: France, Britain, Germany, Belgium, the Netherlands and Denmark<\/td><td>no signal<\/td><td>no signal<\/td><td>Mar to Aug<\/td><td>low<\/td><td class=\"eni-row-top\">no reliable ENSO signal here<\/td><\/tr>\n<tr class=\"eni-row\" data-region=\"kz-steppe\"><td>Kazakhstan steppe<\/td><td>no signal<\/td><td>no signal<\/td><td>Apr to Aug<\/td><td>low<\/td><td class=\"eni-row-top\">no reliable ENSO signal here<\/td><\/tr>\n<\/tbody><\/table>\n<noscript><p>Typical anomalies for a historic El Ni\u00f1o season and the three largest demand shifts per region. Turn on JavaScript for the map, the strength selector and the playbook.<\/p><\/noscript>\n<!-- ENI-ROWS END -->\n  <\/div>\n<\/section>\n\n<section class=\"eni-method\" id=\"eni-method\">\n  <div class=\"eni-prose\">\n    <h2 class=\"eni-h2\">How the numbers are made<\/h2>\n    <p class=\"eni-lede\">Each region carries the typical rainfall and temperature anomaly of past El Ni\u00f1o and La Ni\u00f1a seasons, the months it is felt, and a confidence grade (high, medium or low). The strength you pick scales it: moderate 0.6, strong 1.0, historic 1.25. From the anomaly and the crop calendar come the active stresses, the crops exposed, and a demand shift from -3 to +3 per product category. Values are typical for past events of that phase, not a forecast for this season.<\/p>\n    <p class=\"eni-lede\">For India, Pakistan and the Philippines the national seasonal outlook replaces the typical anomaly for the months it covers. A closed band such as 88 to 112% of the long-period average maps to its midpoint; an open band maps ten points past its edge, so under 85% of the long-period average reads as 25% below; worded categories map as slightly below 7, below 15 and well below 25% below normal. Temperature wording maps as above normal +0.6\u00b0C, well above +1.0\u00b0C, below normal -0.5\u00b0C. The strength selector does not scale an outlook.<\/p>\n  <\/div>\n  <div class=\"eni-cards\">\n    <div class=\"eni-card\"><h3>What the index means<\/h3><p>+3 is a category the season pushes hard, like fungicides in a wet Brazilian south. -3 is one it pulls back hard, like the same fungicides in a dry Southern African season. 0 is a normal programme.<\/p><\/div>\n    <div class=\"eni-card\"><h3>What it does not do<\/h3><p>It does not predict a specific year, does not resolve below the region, and does not know your products. The regional briefing maps your own portfolio and territories onto this model.<\/p><\/div>\n    <div class=\"eni-card\"><h3>Before you act<\/h3><p>Confirm rates, products and timing with local agronomists, product labels and local regulations. The playbook is a starting point for a sales conversation, not a recommendation to a grower.<\/p><\/div>\n  <\/div>\n<\/section>\n\n<section class=\"eni-cta-sec\">\n  <div class=\"eni-cta\">\n    <h2>Run this model on your portfolio<\/h2>\n    <p>The page is the public model. The paid briefing, priced per season and per portfolio, puts your own book on it: insurers get exposure by zone, crop and month; crop-input teams get push, hold and pull-back by territory and product line.<\/p>\n    <form class=\"eni-form\" id=\"eni-form\" novalidate>\n      <div class=\"eni-form-grid\" id=\"eni-form-grid\">\n        <label class=\"eni-f eni-f-wide\"><span>Company type<\/span><select name=\"company-type\" required><option value=\"\">Choose<\/option><option>Insurance and reinsurance<\/option><option>Crop protection, seed and fertilizer<\/option><option>Other<\/option><\/select><\/label>\n        <label class=\"eni-f\"><span>First name<\/span><input type=\"text\" name=\"first-name\" autocomplete=\"given-name\" required><\/label>\n        <label class=\"eni-f\"><span>Last name<\/span><input type=\"text\" name=\"last-name\" autocomplete=\"family-name\" required><\/label>\n        <label class=\"eni-f\"><span>Company<\/span><input type=\"text\" name=\"company-name\" autocomplete=\"organization\" required><\/label>\n        <label class=\"eni-f\"><span>Role<\/span><input type=\"text\" name=\"company-role\" autocomplete=\"organization-title\" required><\/label>\n        <label class=\"eni-f\"><span>Work email<\/span><input type=\"email\" name=\"email\" autocomplete=\"email\" required><\/label>\n        <label class=\"eni-f\"><span>Phone<\/span><input type=\"tel\" name=\"phone\" autocomplete=\"tel\" required><\/label>\n        <label class=\"eni-f\"><span>Countries or regions<\/span><input type=\"text\" name=\"countries\" required><\/label>\n        <div class=\"eni-f\"><span>Area in your portfolio or territories<\/span><div class=\"eni-f-row\"><select name=\"area\" required aria-label=\"Area band\"><option value=\"\">Choose<\/option><option>0-1,000<\/option><option>1,000-10,000<\/option><option>10,000-100,000<\/option><option>100,000+<\/option><\/select><select name=\"size-type\" aria-label=\"Unit\"><option>hectares<\/option><option>acres<\/option><\/select><\/div><\/div>\n        <label class=\"eni-f eni-f-wide\"><span>Your portfolio: products and territories, or crops, zones and exposure<\/span><textarea name=\"portfolio\" rows=\"4\" required><\/textarea><\/label>\n      <\/div>\n      <div class=\"eni-form-actions\">\n        <button type=\"submit\" class=\"eni-btn\" id=\"eni-form-send\">Request a quote<\/button>\n        <a class=\"eni-btn-ghost eni-route-cta\" data-cta=\"signup\" href=\"https:\/\/app.geopard.tech\/auth\/sign-up?utm_source=geopard.tech&amp;utm_medium=lead-magnet&amp;utm_campaign=el-nino-impact&amp;utm_content=below-tool-cta\">Farm or agronomy service? Start free in GeoPard<\/a>\n      <\/div>\n      <p class=\"eni-form-msg\" id=\"eni-form-msg\" role=\"status\" hidden><\/p>\n      <p class=\"eni-form-fallback\" id=\"eni-form-fallback\" hidden>The request did not go through. <a href=\"https:\/\/geopard.tech\/demo-form\/?utm_source=el-nino-impact&amp;utm_medium=wp-embed&amp;utm_campaign=regional-intelligence&amp;utm_content=portfolio-request\">Use the demo form<\/a>.<\/p>\n      <p class=\"eni-form-note\">Requesting a quote accepts the <a href=\"https:\/\/geopard.tech\/policy\/\">privacy policy<\/a>; the details are used to reply. This form is protected by reCAPTCHA; the Google <a href=\"https:\/\/policies.google.com\/privacy\">privacy policy<\/a> and <a href=\"https:\/\/policies.google.com\/terms\">terms of service<\/a> apply.<\/p>\n    <\/form>\n  <\/div>\n<\/section>\n\n<section class=\"eni-ai-sec\">\n  <div class=\"eni-ai\">\n    <div><h2>Ask the AI Assistant about a region or a field.<\/h2><p>Plain-language answers on your own data inside GeoPard.<\/p><\/div>\n    <a class=\"eni-btn2\" href=\"https:\/\/geopard.tech\/ai\/\">Meet the AI Assistant<\/a>\n  <\/div>\n<\/section>\n\n<section class=\"eni-faq-sec eni-prose\" style=\"padding-top:0\">\n  <h2 class=\"eni-h2\">Frequently asked questions<\/h2>\n  <div class=\"eni-faq\">\n    <details open><summary>What does El Ni\u00f1o do to agriculture?<\/summary><div class=\"a\"><p>It shifts where the rain falls for a season. In strong events India, Southeast Asia, eastern Australia, southern Africa, Central America and Brazil&#8217;s centre-north typically see less rain and more heat, while southern Brazil, the Pampas, East Africa&#8217;s short rains, the southern United States and the Peru-Ecuador coast typically see more. Crop stress, pests, diseases and the demand for inputs move with it.<\/p><\/div><\/details>\n    <details><summary>Is the 2026-27 El Ni\u00f1o unusual?<\/summary><div class=\"a\"><p>The current outlook puts a greater than 90% chance on a very strong event through winter 2026-27, and a 75% chance on a historic one in October to December. The strength selector lets you read every region at moderate, strong and historic.<\/p><\/div><\/details>\n    <details><summary>Why does the same El Ni\u00f1o dry one part of Brazil and flood another?<\/summary><div class=\"a\"><p>The warm Pacific shifts the rain belts: the subtropics of South America sit under more storms while the tropics north of them get less. In 2023-24 Mato Grosso lost soybean to heat and dry spells while Rio Grande do Sul flooded.<\/p><\/div><\/details>\n    <details><summary>Does every El Ni\u00f1o behave the same way?<\/summary><div class=\"a\"><p>No, the direction is reliable but the size is not. In 2015 a warm western Indian Ocean partly offset the signal and India&#8217;s monsoon still finished 14% below its long-period average, near the low end of a typical strong event. That is exactly what the confidence grade next to each region captures.<\/p><\/div><\/details>\n    <details><summary>How should a crop-protection or seed team use this?<\/summary><div class=\"a\"><p>Pick the phase and strength, read the playbook per region, and reallocate: push fungicides and adjuvants where the season is wet, biostimulants, insecticides and drought-tolerant seed where it is dry, and time the message to the months shown. The copy button gives distributors the line.<\/p><\/div><\/details>\n    <details><summary>Is this the typical El Ni\u00f1o pattern or this season&#8217;s outlook?<\/summary><div class=\"a\"><p>For India, Pakistan and the Philippines the page shows the national seasonal outlook for the months it covers; the typical pattern of past events stays available for the same region. Every other region shows the typical pattern at the strength you pick. An outlook is a category, below normal or near normal, mapped to a percent by the band it names: under 85% of the long-period average reads as 25% below, 88 to 112% reads as normal.<\/p><\/div><\/details>\n    <details><summary>Where does the data come from and what leaves my browser?<\/summary><div class=\"a\"><p>Anomalies come from the official seasonal outlook and published analyses of past seasons; crop months from the GeoPard Global Crop Calendar. Nothing you upload leaves your browser: there is no upload here, no account and no tracking of what you select beyond anonymous page analytics.<\/p><\/div><\/details>\n  <\/div>\n<\/section>\n\n<script type=\"application\/ld+json\" nowprocket data-no-optimize=\"1\" data-no-defer=\"1\" data-no-minify=\"1\">\n{\"@context\":\"https:\/\/schema.org\",\"@type\":\"FAQPage\",\"mainEntity\":[\n{\"@type\":\"Question\",\"name\":\"What does El Ni\u00f1o do to agriculture?\",\"acceptedAnswer\":{\"@type\":\"Answer\",\"text\":\"It shifts where the rain falls for a season. In strong events India, Southeast Asia, eastern Australia, southern Africa, Central America and Brazil's centre-north typically see less rain and more heat, while southern Brazil, the Pampas, East Africa's short rains, the southern United States and the Peru-Ecuador coast typically see more. Crop stress, pests, diseases and the demand for inputs move with it.\"}},\n{\"@type\":\"Question\",\"name\":\"Is the 2026-27 El Ni\u00f1o unusual?\",\"acceptedAnswer\":{\"@type\":\"Answer\",\"text\":\"The current outlook puts a greater than 90% chance on a very strong event through winter 2026-27, and a 75% chance on a historic one in October to December. The strength selector lets you read every region at moderate, strong and historic.\"}},\n{\"@type\":\"Question\",\"name\":\"Why does the same El Ni\u00f1o dry one part of Brazil and flood another?\",\"acceptedAnswer\":{\"@type\":\"Answer\",\"text\":\"The warm Pacific shifts the rain belts: the subtropics of South America sit under more storms while the tropics north of them get less. In 2023-24 Mato Grosso lost soybean to heat and dry spells while Rio Grande do Sul flooded.\"}},\n{\"@type\":\"Question\",\"name\":\"Does every El Ni\u00f1o behave the same way?\",\"acceptedAnswer\":{\"@type\":\"Answer\",\"text\":\"No, the direction is reliable but the size is not. In 2015 a warm western Indian Ocean partly offset the signal and India's monsoon still finished 14% below its long-period average, near the low end of a typical strong event. That is exactly what the confidence grade next to each region captures.\"}},\n{\"@type\":\"Question\",\"name\":\"How should a crop-protection or seed team use this?\",\"acceptedAnswer\":{\"@type\":\"Answer\",\"text\":\"Pick the phase and strength, read the playbook per region, and reallocate: push fungicides and adjuvants where the season is wet, biostimulants, insecticides and drought-tolerant seed where it is dry, and time the message to the months shown.\"}},\n{\"@type\":\"Question\",\"name\":\"Is this the typical El Ni\u00f1o pattern or this season's outlook?\",\"acceptedAnswer\":{\"@type\":\"Answer\",\"text\":\"For India, Pakistan and the Philippines the page shows the national seasonal outlook for the months it covers; the typical pattern of past events stays available for the same region. Every other region shows the typical pattern at the strength you pick. An outlook is a category, below normal or near normal, mapped to a percent by the band it names: under 85% of the long-period average reads as 25% below, 88 to 112% reads as normal.\"}},\n{\"@type\":\"Question\",\"name\":\"Where does the data come from and what leaves my browser?\",\"acceptedAnswer\":{\"@type\":\"Answer\",\"text\":\"Anomalies come from the official seasonal outlook and published analyses of past seasons; crop months from the GeoPard Global Crop Calendar. Nothing you upload leaves your browser: there is no upload here, no account and no tracking of what you select beyond anonymous page analytics.\"}}\n]}\n<\/script>\n\n<!-- ENI-GEO BEGIN -->\n<script type=\"application\/json\" id=\"eni-geo\" nowprocket data-no-optimize=\"1\" data-no-defer=\"1\" data-no-minify=\"1\">{\"q\":20,\"c\":[{\"i\":\"242\",\"n\":\"Fiji\",\"r\":[\"0-G7VKGOLFTtBADSOMSD\"]},{\"i\":\"834\",\"n\":\"Tanzania\",\"r\":[\"sqBlB4E1CCX6BnBRvBCXaNJhCe_BOHfX3DfvBKdBJ2BVenBGvCkBVyBXYJwCQCoBsBLmBMECYPWsEI\"]},{\"i\":\"732\",\"n\":\"W. Sahara\",\"r\":[\"5KyiBBlChECAnDlBBHVG3B7EAHNCQ6CEWgBM4B4BqBS0BOCMgBiCBmBKGW\"]},{\"i\":\"124\",\"n\":\"Canada\",\"r\":[\"x5Eo9BvD4BnCSViBGazBQFgBvBeBUWUAYjCahCqCzC4BvCjB_BsBtCMA4L0Ff0Ce6BF-DccPeIIUcDkCjB0BaGdyBGOMyBB6Ef-CD2BT3BToCHuEMqBXsBUnBQaOwCGoCfuBEmCR4DGDYkBI-BNBlBagBgBBSoB3CqBCsBwBc0BFoBR4BrBjBTqCHApB2BgBwBZLdmBZqBcckBEsB0DJ0BTETdTcVFTtCb3BFnBM9BnCvBZ3BBfRBZvBDvBhBrBrBPfBtB8BFkBjC4BIqCRmChB8CbuDFHhBMnBetB8BlBeOWoBTgCdUgCUuBcWcBabiBvBeuBqBdiDcKuDNgBK2CjBOPmCDMzCmBFcX6BWgCgCgEnEPX6CtB4CVQhBgBFQPCrB5BdhCNxBfhCF7FGhBdxBRnD5CiBIgC0B0CiB8BEkBTlBbanC0BTiCGoBsBCbaPxBZ_DnBrBbdCBiBmCiBtDFZWA2BRMZFNKddZxBdHDJlEAtC1BrCBRFIXrEvBbOoB-BPoCpBSGIREJQRBLSrE4BhBL_BKfDrDULIFWNAAPziBA\",\"_oDiuCeS2BAAHtBVbCJK\",\"1jDg7CtBWCOwDBkCVEJrEB\",\"rkD0tCOMcJPTRCHQ\",\"_0D49CVPpDOUS6BKyBZ\",\"p1D8gD7CCLMyCBcFFF\",\"94DuiDwBNLN5BHfKRODQsCD\",\"luDg9CpFSTqBnBQxCGtBMOQuGNiBNHPmCRwDDyGIsBNIRzCR3HB\",\"hrE2hD4BFNLpCL7BOgBM8BE\",\"1qEwiD0BHzDHqBSWB\",\"vlCkgCvB7BaOcHNNiBLUKmBLLdcIStBPjBtBGKiBLEtBhBXAcUlBK3DBFMYORKiBaqB-BYYkBOSBHL\",\"7oDsxC6CZEReCcLjBN9BKVS_CpBNY1BDiBUSkCeDGRWGWJ\",\"tiDu6CmBQuEnBGPqCIqBZgDPkBPmBjBpCT-EhB6BjB-BDLblCtBxBS9BmBzBFFVyDzBanBNd3EsBiD5BINtDQzCWxBUOM1DoBCLzDFhBMae-EGNOOU0BoBZetEiBYKpBYhCQVLnCDnJafOqBS5BALqBekBqBQmDKbZgBXkBgBmDQkCpBFZwCM\",\"j2D28CgFL7BjBvBHpBdtBCZkBCUUQoBM\",\"x5Ek_C2E4B0DGFddNvFZ1BI\",\"7lFyjCmBCLrBiBfPA5BwBFeUD\",\"7jEkjD8FTuBjBjES5CCoBMvBIDQ\",\"r6E08BTFhCU3BmBnBIPWEIoDRiBfoBRQV\",\"93Ei9CgFJyCdzElBxBbAPpDTTS9CUwCqClBYmEG\",\"3mE6-CsCEIRXTnEFjDR9BADMyCSzFD3BG2BoBmBMwDNoCXmCD5BoBkBOqBDehB\",\"jlEs7CsBRmBhCqElBDRhCDaPNNrESlJZVS1BMjBFxBgBmGQtCKtEBVO-CQjEK-BuBqDYqBHTR4CM4BTuBUkBLgBnBUQbqBkBGoBF\",\"x9D86CrBawBUwBHmCEMLlBR8BRFjBhCPlBE_DuBAOyCF\",\"nlEg8C2BCeJjBZ9BcOG\",\"j7D8_CeRCTRdhCDrBGCYhCDBgBiFO\",\"_3D4kDkCQRI-CCyBVmEPgBZwBLhEpB5ECpBQAOgBMnCBtBOXScS\",\"vyDsmD6FQ6BO8CNgBW8DMiIE4IHgFPBLlHhB2CA9EjBlCfjHT2BDZHgBRtF1BGHkCAAHpDXnDK1DFnEGDUqCKTciEN1Ba_BGgBQmCKMO3BQRUuEF-BOlHClCOvCcJO\",\"_9Cq0CZLtBBJUSWkBGgBLDV\",\"p4D82CYPXN1BMhBD1BSgCeuCZ\",\"zwCq-BiCFqBXnCMjBS\",\"_vC66BOTiCDhBTzBSJOQM\"],\"a\":\"CA\"},{\"i\":\"840\",\"n\":\"United States of America\",\"r\":[\"x5Eo9B0iBAAQOAGVMHsDTgBEgCJiBMsE3BMRSCKPSDFHqBRQnClB5BQR2EwBHYSGsCCuC2BmEAEKeIayBeeOJaGSLA1BiBjB9DrBbhBBTOVQADOMJBJ1Eb6BGMF3BLXELLMAJdbdZWUrBjBvBKeVODiBHRIXZGcNClBMBI1BXdpBLZVnBRFNrBZpBpBFbIbyB9DNjCdAHSNItByCIapB4BPGnBRzBe_DJQhBHFPGrBFdWhBFbK7BLhDhCJtBKhBPA5BUTwB5BqCbQhBBXfhBMTMXsB5BsBlCAAPtDA3EuBEIhDFFUrBcDMzCWFWlBoBfiCxBuBDgBVWIkCNeQmBKoCH2BX2BGI6BNUlBKKTiC\",\"niGkZYXjBXJGDaIWSF\",\"hwGwrCeDEPXFxBSoBI\",\"x_FuoCcBQLpChBTKFS4BU\",\"nwFk3CA3LuCLgCrBwCkB0C3BiCpCkCZAXVT3BcLiBzBiBVkBlDEtBMxCqBrDW3BD9DkBtBJKZzEhBFYSoBqBMJKnEtCcTlBbxCdJP9BVNRtBRbEtDlBlCLFG-D2ByBEqCoBoBWGgBUWtBLLIVPZWLPNU_BPEoBZOzBH9BcAWdSOYwBqB8BDgBUcDgBMHSVIcQtCRfI3BD5BKjCmByEmBgBAFT0CAfavBOjCmB1BMWWmCA0BSIUqBUyDWmBD8BW-BHcRSIkCBBJ8BFqBEgGV0BGoDR\",\"12G4vC6DThBLrBQjBDJECQ\"],\"a\":\"US\"},{\"i\":\"398\",\"n\":\"Kazakhstan\",\"r\":[\"mtDw9BdZhBDBnBVRtCOdnCjDZkBjCZLCVrBUrEC5BQVHFXhCOZFJRrChBPdPAJUzBAHiBTAEoBvBezDJlBkBlDwBlDXAzETBbgBZKtBHRLIaHOtBORkBVKBMoBDAeiBGkBFGoBFYnBBhBKzCZTGEWZadBhBcYeLIgBsBqBVEcyCsBgCAmErBsBS-BA0BTMM4BBKShCcoBUHKmBMbaSO2EO2DYkBSoCJOnBqBKyBNDVoBCkDmBPL0Bf6ClDUW4BX6BK2C1B0BGUZ\"],\"a\":\"KZ\"},{\"i\":\"860\",\"n\":\"Uzbekistan\",\"r\":[\"-lC0zBA0EmDYmDvBmBjB0DKwBdDnBUAIhB0BAKTQAQesCiBMDhBZeNcKwBVxBbvBCFMISzBHfvBhBCJReJIdVnB1BICY_CmBlCuBTqB5BENKFezBWjCjBGVtBA\"]},{\"i\":\"598\",\"n\":\"Papua New Guinea\",\"r\":[\"owFnDwExByBpBGViCZKTlBDKbkBZapBWCBRgBHLFqBRDLZBJKrCK1BwBTkBzBQ5BXEddN_BKBkI\",\"6-FxEONGTLJRmBlCqBMKkCtB\",\"k9FpHpBRVA3BWEM6BBMUEVWEiBcDYYAIFBVLZVBFL\",\"uhG1GyBvBDJLDROZ4BGEEL\"]},{\"i\":\"360\",\"n\":\"Indonesia\",\"r\":[\"owFnDCjIjBgBnBIJLzBASgBYMbsCtCiBhBE7BkBLRNDJgBdUqBOeBDM5BAPYjBGRU2BKWOgCRQtCqBXiBqBuBYkBAgCbqBH\",\"m8EjLGTZdnBDWmBmBQ\",\"4nFzIDeQcKdVb\",\"szEmFXjBelBHRuBlBvBDLbAjBlBbPjDFOtBRPYbCTOvBPNU7BCF2BTMRiBFiBEmBYaIZaX0BGYUSEmBLgBKyByDyCF\",\"2hFvDsBLQdhBQzCCKWwBC\",\"y-E3EZIHQoBCKLPN\",\"-_E2CCTYDEPBjBVEFXSVLDPaLyBWuB\",\"25EkBuBAmBeIJflBdHnBIjDHFdkBjBUSsCODTRGPVjBPmBzBHNkBtBAZTLPOSiBlBPJMEObYCmBZLGnDZDRKMmBFmBPANcSaa8CqBuByCP\",\"s2E5M1BcmBIkBXDLPA\",\"23E1K-BSFV7BL1BGAOgBIaL\",\"6zEtKaCKP_CNOYWAKOOJ\",\"0nE_HEPuCDISqCTQZ8BHwBVtBPrBQtCCvDaPDpCQFQlBEcmBwBByBR\",\"uiErBWxBcDUXLvDrBAzCiCvB4BxB2CjBiBZgCjBaTiBnCiCDW4CJ-D9DoBAiBbYhBeRPfkBP\"],\"a\":\"ID\"},{\"i\":\"032\",\"n\":\"Argentina\",\"r\":[\"51C5hCkBvB0BX4BJRTlBBTOjCCA4C\",\"_nC3lBjBpF0BhBFbYPBTlBzB7BT7DFKVJdIVXNnBDnBONJEnBcLWMMTlBLfZN9BlBAfTLdoBdmBHNjBtBVZtBlBPPTOnBaX1EORWCeZBPOBsBeQMaDUWiBO2BDYSGFQRIOQRQJuBQIFwBUuCYOLsCeaBiBYmBAmBJGTmCaoBDoBOkB2B-BLQIMAkCqBSOqBDKiBkB0BJWbQgBuBBwCpCgBF6CrBGRlB7B0CRgBGkBgBGiBUIUVAf7BnBhD7C\"],\"a\":\"AR\"},{\"i\":\"152\",\"n\":\"Chile\",\"r\":[\"51C5hCA3CkCBNPhBLxDW7CsB1BsBuEvBiBsBkBScF\",\"_2C_VUZGdUPLlBkBjDeEEJNpBpBRAjCHLMP1B9BNjBEnBZnBUlCKFAlBXlBChBdZMrCXNTtCGvBPHKtBSPNPSHGPRFEXN1BVhBETLZdPCrBQNaCBdSVmELjBA3BXFlBRArBM_C0BLYKYTaDmCQmBqBe7BMmBkBOiCsBNWyCbMLxBZEakEUcP0CSCkC8FH8BMgBFyBYwBgB6HJ6DUKKU\"]},{\"i\":\"180\",\"n\":\"Dem. Rep. Congo\",\"r\":[\"2kBzFKvCYXWxBvCHLXIRL3CoBVKGEpBdAfoBdEJWXNfGNSrBEBMzCFCwBLQCwBHoBxBAEOTAbHPhBVGnBHXiBT0B1DCrBJDMKEIcYEOQWASR4B4BBiBSmByB2BK2CUuBG0BkBiB8Bd6BJSaSDsBUeFUMkCAahBSDyBMuBrBDtBQFbXXnBJtCLJJxBKRCvB\"]},{\"i\":\"706\",\"n\":\"Somalia\",\"r\":[\"g0BjCXiBAyEuB6BYAkBc0BCgFyFAuC2CYB1BT5BtC5ExCjDnElD9BvC\"]},{\"i\":\"404\",\"n\":\"Kenya\",\"r\":[\"gxB7F5BoBBY3E2CAqBuBoCViCTc0ByBUFAVONcAyBhB6BHMSkBQQNcAhBrBAxEYhB1BhBZnCPN\"]},{\"i\":\"729\",\"n\":\"Sudan\",\"r\":[\"2eqKrBcEuBVYbuCNBOeDSMMHKc2BkBDBwFuBAAwC6OAanEkBXTVdHLLV1CBxB7BpDTJJtCLiCTOA8BRCBJZBOhBpBzBTDhBYpBjBpCKNHlBmBdFT1BZLaN\"]},{\"i\":\"148\",\"n\":\"Chad\",\"r\":[\"6dwYC_EjBEb1BIJLLERNdOCW7BtBXbpBlBTxBAENlBdxBPPKHJfDGMRsBpBeIS0BAVkBA0BPaEUZAAaPOQ2B0BmBC0BYiDfkBJ-BoBWgK3E\"]},{\"i\":\"332\",\"n\":\"Haiti\",\"r\":[\"z5C0YAjBJHKVlCGRFVMEMiCHOIRSAQXGIK8BH\"]},{\"i\":\"214\",\"n\":\"Dominican Rep.\",\"r\":[\"z5CyWJWKIEsBiCJINWABLmBPPPxBKVJFKNFPbLS\"]},{\"i\":\"643\",\"n\":\"Russia\",\"r\":[\"o1DqlD2CIuCT8ClBJjB3CFxFcdc1BIoDc\",\"ygEkjDkDXJPhHPoC2BgCC\",\"ytFm_CoDByEVfdzEChCJtCaUc2BI\",\"o5Fm-CmDJtBPrESKOqCF\",\"6uF27CmBQyBE6BPEJ1EG\",\"i4B4kDqEIIL-BQ6BH7EbrBKWM3CC\",\"uc-jC7DEKQ2BO8BNAT\",\"8iCm8CgDkBJS8GuB4IccPZLnInB7DlB7DtCIfuChB5ECLSnCKFWqBKBWwCiBlBE\",\"0yFkjCOlBAnB4BtD5BMZ5BoBnBBbdYZfH0DM0CXoBE2BkBSPUSEKZ\",\"ghHoxCzBRzBCkBTqBrBGRJJrCIxEhB3DzBNR5BanDdROlBP1BENZvBlBCPuBJF5BjBBRfQRlCTNtB5BJLnB5BlB1BwFS2BiBYCU-BIsE8CoCgBgB4BvBDXflDrBfwBnDLjDjCiBX3ENEc9BGxBT5DIjEL5IrF-BFUXmBJaUsBB6BrBChBfnBVvD7B5BNblEzDzBXZAXU1BdFNFcUCGuBJiBiBOwBFamBOsBkB0BhCLhBP7BAPmBvBclCMNoB1ByCjBO7BMlDHfTWJAVVLjBpBAR3BZvBQvBDtBS5Bb5CP3CG9BmBnBG3CL5BQHe_DgBnBpBQXnBZhDKZUpBAhBMpE1B5BJTazBF1C2B5BJ3BYTV5CmDzBgBQMjDlBnBBEWxBOpBJNoBnCKjBR1DX1ENRNcZlBLIJnBTiCbJR3BCLLzBU9BArBRlEsB_BAxCrBDbpBWfrBMHXdiBbeCaZDVUFRXlBFnBpBkBlBDZsBvBfZvCmBNQjBIXF9BahDKhEoCcGiBiBXQ8BQBIjBFCSUMoBCGOJWQgBxCMXUfFxBONYfCBMKIZYtCJTmB4BMlBSCGpBiBIMBSnBKVFDKpBKRsBRIQOLkBeYFIsBWpBS8DqCOU5BcQajBeaiBtBuBmBe9BaGcuEiBgCXuDJ4ErBeTEZtBV_BJzFebDgCdG7ByCVGUXQaQgDZiBKbe-CoBqCRYchBYUYdYwDLWVxBFAVgBN-BKKY-G2BeBlBXyBDcOqCA8BSuBXuBapBWUO2DLoG5BcUpBWAIvBEMUVsBqCkBakBeIqDJIXlBfYLObJ3BsBXPZtC5BsBFQQsBKMUiBSXYUarBCJYgBoBzBgBoCaJeUAWVPlBqBHRckCQyCCqCVjBiBDqB8HMfUuBauBCuCUqDEOMoDEiBJ4CWqCAMQmBS-CQkCN1BH6CHMRkBI2DA6DhBJTzFtBsDPkBIWZQKgCGiEFIToFFCgB2EHgCTSZXPyBfgCPmBqBgCRkCKuCLeMgCFbkB0BSqLZiBXoDdiFIwCHiBPFdyBJ2BI-GBmCjBwBMfaSSyGHsFlB\",\"_gHm2CqGlCBXaJHcsDFuCjBnBRhCDAnBPHlBCzCYHS1CCVOIOvBJSRVP\",\"_gHs5CgDJrBNzBB\",\"ghHy4CrBBFMyBQ\"],\"a\":\"RU\"},{\"i\":\"044\",\"n\":\"Bahamas\",\"r\":[\"3iDwhBuBCCJrBHDQ\",\"nhD6hBgBRFbHaRU\",\"3hDwfMBO3BJBXiBIa\"]},{\"i\":\"238\",\"n\":\"Falkland Is.\",\"r\":[\"vsC5gCwBYiBJYQgBRLN1BLROhBRTS\"]},{\"i\":\"578\",\"n\":\"Norway\",\"r\":[\"-SyjDOO8BC2FrBjDPXbhBHThBvBB1CakBO7BKtCiBdgBsDOWN6BA\",\"8mB-2CjDTQcxBQ9BLTdlBRrBKzBBrBUvBLFZrCGJVnBA_D_DONNPlBAZjBC1BaTNvBxBxBbYtCtB1BH3BUZmEkBaqDiBwCqBoFkEyFwC4CSgCB-BiBwEG-DdzBJsBZ\",\"oiBikD5BV1DDzDGHM5BArBS8DM6BJoBM0FX\",\"8eqhD3CPlCKaKXM0CIQN4BJ\"]},{\"i\":\"304\",\"n\":\"Greenland\",\"r\":[\"t6BqnDmEYsEB0BOsOB6HdpCPvLFUHuEG4DNuCMiBNrBXoJe4DHWP5FlB_DF8CBtC3BCrBwBZhENqCVKhBpBD0BhB5CDuBPLNvDFyBZARvCQTJ2BJ0BZQfnCHvCoBObtBTgFD3GjChFNnBN3BpB1CbpEVhBXBbTZ_BfQfnBnC3BB5BgBvCAnBWZoBlCyBTaFkB1BkBOeZOmBuB8BQQQKgBnDZxBMBcQU2DJnDoBnBFhBKuBmBpD0CxBQAQpDYhJBzDmB6FQrFK5CQGQqJmBQOrDOiBQkGgBPS6GS6DAsBLqDWsHf_CWGS\"]},{\"i\":\"260\",\"n\":\"Fr. S. Antarctic Lands\",\"r\":[\"m2C38BgCRAHJR9BBIuB\"]},{\"i\":\"626\",\"n\":\"Timor-Leste\",\"r\":[\"m8EjLGKiBI4BC5CnBFU\"]},{\"i\":\"710\",\"n\":\"South Africa\",\"r\":[\"uU3jBSUYbqBJ6BYA0EiBrBDZKNcEkC8BkBPiBBYIMgBWEYoB-C8BmCFezCD7BfENnBYVWEISgBAZvChBZzBlCpC_BdT9BPDLhEEjDlBRAvBaR-BMGBgBpC6D\"],\"a\":\"ZA\"},{\"i\":\"426\",\"n\":\"Lesotho\",\"r\":[\"okBlkBMLRfVHHLNDdeqBqBUISL\"]},{\"i\":\"484\",\"n\":\"Mexico\",\"r\":[\"tyE2oBiDGDH4EtBuDAAQmCA6BrBYrBULiBLYgBiBCcP6BpCUvBqCTV_BFnCanC0BnCqBLQP6DeaQSkCmCU8BCKHBTdvBGHPvBJKPANX1CDAVRAoBhBANzBATfAbhC4BfKpCVrF8BpBe_BQ7BoBTaJUOEGiBf2B9CgDhBSHKGYrBcJcVEpBoBjBqCAOhCaFPMxB6DrEmB9CUBejBRVrBwBxBeDyB1CuBXWUCOOCS1BoBhC4D\"],\"a\":\"MX\"},{\"i\":\"858\",\"n\":\"Uruguay\",\"r\":[\"_nC3lBYEgEtCYbRRMVRZtBVxBElBQZAZWiB0E\"]},{\"i\":\"076\",\"n\":\"Brazil\",\"r\":[\"1iClqBLWSSXc_DuCXDiD8C8BoBAgBTWTHOmCNGdDPgCZKRHpBIE2BLWMKDWSyBJYVMCmBrCCPuBMAJ0BXMXA7BiBrBIrBkBCoCzBH_BpB7CAC8BfXjBCNWbCKQnB-BMGASYKDWMgB0CqBkBBUgEHWPOAeeCCQXEAYuCAMOUjBGEWVgBEIMuBQEQeMBIhBED0BRKkCL2CgBOOFMWCIJDPWZPvBMlBYTUBwBc2BFCciBAoBPMMQNSC0ByCOCgB7CWFAbdhBMLoCFAnBgBa0DlBUXHVwBMuCT6BC8BhB0BrBgCNOLUrCPhCrCxC1BvCJALdCpCN3CNPF1BpBzBFpBfPJXrBA9BPnCdvBfhBnBFbGXP5BbVrBnC9BxBRlBZV\"],\"a\":\"BR\"},{\"i\":\"068\",\"n\":\"Bolivia\",\"r\":[\"92C1N0BBgCqB0BIBnCsBjBsBH8BhBYAYLKzBLAQtBsCBBlBWLKXRxBEVLJBOjBUrDLRhBRlCFItBCPfVczBKhBjBdDjBkDMmBTQFeTaasBRiBKOHOQUC-BKOjBgC\"]},{\"i\":\"604\",\"n\":\"Peru\",\"r\":[\"r3CrFjBCzCpBLfEVXJARLFoB9BJPcBOVkBBgBYB7BoBCkB_BJNB9BPTINJNShBjB_BTJpBYBQvCoBlDkCPiBGKrE-H7BqBMSRmBMcgBaEPJJAPiBAQTWQgB-BwBQsBqBMaDeKE6BvBYpB6CCeRZpBMAUV\"]},{\"i\":\"170\",\"n\":\"Colombia\",\"r\":[\"zzCyBFDTkBLNtCAAXYDBPdBAdQNIVT_DTWLAaqBdS5CBXqB5BwBJDlBWLFfGJSvBWFMQCBUIQUCgBuBNKIWJmBKKHiBPUGUMBIMHWYGwBgBGuBYUYAEIgBBiCwBOBKLHLXHlBtBPzBUBObAnBUPqCBchBkCGOFR_BUvBTTYVMnB\"]},{\"i\":\"591\",\"n\":\"Panama\",\"r\":[\"1gD6KEbHLLCFTViBKKjBcRBHNZLDHUVjBNFYRDHQrBIBJGkBJWQCOVUCKJsCgBWBmBLcX\"]},{\"i\":\"188\",\"n\":\"Costa Rica\",\"r\":[\"lnD-LPBKVJdVKHICQnBWNUDVVQAgBLGQMiCRKIsB3B\"]},{\"i\":\"558\",\"n\":\"Nicaragua\",\"r\":[\"xoD2NJHdOpBAtCoCkBOAUSAIMMHkBmBSH0BQN5BCtBPpBIP\"]},{\"i\":\"340\",\"n\":\"Honduras\",\"r\":[\"9nD4SzBPRIjBlBLIHLRAATVJTQBUZBhBWIayBgBoBDsCKaFwBhB\"]},{\"i\":\"222\",\"n\":\"El Salvador\",\"r\":[\"1vDgSiBVSEOFHZ3CYea\"]},{\"i\":\"320\",\"n\":\"Guatemala\",\"r\":[\"pzDmSAcUgB0BAAOnBiBSAAWqCADrCqBFlBbHZdZtBInBY\"]},{\"i\":\"084\",\"n\":\"Belize\",\"r\":[\"tvDoWEIIDOYQFJnCXZLAEsC\"]},{\"i\":\"862\",\"n\":\"Venezuela\",\"r\":[\"9rCwGGLNN1CfjCMSJEzBiBDCHdLDPtBPHLfDVWLoBXWUUTwBSgCNGjCFbiBpCCTQAoBNcTCQ0BmBuBYIAJXFORBTPXOfSEIcLOBeyBSFSOMObcAaVCNuCEYReDWMCKgDChBLORgBDeRIfkBJfVDPONhBNARJLad\"]},{\"i\":\"328\",\"n\":\"Guyana\",\"r\":[\"1mCsCfCvBbTCXULmBQwBVaEQHKVBZeKMASiBONOEQgBWyBnBCTOBmBhBFjBXJFdSbMAe5B\"]},{\"i\":\"740\",\"n\":\"Suriname\",\"r\":[\"jkC8C5BIBbVEd6BLARcGeYKGkBwBHkBMsBLVhBEbQXTzB\"]},{\"i\":\"250\",\"n\":\"France\",\"r\":[\"4H69BsCRTZFdbBAJbVBTUIORKZNLKfWDDRjBVvCK5BNDXtBDtBSNHpCSPOUYIwClC-B9BQDe0BIkCJNuBmBR-CgBMgBiBIGNSAwBjBUE4BV\",\"-Kq1BaOGhBLdRIJaIQ\"],\"a\":\"FR\"},{\"i\":\"218\",\"n\":\"Ecuador\",\"r\":[\"l-CFEdLZrBpBvBPf9BVPPUhBAAQKKDQWeJSNTXSIMHkBOGYyBDQyBawBVKRgBFMGmBV\"]},{\"i\":\"630\",\"n\":\"Puerto Rico\",\"r\":[\"7yCkXcJJJ1BBEWgBA\"]},{\"i\":\"388\",\"n\":\"Jamaica\",\"r\":[\"9gDkXaDcTnBHtBWGIaC\"]},{\"i\":\"192\",\"n\":\"Cuba\",\"r\":[\"5mDgdiCD0BbmBEqCzBkBHBJcBePDJZFvDBaWpBOViBXBxDiBOKnBCxBfjBAuBkB-BQ\"]},{\"i\":\"716\",\"n\":\"Zimbabwe\",\"r\":[\"gnB5blCGZSfGJoBREtBsBjB-BoCH4B8BQCEOWQeGEPgBCkChBHvEPfpBtB\"]},{\"i\":\"072\",\"n\":\"Botswana\",\"r\":[\"6kBzb9C7BXnBVDLfXHhBCjBQjC7BbDJOEahBsBA0DoBCAuE8CQQRYQqBGkB9BuBrBSDKnBgBFaR\"]},{\"i\":\"516\",\"n\":\"Namibia\",\"r\":[\"8Y9eAzE5BXpBKXcRTtB8BfiEFmCjByBdoCfoBBeqBOaAYRoFEcTiDFqDaqBL7BbPS7CPAtEnBBAzD\"]},{\"i\":\"686\",\"n\":\"Senegal\",\"r\":[\"7UgRReRQQGsB-B8BGuBV0B5BIvBQJCbnBDbK9CCtBJFekBAgBOiBHSIHMZFPKVLpBA\"]},{\"i\":\"466\",\"n\":\"Mali\",\"r\":[\"rOyPBcPKHwBMIIYoBJmBEGKgFAKcHGlB4K-BAsItFKRsBRAZsBEA7CVZBZ5CJPNxCAlBPrBnBPHTERjBdhBH1BZJFQRBHLvBCLMCMLAIYdkBnBRjBOPDBO\"]},{\"i\":\"478\",\"n\":\"Mauritania\",\"r\":[\"pVoaIO8EAF4BIWmBCAoDiEBA8B4EhD9BAmB3KIFJb_EAFJlBDnBKHXLHzB6BtBW7BFNLDUQ6BFwCdkB\"]},{\"i\":\"204\",\"n\":\"Benin\",\"r\":[\"sD6HhBDJcC8CJcZYGWOEISUEWYOAeXIjBDbfjBHZA5C\"]},{\"i\":\"562\",\"n\":\"Niger\",\"r\":[\"ySycK9BgBjBXhDBzBzBlBP1BQNAZaAPhBrBsBfVzBOvCVvBUnBJNQnBO1BLPnBDjBdYbLCcvBIAUVaBmBYAQO6CKCaWaA8C6BSyDuCqEsCgCPWVcO\"]},{\"i\":\"566\",\"n\":\"Nigeria\",\"r\":[\"sD6HA6CIagBkBAkDawBsBEoBNOPoBKwBTwCW0BNgBWIBcrBYNHVhBdfzCVPRzBbNVQPAXXJAdjCnCTfAhB2BbahCA\"]},{\"i\":\"120\",\"n\":\"Cameroon\",\"r\":[\"kSiQQZAzBWjBzBAHRqBdSrBjB5BB7BkB3BSNExB_BU7FCGePcRGRYKoBUmBKAYYQAWPcOS0BWQgB0CiBeIWPQAMMC\"]},{\"i\":\"768\",\"n\":\"Togo\",\"r\":[\"kB4NFVaXKbB7CKbfHTmBG4BJQD8BPUCMkBA\"]},{\"i\":\"288\",\"n\":\"Ghana\",\"r\":[\"A4NBLQTE7BKPF3BUlB3DxBjBMCQRiBcuCPuD2DC\"]},{\"i\":\"384\",\"n\":\"C\u00f4te d'Ivoire\",\"r\":[\"hK4MwBBIMSCGPaKqBdiBMaJM5BbtCShBBPnCG5DfG2BpBeMqCSMRwBKQ\"]},{\"i\":\"324\",\"n\":\"Guinea\",\"r\":[\"jR4PwBJoBECNQEkBNoBSejBHXMABLMLJPSvBRLAXPAJPJAVyBdHDkBTgB1BHflBrC2CSUmBKCgB\"]},{\"i\":\"624\",\"n\":\"Guinea-Bissau\",\"r\":[\"7UwPuBKqCBBflBJRTlBUXiB\"]},{\"i\":\"430\",\"n\":\"Liberia\",\"r\":[\"xK0JCfHRqBdF1BzBUhDuCwBgCUGWxBeQ\"]},{\"i\":\"694\",\"n\":\"Sierra Leone\",\"r\":[\"xQkLgBmB2BIUfEjBKCvB_BnBSTWLsB\"]},{\"i\":\"854\",\"n\":\"Burkina Faso\",\"r\":[\"3G-MI2BeiBGcMIUDQIsBoBmBQWGkBFClBWZATwBHJnBTDHRND5EBEzBZKhBLpBe\"]},{\"i\":\"140\",\"n\":\"Central African Rep.\",\"r\":[\"miByGjCAhBNPIrBTRERZ5BK7BejBhBDbzBKXVVlBFeROjB4BBcEgBeuBgBEIKQJyBQmBeDOyBAmBUcqBuBYcpBDtBiCrBANsBlBKXePGL\"]},{\"i\":\"178\",\"n\":\"Congo\",\"r\":[\"iXsEVlCJ1CxB1BRlBChB3B3BRSVANPZSbXfqBeWNcoBOESUTkBASsBFgBRYSuBJIdDLWEQyBAgCTY6BYW0BJ\"]},{\"i\":\"266\",\"n\":\"Gabon\",\"r\":[\"kO6CiCCOnBeEKHRtBSXGfRrBjBATUDRnBNObdVjCqCXqBc0CoCCAwB\"]},{\"i\":\"226\",\"n\":\"Eq. Guinea\",\"r\":[\"iM8CiCBAvBnCBHGOuB\"]},{\"i\":\"894\",\"n\":\"Zambia\",\"r\":[\"umBtKwCjBURKhBPpBIhBXxBUJ3DhBCbdFVPDNPB3B7BnCIVQ7BFzB4BCgEyCADuCOACLsBDORgBFYOKVeDgBnBeADqBJFnBWM4CHSWemCC\"]},{\"i\":\"454\",\"n\":\"Malawi\",\"r\":[\"-oBxLoBFWdK1BJfKzBOCONSbCzBPHLbZYCgCPKJDrBeYyBHiBQqBJiBTS\"]},{\"i\":\"508\",\"n\":\"Mozambique\",\"r\":[\"mrBrOeCwBJmBGQMiCOgBYUvFb3BZXxCjBnD3CDbchCGCDvChDxBRPEPKBBVfALyBIuBd0CqBuBQgBIwEjCiBfBFsB4DiBYTKEQJB_BaXMcQIB0BRcNONBJ0BKgB\"]},{\"i\":\"748\",\"n\":\"eSwatini\",\"r\":[\"ioBthBHRVDXWOoBgBDIjB\"]},{\"i\":\"024\",\"n\":\"Angola\",\"r\":[\"oQ_FNHHbJDLecYQN\",\"sPzHsBK2DBUzBYhBoBIWFQiBcIUADNyBAInBBvBMPBvB0BKSDELAhCxCAB_D0B3BnCRhDGbUnFDXSZApBNDaW4CW0BkBsBEeBWfgCOYTgCTaCI\"]},{\"i\":\"108\",\"n\":\"Burundi\",\"r\":[\"imB_CMlBnBrBPBBwBJSYBMWUB\"]},{\"i\":\"376\",\"n\":\"Israel\",\"r\":[\"0sB8oBFLNGHbIDJPSGAPT_BZkCiBsCcIDX\"]},{\"i\":\"422\",\"n\":\"Lebanon\",\"r\":[\"4sB0pBZHiB-BSBGPVPJT\"]},{\"i\":\"450\",\"n\":\"Madagascar\",\"r\":[\"-9BxPUrBSjCDRHLNYHLGtBLJBhB9C3IjCZ1BYb4CE6BSIWkCTyCUwBqCQ4BwBMUFSSFWcAYOSOP\"]},{\"i\":\"275\",\"n\":\"Palestine\",\"r\":[\"osBsnBRFKQHEIcOFFjB\"]},{\"i\":\"270\",\"n\":\"Gambia\",\"r\":[\"7UgRqBAWMQJaGILRHhBIfNjBAGS\"]},{\"i\":\"788\",\"n\":\"Tunisia\",\"r\":[\"8L8lBRoC5ByBBeYWK8CsBQcDAViBQCHTTAROJFhBZTIVUBKRQFBf7BlBAhBRJ\"]},{\"i\":\"012\",\"n\":\"Algeria\",\"r\":[\"7KoiBC6BgCeoCQQUuBQCeYCSQ0BGGQJId8CmBWqBIgCcmEKUFmBQ2CFJ7CXVCd6BxBerDDzDPPoBjCSGgBRSZpErCxDtClDVAarBSJSjNwI\"]},{\"i\":\"400\",\"n\":\"Jordan\",\"r\":[\"usBwoBGMuBPuCsBQxB3CZoBnBTTdFbZtBMUgCG0B\"]},{\"i\":\"784\",\"n\":\"United Arab Emirates\",\"r\":[\"wgCqeGCCL4CEyCuCINGdTBDZIDRHV5B3DUPyB\"]},{\"i\":\"634\",\"n\":\"Qatar\",\"r\":[\"w_B-eBeWYMLAXHVXE\"]},{\"i\":\"414\",\"n\":\"Kuwait\",\"r\":[\"g8BwlBQ5BbAJSjBEemBcB\"]},{\"i\":\"368\",\"n\":\"Iraq\",\"r\":[\"gxBmoBPyB4CoBQyBDc8BqBuBFOJSGatBcLCXTNJfclByBVUdFbMAAVWTxBEdlBpCEvDwC7BcvBK\"]},{\"i\":\"512\",\"n\":\"Oman\",\"r\":[\"glCscOyBSIHEEaUCSbWN2BNqBxBzBpCRCHJFzBRAZPLZZAPJAPRLVEtBPrB-C4DoBawCRc\"]},{\"i\":\"548\",\"n\":\"Vanuatu\",\"r\":[\"wwGxTFoBSLGfRE\"]},{\"i\":\"116\",\"n\":\"Cambodia\",\"r\":[\"ogEoPJwBaiB0BGmCTSakBNIZDvBjCfSXpBBhBPhBGjB-B\"]},{\"i\":\"764\",\"n\":\"Thailand\",\"r\":[\"wjE6RjBGzBFZhBKvBjBShBAGejBADrBhB9CCbaBYlCkCxBNPZDBUhBSFH_BuCFXHWQgCqBuCPkBDqBjByBOIOkB7B6CQISqBcCuBaSLCXcBJtCqBYkBFIOeBefEnBgBjBBhBNR\"],\"a\":\"TH\"},{\"i\":\"418\",\"n\":\"Laos\",\"r\":[\"omE4RjBORZhBOOSCiBfkBDoBdgBdCHNjBGpBXKuCbCBYRMsBqBCJWBFuBUGqBjCyBAOhBjBZwBX6BxCebKbFnB\"]},{\"i\":\"104\",\"n\":\"Myanmar\",\"r\":[\"k9DwZtBZbBRpBPH8B5CNjBNHkBxBEpBQjBpBtCDeMeLYCqBPWTiDRiBnCxBtBOOyBHkBfuBEQVEdgBBiBOHAeUKIoCeJqB2CAWyBceFDYOIBOWEOXSJB_BlBfDvBqBGKjBaHLhBuBVeMCPrBpB\"]},{\"i\":\"704\",\"n\":\"Vietnam\",\"r\":[\"uiEkNiBQqBCRYkCgBEwBHaGoBJcdc5ByCvBYkBaNiBxBApBkCWKoCEiBWSNkBHFXUPoBJ1BhBflBJbkC9CkBXafSpCFnCvCzBxClCNaMadY\"],\"a\":\"VN\"},{\"i\":\"408\",\"n\":\"North Korea\",\"r\":[\"qjFg1BGHPEdbCb1CtBFVmBXFJtBDNRnBGPLXSUWIetBWiBYsBWacULiBBFW-BQQYaX\"]},{\"i\":\"410\",\"n\":\"South Korea\",\"r\":[\"49EmvBUCOSuBEGKsBnCAtBNVnDbC0BRqBeGZiB\"]},{\"i\":\"496\",\"n\":\"Mongolia\",\"r\":[\"2tD09BqBGqE2BiBLqBAaTiDJoBaPYoBqBgEfId6BP4CMoBF-BlB4CF6CQ6BcuBRwBEvBlCKP-BBeOkCnBDN5CB3BjB9BPnBV_BMTZUb5BjBpFbvBVRMvBAhDe1BF9DKpB8BnCelDMNQOwBZgB5BOhBWJc\"]},{\"i\":\"356\",\"n\":\"India\",\"r\":[\"25DqjBCNNHEXdGxBbAVVhBBTRfdKHnCTJTgCLBFXVUMWSEUiBjDKBczBUNbeThBdYJFXU_BFNrCHCdVX5BZrBvBlCzBARpCZNdM1CRlBAjCTBRdMNjBJdnBlBmBhBgDjB6BPqCjB4BdgEF2C7BXbGzBwBUOLQtBiBaa4CAHiBVUFgBZSsBqBwBDoD8DAciBWfUb-BUS8BJsBGoBiBqBvBDfQTATdEMrB-CzBXRPlBgE5B2BDYTwDNC8BaIEnBkBP8CGCYPMgBGyC4BiBJcQUXNRsBF\"],\"a\":\"IN\"},{\"i\":\"050\",\"n\":\"Bangladesh\",\"r\":[\"6zDybAdNIChBlB0CjBCEPNVvBITgCGYXKiBedUOc0BTCbkDJThBRDLVWTGYMCU_B\"],\"a\":\"BD\"},{\"i\":\"064\",\"n\":\"Bhutan\",\"r\":[\"0yD2iBQLBX7CFjBQamBUKkCV\"]},{\"i\":\"524\",\"n\":\"Nepal\",\"r\":[\"kuD8iBB7BfAvCOXU1BE_D6BQmBoBagDrBOR-BZ8CL\"]},{\"i\":\"586\",\"n\":\"Pakistan\",\"r\":[\"qhDssBnBhBrBF7BKTRc9BgBThBVAbnD7DvBErBpBaRGfWTIhB3CAZZdKLcfehGLQuB4BUBSTIAiBnBSjBuBkCVkDG0BSCiBWWeAEMuBAOMBYSYYKNamBAKOBQUQNkBYSkEaeTMdiCP\"],\"a\":\"PK\"},{\"i\":\"004\",\"n\":\"Afghanistan\",\"r\":[\"kzC2uBiCNcOOHMSYAckBWJDLMBDhBQL4BemCDGJjEZXROjBTPCPJNlBAOZXJRXCXNLtBADLdAVVBhBzBRjDFjCWmBkBDadGP6BQWPGauCqBPeGIS2BSIgBiBIGOeL\"]},{\"i\":\"762\",\"n\":\"Tajikistan\",\"r\":[\"60CuuBWoBHedKKSiBBgBwB0BIHRGLQCNLrBGDVsBCyBLsCGKlBkBDGnBlCE3BdPMEiBLCEMVKbjBXALRNIbNLG\"]},{\"i\":\"417\",\"n\":\"Kyrgyzstan\",\"r\":[\"24C60BKSaGiCNGYWI6BPsEBsBTjCdNPzBFNXrBEZHnBRGJJHrCFxBMrBBEWsBFOMgBDyBcvBWbJdOiBaLE\"]},{\"i\":\"795\",\"n\":\"Turkmenistan\",\"r\":[\"0hCo0BSMuBIaJcfiCCFWkCkB0BVGdOJ6BDUpBmCtBgDlBBXdMFNhBHHf1BRHRdFpBQDiBbCtBiBrCapCDbVjBHFcGqBfOKcZCIiBmBJkBMdYLWfJDbLa\"]},{\"i\":\"364\",\"n\":\"Iran\",\"r\":[\"28BulBVUAWLAGcTexBWbmBKgBUOBYbMvBuCIOLuBcKahBcDsCiBMLNTaVKCMbmBJcT4BFgCKCKkBIcWsBGqDbuBhBcBEhBZtCQFPVQ5BeFEZlBjBkBtBoBRAhBUHCR3BTPtBjFaRwBRInCZvBMnBgBnBK3B8CTFZMPN\"]},{\"i\":\"760\",\"n\":\"Syria\",\"r\":[\"0sB8oBOsBWQFQRCDegBiBCWMHsBM2BHwBQiCGTZVJEbPxBlFzCtBQ\"]},{\"i\":\"051\",\"n\":\"Armenia\",\"r\":[\"k6BuwBNAPcRAhCgBBiB2BGYRHJWNLLkBRAb\"]},{\"i\":\"752\",\"n\":\"Sweden\",\"r\":[\"6NypCyByBOwBZUB2BakBmBAOQNOgEgEoBAKWsCFGaYC0DtBA9BOPjCLnBZGZrEhCd3BkCxBlBtBnBJPhCVlBxBEVftBBNmB9BmD\"]},{\"i\":\"112\",\"n\":\"Belarus\",\"r\":[\"ojBmmCqBJEJWGoBJCRHLqBhBBFmBR3BLUlBhBBNJBTvGYnCLNkBYILwBmBAsBQIWiBMDSkCW\"]},{\"i\":\"804\",\"n\":\"Ukraine\",\"r\":[\"4nBkhCuCKaXJHCLgBBOXyBNgBGYTyCLPfKVFNnBBTLBRhEhBCTzBSJJjCQDOjBDtBzBRGRFRIceDIwBBZmBNGCORKtBOpDbjCORHBKVKScKBLSmBgBSGGKTkBoCMwGXCUOKiBC\",\"6pBu5BKKqBJeVqBCHNrBF1BXVIIUrBMuBUFE\"],\"a\":\"UA\"},{\"i\":\"616\",\"n\":\"Poland\",\"r\":[\"sdsjCMvBXHiBnCFJRFlBfMRvBQnCJTOPDTWdCDMbEFJTICMdETMPaFkBPOMKJUsEsBoBFEJiFDUFKL\"],\"a\":\"PL\"},{\"i\":\"040\",\"n\":\"Austria\",\"r\":[\"oVk8BDPVAIHVf1BJ5CMJOrBN9BOEQMEULGKgCGgBJBiBcYeNkBUyBJSHCT\"]},{\"i\":\"348\",\"n\":\"Hungary\",\"r\":[\"0bw8BWJCJXJrB1B3BFtBPfI5BkBOaHIWAEQiBN2DiB0BH\"],\"a\":\"HU\"},{\"i\":\"498\",\"n\":\"Moldova\",\"r\":[\"ohBo8BkBKuBNSJBNOFalBvBCEHbdD0B9B4B\"]},{\"i\":\"642\",\"n\":\"Romania\",\"r\":[\"qjB84B2BHCJfFLvBzBUjCTnDETYKIJELHXKBSZIZegBGsB2BqBSkCNmCS-B3BEzB\"],\"a\":\"RO\"},{\"i\":\"440\",\"n\":\"Lithuania\",\"r\":[\"khBwlCERhBLHVrBPlBAJMTGAU7BOHiBuBMqDAiCd\"]},{\"i\":\"428\",\"n\":\"Latvia\",\"r\":[\"kiB6nCSHSrBjCVhCepDAtBLCeUYkBOgBdgBCIeiBG0BRiBB\"]},{\"i\":\"233\",\"n\":\"Estonia\",\"r\":[\"gjBsqCGHdXMjBPNhBCzBShBFGYPFXODYkDQ2CD\"]},{\"i\":\"276\",\"n\":\"Germany\",\"r\":[\"0RmjCKTLJQNGjBQZbAxChBKbsBZbXChBfK_BFFJrCWHJhBAGeUa5BIRKFcBkCYAKQKkBHOIIiBCGHcSJmB2BCCPoBJAN-BSgCb\"],\"a\":\"DE\"},{\"i\":\"100\",\"n\":\"Bulgaria\",\"r\":[\"qcq3BMRoDDkCU0BTTPNbMXhBGpBLATjBDbO9BJBaTMYkBTSDOKK\"],\"a\":\"BG\"},{\"i\":\"300\",\"n\":\"Greece\",\"r\":[\"8gBksBFL5BDCIxBIIQWNyCB\",\"2c2zB-BKcNkBEAUULVdtBGvBJcXpBFVWFJIXURPJqBdCVlBKMTXDOjBZAhBSV6BlB2BiBwBuCU\"]},{\"i\":\"792\",\"n\":\"Turkey\",\"r\":[\"-3BuuBRFNKtBGjEb1BIrBLLIBVVRNUOO5BGZX9BDfWrBCHRbDlBWrBBXoBdWUgBZSuBmB8BCSesCDwBauBKiCCgErBwCCwBWqBCoBTChBuBVbJMtBHNWf\",\"0gBq0BqBMiBFEPkBLHJvBBxBhBLaWeTM\"],\"a\":\"TR\"},{\"i\":\"008\",\"n\":\"Albania\",\"r\":[\"oaizBhBvBdYG6BJUSUeTErBQJ\"]},{\"i\":\"191\",\"n\":\"Croatia\",\"r\":[\"2Uk6BsBVgBHQGWZPPvCQbJNKHRsClCkBPDFhDoBfeICTSAOZGLRLOCOkBGeHQgBgBK\"]},{\"i\":\"756\",\"n\":\"Switzerland\",\"r\":[\"gMs7BDPmBHDPRHbGJPZEpBNdaTHCUcWAK-BCIKsBN\"]},{\"i\":\"056\",\"n\":\"Belgium\",\"r\":[\"2Hw_BRxBjBSTDvBkBRAFOiDMwBZ\"]},{\"i\":\"528\",\"n\":\"Netherlands\",\"r\":[\"0I8iCINJjBJPXAGpBvBahCDWKiB8B4BQgBA\"]},{\"i\":\"620\",\"n\":\"Portugal\",\"r\":[\"pLs0BgBQKT2BEKTRLH3BRBQXJbMJTZENPJpBAC4BREJQEaQOMoBLuB\"]},{\"i\":\"724\",\"n\":\"Spain\",\"r\":[\"pJsuBDOUaLKKcPYSCI4BSMJU1BDJUfPCcPS4BcyENiDAQNqCROIuBRuBECVlBZzBJrBjCQVVRJZdHbf3CCpBdREZkBlBG\"],\"a\":\"ES\"},{\"i\":\"372\",\"n\":\"Ireland\",\"r\":[\"3HqjCGbdjBlCX5BGiBqBVqB2CyBIVHV2BH\"]},{\"i\":\"540\",\"n\":\"New Caledonia\",\"r\":[\"ovGra0BpBNJzBc3BgCQA2BnB\"]},{\"i\":\"090\",\"n\":\"Solomon Is.\",\"r\":[\"0qGjNMNbCPYgBL\",\"kqG_LFHdkBHYMAgBzB\",\"ipGpMnBCHGCQaFUR\",\"ynG_JKVjCuBGE0Bb\",\"ukG3IQNZGNYYP\"]},{\"i\":\"554\",\"n\":\"New Zealand\",\"r\":[\"k9GhyBjBxBdPXQYiBNWrBQCOcOG4BPiBhCwCOEWVgBJKjBepBAaSJGd8BPWOUDV5BdAJLBX\",\"i0Gt2B8BqBgBoBGWcSShBcQMPAP9B_BQTfAhBPhBhCxBdpDSHOWeyBoB2BW\"]},{\"i\":\"036\",\"n\":\"Australia\",\"r\":[\"04F_yBYBCvBNNDfNKbbfE1BgDCSgCR2BO\",\"29EnoBtCdVlB1EDXTLClBX5BA9BiBAYaOEqBf2CCYRmBRQDebyBSRNmBgBbBUf4BS2BDYQcCdSayCuBeBoCgBgCK4B8BCmBciBShBQINSMUSJGgBeiBUICKSDAKkBM0BpByBDHWUgBSKFKQWYO4BEBUdOWEwBZmCRwBQSTZlBNAGPZnBCLwDnCgBJGLmBNaOQmBS2BH2BOmBFOS2BOQOtBKDQlBCjBOfaQgBhBGzBQXKhBDVOZiD5BFJYXQrBQKQRKGGpBuCnCMfBvBShBZtERjBdTbxBjBzCDpBXLrBBvCxB3BaGU5BjB1DgBZYPyBTQnBGOSJeTbhBFqBgCDe5BvBNffQCWtBsBGKzDsBnCDhDblBE\"],\"a\":\"AU\"},{\"i\":\"144\",\"n\":\"Sri Lanka\",\"r\":[\"omDsJFnBzBVTgBF6BSgCcVmBlC\"]},{\"i\":\"156\",\"n\":\"China\",\"r\":[\"8oE4WhBMAiBSSkCMIPZnBhBT\",\"qkD-0BBWaMjBkCkDaeoCuCNWSCoBiBEuBeKbiBV6BNafNvBOPmDLoCdqB7B-DJ2BGiDdwBASLwBW8DOuBO6BkBTcUagCLoBW-BQ4BkB6CCEOjCoBdN9BCJQwBmCwBP4BaASkBqBWMAWVKgBUyBI0BAgDZ2BxCOnBmCLwBbQlB8BAiBQiCMjBzBNrBZlBvBGhBNKhBFtBTBATZYPX9BPGVhBCTMZbtCtB3BLbTrBJWSHQeaTWvCpBZZlBBTRUbiBFARgBLsBc-BPGT3BLRVnBTTbsBVOlB0BjCAdZJKVYLP_BVDjDvEtDlCtBFXRNOVThDZNpBVBJcIQvDQTQGYjBIROhBVnCDpBPGtBVCDadLtBWMiBZIJkBpBFEwBmBgBCgCRKNYhCCOSTYbPhBKxC3BfFjCWvBnBBgBZH7CM9BaNS9BgBhBMPH9C0BLsBeDAUPUEgBpBwBhCQLejBeFoBjBEJmBKIFKoBSaIsBDOY0BGOQkCe\"],\"a\":\"CN\"},{\"i\":\"158\",\"n\":\"Taiwan\",\"r\":[\"o4EwepBhDViBDeYoBgBeSLFX\"]},{\"i\":\"380\",\"n\":\"Italy\",\"r\":[\"iN06BYFsBOKN4BJDTKPfGfNDfOTmBTUhBsBfeAKHJHkDvBDVVUjBGPZcNDVPBVhBPDQqBbsBlCuBdCjCsBbYLmBzBS5BZESVEJgBOMJaQHqBOaDKQcFSIEQ\",\"uS2vBeEPhCpDoBEW4CA\",\"8KkzBUMYbFzBRCPNNKLoCWB\"],\"a\":\"IT\"},{\"i\":\"208\",\"n\":\"Denmark\",\"r\":[\"sM4kC1BBRWAqBSWiBCwBYBVLLELWFxBnBKR\",\"uPkmCOTXfpBWFS6BM\"]},{\"i\":\"826\",\"n\":\"United Kingdom\",\"r\":[\"3HqjC1BIIWHWgBAsBXVb\",\"7D4iCGYbYvBIJKQSNMVTBmBTWOoBgBiBwCApBrB0CGJhBjBjBoBBoBzBaFkB7ByBHFZTLQTjBV5DJRIZRlBEbPVI8BqBkBK_BGJQqBMVWGa8BD\"],\"a\":\"GB\"},{\"i\":\"352\",\"n\":\"Iceland\",\"r\":[\"jSizCJZuBZzBf1EhBjFSmBS1CUmCIBMzCIca8BG-BZ-BWyBLiCWiCD\"]},{\"i\":\"031\",\"n\":\"Azerbaijan\",\"r\":[\"g6Bq0B4BbgBaoBxBgBLhBBNtBNJCTJBZWOULM9BhBAcjBSMMVOIKXSKG0BNGGTUKG\",\"25BuwBbEZiBmBJQb\"]},{\"i\":\"268\",\"n\":\"Georgia\",\"r\":[\"-xBq2BiDJ-BZYGkBHOPYJJFUTbDdM_BLnBUpBBGQJc7BgB\"]},{\"i\":\"608\",\"n\":\"Philippines\",\"r\":[\"i3E8PVekBAOPLhBPU\",\"o5EwMOkBWCFbeoBDlBnBzBXcIM\",\"g-EwKGvBNlBNqBTTOdLRvBWJeMSZULRTCbVHMQiBwBaOReKGScCBegBRIjB\",\"k0E0LzBlBoCyCUmBIfvBxB\",\"-4E4WHPObJhBXLFfKfmBAyBVDVOJDRtBoBLNXYjBFTICQMMLIFNZoBAmBQLE-BMkByBLMMEL\",\"y4EoOFUYLYAARrBbCmB\",\"88EmPMrBfKMlBTHBcLCFYYDAQZeoBAKP\"],\"a\":\"PH\"},{\"i\":\"458\",\"n\":\"Malaysia\",\"r\":[\"k9DiIGIiBRCTaEOQgBZSbExCOLQvBdBzC8BvBmDEeHQ\",\"szEmFxCGxBxDfJlBMRDXTzBFZYHaeNeIIiBiCQwB6BSVIOUBEuB0B6BQCUVCP8BXDPZBGRbN\"]},{\"i\":\"096\",\"n\":\"Brunei\",\"r\":[\"qwE6GDtBTCHNRWyBkB\"]},{\"i\":\"705\",\"n\":\"Slovenia\",\"r\":[\"oRk6BiBB-BQONfJPfdIjBFKEJQEU\"]},{\"i\":\"246\",\"n\":\"Finland\",\"r\":[\"4jBq2CFb-BZlBduBtBZhBkBdPZ6BbNT7DpCvGZVWnBMKoBTkBUYkBY2D0BDS3BSNQA-BzDuBYKsBT0BCsBJmBSUe-BMyBPPb\"]},{\"i\":\"703\",\"n\":\"Slovakia\",\"r\":[\"mcs9BbfpBM1DhBhBODOIOgBEaYeCUNoCKmBN\"]},{\"i\":\"203\",\"n\":\"Czechia\",\"r\":[\"4S8_BULeDBLUHGKcDELeBSTrCjBjCSjBTpCoBJcyCiBcA\"]},{\"i\":\"232\",\"n\":\"Eritrea\",\"r\":[\"ytBgSFQW2CMMeIUWiBzC6E_DLJRE5B-BhBQlBKXJXSLdtBI\"]},{\"i\":\"392\",\"n\":\"Japan\",\"r\":[\"sxFgxBlBpBCnBPfGTTbzBTlCB3BtBbQAelCHvBTtBAoBdZjCZPTOKkBZMPcmBMWakCwBwCMsBHoBmCcRyC2BYyBFsBQaqBIW3BAf\",\"40F-2BcSKtB7BJhBnB_BcVrBrBBFoBUgBsBCW2CwBpB6BV\",\"ulF6pBYYWDQQeHENVXPMTHLXZMAS\"]},{\"i\":\"600\",\"n\":\"Paraguay\",\"r\":[\"1oCnZMVD1BqBHSIaJQ_BeEOFTnDjBffFzCSmB8BFS5CsBfGpCiCSmCSiBsDMkBTCN\"],\"a\":\"PY\"},{\"i\":\"887\",\"n\":\"Yemen\",\"r\":[\"ghC4XsB9CbJJfnDjBhBbdAXPjCLZX7BBjBmDICAsBQMDSMUQL2DAKNSGeqBkBS0DQ\"]},{\"i\":\"682\",\"n\":\"Saudi Arabia\",\"r\":[\"2rB2kBsBFcaeGUUnBoB4CawBJ8BbwDvCuDHKRcAQhB2BnBErBWhBYDYhC4DTIISbZvC3DnBzDPjBRdpBRFJO1DAPMLTERPLVsBTQVgBJiBtBiBZmBD0BVsBnBYV0BnCiDTAM0B\"]},{\"n\":\"N. Cyprus\",\"r\":[\"-oB-rBIKiCKbPEHxBE\"]},{\"i\":\"196\",\"n\":\"Cyprus\",\"r\":[\"-oB-rByBFnBRTGJQUC\"]},{\"i\":\"504\",\"n\":\"Morocco\",\"r\":[\"1C-rBe7CKHFPzBFRPXBBdtBPPTnCP_BdFlClBJhCCLfNBRzB3BpBL3BVf5CDCUcgBDMOckBgBamCaOaqBWQkBE2CoCJyBU2BacmCiBmBiCeAYPiDH\"]},{\"i\":\"818\",\"n\":\"Egypt\",\"r\":[\"iuBwb5OAAiJLgBKYFSOS2BCgDdwBYkBEcDKTKM-BLUKajCdjCJFdehB2BoCvEgC3CHHCZ0BrB\"]},{\"i\":\"434\",\"n\":\"Libya\",\"r\":[\"ofwbAvCtBAAP_J4EjCjBVW_BQRafSRFnBkCQQGiDN2BSKAiB8BmBCgB2EjBShBoEtBmBeJeqBmBcG2BHORiCLKNNRGRJXMfAhJ\"]},{\"i\":\"231\",\"n\":\"Ethiopia\",\"r\":[\"47BgKxD3DzBBjBbXALNbAPOjBPLR5BIxBiBbANOAWTGXsBRKbiBXEOWUCS6CUKUwBYUYoCuBHMeYRYKmBJiBPcZejBbjBEXgBCKFJPuB1BiEvBiBA\"]},{\"i\":\"262\",\"n\":\"Djibouti\",\"r\":[\"-0B2PSDMKILAPXJSLNTJGfBDYckB\"]},{\"n\":\"Somaliland\",\"r\":[\"m9BoOAtCtB5BhBAhEwBtB2BYkBmBnBiGmB\"]},{\"i\":\"800\",\"n\":\"Uganda\",\"r\":[\"sqBlB9DBlBRHEKuCYoBcYPGEuBQMaJ8BKYSUbWhCtBnCApB\"]},{\"i\":\"646\",\"n\":\"Rwanda\",\"r\":[\"gmBtBQVBXfBLVXCKyBsBS\"]},{\"i\":\"070\",\"n\":\"Bosnia and Herz.\",\"r\":[\"mXq1BjBQvBoBbeISOJcK-CPJRUNFTdNFV\"]},{\"i\":\"807\",\"n\":\"Macedonia\",\"r\":[\"gc80BULCZtCTPKFQMWiCK\"]},{\"i\":\"688\",\"n\":\"Serbia\",\"r\":[\"yXs5B2BKadaHCRYJMIKDLXYfPLBRlBHGSlBWVRpBcKCGUTOKSNAQQVa\"]},{\"i\":\"499\",\"n\":\"Montenegro\",\"r\":[\"iZo1BJDBIRTCLjBYKcUMuBXLL\"]},{\"n\":\"Kosovo\",\"r\":[\"4Zq0BDORQYYsBTFRnBP\"]},{\"i\":\"780\",\"n\":\"Trinidad and Tobago\",\"r\":[\"jtCuNgBEBdnBAMKBQ\"]},{\"i\":\"728\",\"n\":\"S. Sudan\",\"r\":[\"ymBsEtBsBxBLREfuBdQJYrBmBAOvBeaMU2BeGmBlBOIqCJqBkBiBXUEqB0BNiBaCCKSBA7BUNMhCHLTBNVYDWRwBlCrCjC7BJZKPL\"]}],\"g\":{\"in-monsoon\":[\"25DqjBCNNHEXdGxBbAVVhBBTRfdKHnCTJTgCLBFXVUMWSEUiBjDKBczBUNbeThBdYJFXU_BFNrCHCdVX5BZrBvBlCzBARpCZNdM1CRlBAjCTBRdMNjBJdnBlBmBhBgDjB6BPqCjB4BdgEF2C7BXbGzBwBUOLQtBiBaa4CAHiBVUFgBZSsBqBwBDoD8DAciBWfUb-BUS8BJsBGoBiBqBvBDfQTATdEMrB-CzBXRPlBgE5B2BDYTwDNC8BaIEnBkBP8CGCYPMgBGyC4BiBJcQUXNRsBF\"],\"pk-indus\":[\"qhDssBnBhBrBF7BKTRc9BgBThBVAbnD7DvBErBpBaRGfWTIhB3CAZZdKLcfehGLQuB4BUBSTIAiBnBSjBuBkCVkDG0BSCiBWWeAEMuBAOMBYSYYKNamBAKOBQUQNkBYSkEaeTMdiCP\"],\"sea-rice-palm\":[\"owFnDCjIjBgBnBIJLzBASgBYMbsCtCiBhBE7BkBLRNDJgBdUqBOeBDM5BAPYjBGRU2BKWOgCRQtCqBXiBqBuBYkBAgCbqBH\",\"m8EjLGTZdnBDWmBmBQ\",\"4nFzIDeQcKdVb\",\"szEmFXjBelBHRuBlBvBDLbAjBlBbPjDFOtBRPYbCTOvBPNU7BCF2BTMRiBFiBEmBYaIZaX0BGYUSEmBLgBKyByDyCF\",\"2hFvDsBLQdhBQzCCKWwBC\",\"y-E3EZIHQoBCKLPN\",\"-_E2CCTYDEPBjBVEFXSVLDPaLyBWuB\",\"25EkBuBAmBeIJflBdHnBIjDHFdkBjBUSsCODTRGPVjBPmBzBHNkBtBAZTLPOSiBlBPJMEObYCmBZLGnDZDRKMmBFmBPANcSaa8CqBuByCP\",\"s2E5M1BcmBIkBXDLPA\",\"23E1K-BSFV7BL1BGAOgBIaL\",\"6zEtKaCKP_CNOYWAKOOJ\",\"0nE_HEPuCDISqCTQZ8BHwBVtBPrBQtCCvDaPDpCQFQlBEcmBwBByBR\",\"uiErBWxBcDUXLvDrBAzCiCvB4BxB2CjBiBZgCjBaTiBnCiCDW4CJ-D9DoBAiBbYhBeRPfkBP\",\"k9DiIGIiBRCTaEOQgBZSbExCOLQvBdBzC8BvBmDEeHQ\",\"szEmFxCGxBxDfJlBMRDXTzBFZYHaeNeIIiBiCQwB6BSVIOUBEuB0B6BQCUVCP8BXDPZBGRbN\",\"wjE6RjBGzBFZhBKvBjBShBAGejBADrBhB9CCbaBYlCkCxBNPZDBUhBSFH_BuCFXHWQgCqBuCPkBDqBjByBOIOkB7B6CQISqBcCuBaSLCXcBJtCqBYkBFIOeBefEnBgBjBBhBNR\",\"uiEkNiBQqBCRYkCgBEwBHaGoBJcdc5ByCvBYkBaNiBxBApBkCWKoCEiBWSNkBHFXUPoBJ1BhBflBJbkC9CkBXafSpCFnCvCzBxClCNaMadY\"],\"ph-monsoon\":[\"i3E8PVekBAOPLhBPU\",\"o5EwMOkBWCFbeoBDlBnBzBXcIM\",\"g-EwKGvBNlBNqBTTOdLRvBWJeMSZULRTCbVHMQiBwBaOReKGScCBegBRIjB\",\"k0E0LzBlBoCyCUmBIfvBxB\",\"-4E4WHPObJhBXLFfKfmBAyBVDVOJDRtBoBLNXYjBFTICQMMLIFNZoBAmBQLE-BMkByBLMMEL\",\"y4EoOFUYLYAARrBbCmB\",\"88EmPMrBfKMlBTHBcLCFYYDAQZeoBAKP\"],\"au-winter-crop\":[\"ohFvgBAjHjCV3BBhCbdjBxEBPP_Bb1BC7BeAeOFOSA8BXuBJ4BbqBDehBuBGEKRKCPkBKVUFASf4BWkDGECZWcwCuBcBkCcsCQ2B8BHgBeiBapBCSKBAINQEMuBHNEKSFDDICKKKOHHMUCFQQQMLGYUFOQ0BlBFZSWUBA9N\",\"ohFznBAkHgPABhPVGXaBkBfeOAAIrBHMYPiBPnBfDEOQAEeSWFoBVpBfPVXCNhBQOAJaTcPEHQGIXO5BIpBU1CH\",\"usF1sBGDZHjBGgBMYF\",\"mwFxvBAiFwBFQZIIYHCNyBlBgBKeHmCCIfoCbRJ_BHpBbZDKDBLnBYEMVJJGQKHI1BjBrBQpBCRM\",\"qwFxqBBqG-JAWQaCiBFQRYMBMWMsBAZ_DTnBtBtBT3BXhBJhCnCcHgBlCBdIZL3BoBBOXIHHParBE\",\"wsFvgBA6LoBNKRgBNgBMgB-CHyBGiBOIJQKMIsBQKMrBOFW_CcEiBbG5BSTQtCiD5BGHHDenBKhBKDGQSPEGIpBoBZqB1BKTBxBQlBPHXEVLCLXLPShBGZBVP9JAA4D3DA\"],\"saf-summer\":[\"uU3jBSUYbqBJ6BYA0EiBrBDZKNcEkC8BkBPiBBYIMgBWEYoB-C8BmCFezCD7BfENnBYVWEISgBAZvChBZzBlCpC_BdT9BPDLhEEjDlBRAvBaR-BMGBgBpC6D\",\"umBtKwCjBURKhBPpBIhBXxBUJ3DhBCbdFVPDNPB3B7BnCIVQ7BFzB4BCgEyCADuCOACLsBDORgBFYOKVeDgBnBeADqBJFnBWM4CHSWemCC\",\"gnB5blCGZSfGJoBREtBsBjB-BoCH4B8BQCEOWQeGEPgBCkChBHvEPfpBtB\",\"mrBrOeCwBJmBGQMiCOgBYUvFb3BZXxCjBnD3CDbchCGCDvChDxBRPEPKBBVfALyBIuBd0CqBuBQgBIwEjCiBfBFsB4DiBYTKEQJB_BaXMcQIB0BRcNONBJ0BKgB\",\"6kBzb9C7BXnBVDLfXHhBCjBQjC7BbDJOEahBsBA0DoBCAuE8CQQRYQqBGkB9BuBrBSDKnBgBFaR\",\"8Y9eAzE5BXpBKXcRTtB8BfiEFmCjByBdoCfoBBeqBOaAYRoFEcTiDFqDaqBL7BbPS7CPAtEnBBAzD\"],\"eaf-short-rains\":[\"gxB7F5BoBBY3E2CAqBuBoCViCTc0ByBUFAVONcAyBhB6BHMSkBQQNcAhBrBAxEYhB1BhBZnCPN\",\"47BgKxD3DzBBjBbXALNbAPOjBPLR5BIxBiBbANOAWTGXsBRKbiBXEOWUCS6CUKUwBYUYoCuBHMeYRYKmBJiBPcZejBbjBEXgBCKFJPuB1BiEvBiBA\",\"g0BjCXiBAyEuB6BYAkBc0BCgFyFAuC2CYB1BT5BtC5ExCjDnElD9BvC\"],\"sahel\":[\"sD6HA6CIagBkBAkDawBsBEoBNOPoBKwBTwCW0BNgBWIBcrBYNHVhBdfzCVPRzBbNVQPAXXJAdjCnCTfAhB2BbahCA\",\"7UgRReRQQGsB-B8BGuBV0B5BIvBQJCbnBDbK9CCtBJFekBAgBOiBHSIHMZFPKVLpBA\",\"rOyPBcPKHwBMIIYoBJmBEGKgFAKcHGlB4K-BAsItFKRsBRAZsBEA7CVZBZ5CJPNxCAlBPrBnBPHTERjBdhBH1BZJFQRBHLvBCLMCMLAIYdkBnBRjBOPDBO\",\"3G-MI2BeiBGcMIUDQIsBoBmBQWGkBFClBWZATwBHJnBTDHRND5EBEzBZKhBLpBe\",\"ySycK9BgBjBXhDBzBzBlBP1BQNAZaAPhBrBsBfVzBOvCVvBUnBJNQnBO1BLPnBDjBdYbLCcvBIAUVaBmBYAQO6CKCaWaA8C6BSyDuCqEsCgCPWVcO\",\"6dwYC_EjBEb1BIJLLERNdOCW7BtBXbpBlBTxBAENlBdxBPPKHJfDGMRsBpBeIS0BAVkBA0BPaEUZAAaPOQ2B0BmBC0BYiDfkBJ-BoBWgK3E\",\"-d6KTMEuBVYbuCNBOeDSMMHKc2BkBDBwFuBAAwC6OAanEkBXTVdHLLV1CBxB7BpDTJJtCLiCTOA8BRCBJZBOhBpBzBTDhBYpBjBpCKNHlBmBdFT1B\"],\"cam-dry-corridor\":[\"pzDmSAcUgB0BAAOnBiBSAAWqCADrCqBFlBbHZdZtBInBY\",\"9nD4SzBPRIjBlBLIHLRAATVJTQBUZBhBWIayBgBoBDsCKaFwBhB\",\"1vDgSiBVSEOFHZ3CYea\",\"xoD2NJHdOpBAtCoCkBOAUSAIMMHkBmBSH0BQN5BCtBPpBIP\",\"j6DgeF9BGVUxB0BnCqBLQP6DeaQSkCmCU8BCKHBTdvBGHPvBJKPANX1CDAVRAoBhBANzBATfAbhC4BfKpCVrF8BpBe_BQ7BoBTaJUOEGiBf2BtByBtDAWZRVrBwByQA\"],\"and-north\":[\"zzCyBFDTkBLNtCAAXYDBPdBAdQNIVT_DTWLAaqBdS5CBXqB5BwBJDlBWLFfGJSvBWFMQCBUIQUCgBuBNKIWJmBKKHiBPUGUMBIMHWYGwBgBGuBYUYAEIgBBiCwBOBKLHLXHlBtBPzBUBObAnBUPqCBchBkCGOFR_BUvBTTYVMnB\",\"9rCwGGLNN1CfjCMSJEzBiBDCHdLDPtBPHLfDVWLoBXWUUTwBSgCNGjCFbiBpCCTQAoBNcTCQ0BmBuBYIAJXFORBTPXOfSEIcLOBeyBSFSOMObcAaVCNuCEYReDWMCKgDChBLORgBDeRIfkBJfVDPONhBNARJLad\"],\"br-centre-north\":[\"pzCtMtCtBxCEE-BbTjBBJUfEKQXaPmBKEDIqEpB0EnC\",\"vvB7LHGSUgBTmBSiBAxB_B_BoB\",\"7gCtBXMlB0CzBUBQEMWNQKiBF6B0CKHUtCeTCT3BxBXpB\",\"xzCpMrEkCpEqBaaDOOoB0CmBiBFW8DJcPOAekBCFQVAAaiCAAMKJWOMjBgBRYKKLyBiBIQiBKSJDNOfFfMZHDYZMBCcOKSNQGMkBwBAAVSbsCrBEJxCrFMZP3B9DCHFfgBhBCRRDTbBLRDIVLZGRR\",\"x5BxSGUNcIaLaKeRMgBmBSRUBkBQIQDYOGiBJeMUWSFIXyBkBuBTUpBAVRJSZQChB1BJDHOFHJfI5CJpCTZlBmBESKEQePMrBERYLDhBUhBAAOPEpCnBAQ\",\"1yBnJGYNMTsCIMPiBIWgBEUB6BhByBrBRJjBvBFdILPVbUjBB\",\"j7BhUlBACWgBAEV\",\"lzBzadIFeUGQeLYMCHUQGFISCgBRBlBxBvC\",\"1_BrYrCgBCMJCFmBWsB6B0BgBgDKIDViBLQYKdUMWJCKIFwBSIHHhBMjBJHLKBNNAChBRFDWfADNCHmBAFRMTPRKDATZPnBEzBNbf\",\"78B1GsBgBWcqBsDWHENKKSLELHHMECHLhBSeCNgBQ-BNALZPTfIjBLXKTBPtBDZZdJVzBITFhBPGLQEKVSMYMCASTDbiBMgBDiBjBQLH\",\"7rChRkByBLaIOVQpBCD4C6DAQ4BW3BiBZkIRR7BI7BT_BhBzBfVVnBGblBCMcRPpBBjBUZDbXlBaCmBpCCBeNQOAFsBLO\",\"1_BrYBXVRVtB7BzBZpBPKdFRiCXITFpBIGqBLiBMGLKa-BJSWBSUaEkBTaIKFYQLbmBBANKBBLsCf\",\"3_BjZCYcgB0BOoBDaQAUJEQSLUGSSIBgBOACOSFAPmCoBSBCPiBAiBTMESXsBDQLbpBOhBbCGHPFITLBMXPdTFR1BdNdAjDhBPYIiBTCJyBHG1BFDLPSvBITL\",\"rwBvJGwBQDkBSJZMDIESJCWIE2BHETAVZE5BhBPMOUJKhBVXI\",\"xpCIDsBSAGMMDmBUuBFHQGKoBEMFBb0BTmBzCYLDJZFcBqBaIfMJsBKNjBSeUQOADOQSgBCwBRnBtDVbtBfWHBPFPfZDzBlB9B5HQrBchByCyCsFvC2BRcAW\",\"ngCVKDFNZRWkB\",\"x8BJTxBVALLfEFSGGHIGaQGoCF\",\"1zB7KeYBcoBCYTOKSJoBYKJNTQL6BiBaDL1BhBAXPNBfURTLUlBMxBjBHYRG\",\"l5B9MHCGiBHUW0BeKaaqBAGUJaMSHkBUgBaQAMYFHVQhBFXUlCMFLZEZxBtBdLhBKNFEXPVlBLbW\",\"lwB_HiB2BSKmCNW1B5BILbDKbCMalBRPE\",\"_3BldAOaMbMmDcGeMGGLeHBbbLNZjBAHIBJ5BBEHJD\",\"pzCtMHESSaFWMEHMScCEUSScAcdaDAzC8BHE5BfpBrBExBkB1BIXSPeA-BxBJ\",\"xpCIvBALjBPFRONJBbLCXaIEJYEiBNgBEObKAIZEFsBXcgBNaAUNGQiCUQQDMYCGFFVSFGRLNFjBOlBcRErB\",\"3uBrOPBRaSKHuBgCnBnBnB\",\"riCpcoBmBWuBqBewBHQREM2BGIFKxBUBHhBOVWAGKgBIcLZLANZRTAjBRxBpBFMLBCMfEN4BLOhBBxBSpBF\",\"5-BpMmB-BE0BgBaGQCQTIMIUFQJETLtBchBUEARLBLXWRDJMPYHflBSLJVEZvBRHGBJVKTLJePXhBMEWPPF6BS8B\"],\"br-south\":[\"5jCheaqBaSkBCyBRiBCMNO3BgBDBLMCGLZBOJHPjBHpBGbLFNjCOVENaXAO-B\",\"hjC5gB6CRGOcMqBFkBIHnDjBbJEDFDGQchBETYpBUnCGMkB\",\"hgCpnBaoBCITDJMAbZZblCbXHYQQXcpCwBPJBMfcdDqCwCoCqBAAoCFqBTUXkBHRbSAjB_B\"],\"plata-pampas\":[\"_nC3lBYEgEtCYbRRMVRZtBVxBElBQZAZWiB0E\",\"1oCnZMVD1BqBHSIaJQ_BeEOFTnDjBffFzCSmB8BFS5CsBfGpCiCSmCSiBsDMkBTCN\",\"_nC3lBjBpF0BhBFbYPBTlBzB7BT7DFKVHX5LAOsBYOLsCeaBiBYmBAmBJGTmCaoBDoBOkB2B-BLQIMAkCqBSOqBDKiBkB0BJWbQgBuBBwCpCgBF6CrBGRlB7B0CRgBGkBgBGiBUIUVAf7BnBhD7C\"],\"us-south-west\":[\"nvE4rBSbVjBIZpDHLelBSDK1CYAUxByBEUXODOCKQLJUeChBEDLTGEIfcFkBTWMqBHYqFAA3D4G_E\",\"xuEouBAfbHGnB3GgFA4DuHAAnG\",\"poEmnBvCB3EwBOOHUIWOQRYFsBcIAgBoGAAhH\",\"poEmnBAiHyHABnGvEAIJlCCARhBA\",\"j2DiqBSDA9BUlBFlBHPhBLIGRGENlBbPFKGZCKJdLEFPFATLEKHCdMRHHlCYPsBrC4ClBEdfLAnBUTqBlC4BwEAA0F6DAArCMHmDZIIaJsBKcL\",\"n2D0tBExDbMrBJZKFHzDiBAsC3DAAUwKAAT\",\"jwDgtB1BxCDlBzDAAWREDyDyFACHLLcA\",\"x1DopB0DAIbbzBsCABPMPdIFJaAEJKGCJNHcRPFdWAPNGJFtBcNL_BIM0BTmBAoB\",\"luD4rBN7DE9BrBFLQCQrCAc0BJ4BaqBKK2CA\",\"3tD8lBHQFNJAD-BM8DoDAcrDHPEjBnDAEXAA\",\"nqD4mBDkBIQbsDkDAJLmChCenBVbDXRCFRFIpDGDM\",\"rtDgmBDYoDAELqDFGHGSSB4B1EBtBHTdHBGIBdeLmBLDPaMORAIqBpBqBXEnBNLYhBEOAFElBFIITF\",\"hlDioBdoBlCiCKMcI0BBMLuBBsBjB3BxBbFCHHGBP\",\"9_C4rBQBPJZCXhBVArBkBtBCLMzBCbHAAvBASUoCYQUkHBGRNIPLHKALcABJMKCHPPjBIWL\",\"_qD4rB7FAe8B8BABIiIDPTnCXRTzBA\"],\"pe-ec-coast\":[\"r-C5STQPiBGKrE-H7BqBMSRmBMcgBaEPJJAPiBAQTWQgB-BwBQuBuBA_Q\",\"jiDhFFTVPPUhBAAQKKDQWeJSNTXSIMHkBOGYyBDQyBaOHAxG\"],\"ca-prairies\":[\"vpEo9BhFAbYEQNWhCyBJDhBcRAXerBOGGJIA2HwMAA3N\",\"vpEo9BA4NgKAAnFavI5KA\",\"lvDinC3HhFA3E3HAZwIAoFiJAHlBaNBPKSkBAe5BNPsCOuCP\"],\"cn-yangtze\":[\"suEqkBJCFeNPHCBMVJ_BWLDGJJDJGZJJRXeFDAekCQASVQDYaQZUwBFKGYZeJ6BCIZWAKJQEkBXLLQjBZC_Bf\",\"woEskBKSaKKFKEFKMEgCVWKCLIBOQGdULEPbfMJAbKBFPKBJbdCLHENfKBPZFBSTBSeHGCOZCNNNIHLJGFcIMbCaWJ6B\",\"uuE6fKcJCGQJCAcLKcgBNagCgBeBQKKFFNQOmBPDNSRDXpBJJdTJCRVdJrBPKnBLHIUYZBDI\",\"mxEolBPkBMMbQIOOCAYbIAKLGeYASWNSKDOPGMIwBZELOCFTKBEPQBMIINZBGHNPULBPiBDPXEFRDALVVfGLMTNGOJGTJ\",\"k1E6rBDLqBTY_BoBhB1BMRFaCaThBdVQvBGEOTMOQFIWDAQJEFHPCDQJCGUNBDMxBaCKQCOTcKKLcaSA\",\"03EsmBrBRqBCiBRXNSABNRAKHHLENRCPNNfFITDFOXFHcNEPoBaSIWSEDGQYiBPSKOL\",\"8jEkpBGHSGGJgBEAHkBNWEJLKJVhBRBRdxBOJJGLPPsBjBPINRWHGJpBFJQRJJICYVBCJRHCLXVEjBtBNvBqCLFLMEMRULZJKH8CNUMEboBdOKcLSqBAQbiBPOICLQACJGMSAASUAGQCRaONUgBOMVkBFKVDHKFYDOM\"],\"cn-north-plain\":[\"-yEqwBKTnChBbhBCNnCQDKOGMgBViBMUWEGQFMRGUMVgBOeWOEXOAYOoBCCQiBIUVDNIPkBBPRcJMVlBhBjBCRWBKKCVSKGfQjBTIJTNALmBHQGETHLiBF\",\"mwEonB3BOHa5BBdKlB0BJc-DmBIgByBLUEFNgBMxBrBcPYBUXRJVOARPTNAMTcHAXNBHN\",\"qzE6vBsBHAbOHSAUWUGkBPoBBLVPEtBLFTRCEHnBlBRARXTKbJNUPBHLbAbQwBmBdFGOFMciBeUaCSQ\",\"-pEorBDOOaH4BQWLaQOIiBgBMUYsBCWGEKMRTLSFGLFPVDLTWhBLfNFKPDbbPhBATPvBJ\",\"kmEquBIcyBBKasBsBYHSMJnBPNMZPVI3BNfe5BLJvBGaZVBAfrBUVDjBOAIfDFKVDBGQGBScEDOISNIISwBDCOiBEDUIS3Bc\"],\"cl-central\":[\"_2C_VUZGdUPLlBkBjDeEEJNpBpBRAjCHLMP1B9BNjBEnBZnBUlCKFAlBXlBChBdZE1BlDABiBSCkC8FH8BMgBFyBYwBgB6HJ6DUKKU\"],\"nz-crop\":[\"k9GhyBjBxBdPXQYiBNWrBQCOcOG4BPiBhCwCOEWVgBJKjBepBAaSJGd8BPWOUDV5BdAJLBX\",\"i0Gt2B8BqBgBoBGWcSShBcQMPAP9B_BQTfAhBPhBhCxBdpDSHOWeyBoB2BW\"],\"med-west\":[\"pJsuBDOUaLKKcPYSCI4BSMJU1BDJUfPCcPS4BcyENiDAQNqCROIuBRuBECVlBZzBJrBjCQVVRJZdHbf3CCpBdREZkBlBG\",\"pLs0BgBQKT2BEKTRLH3BRBQXJbMJTZENPJpBAC4BREJQEaQOMoBLuB\",\"iN06BYFsBOKN4BJDTKPfGfNDfOTmBTUhBsBfeAKHJHkDvBDVVUjBGPZcNDVPBVhBPDQqBbsBlCuBdCjCsBbYLmBzBS5BZESVEJgBOMJaQHqBOaDKQcFSIEQ\",\"uS2vBeEPhCpDoBEW4CA\",\"8KkzBUMYbFzBRCPNNKLoCWB\"],\"ua-black-sea\":[\"4nBkhCuCKaXJHCLgBBOXyBNgBGYTyCLPfKVFNnBBTLBRhEhBCTzBSJJjCQDOjBDtBzBRGRFRIceDIwBBZmBNGCORKtBOpDbjCORHBKVKScKBLSmBgBSGGKTkBoCMwGXCUOKiBC\",\"6pBu5BKKqBJeVqBCHNrBF1BXVIIUrBMuBUFE\",\"ohBo8BkBKuBNSJBNOFalBvBCEHbdD0B9B4B\",\"8yBs2BbDzBkBzCkBOEJCGEgBBMYWEdWeAGKSLOIcDIPgBJELPHINYHJLMRJJRELX\",\"kyBg-BgBESWeTAXaNbPANSBSTgBACHSKERVTEHVJtBSALRDBHVBHKXENSrBDJKYGBInBFGU6BMGOLOOILIQKAO\",\"k0Bw5BiBAOKsDrBAPNLGFLDQAAHZNlBOvBHPKIKlBKFGKMXIHOQIDIWC\",\"kyBg-BlBKDgBNGGKRCDIAaiDAGH2BBYLLJbCbPQHHTRPfD\",\"-wBq-BrBCZUfHnBGLYuDSQFBFSBFJOFEf\"],\"eu-central\":[\"sdsjCMvBXHiBnCFJRFlBfMRvBQnCJTOPDTWdCDMbEFJTICMdETMPaFkBPOMKJUsEsBoBFEJiFDUFKL\",\"4S8_BULeDBLUHGKcDELeBSTrCjBjCSjBTpCoBJcyCiBcA\",\"mcs9BbfpBM1DhBhBODOIOgBEaYeCUNoCKmBN\",\"0bw8BWJCJXJrB1B3BFtBPfI5BkBOaHIWAEQiBN2DiB0BH\",\"qjB84B2BHCJfFLvBzBUjCTnDETYKIJELHXKBSZIZegBGsB2BqBSkCNmCS-B3BEzB\",\"qcq3BMRoDDkCU0BTTPNbMXhBGpBLATjBDbO9BJBaTMYkBTSDOKK\"],\"eu-west\":[\"4H69BsCRTZFdbBAJbVBTUIORKZNLKfWDDRjBVvCK5BNDXtBDtBSNHpCSPOUYIwClC-B9BQDe0BIkCJNuBmBR-CgBMgBiBIGNSAwBjBUE4BV\",\"-Kq1BaOGhBLdRIJaIQ\",\"3HqjC1BIIWHWgBAsBXVb\",\"7D4iCGYbYvBIJKQSNMVTBmBTWOoBgBiBwCApBrB0CGJhBjBjBoBBoBzBaFkB7ByBHFZTLQTjBV5DJRIZRlBEbPVI8BqBkBK_BGJQqBMVWGa8BD\",\"0RmjCKTLJQNGjBQZbAxChBKbsBZbXChBfK_BFFJrCWHJhBAGeUa5BIRKFcBkCYAKQKkBHOIIiBCGHcSJmB2BCCPoBJAN-BSgCb\",\"2Hw_BRxBjBSTDvBkBRAFOiDMwBZ\",\"0I8iCINJjBJPXAGpBvBahCDWKiB8B4BQgBA\",\"sM4kC1BBRWAqBSWiBCwBYBVLLELWFxBnBKR\",\"uPkmCOTXfpBWFS6BM\"],\"kz-steppe\":[\"mtDw9BdZhBDBnBVRtCOdnCjDZkBjCZLCVrBUrEC5BQVHFXhCOZFJRrChBPdPAJUzBAHiBTAEoBvBezDJlBkBlDwBlDXAzETBbgBZKtBHRLIaHOtBORkBVKBMoBDAeiBGkBFGoBFYnBBhBKzCZTGEWZadBhBcYeLIgBsBqBVEcyCsBgCAmErBsBS-BA0BTMM4BBKShCcoBUHKmBMbaSO2EO2DYkBSoCJOnBqBKyBNDVoBCkDmBPL0Bf6ClDUW4BX6BK2C1B0BGUZ\"]}}<\/script>\n<!-- ENI-GEO END -->\n<!-- ENI-DATA BEGIN -->\n<script type=\"application\/json\" id=\"eni-data\" nowprocket data-no-optimize=\"1\" data-no-defer=\"1\" data-no-minify=\"1\">{\"version\":\"2026-09\",\"state\":{\"phase\":\"elnino\",\"strength\":\"historic\",\"strengthSource\":\"forecast\",\"headline\":\"El Ni\u00f1o continues to strengthen, with a strong-to-very strong El Ni\u00f1o likely through January-March 2027 (remaining greater than an 83% chance).\",\"issued\":\"2026-10-08\",\"roni\":1.69,\"oni\":2.16,\"indexAsOf\":\"JAS 2026\"},\"regions\":[{\"id\":\"in-monsoon\",\"label\":\"India: Indo-Gangetic Plain and Deccan\",\"short\":\"India\",\"countries\":[\"IN\"],\"coord\":[78,22],\"watch\":[{\"label\":\"the national monsoon forecast\",\"when\":\"April, updated late May and June\"},{\"label\":\"the monthly ENSO update\",\"when\":\"second Thursday of each month\"},{\"label\":\"the weekly rainfall departure maps\",\"when\":\"June to September\"}],\"crops\":[{\"id\":\"wheat\",\"label\":\"India rabi wheat\",\"plant\":[11,12],\"harvest\":[3,4],\"growing\":[12,2],\"weight\":112},{\"id\":\"corn\",\"label\":\"India corn (kharif maize)\",\"plant\":[6,7],\"harvest\":[10,11],\"growing\":[7,9],\"weight\":28},{\"id\":\"corn\",\"label\":\"India corn (rabi maize)\",\"plant\":[10,11],\"harvest\":[3,4],\"growing\":[11,1],\"weight\":12},{\"id\":\"soybean\",\"label\":\"India soybean (kharif)\",\"plant\":[6,7],\"harvest\":[9,11],\"growing\":[7,8],\"weight\":13},{\"id\":\"rice\",\"label\":\"India rice (kharif (monsoon))\",\"plant\":[6,7],\"harvest\":[10,12],\"growing\":[7,9],\"weight\":110},{\"id\":\"rice\",\"label\":\"India rice (rabi \/ summer)\",\"plant\":[11,12],\"harvest\":[3,5],\"growing\":[12,2],\"weight\":30},{\"id\":\"rapeseed\",\"label\":\"India canola (rabi mustard)\",\"plant\":[10,11],\"harvest\":[2,3],\"growing\":[11,1],\"weight\":12},{\"id\":\"cotton\",\"label\":\"Cotton (kharif)\",\"plant\":[5,7],\"harvest\":[10,1],\"growing\":null,\"weight\":6},{\"id\":\"pulses\",\"label\":\"Pulses (kharif)\",\"plant\":[6,7],\"harvest\":[10,11],\"growing\":null,\"weight\":8},{\"id\":\"groundnut\",\"label\":\"Groundnut (kharif)\",\"plant\":[6,7],\"harvest\":[10,11],\"growing\":null,\"weight\":7}]},{\"id\":\"pk-indus\",\"label\":\"Pakistan: Indus Plain\",\"short\":\"Pakistan\",\"countries\":[\"PK\"],\"coord\":[72,32.5],\"watch\":[{\"label\":\"the national monsoon outlook\",\"when\":\"May, updated in July\"},{\"label\":\"IRSA Indus water releases\",\"when\":\"kharif season, April to September\"}],\"crops\":[{\"id\":\"wheat\",\"label\":\"Pakistan rabi wheat\",\"plant\":[11,12],\"harvest\":[4,5],\"growing\":[12,2],\"weight\":28},{\"id\":\"rice\",\"label\":\"Pakistan rice (kharif)\",\"plant\":[5,7],\"harvest\":[9,11],\"growing\":[7,9],\"weight\":9},{\"id\":\"cotton\",\"label\":\"Cotton (kharif)\",\"plant\":[4,6],\"harvest\":[9,12],\"growing\":null,\"weight\":5},{\"id\":\"sugarcane\",\"label\":\"Sugarcane\",\"plant\":[2,3],\"harvest\":[11,3],\"growing\":null,\"weight\":8}]},{\"id\":\"sea-rice-palm\",\"label\":\"Southeast Asia: rice and oil palm belts\",\"short\":\"SE Asia\",\"countries\":[\"ID\",\"MY\",\"TH\",\"VN\"],\"coord\":[101,15],\"watch\":[{\"label\":\"the BMKG dry-season onset outlook\",\"when\":\"March, updated monthly\"},{\"label\":\"MPOB palm oil production data\",\"when\":\"monthly, around the 10th\"},{\"label\":\"the national El Ni\u00f1o advisory\",\"when\":\"monthly\"}],\"crops\":[{\"id\":\"rice\",\"label\":\"Indonesia rice (main wet season)\",\"plant\":[10,12],\"harvest\":[2,4],\"growing\":[12,2],\"weight\":22},{\"id\":\"rice\",\"label\":\"Indonesia rice (dry season)\",\"plant\":[4,6],\"harvest\":[7,9],\"growing\":[6,7],\"weight\":12},{\"id\":\"rice\",\"label\":\"Thailand rice (main wet season)\",\"plant\":[5,7],\"harvest\":[11,12],\"growing\":[7,9],\"weight\":18},{\"id\":\"rice\",\"label\":\"Thailand rice (dry season)\",\"plant\":[11,1],\"harvest\":[3,5],\"growing\":[1,2],\"weight\":5},{\"id\":\"rice\",\"label\":\"Vietnam rice (winter-spring)\",\"plant\":[11,1],\"harvest\":[2,4],\"growing\":[12,3],\"weight\":12},{\"id\":\"rice\",\"label\":\"Vietnam rice (summer-autumn)\",\"plant\":[4,5],\"harvest\":[7,8],\"growing\":[5,6],\"weight\":9},{\"id\":\"rice\",\"label\":\"Vietnam rice (autumn-winter)\",\"plant\":[8,9],\"harvest\":[11,12],\"growing\":[9,10],\"weight\":6},{\"id\":\"oilpalm\",\"label\":\"Oil palm (Indonesia, Malaysia)\",\"plant\":null,\"harvest\":[1,12],\"growing\":null,\"weight\":80},{\"id\":\"sugarcane\",\"label\":\"Sugarcane (Thailand)\",\"plant\":[10,12],\"harvest\":[12,4],\"growing\":null,\"weight\":10}]},{\"id\":\"ph-monsoon\",\"label\":\"Philippines: Luzon and Visayas rice and corn\",\"short\":\"Philippines\",\"countries\":[\"PH\"],\"coord\":[121,15.5],\"watch\":[{\"label\":\"the seasonal climate outlook\",\"when\":\"monthly\"},{\"label\":\"the El Ni\u00f1o advisory\",\"when\":\"monthly, first week\"},{\"label\":\"the monthly ENSO update\",\"when\":\"second Thursday of each month\"}],\"crops\":[{\"id\":\"rice\",\"label\":\"Philippines rice (wet season)\",\"plant\":[6,7],\"harvest\":[9,11],\"growing\":[7,9],\"weight\":8},{\"id\":\"rice\",\"label\":\"Philippines rice (dry season)\",\"plant\":[11,12],\"harvest\":[3,5],\"growing\":[12,2],\"weight\":4},{\"id\":\"corn\",\"label\":\"Corn (wet season)\",\"plant\":[5,6],\"harvest\":[9,10],\"growing\":null,\"weight\":5},{\"id\":\"corn\",\"label\":\"Corn (dry season)\",\"plant\":[11,12],\"harvest\":[3,4],\"growing\":null,\"weight\":3},{\"id\":\"sugarcane\",\"label\":\"Sugarcane (Negros and Luzon)\",\"plant\":[2,3],\"harvest\":[11,4],\"growing\":null,\"weight\":2},{\"id\":\"horticulture\",\"label\":\"Banana and pineapple\",\"plant\":null,\"harvest\":[1,12],\"growing\":null,\"weight\":6}]},{\"id\":\"au-winter-crop\",\"label\":\"Australia: WA wheat belt, eastern wheat belt and Queensland\",\"short\":\"Australia\",\"countries\":[\"AU\"],\"coord\":[136,-30],\"watch\":[{\"label\":\"the BoM ENSO Outlook\",\"when\":\"fortnightly\"},{\"label\":\"the ABARES crop report\",\"when\":\"quarterly, June and September matter most\"}],\"crops\":[{\"id\":\"wheat\",\"label\":\"Australia wheat (main season)\",\"plant\":[4,6],\"harvest\":[10,12],\"growing\":[6,9],\"weight\":28},{\"id\":\"barley\",\"label\":\"Australia barley (main season)\",\"plant\":[4,6],\"harvest\":[10,12],\"growing\":[6,9],\"weight\":13},{\"id\":\"rapeseed\",\"label\":\"Australia canola (main season)\",\"plant\":[4,6],\"harvest\":[10,12],\"growing\":[6,9],\"weight\":6},{\"id\":\"sorghum\",\"label\":\"Sorghum (summer crop)\",\"plant\":[10,12],\"harvest\":[3,5],\"growing\":null,\"weight\":2},{\"id\":\"cotton\",\"label\":\"Cotton (summer crop)\",\"plant\":[10,11],\"harvest\":[3,5],\"growing\":null,\"weight\":1}]},{\"id\":\"saf-summer\",\"label\":\"Southern Africa: Highveld, Zambia, Zimbabwe, Mozambique\",\"short\":\"Southern Africa\",\"countries\":[\"ZA\",\"ZM\",\"ZW\",\"MZ\",\"BW\",\"NA\"],\"coord\":[27,-22],\"watch\":[{\"label\":\"the SADC seasonal outlook\",\"when\":\"late August\"},{\"label\":\"the SAWS seasonal climate watch\",\"when\":\"monthly\"},{\"label\":\"the Crop Estimates Committee planting intentions\",\"when\":\"late October\"}],\"crops\":[{\"id\":\"corn\",\"label\":\"South Africa corn (main season)\",\"plant\":[10,12],\"harvest\":[5,8],\"growing\":[12,2],\"weight\":16},{\"id\":\"sunflower\",\"label\":\"South Africa sunflower (main season)\",\"plant\":[11,12],\"harvest\":[4,6],\"growing\":[12,2],\"weight\":0.8},{\"id\":\"soybean\",\"label\":\"Soybean (South Africa)\",\"plant\":[11,12],\"harvest\":[4,6],\"growing\":null,\"weight\":2},{\"id\":\"corn\",\"label\":\"Maize (Zambia, Zimbabwe, Mozambique)\",\"plant\":[11,12],\"harvest\":[4,6],\"growing\":null,\"weight\":6}]},{\"id\":\"eaf-short-rains\",\"label\":\"East Africa: Kenya and Ethiopian highlands\",\"short\":\"East Africa\",\"countries\":[\"KE\",\"ET\",\"SO\"],\"coord\":[38,4],\"watch\":[{\"label\":\"the ICPAC Greater Horn of Africa outlook\",\"when\":\"late August for the short rains\"},{\"label\":\"the KMD seasonal forecast\",\"when\":\"September\"}],\"crops\":[{\"id\":\"corn\",\"label\":\"Maize (long rains)\",\"plant\":[3,5],\"harvest\":[8,10],\"growing\":null,\"weight\":7},{\"id\":\"corn\",\"label\":\"Maize (short rains)\",\"plant\":[10,11],\"harvest\":[1,3],\"growing\":null,\"weight\":2},{\"id\":\"wheat\",\"label\":\"Wheat (Ethiopia meher)\",\"plant\":[6,7],\"harvest\":[11,1],\"growing\":null,\"weight\":5},{\"id\":\"teff\",\"label\":\"Teff (Ethiopia meher)\",\"plant\":[7,8],\"harvest\":[11,12],\"growing\":null,\"weight\":5},{\"id\":\"coffee\",\"label\":\"Coffee\",\"plant\":null,\"harvest\":[10,1],\"growing\":null,\"weight\":1}]},{\"id\":\"sahel\",\"label\":\"Sahel and West African savanna\",\"short\":\"Sahel\",\"countries\":[\"NG\",\"SN\",\"ML\",\"BF\",\"NE\",\"TD\",\"SD\"],\"coord\":[5,13],\"watch\":[{\"label\":\"the PRESASS seasonal forecast\",\"when\":\"late April\"},{\"label\":\"FAO GIEWS country briefs\",\"when\":\"quarterly\"}],\"crops\":[{\"id\":\"sorghum\",\"label\":\"Sorghum and millet\",\"plant\":[6,7],\"harvest\":[10,11],\"growing\":null,\"weight\":30},{\"id\":\"corn\",\"label\":\"Maize (Nigeria savanna)\",\"plant\":[5,7],\"harvest\":[9,11],\"growing\":null,\"weight\":12},{\"id\":\"groundnut\",\"label\":\"Groundnut\",\"plant\":[6,7],\"harvest\":[10,11],\"growing\":null,\"weight\":6},{\"id\":\"cotton\",\"label\":\"Cotton\",\"plant\":[6,7],\"harvest\":[11,1],\"growing\":null,\"weight\":2}]},{\"id\":\"cam-dry-corridor\",\"label\":\"Central America Dry Corridor and Mexico\",\"short\":\"Central America\",\"countries\":[\"MX\",\"GT\",\"HN\",\"SV\",\"NI\"],\"coord\":[-95,17],\"watch\":[{\"label\":\"the CRRH Central America climate forum\",\"when\":\"April and July\"},{\"label\":\"the SMN Mexico seasonal outlook\",\"when\":\"monthly\"}],\"crops\":[{\"id\":\"corn\",\"label\":\"Mexico corn (spring-summer)\",\"plant\":[5,7],\"harvest\":[11,1],\"growing\":[7,9],\"weight\":23},{\"id\":\"corn\",\"label\":\"Mexico corn (autumn-winter)\",\"plant\":[11,12],\"harvest\":[4,6],\"growing\":[12,2],\"weight\":4},{\"id\":\"pulses\",\"label\":\"Beans (primera)\",\"plant\":[5,6],\"harvest\":[8,9],\"growing\":null,\"weight\":1},{\"id\":\"pulses\",\"label\":\"Beans (postrera)\",\"plant\":[9,10],\"harvest\":[12,1],\"growing\":null,\"weight\":1},{\"id\":\"coffee\",\"label\":\"Coffee\",\"plant\":null,\"harvest\":[11,3],\"growing\":null,\"weight\":1}]},{\"id\":\"and-north\",\"label\":\"Colombia and Venezuela\",\"short\":\"N. Andes\",\"countries\":[\"CO\",\"VE\"],\"coord\":[-70,6],\"watch\":[{\"label\":\"the IDEAM climate outlook\",\"when\":\"monthly\"},{\"label\":\"the FNC coffee harvest bulletin\",\"when\":\"monthly\"}],\"crops\":[{\"id\":\"coffee\",\"label\":\"Coffee (Colombia)\",\"plant\":null,\"harvest\":[10,12],\"growing\":null,\"weight\":1},{\"id\":\"rice\",\"label\":\"Rice\",\"plant\":[3,5],\"harvest\":[8,10],\"growing\":null,\"weight\":3},{\"id\":\"corn\",\"label\":\"Maize\",\"plant\":[3,5],\"harvest\":[8,10],\"growing\":null,\"weight\":3},{\"id\":\"sugarcane\",\"label\":\"Sugarcane\",\"plant\":null,\"harvest\":[1,12],\"growing\":null,\"weight\":4}]},{\"id\":\"br-centre-north\",\"label\":\"Brazil centre-north: Cerrado, MATOPIBA, Sert\u00e3o and Bahia\",\"short\":\"Brazil C-N\",\"countries\":[\"BR\"],\"coord\":[-48,-10],\"watch\":[{\"label\":\"the CONAB monthly crop survey\",\"when\":\"around the 10th of each month\"},{\"label\":\"INMET rainfall onset maps\",\"when\":\"September to November\"}],\"crops\":[{\"id\":\"corn\",\"label\":\"Brazil corn (safrinha (2nd crop))\",\"plant\":[1,3],\"harvest\":[6,8],\"growing\":[3,5],\"weight\":110},{\"id\":\"corn\",\"label\":\"Brazil corn (first crop)\",\"plant\":[9,11],\"harvest\":[2,5],\"growing\":[11,1],\"weight\":25},{\"id\":\"soybean\",\"label\":\"Brazil soybean (main season)\",\"plant\":[9,12],\"harvest\":[1,5],\"growing\":[11,1],\"weight\":165},{\"id\":\"rice\",\"label\":\"Brazil rice (main season)\",\"plant\":[10,12],\"harvest\":[2,5],\"growing\":[11,1],\"weight\":7},{\"id\":\"cotton\",\"label\":\"Cotton (Mato Grosso, Bahia)\",\"plant\":[12,1],\"harvest\":[6,8],\"growing\":null,\"weight\":3}]},{\"id\":\"br-south\",\"label\":\"Brazil south: Paran\u00e1, Santa Catarina, Rio Grande do Sul\",\"short\":\"Brazil South\",\"countries\":[\"BR\"],\"coord\":[-52,-27],\"watch\":[{\"label\":\"the CONAB monthly crop survey\",\"when\":\"around the 10th of each month\"},{\"label\":\"Embrapa soybean rust alerts\",\"when\":\"November to March\"}],\"crops\":[{\"id\":\"corn\",\"label\":\"Brazil corn (safrinha (2nd crop))\",\"plant\":[1,3],\"harvest\":[6,8],\"growing\":[3,5],\"weight\":33},{\"id\":\"corn\",\"label\":\"Brazil corn (first crop)\",\"plant\":[9,11],\"harvest\":[2,5],\"growing\":[11,1],\"weight\":7.5},{\"id\":\"soybean\",\"label\":\"Brazil soybean (main season)\",\"plant\":[9,12],\"harvest\":[1,5],\"growing\":[11,1],\"weight\":49.5},{\"id\":\"rice\",\"label\":\"Brazil rice (main season)\",\"plant\":[10,12],\"harvest\":[2,5],\"growing\":[11,1],\"weight\":2.1},{\"id\":\"wheat\",\"label\":\"Wheat (Paran\u00e1, RS)\",\"plant\":[5,7],\"harvest\":[9,12],\"growing\":null,\"weight\":8}]},{\"id\":\"plata-pampas\",\"label\":\"Argentina, Uruguay and Paraguay: the Pampas\",\"short\":\"Pampas\",\"countries\":[\"AR\",\"UY\",\"PY\"],\"coord\":[-63,-37],\"watch\":[{\"label\":\"the Bolsa de Cereales weekly crop report\",\"when\":\"Thursdays\"},{\"label\":\"the SMN Argentina seasonal outlook\",\"when\":\"monthly\"}],\"crops\":[{\"id\":\"wheat\",\"label\":\"Argentina wheat (main season)\",\"plant\":[5,7],\"harvest\":[11,1],\"growing\":[7,10],\"weight\":17},{\"id\":\"corn\",\"label\":\"Argentina corn (main season)\",\"plant\":[9,1],\"harvest\":[3,7],\"growing\":[11,2],\"weight\":51},{\"id\":\"soybean\",\"label\":\"Argentina soybean (main season)\",\"plant\":[10,1],\"harvest\":[3,6],\"growing\":[12,3],\"weight\":50},{\"id\":\"soybean\",\"label\":\"Paraguay soybean (main season)\",\"plant\":[9,12],\"harvest\":[1,4],\"growing\":[11,1],\"weight\":10},{\"id\":\"barley\",\"label\":\"Argentina barley (main season)\",\"plant\":[6,7],\"harvest\":[11,1],\"growing\":[8,10],\"weight\":5},{\"id\":\"sunflower\",\"label\":\"Argentina sunflower (main season)\",\"plant\":[9,12],\"harvest\":[1,4],\"growing\":[11,1],\"weight\":4.5}]},{\"id\":\"us-south-west\",\"label\":\"US southern tier, Delta and California\",\"short\":\"US South\",\"countries\":[\"US\"],\"coord\":[-100,33],\"watch\":[{\"label\":\"the monthly seasonal outlook\",\"when\":\"third Thursday of each month\"},{\"label\":\"USDA NASS crop progress\",\"when\":\"weekly, April to November\"}],\"crops\":[{\"id\":\"wheat\",\"label\":\"United States winter wheat\",\"plant\":[9,10],\"harvest\":[6,8],\"growing\":[3,5],\"weight\":33},{\"id\":\"wheat\",\"label\":\"United States spring wheat\",\"plant\":[4,5],\"harvest\":[8,9],\"growing\":[5,7],\"weight\":15},{\"id\":\"rice\",\"label\":\"United States rice (main season)\",\"plant\":[3,5],\"harvest\":[8,10],\"growing\":[5,7],\"weight\":7},{\"id\":\"barley\",\"label\":\"United States spring barley\",\"plant\":[4,5],\"harvest\":[7,9],\"growing\":[5,7],\"weight\":3.5},{\"id\":\"rapeseed\",\"label\":\"United States spring canola\",\"plant\":[5,5],\"harvest\":[8,9],\"growing\":[6,7],\"weight\":1.8},{\"id\":\"cotton\",\"label\":\"Cotton (Texas, Delta)\",\"plant\":[4,6],\"harvest\":[9,11],\"growing\":null,\"weight\":3}]},{\"id\":\"pe-ec-coast\",\"label\":\"Peru and Ecuador coast\",\"short\":\"Peru coast\",\"countries\":[\"PE\",\"EC\"],\"coord\":[-79,-6],\"watch\":[{\"label\":\"the ENFEN coastal El Ni\u00f1o alert\",\"when\":\"monthly\"},{\"label\":\"the SENAMHI seasonal outlook\",\"when\":\"monthly\"}],\"crops\":[{\"id\":\"rice\",\"label\":\"Rice (coastal valleys)\",\"plant\":[12,2],\"harvest\":[4,6],\"growing\":null,\"weight\":3},{\"id\":\"horticulture\",\"label\":\"Bananas and vegetables\",\"plant\":null,\"harvest\":[1,12],\"growing\":null,\"weight\":4},{\"id\":\"sugarcane\",\"label\":\"Sugarcane\",\"plant\":null,\"harvest\":[1,12],\"growing\":null,\"weight\":2}]},{\"id\":\"ca-prairies\",\"label\":\"Canada: Alberta, Saskatchewan and Manitoba\",\"short\":\"Canada Prairies\",\"countries\":[\"CA\"],\"coord\":[-108,52],\"watch\":[{\"label\":\"the Environment and Climate Change Canada seasonal outlook\",\"when\":\"issued monthly\"},{\"label\":\"provincial crop condition reports (Alberta, Saskatchewan, Manitoba)\",\"when\":\"weekly, May to September\"}],\"crops\":[{\"id\":\"wheat\",\"label\":\"Canada spring wheat\",\"plant\":[4,6],\"harvest\":[8,9],\"growing\":[6,7],\"weight\":28.05},{\"id\":\"barley\",\"label\":\"Canada spring barley\",\"plant\":[4,5],\"harvest\":[8,9],\"growing\":[6,7],\"weight\":7.6499999999999995},{\"id\":\"rapeseed\",\"label\":\"Canada spring canola\",\"plant\":[5,6],\"harvest\":[8,10],\"growing\":[6,7],\"weight\":16.15},{\"id\":\"pulses\",\"label\":\"Lentils and field peas\",\"plant\":[5,5],\"harvest\":[8,9],\"growing\":null,\"weight\":10}]},{\"id\":\"cn-yangtze\",\"label\":\"China: Yangtze basin (Hubei, Hunan, Jiangxi, Anhui, Jiangsu, Zhejiang, Sichuan)\",\"short\":\"Yangtze basin\",\"countries\":[\"CN\"],\"coord\":[113,30.5],\"watch\":[{\"label\":\"the China Meteorological Administration flood-season outlook\",\"when\":\"issued ahead of the June to August flood season\"},{\"label\":\"the Ministry of Water Resources Yangtze flood bulletin\",\"when\":\"June to August\"}],\"crops\":[{\"id\":\"corn\",\"label\":\"China corn (main season)\",\"plant\":[4,5],\"harvest\":[9,10],\"growing\":[6,7],\"weight\":162.25},{\"id\":\"soybean\",\"label\":\"China soybean (main season)\",\"plant\":[5,6],\"harvest\":[9,10],\"growing\":[6,8],\"weight\":11.55},{\"id\":\"rice\",\"label\":\"China rice (single \/ mid-season)\",\"plant\":[5,6],\"harvest\":[9,10],\"growing\":[6,8],\"weight\":55.00000000000001},{\"id\":\"rice\",\"label\":\"China early rice\",\"plant\":[3,4],\"harvest\":[7,7],\"growing\":[4,6],\"weight\":14.3},{\"id\":\"rice\",\"label\":\"China late rice\",\"plant\":[6,7],\"harvest\":[10,11],\"growing\":[7,9],\"weight\":11},{\"id\":\"rapeseed\",\"label\":\"China canola (winter rapeseed)\",\"plant\":[9,10],\"harvest\":[4,5],\"growing\":[11,3],\"weight\":8.25},{\"id\":\"cotton\",\"label\":\"Cotton (Hubei, Jiangsu)\",\"plant\":[4,5],\"harvest\":[9,11],\"growing\":null,\"weight\":4}]},{\"id\":\"cn-north-plain\",\"label\":\"China: North Plain (Hebei, Henan, Shandong, Shanxi, Shaanxi)\",\"short\":\"North China Plain\",\"countries\":[\"CN\"],\"coord\":[114,36],\"watch\":[{\"label\":\"the China Meteorological Administration drought monitoring bulletin\",\"when\":\"monthly\"},{\"label\":\"the Ministry of Agriculture and Rural Affairs winter wheat condition report\",\"when\":\"March, at green-up\"}],\"crops\":[{\"id\":\"wheat\",\"label\":\"China winter wheat\",\"plant\":[9,10],\"harvest\":[5,6],\"growing\":[3,4],\"weight\":59},{\"id\":\"wheat\",\"label\":\"China spring wheat\",\"plant\":[3,4],\"harvest\":[7,8],\"growing\":[5,6],\"weight\":9.5},{\"id\":\"corn\",\"label\":\"China corn (main season)\",\"plant\":[4,5],\"harvest\":[9,10],\"growing\":[6,7],\"weight\":147.5}]},{\"id\":\"cl-central\",\"label\":\"Chile: central valley\",\"short\":\"Chile\",\"countries\":[\"CL\"],\"coord\":[-71,-35],\"watch\":[{\"label\":\"the DGA reservoir and snowpack bulletin\",\"when\":\"monthly through winter and spring\"},{\"label\":\"the CR2 seasonal climate outlook\",\"when\":\"issued ahead of each season\"}],\"crops\":[{\"id\":\"wheat\",\"label\":\"Wheat (central valley)\",\"plant\":[5,6],\"harvest\":[12,1],\"growing\":null,\"weight\":4},{\"id\":\"corn\",\"label\":\"Maize (central valley)\",\"plant\":[10,11],\"harvest\":[3,4],\"growing\":null,\"weight\":3},{\"id\":\"horticulture\",\"label\":\"Fruit and wine grapes\",\"plant\":null,\"harvest\":[2,4],\"growing\":null,\"weight\":10}]},{\"id\":\"nz-crop\",\"label\":\"New Zealand\",\"short\":\"New Zealand\",\"countries\":[\"NZ\"],\"coord\":[172.5,-43.5],\"watch\":[{\"label\":\"the NIWA seasonal climate outlook\",\"when\":\"issued monthly\"},{\"label\":\"the NIWA ENSO update\",\"when\":\"quarterly\"}],\"crops\":[{\"id\":\"wheat\",\"label\":\"Wheat (Canterbury)\",\"plant\":[4,5],\"harvest\":[1,2],\"growing\":null,\"weight\":5},{\"id\":\"barley\",\"label\":\"Barley (Canterbury)\",\"plant\":[8,9],\"harvest\":[1,2],\"growing\":null,\"weight\":4},{\"id\":\"horticulture\",\"label\":\"Kiwifruit and apples\",\"plant\":null,\"harvest\":[3,6],\"growing\":null,\"weight\":8}]},{\"id\":\"med-west\",\"label\":\"Western Mediterranean: Spain, Portugal and Italy\",\"short\":\"W. Mediterranean\",\"countries\":[\"ES\",\"PT\",\"IT\"],\"coord\":[-3.7,40],\"watch\":[{\"label\":\"the AEMET seasonal outlook\",\"when\":\"issued monthly\"},{\"label\":\"the ECMWF seasonal forecast\",\"when\":\"updated monthly\"}],\"crops\":[{\"id\":\"wheat\",\"label\":\"Spain winter wheat\",\"plant\":[11,12],\"harvest\":[6,7],\"growing\":[1,4],\"weight\":7},{\"id\":\"wheat\",\"label\":\"Italy durum wheat\",\"plant\":[10,11],\"harvest\":[6,7],\"growing\":[12,4],\"weight\":7},{\"id\":\"rice\",\"label\":\"Italy rice (main season)\",\"plant\":[4,5],\"harvest\":[9,10],\"growing\":[6,8],\"weight\":1.5},{\"id\":\"barley\",\"label\":\"Spain winter barley\",\"plant\":[11,12],\"harvest\":[6,7],\"growing\":[1,4],\"weight\":7},{\"id\":\"sunflower\",\"label\":\"Spain sunflower (main season)\",\"plant\":[2,4],\"harvest\":[7,9],\"growing\":[4,6],\"weight\":0.9},{\"id\":\"wheat\",\"label\":\"Wheat (Portugal)\",\"plant\":[11,12],\"harvest\":[6,7],\"growing\":null,\"weight\":2},{\"id\":\"horticulture\",\"label\":\"Olives and wine grapes (Portugal)\",\"plant\":null,\"harvest\":[10,12],\"growing\":null,\"weight\":6}]},{\"id\":\"ua-black-sea\",\"label\":\"Ukraine and the Black Sea\",\"short\":\"Ukraine\",\"countries\":[\"UA\",\"MD\",\"RU\"],\"coord\":[32,49],\"watch\":[{\"label\":\"the Copernicus European Drought Observatory bulletin\",\"when\":\"monthly\"},{\"label\":\"the UkrHydroMet seasonal outlook\",\"when\":\"issued each season\"}],\"crops\":[{\"id\":\"wheat\",\"label\":\"Ukraine winter wheat\",\"plant\":[9,10],\"harvest\":[7,8],\"growing\":[3,5],\"weight\":22},{\"id\":\"corn\",\"label\":\"Ukraine corn (main season)\",\"plant\":[4,5],\"harvest\":[9,11],\"growing\":[6,8],\"weight\":28},{\"id\":\"soybean\",\"label\":\"Ukraine soybean (main season)\",\"plant\":[4,5],\"harvest\":[9,10],\"growing\":[6,8],\"weight\":5},{\"id\":\"barley\",\"label\":\"Ukraine spring barley\",\"plant\":[3,4],\"harvest\":[7,8],\"growing\":[5,6],\"weight\":6},{\"id\":\"rapeseed\",\"label\":\"Ukraine canola (winter rapeseed)\",\"plant\":[8,9],\"harvest\":[6,7],\"growing\":[3,5],\"weight\":4},{\"id\":\"sunflower\",\"label\":\"Ukraine sunflower (main season)\",\"plant\":[4,5],\"harvest\":[8,10],\"growing\":[6,7],\"weight\":13},{\"id\":\"wheat\",\"label\":\"Winter wheat (Moldova, Krasnodar, Rostov, Stavropol)\",\"plant\":[9,10],\"harvest\":[6,7],\"growing\":null,\"weight\":20},{\"id\":\"sunflower\",\"label\":\"Sunflower (Moldova, southern Russia)\",\"plant\":[4,5],\"harvest\":[8,10],\"growing\":null,\"weight\":8},{\"id\":\"corn\",\"label\":\"Maize (Moldova, southern Russia)\",\"plant\":[4,5],\"harvest\":[9,10],\"growing\":null,\"weight\":6}]},{\"id\":\"eu-central\",\"label\":\"Central Europe: Poland, Czechia, Slovakia, Hungary, Romania and Bulgaria\",\"short\":\"Central Europe\",\"countries\":[\"PL\",\"CZ\",\"SK\",\"HU\",\"RO\",\"BG\"],\"coord\":[19.5,47.2],\"watch\":[{\"label\":\"the Copernicus European Drought Observatory bulletin\",\"when\":\"monthly\"},{\"label\":\"national meteorological seasonal outlooks (IMGW, CHMU, SHMU, OMSZ)\",\"when\":\"issued each season\"}],\"crops\":[{\"id\":\"wheat\",\"label\":\"Poland winter wheat\",\"plant\":[9,10],\"harvest\":[7,8],\"growing\":[3,5],\"weight\":12},{\"id\":\"wheat\",\"label\":\"Romania winter wheat\",\"plant\":[10,11],\"harvest\":[6,7],\"growing\":[2,5],\"weight\":10},{\"id\":\"corn\",\"label\":\"Romania corn (main season)\",\"plant\":[4,5],\"harvest\":[9,10],\"growing\":[6,8],\"weight\":10},{\"id\":\"corn\",\"label\":\"Poland corn (main season)\",\"plant\":[4,5],\"harvest\":[9,11],\"growing\":[6,8],\"weight\":9},{\"id\":\"corn\",\"label\":\"Hungary corn (main season)\",\"plant\":[4,5],\"harvest\":[9,10],\"growing\":[6,8],\"weight\":8},{\"id\":\"rapeseed\",\"label\":\"Poland canola (winter rapeseed)\",\"plant\":[8,9],\"harvest\":[7,8],\"growing\":[3,5],\"weight\":3.4},{\"id\":\"sunflower\",\"label\":\"Romania sunflower (main season)\",\"plant\":[3,4],\"harvest\":[8,10],\"growing\":[5,7],\"weight\":2.5},{\"id\":\"sunflower\",\"label\":\"Bulgaria sunflower (main season)\",\"plant\":[3,4],\"harvest\":[8,9],\"growing\":[5,7],\"weight\":1.9},{\"id\":\"sunflower\",\"label\":\"Hungary sunflower (main season)\",\"plant\":[4,4],\"harvest\":[9,10],\"growing\":[5,7],\"weight\":1.8},{\"id\":\"wheat\",\"label\":\"Winter wheat (Czechia, Slovakia)\",\"plant\":[9,10],\"harvest\":[7,8],\"growing\":null,\"weight\":10},{\"id\":\"barley\",\"label\":\"Barley (Czechia, Slovakia)\",\"plant\":[9,10],\"harvest\":[6,7],\"growing\":null,\"weight\":5}]},{\"id\":\"eu-west\",\"label\":\"Western and northern Europe: France, Britain, Germany, Belgium, the Netherlands and Denmark\",\"short\":\"W. Europe\",\"countries\":[\"FR\",\"GB\",\"DE\",\"BE\",\"NL\",\"DK\"],\"coord\":[10,51],\"watch\":[{\"label\":\"the Copernicus European Drought Observatory bulletin\",\"when\":\"monthly\"},{\"label\":\"national meteorological seasonal outlooks (Met Office, Meteo-France, DWD)\",\"when\":\"issued each season\"}],\"crops\":[{\"id\":\"wheat\",\"label\":\"France winter wheat\",\"plant\":[10,11],\"harvest\":[7,8],\"growing\":[3,5],\"weight\":33},{\"id\":\"wheat\",\"label\":\"Germany winter wheat\",\"plant\":[9,10],\"harvest\":[7,8],\"growing\":[3,5],\"weight\":21},{\"id\":\"wheat\",\"label\":\"United Kingdom winter wheat\",\"plant\":[9,10],\"harvest\":[8,9],\"growing\":[3,5],\"weight\":13},{\"id\":\"corn\",\"label\":\"France corn (main season)\",\"plant\":[4,5],\"harvest\":[9,11],\"growing\":[6,8],\"weight\":14},{\"id\":\"barley\",\"label\":\"France winter barley\",\"plant\":[9,10],\"harvest\":[6,7],\"growing\":[3,5],\"weight\":11},{\"id\":\"barley\",\"label\":\"Germany winter barley\",\"plant\":[9,10],\"harvest\":[6,7],\"growing\":[3,5],\"weight\":9},{\"id\":\"barley\",\"label\":\"United Kingdom spring barley\",\"plant\":[2,4],\"harvest\":[7,9],\"growing\":[4,6],\"weight\":4},{\"id\":\"rapeseed\",\"label\":\"France canola (winter rapeseed)\",\"plant\":[8,9],\"harvest\":[6,7],\"growing\":[2,5],\"weight\":4.3},{\"id\":\"rapeseed\",\"label\":\"Germany canola (winter rapeseed)\",\"plant\":[8,9],\"harvest\":[7,7],\"growing\":[3,5],\"weight\":4},{\"id\":\"rapeseed\",\"label\":\"United Kingdom canola (winter rapeseed)\",\"plant\":[8,9],\"harvest\":[7,8],\"growing\":[2,5],\"weight\":1},{\"id\":\"sunflower\",\"label\":\"France sunflower (main season)\",\"plant\":[4,4],\"harvest\":[9,10],\"growing\":[5,7],\"weight\":1.9},{\"id\":\"wheat\",\"label\":\"Winter wheat (Belgium, the Netherlands, Denmark)\",\"plant\":[9,10],\"harvest\":[7,8],\"growing\":null,\"weight\":8},{\"id\":\"barley\",\"label\":\"Barley (Belgium, the Netherlands, Denmark)\",\"plant\":[9,10],\"harvest\":[7,8],\"growing\":null,\"weight\":4}]},{\"id\":\"kz-steppe\",\"label\":\"Kazakhstan steppe\",\"short\":\"Kazakhstan\",\"countries\":[\"KZ\"],\"coord\":[68,51],\"watch\":[{\"label\":\"the Kazhydromet seasonal outlook\",\"when\":\"issued each season\"},{\"label\":\"the Ministry of Agriculture spring sowing report\",\"when\":\"April to May\"}],\"crops\":[{\"id\":\"wheat\",\"label\":\"Kazakhstan spring wheat\",\"plant\":[5,6],\"harvest\":[8,9],\"growing\":[6,7],\"weight\":14},{\"id\":\"sunflower\",\"label\":\"Kazakhstan sunflower (main season)\",\"plant\":[5,5],\"harvest\":[9,10],\"growing\":[6,8],\"weight\":1.3},{\"id\":\"barley\",\"label\":\"Barley (northern Kazakhstan)\",\"plant\":[5,6],\"harvest\":[8,9],\"growing\":null,\"weight\":6}]}],\"anomaly\":{\"in-monsoon\":{\"elnino\":{\"precipPct\":-15,\"tempC\":0.8,\"months\":[6,9],\"onset\":\"late\",\"confidence\":\"medium\",\"mechanism\":\"A warm eastern Pacific weakens the summer monsoon; the direction is reliable, the size depends on the Indian Ocean Dipole (2015: 14% below the long-period average).\",\"sources\":[\"fao-2026-06\",\"scroll-india-2015\",\"climate-gov\",\"nature-2026\"]},\"neutral\":{\"precipPct\":0,\"tempC\":0,\"months\":[6,9],\"onset\":\"normal\",\"confidence\":\"high\",\"mechanism\":\"Climatological monsoon season, June to September.\",\"sources\":[\"climate-gov\"]},\"lanina\":{\"precipPct\":12,\"tempC\":-0.3,\"months\":[6,9],\"onset\":\"normal\",\"confidence\":\"medium\",\"mechanism\":\"La Ni\u00f1a years lean towards an above-normal monsoon, with waterlogging in low-lying fields in the east.\",\"sources\":[\"climate-gov\"]}},\"pk-indus\":{\"elnino\":{\"precipPct\":-15,\"tempC\":0.7,\"months\":[6,9],\"onset\":\"late\",\"confidence\":\"medium\",\"mechanism\":\"Weaker monsoon rain over the Indus basin; canal irrigation buffers much of the signal for rice and cotton.\",\"sources\":[\"fao-2026-06\",\"climate-gov\"]},\"neutral\":{\"precipPct\":0,\"tempC\":0,\"months\":[6,9],\"onset\":\"normal\",\"confidence\":\"high\",\"mechanism\":\"Climatological monsoon season.\",\"sources\":[\"climate-gov\"]},\"lanina\":{\"precipPct\":12,\"tempC\":-0.2,\"months\":[6,9],\"onset\":\"normal\",\"confidence\":\"low\",\"mechanism\":\"Slightly wetter monsoon in most La Ni\u00f1a years; 2022 was an extreme outlier that put much of the lower Indus under water for weeks.\",\"sources\":[\"climate-gov\"]}},\"sea-rice-palm\":{\"elnino\":{\"precipPct\":-25,\"tempC\":0.8,\"months\":[7,12],\"onset\":\"late\",\"confidence\":\"high\",\"mechanism\":\"Drier and hotter through the dry season with a late wet-season onset; oil palm yields lag the drought by 6 to 12 months.\",\"sources\":[\"fao-2026-06\",\"fao-enso-risk\",\"xweather-2026\"]},\"neutral\":{\"precipPct\":0,\"tempC\":0,\"months\":[7,12],\"onset\":\"normal\",\"confidence\":\"high\",\"mechanism\":\"Climatological dry season into the wet-season onset.\",\"sources\":[\"climate-gov\"]},\"lanina\":{\"precipPct\":20,\"tempC\":-0.3,\"months\":[7,12],\"onset\":\"early\",\"confidence\":\"high\",\"mechanism\":\"Wetter dry season and early wet-season onset across Indonesia and the Malay peninsula.\",\"sources\":[\"climate-gov\"]}},\"ph-monsoon\":{\"elnino\":{\"precipPct\":-30,\"tempC\":0.8,\"months\":[11,4],\"onset\":\"late\",\"confidence\":\"high\",\"mechanism\":\"A dry northeast monsoon season and a late start to the next rainy season; the 2015-16 and 2023-24 events put most provinces under dry spell or drought by March.\",\"sources\":[\"fao-enso-risk\",\"climate-gov\"]},\"neutral\":{\"precipPct\":0,\"tempC\":0,\"months\":[11,4],\"onset\":\"normal\",\"confidence\":\"high\",\"mechanism\":\"Climatological northeast monsoon season into the next rainy-season onset.\",\"sources\":[\"climate-gov\"]},\"lanina\":{\"precipPct\":20,\"tempC\":-0.3,\"months\":[10,3],\"onset\":\"early\",\"confidence\":\"high\",\"mechanism\":\"A wetter northeast monsoon season with more typhoon rain over the east, and an early start to the next rainy season.\",\"sources\":[\"climate-gov\"]}},\"au-winter-crop\":{\"elnino\":{\"precipPct\":-20,\"tempC\":0.8,\"months\":[6,11],\"onset\":\"normal\",\"confidence\":\"high\",\"mechanism\":\"Below-normal winter and spring rain in the east; the 2026 winter crop is already sown, so the spring finish is where the risk sits.\",\"sources\":[\"usyd-wheat-2023\",\"xweather-2026\",\"climate-gov\"]},\"neutral\":{\"precipPct\":0,\"tempC\":0,\"months\":[6,11],\"onset\":\"normal\",\"confidence\":\"high\",\"mechanism\":\"Climatological winter crop season.\",\"sources\":[\"climate-gov\"]},\"lanina\":{\"precipPct\":20,\"tempC\":-0.4,\"months\":[6,11],\"onset\":\"normal\",\"confidence\":\"high\",\"mechanism\":\"Wetter winter and spring in the east, with waterlogged paddocks and a harvest under rain.\",\"sources\":[\"climate-gov\",\"usyd-wheat-2023\"]}},\"saf-summer\":{\"elnino\":{\"precipPct\":-25,\"tempC\":1,\"months\":[11,3],\"onset\":\"late\",\"confidence\":\"high\",\"mechanism\":\"Below-normal and late summer rain with heat; 2015-16 cut South African maize by about half against the 5-year average.\",\"sources\":[\"fao-2026-06\",\"ifpri-saf-2016\",\"climate-gov\"]},\"neutral\":{\"precipPct\":0,\"tempC\":0,\"months\":[11,3],\"onset\":\"normal\",\"confidence\":\"high\",\"mechanism\":\"Climatological summer rainy season.\",\"sources\":[\"climate-gov\"]},\"lanina\":{\"precipPct\":15,\"tempC\":-0.4,\"months\":[11,3],\"onset\":\"normal\",\"confidence\":\"medium\",\"mechanism\":\"Wetter summer season across the Highveld and Zambia.\",\"sources\":[\"climate-gov\"]}},\"eaf-short-rains\":{\"elnino\":{\"precipPct\":30,\"tempC\":0.5,\"months\":[10,12],\"onset\":\"early\",\"confidence\":\"high\",\"mechanism\":\"Enhanced October to December short rains with water standing in low-lying parts of Kenya and Somalia; the Ethiopian summer main season tends drier.\",\"sources\":[\"fao-enso-risk\",\"climate-gov\"]},\"neutral\":{\"precipPct\":0,\"tempC\":0,\"months\":[10,12],\"onset\":\"normal\",\"confidence\":\"high\",\"mechanism\":\"Climatological short rains.\",\"sources\":[\"climate-gov\"]},\"lanina\":{\"precipPct\":-25,\"tempC\":0.3,\"months\":[10,12],\"onset\":\"late\",\"confidence\":\"high\",\"mechanism\":\"Failed or weak short rains, as in the 2020 to 2022 drought sequence.\",\"sources\":[\"climate-gov\"]}},\"sahel\":{\"elnino\":{\"precipPct\":-15,\"tempC\":0.5,\"months\":[7,9],\"onset\":\"late\",\"confidence\":\"medium\",\"mechanism\":\"A weaker West African monsoon in many El Ni\u00f1o years; Atlantic sea temperatures also steer the season.\",\"sources\":[\"fao-2026-06\",\"fao-enso-risk\"]},\"neutral\":{\"precipPct\":0,\"tempC\":0,\"months\":[7,9],\"onset\":\"normal\",\"confidence\":\"high\",\"mechanism\":\"Climatological rainy season.\",\"sources\":[\"fao-enso-risk\"]},\"lanina\":{\"precipPct\":12,\"tempC\":-0.2,\"months\":[7,9],\"onset\":\"normal\",\"confidence\":\"low\",\"mechanism\":\"Slightly wetter rainy season in some La Ni\u00f1a years.\",\"sources\":[\"fao-enso-risk\"]}},\"cam-dry-corridor\":{\"elnino\":{\"precipPct\":-25,\"tempC\":0.9,\"months\":[5,10],\"onset\":\"late\",\"confidence\":\"high\",\"mechanism\":\"FAO puts a 70% probability on below-normal rain across the Dry Corridor; maize and beans in both primera and postrera are exposed.\",\"sources\":[\"fao-2026-06\",\"fao-enso-risk\"]},\"neutral\":{\"precipPct\":0,\"tempC\":0,\"months\":[5,10],\"onset\":\"normal\",\"confidence\":\"high\",\"mechanism\":\"Climatological rainy season.\",\"sources\":[\"fao-enso-risk\"]},\"lanina\":{\"precipPct\":15,\"tempC\":-0.3,\"months\":[5,10],\"onset\":\"normal\",\"confidence\":\"medium\",\"mechanism\":\"Wetter rainy season with more tropical-storm rainfall.\",\"sources\":[\"fao-enso-risk\"]}},\"and-north\":{\"elnino\":{\"precipPct\":-25,\"tempC\":0.8,\"months\":[12,3],\"onset\":\"normal\",\"confidence\":\"high\",\"mechanism\":\"Below-normal rain and heat through the event, with hydro-power and irrigation constraints.\",\"sources\":[\"fao-2026-06\",\"fao-enso-risk\"]},\"neutral\":{\"precipPct\":0,\"tempC\":0,\"months\":[12,3],\"onset\":\"normal\",\"confidence\":\"high\",\"mechanism\":\"Climatological dry season.\",\"sources\":[\"fao-enso-risk\"]},\"lanina\":{\"precipPct\":15,\"tempC\":-0.3,\"months\":[12,3],\"onset\":\"normal\",\"confidence\":\"medium\",\"mechanism\":\"Wetter than normal with landslide risk and saturated soils in the Andean valleys.\",\"sources\":[\"fao-enso-risk\"]}},\"br-centre-north\":{\"elnino\":{\"precipPct\":-15,\"tempC\":1,\"months\":[9,2],\"onset\":\"late\",\"confidence\":\"medium\",\"mechanism\":\"Late and irregular rains with heat in the Cerrado and MATOPIBA, a clearly drier rainy season in the Sert\u00e3o; 2023-24 cut soybean in Mato Grosso and squeezed the safrinha window.\",\"sources\":[\"farmdoc-sa-2024\",\"fao-enso-risk\"]},\"neutral\":{\"precipPct\":0,\"tempC\":0,\"months\":[9,2],\"onset\":\"normal\",\"confidence\":\"high\",\"mechanism\":\"Climatological soybean season.\",\"sources\":[\"farmdoc-sa-2024\"]},\"lanina\":{\"precipPct\":12,\"tempC\":-0.3,\"months\":[9,2],\"onset\":\"normal\",\"confidence\":\"low\",\"mechanism\":\"Near-normal to slightly wetter centre-west in most La Ni\u00f1a years.\",\"sources\":[\"farmdoc-sa-2024\"]}},\"br-south\":{\"elnino\":{\"precipPct\":30,\"tempC\":0.3,\"months\":[9,2],\"onset\":\"normal\",\"confidence\":\"high\",\"mechanism\":\"Above-normal spring and summer rain with water standing in low ground; long leaf wetness drives soybean rust and wheat harvest under rain.\",\"sources\":[\"farmdoc-sa-2024\",\"climate-gov\",\"xweather-2026\"]},\"neutral\":{\"precipPct\":0,\"tempC\":0,\"months\":[9,2],\"onset\":\"normal\",\"confidence\":\"high\",\"mechanism\":\"Climatological spring and summer season.\",\"sources\":[\"farmdoc-sa-2024\"]},\"lanina\":{\"precipPct\":-20,\"tempC\":0.5,\"months\":[9,2],\"onset\":\"late\",\"confidence\":\"high\",\"mechanism\":\"Drier spring and summer in the south, as in the 2021-22 drought.\",\"sources\":[\"farmdoc-sa-2024\",\"climate-gov\"]}},\"plata-pampas\":{\"elnino\":{\"precipPct\":25,\"tempC\":0.2,\"months\":[10,3],\"onset\":\"normal\",\"confidence\":\"high\",\"mechanism\":\"Wetter spring and summer, yield upside for soybean and corn, water standing in low ground and a wet wheat harvest in November and December.\",\"sources\":[\"farmdoc-sa-2024\",\"climate-gov\",\"xweather-2026\"]},\"neutral\":{\"precipPct\":0,\"tempC\":0,\"months\":[10,3],\"onset\":\"normal\",\"confidence\":\"high\",\"mechanism\":\"Climatological summer crop season.\",\"sources\":[\"farmdoc-sa-2024\"]},\"lanina\":{\"precipPct\":-20,\"tempC\":0.6,\"months\":[10,3],\"onset\":\"normal\",\"confidence\":\"high\",\"mechanism\":\"Drier and hotter summer; the 2022-23 La Ni\u00f1a drought halved the Argentine soybean crop.\",\"sources\":[\"farmdoc-sa-2024\",\"climate-gov\"]}},\"us-south-west\":{\"elnino\":{\"precipPct\":20,\"tempC\":-0.3,\"months\":[12,3],\"onset\":\"normal\",\"confidence\":\"medium\",\"mechanism\":\"Wetter, cooler winter across the southern tier and California; wet spring fieldwork in the Delta; the following summer is a transition with low confidence.\",\"sources\":[\"climate-gov\",\"xweather-2026\"]},\"neutral\":{\"precipPct\":0,\"tempC\":0,\"months\":[12,3],\"onset\":\"normal\",\"confidence\":\"high\",\"mechanism\":\"Climatological winter.\",\"sources\":[\"climate-gov\"]},\"lanina\":{\"precipPct\":-15,\"tempC\":0.4,\"months\":[12,3],\"onset\":\"normal\",\"confidence\":\"medium\",\"mechanism\":\"Drier, warmer winter across the southern Plains and Southeast; winter wheat moisture stress.\",\"sources\":[\"climate-gov\"]}},\"pe-ec-coast\":{\"elnino\":{\"precipPct\":150,\"tempC\":1.5,\"months\":[12,4],\"onset\":\"early\",\"confidence\":\"high\",\"mechanism\":\"Warm coastal water brings several times the normal rain to the arid coast, with flooding; rice, bananas and infrastructure are exposed.\",\"sources\":[\"fao-enso-risk\",\"climate-gov\"]},\"neutral\":{\"precipPct\":0,\"tempC\":0,\"months\":[12,4],\"onset\":\"normal\",\"confidence\":\"high\",\"mechanism\":\"Climatological coastal summer.\",\"sources\":[\"climate-gov\"]},\"lanina\":{\"precipPct\":-15,\"tempC\":-0.8,\"months\":[12,4],\"onset\":\"normal\",\"confidence\":\"medium\",\"mechanism\":\"Cooler, drier coast with stronger upwelling.\",\"sources\":[\"climate-gov\"]}},\"ca-prairies\":{\"elnino\":{\"precipPct\":-20,\"tempC\":1.2,\"months\":[12,4],\"onset\":\"normal\",\"confidence\":\"medium\",\"mechanism\":\"Strong events run Prairie winters warmer and drier with a smaller mountain snowpack, so spring seeding often starts on lower stored soil moisture; prior strong El Ni\u00f1o winters have coincided with reduced Prairie farm productivity.\",\"sources\":[\"climatedata-ca-2026\"]},\"neutral\":{\"precipPct\":0,\"tempC\":0,\"months\":[12,4],\"onset\":\"normal\",\"confidence\":\"high\",\"mechanism\":\"Climatological Prairie winter into spring seeding.\",\"sources\":[\"climate-gov\"]},\"lanina\":{\"precipPct\":15,\"tempC\":-1,\"months\":[12,4],\"onset\":\"normal\",\"confidence\":\"medium\",\"mechanism\":\"La Ni\u00f1a winters on the Prairies typically run colder with better snowpack, building more stored soil moisture ahead of spring seeding than an El Ni\u00f1o winter leaves behind.\",\"sources\":[\"climate-gov\"]}},\"cn-yangtze\":{\"elnino\":{\"precipPct\":30,\"tempC\":0.4,\"months\":[6,8],\"onset\":\"normal\",\"confidence\":\"medium\",\"mechanism\":\"Strong El Ni\u00f1o winters are consistently followed by an intensified East Asian summer monsoon over the Yangtze basin, echoing the 1997-98 event that put swathes of the basin under water for weeks, while the same monsoon shift tends to leave the North China Plain drier.\",\"sources\":[\"zhang-yangtze-2016\",\"scmp-china-2023\"]},\"neutral\":{\"precipPct\":0,\"tempC\":0,\"months\":[6,8],\"onset\":\"normal\",\"confidence\":\"high\",\"mechanism\":\"Climatological summer monsoon flood season on the Yangtze.\",\"sources\":[\"zhang-yangtze-2016\"]},\"lanina\":{\"precipPct\":-15,\"tempC\":0.3,\"months\":[6,8],\"onset\":\"normal\",\"confidence\":\"low\",\"mechanism\":\"Without a decaying El Ni\u00f1o feeding the monsoon, Yangtze summer rain trends closer to normal or slightly below it, though the north-south rainfall seesaw is less reliable outside El Ni\u00f1o years.\",\"sources\":[\"zhang-yangtze-2016\",\"scmp-china-2023\"]}},\"cn-north-plain\":{\"elnino\":{\"precipPct\":-20,\"tempC\":0.5,\"months\":[10,3],\"onset\":\"late\",\"confidence\":\"medium\",\"mechanism\":\"The same monsoon shift that puts the Yangtze basin under water typically leaves the North China Plain drier over the winter wheat season, the wet-south, dry-north pattern Chinese forecasters describe.\",\"sources\":[\"scmp-china-2023\"]},\"neutral\":{\"precipPct\":0,\"tempC\":0,\"months\":[10,3],\"onset\":\"normal\",\"confidence\":\"high\",\"mechanism\":\"Climatological North China Plain winter wheat season.\",\"sources\":[\"scmp-china-2023\"]},\"lanina\":{\"precipPct\":15,\"tempC\":-0.3,\"months\":[10,3],\"onset\":\"normal\",\"confidence\":\"low\",\"mechanism\":\"La Ni\u00f1a years tip toward the opposite pattern, with above-normal winter and spring moisture across the North China Plain, though the north-south rainfall seesaw is less reliable outside El Ni\u00f1o years.\",\"sources\":[\"scmp-china-2023\"]}},\"cl-central\":{\"elnino\":{\"precipPct\":40,\"tempC\":0.3,\"months\":[6,10],\"onset\":\"normal\",\"confidence\":\"medium\",\"mechanism\":\"Chilean climate scientists flagged a real, if uncertain, chance of a wetter than normal winter and spring for 2026, with rivers running high and low ground under water in the central valley, driven by a stronger, wetter storm track off the subtropical Pacific.\",\"sources\":[\"cr2-godzilla-2026\"]},\"neutral\":{\"precipPct\":0,\"tempC\":0,\"months\":[6,10],\"onset\":\"normal\",\"confidence\":\"high\",\"mechanism\":\"Climatological winter and spring rains in the central valley.\",\"sources\":[\"cr2-godzilla-2026\"]},\"lanina\":{\"precipPct\":-20,\"tempC\":0.3,\"months\":[6,10],\"onset\":\"normal\",\"confidence\":\"medium\",\"mechanism\":\"La Ni\u00f1a years have dominated the decade-plus megadrought in central Chile, reinforcing already low reservoir levels rather than relieving them.\",\"sources\":[\"cr2-godzilla-2026\",\"climate-gov\"]}},\"nz-crop\":{\"elnino\":{\"precipPct\":-20,\"tempC\":0.6,\"months\":[11,3],\"onset\":\"normal\",\"confidence\":\"medium\",\"mechanism\":\"Stronger, more frequent westerlies push moisture to the west coast during El Ni\u00f1o and leave the eastern grain and pasture country of both islands drier, with a higher chance of spring-into-summer drought and wildfire risk.\",\"sources\":[\"niwa-enso-nz-2026\"]},\"neutral\":{\"precipPct\":0,\"tempC\":0,\"months\":[11,3],\"onset\":\"normal\",\"confidence\":\"high\",\"mechanism\":\"Climatological spring and summer growing season.\",\"sources\":[\"niwa-enso-nz-2026\"]},\"lanina\":{\"precipPct\":15,\"tempC\":0.4,\"months\":[11,3],\"onset\":\"normal\",\"confidence\":\"low\",\"mechanism\":\"La Ni\u00f1a brings more north-easterly wind and typically warmer temperatures nationwide, with a more mixed rainfall picture across the main cropping regions than the clear dry-east signal El Ni\u00f1o brings.\",\"sources\":[\"niwa-enso-nz-2026\"]}},\"med-west\":{\"elnino\":{\"precipPct\":18,\"tempC\":-0.2,\"months\":[11,2],\"onset\":\"normal\",\"confidence\":\"low\",\"mechanism\":\"In the strongest El Ni\u00f1o winters the Atlantic storm track has tended to shift south, adding rain to Iberia, southern France and Italy instead of Scandinavia, but the signal is inconsistent across events and has weakened further in recent decades.\",\"sources\":[\"ecmwf-enso-europe\",\"springer-enso-nae-2021\"]},\"neutral\":{\"precipPct\":0,\"tempC\":0,\"months\":[11,2],\"onset\":\"normal\",\"confidence\":\"high\",\"mechanism\":\"Climatological Mediterranean winter rains.\",\"sources\":[\"ecmwf-enso-europe\"]},\"lanina\":{\"precipPct\":-14,\"tempC\":0.2,\"months\":[11,2],\"onset\":\"normal\",\"confidence\":\"low\",\"mechanism\":\"La Ni\u00f1a winters lean toward a more northward storm track, leaving Iberia, southern France and Italy closer to normal or slightly drier, though the Mediterranean ENSO link runs weak in both directions.\",\"sources\":[\"ecmwf-enso-europe\",\"springer-enso-nae-2021\"]}},\"ua-black-sea\":{\"elnino\":{\"signal\":\"none\",\"precipPct\":0,\"tempC\":0,\"months\":[4,9],\"onset\":\"normal\",\"confidence\":\"low\",\"mechanism\":\"Ukraine and the Black Sea grain belt sit far from the reach of the tropical Pacific; the season here answers to autumn soil moisture reserves and the North Atlantic Oscillation, not to El Ni\u00f1o.\",\"sources\":[\"springer-enso-nae-2021\",\"npj-enso-europe-2025\"]},\"neutral\":{\"precipPct\":0,\"tempC\":0,\"months\":[4,9],\"onset\":\"normal\",\"confidence\":\"high\",\"mechanism\":\"Climatological spring-to-harvest season for the Black Sea grain belt.\",\"sources\":[\"springer-enso-nae-2021\"]},\"lanina\":{\"signal\":\"none\",\"precipPct\":0,\"tempC\":0,\"months\":[4,9],\"onset\":\"normal\",\"confidence\":\"low\",\"mechanism\":\"The same Atlantic patterns, not a cold tropical Pacific, set the odds for a wet or dry season here.\",\"sources\":[\"springer-enso-nae-2021\",\"npj-enso-europe-2025\"]}},\"eu-central\":{\"elnino\":{\"signal\":\"none\",\"precipPct\":0,\"tempC\":0,\"months\":[3,8],\"onset\":\"normal\",\"confidence\":\"low\",\"mechanism\":\"Central European harvests answer to the North Atlantic Oscillation and blocking patterns over the continent, a signal the tropical Pacific barely reaches and that has weakened further in recent decades.\",\"sources\":[\"springer-enso-nae-2021\",\"npj-enso-europe-2025\"]},\"neutral\":{\"precipPct\":0,\"tempC\":0,\"months\":[3,8],\"onset\":\"normal\",\"confidence\":\"high\",\"mechanism\":\"Climatological spring and summer growing season.\",\"sources\":[\"springer-enso-nae-2021\"]},\"lanina\":{\"signal\":\"none\",\"precipPct\":0,\"tempC\":0,\"months\":[3,8],\"onset\":\"normal\",\"confidence\":\"low\",\"mechanism\":\"The same Atlantic and blocking patterns, not a cold tropical Pacific, drive the odds of a wet or dry season here.\",\"sources\":[\"springer-enso-nae-2021\",\"npj-enso-europe-2025\"]}},\"eu-west\":{\"elnino\":{\"signal\":\"none\",\"precipPct\":0,\"tempC\":0,\"months\":[3,8],\"onset\":\"normal\",\"confidence\":\"low\",\"mechanism\":\"Western and northern European rainfall and storm tracks follow the North Atlantic Oscillation, which the tropical Pacific barely nudges even in the strongest El Ni\u00f1o winters, and the link has weakened further in recent decades.\",\"sources\":[\"ecmwf-enso-europe\",\"springer-enso-nae-2021\",\"npj-enso-europe-2025\"]},\"neutral\":{\"precipPct\":0,\"tempC\":0,\"months\":[3,8],\"onset\":\"normal\",\"confidence\":\"high\",\"mechanism\":\"Climatological spring and summer growing season.\",\"sources\":[\"ecmwf-enso-europe\"]},\"lanina\":{\"signal\":\"none\",\"precipPct\":0,\"tempC\":0,\"months\":[3,8],\"onset\":\"normal\",\"confidence\":\"low\",\"mechanism\":\"The same North Atlantic Oscillation, not a cold tropical Pacific, drives the odds of a wet or dry season here.\",\"sources\":[\"springer-enso-nae-2021\",\"npj-enso-europe-2025\"]}},\"kz-steppe\":{\"elnino\":{\"signal\":\"none\",\"precipPct\":0,\"tempC\":0,\"months\":[4,8],\"onset\":\"normal\",\"confidence\":\"low\",\"mechanism\":\"Kazakhstan steppe wheat answers mainly to how much moisture is stored from winter snowmelt each spring, not to the tropical Pacific; one published study has linked Kazakh wheat-drought years to the Multivariate ENSO Index, but mainstream regional climatology still points to snowmelt timing and spring soil moisture as the operative driver here.\",\"sources\":[\"carec-snow-kz-2023\",\"shmelev-kz-enso-2021\"]},\"neutral\":{\"precipPct\":0,\"tempC\":0,\"months\":[4,8],\"onset\":\"normal\",\"confidence\":\"high\",\"mechanism\":\"Climatological spring sowing through summer growth on the steppe.\",\"sources\":[\"carec-snow-kz-2023\"]},\"lanina\":{\"signal\":\"none\",\"precipPct\":0,\"tempC\":0,\"months\":[4,8],\"onset\":\"normal\",\"confidence\":\"low\",\"mechanism\":\"The same snowmelt timing, not a cold tropical Pacific, sets the odds of a wet or dry season on the steppe.\",\"sources\":[\"carec-snow-kz-2023\"]}}},\"overrides\":{\"br-south\":{\"elnino\":{\"fungicides\":{\"index\":3,\"reason\":\"Asian soybean rust and wheat head diseases under long wet spells\"}}},\"pk-indus\":{\"elnino\":{\"biostimulants\":{\"index\":1,\"reason\":\"canal irrigation buffers most of the drought signal\"},\"nitrogen\":{\"index\":0,\"reason\":\"irrigated wheat and rice keep their nitrogen programme\"}}},\"au-winter-crop\":{\"elnino\":{\"resilient_seed\":{\"index\":1,\"reason\":\"the 2026 winter crop is already sown; the shift applies to summer sorghum and cotton sowing\"}}}},\"outlook\":{\"in-monsoon\":{\"label\":\"Monsoon outlook\",\"issued\":\"2026-09-30\",\"nextIssue\":\"2026-10-31\",\"months\":[10,12],\"headline\":\"October rainfall below normal over most of the country; October to December normal over the south peninsula and below normal elsewhere.\",\"rain\":{\"wording\":\"Monthly rainfall over the country as a whole during October 2026 is likely to be below normal (under 85% of LPA); October to December over South Peninsular India most likely normal (88 to 112% of LPA).\",\"band\":[null,85],\"pct\":-25},\"temp\":{\"wording\":\"Above-normal maximum and minimum temperatures are likely over most parts of the country.\",\"level\":\"above\",\"c\":0.6},\"onset\":\"normal\",\"confidence\":\"medium\",\"observed\":{\"label\":\"Southwest monsoon 2026, June to September\",\"pct\":-13,\"wording\":\"Rainfall over the country as a whole was 87% of its long period average, the fourth lowest since 2001.\"}},\"pk-indus\":{\"label\":\"Monsoon outlook\",\"issued\":\"2026-10-01\",\"nextIssue\":\"2026-11-01\",\"months\":[10,12],\"headline\":\"Warmer than normal through December; near normal to slightly below normal rain in the centre and south, normal to above normal in the north.\",\"rain\":{\"wording\":\"Normal to above normal rainfall in the north; near normal to slightly below normal in the centre and south, with southern Sindh slightly drier than normal.\",\"band\":null,\"level\":\"slightly below\",\"pct\":-7},\"temp\":{\"wording\":\"Warmer than normal across most of the country, strongest over Gilgit-Baltistan and northern Khyber Pakhtunkhwa.\",\"level\":\"above\",\"c\":0.6},\"onset\":\"normal\",\"confidence\":\"low\",\"observed\":{\"label\":\"Monsoon 2026, July to September\",\"pct\":-19.3,\"wording\":\"Monsoon rainfall 19.3% below normal for the country as a whole.\"}},\"ph-monsoon\":{\"label\":\"Seasonal outlook\",\"issued\":\"2026-10-07\",\"nextIssue\":\"2026-11-09\",\"months\":[10,12],\"headline\":\"Below normal rainfall over most of Luzon, the Visayas and Caraga from October, near normal over the rest of Mindanao, the Negros islands and the far north; below normal across most of the country by December.\",\"rain\":{\"wording\":\"Below-normal rainfall conditions over most parts of Luzon, Visayas and Caraga Region in October, near-normal over Batanes, Cagayan, Negros Island Region, Central Visayas and the rest of Mindanao; generally below-normal conditions over most parts of the country for October to December.\",\"band\":[41,80],\"pct\":-39},\"temp\":{\"wording\":\"Near-average to warmer-than-average mean air temperatures over most parts of the country.\",\"level\":\"above\",\"c\":0.6},\"onset\":\"normal\",\"confidence\":\"high\"}}}<\/script>\n<!-- ENI-DATA END -->\n\n<script nowprocket data-no-optimize=\"1\" data-no-defer=\"1\" data-no-minify=\"1\">\n(function(){\n  var ROOT = document.getElementById('gp-eni');\n  if(!ROOT){ return; }\n  var dataEl = document.getElementById('eni-data');\n  var geoEl = document.getElementById('eni-geo');\n  if(!dataEl){ return; }\n  var D = JSON.parse(dataEl.textContent);\n  var G = geoEl ? JSON.parse(geoEl.textContent) : null;\n  \/* ENI-CORE BEGIN *\/\n\/* El Ni\u00f1o Impact Simulator: the model core. Pure, DOM free, ES5, and it never\n   contains an ampersand: build-data.js pastes this file verbatim into the page\n   script between the ENI-CORE markers, and WordPress rewrites a bare ampersand\n   inside a script body into an entity (factory rule 1). tests.js requires this\n   file AND checks the pasted copy is identical, so what is tested is what ships. *\/\nvar ENI_CORE = (function(){\n  var STRENGTH = { moderate: 0.6, strong: 1.0, historic: 1.25 };\n  var STRENGTH_IDS = ['moderate', 'strong', 'historic'];\n  var STRENGTH_LABEL = { moderate: 'Moderate', strong: 'Strong', historic: 'Historic' };\n  var PHASES = ['elnino', 'neutral', 'lanina'];\n  var PHASE_LABEL = { elnino: 'El Ni\u00f1o', neutral: 'Neutral', lanina: 'La Ni\u00f1a' };\n  var STRESSES = ['drought', 'heat', 'excess_rain', 'flood', 'late_planting', 'wet_harvest'];\n  var STRESS_LABEL = { drought: 'drought', heat: 'heat', excess_rain: 'excess rain', flood: 'flooding', late_planting: 'late planting', wet_harvest: 'wet harvest' };\n  var CATEGORIES = [\n    { id: 'fungicides', label: 'Fungicides' },\n    { id: 'insecticides', label: 'Insecticides' },\n    { id: 'herbicides', label: 'Herbicides' },\n    { id: 'seed_treatment', label: 'Seed treatment' },\n    { id: 'biostimulants', label: 'Biostimulants and anti-stress' },\n    { id: 'resilient_seed', label: 'Short-cycle and tolerant seed' },\n    { id: 'nitrogen', label: 'Nitrogen and foliar nutrition' },\n    { id: 'adjuvants', label: 'Adjuvants' }\n  ];\n  \/* stress -> category index, the spec table *\/\n  var MATRIX = {\n    fungicides:     { drought: -2, heat: -1, excess_rain: 3, flood: 1, late_planting: 0, wet_harvest: 1 },\n    insecticides:   { drought: 2,  heat: 1,  excess_rain: -1, flood: -1, late_planting: 0, wet_harvest: 0 },\n    herbicides:     { drought: -1, heat: 0,  excess_rain: 2, flood: 1, late_planting: 1, wet_harvest: 0 },\n    seed_treatment: { drought: 1,  heat: 0,  excess_rain: 2, flood: 1, late_planting: 1, wet_harvest: 0 },\n    biostimulants:  { drought: 3,  heat: 2,  excess_rain: 1, flood: 1, late_planting: 0, wet_harvest: 0 },\n    resilient_seed: { drought: 2,  heat: 1,  excess_rain: 0, flood: 2, late_planting: 2, wet_harvest: 0 },\n    nitrogen:       { drought: -1, heat: 0,  excess_rain: 2, flood: 1, late_planting: 0, wet_harvest: 0 },\n    adjuvants:      { drought: 0,  heat: 0,  excess_rain: 2, flood: 0, late_planting: 0, wet_harvest: 0 }\n  };\n  var REASON = {\n    fungicides:     { drought: 'less leaf wetness, lower foliar disease pressure', heat: 'hot dry canopies slow most fungal cycles', excess_rain: 'long leaf wetness drives rust, blight and head diseases', flood: 'saturated soils raise root and stem rot pressure', late_planting: 'programme shifts later, volume unchanged', wet_harvest: 'late-season sprays to protect grain quality' },\n    insecticides:   { drought: 'dry heat favours mites, whitefly, thrips and armyworm', heat: 'faster insect generations under heat', excess_rain: 'rain knocks back sucking pests; slugs and snails rise', flood: 'pest pressure resets after flooding', late_planting: 'later crops meet later pest peaks', wet_harvest: 'storage pests matter more than field sprays' },\n    herbicides:     { drought: 'smaller planted area and weaker weed flushes', heat: 'application windows narrow in heat', excess_rain: 'repeated weed flushes and missed windows call for residuals', flood: 'replanted fields need a second burndown', late_planting: 'late sowing shifts the pre-emergence programme', wet_harvest: 'desiccation and pre-harvest timing move' },\n    seed_treatment: { drought: 'vigour and early insect protection matter more in dry seedbeds', heat: 'seedling protection in hot seedbeds', excess_rain: 'damping-off and soil pathogens in wet seedbeds', flood: 'replant seed goes in treated', late_planting: 'compressed emergence windows favour treated seed', wet_harvest: 'no change at seeding' },\n    biostimulants:  { drought: 'anti-stress and osmoprotectant demand peaks in drought', heat: 'heat-stress products at flowering', excess_rain: 'root recovery after waterlogging', flood: 'recovery products after flooding', late_planting: 'no change', wet_harvest: 'no change' },\n    resilient_seed: { drought: 'shift to drought-tolerant hybrids and shorter cycles', heat: 'heat-tolerant hybrids at flowering', excess_rain: 'no change', flood: 'replant seed after flooding', late_planting: 'shorter-cycle hybrids to fit the shortened season', wet_harvest: 'no change' },\n    nitrogen:       { drought: 'top-dress nitrogen cut back, foliar nutrition up', heat: 'no change', excess_rain: 'split applications and leaching losses add top-dress volume', flood: 'nitrogen re-applied after leaching', late_planting: 'no change', wet_harvest: 'no change' },\n    adjuvants:      { drought: 'no change', heat: 'no change', excess_rain: 'rainfastness and drift agents for tight spray windows', flood: 'no change', late_planting: 'no change', wet_harvest: 'no change' }\n  };\n  \/* corn (maize) is its own family, not 'cereals': wheat\/barley\/sorghum\/millet\/teff\n     dislike a wet season alike (lodging, sprouting, head disease at harvest), but\n     rain-limited summer maize (the Pampas, Brazil South) reads extra rain as a\n     GAIN, the opposite sign from wheat under the same excess_rain stress. Folding\n     maize into 'cereals' silently forced every maize crop through wheat's table\n     and was the main reason wet regions came back with every crop at a total\n     loss, contradicting their own mechanism sentence (\"yield upside for soybean\n     and corn\"). See CROP_IMPACT.*.maize below. *\/\n  var FAMILY_OF = { wheat: 'cereals', barley: 'cereals', corn: 'maize', sorghum: 'cereals', millet: 'cereals', teff: 'cereals', rice: 'rice',\n    soybean: 'oilseeds', rapeseed: 'oilseeds', sunflower: 'oilseeds', groundnut: 'oilseeds', oilpalm: 'oil_palm', cotton: 'cotton',\n    pulses: 'pulses', sugarcane: 'sugarcane', coffee: 'coffee_cocoa', cocoa: 'coffee_cocoa', horticulture: 'horticulture' };\n  var CROP_LABEL = { wheat: 'Wheat', corn: 'Maize', soybean: 'Soybean', rice: 'Rice', barley: 'Barley', rapeseed: 'Canola and mustard', sunflower: 'Sunflower', cotton: 'Cotton', pulses: 'Pulses', groundnut: 'Groundnut', sugarcane: 'Sugarcane', oilpalm: 'Oil palm', sorghum: 'Sorghum', millet: 'Millet', teff: 'Teff', coffee: 'Coffee', cocoa: 'Cocoa', horticulture: 'Horticulture' };\n  \/* short names for the distributor message only (never truncated silently, see names() below) *\/\n  var MSG_LABEL = { fungicides: 'fungicides', insecticides: 'insecticides', herbicides: 'herbicides', seed_treatment: 'seed treatment', biostimulants: 'biostimulants', resilient_seed: 'short-cycle seed', nitrogen: 'nitrogen', adjuvants: 'adjuvants' };\n  var CROP_IMPACT = {\n    drought: {\n      cereals: { yield: '--', pests: ['fall armyworm', 'aphids', 'mites'], diseases: ['aflatoxin risk in maize and groundnut'] },\n      rice: { yield: '--', pests: ['stem borer', 'brown planthopper'], diseases: ['lower blast pressure'] },\n      oilseeds: { yield: '--', pests: ['whitefly', 'spider mites', 'thrips'], diseases: ['lower rust pressure', 'charcoal rot'] },\n      cotton: { yield: '-', pests: ['whitefly', 'jassids', 'thrips'], diseases: ['lower boll rot'] },\n      pulses: { yield: '--', pests: ['pod borer', 'aphids'], diseases: ['dry root rot'] },\n      sugarcane: { yield: '-', pests: ['early shoot borer', 'white grub'], diseases: ['lower red rot'] },\n      coffee_cocoa: { yield: '-', pests: ['coffee berry borer', 'mirids'], diseases: ['dieback', 'lower leaf rust'] },\n      oil_palm: { yield: '-', pests: ['bagworm'], diseases: ['bunch failure after drought'] },\n      horticulture: { yield: '--', pests: ['mites', 'whitefly', 'thrips'], diseases: ['lower foliar fungal pressure'] },\n      maize: { yield: '--', pests: ['fall armyworm', 'aphids', 'mites'], diseases: ['aflatoxin risk after drought'] }\n    },\n    heat: {\n      cereals: { yield: '-', pests: ['aphids'], diseases: [] }, rice: { yield: '-', pests: [], diseases: ['spikelet sterility at flowering'] },\n      oilseeds: { yield: '-', pests: ['mites'], diseases: [] }, cotton: { yield: '-', pests: ['whitefly'], diseases: [] },\n      pulses: { yield: '-', pests: [], diseases: [] }, sugarcane: { yield: '0', pests: [], diseases: [] },\n      coffee_cocoa: { yield: '-', pests: [], diseases: [] }, oil_palm: { yield: '0', pests: [], diseases: [] },\n      horticulture: { yield: '-', pests: ['mites'], diseases: ['blossom drop'] },\n      maize: { yield: '-', pests: ['aphids'], diseases: [] }\n    },\n    excess_rain: {\n      cereals: { yield: '-', pests: ['slugs', 'armyworm'], diseases: ['Fusarium head blight', 'Septoria', 'rusts'] },\n      rice: { yield: '0', pests: [], diseases: ['bacterial blight', 'sheath blight'] },\n      oilseeds: { yield: '+', pests: ['slugs'], diseases: ['Asian soybean rust', 'white mould', 'Sclerotinia'] },\n      cotton: { yield: '-', pests: [], diseases: ['boll rot', 'bacterial blight'] },\n      pulses: { yield: '-', pests: [], diseases: ['anthracnose', 'root rots'] },\n      sugarcane: { yield: '+', pests: [], diseases: ['red rot'] },\n      coffee_cocoa: { yield: '-', pests: [], diseases: ['coffee leaf rust', 'black pod'] },\n      oil_palm: { yield: '+', pests: [], diseases: ['bunch rot'] },\n      horticulture: { yield: '-', pests: ['slugs'], diseases: ['late blight', 'downy mildew'] },\n      \/* rain-limited summer maize (Pampas, Brazil South): extra rain is a GAIN,\n         the opposite sign from wheat under the same stress -- see FAMILY_OF. *\/\n      maize: { yield: '+', pests: ['armyworm', 'slugs'], diseases: ['leaf blights'] }\n    },\n    flood: {\n      cereals: { yield: '--', pests: [], diseases: ['damping-off', 'root rots'] }, rice: { yield: '-', pests: [], diseases: [] },\n      oilseeds: { yield: '--', pests: [], diseases: ['Phytophthora', 'damping-off'] }, cotton: { yield: '--', pests: [], diseases: ['seedling disease'] },\n      pulses: { yield: '--', pests: [], diseases: ['root rots'] }, sugarcane: { yield: '-', pests: [], diseases: [] },\n      coffee_cocoa: { yield: '-', pests: [], diseases: ['root rots'] }, oil_palm: { yield: '0', pests: [], diseases: [] },\n      horticulture: { yield: '--', pests: [], diseases: ['soft rots'] },\n      maize: { yield: '--', pests: [], diseases: ['damping-off', 'root rots'] }\n    },\n    late_planting: {\n      cereals: { yield: '-', pests: [], diseases: [] }, rice: { yield: '-', pests: [], diseases: [] }, oilseeds: { yield: '-', pests: [], diseases: [] },\n      cotton: { yield: '-', pests: [], diseases: [] }, pulses: { yield: '-', pests: [], diseases: [] }, sugarcane: { yield: '0', pests: [], diseases: [] },\n      coffee_cocoa: { yield: '0', pests: [], diseases: [] }, oil_palm: { yield: '0', pests: [], diseases: [] }, horticulture: { yield: '-', pests: [], diseases: [] },\n      maize: { yield: '-', pests: [], diseases: [] }\n    },\n    wet_harvest: {\n      cereals: { yield: '-', pests: [], diseases: ['sprouting and mycotoxins in grain'] }, rice: { yield: '-', pests: [], diseases: ['grain discolouration'] },\n      oilseeds: { yield: '-', pests: [], diseases: ['pod shatter and seed rot'] }, cotton: { yield: '-', pests: [], diseases: ['boll rot'] },\n      pulses: { yield: '-', pests: [], diseases: ['seed staining'] }, sugarcane: { yield: '0', pests: [], diseases: [] },\n      coffee_cocoa: { yield: '-', pests: [], diseases: ['cherry drop'] }, oil_palm: { yield: '0', pests: [], diseases: [] }, horticulture: { yield: '-', pests: [], diseases: ['post-harvest rots'] },\n      maize: { yield: '-', pests: [], diseases: ['ear rots and mycotoxins'] }\n    }\n  };\n  \/* the 'oilseeds' family shares ONE yield band across soybean, sunflower,\n     rapeseed and groundnut -- their yield response to these stresses is\n     genuinely similar, so that stays a family table. Disease and pest NAMES\n     are not similar: CROP_IMPACT.excess_rain.oilseeds names Asian soybean\n     rust, a soybean-specific disease that does not affect sunflower, so a\n     Pampas sunflower row was rendering it verbatim (2026-09-25). This table\n     is consulted BEFORE the family list in cropImpacts(), keyed by crop id\n     then stress; a crop with no entry for a stress falls back to the family\n     list unchanged (sunflower drought has no entry here on purpose -- the\n     family list is already accurate for it). Only the lists that needed a\n     crop-specific correction are present; the rest of MSG_LABEL\/CROP_LABEL\/\n     FAMILY_OF above stays untouched. *\/\n  var CROP_IMPACT_OVERRIDE = {\n    soybean: { excess_rain: { diseases: ['Asian soybean rust', 'white mould', 'Sclerotinia'] } },\n    sunflower: { excess_rain: { diseases: ['Sclerotinia head rot', 'downy mildew', 'Phomopsis'] } },\n    rapeseed: { excess_rain: { diseases: ['Sclerotinia stem rot', 'light leaf spot', 'Phoma'] } },\n    groundnut: { drought: { diseases: ['aflatoxin risk in kernels'] }, excess_rain: { diseases: ['leaf spot', 'white mould'] } }\n  };\n  var YIELD_RANK = { '--': -2, '-': -1, '0': 0, '+': 1, '++': 2 };\n  var BAND_OF = { '-2': '--', '-1': '-', '0': '0', '1': '+', '2': '++' };\n  var MON3 = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];\n  \/* seven steps, symmetric around zero: the step is picked by MAGNITUDE, so\n     -15 and +15 sit at the same depth on opposite sides. RAMP is ordered dry\n     to wet and carries the legend label for each step. *\/\n  var RAMP = [[-25, '#8a5a2b', '25% or more below normal'], [-15, '#b98a55', '15 to 25% below'], [-5, '#dfc9a4', '5 to 15% below'], [0, '#e0e7d6', 'near normal'], [5, '#aac8d8', '5 to 15% above'], [15, '#5f9fbe', '15 to 25% above'], [25, '#2c6d96', '25% or more above']];\n  function monthsOf(r){\n    var out = [], m = r[0];\n    for(;;){ out.push(m); if(m === r[1]){ break; } m = m === 12 ? 1 : m + 1; if(out.length > 12){ break; } }\n    return out;\n  }\n  function inRange(r, m){\n    if(!r){ return false; }\n    if(r[0] <= r[1]){ return m >= r[0] ? m <= r[1] : false; }\n    return m >= r[0] ? true : m <= r[1];\n  }\n  function overlap(a, b){\n    if(!a ? true : !b){ return false; }\n    var ms = monthsOf(a), i;\n    for(i = 0; i < ms.length; i++){ if(inRange(b, ms[i])){ return true; } }\n    return false;\n  }\n  function fmtRange(r){ return r[0] === r[1] ? MON3[r[0] - 1] : MON3[r[0] - 1] + ' to ' + MON3[r[1] - 1]; }\n  function clamp01(x){ return x < 0 ? 0 : (x > 1 ? 1 : x); }\n  function roundSym(x){ return x < 0 ? -Math.round(-x) : Math.round(x); }\n  function clampIdx(x){ var v = roundSym(x); if(v === 0){ return 0; } \/* normalise -0 *\/ if(v > 3){ v = 3; } if(v < -3){ v = -3; } return v; }\n  \/* Calibration choice, not a measurement: plain round-to-nearest (roundSym)\n     draws the zero\/nonzero line at |net|=0.5, a full half-band wide, and\n     real signal was landing inside it -- Pampas soybean (plata-pampas,\n     El Ni\u00f1o) nets +0.5044 at strong strength (rounds to a gain) but +0.4722\n     at historic (rounds to \"no effect\"), so the page's own default view\n     (historic strength) showed a wet Pampas season as neutral for soybean\n     while the region's mechanism sentence calls it a yield upside. Narrowing\n     the zero band to |net| < 0.35 fixes that without moving anything else on\n     the scale (the 1\/2 step still sits at 1.5, etc.) -- only values that\n     were already close enough to a full step to round to it under the old\n     rule can flip. See the tool rules for the regions this moved and why each one\n     reads correctly at the narrower width. *\/\n  var YIELD_ZERO_BAND = 0.35;\n  function yieldBandIdx(net){\n    var v = roundSym(net);\n    if(v === 0 ? Math.abs(net) >= YIELD_ZERO_BAND : false){ v = net < 0 ? -1 : 1; }\n    return Math.max(-2, Math.min(2, v));\n  }\n  \/* anomaly + crop rows -> stress weights 0..1. Drought and excess rain saturate at\n     25% of normal rain, heat at +1.5C, flooding runs from +60% to +100%: a\n     regional anomaly of +25% is a wet year with water standing in low ground,\n     not the region-wide flooding that destroys the crop -- that is what a\n     coastal El Nino event produces at +150%-class anomalies (Peru\/Ecuador\n     coast). At the old +20%\/+30% band every wet region (Pampas, Brazil South,\n     East Africa) carried flood weight from an ordinary wet season and every\n     crop came back as a total loss, contradicting the region's own mechanism\n     sentence. The two calendar stresses are production shares: late planting\n     counts the rows whose\n     planting window sits in the anomaly months (all of them when no rows are\n     known), wet harvest the rows whose harvest does. f is the strength factor\n     (0..1ish, default 1): a weaker event delays the calendar less, so the late\n     planting share scales with it too, the same way drought and heat already do. *\/\n  function stressWeights(anom, crops, f){\n    f = (f === undefined) ? 1 : f;\n    var p = anom.precipPct, t = anom.tempC;\n    var w = { drought: 0, heat: 0, excess_rain: 0, flood: 0, late_planting: 0, wet_harvest: 0 };\n    if(p < 0){ w.drought = clamp01(-p \/ 25); }\n    if(p > 0){ w.excess_rain = clamp01(p \/ 25); }\n    if(t > 0){ w.heat = clamp01(t \/ 1.5); }\n    if(p > 60){ w.flood = clamp01((p - 60) \/ 40); }\n    var tot = 0, plant = 0, harv = 0, i, c, wt;\n    crops = crops || [];\n    for(i = 0; i < crops.length; i++){\n      c = crops[i]; wt = c.weight || 1; tot += wt;\n      if(c.plant ? overlap(c.plant, anom.months) : false){ plant += wt; }\n      if(c.harvest ? overlap(c.harvest, anom.months) : false){ harv += wt; }\n    }\n    if(anom.onset === 'late'){ w.late_planting = (tot > 0 ? plant \/ tot : 1) * clamp01(f); }\n    if(w.excess_rain > 0){ w.wet_harvest = tot > 0 ? w.excess_rain * harv \/ tot : w.excess_rain; }\n    return w;\n  }\n  \/* region + anomaly row + strength -> { stress, dominant, categories:[{id,label,index,reason,driver}], precipPct, tempC, signal }.\n     Strength scales the anomaly before the weights; the index follows from the weights,\n     so moderate \/ strong \/ historic read as a gradient without saturating at the ends.\n     Overrides replace the computed index and reason for a category.\n     anom.signal === 'none' (phase 2, task 2 -- a region ENSO genuinely does not\n     reach) short-circuits to an all-zero result carrying signal:'none' on the\n     return value, so every surface that reads demandIndex()'s output (the map\n     fill, the panel tiles and bars, the heatmap row) can tell \"confirmed zero\n     effect\" apart from \"we never computed anything\" with one flag, rather than\n     re-deriving it from precipPct === 0 (which a genuinely calm neutral-phase\n     row would also produce). The normal path below still computes to the same\n     all-zero numbers for a signal:'none' row (its anomaly is precipPct:0,\n     tempC:0, onset:'normal' by construction -- the validator requires it), so\n     this branch is a defensive fast path, not the only thing that keeps the\n     numbers at zero. *\/\n  \/* \u2500\u2500 agency outlooks (2026-10-12) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n     An outlook row (data\/enso-source.js `outlook`) is the agency's own\n     statement for the season ahead. outlookAnomaly gives it the composite\n     row's shape so demandIndex, cropImpacts, playbook and precipColor take\n     it unchanged. `fixed` tells strengthFactor to leave it alone: the agency\n     stated the magnitude, the Strength chips scale the composite only.\n     activeAnomaly is the ONE place that decides which row is in force, for\n     every surface (map, panel, playbook, heatmap, crawler table): the\n     outlook when the region has one, the page is in the live phase and the\n     reader has not asked for the typical view; the composite otherwise. *\/\n  function strengthFactor(anom, strength){ return anom.fixed ? 1 : (STRENGTH[strength] || 1); }\n  function outlookAnomaly(row){\n    return { precipPct: row.rain.pct, tempC: row.temp.c, months: row.months, onset: row.onset, confidence: row.confidence,\n      mechanism: row.headline, sources: row.sources || [], fixed: true, outlook: row };\n  }\n  function activeAnomaly(rows, outlookRow, phase, livePhase, view){\n    var live = outlookRow ? (phase === livePhase) : false;\n    if(live ? view !== 'typical' : false){ return outlookAnomaly(outlookRow); }\n    return rows[phase];\n  }\n  function demandIndex(region, anom, strength, overrides){\n    if(anom.signal === 'none'){\n      var noCats = [], ni, nc;\n      for(ni = 0; ni < CATEGORIES.length; ni++){\n        nc = CATEGORIES[ni];\n        noCats.push({ id: nc.id, label: nc.label, index: 0, reason: 'no reliable signal for this region', driver: null });\n      }\n      return { stress: { drought: 0, heat: 0, excess_rain: 0, flood: 0, late_planting: 0, wet_harvest: 0 }, dominant: null, categories: noCats, precipPct: 0, tempC: 0, signal: 'none' };\n    }\n    var f = strengthFactor(anom, strength);\n    var s = { precipPct: anom.precipPct * f, tempC: anom.tempC * f, months: anom.months, onset: anom.onset };\n    var w = stressWeights(s, region.crops || [], f);\n    var dom = null, domW = 0, si, k;\n    for(si = 0; si < STRESSES.length; si++){ k = STRESSES[si]; if(w[k] > domW){ domW = w[k]; dom = k; } }\n    var cats = [], i, c, st, sum, top, topV, v, idx, reason, ov, nPos, nNeg;\n    for(i = 0; i < CATEGORIES.length; i++){\n      c = CATEGORIES[i]; sum = 0; top = null; topV = 0; nPos = 0; nNeg = 0;\n      for(si = 0; si < STRESSES.length; si++){\n        st = STRESSES[si]; v = w[st] * MATRIX[c.id][st]; sum += v;\n        if(v > 0){ nPos++; } if(v < 0){ nNeg++; }\n      }\n      \/* the reason follows the sign of the index: the largest contribution of the\n         same sign as the sum (largest of any sign only when the sum is zero) *\/\n      for(si = 0; si < STRESSES.length; si++){\n        st = STRESSES[si];\n        v = w[st] * MATRIX[c.id][st];\n        if(v === 0){ continue; }\n        if(sum !== 0 ? (v > 0) !== (sum > 0) : false){ continue; }\n        \/* ties go to the later, more specific stress *\/\n        if(Math.abs(v) >= Math.abs(topV)){ topV = v; top = st; }\n      }\n      idx = clampIdx(sum);\n      reason = top ? REASON[c.id][top] : 'this season does not move this category';\n      if(idx === 0){\n        reason = (nPos > 0 ? nNeg > 0 : false) ? 'opposing pressures balance out this season'\n          : (top !== null ? 'some pressure, too little to shift the plan' : 'this season does not move this category');\n      }\n      ov = overrides ? (overrides[c.id] || null) : null;\n      if(ov){ idx = ov.index; reason = ov.reason; }\n      cats.push({ id: c.id, label: c.label, index: idx, reason: reason, driver: top });\n    }\n    return { stress: w, dominant: dom, categories: cats, precipPct: s.precipPct, tempC: s.tempC, signal: null };\n  }\n  \/* share of a crop's OWN window (its plant or harvest range) that falls\n     inside the anomaly months -- a fractional count, not the boolean overlap()\n     stressWeights uses for the region-level share. Used only by cropImpacts:\n     a crop is exposed to a wet harvest or a late start in proportion to how\n     much of ITS OWN window sits in the wet season, not whether any of it\n     does (a range can tail one month into a six-month anomaly window and\n     still register as fully \"overlapping\" under overlap()). *\/\n  function windowShare(range, anomMonths){\n    if(!range){ return 0; }\n    var ms = monthsOf(range), i, hit = 0;\n    for(i = 0; i < ms.length; i++){ if(inRange(anomMonths, ms[i])){ hit++; } }\n    return ms.length > 0 ? hit \/ ms.length : 0;\n  }\n  \/* the crop's own GROWING window -- first planting month to the month\n     harvest STARTS, inclusive, wrapping the same way monthsOf() does -- fed\n     through windowShare() so \"how much of the crop's season sits in the\n     anomaly\" reuses the exact fractional-overlap logic already proven for\n     wet_harvest\/late_planting, just over the whole standing-crop cycle\n     instead of one tail.\n     Ends where harvest BEGINS, not where it finishes (2026-09-26, second\n     pass): a crop is growing until the combine enters the field: once\n     harvest starts, it is being taken off, not standing in the weather the\n     region's drought\/heat\/excess_rain\/flood terms describe. Using the LAST\n     harvest month double-counted the harvest tail -- once diluting the\n     growing-season gain (folded into growWindowShare) and again as the\n     wet_harvest penalty (already its own, separately-windowed stress) --\n     which is what silently erased Pampas's own \"yield upside for soybean\n     and corn\": excess_rain's gain was being averaged down by months that\n     were never growing months to begin with, while wet_harvest's loss over\n     those SAME months stayed at full weight. See the tool rules \"A crop only\n     feels the weather it stands in\" for the reworked numbers.\n     A crop with no plant OR no harvest on this row (a perennial such as oil\n     palm or coffee, harvest-only in the source tables; also every synthetic\n     crop object the unit tests below build with no calendar at all) has no\n     window to speak of and counts as fully exposed. `anom` missing (no\n     anomaly context at all, as the direct-stress unit tests below pass)\n     also falls back to fully exposed, matching the no-window case: it is\n     only ever reached together with no-window crops in this file.\n     \/\/ TODO: this convention assumes the cycle fits inside monthsOf()'s\n     \/\/ 12-month wraparound; a crop whose harvest range is MORE than a year\n     \/\/ after its planting range with no year field to disambiguate (a long-\n     \/\/ cycle crop like sugarcane) can still produce a too-short window.\n     \/\/ Ending at harvest's FIRST month (rather than its last) shrinks this\n     \/\/ considerably -- see the tool rules for the one row this affects, whether\n     \/\/ it still needs a caveat, and why it is not special-cased here. *\/\n  function growWindowShare(c, anom){\n    if(!c.plant ? true : !c.harvest){ return 1; }\n    return anom ? windowShare([c.plant[0], c.harvest[0]], anom.months) : 1;\n  }\n  \/* reservoir + soil-moisture carry-over, DROUGHT ONLY: gating a crop's\n     regional weather stresses to its own growing window is honest but\n     understates India\/Pakistan, where a failed monsoon still hurts the\n     FOLLOWING rabi crop through empty reservoirs and dry soil at sowing --\n     that is not in-season drought, it is water that was never banked. A\n     crop whose planting begins within three months after the anomaly\n     window ends carries 0.4 of the region's drought weight; 0.4 is a\n     judgement call (enough to matter, not enough to read as a second full\n     season of drought), and nothing else carries over this way. *\/\n  function plantsSoonAfter(anomMonths, plantMonth){\n    var m = anomMonths[1], i;\n    for(i = 0; i < 3; i++){ m = m === 12 ? 1 : m + 1; if(m === plantMonth){ return true; } }\n    return false;\n  }\n  function droughtCarryOver(c, anom){\n    if(!anom ? true : !c.plant){ return false; }\n    return plantsSoonAfter(anom.months, c.plant[0]);\n  }\n  \/* one entry per distinct crop id, plus the union of their pests and diseases.\n     The yield band NETS the stresses rather than letting the worst one win: a\n     strong gain and a weak loss read as a gain. Each stress contributes its\n     own band rank scaled by how present it is; the sum is rounded and clamped\n     back into a band. The effect is super-linear in intensity, so a fully\n     present stress dominates a marginal one without needing a floor. Pests\n     and diseases keep a 0.3 presence floor -- they are presence lists, not a\n     magnitude that can net against something else.\n     drought\/heat\/excess_rain\/flood used to be taken straight off the region-\n     level `stress` object for every crop, justified as \"the same weather\n     hits every crop in the region\" -- true of the WEATHER, false of the\n     EXPOSURE: that only holds while the crop is actually standing in the\n     field. Applying it unconditionally told a US South user that spring\n     canola (sown in May) GAINED from a December-to-March rain anomaly, that\n     spring wheat and cotton (also not yet planted) LOST to it, and scored\n     East African long-rains maize -- already harvested by October -- against\n     the short-rains anomaly. This is the same bug a third time (see the tool rules\n     \"A crop only feels the weather it stands in\"): a table built for one\n     case applied to a crop it does not describe. All four weather stresses\n     are therefore scaled by growWindowShare() per crop ROW (drought also\n     gets the carry-over term above), the same per-row-then-production-\n     weighted-merge treatment late_planting\/wet_harvest already used, so a\n     crop only answers for weather that actually reached it (or, for\n     drought only, reservoir\/soil-moisture carry-over into its sowing).\n     The two calendar stresses (late_planting, wet_harvest) are recomputed\n     per crop ROW as windowShare() exactly as before, never read off the\n     region-level `stress` object passed in (that copy is for DEMAND, where\n     a distributor sells into the whole region). When several seasons (rows)\n     of one crop id merge into one entry, every per-row share above --\n     late_planting, wet_harvest, the growing-window share, the drought\n     carry-over -- is PRODUCTION-WEIGHTED across its rows (sum of row weight\n     * row share, divided by the sum of row weight) -- the band answers\n     \"what happens to this region's crop\", and a minor secondary season\n     should move that answer only in proportion to its own share of the\n     crop's production, never dominate a five-times-larger primary season\n     the way taking the worst row did. *\/\n  function cropImpacts(region, stress, anom, f){\n    f = (f === undefined) ? 1 : f;\n    var crops = region.crops || [], seen = {}, cal = {}, out = [], i, c, fam, si, st, imp, entry, k, wh, lp, gw, dc, cs, wt, ovr, plist, dlist;\n    for(i = 0; i < crops.length; i++){\n      c = crops[i];\n      wt = c.weight || 1;\n      wh = anom ? stress.excess_rain * windowShare(c.harvest, anom.months) : 0;\n      \/* clamp THE FACTOR, not the product -- matches stressWeights' region-\n         level late_planting above. windowShare() is already a 0..1 calendar\n         share; f is a strength multiplier (0.6 \/ 1.0 \/ 1.25) meant to DAMPEN\n         a weaker event, not inflate a fixed calendar geometry past what the\n         calendar itself measured. clamp01(windowShare(...) * f) let historic\n         (f=1.25) push a share as low as 0.8 up to the same 1.0 ceiling a\n         share of 1.0 gets at f=1 -- an artificial boost with no calendar\n         basis, and the two formulas disagreed at historic strength for the\n         same crop. Both now clamp f itself, so historic never exceeds the\n         raw share and moderate still dampens it, same as the region level. *\/\n      lp = (anom ? anom.onset === 'late' : false) ? windowShare(c.plant, anom.months) * clamp01(f) : 0;\n      gw = growWindowShare(c, anom);\n      dc = droughtCarryOver(c, anom) ? 0.4 : 0;\n      if(!cal[c.id]){ cal[c.id] = { wh: wt * wh, lp: wt * lp, gw: wt * gw, dc: wt * dc, w: wt }; }\n      else { cal[c.id].wh += wt * wh; cal[c.id].lp += wt * lp; cal[c.id].gw += wt * gw; cal[c.id].dc += wt * dc; cal[c.id].w += wt; }\n      entry = seen[c.id];\n      if(!entry){\n        fam = FAMILY_OF[c.id] || 'cereals';\n        entry = { id: c.id, label: CROP_LABEL[c.id] || c.label, family: fam, seasons: [], yield: '0', pests: [], diseases: [], weight: 0 };\n        seen[c.id] = entry; out.push(entry);\n      }\n      entry.seasons.push(c.label);\n      entry.weight += (c.weight || 0);\n    }\n    for(i = 0; i < out.length; i++){\n      entry = out[i]; fam = entry.family; cs = cal[entry.id];\n      var gwShare = cs.w > 0 ? cs.gw \/ cs.w : 1;\n      var droughtShare = clamp01(gwShare + (cs.w > 0 ? cs.dc \/ cs.w : 0));\n      var cropStress = { drought: stress.drought * droughtShare, heat: stress.heat * gwShare, excess_rain: stress.excess_rain * gwShare, flood: stress.flood * gwShare, late_planting: (cs.w > 0 ? cs.lp \/ cs.w : 0), wet_harvest: (cs.w > 0 ? cs.wh \/ cs.w : 0) };\n      var net = 0, w;\n      for(si = 0; si < STRESSES.length; si++){\n        st = STRESSES[si];\n        w = cropStress[st];\n        imp = CROP_IMPACT[st][fam];\n        if(!imp){ continue; }\n        if(w > 0){ net += w * YIELD_RANK[imp.yield]; }\n        if(w >= 0.3){\n          \/* crop-specific disease\/pest names win over the family list (see\n             CROP_IMPACT_OVERRIDE above); the yield band above stays family\n             level on purpose, only the presence lists are crop-aware. *\/\n          ovr = CROP_IMPACT_OVERRIDE[entry.id] ? CROP_IMPACT_OVERRIDE[entry.id][st] : null;\n          plist = (ovr ? ovr.pests : null) || imp.pests;\n          dlist = (ovr ? ovr.diseases : null) || imp.diseases;\n          for(k = 0; k < plist.length; k++){ if(entry.pests.indexOf(plist[k]) < 0){ entry.pests.push(plist[k]); } }\n          for(k = 0; k < dlist.length; k++){ if(entry.diseases.indexOf(dlist[k]) < 0){ entry.diseases.push(dlist[k]); } }\n        }\n      }\n      entry.net = net;\n      entry.yield = BAND_OF[yieldBandIdx(net)];\n    }\n    out.sort(function(a, b){ return b.weight - a.weight ? b.weight - a.weight : (a.id < b.id ? -1 : 1); });\n    return out;\n  }\n  \/* demand result -> { push, hold, pull, message } or null in the neutral phase,\n     or { signal:'none', message } for a region ENSO does not reach (phase 2,\n     task 2) -- a DISTINCT shape from both of those, never null (null already\n     means \"neutral phase, run the baseline programme\" and the page renders a\n     different note for that), so the page can tell the three cases apart with\n     one check (`!p` for neutral, `p.signal === 'none'` for no-signal, else the\n     normal push\/hold\/pull shape) instead of re-deriving it from anom.signal\n     itself. The message names every one of the region's own watch items\n     (there is no push\/pull to compete with for space here, unlike the normal\n     message below which caps at the first one). *\/\n  function playbook(result, region, anom, phase){\n    if(phase === 'neutral'){ return null; }\n    if(anom.signal === 'none'){\n      var wNames = [], wi;\n      for(wi = 0; wi < (region.watch || []).length; wi++){ wNames.push(region.watch[wi].label); }\n      var watchLine = wNames.length ? ' Watch ' + wNames.join(', ') + '.' : '';\n      return { signal: 'none', message: region.short + '. ' + PHASE_LABEL[phase] + ' season: no reliable ENSO signal reaches this region, so the normal programme applies.' + watchLine };\n    }\n    var push = [], hold = [], pull = [], i, c, item;\n    for(i = 0; i < result.categories.length; i++){\n      c = result.categories[i];\n      item = { id: c.id, label: c.label, index: c.index, reason: c.reason, months: fmtRange(anom.months) };\n      if(c.index >= 1){ push.push(item); } else if(c.index <= -1){ pull.push(item); } else { hold.push(item); }\n    }\n    push.sort(function(a, b){ return b.index - a.index; });\n    pull.sort(function(a, b){ return a.index - b.index; });\n    var pct = Math.round(Math.abs(result.precipPct));\n    var dir = result.precipPct < 0 ? 'below' : 'above';\n    \/* an outlook row names the outlook where the composite names the phase:\n       a forwarded line must say what the numbers rest on *\/\n    var basis = anom.outlook\n      ? anom.outlook.label + ', ' + fmtRange(anom.months) + ', rain ' + pct + '% ' + dir + ' normal'\n      : PHASE_LABEL[phase] + ' season, rain typically ' + pct + '% ' + dir + ' normal, ' + fmtRange(anom.months);\n    function names(list, n){\n      \/* \"and 1 more\" is clumsy: naming the last item instead reads better, so\n         only fall back to counting once there is more than one item left over *\/\n      var out = [], k, limit, extra;\n      limit = (list.length <= n + 1) ? list.length : n;\n      for(k = 0; k < limit; k++){ out.push(MSG_LABEL[list[k].id] || list[k].label.toLowerCase()); }\n      extra = list.length - out.length;\n      if(extra > 0){ out.push(extra + ' more'); }\n      if(out.length === 1){ return out[0]; }\n      return out.slice(0, out.length - 1).join(', ') + ' and ' + out[out.length - 1];\n    }\n    var msg = region.short + '. ' + basis + '.';\n    if(push.length){ msg += ' Lead with ' + names(push, 3) + '.'; }\n    if(pull.length){ msg += ' Hold back on ' + names(pull, 2) + '.'; }\n    if(region.watch ? region.watch.length : false){ msg += ' Watch ' + region.watch[0].label + ' (' + region.watch[0].when + ').'; }\n    return { push: push, hold: hold, pull: pull, message: msg };\n  }\n  \/* portfolio heatmap sort, pure so it can be tested outside a browser the\n     same way parseState\/buildQuery are (Task 9 review, 2026-09-26): the page\n     script used to carry its own copy of this comparator inline in\n     renderHeat(), and the test suite carried a SECOND, separately-written\n     copy to sort a fixture and assert the result was sorted -- which never\n     actually executed the page's real comparator, so a bug in it (the\n     inverted-direction bug this same review found) could survive untested.\n     `rows` is an array of { r: <region>, cats: <categories from\n     demandIndex()> }, exactly the shape renderHeat() already builds; `dir`\n     follows the page's own SORT.dir convention (negative sorts descending --\n     the label aria-sort shows on the first click of a fresh column, positive\n     ascending). Returns a NEW array; does not mutate `rows`. *\/\n  function sortHeatRows(rows, catId, dir){\n    var out = rows.slice();\n    out.sort(function(x, y){\n      var xi = 0, yi = 0, k;\n      for(k = 0; k < x.cats.length; k++){ if(x.cats[k].id === catId){ xi = x.cats[k].index; } if(y.cats[k].id === catId){ yi = y.cats[k].index; } }\n      return (xi - yi) * dir;\n    });\n    return out;\n  }\n  \/* \u2500\u2500 map label visibility (phase 2, task 4): which region labels render\n     without colliding, pure so it can be tested outside a browser the same\n     way sortHeatRows is above -- the page and tests.js call the SAME\n     function, so a bug in it cannot survive untested. Doubling the region\n     count from 14 to 24 made the old \"show every label\" approach collide;\n     rather than shrinking the type, a deterministic priority order decides\n     which labels show: the selected region always wins (sorted first, so it\n     is placed before anything can be checked against it and therefore never\n     hidden), then every other region by descending total crop production\n     weight, each admitted only if its box clears every label already\n     admitted. Ties break on id, alphabetically, so the order never depends\n     on object\/array iteration quirks.\n     The priority order intentionally reads NOTHING from anomaly, phase or\n     strength -- regionCropWeight sums region.crops[].weight, the same\n     calendar\/extraCrops production data every region carries regardless of\n     ENSO phase, so a no-signal region (no demand numbers, but real crops\n     from its calendarCountries\/extraCrops the same as any other region)\n     computes its weight the SAME WAY and is never penalised for having no\n     numeric demand index. Deriving it from anything phase- or strength-\n     dependent would make labels pop in and out as the user drags the\n     strength selector, which reads as a bug, not a feature. *\/\n  function regionCropWeight(region){\n    var crops = region.crops || [], i, sum = 0;\n    for(i = 0; i < crops.length; i++){ sum += crops[i].weight || 0; }\n    return sum;\n  }\n  \/* LABEL_H\/LABEL_W are measured live (Chrome, Roboto 700 9px, getBBox() on\n     a real render) for every region.short this table has ever shipped --\n     see tests.js's own \"measured entry\" test, which pins this table against\n     the live DOM the same way. A label whose short name is missing from\n     this table (a future region added without re-measuring) falls back to\n     AVG_CHAR_W * short.length rather than going unmeasured silently; that\n     fallback under-measures on this bold condensed face, which makes the\n     gate MORE permissive exactly when a label needs the real number most --\n     tests.js asserts every current region has a real entry so the fallback\n     is a safety net, never the normal path. LABEL_HALO matches text.lb's\n     own CSS stroke-width (the white halo that keeps a label legible over\n     the coloured map): two labels read as touching once their haloes meet,\n     not only once their bare glyph boxes do. LABEL_MOBILE_SCALE is the\n     font-size ratio the `max-width:820px` breakpoint bumps labels by (9px\n     to 13px) -- visibleLabels's caller passes it as `scale` at that\n     breakpoint so the SAME collision math stays correct at the larger\n     physical glyph size, not just at the 9px size these numbers were\n     measured at. *\/\n  var LABEL_H = 10.16, LABEL_HALO = 2.5, LABEL_MOBILE_SCALE = 13 \/ 9;\n  var LABEL_W = { 'India': 19.94, 'Pakistan': 35.27, 'SE Asia': 30.70, 'Philippines': 45.0, \/* computed from Roboto Bold advance widths at 9px (fontTools on the woff2 the page loads, wght 700); the same method reproduces every measured entry within 0.2 units *\/ 'Australia': 36.24, 'Southern Africa': 63.59, 'East Africa': 44.21, 'Sahel': 22.63, 'Central America': 65.13, 'N. Andes': 36.69, 'Brazil C-N': 41.06, 'Brazil South': 49.01, 'Pampas': 32.85, 'US South': 37.44, 'Peru coast': 43.42,\n    'Canada Prairies': 64.01, 'Yangtze basin': 56.88, 'North China Plain': 71.13, 'Chile': 20.56, 'New Zealand': 52.43, 'W. Mediterranean': 71.25, 'Ukraine': 30.99, 'Central Europe': 59.62, 'W. Europe': 40.32, 'Kazakhstan': 47.32 };\n  var LABEL_AVG_CHAR_W = (function(){\n    var sumW = 0, sumLen = 0, k;\n    for(k in LABEL_W){ if(LABEL_W.hasOwnProperty(k)){ sumW += LABEL_W[k]; sumLen += k.length; } }\n    return sumW \/ sumLen;\n  })();\n  function labelWidth(short){\n    \/* hasOwnProperty, not the `in` operator or a bare LABEL_W[short] truthy\n       check: `in` (and a truthy check) walk the prototype chain, so a\n       region whose short name happened to collide with an inherited\n       Object.prototype key ('constructor', 'toString'...) would silently\n       read a function reference instead of falling through to the measured\n       -- or fallback -- width. Same discipline as the URL contract's\n       array-membership checks below, applied here to an object's keys. *\/\n    return LABEL_W.hasOwnProperty(short) ? LABEL_W[short] : short.length * LABEL_AVG_CHAR_W;\n  }\n  \/* greedy set cover, in priority order: a label collides with an\n     already-admitted one iff BOTH axes overlap at once (each label's\n     effective box grows by the halo on every side) -- the same rectangle\n     test tests.js already proved catches the real 2026-09-25 collisions\n     (Pakistan\/India, Brazil South\/Pampas) without flagging harmless near\n     pairs (N. Andes\/Peru coast, close mostly on one axis). `scale` (default\n     1) multiplies width, height and halo together, for the mobile\n     breakpoint's larger glyphs -- see LABEL_MOBILE_SCALE above. Returns a\n     plain object id -> true for every VISIBLE region; an id absent from it\n     is hidden (still fully reachable via its map shape, which carries all\n     the hover\/focus\/click behaviour -- text.lb is pointer-events:none and\n     always has been, so hiding the glyph changes nothing about\n     reachability). *\/\n  function visibleLabels(regions, selectedId, scale){\n    scale = scale || 1;\n    var h = LABEL_H * scale, halo = LABEL_HALO * scale;\n    var order = regions.slice();\n    order.sort(function(a, b){\n      if(a.id === selectedId){ return -1; }\n      if(b.id === selectedId){ return 1; }\n      var wa = regionCropWeight(a), wb = regionCropWeight(b);\n      if(wb !== wa){ return wb - wa; }\n      return a.id < b.id ? -1 : (a.id > b.id ? 1 : 0);\n    });\n    var shown = [], visible = {}, i, r, p, w, j, s, collide, dx, dy, xGap, yGap;\n    for(i = 0; i < order.length; i++){\n      r = order[i];\n      p = project(r.coord[0], r.coord[1]);\n      w = labelWidth(r.short) * scale;\n      collide = false;\n      for(j = 0; j < shown.length; j++){\n        s = shown[j];\n        dx = Math.abs(p[0] - s.p[0]); dy = Math.abs(p[1] - s.p[1]);\n        xGap = (w + s.w) \/ 2 + 2 * halo; yGap = h + 2 * halo;\n        if(dx < xGap ? dy < yGap : false){ collide = true; break; }\n      }\n      if(!collide){ shown.push({ p: p, w: w }); visible[r.id] = true; }\n    }\n    return visible;\n  }\n  \/* \u2500\u2500 URL contract, pure so it can be tested outside a browser \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n     `search` is a query string with or without its leading question mark.\n     Values are checked against ARRAYS, never against object keys, so a\n     crafted `__proto__` or `constructor` cannot pass (they are truthy object\n     keys but never appear in an array of ids). *\/\n  function parseState(search, defaults, regionIds){\n    var out = { region: defaults.region, phase: defaults.phase, strength: defaults.strength, view: defaults.view }, q, r, p, s, v;\n    try {\n      q = new URLSearchParams(search);\n      r = q.get('region'); if(r ? regionIds.indexOf(r) >= 0 : false){ out.region = r; }\n      p = q.get('phase'); if(p ? PHASES.indexOf(p) >= 0 : false){ out.phase = p; }\n      s = q.get('strength'); if(s ? STRENGTH_IDS.indexOf(s) >= 0 : false){ out.strength = s; }\n      v = q.get('view'); if(v === 'typical'){ out.view = 'typical'; }\n    } catch(err){}\n    return out;\n  }\n  function buildQuery(state, defaults, search){\n    var q = new URLSearchParams(), cur;\n    try {\n      cur = new URLSearchParams(search);\n      cur.forEach(function(v, k){ if(['region', 'phase', 'strength', 'view'].indexOf(k) < 0){ q.append(k, v); } });\n    } catch(err){}\n    if(state.region !== defaults.region){ q.set('region', state.region); }\n    if(state.phase !== defaults.phase){ q.set('phase', state.phase); }\n    if(state.strength !== defaults.strength){ q.set('strength', state.strength); }\n    if(state.view !== defaults.view){ q.set('view', state.view); }\n    return q.toString();\n  }\n  function precipColor(p){\n    var m = p < 0 ? -p : p, step = 0, i;\n    for(i = RAMP.length - 1; i > 3; i--){ if(m >= RAMP[i][0]){ step = i - 3; break; } }\n    if(step === 0){ return RAMP[3][1]; }\n    return p < 0 ? RAMP[3 - step][1] : RAMP[3 + step][1];\n  }\n  \/* \u2500\u2500 status-card staleness (phase 2, task 5): pure so it can be tested\n     outside a browser the same way parseState\/sortHeatRows are, and so the\n     page and tests.js call the exact same function instead of the page\n     carrying its own inline date-diff math that a test only re-implements\n     and never actually exercises. `issued` is the ENSO_STATE blob's own\n     'YYYY-MM-DD' date; `ref` is \"now\", passed in rather than read from\n     `new Date()` inside this function, so a test can pin an exact reference\n     date and the boundary (STALE_DAYS) without depending on the real clock\n     or the day the test happens to run. `ref` accepts either a Date object\n     (what the page passes) or a 'YYYY-MM-DD' string (what a test can pass\n     without constructing a Date) -- both are read back to calendar-day\n     components only, never a raw timestamp subtraction, so a same-day\n     comparison never reads as a fraction-of-a-day age from a few hours of\n     clock skew between the issue date (a date, not a timestamp) and the\n     moment the page happens to render. STALE_DAYS (45) is the single\n     threshold both this file's own boundary test and the page's renderState\n     read, so the two can never drift apart. *\/\n  var STALE_DAYS = 45;\n  \/* an outlook row is stale once the agency's next issue is this many days\n     overdue; the cadence is known per product, so the 45-day rule above\n     would be too slow here *\/\n  var OUTLOOK_GRACE_DAYS = 10;\n  function outlookStale(row, ref){ return outlookAgeDays(row.nextIssue, ref) > OUTLOOK_GRACE_DAYS; }\n  function outlookAgeDays(issued, ref){\n    var ip = String(issued).split('-');\n    var issuedMs = Date.UTC(parseInt(ip[0], 10), parseInt(ip[1], 10) - 1, parseInt(ip[2], 10));\n    var refMs;\n    if(ref instanceof Date){ refMs = Date.UTC(ref.getFullYear(), ref.getMonth(), ref.getDate()); }\n    else { var rp = String(ref).split('-'); refMs = Date.UTC(parseInt(rp[0], 10), parseInt(rp[1], 10) - 1, parseInt(rp[2], 10)); }\n    return Math.round((refMs - issuedMs) \/ 86400000);\n  }\n  \/* \u2500\u2500 the season the two index values describe \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n     state.indexAsOf is written the way the agency writes it, 'JJA 2026': one of\n     twelve overlapping three-month seasons, plus a year. Nobody outside\n     climate work reads that, so the status card never prints the token --\n     seasonRangeLabel turns it into months a reader already knows ('Jun to\n     Aug 2026').\n     the agency labels a season by the year of its MIDDLE month, which is why the\n     two seasons that straddle new year name both years: 'DJF 2026' is Dec\n     2025 to Feb 2026, 'NDJ 2026' is Nov 2026 to Jan 2027. Getting that\n     wrong would misdate the card by a whole year twice out of every twelve\n     refreshes, so it is handled here, in the one file the page and the test\n     suite share, rather than inline in the renderer.\n     Returns '' for anything it does not recognise, so renderState can skip\n     the line rather than print a guess. *\/\n  var SEASONS = ['DJF', 'JFM', 'FMA', 'MAM', 'AMJ', 'MJJ', 'JJA', 'JAS', 'ASO', 'SON', 'OND', 'NDJ'];\n  function seasonRangeLabel(asOf){\n    var parts = String(asOf == null ? '' : asOf).trim().split(\/\\s+\/);\n    if(parts.length !== 2){ return ''; }\n    var idx = SEASONS.indexOf(parts[0].toUpperCase());\n    if(idx < 0){ return ''; }\n    if(!\/^\\d{4}$\/.test(parts[1])){ return ''; }\n    var year = parseInt(parts[1], 10);\n    var mid = idx + 1;                                  \/* DJF -> Jan, NDJ -> Dec *\/\n    var first = mid === 1 ? 12 : mid - 1, last = mid === 12 ? 1 : mid + 1;\n    var firstYear = mid === 1 ? year - 1 : year, lastYear = mid === 12 ? year + 1 : year;\n    var head = MON3[first - 1] + (firstYear === lastYear ? '' : ' ' + firstYear);\n    return head + ' to ' + MON3[last - 1] + ' ' + lastYear;\n  }\n  \/* world polygons: zigzag varint over a 64 char alphabet, decoded with % and\n     Math.floor only (no bitwise operators, factory rule 1). Same encoding as the\n     Global Crop Calendar, whose build produced the blob. *\/\n  var ALPHA = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_';\n  var CODE = {}; (function(){ var i; for(i = 0; i < 64; i++){ CODE[ALPHA.charAt(i)] = i; } })();\n  function decodeRing(s, q){\n    var pts = [], i = 0, px = 0, py = 0, u, sh, k;\n    while(i < s.length){\n      u = 0; sh = 1;\n      for(;;){ k = CODE[s.charAt(i++)]; if(k >= 32){ u += (k - 32) * sh; sh *= 32; } else { u += k * sh; break; } }\n      px += (u % 2) ? -((u + 1) \/ 2) : u \/ 2;\n      u = 0; sh = 1;\n      for(;;){ k = CODE[s.charAt(i++)]; if(k >= 32){ u += (k - 32) * sh; sh *= 32; } else { u += k * sh; break; } }\n      py += (u % 2) ? -((u + 1) \/ 2) : u \/ 2;\n      pts.push([px \/ q, py \/ q]);\n    }\n    return pts;\n  }\n  \/* equal area world projection, x100 and y flipped for SVG (as the Global Crop Calendar) *\/\n  var EE = [1.340264, -0.081106, 0.000893, 0.003796], EM = 0.8660254037844386, RAD = Math.PI \/ 180;\n  function project(lon, lat){\n    var th = Math.asin(EM * Math.sin(lat * RAD)), t2 = th * th, t6 = t2 * t2 * t2;\n    var x = (lon * RAD) * Math.cos(th) \/ (EM * (EE[0] + 3 * EE[1] * t2 + t6 * (7 * EE[2] + 9 * EE[3] * t2)));\n    var y = th * (EE[0] + EE[1] * t2 + t6 * (EE[2] + EE[3] * t2));\n    return [x * 100, -y * 100];\n  }\n  return { STRENGTH: STRENGTH, STRENGTH_IDS: STRENGTH_IDS, STRENGTH_LABEL: STRENGTH_LABEL, PHASES: PHASES, PHASE_LABEL: PHASE_LABEL, STRESSES: STRESSES, STRESS_LABEL: STRESS_LABEL,\n    CATEGORIES: CATEGORIES, MATRIX: MATRIX, MON3: MON3, RAMP: RAMP, CROP_LABEL: CROP_LABEL, MSG_LABEL: MSG_LABEL,\n    monthsOf: monthsOf, inRange: inRange, overlap: overlap, fmtRange: fmtRange,\n    stressWeights: stressWeights, demandIndex: demandIndex, cropImpacts: cropImpacts, playbook: playbook, sortHeatRows: sortHeatRows,\n    parseState: parseState, buildQuery: buildQuery, YIELD_ZERO_BAND: YIELD_ZERO_BAND, yieldBandIdx: yieldBandIdx,\n    precipColor: precipColor, decodeRing: decodeRing, project: project,\n    regionCropWeight: regionCropWeight, labelWidth: labelWidth, visibleLabels: visibleLabels,\n    LABEL_H: LABEL_H, LABEL_HALO: LABEL_HALO, LABEL_W: LABEL_W, LABEL_MOBILE_SCALE: LABEL_MOBILE_SCALE,\n    STALE_DAYS: STALE_DAYS, outlookAgeDays: outlookAgeDays,\n    strengthFactor: strengthFactor, outlookAnomaly: outlookAnomaly, activeAnomaly: activeAnomaly, OUTLOOK_GRACE_DAYS: OUTLOOK_GRACE_DAYS, outlookStale: outlookStale,\n    SEASONS: SEASONS, seasonRangeLabel: seasonRangeLabel };\n})();\nif(typeof module !== 'undefined'){ module.exports = ENI_CORE; }\n  \/* ENI-CORE END *\/\n  if(typeof ENI_CORE === 'undefined'){ return; }\n  var C = ENI_CORE;\n  var AMP = String.fromCharCode(38), MIDDOT = '\u00b7';\n  function esc(s){\n    return String(s).split(AMP).join(AMP + 'amp;').split('<').join(AMP + 'lt;').split('>').join(AMP + 'gt;').split('\"').join(AMP + 'quot;');\n  }\n  \/* data-tip values are parsed as HTML by the tooltip (showTip sets innerHTML)\n     AND are themselves the value of the data-tip=\"...\" HTML attribute in the\n     markup a renderer emits: an interpolated value needs escaping twice, once\n     for the tooltip's own HTML and once so it survives living inside an\n     attribute. Renderers building data-tip content call this instead of esc()\n     (see the tool rules). *\/\n  function escTip(s){ return esc(esc(s)); }\n  function sign(n){ return (n > 0 ? '+' : '') + n; }\n  function track(name, params){\n    try{\n      window.dataLayer = window.dataLayer || [];\n      var o = { event: name }, k;\n      for(k in params){ if(Object.prototype.hasOwnProperty.call(params, k)){ o[k] = params[k]; } }\n      window.dataLayer.push(o);\n    }catch(err){}\n  }\n  var REG = {}, REGION_IDS = []; (function(){ var i; for(i = 0; i < D.regions.length; i++){ REG[D.regions[i].id] = D.regions[i]; REGION_IDS.push(D.regions[i].id); } })();\n  \/* \u2500\u2500 state \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 *\/\n  var DEF = { region: D.regions[0].id, phase: D.state.phase, strength: D.state.strength, view: 'outlook' };\n  var S = { region: DEF.region, phase: DEF.phase, strength: DEF.strength, view: DEF.view };\n  \/* the URL contract itself (parseState\/buildQuery) lives in the core so it is\n     pure and testable without a browser (rule: validate against arrays, never\n     object keys -- REG['__proto__'] \/ C.STRENGTH['constructor'] are truthy and\n     must never authorise a state change). *\/\n  function readUrl(){\n    var got = C.parseState(window.location.search, DEF, REGION_IDS);\n    S.region = got.region; S.phase = got.phase; S.strength = got.strength; S.view = got.view;\n  }\n  function writeUrl(){\n    try{\n      if(!window.history.replaceState){ return; }\n      var qs = C.buildQuery(S, DEF, window.location.search);\n      \/* the hash (an anchor link landing) must survive a state write too *\/\n      window.history.replaceState(null, '', window.location.pathname + (qs ? '?' + qs : '') + (window.location.hash || ''));\n    }catch(err){}\n  }\n  \/* the row in force for a region at a phase: the outlook in the live phase\n     unless the reader asked for the typical view, else the composite. Every\n     renderer below goes through here (one decision point, activeAnomaly in\n     the core). *\/\n  function anomFor(id, phase){\n    return C.activeAnomaly(D.anomaly[id], D.outlook ? (D.outlook[id] || null) : null, phase, D.state.phase, S.view);\n  }\n  \/* \u2500\u2500 one floating tooltip for every element carrying data-tip (rule 17) \u2500\u2500 *\/\n  var TIP = document.createElement('div');\n  TIP.className = 'eni-tip'; TIP.setAttribute('role', 'tooltip');\n  ROOT.appendChild(TIP);\n  var TIP_TIMER = null;\n  function showTip(html, x, y){\n    if(TIP_TIMER){ clearTimeout(TIP_TIMER); TIP_TIMER = null; }\n    TIP.innerHTML = html;\n    TIP.classList.add('is-on');\n    var r = TIP.getBoundingClientRect();\n    var left = x - r.width \/ 2, top = y - r.height - 12;\n    if(left < 8){ left = 8; }\n    if(left + r.width > window.innerWidth - 8){ left = window.innerWidth - 8 - r.width; }\n    if(top < 8){ top = y + 18; }\n    TIP.style.left = left + 'px'; TIP.style.top = top + 'px';\n  }\n  function hideTip(){ TIP.classList.remove('is-on'); }\n  \/* is-hover\/is-focus for the region map's edge pass (path.rg-edge, the\n     stroke-only path the two-pass CSS above draws below path.rg) are\n     mirrored here, from the SAME mouseover\/mouseout\/focusin\/focusout that\n     already run for every [data-tip] element's tooltip -- path.rg-edge has\n     pointer-events:none so it can never receive these events itself, and\n     styling it directly is what keeps a hovered\/focused region's highlight\n     from re-exposing its own internal admin borders (a highlight stroke on\n     path.rg, the TOP layer, would sit over everything the fill pass is\n     supposed to cover). Scoped to t.classList.contains('rg') so hovering an\n     unrelated [data-tip] element (a heatmap cell, say) never touches the map. *\/\n  function regionEdgeState(t, cls, on){\n    if(!t.classList.contains('rg')){ return; }\n    var line = RGLINE[t.getAttribute('data-region')];\n    if(line){ line.classList.toggle(cls, on); }\n  }\n  ROOT.addEventListener('mouseover', function(ev){\n    var t = ev.target.closest ? ev.target.closest('[data-tip]') : null;\n    if(!t){ return; }\n    var r = t.getBoundingClientRect();\n    showTip(t.getAttribute('data-tip'), r.left + r.width \/ 2, r.top);\n    regionEdgeState(t, 'is-hover', true);\n  });\n  ROOT.addEventListener('mouseout', function(ev){\n    var t = ev.target.closest ? ev.target.closest('[data-tip]') : null;\n    if(!t){ return; }\n    \/* moving between children of the SAME [data-tip] element must not flicker *\/\n    var to = ev.relatedTarget ? (ev.relatedTarget.closest ? ev.relatedTarget.closest('[data-tip]') : null) : null;\n    if(to === t){ return; }\n    hideTip();\n    regionEdgeState(t, 'is-hover', false);\n  });\n  \/* touch: tap shows, tap elsewhere hides *\/\n  ROOT.addEventListener('touchstart', function(ev){\n    var t = ev.target.closest ? ev.target.closest('[data-tip]') : null;\n    if(!t){ hideTip(); return; }\n    var r = t.getBoundingClientRect();\n    showTip(t.getAttribute('data-tip'), r.left + r.width \/ 2, r.top);\n    TIP_TIMER = setTimeout(hideTip, 2600);\n  }, { passive: true });\n  \/* keyboard: focusin\/focusout bubble (unlike focus\/blur), so the same\n     delegation covers every [data-tip] element -- every region path now and\n     whatever Tasks 7-9 add later. *\/\n  ROOT.addEventListener('focusin', function(ev){\n    var t = ev.target.closest ? ev.target.closest('[data-tip]') : null;\n    if(!t){ return; }\n    var r = t.getBoundingClientRect();\n    showTip(t.getAttribute('data-tip'), r.left + r.width \/ 2, r.top);\n    \/* :focus-visible (not a bare check that it is focused) so a click -- which\n       also focuses a tabindex=0 path -- does not show the keyboard focus ring;\n       matches what path.rg:focus-visible used to gate before this state moved\n       to path.rg-edge. *\/\n    regionEdgeState(t, 'is-focus', t.matches ? t.matches(':focus-visible') : true);\n  });\n  ROOT.addEventListener('focusout', function(ev){\n    var t = ev.target.closest ? ev.target.closest('[data-tip]') : null;\n    if(!t){ return; }\n    hideTip();\n    regionEdgeState(t, 'is-focus', false);\n  });\n  \/* \u2500\u2500 status card \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 *\/\n  var STATE_EL = document.getElementById('eni-state');\n  \/* Staleness line (phase 2, task 5): the outlook is refreshed on a\n     schedule (.github\/workflows\/enso-state.yml, see the tool rules), but that\n     job can stop running (turned off, a CI outage) without anything else\n     noticing, so this stays as the backstop. outlookAgeDays\/STALE_DAYS live\n     in the core (pure, no network call, no real-clock dependency in the\n     test) so the page and tests.js share one threshold. Under the\n     threshold the card is unchanged; at or past it, one extra line names\n     the issue date, the age, and links the same source already in the\n     blob. Styled as a plain note in the dim colour -- information, not an\n     alarm -- so it never competes with the outlook headline itself.\n     Forecast vs measured (2026-09-25, fixing a product regression): `Now`\n     reads `st.strength`, which prefers the agency's own forecast word from the\n     synopsis over the measured value (see fetch-enso-state.js's\n     forecastStrengthFromSynopsis) -- a planner setting up the coming\n     season needs to see what the event is expected to BECOME, not what the\n     ocean measured on its way there. The measurement is never hidden,\n     though: `eni-state-obs`, directly under the Now badge, always names it\n     regardless of which source decided `strength` -- one short dim line,\n     no alarm styling, so the two different facts (forecast tier, measured\n     ocean warmth) both reach the reader instead of only the one that won.\n     TWO measured values, not one (2026-09-26). the agency moved official ENSO\n     classification onto a different index on 1 February 2026 and kept\n     publishing the old one, so the same three months now carry two\n     different numbers: 1.36 and 1.80 for Jun to Aug 2026. Showing only one\n     of them would leave a reader unable to tell which, and a reader whose\n     own data feed still reads the old file unable to see the drift at all,\n     so the line carries both plus the season they share. The copy names\n     neither index: `roni` and `oni` are how the fields are spelled, not\n     how a farmer or an underwriter reads. Season formatting lives in the\n     core (C.seasonRangeLabel) because the agency dates a season by its middle\n     month, which moves the year on two seasons in twelve. *\/\n  \/* the monsoon and seasonal outlook rows: region, label and update date,\n     plus one staleness line per overdue issue (OUTLOOK_GRACE_DAYS past\n     nextIssue). No agency is named anywhere on the page. *\/\n  function outlookRows(){\n    var ids = [], id, i, row, h = '', stale = '';\n    if(!D.outlook){ return ''; }\n    for(id in D.outlook){ if(Object.prototype.hasOwnProperty.call(D.outlook, id)){ ids.push(id); } }\n    if(!ids.length){ return ''; }\n    for(i = 0; i < ids.length; i++){\n      row = D.outlook[ids[i]];\n      h += '<span class=\"eni-state-ol\">' + esc(REG[ids[i]] ? REG[ids[i]].short : ids[i]) + ': ' + esc(row.label.toLowerCase()) + ' updated ' + esc(row.issued) + '<\/span>';\n      if(C.outlookStale(row, new Date())){\n        stale += '<div class=\"eni-state-stale\">The next ' + esc(row.label.toLowerCase()) + ' for ' + esc(REG[ids[i]] ? REG[ids[i]].short : ids[i]) + ' was due ' + esc(row.nextIssue) + '; this page still shows the ' + esc(row.issued) + ' issue.<\/div>';\n      }\n    }\n    return '<div class=\"eni-state-row\"><span class=\"eni-state-k\">Monsoon and seasonal outlooks<\/span><br>' + h + '<\/div>' + stale;\n  }\n  function renderState(){\n    var st = D.state;\n    var age = C.outlookAgeDays(st.issued, new Date());\n    var stale = age >= C.STALE_DAYS\n      ? '<div class=\"eni-state-stale\">This outlook has not been refreshed since ' + esc(st.issued) + ' (' + age + ' days ago).<\/div>'\n      : '';\n    var obs = '', obsSeason = C.seasonRangeLabel(st.indexAsOf);\n    var obsOk = typeof st.roni === 'number' ? (typeof st.oni === 'number' ? !!obsSeason : false) : false;\n    if(obsOk){\n      obs = '<div class=\"eni-state-obs\">Pacific ocean warmth, ' + esc(obsSeason) + ': '\n        + esc(sign(st.roni.toFixed(2))) + '\u00b0C on the index events are classified on today, '\n        + esc(sign(st.oni.toFixed(2))) + '\u00b0C on the one it used before February 2026. '\n        + 'The current index measures the event against the warmth of the wider tropical ocean, which is why the two differ.<\/div>';\n    }\n    STATE_EL.innerHTML =\n      '<div><span class=\"eni-state-k\">Now<\/span><br><b class=\"eni-state-v\">' + esc(C.PHASE_LABEL[st.phase]) + ' ' + MIDDOT + ' ' + esc(C.STRENGTH_LABEL[st.strength]) + '<\/b><\/div>'\n      + '<div><span class=\"eni-state-k\">Outlook<\/span><br><span class=\"eni-state-v\">' + esc(st.headline) + '<\/span><\/div>'\n      + '<div class=\"eni-state-src\">Prediction updated ' + esc(st.issued) + '<\/div>'\n      + obs\n      + stale\n      + outlookRows();\n  }\n  \/* \u2500\u2500 controls \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 *\/\n  var CTL_EL = document.getElementById('eni-controls');\n  function chips(kind, list, labels, activeId){\n    var h = '', i, id;\n    for(i = 0; i < list.length; i++){\n      id = list[i];\n      h += '<button class=\"eni-chip\" type=\"button\" data-' + kind + '=\"' + id + '\" aria-pressed=\"' + (id === activeId ? 'true' : 'false') + '\">' + esc(labels[id]) + '<\/button>';\n    }\n    return h;\n  }\n  \/* built once: rebuilding on every update() would destroy the button the\n     user just pressed (focus falls to body, the new aria-pressed is never\n     announced) and, in Firefox, destroy the select mid arrow-key interaction.\n     Same split as tools\/global-crop-calendar\/source.html. *\/\n  function initControls(){\n    var opts = '', i, r;\n    for(i = 0; i < D.regions.length; i++){\n      r = D.regions[i];\n      opts += '<option value=\"' + r.id + '\"' + (r.id === S.region ? ' selected' : '') + '>' + esc(r.label) + '<\/option>';\n    }\n    CTL_EL.innerHTML =\n      '<div class=\"eni-ctl\"><span class=\"eni-ctl-lab\" id=\"eni-lab-phase\">Phase<\/span><div class=\"eni-chips\" role=\"group\" aria-labelledby=\"eni-lab-phase\" id=\"eni-phase\">'\n      + chips('phase', C.PHASES, C.PHASE_LABEL, S.phase) + '<\/div><\/div>'\n      + '<div class=\"eni-ctl\"><span class=\"eni-ctl-lab\" id=\"eni-lab-strength\">Strength<\/span><div class=\"eni-chips\" role=\"group\" aria-labelledby=\"eni-lab-strength\" id=\"eni-strength\">'\n      + chips('strength', C.STRENGTH_IDS, C.STRENGTH_LABEL, S.strength) + '<\/div><\/div>'\n      + '<div class=\"eni-ctl\"><label class=\"eni-ctl-lab\" for=\"eni-region\">Region<\/label>'\n      + '<select class=\"eni-select\" id=\"eni-region\">' + opts + '<\/select><\/div>';\n  }\n  function setPressed(sel, attr, val){\n    var els = CTL_EL.querySelectorAll(sel), i;\n    for(i = 0; i < els.length; i++){ els[i].setAttribute('aria-pressed', els[i].getAttribute(attr) === val ? 'true' : 'false'); }\n  }\n  function syncControls(){\n    setPressed('button[data-phase]', 'data-phase', S.phase);\n    setPressed('button[data-strength]', 'data-strength', S.strength);\n    var sel = document.getElementById('eni-region');\n    if(sel){ sel.value = S.region; }\n  }\n  CTL_EL.addEventListener('click', function(ev){\n    var b = ev.target.closest ? ev.target.closest('button.eni-chip') : null;\n    if(!b){ return; }\n    if(b.getAttribute('data-phase')){ S.phase = b.getAttribute('data-phase'); track('eni_phase_change', { phase: S.phase }); }\n    else if(b.getAttribute('data-strength')){ S.strength = b.getAttribute('data-strength'); track('eni_strength_change', { strength: S.strength }); }\n    else { return; }\n    update();\n  });\n  CTL_EL.addEventListener('change', function(ev){\n    if(ev.target.id !== 'eni-region'){ return; }\n    if(REG[ev.target.value]){ S.region = ev.target.value; track('eni_region_select', { region: S.region }); update(); }\n  });\n  \/* \u2500\u2500 the current computation, shared by every panel \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 *\/\n  function current(){\n    var r = REG[S.region], a = anomFor(S.region, S.phase);\n    var ov = a.outlook ? null : (D.overrides[S.region] ? (D.overrides[S.region][S.phase] || null) : null);\n    var res = C.demandIndex(r, a, S.strength, ov);\n    return { region: r, anom: a, res: res, play: C.playbook(res, r, a, S.phase) };\n  }\n  var RENDERERS = [];   \/* later tasks push function(cur){} here *\/\n  var BUSY = false;\n  function update(){\n    if(BUSY){ return; }\n    BUSY = true;\n    try {\n      hideTip(); \/* a stale readout from before this state change must not survive it *\/\n      ROOT.setAttribute('data-phase', S.phase);\n      syncControls();\n      var cur = current(), i;\n      for(i = 0; i < RENDERERS.length; i++){\n        try { RENDERERS[i](cur); } catch(err){ if(window.console){ window.console.warn('[ENI] renderer failed', err); } }\n      }\n    } finally { BUSY = false; writeUrl(); }\n  }\n  \/* \u2500\u2500 map: grey country basemap + one filled path per region \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n     Same equal-area projection, ring decoder and frame technique as the\n     Global Crop Calendar (tools\/global-crop-calendar\/source.html), reusing\n     its geometry blob byte for byte. *\/\n  var MAP = document.getElementById('eni-map'), LEGEND = document.getElementById('eni-legend');\n  var LAT0 = -58, LAT1 = 85, RG = {}, RGLINE = {}, LBL = {};\n  function projPath(pts, close, note){\n    var d = 'M', n, p;\n    for(n = 0; n < pts.length; n++){\n      p = C.project(pts[n][0], pts[n][1]);\n      if(note){ note(p); }\n      d += (n ? 'L' : '') + p[0].toFixed(2) + ' ' + p[1].toFixed(2);\n    }\n    return close ? d + 'Z' : d;\n  }\n  function buildMap(){\n    if(!MAP || !LEGEND){ return; }\n    var minX = 1e9, maxX = -1e9, minY = 1e9, maxY = -1e9, i, j, lon, lat;\n    function note(p){\n      if(p[0] < minX){ minX = p[0]; } if(p[0] > maxX){ maxX = p[0]; }\n      if(p[1] < minY){ minY = p[1]; } if(p[1] > maxY){ maxY = p[1]; }\n    }\n    \/* frame: the projected outline of the mapped latitude band bounds every\n       country and region point inside it, so noting only the frame gives the\n       correct viewBox without walking the whole geometry a second time. *\/\n    var frame = [];\n    for(lon = -180; lon <= 180; lon += 3){ frame.push([lon, LAT0]); }\n    for(lat = LAT0; lat <= LAT1; lat += 3){ frame.push([180, lat]); }\n    for(lon = 180; lon >= -180; lon -= 3){ frame.push([lon, LAT1]); }\n    for(lat = LAT1; lat >= LAT0; lat -= 3){ frame.push([-180, lat]); }\n    \/* no-signal fill pattern (phase 2, task 3): a diagonal hatch, defined once,\n       referenced by every no-signal region's path.rg as fill (and, for the\n       hairline-gap fix, stroke) via url(#eni-nosig-fill) -- distinct from the\n       rainfall-ramp colours and from the low-confidence dashed-outline style,\n       so \"no reliable signal\" cannot be mistaken for \"a real reading, just\n       less sure of it\". Tokens only (--land0, --dim2), no new colour (rule 24). *\/\n    var svg = '<defs><pattern id=\"eni-nosig-fill\" width=\"6\" height=\"6\" patternUnits=\"userSpaceOnUse\" patternTransform=\"rotate(45)\"><rect width=\"6\" height=\"6\" fill=\"var(--land0)\"\/><line x1=\"0\" y1=\"0\" x2=\"0\" y2=\"6\" stroke=\"var(--dim2)\" stroke-width=\"1.6\"\/><\/pattern><\/defs>';\n    svg += '<path class=\"sea\" d=\"' + projPath(frame, true, note) + '\"\/>';\n    for(lon = -150; lon <= 150; lon += 30){\n      var mer = []; for(lat = LAT0; lat <= LAT1; lat += 3){ mer.push([lon, lat]); }\n      svg += '<path class=\"grat\" d=\"' + projPath(mer, false) + '\"\/>';\n    }\n    for(lat = -30; lat <= 60; lat += 30){\n      var par = []; for(lon = -180; lon <= 180; lon += 3){ par.push([lon, lat]); }\n      svg += '<path class=\"grat\" d=\"' + projPath(par, false) + '\"\/>';\n    }\n    if(G){\n      for(i = 0; i < G.c.length; i++){\n        var c = G.c[i], d = '';\n        for(j = 0; j < c.r.length; j++){ d += projPath(C.decodeRing(c.r[j], G.q), true); }\n        svg += '<path class=\"c\" d=\"' + d + '\" data-name=\"' + esc(c.n) + '\"\/>';\n      }\n    }\n    var labels = '';\n    for(i = 0; i < D.regions.length; i++){\n      var r = D.regions[i], lp = C.project(r.coord[0], r.coord[1]);\n      \/* a region's fill is one or more real-boundary rings (phase 2, task 1),\n         decoded from G.g[r.id] the same way a country's rings are decoded from\n         c.r above -- a region can now be several disjoint administrative units\n         (e.g. five Australian states), each its own subpath in one <path>.\n         Two-pass draw over the SAME ring data (rd), not a polygon union: the\n         edge pass (below, stroke only, pointer-events:none) draws every unit's\n         own border; the fill pass (above, same rd, no stroke) covers the inner\n         half of every INTERNAL border the edge pass drew, leaving only the\n         region's true outer perimeter visibly haloed -- so a 24-state Brazil\n         or a 7-country Sahel reads as one area. The fill pass stays the sole\n         interactive element (hit test, tooltip, keyboard); is-hover\/is-focus\n         are mirrored onto the edge pass from it (see the mouseover\/focusin\n         handlers below), is-sel\/low from paintMap. *\/\n      var rd = '', rrings = G ? (G.g ? (G.g[r.id] || []) : []) : [];\n      for(j = 0; j < rrings.length; j++){ rd += projPath(C.decodeRing(rrings[j], G.q), true); }\n      svg += '<path class=\"rg-edge\" data-region=\"' + r.id + '\" d=\"' + rd + '\" pointer-events=\"none\"\/>';\n      svg += '<path class=\"rg\" id=\"eni-rg-' + r.id + '\" data-region=\"' + r.id + '\" d=\"' + rd + '\" tabindex=\"0\" role=\"button\" aria-pressed=\"false\" aria-label=\"' + esc(r.label) + '\"\/>';\n      \/* data-region so paintMap can look each label up by id and toggle its\n         display (phase 2, task 4) -- text.lb stays pointer-events:none as it\n         always has been, so hiding one changes nothing about reachability;\n         the region's own path.rg still carries every hover\/focus\/click\/\n         tooltip behaviour regardless of whether its label is drawn. *\/\n      labels += '<text class=\"lb\" data-region=\"' + r.id + '\" x=\"' + lp[0].toFixed(1) + '\" y=\"' + lp[1].toFixed(1) + '\" text-anchor=\"middle\">' + esc(r.short) + '<\/text>';\n    }\n    svg += labels;\n    var pad = (maxX - minX) * 0.012;\n    MAP.setAttribute('viewBox', (minX - pad).toFixed(1) + ' ' + (minY - pad).toFixed(1) + ' ' + (maxX - minX + pad * 2).toFixed(1) + ' ' + (maxY - minY + pad * 2).toFixed(1));\n    MAP.innerHTML = svg;\n    var all = MAP.querySelectorAll('path.rg'), k;\n    for(k = 0; k < all.length; k++){ RG[all[k].getAttribute('data-region')] = all[k]; }\n    var allEdge = MAP.querySelectorAll('path.rg-edge');\n    for(k = 0; k < allEdge.length; k++){ RGLINE[allEdge[k].getAttribute('data-region')] = allEdge[k]; }\n    var allLbl = MAP.querySelectorAll('text.lb');\n    for(k = 0; k < allLbl.length; k++){ LBL[allLbl[k].getAttribute('data-region')] = allLbl[k]; }\n    var lg = '';\n    for(i = 0; i < C.RAMP.length; i++){\n      lg += '<span><i style=\"background:' + C.RAMP[i][1] + '\"><\/i>' + esc(C.RAMP[i][2]) + '<\/span>';\n    }\n    lg += '<span><i class=\"low\"><\/i>low confidence<\/span>';\n    lg += '<span><i class=\"nosig\"><\/i>no reliable signal<\/span>';\n    LEGEND.innerHTML = '<span>Typical rainfall anomaly:<\/span>' + lg + '<span><i class=\"fc\"><\/i>outlined: outlook for this season<\/span>';\n  }\n  \/* regionTip's result is delivered via el.setAttribute('data-tip', ...) below,\n     which stores the string verbatim -- no HTML parsing happens at that call.\n     showTip's TIP.innerHTML = the attribute's exact value is therefore the\n     ONLY decode this string goes through, so it needs exactly one escape\n     (esc()), not two. escTip() is for the OTHER delivery path: a value\n     concatenated into an HTML STRING that is itself assigned via innerHTML\n     (that string's own parse is decode #1, showTip's read-back is decode #2)\n     -- see the data-tip paragraph in the tool rules. *\/\n  function regionTip(id){\n    var r = REG[id], a = anomFor(id, S.phase), f = C.strengthFactor(a, S.strength);\n    var basis = a.outlook ? a.outlook.label : C.PHASE_LABEL[S.phase] + ', ' + C.STRENGTH_LABEL[S.strength].toLowerCase();\n    if(a.signal === 'none'){\n      return '<b>' + esc(r.label) + '<\/b>'\n        + '<span>' + esc(basis) + '<\/span>'\n        + '<span>no reliable ENSO signal ' + MIDDOT + ' ' + esc(C.fmtRange(a.months)) + '<\/span>';\n    }\n    var pp = Math.round(a.precipPct * f), tt = (a.tempC * f).toFixed(1);\n    return '<b>' + esc(r.label) + '<\/b>'\n      + '<span>' + esc(basis) + '<\/span>'\n      + '<span>rain ' + sign(pp) + '% ' + MIDDOT + ' ' + sign(tt) + '\u00b0C ' + MIDDOT + ' ' + esc(C.fmtRange(a.months)) + '<\/span>'\n      + '<span>confidence ' + esc(a.confidence) + '<\/span>';\n  }\n  function paintMap(){\n    \/* the fill only needs the scaled rain percentage, not a full demand-index\n       run (stress weights, categories, overrides) -- C.demandIndex(...).\n       precipPct is exactly anom.precipPct * f, so read that directly instead\n       of computing all fourteen regions' full model on every update(). *\/\n    var i, r, a, el, line, noSig, f = 1;\n    for(i = 0; i < D.regions.length; i++){\n      r = D.regions[i]; el = RG[r.id]; line = RGLINE[r.id]; if(!el){ continue; }\n      a = anomFor(r.id, S.phase); f = C.strengthFactor(a, S.strength);\n      \/* signal:'none' (phase 2, task 3): a hatch fill + solid dim outline, not\n         the rainfall-ramp colour -- see the <defs> pattern in buildMap and\n         the .nosig CSS above. Never true at the neutral phase (every region's\n         neutral row reads the shared land colour, no anomaly to distinguish). *\/\n      noSig = S.phase !== 'neutral' ? a.signal === 'none' : false;\n      el.style.fill = S.phase === 'neutral' ? 'var(--land0)' : (noSig ? 'url(#eni-nosig-fill)' : C.precipColor(a.precipPct * f));\n      \/* hairline stroke in the fill's own colour closes the sub-pixel gaps a\n         multi-unit region's independently-simplified admin borders can leave\n         (Brazil South, Australia) -- see the CSS comment on path.rg above.\n         Reading el.style.fill back (rather than recomputing) means this stays\n         correct for every branch above, url(#eni-nosig-fill) included: an SVG\n         stroke can reference a pattern paint server exactly like a fill can. *\/\n      el.style.stroke = el.style.fill;\n      el.setAttribute('class', 'rg' + (noSig ? ' nosig' : (a.confidence === 'low' ? ' low' : '')));\n      el.setAttribute('aria-pressed', r.id === S.region ? 'true' : 'false');\n      el.setAttribute('data-tip', regionTip(r.id));\n      \/* is-sel\/low\/nosig live on the edge pass now (that's what carries the\n         outline -- see the CSS above); is-hover\/is-focus are transient DOM\n         state the mouseover\/focusin handlers below toggle on the SAME\n         element, so they are read back rather than overwritten here. *\/\n      if(line){\n        line.setAttribute('class', 'rg-edge' + (a.outlook ? ' fc' : '') + (noSig ? ' nosig' : (a.confidence === 'low' ? ' low' : '')) + (r.id === S.region ? ' is-sel' : '')\n          + (line.classList.contains('is-hover') ? ' is-hover' : '') + (line.classList.contains('is-focus') ? ' is-focus' : ''));\n      }\n    }\n    applyLabelVisibility();\n  }\n  \/* label visibility (phase 2, task 4): C.visibleLabels picks the set that\n     does not collide, in priority order (the selected region first, so it\n     is always shown; then every region by descending crop production\n     weight) -- see its long comment in data\/enso-core.js for why the\n     priority order reads nothing from phase or strength. Recomputed on\n     every paintMap() call (every update(), so selecting a previously-hidden\n     region reveals its label immediately) AND on resize\/orientation change,\n     the only other event that can cross the max-width:820px label-size\n     breakpoint (9px desktop -> 13px mobile, C.LABEL_MOBILE_SCALE) without an\n     update() already running to recompute it. A hidden label is simply not\n     drawn (display:none) -- text.lb is pointer-events:none and always has\n     been, so a region's map shape (path.rg) still carries every hover\/\n     focus\/click\/tooltip behaviour regardless of whether its label shows;\n     the Region dropdown lists every region either way. *\/\n  var mobileMQ = window.matchMedia ? window.matchMedia('(max-width:820px)') : null;\n  function applyLabelVisibility(){\n    var scale = mobileMQ ? (mobileMQ.matches ? C.LABEL_MOBILE_SCALE : 1) : 1;\n    var vis = C.visibleLabels(D.regions, S.region, scale), i, r, el;\n    for(i = 0; i < D.regions.length; i++){\n      r = D.regions[i]; el = LBL[r.id]; if(!el){ continue; }\n      el.style.display = vis[r.id] ? '' : 'none';\n    }\n  }\n  var labelResizeTimer = null;\n  window.addEventListener('resize', function(){\n    if(labelResizeTimer){ clearTimeout(labelResizeTimer); }\n    labelResizeTimer = setTimeout(applyLabelVisibility, 120);\n  });\n  if(MAP){\n    MAP.addEventListener('click', function(ev){\n      var t = ev.target.closest ? ev.target.closest('path.rg') : null;\n      if(!t){ return; }\n      S.region = t.getAttribute('data-region'); track('eni_region_select', { region: S.region, via: 'map' }); update();\n    });\n    MAP.addEventListener('keydown', function(ev){\n      var t = ev.target.closest ? ev.target.closest('path.rg') : null;\n      if(!t){ return; }\n      if(ev.key === 'Enter' || ev.key === ' '){\n        ev.preventDefault(); S.region = t.getAttribute('data-region'); track('eni_region_select', { region: S.region, via: 'map-key' }); update();\n      }\n    });\n  }\n  buildMap();\n  RENDERERS.push(paintMap);\n  \/* \u2500\u2500 region panel: tiles, mechanism + sources, crops under stress, demand\n     bars \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n     Every data-tip below is concatenated into an HTML string that is itself\n     assigned via PANEL.innerHTML = h: the browser's own parse of that markup\n     is decode #1, showTip's later innerHTML read is decode #2, so each value\n     needs escTip() (double escape), never esc() (see the data-tip paragraph\n     in the tool rules; this is the OTHER delivery path from\n     paintMap's regionTip, which uses setAttribute and needs esc() only). *\/\n  var PANEL = document.getElementById('eni-panel'), PANEL_H = document.getElementById('eni-panel-h');\n  function yieldClass(y){ return y.charAt(0) === '-' ? 'neg' : (y.charAt(0) === '+' ? 'pos' : ''); }\n  \/* bare punctuation (\"--\", \"+\") is often skipped or misread by a screen\n     reader; the visible glyph stays (sighted users scan it fast), but a\n     hidden word carries the same legend the tooltip already states in\n     words -- see the tooltip text right below. *\/\n  var YIELD_WORD = { '--': 'strong loss', '-': 'loss', '0': 'neutral', '+': 'gain', '++': 'strong gain' };\n  function renderPanel(cur){\n    var r = cur.region, a = cur.anom, res = cur.res, i, h;\n    \/* clear the body BEFORE the heading changes: if anything below throws,\n       update()'s catch leaves this render half-done, and an EMPTY panel\n       under the new heading is an honest \"something broke\" signal -- the\n       previous region's numbers left standing under the new heading would\n       read as still-correct when they are not (Task 9 review). *\/\n    PANEL.innerHTML = '';\n    PANEL_H.textContent = r.label;\n    \/* no reliable ENSO signal (phase 2, task 3): never at the neutral phase\n       (that row carries no signal flag -- the neutral baseline already means\n       \"no numbers\", for every region alike). *\/\n    var noSig = a.signal === 'none';\n    \/* tt stays the toFixed(1) STRING and is handed to sign() as-is: re-coercing\n       it back through Number before calling sign() round-trips it and drops a\n       trailing zero (\"+1.0\" -> \"+1\"), the same bug class renderRows() in\n       build-data.js and regionTip above both avoid. A no-signal region reads\n       \"No signal\" text on the Rain\/Temperature tiles instead of a \"+0%\" \/\n       \"+0.0\u00b0C\" figure that would misread as a confirmed zero change. *\/\n    var pp = Math.round(res.precipPct), tt = res.tempC.toFixed(1);\n    \/* outlook regions in the live phase: a chip pair above the tiles, the\n       outlook (default) or the typical pattern; off the live phase the pair\n       hides, because an outlook describes this season, not a scenario *\/\n    var olRow = D.outlook ? (D.outlook[r.id] || null) : null, live = olRow ? S.phase === D.state.phase : false;\n    var chipsH = '';\n    if(live){\n      chipsH = '<div class=\"eni-chips eni-view\" role=\"group\" aria-label=\"Season basis\">'\n        + '<button class=\"eni-chip\" type=\"button\" data-view=\"outlook\" aria-pressed=\"' + (S.view !== 'typical' ? 'true' : 'false') + '\">' + esc(olRow.label + ', ' + C.fmtRange(olRow.months)) + '<\/button>'\n        + '<button class=\"eni-chip\" type=\"button\" data-view=\"typical\" aria-pressed=\"' + (S.view === 'typical' ? 'true' : 'false') + '\">' + esc('Typical ' + C.PHASE_LABEL[S.phase]) + '<\/button><\/div>';\n    }\n    h = chipsH + '<div class=\"eni-tiles' + (a.outlook ? (a.outlook.observed ? ' five' : '') : '') + '\">'\n      + '<div class=\"eni-tile\" id=\"eni-tile-rain\" tabindex=\"0\" data-tip=\"' + escTip(noSig ? 'No reliable ENSO signal for rainfall in this region' : (a.outlook ? a.outlook.rain.wording : 'Typical rainfall anomaly against the seasonal normal, scaled by the strength you picked')) + '\"><span class=\"k\">Rain<\/span><span class=\"v ' + (noSig ? 'nosig' : (pp < 0 ? 'dry' : (pp > 0 ? 'wet' : ''))) + '\">' + (noSig ? 'No signal' : sign(pp) + '%') + '<\/span><\/div>'\n      + '<div class=\"eni-tile\" id=\"eni-tile-temp\" tabindex=\"0\" data-tip=\"' + escTip(noSig ? 'No reliable ENSO signal for temperature in this region' : (a.outlook ? a.outlook.temp.wording : 'Typical temperature anomaly over the season')) + '\"><span class=\"k\">Temperature<\/span><span class=\"v' + (noSig ? ' nosig' : '') + '\">' + (noSig ? 'No signal' : sign(tt) + '\u00b0C') + '<\/span><\/div>'\n      + '<div class=\"eni-tile\" id=\"eni-tile-months\" tabindex=\"0\" data-tip=\"' + escTip(noSig ? 'Months the growing season runs here; onset is not set by ENSO' : (a.outlook ? 'Months the outlook covers' : 'Months in which the anomaly is usually felt; onset ' + a.onset)) + '\"><span class=\"k\">Months<\/span><span class=\"v\">' + esc(C.fmtRange(a.months)) + '<\/span><\/div>'\n      + '<div class=\"eni-tile\" id=\"eni-tile-conf\" tabindex=\"0\" data-tip=\"' + escTip(noSig ? 'No reliable ENSO signal has been found for this region' : (a.outlook ? 'Confidence the outlook attaches to the category' : 'How consistently past events of this phase produced this anomaly here')) + '\"><span class=\"k\">Confidence<\/span><span class=\"v\"><span class=\"eni-badge ' + (noSig ? 'nosig' : esc(a.confidence)) + '\">' + (noSig ? 'no signal' : esc(a.confidence)) + '<\/span><\/span><\/div>'\n      + (a.outlook ? (a.outlook.observed ? '<div class=\"eni-tile\" id=\"eni-tile-last\" tabindex=\"0\" data-tip=\"' + escTip(a.outlook.observed.wording) + '\"><span class=\"k\">Last season<\/span><span class=\"v ' + (a.outlook.observed.pct < 0 ? 'dry' : 'wet') + '\">' + sign(a.outlook.observed.pct) + '%<\/span><small>' + esc(a.outlook.observed.label) + '<\/small><\/div>' : '') : '')\n      + '<\/div>';\n    h += '<p class=\"eni-mech\">' + esc(a.mechanism) + '<\/p>';\n    if(noSig){\n      \/* replaces the crops-under-stress + demand-bars sections entirely (the\n         same shape as the neutral-phase early return below): every one of\n         those sections would otherwise render an all-zero yield band or an\n         all-zero demand bar for this region, which is exactly the numeric\n         \"confirmed no change\" reading the no-signal state exists to avoid. *\/\n      h += '<p class=\"eni-mech\">For the long-term climate picture in this region, see the <a href=\"https:\/\/geopard.tech\/agroclimate-explorer\/\" target=\"_blank\" rel=\"noopener\">Agroclimate Explorer<\/a>.<\/p>';\n      PANEL.innerHTML = h; return;\n    }\n    if(S.phase === 'neutral'){\n      h += '<p class=\"eni-mech\">A baseline season: the calendar runs as usual and the demand shift is zero across categories.<\/p>';\n      PANEL.innerHTML = h; return;\n    }\n    \/* one entry per crop id (heaviest first); c.label is the crop-level name\n       (e.g. \"Rice\"), c.seasons every per-country season label that rolled up\n       into it -- render the crop-level label as the heading and the seasons\n       beneath it, never seasons[0] repeated as the heading. cropImpacts needs\n       the raw anomaly (months + onset) and the strength factor to compute\n       each crop's OWN wet_harvest\/late_planting share -- the region-level\n       stress object alone is not enough (rule: those two calendar stresses\n       are per crop for crop impact, not per region). *\/\n    var crops = C.cropImpacts(r, res.stress, a, C.strengthFactor(a, S.strength));\n    h += '<p class=\"eni-sub\">Crops under the season<\/p><ul class=\"eni-crops\">';\n    for(i = 0; i < crops.length; i++){\n      var c = crops[i];\n      h += '<li><b>' + esc(c.label) + '<\/b>'\n        + '<span class=\"yr ' + yieldClass(c.yield) + '\" tabindex=\"0\" data-tip=\"' + escTip('Typical yield direction under the active stresses: -- strong loss, - loss, 0 neutral, + gain') + '\"><span class=\"eni-sr\">' + esc(YIELD_WORD[c.yield] || c.yield) + '<\/span><span aria-hidden=\"true\">' + esc(c.yield) + '<\/span><\/span>'\n        + '<small>' + esc(c.seasons.join(', ')) + '<\/small>'\n        + (c.pests.length ? '<small>Pests: ' + esc(c.pests.join(', ')) + '<\/small>' : '')\n        + (c.diseases.length ? '<small>Diseases: ' + esc(c.diseases.join(', ')) + '<\/small>' : '')\n        + '<\/li>';\n    }\n    h += '<\/ul>';\n    h += '<p class=\"eni-sub\">Demand shift by category<\/p><div class=\"eni-bars\">';\n    for(i = 0; i < res.categories.length; i++){\n      var k = res.categories[i], w = Math.abs(k.index) \/ 3 * 50, left = k.index < 0 ? 50 - w : 50;\n      \/* aria-label on a bare <div> is not reliably exposed -- a <div> with\n         no ARIA role carries no accessible name a screen reader is\n         guaranteed to read, the same class of gap the map task's role=\"img\"\n         mistake fell into from the other direction. The full sentence goes\n         in a visually-hidden TEXT NODE instead (always exposed, no role\n         needed), and the visible label\/bar\/index are marked aria-hidden so\n         the sentence is read once, not once hidden then again visible. *\/\n      h += '<div class=\"eni-bar\" tabindex=\"0\" data-tip=\"' + escTip(k.label + ': ' + k.reason) + '\"><span class=\"eni-sr\">' + esc(k.label + ' ' + sign(k.index) + ': ' + k.reason) + '<\/span><span aria-hidden=\"true\">' + esc(k.label) + '<\/span>'\n        + '<div class=\"tr\" aria-hidden=\"true\"><div class=\"fl' + (k.index < 0 ? ' neg' : '') + '\" style=\"left:' + left.toFixed(1) + '%;width:' + w.toFixed(1) + '%\"><\/div><\/div>'\n        + '<span class=\"ix ' + (k.index < 0 ? 'neg' : (k.index > 0 ? 'pos' : '')) + '\" aria-hidden=\"true\">' + sign(k.index) + '<\/span><\/div>';\n    }\n    h += '<\/div>';\n    PANEL.innerHTML = h;\n  }\n  RENDERERS.push(renderPanel);\n  PANEL.addEventListener('click', function(ev){\n    var b = ev.target.closest ? ev.target.closest('button[data-view]') : null, nb;\n    if(!b){ return; }\n    S.view = b.getAttribute('data-view') === 'typical' ? 'typical' : 'outlook';\n    track('eni_view_change', { region: S.region, view: S.view });\n    update();\n    \/* update() rebuilt the panel: put focus back on the chip just pressed *\/\n    nb = PANEL.querySelector('button[data-view=\"' + S.view + '\"]'); if(nb){ nb.focus(); }\n  });\n  \/* \u2500\u2500 playbook \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 *\/\n  var PLAY = document.getElementById('eni-play'), PLAY_H = document.getElementById('eni-play-h');\n  var LAST_TEXT = '';\n  function col(kind, title, list){\n    var h = '<div class=\"eni-col ' + kind + '\"><h3>' + esc(title) + '<\/h3>', i, it;\n    if(!list.length){ return h + '<p class=\"none\">Nothing here this season.<\/p><\/div>'; }\n    h += '<ul>';\n    for(i = 0; i < list.length; i++){\n      it = list[i];\n      h += '<li><b>' + esc(it.label) + ' <span class=\"ix\">' + sign(it.index) + '<\/span><\/b><span>' + esc(it.reason) + '<\/span><small>' + esc(it.months) + '<\/small><\/li>';\n    }\n    return h + '<\/ul><\/div>';\n  }\n  function plainText(cur){\n    var p = cur.play, lines = [p.message, ''], i;\n    \/* region.watch guarded the same way the core's own playbook() guards the\n       same access (`region.watch ? region.watch.length : false`) -- this\n       function reads cur.region.watch.length unconditionally before that\n       fix, one place the core was already careful and the page was not. *\/\n    var watch = (cur.region.watch ? cur.region.watch.length : false) ? cur.region.watch : [];\n    function add(title, list){\n      lines.push(title + ':');\n      if(!list.length){ lines.push('  nothing this season'); }\n      for(i = 0; i < list.length; i++){ lines.push('  ' + sign(list[i].index) + ' ' + list[i].label + ': ' + list[i].reason + ' (' + list[i].months + ')'); }\n      lines.push('');\n    }\n    add('Push', p.push); add('Hold', p.hold); add('Pull back', p.pull);\n    lines.push('Watch:');\n    for(i = 0; i < watch.length; i++){ lines.push('  ' + watch[i].label + ', ' + watch[i].when); }\n    lines.push('', cur.anom.outlook\n      ? 'El Ni\u00f1o and Monsoon Impact Simulator, GeoPard. Basis: ' + cur.anom.outlook.label.toLowerCase() + ' updated ' + cur.anom.outlook.issued + ', ' + C.fmtRange(cur.anom.months) + '.'\n      : 'El Ni\u00f1o and Monsoon Impact Simulator, GeoPard. Typical anomalies for a ' + C.STRENGTH_LABEL[S.strength].toLowerCase() + ' ' + C.PHASE_LABEL[S.phase] + ' season, not a forecast.');\n    return lines.join('\\n');\n  }\n  function renderPlay(cur){\n    var r = cur.region, p = cur.play, i, h, w0;\n    \/* clear before the heading changes -- see the same note in renderPanel;\n       a throw here must show as an empty playbook, not the previous\n       region's push\/hold\/pull under the new region's heading. *\/\n    PLAY.innerHTML = '';\n    PLAY_H.textContent = 'Playbook: ' + r.short + ', ' + (cur.anom.outlook ? cur.anom.outlook.label.toLowerCase() + ' ' + C.fmtRange(cur.anom.months) : C.PHASE_LABEL[S.phase] + ' ' + C.STRENGTH_LABEL[S.strength].toLowerCase());\n    if(!p){\n      LAST_TEXT = '';\n      \/* r.watch[0] guarded the same way the core guards the identical access\n         in playbook()'s own message-building -- this branch read it\n         unconditionally before this fix. *\/\n      w0 = (r.watch ? r.watch.length : false) ? r.watch[0] : { label: 'the seasonal outlook', when: 'regularly' };\n      PLAY.innerHTML = '<div class=\"eni-neutral\">Neutral phase: a baseline season. Run the normal programme for ' + esc(r.label) + ' and watch ' + esc(w0.label) + ' (' + esc(w0.when) + ') for a change of phase.<\/div>';\n      return;\n    }\n    if(p.signal === 'none'){\n      \/* a DISTINCT shape from the neutral branch above (playbook() never\n         returns null for a no-signal row -- null already means \"neutral\n         phase\") and from the normal push\/hold\/pull shape below: a short note\n         plus the region's own watch items, reusing the neutral box's styling\n         since both are \"no plan to push here\" states, for different reasons. *\/\n      LAST_TEXT = p.message;\n      h = '<div class=\"eni-neutral\">' + esc(p.message) + '<\/div>';\n      if(r.watch ? r.watch.length : false){\n        h += '<div class=\"eni-watch\"><h3 class=\"eni-sub\">Watch<\/h3><ul>';\n        for(i = 0; i < r.watch.length; i++){ h += '<li>' + esc(r.watch[i].label) + ', ' + esc(r.watch[i].when) + '<\/li>'; }\n        h += '<\/ul><\/div>';\n      }\n      h += '<div class=\"eni-actions\"><button class=\"eni-btn2\" type=\"button\" id=\"eni-copy\">Copy playbook<\/button><button class=\"eni-btn2 ghost\" type=\"button\" id=\"eni-print\">Print one-pager<\/button><\/div>';\n      PLAY.innerHTML = h;\n      return;\n    }\n    h = '<div class=\"eni-play\">' + col('push', 'Push', p.push) + col('hold', 'Hold', p.hold) + col('pull', 'Pull back', p.pull) + '<\/div>';\n    h += '<div class=\"eni-msg\"><h3>Line for distributors<\/h3><p id=\"eni-msg-text\">' + esc(p.message) + '<\/p><\/div>';\n    h += '<div class=\"eni-watch\"><h3 class=\"eni-sub\">Watch<\/h3><ul>';\n    for(i = 0; i < r.watch.length; i++){ h += '<li>' + esc(r.watch[i].label) + ', ' + esc(r.watch[i].when) + '<\/li>'; }\n    h += '<\/ul><\/div>';\n    \/* LAST_TEXT is computed BEFORE the Copy button goes on screen (the\n       innerHTML write below), not after: this used to run\n       \"PLAY.innerHTML = h; LAST_TEXT = plainText(cur);\", so a throw inside\n       plainText() (it dereferences cur.region.watch.length, now guarded\n       above, but the ordering bug stands on its own) left a fully visible,\n       clickable Copy button wired to a STALE LAST_TEXT from whatever\n       rendered last -- clicking it would silently copy the wrong region's\n       playbook. Computing the text first means a throw here aborts before\n       the button (inside `h`) is ever placed on screen. *\/\n    LAST_TEXT = plainText(cur);\n    h += '<div class=\"eni-actions\"><button class=\"eni-btn2\" type=\"button\" id=\"eni-copy\">Copy playbook<\/button><button class=\"eni-btn2 ghost\" type=\"button\" id=\"eni-print\">Print one-pager<\/button><\/div>';\n    PLAY.innerHTML = h;\n  }\n  PLAY.addEventListener('click', function(ev){\n    var b = ev.target.closest ? ev.target.closest('button') : null;\n    if(!b){ return; }\n    if(b.id === 'eni-copy'){\n      track('eni_copy_playbook', { region: S.region, phase: S.phase, strength: S.strength });\n      \/* legacy fallback ALSO covers a Clipboard-API write that exists but is\n         refused (denied permission, insecure context): without a catch here\n         the button would silently never confirm the copy. *\/\n      function legacyCopy(){\n        var ta = document.createElement('textarea'); ta.value = LAST_TEXT; ROOT.appendChild(ta); ta.select();\n        try{ document.execCommand('copy'); }catch(err){}\n        ROOT.removeChild(ta); b.textContent = 'Copied'; setTimeout(function(){ b.textContent = 'Copy playbook'; }, 1800);\n      }\n      if(navigator.clipboard ? navigator.clipboard.writeText : false){\n        navigator.clipboard.writeText(LAST_TEXT).then(function(){ b.textContent = 'Copied'; setTimeout(function(){ b.textContent = 'Copy playbook'; }, 1800); }).catch(legacyCopy);\n      } else {\n        legacyCopy();\n      }\n    } else if(b.id === 'eni-print'){\n      track('eni_print_playbook', { region: S.region, phase: S.phase, strength: S.strength });\n      window.print();\n    }\n  });\n  RENDERERS.push(renderPlay);\n  \/* \u2500\u2500 portfolio heatmap: every region x every category, for a regional sales\n     director to scan and sort \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n     Headers are real <button>s inside their <th> (not a bare clickable <th>)\n     so a keyboard user tabs to one and activates it with Enter\/Space for\n     free, the same way any other button in this page works -- the map task's\n     role=\"img\" on the SVG container silently stripped 14 path buttons from\n     assistive tech, so this table gets native interactive elements rather\n     than an ARIA role bolted onto a non-interactive one. aria-sort lives on\n     the <th> itself (the ARIA-correct host for it), never the button inside.\n     Rows have no native interactive equivalent, so they get tabindex plus a\n     keydown handler mirroring the map's path.rg pattern (Enter\/Space\n     selects) while the tr keeps its native row role for a screen reader's\n     own table navigation. HEAT.innerHTML = h below is the innerHTML-string\n     delivery path (see the data-tip paragraph in the tool rules), so every\n     data-tip value here goes through escTip(), never esc() -- same rule\n     renderPanel and renderPlay already follow for their tooltips. *\/\n  var HEAT = document.getElementById('eni-heat'), HEAT_SUB = document.getElementById('eni-heat-sub');\n  var HEAT_LEDE = HEAT_SUB ? HEAT_SUB.textContent : '';\n  var SORT = { col: null, dir: -1 };\n  function cellClass(i){ return i === 0 ? 'z' : (i > 0 ? 'p' + i : 'n' + (-i)); }\n  function renderHeat(){\n    var rows = [], i, j, r, a, ov, res, focusCol = null, focusRegion = null, active = document.activeElement, fTh, fTr, restore;\n    \/* record what had keyboard focus BEFORE the rewrite: HEAT.innerHTML below\n       destroys every existing node (a sort click or a row click both call\n       this), so the browser drops focus to <body> and a keyboard user loses\n       their place across 22 tab stops (8 header buttons + 14 rows). Restored\n       at the end by re-finding the same data-col \/ data-region on the freshly\n       built table. *\/\n    if(HEAT.contains ? HEAT.contains(active) : false){\n      fTh = active.closest ? active.closest('th[data-col]') : null;\n      fTr = active.closest ? active.closest('tr[data-region]') : null;\n      if(fTh){ focusCol = fTh.getAttribute('data-col'); }\n      else if(fTr){ focusRegion = fTr.getAttribute('data-region'); }\n    }\n    \/* clear before building: a throw partway through (e.g. a bad region row)\n       used to leave the FULL PREVIOUS table sitting there with no heading of\n       its own to signal anything changed -- silently stale, not just wrong\n       (Task 9 review). Empty is an honest failure state; stale-and-right-\n       looking is not. *\/\n    HEAT.innerHTML = '';\n    \/* neutral is 112 identical grey cells (every category holds at zero,\n       see \"neutral gives all zeros\" in tests.js) under a lede telling the\n       user to sort a column -- sorting ties does nothing to see. The table\n       itself still stays visible (it IS the honest picture: nothing moves\n       in a baseline season), but the lede swaps to say that instead of\n       inviting an action that shows nothing. *\/\n    if(HEAT_SUB){ HEAT_SUB.textContent = S.phase === 'neutral' ? 'A neutral season: every category holds at zero across every region. Switch to El Ni\u00f1o or La Ni\u00f1a above to see where a product line moves.' : HEAT_LEDE; }\n    for(i = 0; i < D.regions.length; i++){\n      r = D.regions[i]; a = anomFor(r.id, S.phase);\n      ov = a.outlook ? null : (D.overrides[r.id] ? (D.overrides[r.id][S.phase] || null) : null);\n      res = C.demandIndex(r, a, S.strength, ov);\n      \/* nosig (phase 2, task 3) carries the flag through to the render loop\n         below, which renders ONE muted band across the row instead of eight\n         \"0\" cells -- cats stays populated (all index 0, from demandIndex's\n         own no-signal branch) so C.sortHeatRows below still has something to\n         sort against; the row just never RENDERS those numbers. *\/\n      rows.push({ r: r, cats: res.categories, nosig: a.signal === 'none', basis: a.outlook ? 'outlook' : null });\n    }\n    \/* the real sort lives in the core (C.sortHeatRows) so the exact function\n       that ships is the one tests.js exercises -- see enso-core.js. *\/\n    if(SORT.col){ rows = C.sortHeatRows(rows, SORT.col, SORT.dir); }\n    var h = '<table class=\"eni-heat\"><thead><tr><th scope=\"col\">Region<\/th>';\n    for(j = 0; j < C.CATEGORIES.length; j++){\n      var cId = C.CATEGORIES[j].id, cLab = C.CATEGORIES[j].label;\n      var srt = SORT.col === cId ? (SORT.dir < 0 ? 'descending' : 'ascending') : null;\n      h += '<th scope=\"col\" data-col=\"' + cId + '\"' + (srt ? ' aria-sort=\"' + srt + '\"' : '') + '><button type=\"button\" data-tip=\"' + escTip('Sort by ' + cLab.toLowerCase()) + '\">' + esc(cLab) + '<\/button><\/th>';\n    }\n    h += '<\/tr><\/thead><tbody>';\n    for(i = 0; i < rows.length; i++){\n      r = rows[i].r;\n      var sel = r.id === S.region;\n      \/* the region name is a ROW HEADER (scope=\"row\"), not a data cell -- it\n         labels the row the same way the column <th> labels the column, so a\n         screen reader's own table navigation announces it with every cell.\n         aria-current, not aria-selected: aria-selected is only guaranteed\n         exposed inside a grid\/listbox\/tree, and this is a plain table. *\/\n      h += '<tr data-region=\"' + r.id + '\" tabindex=\"0\" aria-current=\"' + (sel ? 'true' : 'false') + '\"' + (sel ? ' class=\"is-sel\"' : '') + '><th scope=\"row\">' + esc(r.short) + (rows[i].basis ? ', ' + esc(rows[i].basis) : '') + '<\/th>';\n      if(rows[i].nosig){\n        \/* one muted band, not eight zeros -- eight \"0\" cells reads as\n           \"checked every category, nothing moves\"; one hatched band reads as\n           \"not measured here\", which is the honest state for this region. *\/\n        h += '<td colspan=\"' + C.CATEGORIES.length + '\" class=\"nosig\" data-tip=\"' + escTip(r.short + ' ' + MIDDOT + ' no reliable ENSO signal for this region') + '\">no reliable signal<\/td>';\n      } else {\n        for(j = 0; j < rows[i].cats.length; j++){\n          var k = rows[i].cats[j];\n          h += '<td><i class=\"' + cellClass(k.index) + '\" data-tip=\"' + escTip(r.short + ' ' + MIDDOT + ' ' + k.label + ': ' + k.reason) + '\">' + sign(k.index) + '<\/i><\/td>';\n        }\n      }\n      h += '<\/tr>';\n    }\n    HEAT.innerHTML = h + '<\/tbody><\/table>';\n    if(focusCol){\n      restore = HEAT.querySelector('th[data-col=\"' + focusCol + '\"] button');\n      if(restore){ restore.focus(); }\n    } else if(focusRegion){\n      restore = HEAT.querySelector('tr[data-region=\"' + focusRegion + '\"]');\n      if(restore){ restore.focus(); }\n    }\n  }\n  HEAT.addEventListener('click', function(ev){\n    var th = ev.target.closest ? ev.target.closest('th[data-col]') : null;\n    if(th){\n      var colId = th.getAttribute('data-col');\n      if(SORT.col === colId){ SORT.dir = -SORT.dir; } else { SORT.col = colId; SORT.dir = -1; }\n      \/* this path calls renderHeat() directly, not update() -- update()'s\n         own hideTip() never runs, so a tooltip left open on the cell\/header\n         the user was pointing at would otherwise survive the rebuild,\n         floating over content it no longer describes (the row it was\n         anchored to no longer exists as the same element). *\/\n      hideTip(); renderHeat(); return;\n    }\n    var tr = ev.target.closest ? ev.target.closest('tr[data-region]') : null;\n    if(tr){ S.region = tr.getAttribute('data-region'); track('eni_region_select', { region: S.region, via: 'heatmap' }); update(); }\n  });\n  HEAT.addEventListener('keydown', function(ev){\n    if(ev.key !== 'Enter' ? ev.key !== ' ' : false){ return; }\n    var tr = ev.target.closest ? ev.target.closest('tr[data-region]') : null;\n    if(!tr){ return; }\n    ev.preventDefault();\n    S.region = tr.getAttribute('data-region'); track('eni_region_select', { region: S.region, via: 'heatmap' }); update();\n  });\n  RENDERERS.push(renderHeat);\n  \/* CTA band: click tracking on the one remaining link, through the same\n     dataLayer helper every other interaction on this page uses. *\/\n  var routes = document.querySelectorAll('.eni-route-cta'), ri;\n  for(ri = 0; ri < routes.length; ri++){\n    (function(el){\n      el.addEventListener('click', function(){ track('eni_cta_click', { cta: el.getAttribute('data-cta'), region: S.region }); });\n    })(routes[ri]);\n  }\n  \/* Portfolio request form (2026-10-06). Posts to the site's own Contact\n     Form 7 demo form through its public feedback route: same origin, on the\n     reader's click only, carrying what the reader typed plus the region,\n     phase and strength on screen. This is the ONE runtime request this page\n     makes (rule 4, noted in the factory rules). The demo form's own\n     validation answers come back as JSON and are shown in place; a network\n     failure unhides the static link to the demo page. The company type and\n     the portfolio text travel inside the demo form's message field, because\n     the host does not persist a new form's mail settings over the API. *\/\n  var CF7 = { form: 1091, page: 14338, url: 'https:\/\/geopard.tech\/wp-json\/contact-form-7\/v1\/contact-forms\/' };\n  \/* The demo form scores every submission with reCAPTCHA v3 (site key below,\n     the one the site's own demo page renders) and treats a missing token as\n     spam, so Google's script loads on the reader's send click, never before,\n     and its token rides along as _wpcf7_recaptcha_response. The Akismet\n     fields the demo form carries (honeypot empty, JS timestamp set) are\n     sent the way the real form sends them. *\/\n  var RC = { key: '6LfbXVYdAAAAAHznyhXBj-H9sHrvdiUk_QedN_CO', src: 'https:\/\/www.google.com\/recaptcha\/api.js?render=' };\n  function withRecaptcha(then, fail){\n    var done = false, timer;\n    function finish(fn, v){ if(done){ return; } done = true; clearTimeout(timer); fn(v); }\n    function run(){\n      try{\n        window.grecaptcha.ready(function(){\n          window.grecaptcha.execute(RC.key, { action: 'contact' }).then(function(tok){ finish(then, tok); }, function(){ finish(fail); });\n        });\n      }catch(err){ finish(fail); }\n    }\n    timer = setTimeout(function(){ finish(fail); }, 12000);\n    if(window.grecaptcha ? window.grecaptcha.execute : false){ run(); return; }\n    var s = document.createElement('script'); s.async = true; s.onload = run; s.onerror = function(){ finish(fail); };\n    s.src = RC.src + RC.key; document.head.appendChild(s);\n  }\n  var FORM = document.getElementById('eni-form'), FORM_MSG = document.getElementById('eni-form-msg'), FORM_FALLBACK = document.getElementById('eni-form-fallback');\n  var CF7_FIELDS = ['first-name', 'last-name', 'company-name', 'company-role', 'email', 'phone', 'countries', 'area', 'size-type'];\n  function formNote(text, kind){ FORM_MSG.textContent = text; FORM_MSG.className = 'eni-form-msg ' + kind; FORM_MSG.hidden = false; }\n  function formField(name){ return FORM.querySelector('[name=\"' + name + '\"]'); }\n  if(FORM){\n    FORM.addEventListener('submit', function(ev){\n      ev.preventDefault();\n      var els = FORM.querySelectorAll('[name]'), i, el, missing = [], fd, msg, btn = document.getElementById('eni-form-send');\n      for(i = 0; i < els.length; i++){\n        el = els[i];\n        el.classList.remove('is-bad');\n        if(el.required ? !String(el.value).trim() : false){ missing.push(el); el.classList.add('is-bad'); }\n      }\n      FORM_FALLBACK.hidden = true;\n      if(missing.length){ missing[0].focus(); formNote('Fill in the marked fields.', 'warn'); return; }\n      msg = 'El Ni\u00f1o and Monsoon Impact Simulator, quote request for the paid briefing\\n'\n        + 'Company type: ' + formField('company-type').value + '\\n'\n        + 'Portfolio: ' + formField('portfolio').value + '\\n'\n        + 'Selected on the page: ' + (REG[S.region] ? REG[S.region].label : S.region) + ', ' + C.PHASE_LABEL[S.phase] + ', ' + C.STRENGTH_LABEL[S.strength] + '\\n'\n        + 'Page: ' + window.location.href;\n      fd = new FormData();\n      fd.append('_wpcf7', String(CF7.form));\n      fd.append('_wpcf7_unit_tag', 'wpcf7-f' + CF7.form + '-p' + CF7.page + '-o1');\n      fd.append('_wpcf7_container_post', String(CF7.page));\n      fd.append('_wpcf7_locale', 'en_US');\n      fd.append('_wpcf7_version', '6.1.7');\n      fd.append('_wpcf7_posted_data_hash', '');\n      fd.append('_wpcf7_ak_hp_textarea', '');\n      fd.append('_wpcf7_ak_js', String(new Date().getTime()));\n      for(i = 0; i < CF7_FIELDS.length; i++){ fd.append(CF7_FIELDS[i], formField(CF7_FIELDS[i]).value); }\n      fd.append('message', msg);\n      btn.disabled = true;\n      function fail(){ btn.disabled = false; FORM_MSG.hidden = true; FORM_FALLBACK.hidden = false; }\n      withRecaptcha(function(token){ fd.append('_wpcf7_recaptcha_response', token); send(); }, fail);\n      function send(){\n      fetch(CF7.url + CF7.form + '\/feedback', { method: 'POST', body: fd }).then(function(r){ return r.json(); }).then(function(j){\n        var k, bad;\n        if(j.status === 'mail_sent'){\n          document.getElementById('eni-form-grid').hidden = true; btn.hidden = true;\n          \/* the demo form's own success text is generic; this page's line names what was sent *\/\n          formNote('Request received. The quote comes by email.', 'ok');\n          track('eni_cta_submit', { cta: 'portfolio-request', region: S.region, phase: S.phase, strength: S.strength });\n          return;\n        }\n        if(j.status === 'validation_failed'){\n          btn.disabled = false;\n          for(k = 0; k < (j.invalid_fields || []).length; k++){ bad = formField(j.invalid_fields[k].field); if(bad){ bad.classList.add('is-bad'); } }\n          formNote(j.message || 'One or more fields need attention.', 'warn');\n          return;\n        }\n        fail();\n      }).catch(fail);\n      }\n    });\n  }\n  readUrl();\n  renderState();\n  initControls();\n  update();\n})();\n<\/script>\n<\/div>\n\n","protected":false},"excerpt":{"rendered":"<p>\u042d\u043b\u044c-\u041d\u0438\u043d\u044c\u043e \u0436\u04d9\u043d\u0435 \u043c\u0443\u0441\u0441\u043e\u043d \u04d9\u0441\u0435\u0440\u0456\u043d\u0456\u04a3 \u0441\u0438\u043c\u0443\u043b\u044f\u0442\u043e\u0440\u044b 2026-27 \u0436\u044b\u043b\u0434\u0430\u0440\u0434\u0430\u0493\u044b \u042d\u043b\u044c-\u041d\u0438\u043d\u044c\u043e \u0436\u04d9\u043d\u0435 \u043c\u0443\u0441\u0441\u043e\u043d \u0431\u043e\u043b\u0436\u0430\u043c\u044b \u0434\u0430\u049b\u044b\u043b\u0434\u0430\u0440\u0434\u044b\u04a3 \u043a\u04af\u0439\u0437\u0435\u043b\u0456\u0441\u0456 \u043c\u0435\u043d \u0448\u0438\u043a\u0456\u0437\u0430\u0442\u049b\u0430 \u0434\u0435\u0433\u0435\u043d \u0441\u04b1\u0440\u0430\u043d\u044b\u0441\u0442\u044b \u04e9\u0437\u0433\u0435\u0440\u0442\u0435\u0442\u0456\u043d \u0436\u0435\u0440 ENSO \u043a\u0435\u0437\u0435\u04a3\u0456\u043d \u0442\u0430\u04a3\u0434\u0430\u04a3\u044b\u0437...<\/p>","protected":false},"author":210157960,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"_coblocks_attr":"","_coblocks_dimensions":"","_coblocks_responsive_height":"","_coblocks_accordion_ie_support":"","_eb_attr":"","content-type":"","_wpcom_ai_launchpad_about_page":false,"_wpcom_ai_launchpad_gallery_page":false,"_wpcom_ai_launchpad_contact_page":false,"_wpcom_ai_launchpad_events_page":false,"_wpcom_ai_launchpad_video_page":false,"_wpcom_ai_launchpad_portfolio_piece":false,"footnotes":"","big_sky_generated":false},"class_list":["post-14338","page","type-page","status-publish","hentry"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v28.6 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>El Ni\u00f1o and Monsoon Impact on Agriculture 2026-27 - GeoPard<\/title>\n<meta name=\"description\" content=\"How the 2026-27 El Ni\u00f1o and the monsoon outlook shift rainfall, crop stress and crop-input demand in 25 regions. Push, hold or pull back, region by region.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/geopard.tech\/kz\/\u044d\u043b\u044c-\u043d\u0438\u043d\u044c\u043e-\u04d9\u0441\u0435\u0440\u0456\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"El Ni\u00f1o and Monsoon Impact Simulator\" \/>\n<meta property=\"og:description\" content=\"Where the 2026-27 El Ni\u00f1o and the monsoon outlook move crop stress and input demand, region by region.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/geopard.tech\/kz\/\u044d\u043b\u044c-\u043d\u0438\u043d\u044c\u043e-\u04d9\u0441\u0435\u0440\u0456\/\" \/>\n<meta property=\"og:site_name\" content=\"GeoPard - Precision agriculture Mapping software\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/geopardAgriculture\/\" \/>\n<meta property=\"article:modified_time\" content=\"2026-10-12T13:54:37+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/i0.wp.com\/geopard.tech\/wp-content\/uploads\/2026\/03\/GeoPard-Background-Precision-Ag-software-Do-more-with-your-data.png?fit=3116%2C1754&ssl=1\" \/>\n\t<meta property=\"og:image:width\" content=\"3116\" \/>\n\t<meta property=\"og:image:height\" content=\"1754\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:site\" content=\"@geopardagri\" \/>\n<meta name=\"twitter:label1\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data1\" content=\"7 \u043c\u0438\u043d\u0443\u0442\u044b\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/geopard.tech\\\/el-nino-impact\\\/\",\"url\":\"https:\\\/\\\/geopard.tech\\\/el-nino-impact\\\/\",\"name\":\"El Ni\u00f1o and Monsoon Impact on Agriculture 2026-27 - GeoPard\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/geopard.tech\\\/#website\"},\"datePublished\":\"2026-09-26T15:51:14+00:00\",\"dateModified\":\"2026-10-12T13:54:37+00:00\",\"description\":\"How the 2026-27 El Ni\u00f1o and the monsoon outlook shift rainfall, crop stress and crop-input demand in 25 regions. Push, hold or pull back, region by region.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/geopard.tech\\\/el-nino-impact\\\/#breadcrumb\"},\"inLanguage\":\"ru-RU\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/geopard.tech\\\/el-nino-impact\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/geopard.tech\\\/el-nino-impact\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/geopard.tech\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"El Ni\u00f1o and Monsoon Impact Simulator\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/geopard.tech\\\/#website\",\"url\":\"https:\\\/\\\/geopard.tech\\\/\",\"name\":\"GeoPard - Precision agriculture software\",\"description\":\"Precision agriculture Mapping software\",\"publisher\":{\"@id\":\"https:\\\/\\\/geopard.tech\\\/#organization\"},\"alternateName\":\"GeoPard\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/geopard.tech\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"ru-RU\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/geopard.tech\\\/#organization\",\"name\":\"GeoPard Agriculture\",\"alternateName\":\"GeoPard\",\"url\":\"https:\\\/\\\/geopard.tech\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"ru-RU\",\"@id\":\"https:\\\/\\\/geopard.tech\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/i0.wp.com\\\/geopard.tech\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/geopard_logo_transparentbackground.png?fit=512%2C68&ssl=1\",\"contentUrl\":\"https:\\\/\\\/i0.wp.com\\\/geopard.tech\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/geopard_logo_transparentbackground.png?fit=512%2C68&ssl=1\",\"width\":512,\"height\":68,\"caption\":\"GeoPard Agriculture\"},\"image\":{\"@id\":\"https:\\\/\\\/geopard.tech\\\/#\\\/schema\\\/logo\\\/image\\\/\"},\"sameAs\":[\"https:\\\/\\\/www.facebook.com\\\/geopardAgriculture\\\/\",\"https:\\\/\\\/x.com\\\/geopardagri\",\"https:\\\/\\\/www.linkedin.com\\\/company\\\/geopard-agriculture\\\/\",\"https:\\\/\\\/www.instagram.com\\\/geopardagriculture\\\/\",\"https:\\\/\\\/www.youtube.com\\\/channel\\\/UCiaPGLAhRPNh-s85dXdC-Sw\",\"https:\\\/\\\/www.g2.com\\\/products\\\/geopard-agriculture-precision-farming-software\\\/reviews\"]}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"\u042d\u043b\u044c-\u041d\u0438\u043d\u044c\u043e \u043c\u0435\u043d \u043c\u0443\u0441\u0441\u043e\u043d\u043d\u044b\u04a3 \u0430\u0443\u044b\u043b \u0448\u0430\u0440\u0443\u0430\u0448\u044b\u043b\u044b\u0493\u044b\u043d\u0430 \u04d9\u0441\u0435\u0440\u0456 2026-27 \u0436\u0436. - GeoPard","description":"2026-27 \u0436\u044b\u043b\u0434\u0430\u0440\u0434\u0430\u0493\u044b \u042d\u043b\u044c-\u041d\u0438\u043d\u044c\u043e \u0436\u04d9\u043d\u0435 \u043c\u0443\u0441\u0441\u043e\u043d \u0431\u043e\u043b\u0436\u0430\u043c\u044b 25 \u0430\u0439\u043c\u0430\u049b\u0442\u0430 \u0436\u0430\u0443\u044b\u043d-\u0448\u0430\u0448\u044b\u043d\u0434\u044b, \u0434\u0430\u049b\u044b\u043b\u0434\u0430\u0440\u0493\u0430 \u0442\u04af\u0441\u0435\u0442\u0456\u043d \u0441\u0442\u0440\u0435\u0441\u0441\u0442\u0456 \u0436\u04d9\u043d\u0435 \u0434\u0430\u049b\u044b\u043b\u0434\u0430\u0440\u0493\u0430 \u0434\u0435\u0433\u0435\u043d \u0441\u04b1\u0440\u0430\u043d\u044b\u0441\u0442\u044b \u049b\u0430\u043b\u0430\u0439 \u04e9\u0437\u0433\u0435\u0440\u0442\u0435\u0434\u0456. \u0410\u0439\u043c\u0430\u049b \u0431\u043e\u0439\u044b\u043d\u0448\u0430 \u0438\u0442\u0435\u0440\u043c\u0435\u043b\u0435\u04a3\u0456\u0437, \u0442\u043e\u049b\u0442\u0430\u0442\u044b\u04a3\u044b\u0437 \u043d\u0435\u043c\u0435\u0441\u0435 \u0430\u0440\u0442\u049b\u0430 \u0442\u0430\u0440\u0442\u044b\u04a3\u044b\u0437.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/geopard.tech\/kz\/\u044d\u043b\u044c-\u043d\u0438\u043d\u044c\u043e-\u04d9\u0441\u0435\u0440\u0456\/","og_locale":"en_US","og_type":"article","og_title":"El Ni\u00f1o and Monsoon Impact Simulator","og_description":"Where the 2026-27 El Ni\u00f1o and the monsoon outlook move crop stress and input demand, region by region.","og_url":"https:\/\/geopard.tech\/kz\/\u044d\u043b\u044c-\u043d\u0438\u043d\u044c\u043e-\u04d9\u0441\u0435\u0440\u0456\/","og_site_name":"GeoPard - Precision agriculture Mapping software","article_publisher":"https:\/\/www.facebook.com\/geopardAgriculture\/","article_modified_time":"2026-10-12T13:54:37+00:00","og_image":[{"width":3116,"height":1754,"url":"https:\/\/i0.wp.com\/geopard.tech\/wp-content\/uploads\/2026\/03\/GeoPard-Background-Precision-Ag-software-Do-more-with-your-data.png?fit=3116%2C1754&ssl=1","type":"image\/png"}],"twitter_card":"summary_large_image","twitter_site":"@geopardagri","twitter_misc":{"Est. reading time":"7 \u043c\u0438\u043d\u0443\u0442\u044b"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/geopard.tech\/el-nino-impact\/","url":"https:\/\/geopard.tech\/el-nino-impact\/","name":"\u042d\u043b\u044c-\u041d\u0438\u043d\u044c\u043e \u043c\u0435\u043d \u043c\u0443\u0441\u0441\u043e\u043d\u043d\u044b\u04a3 \u0430\u0443\u044b\u043b \u0448\u0430\u0440\u0443\u0430\u0448\u044b\u043b\u044b\u0493\u044b\u043d\u0430 \u04d9\u0441\u0435\u0440\u0456 2026-27 \u0436\u0436. - GeoPard","isPartOf":{"@id":"https:\/\/geopard.tech\/#website"},"datePublished":"2026-09-26T15:51:14+00:00","dateModified":"2026-10-12T13:54:37+00:00","description":"2026-27 \u0436\u044b\u043b\u0434\u0430\u0440\u0434\u0430\u0493\u044b \u042d\u043b\u044c-\u041d\u0438\u043d\u044c\u043e \u0436\u04d9\u043d\u0435 \u043c\u0443\u0441\u0441\u043e\u043d \u0431\u043e\u043b\u0436\u0430\u043c\u044b 25 \u0430\u0439\u043c\u0430\u049b\u0442\u0430 \u0436\u0430\u0443\u044b\u043d-\u0448\u0430\u0448\u044b\u043d\u0434\u044b, \u0434\u0430\u049b\u044b\u043b\u0434\u0430\u0440\u0493\u0430 \u0442\u04af\u0441\u0435\u0442\u0456\u043d \u0441\u0442\u0440\u0435\u0441\u0441\u0442\u0456 \u0436\u04d9\u043d\u0435 \u0434\u0430\u049b\u044b\u043b\u0434\u0430\u0440\u0493\u0430 \u0434\u0435\u0433\u0435\u043d \u0441\u04b1\u0440\u0430\u043d\u044b\u0441\u0442\u044b \u049b\u0430\u043b\u0430\u0439 \u04e9\u0437\u0433\u0435\u0440\u0442\u0435\u0434\u0456. \u0410\u0439\u043c\u0430\u049b \u0431\u043e\u0439\u044b\u043d\u0448\u0430 \u0438\u0442\u0435\u0440\u043c\u0435\u043b\u0435\u04a3\u0456\u0437, \u0442\u043e\u049b\u0442\u0430\u0442\u044b\u04a3\u044b\u0437 \u043d\u0435\u043c\u0435\u0441\u0435 \u0430\u0440\u0442\u049b\u0430 \u0442\u0430\u0440\u0442\u044b\u04a3\u044b\u0437.","breadcrumb":{"@id":"https:\/\/geopard.tech\/el-nino-impact\/#breadcrumb"},"inLanguage":"ru-RU","potentialAction":[{"@type":"ReadAction","target":["https:\/\/geopard.tech\/el-nino-impact\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/geopard.tech\/el-nino-impact\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/geopard.tech\/"},{"@type":"ListItem","position":2,"name":"El Ni\u00f1o and Monsoon Impact Simulator"}]},{"@type":"WebSite","@id":"https:\/\/geopard.tech\/#website","url":"https:\/\/geopard.tech\/","name":"GeoPard - \u0434\u04d9\u043b \u0430\u0443\u044b\u043b \u0448\u0430\u0440\u0443\u0430\u0448\u044b\u043b\u044b\u0493\u044b \u0431\u0430\u0493\u0434\u0430\u0440\u043b\u0430\u043c\u0430\u0441\u044b","description":"\u0414\u04d9\u043b \u0430\u0443\u044b\u043b \u0448\u0430\u0440\u0443\u0430\u0448\u044b\u043b\u044b\u0493\u044b \u043a\u0430\u0440\u0442\u0430\u043b\u0430\u0443 \u0431\u0430\u0493\u0434\u0430\u0440\u043b\u0430\u043c\u0430\u0441\u044b","publisher":{"@id":"https:\/\/geopard.tech\/#organization"},"alternateName":"GeoPard","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/geopard.tech\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"ru-RU"},{"@type":"Organization","@id":"https:\/\/geopard.tech\/#organization","name":"GeoPard \u0410\u0443\u044b\u043b \u0448\u0430\u0440\u0443\u0430\u0448\u044b\u043b\u044b\u0493\u044b","alternateName":"GeoPard","url":"https:\/\/geopard.tech\/","logo":{"@type":"ImageObject","inLanguage":"ru-RU","@id":"https:\/\/geopard.tech\/#\/schema\/logo\/image\/","url":"https:\/\/i0.wp.com\/geopard.tech\/wp-content\/uploads\/2026\/07\/geopard_logo_transparentbackground.png?fit=512%2C68&ssl=1","contentUrl":"https:\/\/i0.wp.com\/geopard.tech\/wp-content\/uploads\/2026\/07\/geopard_logo_transparentbackground.png?fit=512%2C68&ssl=1","width":512,"height":68,"caption":"GeoPard Agriculture"},"image":{"@id":"https:\/\/geopard.tech\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/geopardAgriculture\/","https:\/\/x.com\/geopardagri","https:\/\/www.linkedin.com\/company\/geopard-agriculture\/","https:\/\/www.instagram.com\/geopardagriculture\/","https:\/\/www.youtube.com\/channel\/UCiaPGLAhRPNh-s85dXdC-Sw","https:\/\/www.g2.com\/products\/geopard-agriculture-precision-farming-software\/reviews"]}]}},"jetpack_likes_enabled":true,"jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/PdiCPa-3Jg","_links":{"self":[{"href":"https:\/\/geopard.tech\/kz\/wp-json\/wp\/v2\/pages\/14338","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/geopard.tech\/kz\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/geopard.tech\/kz\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/geopard.tech\/kz\/wp-json\/wp\/v2\/users\/210157960"}],"replies":[{"embeddable":true,"href":"https:\/\/geopard.tech\/kz\/wp-json\/wp\/v2\/comments?post=14338"}],"version-history":[{"count":0,"href":"https:\/\/geopard.tech\/kz\/wp-json\/wp\/v2\/pages\/14338\/revisions"}],"wp:attachment":[{"href":"https:\/\/geopard.tech\/kz\/wp-json\/wp\/v2\/media?parent=14338"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}