{"title":"MEILLEURS VENDEURS","description":null,"products":[{"product_id":"colombie-huila-decafeine","title":"DECAF - COLOMBIA","description":"\u003cp\u003e \u003c\/p\u003e\n\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;\"\u003eTOFFEE + APRICOT + COLA SYRUP\u003c\/div\u003e\n\u003c\/div\u003e\n\u003c!-- ========= END SECTION 1 ========= --\u003e\n\n\u003cp\u003e \u003c\/p\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 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\u003eBuesaco Municipality, Nariño department, Colombia\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\u003eVARIETY\u003c\/td\u003e\n\u003ctd\u003eVaried\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003ePROCESS\u003c\/td\u003e\n\u003ctd\u003eWashed and decaffeinated with ethyl acetate\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eALTITUDE\u003c\/td\u003e\n\u003ctd\u003e2100 to 2400 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\u003e5600 kg\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eFOB\u003c\/td\u003e\n\u003ctd\u003e$4.20 USD\/lb\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eDELIVERED PRICE\u003c\/td\u003e\n\u003ctd\u003e$8.30 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\n\u003cp\u003e \u003c\/p\u003e\n\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;\"\u003eThis coffee offers a classic profile, with aromas of chocolate, cola syrup and toffee, and a lovely acidity reminiscent of apricot, enjoyable as both espresso and filter. It was decaffeinated with ethyl acetate, a solvent that can be derived from sugarcane. The process involves moistening the green coffee beans, bringing them into contact with the solvent, then rinsing them with steam and drying them. This method removes the caffeine while preserving much of the coffee’s aromas.\u003c\/p\u003e\n\u003cp style=\"margin: 0 0 12px 0;\"\u003eThe name of this coffee, Buesaco Jardines, means “Gardens of Buesaco,” a nod to the lush gardens surrounding the small coffee farms in this municipality perched in the Andes mountain range. The Jardines project was born from a collective desire to pool small harvests in order to create more consistent lots that are easier to manage and better able to highlight the character of the terroir.\u003c\/p\u003e\n\u003cp style=\"margin: 0;\"\u003eThis lot brings together several producers, including Aura Montánchez, a second-generation grower; Yovanny Pinchao of La Esperanza farm, the first in his family to start growing coffee in 2019; and Javier Martínez, a producer from Villa Moreno based in the village of El Cortijo.\u003c\/p\u003e\n\u003c\/div\u003e\n\u003c\/div\u003e\n\u003c!-- ========= END SECTION 3 ========= --\u003e\n\n\u003cp\u003e \u003c\/p\u003e\n\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);\"\u003e17.7 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);\"\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;\"\u003e28 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\n\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\n\u003cp\u003e \u003c\/p\u003e\n\n\u003c!-- =========================================================\n  SECTION 5: V60\n========================================================= --\u003e\n\u003cdiv style=\"width: 100%; margin: 0 auto;\"\u003e\n\u003cdetails id=\"v60Details-decafbuesaco-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:16\u003c\/div\u003e\n\u003cdiv style=\"margin-top: 4px; opacity: .7; font-size: 13px;\"\u003e15 g in – 240 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\n\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-decafbuesaco-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 type=\"button\" id=\"v60StopBtn-decafbuesaco-en\"\u003eStop\u003c\/button\u003e\n\u003c\/div\u003e\n\u003cdiv style=\"display: flex; gap: 10px; align-items: baseline; line-height: 1;\"\u003e\n\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-decafbuesaco-en\"\u003e0:00\u003c\/span\u003e\n\u003c\/div\u003e\n\u003cdiv style=\"flex-basis: 100%; opacity: .6; font-size: 12px; line-height: 1.3; margin-top: 2px;\" id=\"v60WakeStatus-decafbuesaco-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-decafbuesaco-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\n\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-decafbuesaco-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\n\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-decafbuesaco-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\n\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-decafbuesaco-en\"\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 150 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+100 g\u003c\/span\u003e\n\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-decafbuesaco-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\n\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-decafbuesaco-en\"\u003ePour for 0:25s\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 240 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+90 g\u003c\/span\u003e\n\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:15\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\n\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 = '-decafbuesaco-en';\n  var END_AT = 135;\n  var phases = [\n    { key: 1, t: 0,  pourLen: 10 },\n    { key: 2, t: 40, pourLen: 30 },\n    { key: 3, t: 80, pourLen: 25 }\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 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","brand":"ZAB","offers":[{"title":"300g","offer_id":10369779662891,"sku":"CAF-SIN-DECA-300","price":26.5,"currency_code":"CAD","in_stock":true},{"title":"808g","offer_id":32797185572939,"sku":"CAF-SIN-DECA-808","price":64.5,"currency_code":"CAD","in_stock":true},{"title":"2268g (5lbs)","offer_id":32797183901771,"sku":"CAF-SIN-DECA-2268","price":165.0,"currency_code":"CAD","in_stock":true},{"title":"100g","offer_id":51434155704629,"sku":"CAF-SIN-DECA-100","price":13.75,"currency_code":"CAD","in_stock":true},{"title":"Bucket - 5lbs (Livraison locale seulement)","offer_id":52564443463989,"sku":"CAF-SIN-DECA-BUCK-5","price":190.0,"currency_code":"CAD","in_stock":true},{"title":"Bucket - 15lbs (Livraison locale seulement)","offer_id":52478907842869,"sku":"CAF-SIN-DECA-BUCK-15","price":520.0,"currency_code":"CAD","in_stock":true}],"thumbnail_url":"\/\/cdn.shopify.com\/s\/files\/1\/2716\/1842\/files\/decaf-buesaco-300g.jpg?v=1793313023"},{"product_id":"joyeux-roger","title":"BRAZIL - JOYEUX ROGER","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;\"\u003eBROWNIE + HAZELNUT + CREAMY\u003c\/div\u003e\n\u003c\/div\u003e\n\u003c!-- ========= FIN SECTION 1 ========= --\u003e\n\u003cp\u003e \u003c\/p\u003e\n\u003c!-- =========================================================\n  SECTION CAROUSEL : IMAGES\n========================================================= --\u003e\n\u003cdiv id=\"carousel-sancoffee\" style=\"position: relative; width: 100%; padding-bottom: 33.33%; height: 0; overflow: hidden; border-radius: 8px;\"\u003e\n\u003cimg class=\"carousel-img-sancoffee\" src=\"https:\/\/cdn.shopify.com\/s\/files\/1\/2716\/1842\/files\/San-Coffee-image-groupe.jpg?v=1781785600\" alt=\"Sancoffee - group\" style=\"position: absolute; top: 0; left: 0; width: 100%; height: 100%; object-fit: cover; border-radius: 8px; opacity: 1; transition: opacity .6s ease;\"\u003e\n\u003cimg class=\"carousel-img-sancoffee\" src=\"https:\/\/cdn.shopify.com\/s\/files\/1\/2716\/1842\/files\/San-Coffee-image-warehouse.jpg?v=1781785600\" alt=\"Sancoffee - warehouse\" style=\"position: absolute; top: 0; left: 0; width: 100%; height: 100%; object-fit: cover; border-radius: 8px; opacity: 0; transition: opacity .6s ease;\"\u003e\n\u003cimg class=\"carousel-img-sancoffee\" src=\"https:\/\/cdn.shopify.com\/s\/files\/1\/2716\/1842\/files\/San-Coffee-image-ferme.jpg?v=1781785600\" alt=\"Sancoffee - farm\" style=\"position: absolute; top: 0; left: 0; width: 100%; height: 100%; object-fit: cover; border-radius: 8px; opacity: 0; transition: opacity .6s ease;\"\u003e\n\n\u003cbutton type=\"button\" id=\"carousel-prev-sancoffee\" aria-label=\"Previous image\" style=\"position: absolute; top: 50%; left: 8px; transform: translateY(-50%); z-index: 3; cursor: pointer; border: none; background: rgba(0,0,0,.25); color: #fff; font-weight: 400; width: 28px; height: 28px; border-radius: 999px; font-size: 15px; line-height: 1; display: flex; align-items: center; justify-content: center; opacity: .55;\"\u003e‹\u003c\/button\u003e\n\u003cbutton type=\"button\" id=\"carousel-next-sancoffee\" aria-label=\"Next image\" style=\"position: absolute; top: 50%; right: 8px; transform: translateY(-50%); z-index: 3; cursor: pointer; border: none; background: rgba(0,0,0,.25); color: #fff; font-weight: 400; width: 28px; height: 28px; border-radius: 999px; font-size: 15px; line-height: 1; display: flex; align-items: center; justify-content: center; opacity: .55;\"\u003e›\u003c\/button\u003e\n\n\u003cdiv id=\"carousel-dots-sancoffee\" style=\"position: absolute; bottom: 10px; left: 0; right: 0; z-index: 3; display: flex; gap: 8px; align-items: center; justify-content: center;\"\u003e\n\u003cspan class=\"carousel-dot-sancoffee\" data-i=\"0\" style=\"cursor: pointer; width: 10px; height: 10px; border-radius: 999px; background: #fff; border: 1px solid rgba(0,0,0,.4); opacity: 1;\"\u003e\u003c\/span\u003e\n\u003cspan class=\"carousel-dot-sancoffee\" data-i=\"1\" style=\"cursor: pointer; width: 10px; height: 10px; border-radius: 999px; background: #fff; border: 1px solid rgba(0,0,0,.4); opacity: .5;\"\u003e\u003c\/span\u003e\n\u003cspan class=\"carousel-dot-sancoffee\" data-i=\"2\" style=\"cursor: pointer; width: 10px; height: 10px; border-radius: 999px; background: #fff; border: 1px solid rgba(0,0,0,.4); opacity: .5;\"\u003e\u003c\/span\u003e\n\u003c\/div\u003e\n\u003c\/div\u003e\n\u003c!-- ========= FIN SECTION CAROUSEL ========= --\u003e\n\u003cp\u003e \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 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\u003eCampo das Vertentes, Minas Gerais, Brazil\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003ePRODUCERS\u003c\/td\u003e\n\u003ctd\u003eSeveral producers from Sancoffee\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eVARIETIES\u003c\/td\u003e\n\u003ctd\u003eYellow Catucai, Mundo Novo, Red Catuai, Topázio\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\u003e900 – 1200 m\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\u003e96,600 kg\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eFOB\u003c\/td\u003e\n\u003ctd\u003e$2.40 USD\/LB\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eDELIVERED PRICE\u003c\/td\u003e\n\u003ctd\u003e$4.55 CAD\/LB\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eRELATIONSHIP\u003c\/td\u003e\n\u003ctd\u003e2 years\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003c\/tbody\u003e\n\u003c\/table\u003e\n\u003cp style=\"margin: 6px 0 0 0; font-size: 13px;\"\u003e \u003c\/p\u003e\n\u003c\/div\u003e\n\u003c!-- ========= FIN SECTION 2 ========= --\u003e\n\u003cp\u003e \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; text-align: justify;\"\u003eSancoffee is an independent, B-Corp certified cooperative based in the Campo das Vertentes region of Minas Gerais, Brazil. Sancoffee brings together 20 member farms and supports 600 smallholder producers, sharing a collective vision rooted in sustainability, quality, and community impact. The cooperative proudly blends its rich coffee-growing heritage, dating back to 1860, with modern initiatives that champion environmental preservation and social progress. To learn more, visit their \u003ca rel=\"noopener\" href=\"https:\/\/sancoffee.com\/\" target=\"_blank\"\u003e\u003cstrong\u003ewebsite\u003c\/strong\u003e\u003c\/a\u003e.\u003c\/p\u003e\n\u003cp style=\"margin: 0 0 12px 0; text-align: justify;\"\u003eCooperative programs such as Beyond Borders provide smallholder producers with tools and technical support, helping them gain recognition and add value to their work. Through educational workshops and youth training, Sancoffee invests in the future of its communities, fostering sustainable growth and opportunities for all.\u003c\/p\u003e\n\u003cp style=\"margin: 0 0 16px 0; text-align: justify;\"\u003eSancoffee achieved carbon neutrality in 2020, becoming a pioneer in environmentally responsible coffee production. Their efforts include restoring biodiversity, planting native trees, and conducting research to reduce the carbon footprint at the farm level.\u003c\/p\u003e\n\u003cdiv class=\"logos-sancoffee\" style=\"display: flex; gap: 20px; align-items: center; justify-content: space-between; flex-wrap: wrap; padding-top: 16px; border-top: 1px solid rgba(0,0,0,.12);\"\u003e\n\u003ca rel=\"noopener\" href=\"https:\/\/sancoffee.com\/\" target=\"_blank\" style=\"display: inline-block;\"\u003e\n\u003cimg src=\"https:\/\/cdn.shopify.com\/s\/files\/1\/2716\/1842\/files\/san_coffee_logo.svg?v=1781786545\" alt=\"Sancoffee\" style=\"height: 80px; width: auto;\"\u003e\n\u003c\/a\u003e\n\u003cdiv class=\"logos-certs-sancoffee\" style=\"display: flex; gap: 20px; align-items: center; flex-wrap: wrap;\"\u003e\n\u003cimg src=\"https:\/\/cdn.shopify.com\/s\/files\/1\/2716\/1842\/files\/bcorp-logo.webp?v=1781785759\" alt=\"B-Corp Certification\" style=\"height: 80px; width: auto;\"\u003e\n\u003cimg src=\"https:\/\/cdn.shopify.com\/s\/files\/1\/2716\/1842\/files\/For-Profit-Sus-2024-Stone_white.webp?v=1781785759\" alt=\"Sustainability Award 2024\" style=\"height: 80px; width: auto;\"\u003e\n\u003c\/div\u003e\n\u003c\/div\u003e\n\u003c\/div\u003e\n\u003c\/div\u003e\n\u003c!-- ========= FIN SECTION 3 ========= --\u003e\n\u003cp\u003e \u003c\/p\u003e\n\u003c!-- =========================================================\n  SECTION 5 : WHOLESALE\n========================================================= --\u003e\n\u003cdiv style=\"width: 100%; margin: 0 auto 12px auto;\"\u003e\n\u003cdiv style=\"border: 2px solid #000; border-radius: 12px; overflow: hidden;\"\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;\"\u003eWholesale\u003c\/div\u003e\n\u003cdiv style=\"padding: 16px 14px; background: transparent;\"\u003e\n\u003cp style=\"margin: 0;\"\u003eWant to order two 5 lb bags or more? Visit our \u003ca rel=\"noopener\" href=\"https:\/\/zabcafe.com\/en\/products\/bresil-joyeux-roger-en-gros\" target=\"_blank\"\u003e\u003cstrong\u003eWHOLESALE\u003c\/strong\u003e\u003c\/a\u003e section to take advantage of volume discounts!\u003c\/p\u003e\n\u003c\/div\u003e\n\u003c\/div\u003e\n\u003c\/div\u003e\n\u003c!-- ========= FIN SECTION 5 ========= --\u003e\n\u003cp\u003e \u003c\/p\u003e\n\u003c!-- =========================================================\n  SECTION 4 : EXTRACTION PARAMETERS — ESPRESSO\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: transparent;\"\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; background: transparent;\"\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);\"\u003e30 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\n\u003cstrong\u003eNote —\u003c\/strong\u003e\u003cspan\u003e Recipe optimized for an \u003c\/span\u003e\u003cstrong\u003e18 g\u003c\/strong\u003e\u003cspan\u003e basket. Adjust the grind slightly to reach a 32-second extraction.\u003c\/span\u003e\n\u003c\/div\u003e\n\u003c\/div\u003e\n\u003c\/details\u003e\n\u003c\/div\u003e\n\u003c!-- ========= FIN SECTION 4 ========= --\u003e\n\u003cp\u003e \u003c\/p\u003e\n\u003c!-- =========================================================\n  SECTION 6 : FELLOW AIDEN PARAMETERS\n========================================================= --\u003e\n\u003cdiv style=\"width: 100%; margin: 0 auto 12px auto;\"\u003e\n\u003cdiv style=\"border: 2px solid #000; border-radius: 12px; overflow: hidden;\"\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;\"\u003eSettings for the Fellow Aiden\u003c\/div\u003e\n\u003cdiv style=\"padding: 16px 14px; background: transparent;\"\u003e\n\u003cp style=\"margin: 0;\"\u003e\u003ca rel=\"noopener\" href=\"https:\/\/brew.link\/p\/lYvn\" target=\"_blank\"\u003eDownload the Joyeux Roger profile for the Fellow Aiden machine!\u003c\/a\u003e\u003c\/p\u003e\n\u003c\/div\u003e\n\u003c\/div\u003e\n\u003c\/div\u003e\n\u003c!-- ========= FIN SECTION 6 ========= --\u003e\n\n\u003cp\u003e \u003c\/p\u003e\n\n\u003c!-- =========================================================\n  SECTION 7 : V60\n========================================================= --\u003e\n\n\u003cdiv style=\"width: 100%; margin: 0 auto;\"\u003e\n  \u003cdetails id=\"v60Details-joyeuxroger\" 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\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\n\u003cstrong\u003eWater temperature:\u003c\/strong\u003e 85 °C\u003c\/div\u003e\n      \u003c\/div\u003e\n\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\n          \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-joyeuxroger\"\u003eStart\u003c\/button\u003e\n          \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 type=\"button\" id=\"v60StopBtn-joyeuxroger\"\u003eStop\u003c\/button\u003e\n        \u003c\/div\u003e\n        \u003cdiv style=\"display: flex; gap: 10px; align-items: baseline; line-height: 1;\"\u003e\n          \u003cspan style=\"opacity: .70; font-size: 12px; font-weight: 800; text-transform: uppercase; letter-spacing: .04em;\"\u003eTimer\u003c\/span\u003e\n          \u003cspan style=\"font-weight: 950; font-size: 28px; letter-spacing: .01em;\" id=\"v60Timer-joyeuxroger\"\u003e0:00\u003c\/span\u003e\n        \u003c\/div\u003e\n        \u003cdiv style=\"flex-basis: 100%; opacity: .6; font-size: 12px; line-height: 1.3; margin-top: 2px;\" id=\"v60WakeStatus-joyeuxroger\"\u003eℹ️ Tap \"Start\" to keep the screen awake.\u003c\/div\u003e\n      \u003c\/div\u003e\n\n      \u003cdiv style=\"margin-top: 8px; display: grid; gap: 10px;\"\u003e\n\n        \u003cdiv style=\"border: 1px solid rgba(0,0,0,.18); border-radius: 12px; padding: 10px 12px;\" id=\"v60-card-1-joyeuxroger\"\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\n            \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-joyeuxroger\"\u003ePour for 0:10s\u003c\/span\u003e\n            \u003cspan style=\"padding: 5px 9px; border-radius: 999px; background: rgba(0,0,0,.05); border: 1px solid rgba(0,0,0,.12);\"\u003eTotal 35 g\u003c\/span\u003e\n          \u003c\/div\u003e\n        \u003c\/div\u003e\n\n        \u003cdiv style=\"border: 1px solid rgba(0,0,0,.18); border-radius: 12px; padding: 10px 12px;\" id=\"v60-card-2-joyeuxroger\"\u003e\n          \u003cdiv style=\"display: flex; gap: 10px; align-items: baseline; margin-bottom: 6px;\"\u003e\n            \u003cdiv style=\"font-weight: 900;\"\u003e0:30\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\n            \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-joyeuxroger\"\u003ePour for 0:30s\u003c\/span\u003e\n            \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\n            \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+135 g\u003c\/span\u003e\n          \u003c\/div\u003e\n        \u003c\/div\u003e\n\n        \u003cdiv style=\"border: 1px solid rgba(0,0,0,.18); border-radius: 12px; padding: 10px 12px;\" id=\"v60-card-3-joyeuxroger\"\u003e\n          \u003cdiv style=\"display: flex; gap: 10px; align-items: baseline; margin-bottom: 6px;\"\u003e\n            \u003cdiv style=\"font-weight: 900;\"\u003e1:30\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\n            \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-joyeuxroger\"\u003ePour for 0:15s\u003c\/span\u003e\n            \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\n            \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\n          \u003c\/div\u003e\n        \u003c\/div\u003e\n\n      \u003c\/div\u003e\n\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;\"\u003e3:00\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\n          \u003cstrong\u003eℹ️ Tip —\u003c\/strong\u003e If the total time is shorter, the grind is probably too coarse. If it's longer, the grind is probably too fine.\n        \u003c\/div\u003e\n      \u003c\/div\u003e\n    \u003c\/div\u003e\n  \u003c\/details\u003e\n\u003c\/div\u003e\n\n\u003c!-- ========= FIN SECTION 7 ========= --\u003e\n\n\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  @media (max-width: 600px) {\n    .logos-sancoffee { justify-content: center !important; gap: 16px !important; }\n    .logos-sancoffee \u003e a { width: 100% !important; text-align: center !important; }\n    .logos-certs-sancoffee { width: 100% !important; justify-content: center !important; }\n  }\n\u003c\/style\u003e\n\u003cscript\u003e\n(function() {\n  \/* ===== CARROUSEL ===== *\/\n  var cSuffix = '-sancoffee';\n  var cImgs  = document.querySelectorAll('.carousel-img' + cSuffix);\n  var cDots  = document.querySelectorAll('.carousel-dot' + cSuffix);\n  var cPrev  = document.getElementById('carousel-prev' + cSuffix);\n  var cNext  = document.getElementById('carousel-next' + cSuffix);\n  var cIndex = 0;\n  var cTimer = null;\n  function cShow(i) {\n    cIndex = (i + cImgs.length) % cImgs.length;\n    for (var k = 0; k \u003c cImgs.length; k++) cImgs[k].style.opacity = (k === cIndex) ? '1' : '0';\n    for (var d = 0; d \u003c cDots.length; d++) cDots[d].style.opacity = (d === cIndex) ? '1' : '.5';\n  }\n  function cStart() { cStop(); cTimer = setInterval(function() { cShow(cIndex + 1); }, 5000); }\n  function cStop() { if (cTimer) { clearInterval(cTimer); cTimer = null; } }\n  if (cPrev) cPrev.addEventListener('click', function() { cShow(cIndex - 1); cStart(); });\n  if (cNext) cNext.addEventListener('click', function() { cShow(cIndex + 1); cStart(); });\n  for (var dd = 0; dd \u003c cDots.length; dd++) {\n    (function(node) {\n      node.addEventListener('click', function() { cShow(parseInt(node.getAttribute('data-i'), 10)); cStart(); });\n    })(cDots[dd]);\n  }\n  cShow(0);\n  cStart();\n\n  \/* ===== TIMER V60 ===== *\/\n  var SUFFIX = '-joyeuxroger';\n  var END_AT = 180;\n  var phases = [\n    { key: 1, t: 0,  pourLen: 10 },\n    { key: 2, t: 30, pourLen: 30 },\n    { key: 3, t: 90, pourLen: 15 }\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 \u003c 10 ? '0' : '') + s;\n  }\n  function getCurrentPhaseKey(elapsed) {\n    var current = phases[0].key;\n    for (var i = 0; i \u003c phases.length; i++) if (elapsed \u003e= phases[i].t) current = phases[i].key;\n    return current;\n  }\n  function getPourKey(elapsed) {\n    for (var i = phases.length - 1; i \u003e= 0; i--) {\n      var p = phases[i];\n      if (elapsed \u003e= p.t \u0026\u0026 elapsed \u003c (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 keep-screen-awake mode.';\n      return Promise.resolve();\n    }\n    return navigator.wakeLock.request('screen').then(function(wl) {\n      wakeLock = wl;\n      statusEl.textContent = '✅ Screen kept awake during the recipe.';\n      wakeLock.addEventListener('release', function() {\n        statusEl.textContent = 'ℹ️ Keep-screen-awake mode released.';\n      });\n    }).catch(function() {\n      statusEl.textContent = '⚠️ Unable to enable keep-screen-awake mode.';\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 \u003e= 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' \u0026\u0026 startTime \u0026\u0026 !wakeLock) enableWakeLock();\n  });\n})();\n\u003c\/script\u003e\n\u003c\/svg\u003e","brand":"ZAB","offers":[{"title":"300g","offer_id":15744685244459,"sku":"CAF-SIN-JOYE-300","price":22.0,"currency_code":"CAD","in_stock":true},{"title":"808g","offer_id":32176690364491,"sku":"CAF-SIN-JOYE-808","price":50.0,"currency_code":"CAD","in_stock":true},{"title":"2268g (5lbs)","offer_id":15853630717995,"sku":"CAF-SIN-JOYE-2268","price":123.0,"currency_code":"CAD","in_stock":true},{"title":"100g","offer_id":51434079519029,"sku":"CAF-SIN-JOYE-100","price":10.75,"currency_code":"CAD","in_stock":true},{"title":"Bucket - 5lbs (Livraison locale seulement)","offer_id":52569460638005,"sku":"CAF-SIN-JOYE-BUCK-5","price":148.0,"currency_code":"CAD","in_stock":true},{"title":"Bucket - 15lbs (Livraison locale seulement)","offer_id":52569460670773,"sku":"CAF-SIN-JOYE-BUCK-15","price":394.0,"currency_code":"CAD","in_stock":true}],"thumbnail_url":"\/\/cdn.shopify.com\/s\/files\/1\/2716\/1842\/files\/joyeux-roger-300g.jpg?v=1762137534"},{"product_id":"choix-du-torrefacteur-roasters-choice","title":"Roaster's Choice — Subscription Only","description":"\u003cp\u003e\u0026nbsp;\u003c\/p\u003e\n\u003c!-- =========================================================\n  SECTION 1 : ROASTER'S CHOICE\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;\"\u003e✦ Roaster's Choice ✦\u003c\/div\u003e\n\u003cdiv style=\"padding: 20px 16px; background: transparent;\"\u003e\n\u003cp style=\"margin: 0 0 16px 0; font-size: 16px; font-weight: bold; text-align: center; text-transform: uppercase; letter-spacing: .04em;\"\u003eLet our roaster pick what he wants you to discover!\u003c\/p\u003e\n\u003cdiv style=\"border-top: 2px solid #000; margin: 0 0 16px 0;\"\u003e\u003cbr\u003e\u003c\/div\u003e\n\u003cul style=\"margin: 0; padding: 0 0 0 20px; line-height: 2;\"\u003e\n\u003cli\u003e\u003cstrong\u003eAvailable as a monthly subscription only.\u003c\/strong\u003e\u003c\/li\u003e\n\u003cli\u003e\u003cstrong\u003eCoffee selection changes once a month.\u003c\/strong\u003e\u003c\/li\u003e\n\u003cli\u003e\u003cstrong\u003eIf you order multiple \"Roaster's Choice\" per month, you will receive different bags.\u003c\/strong\u003e\u003c\/li\u003e\n\u003c\/ul\u003e\n\u003c\/div\u003e\n\u003c\/div\u003e\n\u003c!-- ========= END SECTION 1 ========= --\u003e","brand":"ZAB","offers":[{"title":"300g","offer_id":30229889155115,"sku":"CAF-340-0013","price":24.5,"currency_code":"CAD","in_stock":true},{"title":"808g","offer_id":30229889220651,"sku":"CAF-2LB-0013","price":61.0,"currency_code":"CAD","in_stock":true},{"title":"2268g (5lbs)","offer_id":30229889187883,"sku":"CAF-5LB-0013","price":152.0,"currency_code":"CAD","in_stock":true}],"thumbnail_url":"\/\/cdn.shopify.com\/s\/files\/1\/2716\/1842\/files\/choix-300g_d5b1aa91-74db-40e5-8f84-ae76312e2b31.jpg?v=1756920101"},{"product_id":"brewmance-1","title":"BREWMANCE","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;\"\u003eFRUITY + CHOCOLATEY + CREAMY\u003c\/div\u003e\n\u003c\/div\u003e\n\u003c!-- ========= END SECTION 1 ========= --\u003e\n\u003cp\u003e\u0026nbsp;\u003c\/p\u003e\n\u003c!-- =========================================================\n  SECTION 2 : SOURCING (80\/20 blend)\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 — Joyeux Roger (80%)\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\u003eCampo das Vertentes, Minas Gerais, Brazil\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003ePRODUCERS\u003c\/td\u003e\n\u003ctd\u003eSeveral producers from Sancoffee\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eVARIETIES\u003c\/td\u003e\n\u003ctd\u003eYellow Catucai, Mundo Novo, Red Catuai, Topázio\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\u003e900 – 1200 m\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\u003e96,600 kg\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eFOB\u003c\/td\u003e\n\u003ctd\u003e$2.40 USD\/LB\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eDELIVERED PRICE\u003c\/td\u003e\n\u003ctd\u003e$4.55 CAD\/LB\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eRELATIONSHIP\u003c\/td\u003e\n\u003ctd\u003e2 years\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003c\/tbody\u003e\n\u003c\/table\u003e\n\u003cp style=\"margin: 6px 0 0 0; font-size: 13px;\"\u003e \u003c\/p\u003e\n\u003c\/div\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 — Tariku (20%)\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 \u003c\/p\u003e\n\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;\"\u003eThe \u003cem\u003eBREWMANCE\u003c\/em\u003e (\u003ca href=\"https:\/\/zabcafe.com\/en\/products\/joyeux-roger\" target=\"_blank\"\u003eJoyeux Roger\u003c\/a\u003e + \u003ca href=\"https:\/\/zabcafe.com\/en\/collections\/cafes\" target=\"_blank\" rel=\"noopener\"\u003eTariku\u003c\/a\u003e) is our blend combining the comfort of chocolate and nuts with the funky touch of ripe fruit. It's an everyday coffee, but with just enough fruity notes to spark curiosity.\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 5 : WHOLESALE\n========================================================= --\u003e\n\u003cdiv style=\"width: 100%; margin: 0 auto 12px auto;\"\u003e\n\u003cdiv style=\"border: 2px solid #000; border-radius: 12px; overflow: hidden;\"\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;\"\u003eWholesale\u003c\/div\u003e\n\u003cdiv style=\"padding: 16px 14px; background: transparent;\"\u003e\n\u003cp style=\"margin: 0;\"\u003eWant to order two 5 lb bags or more? Visit our \u003ca href=\"https:\/\/zabcafe.com\/en\/products\/brewmance-en-gros\" rel=\"noopener\" target=\"_blank\"\u003e\u003cstrong\u003eWHOLESALE\u003c\/strong\u003e\u003c\/a\u003e section to take advantage of volume discounts!\u003c\/p\u003e\n\u003c\/div\u003e\n\u003c\/div\u003e\n\u003c\/div\u003e\n\u003c!-- ========= END SECTION 5 ========= --\u003e\n\u003cp\u003e\u0026nbsp;\u003c\/p\u003e\n\u003c!-- =========================================================\n  SECTION 4 : ESPRESSO 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: transparent;\"\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; background: transparent;\"\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);\"\u003e31 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;\"\u003e33 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\u003cspan\u003e Recipe optimized for an \u003c\/span\u003e\u003cstrong\u003e18 g\u003c\/strong\u003e\u003cspan\u003e basket. Adjust the grind slightly to reach 32 seconds of extraction.\u003c\/span\u003e\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 6 : FELLOW AIDEN SETTINGS\n========================================================= --\u003e\n\u003cdiv style=\"width: 100%; margin: 0 auto 12px auto;\"\u003e\n\u003cdiv style=\"border: 2px solid #000; border-radius: 12px; overflow: hidden;\"\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;\"\u003eFellow Aiden Settings\u003c\/div\u003e\n\u003cdiv style=\"padding: 16px 14px; background: transparent;\"\u003e\n\u003cp style=\"margin: 0;\"\u003e\u003ca href=\"https:\/\/brew.link\/p\/2Cpn\" rel=\"noopener\" target=\"_blank\"\u003eDownload the Brewmance profile for the Fellow Aiden!\u003c\/a\u003e\u003c\/p\u003e\n\u003c\/div\u003e\n\u003c\/div\u003e\n\u003c\/div\u003e\n\u003c!-- ========= END SECTION 6 ========= --\u003e\n\u003cp\u003e\u0026nbsp;\u003c\/p\u003e\n\u003c!-- =========================================================\n  SECTION 7 : V60\n========================================================= --\u003e\n\u003cdiv style=\"width: 100%; margin: 0 auto;\"\u003e\n\u003cdetails id=\"v60Details-brewmance\" 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 88 °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-brewmance\"\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-brewmance\"\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-brewmance\"\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-brewmance\"\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 style=\"border: 1px solid rgba(0,0,0,.18); border-radius: 12px; padding: 10px 12px;\" id=\"v60-card-1-brewmance\"\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-brewmance\"\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 35 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-brewmance\"\u003e\n\u003cdiv style=\"display: flex; gap: 10px; align-items: baseline; margin-bottom: 6px;\"\u003e\n\u003cdiv style=\"font-weight: 900;\"\u003e0:30\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-brewmance\"\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 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+135 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-brewmance\"\u003e\n\u003cdiv style=\"display: flex; gap: 10px; align-items: baseline; margin-bottom: 6px;\"\u003e\n\u003cdiv style=\"font-weight: 900;\"\u003e1:30\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-brewmance\"\u003ePour for 0:15s\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;\"\u003e3:00\u003c\/div\u003e\n\u003cdiv style=\"font-weight: 900;\"\u003eTarget total 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ℹ️ \u003cstrong\u003eℹ️ Tip —\u003c\/strong\u003e If total time is shorter, your grind is likely too coarse. If it's longer, your grind is likely too fine. \u003c\/strong\u003e\u003c\/div\u003e\n\u003cstrong\u003e \u003c\/strong\u003e\u003c\/div\u003e\n\u003cstrong\u003e \u003c\/strong\u003e\u003c\/div\u003e\n\u003cstrong\u003e \u003c\/strong\u003e\u003c\/details\u003e\n\u003cstrong\u003e \u003c\/strong\u003e\u003c\/div\u003e\n\u003cp\u003e\u003cstrong\u003e \u003c!-- ========= END SECTION 7 ========= --\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 = '-brewmance';\n  var END_AT = 180;\n  var phases = [\n    { key: 1, t: 0,  pourLen: 10 },\n    { key: 2, t: 30, pourLen: 30 },\n    { key: 3, t: 90, pourLen: 15 }\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 screen wake lock.';\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 = '⚠️ Could not 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\u003c\/strong\u003e\u003c\/p\u003e","brand":"ZAB","offers":[{"title":"300g","offer_id":31773916430411,"sku":"CAF-BLE-BREW-300","price":23.0,"currency_code":"CAD","in_stock":true},{"title":"808g","offer_id":32176694984779,"sku":"CAF-BLE-BREW-808","price":56.0,"currency_code":"CAD","in_stock":true},{"title":"2268g (5lbs)","offer_id":31773916463179,"sku":"CAF-BLE-BREW-2268","price":135.0,"currency_code":"CAD","in_stock":true},{"title":"100g","offer_id":51434082009397,"sku":"CAF-BLE-BREW-100","price":13.0,"currency_code":"CAD","in_stock":true},{"title":"Bucket - 5lbs (Livraison locale seulement)","offer_id":52569815941429,"sku":"CAF-BLE-BREW-BUCK-5","price":160.0,"currency_code":"CAD","in_stock":true},{"title":"Bucket - 15lbs (Livraison locale seulement)","offer_id":52569815974197,"sku":"CAF-BLE-BREW-BUCK-15","price":430.0,"currency_code":"CAD","in_stock":true}],"thumbnail_url":"\/\/cdn.shopify.com\/s\/files\/1\/2716\/1842\/files\/brewmance-300g.jpg?v=1756855352"},{"product_id":"boite-cafe-introduction-zab","title":"Coffee Box - Zab Introduction","description":"\u003cp\u003e\u0026nbsp;\u003c\/p\u003e\n\u003c!-- =========================================================\n  SECTION 1 : BOX HEADER\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;\"\u003eIntro Box — 3 × 300 g\u003c\/div\u003e\n\u003cdiv style=\"padding: 16px 14px; font-size: 14px; line-height: 1.6; text-align: center; background: transparent;\"\u003e\n\u003cp style=\"margin: 0 0 10px 0;\"\u003eThis box lets you discover our best-selling coffees. Whether for your milk-based drinks or your filter coffee, it's your invitation to explore the Zab universe through our classics.\u003c\/p\u003e\n\u003cp style=\"margin: 0;\"\u003eAnd to spice up your daily routine, we challenge you to use a little less milk than you normally would. You might just discover surprising aromas that could change your coffee habits forever!\u003c\/p\u003e\n\u003c\/div\u003e\n\u003c\/div\u003e\n\u003c!-- ========= END SECTION 1 ========= --\u003e\n\u003cp\u003e\u0026nbsp;\u003c\/p\u003e\n\u003c!-- =========================================================\n  SECTION 2 : COFFEES INCLUDED\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;\"\u003eCoffees Included\u003c\/div\u003e\n\u003cdiv style=\"border: 2px solid #000; border-top: none; border-radius: 0 0 12px 12px; background: transparent; overflow: hidden;\"\u003e\u003c!-- Joyeux Roger --\u003e\n\u003cdiv style=\"padding: 14px 16px; border-bottom: 1px solid rgba(0,0,0,.12);\"\u003e\n\u003cdiv style=\"font-weight: 900; font-size: 20px; margin-bottom: 6px;\"\u003e\u003ca style=\"color: #000; text-decoration: underline;\" rel=\"noopener\" title=\"Joyeux Roger\" href=\"https:\/\/zabcafe.com\/en\/products\/joyeux-roger\" target=\"_blank\"\u003eJoyeux Roger\u003c\/a\u003e\u003cspan style=\"font-weight: 400; opacity: .45; font-size: 14px;\"\u003e | 300g\u003c\/span\u003e\u003c\/div\u003e\n\u003cdiv style=\"font-size: 11px; font-weight: bold; text-transform: uppercase; letter-spacing: .08em; opacity: .5; margin-bottom: 4px;\"\u003eTasting Notes\u003c\/div\u003e\n\u003cdiv style=\"font-size: 13px; font-weight: 800; text-transform: uppercase; letter-spacing: .04em; margin-bottom: 10px;\"\u003eBROWNIE + HAZELNUT + CREAMY\u003c\/div\u003e\n\u003cdiv style=\"font-size: 13px; line-height: 1.6; opacity: .8;\"\u003eOur classic, unbeatable Brazilian coffee delivers a balanced, sweet, comforting, and approachable cup. The result of a long-standing partnership and everyone's favourite coffee.\u003c\/div\u003e\n\u003c\/div\u003e\n\u003c!-- Bon Matin --\u003e\n\u003cdiv style=\"padding: 14px 16px; border-bottom: 1px solid rgba(0,0,0,.12);\"\u003e\n\u003cdiv style=\"font-weight: 900; font-size: 20px; margin-bottom: 6px;\"\u003e\u003ca style=\"color: #000; text-decoration: underline;\" rel=\"noopener\" title=\"Bon Matin\" href=\"https:\/\/zabcafe.com\/en\/products\/bon-matin\" target=\"_blank\"\u003eBon Matin\u003c\/a\u003e\u003cspan style=\"font-weight: 400; opacity: .45; font-size: 14px;\"\u003e | 300g\u003c\/span\u003e\u003c\/div\u003e\n\u003cdiv style=\"font-size: 11px; font-weight: bold; text-transform: uppercase; letter-spacing: .08em; opacity: .5; margin-bottom: 4px;\"\u003eTasting Notes\u003c\/div\u003e\n\u003cdiv style=\"font-size: 13px; font-weight: 800; text-transform: uppercase; letter-spacing: .04em; margin-bottom: 10px;\"\u003eTOASTED PECAN + DARK CHOCOLATE + BUTTERSCOTCH\u003c\/div\u003e\n\u003cdiv style=\"font-size: 13px; line-height: 1.6; opacity: .8;\"\u003eOur take on a dark roast (Brazilian Joyeux Roger), highlighting a creamy texture and bold flavour — perfect with milk. It's our nostalgic coffee with a beautiful bitterness and moderate acidity. A true wake-up call in your cup!\u003c\/div\u003e\n\u003c\/div\u003e\n\u003c!-- Brewmance --\u003e\n\u003cdiv style=\"padding: 14px 16px;\"\u003e\n\u003cdiv style=\"font-weight: 900; font-size: 20px; margin-bottom: 6px;\"\u003e\u003ca style=\"color: #000; text-decoration: underline;\" rel=\"noopener\" title=\"Brewmance\" href=\"https:\/\/zabcafe.com\/en\/products\/brewmance-1\" target=\"_blank\"\u003eBrewmance\u003c\/a\u003e\u003cspan style=\"font-weight: 400; opacity: .45; font-size: 14px;\"\u003e | 300g\u003c\/span\u003e\u003c\/div\u003e\n\u003cdiv style=\"font-size: 11px; font-weight: bold; text-transform: uppercase; letter-spacing: .08em; opacity: .5; margin-bottom: 4px;\"\u003eTasting Notes\u003c\/div\u003e\n\u003cdiv style=\"font-size: 13px; font-weight: 800; text-transform: uppercase; letter-spacing: .04em; margin-bottom: 10px;\"\u003eFRUITY + CHOCOLATY + CREAMY\u003c\/div\u003e\n\u003cdiv style=\"font-size: 13px; line-height: 1.6; opacity: .8;\"\u003eBrewmance (Brazilian Joyeux Roger + Ethiopian Tariku) is our blend that combines the comfort of chocolate and nuts with the funky touch of ripe fruit. It's an everyday coffee, but with just enough fruity notes to spark your curiosity.\u003c\/div\u003e\n\u003c\/div\u003e\n\u003c\/div\u003e\n\u003c\/div\u003e\n\u003c!-- ========= END SECTION 2 ========= --\u003e\n\u003cp\u003e\u0026nbsp;\u003c\/p\u003e","brand":"ZAB","offers":[{"title":"Default Title","offer_id":32018737102923,"sku":"CAF-BOI-TORR-INTR","price":63.25,"currency_code":"CAD","in_stock":true}],"thumbnail_url":"\/\/cdn.shopify.com\/s\/files\/1\/2716\/1842\/files\/boites-classique-fermee_53343e76-9ff0-4122-9927-234ca5918156.jpg?v=1756855653"},{"product_id":"boite-decouvertre-filtre-pour-over-chemex","title":"Coffee Box - Roaster's Choice","description":"\u003cp\u003e \u003c\/p\u003e\n\n\u003c!-- =========================================================\n  SECTION 1 : BOX HEADER\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;\"\u003eRoaster's Choice Box — 3 × 300 g\u003c\/div\u003e\n  \u003cdiv style=\"padding: 16px 14px; font-size: 14px; line-height: 1.6; text-align: center; background: transparent;\"\u003e\n    \u003cp style=\"margin: 0 0 10px 0;\"\u003eThis box lets you discover our current favourite coffees. We'll admit it — we're obsessed with coffee. Whether as a filter, manual brew, or milk-based drink, you'll uncover the unique character of each terroir!\u003c\/p\u003e\n    \u003cp style=\"margin: 0;\"\u003eNote: Some coffees in this box may offer a different experience when paired with milk. If you prefer more classic drinks, this box may not be the right fit for you.\u003c\/p\u003e\n  \u003c\/div\u003e\n\u003c\/div\u003e\n\u003c!-- ========= END SECTION 1 ========= --\u003e\n\n\u003cp\u003e \u003c\/p\u003e\n\n\u003c!-- =========================================================\n  BOTTOM NOTE\n========================================================= --\u003e\n\u003cdiv style=\"padding: 10px 14px; 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.5;\"\u003e\n  \u003cstrong\u003eNote —\u003c\/strong\u003e The box contains 3 bags (300g) selected by the roaster. The box does not include decaffeinated coffee and it is not possible to request a specific coffee. To choose your coffees, please order them individually.\n\u003c\/div\u003e\n\n\u003cp\u003e \u003c\/p\u003e","brand":"ZAB","offers":[{"title":"Default Title","offer_id":32018737856587,"sku":"CAF-BOI-TORR-CHOI","price":73.25,"currency_code":"CAD","in_stock":true}],"thumbnail_url":"\/\/cdn.shopify.com\/s\/files\/1\/2716\/1842\/files\/boites-choix-du-torrefacteur-fermee.jpg?v=1756855415"},{"product_id":"bon-matin","title":"BON MATIN","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;\"\u003eTOASTED PECAN + DARK CHOCOLATE + BUTTERSCOTCH\u003c\/div\u003e\n\u003c\/div\u003e\n\u003c!-- ========= FIN SECTION 1 ========= --\u003e\n\u003cp\u003e\u0026nbsp;\u003c\/p\u003e\n\u003c!-- =========================================================\n  SECTION CAROUSEL : IMAGES\n========================================================= --\u003e\n\u003cdiv style=\"position: relative; width: 100%; padding-bottom: 33.33%; height: 0; overflow: hidden; border-radius: 8px;\" id=\"carousel-sancoffee\"\u003e\u003cimg style=\"position: absolute; top: 0; left: 0; width: 100%; height: 100%; object-fit: cover; border-radius: 8px; opacity: 1; transition: opacity .6s ease;\" alt=\"Sancoffee - group\" src=\"https:\/\/cdn.shopify.com\/s\/files\/1\/2716\/1842\/files\/San-Coffee-image-groupe.jpg?v=1781785600\" class=\"carousel-img-sancoffee\"\u003e \u003cimg style=\"position: absolute; top: 0; left: 0; width: 100%; height: 100%; object-fit: cover; border-radius: 8px; opacity: 0; transition: opacity .6s ease;\" alt=\"Sancoffee - warehouse\" src=\"https:\/\/cdn.shopify.com\/s\/files\/1\/2716\/1842\/files\/San-Coffee-image-warehouse.jpg?v=1781785600\" class=\"carousel-img-sancoffee\"\u003e \u003cimg style=\"position: absolute; top: 0; left: 0; width: 100%; height: 100%; object-fit: cover; border-radius: 8px; opacity: 0; transition: opacity .6s ease;\" alt=\"Sancoffee - farm\" src=\"https:\/\/cdn.shopify.com\/s\/files\/1\/2716\/1842\/files\/San-Coffee-image-ferme.jpg?v=1781785600\" class=\"carousel-img-sancoffee\"\u003e \u003cbutton style=\"position: absolute; top: 50%; left: 8px; transform: translateY(-50%); z-index: 3; cursor: pointer; border: none; background: rgba(0,0,0,.25); color: #fff; font-weight: 400; width: 28px; height: 28px; border-radius: 999px; font-size: 15px; line-height: 1; display: flex; align-items: center; justify-content: center; opacity: .55;\" aria-label=\"Previous image\" id=\"carousel-prev-sancoffee\" type=\"button\"\u003e‹\u003c\/button\u003e \u003cbutton style=\"position: absolute; top: 50%; right: 8px; transform: translateY(-50%); z-index: 3; cursor: pointer; border: none; background: rgba(0,0,0,.25); color: #fff; font-weight: 400; width: 28px; height: 28px; border-radius: 999px; font-size: 15px; line-height: 1; display: flex; align-items: center; justify-content: center; opacity: .55;\" aria-label=\"Next image\" id=\"carousel-next-sancoffee\" type=\"button\"\u003e›\u003c\/button\u003e\n\u003cdiv style=\"position: absolute; bottom: 10px; left: 0; right: 0; z-index: 3; display: flex; gap: 8px; align-items: center; justify-content: center;\" id=\"carousel-dots-sancoffee\"\u003e\u003cspan style=\"cursor: pointer; width: 10px; height: 10px; border-radius: 999px; background: #fff; border: 1px solid rgba(0,0,0,.4); opacity: 1;\" data-i=\"0\" class=\"carousel-dot-sancoffee\"\u003e\u003c\/span\u003e \u003cspan style=\"cursor: pointer; width: 10px; height: 10px; border-radius: 999px; background: #fff; border: 1px solid rgba(0,0,0,.4); opacity: .5;\" data-i=\"1\" class=\"carousel-dot-sancoffee\"\u003e\u003c\/span\u003e \u003cspan style=\"cursor: pointer; width: 10px; height: 10px; border-radius: 999px; background: #fff; border: 1px solid rgba(0,0,0,.4); opacity: .5;\" data-i=\"2\" class=\"carousel-dot-sancoffee\"\u003e\u003c\/span\u003e\u003c\/div\u003e\n\u003c\/div\u003e\n\u003c!-- ========= FIN SECTION CAROUSEL ========= --\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\u003eCampo das Vertentes, Minas Gerais, Brazil\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003ePRODUCERS\u003c\/td\u003e\n\u003ctd\u003eSeveral producers from Sancoffee\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eVARIETIES\u003c\/td\u003e\n\u003ctd\u003eYellow Catucai, Mundo Novo, Red Catuai, Topázio\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\u003e900 – 1200 m\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\u003e96,600 kg\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eFOB\u003c\/td\u003e\n\u003ctd\u003e$2.40 USD\/LB\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eDELIVERED PRICE\u003c\/td\u003e\n\u003ctd\u003e$4.55 CAD\/LB\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eRELATIONSHIP\u003c\/td\u003e\n\u003ctd\u003e2 years\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003c\/tbody\u003e\n\u003c\/table\u003e\n\u003cp style=\"margin: 6px 0 0 0; font-size: 13px;\"\u003e\u0026nbsp;\u003c\/p\u003e\n\u003c\/div\u003e\n\u003c!-- ========= FIN 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; text-align: justify;\"\u003eBon Matin is our Joyeux Roger, but with a slightly longer roast. The caramelization of the sugars is pushed further to give it a more toasted flavor.\u003c\/p\u003e\n\u003cp style=\"margin: 0 0 12px 0; text-align: justify;\"\u003eSancoffee is an independent, B-Corp certified cooperative based in the Campo das Vertentes region of Minas Gerais, Brazil. Sancoffee brings together 20 member farms and supports 600 smallholder producers, sharing a collective vision rooted in sustainability, quality, and community impact. The cooperative proudly blends its rich coffee-growing heritage, dating back to 1860, with modern initiatives that champion environmental preservation and social progress. To learn more, visit their \u003ca href=\"https:\/\/sancoffee.com\/\" rel=\"noopener\" target=\"_blank\"\u003e\u003cstrong\u003ewebsite\u003c\/strong\u003e\u003c\/a\u003e.\u003c\/p\u003e\n\u003cp style=\"margin: 0 0 12px 0; text-align: justify;\"\u003eCooperative programs such as Beyond Borders provide smallholder producers with tools and technical support, helping them gain recognition and add value to their work. Through educational workshops and youth training, Sancoffee invests in the future of its communities, fostering sustainable growth and opportunities for all.\u003c\/p\u003e\n\u003cp style=\"margin: 0 0 16px 0; text-align: justify;\"\u003eSancoffee achieved carbon neutrality in 2020, becoming a pioneer in environmentally responsible coffee production. Their efforts include restoring biodiversity, planting native trees, and conducting research to reduce the carbon footprint at the farm level.\u003c\/p\u003e\n\u003cdiv style=\"display: flex; gap: 20px; align-items: center; justify-content: space-between; flex-wrap: wrap; padding-top: 16px; border-top: 1px solid rgba(0,0,0,.12);\" class=\"logos-sancoffee\"\u003e\u003ca style=\"display: inline-block;\" href=\"https:\/\/sancoffee.com\/\" rel=\"noopener\" target=\"_blank\"\u003e \u003cimg style=\"height: 80px; width: auto;\" alt=\"Sancoffee\" src=\"https:\/\/cdn.shopify.com\/s\/files\/1\/2716\/1842\/files\/san_coffee_logo.svg?v=1781786545\"\u003e \u003c\/a\u003e\n\u003cdiv style=\"display: flex; gap: 20px; align-items: center; flex-wrap: wrap;\" class=\"logos-certs-sancoffee\"\u003e\u003cimg style=\"height: 80px; width: auto;\" alt=\"B-Corp Certification\" src=\"https:\/\/cdn.shopify.com\/s\/files\/1\/2716\/1842\/files\/bcorp-logo.webp?v=1781785759\"\u003e \u003cimg style=\"height: 80px; width: auto;\" alt=\"Sustainability Award 2024\" src=\"https:\/\/cdn.shopify.com\/s\/files\/1\/2716\/1842\/files\/For-Profit-Sus-2024-Stone_white.webp?v=1781785759\"\u003e\u003c\/div\u003e\n\u003c\/div\u003e\n\u003c\/div\u003e\n\u003c\/div\u003e\n\u003c!-- ========= FIN SECTION 3 ========= --\u003e\n\u003cp\u003e\u0026nbsp;\u003c\/p\u003e\n\u003c!-- =========================================================\n  SECTION 5 : WHOLESALE\n========================================================= --\u003e\n\u003cdiv style=\"width: 100%; margin: 0 auto 12px auto;\"\u003e\n\u003cdiv style=\"border: 2px solid #000; border-radius: 12px; overflow: hidden;\"\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;\"\u003eWholesale\u003c\/div\u003e\n\u003cdiv style=\"padding: 16px 14px; background: transparent;\"\u003e\n\u003cp style=\"margin: 0;\"\u003eWant to order two 5 lb bags or more? Visit our \u003ca href=\"https:\/\/zabcafe.com\/en\/products\/bon-matin-en-gros\" rel=\"noopener\" target=\"_blank\"\u003e\u003cstrong\u003eBULK\u003c\/strong\u003e\u003c\/a\u003e section to take advantage of volume discounts!\u003c\/p\u003e\n\u003c\/div\u003e\n\u003c\/div\u003e\n\u003c\/div\u003e\n\u003c!-- ========= FIN SECTION 5 ========= --\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: transparent;\" 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; background: transparent;\"\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);\"\u003e17.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);\"\u003e32 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;\"\u003e30 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\u003cspan\u003e Recipe optimized for an \u003c\/span\u003e\u003cstrong\u003e18 g\u003c\/strong\u003e\u003cspan\u003e basket. Adjust the grind slightly to reach a 32-second extraction.\u003c\/span\u003e\u003c\/div\u003e\n\u003c\/div\u003e\n\u003c\/details\u003e\n\u003c\/div\u003e\n\u003c!-- ========= FIN SECTION 4 ========= --\u003e\n\u003cp\u003e\u0026nbsp;\u003c\/p\u003e\n\u003c!-- =========================================================\n  SECTION 6 : FELLOW AIDEN PARAMETERS\n========================================================= --\u003e\n\u003cdiv style=\"width: 100%; margin: 0 auto 12px auto;\"\u003e\n\u003cdiv style=\"border: 2px solid #000; border-radius: 12px; overflow: hidden;\"\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;\"\u003eSettings for the Fellow Aiden\u003c\/div\u003e\n\u003cdiv style=\"padding: 16px 14px; background: transparent;\"\u003e\n\u003cp style=\"margin: 0;\"\u003e\u003ca href=\"https:\/\/brew.link\/p\/seW0\" rel=\"noopener\" target=\"_blank\"\u003eDownload the Bon Matin profile for the Fellow Aiden machine!\u003c\/a\u003e\u003c\/p\u003e\n\u003c\/div\u003e\n\u003c\/div\u003e\n\u003c\/div\u003e\n\u003c!-- ========= FIN SECTION 6 ========= --\u003e\n\u003cp\u003e\u0026nbsp;\u003c\/p\u003e\n\u003c!-- =========================================================\n  SECTION 7 : 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-bonmatin\"\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 85 °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-bonmatin\" 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-bonmatin\" 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-bonmatin\" style=\"font-weight: 950; font-size: 28px; letter-spacing: .01em;\"\u003e0:00\u003c\/span\u003e\u003c\/div\u003e\n\u003cdiv id=\"v60WakeStatus-bonmatin\" style=\"flex-basis: 100%; opacity: .6; font-size: 12px; line-height: 1.3; margin-top: 2px;\"\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 id=\"v60-card-1-bonmatin\" 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-bonmatin\" 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 35 g\u003c\/span\u003e\u003c\/div\u003e\n\u003c\/div\u003e\n\u003cdiv id=\"v60-card-2-bonmatin\" 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:30\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-bonmatin\" style=\"padding: 5px 9px; border-radius: 999px; background: rgba(0,0,0,.05); border: 1px solid rgba(0,0,0,.12);\"\u003ePour for 0:50s\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+190 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:40\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 probably too coarse. If it's longer, the grind is probably too fine.\u003c\/div\u003e\n\u003c\/div\u003e\n\u003c\/div\u003e\n\u003c\/details\u003e\n\u003c\/div\u003e\n\u003c!-- ========= FIN SECTION 7 ========= --\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  @media (max-width: 600px) {\n    .logos-sancoffee { justify-content: center !important; gap: 16px !important; }\n    .logos-sancoffee \u0026gt; a { width: 100% !important; text-align: center !important; }\n    .logos-certs-sancoffee { width: 100% !important; justify-content: center !important; }\n  }\n\u003c\/style\u003e\n\u003cscript\u003e\n(function() {\n  \/* ===== CARROUSEL ===== *\/\n  var cSuffix = '-sancoffee';\n  var cImgs  = document.querySelectorAll('.carousel-img' + cSuffix);\n  var cDots  = document.querySelectorAll('.carousel-dot' + cSuffix);\n  var cPrev  = document.getElementById('carousel-prev' + cSuffix);\n  var cNext  = document.getElementById('carousel-next' + cSuffix);\n  var cIndex = 0;\n  var cTimer = null;\n  function cShow(i) {\n    cIndex = (i + cImgs.length) % cImgs.length;\n    for (var k = 0; k \u0026lt; cImgs.length; k++) cImgs[k].style.opacity = (k === cIndex) ? '1' : '0';\n    for (var d = 0; d \u0026lt; cDots.length; d++) cDots[d].style.opacity = (d === cIndex) ? '1' : '.5';\n  }\n  function cStart() { cStop(); cTimer = setInterval(function() { cShow(cIndex + 1); }, 5000); }\n  function cStop() { if (cTimer) { clearInterval(cTimer); cTimer = null; } }\n  if (cPrev) cPrev.addEventListener('click', function() { cShow(cIndex - 1); cStart(); });\n  if (cNext) cNext.addEventListener('click', function() { cShow(cIndex + 1); cStart(); });\n  for (var dd = 0; dd \u0026lt; cDots.length; dd++) {\n    (function(node) {\n      node.addEventListener('click', function() { cShow(parseInt(node.getAttribute('data-i'), 10)); cStart(); });\n    })(cDots[dd]);\n  }\n  cShow(0);\n  cStart();\n\n  \/* ===== TIMER V60 ===== *\/\n  var SUFFIX = '-bonmatin';\n  var END_AT = 160;\n  var phases = [\n    { key: 1, t: 0,  pourLen: 10 },\n    { key: 2, t: 30, pourLen: 50 }\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  };\n  var cards = {\n    1: document.getElementById('v60-card-1' + SUFFIX),\n    2: document.getElementById('v60-card-2' + 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 keep-screen-awake mode.';\n      return Promise.resolve();\n    }\n    return navigator.wakeLock.request('screen').then(function(wl) {\n      wakeLock = wl;\n      statusEl.textContent = '✅ Screen kept awake during the recipe.';\n      wakeLock.addEventListener('release', function() {\n        statusEl.textContent = 'ℹ️ Keep-screen-awake mode released.';\n      });\n    }).catch(function() {\n      statusEl.textContent = '⚠️ Unable to enable keep-screen-awake mode.';\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":39442646859851,"sku":"CAF-BLE-BONM-300","price":22.5,"currency_code":"CAD","in_stock":true},{"title":"808g","offer_id":39442646892619,"sku":"CAF-BLE-BONM-808","price":52.0,"currency_code":"CAD","in_stock":true},{"title":"2268g (5lbs)","offer_id":39442646925387,"sku":"CAF-BLE-BONM-2268","price":125.0,"currency_code":"CAD","in_stock":true},{"title":"100g","offer_id":51434083090741,"sku":"CAF-BLE-BONM-100","price":12.0,"currency_code":"CAD","in_stock":true},{"title":"Bucket - 5lbs (Livraison locale seulement)","offer_id":52569821315381,"sku":"CAF-BLE-BONM-BUCK-5","price":150.0,"currency_code":"CAD","in_stock":true},{"title":"Bucket - 15lbs (Livraison locale seulement)","offer_id":52569821348149,"sku":"CAF-BLE-BONM-BUCK-15","price":400.0,"currency_code":"CAD","in_stock":true}],"thumbnail_url":"\/\/cdn.shopify.com\/s\/files\/1\/2716\/1842\/files\/bon-matin-300g.jpg?v=1756855245"},{"product_id":"guatemala-famille-lemus","title":"GUATEMALA - LEMUS FAMILY","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;\"\u003eHAZELNUT + DARK CHOCOLATE + BUTTERSCOTCH\u003c\/div\u003e\n\u003c\/div\u003e\n\u003c!-- ========= END SECTION 1 ========= --\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\u003eVillage of Mataquescuintla, Jalapa department, Guatemala\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003ePRODUCERS\u003c\/td\u003e\n\u003ctd\u003eLemus Family\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eFARM\u003c\/td\u003e\n\u003ctd\u003eEl Durazno\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eVARIETAL\u003c\/td\u003e\n\u003ctd\u003ePache San Ramon\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\u003e1900 m\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003ePARTNERS\u003c\/td\u003e\n\u003ctd\u003eSemilla\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eLOT SIZE PURCHASED\u003c\/td\u003e\n\u003ctd\u003e690 kg\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eFAB \/ FOB\u003c\/td\u003e\n\u003ctd\u003e6.22 $ US\/LB\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003ePRICE DELIVERED\u003c\/td\u003e\n\u003ctd\u003e9.15 $ CAD\/LB\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eFARMGATE PRICE\u003c\/td\u003e\n\u003ctd\u003e2700 Quetzal\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eRELATIONSHIP\u003c\/td\u003e\n\u003ctd\u003e6 years\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;\"\u003eFor the sixth consecutive year, the Lemus family's coffee is back with its charming aromas and great drinkability. As a filter, it offers a classic and indulgent cup with notes of chocolate and nuts — like taking a sip of hot chocolate. As an espresso, it pairs naturally with milk: its creamy texture and aromas of dark chocolate and hazelnut make for a delicious and versatile cup.\u003c\/p\u003e\n\u003cp style=\"margin: 0 0 12px 0;\"\u003eThe history of coffee farming in the Lemus family dates back to 1958, when Juan Raul Lemus's grandfather first began growing coffee. Twenty years later, his father Baudelio followed in his footsteps. Today, Juan Raul, his brothers, and his sister have joined the family business to manage the 13 hectares spread across 4 plots of land belonging to the family. The Lemus family has a long and rich history of coffee farming in Mataquescuintla, which has allowed them to develop far more infrastructure than the average producer that Semilla, our importer, works with. This allows them not only to process their own cherries, but also those of neighbouring producers.\u003c\/p\u003e\n\u003cp style=\"margin: 0;\"\u003eJuan Raul and his family are inspiring activists, fighting for their people, the Xincas. They are part of Café Colis Resistencia, which is fighting against a Canadian mining company operating a silver mine on Xinca land, threatening their livelihood. They also work to expand the community's sales opportunities beyond the local Guatemalan coffee market, which buys cherries at rock-bottom prices. We are very proud to support them through our partnership with Semilla, now for the fifth consecutive year! Their coffee is an essential part of our \"Back to Origin\" initiative, where $0.50 from every bag sold is paid directly back to the producer.\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 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);\"\u003e37 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;\"\u003e29 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. Consult your machine's manual to find 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-eldurazno-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 92 °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-eldurazno-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-eldurazno-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-eldurazno-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-eldurazno-en\"\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 style=\"border: 1px solid rgba(0,0,0,.18); border-radius: 12px; padding: 10px 12px;\" id=\"v60-card-1-eldurazno-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-eldurazno-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 45 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-eldurazno-en\"\u003e\n\u003cdiv style=\"display: flex; gap: 10px; align-items: baseline; margin-bottom: 6px;\"\u003e\n\u003cdiv style=\"font-weight: 900;\"\u003e0:35\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-eldurazno-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 105 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+60 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-eldurazno-en\"\u003e\n\u003cdiv style=\"display: flex; gap: 10px; align-items: baseline; margin-bottom: 6px;\"\u003e\n\u003cdiv style=\"font-weight: 900;\"\u003e1:10\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-eldurazno-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 165 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+60 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-eldurazno-en\"\u003e\n\u003cdiv style=\"display: flex; gap: 10px; align-items: baseline; margin-bottom: 6px;\"\u003e\n\u003cdiv style=\"font-weight: 900;\"\u003e1:45\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-eldurazno-en\"\u003ePour for 0:15s\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+60 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:40\u003c\/div\u003e\n\u003cdiv style=\"font-weight: 900;\"\u003eTarget total 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-eldurazno-en {\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-eldurazno-en {\n    animation: v60PulsePhase-eldurazno-en 700ms ease-out 1;\n    transform-origin: center;\n    will-change: transform;\n  }\n  @keyframes v60BlinkPill-eldurazno-en {\n    0%, 100% { opacity: 1; transform: scale(1); }\n    50%      { opacity: .22; transform: scale(1.03); }\n  }\n  .v60-pill-pour-active-eldurazno-en {\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-eldurazno-en 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-eldurazno-en { animation: none; }\n    .v60-pulse-eldurazno-en { animation: none; }\n  }\n\u003c\/style\u003e\n\u003cscript\u003e\n(function() {\n  var SUFFIX = '-eldurazno-en';\n  var END_AT = 160;\n  var phases = [\n    { key: 1, t: 0,   pourLen: 10 },\n    { key: 2, t: 35,  pourLen: 10 },\n    { key: 3, t: 70,  pourLen: 10 },\n    { key: 4, t: 105, pourLen: 15 }\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\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\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-eldurazno-en');\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-eldurazno-en');\n        void pill.offsetWidth;\n        pill.classList.add('v60-pulse-eldurazno-en');\n      }\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-eldurazno-en');\n    });\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-eldurazno-en');\n  }\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-eldurazno-en');\n      p.classList.remove('v60-pill-pour-active-eldurazno-en');\n    });\n  }\n\n  var wakeLock  = null;\n  var startTime = null;\n  var rafId     = null;\n  var lastPhaseKey = null;\n  var lastPourKey  = null;\n\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\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\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\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\n  function disableWakeLock() {\n    if (wakeLock) { wakeLock.release(); wakeLock = null; }\n  }\n\n  function setButtons(running) {\n    startBtn.disabled = running;\n    stopBtn.disabled  = !running;\n    stopBtn.style.opacity = running ? '1' : '.5';\n  }\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\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\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\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":48415415370037,"sku":"CAF-SIN-LEMU-300","price":28.5,"currency_code":"CAD","in_stock":false},{"title":"808g","offer_id":48415415402805,"sku":"CAF-SIN-LEMU-808","price":68.0,"currency_code":"CAD","in_stock":false},{"title":"2268g (5lbs)","offer_id":48415415435573,"sku":"CAF-SIN-LEMU-2268","price":175.0,"currency_code":"CAD","in_stock":false},{"title":"100g","offer_id":52331298881845,"sku":"CAF-SIN-LEMU-100","price":14.0,"currency_code":"CAD","in_stock":false},{"title":"Bucket - 5lbs (Livraison locale seulement)","offer_id":52568880742709,"sku":"CAF-SIN-LEMU-BUCK-5","price":200.0,"currency_code":"CAD","in_stock":false},{"title":"Bucket - 15lbs (Livraison locale seulement)","offer_id":52568880775477,"sku":"CAF-SIN-LEMU-BUCK-15","price":550.0,"currency_code":"CAD","in_stock":false}],"thumbnail_url":"\/\/cdn.shopify.com\/s\/files\/1\/2716\/1842\/files\/lemus-300g-retour.jpg?v=1771862869"},{"product_id":"honduras-jesus-galeas","title":"HONDURAS - JESUS GALEAS","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;\"\u003eGREEN APPLE + NUTS + CANE SUGAR\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 src=\"https:\/\/www.youtube.com\/embed\/1YALV1SU1QE?si=TCyjdZkwXAAKGLfI\" style=\"position: absolute; top: 0; left: 0; width: 100%; height: 100%; border: 0; border-radius: 8px;\"\u003e\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 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\u003eSelguapa, Comayagua department, Honduras\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003ePRODUCER\u003c\/td\u003e\n\u003ctd\u003eJesus \"Chungo\" Galeas\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eFARM\u003c\/td\u003e\n\u003ctd\u003eLa Falda\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eVARIETY\u003c\/td\u003e\n\u003ctd\u003eMixed varieties\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003ePROCESS\u003c\/td\u003e\n\u003ctd\u003eAnaerobic washed\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eALTITUDE\u003c\/td\u003e\n\u003ctd\u003e1700 m\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003ePARTNERS\u003c\/td\u003e\n\u003ctd\u003eSemilla\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eVOLUME PURCHASED\u003c\/td\u003e\n\u003ctd\u003e690 kg\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eFOB\u003c\/td\u003e\n\u003ctd\u003e$5.26 US\/lb\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eDELIVERED PRICE\u003c\/td\u003e\n\u003ctd\u003e$10.04 CAD\/lb\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eRELATIONSHIP\u003c\/td\u003e\n\u003ctd\u003e2 years\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;\"\u003eWe are truly excited to present Jesús's coffee, not only because it's delicious, but especially because Jesús plays a key role in transforming his community into a hub for specialty coffee production.\u003c\/p\u003e\n\u003cp style=\"margin: 0 0 12px 0;\"\u003eJesus worked for seven years at the Honduran Coffee Institute (IHCAFE), where he supported coffee producers across the country by providing training in soil analysis, harvesting, and coffee processing. Drawing on this experience, his goal is clear: to inspire producers to enter the specialty coffee market and adopt better agricultural practices. In 2018, thanks to his dedication and the support of Rony Game, his hometown of Selguapa saw the number of specialty coffee producers grow from just 2 to 30 in a single year.\u003c\/p\u003e\n\u003cp style=\"margin: 0;\"\u003eHis journey perfectly embodies the vision of Semilla, our importing partner: to offer fair and transparent prices that enable producers to invest in their farms and communities. With Jesús and visionaries like him, we're convinced that a sustainable future for coffee is within reach.\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 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);\"\u003e33 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. Check your machine's manual for 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 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-lafalda\"\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 90 °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-lafalda\" 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-lafalda\" 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-lafalda\" style=\"font-weight: 950; font-size: 28px; letter-spacing: .01em;\"\u003e0:00\u003c\/span\u003e\u003c\/div\u003e\n\u003cdiv id=\"v60WakeStatus-lafalda\" style=\"flex-basis: 100%; opacity: .6; font-size: 12px; line-height: 1.3; margin-top: 2px;\"\u003eℹ️ Press \"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 id=\"v60-card-1-lafalda\" 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-lafalda\" 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 45 g\u003c\/span\u003e\u003c\/div\u003e\n\u003c\/div\u003e\n\u003cdiv id=\"v60-card-2-lafalda\" 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:45\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-lafalda\" style=\"padding: 5px 9px; border-radius: 999px; background: rgba(0,0,0,.05); border: 1px solid rgba(0,0,0,.12);\"\u003ePour for 0:15s\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 105 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+60 g\u003c\/span\u003e\u003c\/div\u003e\n\u003c\/div\u003e\n\u003cdiv id=\"v60-card-3-lafalda\" 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:15\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-lafalda\" 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 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+65 g\u003c\/span\u003e\u003c\/div\u003e\n\u003c\/div\u003e\n\u003cdiv id=\"v60-card-4-lafalda\" 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:50\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 id=\"v60-pill-4-lafalda\" 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+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:50\u003c\/div\u003e\n\u003cdiv style=\"font-weight: 900;\"\u003eTotal 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, 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 { 0% { transform: scale(1); box-shadow: 0 0 0 0 rgba(200,169,126,.35); } 50% { transform: scale(1.06); box-shadow: 0 0 0 10px rgba(200,169,126,0); } 100% { transform: scale(1); box-shadow: 0 0 0 0 rgba(200,169,126,0); } }\n  .v60-pulse { animation: v60PulsePhase 700ms ease-out 1; transform-origin: center; will-change: transform; }\n  @keyframes v60BlinkPill { 0%, 100% { opacity: 1; transform: scale(1); } 50% { opacity: .22; transform: scale(1.03); } }\n  .v60-pill-pour-active { background: #ffe7b7 !important; border: 2px solid #d2a44a !important; color: #3b2a12 !important; font-weight: 900 !important; letter-spacing: .02em; animation: v60BlinkPill 2500ms ease-in-out infinite; box-shadow: 0 0 0 2px rgba(210,164,74,.18) inset, 0 10px 22px rgba(0,0,0,.12), 0 0 0 6px rgba(210,164,74,.10); }\n  @media (prefers-reduced-motion: reduce) { .v60-pill-pour-active { animation: none; } .v60-pulse { animation: none; } }\n\u003c\/style\u003e\n\u003cscript\u003e\n(function() {\n  var SUFFIX = '-lafalda';\n  var END_AT = 170;\n  var phases = [ { key: 1, t: 0, pourLen: 10 }, { key: 2, t: 45, pourLen: 15 }, { key: 3, t: 75, pourLen: 20 }, { key: 4, t: 110, pourLen: 20 } ];\n  var latte = { cardBg: '#f6f1ea', cardBorder: '#c8a97e', pillBg: '#eadfce' };\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 = { 1: document.getElementById('v60-pill-1' + SUFFIX), 2: document.getElementById('v60-pill-2' + SUFFIX), 3: document.getElementById('v60-pill-3' + SUFFIX), 4: document.getElementById('v60-pill-4' + SUFFIX) };\n  var cards = { 1: document.getElementById('v60-card-1' + SUFFIX), 2: document.getElementById('v60-card-2' + SUFFIX), 3: document.getElementById('v60-card-3' + SUFFIX), 4: document.getElementById('v60-card-4' + SUFFIX) };\n  function setCardActive(key) {\n    Object.keys(cards).forEach(function(k) {\n      var c = cards[k]; if (!c) return;\n      if (parseInt(k) === key) { c.style.borderColor = latte.cardBorder; c.style.background = latte.cardBg; c.style.boxShadow = '0 0 0 2px rgba(200,169,126,.25) inset, 0 8px 22px rgba(200,169,126,.28)'; }\n      else { c.style.borderColor = 'rgba(0,0,0,.18)'; c.style.background = 'transparent'; c.style.boxShadow = 'none'; }\n    });\n  }\n  function setPillPhaseActive(key, doPulse) {\n    Object.keys(pills).forEach(function(k) {\n      var p = pills[k]; if (!p) return;\n      p.style.background = 'rgba(0,0,0,.05)'; p.style.borderColor = 'rgba(0,0,0,.12)'; p.style.boxShadow = 'none'; p.classList.remove('v60-pulse');\n    });\n    var pill = pills[key];\n    if (pill) {\n      pill.style.background = latte.pillBg; pill.style.borderColor = latte.cardBorder; pill.style.boxShadow = '0 0 0 2px rgba(200,169,126,.25) inset';\n      if (doPulse) { pill.classList.remove('v60-pulse'); void pill.offsetWidth; pill.classList.add('v60-pulse'); }\n    }\n  }\n  function resetPourPills() { Object.values(pills).forEach(function(p) { if (!p) return; p.classList.remove('v60-pill-pour-active'); }); }\n  function setPourPillActive(key) { resetPourPills(); if (!key) return; var pill = pills[key]; if (pill) pill.classList.add('v60-pill-pour-active'); }\n  function clearAll() {\n    Object.values(cards).forEach(function(c) { if (!c) return; c.style.borderColor = 'rgba(0,0,0,.18)'; c.style.background = 'transparent'; c.style.boxShadow = 'none'; });\n    Object.values(pills).forEach(function(p) { if (!p) return; p.style.background = 'rgba(0,0,0,.05)'; p.style.borderColor = 'rgba(0,0,0,.12)'; p.style.boxShadow = 'none'; p.classList.remove('v60-pulse'); p.classList.remove('v60-pill-pour-active'); });\n  }\n  var wakeLock = null; var startTime = null; var rafId = null; var lastPhaseKey = null; var lastPourKey = null;\n  function fmt(sec) { sec = Math.max(0, Math.floor(sec)); var m = Math.floor(sec \/ 60); var s = sec % 60; return m + ':' + (s \u0026lt; 10 ? '0' : '') + s; }\n  function getCurrentPhaseKey(elapsed) { var current = phases[0].key; for (var i = 0; i \u0026lt; phases.length; i++) if (elapsed \u0026gt;= phases[i].t) current = phases[i].key; return current; }\n  function getPourKey(elapsed) { for (var i = phases.length - 1; i \u0026gt;= 0; i--) { var p = phases[i]; if (elapsed \u0026gt;= p.t \u0026amp;\u0026amp; elapsed \u0026lt; (p.t + p.pourLen)) return p.key; } return null; }\n  function enableWakeLock() {\n    if (!('wakeLock' in navigator)) { statusEl.textContent = '⚠️ Your browser does not support keeping the screen awake.'; return Promise.resolve(); }\n    return navigator.wakeLock.request('screen').then(function(wl) {\n      wakeLock = wl; statusEl.textContent = '✅ Screen kept awake during the recipe.';\n      wakeLock.addEventListener('release', function() { statusEl.textContent = 'ℹ️ Screen wake mode released.'; });\n    }).catch(function() { statusEl.textContent = '⚠️ Unable to enable screen wake mode.'; wakeLock = null; });\n  }\n  function disableWakeLock() { if (wakeLock) { wakeLock.release(); wakeLock = null; } }\n  function setButtons(running) { startBtn.disabled = running; stopBtn.disabled = !running; stopBtn.style.opacity = running ? '1' : '.5'; }\n  function tick() {\n    var elapsed = (Date.now() - startTime) \/ 1000;\n    timerEl.textContent = fmt(elapsed);\n    var phaseKey = getCurrentPhaseKey(elapsed);\n    if (phaseKey !== lastPhaseKey) { setCardActive(phaseKey); setPillPhaseActive(phaseKey, lastPhaseKey !== null); lastPhaseKey = phaseKey; }\n    var pourKey = getPourKey(elapsed);\n    if (pourKey !== lastPourKey) { setPourPillActive(pourKey); lastPourKey = pourKey; }\n    if (elapsed \u0026gt;= END_AT) { stopRecipe(true); return; }\n    rafId = requestAnimationFrame(tick);\n  }\n  function startRecipe() {\n    setButtons(true); timerEl.textContent = '0:00'; lastPhaseKey = null; lastPourKey = null;\n    enableWakeLock().then(function() {\n      setCardActive(1); setPillPhaseActive(1, false); setPourPillActive(1); lastPhaseKey = 1; lastPourKey = 1;\n      startTime = Date.now(); if (rafId) cancelAnimationFrame(rafId); rafId = requestAnimationFrame(tick);\n    });\n  }\n  function stopRecipe(autoEnded) {\n    if (rafId) cancelAnimationFrame(rafId); rafId = null; startTime = null; disableWakeLock(); setButtons(false); clearAll(); lastPhaseKey = null; lastPourKey = null;\n    if (autoEnded) { statusEl.textContent = '✅ Recipe complete — screen released.'; timerEl.textContent = fmt(END_AT); }\n    else { statusEl.textContent = 'ℹ️ Recipe stopped — screen released.'; }\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() { if (document.visibilityState === 'visible' \u0026amp;\u0026amp; startTime \u0026amp;\u0026amp; !wakeLock) enableWakeLock(); });\n})();\n\u003c\/script\u003e\n\u003c\/svg\u003e","brand":"ZAB","offers":[{"title":"300g","offer_id":50752008454453,"sku":"CAF-SIN-JESU-300","price":31.0,"currency_code":"CAD","in_stock":true},{"title":"808g","offer_id":50752008487221,"sku":"CAF-SIN-JESU-808","price":76.0,"currency_code":"CAD","in_stock":true},{"title":"2268g (5lbs)","offer_id":50752008519989,"sku":"CAF-SIN-JESU-2268","price":200.0,"currency_code":"CAD","in_stock":true},{"title":"100g","offer_id":53138133811509,"sku":"CAF-SIN-JESU-100","price":15.5,"currency_code":"CAD","in_stock":true},{"title":"Bucket - 5lbs (Livraison locale seulement)","offer_id":53138133844277,"sku":"CAF-SIN-JESU-BUCK-5","price":225.0,"currency_code":"CAD","in_stock":true},{"title":"Bucket - 15lbs (Livraison locale seulement)","offer_id":53138133877045,"sku":"CAF-SIN-JESU-BUCK-15","price":625.0,"currency_code":"CAD","in_stock":true}],"thumbnail_url":"\/\/cdn.shopify.com\/s\/files\/1\/2716\/1842\/files\/jesus-300g-retour.jpg?v=1784320032"},{"product_id":"ethiopie-tero","title":"ETHIOPIA - TERO","description":"\u003cp\u003e \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;\"\u003eRASPBERRY + CARAMEL + EARL GREY\u003c\/div\u003e\n\u003c\/div\u003e\n\u003c!-- ========= END SECTION 1 ========= --\u003e\n\u003cp\u003e \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\/ISfsfawrmVs\" 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 \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\u003eGuji Zone, Oromia Region, Ethiopia\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003ePRODUCERS\u003c\/td\u003e\n\u003ctd\u003e450 small producers from group Dimtu Coffee Industry\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eFARM\u003c\/td\u003e\n\u003ctd\u003eTero\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eVARIETY\u003c\/td\u003e\n\u003ctd\u003e74110, 74158\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\u003e2400 m\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\u003e600 kg\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eFOB\u003c\/td\u003e\n\u003ctd\u003e$4.90 USD\/lb\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eRELATIONSHIP\u003c\/td\u003e\n\u003ctd\u003e3 years\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 \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;\"\u003eFrom the very first sip, raspberry brings a fruity, delicately tangy touch. Caramel then settles in with an indulgent sweetness and a creamy texture, along with floral, bergamot notes reminiscent of Earl Grey tea. The soft, lingering finish reveals black tea notes that balance the richness of the caramel and the freshness of the raspberry.\u003c\/p\u003e\n\u003cp style=\"margin: 0 0 12px 0;\"\u003eTero is the name of Getachew Zeleke’s farm, the owner of the export group Dimtu. Tero brings together coffee from Getachew’s farm and from 450 smallholder producers of the surrounding hills.\u003c\/p\u003e\n\u003cp style=\"margin: 0 0 12px 0;\"\u003eLong before he started growing coffee, Getachew was an accountant. Thanks to his savings, he was able to buy a piece of land in Addis Ababa. In 2008, as real estate prices soared, he sold that land and used the proceeds to buy a plot of farmland, that later became Tero farm.\u003c\/p\u003e\n\u003cp style=\"margin: 0 0 12px 0;\"\u003eStep by step, he began harvesting his own coffee cherries, then collecting from local producers as well, selling the dried cherries on the local market. In 2016, he built his own washing station and shifted his focus to specialty coffee: Dimtu Coffee Industry was born.\u003c\/p\u003e\n\u003cp style=\"margin: 0;\"\u003eBut it didn’t stop there. Unhappy with the pace and quality of local dry mills, Getachew decided to build one himself. The result? Full control over every step, from cherry to export. And that’s exactly what we love. That attention to detail, the commitment to quality, the accountant’s mindset… it all makes Getachew an outstanding partner!\u003c\/p\u003e\n\u003c\/div\u003e\n\u003c\/div\u003e\n\u003c!-- ========= END SECTION 3 ========= --\u003e\n\u003cp\u003e \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);\"\u003e37 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;\"\u003e27 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\n\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 \u003c\/p\u003e\n\u003c!-- =========================================================\n  SECTION 5: V60\n========================================================= --\u003e\n\u003cdiv style=\"width: 100%; margin: 0 auto;\"\u003e\n\u003cdetails id=\"v60Details-tero-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\n\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-tero-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 type=\"button\" id=\"v60StopBtn-tero-en\"\u003eStop\u003c\/button\u003e\n\u003c\/div\u003e\n\u003cdiv style=\"display: flex; gap: 10px; align-items: baseline; line-height: 1;\"\u003e\n\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-tero-en\"\u003e0:00\u003c\/span\u003e\n\u003c\/div\u003e\n\u003cdiv style=\"flex-basis: 100%; opacity: .6; font-size: 12px; line-height: 1.3; margin-top: 2px;\" id=\"v60WakeStatus-tero-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-tero-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\n\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-tero-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\n\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-tero-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\n\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-tero-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\n\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-tero-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\n\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-tero-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\n\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-tero-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\n\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-tero-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\n\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:40\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\n\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 = '-tero-en';\n  var END_AT = 160;\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","brand":"ZAB","offers":[{"title":"300g","offer_id":51101415866677,"sku":"CAF-SIN-TERO-300","price":33.0,"currency_code":"CAD","in_stock":true},{"title":"808g","offer_id":51101415899445,"sku":"CAF-SIN-TERO-808","price":80.0,"currency_code":"CAD","in_stock":true},{"title":"2268g (5lbs)","offer_id":51101415932213,"sku":"CAF-SIN-TERO-2268","price":205.0,"currency_code":"CAD","in_stock":true},{"title":"100g","offer_id":53629276782901,"sku":"CAF-SIN-TERO-100","price":16.0,"currency_code":"CAD","in_stock":true},{"title":"Bucket - 5lbs (Local delivery only)","offer_id":53629051601205,"sku":"CAF-SIN-TERO-BUCK-5","price":230.0,"currency_code":"CAD","in_stock":true},{"title":"Bucket - 15lbs (Local delivery only)","offer_id":53629051633973,"sku":"CAF-SIN-TERO-BUCK-15","price":640.0,"currency_code":"CAD","in_stock":true}],"thumbnail_url":"\/\/cdn.shopify.com\/s\/files\/1\/2716\/1842\/files\/tero-300g-retour_0615c84f-aa3f-45b6-992d-5db4be0c19cf.jpg?v=1793119978"},{"product_id":"guatemala-raul-perez","title":"GUATEMALA - PEREZ FAMILY","description":"\u003cp\u003e \u003c\/p\u003e\n\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;\"\u003eFUDGE + CARAMEL + RED APPLE\u003c\/div\u003e\n\u003c\/div\u003e\n\u003c!-- ========= END SECTION 1 ========= --\u003e\n\n\u003cp\u003e \u003c\/p\u003e\n\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\/emoBWvgfMF0\" title=\"YouTube video player\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" allowfullscreen\u003e\u003c\/iframe\u003e\u003c\/div\u003e\n\n\u003cp\u003e \u003c\/p\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 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\u003eAcatenango, Chimaltenango, Guatemala\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003ePRODUCERS\u003c\/td\u003e\n\u003ctd\u003ePerez Family\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eFARM\u003c\/td\u003e\n\u003ctd\u003eFinca La Soledad\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eVARIETY\u003c\/td\u003e\n\u003ctd\u003eCaturra, Catuai\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\u003e1400-1600 m\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003ePARTNERS\u003c\/td\u003e\n\u003ctd\u003eApex\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eVOLUME PURCHASED\u003c\/td\u003e\n\u003ctd\u003e345 kg\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eFOB\u003c\/td\u003e\n\u003ctd\u003e$4.75 USD\/lb\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eDELIVERED PRICE\u003c\/td\u003e\n\u003ctd\u003e$9.49 CAD\/LB\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eRELATIONSHIP\u003c\/td\u003e\n\u003ctd\u003e3 years\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\n\u003cp\u003e \u003c\/p\u003e\n\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 Central American coffee with the juicy, sweet side of an apple and a lingering finish of cocoa and sugar. As an espresso, its texture and sweetness are reminiscent of butterscotch. As a filter coffee, it shows lovely delicacy and a vibrancy that takes us back to apple season. Comforting, yet with just enough acidity to make you want another sip.\u003c\/p\u003e\n\u003cp style=\"margin: 0 0 12px 0;\"\u003eFinca La Soledad sits in the heart of Acatenango, Guatemala, and covers 90 hectares, of which only half is dedicated to production; the rest is left as natural forest, a choice that protects the ecosystem and strengthens the quality of the terroir.\u003c\/p\u003e\n\u003cp style=\"margin: 0 0 12px 0;\"\u003eRaúl Pérez is a sixth-generation producer. Together with his father Henio, his mother Mercedes, and his brother José, he constantly refines their processing methods to reveal the full potential of their coffees. Finca La Soledad is also known for its attention to detail and its washed coffees, made with exceptional care.\u003c\/p\u003e\n\u003cp style=\"margin: 0;\"\u003eThe Perez family uses a traditional washed process: ripe cherries are picked by hand, fermented for 40 to 45 hours, then washed and dried on raised African beds for 12 to 18 days. This process yields a clean, vibrant cup with floral, citrus, and tropical notes, a silky body, and lovely complexity.\u003c\/p\u003e\n\u003c\/div\u003e\n\u003c\/div\u003e\n\u003c!-- ========= END SECTION 3 ========= --\u003e\n\n\u003cp\u003e \u003c\/p\u003e\n\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);\"\u003e35 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;\"\u003e30 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\n\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\n\u003cp\u003e \u003c\/p\u003e\n\n\u003c!-- =========================================================\n  SECTION 5: V60\n========================================================= --\u003e\n\u003cdiv style=\"width: 100%; margin: 0 auto;\"\u003e\n\u003cdetails id=\"v60Details-perez-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 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\n\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-perez-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 type=\"button\" id=\"v60StopBtn-perez-en\"\u003eStop\u003c\/button\u003e\n\u003c\/div\u003e\n\u003cdiv style=\"display: flex; gap: 10px; align-items: baseline; line-height: 1;\"\u003e\n\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-perez-en\"\u003e0:00\u003c\/span\u003e\n\u003c\/div\u003e\n\u003cdiv style=\"flex-basis: 100%; opacity: .6; font-size: 12px; line-height: 1.3; margin-top: 2px;\" id=\"v60WakeStatus-perez-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-perez-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\n\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-perez-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 40 g\u003c\/span\u003e\n\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-perez-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\n\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-perez-en\"\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\n\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-perez-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\n\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-perez-en\"\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\n\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\n\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 = '-perez-en';\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 \u003c 10 ? '0' : '') + s;\n  }\n  function getCurrentPhaseKey(elapsed) {\n    var current = phases[0].key;\n    for (var i = 0; i \u003c phases.length; i++) if (elapsed \u003e= phases[i].t) current = phases[i].key;\n    return current;\n  }\n  function getPourKey(elapsed) {\n    for (var i = phases.length - 1; i \u003e= 0; i--) {\n      var p = phases[i];\n      if (elapsed \u003e= p.t \u0026\u0026 elapsed \u003c (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 \u003e= 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' \u0026\u0026 startTime \u0026\u0026 !wakeLock) enableWakeLock();\n  });\n})();\n\u003c\/script\u003e\n\u003c\/svg\u003e","brand":"ZAB","offers":[{"title":"300g","offer_id":51756481282357,"sku":"CAF-SIN-PERE-300","price":30.0,"currency_code":"CAD","in_stock":true},{"title":"808g","offer_id":51756481315125,"sku":"CAF-SIN-PERE-808","price":72.0,"currency_code":"CAD","in_stock":true},{"title":"2268g (5lbs)","offer_id":51756481347893,"sku":"CAF-SIN-PERE-2268","price":190.0,"currency_code":"CAD","in_stock":true},{"title":"100g","offer_id":51756481380661,"sku":"CAF-SIN-PERE-100","price":15.0,"currency_code":"CAD","in_stock":true},{"title":"Bucket - 5lbs (Livraison locale seulement)","offer_id":52568888115509,"sku":"CAF-SIN-PERE-BUCK-5","price":215.0,"currency_code":"CAD","in_stock":true},{"title":"Bucket - 15lbs (Livraison locale seulement)","offer_id":52568888148277,"sku":"CAF-SIN-PERE-BUCK-15","price":595.0,"currency_code":"CAD","in_stock":true}],"thumbnail_url":"\/\/cdn.shopify.com\/s\/files\/1\/2716\/1842\/files\/famille-perez-300g-retour_61700b9a-7699-4ac5-92d0-4f7a678e0631.jpg?v=1791466811"},{"product_id":"cism-perou-las-tabaconas","title":"PERU - TABACONAS","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-top: 10px; padding-right: 14px; padding-bottom: 10px; font-weight: 800; text-transform: uppercase; font-size: 14px; letter-spacing: 0.02em; background: rgb(0, 0, 0); color: rgb(255, 255, 255); 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;\"\u003eNECTARINE + CACAO + CARAMEL\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\u003eTabacones District, San Ignacio Region, Cajamarca Province, Peru\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003ePRODUCERS\u003c\/td\u003e\n\u003ctd\u003e18 small-scale producers\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eVARIETIES\u003c\/td\u003e\n\u003ctd\u003eVarious\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\u003e1500 - 1850 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\u003e1035 kg\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eFOB\u003c\/td\u003e\n\u003ctd\u003e$3.77 USD\/lb\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eDELIVERED PRICE\u003c\/td\u003e\n\u003ctd\u003e$7.87 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\n\u003cp\u003e\u0026nbsp;\u003c\/p\u003e\n\n\u003c!-- =========================================================\n  SECTION 4: 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;\"\u003eTabaconas, in San Ignacio, is a high-altitude coffee region ideal for specialty arabica. Five hundred families cultivate Typica, Bourbon, or Caturra varieties, often shade-grown and sustainably farmed. This blend includes 18 producers from the region and offers notes of nectarine, cacao, and caramel.\u003c\/p\u003e\n\u003cp style=\"margin: 0;\"\u003eThis coffee is part of the Café Solidario initiative, created in 2017 to unite producers and promote sustainable and fair practices. Today, 255 producers (320 families) grow several certified varieties, driven by solidarity and environmental respect, with the ambition of becoming a national and international reference.\u003c\/p\u003e\n\u003c\/div\u003e\n\u003c\/div\u003e\n\u003c!-- ========= END SECTION 4 ========= --\u003e\n\n\u003cp\u003e\u0026nbsp;\u003c\/p\u003e\n\n\u003c!-- =========================================================\n  SECTION 5: 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 cup\u003c\/td\u003e\n\u003ctd style=\"padding: 10px 0; text-align: right; border-bottom: 1px solid rgba(0,0,0,.2);\"\u003e36 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;\"\u003e30 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. Adjust grind slightly to reach 30 seconds extraction time.\u003c\/div\u003e\n\u003c\/div\u003e\n\u003c\/details\u003e\n\u003c\/div\u003e\n\u003c!-- ========= END SECTION 5 ========= --\u003e\n\n\u003cp\u003e \u003c\/p\u003e\n\n\u003c!-- =========================================================\n  SECTION 6: V60\n========================================================= --\u003e\n\u003cdiv style=\"width: 100%; margin: 0 auto;\"\u003e\n\u003cdetails id=\"v60Details-tabacones-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\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 90 °C\u003c\/div\u003e\n\u003c\/div\u003e\n\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\n\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-tabacones-en\"\u003eStart\u003c\/button\u003e\n\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 type=\"button\" id=\"v60StopBtn-tabacones-en\"\u003eStop\u003c\/button\u003e\n\u003c\/div\u003e\n\u003cdiv style=\"display: flex; gap: 10px; align-items: baseline; line-height: 1;\"\u003e\n\u003cspan style=\"opacity: .70; font-size: 12px; font-weight: 800; text-transform: uppercase; letter-spacing: .04em;\"\u003eTimer\u003c\/span\u003e\n\u003cspan style=\"font-weight: 950; font-size: 28px; letter-spacing: .01em;\" id=\"v60Timer-tabacones-en\"\u003e0:00\u003c\/span\u003e\n\u003c\/div\u003e\n\u003cdiv style=\"flex-basis: 100%; opacity: .6; font-size: 12px; line-height: 1.3; margin-top: 2px;\" id=\"v60WakeStatus-tabacones-en\"\u003eℹ️ Press \"Start\" to keep the screen awake.\u003c\/div\u003e\n\u003c\/div\u003e\n\n\u003cdiv style=\"margin-top: 8px; display: grid; gap: 10px;\"\u003e\n\n\u003cdiv style=\"border: 1px solid rgba(0,0,0,.18); border-radius: 12px; padding: 10px 12px;\" id=\"v60-card-1-tabacones-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\n\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-tabacones-en\"\u003ePour for 0:10s\u003c\/span\u003e\n\u003cspan style=\"padding: 5px 9px; border-radius: 999px; background: rgba(0,0,0,.05); border: 1px solid rgba(0,0,0,.12);\"\u003eTotal 35 g\u003c\/span\u003e\n\u003c\/div\u003e\n\u003c\/div\u003e\n\n\u003cdiv style=\"border: 1px solid rgba(0,0,0,.18); border-radius: 12px; padding: 10px 12px;\" id=\"v60-card-2-tabacones-en\"\u003e\n\u003cdiv style=\"display: flex; gap: 10px; align-items: baseline; margin-bottom: 6px;\"\u003e\n\u003cdiv style=\"font-weight: 900;\"\u003e0:35\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\n\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-tabacones-en\"\u003ePour for 0:30s\u003c\/span\u003e\n\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\n\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+135 g\u003c\/span\u003e\n\u003c\/div\u003e\n\u003c\/div\u003e\n\n\u003cdiv style=\"border: 1px solid rgba(0,0,0,.18); border-radius: 12px; padding: 10px 12px;\" id=\"v60-card-3-tabacones-en\"\u003e\n\u003cdiv style=\"display: flex; gap: 10px; align-items: baseline; margin-bottom: 6px;\"\u003e\n\u003cdiv style=\"font-weight: 900;\"\u003e1:30\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\n\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-tabacones-en\"\u003ePour for 0:15s\u003c\/span\u003e\n\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\n\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\n\u003c\/div\u003e\n\u003c\/div\u003e\n\n\u003c\/div\u003e\n\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:50\u003c\/div\u003e\n\u003cdiv style=\"font-weight: 900;\"\u003eTarget total 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\n\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\n\u003c\/div\u003e\n\u003c\/details\u003e\n\u003c\/div\u003e\n\u003c!-- ========= END SECTION 6 ========= --\u003e\n\n\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 = '-tabacones-en';\n  var END_AT = 170;\n  var phases = [\n    { key: 1, t: 0,   pourLen: 10 },\n    { key: 2, t: 35,  pourLen: 30 },\n    { key: 3, t: 90,  pourLen: 15 }\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 \u003c 10 ? '0' : '') + s;\n  }\n  function getCurrentPhaseKey(elapsed) {\n    var current = phases[0].key;\n    for (var i = 0; i \u003c phases.length; i++) if (elapsed \u003e= phases[i].t) current = phases[i].key;\n    return current;\n  }\n  function getPourKey(elapsed) {\n    for (var i = phases.length - 1; i \u003e= 0; i--) {\n      var p = phases[i];\n      if (elapsed \u003e= p.t \u0026\u0026 elapsed \u003c (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 awake 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 \u003e= 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' \u0026\u0026 startTime \u0026\u0026 !wakeLock) enableWakeLock();\n  });\n})();\n\u003c\/script\u003e\n\u003c\/svg\u003e","brand":"ZAB","offers":[{"title":"300g","offer_id":52331777655093,"sku":"CAF-SIN-TABA-300","price":26.5,"currency_code":"CAD","in_stock":false},{"title":"808g","offer_id":52331777687861,"sku":"CAF-SIN-TABA-808","price":62.0,"currency_code":"CAD","in_stock":true},{"title":"2268g (5lbs)","offer_id":52331777720629,"sku":"CAF-SIN-TABA-2268","price":160.0,"currency_code":"CAD","in_stock":true},{"title":"100g","offer_id":52331777753397,"sku":"CAF-SIN-TABA-100","price":13.25,"currency_code":"CAD","in_stock":true},{"title":"Bucket - 5lbs (Livraison locale seulement)","offer_id":52568956993845,"sku":"CAF-SIN-TABA-BUCK-5","price":185.0,"currency_code":"CAD","in_stock":true},{"title":"Bucket - 15lbs (Livraison locale seulement)","offer_id":52568957026613,"sku":"CAF-SIN-TABA-BUCK-15","price":505.0,"currency_code":"CAD","in_stock":true}],"thumbnail_url":"\/\/cdn.shopify.com\/s\/files\/1\/2716\/1842\/files\/tabaconas-300g.jpg?v=1779378844"},{"product_id":"ethiopie-elto","title":"ETHIOPIA - ELTO","description":"\u003c!-- =========================================================\n  PRODUCT SHEET — Elto Coffee \/ Sidama Ethiopia\n========================================================= --\u003e\n\n\u003cp\u003e \u003c\/p\u003e\n\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;\"\u003eRASPBERRY + GUAVA + EARL GREY\u003c\/div\u003e\n\u003c\/div\u003e\n\u003c!-- ========= END SECTION 1 ========= --\u003e\n\n\u003cp\u003e \u003c\/p\u003e\n\n\u003cdiv style=\"position: relative; width: 100%; padding-bottom: 56.25%; height: 0; border-radius: 8px;\"\u003e\n  \u003ciframe style=\"position: absolute; top: 0; left: 0; width: 100%; height: 100%; border: 0; border-radius: 8px;\"\n    src=\"https:\/\/www.youtube.com\/embed\/nOn5ieggbhM?si=Gdcr1YJ6tFaneKhL\"\n    frameborder=\"0\"\n    allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; fullscreen\"\n    allowfullscreen\u003e\u003c\/iframe\u003e\n\u003c\/div\u003e\n\n\u003cp\u003e \u003c\/p\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 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\u003eSidama Region, Ethiopia\u003c\/td\u003e\n      \u003c\/tr\u003e\n      \u003ctr\u003e\n        \u003ctd\u003ePRODUCERS\u003c\/td\u003e\n        \u003ctd\u003eElto Coffee (Eliyas Dukamo \u0026 Atiklit Dejene)\u003c\/td\u003e\n      \u003c\/tr\u003e\n      \u003ctr\u003e\n        \u003ctd\u003eVARIETIES\u003c\/td\u003e\n        \u003ctd\u003e74158, 74165, 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\u003e2200 – 2300 m\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\u003e600 kg\u003c\/td\u003e\n      \u003c\/tr\u003e\n      \u003ctr\u003e\n        \u003ctd\u003eFOB\u003c\/td\u003e\n        \u003ctd\u003e$5.35 USD\/lb\u003c\/td\u003e\n      \u003c\/tr\u003e\n      \u003ctr\u003e\n        \u003ctd\u003eDELIVERED PRICE\u003c\/td\u003e\n        \u003ctd\u003e$11.14 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\n\u003cp\u003e \u003c\/p\u003e\n\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;\"\u003eElto is a textbook example of an Ethiopian natural coffee — full of character, sweetness, and jammy fruit. As a filter, it offers a fascinating complexity: a pleasant acidity with floral aromas upfront, evolving into flavours of preserved berries that linger on the palate. As an espresso, the acidity becomes more pronounced, revealing notes of juicy guava and a creamy body. With milk, it makes a rich, dessert-like cappuccino.\u003c\/p\u003e\n    \u003cp style=\"margin: 0 0 12px 0;\"\u003eEliyas Dukamo and Atiklit Dejene (\"Mimi\"), co-founders of Elto Coffee, are true stars of the Ethiopian specialty coffee scene. Eliyas comes from a legendary family of producers, while Mimi began her career in quality control for a renowned specialty coffee project.\u003c\/p\u003e\n    \u003cp style=\"margin: 0;\"\u003eTheir company, Elto, operates two drying stations in Sidama and focuses on producing high-quality micro-lots — some even destined for coffee competitions — following the best practices in the industry. The name \"Elto\" carries a double meaning in Sidamo: abundance and more than passion, perfectly capturing the spirit and ambition of the duo.\u003c\/p\u003e\n  \u003c\/div\u003e\n\u003c\/div\u003e\n\u003c!-- ========= END SECTION 3 ========= --\u003e\n\n\u003cp\u003e \u003c\/p\u003e\n\n\u003c!-- =========================================================\n  SECTION 4 : ESPRESSO 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.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);\"\u003e37 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;\"\u003e27 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\n        \u003cstrong\u003eNote —\u003c\/strong\u003e Recipe optimized for an \u003cstrong\u003e18 g\u003c\/strong\u003e basket. Check your machine's manual for your basket capacity.\n      \u003c\/div\u003e\n    \u003c\/div\u003e\n  \u003c\/details\u003e\n\u003c\/div\u003e\n\u003c!-- ========= END SECTION 4 ========= --\u003e\n\n\u003cp\u003e \u003c\/p\u003e\n\n\u003c!-- =========================================================\n  SECTION 5 : V60\n========================================================= --\u003e\n\u003cdiv style=\"width: 100%; margin: 0 auto;\"\u003e\n  \u003cdetails id=\"v60Details-elto\" 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\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:16\u003c\/div\u003e\n        \u003cdiv style=\"margin-top: 4px; opacity: .7; font-size: 13px;\"\u003e15 g in – 240 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\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\n          \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-elto\"\u003eStart\u003c\/button\u003e\n          \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 type=\"button\" id=\"v60StopBtn-elto\"\u003eStop\u003c\/button\u003e\n        \u003c\/div\u003e\n        \u003cdiv style=\"display: flex; gap: 10px; align-items: baseline; line-height: 1;\"\u003e\n          \u003cspan style=\"opacity: .70; font-size: 12px; font-weight: 800; text-transform: uppercase; letter-spacing: .04em;\"\u003eTimer\u003c\/span\u003e\n          \u003cspan style=\"font-weight: 950; font-size: 28px; letter-spacing: .01em;\" id=\"v60Timer-elto\"\u003e0:00\u003c\/span\u003e\n        \u003c\/div\u003e\n        \u003cdiv style=\"flex-basis: 100%; opacity: .6; font-size: 12px; line-height: 1.3; margin-top: 2px;\" id=\"v60WakeStatus-elto\"\u003eℹ️ Press \"Start\" to keep your screen on.\u003c\/div\u003e\n      \u003c\/div\u003e\n\n      \u003cdiv style=\"margin-top: 8px; display: grid; gap: 10px;\"\u003e\n\n        \u003c!-- Phase 1 — Bloom --\u003e\n        \u003cdiv style=\"border: 1px solid rgba(0,0,0,.18); border-radius: 12px; padding: 10px 12px;\" id=\"v60-card-1-elto\"\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\n            \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-elto\"\u003ePour for 0:10s\u003c\/span\u003e\n            \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\n          \u003c\/div\u003e\n        \u003c\/div\u003e\n\n        \u003c!-- Phase 2 --\u003e\n        \u003cdiv style=\"border: 1px solid rgba(0,0,0,.18); border-radius: 12px; padding: 10px 12px;\" id=\"v60-card-2-elto\"\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\n            \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-elto\"\u003ePour for 0:30s\u003c\/span\u003e\n            \u003cspan style=\"padding: 5px 9px; border-radius: 999px; background: rgba(0,0,0,.05); border: 1px solid rgba(0,0,0,.12);\"\u003eTotal 155 g\u003c\/span\u003e\n            \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+105 g\u003c\/span\u003e\n          \u003c\/div\u003e\n        \u003c\/div\u003e\n\n        \u003c!-- Phase 3 --\u003e\n        \u003cdiv style=\"border: 1px solid rgba(0,0,0,.18); border-radius: 12px; padding: 10px 12px;\" id=\"v60-card-3-elto\"\u003e\n          \u003cdiv style=\"display: flex; gap: 10px; align-items: baseline; margin-bottom: 6px;\"\u003e\n            \u003cdiv style=\"font-weight: 900;\"\u003e1:25\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\n            \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-elto\"\u003ePour for 0:25s\u003c\/span\u003e\n            \u003cspan style=\"padding: 5px 9px; border-radius: 999px; background: rgba(0,0,0,.05); border: 1px solid rgba(0,0,0,.12);\"\u003eTotal 240 g\u003c\/span\u003e\n            \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+85 g\u003c\/span\u003e\n          \u003c\/div\u003e\n        \u003c\/div\u003e\n\n      \u003c\/div\u003e\n\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:25\u003c\/div\u003e\n          \u003cdiv style=\"font-weight: 900;\"\u003eTarget total 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\n          \u003cstrong\u003eℹ️ Tip —\u003c\/strong\u003e If total time is shorter, your grind is likely too coarse. If it's longer, your grind is likely too fine.\n        \u003c\/div\u003e\n      \u003c\/div\u003e\n\n    \u003c\/div\u003e\n  \u003c\/details\u003e\n\u003c\/div\u003e\n\u003c!-- ========= END SECTION 5 ========= --\u003e\n\n\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 = '-elto';\n  var END_AT = 145; \/* 2:25 *\/\n  var phases = [\n    { key: 1, t: 0,  pourLen: 10 },\n    { key: 2, t: 40, pourLen: 30 },\n    { key: 3, t: 85, pourLen: 25 }\n  ];\n  var latte = {\n    cardBg:     '#f6f1ea',\n    cardBorder: '#c8a97e',\n    pillBg:     '#eadfce'\n  };\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\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\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\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\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\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\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\n  var wakeLock  = null;\n  var startTime = null;\n  var rafId     = null;\n  var lastPhaseKey = null;\n  var lastPourKey  = null;\n\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 \u003c 10 ? '0' : '') + s;\n  }\n\n  function getCurrentPhaseKey(elapsed) {\n    var current = phases[0].key;\n    for (var i = 0; i \u003c phases.length; i++) if (elapsed \u003e= phases[i].t) current = phases[i].key;\n    return current;\n  }\n\n  function getPourKey(elapsed) {\n    for (var i = phases.length - 1; i \u003e= 0; i--) {\n      var p = phases[i];\n      if (elapsed \u003e= p.t \u0026\u0026 elapsed \u003c (p.t + p.pourLen)) return p.key;\n    }\n    return null;\n  }\n\n  function enableWakeLock() {\n    if (!('wakeLock' in navigator)) {\n      statusEl.textContent = '⚠️ Your browser does not support screen wake lock.';\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 = '⚠️ Could not activate screen wake lock.';\n      wakeLock = null;\n    });\n  }\n\n  function disableWakeLock() {\n    if (wakeLock) { wakeLock.release(); wakeLock = null; }\n  }\n\n  function setButtons(running) {\n    startBtn.disabled = running;\n    stopBtn.disabled  = !running;\n    stopBtn.style.opacity = running ? '1' : '.5';\n  }\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 \u003e= END_AT) { stopRecipe(true); return; }\n    rafId = requestAnimationFrame(tick);\n  }\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\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\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' \u0026\u0026 startTime \u0026\u0026 !wakeLock) enableWakeLock();\n  });\n})();\n\u003c\/script\u003e\n\u003c\/svg\u003e","brand":"ZAB","offers":[{"title":"250g","offer_id":52378849902901,"sku":"CAF-SIN-ELTO-250","price":30.0,"currency_code":"CAD","in_stock":true},{"title":"808g","offer_id":52378849935669,"sku":"CAF-SIN-ELTO-808","price":85.0,"currency_code":"CAD","in_stock":true}],"thumbnail_url":"\/\/cdn.shopify.com\/s\/files\/1\/2716\/1842\/files\/elto-250g.jpg?v=1772636655"},{"product_id":"colombie-edison-argote-co-ferment-melon-deau","title":"COLOMBIA - THERMAL CHOC - EDINSON ARGOTE WATERMELON CO-FERMENT","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;\"\u003eWATERMELON + ICED TEA + ORANGE SLICE\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 src=\"https:\/\/www.youtube.com\/embed\/2G2YI8Ozqts?si=BvPpHGCl8XXAvywr\" style=\"position: absolute; top: 0; left: 0; width: 100%; height: 100%; border: 0; border-radius: 8px;\"\u003e\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\u003eMunicipality of Oporapa, Huila Department\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003ePRODUCERS\u003c\/td\u003e\n\u003ctd\u003eEdinson Argote\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eFARM\u003c\/td\u003e\n\u003ctd\u003eQuebraditas\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eVARIETY\u003c\/td\u003e\n\u003ctd\u003eCaturra\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003ePROCESS\u003c\/td\u003e\n\u003ctd\u003eThermal shock and co-fermented\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eALTITUDE\u003c\/td\u003e\n\u003ctd\u003e1600 – 1800 m\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003ePARTNERS\u003c\/td\u003e\n\u003ctd\u003eTravesia\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eVOLUME PURCHASED\u003c\/td\u003e\n\u003ctd\u003e192 kg\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eFOB\u003c\/td\u003e\n\u003ctd\u003e$13.96 USD\/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 THE 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 the 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 beautiful burst of freshness with this superb co-fermented coffee! Edinson Argote crafts his coffees with extraordinary expertise, the result of years of experience in specialty coffee before launching his own project, Quebraditas, with his partner Angela Rojas and their families.\u003c\/p\u003e\n\u003cp style=\"margin: 0 0 12px 0;\"\u003eThe process used for this coffee is complex and executed with great precision. The cherries are first left to rest for 24 hours, then depulped and put into fermentation. During this stage, watermelon and yeast are added to the water-filled fermentation tank. The beans are then left to co-ferment for a total of 72 hours. A thermal shock is also applied: the beans are first immersed in hot water, then quickly cooled in very cold water. Combined with co-fermentation, this process contributes to the explosive profile you'll find in the cup.\u003c\/p\u003e\n\u003cp style=\"margin: 0;\"\u003eQuebraditas is a family project dedicated to producing specialty coffees with unique aromatic profiles. To achieve this, the farm implements agronomic practices focused on soil health, such as strategic shading, the use of organic matter, and maintaining balanced pH through amendments and lime applications. This care given from cultivation improves cup quality, before being processed with the utmost care. The result is superb, original, explosive, and truly sought-after coffees!\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: V60 AND ORIGAMI\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-quebraditas\"\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 and Origami – 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;\"\u003e13 g in – 200 g out\u003c\/div\u003e\n\u003cdiv style=\"margin-top: 6px; font-size: 13px;\"\u003e\u003cstrong\u003eWater temperature:\u003c\/strong\u003e 92 °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-quebraditas\" 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-quebraditas\" 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-quebraditas\" style=\"font-weight: 950; font-size: 28px; letter-spacing: .01em;\"\u003e0:00\u003c\/span\u003e\u003c\/div\u003e\n\u003cdiv id=\"v60WakeStatus-quebraditas\" style=\"flex-basis: 100%; opacity: .6; font-size: 12px; line-height: 1.3; margin-top: 2px;\"\u003eℹ️ Press \"Start\" to keep the 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-quebraditas\" 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-quebraditas\" 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 50 g\u003c\/span\u003e\u003c\/div\u003e\n\u003c\/div\u003e\n\u003cdiv id=\"v60-card-2-quebraditas\" 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:30\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-quebraditas\" 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 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 id=\"v60-card-3-quebraditas\" 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:00\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-quebraditas\" 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 150 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 id=\"v60-card-4-quebraditas\" 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:30\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 id=\"v60-pill-4-quebraditas\" 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 200 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\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:10\u003c\/div\u003e\n\u003cdiv style=\"font-weight: 900;\"\u003eTotal 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 probably too coarse. If it's longer, the grind is probably 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 4 ========= --\u003e\u003csvg style=\"display: none;\"\u003e\n\u003cstyle\u003e\n@keyframes v60PulsePhase {\n0% { transform: scale(1); box-shadow: 0 0 0 0 rgba(200,169,126,.35); }\n50% { transform: scale(1.06); box-shadow: 0 0 0 10px rgba(200,169,126,0); }\n100% { transform: scale(1); box-shadow: 0 0 0 0 rgba(200,169,126,0); }\n}\n.v60-pulse {\nanimation: v60PulsePhase 700ms ease-out 1;\ntransform-origin: center;\nwill-change: transform;\n}\n@keyframes v60BlinkPill {\n0%, 100% { opacity: 1; transform: scale(1); }\n50% { opacity: .22; transform: scale(1.03); }\n}\n.v60-pill-pour-active {\nbackground: #ffe7b7 !important;\nborder: 2px solid #d2a44a !important;\ncolor: #3b2a12 !important;\nfont-weight: 900 !important;\nletter-spacing: .02em;\nanimation: v60BlinkPill 2500ms ease-in-out infinite;\nbox-shadow:\n0 0 0 2px rgba(210,164,74,.18) inset,\n0 10px 22px rgba(0,0,0,.12),\n0 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() {\nvar SUFFIX = '-quebraditas';\nvar END_AT = 130;\nvar phases = [\n{ key: 1, t: 0, pourLen: 10 },\n{ key: 2, t: 30, pourLen: 10 },\n{ key: 3, t: 60, pourLen: 10 },\n{ key: 4, t: 90, pourLen: 10 }\n];\nvar latte = {\ncardBg: '#f6f1ea',\ncardBorder: '#c8a97e',\npillBg: '#eadfce'\n};\nvar details = document.getElementById('v60Details' + SUFFIX);\nvar startBtn = document.getElementById('v60StartBtn' + SUFFIX);\nvar stopBtn = document.getElementById('v60StopBtn' + SUFFIX);\nvar timerEl = document.getElementById('v60Timer' + SUFFIX);\nvar statusEl = document.getElementById('v60WakeStatus' + SUFFIX);\nvar pills = {\n1: document.getElementById('v60-pill-1' + SUFFIX),\n2: document.getElementById('v60-pill-2' + SUFFIX),\n3: document.getElementById('v60-pill-3' + SUFFIX),\n4: document.getElementById('v60-pill-4' + SUFFIX)\n};\nvar cards = {\n1: document.getElementById('v60-card-1' + SUFFIX),\n2: document.getElementById('v60-card-2' + SUFFIX),\n3: document.getElementById('v60-card-3' + SUFFIX),\n4: document.getElementById('v60-card-4' + SUFFIX)\n};\nfunction setCardActive(key) {\nObject.keys(cards).forEach(function(k) {\nvar c = cards[k];\nif (!c) return;\nif (parseInt(k) === key) {\nc.style.borderColor = latte.cardBorder;\nc.style.background = latte.cardBg;\nc.style.boxShadow = '0 0 0 2px rgba(200,169,126,.25) inset, 0 8px 22px rgba(200,169,126,.28)';\n} else {\nc.style.borderColor = 'rgba(0,0,0,.18)';\nc.style.background = 'transparent';\nc.style.boxShadow = 'none';\n}\n});\n}\nfunction setPillPhaseActive(key, doPulse) {\nObject.keys(pills).forEach(function(k) {\nvar p = pills[k];\nif (!p) return;\np.style.background = 'rgba(0,0,0,.05)';\np.style.borderColor = 'rgba(0,0,0,.12)';\np.style.boxShadow = 'none';\np.classList.remove('v60-pulse');\n});\nvar pill = pills[key];\nif (pill) {\npill.style.background = latte.pillBg;\npill.style.borderColor = latte.cardBorder;\npill.style.boxShadow = '0 0 0 2px rgba(200,169,126,.25) inset';\nif (doPulse) {\npill.classList.remove('v60-pulse');\nvoid pill.offsetWidth;\npill.classList.add('v60-pulse');\n}\n}\n}\nfunction resetPourPills() {\nObject.values(pills).forEach(function(p) {\nif (!p) return;\np.classList.remove('v60-pill-pour-active');\n});\n}\nfunction setPourPillActive(key) {\nresetPourPills();\nif (!key) return;\nvar pill = pills[key];\nif (pill) pill.classList.add('v60-pill-pour-active');\n}\nfunction clearAll() {\nObject.values(cards).forEach(function(c) {\nif (!c) return;\nc.style.borderColor = 'rgba(0,0,0,.18)';\nc.style.background = 'transparent';\nc.style.boxShadow = 'none';\n});\nObject.values(pills).forEach(function(p) {\nif (!p) return;\np.style.background = 'rgba(0,0,0,.05)';\np.style.borderColor = 'rgba(0,0,0,.12)';\np.style.boxShadow = 'none';\np.classList.remove('v60-pulse');\np.classList.remove('v60-pill-pour-active');\n});\n}\nvar wakeLock = null;\nvar startTime = null;\nvar rafId = null;\nvar lastPhaseKey = null;\nvar lastPourKey = null;\nfunction fmt(sec) {\nsec = Math.max(0, Math.floor(sec));\nvar m = Math.floor(sec \/ 60);\nvar s = sec % 60;\nreturn m + ':' + (s \u0026lt; 10 ? '0' : '') + s;\n}\nfunction getCurrentPhaseKey(elapsed) {\nvar current = phases[0].key;\nfor (var i = 0; i \u0026lt; phases.length; i++) if (elapsed \u0026gt;= phases[i].t) current = phases[i].key;\nreturn current;\n}\nfunction getPourKey(elapsed) {\nfor (var i = phases.length - 1; i \u0026gt;= 0; i--) {\nvar p = phases[i];\nif (elapsed \u0026gt;= p.t \u0026amp;\u0026amp; elapsed \u0026lt; (p.t + p.pourLen)) return p.key;\n}\nreturn null;\n}\nfunction enableWakeLock() {\nif (!('wakeLock' in navigator)) {\nstatusEl.textContent = '⚠️ Your browser does not support screen wake lock.';\nreturn Promise.resolve();\n}\nreturn navigator.wakeLock.request('screen').then(function(wl) {\nwakeLock = wl;\nstatusEl.textContent = '✅ Screen kept on during the recipe.';\nwakeLock.addEventListener('release', function() {\nstatusEl.textContent = 'ℹ️ Screen wake lock released.';\n});\n}).catch(function() {\nstatusEl.textContent = '⚠️ Unable to activate screen wake lock.';\nwakeLock = null;\n});\n}\nfunction disableWakeLock() {\nif (wakeLock) { wakeLock.release(); wakeLock = null; }\n}\nfunction setButtons(running) {\nstartBtn.disabled = running;\nstopBtn.disabled = !running;\nstopBtn.style.opacity = running ? '1' : '.5';\n}\nfunction tick() {\nvar elapsed = (Date.now() - startTime) \/ 1000;\ntimerEl.textContent = fmt(elapsed);\nvar phaseKey = getCurrentPhaseKey(elapsed);\nif (phaseKey !== lastPhaseKey) {\nsetCardActive(phaseKey);\nsetPillPhaseActive(phaseKey, lastPhaseKey !== null);\nlastPhaseKey = phaseKey;\n}\nvar pourKey = getPourKey(elapsed);\nif (pourKey !== lastPourKey) {\nsetPourPillActive(pourKey);\nlastPourKey = pourKey;\n}\nif (elapsed \u0026gt;= END_AT) { stopRecipe(true); return; }\nrafId = requestAnimationFrame(tick);\n}\nfunction startRecipe() {\nsetButtons(true);\ntimerEl.textContent = '0:00';\nlastPhaseKey = null;\nlastPourKey = null;\nenableWakeLock().then(function() {\nsetCardActive(1);\nsetPillPhaseActive(1, false);\nsetPourPillActive(1);\nlastPhaseKey = 1;\nlastPourKey = 1;\nstartTime = Date.now();\nif (rafId) cancelAnimationFrame(rafId);\nrafId = requestAnimationFrame(tick);\n});\n}\nfunction stopRecipe(autoEnded) {\nif (rafId) cancelAnimationFrame(rafId);\nrafId = null;\nstartTime = null;\ndisableWakeLock();\nsetButtons(false);\nclearAll();\nlastPhaseKey = null;\nlastPourKey = null;\nif (autoEnded) {\nstatusEl.textContent = '✅ Recipe complete — screen released.';\ntimerEl.textContent = fmt(END_AT);\n} else {\nstatusEl.textContent = 'ℹ️ Recipe stopped — screen released.';\n}\n}\nstartBtn.addEventListener('click', startRecipe);\nstopBtn.addEventListener('click', function() { stopRecipe(false); });\ndetails.addEventListener('toggle', function() { if (!details.open) stopRecipe(false); });\ndocument.addEventListener('visibilitychange', function() {\nif (document.visibilityState === 'visible' \u0026amp;\u0026amp; startTime \u0026amp;\u0026amp; !wakeLock) enableWakeLock();\n});\n})();\n\u003c\/script\u003e\n\u003c\/svg\u003e","brand":"ZAB","offers":[{"title":"200g","offer_id":52429418529077,"sku":"CAF-SIN-EDIN-MELO-GB","price":30.0,"currency_code":"CAD","in_stock":true}],"thumbnail_url":"\/\/cdn.shopify.com\/s\/files\/1\/2716\/1842\/files\/melon-deau-200g.jpg?v=1774886018"},{"product_id":"colombie-francy-castillo-varietes-rares","title":"COLOMBIA - FRANCY CASTILLO: RARE VARIETIES","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;\"\u003eHONEYDEW MELON + TANGERINE + OOLONG\u003c\/div\u003e\n\u003c\/div\u003e\n\u003c!-- ========= END SECTION 1 ========= --\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 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\u003eArboleda region, Nariño department, Colombia\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003ePRODUCERS\u003c\/td\u003e\n\u003ctd\u003eFrancy Castillo\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eFARM\u003c\/td\u003e\n\u003ctd\u003eEl Ubérrimo\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eVARIETY\u003c\/td\u003e\n\u003ctd\u003ePink Bourbon, Geisha, Sidra and Wush wush\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\u003e2118 m\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003ePARTNERS\u003c\/td\u003e\n\u003ctd\u003eApex\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eVOLUME PURCHASED\u003c\/td\u003e\n\u003ctd\u003e96 kg\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eFOB\u003c\/td\u003e\n\u003ctd\u003e$8.44 USD\/lb\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eLANDED PRICE\u003c\/td\u003e\n\u003ctd\u003e$18.22 CAD\/lb\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eRELATIONSHIP\u003c\/td\u003e\n\u003ctd\u003e4 years\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=\"position: relative; width: 100%; padding-bottom: 56.25%; height: 0; overflow: hidden; border-radius: 8px;\"\u003e\u003ciframe src=\"https:\/\/www.youtube.com\/embed\/PasUD7LZEUQ?si=aqQ2pJqOIrqiiNWr\" style=\"position: absolute; top: 0; left: 0; width: 100%; height: 100%; border: 0; border-radius: 8px;\"\u003e\u003c\/iframe\u003e\u003c\/div\u003e\n\u003cp\u003e\u0026nbsp;\u003c\/p\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;\"\u003eIn the summer of 2023, we had the privilege of being welcomed in Colombia's Nariño region by none other than the remarkable Francy Castillo. Following her enthusiastic footsteps and her beaming laugh, we made our way up to 2,000 metres of altitude along a narrow and demanding trail, finally arriving at her coffee farm. The view across the mountains was breathtaking, and Francy's hospitality even more so.\u003c\/p\u003e\n\u003cp style=\"margin: 0;\"\u003eFrancy is an extraordinary woman — not only for her exceptional expertise, but also for the dedication she shows to her community. She works her own farm and family lands, while also collaborating with over 900 small producers in her region. She oversees the Berruecos project, which consolidates cherries from local smallholders at her collection point. This initiative gives isolated producers access to the specialty coffee market, allowing them to earn premium prices. The project generates larger, more manageable lots sourced from outstanding farms and producers.\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 : 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-francycastillo\"\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:16\u003c\/div\u003e\n\u003cdiv style=\"margin-top: 4px; opacity: .7; font-size: 13px;\"\u003e15 g in – 240 g out\u003c\/div\u003e\n\u003cdiv style=\"margin-top: 6px; font-size: 13px;\"\u003e\u003cstrong\u003eWater temperature:\u003c\/strong\u003e 92 °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-francycastillo\" 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-francycastillo\" 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-francycastillo\" style=\"font-weight: 950; font-size: 28px; letter-spacing: .01em;\"\u003e0:00\u003c\/span\u003e\u003c\/div\u003e\n\u003cdiv id=\"v60WakeStatus-francycastillo\" 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-francycastillo\" 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-francycastillo\" 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 50 g\u003c\/span\u003e\u003c\/div\u003e\n\u003c\/div\u003e\n\u003cdiv id=\"v60-card-2-francycastillo\" 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:30\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-francycastillo\" 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 115 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\u003cdiv id=\"v60-card-3-francycastillo\" 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:15\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-francycastillo\" 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 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+55 g\u003c\/span\u003e\u003c\/div\u003e\n\u003c\/div\u003e\n\u003cdiv id=\"v60-card-4-francycastillo\" 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:50\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 id=\"v60-pill-4-francycastillo\" style=\"padding: 5px 9px; border-radius: 999px; background: rgba(0,0,0,.05); border: 1px solid rgba(0,0,0,.12);\"\u003ePour for 0:25s\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 240 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\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;\"\u003e3:00\u003c\/div\u003e\n\u003cdiv style=\"font-weight: 900;\"\u003eTarget 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, 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 4 ========= --\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 = '-francycastillo';\n  var END_AT = 180;\n  var phases = [\n    { key: 1, t: 0,   pourLen: 10 },\n    { key: 2, t: 30,  pourLen: 30 },\n    { key: 3, t: 75,  pourLen: 20 },\n    { key: 4, t: 110, pourLen: 25 }\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 does not support the screen wake lock.';\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":"200g","offer_id":52990481629493,"sku":"CAF-SIN-FRAN-FANC-GB","price":35.0,"currency_code":"CAD","in_stock":true}],"thumbnail_url":"\/\/cdn.shopify.com\/s\/files\/1\/2716\/1842\/files\/francy-spring2026-200g.jpg?v=1781285595"},{"product_id":"colombie-nogales","title":"COLOMBIA - NOGALES","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;\"\u003eCHERRY + PINK GRAPEFRUIT + BANANA + FLORAL\u003c\/div\u003e\n\u003c\/div\u003e\n\u003c!-- ========= END SECTION 1 ========= --\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: none; height: 228px;\"\u003e\n\u003ctbody\u003e\n\u003ctr style=\"height: 19px;\"\u003e\n\u003ctd style=\"width: 20%; height: 19px;\"\u003eORIGIN\u003c\/td\u003e\n\u003ctd style=\"height: 19px;\"\u003eMunicipality of Bruselas, Huila region, Colombia\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr style=\"height: 19px;\"\u003e\n\u003ctd style=\"height: 19px;\"\u003ePRODUCERS\u003c\/td\u003e\n\u003ctd style=\"height: 19px;\"\u003eHernández Family\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr style=\"height: 19px;\"\u003e\n\u003ctd style=\"height: 19px;\"\u003eFARM\u003c\/td\u003e\n\u003ctd style=\"height: 19px;\"\u003eNogales\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr style=\"height: 19px;\"\u003e\n\u003ctd style=\"height: 19px;\"\u003eVARIETY\u003c\/td\u003e\n\u003ctd style=\"height: 19px;\"\u003eTypica\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr style=\"height: 19px;\"\u003e\n\u003ctd style=\"height: 19px;\"\u003ePROCESS\u003c\/td\u003e\n\u003ctd style=\"height: 19px;\"\u003eWashed with advanced fermentation\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr style=\"height: 19px;\"\u003e\n\u003ctd style=\"height: 19px;\"\u003eALTITUDE\u003c\/td\u003e\n\u003ctd style=\"height: 19px;\"\u003e1900 m\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr style=\"height: 19px;\"\u003e\n\u003ctd style=\"height: 19px;\"\u003ePARTNERS\u003c\/td\u003e\n\u003ctd style=\"height: 19px;\"\u003eApex Coffee Import\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr style=\"height: 38px;\"\u003e\n\u003ctd style=\"height: 38px;\"\u003eVOLUME PURCHASED\u003c\/td\u003e\n\u003ctd style=\"height: 38px;\"\u003e48 kg\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr style=\"height: 19px;\"\u003e\n\u003ctd style=\"height: 19px;\"\u003eFOB\u003c\/td\u003e\n\u003ctd style=\"height: 19px;\"\u003e$10.25 USD\/lb\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr style=\"height: 19px;\"\u003e\n\u003ctd style=\"height: 19px;\"\u003eLANDED PRICE\u003c\/td\u003e\n\u003ctd style=\"height: 19px;\"\u003e$20.33 CAD\/lb\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr style=\"height: 19px;\"\u003e\n\u003ctd style=\"height: 19px;\"\u003eRELATIONSHIP\u003c\/td\u003e\n\u003ctd style=\"height: 19px;\"\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=\"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\/Nee_D0sJqAE?si=RKeYTkIXfSST_Q3Q\"\u003e\u003c\/iframe\u003e\u003c\/div\u003e\n\u003cp\u003e\u0026nbsp;\u003c\/p\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;\"\u003eIt's always fascinating to taste a coffee where an advanced processing method opens up a whole new flavour world. With the Hernandez family's Nogales, the first thing you notice is a pronounced bubble-gum aroma mixed with banana. In the cup, though, the flavours feel more balanced than the nose suggests. Beginning with a dried fruit or a fruit roll up quality, followed by a citrus-like acidity, and then the banana making its return.\u003c\/p\u003e\n\u003cp style=\"margin: 0 0 12px 0;\"\u003eIt's the Hernandez family's commitment to innovation that sets them apart, both in their processing approach and in the careful attention they give to variety selection. The process used for this coffee, executed with exceptional care and expertise, gives it real character. To start, the cherries are briefly submerged in hot water to release their natural sugars. They are then depulped while retaining as much juice as possible, which is used for a seven-day fermentation with selected yeasts sourced from the same coffee. This method helps create a more complex and expressive cup while highlighting the unique characteristics of its terroir.\u003c\/p\u003e\n\u003cp style=\"margin: 0;\"\u003eThe Nogales Group is a family project that blends tradition, innovation, and community commitment. Recognized for the quality of its coffees since winning the Cup of Excellence in 2005, it continues to grow through forward-thinking projects, sustainable farming practices, and full control over production. In 2025, the acquisition of Finca Niebla, located at 2,150 metres above sea level, marks a new chapter, with the planting of prestigious varieties and the production of coffees crafted entirely on the farm, from seed to 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 4 : V60\n========================================================= --\u003e\n\u003cdiv style=\"width: 100%; margin: 0 auto;\"\u003e\n\u003cdetails id=\"v60Details-hernandez\" 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 90 °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-hernandez\"\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-hernandez\"\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-hernandez\"\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-hernandez\"\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 style=\"border: 1px solid rgba(0,0,0,.18); border-radius: 12px; padding: 10px 12px;\" id=\"v60-card-1-hernandez\"\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-hernandez\"\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 style=\"border: 1px solid rgba(0,0,0,.18); border-radius: 12px; padding: 10px 12px;\" id=\"v60-card-2-hernandez\"\u003e\n\u003cdiv style=\"display: flex; gap: 10px; align-items: baseline; margin-bottom: 6px;\"\u003e\n\u003cdiv style=\"font-weight: 900;\"\u003e0:45\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-hernandez\"\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 115 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+75 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-hernandez\"\u003e\n\u003cdiv style=\"display: flex; gap: 10px; align-items: baseline; margin-bottom: 6px;\"\u003e\n\u003cdiv style=\"font-weight: 900;\"\u003e1:15\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-hernandez\"\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 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+55 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-hernandez\"\u003e\n\u003cdiv style=\"display: flex; gap: 10px; align-items: baseline; margin-bottom: 6px;\"\u003e\n\u003cdiv style=\"font-weight: 900;\"\u003e1:50\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-hernandez\"\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+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:50\u003c\/div\u003e\n\u003cdiv style=\"font-weight: 900;\"\u003eTarget 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, 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 4 ========= --\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 = '-hernandez';\n  var END_AT = 170;\n  var phases = [\n    { key: 1, t: 0,   pourLen: 10 },\n    { key: 2, t: 45,  pourLen: 30 },\n    { key: 3, t: 75,  pourLen: 20 },\n    { key: 4, t: 110, 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    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 does not support the screen wake lock.';\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":"200g","offer_id":52992309002549,"sku":"CAF-SIN-NOGA-GB","price":39.0,"currency_code":"CAD","in_stock":false}],"thumbnail_url":"\/\/cdn.shopify.com\/s\/files\/1\/2716\/1842\/files\/nogales-200g_c21692ad-e1bb-4284-8e31-0d2afb7fa94f.jpg?v=1781886041"},{"product_id":"perou-famille-minga","title":"PERU - MINGA FAMILY","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;\"\u003eYELLOW PLUM + DATE + DARK CHOCOLATE\u003c\/div\u003e\n\u003c\/div\u003e\n\u003c!-- ========= END SECTION 1 ========= --\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\u003eSan Ignacio region, Cajamarca province, Peru\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003ePRODUCERS\u003c\/td\u003e\n\u003ctd\u003eMinga Family\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eVARIETY\u003c\/td\u003e\n\u003ctd\u003eBourbon, Caturra, Pache\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\u003e1800–1950 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\u003e690 kg\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eFOB\u003c\/td\u003e\n\u003ctd\u003e$3.77 USD\/lb\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eLANDED PRICE\u003c\/td\u003e\n\u003ctd\u003e$8.08 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=\"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\/VYr1yer-5sg?si=6y7HNEgZFpIZVP_0\"\u003e\u003c\/iframe\u003e\u003c\/div\u003e\n\u003cp\u003e\u0026nbsp;\u003c\/p\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;\"\u003eThe Minga family grows their coffee in the mountainous Cajamarca region of northern Peru, where high altitude, rich soils, and a temperate climate create ideal conditions for specialty coffee production. Like many producers in the area, the family relies on sustainable farming practices and meticulous attention to every stage of the harvest and processing, bringing out the full potential of their terroir.\u003c\/p\u003e\n\u003cp style=\"margin: 0;\"\u003eAs members of the Café Solidario association, the Minga family is part of a collective project that now brings together more than 250 producers committed to traceability, quality, and sustainable development. Founded in 2017, this organization supports farming families by encouraging responsible practices, better recognition of their coffee's value, and a positive impact within their communities. Every lot from Solidario reflects not only the expertise of its producers, but also a concrete commitment to equity and the future of Peruvian coffee growing.\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 : ESPRESSO — RECOMMENDED 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 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;\"\u003e28 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 capacity.\u003c\/div\u003e\n\u003c\/div\u003e\n\u003c\/details\u003e\n\u003c\/div\u003e","brand":"ZAB","offers":[{"title":"300g","offer_id":53006152433973,"sku":"CAF-SIN-MING-300","price":26.5,"currency_code":"CAD","in_stock":false},{"title":"808g","offer_id":53006152466741,"sku":"CAF-SIN-MING-808","price":62.0,"currency_code":"CAD","in_stock":false},{"title":"2268g (5lbs)","offer_id":53006152499509,"sku":"CAF-SIN-MING-2268","price":160.0,"currency_code":"CAD","in_stock":false},{"title":"100g","offer_id":53006152532277,"sku":"CAF-SIN-MING-100","price":13.25,"currency_code":"CAD","in_stock":false},{"title":"Bucket - 5lbs (Livraison locale seulement)","offer_id":53006152565045,"sku":"CAF-SIN-MING-BUCK-5","price":185.0,"currency_code":"CAD","in_stock":false},{"title":"Bucket - 15lbs (Livraison locale seulement)","offer_id":53006152597813,"sku":"CAF-SIN-MING-BUCK-15","price":505.0,"currency_code":"CAD","in_stock":false}],"thumbnail_url":"\/\/cdn.shopify.com\/s\/files\/1\/2716\/1842\/files\/minga-300g.jpg?v=1781893597"},{"product_id":"colombie-frank-torres-1","title":"COLOMBIA - FRANK TORRES","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;\"\u003eRASPBERRY + BLACK CHERRY + CHOCOLATE MOUSSE + SPICE\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\/k_m6QRPaKwA?si=VFFSxu2aolAbwHhb\"\u003e\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\u003eLa Unión region, Nariño province, Colombia\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003ePRODUCER\u003c\/td\u003e\n\u003ctd\u003eFrank Torres\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eFARM\u003c\/td\u003e\n\u003ctd\u003eLa Indonesia\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eVARIETY\u003c\/td\u003e\n\u003ctd\u003ePink Bourbon\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\u003e1750 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\u003e96 kg\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eFOB\u003c\/td\u003e\n\u003ctd\u003e$10.95 US\/lb\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eDELIVERED PRICE\u003c\/td\u003e\n\u003ctd\u003e$21.75 CAD\/lb\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eRELATIONSHIP\u003c\/td\u003e\n\u003ctd\u003e2 years\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 THE 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 the 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;\"\u003eFrank Torres comes from a family with a long coffee tradition in La Unión, Colombia, where his grandfather, Marco Antonio Torres, was one of the first to grow coffee there over 80 years ago.\u003c\/p\u003e\n\u003cp style=\"margin: 0 0 12px 0;\"\u003eToday, Frank is the main manager of Finca La Indonesia, part of the family estate, where he oversees all agricultural and processing practices. He is constantly working to improve farming methods, with a strong focus on sustainability: soil health, responsible water management, the integration of shade trees, and crop diversity. Thanks to his efforts, 90% of the farm is now certified organic. He also stands out for his work in processing, driven by his experience and his passion for experimentation.\u003c\/p\u003e\n\u003cp style=\"margin: 0 0 12px 0;\"\u003eFor this Pink Bourbon, the cherries are first depulped and then fermented in a bioreactor, a sealed environment that allows very precise control of the process. A small portion of \"must\" is added, a liquid from a previous fermentation that acts as a natural starter, rich in sugars and beneficial microorganisms. Fermentation then takes place under CO₂, without any contact with oxygen, for around 48 hours at stable pressure. Throughout the process, key parameters are closely monitored to ensure optimal development.\u003c\/p\u003e\n\u003cp style=\"margin: 0;\"\u003eA highly controlled and precise process that results in a distinctive coffee, showcasing all of Frank Torres' expertise.\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: V60\n========================================================= --\u003e\n\u003cdiv style=\"width: 100%; margin: 0 auto;\"\u003e\n\u003cdetails id=\"v60Details-laindonesia\" 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 92 °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-laindonesia\"\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-laindonesia\"\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-laindonesia\"\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-laindonesia\"\u003eℹ️ Press \"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-laindonesia\"\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-laindonesia\"\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 45 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-laindonesia\"\u003e\n\u003cdiv style=\"display: flex; gap: 10px; align-items: baseline; margin-bottom: 6px;\"\u003e\n\u003cdiv style=\"font-weight: 900;\"\u003e0:45\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-laindonesia\"\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 105 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+60 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-laindonesia\"\u003e\n\u003cdiv style=\"display: flex; gap: 10px; align-items: baseline; margin-bottom: 6px;\"\u003e\n\u003cdiv style=\"font-weight: 900;\"\u003e1:15\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-laindonesia\"\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+65 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-laindonesia\"\u003e\n\u003cdiv style=\"display: flex; gap: 10px; align-items: baseline; margin-bottom: 6px;\"\u003e\n\u003cdiv style=\"font-weight: 900;\"\u003e1:50\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-laindonesia\"\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:50\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 4 ========= --\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 = '-laindonesia';\n  var END_AT = 170;\n  var phases = [\n    { key: 1, t: 0,   pourLen: 10 },\n    { key: 2, t: 45,  pourLen: 10 },\n    { key: 3, t: 75,  pourLen: 10 },\n    { key: 4, t: 110, 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 does not support keeping the screen awake.';\n      return Promise.resolve();\n    }\n    return navigator.wakeLock.request('screen').then(function(wl) {\n      wakeLock = wl;\n      statusEl.textContent = '✅ Screen kept awake during the recipe.';\n      wakeLock.addEventListener('release', function() {\n        statusEl.textContent = 'ℹ️ Wake lock released.';\n      });\n    }).catch(function() {\n      statusEl.textContent = '⚠️ Unable to enable 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":"200g","offer_id":53100163531061,"sku":"CAF-SIN-FRAN-TORR-GB","price":42.0,"currency_code":"CAD","in_stock":true}],"thumbnail_url":"\/\/cdn.shopify.com\/s\/files\/1\/2716\/1842\/files\/frank-torres-200g.jpg?v=1784050501"},{"product_id":"joyeux-roger-cafe-instantane","title":"JOYEUX ROGER - INSTANT COFFEE","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;\"\u003eBROWNIE + HAZELNUT + CREAMY\u003c\/div\u003e\n\u003c\/div\u003e\n\u003c!-- =========================================================\n  SECTION 3: ABOUT THE 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;\"\u003eZAB INSTANT - ANYTIME!\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\u003ch3 style=\"margin: 0px 0px 16px; text-align: center;\"\u003e\u003cstrong\u003eHere it is at last: the instant version of our superstar, the\u003cbr\u003e⋆·˚˚°✦\u003ca rel=\"noopener\" href=\"https:\/\/zabcafe.com\/en\/collections\/cafes\/products\/joyeux-roger\" target=\"_blank\"\u003eJoyeux Roger\u003c\/a\u003e✦°˚˚·⋆\u003c\/strong\u003e\u003c\/h3\u003e\n\u003cp\u003eNow you have no excuse to drink bad coffee while camping. We decided to fix that with our friends at Hasty Coffee.\u003c\/p\u003e\n\u003cp\u003eAll you have to do is pour the contents of the sachet into a cup, add hot or cold water, and stir. \u003cbr\u003e\u003cstrong\u003eTHAT'S IT! Doesn't get much better than that.\u003c\/strong\u003e\u003c\/p\u003e\n\u003cul\u003e\n\u003cli\u003eEach box contains 4 instant coffee pouches\u003c\/li\u003e\n\u003cli\u003eOne pouch = one cup of coffee (240ml to 300ml)\u003c\/li\u003e\n\u003cli\u003eHave a great summer :)\u003c\/li\u003e\n\u003c\/ul\u003e\n\u003c\/div\u003e\n\u003c\/div\u003e","brand":"ZAB","offers":[{"title":"Default Title","offer_id":53106867503413,"sku":"CAF-INS-JOYE-ROGE-4","price":14.5,"currency_code":"CAD","in_stock":false}],"thumbnail_url":"\/\/cdn.shopify.com\/s\/files\/1\/2716\/1842\/files\/instant-joyeux-4poches.jpg?v=1783533364"},{"product_id":"honduras-efren-sanchez","title":"HONDURAS - EFREN SANCHEZ","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;\"\u003eTANGERINE + BUTTERSCOTCH + COCOA\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 src=\"https:\/\/www.youtube.com\/embed\/Ah07vnT9SOY?si=xF-JkRB42Cw0sJeg\" style=\"position: absolute; top: 0; left: 0; width: 100%; height: 100%; border: 0; border-radius: 8px;\"\u003e\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 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\u003eEl Paraíso municipality, El Paraíso department, Honduras\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003ePRODUCER\u003c\/td\u003e\n\u003ctd\u003eEfren Nefrali Sanchez\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eFARM\u003c\/td\u003e\n\u003ctd\u003eLa Esmeranda\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eVARIETY\u003c\/td\u003e\n\u003ctd\u003eParainema\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\u003e1400 m\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003ePARTNERS\u003c\/td\u003e\n\u003ctd\u003eSemilla\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eVOLUME PURCHASED\u003c\/td\u003e\n\u003ctd\u003e552 kg\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eFOB\u003c\/td\u003e\n\u003ctd\u003e$4.50 US\/lb\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eDELIVERED PRICE\u003c\/td\u003e\n\u003ctd\u003e$10.04 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;\"\u003eEfren is a young coffee producer carrying on a family tradition passed down through generations. Coming from a coffee-growing family, he learned the craft from his grandparents, whose knowledge and experience continue to shape his work today. After spending many years working alongside his family, he began managing his own plot about a decade ago and has since devoted himself to producing high-quality coffee under his own name.\u003c\/p\u003e\n\u003cp style=\"margin: 0;\"\u003eHis goal is to create a distinctive product that not only reflects the potential of his farm but also allows him to increase his income, reinvest in his operation, and reach new markets around the world. 2025 marks an important milestone for Efren, as it is the first year he is exporting coffee through Semilla, our importing partner. It is so exciting to witness this journey and we are so excited to see his coffee being enjoyed far beyond Honduras!\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 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);\"\u003e35 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;\"\u003e26 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 for 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 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-laesmeranda\"\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 90 °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-laesmeranda\" 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-laesmeranda\" 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-laesmeranda\" style=\"font-weight: 950; font-size: 28px; letter-spacing: .01em;\"\u003e0:00\u003c\/span\u003e\u003c\/div\u003e\n\u003cdiv id=\"v60WakeStatus-laesmeranda\" style=\"flex-basis: 100%; opacity: .6; font-size: 12px; line-height: 1.3; margin-top: 2px;\"\u003eℹ️ Press \"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 id=\"v60-card-1-laesmeranda\" 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-laesmeranda\" 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 35 g\u003c\/span\u003e\u003c\/div\u003e\n\u003c\/div\u003e\n\u003cdiv id=\"v60-card-2-laesmeranda\" 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-laesmeranda\" 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 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+135 g\u003c\/span\u003e\u003c\/div\u003e\n\u003c\/div\u003e\n\u003cdiv id=\"v60-card-3-laesmeranda\" 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:25\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-laesmeranda\" 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 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:50\u003c\/div\u003e\n\u003cdiv style=\"font-weight: 900;\"\u003eTotal 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, 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 { 0% { transform: scale(1); box-shadow: 0 0 0 0 rgba(200,169,126,.35); } 50% { transform: scale(1.06); box-shadow: 0 0 0 10px rgba(200,169,126,0); } 100% { transform: scale(1); box-shadow: 0 0 0 0 rgba(200,169,126,0); } }\n  .v60-pulse { animation: v60PulsePhase 700ms ease-out 1; transform-origin: center; will-change: transform; }\n  @keyframes v60BlinkPill { 0%, 100% { opacity: 1; transform: scale(1); } 50% { opacity: .22; transform: scale(1.03); } }\n  .v60-pill-pour-active { background: #ffe7b7 !important; border: 2px solid #d2a44a !important; color: #3b2a12 !important; font-weight: 900 !important; letter-spacing: .02em; animation: v60BlinkPill 2500ms ease-in-out infinite; box-shadow: 0 0 0 2px rgba(210,164,74,.18) inset, 0 10px 22px rgba(0,0,0,.12), 0 0 0 6px rgba(210,164,74,.10); }\n  @media (prefers-reduced-motion: reduce) { .v60-pill-pour-active { animation: none; } .v60-pulse { animation: none; } }\n\u003c\/style\u003e\n\u003cscript\u003e\n(function() {\n  var SUFFIX = '-laesmeranda';\n  var END_AT = 170;\n  var phases = [ { key: 1, t: 0, pourLen: 10 }, { key: 2, t: 40, pourLen: 30 }, { key: 3, t: 85, pourLen: 30 } ];\n  var latte = { cardBg: '#f6f1ea', cardBorder: '#c8a97e', pillBg: '#eadfce' };\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 = { 1: document.getElementById('v60-pill-1' + SUFFIX), 2: document.getElementById('v60-pill-2' + SUFFIX), 3: document.getElementById('v60-pill-3' + SUFFIX) };\n  var cards = { 1: document.getElementById('v60-card-1' + SUFFIX), 2: document.getElementById('v60-card-2' + SUFFIX), 3: document.getElementById('v60-card-3' + SUFFIX) };\n  function setCardActive(key) {\n    Object.keys(cards).forEach(function(k) {\n      var c = cards[k]; if (!c) return;\n      if (parseInt(k) === key) { c.style.borderColor = latte.cardBorder; c.style.background = latte.cardBg; c.style.boxShadow = '0 0 0 2px rgba(200,169,126,.25) inset, 0 8px 22px rgba(200,169,126,.28)'; }\n      else { c.style.borderColor = 'rgba(0,0,0,.18)'; c.style.background = 'transparent'; c.style.boxShadow = 'none'; }\n    });\n  }\n  function setPillPhaseActive(key, doPulse) {\n    Object.keys(pills).forEach(function(k) {\n      var p = pills[k]; if (!p) return;\n      p.style.background = 'rgba(0,0,0,.05)'; p.style.borderColor = 'rgba(0,0,0,.12)'; p.style.boxShadow = 'none'; p.classList.remove('v60-pulse');\n    });\n    var pill = pills[key];\n    if (pill) {\n      pill.style.background = latte.pillBg; pill.style.borderColor = latte.cardBorder; pill.style.boxShadow = '0 0 0 2px rgba(200,169,126,.25) inset';\n      if (doPulse) { pill.classList.remove('v60-pulse'); void pill.offsetWidth; pill.classList.add('v60-pulse'); }\n    }\n  }\n  function resetPourPills() { Object.values(pills).forEach(function(p) { if (!p) return; p.classList.remove('v60-pill-pour-active'); }); }\n  function setPourPillActive(key) { resetPourPills(); if (!key) return; var pill = pills[key]; if (pill) pill.classList.add('v60-pill-pour-active'); }\n  function clearAll() {\n    Object.values(cards).forEach(function(c) { if (!c) return; c.style.borderColor = 'rgba(0,0,0,.18)'; c.style.background = 'transparent'; c.style.boxShadow = 'none'; });\n    Object.values(pills).forEach(function(p) { if (!p) return; p.style.background = 'rgba(0,0,0,.05)'; p.style.borderColor = 'rgba(0,0,0,.12)'; p.style.boxShadow = 'none'; p.classList.remove('v60-pulse'); p.classList.remove('v60-pill-pour-active'); });\n  }\n  var wakeLock = null; var startTime = null; var rafId = null; var lastPhaseKey = null; var lastPourKey = null;\n  function fmt(sec) { sec = Math.max(0, Math.floor(sec)); var m = Math.floor(sec \/ 60); var s = sec % 60; return m + ':' + (s \u0026lt; 10 ? '0' : '') + s; }\n  function getCurrentPhaseKey(elapsed) { var current = phases[0].key; for (var i = 0; i \u0026lt; phases.length; i++) if (elapsed \u0026gt;= phases[i].t) current = phases[i].key; return current; }\n  function getPourKey(elapsed) { for (var i = phases.length - 1; i \u0026gt;= 0; i--) { var p = phases[i]; if (elapsed \u0026gt;= p.t \u0026amp;\u0026amp; elapsed \u0026lt; (p.t + p.pourLen)) return p.key; } return null; }\n  function enableWakeLock() {\n    if (!('wakeLock' in navigator)) { statusEl.textContent = '⚠️ Your browser does not support keeping the screen awake.'; return Promise.resolve(); }\n    return navigator.wakeLock.request('screen').then(function(wl) {\n      wakeLock = wl; statusEl.textContent = '✅ Screen kept awake during the recipe.';\n      wakeLock.addEventListener('release', function() { statusEl.textContent = 'ℹ️ Screen wake mode released.'; });\n    }).catch(function() { statusEl.textContent = '⚠️ Unable to enable screen wake mode.'; wakeLock = null; });\n  }\n  function disableWakeLock() { if (wakeLock) { wakeLock.release(); wakeLock = null; } }\n  function setButtons(running) { startBtn.disabled = running; stopBtn.disabled = !running; stopBtn.style.opacity = running ? '1' : '.5'; }\n  function tick() {\n    var elapsed = (Date.now() - startTime) \/ 1000;\n    timerEl.textContent = fmt(elapsed);\n    var phaseKey = getCurrentPhaseKey(elapsed);\n    if (phaseKey !== lastPhaseKey) { setCardActive(phaseKey); setPillPhaseActive(phaseKey, lastPhaseKey !== null); lastPhaseKey = phaseKey; }\n    var pourKey = getPourKey(elapsed);\n    if (pourKey !== lastPourKey) { setPourPillActive(pourKey); lastPourKey = pourKey; }\n    if (elapsed \u0026gt;= END_AT) { stopRecipe(true); return; }\n    rafId = requestAnimationFrame(tick);\n  }\n  function startRecipe() {\n    setButtons(true); timerEl.textContent = '0:00'; lastPhaseKey = null; lastPourKey = null;\n    enableWakeLock().then(function() {\n      setCardActive(1); setPillPhaseActive(1, false); setPourPillActive(1); lastPhaseKey = 1; lastPourKey = 1;\n      startTime = Date.now(); if (rafId) cancelAnimationFrame(rafId); rafId = requestAnimationFrame(tick);\n    });\n  }\n  function stopRecipe(autoEnded) {\n    if (rafId) cancelAnimationFrame(rafId); rafId = null; startTime = null; disableWakeLock(); setButtons(false); clearAll(); lastPhaseKey = null; lastPourKey = null;\n    if (autoEnded) { statusEl.textContent = '✅ Recipe complete — screen released.'; timerEl.textContent = fmt(END_AT); }\n    else { statusEl.textContent = 'ℹ️ Recipe stopped — screen released.'; }\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() { if (document.visibilityState === 'visible' \u0026amp;\u0026amp; startTime \u0026amp;\u0026amp; !wakeLock) enableWakeLock(); });\n})();\n\u003c\/script\u003e\n\u003c\/svg\u003e","brand":"ZAB","offers":[{"title":"300g","offer_id":53138912969013,"sku":"CAF-SIN-EFRE-300","price":31.0,"currency_code":"CAD","in_stock":true},{"title":"808g","offer_id":53138913001781,"sku":"CAF-SIN-EFRE-808","price":76.0,"currency_code":"CAD","in_stock":true},{"title":"2268g (5lbs)","offer_id":53138913034549,"sku":"CAF-SIN-EFRE-2268","price":200.0,"currency_code":"CAD","in_stock":true},{"title":"100g","offer_id":53138913067317,"sku":"CAF-SIN-EFRE-100","price":15.5,"currency_code":"CAD","in_stock":true},{"title":"Bucket - 5lbs (Livraison locale seulement)","offer_id":53138913100085,"sku":"CAF-SIN-EFRE-BUCK-5","price":225.0,"currency_code":"CAD","in_stock":true},{"title":"Bucket - 15lbs (Livraison locale seulement)","offer_id":53138913132853,"sku":"CAF-SIN-EFRE-BUCK-15","price":625.0,"currency_code":"CAD","in_stock":true}],"thumbnail_url":"\/\/cdn.shopify.com\/s\/files\/1\/2716\/1842\/files\/efren-300g_35ae5a66-ce26-4c1d-ba72-061c088b80d2.jpg?v=1784319953"},{"product_id":"demi-caf-espresso","title":"HALF-CAF - ESPRESSO","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;\"\u003eCHOCOLATE CHIP + CARAMELIZED SUGAR + HAZELNUT\u003c\/div\u003e\n\u003c\/div\u003e\n\u003c!-- ========= FIN 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 src=\"https:\/\/www.youtube.com\/embed\/wLQxuB5RRqg?si=LleA40C9NC9V6Jo4\" style=\"position: absolute; top: 0; left: 0; width: 100%; height: 100%; border: 0; border-radius: 8px;\"\u003e\u003c\/iframe\u003e\u003c\/div\u003e\n\u003cp\u003e\u0026nbsp;\u003c\/p\u003e\n\u003c!-- =========================================================\n  SECTION 2 : SOURCING (50\/50 blend)\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 — Joyeux Roger (50%)\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\u003eCampo das Vertentes, Minas Gerais, Brazil\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003ePRODUCERS\u003c\/td\u003e\n\u003ctd\u003eSeveral producers from Sancoffee\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eVARIETIES\u003c\/td\u003e\n\u003ctd\u003eYellow Catucai, Mundo Novo, Red Catuai, Topázio\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\u003e900 – 1200 m\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\u003e96,600 kg\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eFOB\u003c\/td\u003e\n\u003ctd\u003e$2.40 USD\/LB\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eDELIVERED PRICE\u003c\/td\u003e\n\u003ctd\u003e$4.55 CAD\/LB\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eRELATIONSHIP\u003c\/td\u003e\n\u003ctd\u003e2 years\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003c\/tbody\u003e\n\u003c\/table\u003e\n\u003cp style=\"margin: 6px 0 0 0; font-size: 13px;\"\u003e \u003c\/p\u003e\n\u003c\/div\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 — Colombia Decaf (50%)\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\u003eBuesaco Municipality, Nariño department, Colombia\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003ePRODUCER(S)\u003c\/td\u003e\n\u003ctd\u003eSeveral small producers\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eVARIETY\u003c\/td\u003e\n\u003ctd\u003eVaried\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003ePROCESS\u003c\/td\u003e\n\u003ctd\u003eWashed and decaffeinated with ethyl acetate\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eALTITUDE\u003c\/td\u003e\n\u003ctd\u003e2100 to 2400 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\u003e5,600 kg\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eFOB\u003c\/td\u003e\n\u003ctd\u003e$4.20 USD\/lb\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eDELIVERED PRICE\u003c\/td\u003e\n\u003ctd\u003e$8.30 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 \u003c\/p\u003e\n\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;\"\u003eWhen your heart wants another coffee, but your body hesitates a little, we found the perfect compromise: a coffee that keeps all its character, with a bit less caffeine. Our half-caf blends regular and decaf coffee for a cup full of sweetness, flavor, and comfort.\u003c\/p\u003e\n\u003cp style=\"margin: 0 0 12px 0;\"\u003eFor this edition, we blended our classic Joyeux Roger, a Brazilian coffee with generous notes of chocolate and nuts, with our Colombian decaf from Buesaco, in Nariño. Produced with committed partners like Sancoffee in Brazil and Apex Coffee Imports in Colombia, this blend offers the best of both worlds: a rich cup with cocoa accents, a round texture, and a sweet, smooth finish.\u003c\/p\u003e\n\u003cp style=\"margin: 0;\"\u003eAll the pleasure of a good coffee, with just a little less caffeine.\u003c\/p\u003e\n\u003c\/div\u003e\n\u003c\/div\u003e\n\u003c!-- ========= FIN 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 Settings\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);\"\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;\"\u003e31 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 for your basket's capacity.\u003c\/div\u003e\n\u003c\/div\u003e\n\u003c\/details\u003e\n\u003c\/div\u003e\n\u003c!-- ========= FIN SECTION 4 ========= --\u003e","brand":"ZAB","offers":[{"title":"300g","offer_id":53223415447861,"sku":"CAF-BLE-HALF-ESPR-300","price":26.0,"currency_code":"CAD","in_stock":true},{"title":"808g","offer_id":53223415480629,"sku":"CAF-BLE-HALF-ESPR-808","price":61.5,"currency_code":"CAD","in_stock":true},{"title":"2268g (5lbs)","offer_id":53223415513397,"sku":"CAF-BLE-HALF-ESPR-2268","price":155.0,"currency_code":"CAD","in_stock":true},{"title":"100g","offer_id":53223415546165,"sku":"CAF-BLE-HALF-ESPR-100","price":13.5,"currency_code":"CAD","in_stock":true},{"title":"Bucket - 5lbs (Livraison locale seulement)","offer_id":53223415578933,"sku":"CAF-BLE-HALF-ESPR-B5","price":180.0,"currency_code":"CAD","in_stock":true},{"title":"Bucket - 15lbs (Livraison locale seulement)","offer_id":53223415611701,"sku":"CAF-BLE-HALF-ESPR-B15","price":490.0,"currency_code":"CAD","in_stock":true}],"thumbnail_url":"\/\/cdn.shopify.com\/s\/files\/1\/2716\/1842\/files\/half-caf-espresso-300g.jpg?v=1785765998"},{"product_id":"indonesie-frinsa-estate","title":"INDONESIA - FRINSA ESTATE","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;\"\u003eGRAPE + STRAWBERRY + COLA CANDY\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 src=\"https:\/\/www.youtube.com\/embed\/jFCCEUBPii0?si=nOgVxI8MYCAhxKPP\" style=\"position: absolute; top: 0; left: 0; width: 100%; height: 100%; border: 0; border-radius: 8px;\" title=\"YouTube video player\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" allowfullscreen=\"\"\u003e\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 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\u003eBandung Highlands, West Java province, Indonesia\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003ePRODUCERS\u003c\/td\u003e\n\u003ctd\u003eJava Frinsa Estate\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eVARIETY\u003c\/td\u003e\n\u003ctd\u003eMixed varieties\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003ePROCESS\u003c\/td\u003e\n\u003ctd\u003eNatural with lactic fermentation\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eALTITUDE\u003c\/td\u003e\n\u003ctd\u003e1300-1700 m\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003ePARTNERS\u003c\/td\u003e\n\u003ctd\u003eAcross Indonesian Seas\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eVOLUME PURCHASED\u003c\/td\u003e\n\u003ctd\u003e420 kg\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eDELIVERED PRICE\u003c\/td\u003e\n\u003ctd\u003e$13.61 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;\"\u003eFounded in 2012 by Wildan Mustofa and Atieq Mustikaningtyas, Java Frinsa Estate is a family-run farm located in the Bandung highlands, in West Java. Their vision: to produce exceptional coffees while regenerating the land and adopting sustainable farming practices.\u003c\/p\u003e\n\u003cp style=\"margin: 0 0 12px 0;\"\u003eGrown under forest cover and processed with great precision, Frinsa's coffee reflects a unique mountain terroir where quality, biodiversity, and family know-how come together.\u003c\/p\u003e\n\u003cp style=\"margin: 0;\"\u003eThe lactic fermentation of this coffee is what sets it apart: a controlled fermentation that encourages lactic bacteria activity to develop a more expressive cup, with a creamy texture, delicate acidity, and fruity notes.\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: ESPRESSO EXTRACTION PARAMETERS\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 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);\"\u003e38 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;\"\u003e26 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 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-javafrinsa\"\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 90 °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-javafrinsa\" 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-javafrinsa\" 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-javafrinsa\" style=\"font-weight: 950; font-size: 28px; letter-spacing: .01em;\"\u003e0:00\u003c\/span\u003e\u003c\/div\u003e\n\u003cdiv id=\"v60WakeStatus-javafrinsa\" style=\"flex-basis: 100%; opacity: .6; font-size: 12px; line-height: 1.3; margin-top: 2px;\"\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 id=\"v60-card-1-javafrinsa\" 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-javafrinsa\" 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 45 g\u003c\/span\u003e\u003c\/div\u003e\n\u003c\/div\u003e\n\u003cdiv id=\"v60-card-2-javafrinsa\" 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:45\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-javafrinsa\" 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 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+125 g\u003c\/span\u003e\u003c\/div\u003e\n\u003c\/div\u003e\n\u003cdiv id=\"v60-card-3-javafrinsa\" 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:50\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-javafrinsa\" style=\"padding: 5px 9px; border-radius: 999px; background: rgba(0,0,0,.05); border: 1px solid rgba(0,0,0,.12);\"\u003ePour for 0:25s\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:55\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 = '-javafrinsa';\n  var END_AT = 175;\n  var phases = [\n    { key: 1, t: 0,   pourLen: 10 },\n    { key: 2, t: 45,  pourLen: 30 },\n    { key: 3, t: 110, pourLen: 25 }\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 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","brand":"ZAB","offers":[{"title":"250g","offer_id":53252202791221,"sku":"CAF-SIN-FRIN-250","price":35.0,"currency_code":"CAD","in_stock":false},{"title":"808g","offer_id":53252202823989,"sku":"CAF-SIN-FRIN-808","price":105.0,"currency_code":"CAD","in_stock":false}],"thumbnail_url":"\/\/cdn.shopify.com\/s\/files\/1\/2716\/1842\/files\/frinsa-250g_8c18fad6-f9a3-4428-8617-061b45cc8cd4.jpg?v=1787674162"},{"product_id":"ethiopie-kossa-geshe","title":"ETHIOPIA - KOSSA GESHE","description":"\u003cp\u003e \u003c\/p\u003e\n\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;\"\u003eRASPBERRY JAM + FLORAL + DARK CHOCOLATE\u003c\/div\u003e\n\u003c\/div\u003e\n\u003c!-- ========= END SECTION 1 ========= --\u003e\n\n\u003cp\u003e \u003c\/p\u003e\n\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\/0y9jPTHd9n0\" title=\"YouTube video player\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" allowfullscreen\u003e\u003c\/iframe\u003e\u003c\/div\u003e\n\n\u003cp\u003e \u003c\/p\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 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\u003eLimmu Kossa District, Jimma Zone, Oromia Region, Ethiopia\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003ePRODUCERS\u003c\/td\u003e\n\u003ctd\u003eKossa Geshe Group\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eLOT MANAGER\u003c\/td\u003e\n\u003ctd\u003eAbdulwahid Sherif\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eVARIETY\u003c\/td\u003e\n\u003ctd\u003e74110, 74140, 74112, 74166\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\u003e1800 m\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\u003e1200 kg\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eFOB\u003c\/td\u003e\n\u003ctd\u003e$4.20 USD\/lb\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eDELIVERED PRICE\u003c\/td\u003e\n\u003ctd\u003e$7.83 CAD\/LB\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eRELATIONSHIP\u003c\/td\u003e\n\u003ctd\u003e2 years\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\n\u003cp\u003e \u003c\/p\u003e\n\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;\"\u003eKossa Geshe is a 1,000-hectare farm located in the highlands of the Kebena Forest, in the Limmu Kossa District. Established in 2009 on land granted by the Ethiopian government, the farm was created with the goal of preserving one of the country's last remaining large areas of dense forest.\u003c\/p\u003e\n\u003cp style=\"margin: 0;\"\u003eAbdulwahid Sherif has managed Kossa Geshe since its very first harvest in 2016. His coffees quickly stood out for their quality, notably earning a Good Food Award in 2018. Since then, he has continued to invest in quality, infrastructure, and workers' living conditions, including the construction of a school on the farm.\u003c\/p\u003e\n\u003c\/div\u003e\n\u003c\/div\u003e\n\u003c!-- ========= END SECTION 3 ========= --\u003e\n\n\u003cp\u003e \u003c\/p\u003e\n\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);\"\u003e37 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;\"\u003e27 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\n\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\n\u003cp\u003e \u003c\/p\u003e\n\n\u003c!-- =========================================================\n  SECTION 5: V60\n========================================================= --\u003e\n\u003cdiv style=\"width: 100%; margin: 0 auto;\"\u003e\n\u003cdetails id=\"v60Details-kossageshe-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 89 °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\n\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-kossageshe-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 type=\"button\" id=\"v60StopBtn-kossageshe-en\"\u003eStop\u003c\/button\u003e\n\u003c\/div\u003e\n\u003cdiv style=\"display: flex; gap: 10px; align-items: baseline; line-height: 1;\"\u003e\n\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-kossageshe-en\"\u003e0:00\u003c\/span\u003e\n\u003c\/div\u003e\n\u003cdiv style=\"flex-basis: 100%; opacity: .6; font-size: 12px; line-height: 1.3; margin-top: 2px;\" id=\"v60WakeStatus-kossageshe-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-kossageshe-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\n\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-kossageshe-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\n\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-kossageshe-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\n\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-kossageshe-en\"\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 140 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+90 g\u003c\/span\u003e\n\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-kossageshe-en\"\u003e\n\u003cdiv style=\"display: flex; gap: 10px; align-items: baseline; margin-bottom: 6px;\"\u003e\n\u003cdiv style=\"font-weight: 900;\"\u003e1:25\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\n\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-kossageshe-en\"\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+85 g\u003c\/span\u003e\n\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;\"\u003e3:00\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\n\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 = '-kossageshe-en';\n  var END_AT = 180;\n  var phases = [\n    { key: 1, t: 0,  pourLen: 10 },\n    { key: 2, t: 40, pourLen: 20 },\n    { key: 3, t: 85, 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 \u003c 10 ? '0' : '') + s;\n  }\n  function getCurrentPhaseKey(elapsed) {\n    var current = phases[0].key;\n    for (var i = 0; i \u003c phases.length; i++) if (elapsed \u003e= phases[i].t) current = phases[i].key;\n    return current;\n  }\n  function getPourKey(elapsed) {\n    for (var i = phases.length - 1; i \u003e= 0; i--) {\n      var p = phases[i];\n      if (elapsed \u003e= p.t \u0026\u0026 elapsed \u003c (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 \u003e= 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' \u0026\u0026 startTime \u0026\u0026 !wakeLock) enableWakeLock();\n  });\n})();\n\u003c\/script\u003e\n\u003c\/svg\u003e","brand":"ZAB","offers":[{"title":"300g","offer_id":53628922200373,"sku":"CAF-SIN-KOSS-300","price":26.5,"currency_code":"CAD","in_stock":true},{"title":"808g","offer_id":53628922233141,"sku":"CAF-SIN-KOSS-808","price":62.0,"currency_code":"CAD","in_stock":true},{"title":"2268g (5lbs)","offer_id":53628922265909,"sku":"CAF-SIN-KOSS-2268","price":160.0,"currency_code":"CAD","in_stock":true},{"title":"100g","offer_id":53628922298677,"sku":"CAF-SIN-KOSS-100","price":13.25,"currency_code":"CAD","in_stock":true},{"title":"Bucket - 5lbs (Livraison locale seulement)","offer_id":53628922331445,"sku":"CAF-SIN-KOSS-BUCK-5","price":185.0,"currency_code":"CAD","in_stock":true},{"title":"Bucket - 15lbs (Livraison locale seulement)","offer_id":53628922364213,"sku":"CAF-SIN-KOSS-BUCK-15","price":505.0,"currency_code":"CAD","in_stock":true}],"thumbnail_url":"\/\/cdn.shopify.com\/s\/files\/1\/2716\/1842\/files\/kossa-300g-retour.jpg?v=1791468779"},{"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 4 BIS: FELLOW AIDEN PARAMETERS\n========================================================= --\u003e\n\u003cdiv style=\"width: 100%; margin: 0 auto 12px auto;\"\u003e\n\u003cdiv style=\"border: 2px solid #000; border-radius: 12px; overflow: hidden;\"\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;\"\u003eSettings for the Fellow Aiden\u003c\/div\u003e\n\u003cdiv style=\"padding: 16px 14px; background: transparent;\"\u003e\n\u003cp style=\"margin: 0;\"\u003e\u003ca rel=\"noopener\" href=\"https:\/\/brew.link\/p\/Vk2j\" target=\"_blank\"\u003eDownload the Kenya Kiangoi profile for the Fellow Aiden machine!\u003c\/a\u003e\u003c\/p\u003e\n\u003c\/div\u003e\n\u003c\/div\u003e\n\u003c\/div\u003e\n\u003c!-- ========= END SECTION 4 BIS ========= --\u003e\n\u003cp\u003e \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"},{"product_id":"colombie-augusto-ortega","title":"COLOMBIA - AUGUSTO ORTEGA","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;\"\u003eWHITE NECTARINE + HONEYDEW + FLORAL + CANE SUGAR\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\/I9VhuDSxBl8\" 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=\"display: flex; flex-wrap: wrap; gap: 12px; align-items: stretch; width: 100%; margin: 0 auto 12px auto;\"\u003e\n\u003cdiv class=\"photo-producteur\" style=\"flex: 1 1 220px; max-width: 100%;\"\u003e\u003cimg src=\"https:\/\/cdn.shopify.com\/s\/files\/1\/2716\/1842\/files\/2026-11-01-augusto-ortega-producteur.jpg?v=1793545354\" alt=\"Augusto Ortega holding up a coffee leaf on his farm in San Agustín, Colombia\" width=\"900\" height=\"1200\" loading=\"lazy\" style=\"display: block; width: 100%; height: 100%; min-height: 280px; object-fit: cover; object-position: 15% center; border: 2px solid #000; border-radius: 12px;\"\u003e\u003c\/div\u003e\n\u003cdiv style=\"flex: 2 1 320px; min-width: 0;\"\u003e\n\u003cdiv style=\"width: 100%; margin: 0;\"\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\u003eKennedy village, San Agustin municipality, Huila department, Colombia\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003ePRODUCERS\u003c\/td\u003e\n\u003ctd\u003eAugusto Ortega\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eFARM\u003c\/td\u003e\n\u003ctd\u003eFinca Las Asturias\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eVARIETY\u003c\/td\u003e\n\u003ctd\u003eSidra\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\u003e1680 m\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003ePARTNERS\u003c\/td\u003e\n\u003ctd\u003eSemilla and Monkaaba\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$8.27 USD\/lb\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eDELIVERED PRICE\u003c\/td\u003e\n\u003ctd\u003e$15.55 CAD\/LB\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eFARMGATE PRICE\u003c\/td\u003e\n\u003ctd\u003e5,000,000 COP \/ Carga\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eRELATIONSHIP\u003c\/td\u003e\n\u003ctd\u003e3 years\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003c\/tbody\u003e\n\u003c\/table\u003e\n\u003c\/div\u003e\n\u003c\/div\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 delicate coffee that opens with floral and stone fruit aromas, such as white nectarine. As it cools, it reveals the sweetness of honeydew melon and cane sugar, with a silky texture. Its acidity, reminiscent of apple and pear, gives it a lovely liveliness.\u003c\/p\u003e\n\u003cp style=\"margin: 0 0 12px 0;\"\u003eAugusto founded Finca Las Asturias in 1985, becoming one of the first coffee producers in his region, despite the challenges of arid soils and landslides. In 2000, he turned to specialty coffee. Today, Augusto plays a key role in the development of Semilla, our coffee importer, in San Agustín. Respected in his community, he has helped bring many producers into the project and build relationships based on trust.\u003c\/p\u003e\n\u003cp style=\"margin: 0 0 12px 0;\"\u003eLooking ahead, Augusto hopes to keep taking on the challenges of coffee farming by planting new varieties and encouraging knowledge sharing and mutual support among producers.\u003c\/p\u003e\n\u003cp style=\"margin: 0;\"\u003eThis coffee is made possible by the work of Semilla as importer and Monkaaba at origin. Based in San Agustín, Colombia, Monkaaba is an initiative led by Esnaider Ortega Gómez that supports coffee producers in developing their skills and accessing better markets. Through knowledge sharing and collective cupping sessions, Monkaaba fosters their autonomy and more lasting relationships in the specialty coffee chain. Semilla supports this approach by building connections between producers and roasters.\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: V60\n========================================================= --\u003e\n\u003cdiv style=\"width: 100%; margin: 0 auto;\"\u003e\n\u003cdetails id=\"v60Details-augustoortega-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-augustoortega-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-augustoortega-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-augustoortega-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-augustoortega-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-augustoortega-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-augustoortega-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 40 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-augustoortega-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-augustoortega-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+60 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-augustoortega-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-augustoortega-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-augustoortega-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-augustoortega-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:30\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 4 ========= --\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 = '-augustoortega-en';\n  var END_AT = 150;\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":"200g","offer_id":53634220687669,"sku":"CAF-SIN-AUGU-200","price":32.0,"currency_code":"CAD","in_stock":true}],"thumbnail_url":"\/\/cdn.shopify.com\/s\/files\/1\/2716\/1842\/files\/augusto-ortega-200g-new.jpg?v=1793544436"}],"url":"https:\/\/zabcafe.com\/en\/collections\/meilleurs-vendeurs.oembed","provider":"Zab Café","version":"1.0","type":"link"}