{"product_id":"made-to-order-custom-flat-roman-shade","title":"MADE TO ORDER Flat Roman Shade","description":"\u003cbody\u003e\n\u003cp data-rte-preserve-empty=\"true\"\u003e\u003cem\u003eAll Made To Order pieces are custom-made upon placing your order. FABRIC IS NOT INCLUDED in this price, please ensure that you add the required amount of fabric to your cart, along with trim or any other additions, as we cannot complete your order without these materials. For any questions or specific requests, feel free to contact us. Please note that additional charges may apply for certain customizations.\u003c\/em\u003e\u003c\/p\u003e\n\u003cp data-rte-preserve-empty=\"true\"\u003e\u003cem\u003eFor inquiries about fabrics not listed on our site, please contact us directly. We have established accounts with most major fabric brands worldwide and can often source specific materials upon request. If you’re interested in using Customer’s Own Material (COM), we’d be delighted to assist—please send to us directly using your order number and name as a side mark, or reach out directly for more details.\u003c\/em\u003e\u003c\/p\u003e\n\u003cp data-rte-preserve-empty=\"true\"\u003e\u003cstrong\u003e\u003cem\u003e\u003cspan\u003eYou may use the Flat Roman Shade Fabric Yardage Calculator below to determine required yardage.\u003c\/span\u003e\u003c\/em\u003e\u003c\/strong\u003e\u003c\/p\u003e\n\u003cp\u003e \u003c\/p\u003e\n\u003cp\u003e\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n  \n\n\u003c\/p\u003e\n \n\n\n  \u003cmeta charset=\"UTF-8\"\u003e\n  \u003cmeta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"\u003e\n  \u003ctitle\u003eFlat Roman Shade Calculator\u003c\/title\u003e\n  \u003cstyle\u003e\n    body {font-family:Arial,sans-serif;margin:0;padding:20px;background:#f4f4f4}\n    .calculator-wrapper{display:flex;justify-content:center;align-items:center;gap:20px}\n    .calculator-container{max-width:380px;padding:24px;border:1px solid #ccc;border-radius:12px;background:#f8f8f8;box-shadow:0 4px 12px rgba(0,0,0,.1)}\n    .calculator-container input,.calculator-container select,.calculator-container button{width:100%;padding:12px;margin:5px 0;border-radius:6px;border:1px solid #ccc;font-size:16px;box-sizing:border-box}\n    .calculator-container button{cursor:pointer;transition:background .2s,transform .2s,box-shadow .2s}\n    .calculator-container select:disabled,.calculator-container input:disabled{cursor:not-allowed;opacity:.6;background:#e9ecef}\n    .calculator-container textarea{width:100%;padding:12px;margin:5px 0;border-radius:6px;border:1px solid #ccc;font-size:16px;height:70px;resize:vertical}\n    .result{font-weight:bold;margin-top:20px;text-align:left}\n    .error{color:red;font-size:12px;display:none;margin-top:2px}\n    .note{font-size:.9em;color:#666;font-style:italic;margin-top:8px;line-height:1.4}\n    .calculate-button{background:#007cba;color:#fff;border:none;border-radius:6px;font-size:16px;font-weight:600;text-transform:uppercase;padding:14px;margin-top:10px}\n    .calculate-button:hover:not(:disabled){background:#005f8b;transform:scale(1.05);box-shadow:0 4px 8px rgba(0,0,0,.15)}\n    .calculate-button:active:not(:disabled){transform:scale(1);box-shadow:0 2px 4px rgba(0,0,0,.1)}\n    .calculate-button:disabled{background:#b0c4de;cursor:not-allowed}\n    .reset-button{background:#6c757d;color:#fff;border:none;border-radius:6px;font-size:16px;font-weight:600;text-transform:uppercase;padding:14px;margin-top:10px}\n    .reset-button:hover:not(:disabled){background:#5a6268;transform:scale(1.05);box-shadow:0 4px 8px rgba(0,0,0,.15)}\n    .reset-button:active:not(:disabled){transform:scale(1);box-shadow:0 2px 4px rgba(0,0,0,.1)}\n    .reset-button:disabled{background:#adb5bd;cursor:not-allowed}\n    .checkout-button{background:#28a745;color:#fff;border:none;border-radius:6px;font-size:16px;font-weight:600;text-transform:uppercase;padding:14px;margin-top:20px}\n    .checkout-button:hover:not(:disabled){background:#218838;transform:scale(1.05);box-shadow:0 4px 8px rgba(0,0,0,.15)}\n    .checkout-button:active:not(:disabled){transform:scale(1);box-shadow:0 2px 4px rgba(0,0,0,.1)}\n    .checkout-button:disabled{background:#a3cfbb;cursor:not-allowed}\n    .item_added_message{display:none;align-items:center;background:#e9f7ef;color:#28a745;margin-top:10px;margin-bottom:10px;padding:15px 20px;border:1px solid #d4edda;border-radius:8px;font-size:16px;box-shadow:0 4px 6px rgba(0,0,0,.1);flex-wrap:wrap;gap:10px;justify-content:space-between}\n    .item_added_message.error{background:#f8d7da;color:#dc3545;border-color:#f5c6cb}\n    .view-cart-button{background:#f9d857;color:#333;border:none;border-radius:6px;font-size:16px;font-weight:600;text-transform:uppercase;padding:15px 0;text-decoration:none;text-align:center;cursor:pointer;transition:background .2s,transform .2s,box-shadow .2s;display:block;width:100%;margin-top:10px}\n    .view-cart-button:hover{background:#f7ce3e;transform:scale(1.02);box-shadow:0 4px 8px rgba(0,0,0,.15)}\n    .view-cart-button:active{transform:scale(1);box-shadow:0 2px 4px rgba(0,0,0,.1)}\n    .loading-bar-container{display:none;width:100%;max-width:200px;height:20px;background:#d4edda;border-radius:4px;overflow:hidden;position:relative;margin-right:10px}\n    .loading-bar{height:100%;width:0;background:linear-gradient(90deg, #28a745 0%, #34c759 100%);border-radius:4px}\n    .loading-bar.animate{animation:loading 2s ease-in-out forwards !important}\n    @keyframes loading {\n      0% {width:0}\n      100% {width:100%}\n    }\n    .help-icon{display:inline-block;width:18px;height:18px;line-height:16px;border:1px solid #999;border-radius:50%;text-align:center;font-size:12px;cursor:help;margin-left:6px;color:#333;background:#fff;position:relative;user-select:none}\n    .help-icon::after{content:attr(data-tip);position:absolute;left:50%;bottom:125%;transform:translateX(-50%);background:#333;color:#fff;padding:6px 8px;border-radius:6px;font-size:12px;white-space:nowrap;opacity:0;pointer-events:none;transition:opacity .18s;z-index:1000}\n    .help-icon::before{content:\"\";position:absolute;left:50%;bottom:115%;transform:translateX(-50%);border:6px solid transparent;border-top-color:#333;opacity:0;transition:opacity .18s}\n    .help-icon:hover::after,.help-icon:hover::before{opacity:1}\n    label[for=\"ownFabric\"],label[for=\"customFabricName\"],label[for=\"ownTrim\"],label[for=\"customTrimName\"]{display:flex;align-items:center;gap:8px;margin:10px 0}\n    label[for=\"ownFabric\"] input[type=\"checkbox\"],label[for=\"ownTrim\"] input[type=\"checkbox\"]{margin:0;width:auto}\n    .browse-button{background:#007cba;color:#fff;border:none;border-radius:6px;font-size:14px;font-weight:600;text-transform:uppercase;padding:10px;margin-top:5px;cursor:pointer;transition:background .2s,transform .2s,box-shadow .2s}\n    .browse-button:hover:not(:disabled){background:#005f8b;transform:scale(1.05);box-shadow:0 4px 8px rgba(0,0,0,.15)}\n    .browse-button:active:not(:disabled){transform:scale(1);box-shadow:0 2px 4px rgba(0,0,0,.1)}\n    .browse-button:disabled{background:#b0c4de;cursor:not-allowed}\n    .fabric-swatch-preview,.trim-swatch-preview{display:none;margin-top:5px;align-items:center;gap:6px}\n    .fabric-swatch-image,.trim-swatch-image{width:40px;height:40px;object-fit:cover;border-radius:4px;border:1px solid #ddd;background:#f3f4f6}\n    .fabric-swatch-price,.trim-swatch-price{font-size:12px;color:#666;margin:0}\n    .singleFabricField,.singleTrimField{width:100%;padding:12px;margin:5px 0;border-radius:6px;border:1px solid #ccc;font-size:16px;background:#fff;cursor:text}\n    .singleFabricField:focus,.singleTrimField:focus{border-color:#007cba;box-shadow:0 0 0 2px rgba(0,124,186,.2);outline:none}\n    .swatch-clear-btn{background:transparent !important;border:none !important;cursor:pointer;font-size:18px;color:#999;display:none;padding:0 !important;margin:0 0 0 8px !important;width:auto !important}\n    .swatch-clear-btn.visible{display:inline-block !important}\n    .swatch-clear-btn:hover{color:#666}\n    .catalog-modal{display:none;position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,.9);z-index:10000;justify-content:center;align-items:center;cursor:pointer}\n    .catalog-content{background:#fff;border-radius:12px;padding:20px;max-width:80vw;max-height:80vh;text-align:center;position:relative;overflow-y:auto;cursor:default}\n    .catalog-close{position:absolute;top:10px;right:15px;font-size:32px;font-weight:bold;cursor:pointer;color:#fff;background:rgba(0,0,0,0.6);width:40px;height:40px;border-radius:50%;display:flex;align-items:center;justify-content:center;z-index:100}\n    .catalog-close:hover{background:rgba(0,0,0,0.8)}\n  \u003c\/style\u003e\n\n\n\n\u003cdiv class=\"calculator-wrapper\"\u003e\n  \u003cdiv class=\"calculator-container\"\u003e\n    \u003ch3 style=\"margin-bottom:20px;text-align:center;font-size:20px;\"\u003eFlat Roman Shade Calculator\u003c\/h3\u003e\n    \n    \u003cform id=\"shade-form\" onsubmit=\"return false\" style=\"display:flex;flex-direction:column;gap:14px;text-align:left;\"\u003e\n      \n      \u003clabel for=\"shadeName\"\u003eShade Name:\n        \u003cinput type=\"text\" id=\"shadeName\" placeholder=\"Master Bedroom, Living Room\" required oninput=\"hideError('shadeNameError')\"\u003e\n        \u003cspan style=\"font-size:12px;color:#666;font-style:italic;\"\u003eHelps identify this order\u003c\/span\u003e\n        \u003cspan id=\"shadeNameError\" class=\"error\"\u003ePlease enter a Shade Name.\u003c\/span\u003e\n      \u003c\/label\u003e\n      \n      \u003clabel for=\"shadeWidth\"\u003eWidth (inches):\n        \u003cinput type=\"number\" id=\"shadeWidth\" placeholder=\"Enter width\" min=\"1\" step=\"any\" required oninput=\"hideError('widthError')\"\u003e\n        \u003cspan id=\"widthError\" class=\"error\"\u003eWidth must be at least 1 inch.\u003c\/span\u003e\n      \u003c\/label\u003e\n      \n      \u003clabel for=\"shadeLength\"\u003eLength (inches):\n        \u003cinput type=\"number\" id=\"shadeLength\" placeholder=\"Enter length\" min=\"1\" step=\"any\" required oninput=\"hideError('lengthError')\"\u003e\n        \u003cspan id=\"lengthError\" class=\"error\"\u003eLength must be at least 1 inch.\u003c\/span\u003e\n      \u003c\/label\u003e\n      \n      \u003clabel for=\"singleFabricField\"\u003eFabric Selection:\n        \u003cbutton type=\"button\" class=\"browse-button\" id=\"browseFabricsBtn\"\u003eBrowse Fabrics\u003c\/button\u003e\n        \u003cinput type=\"text\" id=\"singleFabricField\" class=\"singleFabricField\" placeholder=\"Type to search\" readonly\u003e\n        \u003cdiv class=\"fabric-swatch-preview\" id=\"fabricSwatchPreview\"\u003e\n          \u003cimg id=\"fabricSwatchImage\" class=\"fabric-swatch-image\" src=\"\" alt=\"\"\u003e\n          \u003cspan id=\"fabricSwatchPrice\" class=\"fabric-swatch-price\"\u003e\u003c\/span\u003e\n          \u003cbutton type=\"button\" class=\"swatch-clear-btn\" id=\"fabricSwatchClearBtn\"\u003e×\u003c\/button\u003e\n        \u003c\/div\u003e\n        \u003cspan id=\"fabricError\" class=\"error\"\u003ePlease select a fabric or use your own.\u003c\/span\u003e\n      \u003c\/label\u003e\n      \n      \u003clabel for=\"ownFabric\"\u003e\n        \u003cinput type=\"checkbox\" id=\"ownFabric\"\u003e Use My Own Fabric\n      \u003c\/label\u003e\n      \n      \u003clabel for=\"customFabricName\" style=\"display:none;\"\u003eCustom Fabric Name:\n        \u003cinput type=\"text\" id=\"customFabricName\" placeholder=\"Enter fabric name\"\u003e\n        \u003cspan id=\"customFabricNameError\" class=\"error\"\u003ePlease enter fabric name.\u003c\/span\u003e\n      \u003c\/label\u003e\n      \n      \u003clabel for=\"trimPlacement\"\u003eTrim Placement:\n        \u003cselect id=\"trimPlacement\" required\u003e\n          \u003coption value=\"none\"\u003eNone\u003c\/option\u003e\n          \u003coption value=\"center\"\u003eCenter Stripe\u003c\/option\u003e\n          \u003coption value=\"bottom\"\u003eBottom Trim\u003c\/option\u003e\n          \u003coption value=\"sides\"\u003eSide Banding\u003c\/option\u003e\n          \u003coption value=\"picture\"\u003ePicture Frame\u003c\/option\u003e\n        \u003c\/select\u003e\n      \u003c\/label\u003e\n      \n      \u003clabel for=\"singleTrimField\"\u003eTrim Selection:\n        \u003cbutton type=\"button\" class=\"browse-button\" id=\"browseTrimsBtn\" disabled\u003eBrowse Trims\u003c\/button\u003e\n        \u003cinput type=\"text\" id=\"singleTrimField\" class=\"singleTrimField\" placeholder=\"Type to search\" readonly disabled\u003e\n        \u003cdiv class=\"trim-swatch-preview\" id=\"trimSwatchPreview\"\u003e\n          \u003cimg id=\"trimSwatchImage\" class=\"trim-swatch-image\" src=\"\" alt=\"\"\u003e\n          \u003cspan id=\"trimSwatchPrice\" class=\"trim-swatch-price\"\u003e\u003c\/span\u003e\n          \u003cbutton type=\"button\" class=\"swatch-clear-btn\" id=\"trimSwatchClearBtn\"\u003e×\u003c\/button\u003e\n        \u003c\/div\u003e\n        \u003cspan id=\"trimError\" class=\"error\"\u003ePlease select a trim or use your own.\u003c\/span\u003e\n      \u003c\/label\u003e\n      \n      \u003clabel for=\"ownTrim\"\u003e\n        \u003cinput type=\"checkbox\" id=\"ownTrim\" disabled\u003e Use My Own Trim\n      \u003c\/label\u003e\n      \n      \u003clabel for=\"customTrimName\" style=\"display:none;\"\u003eCustom Trim Name:\n        \u003cinput type=\"text\" id=\"customTrimName\" placeholder=\"Enter trim name\"\u003e\n        \u003cspan id=\"customTrimNameError\" class=\"error\"\u003ePlease enter trim name.\u003c\/span\u003e\n      \u003c\/label\u003e\n      \n      \u003clabel for=\"cordOption\"\u003eCord Option:\n        \u003cselect id=\"cordOption\" required\u003e\n          \u003coption value=\"left\"\u003eCord Left\u003c\/option\u003e\n          \u003coption value=\"right\"\u003eCord Right\u003c\/option\u003e\n          \u003coption value=\"cordless\"\u003eCordless\u003c\/option\u003e\n        \u003c\/select\u003e\n      \u003c\/label\u003e\n      \n      \u003clabel for=\"mountOption\"\u003eMount Option:\n        \u003cselect id=\"mountOption\" required\u003e\n          \u003coption value=\"inside\"\u003eInside Mount\u003c\/option\u003e\n          \u003coption value=\"outside\"\u003eOutside Mount\u003c\/option\u003e\n        \u003c\/select\u003e\n      \u003c\/label\u003e\n      \n      \u003clabel for=\"linerOption\"\u003eLiner:\n        \u003cselect id=\"linerOption\" required\u003e\n          \u003coption value=\"0\"\u003eNo Liner\u003c\/option\u003e\n          \u003coption value=\"2\"\u003eStandard White Liner\u003c\/option\u003e\n          \u003coption value=\"3\"\u003eBlackout Liner\u003c\/option\u003e\n        \u003c\/select\u003e\n      \u003c\/label\u003e\n      \n      \u003clabel for=\"fabricWidth\"\u003eFabric Width (inches):\n        \u003cinput type=\"number\" id=\"fabricWidth\" value=\"54\" min=\"36\" step=\"any\" required readonly style=\"background:#f0f0f0;\"\u003e\n        \u003cspan class=\"note\"\u003eIf you have a question about a specific fabric repeat, please reach out\u003c\/span\u003e\n        \u003cspan id=\"fabricWidthError\" class=\"error\"\u003eFabric width must be at least 36 inches.\u003c\/span\u003e\n      \u003c\/label\u003e\n      \n      \u003clabel for=\"quantity\"\u003eQuantity:\n        \u003cinput type=\"number\" id=\"quantity\" min=\"1\" value=\"1\" required\u003e\n        \u003cspan id=\"quantityError\" class=\"error\"\u003eQuantity must be at least 1.\u003c\/span\u003e\n      \u003c\/label\u003e\n      \n      \u003clabel for=\"additionalNotes\"\u003eAdditional Notes:\n        \u003ctextarea id=\"additionalNotes\" placeholder=\"Provide any additional information or requests here. Additional charges may apply.\"\u003e\u003c\/textarea\u003e\n      \u003c\/label\u003e\n      \n      \u003cbutton type=\"button\" id=\"calculateButton\" class=\"calculate-button\"\u003eCalculate\u003c\/button\u003e\n      \u003cspan id=\"calculateError\" class=\"error\"\u003ePlease fix all errors.\u003c\/span\u003e\n      \u003cbutton type=\"button\" id=\"resetButton\" class=\"reset-button\"\u003eReset\u003c\/button\u003e\n      \n      \u003cdiv class=\"result\" id=\"shadeResult\"\u003e\u003c\/div\u003e\n      \n      \u003cbutton type=\"button\" class=\"checkout-button\" id=\"addToCartButton\" disabled\u003eAdd to Cart\u003c\/button\u003e\n      \n      \u003cdiv class=\"item_added_message\" id=\"item_added_message\"\u003e\n        \u003cdiv style=\"display:flex;align-items:center;flex:1;\"\u003e\n          \u003csvg width=\"24px\" height=\"24px\" viewbox=\"0 0 1024 1024\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"margin-right:10px;\"\u003e\n            \u003cpath fill=\"#28a745\" d=\"M512 64a448 448 0 1 1 0 896 448 448 0 0 1 0-896zm-55.808 536.384-99.52-99.584a38.4 38.4 0 1 0-54.336 54.336l126.72 126.72a38.272 38.272 0 0 0 54.336 0l262.4-262.464a38.4 38.4 0 1 0-54.272-54.336L456.192 600.384z\"\u003e\u003c\/path\u003e\n          \u003c\/svg\u003e\n          \u003cdiv class=\"loading-bar-container\" id=\"loadingBar\"\u003e\n            \u003cdiv class=\"loading-bar\"\u003e\u003c\/div\u003e\n          \u003c\/div\u003e\n          \u003cspan id=\"cartMessage\"\u003eSuccess!\u003c\/span\u003e\n        \u003c\/div\u003e\n        \u003ca href=\"\/cart\" class=\"view-cart-button\" id=\"viewCartButton\" style=\"display:none;\"\u003eVIEW CART\u003c\/a\u003e\n      \u003c\/div\u003e\n    \u003c\/form\u003e\n  \u003c\/div\u003e\n\u003c\/div\u003e\n\n\u003cdiv class=\"catalog-modal\" id=\"fabricCatalogModal\"\u003e\n  \u003cdiv class=\"catalog-content\"\u003e\n    \u003cspan class=\"catalog-close\" onclick=\"closeCatalogModal('fabric')\"\u003e×\u003c\/span\u003e\n    \u003ch2\u003eFabric Catalog\u003c\/h2\u003e\n    \u003cp\u003eA new window will open with our fabric collection.\u003c\/p\u003e\n    \u003cbutton type=\"button\" class=\"browse-button\" id=\"fabricPopupBtn\" style=\"width:100%;margin-top:20px;padding:15px;\"\u003eOpen Fabric Collection\u003c\/button\u003e\n  \u003c\/div\u003e\n\u003c\/div\u003e\n\n\u003cdiv class=\"catalog-modal\" id=\"trimCatalogModal\"\u003e\n  \u003cdiv class=\"catalog-content\"\u003e\n    \u003cspan class=\"catalog-close\" onclick=\"closeCatalogModal('trim')\"\u003e×\u003c\/span\u003e\n    \u003ch2\u003eTrim Catalog\u003c\/h2\u003e\n    \u003cp\u003eA new window will open with our trim collection.\u003c\/p\u003e\n    \u003cbutton type=\"button\" class=\"browse-button\" id=\"trimPopupBtn\" style=\"width:100%;margin-top:20px;padding:15px;\"\u003eOpen Trim Collection\u003c\/button\u003e\n  \u003c\/div\u003e\n\u003c\/div\u003e\n\n\u003cscript src=\"https:\/\/code.jquery.com\/jquery-3.7.1.min.js\"\u003e\u003c\/script\u003e\n\n\u003cscript\u003e\n  const SHADE_VARIANT_ID = '50879616123168'; \/\/ Replace with actual Flat Roman Shade variant ID\n  const STYLE_PRICE_PER_SQFT = 34;\n  const STYLE_MINIMUM = 136;\n  const STYLE_FULLNESS = 1; \/\/ No fullness for Flat\n  \n  \/* ============================================\n   * DOMAIN CONFIGURATION - READ CAREFULLY\n   * ============================================\n   * When going live with a custom domain:\n   * \n   * - STOREFRONT_DOMAIN: Update this to your custom domain (e.g., 'www.yourdomain.com')\n   *   This is used for popup windows and public-facing URLs.\n   *   CHANGE THIS when switching to a custom domain.\n   *\/\n  const STOREFRONT_DOMAIN = 'z10i3p-9c.myshopify.com';  \/\/ CHANGE THIS when switching to custom domain\n  \n  let selectedFabric = null, selectedTrim = null;\n  let lastCalculatedYards = { fabric: 0, trim: 0 };\n  let lastCalculatedPrice = 0;\n\n  function hideError(id) { document.getElementById(id).style.display = 'none'; }\n  \n  function sanitize(str) {\n    if (!str) return 'None';\n    return String(str).replace(\/[\\r\\n\\t]+\/g, ' ').replace(\/\"\/g, \"'\").trim().slice(0, 500);\n  }\n\n  function showCatalog(type) {\n    const url = type === 'fabric' \n      ? `https:\/\/${STOREFRONT_DOMAIN}\/collections\/fabric-1?calculator=true`\n      : `https:\/\/${STOREFRONT_DOMAIN}\/collections\/trim?calculator=true`;\n    \n    const windowName = type === 'fabric' ? 'fabricBrowser' : 'trimBrowser';\n    const popupWindow = window.open(url, windowName, 'width=1200,height=900,resizable=yes,scrollbars=yes');\n    \n    if (!popupWindow || popupWindow.closed || typeof popupWindow.closed == 'undefined') {\n      \/\/ Popup was blocked, show the modal with instructions\n      const modal = document.getElementById(type === 'fabric' ? 'fabricCatalogModal' : 'trimCatalogModal');\n      modal.style.display = 'flex';\n      \n      \/\/ Setup the manual button\n      const popupBtn = document.getElementById(type === 'fabric' ? 'fabricPopupBtn' : 'trimPopupBtn');\n      popupBtn.onclick = () =\u003e {\n        window.open(url, windowName, 'width=1200,height=900,resizable=yes,scrollbars=yes');\n      };\n    }\n  }\n\n  function closeCatalogModal(type) {\n    const modal = document.getElementById(type === 'fabric' ? 'fabricCatalogModal' : 'trimCatalogModal');\n    if (modal) modal.style.display = 'none';\n  }\n\n  function clearSelection(type) {\n    if (type === 'fabric') {\n      selectedFabric = null;\n      document.getElementById('singleFabricField').value = '';\n      document.getElementById('fabricSwatchPreview').style.display = 'none';\n      document.getElementById('fabricWidth').value = 54;\n    } else {\n      selectedTrim = null;\n      document.getElementById('singleTrimField').value = '';\n      document.getElementById('trimSwatchPreview').style.display = 'none';\n    }\n  }\n\n  function validateForm(showErrors = true) {\n    let ok = true;\n    const w = parseFloat(document.getElementById('shadeWidth').value);\n    const l = parseFloat(document.getElementById('shadeLength').value);\n    const fw = parseFloat(document.getElementById('fabricWidth').value);\n    const q = parseInt(document.getElementById('quantity').value);\n    const name = document.getElementById('shadeName').value.trim();\n    const ownF = document.getElementById('ownFabric').checked;\n    const custF = document.getElementById('customFabricName').value.trim();\n    const trim = document.getElementById('trimPlacement').value;\n    const ownT = document.getElementById('ownTrim').checked;\n    const custT = document.getElementById('customTrimName').value.trim();\n\n    if (!name) { if (showErrors) document.getElementById('shadeNameError').style.display = 'block'; ok = false; }\n    if (isNaN(w) || w \u003c 1) { if (showErrors) document.getElementById('widthError').style.display = 'block'; ok = false; }\n    if (isNaN(l) || l \u003c 1) { if (showErrors) document.getElementById('lengthError').style.display = 'block'; ok = false; }\n    if (!ownF \u0026\u0026 !selectedFabric) { if (showErrors) document.getElementById('fabricError').style.display = 'block'; ok = false; }\n    if (ownF \u0026\u0026 !custF) { if (showErrors) document.getElementById('customFabricNameError').style.display = 'block'; ok = false; }\n    if (trim !== 'none' \u0026\u0026 !ownT \u0026\u0026 !selectedTrim) { if (showErrors) document.getElementById('trimError').style.display = 'block'; ok = false; }\n    if (ownT \u0026\u0026 trim !== 'none' \u0026\u0026 !custT) { if (showErrors) document.getElementById('customTrimNameError').style.display = 'block'; ok = false; }\n    if (isNaN(fw) || fw \u003c 36) { if (showErrors) document.getElementById('fabricWidthError').style.display = 'block'; ok = false; }\n    if (isNaN(q) || q \u003c 1) { if (showErrors) document.getElementById('quantityError').style.display = 'block'; ok = false; }\n    return ok;\n  }\n\n  function calculateShade() {\n    if (!validateForm(true)) {\n      document.getElementById('calculateError').style.display = 'block';\n      return;\n    }\n    document.getElementById('calculateError').style.display = 'none';\n\n    const width = parseFloat(document.getElementById('shadeWidth').value);\n    const length = parseFloat(document.getElementById('shadeLength').value);\n    const fabricWidth = parseFloat(document.getElementById('fabricWidth').value);\n    const quantity = parseInt(document.getElementById('quantity').value);\n    const cordOption = document.getElementById('cordOption').value;\n    const linerOption = parseFloat(document.getElementById('linerOption').value);\n    const trimPlacement = document.getElementById('trimPlacement').value;\n    const ownFabric = document.getElementById('ownFabric').checked;\n    const ownTrim = document.getElementById('ownTrim').checked;\n\n    \/\/ Base pricing calculation\n    const sqft = (width * length) \/ 144;\n    const totalSqft = sqft * quantity;\n    const basePrice = STYLE_PRICE_PER_SQFT * totalSqft;\n    const linerCost = linerOption * totalSqft;\n    const cordlessCost = (cordOption === 'cordless') ? 160 * quantity : 0;\n\n    \/\/ Fabric yardage calculation\n    const widthsNeeded = Math.ceil((width + 4) \/ fabricWidth);\n    const lengthWithHems = (length * STYLE_FULLNESS) + 10;\n    const fabricYardsPerShade = widthsNeeded * lengthWithHems \/ 36;\n    const totalFabricYards = fabricYardsPerShade * quantity;\n\n    \/\/ Trim calculations\n    let trimPricingInches = 0;\n    let trimYardageInches = 0;\n    \n    if (trimPlacement === 'center') {\n      trimPricingInches = length * 1.5;\n      trimYardageInches = length + 2;\n    } else if (trimPlacement === 'bottom') {\n      trimPricingInches = width * 1.5;\n      trimYardageInches = width + 2;\n    } else if (trimPlacement === 'sides') {\n      trimPricingInches = length * 2 * 1.5;\n      trimYardageInches = (length + 2) * 2;\n    } else if (trimPlacement === 'picture') {\n      trimPricingInches = (length * 2 + width) * 1.5;\n      trimYardageInches = (length + 2) * 2 + (width + 2);\n    }\n    \n    trimPricingInches *= quantity;\n    trimYardageInches *= quantity;\n    const trimYards = trimYardageInches \/ 36;\n    const trimCost = (trimPlacement !== 'none') ? trimPricingInches * 1.5 : 0;\n\n    \/\/ Product costs\n    const fabricPrice = ownFabric ? 0 : (selectedFabric ? selectedFabric.price * totalFabricYards : 0);\n    const trimPrice = (ownTrim || trimPlacement === 'none') ? 0 : (selectedTrim ? selectedTrim.price * trimYards : 0);\n\n    let total = basePrice + linerCost + cordlessCost + trimCost + fabricPrice + trimPrice;\n    total = Math.max(total, STYLE_MINIMUM);\n    total = Math.ceil(total);\n\n    lastCalculatedYards = { fabric: totalFabricYards, trim: trimYards };\n    lastCalculatedPrice = total;\n\n    const laborTotal = Math.ceil(basePrice + linerCost + cordlessCost + trimCost);\n    const fabricDisplay = ownFabric ? 'Customer Fabric' : (selectedFabric ? `$${Math.ceil(fabricPrice)}` : '$0');\n    const trimDisplay = (trimPlacement === 'none') ? 'N\/A' : (ownTrim ? 'Customer Trim' : (selectedTrim ? `$${Math.ceil(trimPrice)}` : '$0'));\n\n    document.getElementById('shadeResult').innerHTML = `\n      \u003cp style=\"font-size:18px;font-weight:bold;margin-bottom:10px;color:#28a745;\"\u003eTotal: $${total}\u003c\/p\u003e\n      \u003cdiv style=\"font-size:14px;line-height:1.8;border-top:1px solid #ddd;padding-top:10px;\"\u003e\n        \u003cp\u003e\u003cstrong\u003eLabor:\u003c\/strong\u003e $${laborTotal}\u003c\/p\u003e\n        \u003cp\u003e\u003cstrong\u003eFabric:\u003c\/strong\u003e ${Math.ceil(totalFabricYards)} yards - ${fabricDisplay}\u003c\/p\u003e\n        ${trimPlacement !== 'none' ? `\u003cp\u003e\u003cstrong\u003eTrim:\u003c\/strong\u003e ${Math.ceil(trimYards)} yards - ${trimDisplay}\u003c\/p\u003e` : ''}\n      \u003c\/div\u003e`;\n    \n    document.getElementById('addToCartButton').disabled = false;\n  }\n\n  function handleAddToCart() {\n    if (!validateForm(true)) {\n      document.getElementById('calculateError').style.display = 'block';\n      return;\n    }\n\n    const qty = parseInt(document.getElementById('quantity').value);\n    const shadeName = sanitize(document.getElementById('shadeName').value);\n    const ownFabric = document.getElementById('ownFabric').checked;\n    const ownTrim = document.getElementById('ownTrim').checked;\n    const trimPlacement = document.getElementById('trimPlacement').value;\n    \n    let fabricDetails = '';\n    if (ownFabric) {\n      fabricDetails = sanitize(document.getElementById('customFabricName').value) + ' (Customer Fabric)';\n    } else if (selectedFabric) {\n      const yards = Math.ceil(lastCalculatedYards.fabric);\n      fabricDetails = `${selectedFabric.title} (${yards} yards @ $${selectedFabric.price.toFixed(2)}\/yd)`;\n    }\n    \n    let trimDetails = '';\n    if (trimPlacement === 'none') {\n      trimDetails = 'None';\n    } else if (ownTrim) {\n      trimDetails = sanitize(document.getElementById('customTrimName').value) + ' (Customer Trim)';\n    } else if (selectedTrim) {\n      const yards = Math.ceil(lastCalculatedYards.trim);\n      trimDetails = `${selectedTrim.title} (${yards} yards @ $${selectedTrim.price.toFixed(2)}\/yd)`;\n    }\n\n    const items = [{\n      id: parseInt(SHADE_VARIANT_ID, 10),\n      quantity: qty,\n      properties: {\n        'Shade Name': shadeName,\n        'Total Price': `$${lastCalculatedPrice}`,\n        'Width': `${document.getElementById('shadeWidth').value} inches`,\n        'Length': `${document.getElementById('shadeLength').value} inches`,\n        'Fabric': fabricDetails,\n        'Trim Placement': trimPlacement === 'none' ? 'None' : trimPlacement,\n        'Trim': trimDetails,\n        'Cord Option': document.getElementById('cordOption').options[document.getElementById('cordOption').selectedIndex].text,\n        'Mount Option': document.getElementById('mountOption').options[document.getElementById('mountOption').selectedIndex].text,\n        'Liner': document.getElementById('linerOption').options[document.getElementById('linerOption').selectedIndex].text,\n        'Fabric Width': `${document.getElementById('fabricWidth').value} inches`,\n        'Additional Notes': sanitize(document.getElementById('additionalNotes').value) || 'None'\n      }\n    }];\n\n    addToCart(items, `Flat Roman Shade - ${shadeName} added to cart!`);\n  }\n\n  async function addToCart(items, successMsg) {\n    const el = document.getElementById('item_added_message');\n    const msgSpan = document.getElementById('cartMessage');\n    const loading = document.getElementById('loadingBar');\n    const bar = loading.querySelector('.loading-bar');\n\n    bar.style.width = '0';\n    loading.style.display = 'block';\n    msgSpan.style.display = 'none';\n    el.classList.remove('error');\n    el.style.display = 'flex';\n    setTimeout(() =\u003e bar.classList.add('animate'), 10);\n\n    try {\n      const resp = await fetch('\/cart\/add.js', {\n        method: 'POST',\n        headers: { 'Content-Type': 'application\/json' },\n        body: JSON.stringify({ items })\n      });\n\n      if (!resp.ok) throw new Error('Failed to add to cart');\n\n      loading.style.display = 'none';\n      msgSpan.textContent = successMsg;\n      msgSpan.style.display = 'block';\n      document.getElementById('viewCartButton').style.display = 'block';\n    } catch (err) {\n      loading.style.display = 'none';\n      msgSpan.textContent = 'Error: ' + err.message;\n      el.classList.add('error');\n    }\n  }\n\n  document.addEventListener('DOMContentLoaded', () =\u003e {\n    window.addEventListener('message', (event) =\u003e {\n      if (event.data.type === 'fabricSelected' \u0026\u0026 event.data.fabricData) {\n        const f = event.data.fabricData;\n        selectedFabric = {\n          id: f.variantId || f.id,\n          title: f.title,\n          price: f.price || 0,\n          imageUrl: f.imageUrl\n        };\n        document.getElementById('singleFabricField').value = f.title;\n        document.getElementById('fabricSwatchImage').src = f.imageUrl;\n        document.getElementById('fabricSwatchPrice').textContent = `$${f.price || 0}\/yd`;\n        document.getElementById('fabricSwatchPreview').style.display = 'flex';\n        document.getElementById('fabricWidth').value = f.fabricWidth || 54;\n        closeCatalogModal('fabric');\n      }\n      \n      if (event.data.type === 'trimSelected' \u0026\u0026 event.data.trimData) {\n        const t = event.data.trimData;\n        selectedTrim = {\n          id: t.variantId || t.id,\n          title: t.title,\n          price: t.price || 0,\n          imageUrl: t.imageUrl\n        };\n        document.getElementById('singleTrimField').value = t.title;\n        document.getElementById('trimSwatchImage').src = t.imageUrl;\n        document.getElementById('trimSwatchPrice').textContent = `$${t.price || 0}\/yd`;\n        document.getElementById('trimSwatchPreview').style.display = 'flex';\n        closeCatalogModal('trim');\n      }\n    });\n\n    document.getElementById('browseFabricsBtn').addEventListener('click', () =\u003e showCatalog('fabric'));\n    document.getElementById('browseTrimsBtn').addEventListener('click', () =\u003e showCatalog('trim'));\n    document.getElementById('fabricSwatchClearBtn').addEventListener('click', () =\u003e clearSelection('fabric'));\n    document.getElementById('trimSwatchClearBtn').addEventListener('click', () =\u003e clearSelection('trim'));\n    \n    document.getElementById('ownFabric').addEventListener('change', function() {\n      const own = this.checked;\n      document.getElementById('customFabricName').parentElement.style.display = own ? 'block' : 'none';\n      document.getElementById('singleFabricField').disabled = own;\n      document.getElementById('browseFabricsBtn').disabled = own;\n      if (own) {\n        selectedFabric = null;\n        document.getElementById('fabricWidth').removeAttribute('readonly');\n        document.getElementById('fabricWidth').style.background = '#fff';\n      } else {\n        document.getElementById('fabricWidth').setAttribute('readonly', 'readonly');\n        document.getElementById('fabricWidth').style.background = '#f0f0f0';\n      }\n    });\n\n    document.getElementById('ownTrim').addEventListener('change', function() {\n      const own = this.checked;\n      document.getElementById('customTrimName').parentElement.style.display = own ? 'block' : 'none';\n      document.getElementById('singleTrimField').disabled = own;\n      document.getElementById('browseTrimsBtn').disabled = own;\n      if (own) selectedTrim = null;\n    });\n\n    document.getElementById('trimPlacement').addEventListener('change', function() {\n      const disabled = this.value === 'none';\n      document.getElementById('singleTrimField').disabled = disabled || document.getElementById('ownTrim').checked;\n      document.getElementById('browseTrimsBtn').disabled = disabled || document.getElementById('ownTrim').checked;\n      document.getElementById('ownTrim').disabled = disabled;\n    });\n\n    document.getElementById('calculateButton').addEventListener('click', calculateShade);\n    document.getElementById('resetButton').addEventListener('click', () =\u003e location.reload());\n    document.getElementById('addToCartButton').addEventListener('click', handleAddToCart);\n  });\n\u003c\/script\u003e\n\n\n\u003c\/body\u003e","brand":"The ReBorn House","offers":[{"title":"Flat Roman Shade","offer_id":50911991726368,"sku":null,"price":0.0,"currency_code":"USD","in_stock":true}],"thumbnail_url":"\/\/cdn.shopify.com\/s\/files\/1\/0914\/3736\/7584\/files\/IMG_0888.jpg?v=1762916718","url":"https:\/\/therebornhouse.com\/products\/made-to-order-custom-flat-roman-shade","provider":"The ReBorn House","version":"1.0","type":"link"}