@import url('https://fonts.googleapis.com/css2?family=Open+Sans:ital,wght@0,400;0,500;0,600;0,700;1,400&display=swap'); @tailwind base; @tailwind components; @tailwind utilities; /* Vue transition helpers */ @layer components { .modal-fade-enter-active, .modal-fade-leave-active { @apply transition-opacity duration-200; } .modal-fade-enter-from, .modal-fade-leave-to { @apply opacity-0; } .modal-enter-active, .modal-leave-active { @apply transition-opacity duration-150 ease-out; } .modal-enter-from, .modal-leave-to { @apply opacity-0; } .popup-fade-enter-active, .popup-fade-leave-active { @apply transition-all duration-150; } .popup-fade-enter-from, .popup-fade-leave-to { @apply scale-95 opacity-0; } .dropdown-enter-active, .dropdown-leave-active { @apply transition-all duration-150 ease-out; } .dropdown-enter-from, .dropdown-leave-to { @apply scale-[0.97] opacity-0 -translate-y-1.5; } .toast-enter-active, .toast-leave-active { @apply transition-all duration-300 ease-out; } .toast-enter-from, .toast-leave-to { @apply translate-x-2 opacity-0; } .study-fade-enter-active, .study-fade-leave-active { @apply transition-all duration-200; } .study-fade-enter-from, .study-fade-leave-to { @apply scale-[0.97] opacity-0; } .fade-colors-enter-active, .fade-colors-leave-active { @apply transition-all duration-200; } .fade-colors-enter-from, .fade-colors-leave-to { @apply -translate-x-1.5 opacity-0; } .slide-right-enter-active, .slide-right-leave-active { @apply transition-transform duration-[250ms] ease-out; } .slide-right-enter-from, .slide-right-leave-to { @apply translate-x-full; } .slide-x-enter-active, .slide-x-leave-active { @apply transition-all duration-150; } .slide-x-enter-from, .slide-x-leave-to { @apply -translate-x-2 opacity-0; } } /* Dynamic HTML highlights (reading / speaking / vocab) */ @layer components { .hl-grammar-error { @apply rounded-sm bg-red-200 px-0.5 text-red-900; } .hl-vocab-weak { @apply rounded-sm bg-yellow-200 px-0.5 text-yellow-900; } .hl-vocab-strong { @apply rounded-sm bg-green-200 px-0.5 text-green-900; } .vocab-blank { @apply inline-block min-w-[60px] border-b-2 border-emerald-400; } /* Gap fill inputs (GapFillingHtml dynamic DOM) */ .gap-wrapper { @apply inline-flex items-center gap-0.5 align-baseline; } .gap-num { @apply inline-flex h-[18px] min-w-[18px] shrink-0 items-center justify-center rounded-full bg-emerald-400 text-[10px] font-bold leading-none text-white align-middle; } .gap-input { @apply inline-block max-w-[160px] min-w-[88px] border-0 border-b-2 border-b-neutral-900 bg-transparent px-1 pb-0.5 pt-px align-baseline font-[inherit] text-sm text-neutral-900 outline-none transition-colors duration-150; } .gap-input:focus { @apply border-b-emerald-400; } .gap-input:disabled { @apply cursor-not-allowed opacity-60; } } /* Modal with sliding panel */ .modal-enter-active .modal-box, .modal-leave-active .modal-box { @apply transition-transform duration-200; } .modal-enter-from .modal-box, .modal-leave-to .modal-box { @apply translate-y-2.5; } @layer utilities { .scrollbar-hide { -ms-overflow-style: none; scrollbar-width: none; } .scrollbar-hide::-webkit-scrollbar { display: none; } } /* ═══════════════════════════════════════════════════════════ LinguaIELTS — Spotify-inspired design tokens (DESIGN.md) ═══════════════════════════════════════════════════════════ */ :root { /* §2 Primary brand */ --spotify-green: #1ed760; --spotify-green-dark: #1db954; --bg-base: #121212; --bg-surface: #181818; --bg-interactive: #1f1f1f; /* §2 Text */ --text-base: #ffffff; --text-subdued: #b3b3b3; --text-bright: #cbcbcb; --text-emphasis: #fdfdfd; /* §2 Semantic */ --text-negative: #f3727f; --text-warning: #ffa42b; --text-announcement: #539df5; /* §2 Surface & border */ --surface-card: #252525; --surface-card-alt: #272727; --border-button: #4d4d4d; --border-outlined: #7c7c7c; --separator: #b3b3b3; --surface-light: #eeeeee; /* §6 Shadows */ --shadow-heavy: rgba(0, 0, 0, 0.5) 0px 8px 24px; --shadow-medium: rgba(0, 0, 0, 0.3) 0px 8px 8px; --shadow-inset-border: rgb(18, 18, 18) 0px 1px 0px, rgb(124, 124, 124) 0px 0px 0px 1px inset; /* §5 Border radius scale */ --radius-minimal: 2px; --radius-subtle: 4px; --radius-standard: 6px; --radius-comfortable: 8px; --radius-panel: 10px; --radius-large: 100px; --radius-pill: 500px; --radius-full-pill: 9999px; --radius-circle: 50%; /* §3 Typography scale */ --text-section-title: 1.5rem; --text-feature: 1.125rem; --text-body: 1rem; --text-button: 0.875rem; --text-caption: 0.875rem; --text-small: 0.75rem; --text-badge: 0.66rem; --text-micro: 0.625rem; --tracking-button: 1.4px; --tracking-button-wide: 2px; /* §3 Font families — Open Sans */ --font-title: 'Open Sans', 'Helvetica Neue', helvetica, arial, sans-serif; --font-body: 'Open Sans', 'Helvetica Neue', helvetica, arial, sans-serif; --font-mono: 'Consolas', 'Courier New', monospace; /* Layout */ --container-max: 1200px; --navbar-height: 64px; --section-padding-y: 80px; --transition-base: 0.2s ease; /* ── Legacy aliases (keep components working) ── */ --accent: var(--spotify-green); --bg: var(--bg-base); --bg2: var(--bg-interactive); --surface: var(--bg-surface); --surface2: var(--surface-card); --border: var(--border-button); --border2: var(--border-outlined); --ink: var(--text-base); --ink2: var(--text-subdued); --ink3: var(--text-bright); --purple: var(--spotify-green); --purple-l: var(--spotify-green); --purple-d: var(--spotify-green-dark); --purple-bg: rgba(30, 215, 96, 0.12); --green: var(--spotify-green-dark); --green-l: var(--spotify-green); --green-bg: rgba(30, 215, 96, 0.12); --amber: var(--text-warning); --amber-l: var(--text-warning); --amber-bg: rgba(255, 164, 43, 0.12); --blue: var(--text-announcement); --blue-l: var(--text-announcement); --blue-bg: rgba(83, 157, 245, 0.12); --rose: var(--text-negative); --rose-l: var(--text-negative); --rose-bg: rgba(243, 114, 127, 0.12); --violet: var(--spotify-green); --violet-l: var(--spotify-green); --violet-bg: rgba(30, 215, 96, 0.12); --gold: var(--text-warning); --gold-l: var(--text-warning); --gold-bg: rgba(255, 164, 43, 0.12); --shadow-sm: var(--shadow-medium); --shadow: var(--shadow-medium); --shadow-lg: var(--shadow-heavy); --r: var(--radius-comfortable); --r-sm: var(--radius-standard); --r-lg: var(--radius-panel); --font-display: var(--font-title); /* Semantic surfaces */ --bubble-assistant-bg: var(--surface-card); --bubble-user-bg: var(--spotify-green); --bubble-user-text: #000000; --header-accent-bg: rgba(30, 215, 96, 0.12); /* Catbot — aligned with page theme (not inverted) */ --catbot-header-bg: color-mix(in srgb, var(--spotify-green) 14%, var(--bg-surface)); --catbot-title-color: var(--text-base); --catbot-subtitle-color: var(--text-subdued); --catbot-bubble-assistant-bg: var(--bg-interactive); --catbot-bubble-assistant-text: var(--text-base); /* Alternating page sections (dark defaults) */ --section-white: var(--bg-surface); --section-cream: var(--bg-interactive); --section-sky: var(--surface-card); --hero-bg: var(--bg-interactive); --hero-heading: var(--text-base); --hero-subtitle: var(--text-subdued); --cta-accent: var(--spotify-green); --cta-accent-text: #000000; } /* ─── Light theme ─── */ [data-theme="light"] { --bg-base: #f5f5f5; --bg-surface: #ffffff; --bg-interactive: #eeeeee; --text-base: #121212; --text-subdued: #6a6a6a; --text-bright: #535353; --text-emphasis: #000000; --surface-card: #ffffff; --surface-card-alt: #fafafa; --border-button: #e5e7eb; --border-outlined: #d1d5db; --separator: #9ca3af; --shadow-heavy: rgba(0, 0, 0, 0.12) 0px 8px 24px; --shadow-medium: rgba(0, 0, 0, 0.08) 0px 4px 12px; --shadow-inset-border: rgb(255, 255, 255) 0px 1px 0px, rgb(209, 213, 219) 0px 0px 0px 1px inset; --purple-bg: rgba(30, 215, 96, 0.1); --green-bg: rgba(30, 215, 96, 0.1); --amber-bg: rgba(255, 164, 43, 0.1); --blue-bg: rgba(83, 157, 245, 0.1); --rose-bg: rgba(243, 114, 127, 0.1); --violet-bg: rgba(30, 215, 96, 0.1); --gold-bg: rgba(255, 164, 43, 0.1); --bubble-assistant-bg: #ffffff; --bubble-user-bg: var(--spotify-green); --bubble-user-text: #000000; --header-accent-bg: rgba(30, 215, 96, 0.08); --catbot-header-bg: color-mix(in srgb, var(--spotify-green) 10%, var(--bg-surface)); --catbot-title-color: var(--text-base); --catbot-subtitle-color: var(--text-subdued); --catbot-bubble-assistant-bg: color-mix(in srgb, var(--spotify-green) 8%, var(--bg-surface)); --catbot-bubble-assistant-text: var(--text-base); --section-white: #ffffff; --section-cream: #eeeeee; --section-sky: #eeeeee; --hero-bg: var(--bg-surface); --hero-heading: var(--text-base); --hero-subtitle: var(--text-subdued); --cta-accent: var(--spotify-green); --cta-accent-text: #000000; --border-button: #121212; --border-outlined: #292929; } html { color-scheme: dark; } [data-theme="light"] { color-scheme: light; } /* ─── RESET ─── */ *, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; } html { font-size: 16px; } body { font-family: var(--font-body); font-size: var(--text-body); font-weight: 400; line-height: normal; background: var(--bg-base); color: var(--text-base); min-height: 100vh; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } /* §3 Typography base */ h1, h2, h3, h4, h5, h6 { font-family: var(--font-title); font-weight: 600; color: var(--text-base); line-height: normal; } [data-theme="light"] h1, [data-theme="light"] h2, [data-theme="light"] h3, [data-theme="light"] h4, [data-theme="light"] h5, [data-theme="light"] h6 { color: var(--text-emphasis); } /* Inline page header (no colored hero band) */ .page-header { margin-bottom: 1.5rem; } .page-header h1 { font-family: var(--font-display); font-size: var(--text-section-title); font-weight: 700; color: var(--ink); line-height: normal; } .page-header .page-subtitle { font-size: var(--text-caption); color: var(--ink2); margin-top: 4px; } .page-header--row { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 12px; } /* Spotify-style unified panels */ .hub-page { margin: -16px -16px 0; width: calc(100% + 32px); } @media (min-width: 768px) { .hub-page { margin: -24px -24px 0; width: calc(100% + 48px); } } .spotify-panel { border-radius: var(--radius-panel); border: 1px solid var(--border-button); background: var(--bg-surface); overflow: hidden; box-shadow: var(--shadow-medium); } .spotify-panel__header { padding: 20px 24px 16px; border-bottom: 1px solid var(--border-button); } .spotify-panel__tabs { padding: 12px 20px; border-bottom: 1px solid var(--border-button); background: var(--bg-base); overflow-x: auto; -webkit-overflow-scrolling: touch; } .spotify-panel__tabs > .inline-flex { min-width: max-content; } .spotify-panel__body { padding: 20px 24px 24px; background: var(--bg-base); } .hub-card-stack { display: flex; flex-direction: column; gap: 12px; padding: 16px 20px 20px; } .stat-pill-inline { display: inline-flex; align-items: center; gap: 6px; border-radius: var(--radius-large); border: 1px solid var(--border-button); background: var(--bg-interactive); padding: 6px 12px; font-size: 12px; color: var(--ink2); } .stat-pill-inline strong { color: var(--ink); } h1 { font-size: var(--text-section-title); } h2 { font-size: var(--text-feature); font-weight: 600; line-height: 1.3; } h3 { font-size: var(--text-body); font-weight: 700; } p, li { font-size: var(--text-body); color: var(--text-base); } small, .text-caption { font-size: var(--text-caption); color: var(--text-subdued); } a { color: var(--text-subdued); transition: color var(--transition-base); } a:hover { color: var(--text-base); } /* ─── SCROLLBAR ─── */ ::-webkit-scrollbar { width: 6px; height: 6px; } ::-webkit-scrollbar-track { background: transparent; } ::-webkit-scrollbar-thumb { background: var(--border2); border-radius: 99px; } ::-webkit-scrollbar-thumb:hover { background: var(--ink3); } /* ─── ANIMATIONS ─── */ @keyframes fadeUp { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: translateY(0); } } @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } } @keyframes pulse-idle { 0%, 100% { box-shadow: 0 0 0 0 rgba(224,87,128,0.4); } 50% { box-shadow: 0 0 0 14px rgba(224,87,128,0); } } @keyframes pulse-record { 0%, 100% { box-shadow: 0 0 0 0 rgba(255,59,59,0.5); } 50% { box-shadow: 0 0 0 20px rgba(255,59,59,0); } } @keyframes waveBar { 0%, 100% { transform: scaleY(0.3); } 50% { transform: scaleY(1); } } @keyframes slideUp { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } } /* ─── PAGE TRANSITION ─── */ .page-enter-active { animation: fadeUp 0.3s ease both; } .page-leave-active { animation: fadeIn 0.15s ease reverse both; } /* ─── FLASHCARD ─── */ .flashcard-container { perspective: 1200px; } .flashcard-inner { position: relative; width: 100%; height: 100%; transform-style: preserve-3d; transition: transform 0.6s cubic-bezier(0.4, 0, 0.2, 1); } .flashcard-inner.flipped { transform: rotateY(180deg); } .card-face { position: absolute; inset: 0; backface-visibility: hidden; -webkit-backface-visibility: hidden; border-radius: var(--r); overflow: hidden; } .card-back-face { transform: rotateY(180deg); } /* ─── WAVEFORM ─── */ .waveform-bar { flex: 1; border-radius: 2px; background: rgba(255,255,255,0.2); transition: background 0.15s; min-height: 4px; transform-origin: bottom; } .waveform-bar.played { background: var(--green-l); } .waveform-bar.current { background: white; } .waveform-bar.playing { animation: waveBar 0.6s ease-in-out infinite; } /* ─── RECORD BUTTON ─── */ .record-btn-idle { animation: pulse-idle 2.5s infinite; } .record-btn-active { background: #ff3b3b !important; animation: pulse-record 1s infinite; } /* ─── HEATMAP ─── */ .heatmap-day { aspect-ratio: 1; border-radius: 5px; display: flex; align-items: center; justify-content: center; font-size: 11px; font-weight: 500; cursor: pointer; transition: transform 0.15s, box-shadow 0.15s; background: var(--bg2); color: var(--ink3); position: relative; } .heatmap-day:hover { transform: scale(1.12); z-index: 2; } .heatmap-day.empty { opacity: 0; pointer-events: none; } .heatmap-day.today { background: var(--ink); color: white; font-weight: 700; } .heatmap-day.done-1 { background: #bbf7d0; color: var(--green); } .heatmap-day.done-2 { background: var(--green-l); color: white; } .heatmap-day.done-3 { background: var(--green); color: white; } /* ─── AUDIO CONTROLS ─── */ .ctrl-btn { @apply flex h-9 w-9 shrink-0 cursor-pointer items-center justify-center rounded-full border-0 text-[15px] text-white transition-colors; background: rgba(255,255,255,0.12); } .ctrl-btn:hover { background: rgba(255,255,255,0.22); } .ctrl-btn.play { @apply h-11 w-11; background: var(--green-l); } .ctrl-btn.play:hover { background: #3da771; } .transcript-html mark { font-weight: 600; } /* ─── PROGRESS SHIMMER ─── */ .progress-fill-shimmer { @apply relative overflow-hidden; } .progress-fill-shimmer::after { content: ''; position: absolute; top: 0; left: -100%; width: 200%; height: 100%; background: linear-gradient(90deg, transparent 0%, rgba(255,255,255,0.15) 50%, transparent 100%); animation: shimmer 2s infinite; } @keyframes shimmer { to { left: 100%; } } /* ─── WORD HIGHLIGHT ─── */ .hl-yellow { background: #fef08a; border-radius: 2px; } .hl-green { background: #bbf7d0; border-radius: 2px; } .hl-rose { background: #fecdd3; border-radius: 2px; } /* ─── DISPLAY FONT ─── */ .font-display { font-family: var(--font-display); } .font-mono { font-family: var(--font-mono); } /* ─── §4 Cards ─── */ .ct-card { background: var(--bg-surface); border: 1px solid var(--border-button); border-radius: var(--radius-comfortable); box-shadow: var(--shadow-medium); transition: background var(--transition-base), box-shadow var(--transition-base), transform var(--transition-base), border-color var(--transition-base); } .ct-card:hover { background: var(--bg-interactive); box-shadow: var(--shadow-heavy); transform: translateY(-2px); } /* ─── §4 Badges ─── */ .ct-badge { display: inline-flex; align-items: center; border-radius: var(--radius-full-pill); padding: 2px 10px; font-size: var(--text-badge); font-weight: 600; line-height: 1.33; text-transform: capitalize; background: rgba(30, 215, 96, 0.15); color: var(--spotify-green); } .ct-badge-black { background: var(--bg-interactive); color: var(--text-base); } .ct-badge-gray { background: var(--surface-card); color: var(--text-subdued); } /* ─── §4 Buttons ─── */ .ct-btn, .btn, .sh-btn, .sh-tab, .theme-toggle-btn, .history-filter-btn { transition: var(--transition-base); } .ct-btn { display: inline-flex; align-items: center; justify-content: center; gap: 6px; border-radius: var(--radius-full-pill); padding: 8px 16px; font-size: var(--text-button); font-weight: 700; letter-spacing: 0.14px; cursor: pointer; transition: background var(--transition-base), color var(--transition-base), border-color var(--transition-base), transform var(--transition-base); border: 1px solid transparent; background: var(--bg-interactive); color: var(--text-subdued); } .ct-btn:hover { background: var(--surface-card); color: var(--text-base); } .ct-btn-primary { background: var(--spotify-green); color: #000000; border-color: transparent; text-transform: uppercase; letter-spacing: var(--tracking-button); } .ct-btn-primary:hover { background: var(--spotify-green-dark); color: #000000; transform: scale(1.02); } .ct-btn-outline { background: transparent; color: var(--text-base); border: 1px solid var(--border-outlined); } .ct-btn-outline:hover { background: var(--bg-interactive); border-color: var(--text-base); } /* ─── §4 Inputs ─── */ .ct-input { border: none; border-radius: var(--radius-pill); padding: 12px 20px; font-size: var(--text-button); outline: none; font-family: var(--font-body); background: var(--bg-interactive); color: var(--text-base); box-shadow: var(--shadow-inset-border); transition: box-shadow var(--transition-base), outline var(--transition-base); } .ct-input:focus { outline: 1px solid var(--text-base); box-shadow: var(--shadow-inset-border); } .ct-input::placeholder { color: var(--text-subdued); } /* ─── SELECT (SaveWordDialog) ─── */ .ct-select { width: 100%; cursor: pointer; appearance: none; border: none; border-radius: var(--radius-pill); background: var(--bg-interactive) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23b3b3b3' stroke-width='2'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E") no-repeat right 16px center; padding: 12px 40px 12px 16px; font-size: var(--text-button); font-family: inherit; font-weight: 500; color: var(--text-base); outline: none; box-shadow: var(--shadow-inset-border); transition: box-shadow var(--transition-base), outline var(--transition-base); } .ct-select:focus { outline: 1px solid var(--text-base); } .ct-select:disabled { cursor: not-allowed; opacity: 0.55; } /* ─── LEGACY COMPAT: .card, .btn ─── */ .card { background: var(--bg-surface); border: none; border-radius: var(--radius-comfortable); box-shadow: var(--shadow-medium); transition: background var(--transition-base), box-shadow var(--transition-base), transform var(--transition-base); } .card:hover { background: var(--bg-interactive); box-shadow: var(--shadow-heavy); } .btn { display: inline-flex; align-items: center; justify-content: center; gap: 6px; border-radius: var(--radius-full-pill); padding: 8px 16px; font-size: var(--text-button); font-weight: 700; cursor: pointer; border: 1px solid transparent; transition: background var(--transition-base), color var(--transition-base), border-color var(--transition-base), transform var(--transition-base); background: var(--bg-interactive); color: var(--text-subdued); } .btn-primary { background: var(--spotify-green); color: #000000; text-transform: uppercase; letter-spacing: var(--tracking-button); } .btn-primary:hover { background: var(--spotify-green-dark); transform: scale(1.02); } .btn-secondary { background: transparent; color: var(--text-base); border: 1px solid var(--border-outlined); } .btn-secondary:hover { background: var(--bg-interactive); } .btn-danger { background: transparent; color: var(--text-negative); border: 1px solid var(--text-negative); } .btn-danger:hover { background: var(--rose-bg); } .btn-sm { padding: 5px 12px; font-size: var(--text-small); } .btn-lg { padding: 12px 32px; font-size: var(--text-body); } /* ─── PAGE WRAPPER ─── */ .page-wrapper { padding: 24px; } @media (min-width: 640px) { .page-wrapper { padding: 32px; } } @media (min-width: 1024px) { .page-wrapper { padding: 40px; } } .container { width: 100%; max-width: var(--container-max); margin-left: auto; margin-right: auto; padding-left: 24px; padding-right: 24px; } /* Layout shell (DESIGN.md §5) */ .app-container { width: 100%; max-width: var(--container-max); margin-left: auto; margin-right: auto; padding-left: 24px; padding-right: 24px; } .app-navbar { height: var(--navbar-height); background: var(--bg-surface); border-bottom: 1px solid var(--border-button); } /* Page sections — alternating surfaces (white → cream → sky in light) */ .section-base { padding-top: var(--section-padding-y); padding-bottom: var(--section-padding-y); background: var(--bg-base); } .section-surface { padding-top: var(--section-padding-y); padding-bottom: var(--section-padding-y); background: var(--bg-surface); } .section-elevated { padding-top: var(--section-padding-y); padding-bottom: var(--section-padding-y); background: var(--bg-interactive); } .section-white { padding-top: var(--section-padding-y); padding-bottom: var(--section-padding-y); background: var(--section-white); } .section-cream { padding-top: var(--section-padding-y); padding-bottom: var(--section-padding-y); background: var(--section-cream); } .section-sky { padding-top: var(--section-padding-y); padding-bottom: var(--section-padding-y); background: var(--section-sky); } .section-hero { padding-top: var(--section-padding-y); padding-bottom: var(--section-padding-y); background: var(--hero-bg); color: var(--text-base); } .section-hero h1, .section-hero h2 { color: var(--text-base); font-size: var(--text-section-title); font-weight: 700; line-height: normal; } .section-hero .hero-subtitle { font-size: var(--text-caption); color: var(--text-subdued); margin-top: 4px; } .section-hero .btn-primary, .section-hero .ct-btn-primary, .section-hero .btn-hero-cta { background: var(--cta-accent); color: var(--cta-accent-text); font-size: var(--text-button); font-weight: 700; letter-spacing: var(--tracking-button); transition: var(--transition-base); } .section-hero .btn-primary:hover, .section-hero .ct-btn-primary:hover, .section-hero .btn-hero-cta:hover { filter: brightness(1.06); } /* App shells — tighter rhythm than marketing pages */ .section-compact { padding-top: 48px; padding-bottom: 48px; } .section-hero.section-compact h1 { font-size: var(--text-section-title); } /* Wave divider between sections */ .wave-divider { display: block; width: 100%; height: 48px; line-height: 0; overflow: hidden; } .wave-divider svg { display: block; width: 100%; height: 48px; } /* Quiz / practice exam shell — header + body share same horizontal rhythm */ .exam-container { width: 100%; max-width: 1400px; margin-left: auto; margin-right: auto; padding-left: 1.25rem; padding-right: 1.25rem; } @media (min-width: 640px) { .exam-container { padding-left: 1.5rem; padding-right: 1.5rem; } } @media (min-width: 1024px) { .exam-container { padding-left: 2rem; padding-right: 2rem; } } /* ─── SLIDE TRANSITION (Quiz / WritingEditor) ─── */ .slide-enter-active, .slide-leave-active { transition: all 0.2s ease; } .slide-enter-from, .slide-leave-to { opacity: 0; transform: translateX(20px); } /* ─── WRITING PROMPT HTML ─── */ .writing-prompt-html p { margin-bottom: 0.75rem; font-size: 13px; line-height: 1.65; } .writing-prompt-html em { font-style: italic; } .writing-prompt-html strong { font-weight: 600; } /* ─── READING PASSAGE (vocab / review) ─── */ .vocab-mode .vocab-word { cursor: pointer; } .vocab-mode .vocab-underline { text-decoration: underline; text-underline-offset: 3px; text-decoration-color: var(--spotify-green); color: var(--spotify-green); } .answer-mark { border-radius: 3px; background: #fef08a; padding: 1px 2px; font-weight: 600; } /* ─── SKILL SEARCH (Speaking / Reading list) ─── */ .skill-search-wrap { position: relative; align-self: flex-start; width: 100%; max-width: 100%; min-width: 0; } @media (min-width: 640px) { .skill-search-wrap { min-width: 240px; width: auto; } } .skill-search-icon { position: absolute; top: 50%; left: 0.75rem; transform: translateY(-50%); color: var(--ink3); pointer-events: none; } .skill-search-input { width: 100%; border: none; border-radius: var(--radius-pill); background: var(--bg-interactive); padding: 0.5rem 0.75rem 0.5rem 2.1rem; font-size: var(--text-button); color: var(--text-base); outline: none; box-shadow: var(--shadow-inset-border); transition: box-shadow var(--transition-base), outline var(--transition-base); } .skill-search-input:focus { outline: 1px solid var(--text-base); } .page-wrapper--constrained { max-width: 1280px; margin-left: auto; margin-right: auto; } /* ─── AUTH (theme-aware, Spotify tokens) ─── */ .auth-page { min-height: 100vh; display: grid; grid-template-columns: 1fr 1fr; background: var(--bg-base); color: var(--text-base); } .auth-page--centered { grid-template-columns: 1fr; place-items: center; padding: 24px; } .auth-page--centered .auth-card { max-width: 480px; width: 100%; border-right: none; border: 1px solid var(--border-button); border-radius: var(--radius-panel); box-shadow: var(--shadow-medium); } .auth-card { display: flex; flex-direction: column; justify-content: center; align-items: center; padding: 48px clamp(24px, 5vw, 64px); background: var(--bg-surface); border-right: 1px solid var(--border-button); } .auth-card > * { width: 100%; max-width: 420px; } .auth-logo { margin-bottom: 32px; } .logo-mark { font-size: 24px; font-weight: 700; color: var(--text-base); letter-spacing: -0.02em; } .logo-mark span { color: var(--spotify-green); } .logo-sub { font-size: 11px; color: var(--text-subdued); letter-spacing: 0.1em; text-transform: uppercase; margin-top: 4px; } .auth-title { font-size: 28px; font-weight: 700; color: var(--text-base); margin-bottom: 6px; } .auth-sub { font-size: 14px; color: var(--text-subdued); margin-bottom: 28px; line-height: 1.5; } .auth-page .form-group { margin-bottom: 16px; } .auth-page .form-label { display: block; font-size: 12px; font-weight: 600; color: var(--text-subdued); margin-bottom: 6px; } .auth-page .form-input, .auth-page select.form-input { width: 100%; padding: 12px 18px; border: none; border-radius: var(--radius-comfortable); font-size: 14px; font-family: inherit; color: var(--text-base); background: var(--bg-interactive); box-shadow: var(--shadow-inset-border); outline: none; transition: box-shadow var(--transition-base), outline var(--transition-base); } .auth-page .form-input::placeholder { color: var(--text-subdued); } .auth-page .form-input:focus, .auth-page select.form-input:focus { outline: 1px solid var(--spotify-green); box-shadow: var(--shadow-inset-border); } .auth-page .error-msg { font-size: 13px; color: var(--text-negative); background: var(--rose-bg); padding: 10px 14px; border-radius: var(--radius-comfortable); border: 1px solid color-mix(in srgb, var(--text-negative) 25%, transparent); margin-bottom: 12px; } .auth-success-msg, .auth-page .success-msg { margin-bottom: 12px; padding: 10px 14px; border-radius: var(--radius-comfortable); border: 1px solid color-mix(in srgb, var(--spotify-green) 35%, transparent); background: var(--green-bg); text-align: center; font-size: 13px; color: var(--spotify-green-dark); } [data-theme="dark"] .auth-success-msg, [data-theme="dark"] .auth-page .success-msg { color: var(--spotify-green); } .auth-page .btn-primary { width: 100%; padding: 12px 24px; border-radius: var(--radius-full-pill); background: var(--spotify-green); color: #000000; font-size: var(--text-button); font-weight: 700; text-transform: uppercase; letter-spacing: var(--tracking-button); border: none; cursor: pointer; font-family: inherit; transition: background var(--transition-base), transform var(--transition-base); margin-top: 4px; } .auth-page .btn-primary:hover:not(:disabled) { background: var(--spotify-green-dark); transform: scale(1.02); } .auth-page .btn-primary:disabled { opacity: 0.6; cursor: not-allowed; transform: none; } .auth-google-btn { display: flex; align-items: center; justify-content: center; gap: 10px; width: 100%; padding: 11px 18px; border: none; border-radius: var(--radius-full-pill); background: var(--bg-interactive); color: var(--text-base); font-size: 14px; font-weight: 600; cursor: pointer; box-shadow: var(--shadow-inset-border); transition: box-shadow var(--transition-base), outline var(--transition-base); margin-bottom: 4px; } .auth-google-btn:hover:not(:disabled) { outline: 1px solid var(--border-outlined); } .auth-google-btn:disabled { opacity: 0.6; cursor: not-allowed; } .auth-divider { display: flex; align-items: center; gap: 12px; margin: 16px 0 8px; color: var(--text-subdued); font-size: 12px; } .auth-divider::before, .auth-divider::after { content: ''; flex: 1; height: 1px; background: var(--border-button); } .auth-footer { margin-top: 24px; font-size: 13px; color: var(--text-subdued); text-align: center; } .auth-footer--stack { display: flex; flex-direction: column; align-items: center; gap: 8px; } .auth-link { color: var(--spotify-green); font-weight: 600; text-decoration: none; margin-left: 4px; background: none; border: none; cursor: pointer; font-family: inherit; font-size: inherit; padding: 0; } .auth-link:hover:not(:disabled) { text-decoration: underline; } .auth-link:disabled { opacity: 0.5; cursor: not-allowed; } .auth-deco { display: flex; align-items: center; justify-content: center; padding: 48px clamp(24px, 5vw, 60px); position: relative; overflow: hidden; background: linear-gradient( 155deg, color-mix(in srgb, var(--spotify-green) 14%, var(--bg-interactive)) 0%, var(--bg-base) 55%, var(--bg-surface) 100% ); } [data-theme="light"] .auth-deco { background: linear-gradient( 155deg, color-mix(in srgb, var(--spotify-green) 18%, var(--bg-interactive)) 0%, var(--bg-base) 50%, color-mix(in srgb, var(--spotify-green) 6%, var(--bg-surface)) 100% ); } .auth-deco::before { content: ''; position: absolute; bottom: -80px; right: -60px; width: 400px; height: 400px; background: radial-gradient(circle, color-mix(in srgb, var(--spotify-green) 22%, transparent) 0%, transparent 70%); pointer-events: none; } .auth-deco::after { content: ''; position: absolute; top: -80px; left: -60px; width: 300px; height: 300px; background: radial-gradient(circle, color-mix(in srgb, var(--text-announcement) 14%, transparent) 0%, transparent 70%); pointer-events: none; } .deco-content { position: relative; z-index: 1; max-width: 400px; } .deco-badge { display: inline-flex; align-items: center; gap: 6px; padding: 6px 14px; border-radius: var(--radius-full-pill); background: var(--green-bg); color: var(--spotify-green); font-size: 12px; font-weight: 600; margin-bottom: 20px; border: 1px solid color-mix(in srgb, var(--spotify-green) 30%, transparent); } .deco-title { font-size: clamp(28px, 4vw, 36px); font-weight: 700; color: var(--text-base); line-height: 1.2; margin-bottom: 28px; } .deco-features { display: flex; flex-direction: column; gap: 12px; } .deco-feature { display: flex; align-items: center; gap: 10px; font-size: 14px; color: var(--text-subdued); } .feature-check { width: 20px; height: 20px; border-radius: 50%; background: var(--spotify-green); color: #000000; display: flex; align-items: center; justify-content: center; flex-shrink: 0; } .auth-register .auth-card { padding: 40px clamp(24px, 5vw, 56px); } .auth-register .auth-logo { margin-bottom: 24px; } .auth-register .auth-title { font-size: 26px; } .auth-register .auth-sub { font-size: 13px; margin-bottom: 24px; } .auth-register .form-group { margin-bottom: 14px; } .auth-register .form-label { margin-bottom: 5px; } .auth-register .form-input { padding: 11px 16px; font-size: 13px; } .auth-register .btn-primary { font-size: 14px; } .auth-register .auth-footer { margin-top: 20px; } .target-row { display: flex; gap: 12px; } .milestone-list { display: flex; flex-direction: column; gap: 14px; } .milestone { display: flex; align-items: center; gap: 12px; } .milestone-band { font-size: 16px; font-weight: 700; color: var(--spotify-green); width: 36px; flex-shrink: 0; } .milestone-bar { flex: 1; height: 6px; background: color-mix(in srgb, var(--text-base) 12%, transparent); border-radius: 99px; overflow: hidden; } .milestone-fill { height: 100%; background: linear-gradient(to right, var(--spotify-green), var(--text-announcement)); border-radius: 99px; } .milestone-label { font-size: 12px; color: var(--text-subdued); width: 80px; } .auth-verify-icon { display: flex; height: 64px; width: 64px; align-items: center; justify-content: center; border-radius: 50%; background: var(--green-bg); border: 1px solid color-mix(in srgb, var(--spotify-green) 40%, transparent); margin: 0 auto 20px; } @media (max-width: 768px) { .auth-page { grid-template-columns: 1fr; } .auth-deco { display: none; } .auth-card { padding: 40px 24px; border-right: none; min-height: 100vh; } .target-row { flex-direction: column; gap: 0; } } /* ─── HISTORY ─── */ .history-filter-btn { display: inline-flex; align-items: center; gap: 5px; padding: 5px 12px; border-radius: 20px; border: 1.5px solid var(--border2); background: var(--surface); color: var(--ink2); font-size: 12px; font-weight: 500; cursor: pointer; transition: all .15s; } .history-filter-btn:hover { border-color: var(--spotify-green); color: var(--spotify-green); } .history-filter-btn.active { border-color: var(--spotify-green); background: var(--green-bg); color: var(--spotify-green); font-weight: 700; } .filter-icon { display: flex; align-items: center; } .history-action-btn { display: inline-flex; align-items: center; gap: 5px; margin-left: 0; white-space: nowrap; border-radius: var(--r-sm); border: 1px solid var(--border2); background: transparent; padding: 6px 12px; font-size: 12px; font-weight: 600; color: var(--ink2); cursor: pointer; transition: all .15s; text-decoration: none; } .history-action-btn:hover { background: var(--bg2); } .history-action-btn--primary { border-color: var(--spotify-green); background: var(--bg-surface); color: var(--spotify-green); } .history-action-btn--primary:hover { background: var(--bg-interactive); } [data-theme="dark"] .history-action-btn--primary { border-color: var(--border2); background: var(--bg); color: var(--spotify-green); } @media (min-width: 640px) { .history-action-btn { margin-left: 8px; } } .lb-page { max-width: 700px; margin-left: auto; margin-right: auto; width: 100%; } .podium { display: flex; align-items: flex-end; justify-content: center; gap: 12px; padding: 0 16px; } .podium-item { display: flex; flex-direction: column; align-items: center; gap: 6px; flex: 1; max-width: 160px; } .podium-crown { margin-bottom: -4px; } .podium-avatar-wrap { position: relative; } .podium-avatar { width: 56px; height: 56px; border-radius: 50%; object-fit: cover; border: 2px solid var(--border); } .podium-avatar--large { width: 68px; height: 68px; } .podium-rank { position: absolute; bottom: -4px; right: -4px; width: 20px; height: 20px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 10px; font-weight: 700; color: white; border: 1.5px solid white; } .rank-1 { background: #f59e0b; } .rank-2 { background: #9ca3af; } .rank-3 { background: #b45309; } .podium-name { font-size: 12px; font-weight: 500; color: var(--ink); text-align: center; max-width: 120px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .podium-xp { font-size: 11px; font-weight: 600; color: var(--ink3); } .xp-gold { color: #d97706; } .podium-bar { width: 100%; border-radius: 8px 8px 0 0; } .bar-1 { height: 64px; background: linear-gradient(180deg, #fde68a, #f59e0b); } .bar-2 { height: 48px; background: linear-gradient(180deg, #e5e7eb, #9ca3af); } .bar-3 { height: 36px; background: linear-gradient(180deg, #fde8c8, #b45309); } .lb-row { display: flex; align-items: center; gap: 12px; border-bottom: 1px solid var(--border); padding: 12px 20px; transition: background 0.15s; } .lb-row:last-child { border-bottom: none; } .lb-row:hover { background: var(--bg); } .lb-row--me { background: var(--green-bg); } .lb-rank { width: 32px; text-align: right; } .lb-rank-num { font-size: 14px; font-weight: 700; color: var(--ink3); } .lb-avatar { width: 36px; height: 36px; border-radius: 50%; object-fit: cover; flex-shrink: 0; } .lb-info { flex: 1; min-width: 0; } .lb-name { font-size: 13px; font-weight: 600; color: var(--ink); display: flex; align-items: center; gap: 6px; } .lb-streak { font-size: 11px; color: var(--ink3); display: flex; align-items: center; gap: 3px; margin-top: 2px; } .lb-you-badge { font-size: 10px; font-weight: 700; background: #d1fae5; color: #065f46; padding: 1px 6px; border-radius: 20px; } .lb-xp-col { display: flex; flex-direction: column; align-items: flex-end; gap: 4px; min-width: 100px; } .lb-xp-bar-wrap { width: 80px; height: 4px; background: var(--bg2); border-radius: 2px; overflow: hidden; } .lb-xp-bar { height: 100%; background: #34d399; border-radius: 2px; transition: width 0.8s ease; } .lb-xp-num { font-size: 12px; font-weight: 700; color: var(--ink2); } /* ─── PROFILE ─── */ .profile-page { max-width: 900px; margin-left: auto; margin-right: auto; width: 100%; } .profile-stack { display: flex; flex-direction: column; gap: 14px; } .profile-grid { display: grid; grid-template-columns: 1fr 1.4fr; gap: 20px; } @media (max-width: 767px) { .profile-grid { grid-template-columns: 1fr; } .profile-page .form-row { grid-template-columns: 1fr; } .stats-row { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; } .profile-card { padding: 20px; } } .profile-page .card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--r); box-shadow: var(--shadow-sm); } .profile-card { padding: 28px; } .avatar-section { display: flex; align-items: center; gap: 16px; margin-bottom: 16px; } .avatar-wrapper { position: relative; width: 72px; height: 72px; border-radius: 50%; flex-shrink: 0; } .avatar-img { width: 72px; height: 72px; border-radius: 50%; object-fit: cover; display: block; } .avatar-upload-overlay { position: absolute; inset: 0; border-radius: 50%; background: rgba(0, 0, 0, 0.45); display: flex; align-items: center; justify-content: center; color: white; opacity: 0; cursor: pointer; transition: opacity 0.18s; } .avatar-wrapper:hover .avatar-upload-overlay { opacity: 1; } .upload-status { display: flex; align-items: center; gap: 6px; font-size: 12px; color: var(--ink3); margin-bottom: 8px; } .user-name { font-size: 18px; font-weight: 600; color: var(--ink); } .user-email { font-size: 13px; color: var(--ink3); margin-top: 2px; } .user-level-badge { margin-top: 6px; font-size: 11px; font-weight: 600; color: var(--green); display: flex; align-items: center; gap: 4px; } .stats-row { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; padding-top: 20px; border-top: 1px solid var(--border); margin-top: 16px; } .stat-box { text-align: center; } .stat-val { font-size: 24px; font-weight: 700; color: var(--ink); } .stat-label { font-size: 11px; color: var(--ink3); margin-top: 2px; } .profile-page .section-title { font-size: 16px; font-weight: 600; color: var(--ink); } .profile-page .form-group { display: flex; flex-direction: column; gap: 6px; margin-bottom: 16px; } .profile-page .form-label { font-size: 12px; font-weight: 600; color: var(--ink2); } .profile-page .form-row { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; } .profile-page .form-input { padding: 9px 12px; border: 1.5px solid var(--border2); border-radius: var(--r-sm); font-size: 13px; font-family: inherit; color: var(--ink); background: var(--bg); outline: none; transition: border-color 0.18s; } .profile-page .form-input:focus { border-color: var(--green-l); } .profile-page .form-input:disabled { opacity: 0.5; cursor: not-allowed; } .profile-page .form-actions { display: flex; justify-content: space-between; margin-top: 20px; } .profile-page .btn-primary { padding: 9px 20px; border-radius: var(--r-sm); background: var(--green); color: white; font-size: 13px; font-weight: 600; border: none; cursor: pointer; font-family: inherit; transition: all 0.18s; } .profile-page .btn-primary:hover { background: var(--spotify-green-dark); } .profile-page .btn-primary:disabled { opacity: 0.6; cursor: not-allowed; } .profile-page .btn-danger { padding: 9px 20px; border-radius: var(--r-sm); background: transparent; color: var(--rose); font-size: 13px; font-weight: 600; border: 1px solid var(--rose-l); cursor: pointer; font-family: inherit; transition: all 0.18s; } .profile-page .btn-danger:hover { background: var(--rose-bg); } .profile-page .error-msg { margin-top: 10px; font-size: 13px; color: var(--rose); } .profile-page .success-msg { margin-top: 10px; font-size: 13px; color: var(--green); } .avatar-info { flex: 1; min-width: 0; } .profile-page .badges-section { padding: 24px; } .profile-password-card { padding: 24px; } .profile-ai-hint { margin: 0 0 16px; font-size: 12px; line-height: 1.55; color: var(--ink3); } .profile-ai-note { margin: -8px 0 12px; font-size: 11px; color: var(--ink3); } .profile-page .badges-header { display: flex; flex-wrap: wrap; align-items: flex-start; justify-content: space-between; gap: 16px; margin-bottom: 16px; } .profile-page .badges-subtitle { margin: 4px 0 0; font-size: 12px; color: var(--ink3); max-width: 420px; } .profile-page .badges-progress-wrap { min-width: 160px; flex: 0 0 auto; } .profile-page .badges-progress-label { display: flex; justify-content: space-between; gap: 8px; font-size: 12px; font-weight: 600; margin-bottom: 6px; } .profile-page .badges-progress-bar { height: 8px; border-radius: 999px; background: var(--border); overflow: hidden; } .profile-page .badges-progress-fill { height: 100%; border-radius: inherit; background: linear-gradient(90deg, var(--spotify-green), var(--spotify-green-dark)); transition: width 0.4s ease; } .profile-page .badges-filters { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 16px; } .profile-page .badges-filter-btn { padding: 6px 12px; border-radius: 999px; border: 1px solid var(--border); background: var(--bg-surface); font-size: 12px; font-weight: 600; color: var(--ink2); cursor: pointer; font-family: inherit; transition: var(--transition-base); } .profile-page .badges-filter-btn:hover { border-color: var(--spotify-green); color: var(--ink); } .profile-page .badges-filter-btn.active { background: var(--green-bg); border-color: var(--spotify-green); color: var(--spotify-green); } .profile-page .badges-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 12px; } .profile-page .badge-card { display: flex; align-items: flex-start; gap: 12px; padding: 14px; border-radius: 14px; border: 1px solid var(--border); background: var(--bg-surface); position: relative; transition: transform var(--transition-base), box-shadow var(--transition-base); cursor: pointer; font-family: inherit; text-align: left; width: 100%; } .badge-hint-overlay { position: fixed; inset: 0; z-index: 9000; display: flex; align-items: center; justify-content: center; padding: 20px; background: rgba(15, 23, 42, 0.45); } .badge-hint-popover { width: min(100%, 380px); padding: 24px; background: #fff; border-radius: 16px; box-shadow: 0 20px 50px rgba(15, 23, 42, 0.18); text-align: center; } .badge-hint-icon { margin-bottom: 12px; display: flex; justify-content: center; } .badge-hint-title { margin: 0 0 6px; font-size: 18px; color: var(--ink); } .badge-hint-desc { margin: 0 0 14px; font-size: 13px; color: var(--ink3); } .badge-hint-box { text-align: left; padding: 12px 14px; border-radius: 10px; background: var(--bg); border: 1px solid var(--border); font-size: 12px; line-height: 1.5; color: var(--ink2); } .badge-hint-label { display: block; font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.08em; color: var(--ink3); margin-bottom: 6px; } .badge-hint-status { margin: 12px 0 0; font-size: 12px; font-weight: 600; color: var(--ink3); } .badge-hint-status--done { color: #059669; } .profile-page .badge-card--unlocked { border-color: var(--spotify-green); background: linear-gradient(145deg, var(--green-bg) 0%, var(--bg-surface) 55%); box-shadow: var(--shadow-sm); } .profile-page .badge-card--unlocked:hover { transform: translateY(-2px); } .profile-page .badge-card--locked { opacity: 0.72; filter: grayscale(0.35); } .profile-page .badge-card-icon { font-size: 28px; line-height: 1; flex-shrink: 0; } .profile-page .badge-card-body { flex: 1; min-width: 0; } .profile-page .badge-card-title { font-size: 13px; font-weight: 700; color: var(--ink); margin-bottom: 4px; } .profile-page .badge-card-desc { font-size: 11px; line-height: 1.45; color: var(--ink3); } .profile-page .badge-card-check { position: absolute; top: 10px; right: 10px; width: 20px; height: 20px; border-radius: 50%; background: var(--spotify-green); color: #000; font-size: 11px; font-weight: 700; display: flex; align-items: center; justify-content: center; } .profile-page .badge-card-lock { position: absolute; top: 10px; right: 10px; font-size: 12px; opacity: 0.5; } /* ─── QUIZ (legacy Quiz.vue) ─── */ .quiz-header { margin-bottom: 1.5rem; } .quiz-back-link { font-size: 0.9rem; color: var(--color-text-muted); text-decoration: none; display: inline-block; margin-bottom: 1rem; } .quiz-back-link:hover { color: var(--color-primary); } .quiz-subject { display: flex; align-items: center; gap: 0.75rem; margin-bottom: 0.5rem; } .quiz-subject h1 { margin: 0; } .quiz-progress-top { margin-bottom: 1.5rem; } .quiz-progress-text { font-size: 0.82rem; display: block; margin-top: 6px; text-align: right; } .quiz-question-card { padding: 2rem; } .quiz-question-num { font-size: 0.8rem; font-weight: 600; color: var(--color-primary); text-transform: uppercase; letter-spacing: 0.05em; margin-bottom: 1rem; } .quiz-question-text { font-size: 1.2rem; font-weight: 700; line-height: 1.5; margin-bottom: 1.75rem; } .quiz-options-list { display: flex; flex-direction: column; gap: 0.75rem; } .quiz-option-btn { display: flex; align-items: center; gap: 1rem; padding: 1rem 1.25rem; width: 100%; background: var(--color-surface-2); border: 2px solid var(--color-border); border-radius: var(--radius-md); cursor: pointer; text-align: left; color: var(--color-text); font-family: inherit; font-size: 0.95rem; transition: all var(--transition-fast); } .quiz-option-btn:hover { border-color: var(--color-primary); background: rgba(124,106,247,0.08); } .quiz-option-btn.selected { border-color: var(--color-primary); background: rgba(124,106,247,0.15); } .quiz-option-letter { width: 32px; height: 32px; border-radius: 50%; background: var(--color-surface); border: 2px solid var(--color-border); display: flex; align-items: center; justify-content: center; font-weight: 700; font-size: 0.85rem; flex-shrink: 0; transition: all var(--transition-fast); } .quiz-option-btn.selected .quiz-option-letter { background: var(--color-primary); border-color: var(--color-primary); color: #fff; } .quiz-nav { display: flex; align-items: center; justify-content: space-between; gap: 1rem; margin-top: 1.5rem; } .quiz-dot-indicators { display: flex; gap: 6px; } .quiz-dot { width: 10px; height: 10px; border-radius: 50%; background: var(--color-surface-2); border: 2px solid var(--color-border); cursor: pointer; transition: all 0.2s; padding: 0; } .quiz-dot.answered { background: rgba(124,106,247,0.4); border-color: var(--color-primary); } .quiz-dot.active { background: var(--color-primary); border-color: var(--color-primary); transform: scale(1.3); } /* ─── QUIZ RUNNER reading panel ─── */ .quiz-runner .reading-passage { max-height: 420px; overflow: auto; padding-right: 8px; } .quiz-runner .reading-paragraph { display: flex; gap: 10px; padding: 10px 12px; border-radius: 12px; border: 1px solid transparent; margin-bottom: 10px; background: var(--surface); } .quiz-runner .reading-paragraph.is-highlight { border-color: rgba(124, 106, 247, 0.35); background: rgba(124, 106, 247, 0.08); } .quiz-runner .para-tag { min-width: 28px; height: 22px; border-radius: 8px; display: inline-flex; align-items: center; justify-content: center; font-size: 11px; font-weight: 700; color: var(--ink2); border: 1px solid var(--border2); background: var(--bg); } /* Passage title (parts[].content) — h2/h3 heading above the reading text */ .passage-title { margin-bottom: 12px; } .passage-title h1, .passage-title h2, .passage-title h3, .passage-title h4, .passage-title h5, .passage-title h6 { font-weight: 700; line-height: 1.4; color: var(--ink); } /* GAP_FILLING table styling for quiz content (border from JSON data) */ .gap-html table, .prose table { width: 100%; border-collapse: collapse; margin-bottom: 8px; } .gap-html td, .gap-html th, .prose td, .prose th { padding: 6px 10px; border: 1px solid var(--border2); vertical-align: top; font-size: 13px; } .gap-html h4, .prose h4 { text-align: center; font-weight: 700; margin: 4px 0; } /* --- VOCAB PAGE (Vocabulary.vue) --- */ /* ── Layout ────────────────────────────────────────────────────────────── */ .vocab-page { min-height: 0; background: transparent; padding: 0; } .vocab-page--sections .vocab-header { display: none; } /* ── Header ──────────────────────────────────────────────────────────── */ .vocab-header { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; margin-bottom: 24px; padding: 20px 24px; background: #fff; border-radius: 16px; border: 1px solid #e2e8f0; box-shadow: 0 2px 8px rgba(0,0,0,.04); } .vocab-header__title { font-size: 20px; font-weight: 800; color: #0f172a; } .vocab-header__sub { font-size: 13px; color: #64748b; margin-top: 2px; } .vocab-header__stats { display: flex; gap: 10px; flex-wrap: wrap; } .stat-pill { display: flex; flex-direction: column; align-items: center; padding: 8px 16px; border-radius: 10px; border: 1.5px solid #e2e8f0; background: #f8fafc; min-width: 64px; } .stat-pill--green { border-color: #15803d; background: #f0fdf4; } .stat-pill--amber { border-color: #d97706; background: #fffbeb; } .stat-num { font-size: 18px; font-weight: 800; color: #0f172a; } .stat-lbl { font-size: 10px; color: #64748b; text-transform: uppercase; letter-spacing: .06em; margin-top: 1px; } .stat-pill--green .stat-num { color: #15803d; } .stat-pill--amber .stat-num { color: #d97706; } /* ── Main layout ──────────────────────────────────────────────────────── */ .vocab-layout { display: flex; gap: 20px; align-items: flex-start; } @media (max-width: 767px) { .vocab-layout { flex-direction: column; gap: 16px; } .vocab-sidebar { width: 100% !important; flex: none !important; } .vocab-main { width: 100%; min-width: 0; } .field-grid { grid-template-columns: 1fr !important; } } .vocab-layout--study { flex-direction: row; align-items: stretch; gap: 0; } .vocab-layout--study .vocab-sidebar { min-width: 180px; max-width: 50%; } .vocab-layout--study .vocab-main { min-width: 260px; } .vocab-layout--resizing { cursor: col-resize; user-select: none; } .split-handle { flex-shrink: 0; width: 10px; margin: 0 4px; cursor: col-resize; border-radius: 6px; background: transparent; transition: background 0.15s; position: relative; } .split-handle::after { content: ''; position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); width: 3px; height: 48px; border-radius: 3px; background: #e2e8f0; transition: background 0.15s, height 0.15s; } .split-handle:hover::after, .vocab-layout--resizing .split-handle::after { background: #15803d; height: 64px; } .vocab-layout--study .topic-list { max-height: min(520px, calc(100vh - 300px)); overflow-y: auto; } @media (max-width: 768px) { .vocab-layout--study { flex-direction: column; gap: 16px; } .vocab-layout--study .split-handle { display: none; } .vocab-layout--study .vocab-sidebar, .vocab-layout--study .vocab-main { flex: none !important; width: 100% !important; max-width: none !important; } } /* ── Sidebar ──────────────────────────────────────────────────────────── */ .vocab-sidebar { width: 240px; flex-shrink: 0; background: #fff; border-radius: 16px; border: 1px solid #e2e8f0; overflow: hidden; box-shadow: 0 2px 8px rgba(0,0,0,.04); } .sidebar-header { display: flex; align-items: center; justify-content: space-between; padding: 14px 16px; border-bottom: 1px solid #f1f5f9; } .sidebar-title { font-size: 12px; font-weight: 700; text-transform: uppercase; letter-spacing: .08em; color: #64748b; } .sidebar-add-btn { width: 28px; height: 28px; border-radius: 8px; border: 1.5px solid #15803d; background: #f0fdf4; color: #15803d; display: flex; align-items: center; justify-content: center; cursor: pointer; transition: all .15s; } .sidebar-add-btn:hover { background: #15803d; color: #fff; } .sidebar-loading, .sidebar-empty { padding: 16px; font-size: 13px; color: #94a3b8; text-align: center; line-height: 1.6; } .sidebar-error { color: #e11d48; display: flex; flex-direction: column; align-items: center; } .link-btn { background: none; border: none; color: #15803d; cursor: pointer; font-weight: 600; } .topic-list { padding: 8px; display: flex; flex-direction: column; gap: 2px; } .topic-item { display: flex; align-items: center; gap: 4px; padding: 10px 10px; border-radius: 10px; cursor: pointer; transition: all .15s; border: 1.5px solid transparent; } .topic-item:hover { background: #f8fafc; } .topic-item.active { background: #f0fdf4; border-color: #15803d; } .topic-item__body { flex: 1; min-width: 0; } .topic-item__name { font-size: 13px; font-weight: 600; color: #0f172a; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; display: block; } .topic-item.active .topic-item__name { color: #15803d; } .topic-item__count { font-size: 10px; color: #94a3b8; margin-top: 1px; display: block; } .topic-item__menu { flex-shrink: 0; } .menu-btn { width: 24px; height: 24px; border-radius: 6px; background: none; border: none; color: #94a3b8; cursor: pointer; display: flex; align-items: center; justify-content: center; opacity: 0; transition: opacity .15s; } .topic-item:hover .menu-btn { opacity: 1; } .menu-btn:hover { background: #f1f5f9; color: #475569; } /* ── Main panel ─────────────────────────────────────────────────────── */ .vocab-main { flex: 1; min-width: 0; background: #fff; border-radius: 16px; border: 1px solid #e2e8f0; overflow: hidden; box-shadow: 0 2px 8px rgba(0,0,0,.04); } .vocab-main--study { min-height: 420px; } .main-header { display: flex; align-items: center; justify-content: space-between; padding: 16px 20px; border-bottom: 1px solid #f1f5f9; gap: 12px; } .main-title { font-size: 15px; font-weight: 800; color: #0f172a; } .main-sub { font-size: 12px; color: #94a3b8; margin-top: 2px; } .main-header-actions { display: flex; align-items: center; gap: 12px; flex-shrink: 0; flex-wrap: wrap; } .word-search-wrap { position: relative; display: flex; align-items: center; } .word-search-icon { position: absolute; left: 8px; color: #94a3b8; pointer-events: none; } .word-search-input { padding: 7px 28px 7px 26px; border: 1.5px solid #e2e8f0; border-radius: 10px; font-size: 12px; color: #0f172a; background: #f8fafc; outline: none; width: 160px; transition: border-color .15s, width .2s; } .word-search-input:focus { border-color: #15803d; width: 200px; } .word-search-clear { position: absolute; right: 6px; background: none; border: none; cursor: pointer; color: #94a3b8; display: flex; align-items: center; padding: 2px; } .word-search-clear:hover { color: #0f172a; } .view-tabs { display: inline-flex; gap: 4px; border-radius: 10px; border: 1px solid var(--border); padding: 3px; background: var(--bg-interactive); } .view-tab { padding: 6px 14px; font-size: 12px; font-weight: 600; border: none; border-radius: 8px; background: transparent; color: var(--ink3); cursor: pointer; transition: background 0.15s, color 0.15s; } .view-tab.active { background: var(--spotify-green); color: #000; } .add-word-btn { display: flex; align-items: center; gap: 6px; padding: 8px 16px; background: #15803d; color: #fff; border: none; border-radius: 10px; font-size: 13px; font-weight: 600; cursor: pointer; transition: background .15s; } .add-word-btn:hover { background: #166534; } /* ── Word table ──────────────────────────────────────────────────────── */ .word-table { padding: 0; } .word-table-head { display: flex; gap: 0; padding: 0 20px; border-bottom: 1px solid #f1f5f9; background: #f8fafc; } .th { padding: 10px 8px; font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: .06em; color: #94a3b8; } .word-row { display: flex; align-items: center; gap: 0; padding: 0 20px; border-bottom: 1px solid #f8fafc; transition: background .1s; } .word-row:hover { background: #f8fafc; } .td { padding: 12px 8px; font-size: 13px; color: #374151; } .word-cell { display: flex; align-items: center; gap: 6px; } .word-text { font-weight: 700; color: #0f172a; } .tts-btn { padding: 3px; background: none; border: none; cursor: pointer; color: #94a3b8; border-radius: 4px; transition: all .1s; } .tts-btn:hover { color: #15803d; background: #f0fdf4; } .word-phonetic { font-size: 11px; color: #94a3b8; font-style: italic; margin-top: 1px; } .word-type-pill { display: inline-block; margin-top: 3px; padding: 1px 8px; background: #dcfce7; color: #15803d; border-radius: 6px; font-size: 10px; font-weight: 600; text-transform: uppercase; } .meaning-vi { color: #15803d; font-weight: 600; } .example-text { color: #64748b; font-size: 12px; font-style: italic; } .srs-cell { display: flex; flex-direction: column; gap: 2px; font-size: 11px; } .srs-due { color: #b45309; font-weight: 700; } .srs-ok { color: #64748b; } .srs-meta { color: #94a3b8; font-size: 10px; } .mastery-select { border: 1.5px solid #e2e8f0; border-radius: 8px; padding: 4px 8px; font-size: 11px; font-weight: 600; background: #f8fafc; cursor: pointer; outline: none; max-width: 100%; } .mastery--new { border-color: #e2e8f0; color: #94a3b8; } .mastery--learning { border-color: #fbbf24; color: #d97706; background: #fffbeb; } .mastery--mastered { border-color: #15803d; color: #15803d; background: #f0fdf4; } .row-actions { display: flex; gap: 4px; } .row-action-btn { width: 28px; height: 28px; border-radius: 6px; background: none; border: 1px solid #e2e8f0; cursor: pointer; display: flex; align-items: center; justify-content: center; color: #94a3b8; transition: all .15s; } .row-action-btn:hover { border-color: #15803d; color: #15803d; background: #f0fdf4; } .row-action-btn--del:hover { border-color: #e11d48; color: #e11d48; background: #fff1f2; } /* ── Empty state ─────────────────────────────────────────────────────── */ .empty-state { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px; padding: 60px 20px; text-align: center; } .empty-icon { color: #cbd5e1; } .empty-title { font-size: 14px; font-weight: 600; color: #94a3b8; } /* ── Modals ───────────────────────────────────────────────────────────── */ .modal-overlay { position: fixed; inset: 0; z-index: 10000; background: rgba(0,0,0,.4); display: flex; align-items: center; justify-content: center; padding: 16px; } .modal-sm { background: #fff; border-radius: 20px; width: 100%; max-width: 360px; box-shadow: 0 24px 80px rgba(0,0,0,.18); overflow: hidden; } .modal-lg { background: #fff; border-radius: 20px; width: 100%; max-width: 560px; box-shadow: 0 24px 80px rgba(0,0,0,.18); overflow: hidden; } .modal-sm-header { display: flex; align-items: center; justify-content: space-between; padding: 14px 18px; border-bottom: 1px solid #f1f5f9; font-size: 14px; font-weight: 700; color: #0f172a; } .modal-sm-header button { background: none; border: none; cursor: pointer; color: #94a3b8; padding: 4px; border-radius: 6px; } .modal-sm-header button:hover { background: #f1f5f9; } .modal-sm-body { padding: 16px 18px; } .topic-input { width: 100%; border: 1.5px solid #e2e8f0; border-radius: 10px; padding: 10px 14px; font-size: 14px; outline: none; font-family: inherit; } .topic-input:focus { border-color: #15803d; } .modal-lg-body { padding: 16px 18px; } .field-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; } .field { display: flex; flex-direction: column; gap: 4px; } .col-span-2 { grid-column: span 2; } .field label { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .05em; color: #94a3b8; } .field input, .field textarea { border: 1.5px solid #e2e8f0; border-radius: 10px; padding: 8px 12px; font-size: 13px; outline: none; font-family: inherit; resize: vertical; } .field input:focus, .field textarea:focus { border-color: #15803d; } .modal-sm-footer { display: flex; justify-content: flex-end; gap: 8px; padding: 12px 18px; border-top: 1px solid #f1f5f9; } .btn-cancel { padding: 8px 16px; border: 1px solid #e2e8f0; border-radius: 8px; background: #f8fafc; color: #475569; font-size: 13px; cursor: pointer; } .btn-green { padding: 8px 20px; background: #15803d; color: #fff; border: none; border-radius: 8px; font-size: 13px; font-weight: 700; cursor: pointer; } .btn-green:disabled { opacity: .4; cursor: not-allowed; } /* ── Topic context menu ────────────────────────────────────────────── */ .topic-ctx-menu { position: fixed; z-index: 10100; background: #fff; border: 1px solid #e2e8f0; border-radius: 10px; padding: 4px; box-shadow: 0 8px 24px rgba(0,0,0,.15); min-width: 140px; } .topic-ctx-menu button { display: flex; align-items: center; gap: 8px; width: 100%; padding: 8px 14px; text-align: left; background: none; border: none; border-radius: 6px; font-size: 13px; color: #374151; cursor: pointer; } .topic-ctx-menu button:hover { background: #f1f5f9; } .topic-ctx-menu button.danger { color: #e11d48; } .topic-ctx-menu button.danger:hover { background: #fff1f2; } /* ── Source badge (Reading / Listening provenance) ─────────────────── */ .source-badge { font-size: 9px; font-weight: 700; text-transform: uppercase; letter-spacing: .05em; padding: 2px 6px; border-radius: 4px; line-height: 1.4; } .source-badge--reading { background: #e0f2fe; color: #0369a1; } .source-badge--listening { background: #fef3c7; color: #92400e; } /* ── Transitions ────────────────────────────────────────────────────── */ .modal-fade-enter-active, .modal-fade-leave-active { transition: opacity .2s; } .modal-fade-enter-from, .modal-fade-leave-to { opacity: 0; } .popup-fade-enter-active, .popup-fade-leave-active { transition: opacity .15s, transform .15s; } .popup-fade-enter-from, .popup-fade-leave-to { opacity: 0; transform: scale(.95); } /* --- REVIEW ANSWER (ReviewAnswer.vue) --- */ /* ── Score summary ─────────────────────────────────────────────────── */ .score-summary { display: flex; align-items: center; gap: 16px; padding: 14px 18px; background: var(--bg-surface); border: 1px solid var(--border); border-radius: 14px; margin-bottom: 4px; flex-wrap: wrap; } .score-ring-wrap { position: relative; flex-shrink: 0; width: 80px; height: 80px; } .score-ring-label { position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; } .score-stats { display: flex; gap: 12px; flex-shrink: 0; } .score-stat { display: flex; flex-direction: column; align-items: center; gap: 2px; padding: 8px 14px; border: 1.5px solid var(--border); border-radius: 10px; background: var(--bg-interactive); min-width: 60px; } .score-stat--correct { border-color: var(--spotify-green-dark); background: var(--green-bg); } .score-stat--wrong { border-color: var(--rose); background: var(--rose-bg); } .score-stat svg { color: var(--ink3); } .score-stat--correct svg { color: var(--spotify-green-dark); } .score-stat--wrong svg { color: var(--rose); } .score-stat-num { font-size: 20px; font-weight: 800; color: var(--ink); } .score-stat-lbl { font-size: 10px; color: var(--ink3); text-transform: uppercase; letter-spacing: .05em; } .score-stat--correct .score-stat-num { color: var(--spotify-green-dark); } .score-stat--wrong .score-stat-num { color: var(--rose); } .part-bars { flex: 1; display: flex; flex-direction: column; gap: 8px; min-width: 160px; } .part-bar-item { display: flex; align-items: center; gap: 10px; } .part-bar-item--clickable { cursor: pointer; padding: 6px 8px; margin: -6px -8px; border-radius: 8px; transition: background 0.15s; } .part-bar-item--clickable:hover { background: var(--bg2); } .part-bar-item--active { background: var(--green-bg); outline: 1px solid var(--spotify-green); } .part-bar-item--active .part-bar-label { color: var(--spotify-green-dark); } .part-bar-label { font-size: 11px; font-weight: 600; color: var(--ink3); white-space: nowrap; min-width: 70px; } .part-bar-track { flex: 1; height: 8px; background: var(--bg-interactive); border-radius: 99px; overflow: hidden; } .part-bar-fill { height: 100%; border-radius: 99px; transition: width 1s ease; } .part-bar-pct { font-size: 11px; font-weight: 700; color: var(--ink2); min-width: 36px; text-align: right; } /* ── Header ────────────────────────────────────────────────────────── */ .review-page-header { background: color-mix(in srgb, var(--bg-surface) 92%, transparent); } .review-back-btn { display: flex; align-items: center; gap: 6px; font-size: 12px; color: var(--ink3); background: none; border: none; cursor: pointer; padding: 6px 10px; border-radius: 8px; transition: all .15s; } .review-back-btn:hover { background: var(--bg2); color: var(--ink); } .review-score-badge { display: flex; flex-direction: column; align-items: center; border: 1px solid var(--border); border-radius: 12px; padding: 6px 16px; background: var(--bg); } .review-tools-rail { position: sticky; top: 120px; align-self: flex-start; } @media (max-width: 1023px) { .review-layout { flex-direction: column !important; } .review-tools-rail { position: static; align-self: stretch; display: flex; justify-content: center; width: 100%; } .review-split-left { width: 100% !important; flex: none !important; } .review-split-divider { display: none !important; } } /* ── App shell (responsive sidebar) ─────────────────────────────── */ .app-main--with-sidebar { margin-left: 0; } @media (min-width: 1024px) { .app-main--with-sidebar.app-main--collapsed { margin-left: 64px; } .app-main--with-sidebar.app-main--expanded { margin-left: 220px; } } .app-main__content { overflow-x: hidden; } /* ── Question cards ──────────────────────────────────────────────── */ .review-question-card { border: 1.5px solid var(--border); border-radius: 12px; overflow: hidden; background: var(--bg-surface); transition: border-color .15s; } .review-question-card--correct { border-left: 4px solid var(--spotify-green); } .review-question-card--wrong { border-left: 4px solid var(--rose); } .review-q-header { display: flex; align-items: center; gap: 8px; padding: 10px 14px; border-bottom: 1px solid var(--border); } .review-q-num { font-size: 11px; font-weight: 700; text-transform: uppercase; color: var(--ink3); letter-spacing: .06em; } .review-q-badge { margin-left: auto; border-radius: 99px; padding: 2px 10px; font-size: 10px; font-weight: 700; text-transform: uppercase; } .badge-correct { background: var(--green-bg); color: var(--spotify-green-dark); } .badge-wrong { background: var(--rose-bg); color: var(--rose); } .review-explain-btn { display: flex; align-items: center; gap: 5px; padding: 4px 10px; border-radius: 8px; border: 1px solid var(--spotify-green-dark); background: var(--green-bg); color: var(--spotify-green-dark); font-size: 11px; font-weight: 600; cursor: pointer; transition: all .15s; } .review-explain-btn:hover, .review-explain-btn.active { background: var(--spotify-green); color: #000; } .review-q-text { padding: 10px 14px; font-size: 13px; color: var(--ink); line-height: 1.6; border-bottom: 1px solid var(--border); } .review-q-stem { white-space: pre-wrap; } .review-answers { padding: 10px 14px; } .review-answer-row { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 4px 0; font-size: 12px; } .review-answer-row--border { border-top: 1px solid var(--border); padding-top: 8px; margin-top: 4px; } .review-answer-label { color: var(--ink3); } .review-answer-val { font-weight: 700; font-family: monospace; } .val-correct { color: var(--spotify-green-dark); } .val-wrong { color: var(--rose); } /* ── Explanation popup ────────────────────────────────────────────── */ .explain-overlay { position: fixed; inset: 0; z-index: 9999; background: rgba(0,0,0,.55); display: flex; align-items: flex-start; justify-content: center; padding: 80px 16px 16px; } @media (min-width: 640px) { .explain-overlay { justify-content: flex-end; } } .explain-box { width: min(100%, 460px); max-height: calc(100vh - 100px); background: var(--bg-surface); border: 1px solid var(--border); border-radius: 20px; box-shadow: var(--shadow-heavy); display: flex; flex-direction: column; overflow: hidden; } .explain-header { display: flex; align-items: center; justify-content: space-between; padding: 14px 18px; border-bottom: 1px solid var(--border); flex-shrink: 0; background: var(--bg-interactive); } .explain-title { font-size: 14px; font-weight: 700; color: var(--ink); } .explain-goto-btn { border: 1px solid var(--spotify-green); background: var(--green-bg); color: var(--spotify-green-dark); border-radius: 999px; font-size: 11px; font-weight: 700; padding: 4px 10px; } .explain-close { background: none; border: none; cursor: pointer; color: var(--ink3); padding: 4px; border-radius: 6px; } .explain-close:hover { background: var(--bg2); } .explain-body { flex: 1; overflow-y: auto; padding: 16px 18px; font-size: 13px; line-height: 1.7; color: var(--ink); } .explain-body u strong { color: var(--spotify-green-dark); } .explain-body .list-bullet1 { padding-left: 18px; } /* ── Shadowing studio (Spotify tokens, dark/light) ──────────────── */ .shadowing-studio { --sh-accent: var(--spotify-green); --sh-accent-dark: var(--spotify-green-dark); --sh-ink: var(--ink); --sh-surface: var(--bg-surface); background-color: var(--bg); background-image: linear-gradient(rgba(30, 215, 96, 0.06) 1px, transparent 1px), linear-gradient(90deg, rgba(30, 215, 96, 0.06) 1px, transparent 1px); background-size: 24px 24px; color: var(--sh-ink); } .sh-tab { border-radius: 999px; padding: 8px 16px; font-size: 12px; font-weight: 600; border: 1px solid var(--border); background: var(--bg-surface); color: var(--ink2); cursor: pointer; transition: background 0.15s, color 0.15s, border-color 0.15s; } .sh-tab:hover { border-color: var(--sh-accent); } .sh-tab.is-active { background: var(--sh-accent); border-color: var(--sh-accent-dark); color: #000; } .sh-btn { display: inline-flex; align-items: center; justify-content: center; gap: 6px; border-radius: 10px; padding: 10px 16px; font-size: 12px; font-weight: 700; cursor: pointer; border: 1px solid var(--border); background: var(--bg-surface); color: var(--ink); transition: background 0.12s, border-color 0.12s; } .sh-btn:hover { background: var(--bg-interactive); } .sh-btn-primary { background: var(--sh-accent, var(--spotify-green)); border-color: var(--sh-accent-dark, var(--spotify-green-dark)); color: #000000 !important; font-weight: 700; } .sh-btn-primary:hover { filter: brightness(1.08); } .sh-btn-primary:disabled { opacity: 0.5; color: #000000 !important; } .sh-btn-block { width: 100%; } .sh-card { border-radius: 14px; border: 1px solid var(--border); background: var(--bg-surface); box-shadow: var(--shadow-sm); } .sh-panel-title { font-size: 11px; font-weight: 800; letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink3); } .sh-transcript-card.is-active { border-color: var(--sh-accent); box-shadow: 0 0 0 2px rgba(30, 215, 96, 0.35); } .sh-transcript-body { word-wrap: break-word; overflow-wrap: break-word; white-space: normal; } .sh-transcript-prose { display: block; width: 100%; text-align: left; } .sh-word-chip { display: inline-block; border-radius: 8px; border: 1px solid var(--border); background: var(--bg-interactive); padding: 6px 12px; font-size: 15px; font-weight: 600; color: var(--ink); } .sh-focus-text { font-size: clamp(1.25rem, 2.5vw, 1.75rem); font-weight: 700; line-height: 1.5; color: var(--ink); text-align: center; word-break: normal; overflow-wrap: break-word; } .sh-focus-text .shadowing-vocab-text.vocab-mode { justify-content: center; } .sh-focus-card { min-height: 120px; } .sh-tab-panel { min-height: 0; height: 100%; width: 100%; } .sh-middle-panel { display: flex; flex-direction: column; min-height: 0; height: 100%; padding: 16px; overflow: hidden; } .sh-middle-panel > * { flex: 1; min-height: 0; } .shadowing-transcript { max-width: none; } /* Shadowing studio: 3 cột tỉ lệ 3 : 2 : 3 */ .sh-studio-grid { display: flex; flex-direction: column; min-height: 0; } @media (min-width: 1024px) { .sh-studio-grid { display: grid; grid-template-columns: 3fr 2fr 3fr; grid-template-rows: minmax(0, 1fr); align-items: stretch; } .sh-studio-grid > * { min-height: 0; max-height: 100%; } } .sh-left-col { display: flex; flex-direction: column; min-height: 0; height: 100%; max-height: 100%; overflow: hidden; } .sh-left-col-scroll { box-sizing: border-box; height: 100%; max-height: 100%; min-height: 0; overflow-x: hidden; overflow-y: auto; padding: 12px 14px 16px; -webkit-overflow-scrolling: touch; overscroll-behavior: contain; scrollbar-gutter: stable; } .sh-video-meta { margin-bottom: 12px; } .sh-video-title { margin: 8px 0 0; font-size: 13px; font-weight: 700; line-height: 1.5; color: #111; word-wrap: break-word; overflow-wrap: break-word; white-space: normal; } .sh-video-shell { position: relative; width: 100%; margin-bottom: 14px; overflow: hidden; border-radius: 12px; border: 1px solid var(--border-button); background: #000; aspect-ratio: 16 / 9; min-height: 180px; z-index: 1; } .sh-video-player { position: absolute; inset: 0; width: 100%; height: 100%; } .sh-video-player iframe { display: block; width: 100% !important; height: 100% !important; } .sh-left-controls { display: flex; flex-direction: column; gap: 12px; } @media (max-width: 1023px) { .sh-left-col { max-height: 50vh; } } .shadowing-studio .sh-middle-panel { min-width: 0; max-width: 100%; } /* ── Transitions ─────────────────────────────────────────────────── */ .popup-fade-enter-active, .popup-fade-leave-active { transition: opacity .2s, transform .2s; } .popup-fade-enter-from, .popup-fade-leave-to { opacity: 0; transform: translateX(20px); } /* ── Vocab page theme bridge (legacy hex → tokens) ─────────────── */ .vocab-header, .vocab-sidebar, .vocab-main, .modal-sm, .modal-lg { background: var(--bg-surface) !important; border-color: var(--border) !important; } .vocab-header__title, .main-title, .word-text, .topic-item__name, .modal-sm-header, .stat-num { color: var(--ink) !important; } .vocab-header__sub, .main-sub, .sidebar-title, .th, .topic-item__count, .field label { color: var(--ink3) !important; } .stat-pill { background: var(--bg-interactive) !important; border-color: var(--border) !important; } .stat-pill--green { border-color: var(--spotify-green-dark) !important; background: var(--green-bg) !important; } .stat-pill--green .stat-num, .topic-item.active .topic-item__name, .meaning-vi, .link-btn, .sidebar-add-btn, .add-word-btn, .view-tab.active, .word-type-pill { color: var(--spotify-green-dark) !important; } .sidebar-add-btn, .topic-item.active, .mastery--mastered, .row-action-btn:hover, .tts-btn:hover { background: var(--green-bg) !important; border-color: var(--spotify-green-dark) !important; } .topic-item:hover, .word-row:hover, .word-table-head { background: var(--bg-interactive) !important; } .word-search-input, .view-tab, .mastery-select, .topic-input, .field input, .field textarea { background: var(--bg-interactive) !important; border-color: var(--border) !important; color: var(--ink) !important; } .add-word-btn, .view-tab.active { background: var(--spotify-green) !important; color: #000 !important; } .add-word-btn:hover { background: var(--spotify-green-dark) !important; } /* ═══════════════════════════════════════════════════════════ Theme-aware utility shim (dark mode remaps legacy Tailwind) ═══════════════════════════════════════════════════════════ */ @layer utilities { [data-theme="light"] .spotify-panel, [data-theme="light"] .ct-card { border-color: #121212 !important; border-width: 1.5px; } [data-theme="dark"] .bg-white { background-color: var(--bg-surface) !important; } [data-theme="dark"] .ct-card { background-color: var(--bg-surface) !important; } [data-theme="dark"] .bg-slate-50, [data-theme="dark"] .bg-gray-50 { background-color: var(--bg-interactive) !important; } [data-theme="dark"] .bg-slate-100, [data-theme="dark"] .bg-gray-100 { background-color: var(--bg-interactive) !important; } [data-theme="dark"] .text-slate-900, [data-theme="dark"] .text-slate-800, [data-theme="dark"] .text-slate-700, [data-theme="dark"] .text-gray-900, [data-theme="dark"] .text-gray-800, [data-theme="dark"] .text-gray-700 { color: var(--text-base) !important; } [data-theme="dark"] .text-slate-600, [data-theme="dark"] .text-slate-500, [data-theme="dark"] .text-slate-400, [data-theme="dark"] .text-gray-600, [data-theme="dark"] .text-gray-500, [data-theme="dark"] .text-gray-400 { color: var(--text-subdued) !important; } [data-theme="dark"] .border-slate-200, [data-theme="dark"] .border-slate-100, [data-theme="dark"] .border-gray-200 { border-color: var(--border-button) !important; } .text-green-700, .text-green-800, .text-emerald-600, .text-emerald-700, .text-emerald-800 { color: var(--spotify-green) !important; } [data-theme="dark"] .bg-emerald-50, [data-theme="dark"] .bg-green-50, [data-theme="dark"] .bg-green-100 { background-color: var(--green-bg) !important; } [data-theme="dark"] .border-emerald-500, [data-theme="dark"] .border-emerald-600 { border-color: var(--spotify-green) !important; } [data-theme="dark"] .hover\:bg-emerald-50:hover { background-color: var(--green-bg) !important; } [data-theme="dark"] .hover\:bg-slate-50:hover, [data-theme="dark"] .hover\:bg-gray-50:hover { background-color: var(--bg-interactive) !important; } [data-theme="dark"] .hover\:bg-slate-100:hover { background-color: var(--surface-card) !important; } } /* Shared semantic UI blocks */ .chat-header-accent { background: var(--header-accent-bg); } .catbot-header { background: var(--catbot-header-bg) !important; border-color: color-mix(in srgb, var(--spotify-green) 35%, var(--border)) !important; } .catbot-title { color: var(--catbot-title-color); } .catbot-subtitle { color: var(--catbot-subtitle-color); } .catbot-bubble-assistant { background: var(--catbot-bubble-assistant-bg); color: var(--catbot-bubble-assistant-text); box-shadow: var(--shadow-medium); } .chat-bubble-assistant { background: var(--bubble-assistant-bg); color: var(--text-base); box-shadow: var(--shadow-medium); } .chat-bubble-user { background: var(--bubble-user-bg); color: var(--bubble-user-text); } .accent-hover:hover { border-color: var(--spotify-green); background: var(--green-bg); } .theme-toggle-btn { display: inline-flex; align-items: center; justify-content: center; width: 36px; height: 36px; border-radius: var(--radius-circle); border: 1px solid var(--border-button); background: var(--bg-interactive); color: var(--text-subdued); cursor: pointer; transition: background var(--transition-base), color var(--transition-base), border-color var(--transition-base); } .theme-toggle-btn:hover { color: var(--text-base); border-color: var(--spotify-green); }