Files
Documents---Re/CONTEXT.md
2026-06-02 18:48:14 +04:00

547 lines
24 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Basic Web Development Series — Project Context
> Drop this file into your project folder and tell Claude Code:
> **"Read CONTEXT.md and continue the project."**
---
## What This Project Is
A complete programming education product catalogue being built to sell on **Gumroad** and **Etsy**. It covers HTML, CSS, and JavaScript across three learning tiers: reference notes, beginner micro-exercises, and intermediate exercises — each with matching answer sheets. Two strategy documents accompany the catalogue.
All documents are Word (.docx) files generated using **Python + python-docx**. The Node.js `docx` library was tried first but produced files Word couldn't open. python-docx 1.2.0 is confirmed working and must be used for all future documents.
---
## Project Folder Structure
Place files like this inside `C:\projects\Docs Re\`:
```
C:\projects\Docs Re\
├── CONTEXT.md ← this file
├── scripts\
│ ├── dochelper.py ← shared helper library (all generators import this)
│ ├── gen_notes.py ← generates 3 fundamentals reference notes
│ ├── gen_strategy.py ← generates 2 strategy documents
│ ├── gen_exercises.py ← generates 6 intermediate exercise docs
│ ├── gen_beginner.py ← generates 6 beginner exercise docs
│ ├── gen_micro_images.py ← generates 6 PIL preview images for HTML beginner exercises
│ └── gen_images.py ← generates 3 PIL preview images for HTML intermediate exercises
├── images\
│ ├── bex1.png through bex6.png ← HTML beginner exercise browser-window previews
│ └── html_ex1_preview.png ← HTML intermediate exercise previews
│ html_ex2_preview.png
│ html_ex3_preview.png
└── output\
├── HTML_Fundamentals.docx
├── CSS_Fundamentals.docx
├── JavaScript_Fundamentals.docx
├── HTML_Beginner_Exercises.docx
├── HTML_Beginner_Answer_Sheet.docx
├── CSS_Beginner_Exercises.docx
├── CSS_Beginner_Answer_Sheet.docx
├── JavaScript_Beginner_Exercises.docx
├── JavaScript_Beginner_Answer_Sheet.docx
├── HTML_Exercises.docx
├── HTML_Answer_Sheet.docx
├── CSS_Exercises.docx
├── CSS_Answer_Sheet.docx
├── JavaScript_Exercises.docx
├── JavaScript_Answer_Sheet.docx
├── Monetising_Your_Programming_Knowledge.docx
└── Gumroad_Sales_Strategy.docx
```
> **Note:** Update the output paths at the top of each generator script to match wherever you want files saved on your machine.
---
## All 17 Completed Documents
### Tier 1 — Reference Notes (3 docs)
| File | Accent Colour | Sections |
|------|--------------|----------|
| HTML_Fundamentals.docx | Orange `#E44D26` | What is HTML, Tags & Elements, Lists, Tables, Forms, Semantic HTML, Attributes, Best Practices, Cheat Sheet |
| CSS_Fundamentals.docx | Blue `#264DE4` | What is CSS, Selectors, Box Model, Typography & Colour, Flexbox, CSS Grid, Positioning, Media Queries, Variables & Animations, Cheat Sheet |
| JavaScript_Fundamentals.docx | Yellow `#B8A800` | What is JS, Variables & Data Types, Operators, Control Flow, Loops, Functions, Arrays, Objects, DOM Manipulation, Fetch API, Cheat Sheet |
### Tier 2 — Beginner Micro-Exercises (6 docs)
Each language has an exercises doc (6 exercises × 5 pts = 30 pts) and a matching green answer sheet.
| Language | Exercises Cover | Difficulty Spread |
|----------|----------------|-------------------|
| HTML | Headings & Paragraphs, Images, Lists, Tables, Hyperlinks, Semantic Layout | 3 × First Steps / 3 × Getting There |
| CSS | Colours & Fonts, Box Model, Backgrounds & Links, Flexbox Centring, Hover & Transitions, CSS Grid | 3 × First Steps / 3 × Getting There |
| JavaScript | Variables & console.log, if/else, Arrays & for Loop, Functions, DOM Manipulation, Objects | 3 × First Steps / 3 × Getting There |
HTML beginner exercises include real browser-window preview images (generated by PIL). CSS exercises use inline text preview boxes. JS exercises show expected Console output in green-on-dark code blocks.
### Tier 3 — Intermediate Exercises (6 docs)
Each language has 3 exercises worth 10 pts each = 30 pts total, with a matching answer sheet.
| Language | Exercises |
|----------|-----------|
| HTML | Personal Bio Page, Recipe Page with Table, Contact Form |
| CSS | Blog Post Card Styling, Flexbox Navigation Bar, Responsive CSS Grid |
| JavaScript | Grade Calculator (functions & conditionals), DOM Array Builder, Interactive Quiz App |
HTML intermediate exercises include real PIL preview images.
### Strategy Documents (2 docs)
| File | Contents |
|------|----------|
| Monetising_Your_Programming_Knowledge.docx | Online courses, tutoring, YouTube/newsletter, selling digital docs, corporate training, recommended starting path, strategy comparison table |
| Gumroad_Sales_Strategy.docx | Full pricing table, bundle structure, Gumroad setup steps, Etsy guidance, product description templates, 8-week launch plan |
---
## Pricing Strategy (Finalised)
### Individual Products
| Product | Price |
|---------|-------|
| Fundamentals notes (each) | £7.00 |
| Beginner exercises + answers (per language) | £5.00 |
| Intermediate exercises + answers (per language) | £8.00 |
| Monetising guide | Free lead magnet or £4.00 |
### Bundles
| Bundle | Includes | Price |
|--------|----------|-------|
| Complete HTML Pack | All 5 HTML docs | £22.00 |
| Complete CSS Pack | All 5 CSS docs | £22.00 |
| Complete JavaScript Pack | All 5 JS docs | £22.00 |
| Notes Bundle | All 3 fundamentals guides | £16.00 |
| Beginner Exercises Bundle | All 6 beginner docs (3 languages) | £18.00 |
| Intermediate Exercises Bundle | All 6 intermediate docs (3 languages) | £20.00 |
| **Complete Series** | **All 16 teaching docs** | **£45.00** |
> After the first 2030 reviews, raise prices 2030%. Early buyers got a founder's discount; this is standard and well-accepted on Gumroad.
---
## Design Decisions (Important — Keep These Consistent)
### Brand Colours
- **HTML** → Orange `#E44D26`
- **CSS** → Blue `#264DE4`
- **JavaScript** → Yellow `#B8A800`
- **Answer sheets** → Green `#1A7A3C` (all languages)
- **Strategy docs** → Teal `#2E86AB`
### Document Design Rules
- Font: **Arial** throughout (body, headings, tables)
- Code blocks: dark background `#1E1E1E`, monospace `Courier New`
- HTML code → amber `#F8C555`
- CSS code → blue `#9CDCFE`
- JavaScript code → yellow `#F0DB4F`
- Console output → green `#98FB98` on `#2D2D2D`
- Exercise badges: 4-column table (title | section ref | time | score)
- Answer headers: full-width green banner with tick mark
- Info boxes: 2-column table (coloured label | tinted text area)
- Reference tables: coloured header row, alternating white/`#F8F8F8` rows
### Scoring
- Beginner exercises: 5 pts each × 6 = 30 pts per language
- Intermediate exercises: 10 pts each × 3 = 30 pts per language
---
## Technical Setup
### Requirements
```
python-docx==1.2.0 pip install python-docx
Pillow pip install Pillow
```
> **Do NOT use the Node.js `docx` library** (v9.6.1 was tried — it produces structurally valid XML but Word rejects the files on open).
### How to Run
```bash
# From your project folder, run scripts in this order:
python scripts/gen_micro_images.py # generates bex1-6.png
python scripts/gen_images.py # generates html_ex1-3_preview.png
python scripts/gen_notes.py # HTML/CSS/JS Fundamentals
python scripts/gen_strategy.py # Monetising guide + Gumroad Strategy
python scripts/gen_exercises.py # 6 intermediate exercise docs
python scripts/gen_beginner.py # 6 beginner exercise docs
```
### Output Path Variable
Each generator script has `OUT = "/mnt/user-data/outputs"` near the top. Change this to your local output folder, e.g.:
```python
OUT = r"C:\projects\Docs Re\output"
```
### Validating Files
Run this to confirm all generated files are Word-compatible:
```python
import zipfile, xml.etree.ElementTree as ET, os
folder = r"C:\projects\Docs Re\output"
for f in sorted(os.listdir(folder)):
if f.endswith('.docx'):
path = os.path.join(folder, f)
try:
with zipfile.ZipFile(path) as z:
ET.fromstring(z.read('word/document.xml'))
print(f"OK {f}")
except Exception as e:
print(f"FAIL {f} -> {e}")
```
---
## Shared Helper Library (dochelper.py)
This file must exist before any generator runs. All generators do `import dochelper` at the top.
```python
"""
Shared helpers for generating Word documents with python-docx.
Produces clean, Word-compatible .docx files.
"""
from docx import Document
from docx.shared import Pt, RGBColor, Inches, Cm, Emu
from docx.enum.text import WD_ALIGN_PARAGRAPH
from docx.enum.table import WD_TABLE_ALIGNMENT, WD_ALIGN_VERTICAL
from docx.oxml.ns import qn
from docx.oxml import OxmlElement
import copy
# ── Colour palette ─────────────────────────────────────────────────────────
def rgb(hex6):
h = hex6.lstrip('#')
return RGBColor(int(h[0:2],16), int(h[2:4],16), int(h[4:6],16))
WHITE = rgb("FFFFFF")
BLACK = rgb("1A1A2E")
GRAY = rgb("666666")
LGRAY = rgb("F5F5F7")
DGRAY = rgb("333333")
ORANGE = rgb("E44D26")
ORANGE_L = rgb("FDF0EC")
BLUE = rgb("264DE4")
BLUE_L = rgb("EEF2FD")
YELLOW = rgb("B8A800")
YELLOW_L = rgb("FFFCE0")
GREEN = rgb("1A7A3C")
GREEN_L = rgb("E8F8EE")
# ── Document setup ──────────────────────────────────────────────────────────
def new_doc():
doc = Document()
for section in doc.sections:
section.top_margin = Cm(2.5)
section.bottom_margin = Cm(2.5)
section.left_margin = Cm(2.5)
section.right_margin = Cm(2.5)
for p in doc.paragraphs:
p._element.getparent().remove(p._element)
return doc
# ── Paragraph helpers ───────────────────────────────────────────────────────
def add_para(doc_or_cell, text="", bold=False, italic=False, size=11,
color=None, align=WD_ALIGN_PARAGRAPH.LEFT,
space_before=0, space_after=6, font_name="Arial"):
if hasattr(doc_or_cell, 'add_paragraph'):
p = doc_or_cell.add_paragraph()
else:
p = doc_or_cell.paragraphs[0] if doc_or_cell.paragraphs else doc_or_cell.add_paragraph()
p.clear()
p.alignment = align
pf = p.paragraph_format
pf.space_before = Pt(space_before)
pf.space_after = Pt(space_after)
if text:
run = p.add_run(text)
run.bold = bold; run.italic = italic
run.font.name = font_name; run.font.size = Pt(size)
run.font.color.rgb = color if color else BLACK
return p
def add_heading(doc, text, level=1, color=None, size=None, border_color=None,
space_before=14, space_after=4):
sizes = {1: 18, 2: 14, 3: 12}
p = doc.add_paragraph()
p.alignment = WD_ALIGN_PARAGRAPH.LEFT
p.paragraph_format.space_before = Pt(space_before)
p.paragraph_format.space_after = Pt(space_after)
run = p.add_run(text)
run.bold = True; run.font.name = "Arial"
run.font.size = Pt(size or sizes.get(level, 11))
run.font.color.rgb = color or BLACK
if border_color:
set_para_border(p, bottom=border_color)
return p
def add_code_block(doc, lines, bg="1E1E1E", fg="F0DB4F", left_bar=None):
for line in lines:
p = doc.add_paragraph()
p.paragraph_format.space_before = Pt(0)
p.paragraph_format.space_after = Pt(0)
p.paragraph_format.left_indent = Cm(0.5)
set_para_shading(p, bg)
if left_bar:
set_para_border(p, left=left_bar)
run = p.add_run(line if line else " ")
run.font.name = "Courier New"; run.font.size = Pt(9.5)
run.font.color.rgb = rgb(fg)
sp = doc.add_paragraph(" ")
sp.paragraph_format.space_before = Pt(0)
sp.paragraph_format.space_after = Pt(4)
def add_bullet(doc, text, size=11, color=None):
p = doc.add_paragraph(style='List Bullet')
p.paragraph_format.space_before = Pt(2)
p.paragraph_format.space_after = Pt(2)
run = p.add_run(text)
run.font.name = "Arial"; run.font.size = Pt(size)
run.font.color.rgb = color or BLACK
return p
def add_numbered(doc, text, size=11, color=None):
p = doc.add_paragraph(style='List Number')
p.paragraph_format.space_before = Pt(2)
p.paragraph_format.space_after = Pt(2)
run = p.add_run(text)
run.font.name = "Arial"; run.font.size = Pt(size)
run.font.color.rgb = color or BLACK
return p
def add_checkbox(doc, text):
p = doc.add_paragraph(style='List Bullet')
p.paragraph_format.space_before = Pt(2)
p.paragraph_format.space_after = Pt(2)
run = p.add_run("☐ " + text)
run.font.name = "Arial"; run.font.size = Pt(10.5)
run.font.color.rgb = BLACK
return p
def add_tick(doc, text):
p = doc.add_paragraph(style='List Bullet')
p.paragraph_format.space_before = Pt(2)
p.paragraph_format.space_after = Pt(2)
run = p.add_run("✓ " + text)
run.font.name = "Arial"; run.font.size = Pt(10.5)
run.font.color.rgb = GREEN
return p
def add_spacer(doc, pts=8):
p = doc.add_paragraph(" ")
p.paragraph_format.space_before = Pt(0)
p.paragraph_format.space_after = Pt(pts)
for run in p.runs:
run.font.size = Pt(2)
def add_page_break(doc):
doc.add_page_break()
# ── Table helpers ───────────────────────────────────────────────────────────
def cell_text(cell, text, bold=False, italic=False, size=10, color=None,
align=WD_ALIGN_PARAGRAPH.LEFT, bg=None, font="Arial"):
cell.text = ""
p = cell.paragraphs[0]
p.alignment = align
p.paragraph_format.space_before = Pt(3)
p.paragraph_format.space_after = Pt(3)
run = p.add_run(text)
run.bold = bold; run.italic = italic
run.font.name = font; run.font.size = Pt(size)
run.font.color.rgb = color or BLACK
if bg:
set_cell_shading(cell, bg)
return cell
def set_cell_shading(cell, hex_color):
tc = cell._tc; tcPr = tc.get_or_add_tcPr()
shd = OxmlElement('w:shd')
shd.set(qn('w:val'), 'clear'); shd.set(qn('w:color'), 'auto')
shd.set(qn('w:fill'), hex_color.lstrip('#'))
tcPr.append(shd)
def set_cell_margins(cell, top=60, bottom=60, left=100, right=100):
tc = cell._tc; tcPr = tc.get_or_add_tcPr()
tcMar = OxmlElement('w:tcMar')
for side, val in [('top',top),('bottom',bottom),('left',left),('right',right)]:
el = OxmlElement(f'w:{side}')
el.set(qn('w:w'), str(val)); el.set(qn('w:type'), 'dxa')
tcMar.append(el)
tcPr.append(tcMar)
# ── XML styling helpers ─────────────────────────────────────────────────────
def set_para_shading(para, hex_color):
pPr = para._p.get_or_add_pPr()
shd = OxmlElement('w:shd')
shd.set(qn('w:val'), 'clear'); shd.set(qn('w:color'), 'auto')
shd.set(qn('w:fill'), hex_color.lstrip('#'))
pPr.append(shd)
def set_para_border(para, bottom=None, left=None, top=None):
pPr = para._p.get_or_add_pPr()
pBdr = OxmlElement('w:pBdr')
for side, color in [('bottom',bottom),('left',left),('top',top)]:
if color:
el = OxmlElement(f'w:{side}')
el.set(qn('w:val'), 'single')
el.set(qn('w:sz'), '6' if side in ('bottom','top') else '18')
el.set(qn('w:space'), '4')
el.set(qn('w:color'), color.lstrip('#') if isinstance(color,str)
else '{:02X}{:02X}{:02X}'.format(*color))
pBdr.append(el)
pPr.append(pBdr)
# ── Compound elements ───────────────────────────────────────────────────────
def add_info_box(doc, label, text, bg_hex, accent_hex, label_color_hex="FFFFFF"):
table = doc.add_table(rows=1, cols=2)
table.style = 'Table Grid'
lc = table.rows[0].cells[0]
lc.width = Cm(1.5)
set_cell_shading(lc, accent_hex); set_cell_margins(lc)
p = lc.paragraphs[0]; p.alignment = WD_ALIGN_PARAGRAPH.CENTER
p.paragraph_format.space_before = Pt(4); p.paragraph_format.space_after = Pt(4)
run = p.add_run(label); run.bold = True; run.font.name = "Arial"
run.font.size = Pt(9); run.font.color.rgb = rgb(label_color_hex)
tc = table.rows[0].cells[1]
set_cell_shading(tc, bg_hex); set_cell_margins(tc, left=120)
p2 = tc.paragraphs[0]
p2.paragraph_format.space_before = Pt(4); p2.paragraph_format.space_after = Pt(4)
run2 = p2.add_run(text); run2.font.name = "Arial"; run2.font.size = Pt(10)
run2.font.color.rgb = BLACK
add_spacer(doc, 6)
return table
def add_cover(doc, title_top, title_main, title_sub, subtitle, part_note, accent_hex):
add_spacer(doc, 40)
if title_top:
add_para(doc, title_top, bold=True, size=14, color=GRAY,
align=WD_ALIGN_PARAGRAPH.CENTER, space_after=2)
add_para(doc, title_main, bold=True, size=36, color=rgb(accent_hex),
align=WD_ALIGN_PARAGRAPH.CENTER, space_after=4)
if title_sub:
add_para(doc, title_sub, bold=True, size=20, color=BLACK,
align=WD_ALIGN_PARAGRAPH.CENTER, space_after=6)
add_para(doc, subtitle, size=12, color=GRAY,
align=WD_ALIGN_PARAGRAPH.CENTER, space_after=4)
if part_note:
p = add_para(doc, part_note, size=10, italic=True, color=GRAY,
align=WD_ALIGN_PARAGRAPH.CENTER, space_after=8)
set_para_border(p, bottom=accent_hex)
add_spacer(doc, 20)
def add_answer_header(doc, num, title, accent_hex="1A7A3C"):
table = doc.add_table(rows=1, cols=1)
table.style = 'Table Grid'
cell = table.rows[0].cells[0]
set_cell_shading(cell, accent_hex); set_cell_margins(cell, top=80, bottom=80, left=150)
p = cell.paragraphs[0]
r1 = p.add_run(f"✓ Answer — Exercise {num}: ")
r1.bold = True; r1.font.name = "Arial"; r1.font.size = Pt(13); r1.font.color.rgb = WHITE
r2 = p.add_run(title)
r2.font.name = "Arial"; r2.font.size = Pt(11); r2.font.color.rgb = rgb("C8F0D4")
add_spacer(doc, 6)
def add_exercise_badge(doc, num, title, section_ref, difficulty, minutes, accent_hex, score_denom=5):
table = doc.add_table(rows=1, cols=4)
table.style = 'Table Grid'
c0 = table.rows[0].cells[0]; c0.width = Cm(8)
set_cell_shading(c0, accent_hex); set_cell_margins(c0, top=80, bottom=80, left=150)
p = c0.paragraphs[0]
r1 = p.add_run(f"Ex {num} "); r1.bold=True; r1.font.name="Arial"
r1.font.size=Pt(13); r1.font.color.rgb=WHITE
r2 = p.add_run(title); r2.font.name="Arial"; r2.font.size=Pt(11); r2.font.color.rgb=rgb("E0E0E0")
c1 = table.rows[0].cells[1]; set_cell_shading(c1, "F5F5F7"); set_cell_margins(c1)
p1a = c1.paragraphs[0]; p1a.alignment = WD_ALIGN_PARAGRAPH.CENTER
r = p1a.add_run(f"After Section {section_ref}"); r.font.name="Arial"; r.font.size=Pt(9); r.font.color.rgb=GRAY
p1b = c1.add_paragraph(); p1b.alignment = WD_ALIGN_PARAGRAPH.CENTER
r2 = p1b.add_run(difficulty); r2.bold=True; r2.font.name="Arial"; r2.font.size=Pt(9); r2.font.color.rgb=rgb(accent_hex)
c2 = table.rows[0].cells[2]; set_cell_shading(c2, "F5F5F7"); set_cell_margins(c2)
p2a = c2.paragraphs[0]; p2a.alignment = WD_ALIGN_PARAGRAPH.CENTER
p2b = c2.add_paragraph(); p2b.alignment = WD_ALIGN_PARAGRAPH.CENTER
r = p2b.add_run(f"{minutes} min"); r.bold=True; r.font.name="Arial"; r.font.size=Pt(9); r.font.color.rgb=BLACK
c3 = table.rows[0].cells[3]; set_cell_shading(c3, "F5F5F7"); set_cell_margins(c3)
p3a = c3.paragraphs[0]; p3a.alignment = WD_ALIGN_PARAGRAPH.CENTER
r = p3a.add_run("Score"); r.font.name="Arial"; r.font.size=Pt(9); r.font.color.rgb=GRAY
p3b = c3.add_paragraph(); p3b.alignment = WD_ALIGN_PARAGRAPH.CENTER
r = p3b.add_run(f"__ / {score_denom}"); r.bold=True; r.font.name="Arial"; r.font.size=Pt(10); r.font.color.rgb=BLACK
add_spacer(doc, 6)
def add_ref_table(doc, headers, rows, accent_hex, col_widths_cm=None):
table = doc.add_table(rows=1+len(rows), cols=len(headers))
table.style = 'Table Grid'
if col_widths_cm:
for row in table.rows:
for j, cell in enumerate(row.cells):
if j < len(col_widths_cm):
cell.width = Cm(col_widths_cm[j])
for j, h in enumerate(headers):
c = table.rows[0].cells[j]
set_cell_shading(c, accent_hex); set_cell_margins(c)
cell_text(c, h, bold=True, size=10, color=WHITE)
for i, row in enumerate(rows):
bg = "FFFFFF" if i % 2 == 0 else "F8F8F8"
for j, val in enumerate(row):
c = table.rows[i+1].cells[j]
set_cell_shading(c, bg); set_cell_margins(c)
font = "Courier New" if j < 2 else "Arial"
clr = rgb("C0392B") if j == 0 else (GRAY if j == 1 else BLACK)
cell_text(c, val, size=9, color=clr, font=font)
add_spacer(doc, 8)
print("dochelper loaded OK")
```
---
## Ideas for What to Build Next
These were discussed but not yet created. Claude Code can pick any of these up:
### Additional Documents
- **Advanced Exercise Tier** — 3 more challenging exercises per language (e.g. building a full responsive landing page in HTML/CSS, a full CRUD app in JS). Worth £1215 each.
- **jQuery Basics** — a notes + exercise pack for the legacy library still widely used in older codebases
- **Git & GitHub Guide** — version control reference doc, highly searched on Etsy
- **CSS Animations Deep Dive** — keyframes, transitions, scroll animations
- **JavaScript Interview Prep** — Q&A format covering closures, hoisting, event loop, promises
### Product Improvements
- Add a **table of contents** page to each fundamentals notes doc
- Add **page numbers** in the footer of each document
- Create **PDF versions** of all documents (some buyers prefer PDFs for printing)
- Add a **"Common Mistakes"** callout box to every exercise (not just answer sheets)
### Marketing Assets
- A **free sample PDF** — 2-page teaser combining one page from each fundamentals guide
- **Gumroad cover images** — 1280×720px branded thumbnails for each product listing
- A **product comparison table** one-pager showing all bundles side by side
### Platform Expansion
- Reformat notes as **Notion templates** (sold separately on Gumroad)
- Create a **Teachable or Udemy course outline** based on the existing document structure
- Package documents as a **Payhip bundle** for a second sales channel
---
## Key Decisions Made (Do Not Change Without Reason)
| Decision | What Was Decided |
|----------|-----------------|
| File format | Word (.docx) via python-docx 1.2.0 — NOT Node.js docx library |
| Image generation | PIL (Pillow) for browser-window preview images |
| Fonts | Arial body, Courier New for all code |
| Code block style | Dark background #1E1E1E, language-specific fg colours |
| Answer sheet colour | Green #1A7A3C for all languages |
| Scoring | Beginner: 5 pts × 6 = 30 | Intermediate: 10 pts × 3 = 30 |
| Pricing anchor | Complete Series £45 is the hero product |
| Lead magnet | Monetising guide offered free to build email list |
| Launch platform | Gumroad first, then Etsy in parallel |
---
*This context file was generated from a claude.ai chat session. Last updated: June 2026.*