diff --git a/docs/images/answer_loop.gif b/docs/images/answer_loop.gif index 36c9373..e2ac234 100644 Binary files a/docs/images/answer_loop.gif and b/docs/images/answer_loop.gif differ diff --git a/docs/images/end_screen.png b/docs/images/end_screen.png index b7f66b1..806acbe 100644 Binary files a/docs/images/end_screen.png and b/docs/images/end_screen.png differ diff --git a/docs/images/home.png b/docs/images/home.png index 27d2175..1b78e23 100644 Binary files a/docs/images/home.png and b/docs/images/home.png differ diff --git a/docs/images/model_answer.png b/docs/images/model_answer.png index a921c54..43d5be0 100644 Binary files a/docs/images/model_answer.png and b/docs/images/model_answer.png differ diff --git a/docs/images/plan.png b/docs/images/plan.png index 0a4d40e..b572b4d 100644 Binary files a/docs/images/plan.png and b/docs/images/plan.png differ diff --git a/docs/images/preflight.png b/docs/images/preflight.png index ace1a2a..9b4b41f 100644 Binary files a/docs/images/preflight.png and b/docs/images/preflight.png differ diff --git a/docs/images/review_hypercorrection.png b/docs/images/review_hypercorrection.png index f2dc3e8..1923ada 100644 Binary files a/docs/images/review_hypercorrection.png and b/docs/images/review_hypercorrection.png differ diff --git a/docs/images/runner_free_recall.png b/docs/images/runner_free_recall.png index 373f943..52dd2e3 100644 Binary files a/docs/images/runner_free_recall.png and b/docs/images/runner_free_recall.png differ diff --git a/docs/images/runner_mcq.png b/docs/images/runner_mcq.png index 64b2261..3c5cf98 100644 Binary files a/docs/images/runner_mcq.png and b/docs/images/runner_mcq.png differ diff --git a/src/app/achievements/page.tsx b/src/app/achievements/page.tsx index 8ffea60..1521119 100644 --- a/src/app/achievements/page.tsx +++ b/src/app/achievements/page.tsx @@ -103,7 +103,7 @@ export default function AchievementsPage() {

{catInfo.label}

{earned}/{badges.length} -
+
{badges.map((badge) => { const isEarned = earnedSet.has(badge.key); const earnedDate = earnedMap.get(badge.key); @@ -116,8 +116,8 @@ export default function AchievementsPage() { style={{ display: "flex", alignItems: "center", - gap: "0.75rem", - padding: "0.75rem 1rem", + gap: "0.85rem", + padding: "1.25rem", background: isEarned ? "var(--color-bg-done)" : "var(--color-bg-card)", border: `1px solid ${isEarned ? "var(--color-border-done)" : "var(--color-border)"}`, borderRadius: "var(--radius)", @@ -198,9 +198,9 @@ export default function AchievementsPage() { // ---- Styles ---- const mainStyle: React.CSSProperties = { - maxWidth: 700, + maxWidth: 1100, margin: "0 auto", - padding: "1.5rem 1rem", + padding: "1.5rem clamp(24px, 4vw, 32px)", fontFamily: "var(--font-body)", color: "var(--color-text)", backgroundColor: "var(--color-bg)", @@ -227,7 +227,7 @@ const overviewCardStyle: React.CSSProperties = { border: "1px solid var(--color-border-subtle)", borderRadius: "var(--radius)", boxShadow: "var(--shadow-card)", - padding: "1.25rem", + padding: "1.5rem", marginBottom: "2rem", }; diff --git a/src/app/auth/styles.ts b/src/app/auth/styles.ts index 0dfba77..58038b6 100644 --- a/src/app/auth/styles.ts +++ b/src/app/auth/styles.ts @@ -59,14 +59,14 @@ export const inputStyle: React.CSSProperties = { export const buttonStyle: React.CSSProperties = { width: "100%", - padding: "0.75rem", + padding: "0.75rem 1.5rem", fontSize: "1.05rem", fontFamily: "inherit", fontWeight: 600, background: "var(--color-primary)", color: "var(--color-bg-darkest)", border: "none", - borderRadius: "var(--radius-sm)", + borderRadius: "var(--radius)", cursor: "pointer", marginTop: "0.5rem", }; diff --git a/src/app/chat/page.tsx b/src/app/chat/page.tsx index 7ca6756..136e2e1 100644 --- a/src/app/chat/page.tsx +++ b/src/app/chat/page.tsx @@ -244,6 +244,7 @@ export default function ChatPage() {

Chat

{messages.length > 0 && (
-
+
{renderAnswerWithCitations(msg.content, msg.citations)}
@@ -462,6 +464,7 @@ export default function ChatPage() { )}
+
{/* Input area */} @@ -477,7 +480,7 @@ export default function ChatPage() { : "Ask a question about your materials..." } disabled={courses.length === 0 || loading} - rows={2} + rows={3} style={inputStyle} onKeyDown={(e) => { if (e.key === "Enter" && !e.shiftKey) { @@ -487,6 +490,7 @@ export default function ChatPage() { }} /> ))} @@ -496,13 +497,13 @@ export default function FlashcardsPage() {
@@ -511,6 +512,7 @@ export default function FlashcardsPage() { )} {error &&

{error}

} +
); @@ -525,7 +527,7 @@ export default function FlashcardsPage() { {courses.length > 0 ? ( -
+
Create a plan and upload your course notes there, then come back to generate study guides.

- + Create a Study Plan
@@ -259,34 +259,36 @@ export default function GuidesPage() { {guides.length > 0 && (

YOUR GUIDES

+
{guides.map((guide) => ( -
-
+
+
@@ -294,6 +296,7 @@ export default function GuidesPage() { {expandedGuide === guide.id && (
+
{renderGuideContent(guide)}
+
)}
))} +
)}
@@ -357,16 +362,16 @@ function renderGuideContent(guide: StudyGuide): React.ReactNode {
{guide.sections.map((s, i) => (
-

+

{s.concept || `Concept ${i + 1}`}

{s.explanation && ( -

+

{s.explanation}

)} {s.importance && ( -

+

Why it matters: {s.importance}

)} @@ -380,11 +385,11 @@ function renderGuideContent(guide: StudyGuide): React.ReactNode {
{guide.sections.map((s, i) => (
-

+

Q: {s.question || `Question ${i + 1}`}

{s.answer && ( -

+

{s.answer}

)} @@ -398,12 +403,12 @@ function renderGuideContent(guide: StudyGuide): React.ReactNode {
{guide.sections.map((s, i) => (
-

+

{s.topic || `Topic ${i + 1}`}

{s.content && (
{s.content}
@@ -421,13 +426,20 @@ function renderGuideContent(guide: StudyGuide): React.ReactNode { // --- Styles --- const pageContainer: React.CSSProperties = { - maxWidth: 700, + maxWidth: 1100, margin: "0 auto", - padding: "1.5rem 1rem", + padding: "1.5rem clamp(1.5rem, 4vw, 2rem)", fontFamily: "var(--font-body)", color: "var(--color-text)", }; +const guidesGrid: React.CSSProperties = { + display: "grid", + gridTemplateColumns: "repeat(auto-fill, minmax(min(320px, 100%), 1fr))", + gap: 16, + alignItems: "start", +}; + const typeButton: React.CSSProperties = { flex: "1 1 auto", minWidth: 0, @@ -443,8 +455,8 @@ const guideHeader: React.CSSProperties = { display: "flex", alignItems: "center", width: "100%", - padding: "0.75rem 1rem", - fontSize: "0.85rem", + padding: "1.25rem 1.5rem", + fontSize: "0.9rem", fontFamily: "inherit", background: "var(--color-bg-card)", color: "var(--color-text)", @@ -470,15 +482,20 @@ const guideContent: React.CSSProperties = { border: "1px solid var(--color-border)", borderTop: "none", borderRadius: "0 0 var(--radius) var(--radius)", - padding: "1rem 1.25rem", + padding: "1.75rem clamp(1rem, 4vw, 2.5rem) 1.5rem", boxShadow: "var(--shadow-card)", }; +const guideProse: React.CSSProperties = { + width: "100%", + maxWidth: 820, + margin: "0 auto", +}; const conceptCard: React.CSSProperties = { background: "var(--color-bg-card)", border: "1px solid var(--color-border)", borderRadius: "var(--radius-sm)", - padding: "0.75rem 1rem", - marginBottom: "0.5rem", + padding: "1rem 1.25rem", + marginBottom: "0.75rem", }; diff --git a/src/app/learn/page.tsx b/src/app/learn/page.tsx index 386d1fa..e92a91e 100644 --- a/src/app/learn/page.tsx +++ b/src/app/learn/page.tsx @@ -220,12 +220,12 @@ export default function LearnPage() { ))}
)} -
- +
+ Recommended: {modeLabel(recs.next_session.mode)}
-

+

{recs.next_session.reason}

{recs.overdue_objectives.length > 0 && ( @@ -241,7 +241,7 @@ export default function LearnPage() { @@ -254,51 +254,51 @@ export default function LearnPage() { {/* Quick actions — focused on what matters now */}

Quick Actions

-
+
{course.deckCount > 0 && course.dueCardCount > 0 && (
-
Review Due Cards
-
+
Review Due Cards
+
{course.dueCardCount} card{course.dueCardCount !== 1 ? "s" : ""} ready for spaced repetition review
- Review + Review → )} {course.processedDocCount > 0 && course.deckCount === 0 && (
-
Generate Flashcards
-
+
Generate Flashcards
+
{course.processedDocCount} doc{course.processedDocCount !== 1 ? "s" : ""} processed and ready
- Generate + Generate → )} {course.guideCount === 0 && course.processedDocCount > 0 && (
-
Create Study Guide
-
+
Create Study Guide
+
Key concepts, FAQs, or cheat sheets from your materials
- Create + Create → )}
-
Ask a Question
-
+
Ask a Question
+
Chat with your {course.courseName} materials
- Chat + Chat → {course.dueCardCount === 0 && course.deckCount > 0 && ( -
+
All caught up! No cards due for review right now.
)} @@ -311,7 +311,7 @@ export default function LearnPage() { {!(course.processedDocCount > 0 && course.deckCount > 0) && (

Suggested Learning Path

-
+

Today

{todaySessions.length === 0 ? ( -
-

+

+

{plans.length === 0 ? "Welcome to Study Bot" : "No sessions today"}

@@ -284,33 +284,61 @@ export default function DashboardPage() { )}

) : ( -
+
{todaySessions.map((item) => { + const single = todaySessions.length === 1; const mc = MODE_COLORS[item.mode] || "var(--color-info)"; const actionable = item.status === "SCHEDULED" || item.status === "IN_PROGRESS"; - const cardContent = ( + const actionLabel = item.status === "IN_PROGRESS" ? "Continue" : "Start"; + const cardContent = single ? ( + // Single session: one wide row so the lone card feels substantial.
{formatTime(item.start_time)} - {formatTime(item.end_time)} - + {MODE_LABELS[item.mode] || item.mode} {formatScope(item.topic_scope)} - {actionable && ( - - {item.status === "IN_PROGRESS" ? "Continue" : "Start"} - - )} + {actionable && {actionLabel}} {item.status === "DONE" && ( Done )}
+ ) : ( + // Grid cards: stacked layout that reads cleanly at ~320px wide. +
+
+ + {formatTime(item.start_time)} - {formatTime(item.end_time)} + + {item.status === "DONE" && ( + Done + )} +
+ + {MODE_LABELS[item.mode] || item.mode} + + + {formatScope(item.topic_scope)} + + {actionable && ( + {actionLabel} + )} +
); const cardStyle = { ...sessionCardStyle, + padding: single ? "1.75rem 2rem" : "1.25rem 1.5rem", + ...(single ? {} : { display: "flex" as const, flexDirection: "column" as const }), textDecoration: "none" as const, cursor: actionable ? "pointer" as const : "default" as const, borderLeft: `3px solid ${mc}`, @@ -370,7 +398,7 @@ export default function DashboardPage() {
{gameState && gameState.achievements.length > 0 ? ( -
+
{gameState.achievements.map((a) => { const info = BADGE_MAP[a.badgeType]; if (!info) return null; @@ -507,8 +535,8 @@ function OnboardingFlow({ border: "1px solid var(--color-border)", borderRadius: "var(--radius-lg)", boxShadow: "var(--shadow-card)", - padding: "2rem", - maxWidth: 480, + padding: "2.5rem", + maxWidth: 560, width: "100%", textAlign: "center", fontFamily: "var(--font-body)", @@ -549,8 +577,8 @@ function OnboardingFlow({ onClick={isLast ? onComplete : onNext} style={{ background: "var(--color-primary)", color: "var(--color-bg-darkest)", border: "none", - padding: "0.55rem 1.5rem", fontSize: "0.95rem", fontWeight: 600, - fontFamily: "inherit", borderRadius: "var(--radius-sm)", cursor: "pointer", + padding: "0.7rem 1.5rem", fontSize: "1rem", fontWeight: 600, + fontFamily: "inherit", borderRadius: "var(--radius)", cursor: "pointer", }} > {isLast ? "Get Started" : "Next"} @@ -686,10 +714,18 @@ function ActivityHeatmap({ activity }: { activity: ActivityDay[] }) { const cellGap = 2; const step = cellSize + cellGap; + // Natural drawing size; the SVGs scale up to fill the container on wide + // viewports (via viewBox + width 100%) and scroll horizontally on narrow ones. + const naturalWidth = weeks.length * step; + return (
-
- +
+ {monthLabels.map((m, i) => ( ))} -
- - {weeks.map((week, wi) => - week.map((day) => ( - - {day.date}: {day.count} session{day.count !== 1 ? "s" : ""} - - )) - )} - -
- Less - {[0, 1, 2, 3, 5].map((n) => ( - - - - ))} - More + + {weeks.map((week, wi) => + week.map((day) => ( + + {day.date}: {day.count} session{day.count !== 1 ? "s" : ""} + + )) + )} + +
+ Less + {[0, 1, 2, 3, 5].map((n) => ( + + + + ))} + More +
); @@ -743,9 +779,9 @@ function ActivityHeatmap({ activity }: { activity: ActivityDay[] }) { // ---- Styles ---- const mainStyle: React.CSSProperties = { - maxWidth: 700, + maxWidth: 1100, margin: "0 auto", - padding: "1.5rem 1rem", + padding: "1.5rem 1.75rem", fontFamily: "var(--font-body)", color: "var(--color-text)", backgroundColor: "var(--color-bg)", @@ -753,7 +789,7 @@ const mainStyle: React.CSSProperties = { }; const headingStyle: React.CSSProperties = { - fontSize: "1.5rem", + fontSize: "1.6rem", margin: "0 0 1.5rem", color: "var(--color-text)", fontWeight: 700, @@ -814,25 +850,25 @@ const emptyCardStyle: React.CSSProperties = { // Filled primary — the single visual primary action on the page. const primaryBtnStyle: React.CSSProperties = { display: "inline-block", - padding: "0.45rem 1.1rem", - fontSize: "0.9rem", + padding: "0.7rem 1.4rem", + fontSize: "1rem", fontWeight: 600, color: "var(--color-bg-darkest)", backgroundColor: "var(--color-primary)", border: "none", - borderRadius: "var(--radius-sm)", + borderRadius: "var(--radius)", textDecoration: "none", cursor: "pointer", fontFamily: "inherit", }; const actionBtnStyle: React.CSSProperties = { - padding: "0.5rem 1rem", - fontSize: "0.9rem", + padding: "0.7rem 1.25rem", + fontSize: "0.95rem", fontWeight: 600, color: "var(--color-primary)", border: "1px solid var(--color-primary)", - borderRadius: "var(--radius-sm)", + borderRadius: "var(--radius)", backgroundColor: "var(--color-bg-selected)", textDecoration: "none", cursor: "pointer", diff --git a/src/app/plan/page.tsx b/src/app/plan/page.tsx index 88d053d..fb6415f 100644 --- a/src/app/plan/page.tsx +++ b/src/app/plan/page.tsx @@ -475,8 +475,8 @@ export default function PlanPage() { )}
-
-
+ +
-
-
-
+
-
-
@@ -743,8 +745,8 @@ const pageStyle: React.CSSProperties = { background: "var(--color-bg)", color: "var(--color-text)", minHeight: "100vh", - padding: "1.5rem 1rem", - maxWidth: 700, + padding: "1.5rem clamp(1.5rem, 4vw, 2rem)", + maxWidth: 1100, margin: "0 auto", }; @@ -766,6 +768,21 @@ const dayHeadingStyle: React.CSSProperties = { fontFamily: "var(--font-display)", }; +// Responsive grid for peer cards (sessions within a day, other plans) +const cardGridStyle: React.CSSProperties = { + display: "grid", + gridTemplateColumns: "repeat(auto-fit, minmax(320px, 1fr))", + gap: 16, +}; + +// Two-column form row on desktop, collapses to one column on narrow screens +const formRowStyle: React.CSSProperties = { + display: "grid", + gridTemplateColumns: "repeat(auto-fit, minmax(240px, 1fr))", + gap: "1rem", + marginBottom: "1.25rem", +}; + const labelStyle: React.CSSProperties = { display: "flex", flexDirection: "column", @@ -788,6 +805,7 @@ function dropZoneStyle(busy: boolean): React.CSSProperties { return { background: "transparent", fontFamily: "inherit", + width: "100%", border: "2px dashed var(--color-border)", borderRadius: "var(--radius)", padding: "1.25rem", @@ -841,9 +859,10 @@ const btnStyle: React.CSSProperties = { background: "var(--color-bg-card)", color: "var(--color-text-secondary)", border: "1px solid var(--color-border)", - padding: "0.4rem 0.75rem", + padding: "0.7rem 1.25rem", fontFamily: "inherit", - fontSize: "0.85rem", + fontSize: "0.95rem", + fontWeight: 600, cursor: "pointer", textDecoration: "none", borderRadius: "var(--radius)", @@ -854,10 +873,10 @@ function googleBtnStyle(disabled: boolean): React.CSSProperties { background: "var(--color-info)", color: "var(--color-bg-darkest)", border: "none", - padding: "0.4rem 0.75rem", + padding: "0.7rem 1.25rem", fontFamily: "inherit", fontWeight: "bold", - fontSize: "0.85rem", + fontSize: "0.95rem", cursor: disabled ? "wait" : "pointer", opacity: disabled ? 0.6 : 1, borderRadius: "var(--radius)", @@ -867,8 +886,8 @@ function googleBtnStyle(disabled: boolean): React.CSSProperties { const sessionCardStyle: React.CSSProperties = { display: "block", background: "var(--color-bg-card)", - padding: "0.75rem 1rem", - marginBottom: "0.4rem", + padding: "1.25rem 1.5rem", + minWidth: 0, border: "1px solid var(--color-border-subtle)", borderLeft: "3px solid var(--color-primary)", textDecoration: "none", @@ -877,7 +896,7 @@ const sessionCardStyle: React.CSSProperties = { const examRowStyle: React.CSSProperties = { background: "var(--color-bg-card)", - padding: "0.75rem 1rem", + padding: "1.25rem 1.5rem", border: "1px solid var(--color-border-subtle)", borderLeft: "3px solid var(--color-warning)", borderRadius: "var(--radius-sm)", @@ -894,8 +913,8 @@ const otherPlanRowStyle: React.CSSProperties = { textAlign: "left", background: "var(--color-bg-card)", color: "var(--color-text-secondary)", - padding: "0.6rem 1rem", - marginBottom: "0.4rem", + padding: "1.25rem 1.5rem", + minWidth: 0, border: "1px solid var(--color-border-subtle)", borderRadius: "var(--radius-sm)", fontFamily: "inherit", diff --git a/src/app/s/[sessionId]/screens/break-screen.tsx b/src/app/s/[sessionId]/screens/break-screen.tsx index d3bfdb4..480a63a 100644 --- a/src/app/s/[sessionId]/screens/break-screen.tsx +++ b/src/app/s/[sessionId]/screens/break-screen.tsx @@ -27,13 +27,13 @@ export function BreakScreen({ breakState, onBreakEnd }: Props) { const seconds = remaining % 60; return ( -
+
@@ -42,38 +42,42 @@ export function BreakScreen({ breakState, onBreakEnd }: Props) {
{String(minutes).padStart(2, "0")}:{String(seconds).padStart(2, "0")}
+ {/* Checklist stays a comfortable reading column, centered on the + wider stage rather than stretched across it. */}

DO THIS NOW:

-
    +
    • Stand up and stretch
    • Get water
    • Look at something far away (20-20-20 rule)
    • @@ -81,15 +85,15 @@ export function BreakScreen({ breakState, onBreakEnd }: Props) {
-

+

Cycle {breakState.current_cycle + 1} of {breakState.total_cycles}

-

+

{session.course_name} | {session.exam_name}

-

+

{session.mode_label}: {session.topic_scope}

@@ -182,13 +182,13 @@ export function EndScreen({ run, session, onNewRun }: Props) {
)} - {/* Stats grid */} + {/* Stats grid: 4-across on desktop, 2x2 on phones (auto-fit grid) */}
@@ -211,12 +211,12 @@ export function EndScreen({ run, session, onNewRun }: Props) { background: "var(--color-bg-card)", border: "1px solid var(--color-border)", borderRadius: "var(--radius)", - padding: "1rem", + padding: "1.5rem 1.75rem", marginBottom: "1.5rem", }} >

RECOMMENDED FOLLOW-UPS

-
    +
      {followups.map((f, i) => (
    • {f.label} — {f.date} @@ -280,10 +280,10 @@ function CalibrationDashboard({ attempts }: { attempts?: RunData["attempts"] }) const color = gap < 0.15 ? "var(--color-success)" : gap < 0.3 ? "var(--color-warning)" : "var(--color-error)"; return ( -
      +

      CONFIDENCE CALIBRATION

      0 || underconfidentCount > 0 ? "0.5rem" : 0 }}> - {label} + {label} ({(gap * 100).toFixed(0)}% gap)
      {overconfidentCount > 0 && ( @@ -307,12 +307,12 @@ function StatCard({ label, value, color }: { label: string; value: string; color background: "var(--color-bg-card)", border: "1px solid var(--color-border)", borderRadius: "var(--radius)", - padding: "0.85rem", + padding: "1.25rem 1rem", textAlign: "center", }} > -
      {value}
      -
      {label}
      +
      {value}
      +
      {label}
      ); } @@ -324,10 +324,10 @@ function accuracyColor(accuracy: number): string { } const sectionTitle: React.CSSProperties = { - fontSize: "0.8rem", + fontSize: "0.85rem", letterSpacing: "0.08em", color: "var(--color-info)", - margin: "0 0 0.5rem", + margin: "0 0 0.65rem", fontFamily: "var(--font-display)", }; @@ -347,8 +347,8 @@ const secondaryBtn: React.CSSProperties = { const primaryBtn: React.CSSProperties = { width: "100%", - padding: "0.75rem 1.5rem", - fontSize: "1.05rem", + padding: "1rem 1.5rem", + fontSize: "1.15rem", fontFamily: "var(--font-body)", fontWeight: 600, background: "var(--color-primary)", diff --git a/src/app/s/[sessionId]/screens/preflight.tsx b/src/app/s/[sessionId]/screens/preflight.tsx index 27ba571..5cf04f5 100644 --- a/src/app/s/[sessionId]/screens/preflight.tsx +++ b/src/app/s/[sessionId]/screens/preflight.tsx @@ -15,34 +15,42 @@ export function PreflightScreen({ session, onStart, loading, hasActiveRun }: Pro return (
      -

      +

      {session.course_name} | {session.exam_name}

      -

      +

      {session.mode_label}: {session.topic_scope}

      -
      + {/* Meta stats: 4-across on desktop, 2x2 on phones (auto-fit grid) */} +
      {outcome?.prompt_count != null && ( -
      +
      Prompts - {outcome.prompt_count as number} + {outcome.prompt_count as number}
      )} {outcome?.target_accuracy != null && ( -
      +
      Target - {((outcome.target_accuracy as number) * 100).toFixed(0)}% + {((outcome.target_accuracy as number) * 100).toFixed(0)}%
      )} -
      +
      Duration - {session.planned_minutes} min + {session.planned_minutes} min
      {breaks && ( -
      +
      Breaks - + {breaks.type === "25_5" ? "25/5" : breaks.type === "50_10" ? "50/10" : breaks.type === "90_15" ? "90/15" : breaks.type === "12_3" ? "12/3" : String(breaks.type)} {breaks.cycles ? ` x${breaks.cycles}` : ""} @@ -53,7 +61,7 @@ export function PreflightScreen({ session, onStart, loading, hasActiveRun }: Pro {/* Deck composition contract: the student sees exactly what the deck holds before starting — no surprise session growth. */} {session.deck_preview && ( -
      +
      Deck {session.deck_preview.new_count > 0 && ( @@ -97,12 +105,25 @@ const metaLabel: React.CSSProperties = { textTransform: "uppercase", letterSpacing: "0.06em", display: "block", - marginBottom: "0.15rem", + marginBottom: "0.3rem", +}; + +const metaCell: React.CSSProperties = { + background: "var(--color-bg-card)", + border: "1px solid var(--color-border)", + borderRadius: "var(--radius)", + padding: "1rem 1.25rem", +}; + +const metaValue: React.CSSProperties = { + fontSize: "1.35rem", + fontWeight: 600, + fontFamily: "var(--font-display)", }; const deckChip = (color: string): React.CSSProperties => ({ - padding: "0.15rem 0.55rem", - fontSize: "0.78rem", + padding: "0.3rem 0.8rem", + fontSize: "0.85rem", color, border: `1px solid ${color}`, borderRadius: "999px", @@ -113,16 +134,16 @@ const examBanner: React.CSSProperties = { background: "var(--color-bg-review-tint)", border: "1px solid var(--color-review)", borderRadius: "var(--radius)", - padding: "0.75rem 1rem", - marginBottom: "1.5rem", - fontSize: "0.95rem", + padding: "1rem 1.25rem", + marginBottom: "1.75rem", + fontSize: "1rem", color: "var(--color-review)", }; const buttonStyle: React.CSSProperties = { width: "100%", - padding: "0.75rem 1.5rem", - fontSize: "1.05rem", + padding: "1rem 1.5rem", + fontSize: "1.15rem", fontFamily: "var(--font-body)", fontWeight: 600, background: "var(--color-primary)", diff --git a/src/app/s/[sessionId]/screens/runner.tsx b/src/app/s/[sessionId]/screens/runner.tsx index 709b296..53d614c 100644 --- a/src/app/s/[sessionId]/screens/runner.tsx +++ b/src/app/s/[sessionId]/screens/runner.tsx @@ -644,20 +644,20 @@ export function RunnerScreen({ run, session, onSubmit, onComplete }: Props) { background: "var(--color-bg-info-tint)", border: "1px solid var(--color-info)", borderRadius: "var(--radius)", - padding: "1rem", + padding: "1.25rem 1.5rem", marginBottom: "1rem", opacity: dimmed ? 0.7 : 1, }} data-testid="model-answer" > -

      +

      MODEL ANSWER — compare before you score

      -

      +

      {reveal.model_answer}

      {reveal.key_points && reveal.key_points.length > 0 && ( -
        +
          {reveal.key_points.map((kp, i) => (
        • {kp}
        • ))} @@ -749,13 +749,13 @@ export function RunnerScreen({ run, session, onSubmit, onComplete }: Props) { border: "1px solid var(--color-border)", borderRadius: "var(--radius)", boxShadow: "var(--shadow-card)", - padding: "1.25rem", + padding: "1.5rem 1.75rem", marginBottom: "1.25rem", }} >
          )} -

          +

          {displayText}

          @@ -782,9 +782,9 @@ export function RunnerScreen({ run, session, onSubmit, onComplete }: Props) { style={{ background: "var(--color-bg-card)", borderRadius: "var(--radius)", - padding: "1rem", + padding: "1.25rem 1.5rem", marginBottom: "1rem", - fontSize: "0.85rem", + fontSize: "0.95rem", lineHeight: 1.6, }} > @@ -807,8 +807,8 @@ export function RunnerScreen({ run, session, onSubmit, onComplete }: Props) { aria-pressed={mcqConfidence === val} aria-keyshortcuts={key.toLowerCase()} style={{ - padding: "0.2rem 0.55rem", - fontSize: "0.72rem", + padding: "0.35rem 0.8rem", + fontSize: "0.8rem", fontFamily: "inherit", background: mcqConfidence === val ? "var(--color-bg-selected)" : "transparent", color: mcqConfidence === val ? "var(--color-info)" : "var(--color-text-muted)", @@ -841,13 +841,13 @@ export function RunnerScreen({ run, session, onSubmit, onComplete }: Props) { style={{ display: "flex", alignItems: "flex-start", - gap: "0.75rem", - padding: "0.85rem 1rem", + gap: "0.85rem", + padding: "1.1rem 1.25rem", background: isSelected ? "var(--color-bg-selected)" : "var(--color-bg-card)", border: `2px solid ${isSelected ? "var(--color-primary)" : "var(--color-border)"}`, borderRadius: "var(--radius-lg)", color: "var(--color-text)", - fontSize: "0.9rem", + fontSize: "1rem", lineHeight: 1.5, cursor: submitting ? "wait" : "pointer", textAlign: "left", @@ -859,8 +859,8 @@ export function RunnerScreen({ run, session, onSubmit, onComplete }: Props) { {label}. {choice} @@ -882,7 +882,7 @@ export function RunnerScreen({ run, session, onSubmit, onComplete }: Props) { value={answer} onChange={(e) => setAnswer(e.target.value)} placeholder="Type your answer from memory..." - rows={6} + rows={9} style={textareaStyle} onKeyDown={(e) => { if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) { @@ -897,15 +897,15 @@ export function RunnerScreen({ run, session, onSubmit, onComplete }: Props) { background: "var(--color-bg-card)", border: "1px solid var(--color-border)", borderRadius: "var(--radius)", - padding: "0.75rem 1rem", + padding: "1rem 1.25rem", marginBottom: "0.75rem", }} > -
          - How confident are you? (optional) +
          + How confident are you? (optional) @@ -973,9 +973,9 @@ export function RunnerScreen({ run, session, onSubmit, onComplete }: Props) { style={{ background: "var(--color-bg-card)", borderRadius: "var(--radius)", - padding: "1rem", + padding: "1.25rem 1.5rem", marginBottom: "1rem", - fontSize: "0.85rem", + fontSize: "0.95rem", lineHeight: 1.6, }} > @@ -1008,17 +1008,17 @@ export function RunnerScreen({ run, session, onSubmit, onComplete }: Props) { style={{ display: "flex", alignItems: "flex-start", - gap: "0.75rem", - padding: "0.85rem 1rem", + gap: "0.85rem", + padding: "1.1rem 1.25rem", background: isCorrectChoice ? "var(--color-bg-done)" : isPicked ? "var(--color-bg-error-tint)" : "var(--color-bg-card)", border: `2px solid ${isCorrectChoice ? "var(--color-success)" : isPicked ? "var(--color-error)" : "var(--color-border)"}`, borderRadius: "var(--radius-lg)", color: "var(--color-text)", - fontSize: "0.9rem", + fontSize: "1rem", lineHeight: 1.5, }} > - {label}. + {label}. {choice} {isCorrectChoice && } {isPicked && !isCorrectChoice && your pick} @@ -1026,7 +1026,7 @@ export function RunnerScreen({ run, session, onSubmit, onComplete }: Props) { ); })}
          -

          +

          {reviewMcqCorrect ? "✓ You picked the correct answer." : "✗ You picked a different answer."}

          @@ -1072,11 +1072,11 @@ export function RunnerScreen({ run, session, onSubmit, onComplete }: Props) { background: score === "INCORRECT" ? "var(--color-bg-error-tint)" : "var(--color-bg-warning-tint)", border: `1px solid ${score === "INCORRECT" ? "var(--color-error)" : "var(--color-warning)"}`, borderRadius: "var(--radius)", - padding: "1rem", + padding: "1.25rem 1.5rem", marginBottom: "1rem", }} > -

          +

          {score === "INCORRECT" ? "✗ Incorrect" : "~ Partial"} — Log the error

          @@ -1139,7 +1139,7 @@ export function RunnerScreen({ run, session, onSubmit, onComplete }: Props) { background: "var(--color-bg-review-tint)", border: "1px solid var(--color-review)", borderRadius: "var(--radius)", - padding: "0.75rem 1rem", + padding: "1rem 1.25rem", marginBottom: "1rem", }} data-testid="hypercorrection-badge" @@ -1147,7 +1147,7 @@ export function RunnerScreen({ run, session, onSubmit, onComplete }: Props) {

          High-confidence miss

          -

          +

          You were sure about this one. Read the correction closely — confidently-held errors, once corrected, are the ones that stick best. This will come back for review. @@ -1162,14 +1162,14 @@ export function RunnerScreen({ run, session, onSubmit, onComplete }: Props) { background: "var(--color-bg-card)", border: "1px solid var(--color-border)", borderRadius: "var(--radius)", - padding: "0.75rem 1rem", + padding: "1rem 1.25rem", marginBottom: "1rem", }} >

          Diagnostic complete

          -

          +

          You haven't studied this yet — attempting it first primes your brain to encode the real material better. It's coming up in this course.

          @@ -1183,21 +1183,21 @@ export function RunnerScreen({ run, session, onSubmit, onComplete }: Props) { background: "var(--color-bg-card)", border: "1px solid var(--color-border)", borderRadius: "var(--radius)", - padding: "1rem", + padding: "1.25rem 1.5rem", marginBottom: "1rem", }} data-testid="mcq-result" > -

          +

          {mcqResult.is_correct ? `✓ Correct — ${String.fromCharCode(65 + mcqResult.correct_index)}` : `✗ Incorrect — the answer is ${String.fromCharCode(65 + mcqResult.correct_index)}`}

          -

          +

          {mcqResult.correct_choice}

          {!mcqResult.is_correct && mcqResult.rationale && ( -

          +

          Why your pick was tempting: {mcqResult.rationale}

          )} @@ -1211,44 +1211,44 @@ export function RunnerScreen({ run, session, onSubmit, onComplete }: Props) { background: "var(--color-bg-card)", border: "1px solid var(--color-border)", borderRadius: "var(--radius)", - padding: "1rem", + padding: "1.25rem 1.5rem", marginBottom: "1rem", }} > -

          +

          Nice work!

          {fb.reinforcement && ( -

          +

          {fb.reinforcement}

          )} {fb.deeper_insight && (
          -

          +

          Deeper Insight

          -

          +

          {fb.deeper_insight}

          )} {fb.concept_connection && (
          -

          +

          Connection

          -

          +

          {fb.concept_connection}

          )} {fb.socratic_followup && (
          -

          +

          Think Deeper

          -

          +

          {fb.socratic_followup}

          @@ -1263,11 +1263,11 @@ export function RunnerScreen({ run, session, onSubmit, onComplete }: Props) { background: "var(--color-bg-card)", border: "1px solid var(--color-border)", borderRadius: "var(--radius)", - padding: "1rem", + padding: "1.25rem 1.5rem", marginBottom: "1rem", }} > -

          +

          {feedbackLoading ? "Generating insight..." : "Correct!"}

          @@ -1280,11 +1280,11 @@ export function RunnerScreen({ run, session, onSubmit, onComplete }: Props) { background: "var(--color-bg-card)", border: "1px solid var(--color-border)", borderRadius: "var(--radius)", - padding: "1rem", + padding: "1.25rem 1.5rem", marginBottom: "1rem", }} > -

          +

          REVIEW (from your materials)

          @@ -1295,14 +1295,14 @@ export function RunnerScreen({ run, session, onSubmit, onComplete }: Props) { background: "var(--color-bg-card)", border: "1px solid var(--color-border)", borderRadius: "var(--radius-sm)", - padding: "0.75rem", + padding: "1rem 1.1rem", marginBottom: "0.75rem", }} >

          Professor's Explanation

          -
          +
          {renderExplanationWithCitations(fb.explanation, feedbackExcerpts, (idx) => { setHighlightedCitation(idx === highlightedCitation ? null : idx); const el = excerptRefs.current.get(idx); @@ -1318,7 +1318,7 @@ export function RunnerScreen({ run, session, onSubmit, onComplete }: Props) { marginTop: "0.5rem", }} > -

          +

          Key Takeaway: {fb.key_takeaway}

          @@ -1343,7 +1343,7 @@ export function RunnerScreen({ run, session, onSubmit, onComplete }: Props) { background: isHighlighted ? "var(--color-bg-selected)" : "var(--color-bg-card)", border: isHighlighted ? "1px solid var(--color-info)" : "1px solid var(--color-border)", borderRadius: "var(--radius-sm)", - padding: "0.75rem", + padding: "1rem 1.1rem", marginBottom: i < feedbackExcerpts.length - 1 ? "0.5rem" : 0, transition: "border-color 0.2s, background 0.2s", cursor: "pointer", @@ -1358,7 +1358,7 @@ export function RunnerScreen({ run, session, onSubmit, onComplete }: Props) { {excerpt.page_number && p. {excerpt.page_number}}

          $1'), @@ -1386,10 +1386,10 @@ export function RunnerScreen({ run, session, onSubmit, onComplete }: Props) { {/* Concept connection */} {fb.concept_connection && (

          -

          +

          Connection

          -

          +

          {fb.concept_connection}

          @@ -1398,10 +1398,10 @@ export function RunnerScreen({ run, session, onSubmit, onComplete }: Props) { {/* Mnemonic / memory aid */} {fb.mnemonic && (
          -

          +

          Memory Aid

          -

          +

          {fb.mnemonic}

          @@ -1410,10 +1410,10 @@ export function RunnerScreen({ run, session, onSubmit, onComplete }: Props) { {/* Mistake pattern advice */} {fb.pattern_advice && (
          -

          +

          Pattern Noticed

          -

          +

          {fb.pattern_advice}

          @@ -1422,10 +1422,10 @@ export function RunnerScreen({ run, session, onSubmit, onComplete }: Props) { {/* Socratic follow-up */} {fb.socratic_followup && (
          -

          +

          Think Deeper

          -

          +

          {fb.socratic_followup}

          {/* Close the loop: an unanswered Socratic question is decoration. @@ -1457,7 +1457,7 @@ export function RunnerScreen({ run, session, onSubmit, onComplete }: Props) { background: "var(--color-bg-card)", border: "1px solid var(--color-border)", borderRadius: "var(--radius-sm)", - padding: "0.75rem", + padding: "1rem 1.1rem", marginTop: "0.75rem", }} > @@ -1509,11 +1509,11 @@ export function RunnerScreen({ run, session, onSubmit, onComplete }: Props) { background: "var(--color-bg-card)", border: "1px solid var(--color-border)", borderRadius: "var(--radius)", - padding: "0.75rem 1rem", + padding: "1rem 1.25rem", marginBottom: "0.75rem", }} > -

          +

          Now explain this in your own words (optional):