/* ---------- Palette ---------- */

:root {
    --accent-cyan: #38bdf8;
    --accent-pink: #f472b6;
    --accent-violet: #a78bfa;
    --accent-amber: #fbbf24;
    --accent-green: #4ade80;
    --accent-orange: #fb923c;

    /* ---- Theme tokens (dark, the original/default look) ----
       --surface-rgb feeds every card/panel/border "rgba(var(--surface-rgb), X)"
       tint in this file — a light overlay on the dark body here, flipped to a
       dark-on-light tint for the light theme below so cards keep reading as
       "a shade off the body" either way. --body-bg is the whole animated
       multi-gradient body background as one swappable value. Code/output
       panels (.output-display, .hint-solution-code, username/token inputs)
       are deliberately left a fixed near-black in both themes, like an IDE's
       terminal pane — see their rules further down. */
    --surface-rgb: 255, 255, 255;
    --text-primary: #f5f3ff;
    --text-secondary: #c9c3ff;
    --accent-amber-text: #facc15;
    --input-bg: rgba(0, 0, 0, 0.35);
    /* Pastel gradient-clipped "hero" numbers/titles read fine on the dark
       body but wash out on the light one — a deeper, more saturated variant
       swaps in for light mode via these two variables. */
    --gradient-hero: linear-gradient(90deg, #7dd3fc, #c4b5fd, #f472b6);
    --gradient-stat: linear-gradient(90deg, #fbcfe8, #f0abfc, #c4b5fd);
    --gradient-title: linear-gradient(90deg, #f5f3ff, #e9d5ff);
    --body-bg:
        radial-gradient(55rem 42rem at 6% -8%, rgba(56, 189, 248, 0.5), transparent 58%),
        radial-gradient(48rem 42rem at 100% 4%, rgba(244, 63, 172, 0.42), transparent 55%),
        radial-gradient(52rem 46rem at 88% 78%, rgba(250, 204, 21, 0.22), transparent 52%),
        radial-gradient(60rem 55rem at 12% 108%, rgba(167, 139, 250, 0.5), transparent 60%),
        radial-gradient(46rem 40rem at 55% 45%, rgba(52, 211, 153, 0.16), transparent 60%),
        linear-gradient(160deg, #100a2e 0%, #341a54 40%, #4a1942 70%, #1a1638 100%);
}

/* Light theme — forced by the theme toggle (see Services/SoundEffect.cs's
   sibling Services/GameState.cs Theme field, applied as documentElement's
   data-theme attribute by wwwroot/js/theme.js). Same vibrant multi-gradient
   identity, just inverted to a bright base with dark-tinted cards/text. */
:root[data-theme="light"] {
    --surface-rgb: 20, 15, 45;
    --text-primary: #241f3d;
    --text-secondary: #4b4470;
    --accent-amber-text: #8a5d05;
    --input-bg: rgba(255, 255, 255, 0.6);
    --gradient-hero: linear-gradient(90deg, #0284c7, #7c3aed, #db2777);
    --gradient-stat: linear-gradient(90deg, #db2777, #a21caf, #7c3aed);
    --gradient-title: linear-gradient(90deg, #1e1b3a, #4c2a80);
    --body-bg:
        radial-gradient(55rem 42rem at 6% -8%, rgba(56, 189, 248, 0.28), transparent 58%),
        radial-gradient(48rem 42rem at 100% 4%, rgba(244, 63, 172, 0.22), transparent 55%),
        radial-gradient(52rem 46rem at 88% 78%, rgba(250, 204, 21, 0.16), transparent 52%),
        radial-gradient(60rem 55rem at 12% 108%, rgba(167, 139, 250, 0.26), transparent 60%),
        radial-gradient(46rem 40rem at 55% 45%, rgba(52, 211, 153, 0.14), transparent 60%),
        linear-gradient(160deg, #fdf8ff 0%, #f3ebff 40%, #ffeaf3 70%, #eef1ff 100%);
}

/* "System" theme (no data-theme attribute set) follows the OS preference. */
@media (prefers-color-scheme: light) {
    :root:not([data-theme="dark"]):not([data-theme="light"]) {
        --surface-rgb: 20, 15, 45;
        --text-primary: #241f3d;
        --text-secondary: #4b4470;
        --accent-amber-text: #8a5d05;
        --input-bg: rgba(255, 255, 255, 0.6);
        --gradient-hero: linear-gradient(90deg, #0284c7, #7c3aed, #db2777);
        --gradient-stat: linear-gradient(90deg, #db2777, #a21caf, #7c3aed);
        --gradient-title: linear-gradient(90deg, #1e1b3a, #4c2a80);
        --body-bg:
            radial-gradient(55rem 42rem at 6% -8%, rgba(56, 189, 248, 0.28), transparent 58%),
            radial-gradient(48rem 42rem at 100% 4%, rgba(244, 63, 172, 0.22), transparent 55%),
            radial-gradient(52rem 46rem at 88% 78%, rgba(250, 204, 21, 0.16), transparent 52%),
            radial-gradient(60rem 55rem at 12% 108%, rgba(167, 139, 250, 0.26), transparent 60%),
            radial-gradient(46rem 40rem at 55% 45%, rgba(52, 211, 153, 0.14), transparent 60%),
            linear-gradient(160deg, #fdf8ff 0%, #f3ebff 40%, #ffeaf3 70%, #eef1ff 100%);
    }
}

/* ---------- Code editor (CodeMirror, see Components/CodeEditor.razor) ---------- */

.code-editor-host {
    border-radius: 0.5rem;
    overflow: hidden;
    border: 1px solid rgba(var(--surface-rgb), 0.15);
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.25);
    transition: border-color 0.2s ease, box-shadow 0.2s ease;
    animation: attention-pulse 1.1s ease-out;
}

@keyframes attention-pulse {
    0% { box-shadow: 0 0 0 5px rgba(167, 139, 250, 0.4), 0 4px 16px rgba(0, 0, 0, 0.25); }
    100% { box-shadow: 0 4px 16px rgba(0, 0, 0, 0.25); }
}

/* Glows like an active level button while the student is actually typing —
   CodeMirror puts focus on an inner textarea, so :focus-within (rather than
   :focus) is what actually fires here. */
.code-editor-host:focus-within {
    border-color: var(--accent-violet);
    box-shadow: 0 0 0 3px rgba(167, 139, 250, 0.25), 0 4px 20px rgba(167, 139, 250, 0.3);
}

.code-editor-host .CodeMirror {
    height: auto;
    min-height: 12rem;
    font-family: "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;
    font-size: 0.95rem;
    line-height: 1.5;
}

.valid.modified:not([type=checkbox]) {
    outline: 1px solid #26b050;
}

.invalid {
    outline: 1px solid red;
}

.validation-message {
    color: red;
}

#blazor-error-ui {
    color-scheme: light only;
    background: lightyellow;
    bottom: 0;
    box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
    box-sizing: border-box;
    display: none;
    left: 0;
    padding: 0.6rem 1.25rem 0.7rem 1.25rem;
    position: fixed;
    width: 100%;
    z-index: 1000;
}

    #blazor-error-ui .dismiss {
        cursor: pointer;
        position: absolute;
        right: 0.75rem;
        top: 0.5rem;
    }

.blazor-error-boundary {
    background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121;
    padding: 1rem 1rem 1rem 3.7rem;
    color: white;
}

    .blazor-error-boundary::after {
        content: "An error has occurred."
    }

/* ---------- Boot / loading screen ----------
   Shown from first paint until Blazor finishes booting and renders the real
   app into #app, at which point Blazor replaces #app's contents entirely — so
   nothing here needs to be manually torn down. */

body {
    margin: 0;
    background: #0b0821;
    background: var(--body-bg);
    background-attachment: fixed;
    background-size: 200% 200%;
    animation: body-glow-shift 24s ease-in-out infinite;
    color: var(--text-primary);
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
    min-height: 100vh;
}

@media (prefers-reduced-motion: reduce) {
    body {
        animation: none;
    }
    .flashcard-shake,
    .cert-card-celebrate,
    .stats-achievement.unlocked.recent,
    .quiz-option.correct,
    .quiz-option.incorrect {
        animation: none;
    }
}

@keyframes body-glow-shift {
    0%, 100% { background-position: 0% 0%; }
    50% { background-position: 100% 40%; }
}

.boot-screen {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.75rem;
    min-height: 100vh;
    padding: 1.5rem;
    box-sizing: border-box;
    text-align: center;
}

.boot-badge {
    width: 3.5rem;
    height: 3.5rem;
    animation: boot-bounce 1.6s ease-in-out infinite;
}

.boot-title {
    margin: 0;
    font-size: 1.75rem;
    font-weight: 800;
    letter-spacing: 0.02em;
    background: var(--gradient-hero);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
}

.boot-subtitle {
    margin: 0 0 1rem 0;
    min-height: 1.4em;
    color: var(--text-secondary);
    font-size: 0.95rem;
    opacity: 0.9;
}

/* Blazor's boot script drives the actual percentage via --blazor-load-percentage
   on this exact svg/circle structure — re-themed as a slim glowing bar instead
   of the default spinner by collapsing the circle into a rect-like arc and
   hiding the raw text in favor of .loading-progress-text below it. */
/* Blazor's boot JS writes --blazor-load-percentage/-text onto the document
   root as real assets download; it doesn't require these specific elements to
   be visible, only present, so the original spinner markup is kept but fully
   collapsed out of the visual layout in favor of the themed bar below. */
.loading-progress {
    position: absolute;
    width: 0;
    height: 0;
    overflow: hidden;
    visibility: hidden;
}

/* A plain animated bar layered via a pseudo-element on the boot screen wrapper
   gives a reliable visual regardless of the svg circle's odd box model. */
.boot-screen::after {
    content: "";
    width: min(20rem, 80vw);
    height: 0.5rem;
    border-radius: 999px;
    background: rgba(var(--surface-rgb), 0.12);
    background-image: linear-gradient(90deg, #7dd3fc, #a78bfa, #f472b6);
    background-repeat: no-repeat;
    background-size: var(--blazor-load-percentage, 8%) 100%;
    transition: background-size 0.2s ease-out;
    order: 3;
}

.loading-progress-text {
    order: 4;
    font-size: 0.8rem;
    color: var(--text-secondary);
    opacity: 0.8;
}

    .loading-progress-text:after {
        content: var(--blazor-load-percentage-text, "Loading…");
    }

@keyframes boot-bounce {
    0%, 100% { transform: translateY(0); }
    50% { transform: translateY(-0.4rem); }
}

code {
    color: #c02d76;
}

.form-floating > .form-control-plaintext::placeholder, .form-floating > .form-control::placeholder {
    color: var(--bs-secondary-color);
    text-align: end;
}

.form-floating > .form-control-plaintext:focus::placeholder, .form-floating > .form-control:focus::placeholder {
    text-align: start;
}

/* ============================================================
   Game UI (Pages/Home.razor) — dark/gradient theme matching the
   boot screen, adapted from the original prototype's layout.
   ============================================================ */

.game-shell {
    max-width: 1200px;
    margin: 0 auto;
    padding: 1.25rem;
    box-sizing: border-box;
}

.panel {
    background: rgba(var(--surface-rgb), 0.07);
    border: 1px solid rgba(var(--surface-rgb), 0.14);
    border-radius: 0.75rem;
}

.game-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    flex-wrap: wrap;
    gap: 1rem;
    padding: 1.25rem 1.75rem;
    margin-bottom: 1.25rem;
    background: linear-gradient(135deg, rgba(125, 211, 252, 0.14), rgba(244, 114, 182, 0.12) 60%, rgba(167, 139, 250, 0.14));
    border: 1px solid rgba(var(--surface-rgb), 0.16);
    border-radius: 1rem;
    backdrop-filter: blur(12px);
    box-shadow: 0 8px 30px rgba(0, 0, 0, 0.35), inset 0 1px 0 rgba(var(--surface-rgb), 0.08);
}

.game-header-title h1 {
    margin: 0 0 0.2rem 0;
    font-size: 1.65rem;
    font-weight: 800;
    letter-spacing: 0.01em;
    background: var(--gradient-hero);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
    text-shadow: 0 0 30px rgba(196, 181, 253, 0.25);
}

.game-header-title p {
    margin: 0;
    color: var(--text-secondary);
    font-size: 0.92rem;
    opacity: 0.95;
}

.header-badge {
    display: inline-block;
    width: 1.9rem;
    height: 1.9rem;
    vertical-align: -0.35rem;
    animation: badge-wiggle 3s ease-in-out infinite;
}

/* Small icon riding inline with text (hint title, task points, level lock/
   check badges) — sized to roughly match the surrounding font's cap-height. */
.inline-icon {
    display: inline-block;
    width: 1em;
    height: 1em;
    vertical-align: -0.15em;
}

.level-btn-title {
    display: flex;
    align-items: center;
    gap: 0.35rem;
}

.stat-icon {
    display: inline-block;
    width: 1.1rem;
    height: 1.1rem;
    vertical-align: -0.15rem;
    margin-right: 0.15rem;
}

@keyframes badge-wiggle {
    0%, 100% { transform: rotate(0deg) scale(1); }
    10% { transform: rotate(-8deg) scale(1.05); }
    20% { transform: rotate(8deg) scale(1.05); }
    30% { transform: rotate(-4deg) scale(1); }
    40% { transform: rotate(0deg) scale(1); }
}

.streak-flame {
    display: inline-block;
    width: 1.1rem;
    height: 1.1rem;
    vertical-align: -0.1rem;
    animation: flame-pulse 1.4s ease-in-out infinite;
}

@keyframes flame-pulse {
    0%, 100% { transform: scale(1); filter: drop-shadow(0 0 0 rgba(251, 146, 60, 0)); }
    50% { transform: scale(1.22); filter: drop-shadow(0 0 6px rgba(251, 146, 60, 0.7)); }
}

.game-header-stats {
    display: flex;
    gap: 1.75rem;
}

.stat {
    text-align: center;
}

.stat-label {
    font-size: 0.7rem;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--text-secondary);
    opacity: 0.85;
    margin-bottom: 0.25rem;
    font-weight: 600;
}

.stat-value {
    font-size: 1.5rem;
    font-weight: 800;
    background: var(--gradient-stat);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
    text-shadow: 0 0 24px rgba(240, 171, 252, 0.35);
}

.game-body {
    display: grid;
    grid-template-columns: 240px 1fr;
    gap: 1.25rem;
    align-items: start;
    /* A grid track's automatic minimum size is based on its content's
       intrinsic width, not 0 — so one long unbreakable line anywhere inside
       (a code line, a URL, ...) can silently force this whole grid, and the
       page along with it, wider than the viewport. min-width: 0 here (and on
       .code-section below, the other grid that hosts the editor) opts back
       into "shrink to fit the track," which is what actually happens for a
       normal block element. */
    min-width: 0;
}

.level-sidebar {
    box-sizing: border-box;
    background: linear-gradient(165deg, rgba(244, 114, 182, 0.10), rgba(56, 189, 248, 0.07) 60%, rgba(167, 139, 250, 0.10));
    border: 1px solid rgba(var(--surface-rgb), 0.14);
    border-radius: 0.9rem;
    padding: 1rem;
    max-height: 70vh;
    overflow-y: auto;
    backdrop-filter: blur(10px);
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.3);
}

.sidebar-title {
    font-size: 0.75rem;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--text-secondary);
    opacity: 0.85;
    font-weight: 700;
    margin-bottom: 0.75rem;
}

.level-list {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

.level-btn {
    --lvl-accent: var(--accent-violet);
    text-align: left;
    padding: 0.7rem 0.9rem;
    border-radius: 0.6rem;
    border: 1px solid rgba(var(--surface-rgb), 0.14);
    border-left: 3px solid color-mix(in srgb, var(--lvl-accent) 55%, transparent);
    background: rgba(var(--surface-rgb), 0.05);
    color: var(--text-primary);
    cursor: pointer;
    font-size: 0.85rem;
    font-weight: 600;
    transition: transform 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease, background 0.15s ease;
    animation: level-btn-in 0.4s ease-out backwards;
    animation-delay: calc(var(--i, 0) * 45ms);
}

@keyframes level-btn-in {
    0% { opacity: 0; transform: translateX(-0.75rem); }
    100% { opacity: 1; transform: translateX(0); }
}

/* Cycle a rainbow of accent hues down the level list instead of one flat
   purple for every row — gives the sidebar visible variety at a glance. */
.level-btn:nth-child(6n+1) { --lvl-accent: var(--accent-cyan); }
.level-btn:nth-child(6n+2) { --lvl-accent: var(--accent-pink); }
.level-btn:nth-child(6n+3) { --lvl-accent: var(--accent-amber); }
.level-btn:nth-child(6n+4) { --lvl-accent: var(--accent-green); }
.level-btn:nth-child(6n+5) { --lvl-accent: var(--accent-violet); }
.level-btn:nth-child(6n+6) { --lvl-accent: var(--accent-orange); }

.level-btn:hover:not(:disabled) {
    border-color: var(--lvl-accent);
    transform: translateX(3px) scale(1.015);
    box-shadow: 0 4px 16px color-mix(in srgb, var(--lvl-accent) 40%, transparent);
}

.level-btn:active:not(:disabled) {
    transform: translateX(1px) scale(0.985);
}

.level-btn.active {
    background: linear-gradient(90deg, color-mix(in srgb, var(--lvl-accent) 35%, transparent), rgba(244, 114, 182, 0.25));
    border-color: var(--lvl-accent);
    box-shadow: 0 4px 20px color-mix(in srgb, var(--lvl-accent) 45%, transparent);
}

.level-btn.completed {
    border-color: rgba(74, 222, 128, 0.6);
    background: linear-gradient(90deg, rgba(74, 222, 128, 0.14), rgba(var(--surface-rgb), 0.04));
}

.level-btn.completed .level-progress {
    color: #4ade80;
    font-weight: 700;
}

.level-btn.locked {
    opacity: 0.4;
    cursor: not-allowed;
}

.level-progress {
    font-size: 0.72rem;
    opacity: 0.8;
    margin-top: 0.25rem;
}

.main-area {
    box-sizing: border-box;
    background: linear-gradient(155deg, rgba(56, 189, 248, 0.08), rgba(167, 139, 250, 0.06) 50%, rgba(244, 114, 182, 0.08));
    border: 1px solid rgba(var(--surface-rgb), 0.14);
    border-radius: 0.9rem;
    padding: 1.5rem;
    backdrop-filter: blur(10px);
    box-shadow: 0 8px 30px rgba(0, 0, 0, 0.3);
}

.task-content {
    animation: task-fade-in 0.35s ease-out;
}

@keyframes task-fade-in {
    0% { opacity: 0; transform: translateY(0.6rem); }
    100% { opacity: 1; transform: translateY(0); }
}

/* Difficulty accent — a colored left rail on the task header + badge tint,
   so difficulty reads at a glance instead of only as plain text. */
.task-content.diff-easy .task-header { border-left: 3px solid var(--accent-green); padding-left: 0.85rem; }
.task-content.diff-medium .task-header { border-left: 3px solid var(--accent-amber); padding-left: 0.85rem; }
.task-content.diff-hard .task-header { border-left: 3px solid var(--accent-pink); padding-left: 0.85rem; }

.diff-easy .task-difficulty-badge { color: var(--accent-green); }
.diff-medium .task-difficulty-badge { color: var(--accent-amber); }
.diff-hard .task-difficulty-badge { color: var(--accent-pink); }

.flashcard-page {
    animation: task-fade-in 0.35s ease-out;
    display: flex;
    flex-direction: column;
    align-items: center;
}

.flashcard-meta {
    width: 100%;
    box-sizing: border-box;
    display: flex;
    justify-content: space-between;
    margin-bottom: 1.25rem;
    padding-bottom: 0.85rem;
    border-bottom: 1px solid rgba(var(--surface-rgb), 0.12);
}

.flashcard {
    width: 100%;
    max-width: 26rem;
    aspect-ratio: 4 / 3;
    perspective: 1400px;
    cursor: pointer;
}

.flashcard-shake {
    animation: flashcard-shake 0.5s ease;
}

@keyframes flashcard-shake {
    10%, 90% { transform: translateX(-1px); }
    20%, 80% { transform: translateX(2px); }
    30%, 50%, 70% { transform: translateX(-4px); }
    40%, 60% { transform: translateX(4px); }
}

.flashcard-inner {
    position: relative;
    width: 100%;
    height: 100%;
    text-align: center;
    transition: transform 0.5s cubic-bezier(0.34, 1.56, 0.64, 1);
    transform-style: preserve-3d;
}

.flashcard.flipped .flashcard-inner {
    transform: rotateY(180deg);
}

.flashcard-face {
    position: absolute;
    inset: 0;
    box-sizing: border-box;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.6rem;
    padding: 1.5rem;
    border-radius: 1rem;
    border: 1px solid rgba(var(--surface-rgb), 0.18);
    box-shadow: 0 8px 30px rgba(0, 0, 0, 0.3);
    backface-visibility: hidden;
}

.flashcard-front {
    background: linear-gradient(155deg, rgba(56, 189, 248, 0.14), rgba(167, 139, 250, 0.1) 50%, rgba(244, 114, 182, 0.14));
}

.flashcard-back {
    background: linear-gradient(155deg, rgba(244, 114, 182, 0.14), rgba(56, 189, 248, 0.1) 60%, rgba(167, 139, 250, 0.14));
    transform: rotateY(180deg);
}

.flashcard-icon {
    font-size: 2.5rem;
}

.flashcard-term {
    font-size: 1.8rem;
    font-weight: 800;
    background: var(--gradient-title);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
}

.flashcard-term-small {
    font-size: 1.15rem;
}

.flashcard-tap-hint {
    font-size: 0.85rem;
    color: var(--text-secondary);
    opacity: 0.8;
}

.flashcard-definition {
    font-size: 1rem;
    line-height: 1.6;
    color: var(--text-primary);
}

.flashcard-controls {
    margin-top: 1.5rem;
}

.welcome-panel {
    padding: 0.5rem;
    animation: task-fade-in 0.4s ease-out;
}

.welcome-cta {
    display: block;
    width: 100%;
    box-sizing: border-box;
    text-align: center;
    background: linear-gradient(135deg, rgba(125, 211, 252, 0.14), rgba(244, 114, 182, 0.12) 60%, rgba(167, 139, 250, 0.14));
    border: 1px solid rgba(var(--surface-rgb), 0.16);
    border-radius: 0.9rem;
    padding: 1.5rem 1.25rem;
    cursor: pointer;
    font: inherit;
    color: inherit;
    transition: transform 0.15s ease, box-shadow 0.15s ease, border-color 0.15s ease;
}

.welcome-cta:hover {
    transform: translateY(-2px);
    border-color: var(--accent-violet);
    box-shadow: 0 8px 24px rgba(124, 58, 237, 0.25);
}

.welcome-cta-label {
    font-size: 0.75rem;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--text-secondary);
    font-weight: 700;
}

.welcome-cta-title {
    font-size: 1.5rem;
    font-weight: 800;
    margin: 0.35rem 0 0.9rem;
    background: var(--gradient-hero);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
}

.welcome-cta-progress {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    max-width: 24rem;
    margin: 0 auto 1.1rem;
}

.welcome-cta-progress .welcome-cta-bar {
    flex: 1;
    background: rgba(0, 0, 0, 0.35);
    border-radius: 999px;
    height: 0.5rem;
    overflow: hidden;
}

.welcome-cta-fill {
    height: 100%;
    background: linear-gradient(90deg, var(--accent-violet), var(--accent-pink));
    border-radius: 999px;
    transition: width 0.4s ease;
}

.welcome-cta-progress span {
    font-size: 0.75rem;
    color: var(--text-secondary);
    white-space: nowrap;
}

.welcome-cta-btn {
    display: inline-block;
    pointer-events: none;
}

.welcome-cta-done .welcome-cta-btn {
    pointer-events: auto;
}

.welcome-stats {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 0.75rem;
    margin-top: 0.9rem;
}

.welcome-stat {
    text-align: center;
    background: rgba(var(--surface-rgb), 0.05);
    border: 1px solid rgba(var(--surface-rgb), 0.12);
    border-radius: 0.7rem;
    padding: 0.75rem 0.5rem;
}

.welcome-stat-value {
    font-size: 1.15rem;
    font-weight: 800;
    color: var(--text-primary);
}

.welcome-stat-label {
    font-size: 0.7rem;
    color: var(--text-secondary);
    margin-top: 0.2rem;
}

.task-header {
    margin-bottom: 1rem;
    padding-bottom: 0.85rem;
    border-bottom: 1px solid rgba(var(--surface-rgb), 0.12);
}

.task-title {
    margin: 0 0 0.4rem 0;
    font-size: 1.55rem;
    font-weight: 800;
    background: var(--gradient-title);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
}

.task-meta {
    display: flex;
    gap: 1rem;
    flex-wrap: wrap;
    font-size: 0.85rem;
    color: var(--text-secondary);
    font-weight: 600;
    opacity: 0.95;
}

.task-points {
    color: var(--accent-amber-text);
    font-weight: 700;
    text-shadow: 0 0 16px rgba(253, 224, 71, 0.4);
}

.success-message {
    background: linear-gradient(90deg, rgba(74, 222, 128, 0.2), rgba(34, 211, 238, 0.12));
    border: 1px solid rgba(74, 222, 128, 0.6);
    color: #86efac;
    padding: 0.75rem 1rem;
    border-radius: 0.6rem;
    margin-bottom: 1rem;
    font-weight: 700;
    box-shadow: 0 4px 16px rgba(74, 222, 128, 0.15);
    animation: success-pop 0.35s cubic-bezier(0.34, 1.56, 0.64, 1);
}

@keyframes success-pop {
    0% { opacity: 0; transform: scale(0.92) translateY(-0.4rem); }
    100% { opacity: 1; transform: scale(1) translateY(0); }
}

.task-description {
    background: rgba(var(--surface-rgb), 0.06);
    border: 1px solid rgba(var(--surface-rgb), 0.08);
    padding: 0.9rem 1.1rem;
    border-radius: 0.6rem;
    margin-bottom: 1rem;
    line-height: 1.65;
    color: var(--text-primary);
    font-size: 0.98rem;
    white-space: pre-wrap;
}

.task-example {
    background: rgba(0, 0, 0, 0.4);
    border-left: 3px solid #a78bfa;
    padding: 0.85rem 1rem;
    border-radius: 0.4rem;
    margin: 0 0 1rem 0;
    font-family: "SF Mono", Menlo, Consolas, monospace;
    font-size: 0.82rem;
    color: #d8d2ff;
    overflow-x: auto;
    white-space: pre-wrap;
}

.hint-box {
    background: rgba(250, 204, 21, 0.1);
    border-left: 3px solid #facc15;
    padding: 0.85rem 1rem;
    border-radius: 0.35rem;
    margin-bottom: 1rem;
    animation: task-fade-in 0.3s ease-out, hint-glow-pulse 1.1s ease-out;
}

@keyframes hint-glow-pulse {
    0% { box-shadow: 0 0 0 5px rgba(250, 204, 21, 0.35); }
    100% { box-shadow: 0 0 0 0 rgba(250, 204, 21, 0); }
}

.hint-title {
    font-weight: 700;
    color: var(--accent-amber-text);
    margin-bottom: 0.5rem;
}

.hint-content {
    font-size: 0.85rem;
    line-height: 1.5;
    color: var(--text-primary);
    margin-bottom: 0.5rem;
}

.hint-solution {
    margin-top: 0.5rem;
    position: relative;
}

.hint-solution-label {
    font-size: 0.8rem;
    font-weight: 600;
    color: var(--accent-amber-text);
    margin-bottom: 0.4rem;
}

.hint-solution-code {
    background: rgba(0, 0, 0, 0.4);
    padding: 0.75rem;
    border-radius: 0.35rem;
    font-family: "SF Mono", Menlo, Consolas, monospace;
    font-size: 0.8rem;
    overflow-x: auto;
    white-space: pre-wrap;
    margin: 0 0 0.5rem 0;
    cursor: pointer;
    transition: background 0.15s ease;
}

.hint-solution-code:hover {
    background: rgba(0, 0, 0, 0.55);
}

.hint-solution-code:active {
    background: rgba(122, 92, 255, 0.25);
}

.copied-toast {
    position: absolute;
    top: 0.4rem;
    right: 0.4rem;
    background: color-mix(in srgb, var(--lvl-accent, #7a5cff) 85%, black);
    color: #fff;
    font-size: 0.7rem;
    font-weight: 600;
    padding: 0.25rem 0.6rem;
    border-radius: 999px;
    pointer-events: none;
    animation: copied-toast-pop 1.2s ease forwards;
}

@keyframes copied-toast-pop {
    0% { opacity: 0; transform: translateY(-4px) scale(0.9); }
    12% { opacity: 1; transform: translateY(0) scale(1); }
    75% { opacity: 1; }
    100% { opacity: 0; }
}

.code-section {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 1rem;
    margin-bottom: 1rem;
    min-width: 0;
}

.code-section > * {
    min-width: 0;
}

/* ---------- Visual game mode (Components/CanvasView.razor) ---------- */

.canvas-section {
    margin-bottom: 1rem;
}

.canvas-play-btn {
    margin-top: 0.6rem;
}

.canvas-stage {
    position: relative;
    max-width: 100%;
    background:
        radial-gradient(30rem 20rem at 15% 0%, rgba(56, 189, 248, 0.12), transparent 60%),
        radial-gradient(28rem 20rem at 100% 100%, rgba(244, 114, 182, 0.12), transparent 60%),
        #0a0a12;
    border: 1px solid rgba(167, 139, 250, 0.35);
    border-radius: 0.5rem;
    overflow: hidden;
    box-shadow: 0 0 24px rgba(167, 139, 250, 0.12);
}

.canvas-shape {
    position: absolute;
    transition: left 0.35s ease, top 0.35s ease, background 0.2s ease;
}

.canvas-shape-circle {
    border-radius: 50%;
}

.canvas-shape-square {
    border-radius: 0.15rem;
}

.canvas-shape-triangle {
    background: none !important;
    width: 0 !important;
    height: 0 !important;
    border-left: 20px solid transparent;
    border-right: 20px solid transparent;
    border-bottom: 40px solid var(--tri-color, #7dd3fc);
}

/* "rect" (no dedicated class — a plain box IS a rectangle by default, since
   Canvas.AddShape's width/height come from inline style already) renders
   correctly with no rule needed here. "star" and "diamond" previously had
   NO matching class at all, so student code that drew them (e.g. Level 6's
   "Spawn Method" task) silently rendered as an indistinguishable plain box
   instead of the shape the task described. */
.canvas-shape-star {
    clip-path: polygon(50% 0%, 61% 35%, 98% 35%, 68% 57%, 79% 91%, 50% 70%, 21% 91%, 32% 57%, 2% 35%, 39% 35%);
}

.canvas-shape-diamond {
    clip-path: polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%);
}

.panel-label {
    font-size: 0.75rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--text-secondary);
    opacity: 0.7;
    margin-bottom: 0.4rem;
}

.output-display {
    background: #0a0a12;
    color: #4ade80;
    padding: 0.85rem;
    border-radius: 0.5rem;
    border: 1px solid rgba(var(--surface-rgb), 0.12);
    min-height: 12rem;
    font-family: "SF Mono", Menlo, Consolas, monospace;
    font-size: 0.85rem;
    line-height: 1.5;
    white-space: pre-wrap;
    overflow-y: auto;
    margin: 0;
}

.output-display.success {
    color: #4ade80;
    border-color: rgba(74, 222, 128, 0.5);
}

.output-display.error {
    color: #f87171;
    border-color: rgba(248, 113, 113, 0.5);
}

.controls {
    display: flex;
    flex-wrap: wrap;
    gap: 0.6rem;
    margin-bottom: 1rem;
}

.controls button, .task-navigation button, .btn-primary, .btn-secondary, .btn-hint, .btn-next {
    padding: 0.6rem 1.1rem;
    border: none;
    border-radius: 0.5rem;
    font-size: 0.85rem;
    font-weight: 600;
    cursor: pointer;
    transition: transform 0.15s ease, box-shadow 0.15s ease, opacity 0.15s ease;
}

.controls button:disabled {
    opacity: 0.6;
    cursor: not-allowed;
}

.controls button:active:not(:disabled), .task-navigation button:active:not(:disabled) {
    transform: translateY(0) scale(0.96);
}

.btn-primary,
.btn-secondary,
.btn-hint,
.btn-next {
    transition: transform 0.15s ease, box-shadow 0.15s ease, background 0.15s ease;
}

.btn-primary:active:not(:disabled),
.btn-secondary:active:not(:disabled),
.btn-hint:active:not(:disabled),
.btn-next:active:not(:disabled) {
    transform: scale(0.96);
}

.btn-primary {
    background: linear-gradient(90deg, #7dd3fc, #a78bfa);
    background-size: 200% 100%;
    color: #0f0c29;
    transition: transform 0.15s ease, box-shadow 0.15s ease, background-position 0.4s ease;
}

.btn-primary:hover:not(:disabled) {
    transform: translateY(-1px) scale(1.02);
    box-shadow: 0 4px 14px rgba(167, 139, 250, 0.4);
    background-position: 100% 0;
}

.btn-secondary {
    background: rgba(var(--surface-rgb), 0.08);
    color: var(--text-primary);
    border: 1px solid rgba(var(--surface-rgb), 0.2) !important;
}

.btn-secondary:hover {
    background: rgba(var(--surface-rgb), 0.15);
}

.btn-small {
    padding: 0.4rem 0.75rem !important;
    font-size: 0.75rem !important;
}

.btn-hint {
    background: #facc15;
    color: #3a2e00;
}

.btn-hint:hover {
    transform: translateY(-1px);
    box-shadow: 0 4px 14px rgba(250, 204, 21, 0.35);
}

.btn-hint-locked {
    background: rgba(var(--surface-rgb), 0.08) !important;
    color: var(--text-secondary) !important;
    border: 1px dashed rgba(var(--surface-rgb), 0.25) !important;
    cursor: not-allowed;
}

.btn-hint-locked:hover {
    transform: none !important;
    box-shadow: none !important;
}

.btn-next {
    background: linear-gradient(90deg, #4ade80, #22d3ee);
    color: #0f0c29;
}

.btn-next:hover {
    transform: translateY(-1px);
    box-shadow: 0 4px 14px rgba(74, 222, 128, 0.35);
}

.task-navigation {
    display: flex;
    gap: 0.6rem;
    padding-top: 1rem;
    border-top: 1px solid rgba(var(--surface-rgb), 0.12);
}

/* ---------- Flash card quiz (Components/QuizView.razor) ---------- */

.quiz-stage {
    animation: task-fade-in 0.35s ease-out;
}

.quiz-header {
    text-align: center;
    margin-bottom: 1.25rem;
}

.quiz-badge {
    width: 3.25rem;
    height: 3.25rem;
    margin-bottom: 0.4rem;
    animation: badge-wiggle 3s ease-in-out infinite;
}

.quiz-header h2 {
    margin: 0 0 0.3rem 0;
    background: var(--gradient-hero);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
}

.quiz-header p {
    margin: 0;
    color: var(--text-secondary);
}

.quiz-progress {
    text-align: center;
    font-size: 0.8rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-secondary);
    opacity: 0.85;
    margin-bottom: 0.75rem;
}

.quiz-card {
    max-width: 32rem;
    margin: 0 auto;
    background: linear-gradient(155deg, rgba(56, 189, 248, 0.10), rgba(167, 139, 250, 0.08) 50%, rgba(244, 114, 182, 0.10));
    border: 1px solid rgba(var(--surface-rgb), 0.14);
    border-radius: 0.9rem;
    padding: 1.5rem;
    animation: task-fade-in 0.3s ease-out;
}

.quiz-prompt {
    font-size: 1.15rem;
    font-weight: 700;
    text-align: center;
    margin-bottom: 1.25rem;
    color: var(--text-primary);
}

.quiz-options {
    display: grid;
    gap: 0.6rem;
}

.quiz-option {
    text-align: left;
    padding: 0.75rem 1rem;
    border-radius: 0.6rem;
    border: 1px solid rgba(var(--surface-rgb), 0.18);
    background: rgba(var(--surface-rgb), 0.06);
    color: var(--text-primary);
    cursor: pointer;
    font-size: 0.92rem;
    font-weight: 600;
    transition: transform 0.15s ease, border-color 0.15s ease, background 0.15s ease;
}

.quiz-option:hover:not(:disabled) {
    border-color: var(--accent-violet);
    transform: translateY(-1px) scale(1.01);
    background: rgba(var(--surface-rgb), 0.1);
}

.quiz-option:disabled {
    cursor: default;
}

.quiz-option.correct {
    border-color: var(--accent-green);
    background: rgba(74, 222, 128, 0.18);
    animation: success-pop 0.3s ease;
}

.quiz-option.incorrect {
    border-color: var(--accent-pink);
    background: rgba(244, 63, 94, 0.18);
    animation: flashcard-shake 0.3s ease;
}

.quiz-next-btn {
    display: block;
    margin: 1.25rem auto 0 auto;
}

/* ---------- Swipe true/false format ---------- */

.swipe-deck {
    max-width: 26rem;
    margin: 0 auto;
    display: flex;
    flex-direction: column;
    align-items: center;
}

.swipe-card {
    position: relative;
    width: 100%;
    min-height: 12rem;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 1.75rem 1.5rem;
    box-sizing: border-box;
    background: linear-gradient(155deg, rgba(56, 189, 248, 0.12), rgba(167, 139, 250, 0.10) 50%, rgba(244, 114, 182, 0.12));
    border: 1px solid rgba(var(--surface-rgb), 0.16);
    border-radius: 1rem;
    box-shadow: 0 12px 30px rgba(0, 0, 0, 0.35);
    cursor: grab;
    touch-action: pan-y;
    user-select: none;
}

.swipe-card:active {
    cursor: grabbing;
}

.swipe-card.swipe-correct {
    border-color: var(--accent-green);
    box-shadow: 0 12px 30px rgba(74, 222, 128, 0.3);
}

.swipe-card.swipe-incorrect {
    border-color: var(--accent-pink);
    box-shadow: 0 12px 30px rgba(244, 63, 94, 0.3);
}

.swipe-hint {
    position: absolute;
    top: 1rem;
    font-size: 0.85rem;
    font-weight: 800;
    letter-spacing: 0.08em;
    padding: 0.3rem 0.7rem;
    border-radius: 0.4rem;
    border: 2px solid currentColor;
}

.swipe-hint-true {
    left: 1rem;
    color: var(--accent-green);
    transform: rotate(-8deg);
}

.swipe-hint-false {
    right: 1rem;
    color: var(--accent-pink);
    transform: rotate(8deg);
}

.swipe-buttons {
    display: flex;
    gap: 1rem;
    margin-top: 1.25rem;
    width: 100%;
}

.swipe-btn {
    flex: 1;
    padding: 0.75rem 1rem;
    border-radius: 0.6rem;
    border: 1px solid rgba(var(--surface-rgb), 0.18);
    font-size: 0.9rem;
    font-weight: 700;
    cursor: pointer;
    transition: transform 0.15s ease, box-shadow 0.15s ease;
}

.swipe-btn:disabled {
    opacity: 0.5;
    cursor: not-allowed;
}

.swipe-btn-true {
    background: rgba(74, 222, 128, 0.16);
    color: #86efac;
}

.swipe-btn-true:hover:not(:disabled) {
    transform: translateY(-1px);
    box-shadow: 0 4px 14px rgba(74, 222, 128, 0.3);
}

.swipe-btn-false {
    background: rgba(244, 63, 94, 0.14);
    color: #fca5a5;
}

.swipe-btn-false:hover:not(:disabled) {
    transform: translateY(-1px);
    box-shadow: 0 4px 14px rgba(244, 63, 94, 0.3);
}

.quiz-results {
    max-width: 26rem;
    margin: 2rem auto 0 auto;
    text-align: center;
    animation: success-pop 0.35s cubic-bezier(0.34, 1.56, 0.64, 1);
}

.quiz-results-icon {
    font-size: 3rem;
    margin-bottom: 0.5rem;
}

.quiz-results h3 {
    margin: 0 0 0.4rem 0;
    font-size: 1.35rem;
}

.quiz-results p {
    color: var(--text-secondary);
    margin: 0 0 1.25rem 0;
}

.quiz-results button {
    padding: 0.75rem 1.5rem;
}

/* ---------- Username prompt (Pages/Home.razor) ---------- */

.username-overlay {
    position: fixed;
    inset: 0;
    background: rgba(8, 5, 25, 0.72);
    backdrop-filter: blur(6px);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 2000;
    padding: 1.25rem;
    box-sizing: border-box;
    animation: task-fade-in 0.3s ease-out;
}

.username-modal {
    max-width: 24rem;
    width: 100%;
    padding: 2rem 1.75rem;
    text-align: center;
    background: linear-gradient(155deg, rgba(56, 189, 248, 0.14), rgba(167, 139, 250, 0.10) 50%, rgba(244, 114, 182, 0.14));
    box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5);
}

.username-badge {
    width: 3.5rem;
    height: 3.5rem;
    margin-bottom: 0.5rem;
    animation: badge-wiggle 3s ease-in-out infinite;
}

.username-modal h2 {
    margin: 0 0 0.35rem 0;
    background: var(--gradient-hero);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
}

.username-modal p {
    margin: 0 0 1.1rem 0;
    color: var(--text-secondary);
}

.username-input {
    width: 100%;
    box-sizing: border-box;
    padding: 0.7rem 0.9rem;
    border-radius: 0.6rem;
    border: 1px solid rgba(var(--surface-rgb), 0.2);
    background: var(--input-bg);
    color: var(--text-primary);
    font-size: 1rem;
    margin-bottom: 1rem;
}

.username-input:focus {
    outline: none;
    border-color: var(--accent-violet);
    box-shadow: 0 0 0 3px rgba(167, 139, 250, 0.25);
}

.username-actions .btn-primary {
    width: 100%;
    padding: 0.75rem 1.1rem;
}

/* Auth mode tabs (New student / Returning / Demo) + status notes inside the
   first-run and migration modals — reuses .btn-secondary/.stats-inline-note
   so the modal keeps its existing look. */
.username-actions.auth-tabs {
    display: flex;
    gap: 0.5rem;
    justify-content: center;
    margin-bottom: 1rem;
}

.username-modal .stats-inline-note {
    margin-top: 0.9rem;
}

.username-modal .username-actions + .username-actions {
    margin-top: 0.75rem;
}

/* Gamified celebration popups (achievement unlocked, level complete) — shown
   dead-center of the screen for a couple of seconds instead of a quiet corner
   toast, with a dimmed backdrop so they read as a "moment" rather than a
   notification. */
.achievement-stack {
    position: fixed;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.75rem;
    z-index: 1000;
    pointer-events: none;
    background: transparent;
    transition: background 0.2s ease;
}

.achievement-stack:has(.achievement-popup) {
    background: rgba(10, 8, 30, 0.45);
}

.celebration-popup {
    animation: celebration-pop 0.45s cubic-bezier(0.34, 1.56, 0.64, 1);
    text-align: center;
}

@keyframes celebration-pop {
    0% { opacity: 0; transform: scale(0.6); }
    60% { opacity: 1; transform: scale(1.08); }
    100% { opacity: 1; transform: scale(1); }
}

.achievement-popup {
    background: linear-gradient(135deg, #302b63, #24243e);
    border: 1px solid #c4b5fd;
    padding: 1.5rem 2rem;
    border-radius: 1rem;
    box-shadow: 0 12px 40px rgba(0, 0, 0, 0.55);
    min-width: 16rem;
    max-width: 22rem;
}

.achievement-icon {
    font-size: 2.75rem;
    margin-bottom: 0.5rem;
    animation: badge-wiggle 1.4s ease-in-out infinite;
}

.achievement-text {
    font-weight: 700;
    font-size: 1.1rem;
    color: #f0abfc;
    margin-bottom: 0.3rem;
}

.achievement-desc {
    font-size: 0.85rem;
    color: #cbd5f5;
    opacity: 0.9;
}

/* A bonus flourish layered on top of whatever celebration popup is showing,
   every 5th one that comes through the queue — cycles between a few plain
   CSS/emoji effects (no canvas, no external library) so it stays cheap and
   lightweight. Sits above both the achievement stack and the level/quest
   overlays (z-index 1000/1001) so it visibly accompanies that popup. */
.celebration-fx {
    position: fixed;
    inset: 0;
    z-index: 1002;
    pointer-events: none;
    overflow: hidden;
}

.fx-piece {
    position: absolute;
}

.celebration-fx-confetti .fx-piece {
    top: -12px;
    left: calc(var(--i) * 4.2%);
    width: 8px;
    height: 14px;
    background: hsl(calc(var(--i) * 53deg), 85%, 60%);
    animation: confetti-fall 1.8s cubic-bezier(0.25, 0.8, 0.4, 1) forwards;
    animation-delay: calc(var(--i) * 35ms);
}

@keyframes confetti-fall {
    0% { transform: translateY(0) rotate(0deg); opacity: 1; }
    100% { transform: translateY(100vh) rotate(540deg); opacity: 0; }
}

.celebration-fx-firework .fx-piece {
    top: 50%;
    left: 50%;
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: hsl(calc(var(--i) * 15deg), 90%, 65%);
    box-shadow: 0 0 6px hsl(calc(var(--i) * 15deg), 90%, 65%);
    animation: firework-burst 1.1s ease-out forwards;
}

@keyframes firework-burst {
    0% { transform: rotate(calc(var(--i) * 15deg)) translateX(0); opacity: 1; }
    100% { transform: rotate(calc(var(--i) * 15deg)) translateX(38vmin); opacity: 0; }
}

.celebration-fx-sparkle .fx-piece {
    left: calc(var(--i) * 4.1%);
    top: calc(12% + (var(--i) * 3.1%));
    font-size: 1.4rem;
    opacity: 0;
    animation: sparkle-pop 1.4s ease-in-out forwards;
    animation-delay: calc(var(--i) * 50ms);
}

.celebration-fx-sparkle .fx-piece::before {
    content: "✨";
}

@keyframes sparkle-pop {
    0% { opacity: 0; transform: scale(0.3); }
    50% { opacity: 1; transform: scale(1.15); }
    100% { opacity: 0; transform: scale(0.6); }
}

/* Level-complete overlay — bigger and celebratory, distinct from the smaller
   achievement popup, since finishing a whole level is a bigger deal. */
.celebration-overlay {
    position: fixed;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 1001;
    background: rgba(10, 8, 30, 0.55);
    pointer-events: none;
}

.level-complete-popup {
    background: linear-gradient(135deg, #4c1d95, #302b63 60%, #24243e);
    border: 1px solid #fbbf24;
    padding: 2.25rem 3rem;
    border-radius: 1.25rem;
    box-shadow: 0 16px 48px rgba(0, 0, 0, 0.6), 0 0 40px rgba(251, 191, 36, 0.25);
}

/* The biggest celebration in the game (finishing every level) — same family
   as .level-complete-popup but a notch grander, and pointer-events: auto so
   the certificate link inside is actually clickable through the otherwise
   click-through overlay. */
.quest-complete-popup {
    background: linear-gradient(135deg, #7c2d92, #4c1d95 45%, #1e1b3a);
    border: 1px solid #fde68a;
    padding: 2.5rem 3rem;
    border-radius: 1.5rem;
    box-shadow: 0 20px 60px rgba(0, 0, 0, 0.65), 0 0 60px rgba(253, 230, 138, 0.35);
    pointer-events: auto;
    max-width: 26rem;
}

.quest-complete-cta {
    display: inline-block;
    margin-top: 1.25rem;
}

.celebration-icon {
    width: 4rem;
    height: 4rem;
    margin-bottom: 0.75rem;
    animation: badge-wiggle 1.4s ease-in-out infinite;
}

.celebration-title {
    font-size: 1.6rem;
    font-weight: 800;
    color: #fde68a;
    letter-spacing: 0.02em;
}

.celebration-subtitle {
    margin-top: 0.35rem;
    font-size: 1rem;
    color: #e0e7ff;
    opacity: 0.9;
}

@media (max-width: 768px) {
    .game-body {
        grid-template-columns: 1fr;
    }

    /* On a narrow screen the level list and the active task/quiz can't sit
       side by side, so they stack — but stacking in DOM order put the level
       list FIRST, forcing a scroll past it on every single visit just to
       reach the task you're actually there for. Reorder visually (grid
       honors `order` the same as flexbox) so the task/quiz you're playing is
       immediately below the header, with the level list available by
       scrolling further down instead of blocking the way in. */
    .level-sidebar {
        order: 2;
    }

    .main-area {
        order: 1;
    }

    .code-section {
        grid-template-columns: 1fr;
    }

    .level-sidebar {
        max-height: 14rem;
    }

    .game-header {
        flex-direction: column;
        align-items: flex-start;
    }

    /* .game-header-stats has exactly 6 children in a fixed order — the 3
       stat blocks (Points/Tasks Done/Streak), then the 3 action controls
       (sound, theme, Stats link). A plain flex-wrap let them break wherever
       they happened to run out of room, landing 2-then-2-then-2 or similar —
       an uneven, "all over the place" look. A 3-column grid instead always
       breaks cleanly between the two groups: one tidy row of stats, one
       tidy row of actions underneath. */
    .game-header-stats {
        width: 100%;
        display: grid;
        grid-template-columns: repeat(3, 1fr);
        gap: 0.75rem;
        align-items: center;
        justify-items: center;
    }

    .achievement-popup,
    .level-complete-popup,
    .quest-complete-popup {
        min-width: 0;
        margin: 0 1rem;
        padding: 1.25rem 1.5rem;
    }
}

/* ---------- Stats link in header (Pages/Home.razor) ---------- */

.stats-link {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    align-self: center;
    text-decoration: none;
    white-space: nowrap;
}

.demo-mode-btn {
    align-self: center;
    white-space: nowrap;
    border-color: rgba(167, 139, 250, 0.5);
    color: var(--accent-amber-text, #c4b5fd);
}

.sound-toggle,
.theme-toggle {
    align-self: center;
    font-size: 1.1rem;
    line-height: 1;
    padding: 0.55rem 0.7rem;
}

.stats-header-toggles {
    position: absolute;
    right: 0;
    top: 0;
    display: flex;
    gap: 0.5rem;
}

/* Narrow phones: the Stats page header packs a "Back to Quest" link
   absolutely on the left and the sound/theme toggles absolutely on the
   right (see .stats-back / .stats-header-toggles above) — fine down to
   ~500px, but the two collide on a genuinely narrow phone. Below that,
   drop both out of absolute positioning so they stack as their own
   centered rows above the title instead of overlapping it. Must come
   after the base .stats-header-toggles rule above: same specificity, so
   source order decides, and this needs to win. */
@media (max-width: 420px) {
    .stats-back,
    .stats-header-toggles {
        position: static;
        display: flex;
        justify-content: center;
        margin: 0 0 0.6rem;
    }
}

/* ---------- Stats page (Pages/Stats.razor) ---------- */

.stats-loading {
    padding: 3rem;
    text-align: center;
    color: var(--text-secondary);
}

.stats-shell {
    max-width: 960px;
    margin: 0 auto;
    padding: 1.5rem;
    box-sizing: border-box;
}

.stats-header {
    text-align: center;
    margin-bottom: 1.75rem;
    position: relative;
}

.stats-header h1 {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.6rem;
    margin: 0.5rem 0 0.25rem;
}

.stats-header p {
    color: var(--text-secondary);
    margin: 0;
}

.stats-back {
    position: absolute;
    left: 0;
    top: 0;
    text-decoration: none;
}

.stats-summary-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
    gap: 0.9rem;
    margin-bottom: 1.75rem;
}

.stats-summary-grid-secondary {
    grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
}

.stats-card {
    background: rgba(var(--surface-rgb), 0.07);
    border: 1px solid rgba(var(--surface-rgb), 0.14);
    border-radius: 0.75rem;
    padding: 1.1rem 0.75rem;
    text-align: center;
}

.stats-card-icon {
    width: 1.8rem;
    height: 1.8rem;
    margin-bottom: 0.4rem;
}

.stats-card-value {
    font-size: 1.6rem;
    font-weight: 800;
    background: var(--gradient-stat);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
}

.stats-card-small .stats-card-value {
    font-size: 1.3rem;
}

.stats-card-label {
    font-size: 0.75rem;
    color: var(--text-secondary);
    margin-top: 0.2rem;
}

.stats-section {
    margin-bottom: 1.75rem;
}

.stats-section h2 {
    font-size: 1.05rem;
    margin-bottom: 0.75rem;
    color: var(--text-primary);
}

.stats-level-list {
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
}

.stats-level-row {
    background: rgba(var(--surface-rgb), 0.06);
    border: 1px solid rgba(var(--surface-rgb), 0.12);
    border-radius: 0.6rem;
    padding: 0.7rem 0.9rem;
}

.stats-level-row.current {
    background: rgba(167, 139, 250, 0.14);
    border-color: var(--accent-violet);
    box-shadow: 0 0 0 1px rgba(167, 139, 250, 0.25), 0 4px 16px rgba(122, 92, 255, 0.2);
}

.stats-level-expand-btn {
    margin-top: 0.85rem;
}

.stats-level-current-badge {
    margin-left: auto;
    font-size: 0.65rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: #fff;
    background: var(--accent-violet);
    padding: 0.2rem 0.5rem;
    border-radius: 999px;
}

.stats-level-name {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    font-weight: 600;
    font-size: 0.9rem;
    margin-bottom: 0.4rem;
}

.stats-level-bar-track {
    background: rgba(0, 0, 0, 0.35);
    border-radius: 999px;
    height: 0.5rem;
    overflow: hidden;
}

.stats-level-bar-fill {
    height: 100%;
    background: linear-gradient(90deg, var(--accent-violet), var(--accent-pink));
    border-radius: 999px;
    transition: width 0.4s ease;
}

.stats-level-numbers {
    font-size: 0.75rem;
    color: var(--text-secondary);
    margin-top: 0.35rem;
}

.stats-achievement-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
    gap: 0.75rem;
}

.stats-achievement {
    border-radius: 0.6rem;
    padding: 0.85rem 0.7rem;
    text-align: center;
    border: 1px solid rgba(var(--surface-rgb), 0.12);
}

.stats-achievement.unlocked {
    background: rgba(167, 139, 250, 0.18);
    border-color: rgba(167, 139, 250, 0.4);
}

.stats-achievement.unlocked.recent {
    animation: achievement-glow-pulse 1.4s ease-out;
}

@keyframes achievement-glow-pulse {
    0% { box-shadow: 0 0 0 6px rgba(167, 139, 250, 0.45); }
    100% { box-shadow: 0 0 0 0 rgba(167, 139, 250, 0); }
}

.stats-achievement.locked {
    background: rgba(var(--surface-rgb), 0.03);
    opacity: 0.45;
    filter: grayscale(1);
}

.stats-achievement-icon {
    font-size: 1.6rem;
    margin-bottom: 0.3rem;
}

.stats-achievement-title {
    font-weight: 700;
    font-size: 0.85rem;
    margin-bottom: 0.2rem;
}

.stats-achievement-desc {
    font-size: 0.72rem;
    color: var(--text-secondary);
}

.stats-section-hint {
    font-size: 0.82rem;
    color: var(--text-secondary);
    margin-bottom: 0.9rem;
}

.stats-backup-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
    gap: 0.9rem;
}

.stats-backup-card {
    background: rgba(var(--surface-rgb), 0.06);
    border: 1px solid rgba(var(--surface-rgb), 0.12);
    border-radius: 0.7rem;
    padding: 1rem;
}

.stats-backup-card h3 {
    margin: 0 0 0.35rem;
    font-size: 0.95rem;
}

.stats-backup-card p {
    font-size: 0.78rem;
    color: var(--text-secondary);
    margin: 0 0 0.7rem;
}

.stats-backup-card-danger {
    border-color: rgba(248, 113, 113, 0.35);
}

.stats-reset-confirm-actions {
    display: flex;
    gap: 0.6rem;
    margin-top: 0.5rem;
}

.stats-token-box {
    width: 100%;
    box-sizing: border-box;
    min-height: 4.5rem;
    resize: vertical;
    background: var(--input-bg);
    color: var(--text-primary);
    border: 1px solid rgba(var(--surface-rgb), 0.15);
    border-radius: 0.4rem;
    padding: 0.6rem;
    font-family: "SF Mono", Menlo, Consolas, monospace;
    font-size: 0.72rem;
    word-break: break-all;
    margin-top: 0.5rem;
    cursor: pointer;
}

.stats-token-input {
    cursor: text;
}

.stats-username-confirm {
    width: 100%;
    box-sizing: border-box;
    margin: 0.6rem 0;
}

.stats-inline-note {
    font-size: 0.78rem;
    color: var(--text-secondary);
    margin-top: 0.5rem;
}

.stats-inline-note.success {
    color: var(--accent-green);
}

.stats-inline-note.error {
    color: #f87171;
}

@media (max-width: 640px) {
    .stats-back {
        position: static;
        display: inline-block;
        margin-bottom: 0.75rem;
    }
}

/* ============================================================
   Certificate (Pages/Certificate.razor)
   ============================================================ */

.cert-shell {
    max-width: 900px;
    margin: 0 auto;
    padding: 1.5rem 1.25rem 3rem;
    box-sizing: border-box;
}

.cert-pending {
    text-align: center;
    padding: 2.5rem 1.5rem;
}

.cert-pending h1 {
    margin: 0.75rem 0 0.5rem;
    font-size: 1.4rem;
}

.cert-pending p {
    color: var(--text-secondary);
    max-width: 32rem;
    margin: 0 auto 1.25rem;
}

.cert-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.6rem;
    justify-content: center;
    margin-bottom: 1.25rem;
}

.cert-card {
    background: rgba(var(--surface-rgb), 0.06);
    border-radius: 1.25rem;
    padding: 0.6rem;
    box-shadow: 0 20px 60px rgba(0, 0, 0, 0.35);
}

.cert-card-celebrate {
    animation: celebration-pop 0.6s cubic-bezier(0.34, 1.56, 0.64, 1);
}

.cert-border {
    border: 2px solid var(--accent-amber-text);
    outline: 1px solid rgba(var(--surface-rgb), 0.25);
    outline-offset: -8px;
    border-radius: 0.9rem;
    padding: 2.5rem 2rem;
    text-align: center;
    background: linear-gradient(160deg, rgba(250, 204, 21, 0.08), transparent 55%),
        rgba(var(--surface-rgb), 0.04);
}

.cert-badge {
    width: 3.5rem;
    height: 3.5rem;
    margin-bottom: 0.5rem;
}

.cert-kicker {
    text-transform: uppercase;
    letter-spacing: 0.14em;
    font-size: 0.75rem;
    color: var(--accent-amber-text);
    font-weight: 700;
}

.cert-title {
    margin: 0.4rem 0 0.1rem;
    font-size: 2.1rem;
    font-weight: 800;
    background: var(--gradient-title);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
}

.cert-subtitle {
    color: var(--text-secondary);
    margin-bottom: 1.5rem;
    font-size: 0.95rem;
}

.cert-presented {
    color: var(--text-secondary);
    font-size: 0.92rem;
    max-width: 34rem;
    margin: 0 auto;
}

.cert-name {
    font-size: 1.8rem;
    font-weight: 800;
    margin: 0.5rem 0;
    color: var(--text-primary);
}

.cert-stats-row {
    display: flex;
    justify-content: center;
    gap: 2rem;
    flex-wrap: wrap;
    margin: 1.75rem 0;
    padding: 1rem 0;
    border-top: 1px solid rgba(var(--surface-rgb), 0.14);
    border-bottom: 1px solid rgba(var(--surface-rgb), 0.14);
}

.cert-stat-value {
    font-size: 1.4rem;
    font-weight: 800;
    color: var(--accent-amber-text);
}

.cert-stat-label {
    font-size: 0.72rem;
    color: var(--text-secondary);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    margin-top: 0.15rem;
}

.cert-footer {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-top: 1rem;
    color: var(--text-secondary);
    font-size: 0.82rem;
}

@media (max-width: 640px) {
    .cert-border {
        padding: 1.75rem 1.25rem;
    }

    .cert-title {
        font-size: 1.6rem;
    }

    .cert-name {
        font-size: 1.4rem;
    }

    .cert-stats-row {
        gap: 1.25rem;
    }

    .cert-footer {
        flex-direction: column;
        gap: 0.35rem;
        text-align: center;
    }
}

/* Printing/exporting the certificate as a PDF: hide everything except the
   certificate card itself, and drop the dark app chrome in favor of plain
   white so it prints/saves cleanly regardless of the player's theme. */
@media print {
    body * {
        visibility: hidden;
    }

    .cert-card,
    .cert-card * {
        visibility: visible;
    }

    .no-print {
        display: none !important;
    }

    .cert-card {
        position: absolute;
        top: 0;
        left: 0;
        width: 100%;
        margin: 0;
        box-shadow: none;
        background: #fff;
    }

    .cert-border {
        background: #fff;
    }
}

/* Skip power-up: the wallet stat pulses whenever the balance changes (the
   markup re-keys on SkipsAvailable so this animation replays per spend or
   refill), the Skip button reads as a deliberate power-up move rather than a
   quiet link, and every skip/streak-refill fires a bold toast plus a burst of
   ⏭ pieces flying across the screen — same cheap pure-CSS pattern as the
   celebration-fx bursts. */
.skip-balance {
    display: inline-block;
    animation: skip-balance-pop 0.5s cubic-bezier(0.34, 1.56, 0.64, 1);
}

@keyframes skip-balance-pop {
    0% { transform: scale(0.5); }
    60% { transform: scale(1.25); }
    100% { transform: scale(1); }
}

.btn-skip {
    background: linear-gradient(135deg, #7c3aed, #4f46e5);
    border: 1px solid #a78bfa;
    color: #fff;
    font-weight: 700;
    padding: 0.6rem 1.1rem;
    border-radius: 0.6rem;
    cursor: pointer;
    transition: transform 0.12s ease, box-shadow 0.12s ease, filter 0.12s ease;
    box-shadow: 0 4px 18px rgba(124, 58, 237, 0.45);
}

.btn-skip:hover:not(:disabled) {
    transform: translateY(-1px) scale(1.03);
    filter: brightness(1.1);
    box-shadow: 0 6px 24px rgba(124, 58, 237, 0.6);
}

.btn-skip:disabled {
    cursor: not-allowed;
}

.btn-skip-locked {
    background: linear-gradient(135deg, #3f3f5a, #2c2c44);
    border-color: #55556e;
    color: #a5a5c0;
    box-shadow: none;
}

.skip-limit-note {
    margin-top: 0.5rem;
    font-size: 0.85rem;
    color: #fbbf24;
    opacity: 0.95;
}

.task-skipped-badge {
    background: rgba(124, 58, 237, 0.2);
    border: 1px solid #a78bfa;
    color: #d8b4fe;
    font-size: 0.78rem;
    font-weight: 700;
    padding: 0.15rem 0.55rem;
    border-radius: 999px;
    white-space: nowrap;
}

.skip-toast {
    position: fixed;
    top: 4.5rem;
    left: 50%;
    transform: translateX(-50%);
    z-index: 1003;
    background: linear-gradient(135deg, #7c3aed, #4f46e5);
    border: 1px solid #c4b5fd;
    color: #fff;
    font-weight: 800;
    font-size: 1.05rem;
    padding: 0.8rem 1.6rem;
    border-radius: 1rem;
    box-shadow: 0 12px 40px rgba(124, 58, 237, 0.55);
    animation: skip-toast-in 2.6s ease forwards;
    pointer-events: none;
    text-align: center;
    max-width: min(90vw, 32rem);
}

@keyframes skip-toast-in {
    0% { opacity: 0; transform: translateX(-50%) translateY(-1.2rem) scale(0.8); }
    12% { opacity: 1; transform: translateX(-50%) translateY(0) scale(1.05); }
    20% { transform: translateX(-50%) translateY(0) scale(1); }
    82% { opacity: 1; transform: translateX(-50%) translateY(0) scale(1); }
    100% { opacity: 0; transform: translateX(-50%) translateY(-0.8rem) scale(0.95); }
}

.skip-fx {
    position: fixed;
    inset: 0;
    z-index: 1002;
    pointer-events: none;
    overflow: hidden;
}

.skip-fx-piece {
    position: absolute;
    top: 4.5rem;
    left: 50%;
    font-size: 1.5rem;
    opacity: 0;
    animation: skip-fly 1.6s ease-out forwards;
    animation-delay: calc(var(--i) * 60ms);
}

@keyframes skip-fly {
    0% { opacity: 0; transform: translate(0, 0) scale(0.5) rotate(0deg); }
    15% { opacity: 1; }
    100% {
        opacity: 0;
        transform: translate(calc((var(--i) - 7) * 7vmin), 46vh) scale(1.2) rotate(calc((var(--i) - 7) * 24deg));
    }
}