<!-- ========================= FULL-WIDTH OVERRIDE (DROP-IN) Put at TOP of page Purpose: remove left/right buffers (padding/margins) Does NOT require any changes to other blocks ========================= --> <style> /* Prevent accidental sideways scroll */ html, body { max-width:100%; overflow-x:hidden; }
/* If your theme applies padding to rows/columns */ .wsite-multicol, .wsite-multicol-table, .wsite-multicol-col, .wsite-multicol-col > div{ padding-left: 0 !important; padding-right: 0 !important; margin-left: 0 !important; margin-right: 0 !important; }
/* Your price list wrapper currently has side padding (0 12px) in Block 1. This overrides it WITHOUT editing Block 1. */ .ghPL-wrap{ padding-left: 0 !important; padding-right: 0 !important; max-width: 100% !important; }
/* Optional: if any sections still “center” content with auto margins */ .wsite-section-content{ width: 100% !important; } </style>
<!-- ========================================================= DOUBLE VERTICAL SCROLLBAR NUKER (Weebly-safe) Drop into ANY page with the issue. - Forces the page to scroll normally (body) - Prevents common Weebly wrappers from creating inner scrollbars - JS failsafe removes inline overflow:auto/scroll on wrappers ========================================================== -->
<style id="ghScrollNukerCSS"> /* 1) Normalise root scrolling */ html{ height: auto !important; min-height: 100% !important; overflow-y: auto !important; /* only one scrollbar */ overflow-x: hidden !important; }
body{ height: auto !important; min-height: 100% !important; overflow-y: auto !important; /* ensure body owns scrolling */ overflow-x: hidden !important; -webkit-overflow-scrolling: touch; }
/* 3) If the theme uses fixed heights on a main area, neutralise */ #wsite-content, #wsite-content-wrapper, #wsite-wrapper{ position: relative !important; }
// Elements that often cause the “second scrollbar” var selectors = [ "#wsite-content", "#wsite-content-wrapper", "#wsite-wrapper", ".wsite-content", ".page-content", ".main-wrap", ".content-wrap", ".container", ".wrapper", ".wsite-section-content", ".wsite-section-elements", "#main", "#page" ];
function cleanOverflow(el){ if(!el || !el.style) return;
// If theme set inline overflow/height, remove it var ov = (el.style.overflow || "").toLowerCase(); var ovy = (el.style.overflowY || "").toLowerCase();
function run(){ try{ selectors.forEach(function(sel){ var nodes = document.querySelectorAll(sel); for(var i=0;i<nodes.length;i++) cleanOverflow(nodes[i]); }); }catch(e){} }
// Run now + after layout settles (themes often apply styles late) run(); setTimeout(run, 50); setTimeout(run, 250); setTimeout(run, 800); })(); </script>
<style> /* ========================= GLOBAL WEELY HEADER ABOVE EVERYTHING (Fixes price pills appearing over burger/menu) ========================= */
/* The header/nav containers must be positioned for z-index to apply */ header, #header, .wsite-header, .wsite-header-section, .wsite-nav-wrap, .wsite-mobile-nav, .wsite-menu-default, .wsite-mobile-menu, .wsite-nav-mobile, .wsite-navwrap { position: relative !important; z-index: 999999 !important; }
/* Some themes put the mobile menu panel in its own wrapper */ .wsite-mobile-nav, .wsite-mobile-menu, .wsite-menu-default { z-index: 999999 !important; }
<!-- ticker --> <div class="ghTicker" aria-hidden="true"> <div class="ghTickerTrack" id="ghTickerTrackShowroom"> <div class="ghTickerText"> Take a quick showroom tour — see real sheds, summerhouses and greenhouses on display, with friendly advice and no-pressure quotes. </div> </div> </div>
<script> (function(){ var wrap = document.getElementById("ghThumbWrapShowroom"); var card = document.getElementById("ghThumbCardShowroom"); var video = document.getElementById("ghVideoShowroom");
var lightbox = document.getElementById("ghLightboxShowroom"); var stage = document.getElementById("ghLightboxStageShowroom"); var closeBtn = document.getElementById("ghCloseShowroom"); var ticker = document.getElementById("ghTickerTrackShowroom");
/* show immediately */ wrap.classList.remove("gh-hidden");
/* force lightbox to body (Weebly stacking fix) */ document.body.appendChild(lightbox);
/* move video */ var home = video.parentNode; function toStage(){ stage.insertBefore(video, stage.firstChild); } function toHome(){ home.appendChild(video); }
{"model":"QUBE 6X6 Black Toughened Glass","price":1088.50,"install":375.00}, {"model":"QUBE 6X8 Black Toughened Glass","price":1143.50,"install":415.00}, {"model":"QUBE 6X10 Black Toughened Glass","price":1198.50,"install":460.00}, {"model":"QUBE 8X8 Black Toughened Glass","price":1513.50,"install":460.00}, {"model":"QUBE 8X12 Black Toughened Glass","price":1718.50,"install":545.00}, {"model":"QUBE 8X16 Black Toughened Glass","price":1923.50,"install":610.00}, {"model":"QUBE-SQ 8X8 Black Toughened Glass","price":2423.50,"install":545.00},
{"model":"ICON 6X4 Silver 3mm Glass","price":753.00,"install":325.00}, {"model":"ICON 6X4 Silver Toughened Glass","price":903.00,"install":325.00}, {"model":"ICON 6X4 Silver Polycarbonate","price":953.00,"install":325.00}, {"model":"ICON 6X4 Green 3mm Glass","price":803.00,"install":325.00}, {"model":"ICON 6X4 Green Toughened Glass","price":953.00,"install":325.00}, {"model":"ICON 6X4 Green Polycarbonate","price":1003.00,"install":325.00}, {"model":"ICON 6X4 Black 3mm Glass","price":803.00,"install":325.00}, {"model":"ICON 6X4 Black Toughened Glass","price":953.00,"install":325.00}, {"model":"ICON 6X4 Black Polycarbonate","price":1003.00,"install":325.00},
{"model":"ICON 6X6 Silver 3mm Glass","price":813.00,"install":375.00}, {"model":"ICON 6X6 Silver Toughened Glass","price":963.00,"install":375.00}, {"model":"ICON 6X6 Silver Polycarbonate","price":1013.00,"install":375.00}, {"model":"ICON 6X6 Green 3mm Glass","price":863.00,"install":375.00}, {"model":"ICON 6X6 Green Toughened Glass","price":1013.00,"install":375.00}, {"model":"ICON 6X6 Green Polycarbonate","price":1063.00,"install":375.00}, {"model":"ICON 6X6 Black 3mm Glass","price":863.00,"install":375.00}, {"model":"ICON 6X6 Black Toughened Glass","price":1013.00,"install":375.00}, {"model":"ICON 6X6 Black Polycarbonate","price":1063.00,"install":375.00},
{"model":"ICON 6X8 Silver 3mm Glass","price":873.00,"install":415.00}, {"model":"ICON 6X8 Silver Toughened Glass","price":1023.00,"install":415.00}, {"model":"ICON 6X8 Silver Polycarbonate","price":1073.00,"install":415.00}, {"model":"ICON 6X8 Green 3mm Glass","price":923.00,"install":415.00}, {"model":"ICON 6X8 Green Toughened Glass","price":1073.00,"install":415.00}, {"model":"ICON 6X8 Green Polycarbonate","price":1123.00,"install":415.00}, {"model":"ICON 6X8 Black 3mm Glass","price":923.00,"install":415.00}, {"model":"ICON 6X8 Black Toughened Glass","price":1073.00,"install":415.00}, {"model":"ICON 6X8 Black Polycarbonate","price":1123.00,"install":415.00},
{"model":"ICON 6X10 Silver 3mm Glass","price":933.00,"install":465.00}, {"model":"ICON 6X10 Silver Toughened Glass","price":1083.00,"install":465.00}, {"model":"ICON 6X10 Silver Polycarbonate","price":1133.00,"install":465.00}, {"model":"ICON 6X10 Green 3mm Glass","price":983.00,"install":465.00}, {"model":"ICON 6X10 Green Toughened Glass","price":1133.00,"install":465.00}, {"model":"ICON 6X10 Green Polycarbonate","price":1183.00,"install":465.00}, {"model":"ICON 6X10 Black 3mm Glass","price":983.00,"install":465.00}, {"model":"ICON 6X10 Black Toughened Glass","price":1133.00,"install":465.00}, {"model":"ICON 6X10 Black Polycarbonate","price":1183.00,"install":465.00},
{"model":"ICON 6 6X10 Green Toughened Glass","price":1599.00,"install":495.00}, {"model":"ICON 6 6X10 Black Toughened Glass","price":1599.00,"install":495.00}, {"model":"ICON 6 6X12 Green Toughened Glass","price":2799.00,"install":535.00}, {"model":"ICON 6 6X12 Black Toughened Glass","price":2799.00,"install":535.00},
{"model":"ICON 8X10 Silver 3mm Glass","price":1478.00,"install":495.00}, {"model":"ICON 8X10 Silver Toughened Glass","price":1778.00,"install":495.00}, {"model":"ICON 8X10 Green 3mm Glass","price":1578.00,"install":495.00}, {"model":"ICON 8X10 Green Toughened Glass","price":1878.00,"install":495.00}, {"model":"ICON 8X10 Black 3mm Glass","price":1578.00,"install":495.00}, {"model":"ICON 8X10 Black Toughened Glass","price":1878.00,"install":495.00},
{"model":"ICON 8X12 Silver 3mm Glass","price":1598.00,"install":525.00}, {"model":"ICON 8X12 Silver Toughened Glass","price":1898.00,"install":525.00}, {"model":"ICON 8X12 Green 3mm Glass","price":1698.00,"install":525.00}, {"model":"ICON 8X12 Green Toughened Glass","price":1998.00,"install":525.00}, {"model":"ICON 8X12 Black 3mm Glass","price":1698.00,"install":525.00}, {"model":"ICON 8X12 Black Toughened Glass","price":1998.00,"install":525.00},
{"model":"ICON 8X14 Silver 3mm Glass","price":1718.00,"install":565.00}, {"model":"ICON 8X14 Silver Toughened Glass","price":2018.00,"install":565.00}, {"model":"ICON 8X14 Green 3mm Glass","price":1818.00,"install":565.00}, {"model":"ICON 8X14 Green Toughened Glass","price":2118.00,"install":565.00}, {"model":"ICON 8X14 Black 3mm Glass","price":1818.00,"install":565.00}, {"model":"ICON 8X14 Black Toughened Glass","price":2118.00,"install":565.00} ] </script>
<div class="acc-title">Accessories</div> <div class="acc-body"> <p>After you have placed your main order we will send you details of model/size spacific accessories you may wish to add.</p> </div>
<div class="dims-note"> <div class="dims-noteTitle">Please note:</div> <div class="dims-noteText"> These accurate dimensions are bigger than advertised greenhouse size (as the advertised size is an approximate). Also, please allow a little ‘wiggle-room’ around the greenhouse as during installation there needs to be room to fit the glass safely. </div> </div> </div>
let i = 0; function tryNext(){ if(i >= tries.length) return; img.src = tries[i++]; } img.onerror = function(){ tryNext(); }; tryNext(); return img; }
/* --------------------------- RAW FILE LIST loader --------------------------- */ function readRawFileList(){ const el = document.getElementById("ghRawFileList"); if(el && el.textContent){ let txt = el.textContent.trim();
// 1) If it's JSON (or looks like it), parse it if(txt.startsWith("[")){ try{ const arr = JSON.parse(txt); if(Array.isArray(arr)){ return arr .map(s => String(s || "").trim()) .filter(Boolean); } }catch(e){ // fall through to cleanup mode } }
// If someone pasted JSON but it failed parse, the cleanup still works. // Also remove a lone "[" or "]" if present. return cleaned.filter(s => s !== "[" && s !== "]");
}
// Fallback: paste filenames here if you want return [ /* "POPULAR_6X4_SILVER_HORT_SO0200_PIC1.png", */ ]; }
let size = rawSize.replace(/[^0-9X]/g,"").replace(/x/g,"X"); if(!size) return null;
let color = (parts[2] || "").toUpperCase(); if(rawSize === "GARDENHOUSE") color = (parts[3] || "").toUpperCase(); // not usually used for dims, but safe if(color === "MILL") color = "SILVER";
/* --------------------------- Hide buttons that have zero possible results --------------------------- */ function updateAvailableButtons(){ const tiles = Array.from(document.querySelectorAll(".gh-item.icon-link:not(.is-dims)"));
/* --------------------------- Banner visibility logic: - Size banner hidden if no visible product tiles for that size - Colour banner hidden if no visible product tiles matching its size+range+colour --------------------------- */ function syncBannerVisibility(){ const visibleProductTiles = Array.from(document.querySelectorAll(".gh-item.icon-link:not(.is-dims):not(.hidden-item)"));
const sizeHas = new Set(); const colourHas = new Set(); // key: sz|rng|col
allItems.forEach(item => { // banners handled later by syncBannerVisibility (but we still hide them initially based on their classes) const fName = (item.getAttribute("data-f") || "").toLowerCase(); const matchesSearch = (!isProductTile(item)) ? true : ((keywords.length === 0) || keywords.every(kw => fName.includes(kw)));
// ✅ Product tiles + DIMS tiles MUST match model (unless model=all) // ✅ Banners will be handled later by syncBannerVisibility() let mM = true; if(currentModel !== "all"){ if(isBanner(item)){ mM = true; // banner visibility handled by syncBannerVisibility() }else{ mM = (itemRng === currentModel) || item.classList.contains("rng-" + currentModel); } }
function rangeSafe(rng){ return String(rng||"").toLowerCase().replace(/-/g,""); }
function makeChoiceText(rng, sz, colName, glzKey){ const c = (colName === "SILVER") ? "Silver" : (colName.charAt(0) + colName.slice(1).toLowerCase()); const g = glazingLabelFromKey(glzKey); // This must match your ghPriceData "model" keys exactly if you want pricing to appear return `${rng.replace(/-/g," ")} ${sz} ${c} ${g}`.trim(); }
}catch(err){ filterCountEl.textContent = "Showroom error (check console)"; console.error("Showroom render error:", err); } } window.__ghRenderShowroom = renderShowroom; // ✅ MUST be here, outside /* --------------------------- DOM ready (safe) --------------------------- */ function init(){ setSiteHeaderOffset(); window.addEventListener("resize", setSiteHeaderOffset);
// ✅ Weebly-safe: wait until required nodes exist let tries = 0; const boot = () => { tries++;
const g = document.getElementById("gallery"); const fc = document.getElementById("filterCount");
// still not ready? try again if(!g || !fc){ if(tries < 80) return setTimeout(boot, 80); console.warn("Showroom: required nodes not found (#gallery / #filterCount)"); return; }
// run initial render renderShowroom();
// ✅ Self-heal watchdog: if anything wipes gallery after render, bring it back let guard = 0; const watchdog = setInterval(() => { guard++; const tilesNow = document.querySelectorAll("#gallery .gh-item.icon-link").length; const rawCount = (window.__rawFileList && window.__rawFileList.length) || 0;
if(document.readyState === "loading"){ document.addEventListener("DOMContentLoaded", init); }else{ // Weebly sometimes injects blocks after DOMContentLoaded setTimeout(init, 0); }
})(); </script>
<script> (function(){ "use strict";
/* ========================================================= SELECT / ACCESSORIES / ORDER POPUPS + DEEP LINK SHARE ✅ Bulletproof PIC grouping by scanning __rawFileList ========================================================= */
function buildWhatsAppLink(message){ var phone = "447720377778"; var prefix = "Hi Chris, i was on your website and have a question. "; return "https://wa.me/" + phone + "?text=" + encodeURIComponent(prefix + (message || "")); }
var back = document.getElementById("ghBackdrop"); if(back){ back.style.display = "none"; back.setAttribute("aria-hidden","true"); } }
var GH_SELECTED = null;
var BASE_PUBLIC = "https://www.shedsni.com/uploads/1/0/1/3/10130609/"; var BASE_EDITOR = "https://www.weebly.com/editor/uploads/1/0/1/3/10130609/";
function fileVariants(file){ var clean = String(file || "").trim(); if(!clean) return [];
// ✅ BEST FIRST: lowercase + hyphens var hyphenLower = clean.toLowerCase().replace(/_/g, "-");
// fallbacks var original = clean; var underscoreLower = clean.toLowerCase().replace(/-/g, "_"); var underscoreUpper = clean.toUpperCase().replace(/-/g, "_"); var hyphenUpper = clean.toUpperCase().replace(/_/g, "-");
var v = []; [hyphenLower, original, underscoreLower, underscoreUpper, hyphenUpper].forEach(function(x){ if(x && v.indexOf(x) === -1) v.push(x); });
return v; }
function setImgWithFallback(img, file){ var vars = fileVariants(file); var tries = []; vars.forEach(function(fn){ tries.push(BASE_PUBLIC + fn); }); vars.forEach(function(fn){ tries.push(BASE_EDITOR + fn); });
var i = 0; function next(){ if(i >= tries.length) return; img.src = tries[i++]; } img.onerror = function(){ next(); }; next(); }
function parsePicMeta(file){ var f = String(file || "").trim(); var norm = f.replace(/_/g, "-");
if(!f) return null;
var upper = norm.toUpperCase(); if(upper.indexOf("_DIMS") !== -1) return null;
var base = norm.replace(/\.(png|jpg|jpeg|webp)$/i, ""); var parts = base.split(/[-]/).filter(Boolean); if(parts.length < 5) return null;
var colorIdx = (parts[1] || "").toUpperCase() === "GARDENHOUSE" ? 3 : 2; var glazeIdx = colorIdx + 1; var refIdx = colorIdx + 2;
var color = (parts[colorIdx] || "").toUpperCase(); if(color === "MILL") color = "SILVER";
var glaze = (parts[glazeIdx] || "").toUpperCase(); var ref = (parts[refIdx] || "").toUpperCase();
var picPart = parts.find(function(p){ return /PIC\d+/i.test(p); }) || ""; var m = String(picPart).match(/PIC(\d+)/i); var pic = m ? parseInt(m[1],10) : 0;
function getChoiceTextFromTile(tile){ // Use data-choice if present (most accurate / consistent with price map) var c = (tile.getAttribute("data-choice") || "").trim(); if(c) return c;
// Fallback: parse from filename var f = (tile.getAttribute("data-f") || "").trim(); if(!f) return "";
var base = f.replace(/\.(png|jpg|jpeg|webp)$/i,""); var parts = base.split(/[_-]/).filter(Boolean);
var range = (parts[0] || "").toUpperCase(); var sizeTok = (parts[1] || "").toUpperCase(); if(sizeTok === "GARDENHOUSE") sizeTok = (parts[2] || "").toUpperCase();
var size = sizeTok.replace(/[^0-9X]/g,"").replace(/x/g,"X"); var isDims = base.toUpperCase().indexOf("_DIMS") !== -1;
var colorIdx = (parts[1] || "").toUpperCase() === "GARDENHOUSE" ? 3 : 2; var glazeIdx = colorIdx + 1;
var color = (parts[colorIdx] || "").toUpperCase(); if(color === "MILL") color = "SILVER";
function gbp(n){ var num = Number(n); if(!isFinite(num)) return ""; return "£" + num.toLocaleString("en-GB",{minimumFractionDigits:2,maximumFractionDigits:2}); }
function openSelectPopup(sel){ GH_SELECTED = sel || null;
var overlay = document.getElementById("selectOverlay"); var title = document.getElementById("selectTitle"); var priceEl = document.getElementById("selectPrice"); var sub = document.getElementById("selectSub"); var wa = document.getElementById("selectWhatsApp"); var shareBtn = document.getElementById("selectShareBtn");
var track = document.getElementById("ghPicTrack"); var prevBtn = overlay ? overlay.querySelector(".ghPicPrev") : null; var nextBtn = overlay ? overlay.querySelector(".ghPicNext") : null;
(function bindPopupBackdropClose(){ var selectOverlay = document.getElementById("selectOverlay"); var accOverlay = document.getElementById("accOverlay");
// ORDER popup var ORDER_PAGE_URL = "https://www.shedsni.com/OrderPage.html"; var COGNITO_FIELDS = ["Greenhouse", "Greenhouse2", "Greenhouse3"];
function setUiHidden(isHidden){ var controls = document.getElementById("ghControls"); var topFab = document.getElementById("ghTopFab"); var back = document.getElementById("ghBackdrop"); if(controls) controls.style.display = isHidden ? "none" : ""; if(topFab) topFab.style.display = isHidden ? "none" : ""; if(back) back.style.display = isHidden ? "none" : ""; }
function openOrderPopup(url){ var ov = document.getElementById("cogOverlay"); var fr = document.getElementById("orderIframe"); if(fr) fr.src = url; setUiHidden(true); openOverlay(ov); }
window.closeOrderPopup = function(){ var ov = document.getElementById("cogOverlay"); var fr = document.getElementById("orderIframe"); if(fr) fr.src = ""; closeOverlay(ov); setUiHidden(false); openOverlay(document.getElementById("selectOverlay")); };
(function bindOrderBackdropClose(){ var ov = document.getElementById("cogOverlay"); if(!ov) return; ov.addEventListener("click", function(e){ if(e.target === ov) window.closeOrderPopup(); }); })();
var accOverlay = document.getElementById("accOverlay"); var selectOverlay = document.getElementById("selectOverlay"); var noMatch = document.getElementById("noMatchOverlay"); var dims = document.getElementById("dimsOverlay");
/* ✅ The shimmer overlay does the sweep (not the background) */ .ghPriceBadge::before{ content:""; position:absolute; inset:0; pointer-events:none; z-index:0;
/* single bright band */ background: linear-gradient( 110deg, transparent 35%, rgba(255,255,255,.65) 50%, transparent 65% );
/* start fully off left */ transform: translateX(-140%); opacity: 0; /* hidden during the quiet time */
/* If we set textContent directly (no inner spans), ensure it stays above */ .ghPriceBadge{ z-index:80; } .ghPriceBadge{ /* text sits naturally above ::before if ::before is z-index:0 */ }
/* ✅ ONE sweep (0–7s) then quiet (7–12s) */ @keyframes ghPriceOneSweepThenPause{ /* quiet at start */ 0% { transform: translateX(-140%); opacity:0; }
/* turn shimmer on immediately and begin sweep */ 1% { opacity:1; transform: translateX(-140%); }
/* end of sweep at 7s (7/12 = 58.33%) */ 58.33% { opacity:1; transform: translateX(140%); }
function upper(s){ return String(s||"").toUpperCase(); } function gbp(n){ const num = Number(n); if(!isFinite(num)) return ""; return "£" + num.toLocaleString("en-GB",{minimumFractionDigits:2,maximumFractionDigits:2}); }
// --------------------------- // Model string -> canonical key // e.g. "ICON 6X4 Silver 3mm Glass" => "ICON_6X4_SILVER_HORT" // --------------------------- function modelToBaseKey(model){ const s = upper(model);
let range = ""; if(s.startsWith("POPULAR")) range = "POPULAR"; else if(s.startsWith("ICON")) range = "ICON"; else if(s.startsWith("MAGNUM")) range = "MAGNUM"; else if(s.startsWith("QUBE-SQ")) range = "QUBE-SQ"; else if(s.startsWith("QUBE")) range = "QUBE";