Skip to content

About the studio

Growing Greens Courses is built for gardeners who want clear, science-first progress—without the noise.

We teach practical gardening with measurable outcomes: healthier soil, resilient plants, and confident decision-making. Our approach blends accessible explanations with real-world constraints—small spaces, tight schedules, and changing seasons.

Reading controls

Switch theme, enable Focus Reader Mode, and keep distractions low.

Learners served

0+

Lessons refined

0

Avg. course rating

0.0/5

Next live Q&A starts in
00: 00: 00

Our mission

Make gardening education accessible and reliable—so learners can build thriving green spaces with repeatable methods, not myths.

Science-first Practical Accessible

How we teach

  • Explain the “why” with simple models (soil, water, light, time).
  • Demonstrate a method with constraints (containers, balconies, microclimates).
  • Measure outcomes using checklists and seasonal milestones.
  • Iterate fast—small experiments, low risk, clear feedback.

Values

Clarity over complexity

We prefer simple, testable advice. If a method can’t be explained clearly, it’s not ready to teach.

Outcomes you can see

We design lessons around visible results: healthier leaves, steadier growth, improved soil texture, and predictable harvest windows.

Respect for your time

We keep workflows lean: the smallest set of actions that reliably move your garden forward.

Brand story

Growing Greens started as a tiny set of notes for friends who wanted healthier plants but were overwhelmed by conflicting advice. The work grew into a course system: a clear baseline, repeatable routines, and a way to debug problems without guesswork.

Interactive timeline

Use Arrow keys to move. Press Enter/Space to open. Press Esc to collapse.

We condensed gardening fundamentals into a single page: light, water, soil, and a weekly rhythm. It became the seed of our curriculum.
We split content into short modules: planting, nutrition, pest management, and seasonal strategy—each with a checklist and “what to measure.”
We redesigned lessons for scanability, added inclusive language, and built tighter summaries—then paired it with deeper reading options.
We improved feedback loops: short Q&A sessions, seasonal goal tracking, and faster updates based on learner outcomes.
Tip: You can tab into the timeline, then use / or /.

Contact

Have a question about course fit, accessibility needs, or your current setup? Send a note—we answer with concrete next steps.

Office hours

Mon–Fri, 10:00–18:00

Response time: under 24 hours

Send a message

'; mount.replaceChildren(fallback); const y = v('#f1y8d_year'); if(y) y.textContent = String(new Date().getFullYear()); } } function initTheme(){ const prefs = getPrefs(); const btn = v('#xk9h7_themeBtn'); applyTheme(prefs.theme || 'system'); const mq = window.matchMedia ? window.matchMedia('(prefers-color-scheme: dark)') : null; if(mq){ const handler = ()=>{ const p = getPrefs(); if((p.theme||'system')==='system') applyTheme('system'); }; if(mq.addEventListener) mq.addEventListener('change', handler); else if(mq.addListener) mq.addListener(handler); } if(btn){ btn.addEventListener('click', ()=>{ const p = getPrefs(); const current = p.theme || 'system'; const next = current === 'system' ? 'dark' : (current === 'dark' ? 'light' : 'system'); setPrefs({ theme: next }); applyTheme(next); toast(next === 'system' ? 'Theme: system' : `Theme: ${next}`); }); } } function initFocusReader(){ const prefs = getPrefs(); applyFocusReader(!!prefs.focusReader); const btn = v('#p2aql_focusBtn'); if(btn){ btn.addEventListener('click', ()=>{ const p = getPrefs(); const next = !p.focusReader; setPrefs({ focusReader: next }); applyFocusReader(next); toast(next ? 'Focus Reader Mode: on' : 'Focus Reader Mode: off'); }); } } function initCounters(){ const a = v('#k3t7p_countA'); const b = v('#r5v1h_countB'); const c = v('#q7e4z_countC'); const targets = { a: 18400, b: 146, c: 4.8 }; const start = performance.now(); const dur = 1200; function tick(t){ const p = clamp((t - start) / dur, 0, 1); const ease = 1 - Math.pow(1 - p, 3); if(a) a.textContent = String(Math.floor(targets.a * ease)); if(b) b.textContent = String(Math.floor(targets.b * ease)); if(c) c.textContent = (targets.c * ease).toFixed(1); if(p < 1) requestAnimationFrame(tick); } requestAnimationFrame(tick); } function initCountdown(){ const h = v('#c6j2n_cdH'); const m = v('#g4s8b_cdM'); const s = v('#u8d1f_cdS'); const now = Date.now(); const offsetMin = 47; const target = now + (offsetMin * 60 * 1000) + 12000; function pad2(n){ return String(n).padStart(2,'0'); } function upd(){ const left = Math.max(0, target - Date.now()); const sec = Math.floor(left/1000); const hh = Math.floor(sec/3600); const mm = Math.floor((sec%3600)/60); const ss = sec%60; if(h) h.textContent = pad2(hh); if(m) m.textContent = pad2(mm); if(s) s.textContent = pad2(ss); if(left <= 0){ clearInterval(upd._iv); toast('Live Q&A has started'); } } upd(); upd._iv = setInterval(upd, 1000); } function initModal(){ const overlay = v('#d5p8u_modalOverlay'); const panel = v('#z8a1n_modalPanel'); const title = v('#t3b6q_modalTitle'); const sub = v('#s7u1m_modalSub'); const body = v('#p6v2c_modalBody'); const close = v('#h2z9e_modalClose'); const ok = v('#x1c9m_modalOk'); let lastFocus = null; function open(opts){ if(!overlay || !panel || !title || !body) return; lastFocus = document.activeElement; title.textContent = opts.title || 'Info'; sub.textContent = opts.sub || ''; body.innerHTML = opts.html || ''; overlay.classList.remove('hidden'); overlay.classList.add('flex'); overlay.setAttribute('aria-hidden','false'); document.body.style.overflow = 'hidden'; setTimeout(()=>{ (close || ok || panel).focus?.(); }, 0); } function hide(){ if(!overlay) return; overlay.classList.add('hidden'); overlay.classList.remove('flex'); overlay.setAttribute('aria-hidden','true'); document.body.style.overflow = ''; if(lastFocus && lastFocus.focus) lastFocus.focus(); } function trap(e){ if(overlay.classList.contains('hidden')) return; if(e.key === 'Escape'){ e.preventDefault(); hide(); return; } if(e.key !== 'Tab') return; const focusables = vv('button,[href],input,select,textarea,[tabindex]:not([tabindex="-1"])', panel).filter(el=>!el.hasAttribute('disabled') && el.getAttribute('aria-hidden')!=='true'); if(!focusables.length) return; const first = focusables[0]; const last = focusables[focusables.length-1]; if(e.shiftKey && document.activeElement === first){ e.preventDefault(); last.focus(); } else if(!e.shiftKey && document.activeElement === last){ e.preventDefault(); first.focus(); } } if(close) close.addEventListener('click', hide); if(ok) ok.addEventListener('click', hide); if(overlay) overlay.addEventListener('mousedown', (e)=>{ if(e.target === overlay) hide(); }); document.addEventListener('keydown', trap); const mission = v('#w1m9c_openMission'); const story = v('#m4k2y_openStory'); if(mission){ mission.addEventListener('click', ()=>{ open({ title: 'Methodology: small loops, big confidence', sub: 'Our framework stays calm under real-life conditions.', html: `

1) Baseline — establish light exposure, watering rhythm, and soil structure. We avoid “magic fixes” and start with fundamentals.

2) One change at a time — we treat improvements like experiments: change one variable, observe for a week, log results.

3) Seasonal strategy — plan for temperature swings and day-length. Your calendar is part of your toolkit.

Focus tip: enable Focus Reader Mode to reduce visual density and improve reading comfort.

` }); }); } if(story){ story.addEventListener('click', ()=>{ open({ title: 'The longer story', sub: 'Why this brand exists—and what we refuse to compromise on.', html: `

We saw a pattern: people didn’t fail because they “couldn’t garden.” They failed because the advice they found was inconsistent, overly complicated, or built on assumptions that didn’t match their space.

Growing Greens Courses was designed as a calmer alternative: small lessons, clear measurements, and enough context to make confident choices—whether you’re growing herbs on a windowsill or managing raised beds.

We keep standards high: if a claim can’t be explained, tested, or responsibly caveated, we won’t teach it as a rule.

What you can expect

` }); }); } } function initTimeline(){ const details = vv('details[data-tl]'); if(!details.length) return; const summaries = details.map(d => d.querySelector('summary')).filter(Boolean); let idx = 0; function setExpanded(el, open){ if(open) el.setAttribute('open',''); else el.removeAttribute('open'); const sum = el.querySelector('summary'); if(sum) sum.setAttribute('aria-expanded', String(!!open)); } function syncButtons(){ const prev = v('#v9d0s_tlPrev'); const next = v('#b6r8e_tlNext'); if(prev) prev.disabled = idx <= 0; if(next) next.disabled = idx >= details.length - 1; } function focusAt(i){ idx = clamp(i, 0, details.length - 1); const sum = summaries[idx]; if(sum) sum.focus(); syncButtons(); } function collapseAll(exceptIndex=null){ details.forEach((d, i)=>{ const shouldOpen = (exceptIndex !== null && i === exceptIndex); setExpanded(d, shouldOpen); }); } details.forEach((d, i)=>{ const sum = d.querySelector('summary'); if(!sum) return; sum.addEventListener('click', ()=>{ idx = i; const willOpen = !d.hasAttribute('open'); collapseAll(willOpen ? i : null); syncButtons(); }); sum.addEventListener('keydown', (e)=>{ const k = e.key; if(k === 'ArrowDown' || k === 'ArrowRight'){ e.preventDefault(); focusAt(idx + 1); } else if(k === 'ArrowUp' || k === 'ArrowLeft'){ e.preventDefault(); focusAt(idx - 1); } else if(k === 'Home'){ e.preventDefault(); focusAt(0); } else if(k === 'End'){ e.preventDefault(); focusAt(details.length - 1); } else if(k === 'Enter' || k === ' '){ e.preventDefault(); const willOpen = !d.hasAttribute('open'); collapseAll(willOpen ? i : null); syncButtons(); }else if(k === 'Escape'){ e.preventDefault(); collapseAll(null); sum.setAttribute('aria-expanded','false'); syncButtons(); } }); d.addEventListener('toggle', ()=>{ const open = d.open; sum.setAttribute('aria-expanded', String(open)); if(open){ idx = i; details.forEach((other, j)=>{ if(j !== i) setExpanded(other, false); }); } syncButtons(); }); sum.setAttribute('aria-expanded', String(d.open)); }); const prev = v('#v9d0s_tlPrev'); const next = v('#b6r8e_tlNext'); if(prev) prev.addEventListener('click', ()=>focusAt(idx - 1)); if(next) next.addEventListener('click', ()=>focusAt(idx + 1)); collapseAll(0); focusAt(0); } function initCookieBanner(){ const banner = v('#kk3m8_cookieBanner'); const accept = v('#j2s7a_cookieAccept'); const reject = v('#f9k2c_cookieReject'); const close = v('#q0w2l_cookieClose'); const analytics = v('#y8n1v_analytics'); if(!banner || !accept || !reject || !close || !analytics) return; const c = getConsent(); if(c.decided){ analytics.checked = !!c.analytics; return; } banner.classList.remove('hidden'); function decide(allowAnalytics){ setConsent({ decided: true, analytics: !!allowAnalytics, ts: Date.now() }); banner.classList.add('hidden'); toast(allowAnalytics ? 'Preferences saved: analytics enabled' : 'Preferences saved: analytics disabled'); } accept.addEventListener('click', ()=>decide(analytics.checked)); reject.addEventListener('click', ()=>decide(false)); close.addEventListener('click', ()=>decide(false)); banner.addEventListener('keydown', (e)=>{ if(e.key === 'Escape'){ e.preventDefault(); decide(false); } }); } function initForm(){ const form = v('#h7q1x_contactForm'); if(!form) return; const name = v('#y2c5v_name'); const email = v('#e0s6k_email'); const msg = v('#z6l2r_msg'); const nErr = v('#t1n8p_nameErr'); const eErr = v('#a9p3d_emailErr'); const mErr = v('#s2w8q_msgErr'); const note = v('#l3e7x_formNote'); const btn = v('#g1h9a_sendBtn'); const emailRe = /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/i; function setErr(el, box, text){ if(!el || !box) return; if(text){ box.textContent = text; box.classList.remove('hidden'); el.setAttribute('aria-invalid','true'); }else{ box.textContent = ''; box.classList.add('hidden'); el.removeAttribute('aria-invalid'); } } function validate(){ let ok = true; const nv = (name?.value || '').trim(); const ev = (email?.value || '').trim(); const mv = (msg?.value || '').trim(); if(nv.length < 2){ ok=false; setErr(name,nErr,'Please enter at least 2 characters.'); } else setErr(name,nErr,''); if(!emailRe.test(ev)){ ok=false; setErr(email,eErr,'Please enter a valid email address.'); } else setErr(email,eErr,''); if(mv.length < 18){ ok=false; setErr(msg,mErr,'Please write at least 18 characters so we can help effectively.'); } else setErr(msg,mErr,''); return ok; } [name,email,msg].forEach(el=>{ if(!el) return; el.addEventListener('input', ()=>validate()); el.addEventListener('blur', ()=>validate()); }); form.addEventListener('submit', async (e)=>{ e.preventDefault(); if(note) note.textContent = ''; if(!validate()){ toast('Please check the form fields'); return; } if(btn) btn.disabled = true; const payload = { name: (name.value||'').trim(), email: (email.value||'').trim(), message: (msg.value||'').trim(), page: 'about.html', ts: new Date().toISOString() }; await new Promise(r=>setTimeout(r, 650)); if(btn) btn.disabled = false; form.reset(); validate(); if(note) note.textContent = 'Message queued. We’ll reply within 24 hours.'; toast('Message sent'); try{ const c = getConsent(); if(c.analytics){ const key = 'ggc_analytics_events_v1'; const prev = store.get(key, []); const next = Array.isArray(prev) ? prev : []; next.push({ type: 'contact_submit', payload, at: Date.now() }); store.set(key, next.slice(-25)); } }catch(e){} }); } async function boot(){ await Promise.all([ mountComponent('./header.html', '#dd23l_headerMount'), mountComponent('./footer.html', '#ee0c2_footerMount') ]); initTheme(); initFocusReader(); initCounters(); initCountdown(); initModal(); initTimeline(); initCookieBanner(); initForm(); const y = v('#f1y8d_year'); if(y) y.textContent = String(new Date().getFullYear()); const prefs = getPrefs(); applyTheme(prefs.theme || 'system'); applyFocusReader(!!prefs.focusReader); } boot(); })();