+
+
+
+
+
+
diff --git a/components.css b/components.css
new file mode 100644
index 0000000..75dd48f
--- /dev/null
+++ b/components.css
@@ -0,0 +1,536 @@
+/* Project Friction - Components CSS */
+/* Reusable UI components for the museum exhibit */
+
+/* Navigation Cards */
+.nav-card {
+ background: var(--color-white);
+ border: 2px solid #e9ecef;
+ border-radius: var(--radius-lg);
+ padding: var(--spacing-xl);
+ margin-bottom: var(--spacing-lg);
+ cursor: pointer;
+ transition: all var(--transition-normal);
+ position: relative;
+ overflow: hidden;
+}
+
+.nav-card::before {
+ content: '';
+ position: absolute;
+ left: 0;
+ top: 0;
+ bottom: 0;
+ width: 5px;
+ background: var(--theme-color);
+ transition: width var(--transition-normal);
+}
+
+.nav-card:hover {
+ transform: translateX(5px);
+ box-shadow: var(--shadow-lg);
+ border-color: var(--theme-color);
+}
+
+.nav-card:hover::before {
+ width: 8px;
+}
+
+.nav-card[data-section="context"] { --theme-color: var(--color-context); }
+.nav-card[data-section="rcaf"] { --theme-color: var(--color-rcaf); }
+.nav-card[data-section="rcn"] { --theme-color: var(--color-rcn); }
+.nav-card[data-section="army"] { --theme-color: var(--color-army); }
+.nav-card[data-section="legacy"] { --theme-color: var(--color-legacy); }
+
+.nav-card-header {
+ display: flex;
+ align-items: center;
+ gap: var(--spacing-lg);
+ margin-bottom: var(--spacing-md);
+}
+
+.nav-card-icon {
+ font-size: 28px;
+}
+
+.nav-card-title {
+ flex: 1;
+}
+
+.nav-card-title h3 {
+ font-size: 16px;
+ margin-bottom: var(--spacing-xs);
+ color: var(--color-black);
+ font-family: var(--font-primary);
+}
+
+.nav-card-title span {
+ font-size: 12px;
+ color: var(--color-dark-gray);
+ font-family: var(--font-secondary);
+}
+
+.nav-card-preview {
+ font-size: 13px;
+ line-height: 1.6;
+ color: var(--color-dark-gray);
+ margin-bottom: var(--spacing-md);
+ font-family: var(--font-secondary);
+}
+
+.nav-card-links {
+ display: flex;
+ gap: var(--spacing-lg);
+ font-size: 12px;
+ color: var(--color-rcaf);
+ font-family: var(--font-secondary);
+}
+
+.nav-card-link {
+ display: flex;
+ align-items: center;
+ gap: var(--spacing-xs);
+}
+
+/* Interactive Map Buttons */
+.map-button {
+ display: inline-flex;
+ align-items: center;
+ gap: var(--spacing-sm);
+ padding: var(--spacing-md) var(--spacing-lg);
+ background: linear-gradient(135deg, var(--color-rcaf) 0%, #2980b9 100%);
+ color: var(--color-white);
+ border: none;
+ border-radius: 25px;
+ font-size: 14px;
+ cursor: pointer;
+ transition: all var(--transition-normal);
+ margin: var(--spacing-md) var(--spacing-md) var(--spacing-md) 0;
+ box-shadow: 0 2px 5px rgba(52, 152, 219, 0.3);
+ font-family: var(--font-secondary);
+}
+
+.map-button:hover {
+ transform: translateY(-2px);
+ box-shadow: 0 4px 10px rgba(52, 152, 219, 0.4);
+}
+
+.map-button.active {
+ background: linear-gradient(135deg, var(--color-accent) 0%, #c0392b 100%);
+ box-shadow: 0 2px 5px rgba(192, 57, 43, 0.3);
+}
+
+.map-button-icon {
+ font-size: 16px;
+}
+
+/* Fact Boxes */
+.fact-box {
+ background: linear-gradient(to right, #fef5e7, #fdf2e9);
+ border-left: 5px solid #f39c12;
+ padding: var(--spacing-xl);
+ margin: var(--spacing-xl) 0;
+ border-radius: var(--radius-sm);
+ box-shadow: var(--shadow-sm);
+}
+
+.fact-box h3 {
+ font-size: 16px;
+ color: #d68910;
+ margin-bottom: var(--spacing-md);
+ font-weight: 600;
+ text-transform: uppercase;
+ letter-spacing: 1px;
+ font-family: var(--font-secondary);
+}
+
+.fact-box ul {
+ list-style: none;
+}
+
+.fact-box li {
+ padding: 6px 0;
+ color: #7f6000;
+ font-size: 14px;
+ display: flex;
+ align-items: flex-start;
+ font-family: var(--font-secondary);
+}
+
+.fact-box li::before {
+ content: "βΈ";
+ margin-right: var(--spacing-md);
+ color: #f39c12;
+ font-weight: bold;
+}
+
+/* Quote Blocks */
+.quote-block {
+ background: var(--color-light-gray);
+ border-left: 4px solid var(--color-secondary);
+ padding: var(--spacing-xl);
+ margin: var(--spacing-xxl) 0;
+ font-style: italic;
+ position: relative;
+ border-radius: var(--radius-sm);
+}
+
+.quote-block::before {
+ content: """;
+ font-size: 60px;
+ color: #cbd5e0;
+ position: absolute;
+ top: -10px;
+ left: 10px;
+ font-family: var(--font-primary);
+}
+
+.quote-text {
+ font-size: 17px;
+ line-height: 1.6;
+ color: var(--color-secondary);
+ margin-bottom: var(--spacing-md);
+ padding-left: 30px;
+ font-family: var(--font-primary);
+}
+
+.quote-attribution {
+ text-align: right;
+ font-size: 14px;
+ color: var(--color-dark-gray);
+ font-style: normal;
+ font-family: var(--font-secondary);
+}
+
+/* Timeline Cards */
+.timeline-card {
+ background: var(--color-white);
+ border: 1px solid var(--color-gray);
+ border-radius: var(--radius-md);
+ padding: var(--spacing-xl);
+ margin: var(--spacing-xl) 0;
+ position: relative;
+ transition: all var(--transition-normal);
+}
+
+.timeline-card:hover {
+ box-shadow: var(--shadow-lg);
+ transform: translateX(5px);
+}
+
+.timeline-date {
+ position: absolute;
+ left: -15px;
+ top: var(--spacing-xl);
+ background: var(--color-accent);
+ color: var(--color-white);
+ padding: var(--spacing-sm) var(--spacing-md);
+ border-radius: var(--radius-sm);
+ font-size: 12px;
+ font-weight: bold;
+ font-family: var(--font-secondary);
+}
+
+.timeline-content {
+ margin-left: var(--spacing-xl);
+}
+
+.timeline-content h4 {
+ font-size: 18px;
+ color: var(--color-primary);
+ margin-bottom: var(--spacing-md);
+ font-family: var(--font-primary);
+}
+
+.timeline-content p {
+ font-size: 14px;
+ line-height: 1.6;
+ color: var(--color-dark-gray);
+ font-family: var(--font-secondary);
+}
+
+/* Media Gallery */
+.media-section {
+ margin: var(--spacing-xxl) 0;
+ padding: var(--spacing-xl);
+ background: var(--color-light-gray);
+ border-radius: var(--radius-md);
+}
+
+.media-header {
+ display: flex;
+ align-items: center;
+ gap: var(--spacing-md);
+ margin-bottom: var(--spacing-lg);
+}
+
+.media-header h3 {
+ font-size: 18px;
+ color: var(--color-primary);
+ font-family: var(--font-primary);
+}
+
+.media-grid {
+ display: grid;
+ grid-template-columns: repeat(2, 1fr);
+ gap: var(--spacing-lg);
+}
+
+.media-item {
+ position: relative;
+ aspect-ratio: 4/3;
+ background: #ddd;
+ border-radius: var(--radius-sm);
+ overflow: hidden;
+ cursor: pointer;
+ transition: transform var(--transition-normal);
+}
+
+.media-item:hover {
+ transform: scale(1.05);
+ box-shadow: var(--shadow-lg);
+}
+
+.media-caption {
+ position: absolute;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ background: linear-gradient(to top, rgba(0,0,0,0.8), transparent);
+ color: var(--color-white);
+ padding: var(--spacing-md);
+ font-size: 12px;
+ font-family: var(--font-secondary);
+}
+
+/* Document Section */
+.document-section {
+ background: var(--color-white);
+ border: 2px solid #ecf0f1;
+ border-radius: var(--radius-md);
+ padding: var(--spacing-xl);
+ margin: var(--spacing-xl) 0;
+}
+
+.document-header {
+ display: flex;
+ align-items: center;
+ gap: var(--spacing-md);
+ margin-bottom: var(--spacing-lg);
+ padding-bottom: var(--spacing-md);
+ border-bottom: 2px solid #ecf0f1;
+}
+
+.document-header h3 {
+ font-size: 16px;
+ color: var(--color-primary);
+ font-family: var(--font-primary);
+}
+
+.document-list {
+ list-style: none;
+}
+
+.document-list li {
+ padding: var(--spacing-md) 0;
+ border-bottom: 1px solid #f5f5f5;
+}
+
+.document-link {
+ display: flex;
+ align-items: center;
+ gap: var(--spacing-md);
+ color: var(--color-rcaf);
+ text-decoration: none;
+ transition: all var(--transition-fast);
+ font-family: var(--font-secondary);
+ font-size: 14px;
+}
+
+.document-link:hover {
+ color: #2980b9;
+ padding-left: var(--spacing-md);
+}
+
+/* Article Index */
+.article-index {
+ padding: var(--spacing-xl);
+ background: var(--color-white);
+ border-radius: var(--radius-md);
+ border: 1px solid var(--color-gray);
+ margin: var(--spacing-xl) 0;
+}
+
+.article-index h3 {
+ font-size: 16px;
+ margin-bottom: var(--spacing-lg);
+ padding-bottom: var(--spacing-md);
+ border-bottom: 2px solid var(--color-rcaf);
+ color: var(--color-primary);
+ font-family: var(--font-primary);
+}
+
+.article-list {
+ list-style: none;
+}
+
+.article-list li {
+ padding: var(--spacing-sm) 0;
+ border-bottom: 1px solid #f1f3f5;
+}
+
+.article-list a {
+ color: var(--color-rcaf);
+ text-decoration: none;
+ font-size: 14px;
+ display: flex;
+ align-items: center;
+ gap: var(--spacing-sm);
+ transition: all var(--transition-fast);
+ font-family: var(--font-secondary);
+}
+
+.article-list a:hover {
+ padding-left: var(--spacing-md);
+ color: #0056b3;
+}
+
+/* Info Box */
+.info-box {
+ background: linear-gradient(to right, var(--color-light-gray), var(--color-white));
+ border-left: 4px solid var(--color-rcaf);
+ padding: var(--spacing-lg);
+ margin: var(--spacing-xl) 0;
+ border-radius: var(--radius-sm);
+}
+
+.info-box h4 {
+ font-size: 14px;
+ margin-bottom: var(--spacing-md);
+ color: var(--color-black);
+ font-family: var(--font-secondary);
+ font-weight: 600;
+}
+
+.info-box ul {
+ list-style: none;
+}
+
+.info-box li {
+ font-size: 13px;
+ padding: 4px 0;
+ color: #495057;
+ font-family: var(--font-secondary);
+}
+
+/* Story Map Banner */
+.story-map-banner {
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+ color: var(--color-white);
+ padding: var(--spacing-xl);
+ border-radius: var(--radius-lg);
+ margin: var(--spacing-xl) 0;
+ cursor: pointer;
+ transition: transform var(--transition-normal);
+}
+
+.story-map-banner:hover {
+ transform: scale(1.02);
+ box-shadow: 0 5px 20px rgba(102, 126, 234, 0.4);
+}
+
+.story-map-banner h4 {
+ font-size: 18px;
+ margin-bottom: var(--spacing-sm);
+ display: flex;
+ align-items: center;
+ gap: var(--spacing-md);
+ font-family: var(--font-primary);
+}
+
+.story-map-banner p {
+ font-size: 14px;
+ opacity: 0.9;
+ line-height: 1.6;
+ font-family: var(--font-secondary);
+}
+
+/* Section Headers */
+.chapter-header {
+ margin: var(--spacing-xxl) 0 var(--spacing-xl) 0;
+ padding-bottom: var(--spacing-md);
+ border-bottom: 2px solid var(--color-context);
+}
+
+.chapter-header h2 {
+ font-size: 24px;
+ color: var(--color-primary);
+ font-family: var(--font-primary);
+ font-weight: normal;
+}
+
+.chapter-date {
+ font-size: 14px;
+ color: var(--color-dark-gray);
+ margin-top: var(--spacing-sm);
+ font-style: italic;
+ font-family: var(--font-secondary);
+}
+
+/* Buttons */
+.btn {
+ padding: var(--spacing-md) var(--spacing-lg);
+ border: none;
+ border-radius: var(--radius-sm);
+ cursor: pointer;
+ font-size: 14px;
+ font-family: var(--font-secondary);
+ transition: all var(--transition-fast);
+ display: inline-flex;
+ align-items: center;
+ gap: var(--spacing-sm);
+}
+
+.btn-primary {
+ background: var(--color-rcaf);
+ color: var(--color-white);
+}
+
+.btn-primary:hover {
+ background: #2980b9;
+ transform: translateY(-2px);
+}
+
+.btn-secondary {
+ background: var(--color-gray);
+ color: var(--color-black);
+}
+
+.btn-secondary:hover {
+ background: #adb5bd;
+}
+
+/* Close button */
+.close-btn,
+.close-info {
+ position: absolute;
+ top: var(--spacing-md);
+ right: var(--spacing-md);
+ width: 30px;
+ height: 30px;
+ border: none;
+ background: rgba(0,0,0,0.1);
+ border-radius: var(--radius-full);
+ cursor: pointer;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 16px;
+ color: var(--color-dark-gray);
+ transition: all var(--transition-fast);
+}
+
+.close-btn:hover,
+.close-info:hover {
+ background: rgba(0,0,0,0.2);
+ color: var(--color-black);
+}
\ No newline at end of file
diff --git a/copilot_instructions.md b/copilot_instructions.md
new file mode 100644
index 0000000..32fa688
--- /dev/null
+++ b/copilot_instructions.md
@@ -0,0 +1,200 @@
+# Project Friction - Digital Gulf War Exhibit
+## Copilot Development Instructions
+
+### PROJECT SCOPE & CONTEXT
+
+**Project Name**: Project Friction - Canada's Role in the Gulf War Digital Exhibit
+**Client**: Canadian Research and Mapping Association (CRMA) / Veterans Affairs Canada
+**Purpose**: Interactive digital museum exhibit for online and touchscreen kiosk deployment
+**Timeline**: Phase 2 development (Feb-Jun 2026) - Content Creation & Frontend Development
+
+**Core Mission**:
+Create a comprehensive, educational digital exhibit showcasing Canada's military contribution to the 1991 Gulf War through interactive maps, historical narratives, and multimedia content. The exhibit must serve both online users and museum visitors using touchscreen kiosks.
+
+### TECHNICAL REQUIREMENTS
+
+**Primary Technologies**:
+- HTML5 for structure
+- CSS3 for styling (museum-quality visual design)
+- Vanilla JavaScript for interactivity
+- Leaflet.js for interactive mapping
+- No frameworks required - keep dependencies minimal for kiosk compatibility
+
+**Target Platforms**:
+- Desktop browsers (museum kiosks)
+- Modern tablets and mobile devices
+- Must work offline after initial load
+
+**Performance Standards**:
+- Load time under 3 seconds
+- Touch-friendly interface (minimum 44px touch targets)
+- WCAG 2.1 AA accessibility compliance
+- Responsive design for multiple screen sizes
+
+### FILE STRUCTURE TO CREATE
+
+```
+project-friction/
+βββ index.html # Main navigation hub
+βββ css/
+β βββ main.css # Global styles and layout
+β βββ components.css # Reusable UI components
+β βββ sections.css # Section-specific styles
+β βββ responsive.css # Media queries and responsive design
+βββ js/
+β βββ app.js # Main application logic
+β βββ navigation.js # Section switching and breadcrumbs
+β βββ map-controller.js # Map initialization and controls
+β βββ timeline.js # Timeline animation and controls
+β βββ data-layers.js # Map data and layer management
+β βββ interactions.js # UI interactions and animations
+βββ data/
+β βββ map-data.json # Geographic data for all sections
+β βββ timeline-events.json # Timeline event data
+β βββ articles.json # Article content and metadata
+β βββ media-gallery.json # Image and media references
+βββ sections/
+β βββ context.html # Historical Context section
+β βββ rcaf.html # RCAF Desert Cats section
+β βββ rcn.html # RCN Task Group section
+β βββ army.html # Canadian Army section
+β βββ legacy.html # Post-War Legacy section
+βββ assets/
+ βββ images/ # Historical photos and media
+ βββ icons/ # UI icons and map markers
+ βββ fonts/ # Custom typography files
+```
+
+### DEVELOPMENT APPROACH
+
+**Phase 1: Core Structure**
+1. Create main HTML layout with sidebar navigation
+2. Implement CSS grid/flexbox layout system
+3. Build basic JavaScript navigation between sections
+4. Initialize Leaflet map with basic controls
+
+**Phase 2: Interactive Features**
+1. Timeline control implementation
+2. Map layer switching system
+3. Interactive buttons for map filters
+4. Content loading and display system
+
+**Phase 3: Content Integration**
+1. Load historical narrative content
+2. Implement map data layers
+3. Add media galleries and fact boxes
+4. Polish animations and transitions
+
+### SPECIFIC IMPLEMENTATION GUIDELINES
+
+**CSS Architecture**:
+- Use CSS Custom Properties for theming
+- BEM methodology for class naming
+- Mobile-first responsive design
+- Print stylesheet for offline reading
+
+**JavaScript Patterns**:
+- Module pattern for code organization
+- Event delegation for touch interactions
+- Async/await for data loading
+- Error handling for offline scenarios
+
+**Map Integration**:
+- Leaflet.js with custom marker styles
+- GeoJSON data format for geographic features
+- Layer groups for different data types
+- Custom popup templates
+
+**Accessibility Requirements**:
+- Semantic HTML structure
+- ARIA labels for interactive elements
+- Keyboard navigation support
+- Screen reader compatible content
+- High contrast mode support
+
+### CONTENT SPECIFICATIONS
+
+**Historical Context Section** (already developed):
+- 2,500+ word narrative in 6 chapters
+- Interactive map buttons for key events
+- Timeline integration
+- Fact boxes and quote blocks
+- Document reference sections
+
+**Remaining Sections** (to be developed):
+- RCAF: CF-18 operations, pilot stories, mission details
+- RCN: Naval operations, ship modifications, MIF operations
+- Army: Field hospital operations, security details, humanitarian missions
+- Legacy: Veteran health, commemorations, lessons learned
+
+**Map Data Requirements**:
+- Force positions and movements
+- Event locations with timestamps
+- Base locations and infrastructure
+- Supply routes and operational areas
+- Political boundaries and geographic context
+
+### QUALITY STANDARDS
+
+**Content Quality**:
+- Museum-grade historical accuracy
+- Canadian perspective throughout
+- Primary source citations
+- Appropriate reading level (Grade 8-10)
+
+**Visual Design**:
+- Professional museum aesthetic
+- Consistent color coding by section
+- Clear typography hierarchy
+- Intuitive navigation patterns
+
+**User Experience**:
+- Maximum 3-click depth to any content
+- Clear breadcrumb navigation
+- Immediate visual feedback on interactions
+- Graceful degradation for older devices
+
+### TESTING REQUIREMENTS
+
+**Device Testing**:
+- Desktop browsers (Chrome, Firefox, Safari, Edge)
+- Tablet devices (iPad, Android tablets)
+- Touch screen kiosks (Windows-based museum hardware)
+
+**Content Validation**:
+- Historical accuracy review by subject matter experts
+- Canadian military veteran feedback
+- Museum educator usability testing
+
+### DEPLOYMENT CONSIDERATIONS
+
+**Online Deployment**:
+- Static site hosting (Netlify/Vercel compatible)
+- CDN integration for media assets
+- Progressive web app features
+
+**Kiosk Deployment**:
+- Offline functionality
+- Reset mechanism for public use
+- Screensaver integration
+- Maintenance mode capabilities
+
+---
+
+## IMPORTANT CONSTRAINTS
+
+1. **Stick to defined scope**: 5 thematic sections covering Canada's Gulf War role
+2. **No feature creep**: Request approval for any additions beyond specified content
+3. **Museum standards**: All content must meet professional exhibition quality
+4. **Accessibility first**: Design for all users, including those with disabilities
+5. **Historical accuracy**: No fictional elements or speculative content
+6. **Canadian focus**: Maintain Canadian perspective while showing international context
+
+## APPROVAL REQUIRED FOR:
+- Additional sections beyond the 5 defined areas
+- New interactive features not specified in requirements
+- Integration of external APIs or services
+- Significant changes to visual design approach
+- Addition of audio/video content beyond static images
+
+This project represents a significant digital heritage initiative. Maintain focus on educational value, historical accuracy, and professional presentation standards throughout development.
\ No newline at end of file
diff --git a/data/sections-content.json b/data/sections-content.json
new file mode 100644
index 0000000..6b366b7
--- /dev/null
+++ b/data/sections-content.json
@@ -0,0 +1,113 @@
+{
+ "context": {
+ "blocks": [
+ { "id": "c1", "type": "heading", "level": 1, "text": "Historical Context: The Road to War" },
+ { "id": "c2", "type": "paragraph", "text": "On August 2, 1990, Iraqi forces under President Saddam Hussein crossed the border into neighbouring Kuwait, overwhelming its small military in a matter of hours. The invasion shocked the international community and triggered an unprecedented diplomatic and military response. Within days, the United Nations Security Council passed Resolution 660, condemning the invasion and demanding an immediate, unconditional withdrawal of Iraqi forces." },
+ { "id": "c3", "type": "statistics", "stats": [
+ { "number": "34", "label": "Coalition Nations" },
+ { "number": "12", "label": "UN Resolutions" },
+ { "number": "43", "label": "Days Air Campaign" },
+ { "number": "100", "label": "Hours Ground War" }
+ ]},
+ { "id": "c4", "type": "map-button", "label": "Show Iraqi Invasion Routes", "lat": 29.8, "lng": 47.9, "zoom": 8 },
+ { "id": "c5", "type": "heading", "level": 2, "text": "Canada's Diplomatic Response" },
+ { "id": "c6", "type": "paragraph", "text": "Canada was among the first nations to condemn Iraq's aggression and commit forces to the coalition. Prime Minister Brian Mulroney announced on August 10, 1990 that Canada would deploy naval vessels to the Persian Gulf as part of the multinational force. This decision reflected Canada's longstanding commitment to collective security and the rule of international law." },
+ { "id": "c7", "type": "quote", "text": "Canada will not stand idly by while a small nation is crushed by its neighbour in clear violation of international law.", "author": "Prime Minister Brian Mulroney, August 1990" },
+ { "id": "c8", "type": "map-button", "label": "Show Coalition Force Positions", "lat": 27.0, "lng": 50.0, "zoom": 6 },
+ { "id": "c9", "type": "heading", "level": 2, "text": "Operation Desert Shield" },
+ { "id": "c10", "type": "paragraph", "text": "Operation Desert Shield β the build-up phase from August 1990 to January 1991 β saw the massing of over 700,000 coalition troops in Saudi Arabia and the surrounding region. Canada contributed naval, air, and later ground forces, making it one of the most significant Canadian military deployments since the Korean War." },
+ { "id": "c11", "type": "image", "src": "https://placehold.co/800x450/2c3e50/ffffff?text=Coalition+Forces+Assembling", "alt": "Coalition forces assembling in Saudi Arabia", "caption": "Coalition forces assembling in Saudi Arabia, late 1990. Canada contributed 4,500 personnel across naval, air, and ground components." }
+ ]
+ },
+ "rcaf": {
+ "blocks": [
+ { "id": "r1", "type": "heading", "level": 1, "text": "RCAF Desert Cats: 409 Squadron" },
+ { "id": "r2", "type": "paragraph", "text": "Canada's air contribution to the Gulf War was led by 409 Tactical Fighter Squadron. Known as the 'Nighthawks,' the squadron's CF-18 Hornets were deployed to Doha, Qatar, where they formed the core of Canada's Gulf War air contingent β the Desert Cats. From their base at Canada Dry 1, pilots flew Combat Air Patrol and, later, offensive strike missions deep into Iraq." },
+ { "id": "r3", "type": "statistics", "stats": [
+ { "number": "26", "label": "CF-18 Hornets" },
+ { "number": "2,700+", "label": "Sorties Flown" },
+ { "number": "5", "label": "Months Deployed" },
+ { "number": "0", "label": "Aircraft Lost" }
+ ]},
+ { "id": "r4", "type": "map-button", "label": "Show Doha Air Base (Canada Dry 1)", "lat": 25.27, "lng": 51.61, "zoom": 10 },
+ { "id": "r5", "type": "heading", "level": 2, "text": "From Defence to Offence" },
+ { "id": "r6", "type": "paragraph", "text": "Initially tasked with Combat Air Patrol (CAP) missions protecting the naval fleet, the Desert Cats transitioned to offensive strike operations after Operation Desert Storm began on January 17, 1991. CF-18 pilots flew interdiction missions targeting Iraqi airfields, radar sites, and command infrastructure β a significant shift that required rapid retraining and aircraft modification." },
+ { "id": "r7", "type": "quote", "text": "We went from protecting the fleet to striking deep into Iraq. The transition was fast, but the training paid off. The Desert Cats were ready.", "author": "Pilot, 409 Squadron" },
+ { "id": "r8", "type": "heading", "level": 2, "text": "The TNC-45 Engagement" },
+ { "id": "r9", "type": "paragraph", "text": "On January 30, 1991, two CF-18s from 409 Squadron engaged and sank an Iraqi Zhuk-class patrol vessel, the TNC-45, in the northern Persian Gulf. It was the first time Canadian aircraft had destroyed an enemy vessel since the Second World War β a historic moment for the RCAF and a demonstration of the Desert Cats' combat effectiveness." },
+ { "id": "r10", "type": "map-button", "label": "Show TNC-45 Engagement Site", "lat": 29.14, "lng": 48.13, "zoom": 9 },
+ { "id": "r11", "type": "grid4", "images": [
+ { "src": "https://placehold.co/400x300/3498db/ffffff?text=CF-18+Hornet", "alt": "CF-18 Hornet", "caption": "CF-18 Hornet in Desert Cats livery" },
+ { "src": "https://placehold.co/400x300/2980b9/ffffff?text=Doha+Air+Base", "alt": "Doha Air Base", "caption": "Canada Dry 1, Doha, Qatar" },
+ { "src": "https://placehold.co/400x300/1a5276/ffffff?text=Desert+Cats+Patch", "alt": "Desert Cats patch", "caption": "409 Squadron Desert Cats patch" },
+ { "src": "https://placehold.co/400x300/154360/ffffff?text=Mission+Briefing", "alt": "Mission briefing", "caption": "Pre-mission briefing, 1991" }
+ ]}
+ ]
+ },
+ "rcn": {
+ "blocks": [
+ { "id": "n1", "type": "heading", "level": 1, "text": "RCN Task Group: Naval Blockade Operations" },
+ { "id": "n2", "type": "paragraph", "text": "Canada was among the first nations to respond to the Gulf Crisis with a naval contribution. Three Royal Canadian Navy vessels β HMCS Athabaskan, HMCS Terra Nova, and HMCS Protecteur β were dispatched to the Persian Gulf as part of Operation Friction. Together they formed Canadian Task Group 302.3, operating under the Maritime Interception Force." },
+ { "id": "n3", "type": "statistics", "stats": [
+ { "number": "3", "label": "RCN Vessels" },
+ { "number": "1,000+", "label": "Sailors Deployed" },
+ { "number": "160+", "label": "Ships Challenged" },
+ { "number": "8", "label": "Months at Sea" }
+ ]},
+ { "id": "n4", "type": "map-button", "label": "Show Naval Operations Area", "lat": 27.0, "lng": 50.5, "zoom": 7 },
+ { "id": "n5", "type": "heading", "level": 2, "text": "HMCS Terra Nova: A Remarkable Transformation" },
+ { "id": "n6", "type": "paragraph", "text": "One of the most significant operational achievements was the rapid conversion of HMCS Terra Nova into a guided-missile destroyer. Canadian naval technicians worked around the clock to retrofit the vessel with modern anti-aircraft missile systems, significantly upgrading her capability for the high-threat Persian Gulf environment. The conversion was completed in record time." },
+ { "id": "n7", "type": "image", "src": "https://placehold.co/800x450/2c3e50/ffffff?text=HMCS+Terra+Nova", "alt": "HMCS Terra Nova in the Persian Gulf", "caption": "HMCS Terra Nova operating in the Persian Gulf, 1990β91. The vessel underwent rapid modifications to enhance her missile defence capability." },
+ { "id": "n8", "type": "quote", "text": "The men and women of the task group performed extraordinary work under pressure. What they achieved in those weeks of preparation was remarkable.", "author": "Commodore Ken Summers, CTG 302.3 Commander" },
+ { "id": "n9", "type": "heading", "level": 2, "text": "Maritime Interception Force" },
+ { "id": "n10", "type": "paragraph", "text": "Canada's naval task group formed a key part of the Maritime Interception Force (MIF), enforcing the UN-mandated blockade of Iraq. Canadian vessels challenged hundreds of merchant ships, and the task group was recognised for its professionalism and effectiveness in this complex multinational operation at sea." },
+ { "id": "n11", "type": "map-button", "label": "Show HMCS Task Group Position", "lat": 26.23, "lng": 50.59, "zoom": 9 }
+ ]
+ },
+ "army": {
+ "blocks": [
+ { "id": "a1", "type": "heading", "level": 1, "text": "Canadian Army: Medical & Security Forces" },
+ { "id": "a2", "type": "paragraph", "text": "Canada's army contribution to the Gulf War centred on two primary missions: the deployment of 1 Canadian Field Hospital to Saudi Arabia, and the provision of security forces to protect coalition installations. Together, these elements brought Canada's ground commitment to over 1,200 personnel operating in one of the most hostile environments in the world." },
+ { "id": "a3", "type": "statistics", "stats": [
+ { "number": "530+", "label": "Hospital Personnel" },
+ { "number": "600", "label": "Bed Capacity" },
+ { "number": "500+", "label": "Security Forces" },
+ { "number": "0", "label": "Canadian Fatalities" }
+ ]},
+ { "id": "a4", "type": "map-button", "label": "Show 1 Canadian Field Hospital", "lat": 28.43, "lng": 46.09, "zoom": 9 },
+ { "id": "a5", "type": "heading", "level": 2, "text": "1 Canadian Field Hospital" },
+ { "id": "a6", "type": "paragraph", "text": "Established at Al-Qaysumah, Saudi Arabia, 1 Canadian Field Hospital (1 CFH) was one of the most capable coalition medical facilities in the theatre of operations. With a planned capacity of 600 beds, it included surgical, intensive care, and recovery wards staffed by some of Canada's finest medical personnel. The swift coalition victory meant the hospital treated fewer battlefield casualties than anticipated, but the hospital remained on standby throughout the conflict." },
+ { "id": "a7", "type": "quote", "text": "We prepared for the worst. The training was intense, the equipment was first-class, and the people were exceptional. We were ready for whatever came our way.", "author": "Colonel John Abt, Commanding Officer, 1 Canadian Field Hospital" },
+ { "id": "a8", "type": "image", "src": "https://placehold.co/800x450/27ae60/ffffff?text=1+Canadian+Field+Hospital", "alt": "1 Canadian Field Hospital, Al-Qaysumah", "caption": "1 Canadian Field Hospital at Al-Qaysumah, Saudi Arabia. The 530-person unit was fully operational and prepared for mass casualty scenarios." },
+ { "id": "a9", "type": "heading", "level": 2, "text": "Security Operations in Bahrain" },
+ { "id": "a10", "type": "paragraph", "text": "Members of the Royal Canadian Regiment and other army units provided security for coalition installations in Bahrain and Saudi Arabia. These operations, while less visible than combat missions, were essential to the smooth functioning of the broader coalition effort. Canadian soldiers maintained a professional presence and provided force protection in a tense and unpredictable environment." },
+ { "id": "a11", "type": "map-button", "label": "Show Bahrain Security Operations", "lat": 26.07, "lng": 50.56, "zoom": 10 }
+ ]
+ },
+ "legacy": {
+ "blocks": [
+ { "id": "l1", "type": "heading", "level": 1, "text": "After the War: Veterans, Legacy & Long-Term Impact" },
+ { "id": "l2", "type": "paragraph", "text": "Operation Desert Storm ended on February 28, 1991 β just 100 hours after the ground offensive began. The swift coalition victory liberated Kuwait and expelled Iraqi forces, but for thousands of Canadian veterans, the war's end was only the beginning of a longer struggle. Gulf War Syndrome, commemorations, peacekeeping deployments, and ongoing veteran support shaped the post-war legacy of Canada's participation." },
+ { "id": "l3", "type": "statistics", "stats": [
+ { "number": "4,449", "label": "Medals Awarded" },
+ { "number": "4,500+", "label": "Veterans" },
+ { "number": "700+", "label": "Gulf War Illness Claims" },
+ { "number": "1991β2003", "label": "UNIKOM Service" }
+ ]},
+ { "id": "l4", "type": "heading", "level": 2, "text": "Gulf War Syndrome" },
+ { "id": "l5", "type": "paragraph", "text": "In the years following the war, thousands of veterans across the coalition reported a range of unexplained illnesses β chronic fatigue, muscle pain, cognitive difficulties, and other debilitating symptoms. This cluster of conditions became known as Gulf War Syndrome. Canadian veterans fought for official recognition of their illnesses and improved healthcare support, a battle that continued for many years after they returned home." },
+ { "id": "l6", "type": "quote", "text": "We served with honour and came home changed. The government needed to understand that the war didn't end when we crossed the ocean and came home.", "author": "Gulf War Veteran, Royal Canadian Regiment" },
+ { "id": "l7", "type": "map-button", "label": "Show Veterans Affairs Canada", "lat": 45.42, "lng": -75.70, "zoom": 10 },
+ { "id": "l8", "type": "heading", "level": 2, "text": "Peacekeeping & UNIKOM" },
+ { "id": "l9", "type": "paragraph", "text": "Following the ceasefire, Canada contributed personnel to the UN Iraq-Kuwait Observation Mission (UNIKOM), established to monitor the demilitarised zone along the Iraq-Kuwait border. Canadian peacekeepers served with UNIKOM from 1991 until the mission's end in 2003, reflecting Canada's ongoing commitment to regional stability and the international rule of law." },
+ { "id": "l10", "type": "map-button", "label": "Show UNIKOM Peacekeeping Zone", "lat": 30.05, "lng": 47.80, "zoom": 9 },
+ { "id": "l11", "type": "gallery", "images": [
+ { "src": "https://placehold.co/600x400/c0392b/ffffff?text=Medal+Parade", "alt": "Medal parade", "caption": "Veterans receiving Gulf War Service Medals" },
+ { "src": "https://placehold.co/600x400/922b21/ffffff?text=Homecoming", "alt": "Homecoming ceremony", "caption": "Canadian troops returning home, 1991" },
+ { "src": "https://placehold.co/600x400/76261d/ffffff?text=Commemorations", "alt": "Commemoration ceremony", "caption": "Annual Gulf War commemoration" },
+ { "src": "https://placehold.co/600x400/4a1515/ffffff?text=UNIKOM+Service", "alt": "UNIKOM peacekeeping", "caption": "Canadian peacekeepers with UNIKOM, 1992" }
+ ]}
+ ]
+ }
+}
+
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..56b0c69
--- /dev/null
+++ b/index.html
@@ -0,0 +1,112 @@
+
+
+
+
+
+ Project Friction - Canada's Gulf War Digital Exhibit
+
+
+
+
+
+
+
+
+
+
+
+ β
+
+
+
+
+
+
PF
+
+
Project Friction
+
Canada's Role in the Gulf War 1990-1991
+
+
+
+
+
+
+ β
+ Back to Main Navigation
+
+
+
+
+
+
Welcome to Project Friction
+
Explore Canada's military contribution to the Gulf War through interactive maps, detailed articles, and veteran stories. Select a thematic area below to begin.
+
+
+
+
+
+
+
+
Explore Thematic Areas
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Loading Project Friction
+
Preparing the interactive exhibit...
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/js/block-renderer.js b/js/block-renderer.js
new file mode 100644
index 0000000..ecd7892
--- /dev/null
+++ b/js/block-renderer.js
@@ -0,0 +1,95 @@
+/**
+ * Block Renderer - Project Friction
+ * Converts a block array into HTML strings.
+ * Used by both the main exhibit (app.js) and the builder preview.
+ */
+class BlockRenderer {
+
+ static render(blocks) {
+ if (!Array.isArray(blocks)) return '';
+ return blocks.map(function(block) { return BlockRenderer.renderBlock(block); }).join('\n');
+ }
+
+ static renderBlock(block) {
+ if (!block || !block.type) return '';
+ switch (block.type) {
+ case 'heading': return BlockRenderer.renderHeading(block);
+ case 'paragraph': return BlockRenderer.renderParagraph(block);
+ case 'image': return BlockRenderer.renderImage(block);
+ case 'quote': return BlockRenderer.renderQuote(block);
+ case 'gallery': return BlockRenderer.renderGallery(block);
+ case 'grid4': return BlockRenderer.renderGrid4(block);
+ case 'statistics': return BlockRenderer.renderStatistics(block);
+ case 'map-button': return BlockRenderer.renderMapButton(block);
+ default: return '';
+ }
+ }
+
+ static renderHeading(block) {
+ var level = Math.min(Math.max(parseInt(block.level) || 2, 1), 6);
+ return '' + (block.text || '') + '';
+ }
+
+ static renderParagraph(block) {
+ return '