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!

- 🎉 Großartige Unterhaltung! Hier ist hilfreiche Rückmeldung: + 🎉 Great conversation! Here's some helpful feedback:

@@ -202,7 +202,7 @@
-

💡 Tipps, um noch natürlicher zu klingen:

+

💡 Tips to sound even more natural:

@@ -428,7 +428,7 @@ export default { async startRecording() { if (this.connectionStatus !== 'connected') { - alert('Bitte warten Sie, bis die Verbindung hergestellt ist') + alert('Please wait for connection to establish') return } @@ -472,7 +472,7 @@ export default { } catch (error) { console.error('Error starting recording:', error) - alert('Fehler beim Zugriff auf das Mikrofon: ' + error.message) + alert('Error accessing microphone: ' + error.message) } }, @@ -495,7 +495,7 @@ export default { this.isRecording = false this.isAutoListening = false - this.currentTranscription = 'Verarbeitung...' + this.currentTranscription = 'Processing...' this.isTranscriptionFinal = false }, @@ -571,10 +571,10 @@ export default { getStatusMessage() { const statusMessages = { - connecting: 'Verbindung wird hergestellt...', - connected: 'Verbunden', - disconnected: 'Getrennt', - error: 'Verbindungsfehler' + connecting: 'Connecting...', + connected: 'Connected', + disconnected: 'Disconnected', + error: 'Connection Error' } return statusMessages[this.connectionStatus] || 'Unbekannt' }, @@ -623,7 +623,7 @@ export default { }, showConversationComplete() { - this.addMessage('system', '🎉 Herzlichen Glückwunsch! Sie haben alle Ziele für dieses Szenario erreicht!') + this.addMessage('system', '🎉 Congratulations! You have completed all goals for this scenario!') setTimeout(() => { this.scrollToBottom() @@ -693,7 +693,7 @@ export default { message.showTranslation = true } catch (error) { console.error('Translation error:', error) - message.englishTranslation = 'Übersetzung fehlgeschlagen. Bitte versuchen Sie es erneut.' + message.englishTranslation = 'Translation failed. Please try again.' message.showTranslation = true } finally { message.loadingTranslation = false @@ -881,11 +881,11 @@ export default { getTranscriptionStatus() { if (this.isTranscriptionFinal) { - return 'Fertig' + return 'Final' } else if (this.isAutoListening) { - return 'Auto-Zuhören...' + return 'Auto-listening...' } else { - return 'Höre zu...' + return 'Listening...' } }, @@ -1047,7 +1047,7 @@ export default { console.error('Failed to get conversation feedback:', response.status) // Show a fallback message this.conversationFeedback = { - encouragement: "Großartige Übung! Jedes Gespräch hilft Ihnen dabei, sich zu verbessern.", + encouragement: "Great job practicing! Every conversation helps you improve.", suggestions: [], examples: [] } @@ -1057,7 +1057,7 @@ export default { console.error('Error getting conversation feedback:', error) // Show a fallback message this.conversationFeedback = { - encouragement: "Großartige Übung! Jedes Gespräch hilft Ihnen dabei, sich zu verbessern.", + encouragement: "Great job practicing! Every conversation helps you improve.", suggestions: [], examples: [] } diff --git a/apps/german-app/src/main.js b/apps/german-app/src/main.js index b39d85e..db7baa7 100644 --- a/apps/german-app/src/main.js +++ b/apps/german-app/src/main.js @@ -2,6 +2,7 @@ import { createApp } from 'vue' import { createRouter, createWebHistory } from 'vue-router' import App from './App.vue' import ScenarioView from './views/ScenarioView.vue' +import { getLanguageConfig } from '../../shared/config/languages.js' const routes = [ { path: '/', redirect: '/scenario/spati' }, @@ -13,4 +14,6 @@ const router = createRouter({ routes }) -createApp(App).use(router).mount('#app') \ No newline at end of file +const app = createApp(App) +app.config.globalProperties.$languageConfig = getLanguageConfig('german') +app.use(router).mount('#app') \ No newline at end of file diff --git a/apps/german-app/src/views/ScenarioView.vue b/apps/german-app/src/views/ScenarioView.vue index 6077ec0..4ad5654 100644 --- a/apps/german-app/src/views/ScenarioView.vue +++ b/apps/german-app/src/views/ScenarioView.vue @@ -3,7 +3,7 @@

{{ getScenarioEmoji(type) }} {{ scenarioData.title }}

- Ziel: {{ scenarioData.goal }} + Goal: {{ scenarioData.goal }}
@@ -22,31 +22,31 @@
- +
-

📍 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; + } +}