top of page


index.html

<!DOCTYPE html>

<html lang="en">

<head>

  <meta charset="UTF-8">

  <meta name="viewport" content="width=device-width, initial-scale=1.0">

  <title>GLH – Global Local Harvest</title>

  <link rel="stylesheet" href="style.css">

</head>

<body>

 

<nav>

  <a href="index.html" class="logo">GL<span>H</span></a>

  <ul class="nav-links">

    <li><a href="index.html">Home</a></li>

    <li><a href="shop.html">Shop</a></li>

    <li><a href="about.html">About Us</a></li>

    <li><a href="producer.html">Producers</a></li>

    <li><a href="login.php">Log In</a></li>

    <li><a href="register.php" class="btn-nav">Register</a></li>

    <li>

      <a href="basket.html" style="position:relative">

        🛒

        <span id="basket-count" style="background:var(--earth);color:white;border-radius:50%;font-size:.7rem;width:18px;height:18px;display:none;align-items:center;justify-content:center;position:absolute;top:-6px;right:-8px;font-weight:700;"></span>

      </a>

    </li>

  </ul>

</nav>

 

<main>

 

  <!-- HERO -->

  <section class="hero">

    <h1>Local Food.<br>Real Farmers.<br>Your Community.</h1>

    <p>GLH connects you with the finest local farms and producers. Fresh, seasonal, and always nearby.</p>

    <div class="hero-btns">

      <a href="shop.html" class="btn btn-white">Browse the Shop</a>

      <a href="about.html" class="btn btn-outline">Our Story</a>

    </div>

  </section>

 

  <!-- WHY GLH -->

  <div class="section">

    <p class="section-title">Why GLH?</p>

    <div class="divider"></div>

    <div class="grid-3">

      <div class="card">

        <div class="card-icon">🌱</div>

        <h3>100% Local</h3>

        <p>Every product is sourced from farms within your region. No middlemen, no food miles.</p>

      </div>

      <div class="card">

        <div class="card-icon">🤝</div>

        <h3>Support Farmers</h3>

        <p>Purchases go directly to producers. We keep only a small fee to keep the platform running.</p>

      </div>

      <div class="card">

        <div class="card-icon">🌍</div>

        <h3>Sustainable</h3>

        <p>Shorter supply chains mean less packaging, less waste, and a smaller carbon footprint.</p>

      </div>

      <div class="card">

        <div class="card-icon">📦</div>

        <h3>Always Fresh</h3>

        <p>Products are updated each week by producers. What you see is in season right now.</p>

      </div>

    </div>

  </div>

 

  <!-- FEATURED PRODUCTS -->

  <div style="background:var(--green-lite);padding:1px 0">

    <div class="section">

      <p class="section-title">Featured This Week</p>

      <p style="color:var(--muted);margin-bottom:.5rem">Handpicked from our producers.</p>

      <div class="divider"></div>

      <div class="grid-3" id="featured-products"></div>

      <div style="text-align:center;margin-top:2rem">

        <a href="shop.html" class="btn btn-green">View All Products →</a>

      </div>

    </div>

  </div>

 

  <!-- PRODUCER CTA -->

  <div class="section" style="text-align:center;max-width:650px">

    <p class="section-title">Are You a Local Producer?</p>

    <div class="divider" style="margin:.6rem auto 1.4rem"></div>

    <p style="color:var(--muted);margin-bottom:1.8rem">Join GLH and get your products in front of thousands of customers who value locally sourced food and drink. Free to join, simple to use.</p>

    <a href="register.php" class="btn btn-earth">Register as a Producer</a>

  </div>

 

</main>

 

<footer>

  <div class="footer-inner">

    <div>

      <a href="index.html" class="footer-logo">GLH</a>

      <p style="margin-top:.8rem;font-size:.88rem">Connecting local farms with communities who care about where their food comes from.</p>

    </div>

    <div class="footer-col">

      <h4>Navigate</h4>

      <a href="index.html">Home</a>

      <a href="shop.html">Shop</a>

      <a href="about.html">About Us</a>

      <a href="basket.html">Basket</a>

    </div>

    <div class="footer-col">

      <h4>Producers</h4>

      <a href="register.php">Register</a>

      <a href="login.php">Producer Login</a>

      <a href="producer.html">Dashboard</a>

    </div>

  </div>

  <div class="footer-bottom">&copy; 2025 GLH – Global Local Harvest. All rights reserved.</div>

</footer>

 

<script src="app.js"></script>

<script>

  // Render first 4 featured products

  const container = document.getElementById('featured-products');

  PRODUCTS.slice(0, 4).forEach(p => {

    container.innerHTML += `

      <div class="product-card">

        <div class="product-img" style="${p.image ? 'padding:0;background:none' : ''}">

          ${p.image ? `<img src="${p.image}" alt="${p.name}" style="width:100%;height:100%;object-fit:cover">` : p.icon}

        </div>

        <div class="product-body">

          <div class="product-cat">${p.category}</div>

          <div class="product-name">${p.name}</div>

          <div class="product-farm">by ${p.farm}</div>

        </div>

        <div class="product-foot">

          <span class="product-price">£${p.price.toFixed(2)}</span>

          <button class="add-btn" onclick="addToBasket(${p.id}); this.textContent='Added ✓'; setTimeout(()=>this.textContent='+ Add',1200)">+ Add</button>

        </div>

      </div>`;

  });

</script>

</body>

</html>

style.css

@import url('https://fonts.googleapis.com/css2?family=Lora:wght@400;600;700&family=Nunito:wght@300;400;600&display=swap');

 

:root {

  --green:      #3d6b46;

  --green-lite: #edf4ee;

  --earth:      #8c6a3f;

  --cream:      #f9f5f0;

  --white:      #ffffff;

  --border:     #e2dbd4;

  --dark:       #1e1e1e;

  --muted:      #666;

  --radius:     10px;

  --head:       'Lora', serif;

  --body:       'Nunito', sans-serif;

}

 

* { box-sizing: border-box; margin: 0; padding: 0; }

html { scroll-behavior: smooth; }

 

body {

  font-family: var(--body);

  background: var(--cream);

  color: var(--dark);

  line-height: 1.7;

  display: flex;

  flex-direction: column;

  min-height: 100vh;

}

 

/* NAV */

nav {

  background: var(--white);

  border-bottom: 1px solid var(--border);

  display: flex;

  align-items: center;

  justify-content: space-between;

  padding: 0 2rem;

  height: 65px;

  position: sticky;

  top: 0;

  z-index: 50;

}

.logo { font-family: var(--head); font-size: 1.5rem; color: var(--green); text-decoration: none; font-weight: 700; }

.logo span { color: var(--earth); }

.nav-links { display: flex; gap: 1.5rem; list-style: none; align-items: center; }

.nav-links a { text-decoration: none; color: var(--muted); font-size: 0.92rem; font-weight: 600; transition: color .2s; }

.nav-links a:hover, .nav-links a.active { color: var(--green); }

.nav-links .btn-nav {

  background: var(--green); color: var(--white) !important;

  padding: 0.4rem 1.1rem; border-radius: 6px;

}

.nav-links .btn-nav:hover { opacity: 0.85; }

 

main { flex: 1; }

 

/* HERO */

.hero {

  background: linear-gradient(135deg, #3d6b46, #2c4f33);

  color: white; text-align: center;

  padding: 5rem 2rem;

}

.hero h1 { font-family: var(--head); font-size: clamp(2rem, 5vw, 3.2rem); margin-bottom: 1rem; line-height: 1.25; }

.hero p  { font-size: 1.05rem; opacity: .85; max-width: 500px; margin: 0 auto 2rem; }

.hero-btns { display: flex; gap: 1rem; justify-content: center; flex-wrap: wrap; }

 

/* BUTTONS */

.btn { display: inline-block; padding: .7rem 1.6rem; border-radius: var(--radius); font-family: var(--body); font-size: .95rem; font-weight: 600; cursor: pointer; text-decoration: none; border: none; transition: all .2s; }

.btn-white   { background: white; color: var(--green); }

.btn-white:hover { opacity: .9; transform: translateY(-1px); }

.btn-outline { background: transparent; color: white; border: 2px solid rgba(255,255,255,.6); }

.btn-outline:hover { background: rgba(255,255,255,.1); }

.btn-green   { background: var(--green); color: white; }

.btn-green:hover { opacity: .85; transform: translateY(-1px); }

.btn-earth   { background: var(--earth); color: white; }

.btn-earth:hover { opacity: .85; }

.btn-full    { width: 100%; display: block; text-align: center; padding: .8rem; }

 

/* SECTIONS */

.section { max-width: 1080px; margin: 0 auto; padding: 4rem 2rem; }

.section-title { font-family: var(--head); font-size: 2rem; color: var(--green); margin-bottom: .4rem; }

.divider { width: 40px; height: 3px; background: var(--earth); border-radius: 2px; margin: .6rem 0 2rem; }

 

/* PAGE HEADER */

.page-header { background: linear-gradient(to right, var(--green), #4d7a56); color: white; text-align: center; padding: 3rem 2rem; }

.page-header h1 { font-family: var(--head); font-size: 2.2rem; margin-bottom: .4rem; }

.page-header p  { opacity: .85; }

 

/* CARDS */

.grid-3 { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 1.4rem; }

.card { background: var(--white); border: 1px solid var(--border); border-radius: var(--radius); padding: 1.6rem; transition: box-shadow .2s, transform .2s; }

.card:hover { box-shadow: 0 6px 24px rgba(0,0,0,.08); transform: translateY(-2px); }

.card-icon { font-size: 2rem; margin-bottom: .8rem; }

.card h3 { font-family: var(--head); color: var(--green); margin-bottom: .4rem; }

.card p  { font-size: .92rem; color: var(--muted); }

 

/* PRODUCT CARDS */

.product-card { background: var(--white); border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden; transition: box-shadow .2s, transform .2s; }

.product-card:hover { box-shadow: 0 6px 24px rgba(0,0,0,.09); transform: translateY(-2px); }

.product-img { height: 160px; background: var(--green-lite); display: flex; align-items: center; justify-content: center; font-size: 3.5rem; }

.product-body { padding: 1rem; }

.product-cat  { font-size: .75rem; text-transform: uppercase; letter-spacing: 1px; color: var(--earth); font-weight: 600; margin-bottom: .2rem; }

.product-name { font-family: var(--head); font-size: 1.05rem; margin-bottom: .2rem; }

.product-farm { font-size: .82rem; color: var(--muted); }

.product-foot { display: flex; align-items: center; justify-content: space-between; padding: .8rem 1rem; border-top: 1px solid var(--border); background: var(--cream); }

.product-price { font-weight: 700; color: var(--green); font-size: 1.05rem; }

.add-btn { background: var(--green); color: white; border: none; padding: .35rem .85rem; border-radius: 6px; font-family: var(--body); font-weight: 600; font-size: .85rem; cursor: pointer; transition: opacity .2s; }

.add-btn:hover { opacity: .8; }

 

/* FORM */

.form-wrap { background: var(--white); border: 1px solid var(--border); border-radius: var(--radius); padding: 2.2rem; max-width: 440px; margin: 3rem auto; box-shadow: 0 4px 20px rgba(0,0,0,.07); }

.form-title { font-family: var(--head); font-size: 1.7rem; color: var(--green); margin-bottom: .2rem; }

.form-sub   { color: var(--muted); font-size: .9rem; margin-bottom: 1.6rem; }

.form-group { margin-bottom: 1rem; }

.form-group label { display: block; font-size: .88rem; font-weight: 600; margin-bottom: .3rem; }

.form-group input, .form-group select, .form-group textarea {

  width: 100%; padding: .65rem .9rem;

  border: 1.5px solid var(--border); border-radius: 7px;

  font-family: var(--body); font-size: .95rem;

  background: var(--cream); color: var(--dark);

  transition: border-color .2s;

}

.form-group input:focus, .form-group select:focus, .form-group textarea:focus {

  outline: none; border-color: var(--green); background: white;

}

.form-group textarea { resize: vertical; min-height: 90px; }

.form-row  { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; }

.form-link { text-align: center; font-size: .88rem; color: var(--muted); margin-top: 1rem; }

.form-link a { color: var(--green); font-weight: 600; text-decoration: none; }

 

/* ALERTS */

.alert { padding: .75rem 1rem; border-radius: 7px; font-size: .9rem; margin-bottom: 1rem; }

.alert-ok  { background: var(--green-lite); color: var(--green); border: 1px solid #b8d9bb; }

.alert-err { background: #fce9e9; color: #b22; border: 1px solid #f5bbbb; }

 

/* BASKET */

.basket-table { width: 100%; border-collapse: collapse; background: white; border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden; }

.basket-table th { background: var(--green); color: white; padding: .8rem 1rem; text-align: left; font-size: .88rem; }

.basket-table td { padding: .8rem 1rem; border-bottom: 1px solid var(--border); font-size: .92rem; }

.basket-table tr:last-child td { border-bottom: none; }

.qty-btn { background: var(--green-lite); border: none; width: 26px; height: 26px; border-radius: 4px; font-size: 1rem; font-weight: 700; color: var(--green); cursor: pointer; transition: background .15s; }

.qty-btn:hover { background: var(--green); color: white; }

.summary-box { background: white; border: 1px solid var(--border); border-radius: var(--radius); padding: 1.5rem; }

.summary-box h3 { font-family: var(--head); color: var(--green); margin-bottom: 1rem; }

.summary-row { display: flex; justify-content: space-between; font-size: .92rem; margin-bottom: .4rem; }

.summary-total { display: flex; justify-content: space-between; font-weight: 700; font-size: 1.05rem; padding-top: .7rem; border-top: 1px solid var(--border); margin-top: .4rem; }

.checkout-layout { display: grid; grid-template-columns: 1fr 320px; gap: 2rem; align-items: start; }

 

/* PRODUCER TABLE */

.data-table { width: 100%; border-collapse: collapse; background: white; border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden; }

.data-table th { background: var(--green); color: white; padding: .75rem 1rem; text-align: left; font-size: .85rem; }

.data-table td { padding: .75rem 1rem; border-bottom: 1px solid var(--border); font-size: .9rem; }

.data-table tr:last-child td { border-bottom: none; }

.badge { display: inline-block; padding: .2rem .65rem; border-radius: 20px; font-size: .78rem; font-weight: 600; }

.badge-green { background: var(--green-lite); color: var(--green); }

.badge-earth { background: #f5ede1; color: var(--earth); }

 

/* FOOTER */

footer { background: #1a1a1a; color: rgba(255,255,255,.65); padding: 2.5rem 2rem 1.2rem; margin-top: auto; }

.footer-inner { max-width: 1080px; margin: 0 auto; display: grid; grid-template-columns: 2fr 1fr 1fr; gap: 2.5rem; margin-bottom: 1.8rem; }

.footer-logo { font-family: var(--head); font-size: 1.4rem; color: #f9f5f0; text-decoration: none; }

.footer-col h4 { font-size: .8rem; text-transform: uppercase; letter-spacing: 1.5px; color: #c4a882; margin-bottom: .8rem; }

.footer-col a  { display: block; color: rgba(255,255,255,.55); text-decoration: none; font-size: .88rem; margin-bottom: .4rem; transition: color .2s; }

.footer-col a:hover { color: #f9f5f0; }

.footer-bottom { border-top: 1px solid rgba(255,255,255,.1); padding-top: 1rem; text-align: center; font-size: .8rem; max-width: 1080px; margin: 0 auto; }

 

/* RESPONSIVE */

@media (max-width: 700px) {

  .footer-inner, .checkout-layout, .form-row { grid-template-columns: 1fr; }

  nav { padding: 0 1rem; }

  .section { padding: 2.5rem 1.2rem; }

}

about.html

<!DOCTYPE html>

<html lang="en">

<head>

  <meta charset="UTF-8">

  <meta name="viewport" content="width=device-width, initial-scale=1.0">

  <title>About Us – GLH</title>

  <link rel="stylesheet" href="style.css">

</head>

<body>

 

<nav>

  <a href="index.html" class="logo">GL<span>H</span></a>

  <ul class="nav-links">

    <li><a href="index.html">Home</a></li>

    <li><a href="shop.html">Shop</a></li>

    <li><a href="about.html">About Us</a></li>

    <li><a href="producer.html">Producers</a></li>

    <li><a href="login.php">Log In</a></li>

    <li><a href="register.php" class="btn-nav">Register</a></li>

    <li>

      <a href="basket.html" style="position:relative">

        🛒

        <span id="basket-count" style="background:var(--earth);color:white;border-radius:50%;font-size:.7rem;width:18px;height:18px;display:none;align-items:center;justify-content:center;position:absolute;top:-6px;right:-8px;font-weight:700;"></span>

      </a>

    </li>

  </ul>

</nav>

 

<main>

  <div class="page-header">

    <h1>About GLH</h1>

    <p>Our story, our mission, and the people behind it.</p>

  </div>

 

  <div class="section" style="max-width:780px">

    <p class="section-title">Our Story</p>

    <div class="divider"></div>

    <p style="color:var(--muted);margin-bottom:1.2rem;font-size:1.02rem">

      GLH – <em>Global Local Harvest</em> – was founded on a simple belief: that the food on your table should come from fields you can see from your window, not warehouses on the other side of the world.

    </p>

    <p style="color:var(--muted);margin-bottom:1.2rem">

      We started as a small farmers' market collective, frustrated by the barriers that kept exceptional local produce off supermarket shelves. Our founders — a mix of farmers, food lovers, and tech enthusiasts — decided to build something better.

    </p>

    <p style="color:var(--muted);margin-bottom:3rem">

      Today, GLH is home to dozens of independent farms, dairies, bakeries, orchards and artisan producers. We handle the digital shopfront so they can focus on what they do best — growing and making brilliant food.

    </p>

 

    <p class="section-title">Our Mission</p>

    <div class="divider"></div>

    <div class="grid-3" style="margin-bottom:3rem">

      <div class="card">

        <div class="card-icon">🎯</div>

        <h3>Collective Marketing</h3>

        <p>We pool resources so small farms get the reach of a big brand without losing their identity.</p>

      </div>

      <div class="card">

        <div class="card-icon">💷</div>

        <h3>Fair Returns</h3>

        <p>Producers set their own prices and receive the vast majority of every sale.</p>

      </div>

      <div class="card">

        <div class="card-icon">🏘️</div>

        <h3>Community Roots</h3>

        <p>Every producer is vetted and local. We build food systems that strengthen communities.</p>

      </div>

    </div>

 

    <p class="section-title">Our Producers</p>

    <div class="divider"></div>

    <div class="grid-3">

      <div class="card" style="text-align:center">

        <div style="font-size:2.2rem;margin-bottom:.6rem">🌻</div>

        <h3>Meadow Apiary</h3>

        <p>Raw honey & bee products<br><small style="color:var(--earth)">📍 Buckinghamshire</small></p>

      </div>

      <div class="card" style="text-align:center">

        <div style="font-size:2.2rem;margin-bottom:.6rem">🥬</div>

        <h3>Green Fields Farm</h3>

        <p>Seasonal vegetables & salads<br><small style="color:var(--earth)">📍 Oxfordshire</small></p>

      </div>

      <div class="card" style="text-align:center">

        <div style="font-size:2.2rem;margin-bottom:.6rem">🐄</div>

        <h3>Sunside Dairy</h3>

        <p>Milk, cream & butter<br><small style="color:var(--earth)">📍 Berkshire</small></p>

      </div>

      <div class="card" style="text-align:center">

        <div style="font-size:2.2rem;margin-bottom:.6rem">🍞</div>

        <h3>Old Mill Bakery</h3>

        <p>Sourdough & artisan breads<br><small style="color:var(--earth)">📍 Hertfordshire</small></p>

      </div>

      <div class="card" style="text-align:center">

        <div style="font-size:2.2rem;margin-bottom:.6rem">🐔</div>

        <h3>Happy Hen Farm</h3>

        <p>Free-range eggs<br><small style="color:var(--earth)">📍 Bedfordshire</small></p>

      </div>

      <div class="card" style="text-align:center">

        <div style="font-size:2.2rem;margin-bottom:.6rem">🍎</div>

        <h3>Orchard Vale</h3>

        <p>Ciders, juices & orchard fruit<br><small style="color:var(--earth)">📍 Worcestershire</small></p>

      </div>

    </div>

  </div>

 

  <div style="text-align:center;padding:3rem 2rem">

    <a href="shop.html" class="btn btn-green" style="margin-right:.8rem">Start Shopping</a>

    <a href="register.php" class="btn btn-earth">Register as Producer</a>

  </div>

</main>

 

<footer>

  <div class="footer-inner">

    <div>

      <a href="index.html" class="footer-logo">GLH</a>

      <p style="margin-top:.8rem;font-size:.88rem">Connecting local farms with communities who care about where their food comes from.</p>

    </div>

    <div class="footer-col">

      <h4>Navigate</h4>

      <a href="index.html">Home</a>

      <a href="shop.html">Shop</a>

      <a href="about.html">About Us</a>

    </div>

    <div class="footer-col">

      <h4>Producers</h4>

      <a href="register.php">Register</a>

      <a href="login.php">Login</a>

    </div>

  </div>

  <div class="footer-bottom">&copy; 2025 GLH – Global Local Harvest. All rights reserved.</div>

</footer>

<script src="app.js"></script>

</body>

</html>

app.js

// ── Shared data (in a real app this would come from a database) ──────────

const PRODUCTS = [

  { id:1, name:'Wildflower Honey',   category:'Condiments', farm:'Meadow Apiary',     price:6.50, unit:'jar',    icon:'🍯', stock:24 },

  { id:2, name:'Heritage Tomatoes',  category:'Vegetables', farm:'Green Fields Farm', price:3.20, unit:'punnet', icon:'🍅', stock:40 },

  { id:3, name:'Raw Whole Milk',     category:'Dairy',      farm:'Sunside Dairy',     price:1.10, unit:'litre',  icon:'🥛', stock:60 },

  { id:4, name:'Sourdough Loaf',     category:'Bakery',     farm:'Old Mill Bakery',   price:4.50, unit:'loaf',   icon:'🍞', stock:15 },

  { id:5, name:'Free-Range Eggs',    category:'Eggs',       farm:'Happy Hen Farm',    price:2.80, unit:'dozen',  icon:'🥚', stock:50 },

  { id:6, name:'Apple Cider',        category:'Drinks',     farm:'Orchard Vale',      price:5.00, unit:'bottle', icon:'🍺', stock:30 },

  { id:7, name:'New Potatoes',       category:'Vegetables', farm:'Green Fields Farm', price:2.00, unit:'kg',     icon:'🥔', stock:80 },

  { id:8, name:'Goat Cheese',        category:'Dairy',      farm:'Hillside Goat Farm',price:5.50, unit:'round',  icon:'🧀', stock:18 },

];

 

// ── Basket (stored in sessionStorage) ───────────────────────────────────

function getBasket() {

  return JSON.parse(sessionStorage.getItem('glh_basket') || '[]');

}

function saveBasket(basket) {

  sessionStorage.setItem('glh_basket', JSON.stringify(basket));

  updateNavCount();

}

function addToBasket(productId) {

  const basket = getBasket();

  const product = PRODUCTS.find(p => p.id === productId);

  if (!product) return;

  const existing = basket.find(i => i.id === productId);

  if (existing) { existing.qty++; }

  else { basket.push({ ...product, qty: 1 }); }

  saveBasket(basket);

}

function removeFromBasket(productId) {

  saveBasket(getBasket().filter(i => i.id !== productId));

}

function changeQty(productId, delta) {

  const basket = getBasket();

  const item = basket.find(i => i.id === productId);

  if (item) {

    item.qty += delta;

    if (item.qty <= 0) return removeFromBasket(productId);

  }

  saveBasket(basket);

}

function clearBasket() {

  sessionStorage.removeItem('glh_basket');

  updateNavCount();

}

function basketTotal() {

  return getBasket().reduce((sum, i) => sum + i.price * i.qty, 0);

}

function basketCount() {

  return getBasket().reduce((sum, i) => sum + i.qty, 0);

}

function updateNavCount() {

  const el = document.getElementById('basket-count');

  if (!el) return;

  const n = basketCount();

  el.textContent = n;

  el.style.display = n > 0 ? 'inline-flex' : 'none';

}

// ── Nav highlight & basket count ─────────────────────────────────────────

document.addEventListener('DOMContentLoaded', () => {

  updateNavCount();

  // highlight current page

  const page = location.pathname.split('/').pop() || 'index.html';

  document.querySelectorAll('.nav-links a').forEach(a => {

    if (a.getAttribute('href') === page) a.classList.add('active');

  });

});

basket.html

<!DOCTYPE html>

<html lang="en">

<head>

  <meta charset="UTF-8">

  <meta name="viewport" content="width=device-width, initial-scale=1.0">

  <title>Basket – GLH</title>

  <link rel="stylesheet" href="style.css">

</head>

<body>

 

<nav>

  <a href="index.html" class="logo">GL<span>H</span></a>

  <ul class="nav-links">

    <li><a href="index.html">Home</a></li>

    <li><a href="shop.html">Shop</a></li>

    <li><a href="about.html">About Us</a></li>

    <li><a href="producer.html">Producers</a></li>

    <li><a href="login.php">Log In</a></li>

    <li><a href="register.php" class="btn-nav">Register</a></li>

    <li>

      <a href="basket.html" style="position:relative">

        🛒

        <span id="basket-count" style="background:var(--earth);color:white;border-radius:50%;font-size:.7rem;width:18px;height:18px;display:none;align-items:center;justify-content:center;position:absolute;top:-6px;right:-8px;font-weight:700;"></span>

      </a>

    </li>

  </ul>

</nav>

 

<main>

  <div class="page-header">

    <h1>Your Basket</h1>

    <p id="basket-subtitle">Loading…</p>

  </div>

 

  <div class="section">

    <div id="empty-state" style="display:none;text-align:center;padding:4rem 1rem">

      <div style="font-size:4rem;margin-bottom:1rem">🛒</div>

      <h3 style="font-family:var(--head);color:var(--green);margin-bottom:.8rem">Your basket is empty</h3>

      <p style="color:var(--muted);margin-bottom:2rem">Head to the shop to find fresh local produce.</p>

      <a href="shop.html" class="btn btn-green">Browse the Shop</a>

    </div>

 

    <div id="basket-content" style="display:none">

      <div class="checkout-layout">

        <div>

          <table class="basket-table" id="basket-table">

            <thead>

              <tr>

                <th>Product</th>

                <th>Farm</th>

                <th>Price</th>

                <th>Qty</th>

                <th>Line Total</th>

                <th></th>

              </tr>

            </thead>

            <tbody id="basket-rows"></tbody>

          </table>

          <div style="margin-top:1rem;display:flex;gap:1rem;align-items:center">

            <button onclick="clearBasket();renderBasket()" class="btn" style="background:none;border:1.5px solid var(--border);color:var(--muted);font-size:.88rem">🗑 Clear Basket</button>

            <a href="shop.html" style="font-size:.9rem;color:var(--green);text-decoration:none">← Continue Shopping</a>

          </div>

        </div>

 

        <div class="summary-box" style="position:sticky;top:80px">

          <h3>Order Summary</h3>

          <div id="summary-rows"></div>

          <div class="summary-total" id="summary-total"></div>

          <a href="checkout.html" class="btn btn-green btn-full" style="margin-top:1rem">Proceed to Checkout →</a>

          <p style="text-align:center;font-size:.78rem;color:var(--muted);margin-top:.6rem">🔒 Secure mock checkout</p>

        </div>

      </div>

    </div>

  </div>

</main>

 

<footer>

  <div class="footer-inner">

    <div>

      <a href="index.html" class="footer-logo">GLH</a>

      <p style="margin-top:.8rem;font-size:.88rem">Connecting local farms with communities who care about where their food comes from.</p>

    </div>

    <div class="footer-col">

      <h4>Navigate</h4>

      <a href="index.html">Home</a>

      <a href="shop.html">Shop</a>

      <a href="about.html">About Us</a>

    </div>

    <div class="footer-col">

      <h4>Producers</h4>

      <a href="register.php">Register</a>

      <a href="login.php">Login</a>

    </div>

  </div>

  <div class="footer-bottom">&copy; 2025 GLH – Global Local Harvest. All rights reserved.</div>

</footer>

 

<script src="app.js"></script>

<script>

  function renderBasket() {

    const basket = getBasket();

    const subtitle = document.getElementById('basket-subtitle');

    const empty    = document.getElementById('empty-state');

    const content  = document.getElementById('basket-content');

 

    if (basket.length === 0) {

      subtitle.textContent = 'Your basket is empty.';

      empty.style.display   = 'block';

      content.style.display = 'none';

      return;

    }

 

    const count = basketCount();

    subtitle.textContent = `${count} item${count !== 1 ? 's' : ''} in your basket`;

    empty.style.display   = 'none';

    content.style.display = 'block';

 

    // Table rows

    document.getElementById('basket-rows').innerHTML = basket.map(item => `

      <tr>

        <td><span style="font-size:1.3rem;margin-right:.4rem">${item.icon}</span><strong>${item.name}</strong></td>

        <td style="color:var(--muted);font-size:.85rem">${item.farm}</td>

        <td>£${item.price.toFixed(2)}</td>

        <td>

          <div style="display:flex;align-items:center;gap:.4rem">

            <button class="qty-btn" onclick="changeQty(${item.id},-1);renderBasket()">−</button>

            <span style="min-width:20px;text-align:center;font-weight:700">${item.qty}</span>

            <button class="qty-btn" onclick="changeQty(${item.id},1);renderBasket()">+</button>

          </div>

        </td>

        <td style="font-weight:700;color:var(--green)">£${(item.price * item.qty).toFixed(2)}</td>

        <td><button onclick="removeFromBasket(${item.id});renderBasket()" style="background:none;border:none;color:#c00;font-size:1.1rem;cursor:pointer">✕</button></td>

      </tr>`).join('');

 

    // Summary

    const subtotal = basketTotal();

    const delivery = 2.99;

    const total    = subtotal + delivery;

 

    document.getElementById('summary-rows').innerHTML = basket.map(item =>

      `<div class="summary-row"><span>${item.name} × ${item.qty}</span><span>£${(item.price*item.qty).toFixed(2)}</span></div>`

    ).join('') + `

      <div class="summary-row" style="margin-top:.6rem;padding-top:.6rem;border-top:1px solid var(--border)">

        <span>Subtotal</span><span>£${subtotal.toFixed(2)}</span>

      </div>

      <div class="summary-row"><span>Delivery</span><span>£${delivery.toFixed(2)}</span></div>`;

    document.getElementById('summary-total').innerHTML =

      `<span>Total</span><span>£${total.toFixed(2)}</span>`;

  }

  renderBasket();

</script>

</body>

</html>

checkout.html

<!DOCTYPE html>

<html lang="en">

<head>

  <meta charset="UTF-8">

  <meta name="viewport" content="width=device-width, initial-scale=1.0">

  <title>Checkout – GLH</title>

  <link rel="stylesheet" href="style.css">

</head>

<body>

 

<nav>

  <a href="index.html" class="logo">GL<span>H</span></a>

  <ul class="nav-links">

    <li><a href="index.html">Home</a></li>

    <li><a href="shop.html">Shop</a></li>

    <li><a href="about.html">About Us</a></li>

    <li><a href="producer.html">Producers</a></li>

    <li><a href="login.php">Log In</a></li>

    <li><a href="register.php" class="btn-nav">Register</a></li>

    <li>

      <a href="basket.html" style="position:relative">

        🛒

        <span id="basket-count" style="background:var(--earth);color:white;border-radius:50%;font-size:.7rem;width:18px;height:18px;display:none;align-items:center;justify-content:center;position:absolute;top:-6px;right:-8px;font-weight:700;"></span>

      </a>

    </li>

  </ul>

</nav>

 

<main>

  <div class="page-header">

    <h1>Checkout</h1>

    <p>Mock checkout — no real payment will be taken.</p>

  </div>

 

  <div class="section">

 

    <!-- CONFIRMATION screen (hidden until order placed) -->

    <div id="confirmation" style="display:none;max-width:580px;margin:0 auto;text-align:center;padding:2rem 0">

      <div style="font-size:4rem;margin-bottom:1rem">🎉</div>

      <h2 style="font-family:var(--head);color:var(--green);margin-bottom:.5rem">Order Confirmed!</h2>

      <p style="color:var(--muted);margin-bottom:1.5rem">Thank you! Your mock order has been placed.</p>

      <div class="summary-box" style="text-align:left;max-width:420px;margin:0 auto 1.5rem">

        <div class="summary-row"><strong>Reference</strong><span id="conf-ref" style="color:var(--green);font-weight:700"></span></div>

        <div class="summary-row" style="margin-top:.4rem"><span>Name</span><span id="conf-name"></span></div>

        <div class="summary-row"><span>Total</span><span id="conf-total" style="font-weight:700"></span></div>

      </div>

      <div class="alert alert-ok" style="max-width:420px;margin:0 auto 1.5rem;text-align:left">

        ℹ️ This is a <strong>demonstration checkout</strong>. No real payment has been processed.

      </div>

      <a href="shop.html" class="btn btn-green">Continue Shopping</a>

    </div>

 

    <!-- CHECKOUT form -->

    <div id="checkout-form">

      <div id="empty-warn" class="alert alert-ok" style="display:none;max-width:500px">

        Your basket is empty. <a href="shop.html">Go shopping →</a>

      </div>

 

      <div id="checkout-layout" class="checkout-layout">

        <div>

          <!-- Delivery -->

          <div class="summary-box" style="margin-bottom:1.5rem">

            <h3 style="margin-bottom:1.2rem;padding-bottom:.8rem;border-bottom:1px solid var(--border)">📦 Delivery Details</h3>

            <div class="form-row">

              <div class="form-group"><label>First name</label><input type="text" id="fname" placeholder="Jane"></div>

              <div class="form-group"><label>Last name</label><input type="text" id="lname" placeholder="Smith"></div>

            </div>

            <div class="form-group"><label>Email</label><input type="email" id="email" placeholder="jane@example.com"></div>

            <div class="form-group"><label>Address</label><input type="text" id="address" placeholder="12 Farm Lane"></div>

            <div class="form-row">

              <div class="form-group"><label>City</label><input type="text" id="city" placeholder="Oxford"></div>

              <div class="form-group"><label>Postcode</label><input type="text" id="postcode" placeholder="OX1 1AB"></div>

            </div>

          </div>

 

          <!-- Payment -->

          <div class="summary-box">

            <h3 style="margin-bottom:1.2rem;padding-bottom:.8rem;border-bottom:1px solid var(--border)">

              💳 Payment <span style="font-size:.75rem;color:var(--earth);font-weight:400">(Mock — enter any values)</span>

            </h3>

            <div class="form-group"><label>Name on card</label><input type="text" id="card-name" placeholder="Jane Smith"></div>

            <div class="form-group"><label>Card number</label><input type="text" id="card-num" placeholder="1234 5678 9012 3456" maxlength="19" oninput="fmtCard(this)"></div>

            <div class="form-row">

              <div class="form-group"><label>Expiry (MM/YY)</label><input type="text" id="expiry" placeholder="08/27" maxlength="5"></div>

              <div class="form-group"><label>CVV</label><input type="text" id="cvv" placeholder="123" maxlength="4"></div>

            </div>

          </div>

 

          <div id="form-error" class="alert alert-err" style="display:none;margin-top:1rem"></div>

 

          <button onclick="placeOrder()" class="btn btn-green btn-full" style="margin-top:1.2rem;font-size:1rem" id="place-btn">

            🔒 Place Order

          </button>

          <p style="text-align:center;font-size:.78rem;color:var(--muted);margin-top:.6rem">No real payment will be processed.</p>

        </div>

 

        <!-- Order summary -->

        <div class="summary-box" style="position:sticky;top:80px">

          <h3>Your Order</h3>

          <div id="order-items"></div>

          <div id="order-totals"></div>

        </div>

      </div>

    </div>

 

  </div>

</main>

 

<footer>

  <div class="footer-inner">

    <div>

      <a href="index.html" class="footer-logo">GLH</a>

      <p style="margin-top:.8rem;font-size:.88rem">Connecting local farms with communities who care about where their food comes from.</p>

    </div>

    <div class="footer-col">

      <h4>Navigate</h4>

      <a href="index.html">Home</a>

      <a href="shop.html">Shop</a>

    </div>

    <div class="footer-col">

      <h4>Producers</h4>

      <a href="register.php">Register</a>

      <a href="login.php">Login</a>

    </div>

  </div>

  <div class="footer-bottom">&copy; 2025 GLH – Global Local Harvest. All rights reserved.</div>

</footer>

 

<script src="app.js"></script>

<script>

  function fmtCard(el) {

    el.value = el.value.replace(/\D/g,'').substring(0,16).replace(/(.{4})/g,'$1 ').trim();

  }

 

  function renderSummary() {

    const basket = getBasket();

    if (!basket.length) {

      document.getElementById('empty-warn').style.display = 'block';

      document.getElementById('checkout-layout').style.display = 'none';

      return;

    }

    const subtotal = basketTotal();

    const delivery = 2.99;

    const total = subtotal + delivery;

 

    document.getElementById('order-items').innerHTML = basket.map(i =>

      `<div class="summary-row"><span>${i.icon} ${i.name} × ${i.qty}</span><span>£${(i.price*i.qty).toFixed(2)}</span></div>`

    ).join('');

 

    document.getElementById('order-totals').innerHTML = `

      <div class="summary-row" style="margin-top:.6rem;padding-top:.6rem;border-top:1px solid var(--border)">

        <span>Subtotal</span><span>£${subtotal.toFixed(2)}</span>

      </div>

      <div class="summary-row"><span>Delivery</span><span>£2.99</span></div>

      <div class="summary-total"><span>Total</span><span>£${total.toFixed(2)}</span></div>`;

 

    document.getElementById('place-btn').textContent = `🔒 Place Order – £${total.toFixed(2)}`;

  }

 

  function placeOrder() {

    const fields = [

      { id:'fname', label:'First name' },

      { id:'lname', label:'Last name' },

      { id:'email', label:'Email' },

      { id:'address', label:'Address' },

      { id:'city', label:'City' },

      { id:'postcode', label:'Postcode' },

      { id:'card-name', label:'Name on card' },

      { id:'card-num', label:'Card number' },

      { id:'expiry', label:'Expiry' },

      { id:'cvv', label:'CVV' },

    ];

    const missing = fields.filter(f => !document.getElementById(f.id).value.trim());

    if (missing.length) {

      const errEl = document.getElementById('form-error');

      errEl.textContent = 'Please fill in: ' + missing.map(f => f.label).join(', ');

      errEl.style.display = 'block';

      return;

    }

    document.getElementById('form-error').style.display = 'none';

 

    const ref = 'GLH-' + Math.random().toString(36).substring(2,10).toUpperCase();

    const name = document.getElementById('fname').value + ' ' + document.getElementById('lname').value;

    const total = (basketTotal() + 2.99).toFixed(2);

 

    document.getElementById('conf-ref').textContent   = ref;

    document.getElementById('conf-name').textContent  = name;

    document.getElementById('conf-total').textContent = '£' + total;

 

    clearBasket();

    document.getElementById('checkout-form').style.display = 'none';

    document.getElementById('confirmation').style.display  = 'block';

  }

 

  renderSummary();

</script>

</body>

</html>

producer.html

<!DOCTYPE html>

<html lang="en">

<head>

  <meta charset="UTF-8">

  <meta name="viewport" content="width=device-width, initial-scale=1.0">

  <title>Producer Dashboard – GLH</title>

  <link rel="stylesheet" href="style.css">

</head>

<body>

 

<nav>

  <a href="index.html" class="logo">GL<span>H</span></a>

  <ul class="nav-links">

    <li><a href="index.html">Home</a></li>

    <li><a href="shop.html">Shop</a></li>

    <li><a href="about.html">About Us</a></li>

    <li><a href="producer.html">Producers</a></li>

    <li><a href="login.php">Log In</a></li>

    <li><a href="register.php" class="btn-nav">Register</a></li>

    <li>

      <a href="basket.html" style="position:relative">

        🛒

        <span id="basket-count" style="background:var(--earth);color:white;border-radius:50%;font-size:.7rem;width:18px;height:18px;display:none;align-items:center;justify-content:center;position:absolute;top:-6px;right:-8px;font-weight:700;"></span>

      </a>

    </li>

  </ul>

</nav>

 

<main>

  <div class="page-header">

    <h1>Producer Dashboard</h1>

    <p>Add, update or remove your product listings.</p>

  </div>

 

  <div class="section">

    <div id="flash" class="alert alert-ok" style="display:none;margin-bottom:1.2rem"></div>

 

    <div style="display:grid;grid-template-columns:1fr 320px;gap:2rem;align-items:start">

 

      <!-- Product list -->

      <div>

        <h3 style="font-family:var(--head);color:var(--green);margin-bottom:1.2rem">Your Products</h3>

        <div id="no-products" style="display:none" class="card" style="text-align:center;padding:2.5rem">

          <p style="font-size:2rem;margin-bottom:.5rem">🌾</p>

          <p style="color:var(--muted)">No products yet — add your first one!</p>

        </div>

        <table class="data-table" id="product-table" style="display:none">

          <thead>

            <tr>

              <th>Image</th>

              <th>Product</th>

              <th>Category</th>

              <th>Price</th>

              <th>Stock</th>

              <th>Actions</th>

            </tr>

          </thead>

          <tbody id="product-rows"></tbody>

        </table>

      </div>

 

      <!-- Add / Edit form -->

      <div class="summary-box" style="position:sticky;top:80px">

        <h3 style="font-family:var(--head);color:var(--green);margin-bottom:1rem;padding-bottom:.8rem;border-bottom:1px solid var(--border)" id="form-title">Add Product</h3>

 

        <!-- Image upload -->

        <div class="form-group">

          <label>Product image</label>

          <div id="img-drop" onclick="document.getElementById('f-image').click()"

            style="border:2px dashed var(--border);border-radius:8px;padding:1.2rem;text-align:center;cursor:pointer;background:var(--cream);transition:border-color .2s"

            ondragover="event.preventDefault();this.style.borderColor='var(--green)'"

            ondragleave="this.style.borderColor='var(--border)'"

            ondrop="handleDrop(event)">

            <div id="img-preview" style="display:none;margin-bottom:.6rem">

              <img id="img-thumb" src="" alt="preview" style="max-height:100px;max-width:100%;border-radius:6px;object-fit:cover">

            </div>

            <div id="img-placeholder">

              <div style="font-size:1.8rem;margin-bottom:.3rem">📷</div>

              <p style="font-size:.82rem;color:var(--muted)">Click or drag & drop an image</p>

              <p style="font-size:.75rem;color:var(--muted)">JPG, PNG, WEBP — max 2MB</p>

            </div>

            <input type="file" id="f-image" accept="image/*" style="display:none" onchange="handleImageFile(this.files[0])">

          </div>

          <button type="button" id="img-clear" onclick="clearImage()" style="display:none;margin-top:.4rem;font-size:.8rem;background:none;border:none;color:#c00;cursor:pointer">✕ Remove image</button>

        </div>

 

        <!-- Fallback emoji -->

        <div class="form-group">

          <label>Fallback icon <span style="font-weight:400;color:var(--muted)">(shown if no image)</span></label>

          <div style="display:flex;flex-wrap:wrap;gap:.3rem;margin-bottom:.5rem">

            <span style="font-size:1.3rem;cursor:pointer" onclick="pickIcon(this)">🥦</span>

            <span style="font-size:1.3rem;cursor:pointer" onclick="pickIcon(this)">🍅</span>

            <span style="font-size:1.3rem;cursor:pointer" onclick="pickIcon(this)">🥕</span>

            <span style="font-size:1.3rem;cursor:pointer" onclick="pickIcon(this)">🧅</span>

            <span style="font-size:1.3rem;cursor:pointer" onclick="pickIcon(this)">🍎</span>

            <span style="font-size:1.3rem;cursor:pointer" onclick="pickIcon(this)">🍓</span>

            <span style="font-size:1.3rem;cursor:pointer" onclick="pickIcon(this)">🥛</span>

            <span style="font-size:1.3rem;cursor:pointer" onclick="pickIcon(this)">🧀</span>

            <span style="font-size:1.3rem;cursor:pointer" onclick="pickIcon(this)">🥚</span>

            <span style="font-size:1.3rem;cursor:pointer" onclick="pickIcon(this)">🍞</span>

            <span style="font-size:1.3rem;cursor:pointer" onclick="pickIcon(this)">🥩</span>

            <span style="font-size:1.3rem;cursor:pointer" onclick="pickIcon(this)">🍯</span>

            <span style="font-size:1.3rem;cursor:pointer" onclick="pickIcon(this)">🍺</span>

            <span style="font-size:1.3rem;cursor:pointer" onclick="pickIcon(this)">🫐</span>

            <span style="font-size:1.3rem;cursor:pointer" onclick="pickIcon(this)">🥔</span>

          </div>

          <input type="text" id="f-icon" value="🥦" placeholder="Or type emoji" style="width:70px">

        </div>

 

        <div class="form-group">

          <label>Product name *</label>

          <input type="text" id="f-name" placeholder="e.g. Heritage Tomatoes">

        </div>

        <div class="form-group">

          <label>Farm / Producer name *</label>

          <input type="text" id="f-farm" placeholder="e.g. Green Fields Farm">

        </div>

        <div class="form-group">

          <label>Category</label>

          <select id="f-category">

            <option>Vegetables</option><option>Fruit</option><option>Dairy</option>

            <option>Meat</option><option>Bakery</option><option>Eggs</option>

            <option>Condiments</option><option>Drinks</option><option>Other</option>

          </select>

        </div>

        <div style="display:grid;grid-template-columns:1fr 1fr;gap:.8rem">

          <div class="form-group">

            <label>Price (£) *</label>

            <input type="number" id="f-price" step="0.01" min="0.01" placeholder="3.50">

          </div>

          <div class="form-group">

            <label>Unit</label>

            <input type="text" id="f-unit" placeholder="kg / jar…">

          </div>

        </div>

        <div class="form-group">

          <label>Stock quantity</label>

          <input type="number" id="f-stock" min="0" placeholder="20">

        </div>

 

        <input type="hidden" id="edit-id" value="">

        <button onclick="saveProduct()" class="btn btn-green btn-full" id="save-btn">Add Product</button>

        <button onclick="cancelEdit()" id="cancel-btn" class="btn btn-full" style="display:none;margin-top:.5rem;background:none;border:1.5px solid var(--border);color:var(--muted)">Cancel</button>

      </div>

    </div>

  </div>

</main>

 

<footer>

  <div class="footer-inner">

    <div>

      <a href="index.html" class="footer-logo">GLH</a>

      <p style="margin-top:.8rem;font-size:.88rem">Connecting local farms with communities who care about where their food comes from.</p>

    </div>

    <div class="footer-col">

      <h4>Navigate</h4>

      <a href="index.html">Home</a>

      <a href="shop.html">Shop</a>

    </div>

    <div class="footer-col">

      <h4>Account</h4>

      <a href="login.php">Login</a>

      <a href="register.php">Register</a>

    </div>

  </div>

  <div class="footer-bottom">&copy; 2025 GLH – Global Local Harvest. All rights reserved.</div>

</footer>

 

<script src="app.js"></script>

<script>

  let pendingImageBase64 = null; // holds base64 of newly selected image

 

  // ── Image handling ──────────────────────────────────────────────────────

  function handleImageFile(file) {

    if (!file) return;

    if (file.size > 2 * 1024 * 1024) { alert('Image must be under 2MB.'); return; }

    const reader = new FileReader();

    reader.onload = e => {

      pendingImageBase64 = e.target.result;

      showPreview(pendingImageBase64);

    };

    reader.readAsDataURL(file);

  }

 

  function handleDrop(e) {

    e.preventDefault();

    document.getElementById('img-drop').style.borderColor = 'var(--border)';

    const file = e.dataTransfer.files[0];

    if (file && file.type.startsWith('image/')) handleImageFile(file);

  }

 

  function showPreview(src) {

    document.getElementById('img-thumb').src = src;

    document.getElementById('img-preview').style.display = 'block';

    document.getElementById('img-placeholder').style.display = 'none';

    document.getElementById('img-clear').style.display = 'inline';

    document.getElementById('img-drop').style.borderColor = 'var(--green)';

  }

 

  function clearImage() {

    pendingImageBase64 = null;

    document.getElementById('f-image').value = '';

    document.getElementById('img-thumb').src = '';

    document.getElementById('img-preview').style.display = 'none';

    document.getElementById('img-placeholder').style.display = 'block';

    document.getElementById('img-clear').style.display = 'none';

    document.getElementById('img-drop').style.borderColor = 'var(--border)';

  }

 

  // ── Producer products stored in localStorage ────────────────────────────

  function getProducerProducts() {

    return JSON.parse(localStorage.getItem('glh_producer_products') || '[]');

  }

  function saveProducerProducts(products) {

    localStorage.setItem('glh_producer_products', JSON.stringify(products));

  }

 

  function pickIcon(el) {

    document.getElementById('f-icon').value = el.textContent;

  }

 

  function flash(msg) {

    const el = document.getElementById('flash');

    el.textContent = '✅ ' + msg;

    el.style.display = 'block';

    setTimeout(() => el.style.display = 'none', 2500);

  }

 

  function renderProducts() {

    const products = getProducerProducts();

    const table = document.getElementById('product-table');

    const noP   = document.getElementById('no-products');

 

    if (!products.length) {

      table.style.display = 'none';

      noP.style.display   = 'block';

      return;

    }

    noP.style.display   = 'none';

    table.style.display = 'table';

 

    document.getElementById('product-rows').innerHTML = products.map(p => `

      <tr>

        <td>

          ${p.image

            ? `<img src="${p.image}" alt="${p.name}" style="width:50px;height:50px;object-fit:cover;border-radius:6px;border:1px solid var(--border)">`

            : `<span style="font-size:1.8rem">${p.icon}</span>`}

        </td>

        <td><strong>${p.name}</strong><br><span style="font-size:.8rem;color:var(--muted)">${p.farm}</span></td>

        <td><span class="badge badge-earth">${p.category}</span></td>

        <td>£${parseFloat(p.price).toFixed(2)}</td>

        <td>${p.stock}</td>

        <td>

          <button class="add-btn" onclick="editProduct(${p.id})" style="margin-right:.3rem">Edit</button>

          <button onclick="deleteProduct(${p.id})" style="background:#c00;color:white;border:none;padding:.3rem .7rem;border-radius:5px;font-size:.82rem;cursor:pointer">Remove</button>

        </td>

      </tr>`).join('');

  }

 

  function saveProduct() {

    const name   = document.getElementById('f-name').value.trim();

    const farm   = document.getElementById('f-farm').value.trim();

    const price  = parseFloat(document.getElementById('f-price').value);

    const unit   = document.getElementById('f-unit').value.trim() || 'unit';

    const stock  = parseInt(document.getElementById('f-stock').value) || 0;

    const icon   = document.getElementById('f-icon').value.trim() || '🛒';

    const cat    = document.getElementById('f-category').value;

    const editId = document.getElementById('edit-id').value;

 

    if (!name || !farm || !price || price <= 0) {

      alert('Please fill in Name, Farm and a valid Price.');

      return;

    }

 

    let products = getProducerProducts();

 

    if (editId) {

      products = products.map(p => {

        if (p.id !== parseInt(editId)) return p;

        return {

          ...p, name, farm, price, unit, stock, icon, category: cat,

          // only update image if a new one was selected

          image: pendingImageBase64 !== null ? pendingImageBase64 : p.image

        };

      });

      flash(`"${name}" updated!`);

    } else {

      const id = Date.now();

      products.push({ id, name, farm, price, unit, stock, icon, category: cat, image: pendingImageBase64 });

      flash(`"${name}" added to the shop!`);

    }

 

    saveProducerProducts(products);

    cancelEdit();

    renderProducts();

  }

 

  function editProduct(id) {

    const p = getProducerProducts().find(x => x.id === id);

    if (!p) return;

    document.getElementById('f-name').value     = p.name;

    document.getElementById('f-farm').value     = p.farm;

    document.getElementById('f-price').value    = p.price;

    document.getElementById('f-unit').value     = p.unit;

    document.getElementById('f-stock').value    = p.stock;

    document.getElementById('f-icon').value     = p.icon;

    document.getElementById('f-category').value = p.category;

    document.getElementById('edit-id').value    = p.id;

    // Show existing image if there is one

    pendingImageBase64 = null; // reset pending; existing image kept unless replaced

    if (p.image) { showPreview(p.image); }

    else { clearImage(); }

    document.getElementById('form-title').textContent    = 'Edit Product';

    document.getElementById('save-btn').textContent      = 'Save Changes';

    document.getElementById('cancel-btn').style.display  = 'block';

    window.scrollTo({ top: 0, behavior: 'smooth' });

  }

 

  function deleteProduct(id) {

    if (!confirm('Remove this product?')) return;

    saveProducerProducts(getProducerProducts().filter(p => p.id !== id));

    renderProducts();

    flash('Product removed.');

  }

 

  function cancelEdit() {

    document.getElementById('f-name').value  = '';

    document.getElementById('f-farm').value  = '';

    document.getElementById('f-price').value = '';

    document.getElementById('f-unit').value  = '';

    document.getElementById('f-stock').value = '';

    document.getElementById('f-icon').value  = '🥦';

    document.getElementById('edit-id').value = '';

    clearImage();

    document.getElementById('form-title').textContent    = 'Add Product';

    document.getElementById('save-btn').textContent      = 'Add Product';

    document.getElementById('cancel-btn').style.display  = 'none';

  }

 

  renderProducts();

</script>

</body>

</html>

shop.html

!DOCTYPE html>

<html lang="en">

<head>

  <meta charset="UTF-8">

  <meta name="viewport" content="width=device-width, initial-scale=1.0">

  <title>Shop – GLH</title>

  <link rel="stylesheet" href="style.css">

</head>

<body>

 

<nav>

  <a href="index.html" class="logo">GL<span>H</span></a>

  <ul class="nav-links">

    <li><a href="index.html">Home</a></li>

    <li><a href="shop.html">Shop</a></li>

    <li><a href="about.html">About Us</a></li>

    <li><a href="producer.html">Producers</a></li>

    <li><a href="login.php">Log In</a></li>

    <li><a href="register.php" class="btn-nav">Register</a></li>

    <li>

      <a href="basket.html" style="position:relative">

        🛒

        <span id="basket-count" style="background:var(--earth);color:white;border-radius:50%;font-size:.7rem;width:18px;height:18px;display:none;align-items:center;justify-content:center;position:absolute;top:-6px;right:-8px;font-weight:700;"></span>

      </a>

    </li>

  </ul>

</nav>

 

<main>

  <div class="page-header">

    <h1>The GLH Shop</h1>

    <p>Fresh, local produce — updated weekly by our producers.</p>

  </div>

 

  <div class="section">

    <!-- Flash message -->

    <div id="flash" class="alert alert-ok" style="display:none;max-width:450px;margin-bottom:1.2rem"></div>

 

    <!-- Category filter tabs -->

    <div style="display:flex;gap:.6rem;flex-wrap:wrap;margin-bottom:2rem" id="tabs"></div>

 

    <!-- Product grid -->

    <div class="grid-3" id="product-grid"></div>

  </div>

</main>

 

<footer>

  <div class="footer-inner">

    <div>

      <a href="index.html" class="footer-logo">GLH</a>

      <p style="margin-top:.8rem;font-size:.88rem">Connecting local farms with communities who care about where their food comes from.</p>

    </div>

    <div class="footer-col">

      <h4>Navigate</h4>

      <a href="index.html">Home</a>

      <a href="shop.html">Shop</a>

      <a href="about.html">About Us</a>

    </div>

    <div class="footer-col">

      <h4>Producers</h4>

      <a href="register.php">Register</a>

      <a href="login.php">Login</a>

    </div>

  </div>

  <div class="footer-bottom">&copy; 2025 GLH – Global Local Harvest. All rights reserved.</div>

</footer>

 

<script src="app.js"></script>

<script>

  // Load extra products saved by producers from localStorage

  function getAllProducts() {

    const extra = JSON.parse(localStorage.getItem('glh_producer_products') || '[]');

    return [...PRODUCTS, ...extra];

  }

 

  let activeCategory = 'All';

 

  function renderTabs() {

    const all = getAllProducts();

    const cats = ['All', ...new Set(all.map(p => p.category))];

    const tabsEl = document.getElementById('tabs');

    tabsEl.innerHTML = cats.map(c => `

      <button onclick="setCategory('${c}')" id="tab-${c}"

        style="padding:.4rem 1rem;border-radius:6px;border:1.5px solid ${c===activeCategory?'var(--green)':'var(--border)'};

               background:${c===activeCategory?'var(--green)':'var(--white)'};

               color:${c===activeCategory?'white':'var(--muted)'};

               font-family:var(--body);font-weight:600;font-size:.88rem;cursor:pointer">

        ${c}

      </button>`).join('');

  }

 

  function renderProducts() {

    const all = getAllProducts();

    const filtered = activeCategory === 'All' ? all : all.filter(p => p.category === activeCategory);

    const grid = document.getElementById('product-grid');

    if (!filtered.length) {

      grid.innerHTML = '<p style="color:var(--muted);grid-column:1/-1;text-align:center;padding:3rem">No products in this category yet.</p>';

      return;

    }

    grid.innerHTML = filtered.map(p => `

      <div class="product-card">

        <div class="product-img" style="${p.image ? 'padding:0;background:none' : ''}">

          ${p.image

            ? `<img src="${p.image}" alt="${p.name}" style="width:100%;height:100%;object-fit:cover">`

            : p.icon}

        </div>

        <div class="product-body">

          <div class="product-cat">${p.category}</div>

          <div class="product-name">${p.name}</div>

          <div class="product-farm">by ${p.farm}</div>

          <p style="font-size:.8rem;margin-top:.3rem;color:${p.stock>10?'var(--green)':'var(--earth)'}">

            ${p.stock > 10 ? '✓ In stock' : '⚠ Low stock ('+p.stock+' left)'}

          </p>

        </div>

        <div class="product-foot">

          <span class="product-price">£${p.price.toFixed(2)} <span style="font-size:.75rem;font-weight:400;color:var(--muted)">/ ${p.unit}</span></span>

          <button class="add-btn" id="addbtn-${p.id}" onclick="handleAdd(${p.id}, '${p.name}')">+ Add</button>

        </div>

      </div>`).join('');

  }

 

  function setCategory(cat) {

    activeCategory = cat;

    renderTabs();

    renderProducts();

  }

 

  function handleAdd(id, name) {

    addToBasket(id);

    const btn = document.getElementById('addbtn-' + id);

    if (btn) { btn.textContent = 'Added ✓'; setTimeout(() => btn.textContent = '+ Add', 1300); }

    const flash = document.getElementById('flash');

    flash.textContent = `✅ ${name} added to your basket!`;

    flash.style.display = 'block';

    setTimeout(() => flash.style.display = 'none', 2500);

  }

 

  renderTabs();

  renderProducts();

</script>

</body>

</html>

login.php

<?php

session_start();

 

// Simple demo users

$users = [

  'admin@glh.co.uk'         => ['name' => 'GLH Admin',       'password' => 'admin123',  'role' => 'admin'],

  'producer@greenfields.co.uk' => ['name' => 'Green Fields Farm','password' => 'farm123','role' => 'producer'],

];

 

$error = '';

 

if ($_SERVER['REQUEST_METHOD'] === 'POST') {

  $email    = trim($_POST['email'] ?? '');

  $password = $_POST['password'] ?? '';

 

  if (isset($users[$email]) && $users[$email]['password'] === $password) {

    $_SESSION['user'] = [

      'name' => $users[$email]['name'],

      'role' => $users[$email]['role'],

    ];

    header('Location: producer.html');

    exit;

  } else {

    $error = 'Incorrect email or password.';

  }

}

?>

<!DOCTYPE html>

<html lang="en">

<head>

  <meta charset="UTF-8">

  <meta name="viewport" content="width=device-width, initial-scale=1.0">

  <title>Log In – GLH</title>

  <link rel="stylesheet" href="style.css">

</head>

<body>

 

<nav>

  <a href="index.html" class="logo">GL<span>H</span></a>

  <ul class="nav-links">

    <li><a href="index.html">Home</a></li>

    <li><a href="shop.html">Shop</a></li>

    <li><a href="about.html">About Us</a></li>

    <li><a href="login.php">Log In</a></li>

    <li><a href="register.php" class="btn-nav">Register</a></li>

    <li><a href="basket.html">🛒</a></li>

  </ul>

</nav>

 

<main>

<div style="min-height:70vh;display:flex;align-items:center;padding:2rem 1rem">

  <div class="form-wrap">

    <h2 class="form-title">Welcome back</h2>

    <p class="form-sub">Sign in to your GLH account.</p>

 

    <?php if ($error): ?>

    <div class="alert alert-err"><?= htmlspecialchars($error) ?></div>

    <?php endif; ?>

 

    <?php if (isset($_GET['registered'])): ?>

    <div class="alert alert-ok">Account created! You can now log in.</div>

    <?php endif; ?>

 

    <form method="post">

      <div class="form-group">

        <label>Email address</label>

        <input type="email" name="email" placeholder="you@example.com" value="<?= htmlspecialchars($_POST['email'] ?? '') ?>" required>

      </div>

      <div class="form-group">

        <label>Password</label>

        <input type="password" name="password" placeholder="••••••••" required>

      </div>

      <button type="submit" class="btn btn-green btn-full" style="margin-top:.5rem">Log In</button>

    </form>

 

    <div style="margin-top:1.2rem;padding:.9rem;background:var(--cream);border:1px solid var(--border);border-radius:7px">

      <p style="font-size:.8rem;color:var(--muted);margin-bottom:.3rem;font-weight:600">Demo credentials</p>

      <p style="font-size:.8rem;color:var(--muted)">Admin: <code>admin@glh.co.uk</code> / <code>admin123</code></p>

      <p style="font-size:.8rem;color:var(--muted)">Producer: <code>producer@greenfields.co.uk</code> / <code>farm123</code></p>

    </div>

 

    <p class="form-link">No account? <a href="register.php">Register here</a></p>

  </div>

</div>

</main>

 

<footer>

  <div class="footer-inner">

    <div><a href="index.html" class="footer-logo">GLH</a></div>

    <div class="footer-col">

      <h4>Navigate</h4>

      <a href="index.html">Home</a><a href="shop.html">Shop</a>

    </div>

    <div class="footer-col">

      <h4>Account</h4>

      <a href="register.php">Register</a>

    </div>

  </div>

  <div class="footer-bottom">&copy; 2025 GLH – Global Local Harvest.</div>

</footer>

<script src="app.js"></script>

</body>

</html>

 

Register.php
<?php
session_start();

$errors  = [];
$role    = $_POST['role'] ?? 'customer';

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
  $name     = trim($_POST['name'] ?? '');
  $email    = trim($_POST['email'] ?? '');
  $password = $_POST['password'] ?? '';
  $confirm  = $_POST['confirm']  ?? '';
  $farm     = trim($_POST['farm'] ?? '');

  if (!$name)                                      $errors[] = 'Full name is required.';
  if (!filter_var($email, FILTER_VALIDATE_EMAIL))  $errors[] = 'A valid email is required.';
  if (strlen($password) < 6)                       $errors[] = 'Password must be at least 6 characters.';
  if ($password !== $confirm)                      $errors[] = 'Passwords do not match.';
  if ($role === 'producer' && !$farm)              $errors[] = 'Farm name is required for producers.';

  if (empty($errors)) {
    // In a real app you'd save to a database here.
    // For this demo we just redirect to login with a success flag.
    header('Location: login.php?registered=1');
    exit;
  }
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Register – GLH</title>
  <link rel="stylesheet" href="style.css">
</head>
<body>

<nav>
  <a href="index.html" class="logo">GL<span>H</span></a>
  <ul class="nav-links">
    <li><a href="index.html">Home</a></li>
    <li><a href="shop.html">Shop</a></li>
    <li><a href="about.html">About Us</a></li>
    <li><a href="login.php">Log In</a></li>
    <li><a href="register.php" class="btn-nav">Register</a></li>
    <li><a href="basket.html">🛒</a></li>
  </ul>
</nav>

<main>
<div style="min-height:70vh;display:flex;align-items:center;padding:2rem 1rem">
  <div class="form-wrap" style="max-width:480px">
    <h2 class="form-title">Create account</h2>
    <p class="form-sub">Join GLH as a shopper or register your farm.</p>

    <?php if ($errors): ?>
    <div class="alert alert-err">
      <?php foreach ($errors as $e): ?><div>• <?= htmlspecialchars($e) ?></div><?php endforeach; ?>
    </div>
    <?php endif; ?>

    <form method="post">
      <!-- Account type -->
      <div class="form-group">
        <label>I am a…</label>
        <div style="display:flex;gap:.6rem;margin-top:.3rem">
          <label style="flex:1;padding:.6rem .9rem;border:1.5px solid var(--border);border-radius:7px;cursor:pointer;display:flex;align-items:center;gap:.5rem;background:var(--cream)">
            <input type="radio" name="role" value="customer" <?= $role !== 'producer' ? 'checked' : '' ?> onchange="toggleFarm(this)">
            🛒 Shopper
          </label>
          <label style="flex:1;padding:.6rem .9rem;border:1.5px solid var(--border);border-radius:7px;cursor:pointer;display:flex;align-items:center;gap:.5rem;background:var(--cream)">
            <input type="radio" name="role" value="producer" <?= $role === 'producer' ? 'checked' : '' ?> onchange="toggleFarm(this)">
            🌿 Producer
          </label>
        </div>
      </div>

      <div class="form-group">
        <label>Full name</label>
        <input type="text" name="name" placeholder="Jane Smith" value="<?= htmlspecialchars($_POST['name'] ?? '') ?>" required>
      </div>
      <div class="form-group">
        <label>Email address</label>
        <input type="email" name="email" placeholder="you@example.com" value="<?= htmlspecialchars($_POST['email'] ?? '') ?>" required>
      </div>
      <div class="form-row">
        <div class="form-group">
          <label>Password</label>
          <input type="password" name="password" placeholder="Min 6 chars" required>
        </div>
        <div class="form-group">
          <label>Confirm</label>
          <input type="password" name="confirm" placeholder="Repeat" required>
        </div>
      </div>

      <div id="farm-field" style="<?= $role === 'producer' ? '' : 'display:none' ?>">
        <div class="form-group">
          <label>Farm / Business name</label>
          <input type="text" name="farm" placeholder="e.g. Green Fields Farm" value="<?= htmlspecialchars($_POST['farm'] ?? '') ?>">
        </div>
      </div>

      <button type="submit" class="btn btn-green btn-full" style="margin-top:.5rem">Create Account</button>
    </form>

    <p class="form-link">Already registered? <a href="login.php">Log in here</a></p>
  </div>
</div>
</main>

<footer>
  <div class="footer-inner">
    <div><a href="index.html" class="footer-logo">GLH</a></div>
    <div class="footer-col">
      <h4>Navigate</h4>
      <a href="index.html">Home</a><a href="shop.html">Shop</a>
    </div>
    <div class="footer-col">
      <h4>Account</h4>
      <a href="login.php">Log In</a>
    </div>
  </div>
  <div class="footer-bottom">&copy; 2025 GLH – Global Local Harvest.</div>
</footer>

<script src="app.js"></script>
<script>
function toggleFarm(el) {
  document.getElementById('farm-field').style.display = el.value === 'producer' ? 'block' : 'none';
}
</script>
</body>
</html>
 

bottom of page