.sbc-quarry { max-width: 1100px; margin: 1.5rem auto; font-family: -apple-system, BlinkMacSystemFont, “Segoe UI”, Roboto, sans-serif; color: #2c3338; }
.sbc-quarry__intro { margin: 0 0 2rem; line-height: 1.55; }
.sbc-quarry__intro strong { color: #1f4d2b; }
.sbc-quarry__grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 1.25rem; }
.sbc-quarry__card { background: #fff; border: 1px solid #e5e7eb; border-radius: 14px; overflow: hidden; box-shadow: 0 1px 2px rgba(0,0,0,0.04); transition: transform 0.15s ease, box-shadow 0.15s ease; display: flex; flex-direction: column; }
.sbc-quarry__card:hover { transform: translateY(-2px); box-shadow: 0 4px 12px rgba(0,0,0,0.08); }
.sbc-quarry__photo { width: 100%; aspect-ratio: 4 / 3; background: #f3f4f6 no-repeat center/cover; }
.sbc-quarry__body { padding: 1rem 1.1rem 1.15rem; display: flex; flex-direction: column; gap: 0.55rem; flex: 1; }
.sbc-quarry__head { display: flex; justify-content: space-between; align-items: flex-start; gap: 0.75rem; }
.sbc-quarry__model { font-size: 1.05rem; font-weight: 600; line-height: 1.3; margin: 0; }
.sbc-quarry__badge { font-size: 0.72rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em; padding: 0.2rem 0.55rem; border-radius: 999px; white-space: nowrap; align-self: flex-start; }
.sbc-quarry__badge–available { background: #d1fae5; color: #065f46; }
.sbc-quarry__badge–refurbishing { background: #ffedd5; color: #9a3412; }
.sbc-quarry__badge–sponsored { background: #ede9fe; color: #5b21b6; }
.sbc-quarry__badge–donated { background: #fce7f3; color: #9d174d; }
.sbc-quarry__badge–sold { background: #f3f4f6; color: #4b5563; }
.sbc-quarry__meta { font-size: 0.85rem; color: #6b7280; line-height: 1.45; }
.sbc-quarry__desc { font-size: 0.9rem; line-height: 1.5; color: #374151; margin: 0; }
.sbc-quarry__price { font-size: 1rem; font-weight: 600; color: #1f4d2b; margin-top: auto; padding-top: 0.4rem; }
.sbc-quarry__price-waived { font-size: 0.85rem; font-weight: 500; color: #9d174d; }
.sbc-quarry__price–sold { color: #6b7280; font-weight: 500; }
.sbc-quarry__loading, .sbc-quarry__error { padding: 2rem; text-align: center; color: #6b7280; font-size: 0.95rem; }
.sbc-quarry__error { color: #b91c1c; }
.sbc-quarry__cta { margin: 2.5rem auto 0; padding: 1.75rem 1.5rem; background: #f9fafb; border: 1px solid #e5e7eb; border-radius: 14px; text-align: center; }
.sbc-quarry__cta h3 { margin: 0 0 0.5rem; font-size: 1.25rem; font-weight: 700; color: #1f4d2b; }
.sbc-quarry__cta p { margin: 0 0 1.1rem; color: #4b5563; font-size: 0.95rem; line-height: 1.5; }
.sbc-quarry__cta a.sbc-quarry__btn { display: inline-block; padding: 0.7rem 1.5rem; background: #1f4d2b; color: #fff !important; text-decoration: none; border-radius: 8px; font-weight: 600; font-size: 0.95rem; }
.sbc-quarry__cta a.sbc-quarry__btn:hover { background: #14361e; }
The Quarry is Stone Bicycle Coalition’s volunteer-run bike shop in Rapid City. Every bike here was donated, refurbished by our crew, and inspected ride-ready. Sponsor a bike to cover refurb costs, or join the wait list — we match bikes to riders who need them.
(function () {
const FEED = “
https://stonebc-inventory.netlify.app/bikes.json”;
const PHOTO_BASE = “
https://stonebc-inventory.netlify.app/photos/”;
const grid = document.getElementById(“sbc-quarry-grid”);
if (!grid) return;
const statusOrder = { available: 0, refurbishing: 1, sponsored: 2, donated: 3, sold: 4 };
const statusLabel = { available: “Available”, refurbishing: “In refurb”, sponsored: “Sponsored”, donated: “Donated”, sold: “Sold” };
function el(tag, opts) {
const node = document.createElement(tag);
if (!opts) return node;
if (opts.className) node.className = opts.className;
if (opts.text != null) node.textContent = String(opts.text);
if (opts.style) node.setAttribute(“style”, opts.style);
if (opts.ariaLabel) node.setAttribute(“aria-label”, String(opts.ariaLabel));
return node;
}
function buildPrice(bike) {
const price = el(“div”, { className: “sbc-quarry__price” });
if (bike.status === “donated”) {
price.appendChild(document.createTextNode(“$” + bike.sponsorPrice + ” “));
price.appendChild(el(“span”, { className: “sbc-quarry__price-waived”, text: “— gifted, sponsor price waived” }));
} else if (bike.status === “sold”) {
price.className = “sbc-quarry__price sbc-quarry__price–sold”;
price.textContent = “Sold — $” + bike.sponsorPrice;
} else {
price.textContent = “Sponsor for $” + bike.sponsorPrice;
}
return price;
}
function buildCard(bike) {
const card = el(“article”, { className: “sbc-quarry__card” });
const photo = el(“div”, { className: “sbc-quarry__photo”, ariaLabel: bike.model });
if (bike.photos && bike.photos.length) {
const url = new URL(encodeURIComponent(bike.photos[0]), PHOTO_BASE).toString();
photo.style.backgroundImage = “url(” + JSON.stringify(url) + “)”;
}
card.appendChild(photo);
const body = el(“div”, { className: “sbc-quarry__body” });
const head = el(“div”, { className: “sbc-quarry__head” });
head.appendChild(el(“h3”, { className: “sbc-quarry__model”, text: bike.model }));
const status = bike.status || “available”;
head.appendChild(el(“span”, {
className: “sbc-quarry__badge sbc-quarry__badge–” + status,
text: statusLabel[status] || status,
}));
body.appendChild(head);
const typeLabel = (bike.type || “”).charAt(0).toUpperCase() + (bike.type || “”).slice(1);
const metaParts = [typeLabel, bike.frameSize, bike.wheelSize, bike.color].filter(Boolean);
body.appendChild(el(“div”, { className: “sbc-quarry__meta”, text: metaParts.join(” · “) }));
if (bike.description) {
body.appendChild(el(“p”, { className: “sbc-quarry__desc”, text: bike.description }));
}
body.appendChild(buildPrice(bike));
card.appendChild(body);
return card;
}
function render(bikes) {
grid.replaceChildren();
if (!bikes.length) {
grid.appendChild(el(“div”, { className: “sbc-quarry__loading”, text: “No bikes in inventory right now — check back soon.” }));
return;
}
bikes.forEach((bike) => grid.appendChild(buildCard(bike)));
}
fetch(FEED, { cache: “no-store” })
.then((r) => { if (!r.ok) throw new Error(“HTTP ” + r.status); return r.json(); })
.then((data) => {
const bikes = (data.bikes || []).slice().sort((a, b) => {
const sa = statusOrder[a.status] != null ? statusOrder[a.status] : 99;
const sb = statusOrder[b.status] != null ? statusOrder[b.status] : 99;
if (sa !== sb) return sa – sb;
return (a.dateAdded || “”).localeCompare(b.dateAdded || “”);
});
render(bikes);
})
.catch((e) => {
grid.replaceChildren();
grid.appendChild(el(“div”, {
className: “sbc-quarry__error”,
text: “Couldn’t load the bike list. Email us at
info@stonebicyclecoalition.com and we’ll send the current inventory.”,
}));
console.error(“[sbc-quarry]”, e);
});
})();