From 5308220441324d6a2c68574bd6af78e1d5b11964 Mon Sep 17 00:00:00 2001 From: Gal Date: Fri, 25 Jul 2025 00:16:42 +0200 Subject: [PATCH] refactor --- .../src/components/GermanSpeechInterface.vue | 82 +- apps/german-app/src/main.js | 5 +- apps/german-app/src/views/ScenarioView.vue | 38 +- .../src/components/ScenarioView.vue | 22 +- apps/indonesian-app/src/main.js | 5 +- .../shared/components/BaseSpeechInterface.vue | 997 ++++++++++++++++ apps/shared/config/languages.js | 62 + apps/shared/styles/speech-interface.css | 1032 +++++++++++++++++ 8 files changed, 2156 insertions(+), 87 deletions(-) create mode 100644 apps/shared/components/BaseSpeechInterface.vue create mode 100644 apps/shared/config/languages.js create mode 100644 apps/shared/styles/speech-interface.css diff --git a/apps/german-app/src/components/GermanSpeechInterface.vue b/apps/german-app/src/components/GermanSpeechInterface.vue index 8a3ff6b..b9555fa 100644 --- a/apps/german-app/src/components/GermanSpeechInterface.vue +++ b/apps/german-app/src/components/GermanSpeechInterface.vue @@ -4,34 +4,34 @@
-

Willkommen bei Street Lingo! 🎉

+

Welcome to Street Lingo! 🎉

🎙️
- Sprechen üben -

Klicken Sie auf "Gespräch beginnen", um mit KI-Charakteren in realen deutschen Szenarien zu sprechen

+ Practice Speaking +

Click "Start Conversation" to begin chatting with AI characters in real German scenarios

💡
- Hilfe erhalten -

Aktivieren Sie die "Hilfe"-Schaltfläche und pausieren Sie während des Gesprächs, um hilfreiche Phrasen zu erhalten

+ Get Help +

Enable the "Help" toggle and pause during conversation to get helpful phrase suggestions

📊
- Gesprächsanalyse -

Klicken Sie auf "Gespräch beenden", um personalisiertes Feedback zu Ihrem Deutsch zu erhalten

+ Conversation Analysis +

Click "Finish Conversation" to get personalized feedback on your German

@@ -53,13 +53,13 @@ :disabled="message.loadingTranslation" class="translation-toggle" > - {{ message.loadingTranslation ? 'Übersetzen...' : '🌍 English zeigen' }} + {{ message.loadingTranslation ? 'Translating...' : '🌍 Show English' }}

{{ message.englishTranslation }}

@@ -80,7 +80,7 @@
-

💡 Hilfe-Vorschläge

+

💡 Help Suggestions

@@ -111,7 +111,7 @@ class="start-conversation-btn" :disabled="isConnecting" > - 🎙️ Gespräch beginnen + 🎙️ Start Conversation
@@ -148,24 +148,24 @@ :disabled="!textInput.trim() || isRecording || isFinished" class="send-btn" > - Senden + Send
@@ -186,14 +186,14 @@
- 🎉 Alle Ziele erreicht! Gut gemacht! + 🎉 All goals completed! Well done!
-

📍 Situationskontext

+

📍 Scenario Context

-
Ort
+
Location
{{ scenarioData.location }}
-
Beschreibung
+
Description
{{ scenarioData.description }}
-
Herausforderung
+
Challenge
{{ scenarioData.challenge }}
-

💬 Hilfreiche Phrasen:

+

💬 Helpful Phrases:

+ + \ No newline at end of file diff --git a/apps/shared/config/languages.js b/apps/shared/config/languages.js new file mode 100644 index 0000000..0ccb11e --- /dev/null +++ b/apps/shared/config/languages.js @@ -0,0 +1,62 @@ +export const LANGUAGE_CONFIGS = { + german: { + code: 'de', + name: 'German', + flag: '🇩🇪', + apiEndpoint: '/api/scenarios/german', + wsEndpoint: '/ws/speech/german', + theme: 'german-theme', + defaultScenario: 'spati', + branding: { + title: 'Street Lingo', + tagline: 'Deutsch lernen in Berlin - Learn German through real Berlin scenarios' + }, + translation: { + sourceLanguage: 'de', + targetLanguage: 'en' + }, + phrases: { + nativeField: 'german_text', + translationField: 'english_meaning' + }, + scenarios: { + 'spati': { name: 'Späti Shopping', emoji: '🏪', avatar: '👨‍💼' }, + 'wg_viewing': { name: 'WG Apartment Viewing', emoji: '🏠', avatar: '👩‍🎓' }, + 'burgeramt': { name: 'Bürgeramt Visit', emoji: '🏛️', avatar: '👩‍💼' }, + 'biergarten': { name: 'Biergarten Chat', emoji: '🍺', avatar: '👨‍🍳' }, + 'ber_airport': { name: 'BER Airport Train Help', emoji: '✈️', avatar: '👩‍💼' }, + 'arzt': { name: 'Doctor Visit', emoji: '👨‍⚕️', avatar: '👨‍⚕️' } + } + }, + indonesian: { + code: 'id', + name: 'Indonesian', + flag: '🇮🇩', + apiEndpoint: '/api/scenarios/indonesian', + wsEndpoint: '/ws/speech/indonesian', + theme: 'indonesian-theme', + defaultScenario: 'warung', + branding: { + title: 'Street Lingo', + tagline: 'Learn Indonesian through everyday scenarios' + }, + translation: { + sourceLanguage: 'id', + targetLanguage: 'en' + }, + phrases: { + nativeField: 'indonesian_text', + translationField: 'english_meaning' + }, + scenarios: { + 'warung': { name: 'Warung Dining', emoji: '🍜', avatar: '👨‍🍳' }, + 'ojek': { name: 'Ojek Ride', emoji: '🏍️', avatar: '👩‍🦱' }, + 'alfamart': { name: 'Alfamart Shopping', emoji: '🏪', avatar: '👩‍💼' }, + 'coffee_shop': { name: 'Coffee Shop Small Talk', emoji: '☕', avatar: '👨‍💼' } + } + } +} + +export function getLanguageConfig(language) { + return LANGUAGE_CONFIGS[language] || LANGUAGE_CONFIGS.indonesian +} \ No newline at end of file diff --git a/apps/shared/styles/speech-interface.css b/apps/shared/styles/speech-interface.css new file mode 100644 index 0000000..5c13732 --- /dev/null +++ b/apps/shared/styles/speech-interface.css @@ -0,0 +1,1032 @@ +.speech-interface { + display: flex; + flex-direction: column; + background: transparent; + padding: 1.5rem; /* Add padding to prevent goal section from touching edges */ +} + +.conversation-area { + display: flex; + flex-direction: column; +} + +.messages { + overflow-y: auto; + padding: 1.5rem; + background: var(--surface-alt); + margin-bottom: 1rem; + border-radius: var(--radius) var(--radius) 0 0; + height: 400px; /* Fixed height for messages area */ + scrollbar-width: thin; + scrollbar-color: var(--border) var(--surface-alt); +} + +.messages::-webkit-scrollbar { + width: 6px; +} + +.messages::-webkit-scrollbar-track { + background: var(--surface-alt); +} + +.messages::-webkit-scrollbar-thumb { + background: var(--border); + border-radius: 3px; +} + +.messages::-webkit-scrollbar-thumb:hover { + background: var(--text-muted); +} + +.message { + margin-bottom: 1rem; + padding: 1rem; + border-radius: var(--radius-lg); + max-width: 75%; + position: relative; + animation: messageSlide 0.3s ease; +} + +@keyframes messageSlide { + from { + opacity: 0; + transform: translateY(10px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +.message.user { + background: var(--primary); + color: white; + margin-left: auto; + border-bottom-right-radius: 4px; +} + +.message.ai { + background: var(--surface); + border: 1px solid var(--border); + margin-right: auto; + border-bottom-left-radius: 4px; +} + +.message.system { + background: var(--accent); + color: white; + margin: 0 auto; + text-align: center; + font-weight: 500; + border-radius: var(--radius-lg); + box-shadow: var(--shadow); +} + +.message.error { + background: #fef2f2; + color: #dc2626; + border: 1px solid #fecaca; + margin-right: auto; +} + +.message-content { + margin-bottom: 0.5rem; +} + +.message-content p { + margin: 0; + line-height: 1.5; +} + +.audio-player { + margin-top: 0.75rem; +} + +.audio-player audio { + width: 100%; + max-width: 250px; + height: 32px; + border-radius: 16px; +} + +.timestamp { + font-size: 0.75rem; + color: var(--text-muted); + opacity: 0.7; + font-weight: 400; +} + +.message.user .timestamp { + color: rgba(255, 255, 255, 0.8); +} + +/* Translation styles */ +.translation-section { + margin-top: 0.75rem; + border-top: 1px solid var(--border); + padding-top: 0.75rem; +} + +.translation-toggle { + background: var(--surface-alt); + border: 1px solid var(--border); + color: var(--text-light); + padding: 0.5rem 0.75rem; + border-radius: var(--radius); + font-size: 0.75rem; + font-weight: 500; + cursor: pointer; + transition: all 0.2s ease; + display: inline-flex; + align-items: center; + gap: 0.25rem; +} + +.translation-toggle:hover { + background: var(--primary); + color: white; + border-color: var(--primary); + transform: translateY(-1px); +} + +.translation-toggle:disabled { + opacity: 0.6; + cursor: not-allowed; + transform: none; +} + +.translation-toggle.hide { + background: var(--surface); + color: var(--text-muted); + font-size: 0.7rem; + padding: 0.25rem 0.5rem; +} + +.translation-toggle.hide:hover { + background: var(--text-muted); + color: white; +} + +.translation-content { + margin-top: 0.5rem; +} + +.translation-text { + background: var(--surface-alt); + border: 1px solid var(--border); + border-radius: var(--radius); + padding: 0.75rem; + margin: 0 0 0.5rem 0; + font-style: italic; + color: var(--text-light); + font-size: 0.9rem; + line-height: 1.4; + position: relative; +} + +.translation-text::before { + content: "🇺🇸"; + position: absolute; + top: 0.5rem; + right: 0.75rem; + font-size: 0.8rem; + opacity: 0.6; +} + +.transcription-display { + background: var(--surface); + border: 1px solid var(--border); + padding: 1rem; + border-radius: var(--radius); + margin-bottom: 1rem; + border-left: 3px solid var(--secondary); +} + +.transcription-text { + font-style: italic; + margin-bottom: 0.5rem; + color: var(--text-light); +} + +.transcription-status { + font-size: 0.8rem; + color: var(--text-muted); + font-weight: 500; +} + +.recording-stopped-notification { + background: var(--secondary); + color: white; + padding: 1rem; + border-radius: var(--radius); + margin-bottom: 1rem; + text-align: center; + box-shadow: var(--shadow); + animation: slideIn 0.3s ease; +} + +.recording-stopped-notification p { + margin: 0; + font-weight: 500; + font-size: 0.9rem; +} + +.controls { + display: flex; + gap: 0.75rem; + align-items: center; + padding: 1rem; + background: var(--surface); + border-radius: 0 0 var(--radius) var(--radius); + border-top: 1px solid var(--border); +} + +.record-btn { + background: var(--accent); + color: white; + border: none; + padding: 0.75rem 1.25rem; + border-radius: var(--radius-lg); + cursor: pointer; + font-family: 'DM Sans', sans-serif; + font-size: 0.9rem; + font-weight: 500; + transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1); + min-width: 100px; + display: flex; + align-items: center; + gap: 0.5rem; + box-shadow: var(--shadow-sm); +} + +.record-btn:hover { + background: #059669; + transform: translateY(-1px); + box-shadow: var(--shadow); +} + +.record-btn.recording { + background: #dc2626; + animation: recordingPulse 2s ease-in-out infinite; +} + +.record-btn:disabled { + background: var(--text-muted); + cursor: not-allowed; + transform: none; + box-shadow: none; +} + +@keyframes recordingPulse { + 0%, 100% { + transform: scale(1); + box-shadow: 0 0 0 0 rgba(220, 38, 38, 0.4); + } + 50% { + transform: scale(1.02); + box-shadow: 0 0 0 8px rgba(220, 38, 38, 0); + } +} + +.text-input { + flex: 1; + padding: 0.75rem 1rem; + border: 1px solid var(--border); + border-radius: var(--radius-lg); + font-family: 'DM Sans', sans-serif; + font-size: 0.9rem; + background: var(--surface); + color: var(--text); + transition: all 0.2s ease; +} + +.text-input:focus { + outline: none; + border-color: var(--primary); + box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.1); +} + +.text-input::placeholder { + color: var(--text-muted); +} + +.send-btn { + background: var(--primary); + color: white; + border: none; + padding: 0.75rem 1.25rem; + border-radius: var(--radius-lg); + cursor: pointer; + font-family: 'DM Sans', sans-serif; + font-size: 0.9rem; + font-weight: 500; + transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1); + box-shadow: var(--shadow-sm); +} + +.send-btn:hover { + background: var(--primary-dark); + transform: translateY(-1px); + box-shadow: var(--shadow); +} + +.send-btn:disabled { + background: var(--text-muted); + cursor: not-allowed; + transform: none; + box-shadow: none; +} + +.reset-btn { + background: var(--surface); + color: var(--text-light); + border: 1px solid var(--border); + padding: 0.75rem 1rem; + border-radius: var(--radius-lg); + cursor: pointer; + font-family: 'DM Sans', sans-serif; + font-size: 0.9rem; + font-weight: 500; + transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1); +} + +.reset-btn:hover { + background: var(--surface-alt); + border-color: var(--text-muted); + transform: translateY(-1px); +} + +.finish-btn { + background: var(--accent); + color: white; + border: none; + padding: 0.75rem 1.25rem; + border-radius: var(--radius-lg); + cursor: pointer; + font-family: 'DM Sans', sans-serif; + font-size: 0.9rem; + font-weight: 500; + transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1); + box-shadow: var(--shadow-sm); +} + +.finish-btn:hover:not(:disabled) { + background: #047857; + transform: translateY(-1px); + box-shadow: var(--shadow); +} + +.finish-btn:disabled { + background: var(--text-muted); + cursor: not-allowed; + transform: none; + box-shadow: none; +} + + +.status { + padding: 0.75rem; + text-align: center; +} + +.status-indicator { + display: inline-flex; + align-items: center; + gap: 0.5rem; + padding: 0.5rem 1rem; + border-radius: var(--radius-lg); + font-size: 0.85rem; + font-weight: 500; +} + +.status-indicator.connected { + background: #f0fdf4; + color: var(--accent); + border: 1px solid #bbf7d0; +} + +.status-indicator.connecting { + background: #fffbeb; + color: var(--secondary); + border: 1px solid #fed7aa; +} + +.status-indicator.disconnected, +.status-indicator.error { + background: #fef2f2; + color: #dc2626; + border: 1px solid #fecaca; +} + +/* Goal Progress Styles */ +.goal-section { + background: var(--surface); + border: 1px solid var(--border); + border-radius: var(--radius-lg); + padding: 1.5rem; + margin-bottom: 1.5rem; + box-shadow: var(--shadow-sm); + position: relative; + overflow: hidden; +} + +.goal-section::before { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + height: 3px; + background: var(--primary); +} + +.goal-title { + margin: 0 0 1rem 0; + color: var(--text); + font-size: 1.1rem; + font-weight: 600; + display: flex; + align-items: center; + gap: 0.5rem; +} + +.goal-checklist { + margin-bottom: 1rem; +} + +.goal-item { + display: flex; + align-items: center; + padding: 0.75rem 0; + transition: all 0.2s ease; + border-radius: var(--radius); +} + +.goal-item.completed { + opacity: 0.7; +} + +.goal-checkbox { + margin-right: 0.75rem; + font-size: 1.1rem; + transition: transform 0.2s ease; +} + +.goal-item.completed .goal-checkbox { + transform: scale(1.1); +} + +.goal-description { + color: var(--text-light); + font-weight: 500; + font-size: 0.9rem; +} + +.goal-item.completed .goal-description { + text-decoration: line-through; + color: var(--text-muted); +} + +.completion-banner { + background: var(--accent); + color: white; + padding: 1.25rem; + border-radius: var(--radius-lg); + text-align: center; + font-weight: 600; + font-size: 1rem; + box-shadow: var(--shadow); + animation: celebrationPulse 3s ease-in-out; +} + +@keyframes celebrationPulse { + 0%, 100% { + transform: scale(1); + box-shadow: var(--shadow); + } + 50% { + transform: scale(1.02); + box-shadow: var(--shadow-lg); + } +} + +@media (max-width: 768px) { + .controls { + gap: 0.5rem; + padding: 0.75rem; + flex-wrap: wrap; + } + + .suggestion-toggle-container { + margin-left: 0; + margin-top: 0.5rem; + } + + .suggestion-panel { + margin-bottom: 0.75rem; + } + + .suggestion-panel-content { + padding: 0.75rem; + } + + .suggestion-panel-item { + padding: 0.5rem; + } + + .record-btn, + .send-btn { + padding: 0.625rem 1rem; + font-size: 0.85rem; + min-width: 80px; + } + + .text-input { + min-width: 0; + flex: 1 1 100%; + order: -1; + margin-bottom: 0.5rem; + } + + .speech-interface { + padding: 1rem; /* Reduce padding on mobile */ + } + + .goal-section { + padding: 1rem; + } + + .messages { + padding: 1rem; + height: 300px; /* Fixed height for mobile */ + } +} + +/* Suggestion Toggle Styles */ +.suggestion-toggle-container { + display: flex; + align-items: center; + gap: 0.5rem; + margin-left: 0.5rem; +} + +.suggestion-toggle-label { + font-size: 0.8rem; + color: var(--text-light); + font-weight: 500; + cursor: pointer; +} + +.suggestion-toggle { + width: 16px; + height: 16px; + cursor: pointer; + accent-color: var(--primary); +} + +/* Inline Suggestion Panel Styles */ +.suggestion-panel { + background: var(--surface); + border: 1px solid var(--primary); + border-radius: var(--radius); + margin-bottom: 1rem; + box-shadow: var(--shadow-sm); + animation: slideIn 0.3s ease; +} + +@keyframes slideIn { + from { + opacity: 0; + transform: translateY(-10px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +.suggestion-panel-header { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0.75rem 1rem; + border-bottom: 1px solid var(--border); + background: var(--surface-alt); +} + +.suggestion-panel-header h4 { + margin: 0; + color: var(--text); + font-size: 0.95rem; + font-weight: 600; +} + +.suggestion-close-btn { + background: none; + border: none; + font-size: 1rem; + cursor: pointer; + color: var(--text-muted); + padding: 0.25rem; + border-radius: var(--radius); + transition: all 0.2s ease; + width: 24px; + height: 24px; + display: flex; + align-items: center; + justify-content: center; +} + +.suggestion-close-btn:hover { + background: var(--surface); + color: var(--text); +} + +.suggestion-panel-content { + padding: 1rem; +} + +.suggestion-panel-intro { + color: var(--text-light); + font-size: 0.85rem; + margin-bottom: 0.75rem; + line-height: 1.4; +} + +.suggestion-panel-list { + display: flex; + flex-direction: column; + gap: 0.5rem; +} + +.suggestion-panel-item { + background: var(--surface-alt); + border: 1px solid var(--border); + border-radius: var(--radius); + padding: 0.75rem; + transition: all 0.2s ease; +} + +.suggestion-panel-text { + margin-bottom: 0.25rem; + font-size: 0.9rem; + font-weight: 500; + color: var(--text); +} + +.suggestion-panel-translation { + font-size: 0.8rem; + opacity: 0.7; + font-style: italic; + color: var(--text-muted); +} + +/* Feedback Section Styles */ +.feedback-section { + background: var(--surface); + border: 1px solid var(--accent); + border-radius: var(--radius-lg); + padding: 1.5rem; + margin-bottom: 1.5rem; + box-shadow: var(--shadow-sm); + position: relative; + overflow: hidden; +} + +.feedback-section::before { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + height: 3px; + background: var(--accent); +} + +.feedback-title { + margin: 0 0 1rem 0; + color: var(--text); + font-size: 1.2rem; + font-weight: 600; + text-align: center; +} + +.feedback-content { + margin-bottom: 1rem; +} + +.feedback-encouragement { + font-size: 1rem; + color: var(--text-light); + text-align: center; + margin-bottom: 1.5rem; + font-style: italic; +} + +.feedback-suggestions h4, +.feedback-examples h4 { + color: var(--text); + font-size: 1rem; + font-weight: 600; + margin: 1.5rem 0 1rem 0; +} + +.feedback-suggestion { + background: var(--surface-alt); + border-radius: var(--radius); + padding: 1rem; + margin-bottom: 0.75rem; + border-left: 3px solid var(--primary); +} + +.suggestion-title { + font-weight: 600; + color: var(--text); + margin-bottom: 0.5rem; +} + +.suggestion-text { + color: var(--text-light); + line-height: 1.5; +} + +.feedback-example { + background: var(--surface-alt); + border-radius: var(--radius); + padding: 1rem; + margin-bottom: 0.75rem; + border-left: 3px solid var(--secondary); +} + +.example-original { + margin-bottom: 0.5rem; + color: var(--text-light); +} + +.example-improved { + margin-bottom: 0.5rem; + color: var(--text); +} + +.example-reason { + color: var(--text-muted); + font-size: 0.9rem; +} + +.feedback-encouragement-final { + text-align: center; + margin-top: 1.5rem; + color: var(--text-light); + font-size: 1rem; + font-style: italic; +} + +/* Feedback Loading Styles */ +.feedback-loading { + background: var(--surface); + border: 1px solid var(--border); + border-radius: var(--radius-lg); + padding: 1.5rem; + margin-bottom: 1.5rem; + box-shadow: var(--shadow-sm); + position: relative; + overflow: hidden; +} + +.feedback-loading::before { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + height: 3px; + background: var(--primary); +} + +.loading-content { + display: flex; + align-items: center; + justify-content: center; + gap: 1rem; + text-align: center; +} + +.loading-content p { + margin: 0; + color: var(--text-light); + font-size: 1rem; + font-weight: 500; +} + +.loading-spinner { + width: 24px; + height: 24px; + border: 3px solid var(--surface-alt); + border-top: 3px solid var(--primary); + border-radius: 50%; + animation: spin 1s linear infinite; +} + +@keyframes spin { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } +} + +/* Start Conversation Button Styles */ +.start-conversation-btn { + background: var(--primary); + color: white; + border: none; + padding: 1rem 2rem; + border-radius: var(--radius-lg); + cursor: pointer; + font-family: 'DM Sans', sans-serif; + font-size: 0.9rem; + font-weight: 500; + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); + box-shadow: var(--shadow); + display: flex; + align-items: center; + gap: 0.5rem; + min-width: 200px; + justify-content: center; +} + +.start-conversation-btn:hover:not(:disabled) { + background: var(--primary-dark); + transform: translateY(-2px); + box-shadow: var(--shadow-lg); +} + +.start-conversation-btn:disabled { + background: var(--text-muted); + cursor: not-allowed; + transform: none; + box-shadow: var(--shadow-sm); +} + +/* Tutorial Popup Styles */ +.tutorial-overlay { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(0, 0, 0, 0.6); + display: flex; + align-items: center; + justify-content: center; + z-index: 9999; + backdrop-filter: blur(4px); +} + +.tutorial-popup { + background: var(--surface); + border-radius: var(--radius-lg); + box-shadow: var(--shadow-lg); + max-width: 500px; + width: 90%; + max-height: 80vh; + overflow-y: auto; + animation: tutorialSlideIn 0.3s ease-out; +} + +@keyframes tutorialSlideIn { + from { + opacity: 0; + transform: translateY(-20px) scale(0.95); + } + to { + opacity: 1; + transform: translateY(0) scale(1); + } +} + +.tutorial-header { + display: flex; + justify-content: space-between; + align-items: center; + padding: 1.5rem 1.5rem 1rem 1.5rem; + border-bottom: 1px solid var(--border); +} + +.tutorial-header h3 { + margin: 0; + color: var(--text); + font-size: 1.3rem; + font-weight: 700; +} + +.tutorial-close { + background: none; + border: none; + font-size: 1.2rem; + cursor: pointer; + color: var(--text-muted); + padding: 0.25rem; + border-radius: var(--radius); + transition: all 0.2s ease; +} + +.tutorial-close:hover { + background: var(--surface-alt); + color: var(--text); +} + +.tutorial-content { + padding: 1.5rem; +} + +.tutorial-step { + display: flex; + align-items: flex-start; + gap: 1rem; + margin-bottom: 1.5rem; +} + +.tutorial-step:last-child { + margin-bottom: 0; +} + +.tutorial-icon { + font-size: 2rem; + flex-shrink: 0; +} + +.tutorial-text { + flex: 1; +} + +.tutorial-text strong { + display: block; + color: var(--text); + font-size: 1rem; + font-weight: 600; + margin-bottom: 0.5rem; +} + +.tutorial-text p { + margin: 0; + color: var(--text-light); + font-size: 0.9rem; + line-height: 1.4; +} + +.tutorial-footer { + padding: 1rem 1.5rem 1.5rem 1.5rem; + border-top: 1px solid var(--border); + display: flex; + justify-content: center; +} + +.tutorial-got-it { + background: var(--primary); + color: white; + border: none; + padding: 0.75rem 2rem; + border-radius: var(--radius-lg); + cursor: pointer; + font-family: 'DM Sans', sans-serif; + font-size: 0.9rem; + font-weight: 600; + transition: all 0.2s ease; + box-shadow: var(--shadow-sm); +} + +.tutorial-got-it:hover { + background: var(--primary-dark); + transform: translateY(-1px); + box-shadow: var(--shadow); +} + +@media (max-width: 768px) { + .tutorial-popup { + width: 95%; + max-height: 85vh; + } + + .tutorial-header { + padding: 1rem 1rem 0.75rem 1rem; + } + + .tutorial-header h3 { + font-size: 1.1rem; + } + + .tutorial-content { + padding: 1rem; + } + + .tutorial-step { + gap: 0.75rem; + margin-bottom: 1rem; + } + + .tutorial-icon { + font-size: 1.5rem; + } + + .tutorial-footer { + padding: 0.75rem 1rem 1rem 1rem; + } +}