{"title":"Specialty Coffee Discovery","description":null,"products":[{"product_id":"aeropress-bundle-1","title":"AeroPress Starter Kit","description":"\u003cp\u003eA compact, versatile setup for bold, smooth, and expressive coffee.\u003c\/p\u003e\u003cp\u003eThe \u003cstrong\u003eAeroPress Brewing Bundle\u003c\/strong\u003e combines the full AeroPress kit with a specialty coffee selected by our roasters to perform beautifully with this method. Ideal for home, travel, or the office, this bundle delivers rich flavour with low bitterness and total control over your brew.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eWhat’s included:\u003c\/strong\u003e\u003c\/p\u003e\u003cul\u003e\n\u003cli\u003eAeroPress Brewer\n\u003c\/li\u003e\n\u003cli\u003eAeroPress Paper Filters\n\u003c\/li\u003e\n\u003cli\u003eStirrer\n\u003c\/li\u003e\n\u003cli\u003eMeasuring Spoon\n\u003c\/li\u003e\n\u003cli\u003e1 bag of specialty coffee, chosen by our roasters to match the AeroPress profile\n\u003c\/li\u003e\n\u003c\/ul\u003e\u003cp\u003eQuick to use, endlessly adaptable, and consistently delicious — this bundle is perfect for curious brewers who enjoy experimenting without compromising on quality.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eNOTE: \u003c\/strong\u003eIf you wish to have your coffee ground, select your grind options. We recommend it ground for AeroPress.\u003c\/p\u003e","brand":"Fábrica Coffee Roasters","offers":[{"title":"Default Title","offer_id":52083511296347,"sku":"BDL-AEROSTART","price":54.9,"currency_code":"EUR","in_stock":true}],"thumbnail_url":"\/\/cdn.shopify.com\/s\/files\/1\/0953\/5553\/5707\/files\/aeropress-starter-kit-specialty-coffee-fabrica.webp?v=1769107760"},{"product_id":"v60-bundle","title":"V60 Starter Kit","description":"\u003cp\u003e\u003cspan class=\"\"\u003eEverything you need to master the art of the pour-over is right here.\u003c\/span\u003e\u003cspan class=\"\"\u003e This curated bundle pairs the iconic \u003c\/span\u003e\u003cb data-path-to-node=\"3\" data-index-in-node=\"107\" class=\"\"\u003eHario V60 Craft Coffee Maker\u003c\/b\u003e\u003cspan class=\"\"\u003e—renowned for its ability to highlight the delicate,\u003c\/span\u003e\u003cspan class=\"\"\u003e clean notes of high-quality beans—with a bag of our \u003c\/span\u003e\u003cb data-path-to-node=\"3\" data-index-in-node=\"240\" class=\"\"\u003ePremium Specialty Filter Coffee\u003c\/b\u003e\u003cspan class=\"\"\u003e.\u003c\/span\u003e\u003cspan class=\"\"\u003e Whether you are a beginner or a seasoned barista,\u003c\/span\u003e\u003cspan class=\"\"\u003e this combination ensures a bright,\u003c\/span\u003e\u003cspan class=\"\"\u003e aromatic,\u003c\/span\u003e\u003cspan class=\"\"\u003e and balanced cup every single morning.\u003c\/span\u003e\u003cspan class=\"\"\u003e Simply let us know your preferred brewing method,\u003c\/span\u003e\u003cspan class=\"\"\u003e and we will custom-grind your coffee to perfection.\u003c\/span\u003e\u003c\/p\u003e","brand":"Fábrica Coffee Roasters","offers":[{"title":"Default Title","offer_id":52083527549275,"sku":"BDL-V60START","price":41.9,"currency_code":"EUR","in_stock":true}],"thumbnail_url":"\/\/cdn.shopify.com\/s\/files\/1\/0953\/5553\/5707\/files\/v60-starter-kit-specialty-coffee-fabrica.webp?v=1769107222"},{"product_id":"specialty-coffee-discovery-pack","title":"Specialty Coffee Discovery Pack","description":"\u003cp\u003eDiscover the world of Specialty Coffee - Specialty coffee is characterized by the distinct presence of sensory profiles, including fruity, chocolatey, floral, sweet, spicy notes, and a vast array of others. Discover a range of unique origins from the world's finest terroirs.\u003c\/p\u003e\n\u003cp\u003e \u003c\/p\u003e\n\u003cp\u003eThis discovery pack contains 6 x 35g specialty coffee bags. A 35g bag yields around 2x 250ml filter coffee brews and around 4 single espresso shots - the perfect dose to experience out of the ordinary flavors.\u003c\/p\u003e","brand":"Fábrica Coffee Roasters","offers":[{"title":"Default Title","offer_id":52846216839515,"sku":null,"price":14.9,"currency_code":"EUR","in_stock":true}],"thumbnail_url":"\/\/cdn.shopify.com\/s\/files\/1\/0953\/5553\/5707\/files\/discovery-pack-specialty-coffee-fabrica-front.webp?v=1776868467"},{"product_id":"fabrica-coffee-subscription-exotics","title":"Fábrica's Coffee Subscription - Exotics","description":"\u003cp\u003eOut of the ordinary, special flavour profiles. Packed from our freshest roast and shipped within 24-48h.\u003c\/p\u003e\n\u003cdiv id=\"fspdp-exotics\" class=\"fspdp-exotics-scope\" style=\"display:none\"\u003e\n  \u003ch3 class=\"fspdp-exotics-title\"\u003eIn this week's lineup\u003c\/h3\u003e\n  \u003cdiv class=\"fspdp-exotics-grid\"\u003e\n    \u003cdiv class=\"fspdp-exotics-coffee\" data-c=\"xEsp1\"\u003e\n      \u003cdiv class=\"fspdp-exotics-img\"\u003e\u003cimg src=\"https:\/\/cdn.shopify.com\/s\/files\/1\/0953\/5553\/5707\/files\/cyeza-250g-fabrica-specialty-coffee-bag.webp?v=1785771983\u0026amp;width=420\" alt=\"Cyeza - Rwanda\" loading=\"lazy\"\u003e\u003c\/div\u003e\n      \u003cspan class=\"fspdp-exotics-tag\"\u003eExotics\u003c\/span\u003e\n      \u003ch4\u003eCyeza - Rwanda\u003c\/h4\u003e\n      \u003cdiv class=\"fspdp-exotics-notes\"\u003eRed berries, cola, dark chocolate\u003c\/div\u003e\n      \u003cdiv class=\"fspdp-exotics-colr\"\u003e\n\u003cspan class=\"fspdp-exotics-role\"\u003eEspresso\u003c\/span\u003e\u003cspan class=\"fspdp-exotics-cnt\"\u003e\u003c\/span\u003e\n\u003c\/div\u003e\n    \u003c\/div\u003e\n    \u003cdiv class=\"fspdp-exotics-coffee\" data-c=\"xEsp2\"\u003e\n      \u003cdiv class=\"fspdp-exotics-img\"\u003e\u003cimg src=\"https:\/\/cdn.shopify.com\/s\/files\/1\/0953\/5553\/5707\/files\/las-amapolas-250g-fabrica-specialty-coffee-bag.webp?v=1785771788\u0026amp;width=420\" alt=\"Las Amapolas - Guatemala\" loading=\"lazy\"\u003e\u003c\/div\u003e\n      \u003cspan class=\"fspdp-exotics-tag\"\u003eExotics\u003c\/span\u003e\n      \u003ch4\u003eLas Amapolas - Guatemala\u003c\/h4\u003e\n      \u003cdiv class=\"fspdp-exotics-notes\"\u003eChocolate, orange, plum\u003c\/div\u003e\n      \u003cdiv class=\"fspdp-exotics-colr\"\u003e\n\u003cspan class=\"fspdp-exotics-role\"\u003eEspresso\u003c\/span\u003e\u003cspan class=\"fspdp-exotics-cnt\"\u003e\u003c\/span\u003e\n\u003c\/div\u003e\n    \u003c\/div\u003e\n    \u003cdiv class=\"fspdp-exotics-coffee\" data-c=\"xFil1\"\u003e\n      \u003cdiv class=\"fspdp-exotics-img\"\u003e\u003cimg src=\"https:\/\/cdn.shopify.com\/s\/files\/1\/0953\/5553\/5707\/files\/sholi-250g-fabrica-specialty-coffee-bag.webp?v=1785771945\u0026amp;width=420\" alt=\"Sholi - Rwanda\" loading=\"lazy\"\u003e\u003c\/div\u003e\n      \u003cspan class=\"fspdp-exotics-tag\"\u003eExotics\u003c\/span\u003e\n      \u003ch4\u003eSholi - Rwanda\u003c\/h4\u003e\n      \u003cdiv class=\"fspdp-exotics-notes\"\u003eFlorals, citrus, black tea\u003c\/div\u003e\n      \u003cdiv class=\"fspdp-exotics-colr\"\u003e\n\u003cspan class=\"fspdp-exotics-role\"\u003eFilter\u003c\/span\u003e\u003cspan class=\"fspdp-exotics-cnt\"\u003e\u003c\/span\u003e\n\u003c\/div\u003e\n    \u003c\/div\u003e\n    \u003cdiv class=\"fspdp-exotics-coffee\" data-c=\"xFil2\"\u003e\n      \u003cdiv class=\"fspdp-exotics-img\"\u003e\u003cimg src=\"https:\/\/cdn.shopify.com\/s\/files\/1\/0953\/5553\/5707\/files\/nahuatl-250g-fabrica-specialty-coffee-bag.webp?v=1785771836\u0026amp;width=420\" alt=\"Nahuatl - Guatemala\" loading=\"lazy\"\u003e\u003c\/div\u003e\n      \u003cspan class=\"fspdp-exotics-tag\"\u003eExotics\u003c\/span\u003e\n      \u003ch4\u003eNahuatl - Guatemala\u003c\/h4\u003e\n      \u003cdiv class=\"fspdp-exotics-notes\"\u003eStone fruit, honey, toffee\u003c\/div\u003e\n      \u003cdiv class=\"fspdp-exotics-colr\"\u003e\n\u003cspan class=\"fspdp-exotics-role\"\u003eFilter\u003c\/span\u003e\u003cspan class=\"fspdp-exotics-cnt\"\u003e\u003c\/span\u003e\n\u003c\/div\u003e\n    \u003c\/div\u003e\n\u003c\/div\u003e\n\u003c\/div\u003e\n\u003cdiv id=\"fspdp-exotics-extra\" class=\"fspdp-exotics-scope\" style=\"display:none\"\u003e\n  \u003cdiv class=\"fspdp-exotics-how\"\u003e\n    \u003ch3 class=\"fspdp-exotics-title\" style=\"margin-top:20px;\"\u003eHow it works\u003c\/h3\u003e\n    \u003cdiv class=\"fspdp-exotics-step\"\u003e\n\u003cspan class=\"fspdp-exotics-dot\"\u003e\u003c\/span\u003e\u003cdiv\u003e\n\u003cb\u003eToday\u003c\/b\u003e\u003cspan\u003eYou subscribe\u003c\/span\u003e\n\u003c\/div\u003e\n\u003c\/div\u003e\n    \u003cdiv class=\"fspdp-exotics-step\"\u003e\n\u003cspan class=\"fspdp-exotics-dot\"\u003e\u003c\/span\u003e\u003cdiv\u003e\n\u003cb\u003eWithin 24-48h\u003c\/b\u003e\u003cspan\u003ePacked from the freshest roast \u0026amp; shipped\u003c\/span\u003e\n\u003c\/div\u003e\n\u003c\/div\u003e\n    \u003cdiv class=\"fspdp-exotics-step\"\u003e\n\u003cspan class=\"fspdp-exotics-dot g\"\u003e\u003c\/span\u003e\u003cdiv\u003e\n\u003cb\u003e1-2 business days\u003c\/b\u003e\u003cspan\u003eAt your door\u003c\/span\u003e\n\u003c\/div\u003e\n\u003c\/div\u003e\n  \u003c\/div\u003e\n  \u003cdiv class=\"fspdp-exotics-pills\"\u003e\n    \u003cspan class=\"fspdp-exotics-pill\"\u003eShips in 24-48h\u003c\/span\u003e\n    \u003cspan class=\"fspdp-exotics-pill\"\u003eFree shipping\u003c\/span\u003e\n    \u003cspan class=\"fspdp-exotics-pill\"\u003eTailored to you\u003c\/span\u003e\n    \u003cspan class=\"fspdp-exotics-pill\"\u003ePause, skip or cancel anytime\u003c\/span\u003e\n  \u003c\/div\u003e\n\u003c\/div\u003e\n\u003cstyle\u003e\n  .fspdp-exotics-scope { display: block; width: 100%; padding: 8px 0; }\n  .fspdp-exotics-scope .fspdp-exotics-title { font-size: 22px; font-weight: 700; letter-spacing: -0.02em; color: #191919; margin: 0 0 12px; }\n  .fspdp-exotics-scope .fspdp-exotics-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 12px; }\n  .fspdp-exotics-scope .fspdp-exotics-coffee { display: flex; flex-direction: column; padding: 18px 18px 16px; border-radius: 16px; background: rgba(237, 231, 248, 0.75); transition: opacity 0.25s ease; }\n  .fspdp-exotics-scope .fspdp-exotics-coffee.dim { opacity: 0.35; }\n  .fspdp-exotics-scope .fspdp-exotics-img { width: 100%; height: 200px; display: flex; align-items: center; justify-content: center; margin-bottom: 12px; }\n  .fspdp-exotics-scope .fspdp-exotics-img img { width: auto; height: 100%; }\n  .fspdp-exotics-scope .fspdp-exotics-img img { max-width: 100%; max-height: 100%; object-fit: contain; display: block; mix-blend-mode: multiply; border: none !important; box-shadow: none !important; }\n  .fspdp-exotics-scope h4 { font-size: 16px; font-weight: 700; letter-spacing: -0.01em; line-height: 1.25; color: #191919; margin: 0 0 2px; }\n  .fspdp-exotics-scope .fspdp-exotics-tag { display: block; font-size: 10px; text-transform: uppercase; letter-spacing: 0.8px; font-weight: 800; color: #534AB7; margin-bottom: 3px; }\n  .fspdp-exotics-scope .fspdp-exotics-notes { font-size: 13px; color: #6f6a62; }\n  .fspdp-exotics-scope .fspdp-exotics-colr { display: flex; justify-content: space-between; align-items: center; gap: 8px; margin-top: auto; padding-top: 14px; flex-wrap: wrap; }\n  .fspdp-exotics-scope .fspdp-exotics-role { font-size: 10px; text-transform: uppercase; letter-spacing: 0.5px; font-weight: 700; border: 1px solid rgba(25, 25, 25, 0.35); border-radius: 90px; padding: 4px 12px; white-space: nowrap; color: #191919; }\n  .fspdp-exotics-scope .fspdp-exotics-cnt { display: none; font-size: 12px; font-weight: 800; background: #191919; color: #FFFEFA; border-radius: 90px; padding: 3px 12px; white-space: nowrap; }\n  .fspdp-exotics-scope .fspdp-exotics-coffee.on .fspdp-exotics-cnt { display: inline-block; }\n  .fspdp-exotics-scope .fspdp-exotics-note { font-size: 12px; color: #6f6a62; margin: 12px 0 0; }\n  .fspdp-exotics-scope .fspdp-exotics-how { margin-top: 4px; }\n  .fspdp-exotics-scope .fspdp-exotics-step { display: flex; gap: 14px; align-items: flex-start; padding: 10px 4px; border-bottom: 1px solid rgba(25, 25, 25, 0.08); }\n  .fspdp-exotics-scope .fspdp-exotics-step:last-child { border-bottom: none; }\n  .fspdp-exotics-scope .fspdp-exotics-dot { display: inline-block !important; width: 10px; height: 10px; border-radius: 50%; background: #191919; margin-top: 7px; flex-shrink: 0; }\n  .fspdp-exotics-scope .fspdp-exotics-dot.g { background: #2FAC66; }\n  .fspdp-exotics-scope .fspdp-exotics-step b { display: block; font-size: 12px; text-transform: uppercase; letter-spacing: 0.5px; color: #6f6a62; font-weight: 700; }\n  .fspdp-exotics-scope .fspdp-exotics-step span:not(.fspdp-exotics-dot) { font-size: 15px; font-weight: 600; color: #191919; }\n  .fspdp-exotics-scope .fspdp-exotics-pills { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 24px; }\n  .fspdp-exotics-scope .fspdp-exotics-pill { font-size: 14px; font-weight: 400; color: #191919; padding: 9px 18px; border-radius: 90px; border: 1px solid #191919; background: transparent; white-space: nowrap; }\n\u003c\/style\u003e\n\u003cscript\u003e\n(function () {\n  var TIER = \"exotics\";\n  var HANDLE = 'fabrica-coffee-subscription-' + TIER;\n  if (window.location.pathname.indexOf(HANDLE) === -1) return; \/\/ not this product's page - do nothing\n  var panel = document.getElementById(\"fspdp-exotics\");\n  if (!panel) return;\n  var WASH = \"#F2EDFB\", ACCENT = \"#534AB7\", TILE = \"#EDE7F8\", STROKE = \"#CFC5EE\";\n  \/\/ The JS-written strings can't go through Shopify's translate app (it only\n  \/\/ sees static content), so they localize off the storefront locale directly.\n  var IS_PT = (((window.Shopify \u0026\u0026 window.Shopify.locale) || document.documentElement.lang || '') + '').toLowerCase().indexOf('pt') === 0;\n  var L = IS_PT\n    ? { youPay: 'Total', perDelivery: 'por entrega', perBag: '\/ bag', bag: 'bag', bags: 'bags',\n        youSave: 'Poupe ', shipStrong: 'Portes grátis', shipRest: ' em Portugal e Espanha, em cada entrega' }\n    : { youPay: 'You pay', perDelivery: 'per delivery', perBag: '\/ bag', bag: 'bag', bags: 'bags',\n        youSave: 'You save ', shipStrong: 'Free shipping', shipRest: ' across Portugal and Spain, on every delivery' };\n  var BAGS = { '1 bag': 1, '2 bags': 2, '4 bags': 4, '6 bags': 6 };\n  var BREW = { 'Espresso': 'esp', 'Filter': 'fil', 'Half \u0026 half': 'mix' };\n  function sel() {\n    var q = 1, b = 'esp';\n    Array.prototype.forEach.call(document.querySelectorAll('input[type=radio]'), function (r) {\n      if (r.checked) {\n        if (BAGS[r.value]) q = BAGS[r.value];\n        if (BREW[r.value]) b = BREW[r.value];\n      }\n    });\n    return { q: q, b: b };\n  }\n  function half(m) { return [Math.ceil(m \/ 2), Math.floor(m \/ 2)]; }\n  function allocation(q, b) {\n    var c = {}, s, e, f;\n    if (TIER === 'decaf') { c.decaf = q; return c; }\n    if (TIER === 'classics') {\n      if (b === 'esp') c.cEsp = q;\n      else if (b === 'fil') c.cFil = q;\n      else { s = half(q); c.cEsp = s[0]; if (s[1]) c.cFil = s[1]; }\n      return c;\n    }\n    if (b === 'esp') { s = half(q); c.xEsp1 = s[0]; if (s[1]) c.xEsp2 = s[1]; }\n    else if (b === 'fil') { s = half(q); c.xFil1 = s[0]; if (s[1]) c.xFil2 = s[1]; }\n    else {\n      s = half(q); e = half(s[0]); f = half(s[1]);\n      c.xEsp1 = e[0]; if (e[1]) c.xEsp2 = e[1];\n      if (f[0]) c.xFil1 = f[0]; if (f[1]) c.xFil2 = f[1];\n    }\n    return c;\n  }\n  function update() {\n    var s = sel();\n    var alloc = allocation(s.q, s.b);\n    Array.prototype.forEach.call(panel.querySelectorAll('[data-c]'), function (el) {\n      var n = alloc[el.getAttribute('data-c')];\n      var cnt = el.querySelector('.' + \"fspdp-exotics\" + '-cnt');\n      if (n) { el.classList.add('on'); el.classList.remove('dim'); cnt.textContent = '\\u00d7 ' + n + ' ' + (n === 1 ? L.bag : L.bags); }\n      else { el.classList.remove('on'); el.classList.add('dim'); }\n    });\n  }\n  \/\/ \"You pay\" summary above the subscribe button. Reads the widget's server-\n  \/\/ rendered variant-\u003eplan price map, so it never depends on the widget JS's\n  \/\/ own rebase timing. Prices are flat across frequencies, but we still honour\n  \/\/ the selected plan id in case that ever changes.\n  function money(c) {\n    try { if (window.Shopify \u0026\u0026 Shopify.formatMoney \u0026\u0026 Shopify.money_format) return Shopify.formatMoney(Math.round(c), Shopify.money_format); } catch (e) { \/* fall through *\/ }\n    return (Math.round(c) \/ 100).toFixed(2).replace('.', ',') + '\\u20ac';\n  }\n  \/\/ The info container holds several cart forms (sample add-on etc.) - anchor\n  \/\/ on the buy buttons and walk up to THEIR form, which carries the variant id.\n  function buyButtons() {\n    return document.querySelector('.product__info-container .product-form__buttons');\n  }\n  function payData() {\n    var mapEl = document.querySelector('.js-variant-plans-data');\n    var btns = buyButtons();\n    var form = btns \u0026\u0026 btns.closest('form');\n    if (!mapEl || !form) return null;\n    var data; try { data = JSON.parse(mapEl.textContent); } catch (e) { return null; }\n    var vid = form.querySelector('input[name=\"id\"]');\n    var v = vid \u0026\u0026 data[String(vid.value)];\n    if (!v) return null;\n    var planInp = document.querySelector('input[name=\"selling_plan_id\"]:checked');\n    var hidden = form.querySelector('input[name=\"selling_plan\"]');\n    var planId = planInp ? String(planInp.value) : String((hidden \u0026\u0026 hidden.value) || '');\n    function priceOf(x) { return planId \u0026\u0026 x.plans \u0026\u0026 x.plans[planId] != null ? x.plans[planId] : x.base; }\n    var total = priceOf(v);\n    var bags = parseInt(v.bags, 10) || 1;\n    \/\/ The struck price is what these same bags cost bought one at a time on the\n    \/\/ same plan. Every 1-bag variant of a tier shares one price, so the first\n    \/\/ one found is the tier's unit price.\n    var unit = null;\n    for (var k in data) { if (parseInt(data[k].bags, 10) === 1) { unit = priceOf(data[k]); break; } }\n    var was = unit != null ? unit * bags : 0;\n    return { total: total, bags: bags, was: was \u003e total ? was : 0 };\n  }\n  function updatePay() {\n    var el = document.getElementById(\"fspdp-exotics\" + '-pay');\n    if (!el) return;\n    var d = payData();\n    if (!d || !d.total) { el.style.display = 'none'; return; }\n    el.style.display = '';\n    el.querySelector('.js-pay-total').textContent = money(d.total);\n    el.querySelector('.js-pay-per').textContent = money(Math.round(d.total \/ d.bags)) + ' ' + L.perBag + (d.bags \u003e 1 ? ' \\u00b7 ' + d.bags + ' ' + L.bags : '');\n    \/\/ No saving at 1 bag - both elements empty themselves rather than show a\n    \/\/ struck price identical to the one beside it.\n    el.querySelector('.js-pay-was').textContent = d.was ? money(d.was) : '';\n    el.querySelector('.js-pay-save').textContent = d.was ? L.youSave + money(d.was - d.total) : '';\n  }\n  function mountPay() {\n    if (document.getElementById(\"fspdp-exotics\" + '-pay')) { updatePay(); return; }\n    var btns = buyButtons();\n    if (!btns) return;\n    var el = document.createElement('div');\n    el.id = \"fspdp-exotics\" + '-pay';\n    el.className = \"fspdp-exotics\" + '-pay';\n    el.innerHTML = '\u003cdiv\u003e\u003cspan class=\"' + \"fspdp-exotics\" + '-pay-label\"\u003e' + L.youPay + '\u003c\/span\u003e'\n      + '\u003cs class=\"' + \"fspdp-exotics\" + '-pay-was js-pay-was\"\u003e\u003c\/s\u003e'\n      + '\u003cspan class=\"' + \"fspdp-exotics\" + '-pay-total js-pay-total\"\u003e\u003c\/span\u003e'\n      + '\u003cspan class=\"' + \"fspdp-exotics\" + '-pay-freq\"\u003e' + L.perDelivery + '\u003c\/span\u003e\u003c\/div\u003e'\n      + '\u003cdiv\u003e\u003cdiv class=\"' + \"fspdp-exotics\" + '-pay-save js-pay-save\"\u003e\u003c\/div\u003e'\n      + '\u003cdiv class=\"' + \"fspdp-exotics\" + '-pay-per js-pay-per\"\u003e\u003c\/div\u003e\u003c\/div\u003e';\n    btns.parentNode.insertBefore(el, btns);\n    updatePay();\n  }\n  \/\/ Free shipping sits UNDER the subscribe button, where the reassurance is\n  \/\/ wanted. The zone qualifier is not decoration - an unqualified \"free\n  \/\/ shipping\" is a claim we cannot keep everywhere (docs\/shipping-rules.md).\n  function mountShip() {\n    if (document.getElementById(\"fspdp-exotics\" + '-ship')) return;\n    var btns = buyButtons();\n    if (!btns) return;\n    var el = document.createElement('div');\n    el.id = \"fspdp-exotics\" + '-ship';\n    el.className = \"fspdp-exotics\" + '-ship';\n    el.innerHTML = '\u003csvg viewBox=\"0 0 24 24\" width=\"24\" height=\"24\" fill=\"none\" stroke=\"' + \"#00C853\" + '\" stroke-width=\"2.1\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"\u003e'\n      + '\u003cpath d=\"M2.6 6.5h10.9v9H2.6z\"\/\u003e\u003cpath d=\"M13.5 9.6h3.7l3.8 3.7v2.2h-7.5z\"\/\u003e'\n      + '\u003ccircle cx=\"6.6\" cy=\"17.6\" r=\"2\"\/\u003e\u003ccircle cx=\"17.1\" cy=\"17.6\" r=\"2\"\/\u003e\u003c\/svg\u003e'\n      + '\u003cspan\u003e\u003cb\u003e' + L.shipStrong + '\u003c\/b\u003e' + L.shipRest + '\u003c\/span\u003e';\n    btns.parentNode.insertBefore(el, btns.nextSibling);\n  }\n  function mount() {\n    document.body.style.setProperty('background', WASH, 'important');\n    var title = document.querySelector('.product__title h1') || document.querySelector('h1.product__title') || document.querySelector('.product__title');\n    if (title) title.style.setProperty('color', ACCENT);\n    var css = document.createElement('style');\n    css.textContent = [\n      '.product__info-container .text-brown1 { color: ' + ACCENT + ' !important; }',\n      '.product__price .text-brown1, .custom-subscription-block .text-brown1, .sticky-bar .text-brown1 { color: ' + ACCENT + ' !important; }',\n      '.' + \"fspdp-exotics\" + '-pay { display: flex; align-items: flex-end; justify-content: space-between; gap: 12px 16px; flex-wrap: wrap; margin: 26px 0 20px; }',\n      '.product__info-container .product-form__buttons .product-form__submit, .sticky-bar .product-form__submit { background-color: ' + ACCENT + ' !important; border-color: ' + ACCENT + ' !important; color: #FFFEFA !important; }',\n      '.' + \"fspdp-exotics\" + '-pay-label { display: block; font-size: 11px; text-transform: uppercase; letter-spacing: 0.8px; font-weight: 800; color: #6f6a62; margin-bottom: 4px; }',\n      '.' + \"fspdp-exotics\" + '-pay-total { font-size: 32px; line-height: 1; font-weight: 700; letter-spacing: -0.02em; color: ' + \"#2FAC66\" + '; }',\n      '.' + \"fspdp-exotics\" + '-pay-was { font-size: 19px; font-weight: 600; color: #9a948b; text-decoration: line-through; margin-right: 9px; }',\n      '.' + \"fspdp-exotics\" + '-pay-was:empty { display: none; }',\n      '.' + \"fspdp-exotics\" + '-pay-save { font-size: 13px; font-weight: 800; text-transform: uppercase; letter-spacing: 0.4px; color: ' + \"#2FAC66\" + '; text-align: right; margin-bottom: 4px; }',\n      '.' + \"fspdp-exotics\" + '-pay-save:empty { display: none; }',\n      '.' + \"fspdp-exotics\" + '-ship { display: flex; align-items: center; gap: 10px; margin: 14px 0 4px; padding: 10px 14px; border-radius: 12px; background: rgba(0, 200, 83, 0.09); font-size: 14px; line-height: 1.35; color: #191919; }',\n      '.' + \"fspdp-exotics\" + '-ship svg { flex-shrink: 0; }',\n      '.' + \"fspdp-exotics\" + '-ship b { font-weight: 700; color: ' + \"#2FAC66\" + '; }',\n      '.' + \"fspdp-exotics\" + '-pay-freq { font-size: 14px; font-weight: 500; color: #6f6a62; margin-left: 6px; }',\n      '.' + \"fspdp-exotics\" + '-pay-per { font-size: 15px; font-weight: 600; color: #6f6a62; padding-bottom: 3px; }',\n      '.product__info-container [class*=\"bg-brown\"], .product__info-container [class*=\"bg-tan\"] { background-color: ' + TILE + ' !important; }',\n      '.product__info-container [class*=\"border-brown\"] { border-color: ' + ACCENT + ' !important; }',\n      '.product__info-container label:has(input:checked) { background-color: ' + TILE + ' !important; border-color: ' + ACCENT + ' !important; }',\n      '.product__info-container input:checked + label { background-color: ' + TILE + ' !important; border-color: ' + ACCENT + ' !important; }',\n      '.grind-note-wrapper input:checked + label { background-color: ' + TILE + ' !important; border-color: ' + ACCENT + ' !important; }',\n      '.product__info-container input:not(:checked) + label { border-color: ' + STROKE + ' !important; }',\n      '.grind-note-wrapper input:not(:checked) + label { border-color: ' + STROKE + ' !important; }',\n      'label.subscription-plan-row:not(:has(input:checked)) { border-color: ' + STROKE + ' !important; }',\n      'quantity-input.quantity { border-color: ' + STROKE + ' !important; }',\n      '.grind-note .custom-select-trigger { border-color: ' + STROKE + ' !important; }',\n      '.grind-note.has-selection .custom-select-trigger, .grind-note.is-open .custom-select-trigger { background-color: ' + TILE + ' !important; border-color: ' + ACCENT + ' !important; }',\n      '.grind-note .custom-select-option::before { border-color: ' + STROKE + ' !important; }',\n      '.grind-note .custom-select-option.selected::before { background-color: ' + ACCENT + ' !important; border-color: ' + ACCENT + ' !important; }',\n      '.quantity__input { background: transparent !important; -webkit-appearance: none !important; appearance: textfield !important; -moz-appearance: textfield !important; }',\n      '.quantity__input::-webkit-inner-spin-button, .quantity__input::-webkit-outer-spin-button { -webkit-appearance: none !important; display: none !important; margin: 0 !important; }',\n      'label.subscription-plan-row:has(input:checked) { background-color: ' + TILE + ' !important; border-color: ' + ACCENT + ' !important; }'\n    ].join('\\n');\n    document.head.appendChild(css);\n    var host = document.querySelector('.product__media-wrapper') || document.querySelector('media-gallery') || document.querySelector('.product__media-gallery') || document.querySelector('.product__media-list');\n    if (host) {\n      Array.prototype.forEach.call(host.children, function (ch) { ch.style.display = 'none'; });\n      host.appendChild(panel);\n    }\n    panel.style.display = 'block';\n    var extra = document.getElementById(\"fspdp-exotics\" + '-extra');\n    var mq = window.matchMedia('(max-width: 749px)');\n    function placeExtra() {\n      if (!extra) return;\n      if (mq.matches) {\n        var info = document.querySelector('.product__info-wrapper') || document.querySelector('.product__info-container');\n        if (info) info.appendChild(extra);\n      } else if (host) {\n        host.appendChild(extra);\n      }\n      extra.style.display = 'block';\n    }\n    placeExtra();\n    if (mq.addEventListener) mq.addEventListener('change', placeExtra);\n    update();\n    mountPay();\n    mountShip();\n    \/\/ Widget builds its rows async - retry so the panel lands even on slow loads.\n    setTimeout(function () { mountPay(); mountShip(); }, 600);\n    setTimeout(function () { mountPay(); mountShip(); }, 2000);\n  }\n  document.addEventListener('change', function (e) {\n    if (e.target \u0026\u0026 e.target.type === 'radio') update();\n    \/\/ After the widget's own 80ms rebase, refresh the pay panel too.\n    setTimeout(updatePay, 160);\n  });\n  \/\/ Live lineup from the roastery app: replace this tier's fallback cards when\n  \/\/ the feed has coffees for it. Same slot-\u003ecard mapping as the landing page.\n  var SLOT_KEY = { exoticEsp1: 'xEsp1', exoticEsp2: 'xEsp2', exoticFil1: 'xFil1', exoticFil2: 'xFil2', classicEsp: 'cEsp', classicFil: 'cFil', decaf: 'decaf' };\n  function escHtml(s) { return String(s).replace(\/\u0026\/g, '\u0026amp;').replace(\/\u003c\/g, '\u0026lt;').replace(\/\u003e\/g, '\u0026gt;').replace(\/\"\/g, '\u0026quot;'); }\n  function liveCards() {\n    fetch('https:\/\/fabrica-roastery.vercel.app\/api\/public\/lineup').then(function (r) { return r.json(); }).then(function (d) {\n      if (!d || !d.slots) return;\n      var mine = d.slots.filter(function (s) { return s.tier === TIER \u0026\u0026 SLOT_KEY[s.slot]; });\n      if (!mine.length) return;\n      var html = mine.map(function (s) {\n        var img = s.imageUrl ? s.imageUrl + (s.imageUrl.indexOf('?') === -1 ? '?' : '\u0026') + 'width=420' : null;\n        var blend = img \u0026\u0026 img.toLowerCase().split('?')[0].slice(-4) === '.png' ? ' style=\"mix-blend-mode:normal\"' : '';\n        var name = s.name + (s.origin ? ' - ' + s.origin : '');\n        return '\u003cdiv class=\"' + \"fspdp-exotics\" + '-coffee\" data-c=\"' + SLOT_KEY[s.slot] + '\"\u003e'\n          + '\u003cdiv class=\"' + \"fspdp-exotics\" + '-img\"\u003e' + (img ? '\u003cimg src=\"' + escHtml(img) + '\" alt=\"' + escHtml(name) + '\"' + blend + '\u003e' : '') + '\u003c\/div\u003e'\n          + '\u003cspan class=\"' + \"fspdp-exotics\" + '-tag\"\u003e' + \"Exotics\" + '\u003c\/span\u003e'\n          + '\u003ch4\u003e' + escHtml(name) + '\u003c\/h4\u003e'\n          + '\u003cdiv class=\"' + \"fspdp-exotics\" + '-notes\"\u003e' + escHtml(s.notes || '') + '\u003c\/div\u003e'\n          + '\u003cdiv class=\"' + \"fspdp-exotics\" + '-colr\"\u003e\u003cspan class=\"' + \"fspdp-exotics\" + '-role\"\u003e' + escHtml(s.role) + '\u003c\/span\u003e\u003cspan class=\"' + \"fspdp-exotics\" + '-cnt\"\u003e\u003c\/span\u003e\u003c\/div\u003e\u003c\/div\u003e';\n      }).join('');\n      var grid = panel.querySelector('[class$=\"-grid\"]');\n      if (grid \u0026\u0026 html) { grid.innerHTML = html; update(); }\n    }).catch(function () {});\n  }\n  liveCards();\n  if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', mount);\n  else mount();\n})();\n\u003c\/script\u003e","brand":"Fábrica Coffee Roasters","offers":[{"title":"1 bag \/ Espresso","offer_id":53834159718747,"sku":"SUB-EXO-1-ESP","price":17.9,"currency_code":"EUR","in_stock":true},{"title":"1 bag \/ Filter","offer_id":53834159915355,"sku":"SUB-EXO-1-FIL","price":17.9,"currency_code":"EUR","in_stock":true},{"title":"2 bags \/ Espresso","offer_id":53834160111963,"sku":"SUB-EXO-2-ESP","price":24.9,"currency_code":"EUR","in_stock":true},{"title":"2 bags \/ Filter","offer_id":53834160308571,"sku":"SUB-EXO-2-FIL","price":24.9,"currency_code":"EUR","in_stock":true},{"title":"2 bags \/ Half \u0026 half","offer_id":53834160505179,"sku":"SUB-EXO-2-MIX","price":24.9,"currency_code":"EUR","in_stock":true},{"title":"4 bags \/ Espresso","offer_id":53834160701787,"sku":"SUB-EXO-4-ESP","price":43.9,"currency_code":"EUR","in_stock":true},{"title":"4 bags \/ Filter","offer_id":53834160898395,"sku":"SUB-EXO-4-FIL","price":43.9,"currency_code":"EUR","in_stock":true},{"title":"4 bags \/ Half \u0026 half","offer_id":53834161095003,"sku":"SUB-EXO-4-MIX","price":43.9,"currency_code":"EUR","in_stock":true},{"title":"6 bags \/ Espresso","offer_id":53834161291611,"sku":"SUB-EXO-6-ESP","price":59.9,"currency_code":"EUR","in_stock":true},{"title":"6 bags \/ Filter","offer_id":53834161488219,"sku":"SUB-EXO-6-FIL","price":59.9,"currency_code":"EUR","in_stock":true},{"title":"6 bags \/ Half \u0026 half","offer_id":53834161684827,"sku":"SUB-EXO-6-MIX","price":59.9,"currency_code":"EUR","in_stock":true}],"thumbnail_url":"\/\/cdn.shopify.com\/s\/files\/1\/0953\/5553\/5707\/files\/fabrica-coffee-roasters-new-subscription-model-front-images-specialty-coffee-03-02.webp?v=1788201638"},{"product_id":"aeropress-mug-coffee-bundle","title":"AeroPress + Mug + Coffee Bundle","description":"\u003cp\u003eA full-immersion brewer, a mug made for it, and the coffee to fill both.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eIn the box:\u003c\/strong\u003e\u003c\/p\u003e\u003cul\u003e\n\u003cli\u003eAeroPress® Kit — brewer, paper filters, stirrer and scoop\u003c\/li\u003e\n\u003cli\u003eCozy ceramic mug, made with Mónica V Ceramics\u003c\/li\u003e\n\u003cli\u003e250 g of specialty coffee, chosen by our roasters to suit the AeroPress\u003c\/li\u003e\n\u003c\/ul\u003e\u003cp\u003eChoose your grind at checkout, or it ships whole bean — packed from our freshest roast.\u003c\/p\u003e","brand":"Fábrica Coffee Roasters","offers":[{"title":"Default Title","offer_id":54018756477275,"sku":"BDL-AEROMUG","price":69.9,"currency_code":"EUR","in_stock":true}],"thumbnail_url":"\/\/cdn.shopify.com\/s\/files\/1\/0953\/5553\/5707\/files\/bundle-aeropress-coffee-bag-handmade-mug.webp?v=1789033877"},{"product_id":"v60-kit-mug-coffee","title":"V60 Kit + Mug + Coffee Bundle","description":"\u003cp\u003eEverything a clean, aromatic pour-over needs, and the mug to drink it from.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eIn the box:\u003c\/strong\u003e\u003c\/p\u003e\u003cul\u003e\n\u003cli\u003eHario® V60 Craft Coffee Maker 02 — dripper, server, filters and scoop\u003c\/li\u003e\n\u003cli\u003eCozy ceramic mug, made with Mónica V Ceramics\u003c\/li\u003e\n\u003cli\u003e250 g of specialty filter coffee, chosen by our roasters\u003c\/li\u003e\n\u003c\/ul\u003e\u003cp\u003eChoose your grind at checkout, or it ships whole bean — packed from our freshest roast.\u003c\/p\u003e","brand":"Fábrica Coffee Roasters","offers":[{"title":"Default Title","offer_id":54018881487195,"sku":"BDL-V60MUG","price":56.9,"currency_code":"EUR","in_stock":true}],"thumbnail_url":"\/\/cdn.shopify.com\/s\/files\/1\/0953\/5553\/5707\/files\/bundle-v60-coffee-bag-handmade-mug.webp?v=1789033934"}],"url":"https:\/\/fabricacoffeeroasters.com\/collections\/specialty-coffee-discovery.oembed","provider":"Fábrica Coffee Roasters","version":"1.0","type":"link"}