{"product_id":"kenya-rungeto-kiangoi","title":"KENYA - KIANGOI","description":"\u003cp\u003e\u0026nbsp;\u003c\/p\u003e\n\u003c!-- =========================================================\n  SECTION 1: TASTING NOTES\n========================================================= --\u003e\n\u003cdiv style=\"width: 100%; margin: 0 auto 12px auto; border: 2px solid #000; border-radius: 12px; overflow: hidden;\"\u003e\n\u003cdiv style=\"padding: 10px 14px; font-weight: 800; text-transform: uppercase; font-size: 14px; letter-spacing: .02em; background: #000; color: #fff; text-align: center;\"\u003eTasting Notes\u003c\/div\u003e\n\u003cdiv style=\"padding: 16px 14px; font-weight: 900; text-transform: uppercase; font-size: 28px; letter-spacing: .05em; text-align: center; background: transparent;\"\u003eHONEYBERRY + GRAPEFRUIT + VANILLA\u003c\/div\u003e\n\u003c\/div\u003e\n\u003c!-- ========= END SECTION 1 ========= --\u003e\n\u003cp\u003e\u0026nbsp;\u003c\/p\u003e\n\u003cdiv style=\"position: relative; width: 100%; padding-bottom: 56.25%; height: 0; overflow: hidden; border-radius: 8px;\"\u003e\u003ciframe style=\"position: absolute; top: 0; left: 0; width: 100%; height: 100%; border: 0; border-radius: 8px;\" src=\"https:\/\/www.youtube.com\/embed\/PAlWZj5F3lk\" title=\"YouTube video player\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" allowfullscreen=\"\"\u003e\n\u003c\/iframe\u003e\u003c\/div\u003e\n\u003cp\u003e\u0026nbsp;\u003c\/p\u003e\n\u003c!-- =========================================================\n  SECTION 2: SOURCING\n========================================================= --\u003e\n\u003cdiv style=\"width: 100%; margin: 0 auto 12px auto;\"\u003e\n\u003cdiv style=\"padding: 12px 14px; font-weight: 800; text-transform: uppercase; font-size: 14px; letter-spacing: .02em; background: #000; color: #fff; text-align: center; border-radius: 12px 12px 0 0;\"\u003eSourcing\u003c\/div\u003e\n\u003ctable border=\"3\" cellpadding=\"1\" cellspacing=\"1\" style=\"width: 100%; border-collapse: collapse; background: transparent;\"\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd style=\"width: 20%;\"\u003eORIGIN\u003c\/td\u003e\n\u003ctd\u003eGichugu area, Kirinyaga County, Kenya\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003ePRODUCERS\u003c\/td\u003e\n\u003ctd\u003eSeveral small producers\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eCOOPERATIVE\u003c\/td\u003e\n\u003ctd\u003eKiangoi\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eVARIETY\u003c\/td\u003e\n\u003ctd\u003eBatian, SL-34, Ruiru 11, SL-28\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003ePROCESS\u003c\/td\u003e\n\u003ctd\u003eWashed\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eALTITUDE\u003c\/td\u003e\n\u003ctd\u003e1600 to 1800 m\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003ePARTNERS\u003c\/td\u003e\n\u003ctd\u003eApex Coffee imports\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eVOLUME PURCHASED\u003c\/td\u003e\n\u003ctd\u003e180 kg\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eFOB\u003c\/td\u003e\n\u003ctd\u003e$5.84 USD\/lb\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eDELIVERED PRICE\u003c\/td\u003e\n\u003ctd\u003e$12.20 CAD\/LB\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eRELATIONSHIP\u003c\/td\u003e\n\u003ctd\u003e1 year\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003c\/tbody\u003e\n\u003c\/table\u003e\n\u003c\/div\u003e\n\u003c!-- ========= END SECTION 2 ========= --\u003e\n\u003cp\u003e\u0026nbsp;\u003c\/p\u003e\n\u003c!-- =========================================================\n  SECTION 3: ABOUT THIS COFFEE\n========================================================= --\u003e\n\u003cdiv style=\"width: 100%; margin: 0 auto 12px auto;\"\u003e\n\u003cdiv style=\"padding: 12px 14px; font-weight: 800; text-transform: uppercase; font-size: 14px; letter-spacing: .02em; background: #000; color: #fff; text-align: center; border-radius: 12px 12px 0 0;\"\u003eAbout This Coffee\u003c\/div\u003e\n\u003cdiv style=\"border: 2px solid #000; border-top: none; border-radius: 0 0 12px 12px; padding: 16px 14px; background: transparent;\"\u003e\n\u003cp style=\"margin: 0 0 12px 0;\"\u003eA bright coffee that, as drip coffee, offers us a beautiful complexity, balancing the gentle bitterness of grapefruit and the lively acidity of honeyberry, with a base full of sugar. For espresso, we aim for a long but fast shot, sacrificing body to leave us with a lively, expressive coffee that tastes of blackberry and orange juice, yum!\u003c\/p\u003e\n\u003cp style=\"margin: 0 0 12px 0;\"\u003eThe Kiangoi washing station is in Gichugu, in Kirinyaga County, in the heart of Kenya. It was founded in the 1960s and works with producers from the villages of Kiangoro and Karinga. The station is Fairtrade certified and is located in a region where native trees are still part of the landscape. The cherries are also sorted by hand there, to keep only the ripest ones and get the best possible bean quality.\u003c\/p\u003e\n\u003cp style=\"margin: 0;\"\u003eThe coffee is pulped and then fermented for 8 to 12 hours. The beans are then washed, soaked in water for 16 to 18 hours, and sun-dried on raised beds for nearly two weeks. Meticulous work, from fruit to green bean, to preserve all of the coffee's quality. And you can clearly taste it in the cup!\u003c\/p\u003e\n\u003c\/div\u003e\n\u003c\/div\u003e\n\u003c!-- ========= END SECTION 3 ========= --\u003e\n\u003cp\u003e\u0026nbsp;\u003c\/p\u003e\n\u003c!-- =========================================================\n  SECTION 3 BIS: PHOTO CAROUSEL\n========================================================= --\u003e\n\u003cdiv style=\"width: 100%; margin: 0 auto 12px auto;\"\u003e\n\u003cdiv id=\"zabCar-kiangoi-en\" style=\"display: flex; overflow-x: auto; scroll-snap-type: x mandatory; scroll-behavior: smooth; border: 2px solid #000; border-radius: 12px; scrollbar-width: none;\"\u003e\u003cimg src=\"https:\/\/cdn.shopify.com\/s\/files\/1\/2716\/1842\/files\/2026-11-01-kiangoi-01-web.jpg?v=1793546185\" alt=\"Smiling man wearing a grey cap and a white polo shirt, in front of a wooden building and greenery\" loading=\"lazy\" width=\"1600\" height=\"1067\" style=\"flex: 0 0 100%; width: 100%; height: auto; aspect-ratio: 3 \/ 2; object-fit: cover; scroll-snap-align: center; display: block;\"\u003e \u003cimg src=\"https:\/\/cdn.shopify.com\/s\/files\/1\/2716\/1842\/files\/2026-11-01-kiangoi-02-web.jpg?v=1793546185\" alt=\"Brick wall of the Kiangoi station, “Rungeto Farmers Co-op Society – Kiangoi Coffee Factory” sign\" loading=\"lazy\" width=\"1600\" height=\"1067\" style=\"flex: 0 0 100%; width: 100%; height: auto; aspect-ratio: 3 \/ 2; object-fit: cover; scroll-snap-align: center; display: block;\"\u003e\u003c\/div\u003e\n\u003cdiv style=\"display: flex; justify-content: center; gap: 8px; margin-top: 8px;\"\u003e\u003cbutton type=\"button\" id=\"zabCarDot-1-kiangoi-en\" aria-label=\"Photo 1\" style=\"cursor: pointer; width: 10px; height: 10px; padding: 0; border-radius: 999px; border: 2px solid #000; background: #000;\"\u003e\u003c\/button\u003e \u003cbutton type=\"button\" id=\"zabCarDot-2-kiangoi-en\" aria-label=\"Photo 2\" style=\"cursor: pointer; width: 10px; height: 10px; padding: 0; border-radius: 999px; border: 2px solid #000; background: transparent;\"\u003e\u003c\/button\u003e\u003c\/div\u003e\n\u003c\/div\u003e\n\u003c!-- ========= END SECTION 3 BIS ========= --\u003e\u003csvg style=\"display: none;\"\u003e\n\u003cscript\u003e\n(function() {\n  var SUFFIX = '-kiangoi-en';\n  var N = 2;\n  var track = document.getElementById('zabCar' + SUFFIX);\n  if (!track) return;\n  function dot(i) { return document.getElementById('zabCarDot-' + i + SUFFIX); }\n  function setActive(k) {\n    for (var i = 1; i \u0026lt;= N; i++) { var d = dot(i); if (d) d.style.background = (i === k) ? '#000' : 'transparent'; }\n  }\n  var DELAY = 3000;\n  var cur = 1;\n  var timer = null;\n  var reduce = window.matchMedia ? window.matchMedia('(prefers-reduced-motion: reduce)').matches : false;\n  function go(k) { track.scrollTo({ left: (k - 1) * track.clientWidth, behavior: 'smooth' }); }\n  function stop() { if (timer) { clearInterval(timer); timer = null; } }\n  function start() {\n    stop();\n    if (reduce) return;\n    timer = setInterval(function() { cur = (cur % N) + 1; go(cur); }, DELAY);\n  }\n  for (var i = 1; i \u0026lt;= N; i++) {\n    (function(k) {\n      var d = dot(k);\n      if (d) d.addEventListener('click', function() { cur = k; go(k); start(); });\n    })(i);\n  }\n  track.addEventListener('scroll', function() {\n    cur = Math.round(track.scrollLeft \/ Math.max(1, track.clientWidth)) + 1;\n    setActive(cur);\n  });\n  track.addEventListener('mouseenter', stop);\n  track.addEventListener('mouseleave', start);\n  track.addEventListener('touchstart', stop, { passive: true });\n  track.addEventListener('touchend', start);\n  document.addEventListener('visibilitychange', function() {\n    if (document.visibilityState === 'visible') { start(); } else { stop(); }\n  });\n  start();\n})();\n\u003c\/script\u003e\n\u003c\/svg\u003e\n\u003cp\u003e\u0026nbsp;\u003c\/p\u003e\n\u003c!-- =========================================================\n  SECTION 4: ESPRESSO EXTRACTION PARAMETERS\n========================================================= --\u003e\n\u003cdiv style=\"width: 100%; margin: 0 auto;\"\u003e\n\u003cdetails open=\"\" style=\"border: 2px solid #000; border-radius: 12px; overflow: hidden; margin: 0 0 12px 0; background: rgba(255,255,255,0.5);\"\u003e\n\u003csummary style=\"cursor: pointer; list-style: none; padding: 12px 14px; font-weight: 800; text-transform: uppercase; font-size: 14px; letter-spacing: .02em; background: #000; color: #fff; text-align: center;\"\u003eEspresso — Recommended Parameters\u003c\/summary\u003e\n\u003cdiv style=\"padding: 12px 14px;\"\u003e\n\u003ctable style=\"width: 100%; border-collapse: collapse; background: transparent;\"\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd style=\"padding: 10px 0; font-weight: 800; border-bottom: 1px solid rgba(0,0,0,.2);\"\u003eGround coffee\u003c\/td\u003e\n\u003ctd style=\"padding: 10px 0; text-align: right; border-bottom: 1px solid rgba(0,0,0,.2);\"\u003e18 g\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"padding: 10px 0; font-weight: 800; border-bottom: 1px solid rgba(0,0,0,.2);\"\u003eCoffee in cup\u003c\/td\u003e\n\u003ctd style=\"padding: 10px 0; text-align: right; border-bottom: 1px solid rgba(0,0,0,.2);\"\u003e42 g\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"padding: 10px 0; font-weight: 800;\"\u003eExtraction time\u003c\/td\u003e\n\u003ctd style=\"padding: 10px 0; text-align: right;\"\u003e21 sec\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003c\/tbody\u003e\n\u003c\/table\u003e\n\u003cdiv style=\"margin-top: 10px; padding: 8px 10px; border-radius: 8px; background: rgba(0,0,0,.04); border: 1px dashed rgba(0,0,0,.2); font-size: 12px; opacity: .7; line-height: 1.4;\"\u003e\u003cstrong\u003eNote —\u003c\/strong\u003e Recipe optimized for an \u003cstrong\u003e18 g\u003c\/strong\u003e basket. Check your machine's manual to confirm your basket's capacity.\u003c\/div\u003e\n\u003c\/div\u003e\n\u003c\/details\u003e\n\u003c\/div\u003e\n\u003c!-- ========= END SECTION 4 ========= --\u003e\n\u003cp\u003e\u0026nbsp;\u003c\/p\u003e\n\u003c!-- =========================================================\n  SECTION 5: V60\n========================================================= --\u003e\n\u003cdiv style=\"width: 100%; margin: 0 auto;\"\u003e\n\u003cdetails id=\"v60Details-kiangoi-en\" open=\"\" style=\"border: 2px solid #000; border-radius: 12px; overflow: hidden; margin: 0 0 12px 0; background: rgba(255,255,255,0.5);\"\u003e\n\u003csummary style=\"cursor: pointer; list-style: none; padding: 12px 14px; font-weight: 800; text-transform: uppercase; font-size: 14px; letter-spacing: .02em; background: #000; color: #fff; text-align: center;\"\u003eV60 – Recipe\u003c\/summary\u003e\n\u003cdiv style=\"padding: 12px 14px;\"\u003e\n\u003cdiv style=\"padding: 10px 0 10px; border-bottom: 1px solid rgba(0,0,0,.2);\"\u003e\n\u003cdiv style=\"font-weight: 900; font-size: 16px;\"\u003eRatio 1:15\u003c\/div\u003e\n\u003cdiv style=\"margin-top: 4px; opacity: .7; font-size: 13px;\"\u003e15 g in – 225 g out\u003c\/div\u003e\n\u003cdiv style=\"margin-top: 6px; font-size: 13px;\"\u003e\u003cstrong\u003eWater temperature:\u003c\/strong\u003e 91 °C\u003c\/div\u003e\n\u003c\/div\u003e\n\u003cdiv style=\"display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap; padding: 10px 0 8px;\"\u003e\n\u003cdiv style=\"display: flex; gap: 8px; align-items: center; flex-wrap: wrap;\"\u003e\u003cbutton style=\"cursor: pointer; border: 2px solid #000; background: #000; color: #fff; font-weight: 900; padding: 8px 10px; border-radius: 10px; text-transform: uppercase; letter-spacing: .02em; font-size: 12px;\" type=\"button\" id=\"v60StartBtn-kiangoi-en\"\u003eStart\u003c\/button\u003e \u003cbutton style=\"cursor: pointer; border: 2px solid #000; background: #fff; color: #000; font-weight: 900; padding: 8px 10px; border-radius: 10px; text-transform: uppercase; letter-spacing: .02em; font-size: 12px; opacity: .5;\" disabled=\"disabled\" type=\"button\" id=\"v60StopBtn-kiangoi-en\"\u003eStop\u003c\/button\u003e\u003c\/div\u003e\n\u003cdiv style=\"display: flex; gap: 10px; align-items: baseline; line-height: 1;\"\u003e\u003cspan style=\"opacity: .70; font-size: 12px; font-weight: 800; text-transform: uppercase; letter-spacing: .04em;\"\u003eTimer\u003c\/span\u003e \u003cspan style=\"font-weight: 950; font-size: 28px; letter-spacing: .01em;\" id=\"v60Timer-kiangoi-en\"\u003e0:00\u003c\/span\u003e\u003c\/div\u003e\n\u003cdiv style=\"flex-basis: 100%; opacity: .6; font-size: 12px; line-height: 1.3; margin-top: 2px;\" id=\"v60WakeStatus-kiangoi-en\"\u003eℹ️ Tap \"Start\" to keep the screen awake.\u003c\/div\u003e\n\u003c\/div\u003e\n\u003cdiv style=\"margin-top: 8px; display: grid; gap: 10px;\"\u003e\n\u003cdiv style=\"border: 1px solid rgba(0,0,0,.18); border-radius: 12px; padding: 10px 12px;\" id=\"v60-card-1-kiangoi-en\"\u003e\n\u003cdiv style=\"display: flex; gap: 10px; align-items: baseline; margin-bottom: 6px;\"\u003e\n\u003cdiv style=\"font-weight: 900;\"\u003e0:00\u003c\/div\u003e\n\u003cdiv style=\"font-weight: 900;\"\u003ePhase 1 — Bloom\u003c\/div\u003e\n\u003c\/div\u003e\n\u003cdiv style=\"display: flex; gap: 8px; flex-wrap: wrap; font-size: 12.5px; font-weight: 800;\"\u003e\u003cspan style=\"padding: 5px 9px; border-radius: 999px; background: rgba(0,0,0,.05); border: 1px solid rgba(0,0,0,.12);\" id=\"v60-pill-1-kiangoi-en\"\u003ePour for 0:10s\u003c\/span\u003e \u003cspan style=\"padding: 5px 9px; border-radius: 999px; background: rgba(0,0,0,.05); border: 1px solid rgba(0,0,0,.12);\"\u003eTotal 50 g\u003c\/span\u003e\u003c\/div\u003e\n\u003c\/div\u003e\n\u003cdiv style=\"border: 1px solid rgba(0,0,0,.18); border-radius: 12px; padding: 10px 12px;\" id=\"v60-card-2-kiangoi-en\"\u003e\n\u003cdiv style=\"display: flex; gap: 10px; align-items: baseline; margin-bottom: 6px;\"\u003e\n\u003cdiv style=\"font-weight: 900;\"\u003e0:40\u003c\/div\u003e\n\u003cdiv style=\"font-weight: 900;\"\u003ePhase 2\u003c\/div\u003e\n\u003c\/div\u003e\n\u003cdiv style=\"display: flex; gap: 8px; flex-wrap: wrap; font-size: 12.5px; font-weight: 800;\"\u003e\u003cspan style=\"padding: 5px 9px; border-radius: 999px; background: rgba(0,0,0,.05); border: 1px solid rgba(0,0,0,.12);\" id=\"v60-pill-2-kiangoi-en\"\u003ePour for 0:10s\u003c\/span\u003e \u003cspan style=\"padding: 5px 9px; border-radius: 999px; background: rgba(0,0,0,.05); border: 1px solid rgba(0,0,0,.12);\"\u003eTotal 100 g\u003c\/span\u003e \u003cspan style=\"padding: 5px 9px; border-radius: 999px; background: rgba(0,0,0,.05); border: 1px solid rgba(0,0,0,.12); opacity: .6;\"\u003e+50 g\u003c\/span\u003e\u003c\/div\u003e\n\u003c\/div\u003e\n\u003cdiv style=\"border: 1px solid rgba(0,0,0,.18); border-radius: 12px; padding: 10px 12px;\" id=\"v60-card-3-kiangoi-en\"\u003e\n\u003cdiv style=\"display: flex; gap: 10px; align-items: baseline; margin-bottom: 6px;\"\u003e\n\u003cdiv style=\"font-weight: 900;\"\u003e1:20\u003c\/div\u003e\n\u003cdiv style=\"font-weight: 900;\"\u003ePhase 3\u003c\/div\u003e\n\u003c\/div\u003e\n\u003cdiv style=\"display: flex; gap: 8px; flex-wrap: wrap; font-size: 12.5px; font-weight: 800;\"\u003e\u003cspan style=\"padding: 5px 9px; border-radius: 999px; background: rgba(0,0,0,.05); border: 1px solid rgba(0,0,0,.12);\" id=\"v60-pill-3-kiangoi-en\"\u003ePour for 0:10s\u003c\/span\u003e \u003cspan style=\"padding: 5px 9px; border-radius: 999px; background: rgba(0,0,0,.05); border: 1px solid rgba(0,0,0,.12);\"\u003eTotal 170 g\u003c\/span\u003e \u003cspan style=\"padding: 5px 9px; border-radius: 999px; background: rgba(0,0,0,.05); border: 1px solid rgba(0,0,0,.12); opacity: .6;\"\u003e+70 g\u003c\/span\u003e\u003c\/div\u003e\n\u003c\/div\u003e\n\u003cdiv style=\"border: 1px solid rgba(0,0,0,.18); border-radius: 12px; padding: 10px 12px;\" id=\"v60-card-4-kiangoi-en\"\u003e\n\u003cdiv style=\"display: flex; gap: 10px; align-items: baseline; margin-bottom: 6px;\"\u003e\n\u003cdiv style=\"font-weight: 900;\"\u003e1:55\u003c\/div\u003e\n\u003cdiv style=\"font-weight: 900;\"\u003ePhase 4\u003c\/div\u003e\n\u003c\/div\u003e\n\u003cdiv style=\"display: flex; gap: 8px; flex-wrap: wrap; font-size: 12.5px; font-weight: 800;\"\u003e\u003cspan style=\"padding: 5px 9px; border-radius: 999px; background: rgba(0,0,0,.05); border: 1px solid rgba(0,0,0,.12);\" id=\"v60-pill-4-kiangoi-en\"\u003ePour for 0:10s\u003c\/span\u003e \u003cspan style=\"padding: 5px 9px; border-radius: 999px; background: rgba(0,0,0,.05); border: 1px solid rgba(0,0,0,.12);\"\u003eTotal 225 g\u003c\/span\u003e \u003cspan style=\"padding: 5px 9px; border-radius: 999px; background: rgba(0,0,0,.05); border: 1px solid rgba(0,0,0,.12); opacity: .6;\"\u003e+55 g\u003c\/span\u003e\u003c\/div\u003e\n\u003c\/div\u003e\n\u003c\/div\u003e\n\u003cdiv style=\"margin-top: 12px; border-top: 1px solid rgba(0,0,0,.2); padding-top: 10px;\"\u003e\n\u003cdiv style=\"display: flex; gap: 10px; align-items: baseline;\"\u003e\n\u003cdiv style=\"font-weight: 900;\"\u003e2:45\u003c\/div\u003e\n\u003cdiv style=\"font-weight: 900;\"\u003eFinal full drawdown time\u003c\/div\u003e\n\u003c\/div\u003e\n\u003cdiv style=\"margin-top: 8px; padding: 8px 10px; border-radius: 8px; background: rgba(0,0,0,.04); border: 1px dashed rgba(0,0,0,.2); font-size: 12px; opacity: .6; line-height: 1.4;\"\u003e\u003cstrong\u003eℹ️ Tip —\u003c\/strong\u003e If the total time is shorter, the grind is likely too coarse. If it's longer, the grind is likely too fine.\u003c\/div\u003e\n\u003c\/div\u003e\n\u003c\/div\u003e\n\u003c\/details\u003e\n\u003c\/div\u003e\n\u003c!-- ========= END SECTION 5 ========= --\u003e\u003csvg style=\"display: none;\"\u003e\n\u003cstyle\u003e\n  @keyframes v60PulsePhase {\n    0%   { transform: scale(1);    box-shadow: 0 0 0 0 rgba(200,169,126,.35); }\n    50%  { transform: scale(1.06); box-shadow: 0 0 0 10px rgba(200,169,126,0); }\n    100% { transform: scale(1);    box-shadow: 0 0 0 0 rgba(200,169,126,0); }\n  }\n  .v60-pulse {\n    animation: v60PulsePhase 700ms ease-out 1;\n    transform-origin: center;\n    will-change: transform;\n  }\n  @keyframes v60BlinkPill {\n    0%, 100% { opacity: 1; transform: scale(1); }\n    50%      { opacity: .22; transform: scale(1.03); }\n  }\n  .v60-pill-pour-active {\n    background: #ffe7b7 !important;\n    border: 2px solid #d2a44a !important;\n    color: #3b2a12 !important;\n    font-weight: 900 !important;\n    letter-spacing: .02em;\n    animation: v60BlinkPill 2500ms ease-in-out infinite;\n    box-shadow:\n      0 0 0 2px rgba(210,164,74,.18) inset,\n      0 10px 22px rgba(0,0,0,.12),\n      0 0 0 6px rgba(210,164,74,.10);\n  }\n  @media (prefers-reduced-motion: reduce) {\n    .v60-pill-pour-active { animation: none; }\n    .v60-pulse { animation: none; }\n  }\n\u003c\/style\u003e\n\u003cscript\u003e\n(function() {\n  var SUFFIX = '-kiangoi-en';\n  var END_AT = 165;\n  var phases = [\n    { key: 1, t: 0, pourLen: 10 },\n    { key: 2, t: 40, pourLen: 10 },\n    { key: 3, t: 80, pourLen: 10 },\n    { key: 4, t: 115, pourLen: 10 }\n  ];\n  var latte = {\n    cardBg:     '#f6f1ea',\n    cardBorder: '#c8a97e',\n    pillBg:     '#eadfce'\n  };\n  var details  = document.getElementById('v60Details'    + SUFFIX);\n  var startBtn = document.getElementById('v60StartBtn'   + SUFFIX);\n  var stopBtn  = document.getElementById('v60StopBtn'    + SUFFIX);\n  var timerEl  = document.getElementById('v60Timer'      + SUFFIX);\n  var statusEl = document.getElementById('v60WakeStatus' + SUFFIX);\n  var pills = {\n    1: document.getElementById('v60-pill-1' + SUFFIX),\n    2: document.getElementById('v60-pill-2' + SUFFIX),\n    3: document.getElementById('v60-pill-3' + SUFFIX),\n    4: document.getElementById('v60-pill-4' + SUFFIX)\n  };\n  var cards = {\n    1: document.getElementById('v60-card-1' + SUFFIX),\n    2: document.getElementById('v60-card-2' + SUFFIX),\n    3: document.getElementById('v60-card-3' + SUFFIX),\n    4: document.getElementById('v60-card-4' + SUFFIX)\n  };\n  function setCardActive(key) {\n    Object.keys(cards).forEach(function(k) {\n      var c = cards[k];\n      if (!c) return;\n      if (parseInt(k) === key) {\n        c.style.borderColor = latte.cardBorder;\n        c.style.background  = latte.cardBg;\n        c.style.boxShadow   = '0 0 0 2px rgba(200,169,126,.25) inset, 0 8px 22px rgba(200,169,126,.28)';\n      } else {\n        c.style.borderColor = 'rgba(0,0,0,.18)';\n        c.style.background  = 'transparent';\n        c.style.boxShadow   = 'none';\n      }\n    });\n  }\n  function setPillPhaseActive(key, doPulse) {\n    Object.keys(pills).forEach(function(k) {\n      var p = pills[k];\n      if (!p) return;\n      p.style.background  = 'rgba(0,0,0,.05)';\n      p.style.borderColor = 'rgba(0,0,0,.12)';\n      p.style.boxShadow   = 'none';\n      p.classList.remove('v60-pulse');\n    });\n    var pill = pills[key];\n    if (pill) {\n      pill.style.background  = latte.pillBg;\n      pill.style.borderColor = latte.cardBorder;\n      pill.style.boxShadow   = '0 0 0 2px rgba(200,169,126,.25) inset';\n      if (doPulse) {\n        pill.classList.remove('v60-pulse');\n        void pill.offsetWidth;\n        pill.classList.add('v60-pulse');\n      }\n    }\n  }\n  function resetPourPills() {\n    Object.values(pills).forEach(function(p) {\n      if (!p) return;\n      p.classList.remove('v60-pill-pour-active');\n    });\n  }\n  function setPourPillActive(key) {\n    resetPourPills();\n    if (!key) return;\n    var pill = pills[key];\n    if (pill) pill.classList.add('v60-pill-pour-active');\n  }\n  function clearAll() {\n    Object.values(cards).forEach(function(c) {\n      if (!c) return;\n      c.style.borderColor = 'rgba(0,0,0,.18)';\n      c.style.background  = 'transparent';\n      c.style.boxShadow   = 'none';\n    });\n    Object.values(pills).forEach(function(p) {\n      if (!p) return;\n      p.style.background  = 'rgba(0,0,0,.05)';\n      p.style.borderColor = 'rgba(0,0,0,.12)';\n      p.style.boxShadow   = 'none';\n      p.classList.remove('v60-pulse');\n      p.classList.remove('v60-pill-pour-active');\n    });\n  }\n  var wakeLock  = null;\n  var startTime = null;\n  var rafId     = null;\n  var lastPhaseKey = null;\n  var lastPourKey  = null;\n  function fmt(sec) {\n    sec = Math.max(0, Math.floor(sec));\n    var m = Math.floor(sec \/ 60);\n    var s = sec % 60;\n    return m + ':' + (s \u0026lt; 10 ? '0' : '') + s;\n  }\n  function getCurrentPhaseKey(elapsed) {\n    var current = phases[0].key;\n    for (var i = 0; i \u0026lt; phases.length; i++) if (elapsed \u0026gt;= phases[i].t) current = phases[i].key;\n    return current;\n  }\n  function getPourKey(elapsed) {\n    for (var i = phases.length - 1; i \u0026gt;= 0; i--) {\n      var p = phases[i];\n      if (elapsed \u0026gt;= p.t \u0026amp;\u0026amp; elapsed \u0026lt; (p.t + p.pourLen)) return p.key;\n    }\n    return null;\n  }\n  function enableWakeLock() {\n    if (!('wakeLock' in navigator)) {\n      statusEl.textContent = '⚠️ Your browser doesn\\'t support the screen wake lock mode.';\n      return Promise.resolve();\n    }\n    return navigator.wakeLock.request('screen').then(function(wl) {\n      wakeLock = wl;\n      statusEl.textContent = '✅ Screen kept awake for the recipe.';\n      wakeLock.addEventListener('release', function() {\n        statusEl.textContent = 'ℹ️ Wake lock released.';\n      });\n    }).catch(function() {\n      statusEl.textContent = '⚠️ Unable to enable the screen wake lock.';\n      wakeLock = null;\n    });\n  }\n  function disableWakeLock() {\n    if (wakeLock) { wakeLock.release(); wakeLock = null; }\n  }\n  function setButtons(running) {\n    startBtn.disabled = running;\n    stopBtn.disabled  = !running;\n    stopBtn.style.opacity = running ? '1' : '.5';\n  }\n  function tick() {\n    var elapsed = (Date.now() - startTime) \/ 1000;\n    timerEl.textContent = fmt(elapsed);\n    var phaseKey = getCurrentPhaseKey(elapsed);\n    if (phaseKey !== lastPhaseKey) {\n      setCardActive(phaseKey);\n      setPillPhaseActive(phaseKey, lastPhaseKey !== null);\n      lastPhaseKey = phaseKey;\n    }\n    var pourKey = getPourKey(elapsed);\n    if (pourKey !== lastPourKey) {\n      setPourPillActive(pourKey);\n      lastPourKey = pourKey;\n    }\n    if (elapsed \u0026gt;= END_AT) { stopRecipe(true); return; }\n    rafId = requestAnimationFrame(tick);\n  }\n  function startRecipe() {\n    setButtons(true);\n    timerEl.textContent = '0:00';\n    lastPhaseKey = null;\n    lastPourKey  = null;\n    enableWakeLock().then(function() {\n      setCardActive(1);\n      setPillPhaseActive(1, false);\n      setPourPillActive(1);\n      lastPhaseKey = 1;\n      lastPourKey  = 1;\n      startTime = Date.now();\n      if (rafId) cancelAnimationFrame(rafId);\n      rafId = requestAnimationFrame(tick);\n    });\n  }\n  function stopRecipe(autoEnded) {\n    if (rafId) cancelAnimationFrame(rafId);\n    rafId     = null;\n    startTime = null;\n    disableWakeLock();\n    setButtons(false);\n    clearAll();\n    lastPhaseKey = null;\n    lastPourKey  = null;\n    if (autoEnded) {\n      statusEl.textContent = '✅ Recipe complete — screen released.';\n      timerEl.textContent  = fmt(END_AT);\n    } else {\n      statusEl.textContent = 'ℹ️ Recipe stopped — screen released.';\n    }\n  }\n  startBtn.addEventListener('click', startRecipe);\n  stopBtn.addEventListener('click', function() { stopRecipe(false); });\n  details.addEventListener('toggle', function() { if (!details.open) stopRecipe(false); });\n  document.addEventListener('visibilitychange', function() {\n    if (document.visibilityState === 'visible' \u0026amp;\u0026amp; startTime \u0026amp;\u0026amp; !wakeLock) enableWakeLock();\n  });\n})();\n\u003c\/script\u003e\n\u003c\/svg\u003e\n","brand":"ZAB","offers":[{"title":"250g","offer_id":53629325312309,"sku":"CAF-SIN-RUNG-250","price":32.0,"currency_code":"CAD","in_stock":true},{"title":"808g","offer_id":53629325345077,"sku":"CAF-SIN-RUNG-808","price":90.0,"currency_code":"CAD","in_stock":true}],"thumbnail_url":"\/\/cdn.shopify.com\/s\/files\/1\/2716\/1842\/files\/kiangoi-250g-new.jpg?v=1793544333","url":"https:\/\/zabcafe.com\/en\/products\/kenya-rungeto-kiangoi","provider":"Zab Café","version":"1.0","type":"link"}