{"product_id":"minivan-1","title":"Minivan","description":"\u003cp\u003e\u003cmeta charset=\"utf-8\"\u003eMinivan has been a staple since the Melk Cafe beginnings! It’s the blend we most often use at our cafés in Montreal, QC! Perfect for espresso or filter, it’s the best balance between classic and third wave coffee. Like a minivan: versatile and reliable, it'll never let you down. Try our best seller in 300g and 907g!\u003c\/p\u003e\n\u003cp\u003e\u003cstrong\u003e300g\u003c\/strong\u003e\u003c\/p\u003e\n\u003cp\u003e\u003cspan\u003eIngredients: \u003c\/span\u003e\u003cspan\u003eOrganic coffee, certified organic by Ecocert \u003c\/span\u003e\u003c\/p\u003e\n\u003c!-- START OF FILE find-grind.html --\u003e\n\n\u003c!-- Complete Coffee Grind Finder Solution --\u003e\n\u003c!-- This is a fully self-contained solution that can be added to any Shopify page using the custom HTML block --\u003e\n\n\u003cstyle\u003e\n  \/* Color variables based on Holistic Roasters branding *\/\n  :root {\n    --primary: #555759;\n    --secondary: #ef4e23;\n    --accent: #ff7f2f;\n    --accent-yellow: #ffb819;\n    --light-green: #6cc04a;\n    --medium-green: #009d4e;\n    --dark-green: #006f42;\n    --light-gray: #f5f5f5;\n    --dark: #333333;\n    --box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);\n    --transition: all 0.3s ease;\n  }\n\n  \/* Manual button styling *\/\n  .coffee-grind-manual-button {\n    background-color: var(--secondary);\n    color: white;\n    border: none;\n    border-radius: 8px;\n    padding: 10px 20px;\n    font-size: 16px;\n    font-weight: bold;\n    cursor: pointer;\n    display: inline-block;\n    margin: 20px 0;\n    box-shadow: var(--box-shadow);\n    transition: var(--transition);\n  }\n\n  .coffee-grind-manual-button:hover {\n    background-color: var(--accent);\n    transform: translateY(-2px);\n  }\n\n  \/* Widget container *\/\n  #coffee-grind-widget-wrapper {\n    position: fixed;\n    top: 0;\n    left: 0;\n    width: 100%;\n    height: 100%;\n    background-color: rgba(0, 0, 0, 0.5);\n    display: none;\n    justify-content: center;\n    align-items: center;\n    z-index: 9999;\n  }\n\n  .coffee-grind-widget {\n    background-color: white;\n    border-radius: 12px;\n    box-shadow: var(--box-shadow);\n    width: 90%;\n    max-width: 500px;\n    max-height: 70vh;\n    overflow-y: auto;\n    position: relative;\n  }\n\n  .widget-header {\n    background-color: var(--secondary);\n    color: white;\n    padding: 15px 20px;\n    border-radius: 12px 12px 0 0;\n    position: sticky;\n    top: 0;\n    z-index: 1;\n    display: flex;\n    justify-content: space-between;\n    align-items: center;\n  }\n\n  .widget-header h2 {\n    margin: 0;\n    font-size: 1.4rem;\n    font-weight: 600;\n  }\n\n  .close-widget {\n    background: none;\n    border: none;\n    color: white;\n    font-size: 1.5rem;\n    cursor: pointer;\n    padding: 0 5px;\n  }\n\n  .widget-content {\n    padding: 20px;\n  }\n\n  .search-container {\n    margin-bottom: 20px;\n  }\n\n  .search-input {\n    width: 100%;\n    padding: 12px 15px;\n    border: 2px solid var(--light-gray);\n    border-radius: 6px;\n    font-size: 1rem;\n    transition: var(--transition);\n    box-sizing: border-box;\n  }\n\n  .search-input:focus {\n    outline: none;\n    border-color: var(--medium-green);\n  }\n\n  .search-button {\n    background-color: var(--medium-green);\n    color: white;\n    border: none;\n    border-radius: 6px;\n    padding: 12px 20px;\n    font-size: 1rem;\n    cursor: pointer;\n    width: 100%;\n    margin-top: 10px;\n    transition: var(--transition);\n    box-sizing: border-box;\n  }\n\n  .search-button:hover {\n    background-color: var(--dark-green);\n  }\n\n  .results-container {\n    margin-top: 25px;\n  }\n\n  .result-card {\n    background-color: white;\n    border-radius: 8px;\n    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);\n    padding: 20px;\n    margin-bottom: 15px;\n    border-left: 4px solid var(--medium-green);\n  }\n\n  .result-card h3 {\n    color: var(--secondary);\n    margin-bottom: 10px;\n    font-size: 1.2rem;\n  }\n\n  .result-details {\n    display: flex;\n    align-items: flex-start;\n    margin-bottom: 10px;\n  }\n\n  .result-label {\n    width: 130px;\n    min-width: 130px;\n    font-weight: bold;\n    color: var(--primary);\n    margin-right: 10px;\n  }\n\n  .result-value {\n    flex: 1;\n  }\n  .result-value strong {\n     color: var(--secondary);\n  }\n\n  .model-list {\n    list-style: disc;\n    margin-left: 20px;\n    padding-left: 0;\n    margin-top: 5px;\n  }\n  .model-list li {\n     margin-bottom: 3px;\n  }\n\n\n  .grind-size-icon {\n    width: 60px;\n    height: 60px;\n    border-radius: 50%;\n    background-color: var(--light-gray);\n    display: flex;\n    justify-content: center;\n    align-items: center;\n    margin-right: 15px;\n  }\n\n  .grind-icon-container {\n    margin-top: 15px;\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    background-color: #fafafa;\n    padding: 15px;\n    border-radius: 6px;\n    margin-top: 20px;\n    border: 1px solid #eee;\n  }\n\n  .grind-icon {\n    width: 80px;\n    height: 80px;\n    background-color: var(--light-gray);\n    border-radius: 50%;\n    margin-bottom: 10px;\n    display: flex;\n    justify-content: center;\n    align-items: center;\n    position: relative;\n    overflow: hidden;\n    border: 1px solid #ddd;\n  }\n\n  .grind-icon-inner {\n    position: absolute;\n    width: 100%;\n    height: 100%;\n    display: flex;\n    justify-content: center;\n    align-items: center;\n  }\n\n  .grind-icon-label {\n    text-align: center;\n    font-weight: bold;\n    color: var(--primary);\n  }\n\n  .grind-particle-size {\n    font-size: 0.9rem;\n    color: var(--secondary);\n    margin-top: 5px;\n    text-align: center;\n  }\n  .grind-description {\n      font-size: 0.9rem;\n      color: var(--primary);\n      margin-top: 5px;\n      text-align: center;\n  }\n\n  .category-list {\n    margin-top: 20px;\n  }\n\n  .category-item {\n    background-color: white;\n    border-radius: 8px;\n    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);\n    padding: 15px;\n    margin-bottom: 10px;\n    border-left: 4px solid var(--accent);\n    cursor: pointer;\n    transition: var(--transition);\n  }\n\n  .category-item:hover {\n    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);\n    transform: translateY(-2px);\n  }\n\n  .category-item h4 {\n    color: var(--primary);\n    margin-bottom: 5px;\n    font-size: 1.1rem;\n  }\n\n  .category-grind {\n    font-size: 0.9rem;\n    color: var(--primary); \/* Adjusted color slightly for raw text *\/\n    margin-top: 5px;\n  }\n   .category-grind strong {\n       color: var(--secondary); \/* Highlight 'Grind:' *\/\n   }\n   .category-grind span { \/* Class for particle size *\/\n        display: block;\n        font-size: 0.85em;\n        color: var(--primary);\n        margin-top: 3px;\n   }\n\n  .no-results {\n    background-color: var(--light-gray);\n    padding: 20px;\n    border-radius: 8px;\n    text-align: center;\n    margin-bottom: 20px;\n    color: var(--primary);\n  }\n\n  .loading {\n    display: flex;\n    justify-content: center;\n    align-items: center;\n    padding: 20px;\n  }\n\n  .loading-spinner {\n    border: 4px solid var(--light-gray);\n    border-top: 4px solid var(--secondary);\n    border-radius: 50%;\n    width: 30px;\n    height: 30px;\n    animation: spin 1s linear infinite;\n  }\n\n  @keyframes spin {\n    0% { transform: rotate(0deg); }\n    100% { transform: rotate(360deg); }\n  }\n\n  \/* Particle visualization styles *\/\n  .fine-particles {\n    background-image: radial-gradient(circle, var(--secondary) 1px, transparent 1px);\n    background-size: 5px 5px;\n  }\n\n  .medium-fine-particles {\n    background-image: radial-gradient(circle, var(--secondary) 2px, transparent 2px);\n    background-size: 8px 8px;\n  }\n\n  .medium-particles {\n    background-image: radial-gradient(circle, var(--secondary) 3px, transparent 3px);\n    background-size: 12px 12px;\n  }\n\n  .coarse-particles {\n    background-image: radial-gradient(circle, var(--secondary) 4px, transparent 4px);\n    background-size: 16px 16px;\n  }\n\n  \/* Animation for widget appearance *\/\n  @keyframes fadeIn {\n    from { opacity: 0; }\n    to { opacity: 1; }\n  }\n\n  .fade-in {\n    animation: fadeIn 0.3s ease-in-out;\n  }\n\n  \/* Making the widget responsive *\/\n  @media (max-width: 768px) {\n    .coffee-grind-widget {\n      width: 95%;\n      max-height: 80vh;\n    }\n\n    .widget-header h2 {\n      font-size: 1.2rem;\n    }\n\n     .result-label {\n       width: 100px;\n       min-width: 100px;\n    }\n  }\n\u003c\/style\u003e\n\n\u003c!-- The main button to open the widget --\u003e\n\u003cbutton onclick=\"openCoffeeGrindWidget()\" class=\"coffee-grind-manual-button\"\u003e\n  Find Your Perfect Coffee Grind Size\n\u003c\/button\u003e\n\n\u003c!-- The widget markup --\u003e\n\u003cdiv id=\"coffee-grind-widget-wrapper\"\u003e\n  \u003cdiv class=\"coffee-grind-widget fade-in\"\u003e\n    \u003cdiv class=\"widget-header\"\u003e\n      \u003ch2\u003eFind Your Perfect Coffee Grind\u003c\/h2\u003e\n      \u003cbutton class=\"close-widget\" onclick=\"closeCoffeeGrindWidget()\"\u003e×\u003c\/button\u003e\n    \u003c\/div\u003e\n    \u003cdiv class=\"widget-content\"\u003e\n      \u003cdiv class=\"search-container\"\u003e\n        \u003c!-- UPDATED: Placeholder text --\u003e\n        \u003cinput type=\"text\" class=\"search-input\" id=\"coffee-maker-search\" placeholder=\"Enter your coffee maker brand or model...\"\u003e\n        \u003cbutton class=\"search-button\" id=\"search-button\" onclick=\"searchCoffeeMaker()\"\u003eFind My Grind\u003c\/button\u003e\n      \u003c\/div\u003e\n\n      \u003cdiv id=\"results-area\"\u003e\n        \u003c!-- Results will appear here --\u003e\n        \u003cdiv class=\"no-results\"\u003eEnter your coffee maker to find the ideal grind size.\u003c\/div\u003e\n      \u003c\/div\u003e\n    \u003c\/div\u003e\n  \u003c\/div\u003e\n\u003c\/div\u003e\n\n\u003cscript\u003e\n  \/\/ Raw data from the provided text (simulating file read)\n  \/\/ UPDATED: Corrected \"gorund\" to \"ground\"\n  const rawCoffeeData = `\nCategory,Brand \u0026 Model,Ideal Grind Size,Particle Size (microns)\nManual \/ Lever Espresso Machines,Flair 58,Fine espresso (ground coffee),200–400\nManual \/ Lever Espresso Machines,Flair Pro 2,Fine espresso (ground coffee),200–400\nManual \/ Lever Espresso Machines,Cafelat Robot,Fine espresso (ground coffee),200–400\nManual \/ Lever Espresso Machines,ROK Espresso GC,Fine espresso (ground coffee),200–400\nManual \/ Lever Espresso Machines,La Pavoni Europiccola,Fine espresso (ground coffee),200–400\nManual \/ Lever Espresso Machines,La Pavoni Professional,Fine espresso (ground coffee),200–400\nManual \/ Lever Espresso Machines,Elektra Micro Casa a Leva,Fine espresso (ground coffee),200–400\nManual \/ Lever Espresso Machines,Odyssey Argos,Fine espresso (ground coffee),200–400\nProsumer \/ High-End Espresso Machines,La Marzocco Linea Mini,Fine espresso (ground coffee),200–400\nProsumer \/ High-End Espresso Machines,La Marzocco GS3,Fine espresso (ground coffee),200–400\nProsumer \/ High-End Espresso Machines,ECM Synchronika,Fine espresso (ground coffee),200–400\nProsumer \/ High-End Espresso Machines,Profitec Pro 700,Fine espresso (ground coffee),200–400\nProsumer \/ High-End Espresso Machines,Rocket Espresso R58 Cinquantotto,Fine espresso (ground coffee),200–400\nProsumer \/ High-End Espresso Machines,Rocket Appartamento (TCA and Classic),Fine espresso (ground coffee),200–400\nProsumer \/ High-End Espresso Machines,Lelit Bianca V3,Fine espresso (ground coffee),200–400\nProsumer \/ High-End Espresso Machines,Bezzera Duo DE,Fine espresso (ground coffee),200–400\nProsumer \/ High-End Espresso Machines,Quick Mill Vetrano 2B Evo,Fine espresso (ground coffee),200–400\nProsumer \/ High-End Espresso Machines,Slayer Single Group (Manual paddle version),Fine espresso (ground coffee),200–400\nPopular Consumer Espresso Machines,Rancilio Silvia,Fine espresso (ground coffee),200–400\nPopular Consumer Espresso Machines,Gaggia Classic Evo Pro,Fine espresso (ground coffee),200–400\nPopular Consumer Espresso Machines,De’Longhi Dedica EC685,Fine espresso (ground coffee),200–400\nPopular Consumer Espresso Machines,Breville Bambino Plus,Fine espresso (ground coffee),200–400\nPopular Consumer Espresso Machines,Breville Bambino,Fine espresso (ground coffee),200–400\nPopular Consumer Espresso Machines,Breville Duo-Temp Pro,Fine espresso (ground coffee),200–400\nPopular Consumer Espresso Machines,Lelit Anna,Fine espresso (ground coffee),200–400\nPopular Consumer Espresso Machines,Ascaso Dream PID,Fine espresso (ground coffee),200–400\nPopular Consumer Espresso Machines,Capresso Café Pro,Fine espresso (ground coffee),200–400\nPopular Consumer Espresso Machines,Diletta Mio,Fine espresso (ground coffee),200–400\nPour-Over: Cone-Shaped Drippers,Hario V60,Pourover (ground coffee),400–600\nPour-Over: Cone-Shaped Drippers,Origami Dripper,Pourover (ground coffee),400–600\nPour-Over: Cone-Shaped Drippers,Fellow Stagg [X] and [XF],Pourover (ground coffee),400–600\nPour-Over: Cone-Shaped Drippers,OXO Brew Pour-Over Coffee Maker,Pourover (ground coffee),400–600\nPour-Over: Cone-Shaped Drippers,Tiamo V60-Style,Pourover (ground coffee),400–600\nPour-Over: Cone-Shaped Drippers,Chemex Classic 6-Cup,Filter \/ Drip (ground coffee),600–800\nPour-Over: Flat-Bottom Drippers,Kalita Wave 155 \/ 185,Filter \/ Drip (ground coffee),600–800\nPour-Over: Flat-Bottom Drippers,April Brewer,Filter \/ Drip (ground coffee),600–800\nPour-Over: Flat-Bottom Drippers,Orea V3,Filter \/ Drip (ground coffee),600–800\nPour-Over: Flat-Bottom Drippers,Cafec Flower Dripper,Filter \/ Drip (ground coffee),600–800\nPour-Over: Flat-Bottom Drippers,NotNeutral GINO,Filter \/ Drip (ground coffee),600–800\nPour-Over: Flat-Bottom Drippers,Torch Mountain Dripper,Filter \/ Drip (ground coffee),600–800\nFrench Press,Bodum Chambord,French Press (ground coffee),1000–1200\nFrench Press,Fellow Clara,French Press (ground coffee),1000–1200\nFrench Press,Espro P3,French Press (ground coffee),1000–1200\nFrench Press,Espro P7,French Press (ground coffee),1000–1200\nFrench Press,Frieling Double Wall,French Press (ground coffee),1000–1200\nFrench Press,Coffee Gator,French Press (ground coffee),1000–1200\nFrench Press,Le Creuset Stoneware,French Press (ground coffee),1000–1200\nFrench Press,Secura Stainless Steel,French Press (ground coffee),1000–1200\nCold Brew Makers,OXO Good Grips Cold Brew,French Press (ground coffee),1000–1200\nCold Brew Makers,Hario Mizudashi,French Press (ground coffee),1000–1200\nCold Brew Makers,Toddy Cold Brew System,French Press (ground coffee),1000–1200\nCold Brew Makers,Takeya Deluxe,French Press (ground coffee),1000–1200\nCold Brew Makers,County Line Kitchen,French Press (ground coffee),1000–1200\nCold Brew Makers,Brewista Cold Pro,French Press (ground coffee),1000–1200\nCold Brew Makers,Filtron Cold Brew,French Press (ground coffee),1000–1200\nDrip Coffee Makers,Technivorm Moccamaster KBGV Select,Pourover (ground coffee),400–600\nDrip Coffee Makers,OXO Brew 8-Cup,Filter \/ Drip (ground coffee),600–800\nDrip Coffee Makers,Bonavita Connoisseur 8-Cup,Filter \/ Drip (ground coffee),600–800\nDrip Coffee Makers,Breville Precision Brewer,Filter \/ Drip (ground coffee),600–800\nDrip Coffee Makers,Ratio Six,Filter \/ Drip (ground coffee),600–800\nDrip Coffee Makers,Wilfa Classic+,Filter \/ Drip (ground coffee),600–800\nDrip Coffee Makers,Zojirushi EC-YGC120,Filter \/ Drip (ground coffee),600–800\nDrip Coffee Makers,Behmor Connected,Filter \/ Drip (ground coffee),600–800\nStovetop \/ Moka Pot,Bialetti Moka Express,Pourover (ground coffee),400–600\nStovetop \/ Moka Pot,Bialetti Brikka,Pourover (ground coffee),400–600\nStovetop \/ Moka Pot,Bialetti Mini Express,Pourover (ground coffee),400–600\nStovetop \/ Moka Pot,Alessi 9090,Pourover (ground coffee),400–600\nStovetop \/ Moka Pot,GROSCHE Milano,Pourover (ground coffee),400–600\nStovetop \/ Moka Pot,Ilsa Turbo Express,Pourover (ground coffee),400–600\nStovetop \/ Moka Pot,Cuisinox Roma,Pourover (ground coffee),400–600\nStovetop \/ Moka Pot,Bellman CX-25P,Pourover (ground coffee),400–600\nAeropress, AeroPress Coffee Maker, Widest range – we recommend starting with Pourover (ground coffee), 300-900\n  `;\n\n  \/\/ Function to parse and standardize the coffee data\n  function parseCoffeeData(rawData) {\n    const lines = rawData.trim().split('\\n');\n    const headers = lines[0].split(',').map(h =\u003e h.trim());\n    const data = [];\n    const categoryIndex = headers.indexOf('Category');\n    const modelIndex = headers.indexOf('Brand \u0026 Model');\n    const grindIndex = headers.indexOf('Ideal Grind Size');\n    const particleIndex = headers.indexOf('Particle Size (microns)');\n\n    if ([categoryIndex, modelIndex, grindIndex, particleIndex].includes(-1)) {\n        console.error(\"Error parsing headers. Check CSV format.\", headers);\n        alert(\"Error: Could not read coffee data headers correctly.\");\n        return [];\n    }\n\n    for (let i = 1; i \u003c lines.length; i++) {\n      const values = lines[i].split(',');\n      if (values.length \u003e Math.max(categoryIndex, modelIndex, grindIndex, particleIndex)) {\n         const rawIdealGrind = values[grindIndex].trim();\n         let standardizedGrind = 'Medium';\n         let particleSize = values[particleIndex].trim().replace('–', '-');\n\n         \/\/ Determine standardizedGrind (same logic)\n         if (rawIdealGrind.toLowerCase().includes('fine espresso')) standardizedGrind = 'Fine (espresso)';\n         else if (rawIdealGrind.toLowerCase().includes('pourover')) standardizedGrind = 'Medium-fine';\n         else if (rawIdealGrind.toLowerCase().includes('filter \/ drip')) standardizedGrind = 'Medium';\n         else if (rawIdealGrind.toLowerCase().includes('french press')) standardizedGrind = 'Coarse';\n         else {\n              try {\n                const firstParticle = parseInt(particleSize.split('-')[0]);\n                if (!isNaN(firstParticle)) {\n                   if (firstParticle \u003c= 400) standardizedGrind = 'Fine (espresso)';\n                   else if (firstParticle \u003c= 600) standardizedGrind = 'Medium-fine';\n                   else if (firstParticle \u003c= 800) standardizedGrind = 'Medium';\n                   else standardizedGrind = 'Coarse';\n                } else console.warn(`Could not parse particle size for fallback: ${particleSize} on line ${i+1}`);\n              } catch (e) { console.warn(`Error parsing particle size for fallback: ${particleSize} on line ${i+1}`, e); }\n         }\n\n        data.push({\n          category: values[categoryIndex].trim(), model: values[modelIndex].trim(),\n          idealGrindSize: rawIdealGrind, standardizedGrindSize: standardizedGrind, particleSize: particleSize\n        });\n      } else { console.warn(`Skipping malformed CSV line ${i+1}: ${lines[i]}`); }\n    }\n    return data;\n  }\n\n  \/\/ Parsed coffee data\n  const coffeeData = parseCoffeeData(rawCoffeeData);\n  console.log(`Loaded ${coffeeData.length} coffee maker entries.`);\n\n  \/\/ Grind size info (keys match standardizedGrindSize)\n  const grindSizeInfo = {\n    \"Fine (espresso)\": { size: \"Fine (espresso)\", particleSize: \"200-400\", description: \"Texture similar to fine salt or sugar - adjust from medium espresso grind to fine or very fine depending on results\", cssClass: \"fine-particles\" },\n    \"Medium-fine\": { size: \"Medium-fine\", particleSize: \"400-600\", description: \"Slightly finer than table salt\", cssClass: \"medium-fine-particles\" },\n    \"Medium\": { size: \"Medium\", particleSize: \"600-800\", description: \"Similar to coarse sand texture\", cssClass: \"medium-particles\" },\n    \"Coarse\": { size: \"Coarse\", particleSize: \"1000-1200\", description: \"Texture similar to kosher salt\", cssClass: \"coarse-particles\" }\n  };\n\n  \/\/ Consolidated categories\n  \/\/ UPDATED: Added 'representativeRawGrind' field\n   const consolidatedCategories = [\n    {\n        name: \"Espresso Machines (All Types)\",\n        subcategories: [\"Manual \/ Lever Espresso Machines\", \"Prosumer \/ High-End Espresso Machines\", \"Popular Consumer Espresso Machines\"],\n        standardizedGrind: \"Fine (espresso)\", \/\/ For icon lookup\n        representativeRawGrind: \"Fine espresso (ground coffee)\", \/\/ For display\n        particleSize: \"200-400\"\n    },\n    {\n        name: \"Pour-Over: Cone-Shaped Drippers \u0026 Moka Pots\",\n        subcategories: [\"Pour-Over: Cone-Shaped Drippers\", \"Stovetop \/ Moka Pot\", \"Drip Coffee Makers\"], \/\/ Some Drips use this too\n        standardizedGrind: \"Medium-fine\", \/\/ For icon lookup\n        representativeRawGrind: \"Pourover (ground coffee)\", \/\/ For display\n        particleSize: \"400-600\"\n    },\n    {\n        name: \"Pour-Over: Flat-Bottom Drippers \u0026 Auto Drip\",\n       subcategories: [\"Pour-Over: Flat-Bottom Drippers\", \"Drip Coffee Makers\"],\n       standardizedGrind: \"Medium\", \/\/ For icon lookup\n       representativeRawGrind: \"Filter \/ Drip (ground coffee)\", \/\/ For display\n       particleSize: \"600-800\"\n    },\n    {\n        name: \"French Press \u0026 Cold Brew\",\n        subcategories: [\"French Press\", \"Cold Brew Makers\"],\n        standardizedGrind: \"Coarse\", \/\/ For icon lookup\n        representativeRawGrind: \"French Press (ground coffee)\", \/\/ For display\n        particleSize: \"1000-1200\"\n    }\n  ];\n\n  \/\/ Initialize DOM listeners\n  document.addEventListener('DOMContentLoaded', function() {\n    console.log('Coffee grind finder initialized');\n    document.getElementById('coffee-maker-search').addEventListener('keypress', function(e) { if (e.key === 'Enter') searchCoffeeMaker(); });\n    document.getElementById('coffee-grind-widget-wrapper').addEventListener('click', function(e) { if (e.target === this) closeCoffeeGrindWidget(); });\n  });\n\n  \/\/ Widget open\/close functions\n  function openCoffeeGrindWidget() {\n    document.getElementById('coffee-grind-widget-wrapper').style.display = 'flex';\n    document.body.style.overflow = 'hidden';\n  }\n  function closeCoffeeGrindWidget() {\n    document.getElementById('coffee-grind-widget-wrapper').style.display = 'none';\n    document.body.style.overflow = '';\n  }\n\n  \/\/ Search function\n  function searchCoffeeMaker() {\n    const searchQuery = document.getElementById('coffee-maker-search').value.trim().toLowerCase();\n    if (searchQuery.length \u003c 2) {\n      document.getElementById('results-area').innerHTML = '\u003cdiv class=\"no-results\"\u003ePlease enter at least 2 characters to search.\u003c\/div\u003e';\n      return;\n    }\n    document.getElementById('results-area').innerHTML = '\u003cdiv class=\"loading\"\u003e\u003cdiv class=\"loading-spinner\"\u003e\u003c\/div\u003e\u003c\/div\u003e';\n    setTimeout(() =\u003e {\n      const matches = coffeeData.filter(item =\u003e item.model.toLowerCase().includes(searchQuery) || item.category.toLowerCase().includes(searchQuery));\n      if (matches.length \u003e 0) displayMatchResults(matches, searchQuery);\n      else displayCategories(searchQuery);\n    }, 300);\n  }\n\n  \/\/ Function to display match results\n  function displayMatchResults(matches, query) {\n    let html = `\u003cdiv class=\"results-header no-results\" style=\"margin-bottom:15px; background-color: var(--light-green); color: var(--dark-green);\"\u003eFound ${matches.length} result(s) for \"${query}\":\u003c\/div\u003e`;\n    const groupedMatches = matches.reduce((acc, match) =\u003e {\n      const key = `${match.standardizedGrindSize}|${match.particleSize}`;\n      if (!acc[key]) acc[key] = { standardizedGrindSize: match.standardizedGrindSize, particleSize: match.particleSize, models: [] };\n      acc[key].models.push(match);\n      return acc;\n    }, {});\n\n    for (const key in groupedMatches) {\n      const group = groupedMatches[key];\n      const grindInfo = grindSizeInfo[group.standardizedGrindSize];\n      if (!grindInfo) { console.error(`Grind info not found for key: ${group.standardizedGrindSize}`); continue; }\n      const displayGrindText = group.models[0]?.idealGrindSize || group.standardizedGrindSize; \/\/ Raw text for display\n\n      html += `\n        \u003cdiv class=\"result-card\"\u003e\n          ${group.models.length === 1\n            ? `\u003ch3\u003e${group.models[0].model}\u003c\/h3\u003e\u003cdiv class=\"result-details\"\u003e\u003cspan class=\"result-label\"\u003eCategory:\u003c\/span\u003e\u003cspan class=\"result-value\"\u003e${group.models[0].category}\u003c\/span\u003e\u003c\/div\u003e`\n            : `\u003ch3\u003eMultiple Models Found:\u003c\/h3\u003e\u003cdiv class=\"result-details\"\u003e\u003cspan class=\"result-label\"\u003eModels:\u003c\/span\u003e\u003cspan class=\"result-value\"\u003e\u003cul class=\"model-list\"\u003e${group.models.map(m =\u003e `\u003cli\u003e${m.model} (${m.category})\u003c\/li\u003e`).join('')}\u003c\/ul\u003e\u003c\/span\u003e\u003c\/div\u003e`\n          }\n          \u003cdiv class=\"result-details\"\u003e\u003cspan class=\"result-label\"\u003eIdeal Grind Size:\u003c\/span\u003e\u003cspan class=\"result-value\"\u003e\u003cstrong\u003e${displayGrindText}\u003c\/strong\u003e\u003c\/span\u003e\u003c\/div\u003e\n          \u003cdiv class=\"result-details\"\u003e\u003cspan class=\"result-label\"\u003eParticle Size:\u003c\/span\u003e\u003cspan class=\"result-value\"\u003e${group.particleSize} microns\u003c\/span\u003e\u003c\/div\u003e\n          \u003cdiv class=\"grind-icon-container\"\u003e\n            \u003cdiv class=\"grind-icon\"\u003e\u003cdiv class=\"grind-icon-inner ${grindInfo.cssClass}\"\u003e\u003c\/div\u003e\u003c\/div\u003e\n            \u003cdiv class=\"grind-icon-label\"\u003e${displayGrindText}\u003c\/div\u003e\n            \u003cdiv class=\"grind-particle-size\"\u003e${grindInfo.particleSize} microns\u003c\/div\u003e\n            \u003cdiv class=\"grind-description\"\u003e${grindInfo.description}\u003c\/div\u003e\n          \u003c\/div\u003e\n        \u003c\/div\u003e`;\n    }\n    document.getElementById('results-area').innerHTML = html;\n  }\n\n  \/\/ Function to display categories when no match is found\n  function displayCategories(query = \"\") {\n    let html = `\u003cdiv class=\"no-results\"\u003e\u003cp\u003eWe didn't find a specific match${query ? ` for \"${query}\"` : ''}. Select a category below for general recommendations:\u003c\/p\u003e\u003c\/div\u003e\u003cdiv class=\"category-list\"\u003e`;\n\n    consolidatedCategories.forEach(category =\u003e {\n      \/\/ Use standardizedGrind for icon lookup\n      const grindInfo = grindSizeInfo[category.standardizedGrind];\n       if (!grindInfo) {\n           console.error(`Grind info missing for category: ${category.name} (Standardized Grind: ${category.standardizedGrind})`);\n           return;\n       }\n\n      \/\/ UPDATED: Use representativeRawGrind for the text display\n      html += `\n        \u003cdiv class=\"category-item\" onclick=\"expandCategoryDisplay('${category.name}')\"\u003e\n          \u003ch4\u003e${category.name}\u003c\/h4\u003e\n          \u003cdiv class=\"category-grind\"\u003e\n            \u003cstrong\u003eGrind:\u003c\/strong\u003e ${category.representativeRawGrind}\n            \u003cspan class=\"particle-size-cat\"\u003e(Approx. ${category.particleSize} microns)\u003c\/span\u003e\n          \u003c\/div\u003e\n           \u003cdiv class=\"grind-icon-container\" style=\"margin-top: 10px; padding: 10px;\"\u003e\n             \u003cdiv class=\"grind-icon\" style=\"width: 50px; height: 50px; margin-bottom: 5px;\"\u003e\n               \u003cdiv class=\"grind-icon-inner ${grindInfo.cssClass}\"\u003e\u003c\/div\u003e\n             \u003c\/div\u003e\n             \u003cdiv class=\"grind-description\" style=\"font-size: 0.8rem;\"\u003e${grindInfo.description}\u003c\/div\u003e\n           \u003c\/div\u003e\n        \u003c\/div\u003e`;\n    });\n\n    html += `\u003c\/div\u003e`;\n    document.getElementById('results-area').innerHTML = html;\n  }\n\n  \/\/ Function to expand a category\n  function expandCategoryDisplay(categoryName) {\n    const category = consolidatedCategories.find(cat =\u003e cat.name === categoryName);\n    if (!category) { console.error(\"Category not found:\", categoryName); displayAllCategories(); return; }\n    \/\/ Use standardizedGrind for icon lookup\n    const grindInfo = grindSizeInfo[category.standardizedGrind];\n    if (!grindInfo) { console.error(`Grind info missing for category: ${category.name}`); displayAllCategories(); return; }\n\n    let html = `\n      \u003cdiv class=\"result-card\"\u003e\n        \u003ch3\u003e${category.name}\u003c\/h3\u003e\n        \u003cdiv class=\"result-details\"\u003e\n           \u003cspan class=\"result-label\"\u003eTypical Grind:\u003c\/span\u003e\n           \u003c!-- Display representative raw grind here too for consistency with category list --\u003e\n           \u003cspan class=\"result-value\"\u003e\u003cstrong\u003e${category.representativeRawGrind}\u003c\/strong\u003e\u003c\/span\u003e\n        \u003c\/div\u003e\n        \u003cdiv class=\"result-details\"\u003e\n           \u003cspan class=\"result-label\"\u003eParticle Size:\u003c\/span\u003e\n           \u003cspan class=\"result-value\"\u003e${category.particleSize} microns\u003c\/span\u003e\n        \u003c\/div\u003e\n        \u003cdiv class=\"grind-icon-container\"\u003e\n          \u003cdiv class=\"grind-icon\"\u003e\u003cdiv class=\"grind-icon-inner ${grindInfo.cssClass}\"\u003e\u003c\/div\u003e\u003c\/div\u003e\n          \u003c!-- Icon label uses standardized name --\u003e\n          \u003cdiv class=\"grind-icon-label\"\u003e${grindInfo.size}\u003c\/div\u003e\n          \u003cdiv class=\"grind-particle-size\"\u003e${grindInfo.particleSize} microns\u003c\/div\u003e\n          \u003cdiv class=\"grind-description\"\u003e${grindInfo.description}\u003c\/div\u003e\n        \u003c\/div\u003e\n        \u003cdiv style=\"margin-top: 20px; background-color: #f0f0f0; padding: 10px; border-radius: 4px;\"\u003e\n           \u003cp style=\"margin-bottom: 5px;\"\u003e\u003cstrong\u003eIncludes maker types like:\u003c\/strong\u003e\u003c\/p\u003e\n           \u003cul style=\"margin-left: 20px; margin-top: 0; padding-left: 5px; font-size: 0.9em;\"\u003e${category.subcategories.map(sub =\u003e `\u003cli\u003e${sub}\u003c\/li\u003e`).join('')}\u003c\/ul\u003e\n           \u003cp style=\"font-size: 0.8em; margin-top: 10px; color: #666;\"\u003eNote: This is a general guideline for the category.\u003c\/p\u003e\n        \u003c\/div\u003e\n      \u003c\/div\u003e\n      \u003cbutton class=\"search-button\" onclick=\"displayAllCategories()\" style=\"margin-top: 15px; background-color: var(--accent);\"\u003e← Back to All Categories\u003c\/button\u003e`;\n    document.getElementById('results-area').innerHTML = html;\n  }\n\n  \/\/ Function to display all categories (back button)\n  function displayAllCategories() {\n    displayCategories();\n  }\n\n\u003c\/script\u003e\n\n\u003c!-- END OF FILE find-grind.html --\u003e","brand":"Holistic Roasters","offers":[{"title":"300g \/ Whole Bean","offer_id":62775316742303,"sku":"10127","price":19.95,"currency_code":"USD","in_stock":true},{"title":"300g \/ French Press (ground coffee)","offer_id":62775316775071,"sku":"17351","price":19.95,"currency_code":"USD","in_stock":true},{"title":"300g \/ Pourover (ground coffee)","offer_id":62775316807839,"sku":"17353","price":19.95,"currency_code":"USD","in_stock":true},{"title":"300g \/ Filter \/ Drip (ground coffee)","offer_id":62775316840607,"sku":"17352","price":19.95,"currency_code":"USD","in_stock":true},{"title":"300g \/ Moka Pot (ground coffee)","offer_id":62775316873375,"sku":"17354","price":19.95,"currency_code":"USD","in_stock":true},{"title":"300g \/ Medium Espresso (ground coffee)","offer_id":62775316906143,"sku":"17355","price":19.95,"currency_code":"USD","in_stock":true},{"title":"300g \/ Fine Espresso (ground coffee)","offer_id":62775316938911,"sku":"17356","price":19.95,"currency_code":"USD","in_stock":true},{"title":"300g \/ Very Fine Espresso (ground coffee)","offer_id":62775316971679,"sku":"17357","price":19.95,"currency_code":"USD","in_stock":true},{"title":"907g \/ Whole Bean","offer_id":62775317004447,"sku":"10126","price":19.95,"currency_code":"USD","in_stock":true},{"title":"907g \/ French Press (ground coffee)","offer_id":62775317037215,"sku":"17358","price":19.95,"currency_code":"USD","in_stock":true},{"title":"907g \/ Pourover (ground coffee)","offer_id":62775317069983,"sku":"17360","price":19.95,"currency_code":"USD","in_stock":true},{"title":"907g \/ Filter \/ Drip (ground coffee)","offer_id":62775317102751,"sku":"17359","price":19.95,"currency_code":"USD","in_stock":true},{"title":"907g \/ Moka Pot (ground coffee)","offer_id":62775317135519,"sku":"17361","price":19.95,"currency_code":"USD","in_stock":true},{"title":"907g \/ Medium Espresso (ground coffee)","offer_id":62775317168287,"sku":"17362","price":19.95,"currency_code":"USD","in_stock":true},{"title":"907g \/ Fine Espresso (ground coffee)","offer_id":62775317201055,"sku":"17363","price":19.95,"currency_code":"USD","in_stock":true},{"title":"907g \/ Very Fine Espresso (ground coffee)","offer_id":62775317233823,"sku":"17364","price":19.95,"currency_code":"USD","in_stock":true}],"thumbnail_url":"\/\/cdn.shopify.com\/s\/files\/1\/0484\/7475\/1135\/files\/minivan-726487.png?v=1742341521","url":"https:\/\/biodynamic.coffee\/products\/minivan-1","provider":"Biodynamic Coffee","version":"1.0","type":"link"}