Skip to content
Aabha AI Academy
Skip to reading

Statistics

Build Guide

#!/usr/bin/env python3
"""Build three offline reading pages from the editable Markdown sources."""
from pathlib import Path
import html,re
import markdown
ROOT=Path(__file__).resolve().parents[1]
CSS='''
:root{--ink:#183548;--muted:#52616b;--accent:#075f86;--line:#d1dde3;--paper:#fff;--soft:#edf4f7}*{box-sizing:border-box}html{scroll-padding-top:24px}body{margin:0;background:#f2f6f8;color:var(--ink);font:17px/1.75 system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif}a{color:var(--accent);text-underline-offset:3px}a:focus-visible,summary:focus-visible,.table-wrap:focus-visible{outline:3px solid #9d4d00;outline-offset:4px}.skip{position:absolute;top:-100px;left:20px;background:white;padding:12px;z-index:10}.skip:focus{top:12px}.hero{background:#183548;color:#fff;padding:48px max(24px,calc((100% - 1180px)/2));border-bottom:6px solid #75c4b2}.hero h1{font-size:clamp(30px,4vw,48px);line-height:1.15;max-width:900px;margin:16px 0}.hero p{max-width:850px;color:#e7f1f5}.hero a{color:#fff}.eyebrow{font-size:13px;text-transform:uppercase;letter-spacing:.1em;font-weight:650}.layout{max-width:1220px;margin:auto;display:grid;grid-template-columns:240px minmax(0,1fr);gap:28px;padding:30px 22px 60px}nav{position:sticky;top:20px;align-self:start;max-height:95vh;overflow:auto;font-size:14px;line-height:1.5;padding-right:6px}nav a{display:block;border-bottom:1px solid var(--line);padding:8px 5px;text-decoration:none}nav summary{font-weight:700;cursor:pointer;padding:10px 0}nav strong{display:block;margin:20px 0 8px}main{min-width:0}section{background:#fff;border:1px solid var(--line);border-radius:10px;padding:34px 40px;margin-bottom:26px}h2,h3,h4{line-height:1.3;scroll-margin-top:22px}h2{font-size:30px;margin:0 0 24px}h3{font-size:23px;margin:34px 0 14px}h4{font-size:19px;margin:26px 0 10px}p{margin:15px 0 20px}li{margin:7px 0}code{font-family:ui-monospace,SFMono-Regular,Consolas,monospace;font-size:.86em;overflow-wrap:anywhere}pre{background:var(--soft);border:1px solid var(--line);border-radius:5px;padding:18px;overflow:auto;line-height:1.65;font-size:14px}pre code{font-size:inherit;overflow-wrap:normal}.table-wrap{overflow:auto;max-width:100%;margin:25px 0}table{border-collapse:collapse;width:100%;font-size:14px;line-height:1.5}th,td{border:1px solid var(--line);padding:11px 12px;text-align:left;vertical-align:top}th{background:var(--soft)}tr:nth-child(even){background:#f8fafb}img{display:block;width:100%;height:auto;margin:26px auto;border:1px solid var(--line);border-radius:6px}.tag{font-size:13px;font-weight:700;letter-spacing:.05em;text-transform:uppercase;color:#066653}.jump{border-top:1px solid var(--line);padding-top:18px;margin-top:28px;display:flex;gap:18px;flex-wrap:wrap;font-size:14px}footer{max-width:1180px;margin:auto;padding:0 24px 40px;color:var(--muted);font-size:14px}.note{padding:15px;background:var(--soft);border-left:4px solid var(--accent)}
@media(max-width:920px){.layout{display:block;padding:20px 14px}nav{position:static;max-height:none;background:white;border:1px solid var(--line);border-radius:8px;padding:10px 18px;margin-bottom:22px}section{padding:28px 25px}.hero{padding:34px 24px}}
@media(max-width:480px){body{font-size:16px;line-height:1.7}section{padding:24px 18px}h2{font-size:27px}h3{font-size:22px}table{min-width:500px}pre{font-size:12.5px}img{border-radius:0}}
@media print{body{background:white;color:black;font-size:11pt}.hero{background:white;color:black;padding:0;border-bottom:1px solid black}.hero p,.hero a{color:black}.hero h1{font-size:26pt}.layout{display:block;padding:0}nav,.skip,.jump{display:none}section{padding:0;border:0;break-before:page}section:first-child{break-before:auto}h2,h3,h4{break-after:avoid}img{break-inside:avoid}pre{white-space:pre-wrap;overflow-wrap:anywhere;font-size:8pt}.table-wrap{overflow:visible}table{font-size:9pt;min-width:0}a{color:black}footer{padding:15px 0}}
'''
(ROOT/'style.css').write_text(CSS)
def render(path,prefix):
    source=(ROOT/path).read_text().replace('../assets/','assets/')
    out=markdown.markdown(source,extensions=['tables','fenced_code','toc'])
    # Keep a single page-level h1 and make fragment IDs unique across source documents.
    out=re.sub(r'<(/?)h([1-5])\b',lambda m:f'<{m[1]}h{int(m[2])+1}',out)
    out=re.sub(r'id="([^"]+)"',lambda m:f'id="{prefix}-{m[1]}"',out)
    out=re.sub(r'href="#([^"]+)"',lambda m:f'href="#{prefix}-{m[1]}"',out)
    out=out.replace('<table>','<div class="table-wrap" role="region" aria-label="Scrollable data table" tabindex="0"><table>').replace('</table>','</table></div>')
    return out
lessons=sorted((ROOT/'lessons').glob('*.md'))
base_links='<a href="index.html">Course and lessons</a><a href="practice.html">Practice and capstone</a><a href="solutions.html">Separate explained solutions</a>'
def section(id,path,extra=''):
    return f'<section id="{id}">{render(path,id)}{extra}</section>'
def write_page(filename,title,subtitle,nav,content):
    page='<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>'+html.escape(title)+' | Aabha AI Academy</title><link rel="stylesheet" href="style.css"></head><body><a class="skip" href="#main">Skip to content</a><header class="hero"><div class="eyebrow">Aabha AI Academy · Synthetic operational case study</div><h1>'+html.escape(title)+'</h1><p>'+subtitle+'</p><p><a href="index.html">Course</a> · <a href="practice.html">Practice</a> · <a href="solutions.html">Solutions after your attempt</a></p></header><div class="layout"><nav aria-label="Course navigation"><details open><summary>Contents</summary>'+base_links+nav+'</details></nav><main id="main">'+content+'</main></div><footer>Review edition 2026-10-14 · Original fictional data · Provisional, unpiloted timings. Offline reading guide; no embedded Python runner, learner tracking or automatic certification.</footer></body></html>'
    (ROOT/filename).write_text(page)
nav='<strong>Start here</strong><a href="#syllabus">Syllabus and prerequisites</a><a href="#setup">Practice setup</a><a href="#dictionary">Data dictionary and generating logic</a><strong>12 ordered lessons</strong>'
content=section('syllabus','SYLLABUS.md')+section('setup','SETUP.md')+section('dictionary','DATA_DICTIONARY.md')
for i,p in enumerate(lessons,1):
    title=p.read_text().splitlines()[0].lstrip('# ');nav+=f'<a href="#lesson-{i:02}">{html.escape(title)}</a>'
    extra=f'<div class="jump"><a href="practice.html#workbook-lesson-{i}">Attempt Lesson {i} exercises</a>'+(f'<a href="#lesson-{i+1:02}">Next lesson</a>' if i<12 else '<a href="practice.html#capstone">Capstone brief</a>')+'</div>'
    content+=section(f'lesson-{i:02}',str(p.relative_to(ROOT)),extra)
nav+='<strong>Use and review</strong><a href="#validation">Validation and acceptance checklist</a><a href="#sources">Primary references</a><a href="#instructors">Teaching guide</a>'
for id,file in [('validation','VALIDATION.md'),('sources','SOURCES.md'),('instructors','INSTRUCTOR_GUIDE.md')]:content+=section(id,file)
content+=section('files','FILES.md')
write_page('index.html','Statistics with Data Storytelling','Ask a question the data can answer, quantify a useful difference, and make a recommendation that carries its uncertainty.',nav,content)
nav='<strong>Work independently</strong><a href="#workbook">36 practice exercises</a><a href="#checkpoints">Three checkpoint assessments</a><a href="#capstone">Staged capstone and rubric</a>'
content=section('workbook','WORKBOOK.md')+section('checkpoints','ASSESSMENTS.md')+section('capstone','CAPSTONE.md')
write_page('practice.html','Practice and capstone','Show the counts, units and reasoning. Attempt the work before opening the separate answer key.',nav,content)
nav='<strong>Review after your attempt</strong><a href="#answers">Practice and checkpoint answers</a><a href="#reference">Reference capstone</a>'
content=section('answers','SOLUTIONS.md')+section('reference','CAPSTONE_REFERENCE.md')
write_page('solutions.html','Explained solutions','Compare your method, interpretation and limitations. A matching number is only part of a good answer.',nav,content)
print('Built index.html, practice.html and solutions.html from Markdown sources.')

Download this source file