chinese_learning_v2 / app /static /css /elearning.css
GphaHoa156
Add application file
8b3b66c
/* ============================================================
HanziLearn – E-Learning Stylesheet
============================================================ */
/* ── Learn Header ────────────────────────────────────────────── */
.learn-header {
background: var(--bg-elevated);
border-bottom: 1px solid var(--border);
padding: 2rem 0 0;
position: relative;
}
/* Coloured top bar β€” colour injected by JS via --lc on #learnHeader */
.learn-header::before {
content: '';
position: absolute; top:0; left:0; right:0; height:3px;
background: var(--lc, var(--accent));
}
.learn-badge {
display:inline-flex; align-items:center;
background: var(--lc, var(--accent));
color:#fff; font-family:var(--mono-font); font-size:.85rem;
font-weight:700; padding:.4rem .9rem; border-radius:999px;
}
.learn-title { font-size:1.5rem; font-weight:700; }
.learn-subtitle { font-size:.85rem; color:var(--text-muted); }
.learn-user-chip {
background:var(--bg-base); border:1px solid var(--border);
border-radius:999px; padding:.35rem 1rem;
font-size:.85rem; color:var(--text-muted);
}
/* ── Mode Tabs ───────────────────────────────────────────────── */
.mode-tabs {
display:flex; gap:.25rem; overflow-x:auto; padding-bottom:0;
}
.mode-tabs::-webkit-scrollbar { height:0; }
.mode-tab {
padding:.6rem 1.2rem; border-radius:10px 10px 0 0;
font-size:.875rem; font-weight:500; color:var(--text-muted);
text-decoration:none; white-space:nowrap;
border:1px solid transparent; border-bottom:none;
transition:all .2s;
}
.mode-tab:hover { color:var(--text-primary); background:rgba(255,255,255,.04); }
.mode-tab.active {
color:var(--text-primary); background:var(--bg-base);
border-color:var(--border);
}
/* ── Level Strip ─────────────────────────────────────────────── */
.level-strip {
background:var(--bg-base); border-bottom:1px solid var(--border);
padding:.75rem 0;
}
.level-pill {
font-family:var(--mono-font); font-size:.8rem; font-weight:600;
padding:.3rem .75rem; border-radius:999px;
border:1.5px solid var(--border); color:var(--text-muted);
text-decoration:none; transition:all .2s; white-space:nowrap;
}
.level-pill:hover { border-color:var(--accent); color:var(--accent); }
.level-pill.active { background:var(--accent); border-color:var(--accent); color:#fff; }
/* ── Loading Spinner ─────────────────────────────────────────── */
.learn-spinner {
width:48px; height:48px;
border:3px solid var(--border); border-top-color:var(--accent);
border-radius:50%; animation:spin .8s linear infinite; margin:0 auto;
}
@keyframes spin { to { transform:rotate(360deg); } }
/* ════════════════════════════════════════════════════════════
FLASHCARD – 3-D flip animation
════════════════════════════════════════════════════════════ */
.fc-progress-wrap { max-width:520px; margin:0 auto; }
/*
.fc-scene β€” sets up the 3-D perspective container
.fc-card β€” the card that actually rotates
.fc-front / .fc-back β€” the two faces (back is pre-rotated 180Β°)
Adding .flipped to .fc-card triggers the flip.
*/
.fc-scene {
width:100%; max-width:420px; height:300px;
perspective: 1200px; /* depth of 3-D space */
cursor:pointer; margin:0 auto;
outline:none; /* handled by card border */
}
.fc-card {
position:relative; width:100%; height:100%;
transform-style: preserve-3d; /* children exist in 3-D */
transition: transform .65s cubic-bezier(.4, 0, .2, 1);
border-radius:20px;
}
/* Click/keyboard β€” JS toggles this class */
.fc-card.flipped {
transform: rotateY(180deg);
}
.fc-front,
.fc-back {
position:absolute; inset:0;
backface-visibility: hidden; /* hide face when rotated away */
-webkit-backface-visibility: hidden;
border-radius:20px;
display:flex; flex-direction:column;
align-items:center; justify-content:center;
padding:2rem; text-align:center;
}
/* Front face */
.fc-front {
background: var(--bg-elevated);
border:2px solid var(--border);
}
/* Back face β€” pre-rotated 180Β° so it faces backward initially */
.fc-back {
background: linear-gradient(135deg, rgba(230,57,70,.08), var(--bg-elevated));
border:2px solid rgba(230,57,70,.25);
transform: rotateY(180deg);
}
/* Hover hint on front */
.fc-scene:hover .fc-front:not(.fc-card.flipped .fc-front) {
border-color:rgba(230,57,70,.3);
}
.fc-hanzi {
font-family:var(--hanzi-font); font-size:4rem;
font-weight:700; color:var(--accent); line-height:1;
}
.fc-hanzi--sm { font-size:2.5rem; }
.fc-tap-hint { margin-top:1rem; color:var(--text-muted); font-size:.8rem; }
.fc-pinyin {
font-family:var(--mono-font); font-size:1.1rem;
color:var(--text-muted); margin:.5rem 0;
}
.fc-topic {
font-size:.75rem; color:var(--text-muted);
background:rgba(255,255,255,.06); border:1px solid var(--border);
border-radius:999px; padding:.15rem .6rem; margin-bottom:.5rem;
}
.fc-divider { width:40px; height:2px; background:var(--border); margin:.75rem 0; }
.fc-meaning { font-size:.95rem; color:var(--text-primary); margin-bottom:.2rem; }
.fc-meaning--vi { color:var(--text-muted); font-size:.85rem; }
.btn-icon {
width:48px; height:48px; border-radius:50%;
display:flex; align-items:center; justify-content:center; padding:0;
}
/* ════════════════════════════════════════════════════════════
QUIZ MODE
════════════════════════════════════════════════════════════ */
.quiz-timer {
font-family:var(--mono-font); font-size:1.5rem; font-weight:700;
color:var(--accent); min-width:48px; text-align:center; transition:color .3s;
}
.quiz-timer.urgent { color:#F44336; animation:pulse .5s ease-in-out infinite alternate; }
@keyframes pulse { from{opacity:1} to{opacity:.4} }
.quiz-question-card {
background:var(--bg-elevated); border:1px solid var(--border);
border-radius:var(--radius-lg); padding:2.5rem; text-align:center;
max-width:480px; margin:0 auto;
}
.quiz-hanzi { font-family:var(--hanzi-font); font-size:3.5rem; font-weight:700; color:var(--accent); line-height:1; }
.quiz-pinyin { font-family:var(--mono-font); color:var(--text-muted); margin-top:.5rem; }
.quiz-options {
display:grid; grid-template-columns:1fr 1fr; gap:.75rem;
max-width:480px; margin:0 auto;
}
.quiz-option {
background:var(--bg-elevated); border:2px solid var(--border);
border-radius:var(--radius); padding:1rem; cursor:pointer;
transition:all .2s; font-size:.95rem; text-align:center;
color:var(--text-primary);
}
.quiz-option:hover:not(:disabled) { border-color:var(--accent); background:var(--accent-soft); }
.quiz-option.correct { border-color:#4CAF50; background:rgba(76,175,80,.12); color:#4CAF50; }
.quiz-option.wrong { border-color:#F44336; background:rgba(244,67,54,.12); color:#F44336; }
.quiz-option:disabled { cursor:default; opacity:.7; }
.result-emoji { font-size:4rem; }
.result-score-wrap {
display:inline-block; background:var(--bg-elevated);
border:1px solid var(--border); border-radius:var(--radius-lg); padding:1.5rem 3rem;
}
.result-score { font-family:var(--mono-font); font-size:2.5rem; font-weight:700; color:var(--accent); }
.result-percent { font-size:1rem; color:var(--text-muted); }
/* ════════════════════════════════════════════════════════════
FILL BLANK MODE
════════════════════════════════════════════════════════════ */
.fb-exercise-card {
background:var(--bg-elevated); border:1px solid var(--border);
border-radius:var(--radius-lg); padding:2rem;
max-width:600px; margin:0 auto;
}
.fb-context { font-size:.85rem; text-transform:uppercase; letter-spacing:.06em; margin-bottom:1rem; }
.fb-sentence { font-family:var(--hanzi-font); font-size:1.8rem; color:var(--text-primary); line-height:1.6; margin-bottom:.75rem; }
.fb-blank { display:inline-block; min-width:80px; border-bottom:3px solid var(--accent); color:var(--accent); font-weight:700; text-align:center; padding:0 .5rem; }
.fb-hint { font-family:var(--mono-font); font-size:.85rem; color:var(--text-muted); }
.fb-input {
background:var(--bg-elevated); border:2px solid var(--border);
border-radius:var(--radius); color:var(--text-primary);
font-size:1.1rem; font-family:var(--hanzi-font);
}
.fb-input:focus {
border-color:var(--accent); box-shadow:0 0 0 3px var(--accent-soft);
background:var(--bg-elevated); color:var(--text-primary);
}
.fb-feedback {
max-width:480px; padding:.75rem 1rem; border-radius:var(--radius); font-weight:600;
}
.fb-feedback.correct { background:rgba(76,175,80,.12); border:1px solid rgba(76,175,80,.3); color:#4CAF50; }
.fb-feedback.wrong { background:rgba(244,67,54,.12); border:1px solid rgba(244,67,54,.3); color:#F44336; }
.fb-translation { font-size:.85rem; color:var(--text-muted); font-style:italic; max-width:480px; margin-top:.5rem; }
/* ════════════════════════════════════════════════════════════
LEADERBOARD MODE
════════════════════════════════════════════════════════════ */
.lb-card {
background:var(--bg-elevated); border:1px solid var(--border);
border-radius:var(--radius-lg); padding:1.5rem;
}
.lb-card-title {
font-size:1rem; font-weight:700; margin-bottom:1.25rem;
padding-bottom:.75rem; border-bottom:1px solid var(--border);
}
.lb-item {
display:flex; align-items:center; gap:1rem;
padding:.75rem 0; border-bottom:1px solid rgba(255,255,255,.04);
transition:all .2s;
}
.lb-item:last-child { border-bottom:none; }
.lb-item:hover { padding-left:.25rem; }
.lb-rank { font-family:var(--mono-font); font-size:.85rem; color:var(--text-muted); width:24px; text-align:center; flex-shrink:0; }
.lb-rank.gold { color:#FFD700; font-weight:700; font-size:1rem; }
.lb-rank.silver { color:#C0C0C0; font-weight:700; }
.lb-rank.bronze { color:#CD7F32; font-weight:700; }
.lb-avatar {
width:36px; height:36px; border-radius:50%;
background:var(--accent-soft); border:1.5px solid rgba(230,57,70,.2);
display:flex; align-items:center; justify-content:center;
font-family:var(--hanzi-font); font-size:.9rem; color:var(--accent); flex-shrink:0;
}
.lb-name { flex:1; font-weight:500; font-size:.9rem; }
.lb-score { font-family:var(--mono-font); font-size:.85rem; color:var(--accent); font-weight:600; }
.lb-my-stats {
background:var(--bg-elevated);
border:1px solid rgba(230,57,70,.2); border-radius:var(--radius-lg); padding:1.5rem;
}
.my-stat-card { background:var(--bg-base); border-radius:var(--radius); padding:1.25rem; text-align:center; }
.my-stat-val { font-family:var(--mono-font); font-size:1.75rem; font-weight:700; color:var(--accent); }
.my-stat-label { font-size:.8rem; color:var(--text-muted); margin-top:.25rem; }