✨ Nine Year Plan β€” Source Code

File structure and key code explained

πŸ“ File Structure

projects/nine-year-plan/
β”œβ”€β”€ index.html          ← Main app (all content embedded)
β”œβ”€β”€ css/
β”‚   └── style.css       ← All styles, variables, animations, responsive
β”œβ”€β”€ js/
β”‚   └── app.js          ← Scroll nav, fade-in observer, animated counters
└── knowledge/
    β”œβ”€β”€ the-plan.md
    β”œβ”€β”€ core-activities.md
    β”œβ”€β”€ framework.md
    β”œβ”€β”€ institutions.md
    β”œβ”€β”€ social-action.md
    β”œβ”€β”€ messages.md
    └── youth.md
Design principle: All visible content is embedded directly in index.html. The knowledge/ folder contains Markdown source documents used to author the HTML β€” they are not loaded at runtime.

πŸ”‘ Key Code: Animated Number Counters

Statistics animate from 0 to their target value when they scroll into view. Uses requestAnimationFrame with ease-out cubic easing for a smooth deceleration effect. Each counter fires once and then unobserves itself.

js/app.js β€” Animated counters
function formatNum(n) {
  if (n >= 1000000) return (n / 1000000).toFixed(1).replace('.0','') + 'M';
  if (n >= 1000)    return (n / 1000).toFixed(0) + ',000';
  return n.toLocaleString();
}

const statNums = document.querySelectorAll('.stat-num[data-target]');

const counterIO = new IntersectionObserver(entries => {
  entries.forEach(entry => {
    if (!entry.isIntersecting) return;
    const el     = entry.target;
    const target = parseInt(el.dataset.target, 10);
    const dur    = 1800;
    const start  = performance.now();

    function tick(now) {
      const p    = Math.min((now - start) / dur, 1);
      const ease = 1 - Math.pow(1 - p, 3); // ease-out cubic
      el.textContent = formatNum(Math.round(ease * target));
      if (p < 1) requestAnimationFrame(tick);
      else el.textContent = formatNum(target);
    }
    requestAnimationFrame(tick);
    counterIO.unobserve(el); // fire once only
  });
}, { threshold: 0.5 });

statNums.forEach(el => counterIO.observe(el));
How to use in HTML: Add data-target="5700000" to any element with class stat-num and it will animate automatically on scroll.

πŸ”‘ Key Code: Staggered Fade-in Animations

Cards fade in with a staggered delay β€” each card waits 60ms longer than the previous one, creating a cascade effect as a grid of cards enters the viewport.

js/app.js β€” Staggered fade-in
const fadeTargets = document.querySelectorAll(
  '.activity-card, .framework-card, .institution-card, ' +
  '.message-card, .social-card, .stat-card, .timeline-item, ' +
  '.youth-item, .glossary-item, .variation-card'
);
fadeTargets.forEach(el => el.classList.add('fade-in'));

const io = new IntersectionObserver(entries => {
  entries.forEach((e, i) => {
    if (e.isIntersecting) {
      setTimeout(() => e.target.classList.add('visible'), i * 60);
    }
  });
}, { threshold: 0.08, rootMargin: '0px 0px -30px 0px' });

fadeTargets.forEach(el => io.observe(el));

πŸ”‘ Key Code: CSS Design Tokens

The site uses a deep navy/gold/ivory palette appropriate for the subject matter, defined as CSS custom properties.

css/style.css β€” Root variables
:root {
  --navy:        #1B2A4A;
  --navy-mid:    #243556;
  --navy-light:  #2E4270;
  --gold:        #C8973E;
  --gold-light:  #E8B96A;
  --ivory:       #F8F4EE;
  --ivory-mid:   #EDE7DC;
  --text-dark:   #1B2A4A;
  --text-mid:    #3D4F70;
  --text-light:  #6B7A9A;
  --section-light: #F8F4EE;
  --section-mid:   #EDE7DC;
  --section-dark:  #1B2A4A;
  --radius:      8px;
  --shadow-sm:   0 2px 8px rgba(0,0,0,0.08);
  --shadow-md:   0 4px 16px rgba(0,0,0,0.12);
  --transition:  0.3s ease;
}

πŸ“„ Knowledge Source Files

Each major section of the site was authored from a corresponding Markdown file in knowledge/, containing verified facts and quotes from official BahΓ‘'Γ­ documents.

Example: knowledge/the-plan.md

knowledge/the-plan.md (excerpt)
---
title: "The Nine Year Plan"
description: "Overview of the Nine Year Plan 2022–2031"
tags: ["plan", "UHJ", "2022", "2031", "society-building"]
category: "Overview"
---

## What Is the Nine Year Plan?

The Nine Year Plan (2022–2031) is the first major undertaking in a
new twenty-five-year series of global Plans launched by the Universal
House of Justice at RiḍvÑn 2022.

## Core Aim

> "The release of the society-building power of the Faith of
> BahΓ‘'u'llΓ‘h in ever-greater measures."

## Duration
2022 – 2031 (first of a series ending RiḍvΓ‘n 2046)