Hma47 commited on
Commit
fb74069
·
verified ·
1 Parent(s): 8e44130

Upload 4 files

Browse files
Files changed (4) hide show
  1. Apache License.txt +17 -0
  2. README.md +92 -0
  3. index.html +1532 -0
  4. 📘 Step-by-Step Guide.txt +76 -0
Apache License.txt ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ Copyright 2025 Shift Mind AI Labs
6
+
7
+ Licensed under the Apache License, Version 2.0 (the "License");
8
+ you may not use this file except in compliance with the License.
9
+ You may obtain a copy of the License at
10
+
11
+ http://www.apache.org/licenses/LICENSE-2.0
12
+
13
+ Unless required by applicable law or agreed to in writing, software
14
+ distributed under the License is distributed on an "AS IS" BASIS,
15
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ See the License for the specific language governing permissions and
17
+ limitations under the License.
README.md ADDED
@@ -0,0 +1,92 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: "🌍 Cultural Intelligence Explorer"
3
+ emoji: "🧭"
4
+ colorFrom: "purple"
5
+ colorTo: "red"
6
+ sdk: "static"
7
+ sdk_version: "0.1.0"
8
+ app_file: "index.html"
9
+ pinned: false
10
+ ---
11
+
12
+ # 🌍 Cultural Intelligence Explorer – Global Edition with AI Analysis
13
+ **Developed by Shift Mind AI Labs**
14
+
15
+ The Cultural Intelligence Explorer is an open-source, browser-based learning tool that empowers students, educators, and global citizens to deeply explore world cultures, compare cultural themes, and develop empathy and global citizenship skills. With an integrated AI engine (via your OpenAI API key), users can select any country, focus on cultural themes, receive rich AI-generated insights, reflect on their learning, and receive a personal growth analysis.
16
+
17
+ ---
18
+
19
+ ## 🚀 Features
20
+
21
+ - **Explore Any Country**: Select from a global list, complete with flags and regions.
22
+ - **Thematic Focus**: Dive into specific cultural themes—family, education, communication, work, food, values, modern challenges, and more.
23
+ - **AI-Generated Insights**: Instantly generate nuanced, non-stereotypical cultural analyses (OpenAI API key required, stored only in your browser).
24
+ - **Guided Reflection**: Respond to evidence-based reflection prompts designed for cultural empathy and self-awareness.
25
+ - **AI Analysis**: Receive a structured AI comparison and growth report between cultural insights and your personal reflections.
26
+ - **Progress Tracking**: Save and revisit your exploration history—each journey is unique!
27
+ - **Privacy-First**: All processing and key storage are client-side; no user data leaves your browser.
28
+
29
+ ---
30
+
31
+ ## 🛠 How to Use
32
+
33
+ 1. **Open the tool** in your browser (no installation or login required).
34
+ 2. **Select a country** to explore, and optionally choose a specific theme.
35
+ 3. **Provide your OpenAI API key** when prompted (needed for AI features; your key stays private in your browser).
36
+ 4. **Generate Cultural Insights**: The AI summarizes key values, history, daily life, challenges, and misconceptions for your chosen country and theme.
37
+ 5. **Reflect**: Complete reflection prompts comparing your culture with the one explored—identify similarities, differences, surprises, and new perspectives.
38
+ 6. **Receive AI Analysis**: Generate a structured table that analyzes your learning, empathy development, and global citizenship growth.
39
+ 7. **Track Your Cultural Journey**: Review or revisit your past explorations in the built-in journey log.
40
+ 8. **Restart Anytime**: Explore as many countries or themes as you like.
41
+
42
+ ---
43
+
44
+ ## 👩‍🏫 For Educators: How It Supports Teaching
45
+
46
+ - **Global Citizenship & SEL**: Scaffolded to foster cultural intelligence, perspective-taking, and self-reflection.
47
+ - **Any Subject or Level**: Use in social studies, languages, IB Global Contexts, humanities, and more.
48
+ - **Portfolio & Assessment Ready**: Save and review students’ analysis and reflections for evidence of learning.
49
+ - **Safe for School Use**: No accounts, logins, or central data collection.
50
+
51
+ ---
52
+
53
+ ## 👨‍🎓 For Students: Benefits & Learning Outcomes
54
+
55
+ - **Personalized Global Learning**: Choose your own country and cultural theme for maximum relevance.
56
+ - **Empathy & Critical Thinking**: Evidence-based prompts support deep, honest self-reflection and challenge assumptions.
57
+ - **Skill Growth**: AI feedback highlights strengths and growth in cultural intelligence.
58
+ - **Reflection Portfolio**: Use AI analyses as evidence in digital portfolios or class projects.
59
+
60
+ ---
61
+
62
+ ## 🔐 Data Privacy Notice
63
+
64
+ - Your OpenAI API key is only stored locally in your browser.
65
+ - No user data is collected, shared, or sent to Shift Mind AI Labs, Hugging Face, or any third party.
66
+ - All AI requests go directly from your browser to OpenAI via your key.
67
+
68
+ ---
69
+
70
+ ## 📄 License
71
+
72
+ Licensed under the [Apache License 2.0](./LICENSE).
73
+
74
+ ---
75
+
76
+ ## 🧠 About Shift Mind AI Labs
77
+
78
+ Shift Mind AI Labs builds open-source, ethical AI tools for global learning and citizenship.
79
+
80
+ 🌐 www.shiftmind.io
81
+ ✉️ info@shiftmind.io
82
+
83
+ ---
84
+
85
+ ## 🙌 Contributing
86
+
87
+ Pull requests, bug reports, and feedback welcome!
88
+ For partnerships, integration, or pilots: **info@shiftmind.io**
89
+
90
+ ---
91
+
92
+ *Empowering global citizenship—one culture at a time.*
index.html ADDED
@@ -0,0 +1,1532 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <title>Cultural Intelligence Explorer - Global Edition with AI Analysis</title>
6
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
7
+ <!-- Tailwind CSS -->
8
+ <script src="https://cdn.tailwindcss.com"></script>
9
+ <!-- React & ReactDOM -->
10
+ <script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
11
+ <script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
12
+ <!-- @babel/standalone -->
13
+ <script crossorigin src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
14
+ <!-- Font Awesome for icons -->
15
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
16
+ <style>
17
+ html, body {
18
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
19
+ min-height: 100%;
20
+ margin: 0;
21
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
22
+ }
23
+
24
+ .glass {
25
+ background: rgba(255, 255, 255, 0.9);
26
+ backdrop-filter: blur(15px);
27
+ border-radius: 1.5rem;
28
+ box-shadow: 0 8px 32px rgba(31, 38, 135, 0.37);
29
+ border: 1px solid rgba(255, 255, 255, 0.18);
30
+ }
31
+
32
+ .country-dropdown {
33
+ background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
34
+ border-radius: 1rem;
35
+ padding: 1.5rem;
36
+ color: white;
37
+ margin-bottom: 2rem;
38
+ }
39
+
40
+ .dropdown-container {
41
+ position: relative;
42
+ width: 100%;
43
+ }
44
+
45
+ .dropdown-input {
46
+ width: 100%;
47
+ padding: 1rem;
48
+ border: 2px solid rgba(255,255,255,0.3);
49
+ border-radius: 0.75rem;
50
+ background: rgba(255,255,255,0.9);
51
+ color: #333;
52
+ font-size: 1rem;
53
+ cursor: pointer;
54
+ }
55
+
56
+ .dropdown-input:focus {
57
+ outline: none;
58
+ border-color: #fbbf24;
59
+ box-shadow: 0 0 0 3px rgba(251, 191, 36, 0.3);
60
+ }
61
+
62
+ .dropdown-list {
63
+ position: absolute;
64
+ top: 100%;
65
+ left: 0;
66
+ right: 0;
67
+ background: white;
68
+ border: 1px solid #e5e7eb;
69
+ border-radius: 0.75rem;
70
+ max-height: 300px;
71
+ overflow-y: auto;
72
+ z-index: 1000;
73
+ box-shadow: 0 10px 25px rgba(0,0,0,0.15);
74
+ }
75
+
76
+ .dropdown-item {
77
+ padding: 0.75rem 1rem;
78
+ cursor: pointer;
79
+ border-bottom: 1px solid #f3f4f6;
80
+ display: flex;
81
+ align-items: center;
82
+ gap: 0.75rem;
83
+ transition: background-color 0.2s;
84
+ }
85
+
86
+ .dropdown-item:hover {
87
+ background-color: #f8fafc;
88
+ }
89
+
90
+ .dropdown-item:last-child {
91
+ border-bottom: none;
92
+ }
93
+
94
+ .dropdown-item.highlighted {
95
+ background-color: #eff6ff;
96
+ }
97
+
98
+ .theme-card {
99
+ background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
100
+ border-radius: 0.75rem;
101
+ padding: 1rem;
102
+ color: white;
103
+ cursor: pointer;
104
+ transition: all 0.3s ease;
105
+ border: 2px solid transparent;
106
+ text-align: center;
107
+ }
108
+
109
+ .theme-card:hover {
110
+ transform: scale(1.05);
111
+ border-color: rgba(255,255,255,0.5);
112
+ }
113
+
114
+ .theme-card.selected {
115
+ border-color: #fbbf24;
116
+ box-shadow: 0 0 15px rgba(251, 191, 36, 0.4);
117
+ }
118
+
119
+ .insight-section {
120
+ background: linear-gradient(135deg, #a8edea 0%, #fed6e3 100%);
121
+ border-radius: 1rem;
122
+ padding: 1.5rem;
123
+ margin: 1rem 0;
124
+ border-left: 4px solid #667eea;
125
+ }
126
+
127
+ .reflection-card {
128
+ background: rgba(255, 255, 255, 0.95);
129
+ border-radius: 1rem;
130
+ padding: 1.5rem;
131
+ margin: 1rem 0;
132
+ box-shadow: 0 4px 15px rgba(0,0,0,0.1);
133
+ border: 1px solid rgba(102, 126, 234, 0.2);
134
+ }
135
+
136
+ .analysis-table {
137
+ background: rgba(255, 255, 255, 0.98);
138
+ border-radius: 1rem;
139
+ overflow: hidden;
140
+ box-shadow: 0 8px 25px rgba(0,0,0,0.1);
141
+ border: 1px solid rgba(102, 126, 234, 0.2);
142
+ }
143
+
144
+ .analysis-table table {
145
+ width: 100%;
146
+ border-collapse: collapse;
147
+ }
148
+
149
+ .analysis-table th {
150
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
151
+ color: white;
152
+ padding: 1rem;
153
+ text-align: left;
154
+ font-weight: 600;
155
+ border-bottom: 2px solid rgba(255,255,255,0.2);
156
+ }
157
+
158
+ .analysis-table td {
159
+ padding: 1rem;
160
+ border-bottom: 1px solid #e5e7eb;
161
+ vertical-align: top;
162
+ }
163
+
164
+ .analysis-table tr:last-child td {
165
+ border-bottom: none;
166
+ }
167
+
168
+ .analysis-table tr:nth-child(even) {
169
+ background-color: #f8fafc;
170
+ }
171
+
172
+ .analysis-table tr:hover {
173
+ background-color: #eff6ff;
174
+ }
175
+
176
+ .insight-badge {
177
+ display: inline-block;
178
+ background: linear-gradient(135deg, #10b981 0%, #059669 100%);
179
+ color: white;
180
+ padding: 0.25rem 0.75rem;
181
+ border-radius: 1rem;
182
+ font-size: 0.75rem;
183
+ font-weight: 600;
184
+ margin: 0.25rem 0.25rem 0.25rem 0;
185
+ }
186
+
187
+ .comparison-badge {
188
+ display: inline-block;
189
+ background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%);
190
+ color: white;
191
+ padding: 0.25rem 0.75rem;
192
+ border-radius: 1rem;
193
+ font-size: 0.75rem;
194
+ font-weight: 600;
195
+ margin: 0.25rem 0.25rem 0.25rem 0;
196
+ }
197
+
198
+ .progress-bar {
199
+ background: linear-gradient(90deg, #667eea 0%, #764ba2 100%);
200
+ height: 6px;
201
+ border-radius: 3px;
202
+ transition: width 0.5s ease;
203
+ }
204
+
205
+ .typing-indicator {
206
+ display: inline-flex;
207
+ align-items: center;
208
+ gap: 4px;
209
+ }
210
+
211
+ .typing-dot {
212
+ width: 8px;
213
+ height: 8px;
214
+ border-radius: 50%;
215
+ background: #667eea;
216
+ animation: typing 1.4s infinite ease-in-out;
217
+ }
218
+
219
+ .typing-dot:nth-child(1) { animation-delay: -0.32s; }
220
+ .typing-dot:nth-child(2) { animation-delay: -0.16s; }
221
+
222
+ @keyframes typing {
223
+ 0%, 80%, 100% { transform: scale(0); opacity: 0.5; }
224
+ 40% { transform: scale(1); opacity: 1; }
225
+ }
226
+
227
+ .fade-in {
228
+ animation: fadeIn 0.6s ease-in;
229
+ }
230
+
231
+ @keyframes fadeIn {
232
+ from { opacity: 0; transform: translateY(20px); }
233
+ to { opacity: 1; transform: translateY(0); }
234
+ }
235
+
236
+ .slide-in {
237
+ animation: slideIn 0.5s ease-out;
238
+ }
239
+
240
+ @keyframes slideIn {
241
+ from { opacity: 0; transform: translateX(-30px); }
242
+ to { opacity: 1; transform: translateX(0); }
243
+ }
244
+
245
+ /* Accessibility improvements */
246
+ .sr-only {
247
+ position: absolute;
248
+ width: 1px;
249
+ height: 1px;
250
+ padding: 0;
251
+ margin: -1px;
252
+ overflow: hidden;
253
+ clip: rect(0, 0, 0, 0);
254
+ white-space: nowrap;
255
+ border: 0;
256
+ }
257
+
258
+ button:focus, input:focus, textarea:focus, select:focus {
259
+ outline: 3px solid #fbbf24;
260
+ outline-offset: 2px;
261
+ }
262
+
263
+ .theme-card:focus {
264
+ outline: 3px solid #fbbf24;
265
+ outline-offset: 2px;
266
+ }
267
+
268
+ /* Responsive design */
269
+ @media (max-width: 768px) {
270
+ .theme-grid {
271
+ grid-template-columns: repeat(2, 1fr);
272
+ }
273
+
274
+ .analysis-table {
275
+ overflow-x: auto;
276
+ }
277
+
278
+ .analysis-table table {
279
+ min-width: 600px;
280
+ }
281
+ }
282
+
283
+ @media (max-width: 640px) {
284
+ .theme-grid {
285
+ grid-template-columns: 1fr;
286
+ }
287
+ }
288
+ </style>
289
+ </head>
290
+ <body>
291
+ <div id="root"></div>
292
+ <script type="text/babel">
293
+ const { useState, useEffect, useCallback, useRef } = React;
294
+
295
+ // Comprehensive list of world countries with flags and regions
296
+ const WORLD_COUNTRIES = [
297
+ // Africa
298
+ { id: 'algeria', name: 'Algeria', flag: '🇩🇿', region: 'North Africa' },
299
+ { id: 'angola', name: 'Angola', flag: '🇦🇴', region: 'Central Africa' },
300
+ { id: 'benin', name: 'Benin', flag: '🇧🇯', region: 'West Africa' },
301
+ { id: 'botswana', name: 'Botswana', flag: '🇧🇼', region: 'Southern Africa' },
302
+ { id: 'burkina-faso', name: 'Burkina Faso', flag: '🇧🇫', region: 'West Africa' },
303
+ { id: 'burundi', name: 'Burundi', flag: '🇧🇮', region: 'East Africa' },
304
+ { id: 'cameroon', name: 'Cameroon', flag: '🇨🇲', region: 'Central Africa' },
305
+ { id: 'cape-verde', name: 'Cape Verde', flag: '🇨🇻', region: 'West Africa' },
306
+ { id: 'chad', name: 'Chad', flag: '🇹🇩', region: 'Central Africa' },
307
+ { id: 'comoros', name: 'Comoros', flag: '🇰🇲', region: 'East Africa' },
308
+ { id: 'congo', name: 'Congo', flag: '🇨🇬', region: 'Central Africa' },
309
+ { id: 'drc', name: 'Democratic Republic of Congo', flag: '🇨🇩', region: 'Central Africa' },
310
+ { id: 'djibouti', name: 'Djibouti', flag: '🇩🇯', region: 'East Africa' },
311
+ { id: 'egypt', name: 'Egypt', flag: '🇪🇬', region: 'North Africa' },
312
+ { id: 'equatorial-guinea', name: 'Equatorial Guinea', flag: '🇬🇶', region: 'Central Africa' },
313
+ { id: 'eritrea', name: 'Eritrea', flag: '🇪🇷', region: 'East Africa' },
314
+ { id: 'eswatini', name: 'Eswatini', flag: '🇸🇿', region: 'Southern Africa' },
315
+ { id: 'ethiopia', name: 'Ethiopia', flag: '🇪🇹', region: 'East Africa' },
316
+ { id: 'gabon', name: 'Gabon', flag: '🇬🇦', region: 'Central Africa' },
317
+ { id: 'gambia', name: 'Gambia', flag: '🇬🇲', region: 'West Africa' },
318
+ { id: 'ghana', name: 'Ghana', flag: '🇬🇭', region: 'West Africa' },
319
+ { id: 'guinea', name: 'Guinea', flag: '🇬🇳', region: 'West Africa' },
320
+ { id: 'guinea-bissau', name: 'Guinea-Bissau', flag: '🇬🇼', region: 'West Africa' },
321
+ { id: 'ivory-coast', name: 'Ivory Coast', flag: '🇨🇮', region: 'West Africa' },
322
+ { id: 'kenya', name: 'Kenya', flag: '🇰🇪', region: 'East Africa' },
323
+ { id: 'lesotho', name: 'Lesotho', flag: '🇱🇸', region: 'Southern Africa' },
324
+ { id: 'liberia', name: 'Liberia', flag: '🇱🇷', region: 'West Africa' },
325
+ { id: 'libya', name: 'Libya', flag: '🇱🇾', region: 'North Africa' },
326
+ { id: 'madagascar', name: 'Madagascar', flag: '🇲🇬', region: 'East Africa' },
327
+ { id: 'malawi', name: 'Malawi', flag: '🇲🇼', region: 'Southern Africa' },
328
+ { id: 'mali', name: 'Mali', flag: '🇲🇱', region: 'West Africa' },
329
+ { id: 'mauritania', name: 'Mauritania', flag: '🇲🇷', region: 'West Africa' },
330
+ { id: 'mauritius', name: 'Mauritius', flag: '🇲🇺', region: 'East Africa' },
331
+ { id: 'morocco', name: 'Morocco', flag: '🇲🇦', region: 'North Africa' },
332
+ { id: 'mozambique', name: 'Mozambique', flag: '🇲🇿', region: 'Southern Africa' },
333
+ { id: 'namibia', name: 'Namibia', flag: '🇳🇦', region: 'Southern Africa' },
334
+ { id: 'niger', name: 'Niger', flag: '🇳🇪', region: 'West Africa' },
335
+ { id: 'nigeria', name: 'Nigeria', flag: '🇳🇬', region: 'West Africa' },
336
+ { id: 'rwanda', name: 'Rwanda', flag: '🇷🇼', region: 'East Africa' },
337
+ { id: 'sao-tome', name: 'São Tomé and Príncipe', flag: '🇸🇹', region: 'Central Africa' },
338
+ { id: 'senegal', name: 'Senegal', flag: '🇸🇳', region: 'West Africa' },
339
+ { id: 'seychelles', name: 'Seychelles', flag: '🇸🇨', region: 'East Africa' },
340
+ { id: 'sierra-leone', name: 'Sierra Leone', flag: '🇸🇱', region: 'West Africa' },
341
+ { id: 'somalia', name: 'Somalia', flag: '🇸🇴', region: 'East Africa' },
342
+ { id: 'south-africa', name: 'South Africa', flag: '🇿🇦', region: 'Southern Africa' },
343
+ { id: 'south-sudan', name: 'South Sudan', flag: '🇸🇸', region: 'East Africa' },
344
+ { id: 'sudan', name: 'Sudan', flag: '🇸🇩', region: 'North Africa' },
345
+ { id: 'tanzania', name: 'Tanzania', flag: '🇹🇿', region: 'East Africa' },
346
+ { id: 'togo', name: 'Togo', flag: '🇹🇬', region: 'West Africa' },
347
+ { id: 'tunisia', name: 'Tunisia', flag: '🇹🇳', region: 'North Africa' },
348
+ { id: 'uganda', name: 'Uganda', flag: '🇺🇬', region: 'East Africa' },
349
+ { id: 'zambia', name: 'Zambia', flag: '🇿🇲', region: 'Southern Africa' },
350
+ { id: 'zimbabwe', name: 'Zimbabwe', flag: '🇿🇼', region: 'Southern Africa' },
351
+
352
+ // Asia
353
+ { id: 'afghanistan', name: 'Afghanistan', flag: '🇦🇫', region: 'Central Asia' },
354
+ { id: 'armenia', name: 'Armenia', flag: '🇦🇲', region: 'Western Asia' },
355
+ { id: 'azerbaijan', name: 'Azerbaijan', flag: '🇦🇿', region: 'Western Asia' },
356
+ { id: 'bahrain', name: 'Bahrain', flag: '🇧🇭', region: 'Western Asia' },
357
+ { id: 'bangladesh', name: 'Bangladesh', flag: '🇧🇩', region: 'South Asia' },
358
+ { id: 'bhutan', name: 'Bhutan', flag: '🇧🇹', region: 'South Asia' },
359
+ { id: 'brunei', name: 'Brunei', flag: '🇧🇳', region: 'Southeast Asia' },
360
+ { id: 'cambodia', name: 'Cambodia', flag: '🇰🇭', region: 'Southeast Asia' },
361
+ { id: 'china', name: 'China', flag: '🇨🇳', region: 'East Asia' },
362
+ { id: 'cyprus', name: 'Cyprus', flag: '🇨🇾', region: 'Western Asia' },
363
+ { id: 'georgia', name: 'Georgia', flag: '🇬🇪', region: 'Western Asia' },
364
+ { id: 'india', name: 'India', flag: '🇮🇳', region: 'South Asia' },
365
+ { id: 'indonesia', name: 'Indonesia', flag: '🇮🇩', region: 'Southeast Asia' },
366
+ { id: 'iran', name: 'Iran', flag: '🇮🇷', region: 'Western Asia' },
367
+ { id: 'iraq', name: 'Iraq', flag: '🇮🇶', region: 'Western Asia' },
368
+ { id: 'israel', name: 'Israel', flag: '🇮🇱', region: 'Western Asia' },
369
+ { id: 'japan', name: 'Japan', flag: '🇯🇵', region: 'East Asia' },
370
+ { id: 'jordan', name: 'Jordan', flag: '🇯🇴', region: 'Western Asia' },
371
+ { id: 'kazakhstan', name: 'Kazakhstan', flag: '🇰🇿', region: 'Central Asia' },
372
+ { id: 'kuwait', name: 'Kuwait', flag: '🇰🇼', region: 'Western Asia' },
373
+ { id: 'kyrgyzstan', name: 'Kyrgyzstan', flag: '🇰🇬', region: 'Central Asia' },
374
+ { id: 'laos', name: 'Laos', flag: '🇱🇦', region: 'Southeast Asia' },
375
+ { id: 'lebanon', name: 'Lebanon', flag: '🇱🇧', region: 'Western Asia' },
376
+ { id: 'malaysia', name: 'Malaysia', flag: '🇲🇾', region: 'Southeast Asia' },
377
+ { id: 'maldives', name: 'Maldives', flag: '🇲🇻', region: 'South Asia' },
378
+ { id: 'mongolia', name: 'Mongolia', flag: '🇲🇳', region: 'East Asia' },
379
+ { id: 'myanmar', name: 'Myanmar', flag: '🇲🇲', region: 'Southeast Asia' },
380
+ { id: 'nepal', name: 'Nepal', flag: '🇳🇵', region: 'South Asia' },
381
+ { id: 'north-korea', name: 'North Korea', flag: '🇰🇵', region: 'East Asia' },
382
+ { id: 'oman', name: 'Oman', flag: '🇴🇲', region: 'Western Asia' },
383
+ { id: 'pakistan', name: 'Pakistan', flag: '🇵🇰', region: 'South Asia' },
384
+ { id: 'palestine', name: 'Palestine', flag: '🇵🇸', region: 'Western Asia' },
385
+ { id: 'philippines', name: 'Philippines', flag: '🇵🇭', region: 'Southeast Asia' },
386
+ { id: 'qatar', name: 'Qatar', flag: '🇶🇦', region: 'Western Asia' },
387
+ { id: 'saudi-arabia', name: 'Saudi Arabia', flag: '🇸🇦', region: 'Western Asia' },
388
+ { id: 'singapore', name: 'Singapore', flag: '🇸🇬', region: 'Southeast Asia' },
389
+ { id: 'south-korea', name: 'South Korea', flag: '🇰🇷', region: 'East Asia' },
390
+ { id: 'sri-lanka', name: 'Sri Lanka', flag: '🇱🇰', region: 'South Asia' },
391
+ { id: 'syria', name: 'Syria', flag: '🇸🇾', region: 'Western Asia' },
392
+ { id: 'taiwan', name: 'Taiwan', flag: '🇹🇼', region: 'East Asia' },
393
+ { id: 'tajikistan', name: 'Tajikistan', flag: '🇹🇯', region: 'Central Asia' },
394
+ { id: 'thailand', name: 'Thailand', flag: '🇹🇭', region: 'Southeast Asia' },
395
+ { id: 'timor-leste', name: 'Timor-Leste', flag: '🇹🇱', region: 'Southeast Asia' },
396
+ { id: 'turkey', name: 'Turkey', flag: '🇹🇷', region: 'Western Asia' },
397
+ { id: 'turkmenistan', name: 'Turkmenistan', flag: '🇹🇲', region: 'Central Asia' },
398
+ { id: 'uae', name: 'United Arab Emirates', flag: '🇦🇪', region: 'Western Asia' },
399
+ { id: 'uzbekistan', name: 'Uzbekistan', flag: '🇺🇿', region: 'Central Asia' },
400
+ { id: 'vietnam', name: 'Vietnam', flag: '🇻🇳', region: 'Southeast Asia' },
401
+ { id: 'yemen', name: 'Yemen', flag: '🇾🇪', region: 'Western Asia' },
402
+
403
+ // Europe
404
+ { id: 'albania', name: 'Albania', flag: '🇦🇱', region: 'Southern Europe' },
405
+ { id: 'andorra', name: 'Andorra', flag: '🇦🇩', region: 'Southern Europe' },
406
+ { id: 'austria', name: 'Austria', flag: '🇦🇹', region: 'Central Europe' },
407
+ { id: 'belarus', name: 'Belarus', flag: '🇧🇾', region: 'Eastern Europe' },
408
+ { id: 'belgium', name: 'Belgium', flag: '🇧🇪', region: 'Western Europe' },
409
+ { id: 'bosnia', name: 'Bosnia and Herzegovina', flag: '🇧🇦', region: 'Southern Europe' },
410
+ { id: 'bulgaria', name: 'Bulgaria', flag: '🇧🇬', region: 'Eastern Europe' },
411
+ { id: 'croatia', name: 'Croatia', flag: '🇭🇷', region: 'Southern Europe' },
412
+ { id: 'czech-republic', name: 'Czech Republic', flag: '🇨🇿', region: 'Central Europe' },
413
+ { id: 'denmark', name: 'Denmark', flag: '🇩🇰', region: 'Northern Europe' },
414
+ { id: 'estonia', name: 'Estonia', flag: '🇪🇪', region: 'Northern Europe' },
415
+ { id: 'finland', name: 'Finland', flag: '🇫🇮', region: 'Northern Europe' },
416
+ { id: 'france', name: 'France', flag: '🇫🇷', region: 'Western Europe' },
417
+ { id: 'germany', name: 'Germany', flag: '🇩🇪', region: 'Central Europe' },
418
+ { id: 'greece', name: 'Greece', flag: '🇬🇷', region: 'Southern Europe' },
419
+ { id: 'hungary', name: 'Hungary', flag: '🇭🇺', region: 'Central Europe' },
420
+ { id: 'iceland', name: 'Iceland', flag: '🇮🇸', region: 'Northern Europe' },
421
+ { id: 'ireland', name: 'Ireland', flag: '🇮🇪', region: 'Northern Europe' },
422
+ { id: 'italy', name: 'Italy', flag: '🇮🇹', region: 'Southern Europe' },
423
+ { id: 'kosovo', name: 'Kosovo', flag: '🇽🇰', region: 'Southern Europe' },
424
+ { id: 'latvia', name: 'Latvia', flag: '🇱🇻', region: 'Northern Europe' },
425
+ { id: 'liechtenstein', name: 'Liechtenstein', flag: '🇱🇮', region: 'Central Europe' },
426
+ { id: 'lithuania', name: 'Lithuania', flag: '🇱🇹', region: 'Northern Europe' },
427
+ { id: 'luxembourg', name: 'Luxembourg', flag: '🇱🇺', region: 'Western Europe' },
428
+ { id: 'malta', name: 'Malta', flag: '🇲🇹', region: 'Southern Europe' },
429
+ { id: 'moldova', name: 'Moldova', flag: '🇲🇩', region: 'Eastern Europe' },
430
+ { id: 'monaco', name: 'Monaco', flag: '🇲🇨', region: 'Western Europe' },
431
+ { id: 'montenegro', name: 'Montenegro', flag: '🇲🇪', region: 'Southern Europe' },
432
+ { id: 'netherlands', name: 'Netherlands', flag: '🇳🇱', region: 'Western Europe' },
433
+ { id: 'north-macedonia', name: 'North Macedonia', flag: '🇲🇰', region: 'Southern Europe' },
434
+ { id: 'norway', name: 'Norway', flag: '🇳🇴', region: 'Northern Europe' },
435
+ { id: 'poland', name: 'Poland', flag: '🇵🇱', region: 'Central Europe' },
436
+ { id: 'portugal', name: 'Portugal', flag: '🇵🇹', region: 'Southern Europe' },
437
+ { id: 'romania', name: 'Romania', flag: '🇷🇴', region: 'Eastern Europe' },
438
+ { id: 'russia', name: 'Russia', flag: '🇷🇺', region: 'Eastern Europe' },
439
+ { id: 'san-marino', name: 'San Marino', flag: '🇸🇲', region: 'Southern Europe' },
440
+ { id: 'serbia', name: 'Serbia', flag: '🇷🇸', region: 'Southern Europe' },
441
+ { id: 'slovakia', name: 'Slovakia', flag: '🇸🇰', region: 'Central Europe' },
442
+ { id: 'slovenia', name: 'Slovenia', flag: '🇸🇮', region: 'Central Europe' },
443
+ { id: 'spain', name: 'Spain', flag: '🇪🇸', region: 'Southern Europe' },
444
+ { id: 'sweden', name: 'Sweden', flag: '🇸🇪', region: 'Northern Europe' },
445
+ { id: 'switzerland', name: 'Switzerland', flag: '🇨🇭', region: 'Central Europe' },
446
+ { id: 'ukraine', name: 'Ukraine', flag: '🇺🇦', region: 'Eastern Europe' },
447
+ { id: 'united-kingdom', name: 'United Kingdom', flag: '🇬🇧', region: 'Northern Europe' },
448
+ { id: 'vatican', name: 'Vatican City', flag: '🇻🇦', region: 'Southern Europe' },
449
+
450
+ // North America
451
+ { id: 'antigua', name: 'Antigua and Barbuda', flag: '🇦🇬', region: 'Caribbean' },
452
+ { id: 'bahamas', name: 'Bahamas', flag: '🇧🇸', region: 'Caribbean' },
453
+ { id: 'barbados', name: 'Barbados', flag: '🇧🇧', region: 'Caribbean' },
454
+ { id: 'belize', name: 'Belize', flag: '🇧🇿', region: 'Central America' },
455
+ { id: 'canada', name: 'Canada', flag: '🇨🇦', region: 'North America' },
456
+ { id: 'costa-rica', name: 'Costa Rica', flag: '🇨🇷', region: 'Central America' },
457
+ { id: 'cuba', name: 'Cuba', flag: '🇨🇺', region: 'Caribbean' },
458
+ { id: 'dominica', name: 'Dominica', flag: '🇩🇲', region: 'Caribbean' },
459
+ { id: 'dominican-republic', name: 'Dominican Republic', flag: '🇩🇴', region: 'Caribbean' },
460
+ { id: 'el-salvador', name: 'El Salvador', flag: '🇸🇻', region: 'Central America' },
461
+ { id: 'grenada', name: 'Grenada', flag: '🇬🇩', region: 'Caribbean' },
462
+ { id: 'guatemala', name: 'Guatemala', flag: '🇬🇹', region: 'Central America' },
463
+ { id: 'haiti', name: 'Haiti', flag: '🇭🇹', region: 'Caribbean' },
464
+ { id: 'honduras', name: 'Honduras', flag: '🇭🇳', region: 'Central America' },
465
+ { id: 'jamaica', name: 'Jamaica', flag: '🇯🇲', region: 'Caribbean' },
466
+ { id: 'mexico', name: 'Mexico', flag: '🇲🇽', region: 'North America' },
467
+ { id: 'nicaragua', name: 'Nicaragua', flag: '🇳🇮', region: 'Central America' },
468
+ { id: 'panama', name: 'Panama', flag: '🇵🇦', region: 'Central America' },
469
+ { id: 'saint-kitts', name: 'Saint Kitts and Nevis', flag: '🇰🇳', region: 'Caribbean' },
470
+ { id: 'saint-lucia', name: 'Saint Lucia', flag: '🇱🇨', region: 'Caribbean' },
471
+ { id: 'saint-vincent', name: 'Saint Vincent and the Grenadines', flag: '🇻🇨', region: 'Caribbean' },
472
+ { id: 'trinidad', name: 'Trinidad and Tobago', flag: '🇹🇹', region: 'Caribbean' },
473
+ { id: 'usa', name: 'United States', flag: '🇺🇸', region: 'North America' },
474
+
475
+ // South America
476
+ { id: 'argentina', name: 'Argentina', flag: '🇦🇷', region: 'South America' },
477
+ { id: 'bolivia', name: 'Bolivia', flag: '🇧🇴', region: 'South America' },
478
+ { id: 'brazil', name: 'Brazil', flag: '🇧🇷', region: 'South America' },
479
+ { id: 'chile', name: 'Chile', flag: '🇨🇱', region: 'South America' },
480
+ { id: 'colombia', name: 'Colombia', flag: '🇨🇴', region: 'South America' },
481
+ { id: 'ecuador', name: 'Ecuador', flag: '🇪🇨', region: 'South America' },
482
+ { id: 'guyana', name: 'Guyana', flag: '🇬🇾', region: 'South America' },
483
+ { id: 'paraguay', name: 'Paraguay', flag: '🇵🇾', region: 'South America' },
484
+ { id: 'peru', name: 'Peru', flag: '🇵🇪', region: 'South America' },
485
+ { id: 'suriname', name: 'Suriname', flag: '🇸🇷', region: 'South America' },
486
+ { id: 'uruguay', name: 'Uruguay', flag: '🇺🇾', region: 'South America' },
487
+ { id: 'venezuela', name: 'Venezuela', flag: '🇻🇪', region: 'South America' },
488
+
489
+ // Oceania
490
+ { id: 'australia', name: 'Australia', flag: '🇦🇺', region: 'Oceania' },
491
+ { id: 'fiji', name: 'Fiji', flag: '🇫🇯', region: 'Oceania' },
492
+ { id: 'kiribati', name: 'Kiribati', flag: '🇰🇮', region: 'Oceania' },
493
+ { id: 'marshall-islands', name: 'Marshall Islands', flag: '🇲🇭', region: 'Oceania' },
494
+ { id: 'micronesia', name: 'Micronesia', flag: '🇫🇲', region: 'Oceania' },
495
+ { id: 'nauru', name: 'Nauru', flag: '🇳🇷', region: 'Oceania' },
496
+ { id: 'new-zealand', name: 'New Zealand', flag: '🇳🇿', region: 'Oceania' },
497
+ { id: 'palau', name: 'Palau', flag: '🇵🇼', region: 'Oceania' },
498
+ { id: 'papua-new-guinea', name: 'Papua New Guinea', flag: '🇵🇬', region: 'Oceania' },
499
+ { id: 'samoa', name: 'Samoa', flag: '🇼🇸', region: 'Oceania' },
500
+ { id: 'solomon-islands', name: 'Solomon Islands', flag: '🇸🇧', region: 'Oceania' },
501
+ { id: 'tonga', name: 'Tonga', flag: '🇹🇴', region: 'Oceania' },
502
+ { id: 'tuvalu', name: 'Tuvalu', flag: '🇹🇻', region: 'Oceania' },
503
+ { id: 'vanuatu', name: 'Vanuatu', flag: '🇻🇺', region: 'Oceania' }
504
+ ];
505
+
506
+ const THEMES = [
507
+ {
508
+ id: 'family',
509
+ name: 'Family Life',
510
+ icon: '👨‍👩‍👧‍👦',
511
+ description: 'Family structures, relationships, and traditions'
512
+ },
513
+ {
514
+ id: 'education',
515
+ name: 'Education',
516
+ icon: '📚',
517
+ description: 'Learning systems, values, and approaches to knowledge'
518
+ },
519
+ {
520
+ id: 'traditions',
521
+ name: 'Traditions & Festivals',
522
+ icon: '🎭',
523
+ description: 'Cultural celebrations, rituals, and customs'
524
+ },
525
+ {
526
+ id: 'communication',
527
+ name: 'Communication',
528
+ icon: '💬',
529
+ description: 'Language, non-verbal cues, and social interactions'
530
+ },
531
+ {
532
+ id: 'work',
533
+ name: 'Work & Business',
534
+ icon: '💼',
535
+ description: 'Professional culture, work ethics, and business practices'
536
+ },
537
+ {
538
+ id: 'food',
539
+ name: 'Food & Dining',
540
+ icon: '🍽️',
541
+ description: 'Culinary traditions, dining etiquette, and food culture'
542
+ },
543
+ {
544
+ id: 'values',
545
+ name: 'Core Values',
546
+ icon: '⭐',
547
+ description: 'Fundamental beliefs, principles, and worldviews'
548
+ },
549
+ {
550
+ id: 'challenges',
551
+ name: 'Modern Challenges',
552
+ icon: '🌍',
553
+ description: 'Contemporary issues and cultural adaptations'
554
+ }
555
+ ];
556
+
557
+ const REFLECTION_PROMPTS = [
558
+ {
559
+ id: 'similarities',
560
+ question: 'What similarities did you discover between this culture and your own?',
561
+ icon: '🤝'
562
+ },
563
+ {
564
+ id: 'differences',
565
+ question: 'What differences surprised you the most?',
566
+ icon: '🔍'
567
+ },
568
+ {
569
+ id: 'assumptions',
570
+ question: 'What assumptions about this culture were challenged?',
571
+ icon: '💭'
572
+ },
573
+ {
574
+ id: 'learning',
575
+ question: 'What valuable lesson or practice could you adopt from this culture?',
576
+ icon: '💡'
577
+ },
578
+ {
579
+ id: 'empathy',
580
+ question: 'How has this exploration changed your perspective on cultural diversity?',
581
+ icon: '❤️'
582
+ }
583
+ ];
584
+
585
+ // Country Dropdown Component
586
+ function CountryDropdown({ selectedCountry, onCountrySelect }) {
587
+ const [isOpen, setIsOpen] = useState(false);
588
+ const [searchTerm, setSearchTerm] = useState('');
589
+ const [highlightedIndex, setHighlightedIndex] = useState(-1);
590
+ const dropdownRef = useRef(null);
591
+ const inputRef = useRef(null);
592
+
593
+ const filteredCountries = WORLD_COUNTRIES.filter(country =>
594
+ country.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
595
+ country.region.toLowerCase().includes(searchTerm.toLowerCase())
596
+ );
597
+
598
+ useEffect(() => {
599
+ function handleClickOutside(event) {
600
+ if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
601
+ setIsOpen(false);
602
+ setHighlightedIndex(-1);
603
+ }
604
+ }
605
+
606
+ document.addEventListener('mousedown', handleClickOutside);
607
+ return () => document.removeEventListener('mousedown', handleClickOutside);
608
+ }, []);
609
+
610
+ const handleInputChange = (e) => {
611
+ setSearchTerm(e.target.value);
612
+ setIsOpen(true);
613
+ setHighlightedIndex(-1);
614
+ };
615
+
616
+ const handleKeyDown = (e) => {
617
+ if (!isOpen) {
618
+ if (e.key === 'Enter' || e.key === 'ArrowDown') {
619
+ setIsOpen(true);
620
+ setHighlightedIndex(0);
621
+ }
622
+ return;
623
+ }
624
+
625
+ switch (e.key) {
626
+ case 'ArrowDown':
627
+ e.preventDefault();
628
+ setHighlightedIndex(prev =>
629
+ prev < filteredCountries.length - 1 ? prev + 1 : 0
630
+ );
631
+ break;
632
+ case 'ArrowUp':
633
+ e.preventDefault();
634
+ setHighlightedIndex(prev =>
635
+ prev > 0 ? prev - 1 : filteredCountries.length - 1
636
+ );
637
+ break;
638
+ case 'Enter':
639
+ e.preventDefault();
640
+ if (highlightedIndex >= 0 && filteredCountries[highlightedIndex]) {
641
+ handleCountrySelect(filteredCountries[highlightedIndex]);
642
+ }
643
+ break;
644
+ case 'Escape':
645
+ setIsOpen(false);
646
+ setHighlightedIndex(-1);
647
+ inputRef.current?.blur();
648
+ break;
649
+ }
650
+ };
651
+
652
+ const handleCountrySelect = (country) => {
653
+ onCountrySelect(country);
654
+ setSearchTerm('');
655
+ setIsOpen(false);
656
+ setHighlightedIndex(-1);
657
+ };
658
+
659
+ const displayValue = selectedCountry
660
+ ? `${selectedCountry.flag} ${selectedCountry.name}`
661
+ : searchTerm;
662
+
663
+ return (
664
+ <div className="dropdown-container" ref={dropdownRef}>
665
+ <input
666
+ ref={inputRef}
667
+ type="text"
668
+ className="dropdown-input"
669
+ placeholder={selectedCountry ? `${selectedCountry.flag} ${selectedCountry.name}` : "Search for a country..."}
670
+ value={isOpen ? searchTerm : displayValue}
671
+ onChange={handleInputChange}
672
+ onKeyDown={handleKeyDown}
673
+ onFocus={() => setIsOpen(true)}
674
+ autoComplete="off"
675
+ aria-expanded={isOpen}
676
+ aria-haspopup="listbox"
677
+ role="combobox"
678
+ />
679
+
680
+ {isOpen && (
681
+ <div className="dropdown-list" role="listbox">
682
+ {filteredCountries.length > 0 ? (
683
+ filteredCountries.map((country, index) => (
684
+ <div
685
+ key={country.id}
686
+ className={`dropdown-item ${index === highlightedIndex ? 'highlighted' : ''}`}
687
+ onClick={() => handleCountrySelect(country)}
688
+ role="option"
689
+ aria-selected={selectedCountry?.id === country.id}
690
+ >
691
+ <span className="text-xl">{country.flag}</span>
692
+ <div>
693
+ <div className="font-semibold text-gray-800">{country.name}</div>
694
+ <div className="text-sm text-gray-500">{country.region}</div>
695
+ </div>
696
+ </div>
697
+ ))
698
+ ) : (
699
+ <div className="dropdown-item text-gray-500">
700
+ No countries found matching "{searchTerm}"
701
+ </div>
702
+ )}
703
+ </div>
704
+ )}
705
+ </div>
706
+ );
707
+ }
708
+
709
+ function CulturalIntelligenceExplorer() {
710
+ // Core state
711
+ const [phase, setPhase] = useState(1); // 1: Selection, 2: Insights, 3: Reflection, 4: Analysis
712
+ const [selectedCountry, setSelectedCountry] = useState(null);
713
+ const [selectedTheme, setSelectedTheme] = useState(null);
714
+ const [apiKey, setApiKey] = useState('');
715
+ const [showApiKeyModal, setShowApiKeyModal] = useState(false);
716
+
717
+ // AI and insights state
718
+ const [insights, setInsights] = useState(null);
719
+ const [isGeneratingInsights, setIsGeneratingInsights] = useState(false);
720
+ const [aiError, setAiError] = useState('');
721
+
722
+ // Reflection state
723
+ const [reflections, setReflections] = useState({});
724
+ const [explorationHistory, setExplorationHistory] = useState([]);
725
+
726
+ // Analysis state
727
+ const [analysis, setAnalysis] = useState(null);
728
+ const [isGeneratingAnalysis, setIsGeneratingAnalysis] = useState(false);
729
+
730
+ // Load data from localStorage
731
+ useEffect(() => {
732
+ try {
733
+ const savedApiKey = localStorage.getItem('cultural-explorer-api-key');
734
+ const savedHistory = localStorage.getItem('cultural-explorer-history');
735
+
736
+ if (savedApiKey) {
737
+ setApiKey(savedApiKey);
738
+ }
739
+ if (savedHistory) {
740
+ setExplorationHistory(JSON.parse(savedHistory));
741
+ }
742
+ } catch (error) {
743
+ console.error('Error loading saved data:', error);
744
+ }
745
+ }, []);
746
+
747
+ // Save data to localStorage
748
+ useEffect(() => {
749
+ try {
750
+ if (apiKey) {
751
+ localStorage.setItem('cultural-explorer-api-key', apiKey);
752
+ }
753
+ } catch (error) {
754
+ console.error('Error saving API key:', error);
755
+ }
756
+ }, [apiKey]);
757
+
758
+ useEffect(() => {
759
+ try {
760
+ localStorage.setItem('cultural-explorer-history', JSON.stringify(explorationHistory));
761
+ } catch (error) {
762
+ console.error('Error saving history:', error);
763
+ }
764
+ }, [explorationHistory]);
765
+
766
+ const handleCountrySelect = (country) => {
767
+ setSelectedCountry(country);
768
+ };
769
+
770
+ const handleThemeSelect = (theme) => {
771
+ setSelectedTheme(theme);
772
+ };
773
+
774
+ const proceedToInsights = () => {
775
+ if (!selectedCountry) {
776
+ alert('Please select a country to explore');
777
+ return;
778
+ }
779
+
780
+ if (!apiKey) {
781
+ setShowApiKeyModal(true);
782
+ return;
783
+ }
784
+
785
+ setPhase(2);
786
+ generateInsights();
787
+ };
788
+
789
+ const generateInsights = async () => {
790
+ if (!apiKey || !selectedCountry) return;
791
+
792
+ setIsGeneratingInsights(true);
793
+ setAiError('');
794
+
795
+ try {
796
+ const prompt = createInsightPrompt();
797
+ const response = await callOpenAI(prompt);
798
+ setInsights(response);
799
+ } catch (error) {
800
+ console.error('Error generating insights:', error);
801
+ setAiError(`Failed to generate insights: ${error.message}`);
802
+ } finally {
803
+ setIsGeneratingInsights(false);
804
+ }
805
+ };
806
+
807
+ const createInsightPrompt = () => {
808
+ const country = selectedCountry;
809
+ const theme = selectedTheme;
810
+
811
+ return `You are a cultural intelligence educator helping students develop empathy and global citizenship. Provide comprehensive, respectful insights about ${country.name} culture.
812
+
813
+ ${theme ? `Focus specifically on: ${theme.name} - ${theme.description}` : 'Provide a general cultural overview.'}
814
+
815
+ Structure your response with the following sections:
816
+
817
+ **CULTURAL OVERVIEW:**
818
+ Provide a respectful, nuanced introduction to ${country.name} culture, avoiding stereotypes.
819
+
820
+ **KEY CULTURAL VALUES:**
821
+ List and explain 4-5 core values that guide this culture.
822
+
823
+ **DAILY LIFE INSIGHTS:**
824
+ Describe how these values manifest in everyday life.
825
+
826
+ ${theme ? `**${theme.name.toUpperCase()} FOCUS:**
827
+ Provide detailed insights about ${theme.description} in ${country.name} culture.` : ''}
828
+
829
+ **HISTORICAL CONTEXT:**
830
+ Brief background on how history shaped current cultural practices.
831
+
832
+ **MODERN ADAPTATIONS:**
833
+ How this culture navigates contemporary global challenges while preserving traditions.
834
+
835
+ **COMMON MISCONCEPTIONS:**
836
+ Address 2-3 common stereotypes or misconceptions about this culture.
837
+
838
+ **CULTURAL WISDOM:**
839
+ Share a meaningful lesson or perspective this culture offers to the world.
840
+
841
+ Keep the tone educational, respectful, and engaging. Use specific examples while avoiding overgeneralization. Aim for 800-1000 words total.`;
842
+ };
843
+
844
+ const callOpenAI = async (prompt) => {
845
+ if (!apiKey) {
846
+ throw new Error('API key not provided');
847
+ }
848
+
849
+ const response = await fetch('https://api.openai.com/v1/chat/completions', {
850
+ method: 'POST',
851
+ headers: {
852
+ 'Content-Type': 'application/json',
853
+ 'Authorization': `Bearer ${apiKey.trim()}`
854
+ },
855
+ body: JSON.stringify({
856
+ model: 'gpt-4o-mini',
857
+ messages: [
858
+ { role: 'system', content: 'You are a cultural intelligence educator focused on promoting empathy, understanding, and global citizenship.' },
859
+ { role: 'user', content: prompt }
860
+ ],
861
+ max_tokens: 1200,
862
+ temperature: 0.7
863
+ })
864
+ });
865
+
866
+ if (!response.ok) {
867
+ const errorData = await response.json().catch(() => ({}));
868
+ throw new Error(`OpenAI API error: ${response.status} ${response.statusText}${errorData.error ? ` - ${errorData.error.message}` : ''}`);
869
+ }
870
+
871
+ const data = await response.json();
872
+
873
+ if (!data.choices || !data.choices[0] || !data.choices[0].message) {
874
+ throw new Error('Invalid response format from OpenAI API');
875
+ }
876
+
877
+ return data.choices[0].message.content;
878
+ };
879
+
880
+ const proceedToReflection = () => {
881
+ setPhase(3);
882
+ };
883
+
884
+ const handleReflectionChange = (promptId, value) => {
885
+ setReflections(prev => ({
886
+ ...prev,
887
+ [promptId]: value
888
+ }));
889
+ };
890
+
891
+ const proceedToAnalysis = () => {
892
+ setPhase(4);
893
+ generateAnalysis();
894
+ };
895
+
896
+ const generateAnalysis = async () => {
897
+ if (!apiKey || !selectedCountry || !insights) return;
898
+
899
+ setIsGeneratingAnalysis(true);
900
+ setAiError('');
901
+
902
+ try {
903
+ const prompt = createAnalysisPrompt();
904
+ const response = await callOpenAI(prompt);
905
+ setAnalysis(response);
906
+ } catch (error) {
907
+ console.error('Error generating analysis:', error);
908
+ setAiError(`Failed to generate analysis: ${error.message}`);
909
+ } finally {
910
+ setIsGeneratingAnalysis(false);
911
+ }
912
+ };
913
+
914
+ const createAnalysisPrompt = () => {
915
+ const country = selectedCountry;
916
+ const theme = selectedTheme;
917
+ const reflectionText = Object.entries(reflections)
918
+ .map(([key, value]) => {
919
+ const prompt = REFLECTION_PROMPTS.find(p => p.id === key);
920
+ return `${prompt?.question}: ${value}`;
921
+ })
922
+ .join('\n\n');
923
+
924
+ return `You are a cultural intelligence educator analyzing a student's cultural exploration journey. Based on the cultural insights and student reflections below, provide a comprehensive analysis in a structured tabular format.
925
+
926
+ **CULTURAL CONTEXT:**
927
+ Country: ${country.name} (${country.region})
928
+ ${theme ? `Focus Theme: ${theme.name} - ${theme.description}` : 'General cultural exploration'}
929
+
930
+ **CULTURAL INSIGHTS PROVIDED:**
931
+ ${insights}
932
+
933
+ **STUDENT REFLECTIONS:**
934
+ ${reflectionText}
935
+
936
+ **ANALYSIS REQUIREMENTS:**
937
+ Create a detailed analysis table with the following structure. Format your response as a structured table with clear rows and columns:
938
+
939
+ | Analysis Category | Cultural Theme Insights | Student Reflection Analysis | Comparison & Growth Indicators |
940
+ |-------------------|------------------------|----------------------------|-------------------------------|
941
+ | Cultural Understanding | [Key cultural insights from the theme] | [Analysis of student's understanding] | [Evidence of learning and growth] |
942
+ | Personal Connection | [How culture relates to universal themes] | [Student's personal connections made] | [Depth of empathy development] |
943
+ | Assumption Challenges | [Cultural misconceptions addressed] | [Student's assumption changes] | [Critical thinking evidence] |
944
+ | Learning Integration | [Key cultural lessons identified] | [Student's learning takeaways] | [Application potential] |
945
+ | Perspective Transformation | [Cultural wisdom shared] | [Student's perspective shifts] | [Global citizenship development] |
946
+
947
+ For each row, provide:
948
+ - 2-3 specific insights from the cultural theme
949
+ - Detailed analysis of the student's reflection quality and depth
950
+ - Evidence of learning, growth, and cultural intelligence development
951
+ - Specific examples and quotes from student responses where relevant
952
+
953
+ Keep the analysis educational, encouraging, and focused on cultural intelligence development. Highlight strengths and areas for continued growth.`;
954
+ };
955
+
956
+ const completeExploration = () => {
957
+ const exploration = {
958
+ id: Date.now(),
959
+ timestamp: new Date().toISOString(),
960
+ country: selectedCountry,
961
+ theme: selectedTheme,
962
+ insights: insights,
963
+ reflections: reflections,
964
+ analysis: analysis
965
+ };
966
+
967
+ setExplorationHistory(prev => [...prev, exploration]);
968
+
969
+ // Reset for new exploration
970
+ setPhase(1);
971
+ setSelectedCountry(null);
972
+ setSelectedTheme(null);
973
+ setInsights(null);
974
+ setReflections({});
975
+ setAnalysis(null);
976
+ setAiError('');
977
+ };
978
+
979
+ const validateApiKey = async (key) => {
980
+ try {
981
+ const response = await fetch('https://api.openai.com/v1/models', {
982
+ headers: {
983
+ 'Authorization': `Bearer ${key.trim()}`
984
+ }
985
+ });
986
+
987
+ if (!response.ok) {
988
+ throw new Error('Invalid API key');
989
+ }
990
+
991
+ return true;
992
+ } catch (error) {
993
+ throw new Error('Invalid API key. Please check and try again.');
994
+ }
995
+ };
996
+
997
+ const handleApiKeySubmit = async (key) => {
998
+ try {
999
+ await validateApiKey(key);
1000
+ setApiKey(key);
1001
+ setShowApiKeyModal(false);
1002
+ setPhase(2);
1003
+ generateInsights();
1004
+ } catch (error) {
1005
+ setAiError(error.message);
1006
+ }
1007
+ };
1008
+
1009
+ const formatInsights = (content) => {
1010
+ // Convert markdown-style formatting to HTML
1011
+ let formatted = content
1012
+ .replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>')
1013
+ .replace(/^• (.+)$/gm, '<li>$1</li>')
1014
+ .replace(/^- (.+)$/gm, '<li>$1</li>')
1015
+ .split('\n\n')
1016
+ .map(paragraph => {
1017
+ if (paragraph.includes('<li>')) {
1018
+ return `<ul class="list-disc list-inside space-y-1">${paragraph}</ul>`;
1019
+ }
1020
+ return paragraph.trim() ? `<p class="mb-3">${paragraph.trim()}</p>` : '';
1021
+ })
1022
+ .join('');
1023
+
1024
+ return formatted;
1025
+ };
1026
+
1027
+ const parseAnalysisTable = (content) => {
1028
+ // Parse the AI response into a structured table format
1029
+ const lines = content.split('\n').filter(line => line.trim());
1030
+ const tableData = [];
1031
+
1032
+ let currentRow = null;
1033
+ let inTable = false;
1034
+
1035
+ for (const line of lines) {
1036
+ if (line.includes('|') && line.includes('Analysis Category')) {
1037
+ inTable = true;
1038
+ continue;
1039
+ }
1040
+
1041
+ if (line.includes('|') && line.includes('---')) {
1042
+ continue;
1043
+ }
1044
+
1045
+ if (inTable && line.includes('|')) {
1046
+ const cells = line.split('|').map(cell => cell.trim()).filter(cell => cell);
1047
+ if (cells.length >= 4) {
1048
+ tableData.push({
1049
+ category: cells[0],
1050
+ cultural: cells[1],
1051
+ reflection: cells[2],
1052
+ comparison: cells[3]
1053
+ });
1054
+ }
1055
+ }
1056
+ }
1057
+
1058
+ // If no table found, create a simple structure from the content
1059
+ if (tableData.length === 0) {
1060
+ const sections = content.split('\n\n');
1061
+ sections.forEach((section, index) => {
1062
+ if (section.trim()) {
1063
+ tableData.push({
1064
+ category: `Analysis ${index + 1}`,
1065
+ cultural: section.substring(0, 200) + '...',
1066
+ reflection: 'Detailed analysis provided',
1067
+ comparison: 'Growth indicators identified'
1068
+ });
1069
+ }
1070
+ });
1071
+ }
1072
+
1073
+ return tableData;
1074
+ };
1075
+
1076
+ const getProgressPercentage = () => {
1077
+ return (phase / 4) * 100;
1078
+ };
1079
+
1080
+ // API Key Modal Component
1081
+ const ApiKeyModal = () => {
1082
+ const [keyInput, setKeyInput] = useState('');
1083
+ const [isValidating, setIsValidating] = useState(false);
1084
+
1085
+ const handleSubmit = async (e) => {
1086
+ e.preventDefault();
1087
+ if (!keyInput.trim()) return;
1088
+
1089
+ setIsValidating(true);
1090
+ try {
1091
+ await handleApiKeySubmit(keyInput);
1092
+ } catch (error) {
1093
+ // Error is handled in parent component
1094
+ } finally {
1095
+ setIsValidating(false);
1096
+ }
1097
+ };
1098
+
1099
+ return (
1100
+ <div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 p-4">
1101
+ <div className="glass p-6 max-w-md w-full">
1102
+ <h3 className="text-xl font-bold text-gray-800 mb-4">🔑 OpenAI API Key Required</h3>
1103
+ <p className="text-gray-600 mb-4">
1104
+ To generate cultural insights, please provide your OpenAI API key.
1105
+ This will be stored locally and used only for this application.
1106
+ </p>
1107
+ <form onSubmit={handleSubmit}>
1108
+ <input
1109
+ type="password"
1110
+ value={keyInput}
1111
+ onChange={(e) => setKeyInput(e.target.value)}
1112
+ placeholder="sk-..."
1113
+ className="w-full px-3 py-2 border rounded-lg mb-4"
1114
+ autoFocus
1115
+ />
1116
+ <div className="flex gap-2">
1117
+ <button
1118
+ type="submit"
1119
+ disabled={!keyInput.trim() || isValidating}
1120
+ className="flex-1 bg-blue-600 text-white py-2 rounded-lg hover:bg-blue-700 transition disabled:opacity-50"
1121
+ >
1122
+ {isValidating ? 'Validating...' : 'Continue'}
1123
+ </button>
1124
+ <button
1125
+ type="button"
1126
+ onClick={() => setShowApiKeyModal(false)}
1127
+ className="px-4 py-2 bg-gray-300 text-gray-700 rounded-lg hover:bg-gray-400 transition"
1128
+ >
1129
+ Cancel
1130
+ </button>
1131
+ </div>
1132
+ </form>
1133
+ {aiError && (
1134
+ <div className="mt-3 text-red-600 text-sm">{aiError}</div>
1135
+ )}
1136
+ <p className="text-xs text-gray-500 mt-3">
1137
+ Get your API key at <a href="https://platform.openai.com/api-keys" target="_blank" rel="noopener noreferrer" className="text-blue-600 underline">OpenAI</a>
1138
+ </p>
1139
+ </div>
1140
+ </div>
1141
+ );
1142
+ };
1143
+
1144
+ return (
1145
+ <div className="min-h-screen py-6">
1146
+ <div className="max-w-6xl mx-auto px-4">
1147
+ {/* Header */}
1148
+ <div className="glass p-6 mb-6 text-center">
1149
+ <h1 className="text-4xl font-bold text-gray-800 mb-2">
1150
+ 🌍 Cultural Intelligence Explorer
1151
+ </h1>
1152
+ <p className="text-gray-600 mb-4">
1153
+ Develop empathy and global citizenship through cultural exploration
1154
+ </p>
1155
+ <p className="text-sm text-blue-600 font-semibold">
1156
+ Global Edition with AI Analysis - Explore any country in the world!
1157
+ </p>
1158
+
1159
+ {/* Progress Bar */}
1160
+ <div className="max-w-md mx-auto mt-4">
1161
+ <div className="flex justify-between text-xs text-gray-500 mb-2">
1162
+ <span className={phase >= 1 ? 'text-blue-600 font-semibold' : ''}>Selection</span>
1163
+ <span className={phase >= 2 ? 'text-blue-600 font-semibold' : ''}>Insights</span>
1164
+ <span className={phase >= 3 ? 'text-blue-600 font-semibold' : ''}>Reflection</span>
1165
+ <span className={phase >= 4 ? 'text-blue-600 font-semibold' : ''}>Analysis</span>
1166
+ </div>
1167
+ <div className="w-full bg-gray-200 rounded-full h-2">
1168
+ <div
1169
+ className="progress-bar rounded-full h-2"
1170
+ style={{ width: `${getProgressPercentage()}%` }}
1171
+ ></div>
1172
+ </div>
1173
+ </div>
1174
+ </div>
1175
+
1176
+ {/* Phase 1: Cultural Selection */}
1177
+ {phase === 1 && (
1178
+ <div className="fade-in">
1179
+ <div className="glass p-6 mb-6">
1180
+ <h2 className="text-2xl font-bold text-gray-800 mb-4">
1181
+ 🎯 Phase 1: Choose Your Cultural Journey
1182
+ </h2>
1183
+ <p className="text-gray-600 mb-6">
1184
+ Select any country in the world to explore and optionally choose a specific theme to focus on.
1185
+ </p>
1186
+
1187
+ {/* Country Selection */}
1188
+ <div className="mb-8">
1189
+ <div className="country-dropdown">
1190
+ <h3 className="text-xl font-semibold mb-4">🌎 Select a Country</h3>
1191
+ <p className="text-sm opacity-90 mb-4">
1192
+ Search from {WORLD_COUNTRIES.length} countries worldwide
1193
+ </p>
1194
+ <CountryDropdown
1195
+ selectedCountry={selectedCountry}
1196
+ onCountrySelect={handleCountrySelect}
1197
+ />
1198
+ </div>
1199
+ </div>
1200
+
1201
+ {/* Theme Selection */}
1202
+ <div className="mb-8">
1203
+ <h3 className="text-xl font-semibold text-gray-700 mb-4">
1204
+ Choose a Focus Theme (Optional)
1205
+ </h3>
1206
+ <div className="grid grid-cols-2 md:grid-cols-4 gap-3 theme-grid">
1207
+ {THEMES.map(theme => (
1208
+ <div
1209
+ key={theme.id}
1210
+ className={`theme-card ${selectedTheme?.id === theme.id ? 'selected' : ''}`}
1211
+ onClick={() => handleThemeSelect(selectedTheme?.id === theme.id ? null : theme)}
1212
+ tabIndex={0}
1213
+ role="button"
1214
+ aria-pressed={selectedTheme?.id === theme.id}
1215
+ onKeyPress={(e) => e.key === 'Enter' && handleThemeSelect(selectedTheme?.id === theme.id ? null : theme)}
1216
+ >
1217
+ <div className="text-2xl mb-2">{theme.icon}</div>
1218
+ <h4 className="font-semibold text-sm">{theme.name}</h4>
1219
+ <p className="text-xs opacity-80 mt-1">{theme.description}</p>
1220
+ </div>
1221
+ ))}
1222
+ </div>
1223
+ </div>
1224
+
1225
+ {/* Selection Summary */}
1226
+ {selectedCountry && (
1227
+ <div className="bg-blue-50 border border-blue-200 rounded-lg p-4 mb-6">
1228
+ <h4 className="font-semibold text-blue-800 mb-2">Your Selection:</h4>
1229
+ <p className="text-blue-700">
1230
+ <strong>{selectedCountry.flag} {selectedCountry.name}</strong> ({selectedCountry.region})
1231
+ {selectedTheme && (
1232
+ <span> - Focus: {selectedTheme.icon} {selectedTheme.name}</span>
1233
+ )}
1234
+ </p>
1235
+ </div>
1236
+ )}
1237
+
1238
+ {/* Continue Button */}
1239
+ <div className="text-center">
1240
+ <button
1241
+ onClick={proceedToInsights}
1242
+ disabled={!selectedCountry}
1243
+ className="bg-gradient-to-r from-blue-600 to-purple-600 text-white px-8 py-3 rounded-lg font-semibold hover:from-blue-700 hover:to-purple-700 transition disabled:opacity-50 disabled:cursor-not-allowed"
1244
+ >
1245
+ Explore Culture 🚀
1246
+ </button>
1247
+ </div>
1248
+ </div>
1249
+ </div>
1250
+ )}
1251
+
1252
+ {/* Phase 2: AI Cultural Insights */}
1253
+ {phase === 2 && (
1254
+ <div className="fade-in">
1255
+ <div className="glass p-6 mb-6">
1256
+ <div className="flex items-center justify-between mb-6">
1257
+ <div>
1258
+ <h2 className="text-2xl font-bold text-gray-800">
1259
+ 🧠 Phase 2: Cultural Insights
1260
+ </h2>
1261
+ <p className="text-gray-600">
1262
+ Exploring {selectedCountry?.flag} {selectedCountry?.name} ({selectedCountry?.region})
1263
+ {selectedTheme && ` - ${selectedTheme.icon} ${selectedTheme.name}`}
1264
+ </p>
1265
+ </div>
1266
+ <button
1267
+ onClick={() => setPhase(1)}
1268
+ className="text-blue-600 hover:text-blue-800 transition"
1269
+ >
1270
+ ← Back to Selection
1271
+ </button>
1272
+ </div>
1273
+
1274
+ {isGeneratingInsights && (
1275
+ <div className="text-center py-12">
1276
+ <div className="typing-indicator mb-4">
1277
+ <span className="text-lg text-gray-600 mr-3">Generating cultural insights</span>
1278
+ <div className="typing-dot"></div>
1279
+ <div className="typing-dot"></div>
1280
+ <div className="typing-dot"></div>
1281
+ </div>
1282
+ <p className="text-gray-500">This may take a moment...</p>
1283
+ </div>
1284
+ )}
1285
+
1286
+ {aiError && (
1287
+ <div className="bg-red-50 border border-red-200 rounded-lg p-4 mb-6">
1288
+ <h4 className="font-semibold text-red-800 mb-2">Error:</h4>
1289
+ <p className="text-red-700">{aiError}</p>
1290
+ <button
1291
+ onClick={generateInsights}
1292
+ className="mt-3 bg-red-600 text-white px-4 py-2 rounded hover:bg-red-700 transition"
1293
+ >
1294
+ Try Again
1295
+ </button>
1296
+ </div>
1297
+ )}
1298
+
1299
+ {insights && (
1300
+ <div className="slide-in">
1301
+ <div className="insight-section">
1302
+ <div
1303
+ className="prose prose-lg max-w-none"
1304
+ dangerouslySetInnerHTML={{ __html: formatInsights(insights) }}
1305
+ />
1306
+ </div>
1307
+
1308
+ <div className="text-center mt-8">
1309
+ <button
1310
+ onClick={proceedToReflection}
1311
+ className="bg-gradient-to-r from-green-600 to-blue-600 text-white px-8 py-3 rounded-lg font-semibold hover:from-green-700 hover:to-blue-700 transition"
1312
+ >
1313
+ Reflect on Learning 💭
1314
+ </button>
1315
+ </div>
1316
+ </div>
1317
+ )}
1318
+ </div>
1319
+ </div>
1320
+ )}
1321
+
1322
+ {/* Phase 3: Reflection & Comparison */}
1323
+ {phase === 3 && (
1324
+ <div className="fade-in">
1325
+ <div className="glass p-6 mb-6">
1326
+ <div className="flex items-center justify-between mb-6">
1327
+ <div>
1328
+ <h2 className="text-2xl font-bold text-gray-800">
1329
+ 💭 Phase 3: Reflection & Growth
1330
+ </h2>
1331
+ <p className="text-gray-600">
1332
+ Reflect on your cultural exploration and personal insights
1333
+ </p>
1334
+ </div>
1335
+ <button
1336
+ onClick={() => setPhase(2)}
1337
+ className="text-blue-600 hover:text-blue-800 transition"
1338
+ >
1339
+ ← Back to Insights
1340
+ </button>
1341
+ </div>
1342
+
1343
+ <div className="space-y-6">
1344
+ {REFLECTION_PROMPTS.map(prompt => (
1345
+ <div key={prompt.id} className="reflection-card">
1346
+ <div className="flex items-start gap-3 mb-3">
1347
+ <span className="text-2xl">{prompt.icon}</span>
1348
+ <h3 className="font-semibold text-gray-800 flex-1">
1349
+ {prompt.question}
1350
+ </h3>
1351
+ </div>
1352
+ <textarea
1353
+ value={reflections[prompt.id] || ''}
1354
+ onChange={(e) => handleReflectionChange(prompt.id, e.target.value)}
1355
+ placeholder="Share your thoughts and insights..."
1356
+ className="w-full px-4 py-3 border border-gray-300 rounded-lg resize-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
1357
+ rows={4}
1358
+ />
1359
+ </div>
1360
+ ))}
1361
+ </div>
1362
+
1363
+ <div className="text-center mt-8">
1364
+ <button
1365
+ onClick={proceedToAnalysis}
1366
+ className="bg-gradient-to-r from-purple-600 to-pink-600 text-white px-8 py-3 rounded-lg font-semibold hover:from-purple-700 hover:to-pink-700 transition"
1367
+ >
1368
+ Generate AI Analysis 📊
1369
+ </button>
1370
+ </div>
1371
+ </div>
1372
+ </div>
1373
+ )}
1374
+
1375
+ {/* Phase 4: AI Analysis & Comparison */}
1376
+ {phase === 4 && (
1377
+ <div className="fade-in">
1378
+ <div className="glass p-6 mb-6">
1379
+ <div className="flex items-center justify-between mb-6">
1380
+ <div>
1381
+ <h2 className="text-2xl font-bold text-gray-800">
1382
+ 📊 Phase 4: AI Analysis & Insights
1383
+ </h2>
1384
+ <p className="text-gray-600">
1385
+ AI-powered comparison between cultural themes and your reflections
1386
+ </p>
1387
+ </div>
1388
+ <button
1389
+ onClick={() => setPhase(3)}
1390
+ className="text-blue-600 hover:text-blue-800 transition"
1391
+ >
1392
+ ← Back to Reflection
1393
+ </button>
1394
+ </div>
1395
+
1396
+ {isGeneratingAnalysis && (
1397
+ <div className="text-center py-12">
1398
+ <div className="typing-indicator mb-4">
1399
+ <span className="text-lg text-gray-600 mr-3">Analyzing your cultural journey</span>
1400
+ <div className="typing-dot"></div>
1401
+ <div className="typing-dot"></div>
1402
+ <div className="typing-dot"></div>
1403
+ </div>
1404
+ <p className="text-gray-500">Creating personalized insights...</p>
1405
+ </div>
1406
+ )}
1407
+
1408
+ {aiError && (
1409
+ <div className="bg-red-50 border border-red-200 rounded-lg p-4 mb-6">
1410
+ <h4 className="font-semibold text-red-800 mb-2">Error:</h4>
1411
+ <p className="text-red-700">{aiError}</p>
1412
+ <button
1413
+ onClick={generateAnalysis}
1414
+ className="mt-3 bg-red-600 text-white px-4 py-2 rounded hover:bg-red-700 transition"
1415
+ >
1416
+ Try Again
1417
+ </button>
1418
+ </div>
1419
+ )}
1420
+
1421
+ {analysis && (
1422
+ <div className="slide-in">
1423
+ <div className="mb-6">
1424
+ <h3 className="text-xl font-semibold text-gray-800 mb-4">
1425
+ 🎯 Cultural Intelligence Analysis
1426
+ </h3>
1427
+ <div className="bg-blue-50 border border-blue-200 rounded-lg p-4 mb-6">
1428
+ <p className="text-blue-700">
1429
+ <strong>Analysis for:</strong> {selectedCountry?.flag} {selectedCountry?.name}
1430
+ {selectedTheme && ` - ${selectedTheme.icon} ${selectedTheme.name}`}
1431
+ </p>
1432
+ </div>
1433
+ </div>
1434
+
1435
+ <div className="analysis-table mb-8">
1436
+ <table>
1437
+ <thead>
1438
+ <tr>
1439
+ <th className="w-1/4">Analysis Category</th>
1440
+ <th className="w-1/4">Cultural Theme Insights</th>
1441
+ <th className="w-1/4">Your Reflection Analysis</th>
1442
+ <th className="w-1/4">Growth Indicators</th>
1443
+ </tr>
1444
+ </thead>
1445
+ <tbody>
1446
+ {parseAnalysisTable(analysis).map((row, index) => (
1447
+ <tr key={index}>
1448
+ <td className="font-semibold text-gray-800">
1449
+ {row.category}
1450
+ <div className="mt-2">
1451
+ <span className="insight-badge">Cultural Insight</span>
1452
+ </div>
1453
+ </td>
1454
+ <td className="text-gray-700">
1455
+ {row.cultural}
1456
+ </td>
1457
+ <td className="text-gray-700">
1458
+ {row.reflection}
1459
+ <div className="mt-2">
1460
+ <span className="comparison-badge">Personal Growth</span>
1461
+ </div>
1462
+ </td>
1463
+ <td className="text-gray-700">
1464
+ {row.comparison}
1465
+ </td>
1466
+ </tr>
1467
+ ))}
1468
+ </tbody>
1469
+ </table>
1470
+ </div>
1471
+
1472
+ <div className="text-center mt-8">
1473
+ <button
1474
+ onClick={completeExploration}
1475
+ className="bg-gradient-to-r from-green-600 to-teal-600 text-white px-8 py-3 rounded-lg font-semibold hover:from-green-700 hover:to-teal-700 transition"
1476
+ >
1477
+ Complete Exploration ✨
1478
+ </button>
1479
+ </div>
1480
+ </div>
1481
+ )}
1482
+ </div>
1483
+ </div>
1484
+ )}
1485
+
1486
+ {/* Exploration History */}
1487
+ {explorationHistory.length > 0 && (
1488
+ <div className="glass p-6">
1489
+ <h3 className="text-xl font-bold text-gray-800 mb-4">
1490
+ 📚 Your Cultural Journey
1491
+ </h3>
1492
+ <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
1493
+ {explorationHistory.slice(-6).map(exploration => (
1494
+ <div key={exploration.id} className="bg-white rounded-lg p-4 border border-gray-200">
1495
+ <div className="flex items-center gap-2 mb-2">
1496
+ <span className="text-xl">{exploration.country.flag}</span>
1497
+ <h4 className="font-semibold text-gray-800">{exploration.country.name}</h4>
1498
+ </div>
1499
+ <p className="text-xs text-gray-500 mb-1">{exploration.country.region}</p>
1500
+ {exploration.theme && (
1501
+ <p className="text-sm text-gray-600 mb-2">
1502
+ {exploration.theme.icon} {exploration.theme.name}
1503
+ </p>
1504
+ )}
1505
+ <div className="flex gap-1 mb-2">
1506
+ <span className="insight-badge text-xs">Insights</span>
1507
+ <span className="comparison-badge text-xs">Analysis</span>
1508
+ </div>
1509
+ <p className="text-xs text-gray-500">
1510
+ {new Date(exploration.timestamp).toLocaleDateString()}
1511
+ </p>
1512
+ </div>
1513
+ ))}
1514
+ </div>
1515
+ <p className="text-center text-gray-500 mt-4">
1516
+ {explorationHistory.length} culture{explorationHistory.length !== 1 ? 's' : ''} explored with AI analysis
1517
+ </p>
1518
+ </div>
1519
+ )}
1520
+ </div>
1521
+
1522
+ {/* API Key Modal */}
1523
+ {showApiKeyModal && <ApiKeyModal />}
1524
+ </div>
1525
+ );
1526
+ }
1527
+
1528
+ ReactDOM.createRoot(document.getElementById("root")).render(<CulturalIntelligenceExplorer />);
1529
+ </script>
1530
+ </body>
1531
+ </html>
1532
+
📘 Step-by-Step Guide.txt ADDED
@@ -0,0 +1,76 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ 📘 Step-by-Step Guide: Cultural Intelligence Explorer
2
+ 1. Introduction
3
+ The Cultural Intelligence Explorer empowers students and educators to explore, compare, and analyze cultures worldwide through AI-powered insights and guided reflection—helping everyone build empathy, self-awareness, and true global citizenship.
4
+
5
+ 2. How to Use the Tool
6
+ A. Getting Started
7
+ Access the App:
8
+ Open “Cultural Intelligence Explorer.html” in your browser—no login, install, or sign-up required.
9
+
10
+ Select a Country and Theme:
11
+
12
+ Use the searchable dropdown to pick any country (with flag and region).
13
+
14
+ Optionally, choose a focus theme: family, education, food, values, communication, business, traditions, or challenges.
15
+
16
+ Provide Your OpenAI API Key:
17
+
18
+ When prompted, enter your OpenAI API key (see instructions in-app if you need one).
19
+
20
+ Your key is only stored in your browser for this tool.
21
+
22
+ B. Exploring and Reflecting
23
+ Generate AI Cultural Insights:
24
+
25
+ Click “Explore Culture.”
26
+
27
+ The tool provides a detailed, structured analysis of your chosen country/theme, including cultural overview, values, daily life, history, challenges, misconceptions, and cultural wisdom.
28
+
29
+ Reflect on Learning:
30
+
31
+ Respond to guided prompts: similarities, differences, surprises, challenged assumptions, valuable lessons, empathy development, and more.
32
+
33
+ Get AI-Powered Growth Analysis:
34
+
35
+ Click to generate a personalized analysis table.
36
+
37
+ See a structured comparison between cultural insights and your reflection—highlighting growth in understanding, empathy, and global citizenship.
38
+
39
+ Track and Review Your Journey:
40
+
41
+ All completed explorations are saved in your browser’s “journey” log—review at any time.
42
+
43
+ 3. How It Supports Educators
44
+ Global Citizenship:
45
+ Build cultural intelligence, perspective-taking, and self-reflection as part of any subject.
46
+
47
+ Differentiation:
48
+ Students choose countries/themes for personally meaningful learning.
49
+
50
+ Formative/Summative Assessment:
51
+ Use reflection and AI analysis outputs as portfolio evidence or learning artifacts.
52
+
53
+ Safe for Schools:
54
+ Privacy-first, no logins, no central data collection.
55
+
56
+ 4. How It Benefits Students
57
+ Personalized Global Learning:
58
+ Explore the world—your way. Every session is unique.
59
+
60
+ Empathy & Critical Thinking:
61
+ Evidence-based prompts drive deep reflection and growth.
62
+
63
+ Growth Feedback:
64
+ AI analysis shows your cultural intelligence progress.
65
+
66
+ Portfolio-Ready:
67
+ Use your journey log and AI feedback in digital portfolios or class projects.
68
+
69
+ 5. Best Practices
70
+ Encourage students to explore multiple countries/themes.
71
+
72
+ Use reflections and AI tables for classroom or group discussions.
73
+
74
+ Have students compare journeys to highlight diversity and shared humanity.
75
+
76
+ Remind everyone to keep API keys private.