/* ── CSS Variables (themes) ─────────────────────────────────── */ :root { --bg: #f0f4f8; --card-bg: #ffffff; --card-border: 1px solid rgba(0,0,0,0.07); --card-shadow: 0 1px 4px rgba(0,0,0,0.07), 0 4px 16px rgba(0,0,0,0.04); --card-radius: 12px; --primary: #2563eb; --primary-hover: #1d4ed8; --primary-fg: #ffffff; --text: #1e293b; --text-muted: #64748b; --text-subtle: #94a3b8; --border: #e2e8f0; --input-bg: #ffffff; --option-bg: #ffffff; --option-hover: #f8fafc; --option-sel-bg: #eff6ff; --option-sel-bd: #2563eb; --correct-bg: #d1fae5; --correct-bd: #86efac; --correct-fg: #14532d; --wrong-bg: #fee2e2; --wrong-bd: #fca5a5; --wrong-fg: #7f1d1d; --expl-bg: #f0f9ff; --expl-bd: #38bdf8; /* The same slate as before, two steps up: dark enough to sit under the page without the bar reading as a black band across the top. */ --navbar-bg: #1e293b; --exam-bar: #1b3a63; --navbar-fg: #e2e8f0; --badge-radius: 12px; } /* ── Warm / Literary theme ────────────────────────────────────── */ [data-theme="markdown"] { --bg: #f5f0e8; --card-bg: #fdfaf4; --card-border: 1px solid #e0d5c5; --card-shadow: 0 2px 8px rgba(60,40,10,0.06); --card-radius: 10px; --primary: #8b5a2b; --primary-hover: #6d4420; --primary-fg: #fdf8f0; --text: #1e140a; --text-muted: #7a5c42; --text-subtle: #aa8a6a; --border: #e0d5c5; --input-bg: #fdfaf4; --option-bg: #fdfaf4; --option-hover: #f7f0e4; --option-sel-bg: #f2e4d0; --option-sel-bd: #8b5a2b; --correct-bg: #e8f5e8; --correct-bd: #8abf8a; --correct-fg: #1a4a1a; --wrong-bg: #fdecea; --wrong-bd: #d99090; --wrong-fg: #6b1a1a; --expl-bg: #f9f4ea; --expl-bd: #c4965a; --navbar-bg: #33230f; --exam-bar: #33230f; --navbar-fg: #f0e8d8; --badge-radius: 4px; --font-body: 'Source Serif 4', Georgia, serif; --font-heading: 'Inter', ui-sans-serif, system-ui, -apple-system, sans-serif; --font-ui: 'Inter', system-ui, sans-serif; } /* ── Warm theme overrides ────────────────────────────────────── */ body[data-theme="markdown"] { font-family: var(--font-ui); font-size: 15.5px; line-height: 1.7; } [data-theme="markdown"] .navbar .logo { color: #e0a84a; font-family: var(--font-heading); letter-spacing: -0.02em; } [data-theme="markdown"] h1 { font-family: var(--font-heading); font-weight: 760; letter-spacing: -0.03em; line-height: 1.12; } [data-theme="markdown"] h2, [data-theme="markdown"] .card h2 { font-family: var(--font-heading); font-weight: 680; letter-spacing: -0.02em; line-height: 1.2; } [data-theme="markdown"] h3 { font-family: var(--font-ui); font-weight: 600; } [data-theme="markdown"] .card h2 { border-bottom: 1px solid var(--border); padding-bottom: 10px; margin-bottom: 18px; } [data-theme="markdown"] .question-card { border-left: 3px solid var(--primary); } [data-theme="markdown"] .question-card h3 { font-family: var(--font-body); font-size: 1.05rem; line-height: 1.7; font-weight: 400; font-style: normal; color: var(--text); } [data-theme="markdown"] .option { border-radius: 6px; font-size: 0.94rem; } [data-theme="markdown"] .option-letter { border-radius: 3px; font-family: var(--font-ui); font-weight: 600; } [data-theme="markdown"] .explanation { font-family: var(--font-body); font-size: 0.9rem; line-height: 1.85; border-left: 3px solid var(--expl-bd); background: var(--expl-bg); color: var(--text-muted); } [data-theme="markdown"] .btn { font-family: var(--font-ui); font-weight: 500; } [data-theme="markdown"] .score-display .score-value { font-family: var(--font-heading); letter-spacing: -3px; } /* ── Reset ──────────────────────────────────────────────────── */ * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: 'Inter', ui-sans-serif, system-ui, -apple-system, sans-serif; background: var(--bg); color: var(--text); line-height: 1.6; transition: background 0.25s, color 0.25s; } /* Both, not just body: with `overflow-x: hidden` on body alone the browser can still propagate the overflow to the viewport, and one element a few pixels too wide then scrolls the whole page sideways — which is why the navbar could be found clipped mid-word at its left edge. Anything genuinely wider than the window scrolls inside its own box instead. */ html, body { max-width: 100%; } /* `overflow-x: hidden` on an ancestor silently disables `position: sticky` for every descendant — it makes the element a scroll container, and a sticky child sticks to that instead of to the viewport. That is why the session rail, the settings nav and the article column would not stay put. `clip` does the same job without becoming a scroll container. Hidden is kept as the fallback, so a browser without `clip` still cannot be scrolled sideways; it just loses stickiness, which is the lesser fault. */ html, body { overflow-x: hidden; } @supports (overflow-x: clip) { html, body { overflow-x: clip; } } /* ── Layout ─────────────────────────────────────────────────── */ .container { max-width: 1200px; margin: 0 auto; padding: 0 28px; } /* The footer belongs at the bottom of the window, not wherever the content happens to stop. A loading page is a spinner, and without this the footer sat mid-screen with the page background below it. */ :root { /* The sticky header: the navbar plus the section bar beneath it. Anything that pins itself below the header measures from here rather than guessing. */ --app-header: 98px; } /* ── iOS Safari's zoom-on-focus ─────────────────────────────────────── Safari on iOS zooms the whole page in when a form control whose font is smaller than 16px takes focus, and it never zooms back out. The page is left scaled, the layout looks broken, and the only way back is a manual pinch. It is not a bug we can catch — it is the platform's behaviour, and the only lever is the font size. Set once, for every control, on touch pointers. It was being remembered at each individual field, which meant it was being forgotten at most of them — `!important` because those per-field rules are class-scoped and would otherwise win. Above 16px nothing here applies, so a deliberately larger field keeps its size. */ @media (pointer: coarse) { input:not([type="checkbox"]):not([type="radio"]):not([type="range"]), select, textarea { font-size: max(16px, 1rem) !important; } } .app-shell { display: flex; flex-direction: column; min-height: 100dvh; } .app-main { flex: 1 0 auto; width: 100%; } .app-shell > .site-footer { flex: none; } /* ── Navbar ─────────────────────────────────────────────────── */ /* Two bars. The primary one — identity, search, account — never moves. The section bar leaves while you scroll down and returns on the way up: it is wanted at the moment you decide to go elsewhere, and in the way in between. */ .navbar { color: var(--navbar-fg); margin-bottom: 32px; position: sticky; top: 0; z-index: 50; } .navbar-primary { background: var(--navbar-bg); } .navbar .navbar-inner { display: flex; justify-content: space-between; align-items: center; gap: 14px; height: 52px; } .navbar .logo { font-size: 1.15rem; font-weight: 700; color: #60a5fa; text-decoration: none; letter-spacing: -0.01em; white-space: nowrap; } .navbar-account { display: flex; align-items: center; gap: 8px; } .navbar-sections { /* A shade off the page, so the bar reads as a surface rather than as the top of the content — white on white left it looking like a stray row of links. */ background: linear-gradient(var(--card-bg), var(--bg)); /* A light surface inside a dark navbar, and `.navbar` sets a near-white text colour for that dark background. Everything in here inherited it — the study objective and its dropdown especially — so it was near-white on near-white and barely legible. The links had their own override and looked fine, which is why it went unnoticed. */ color: var(--text); border-bottom: 1px solid var(--border); box-shadow: 0 1px 3px rgba(15, 23, 42, 0.05); height: 46px; overflow: hidden; transition: height 0.18s ease; } /* Collapsing the height rather than sliding it away, so the page moves up with it instead of leaving a gap where the bar used to be. */ .navbar-sections.is-hidden { height: 0; border-bottom-color: transparent; } .navbar-sections:focus-within { height: 46px; } .navbar-sections-inner { display: flex; align-items: center; gap: 14px; height: 46px; } /* The strip scrolls when the links outrun the width; the fade on the right is what says so, since a hard cut just looks like a broken layout. */ .navbar-sections-inner { position: relative; } /* Layout and scrolling belong to ScrollStrip; this only styles the links. The mask fade that used to sit here implied scrollability and gave nothing to act on — the arrows do that job now, and a fade over one of them would only make the arrow look broken. */ .navbar .nav-sections a { color: var(--text); font-size: 0.84rem; font-weight: 500; opacity: 0.78; padding: 7px 11px; border-radius: 7px; white-space: nowrap; } .navbar .nav-sections a:hover { background: var(--option-hover); opacity: 1 !important; } .navbar .nav-sections a.is-current { color: var(--primary); font-weight: 700; opacity: 1; background: var(--option-sel-bg); box-shadow: inset 0 -2px 0 var(--primary); } @media (prefers-reduced-motion: reduce) { .navbar-sections { transition: none; } } [data-theme="markdown"] .navbar .logo { color: #d4a96a; } .nav-burger { display: none; background: none !important; border: 0 !important; cursor: pointer; color: var(--navbar-fg); padding: 6px; flex-direction: column; gap: 5px; opacity: 0.85; } /* Scoped to the dark bar. These were `.navbar a` and `.navbar button`, which also caught everything in the light section bar beneath it — near-white text and a translucent white border, on a white surface. */ .navbar-primary a { color: var(--navbar-fg); text-decoration: none; font-size: 0.83rem; padding: 6px 10px; border-radius: 6px; white-space: nowrap; transition: opacity 0.15s, background 0.15s; } .navbar-primary a:hover { background: rgba(255,255,255,0.09); opacity: 1 !important; } .navbar-primary button { background: transparent; border: 1px solid rgba(255,255,255,0.2); color: var(--navbar-fg); padding: 5px 14px; border-radius: 6px; cursor: pointer; font-size: 0.82rem; white-space: nowrap; font-family: inherit; } /* ── Cards ──────────────────────────────────────────────────── */ .card { background: var(--card-bg); border: var(--card-border); border-radius: var(--card-radius); padding: 28px; box-shadow: var(--card-shadow); margin-bottom: 16px; } .card h2 { margin-bottom: 16px; font-size: 1.15rem; color: var(--text); font-weight: 600; } .quiz-header-card .quiz-header-title, [data-theme="markdown"] .quiz-header-card .quiz-header-title { margin: 0 0 2px; padding: 0; border: 0; font-family: var(--font-ui, 'Inter', ui-sans-serif, system-ui, -apple-system, sans-serif); font-size: clamp(0.98rem, 1.8vw, 1.14rem); font-weight: 720; line-height: 1.18; letter-spacing: -0.025em; } .quiz-code-badge { display: inline-flex; align-items: center; gap: 6px; flex-wrap: wrap; margin: 4px 0 10px; color: var(--text-muted); font-size: 0.78rem; } .quiz-header-card .quiz-code-badge { margin: 0; } .quiz-code-badge code { border: 1px solid var(--border); border-radius: 6px; padding: 2px 7px; background: var(--bg); color: var(--text); font-size: 0.82rem; font-weight: 800; } .quiz-nav-controls { display: flex; justify-content: space-between; align-items: center; gap: 8px; margin-top: 14px; } .quiz-nav-controls-top { margin: -4px 0 16px; padding: 10px 12px; background: color-mix(in srgb, var(--card-bg) 92%, transparent); border: var(--card-border); border-radius: var(--card-radius); box-shadow: var(--card-shadow); } /* ── Buttons ────────────────────────────────────────────────── */ .btn { display: inline-flex; align-items: center; gap: 6px; padding: 9px 20px; border-radius: 8px; border: none; cursor: pointer; font-size: 0.875rem; font-weight: 500; text-decoration: none; transition: background 0.15s, opacity 0.15s; white-space: nowrap; } [data-theme="minimal"] .btn { border-radius: 6px; } .btn-primary { background: var(--primary); color: var(--primary-fg); } .btn-primary:hover { background: var(--primary-hover); } .btn-secondary { background: var(--border); color: var(--text); } .btn-secondary:hover { filter: brightness(0.94); } .btn-danger { background: #ef4444; color: white; } .btn-danger:hover { background: #dc2626; } .btn-sm { padding: 5px 12px; font-size: 0.78rem; } .btn:disabled { opacity: 0.45; cursor: not-allowed; } /* ── Forms ──────────────────────────────────────────────────── */ .form-group { margin-bottom: 16px; } .form-group label { display: block; font-weight: 500; margin-bottom: 6px; font-size: 0.85rem; color: var(--text-muted); } .form-group input, .form-group select, .form-group textarea { width: 100%; padding: 9px 13px; border: 1px solid var(--border); border-radius: 8px; font-size: 0.9rem; background: var(--input-bg); color: var(--text); font-family: inherit; } [data-theme="minimal"] .form-group input, [data-theme="minimal"] .form-group select, [data-theme="minimal"] .form-group textarea { border-radius: 6px; background: var(--input-bg); } .form-group input:focus, .form-group select:focus, .form-group textarea:focus { outline: none; border-color: var(--primary); box-shadow: 0 0 0 3px rgba(37,99,235,0.1); } [data-theme="minimal"] .form-group input:focus { box-shadow: 0 0 0 2px #09090b18; } /* The same two controls outside a .form-group wrapper. Four pages — articles, flashcards, the article editor, the category tree — write `.form-label` and `.input` directly, and neither class was defined anywhere, so a label fell back to inline and sat flush against an unbordered box: "Titlee.g. Febrile seizures". Defined here rather than fixed on one page, because the classes were always meant to be the standalone form of the rules above, and a form should not look different for having no wrapper around it. */ .form-label { display: block; font-weight: 500; margin-bottom: 6px; font-size: 0.85rem; color: var(--text-muted); } .form-label + .input, .form-label + textarea.input { margin-bottom: 12px; } .input { width: 100%; padding: 9px 13px; border: 1px solid var(--border); border-radius: 8px; font-size: 0.9rem; background: var(--input-bg); color: var(--text); font-family: inherit; } [data-theme="minimal"] .input { border-radius: 6px; } .input:focus { outline: none; border-color: var(--primary); box-shadow: 0 0 0 3px rgba(37,99,235,0.1); } [data-theme="minimal"] .input:focus { box-shadow: 0 0 0 2px #09090b18; } /* ── Question card (quiz-taking) ────────────────────────────── */ .question-card { background: var(--card-bg); border: var(--card-border); border-left: 4px solid var(--primary); border-radius: var(--card-radius); padding: 28px 28px 24px; margin-bottom: 20px; box-shadow: var(--card-shadow); } .question-card h3 { font-size: 1.05rem; line-height: 1.6; margin-bottom: 20px; color: var(--text); font-weight: 600; } .question-image-preview { display: block; margin: 10px 0; padding: 0; border: 0; background: transparent; cursor: zoom-in; text-align: left; } .question-image-preview img { display: block; max-width: 100%; max-height: 280px; border-radius: 8px; border: 1px solid var(--border); } .image-lightbox { position: fixed; inset: 0; z-index: 1000; padding: 24px; background: rgba(15, 23, 42, 0.82); cursor: zoom-out; } .image-lightbox-viewport { width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; overflow: auto; cursor: default; } .image-lightbox img { display: block; border-radius: 10px; box-shadow: 0 24px 80px rgba(0, 0, 0, 0.35); cursor: default; } .image-lightbox-controls { position: fixed; top: 16px; left: 50%; z-index: 1001; display: flex; align-items: center; gap: 8px; padding: 7px 9px; border: 1px solid rgba(255, 255, 255, 0.28); border-radius: 999px; background: rgba(15, 23, 42, 0.82); color: white; transform: translateX(-50%); } .image-lightbox-controls button { min-width: 34px; height: 30px; padding: 0 10px; border: 1px solid rgba(255, 255, 255, 0.28); border-radius: 999px; background: rgba(255, 255, 255, 0.12); color: white; cursor: pointer; } .image-lightbox-controls button:disabled { cursor: not-allowed; opacity: 0.45; } .image-lightbox-controls span { min-width: 48px; text-align: center; font-size: 0.86rem; font-weight: 700; } .image-lightbox-close { position: fixed; top: 16px; right: 16px; width: 40px; height: 40px; border: 1px solid rgba(255, 255, 255, 0.35); border-radius: 999px; background: rgba(15, 23, 42, 0.72); color: white; font-size: 1.5rem; line-height: 1; cursor: pointer; } .mynote-tab { position: fixed; right: 18px; bottom: 18px; z-index: 45; } .mynote-tab.dragging { user-select: none; } .mynote-tab-button { border: 1px solid rgba(37, 99, 235, 0.22); border-radius: 999px; padding: 11px 18px; background: linear-gradient(135deg, #2563eb, #7c3aed); color: white; box-shadow: 0 16px 40px rgba(37, 99, 235, 0.28); cursor: grab; font-weight: 800; letter-spacing: -0.02em; touch-action: none; } .mynote-editor { width: min(420px, calc(100vw - 28px)); border: 1px solid rgba(148, 163, 184, 0.28); border-radius: 18px; background: linear-gradient(180deg, color-mix(in srgb, var(--card-bg) 96%, transparent), var(--card-bg)), radial-gradient(circle at top left, rgba(37, 99, 235, 0.12), transparent 42%); box-shadow: 0 24px 70px rgba(15, 23, 42, 0.24); overflow: hidden; } .mynote-editor-header { display: flex; justify-content: space-between; align-items: flex-start; gap: 12px; padding: 14px 16px 10px; border-bottom: 1px solid var(--border); } .mynote-drag-handle { cursor: grab; touch-action: none; user-select: none; } .mynote-tab.dragging .mynote-tab-button, .mynote-tab.dragging .mynote-drag-handle { cursor: grabbing; } .mynote-title { font-weight: 850; font-size: 1rem; letter-spacing: -0.03em; color: var(--text); } .mynote-status { margin-top: 2px; color: var(--text-muted); font-size: 0.75rem; } .mynote-close, .mynote-modal-close { border: 0; background: var(--border); color: var(--text); border-radius: 999px; cursor: pointer; } .mynote-close { padding: 6px 10px; font-size: 0.76rem; } .mynote-error { margin: 10px 16px 0; color: var(--wrong-fg); font-size: 0.8rem; } .mynote-editor textarea { width: 100%; min-height: 260px; resize: vertical; border: 0; outline: 0; padding: 16px; background: transparent; color: var(--text); font: inherit; line-height: 1.65; } .mynote-card { display: flex; align-items: center; justify-content: space-between; gap: 18px; border-left: 4px solid #7c3aed; } .mynote-card-copy { min-width: 0; } .mynote-eyebrow { margin-bottom: 4px; color: #7c3aed; font-size: 0.72rem; font-weight: 850; letter-spacing: 0.06em; text-transform: uppercase; } .mynote-card h2 { margin: 0 0 6px; } .mynote-card p { margin: 0 0 6px; color: var(--text-muted); font-size: 0.9rem; line-height: 1.55; overflow-wrap: anywhere; } .mynote-card span { color: var(--text-subtle); font-size: 0.76rem; } .mynote-modal { position: fixed; inset: 0; z-index: 1000; display: flex; align-items: center; justify-content: center; padding: 18px; background: rgba(15, 23, 42, 0.55); } .mynote-modal-panel { position: relative; width: min(720px, 100%); } .mynote-modal-panel .mynote-editor { width: 100%; } .mynote-modal-panel .mynote-editor textarea { min-height: min(58vh, 520px); } .mynote-modal-close { position: absolute; top: -12px; right: -12px; z-index: 1; width: 34px; height: 34px; background: var(--navbar-bg); color: white; font-size: 1.2rem; } .manual-highlight-toolbar { display: inline-flex; gap: 6px; flex-wrap: wrap; align-items: center; padding: 4px; border-radius: 10px; background: color-mix(in srgb, var(--card-bg) 88%, transparent); } .manual-highlight-segment { user-select: text; -webkit-user-select: text; touch-action: auto; } /* A marker stroke under the words, not a block across them. * * It was a 72%-opacity band covering the bottom 62% of the line, which sat * over the text rather than behind it: descenders disappeared into it, small * type became hard to read, and a link inside a highlight lost the underline * that said it was a link. The band now starts below the x-height and is * light enough to read through, which is what a highlighter actually does. */ .manual-highlight-active { /* A solid band, the way a real highlighter leaves one and the way every question bank draws it. It was a gradient stripe under the x-height, which read as an underline rather than a highlight and disappeared entirely against a wrapped line. */ background: var(--marker, #fff07a); color: #1e293b; border-radius: 2px; cursor: context-menu; box-decoration-break: clone; -webkit-box-decoration-break: clone; } /* A cross-reference inside a highlight is still a cross-reference. The band used to swallow its underline, so the two were indistinguishable. */ .manual-highlight-active a, .manual-highlight-active .al-link { text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 2px; border-bottom: 0; } .speech-highlight-active { background: rgba(96, 165, 250, 0.18); box-shadow: inset 0 -2px 0 rgba(59, 130, 246, 0.72); border-radius: 3px; padding: 0 2px; box-decoration-break: clone; -webkit-box-decoration-break: clone; } .manual-highlight-active.speech-highlight-active { background: var(--marker, #fff07a); box-shadow: inset 0 -2px 0 rgba(59, 130, 246, 0.72); } /* On a dark ground the same yellow glares. Dimmer, and warmer, so the text on top of it stays the brightest thing. */ @media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) { --marker: rgba(250, 204, 21, 0.32); } } :root[data-theme="dark"] { --marker: rgba(250, 204, 21, 0.32); } /* Options */ .question-card .options { display: flex; flex-direction: column; gap: 10px; min-width: 0; } .question-card .option { display: flex; align-items: flex-start; gap: 12px; flex-wrap: wrap; width: 100%; min-width: 0; padding: 13px 16px; border: 1.5px solid var(--border); border-radius: 8px; cursor: pointer; transition: border-color 0.12s, background 0.12s; background: var(--option-bg); font-size: 0.9rem; color: var(--text); user-select: text; overflow-wrap: anywhere; -webkit-tap-highlight-color: transparent; touch-action: manipulation; } .question-card .option:hover { background: var(--option-hover); border-color: var(--text-subtle); } .question-card .option.selected { border-color: var(--option-sel-bd); background: var(--option-sel-bg); } .question-card .option.correct { border-color: var(--correct-bd); background: var(--correct-bg); color: var(--correct-fg); } .question-card .option.incorrect { border-color: var(--wrong-bd); background: var(--wrong-bg); color: var(--wrong-fg); } .option-letter { display: inline-flex; align-items: center; justify-content: center; width: 27px; height: 27px; border-radius: 50%; flex-shrink: 0; font-size: 0.75rem; font-weight: 700; background: var(--border); color: var(--text-muted); transition: background 0.12s; } .option.selected .option-letter { background: var(--primary); color: white; } .option.correct .option-letter { background: #16a34a; color: white; } .option.incorrect .option-letter { background: #dc2626; color: white; } .option-text { flex: 1 1 auto; min-width: 0; line-height: 1.55; overflow-wrap: anywhere; word-break: break-word; } .option-status { flex: 0 0 auto; margin-left: auto; font-size: 0.8rem; font-weight: 700; white-space: nowrap; } .option-status-correct { color: var(--correct-fg); } .option-status-wrong { color: var(--wrong-fg); } /* Explanation */ .explanation { margin-top: 20px; padding: 18px 20px; background: var(--expl-bg); border-left: 3px solid var(--expl-bd); border-radius: 8px; font-size: 0.875rem; color: var(--text-muted); line-height: 1.75; white-space: pre-line; } .explanation strong { color: var(--text); font-weight: 600; } /* ── Review card (results) ──────────────────────────────────── */ .review-card { background: var(--card-bg); border: var(--card-border); border-radius: var(--card-radius); padding: 28px 28px 24px; margin-bottom: 20px; box-shadow: var(--card-shadow); border-left: 4px solid var(--border); } .review-card.correct-card { border-left-color: #22c55e; } .review-card.wrong-card { border-left-color: #ef4444; } .review-card.skipped-card { border-left-color: var(--text-subtle); } /* ── Badges ─────────────────────────────────────────────────── */ .badge { display: inline-block; padding: 3px 10px; border-radius: var(--badge-radius); font-size: 0.72rem; font-weight: 600; } .badge-processing { background: #fef3c7; color: #92400e; } .badge-ready { background: #d1fae5; color: #065f46; } .badge-error { background: #fee2e2; color: #991b1b; } /* ── Stats ──────────────────────────────────────────────────── */ .stats-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 16px; margin-bottom: 20px; } .stat-card { background: var(--card-bg); border: var(--card-border); padding: 24px; border-radius: var(--card-radius); box-shadow: var(--card-shadow); text-align: center; } .stat-card .stat-value { font-size: 2.2rem; font-weight: 800; color: var(--primary); } .stat-card .stat-label { font-size: 0.8rem; color: var(--text-muted); margin-top: 4px; text-transform: uppercase; letter-spacing: 0.04em; } /* ── Grid ───────────────────────────────────────────────────── */ .grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; } /* ── Alerts ─────────────────────────────────────────────────── */ .alert { padding: 12px 16px; border-radius: 8px; margin-bottom: 16px; font-size: 0.875rem; } .alert-error { background: #fef2f2; color: #991b1b; border: 1px solid #fecaca; } .alert-success { background: #f0fdf4; color: #166534; border: 1px solid #bbf7d0; } /* ── Score display ──────────────────────────────────────────── */ .score-display { text-align: center; padding: 40px 24px; } .score-display .score-value { font-size: 4.5rem; font-weight: 900; line-height: 1; letter-spacing: -2px; } .score-display .score-value.good { color: #22c55e; } .score-display .score-value.ok { color: #f59e0b; } .score-display .score-value.poor { color: #ef4444; } /* ── Upload ─────────────────────────────────────────────────── */ .upload-area { border: 2px dashed var(--border); border-radius: 12px; padding: 56px; text-align: center; cursor: pointer; transition: all 0.2s; } .upload-area:hover, .upload-area.dragging { border-color: var(--primary); background: var(--option-sel-bg); } /* ── Progress bar ───────────────────────────────────────────── */ .progress-bar { background: var(--border); border-radius: 999px; height: 6px; overflow: hidden; } .progress-bar .fill { background: var(--primary); height: 100%; border-radius: 999px; transition: width 0.3s; } /* ── Spinner ────────────────────────────────────────────────── */ .spinner { display: inline-block; width: 20px; height: 20px; border: 3px solid var(--border); border-top-color: var(--primary); border-radius: 50%; animation: spin 0.6s linear infinite; } @keyframes spin { to { transform: rotate(360deg); } } @keyframes fadeInUp { from { opacity: 0; transform: translateX(-50%) translateY(8px); } to { opacity: 1; transform: translateX(-50%) translateY(0); } } /* ── Section items ──────────────────────────────────────────── */ .section-item { display: flex; justify-content: space-between; align-items: center; padding: 12px 16px; border: 1px solid var(--border); border-radius: 8px; margin-bottom: 8px; background: var(--card-bg); } /* ── Auth pages ─────────────────────────────────────────────── */ .auth-page { display: flex; justify-content: center; align-items: center; min-height: 80vh; } .auth-card { background: var(--card-bg); padding: 40px; border-radius: 14px; box-shadow: 0 4px 24px rgba(0,0,0,0.08); width: 100%; max-width: 420px; border: var(--card-border); } .auth-card h1 { text-align: center; margin-bottom: 24px; color: var(--text); } .auth-card .auth-link { text-align: center; margin-top: 14px; font-size: 0.875rem; color: var(--text-muted); } .auth-card .auth-link a { color: var(--primary); text-decoration: none; } /* ── Loading / empty ────────────────────────────────────────── */ .loading { text-align: center; padding: 56px; color: var(--text-muted); } .empty-state { text-align: center; padding: 48px; color: var(--text-subtle); } /* ── Footer ─────────────────────────────────────────────────── */ /* ── Quiz page layout ───────────────────────────────────────── */ .quiz-bottom { padding-bottom: 48px; } /* Two-column: content + sidebar */ .quiz-layout { display: flex; gap: 24px; align-items: flex-start; } /* Desktop sidebar (UWorld-style) */ .quiz-sidebar { width: 200px; flex-shrink: 0; position: sticky; top: 68px; background: var(--card-bg); border: var(--card-border); border-radius: var(--card-radius); padding: 16px; box-shadow: var(--card-shadow); max-height: calc(100dvh - 100px); overflow-y: auto; } /* Mobile: hide sidebar, show toggle button */ .quiz-nav-toggle { display: none; } /* ── Responsive ─────────────────────────────────────────────── */ @media (max-width: 768px) { .container { padding: 0 14px; } .grid-2 { grid-template-columns: 1fr; } .stats-grid { grid-template-columns: 1fr 1fr; } .question-card, .review-card { padding: 18px 14px; } .card { padding: 18px 16px; } .navbar .navbar-inner { height: 48px; } /* Mobile: show hamburger, hide desktop nav */ /* The burger carries the sections on a phone; the strip would be a second copy of the same links competing for the same thumb. */ .nav-burger { display: flex; } .nav-logout { display: none; } /* At the left-hand end, before the logo — it is the first child of the bar now, so nothing here has to reorder it. A control that changes what it holds must at least not change where it is: reaching for the top right and finding the account chip is how a menu gets a reputation. */ .navbar-inner > .nav-burger { margin-right: 2px; } /* Hide the whole strip, wrapper and arrows, not just the link row. */ .navbar-sections .ss-wrap { display: none; } .navbar-sections, .navbar-sections-inner, .navbar-sections:focus-within { height: 42px; } .navbar-sections.is-hidden { height: 0; } /* Mobile quiz: hide sidebar, show toggle */ .quiz-sidebar { display: none; } .quiz-nav-toggle { display: inline-flex; } .quiz-nav-controls { gap: 6px; } .quiz-nav-controls .btn { flex: 1; justify-content: center; padding-left: 10px; padding-right: 10px; } .quiz-nav-controls .quiz-nav-toggle { flex: 0 0 auto; } .manual-highlight-toolbar { display: grid; grid-template-columns: auto; gap: 8px; width: 100%; margin-top: 4px; position: sticky; top: 54px; z-index: 5; border: 1px solid var(--border); box-shadow: 0 8px 20px rgba(15, 23, 42, 0.08); } .manual-highlight-toolbar .btn { justify-content: center; min-height: 36px; white-space: normal; } .question-card .option { gap: 10px; padding: 12px; } .option-status { width: 100%; margin-left: 39px; } .mynote-tab { right: 12px; bottom: 12px; } .mynote-tab.open { left: 10px; } .mynote-editor textarea { min-height: 220px; } .mynote-card { align-items: stretch; flex-direction: column; } .mynote-card .btn { justify-content: center; } } /* ── Lesson content (markdown/HTML) ───────────────────────────── */ .lesson-content h1, .lesson-content h2, .lesson-content h3, .lesson-content h4 { margin-top: 1.2em; margin-bottom: 0.5em; } .lesson-content h2 { font-size: 1.3rem; border-bottom: 1px solid var(--border); padding-bottom: 6px; } .lesson-content h3 { font-size: 1.1rem; } .lesson-content h4 { font-size: 0.95rem; } .lesson-content p { margin: 0.6em 0; } .lesson-content ul, .lesson-content ol { padding-left: 1.5em; margin: 0.5em 0; } .lesson-content li { margin-bottom: 0.3em; } .lesson-content table { width: 100%; border-collapse: collapse; margin: 1em 0; font-size: 0.88rem; } .lesson-content th, .lesson-content td { padding: 8px 12px; border: 1px solid var(--border); text-align: left; } .lesson-content th { background: var(--bg); font-weight: 600; } .lesson-content hr { border: none; border-top: 1px solid var(--border); margin: 1.5em 0; } .lesson-content blockquote { border-left: 3px solid var(--primary); padding-left: 12px; margin: 1em 0; color: var(--text-muted); } .lesson-content code { background: var(--bg); padding: 2px 6px; border-radius: 4px; font-size: 0.88em; } .lesson-content pre { background: var(--bg); padding: 12px 16px; border-radius: 8px; overflow-x: auto; } .lesson-content strong { font-weight: 700; } .category-performance-row { display: grid; grid-template-columns: minmax(120px, 1fr) minmax(80px, 2fr) 64px 84px; gap: 10px; align-items: center; padding: 8px 0; border-bottom: 1px solid var(--border); font-size: .86rem; } .category-performance-row:last-child { border-bottom: none; } .cp-name { font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .cp-track { height: 8px; background: var(--bg, #e2e8f0); border-radius: 999px; overflow: hidden; display: block; } .cp-fill { display: block; height: 100%; background: var(--primary, #2563eb); border-radius: 999px; } .cp-accuracy { font-weight: 700; text-align: right; } .cp-count { color: var(--text-muted); text-align: right; } @media (max-width: 560px) { .category-performance-row { grid-template-columns: 1fr 56px; } .cp-track { grid-column: 1 / -1; grid-row: 2; } } .cp-heading { display: flex; justify-content: space-between; align-items: center; gap: 10px; flex-wrap: wrap; } .cp-overlay { position: fixed; inset: 0; background: rgba(15, 23, 42, 0.35); z-index: 1050; display: flex; justify-content: flex-end; } .cp-panel { background: var(--card-bg); width: min(520px, 92vw); height: 100%; display: flex; flex-direction: column; box-shadow: -12px 0 40px rgba(0,0,0,0.18); } .cp-panel-header { display: flex; justify-content: space-between; align-items: center; padding: 14px 18px; border-bottom: 1px solid var(--border); } .cp-panel-header h2 { margin: 0; font-size: 1rem; } .cp-panel-header button { background: none; border: none; font-size: 1.1rem; cursor: pointer; color: var(--text-muted); } .cp-panel-body { flex: 1; overflow-y: auto; padding: 14px 18px; } @media (max-width: 640px) { .cp-overlay { align-items: flex-end; } .cp-panel { width: 100%; height: 85vh; border-radius: 16px 16px 0 0; } } .cp-adaptive-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 12px; padding: 10px; border: 1px solid var(--border); border-radius: 10px; background: var(--input-bg); } .cp-adaptive-label { display: flex; align-items: center; gap: 6px; font-size: .82rem; } .cp-adaptive-label select { padding: 4px 8px; border: 1px solid var(--border); border-radius: 6px; } /* Deck category — same tree as questions and articles. */ .deck-category { margin-bottom: 8px; } .deck-category select { width: 100%; padding: 5px 8px; font-size: .76rem; border: 1px solid var(--border); border-radius: 6px; background: var(--input-bg); color: var(--text-muted); } .deck-category select:hover { color: var(--text); } /* Exam switcher — the study objective, above systems and disciplines. It sits on the light section bar now, so it is styled like every other control on a light surface rather than for a dark one. */ /* The study-objective control lives in ExamSwitcher.css: it is a dialog now, not a