feat(i18n): add new localization keys for lesson details and deepening sections
All checks were successful
Deploy to production / deploy (push) Successful in 2m46s

- Introduced new localization strings in German, English, and Spanish for lesson detail toggles and deepening sections, enhancing user experience across multiple languages.
- Updated VocabLessonView to incorporate these new localization keys, improving the clarity and accessibility of lesson information for users.
This commit is contained in:
Torsten Schulz (local)
2026-04-01 10:05:37 +02:00
parent 6d13965c76
commit 8bbfd46ada
4 changed files with 222 additions and 164 deletions

View File

@@ -456,6 +456,9 @@
"vocabPrepStep2": "Gehe die gleichen Begriffe noch einmal durch (aktive Wiederholung, ohne zu üben).", "vocabPrepStep2": "Gehe die gleichen Begriffe noch einmal durch (aktive Wiederholung, ohne zu üben).",
"vocabPrepConfirm2": "Zweite Durchsicht erledigt", "vocabPrepConfirm2": "Zweite Durchsicht erledigt",
"vocabPrepReady": "Du kannst jetzt mit dem Vokabeltrainer starten.", "vocabPrepReady": "Du kannst jetzt mit dem Vokabeltrainer starten.",
"lessonDetailsToggle": "Mehr Lektionsdetails anzeigen",
"deepenSectionTitle": "Vertiefen und nachlesen",
"assistantSectionTitle": "Mit Sprachassistent vertiefen",
"vocabOverviewToggle": "Gesamtübersicht der Begriffe anzeigen", "vocabOverviewToggle": "Gesamtübersicht der Begriffe anzeigen",
"vocabTrainerLockedHint": "Bitte bestätige zuerst zwei Lern-Durchgänge bei „Vorbereitung vor dem Vokabeltrainer“.", "vocabTrainerLockedHint": "Bitte bestätige zuerst zwei Lern-Durchgänge bei „Vorbereitung vor dem Vokabeltrainer“.",
"exerciseUnlockHintAfterPrep": "Arbeite zuerst die vorbereiteten Begriffe durch. Danach wird die Kapitel-Prüfung freigeschaltet.", "exerciseUnlockHintAfterPrep": "Arbeite zuerst die vorbereiteten Begriffe durch. Danach wird die Kapitel-Prüfung freigeschaltet.",

View File

@@ -456,6 +456,9 @@
"vocabPrepStep2": "Go through the same items again (active review, not testing yet).", "vocabPrepStep2": "Go through the same items again (active review, not testing yet).",
"vocabPrepConfirm2": "Second pass done", "vocabPrepConfirm2": "Second pass done",
"vocabPrepReady": "You can start the vocabulary trainer now.", "vocabPrepReady": "You can start the vocabulary trainer now.",
"lessonDetailsToggle": "Show more lesson details",
"deepenSectionTitle": "Deepen and review",
"assistantSectionTitle": "Deepen with language assistant",
"vocabOverviewToggle": "Show full overview of terms", "vocabOverviewToggle": "Show full overview of terms",
"vocabTrainerLockedHint": "Please confirm two preparation steps under “Preparation before the vocabulary trainer” first.", "vocabTrainerLockedHint": "Please confirm two preparation steps under “Preparation before the vocabulary trainer” first.",
"exerciseUnlockHintAfterPrep": "Work through the prepared terms first. The chapter test will unlock afterwards.", "exerciseUnlockHintAfterPrep": "Work through the prepared terms first. The chapter test will unlock afterwards.",

View File

@@ -454,6 +454,9 @@
"vocabPrepStep2": "Repasa los mismos elementos otra vez (repaso activo, aún sin practicar).", "vocabPrepStep2": "Repasa los mismos elementos otra vez (repaso activo, aún sin practicar).",
"vocabPrepConfirm2": "Segunda lectura hecha", "vocabPrepConfirm2": "Segunda lectura hecha",
"vocabPrepReady": "Ya puedes iniciar el entrenador de vocabulario.", "vocabPrepReady": "Ya puedes iniciar el entrenador de vocabulario.",
"lessonDetailsToggle": "Mostrar más detalles de la lección",
"deepenSectionTitle": "Profundizar y repasar",
"assistantSectionTitle": "Profundizar con el asistente de idiomas",
"vocabOverviewToggle": "Mostrar vista general completa de los términos", "vocabOverviewToggle": "Mostrar vista general completa de los términos",
"vocabTrainerLockedHint": "Confirma primero los dos pasos de preparación arriba.", "vocabTrainerLockedHint": "Confirma primero los dos pasos de preparación arriba.",
"exerciseUnlockHintAfterPrep": "Primero recorre los términos preparados. Después se desbloqueará la prueba del capítulo.", "exerciseUnlockHintAfterPrep": "Primero recorre los términos preparados. Después se desbloqueará la prueba del capítulo.",

View File

@@ -7,8 +7,6 @@
<h2>{{ lesson.title }}</h2> <h2>{{ lesson.title }}</h2>
</div> </div>
<p v-if="lesson.description" class="lesson-description">{{ lesson.description }}</p>
<!-- Tabs für Lernen und Übungen --> <!-- Tabs für Lernen und Übungen -->
<div class="lesson-tabs"> <div class="lesson-tabs">
<button <button
@@ -43,10 +41,6 @@
<span class="lesson-meta-label">{{ $t('socialnetwork.vocab.courses.lessonTypeLabel') }}</span> <span class="lesson-meta-label">{{ $t('socialnetwork.vocab.courses.lessonTypeLabel') }}</span>
<strong>{{ getLessonTypeLabel(lesson.lessonType) }}</strong> <strong>{{ getLessonTypeLabel(lesson.lessonType) }}</strong>
</div> </div>
<div class="lesson-meta-item" v-if="lessonPedagogy.phaseLabel">
<span class="lesson-meta-label">Phase</span>
<strong>{{ getPhaseLabel(lessonPedagogy.phaseLabel) }}</strong>
</div>
<div class="lesson-meta-item" v-if="lessonPedagogy.didacticMode"> <div class="lesson-meta-item" v-if="lessonPedagogy.didacticMode">
<span class="lesson-meta-label">Fokus</span> <span class="lesson-meta-label">Fokus</span>
<strong>{{ getDidacticModeLabel(lessonPedagogy.didacticMode) }}</strong> <strong>{{ getDidacticModeLabel(lessonPedagogy.didacticMode) }}</strong>
@@ -59,15 +53,29 @@
<span class="lesson-meta-label">{{ $t('socialnetwork.vocab.courses.exerciseLoad') }}</span> <span class="lesson-meta-label">{{ $t('socialnetwork.vocab.courses.exerciseLoad') }}</span>
<strong>{{ effectiveExercises?.length || 0 }} {{ $t('socialnetwork.vocab.courses.exercisesShort') }}</strong> <strong>{{ effectiveExercises?.length || 0 }} {{ $t('socialnetwork.vocab.courses.exercisesShort') }}</strong>
</div> </div>
<div class="lesson-meta-item" v-if="lessonPedagogy.newUnitTarget">
<span class="lesson-meta-label">Neue Einheiten</span>
<strong>{{ lessonPedagogy.newUnitTarget }}</strong>
</div>
<div class="lesson-meta-item" v-if="lessonPedagogy.reviewWeight != null">
<span class="lesson-meta-label">Wiederholung</span>
<strong>{{ lessonPedagogy.reviewWeight }}%</strong>
</div>
</div> </div>
<details
v-if="lessonPedagogy.phaseLabel || lessonPedagogy.newUnitTarget || lessonPedagogy.reviewWeight != null"
class="lesson-overview-more"
>
<summary class="lesson-overview-more__summary">
{{ $t('socialnetwork.vocab.courses.lessonDetailsToggle') }}
</summary>
<div class="lesson-overview-more__grid">
<div class="lesson-meta-item" v-if="lessonPedagogy.phaseLabel">
<span class="lesson-meta-label">Phase</span>
<strong>{{ getPhaseLabel(lessonPedagogy.phaseLabel) }}</strong>
</div>
<div class="lesson-meta-item" v-if="lessonPedagogy.newUnitTarget">
<span class="lesson-meta-label">Neue Einheiten</span>
<strong>{{ lessonPedagogy.newUnitTarget }}</strong>
</div>
<div class="lesson-meta-item" v-if="lessonPedagogy.reviewWeight != null">
<span class="lesson-meta-label">Wiederholung</span>
<strong>{{ lessonPedagogy.reviewWeight }}%</strong>
</div>
</div>
</details>
</div> </div>
<div v-if="lessonPedagogy.isIntensiveReview" class="lesson-intensity-banner"> <div v-if="lessonPedagogy.isIntensiveReview" class="lesson-intensity-banner">
@@ -75,148 +83,6 @@
<p>Diese Lektion priorisiert Wiederholung und Vertiefung. Neuer Stoff wird bewusst reduziert, damit vorhandene Muster stabil werden.</p> <p>Diese Lektion priorisiert Wiederholung und Vertiefung. Neuer Stoff wird bewusst reduziert, damit vorhandene Muster stabil werden.</p>
</div> </div>
<div class="learn-grid">
<div
v-if="(lesson && lesson.description) || lessonDidactics.learningGoals.length > 0"
class="didactic-card lesson-intro-combined"
>
<div v-if="lesson && lesson.description" class="lesson-intro-block">
<h4>{{ $t('socialnetwork.vocab.courses.lessonDescription') }}</h4>
<p>{{ lesson.description }}</p>
</div>
<div v-if="lessonDidactics.learningGoals.length > 0" class="lesson-intro-block">
<h4>{{ $t('socialnetwork.vocab.courses.learningGoals') }}</h4>
<ul class="didactic-list">
<li v-for="(goal, index) in lessonDidactics.learningGoals" :key="'goal-' + index">{{ goal }}</li>
</ul>
</div>
</div>
<div v-if="normalizedCorePatterns.length > 0" class="didactic-card">
<h4>{{ $t('socialnetwork.vocab.courses.corePatterns') }}</h4>
<p v-if="corePatternsHaveGloss" class="core-patterns-hint">
{{ $t('socialnetwork.vocab.courses.corePatternsHint') }}
</p>
<div class="pattern-list">
<div v-for="(pattern, index) in normalizedCorePatterns" :key="'pattern-' + index" class="pattern-item">
<div class="pattern-target">{{ pattern.target }}</div>
<div v-if="pattern.gloss" class="pattern-gloss">{{ pattern.gloss }}</div>
</div>
</div>
</div>
<div v-if="lessonDidactics.grammarFocus.length > 0" class="grammar-explanations didactic-card">
<h4>{{ $t('socialnetwork.vocab.courses.grammarExplanations') }}</h4>
<div v-for="(explanation, index) in lessonDidactics.grammarFocus" :key="'grammar-' + index" class="grammar-explanation-item">
<strong>{{ explanation.title || $t('socialnetwork.vocab.courses.grammarImpulse') }}</strong>
<p>{{ explanation.text }}</p>
<p v-if="explanation.example" class="grammar-example">{{ explanation.example }}</p>
</div>
</div>
<div v-if="lessonDidactics.speakingPrompts.length > 0" class="didactic-card">
<h4>{{ $t('socialnetwork.vocab.courses.speakingTasks') }}</h4>
<div v-for="(prompt, index) in lessonDidactics.speakingPrompts" :key="'speaking-' + index" class="speaking-prompt-item">
<strong>{{ prompt.title || $t('socialnetwork.vocab.courses.speakingPrompt') }}</strong>
<p>{{ prompt.prompt }}</p>
<p v-if="prompt.cue" class="speaking-cue">{{ prompt.cue }}</p>
</div>
</div>
<div v-if="lessonDidactics.practicalTasks.length > 0" class="didactic-card">
<h4>{{ $t('socialnetwork.vocab.courses.practicalTasks') }}</h4>
<div v-for="(task, index) in lessonDidactics.practicalTasks" :key="'task-' + index" class="practical-task-item">
<strong>{{ task.title }}</strong>
<p>{{ task.text }}</p>
</div>
</div>
<div ref="assistantCard" class="didactic-card language-assistant-card" :class="{ 'language-assistant-card--focused': isAssistantFocused }">
<div class="language-assistant-card__header">
<div>
<h4>{{ $t('socialnetwork.vocab.courses.languageAssistantTitle') }}</h4>
<p class="language-assistant-card__intro">{{ $t('socialnetwork.vocab.courses.languageAssistantIntro') }}</p>
</div>
<button @click="openLanguageAssistantSettings" class="button-secondary language-assistant-card__settings">
{{ $t('socialnetwork.vocab.courses.languageAssistantSettings') }}
</button>
</div>
<div v-if="assistantLoading" class="language-assistant-card__state">
{{ $t('general.loading') }}
</div>
<div v-else-if="!assistantAvailable" class="language-assistant-card__state">
<p>{{ $t('socialnetwork.vocab.courses.languageAssistantSetupHint') }}</p>
</div>
<div v-else class="language-assistant-panel">
<div class="language-assistant-panel__modes">
<button
v-for="mode in assistantModes"
:key="mode.value"
type="button"
class="assistant-mode-button"
:class="{ active: assistantMode === mode.value }"
@click="assistantMode = mode.value"
>
{{ mode.label }}
</button>
</div>
<div class="language-assistant-panel__presets">
<button type="button" class="assistant-preset-button" @click="sendPresetPrompt('explain')">
{{ $t('socialnetwork.vocab.courses.languageAssistantPromptExplain') }}
</button>
<button type="button" class="assistant-preset-button" @click="sendPresetPrompt('practice')">
{{ $t('socialnetwork.vocab.courses.languageAssistantPromptPractice') }}
</button>
<button type="button" class="assistant-preset-button" @click="sendPresetPrompt('correct')">
{{ $t('socialnetwork.vocab.courses.languageAssistantPromptCorrect') }}
</button>
</div>
<div v-if="assistantMessages.length > 0" class="language-assistant-chat">
<article
v-for="(message, index) in assistantMessages"
:key="`${message.role}-${index}`"
class="assistant-message"
:class="`assistant-message--${message.role}`"
>
<strong>{{ message.role === 'assistant' ? $t('socialnetwork.vocab.courses.languageAssistantSpeakerAi') : $t('socialnetwork.vocab.courses.languageAssistantSpeakerYou') }}</strong>
<p>{{ message.content }}</p>
</article>
</div>
<label class="language-assistant-panel__input">
<span>{{ $t('socialnetwork.vocab.courses.languageAssistantInputLabel') }}</span>
<textarea
v-model="assistantInput"
:placeholder="$t('socialnetwork.vocab.courses.languageAssistantInputPlaceholder')"
rows="4"
/>
</label>
<p v-if="assistantError" class="form-error">{{ assistantError }}</p>
<div class="language-assistant-panel__actions">
<button
type="button"
@click="sendAssistantMessage()"
:disabled="assistantSubmitting || !assistantInput.trim()"
>
{{ assistantSubmitting ? $t('socialnetwork.vocab.courses.languageAssistantSending') : $t('socialnetwork.vocab.courses.languageAssistantSend') }}
</button>
</div>
</div>
</div>
<div v-if="lesson && lesson.culturalNotes" class="cultural-notes didactic-card">
<h4>{{ $t('socialnetwork.vocab.courses.culturalNotes') }}</h4>
<p>{{ lesson.culturalNotes }}</p>
</div>
</div>
<!-- Zwei Durchgänge: dieselben Kernmuster schrittweise vor dem Trainer --> <!-- Zwei Durchgänge: dieselben Kernmuster schrittweise vor dem Trainer -->
<div <div
v-if="prepItems.length > 0 && !vocabTrainerActive" v-if="prepItems.length > 0 && !vocabTrainerActive"
@@ -380,6 +246,158 @@
{{ $t('socialnetwork.vocab.courses.startExercises') }} {{ $t('socialnetwork.vocab.courses.startExercises') }}
</button> </button>
</div> </div>
<details class="lesson-deepen-section surface-card">
<summary class="lesson-deepen-section__summary">
{{ $t('socialnetwork.vocab.courses.deepenSectionTitle') }}
</summary>
<div class="learn-grid">
<div
v-if="(lesson && lesson.description) || lessonDidactics.learningGoals.length > 0"
class="didactic-card lesson-intro-combined"
>
<div v-if="lesson && lesson.description" class="lesson-intro-block">
<h4>{{ $t('socialnetwork.vocab.courses.lessonDescription') }}</h4>
<p>{{ lesson.description }}</p>
</div>
<div v-if="lessonDidactics.learningGoals.length > 0" class="lesson-intro-block">
<h4>{{ $t('socialnetwork.vocab.courses.learningGoals') }}</h4>
<ul class="didactic-list">
<li v-for="(goal, index) in lessonDidactics.learningGoals" :key="'goal-' + index">{{ goal }}</li>
</ul>
</div>
</div>
<div v-if="normalizedCorePatterns.length > 0" class="didactic-card">
<h4>{{ $t('socialnetwork.vocab.courses.corePatterns') }}</h4>
<p v-if="corePatternsHaveGloss" class="core-patterns-hint">
{{ $t('socialnetwork.vocab.courses.corePatternsHint') }}
</p>
<div class="pattern-list">
<div v-for="(pattern, index) in normalizedCorePatterns" :key="'pattern-' + index" class="pattern-item">
<div class="pattern-target">{{ pattern.target }}</div>
<div v-if="pattern.gloss" class="pattern-gloss">{{ pattern.gloss }}</div>
</div>
</div>
</div>
<div v-if="lessonDidactics.grammarFocus.length > 0" class="grammar-explanations didactic-card">
<h4>{{ $t('socialnetwork.vocab.courses.grammarExplanations') }}</h4>
<div v-for="(explanation, index) in lessonDidactics.grammarFocus" :key="'grammar-' + index" class="grammar-explanation-item">
<strong>{{ explanation.title || $t('socialnetwork.vocab.courses.grammarImpulse') }}</strong>
<p>{{ explanation.text }}</p>
<p v-if="explanation.example" class="grammar-example">{{ explanation.example }}</p>
</div>
</div>
<div v-if="lessonDidactics.speakingPrompts.length > 0" class="didactic-card">
<h4>{{ $t('socialnetwork.vocab.courses.speakingTasks') }}</h4>
<div v-for="(prompt, index) in lessonDidactics.speakingPrompts" :key="'speaking-' + index" class="speaking-prompt-item">
<strong>{{ prompt.title || $t('socialnetwork.vocab.courses.speakingPrompt') }}</strong>
<p>{{ prompt.prompt }}</p>
<p v-if="prompt.cue" class="speaking-cue">{{ prompt.cue }}</p>
</div>
</div>
<div v-if="lessonDidactics.practicalTasks.length > 0" class="didactic-card">
<h4>{{ $t('socialnetwork.vocab.courses.practicalTasks') }}</h4>
<div v-for="(task, index) in lessonDidactics.practicalTasks" :key="'task-' + index" class="practical-task-item">
<strong>{{ task.title }}</strong>
<p>{{ task.text }}</p>
</div>
</div>
<div v-if="lesson && lesson.culturalNotes" class="cultural-notes didactic-card">
<h4>{{ $t('socialnetwork.vocab.courses.culturalNotes') }}</h4>
<p>{{ lesson.culturalNotes }}</p>
</div>
</div>
</details>
<details class="lesson-assistant-section surface-card">
<summary class="lesson-deepen-section__summary">
{{ $t('socialnetwork.vocab.courses.assistantSectionTitle') }}
</summary>
<div ref="assistantCard" class="didactic-card language-assistant-card" :class="{ 'language-assistant-card--focused': isAssistantFocused }">
<div class="language-assistant-card__header">
<div>
<h4>{{ $t('socialnetwork.vocab.courses.languageAssistantTitle') }}</h4>
<p class="language-assistant-card__intro">{{ $t('socialnetwork.vocab.courses.languageAssistantIntro') }}</p>
</div>
<button @click="openLanguageAssistantSettings" class="button-secondary language-assistant-card__settings">
{{ $t('socialnetwork.vocab.courses.languageAssistantSettings') }}
</button>
</div>
<div v-if="assistantLoading" class="language-assistant-card__state">
{{ $t('general.loading') }}
</div>
<div v-else-if="!assistantAvailable" class="language-assistant-card__state">
<p>{{ $t('socialnetwork.vocab.courses.languageAssistantSetupHint') }}</p>
</div>
<div v-else class="language-assistant-panel">
<div class="language-assistant-panel__modes">
<button
v-for="mode in assistantModes"
:key="mode.value"
type="button"
class="assistant-mode-button"
:class="{ active: assistantMode === mode.value }"
@click="assistantMode = mode.value"
>
{{ mode.label }}
</button>
</div>
<div class="language-assistant-panel__presets">
<button type="button" class="assistant-preset-button" @click="sendPresetPrompt('explain')">
{{ $t('socialnetwork.vocab.courses.languageAssistantPromptExplain') }}
</button>
<button type="button" class="assistant-preset-button" @click="sendPresetPrompt('practice')">
{{ $t('socialnetwork.vocab.courses.languageAssistantPromptPractice') }}
</button>
<button type="button" class="assistant-preset-button" @click="sendPresetPrompt('correct')">
{{ $t('socialnetwork.vocab.courses.languageAssistantPromptCorrect') }}
</button>
</div>
<div v-if="assistantMessages.length > 0" class="language-assistant-chat">
<article
v-for="(message, index) in assistantMessages"
:key="`${message.role}-${index}`"
class="assistant-message"
:class="`assistant-message--${message.role}`"
>
<strong>{{ message.role === 'assistant' ? $t('socialnetwork.vocab.courses.languageAssistantSpeakerAi') : $t('socialnetwork.vocab.courses.languageAssistantSpeakerYou') }}</strong>
<p>{{ message.content }}</p>
</article>
</div>
<label class="language-assistant-panel__input">
<span>{{ $t('socialnetwork.vocab.courses.languageAssistantInputLabel') }}</span>
<textarea
v-model="assistantInput"
:placeholder="$t('socialnetwork.vocab.courses.languageAssistantInputPlaceholder')"
rows="4"
/>
</label>
<p v-if="assistantError" class="form-error">{{ assistantError }}</p>
<div class="language-assistant-panel__actions">
<button
type="button"
@click="sendAssistantMessage()"
:disabled="assistantSubmitting || !assistantInput.trim()"
>
{{ assistantSubmitting ? $t('socialnetwork.vocab.courses.languageAssistantSending') : $t('socialnetwork.vocab.courses.languageAssistantSend') }}
</button>
</div>
</div>
</div>
</details>
</div> </div>
<!-- Übungen-Tab (Kapitel-Prüfung) --> <!-- Übungen-Tab (Kapitel-Prüfung) -->
@@ -2388,7 +2406,7 @@ export default {
.lesson-overview-card { .lesson-overview-card {
display: flex; display: flex;
justify-content: space-between; flex-direction: column;
gap: 20px; gap: 20px;
padding: 20px; padding: 20px;
margin-bottom: 20px; margin-bottom: 20px;
@@ -2404,9 +2422,8 @@ export default {
.lesson-meta-grid { .lesson-meta-grid {
display: grid; display: grid;
grid-template-columns: repeat(3, minmax(130px, 1fr)); grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
gap: 12px; gap: 12px;
min-width: 360px;
} }
.lesson-meta-item { .lesson-meta-item {
@@ -2440,6 +2457,25 @@ export default {
margin-top: 6px; margin-top: 6px;
} }
.lesson-overview-more {
border-top: 1px solid rgba(160, 120, 40, 0.18);
padding-top: 14px;
}
.lesson-overview-more__summary,
.lesson-deepen-section__summary {
cursor: pointer;
font-weight: 600;
color: #5f4313;
}
.lesson-overview-more__grid {
margin-top: 12px;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
gap: 12px;
}
.learn-grid { .learn-grid {
display: grid; display: grid;
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
@@ -2553,6 +2589,17 @@ export default {
color: #8a5a00; color: #8a5a00;
} }
.lesson-deepen-section,
.lesson-assistant-section {
margin-top: 20px;
padding: 16px 18px;
}
.lesson-deepen-section .learn-grid,
.lesson-assistant-section .language-assistant-card {
margin-top: 16px;
}
.grammar-example, .grammar-example,
.speaking-cue, .speaking-cue,
.pattern-drill-hint { .pattern-drill-hint {
@@ -2610,11 +2657,6 @@ export default {
box-shadow: none; box-shadow: none;
} }
.lesson-description {
color: #666;
margin-bottom: 20px;
}
.grammar-exercises { .grammar-exercises {
margin-top: 30px; margin-top: 30px;
} }
@@ -2835,6 +2877,13 @@ export default {
margin-bottom: 14px; margin-bottom: 14px;
} }
.vocab-list--overview {
padding: 14px 16px;
background: rgba(255, 255, 255, 0.86);
border: 1px solid #eadfcf;
border-radius: 12px;
}
.vocab-list h4 { .vocab-list h4 {
margin-bottom: 15px; margin-bottom: 15px;
color: #333; color: #333;