{"product_id":"ethiopie-tariku","title":"ETHIOPIA - TARIKU","description":"\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;\"\u003eBLUEBERRY + CHERRY + DARK CHOCOLATE\u003c\/div\u003e\n\u003c\/div\u003e\n\u003c!-- ========= END SECTION 1 ========= --\u003e\n\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 style=\"width: 100%; border-collapse: collapse; background: transparent;\" cellspacing=\"1\" cellpadding=\"1\" border=\"3\"\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd style=\"width: 20%;\"\u003eORIGIN\u003c\/td\u003e\n\u003ctd\u003eOromia Region, West Arsi Zone, Nensebo District, Ethiopia\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003ePRODUCERS\u003c\/td\u003e\n\u003ctd\u003e593 smallholder producers\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eLOT MANAGER\u003c\/td\u003e\n\u003ctd\u003eTariku Kare\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eWASHING STATION\u003c\/td\u003e\n\u003ctd\u003eRafisa\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eVARIETY\u003c\/td\u003e\n\u003ctd\u003e74158, 74110, 74112\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003ePROCESS\u003c\/td\u003e\n\u003ctd\u003eNatural\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eALTITUDE\u003c\/td\u003e\n\u003ctd\u003e2000–2200 masl\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003ePARTNERS\u003c\/td\u003e\n\u003ctd\u003eCrop to Cup\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eVOLUME PURCHASED\u003c\/td\u003e\n\u003ctd\u003e5,400 kg\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eFOB\u003c\/td\u003e\n\u003ctd\u003e$4.35 USD\/lb\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eLANDED PRICE\u003c\/td\u003e\n\u003ctd\u003e$9.16 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 : COFFEE INFORMATION\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;\"\u003eCoffee Information\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;\"\u003eThis Ethiopian natural opens with a burst of wild blueberry and dark cherry. The fruitiness is grounded by layers of dark chocolate and an enveloping sweetness, with a silky texture and a long, lingering finish.\u003c\/p\u003e\n\u003cp style=\"margin: 0 0 12px 0;\"\u003eIn the heart of Nensebo, the Rafisa washing station works with nearly 600 small producers from the villages of Refisa, Roricho, Bulga, and Riripa. Located in the Oromia region, about 400 km south of Addis Ababa, this young coffee-growing area reaches elevations up to 2200 masl and is home to a mix of local and wild coffee varieties.\u003c\/p\u003e\n\u003cp style=\"margin: 0;\"\u003eBehind Rafisa is Tariku Kare. Born in Bombe, he began working in coffee at just 15 years old before managing several washing stations across the region. After years in the industry, he eventually opened his own station to export his coffees internationally. Today, Tariku is known for paying higher prices for ripe coffee cherries and for building long-term relationships with the producers who deliver to his washing stations.\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 4 : EXTRACTION PARAMETERS — ESPRESSO\n========================================================= --\u003e\n\u003cdiv style=\"width: 100%; margin: 0 auto;\"\u003e\n\u003cdetails style=\"border: 2px solid #000; border-radius: 12px; overflow: hidden; margin: 0 0 12px 0; background: rgba(255,255,255,0.5);\" open=\"\"\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.5 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 the cup\u003c\/td\u003e\n\u003ctd style=\"padding: 10px 0; text-align: right; border-bottom: 1px solid rgba(0,0,0,.2);\"\u003e34 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;\"\u003e32 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. Please consult your machine's manual to confirm your basket size.\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 style=\"border: 2px solid #000; border-radius: 12px; overflow: hidden; margin: 0 0 12px 0; background: rgba(255,255,255,0.5);\" open=\"\" id=\"v60Details-rafisa\"\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 93 °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 id=\"v60StartBtn-rafisa\" type=\"button\" 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;\"\u003eStart\u003c\/button\u003e \u003cbutton id=\"v60StopBtn-rafisa\" type=\"button\" disabled=\"disabled\" 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;\"\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 id=\"v60Timer-rafisa\" style=\"font-weight: 950; font-size: 28px; letter-spacing: .01em;\"\u003e0:00\u003c\/span\u003e\u003c\/div\u003e\n\u003cdiv id=\"v60WakeStatus-rafisa\" style=\"flex-basis: 100%; opacity: .6; font-size: 12px; line-height: 1.3; margin-top: 2px;\"\u003eℹ️ Press \"Start\" to keep your screen on.\u003c\/div\u003e\n\u003c\/div\u003e\n\u003cdiv style=\"margin-top: 8px; display: grid; gap: 10px;\"\u003e\n\u003cdiv id=\"v60-card-1-rafisa\" style=\"border: 1px solid rgba(0,0,0,.18); border-radius: 12px; padding: 10px 12px;\"\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 id=\"v60-pill-1-rafisa\" style=\"padding: 5px 9px; border-radius: 999px; background: rgba(0,0,0,.05); border: 1px solid rgba(0,0,0,.12);\"\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 40 g\u003c\/span\u003e\u003c\/div\u003e\n\u003c\/div\u003e\n\u003cdiv id=\"v60-card-2-rafisa\" style=\"border: 1px solid rgba(0,0,0,.18); border-radius: 12px; padding: 10px 12px;\"\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 id=\"v60-pill-2-rafisa\" style=\"padding: 5px 9px; border-radius: 999px; background: rgba(0,0,0,.05); border: 1px solid rgba(0,0,0,.12);\"\u003ePour for 0:30s\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 160 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+120 g\u003c\/span\u003e\u003c\/div\u003e\n\u003c\/div\u003e\n\u003cdiv id=\"v60-card-3-rafisa\" style=\"border: 1px solid rgba(0,0,0,.18); border-radius: 12px; padding: 10px 12px;\"\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 id=\"v60-pill-3-rafisa\" style=\"padding: 5px 9px; border-radius: 999px; background: rgba(0,0,0,.05); border: 1px solid rgba(0,0,0,.12);\"\u003ePour for 0:20s\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+65 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;\"\u003eTotal draw-down 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, your grind is likely too coarse. If it's longer, your 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 = '-rafisa';\n  var END_AT = 165;\n  var phases = [\n    { key: 1, t: 0,  pourLen: 10 },\n    { key: 2, t: 40, pourLen: 30 },\n    { key: 3, t: 80, pourLen: 20 }\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  };\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  };\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 does not support the screen wake lock feature.';\n      return Promise.resolve();\n    }\n    return navigator.wakeLock.request('screen').then(function(wl) {\n      wakeLock = wl;\n      statusEl.textContent = '✅ Screen kept on during the recipe.';\n      wakeLock.addEventListener('release', function() {\n        statusEl.textContent = 'ℹ️ Screen wake lock released.';\n      });\n    }).catch(function() {\n      statusEl.textContent = '⚠️ Unable to activate 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","brand":"ZAB","offers":[{"title":"300g","offer_id":52900988911925,"sku":"CAF-SIN-TARI-300","price":19.95,"currency_code":"EUR","in_stock":true},{"title":"808g","offer_id":52900988944693,"sku":"CAF-SIN-TARI-808","price":46.95,"currency_code":"EUR","in_stock":true},{"title":"2268g (5lbs)","offer_id":52900988977461,"sku":"CAF-SIN-TARI-2268","price":123.95,"currency_code":"EUR","in_stock":true},{"title":"100g","offer_id":52900989010229,"sku":"CAF-SIN-TARI-100","price":9.95,"currency_code":"EUR","in_stock":true},{"title":"Bucket - 5lbs (Livraison locale seulement)","offer_id":52900989042997,"sku":"CAF-SIN-TARI-BUCK-5","price":139.95,"currency_code":"EUR","in_stock":true},{"title":"Bucket - 15lbs (Livraison locale seulement)","offer_id":52900989075765,"sku":"CAF-SIN-TARI-BUCK-15","price":417.95,"currency_code":"EUR","in_stock":true}],"thumbnail_url":"\/\/cdn.shopify.com\/s\/files\/1\/2716\/1842\/files\/tariku-300g-new.webp?v=1780337070","url":"https:\/\/zabcafe.com\/en\/products\/ethiopie-tariku","provider":"Zab Café","version":"1.0","type":"link"}