{"product_id":"schrage-streifen-grun-stoff","title":"Schräge Streifen Grün – Stoff","description":"\u003c!-- PRODUKTBESCHREIBUNG MIT PARALLAX-LOGO --\u003e\n\n\u003csection class=\"bine-stoff-intro\"\u003e\n\n  \u003cdiv class=\"bine-logo-parallax\" data-bine-parallax\u003e\n    \u003cimg src=\"https:\/\/cdn.shopify.com\/s\/files\/1\/0042\/4758\/4881\/files\/Logo-Stoffe-bunt.png?v=1787871207\" alt=\"Bine Brändle Stoffe Logo\" class=\"bine-stoff-logo\"\u003e\n  \u003c\/div\u003e\n  \u003cdiv class=\"bine-stoff-text\"\u003e\n\n    \u003ch2\u003eFarbenfrohe Stoffe mit Design von Bine Brändle\u003c\/h2\u003e\n\n    \u003cp class=\"bine-stoff-einleitung\"\u003e\n      Mach dein nächstes Nähprojekt zu etwas ganz Besonderem! Unsere\n      wunderschön bedruckten Stoffe mit einem liebevoll gestalteten Design\n      von \u003cstrong\u003eBine Brändle\u003c\/strong\u003e bringen Farbe, Freude und gute Laune\n      an die Nähmaschine.\n    \u003c\/p\u003e\n  \u003cdiv class=\"bine-logo-parallax\" data-bine-parallax\u003e\n    \u003cimg src=\"https:\/\/cdn.shopify.com\/s\/files\/1\/0042\/4758\/4881\/files\/Oko-TEX100.jpg?v=1750455570\" alt=\"Bine Brändle\" class=\"bine-stoff-logo\"\u003e\n  \u003c\/div\u003e\n    \u003cp\u003e\n      Du kannst dein Lieblingsdesign passend zu deinem Projekt als\n      \u003cstrong\u003eBaumwollgewebe\u003c\/strong\u003e oder \u003cstrong\u003eJersey\u003c\/strong\u003e auswählen.\n    \u003c\/p\u003e\n\n    \u003cdiv class=\"bine-stoffarten\"\u003e\n\n      \u003cdiv class=\"bine-stoffart\"\u003e\n        \u003ch3\u003eBaumwollgewebe\u003c\/h3\u003e\n\n        \u003cp\u003e\n          Das angenehm glatte und formstabile Baumwollgewebe eignet sich\n          wunderbar für:\n        \u003c\/p\u003e\n\n        \u003cul\u003e\n          \u003cli\u003eHemden und Hosen\u003c\/li\u003e\n          \u003cli\u003eTaschen und Beutel\u003c\/li\u003e\n          \u003cli\u003eKissen und Wohnaccessoires\u003c\/li\u003e\n          \u003cli\u003eDekorationen\u003c\/li\u003e\n          \u003cli\u003ePatchwork-Projekte\u003c\/li\u003e\n          \u003cli\u003eSchultüten und kleine Geschenkideen\u003c\/li\u003e\n        \u003c\/ul\u003e\n      \u003c\/div\u003e\n\n      \u003cdiv class=\"bine-stoffart\"\u003e\n        \u003ch3\u003eJersey\u003c\/h3\u003e\n\n        \u003cp\u003e\n          Der weiche und elastische Jersey-Stoff ist besonders angenehm\n          auf der Haut und ideal für:\n        \u003c\/p\u003e\n\n        \u003cul\u003e\n          \u003cli\u003eShirts und Kleider\u003c\/li\u003e\n          \u003cli\u003eHosen und Leggings\u003c\/li\u003e\n          \u003cli\u003eMützen und Halstücher\u003c\/li\u003e\n          \u003cli\u003eKinder- und Babykleidung\u003c\/li\u003e\n          \u003cli\u003eBequeme Lieblingsstücke für Groß und Klein\u003c\/li\u003e\n        \u003c\/ul\u003e\n      \u003c\/div\u003e\n\n    \u003c\/div\u003e\n\n    \u003cdiv class=\"bine-stofflaengen\"\u003e\n      \u003ch3\u003eErhältliche Stofflängen\u003c\/h3\u003e\n\n      \u003cp\u003e\n        Du erhältst den Stoff fertig zugeschnitten in folgenden Längen:\n      \u003c\/p\u003e\n\n      \u003cdiv class=\"bine-laengen-auswahl\"\u003e\n        \u003cspan\u003e1 Meter\u003c\/span\u003e\n        \u003cspan\u003e2 Meter\u003c\/span\u003e\n        \u003cspan\u003e3 Meter\u003c\/span\u003e\n      \u003c\/div\u003e\n\n      \u003cp\u003e\n        Wähle einfach deine gewünschte Stoffart und anschließend die\n        passende Länge aus.\n      \u003c\/p\u003e\n\n      \u003cp class=\"bine-stoff-hinweis\"\u003e\n        \u003cstrong\u003eBitte beachte:\u003c\/strong\u003e Die ausgewählte Länge wird als\n        zusammenhängendes Stoffstück geliefert. Bei der Auswahl von\n        2 Metern erhältst du ein 2 Meter langes Stück, bei 3 Metern ein\n        zusammenhängendes 3-Meter-Stück.\n      \u003c\/p\u003e\n    \u003c\/div\u003e\n\n    \u003cp\u003e\n      Ob als farbenfrohes Kleidungsstück, liebevoll genähtes Geschenk oder\n      besonderer Blickfang für dein Zuhause – mit den Designs von\n      \u003cstrong\u003eBine Brändle\u003c\/strong\u003e wird jedes Nähprojekt herrlich bunt und\n      unverwechselbar.\n    \u003c\/p\u003e\n\n  \u003c\/div\u003e\n\n\u003c\/section\u003e\n\n\u003cstyle\u003e\n  .bine-stoff-intro {\n    margin: 20px 0 35px;\n    overflow: hidden;\n  }\n\n  .bine-logo-parallax {\n    display: flex;\n    justify-content: center;\n    align-items: center;\n    min-height: 150px;\n    margin-bottom: 20px;\n    padding: 20px;\n    \n    border-radius: 16px;\n    overflow: hidden;\n  }\n\n  .bine-stoff-logo {\n    display: block;\n    width: auto;\n    max-width: min(320px, 80%);\n    max-height: 130px;\n    object-fit: contain;\n    will-change: transform;\n    transform: translate3d(0, 0, 0);\n  }\n\n  .bine-stoff-text h2 {\n    margin-top: 0;\n    margin-bottom: 15px;\n    color: #08868a;\n    font-size: clamp(24px, 4vw, 34px);\n    line-height: 1.2;\n  }\n\n  .bine-stoff-text h3 {\n    margin-top: 0;\n    margin-bottom: 10px;\n  }\n\n  .bine-stoff-einleitung {\n    font-size: 1.08em;\n    line-height: 1.65;\n  }\n\n  .bine-stoffarten {\n    display: grid;\n    grid-template-columns: repeat(2, minmax(0, 1fr));\n    gap: 16px;\n    margin: 25px 0;\n  }\n\n  .bine-stoffart {\n    padding: 20px;\n    background: #f7f7f7;\n    border-top: 4px solid #08868a;\n    border-radius: 10px;\n  }\n\n  .bine-stoffart ul {\n    margin-bottom: 0;\n    padding-left: 20px;\n  }\n\n  .bine-stoffart li {\n    margin-bottom: 5px;\n  }\n\n  .bine-stofflaengen {\n    margin: 25px 0;\n    padding: 22px;\n    background: rgba(8, 134, 138, 0.08);\n    border-radius: 12px;\n  }\n\n  .bine-laengen-auswahl {\n    display: flex;\n    flex-wrap: wrap;\n    gap: 10px;\n    margin: 16px 0;\n  }\n\n  .bine-laengen-auswahl span {\n    display: inline-flex;\n    align-items: center;\n    justify-content: center;\n    min-width: 90px;\n    padding: 9px 15px;\n    background: #08868a;\n    color: #ffffff;\n    border-radius: 20px;\n    font-weight: 700;\n  }\n\n  .bine-stoff-hinweis {\n    margin-bottom: 0;\n    padding: 14px;\n    background: #ffffff;\n    border-left: 4px solid #08868a;\n    border-radius: 5px;\n  }\n\n  @media screen and (max-width: 650px) {\n    .bine-stoffarten {\n      grid-template-columns: 1fr;\n    }\n\n    .bine-logo-parallax {\n      min-height: 120px;\n    }\n\n    .bine-stoff-logo {\n      max-width: 75%;\n      max-height: 100px;\n    }\n  }\n\n  @media (prefers-reduced-motion: reduce) {\n    .bine-stoff-logo {\n      transform: none !important;\n    }\n  }\n\u003c\/style\u003e\n\n\u003cscript\u003e\n(function () {\n  const parallaxElements = document.querySelectorAll(\n    \"[data-bine-parallax] .bine-stoff-logo\"\n  );\n\n  if (\n    !parallaxElements.length ||\n    window.matchMedia(\"(prefers-reduced-motion: reduce)\").matches\n  ) {\n    return;\n  }\n\n  let animationFrameRequested = false;\n\n  function updateParallax() {\n    parallaxElements.forEach(function (logo) {\n      const container = logo.closest(\"[data-bine-parallax]\");\n      const position = container.getBoundingClientRect();\n      const windowHeight = window.innerHeight;\n\n      if (\n        position.bottom \u003e= 0 \u0026\u0026\n        position.top \u003c= windowHeight\n      ) {\n        const containerCenter =\n          position.top + position.height \/ 2;\n\n        const screenCenter = windowHeight \/ 2;\n\n        const offset =\n          (containerCenter - screenCenter) * -0.08;\n\n        const limitedOffset = Math.max(\n          -22,\n          Math.min(22, offset)\n        );\n\n        logo.style.transform =\n          \"translate3d(0,\" + limitedOffset + \"px,0)\";\n      }\n    });\n\n    animationFrameRequested = false;\n  }\n\n  function requestParallaxUpdate() {\n    if (!animationFrameRequested) {\n      window.requestAnimationFrame(updateParallax);\n      animationFrameRequested = true;\n    }\n  }\n\n  window.addEventListener(\n    \"scroll\",\n    requestParallaxUpdate,\n    { passive: true }\n  );\n\n  window.addEventListener(\n    \"resize\",\n    requestParallaxUpdate\n  );\n\n  requestParallaxUpdate();\n})();\n\u003c\/script\u003e\n\u003cdiv class=\"stoff-tabs\" data-stoff-tabs\u003e\n\n  \u003cdiv class=\"stoff-tabs__buttons\" role=\"tablist\"\u003e\n\n    \u003cbutton type=\"button\" class=\"stoff-tab-button\" data-stoff-button=\"Baumwolle\" role=\"tab\" aria-selected=\"false\"\u003e\n\n      \u003cimg src=\"https:\/\/cdn.shopify.com\/s\/files\/1\/0042\/4758\/4881\/files\/Button-Gif02?v=1787787739\" alt=\"\" class=\"stoff-tab-gif\"\u003e\n\n      \u003cspan\u003eBaumwolle\u003c\/span\u003e\n    \u003c\/button\u003e\n\n    \u003cbutton type=\"button\" class=\"stoff-tab-button\" data-stoff-button=\"Jersey\" role=\"tab\" aria-selected=\"false\"\u003e\n\n      \u003cimg src=\"https:\/\/cdn.shopify.com\/s\/files\/1\/0042\/4758\/4881\/files\/Button-Gif01?v=1787787739\" alt=\"\" class=\"stoff-tab-gif\"\u003e\n\n      \u003cspan\u003eJersey\u003c\/span\u003e\n    \u003c\/button\u003e\n\n  \u003c\/div\u003e\n\n  \u003c!-- BAUMWOLLE --\u003e\n\n  \u003cdiv class=\"stoff-tab-content\" data-stoff-content=\"Baumwolle\" role=\"tabpanel\" hidden\u003e\n\n   \u003ch3\u003eBaumwollgewebe\u003c\/h3\u003e \u003cp\u003e 100 % Baumwolle (gekämmtes Garn)\u003cbr\u003e Schöne, glatte Oberfläche \u003c\/p\u003e \u003cp\u003e\u003cstrong\u003eMaterialzusammensetzung\u003c\/strong\u003e\u003cbr\u003e Rohgewebe aus 100 % Baumwolle,\u003cbr\u003e hergestellt aus Materialien, die gemäß OEKO-TEX® STANDARD 100 zertifiziert sind. \u003c\/p\u003e \u003cp\u003e \u003cstrong\u003eStoffbreite:\u003c\/strong\u003e 160 cm ± 2 cm\u003cbr\u003e\u003cstrong\u003eGrammgewicht:\u003c\/strong\u003e 150–153 g\/m² \u003c\/p\u003e \u003chr\u003e \n\u003c\/div\u003e\n\n  \u003c!-- JERSEY --\u003e\n\n  \u003cdiv class=\"stoff-tab-content\" data-stoff-content=\"Jersey\" role=\"tabpanel\" hidden\u003e\n\n\n   \u003ch3\u003eJersey\u003c\/h3\u003e \u003cp\u003e \u003cstrong\u003eZusammensetzung:\u003c\/strong\u003e\u003cbr\u003e 92 % Baumwolle (gekämmtes Garn)\u003cbr\u003e Schöne, glatte Oberfläche\u003cbr\u003e 8 % Elasthan \u003c\/p\u003e \u003cp\u003e \u003cstrong\u003eMaterialzusammensetzung\u003c\/strong\u003e\u003cbr\u003e Maschenwaren aus Baumwollgarnen mit Zusatz von Elastangarnen (EL-Anteil bis zu 8 %).\u003cbr\u003e Ausschließlich hergestellt unter Verwendung von Komponenten und Veredelungsverfahren, die gemäß OEKO-TEX® STANDARD 100 vorzertifiziert sind. \u003c\/p\u003e \u003cp\u003e\u003cstrong\u003eStoffbreite:\u003c\/strong\u003e 160 cm ± 3 cm\u003cbr\u003e \u003cstrong\u003eGrammgewicht:\u003c\/strong\u003e 200–210 g\/m² \u003c\/p\u003e\n\n\u003c\/div\u003e\n\n\u003cstyle\u003e\n  .stoff-tabs {\n    margin: 25px 0;\n  }\n\n  .stoff-tabs__buttons {\n    display: flex;\n    gap: 6px;\n    border-bottom: 1px solid #d8d8d8;\n  }\n\n  .stoff-tab-button {\n    appearance: none;\n    display: flex;\n    align-items: center;\n    justify-content: center;\n    gap: 8px;\n    flex: 1;\n    padding: 12px 20px;\n    border: 1px solid #d8d8d8;\n    border-bottom: 0;\n    border-radius: 7px 7px 0 0;\n    background: #f5f5f5;\n    color: inherit;\n    font: inherit;\n    font-weight: 600;\n    cursor: pointer;\n  }\n\n  .stoff-tab-gif {\n    width: 32px;\n    height: 32px;\n    object-fit: contain;\n    flex-shrink: 0;\n  }\n\n  .stoff-tab-button:hover {\n    background: #e9e9e9;\n  }\n\n  .stoff-tab-button.is-active {\n    background: #08868a;\n    border-color: #08868a;\n    color: #ffffff;\n  }\n\n  .stoff-tab-button.is-unavailable {\n    display: none !important;\n  }\n\n  .stoff-tab-content {\n    padding: 20px;\n    border: 1px solid #d8d8d8;\n    border-top: 0;\n  }\n\n  .stoff-tab-content h3 {\n    margin-top: 0;\n  }\n\n  .stoff-tab-content h4 {\n    margin-top: 20px;\n    margin-bottom: 8px;\n  }\n\n  .stoff-tab-content[hidden],\n  .stoff-tab-content.is-unavailable {\n    display: none !important;\n  }\n\n  @media screen and (max-width: 600px) {\n    .stoff-tab-button {\n      padding: 11px 8px;\n      gap: 6px;\n    }\n\n    .stoff-tab-gif {\n      width: 28px;\n      height: 28px;\n    }\n\n    .stoff-tab-content {\n      padding: 16px;\n    }\n  }\n\u003c\/style\u003e\n\n\u003cscript\u003e\n(function () {\n  const STOFFARTEN = [\"Baumwolle\", \"Jersey\"];\n\n  function normalize(value) {\n    return String(value || \"\").trim().toLowerCase();\n  }\n\n  function getCorrectName(value) {\n    const wanted = normalize(value);\n\n    return STOFFARTEN.find(function (stoffart) {\n      return normalize(stoffart) === wanted;\n    }) || null;\n  }\n\n  function getTabs() {\n    return document.querySelectorAll(\"[data-stoff-tabs]\");\n  }\n\n  function isTabAvailable(container, stoffart) {\n    const button = Array.from(\n      container.querySelectorAll(\"[data-stoff-button]\")\n    ).find(function (element) {\n      return normalize(element.dataset.stoffButton) === normalize(stoffart);\n    });\n\n    return button \u0026\u0026 !button.classList.contains(\"is-unavailable\");\n  }\n\n  function openStoffTab(container, stoffart) {\n    const correctName = getCorrectName(stoffart);\n\n    if (!correctName || !isTabAvailable(container, correctName)) {\n      return;\n    }\n\n    const wanted = normalize(correctName);\n\n    container\n      .querySelectorAll(\"[data-stoff-button]\")\n      .forEach(function (button) {\n        const active =\n          !button.classList.contains(\"is-unavailable\") \u0026\u0026\n          normalize(button.dataset.stoffButton) === wanted;\n\n        button.classList.toggle(\"is-active\", active);\n        button.setAttribute(\n          \"aria-selected\",\n          active ? \"true\" : \"false\"\n        );\n      });\n\n    container\n      .querySelectorAll(\"[data-stoff-content]\")\n      .forEach(function (content) {\n        const active =\n          !content.classList.contains(\"is-unavailable\") \u0026\u0026\n          normalize(content.dataset.stoffContent) === wanted;\n\n        content.classList.toggle(\"is-active\", active);\n        content.hidden = !active;\n      });\n  }\n\n  function openFirstAvailableTab(container) {\n    const firstButton = Array.from(\n      container.querySelectorAll(\"[data-stoff-button]\")\n    ).find(function (button) {\n      return !button.classList.contains(\"is-unavailable\");\n    });\n\n    if (firstButton) {\n      openStoffTab(\n        container,\n        firstButton.dataset.stoffButton\n      );\n    }\n  }\n\n  function getSelectedStoffart(container) {\n    const section =\n      container.closest(\".shopify-section\") || document;\n\n    const selectedFields = section.querySelectorAll(\n      'input[type=\"radio\"]:checked, select'\n    );\n\n    for (const field of selectedFields) {\n      const name = getCorrectName(field.value);\n\n      if (name) {\n        return name;\n      }\n    }\n\n    return null;\n  }\n\n  function syncTabs() {\n    getTabs().forEach(function (container) {\n      const selectedStoffart =\n        getSelectedStoffart(container);\n\n      if (\n        selectedStoffart \u0026\u0026\n        isTabAvailable(container, selectedStoffart)\n      ) {\n        openStoffTab(container, selectedStoffart);\n      } else {\n        openFirstAvailableTab(container);\n      }\n    });\n  }\n\n  function updateAvailability(product) {\n    if (!product || !Array.isArray(product.variants)) {\n      syncTabs();\n      return;\n    }\n\n    const availability = {\n      baumwolle: false,\n      jersey: false\n    };\n\n    product.variants.forEach(function (variant) {\n      if (!variant.available) {\n        return;\n      }\n\n      const options = variant.options || [\n        variant.option1,\n        variant.option2,\n        variant.option3\n      ];\n\n      options.forEach(function (optionValue) {\n        const stoffart =\n          getCorrectName(optionValue);\n\n        if (stoffart) {\n          availability[normalize(stoffart)] = true;\n        }\n      });\n    });\n\n    getTabs().forEach(function (container) {\n      STOFFARTEN.forEach(function (stoffart) {\n        const available =\n          availability[normalize(stoffart)] === true;\n\n        const button = container.querySelector(\n          '[data-stoff-button=\"' + stoffart + '\"]'\n        );\n\n        const content = container.querySelector(\n          '[data-stoff-content=\"' + stoffart + '\"]'\n        );\n\n        if (button) {\n          button.classList.toggle(\n            \"is-unavailable\",\n            !available\n          );\n\n          button.hidden = !available;\n        }\n\n        if (content) {\n          content.classList.toggle(\n            \"is-unavailable\",\n            !available\n          );\n\n          if (!available) {\n            content.hidden = true;\n          }\n        }\n      });\n\n      const activeButton = container.querySelector(\n        \"[data-stoff-button].is-active:not(.is-unavailable)\"\n      );\n\n      if (!activeButton) {\n        openFirstAvailableTab(container);\n      }\n    });\n\n    syncTabs();\n  }\n\n  function loadProductAvailability() {\n    const productPath =\n      window.location.pathname.replace(\/\\\/$\/, \"\");\n\n    if (!productPath.includes(\"\/products\/\")) {\n      syncTabs();\n      return;\n    }\n\n    fetch(productPath + \".js\")\n      .then(function (response) {\n        if (!response.ok) {\n          throw new Error(\n            \"Produktdaten konnten nicht geladen werden.\"\n          );\n        }\n\n        return response.json();\n      })\n      .then(updateAvailability)\n      .catch(function () {\n        syncTabs();\n      });\n  }\n\n  document.addEventListener(\"click\", function (event) {\n    const button =\n      event.target.closest(\"[data-stoff-button]\");\n\n    if (\n      !button ||\n      button.classList.contains(\"is-unavailable\")\n    ) {\n      return;\n    }\n\n    const container =\n      button.closest(\"[data-stoff-tabs]\");\n\n    if (container) {\n      openStoffTab(\n        container,\n        button.dataset.stoffButton\n      );\n    }\n  });\n\n  document.addEventListener(\"change\", function (event) {\n    if (\n      event.target.matches(\n        'input[type=\"radio\"], select'\n      )\n    ) {\n      window.setTimeout(syncTabs, 50);\n    }\n  });\n\n  function initializeStoffTabs() {\n    loadProductAvailability();\n    window.setTimeout(syncTabs, 300);\n  }\n\n  if (document.readyState === \"loading\") {\n    document.addEventListener(\n      \"DOMContentLoaded\",\n      initializeStoffTabs\n    );\n  } else {\n    initializeStoffTabs();\n  }\n})();\n\u003c\/script\u003e\n\u003cdiv class=\"dynamisches-moodbild\" data-moodbild\u003e\u003c\/div\u003e\n\n\u003cstyle\u003e\n  .dynamisches-moodbild {\n    display: none;\n    margin: 25px 0;\n    text-align: center;\n  }\n\n  .dynamisches-moodbild.is-visible {\n    display: block;\n  }\n\n  .moodbild-link {\n    display: block;\n    text-decoration: none;\n    border-radius: 14px;\n    overflow: hidden;\n  }\n\n  .dynamisches-moodbild img {\n    display: block;\n    width: 100%;\n    height: auto;\n    margin: 0 auto;\n    border-radius: 14px;\n    transition: transform 0.25s ease;\n  }\n\n  .moodbild-link:hover img {\n    transform: scale(1.015);\n  }\n\n  @media (prefers-reduced-motion: reduce) {\n    .dynamisches-moodbild img {\n      transition: none;\n    }\n\n    .moodbild-link:hover img {\n      transform: none;\n    }\n  }\n\u003c\/style\u003e\n\n\u003cscript\u003e\n(function () {\n  const MARKER = \"#moodbild\";\n\n  const containers = document.querySelectorAll(\n    \"[data-moodbild]\"\n  );\n\n  if (!containers.length) return;\n\n  function cleanAlt(text) {\n    return String(text || \"\")\n      .replace(\/\\s*#Moodbild\\s*\/gi, \"\")\n      .trim();\n  }\n\n  function getImageUrl(image) {\n    if (image.currentSrc) {\n      return image.currentSrc;\n    }\n\n    const srcset =\n      image.getAttribute(\"srcset\") ||\n      image.getAttribute(\"data-srcset\");\n\n    if (srcset) {\n      const sources = srcset\n        .split(\",\")\n        .map(function (entry) {\n          return entry.trim().split(\/\\s+\/)[0];\n        })\n        .filter(Boolean);\n\n      if (sources.length) {\n        return sources[sources.length - 1];\n      }\n    }\n\n    return (\n      image.getAttribute(\"data-src\") ||\n      image.getAttribute(\"src\") ||\n      \"\"\n    );\n  }\n\n  function insertMoodbild(imageUrl, altText) {\n    if (!imageUrl) return false;\n\n    containers.forEach(function (container) {\n      if (\n        container.dataset.moodbildLoaded === \"true\"\n      ) {\n        return;\n      }\n\n      const link = document.createElement(\"a\");\n\n      link.href = \"https:\/\/www.bines-shop.com\";\n      link.target = \"_blank\";\n      link.rel = \"noopener noreferrer\";\n      link.className = \"moodbild-link\";\n\n      link.setAttribute(\n        \"aria-label\",\n        \"Bines Shop in einem neuen Fenster öffnen\"\n      );\n\n      const image = document.createElement(\"img\");\n\n      image.src = imageUrl;\n\n      image.alt =\n        cleanAlt(altText) ||\n        \"Moodbild zum Produkt\";\n\n      image.loading = \"lazy\";\n      image.decoding = \"async\";\n\n      link.appendChild(image);\n      container.replaceChildren(link);\n\n      container.classList.add(\"is-visible\");\n\n      container.dataset.moodbildLoaded = \"true\";\n    });\n\n    return true;\n  }\n\n  function findMoodbildInGallery() {\n    const images = Array.from(\n      document.querySelectorAll(\"img\")\n    ).filter(function (image) {\n      if (image.closest(\"[data-moodbild]\")) {\n        return false;\n      }\n\n      const searchableText = [\n        image.getAttribute(\"alt\"),\n        image.getAttribute(\"data-alt\"),\n        image.getAttribute(\"aria-label\")\n      ]\n        .filter(Boolean)\n        .join(\" \")\n        .toLowerCase();\n\n      return searchableText.includes(MARKER);\n    });\n\n    if (!images.length) {\n      return false;\n    }\n\n    const moodbild = images.find(function (image) {\n      return getImageUrl(image);\n    });\n\n    if (!moodbild) {\n      return false;\n    }\n\n    const altText =\n      moodbild.getAttribute(\"alt\") ||\n      moodbild.getAttribute(\"data-alt\") ||\n      moodbild.getAttribute(\"aria-label\") ||\n      \"\";\n\n    return insertMoodbild(\n      getImageUrl(moodbild),\n      altText\n    );\n  }\n\n  function findMoodbildInProductData() {\n    const productPath =\n      window.location.pathname.replace(\/\\\/$\/, \"\");\n\n    if (!productPath.includes(\"\/products\/\")) {\n      return Promise.resolve(false);\n    }\n\n    return fetch(productPath + \".js\")\n      .then(function (response) {\n        if (!response.ok) {\n          throw new Error(\n            \"Produktdaten konnten nicht geladen werden.\"\n          );\n        }\n\n        return response.json();\n      })\n      .then(function (product) {\n        const media = Array.isArray(product.media)\n          ? product.media\n          : [];\n\n        const moodbild = media.find(function (item) {\n          return String(item.alt || \"\")\n            .toLowerCase()\n            .includes(MARKER);\n        });\n\n        if (!moodbild) {\n          return false;\n        }\n\n        const imageUrl =\n          moodbild.preview_image \u0026\u0026\n          moodbild.preview_image.src\n            ? moodbild.preview_image.src\n            : moodbild.src;\n\n        return insertMoodbild(\n          imageUrl,\n          moodbild.alt\n        );\n      })\n      .catch(function () {\n        return false;\n      });\n  }\n\n  function initializeMoodbild() {\n    if (findMoodbildInGallery()) {\n      return;\n    }\n\n    findMoodbildInProductData()\n      .then(function (found) {\n        if (found) return;\n\n        const observer = new MutationObserver(\n          function () {\n            if (findMoodbildInGallery()) {\n              observer.disconnect();\n            }\n          }\n        );\n\n        observer.observe(\n          document.documentElement,\n          {\n            childList: true,\n            subtree: true,\n            attributes: true,\n            attributeFilter: [\n              \"alt\",\n              \"data-alt\",\n              \"src\",\n              \"data-src\",\n              \"srcset\",\n              \"data-srcset\"\n            ]\n          }\n        );\n\n        window.setTimeout(function () {\n          observer.disconnect();\n        }, 15000);\n      });\n  }\n\n  if (document.readyState === \"loading\") {\n    document.addEventListener(\n      \"DOMContentLoaded\",\n      initializeMoodbild\n    );\n  } else {\n    initializeMoodbild();\n  }\n})();\n\u003c\/script\u003e\n\u003c\/div\u003e","brand":"DESDA Verlag GmbH","offers":[{"title":"Baumwolle \/ 1 Meter","offer_id":53327378481419,"sku":null,"price":24.95,"currency_code":"EUR","in_stock":true},{"title":"Baumwolle \/ 2 Meter","offer_id":53327378514187,"sku":null,"price":47.95,"currency_code":"EUR","in_stock":true},{"title":"Baumwolle \/ 3 Meter","offer_id":53327378546955,"sku":null,"price":69.95,"currency_code":"EUR","in_stock":true},{"title":"Jersey \/ 1 Meter","offer_id":53327378579723,"sku":null,"price":27.95,"currency_code":"EUR","in_stock":true},{"title":"Jersey \/ 2 Meter","offer_id":53327378612491,"sku":null,"price":53.95,"currency_code":"EUR","in_stock":true},{"title":"Jersey \/ 3 Meter","offer_id":53327378645259,"sku":null,"price":77.95,"currency_code":"EUR","in_stock":true}],"thumbnail_url":"\/\/cdn.shopify.com\/s\/files\/1\/0042\/4758\/4881\/files\/Aufmacher-SchrageStreifenGrun-Stoff-Baumwolle-Jersey-nahen-bunt-Muster.jpg?v=1787880657","url":"https:\/\/desda.shop\/products\/schrage-streifen-grun-stoff","provider":"DESDA Verlag GmbH","version":"1.0","type":"link"}