/*
 * study.css — study session UI + reward layer.
 *
 * Sections:
 *   - Card List (deck detail page)
 *   - Study Session (study card, answer input, progress HUD)
 *   - Decomposition (Break-it-Down stepper, depth indicator)
 *   - Reward Effects (XP orb, streak, criticals)
 *   - Next-unlock card (concept side rail)
 *   - Card Cascade (concept-unlock card reveal)
 *   - Cinematic engine (locked → unlocked transitions)
 */

/* ==========================================================
   Card List (deck detail)
   ========================================================== */

.card-list {
    display: flex;
    flex-direction: column;
    gap: .5rem;
}

/* --- Card row (deck detail — stacked Q/A layout) --- */

.card-row-detail {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: .85rem 1rem;
}

.card-row-q {
    display: flex;
    gap: .6rem;
    align-items: baseline;
    margin-bottom: .4rem;
}
.card-num {
    font-size: .75rem;
    font-weight: 700;
    color: var(--text-muted);
    flex-shrink: 0;
    min-width: 1.2rem;
}
.card-q-text {
    flex: 1;
    min-width: 0;
}
.card-q-text .katex { white-space: normal; }

.card-row-a {
    display: flex;
    align-items: center;
    gap: .5rem;
    padding-left: 1.8rem;
}
.card-a-label {
    font-size: .75rem;
    font-weight: 600;
    color: var(--text-muted);
    flex-shrink: 0;
}
.card-a-text {
    flex: 1;
    min-width: 0;
}
.card-a-text .katex { white-space: normal; }

.card-row-detail .card-delete-form { margin-left: auto; flex-shrink: 0; }
.card-row-detail .btn-icon { opacity: 0; transition: opacity var(--transition); }
.card-row-detail:hover .btn-icon { opacity: 1; }

.card-delete-form { flex-shrink: 0; }
.btn-icon {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    border: none;
    background: none;
    color: var(--text-muted);
    border-radius: 6px;
    cursor: pointer;
    transition: all var(--transition);
}
.btn-icon:hover { background: #fef2f2; color: var(--red); }

/* --- Deck manager --- */

.deck-rename-form {
    display: flex;
    align-items: center;
    gap: .5rem;
}
.input-rename {
    font-size: 1.25rem;
    font-weight: 700;
    font-family: inherit;
    color: var(--text);
    border: none;
    border-bottom: 1.5px solid transparent;
    border-radius: 0;
    padding: .15rem 0;
    background: transparent;
    outline: none;
    transition: border-color 200ms ease;
    cursor: text;
}
.input-rename:hover {
    border-bottom-color: var(--border);
}
.input-rename:focus {
    border-bottom-color: var(--primary);
}

.danger-zone {
    margin-top: 3rem;
    padding-top: 1.5rem;
    border-top: 1px solid var(--border);
}
.btn-danger {
    background: transparent;
    color: var(--red);
    border: 1.5px solid var(--red);
    font-size: .82rem;
    padding: .45rem .9rem;
    font-weight: 600;
    font-family: inherit;
    border-radius: 8px;
    cursor: pointer;
    transition: all var(--transition);
}
.btn-danger:hover { background: #fef2f2; }

/* Settings pages */
.settings-section {
    margin-bottom: 2rem;
}

.settings-label {
    font-size: .85rem;
    font-weight: 600;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: .04em;
    margin-bottom: .5rem;
}

.settings-row {
    display: flex;
    gap: .5rem;
    align-items: center;
}

/* Save button morphs into a checkmark on success — width is locked
   so neighbouring inputs don't shift. */
.rename-save-btn {
    min-width: 84px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: background .3s ease, color .3s ease;
}
.rename-save-btn-success {
    background: var(--green) !important;
    color: #fff !important;
    border-color: var(--green) !important;
}
.rename-save-btn-success:disabled {
    opacity: 1 !important;
    cursor: default;
}
.rename-save-check { flex-shrink: 0; }

.settings-hint {
    font-size: .82rem;
    color: var(--text-muted);
    margin-bottom: .75rem;
}

.settings-danger {
    margin-top: 3rem;
    padding-top: 1.5rem;
    border-top: 1px solid var(--border);
}


/* ==========================================================
   Study Session
   ========================================================== */

/* Two-column layout: study area + knowledge map sidebar */
.study-layout {
    display: flex;
    gap: 0;
    align-items: stretch;
    flex: 1;
    height: 100vh;
    margin: 0;
    padding: 0;
    overflow: hidden;
}

.study {
    width: 100%;
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    padding: .5rem 8rem 0 8rem;
    overflow: hidden;
    /* Smoothly reflow when the concepts rail opens/closes (see below). */
    transition: padding .4s cubic-bezier(.22, 1, .36, 1);
}
@media (max-width: 720px) {
    .study { padding: 4rem 1rem 0 1rem; }
}

/* Concepts rail open: reserve its width on the right so the panel sits
   BESIDE the card instead of floating over it. The card shifts left into
   the spare gutter (less left padding), which also keeps the deck-info
   hamburger toggle uncovered and easy to find. Mobile (<=720px) hides the
   panel entirely, so this only applies on wider viewports. --rail-w mirrors
   the rail's own width at each breakpoint. */
html { --rail-w: 280px; }
@media (max-width: 1100px) { html { --rail-w: 220px; } }
@media (min-width: 721px) {
    html:not(.study-rail-hidden) .study {
        padding-left: 3rem;
        padding-right: calc(var(--rail-w) + 2.5rem);
    }
}

/* Concepts rail hidden: slide off-canvas to the right. Main column
   keeps its padding so the card stays anchored — no reflow, no squish.
   Pointer-events killed when hidden so nothing in the off-canvas rail
   (e.g. tutor-chat FAB) intercepts clicks. */
html.study-rail-hidden .study-side-rail {
    transform: translateX(calc(100% + 2rem));
    opacity: 0;
    pointer-events: none;
}

.study-progress {
    text-align: center;
    font-size: .82rem;
    color: var(--text-muted);
    margin-bottom: .5rem;
}

.study-score {
    display: flex;
    justify-content: center;
    gap: 1rem;
    font-size: .82rem;
    font-weight: 600;
    margin-bottom: 1rem;
}
.score-correct { color: var(--green); }
.score-wrong { color: var(--red); }
.score-remaining { color: var(--text-muted); }

.done-stats {
    display: flex;
    justify-content: center;
    gap: 1.5rem;
    font-size: 1rem;
    font-weight: 600;
    margin-top: .75rem;
}

.done-folder-mastery {
    margin-top: 1.25rem;
    padding: .85rem 1.25rem;
    background: rgba(224, 100, 73, .04);
    border-radius: 10px;
    text-align: center;
    font-size: .88rem;
    color: var(--text);
}

.done-folder-pct {
    font-weight: 800;
    color: var(--primary);
}

.done-folder-bar {
    height: 6px;
    background: var(--border);
    border-radius: 999px;
    overflow: hidden;
    margin-top: .6rem;
}

.done-folder-bar-fill {
    height: 100%;
    border-radius: 999px;
    background: linear-gradient(90deg, var(--primary), var(--green));
}

.done-folder-hint {
    font-size: .8rem;
    color: var(--text-muted);
    margin: .5rem 0 0;
}

.near-miss {
    margin-top: .75rem;
    font-size: .9rem;
    font-weight: 600;
    color: #f59e0b;
    text-align: center;
}
.near-miss.perfect { color: var(--green); }

.study-card {
    position: relative;
    background: var(--surface);
    border: 1.5px solid var(--border);
    border-radius: 20px;
    /* Sized to read as the same visual family as the 1160px folder
       page — 900px is enough wider than the old 720 cap to bridge
       the spacing gap, while still keeping the inner 540px input
       column visually anchored. */
    width: 100%;
    max-width: 900px;
    /* Snug under the deck-info-card above — small breathing margin,
       not the big optical-center push that left a vacuum strip. */
    margin: .35rem auto .25rem;
    overflow: visible;
    /* No flex:1 — card sizes to its content + padding, doesn't inflate
       to fill remaining viewport height. */
    flex: 0 0 auto;
    display: flex;
    flex-direction: column;
    /* Top-align content so the question stays at a stable position card-to-card.
       Centering would slide everything upward whenever the post-answer rating /
       Break it Down / diff panel appears, which reads as a discontinuous jump
       between consecutive cards. */
    justify-content: flex-start;
    padding: 2.5rem 2.5rem 2.25rem;
    box-shadow:
        0 1px 3px rgba(15, 23, 42, .04),
        0 12px 32px rgba(15, 23, 42, .05);
}
@media (max-width: 720px) {
    .study-card {
        margin: clamp(1rem, 6vh, 3rem) auto .25rem;
        padding: 1.75rem 1.25rem 1.5rem;
        border-radius: 16px;
    }
}

/* Wrong answer action buttons — right-aligned column so the eye lands
   on the next action after reading the diff above. The buttons cap
   their width so they don't span the whole card on large screens. */
.wrong-actions {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: .4rem;
    padding: .5rem 1.25rem 1rem;
}

.wrong-action-primary {
    display: flex;
    align-items: center;
    justify-content: center;
    width: auto;
    min-width: 260px;
    padding: .75rem 1.25rem;
    background: var(--primary);
    color: #fff;
    border: none;
    border-radius: 12px;
    cursor: pointer;
    font-family: inherit;
    transition: background .15s ease;
}

.wrong-action-primary:hover { background: var(--primary-hover); }

.wrong-action-content {
    display: flex;
    align-items: center;
    gap: .6rem;
}

.wrong-action-content svg { flex-shrink: 0; }

.wrong-action-label {
    display: block;
    font-size: .92rem;
    font-weight: 700;
}

.wrong-action-desc {
    display: block;
    font-size: .72rem;
    opacity: .75;
    margin-top: .1rem;
}

.wrong-action-row {
    display: flex;
    justify-content: flex-end;
    gap: .5rem;
    width: 100%;
}

.wrong-action-secondary {
    min-width: 260px;
    display: flex;
    align-items: center;
    gap: .5rem;
    padding: .5rem .85rem;
    border: 1.5px solid var(--border);
    border-radius: 10px;
    background: transparent;
    font-family: inherit;
    cursor: pointer;
    color: var(--text-muted);
    text-align: left;
    transition: border-color .15s ease, color .15s ease, background .15s ease;
}

.wrong-action-secondary svg { flex-shrink: 0; }

.wrong-action-label-sm {
    display: block;
    font-size: .82rem;
    font-weight: 600;
}

.wrong-action-desc-sm {
    display: block;
    font-size: .65rem;
    opacity: .7;
}

.wrong-action-next:hover {
    border-color: var(--green);
    color: var(--green);
}

/* Break it Down transition overlay */
.breakdown-overlay {
    position: fixed;
    inset: 0;
    background:
        radial-gradient(circle, rgba(30, 64, 232, .10) 1px, transparent 1.4px) 0 0 / 24px 24px,
        rgba(245, 246, 250, .92);
    backdrop-filter: blur(12px);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 1.25rem;
    z-index: var(--z-hype);
    pointer-events: none;
    overflow: hidden;
}

/* Slow center "spotlight" — fills the empty viewport with depth. */
.breakdown-bg-pulse {
    position: absolute;
    inset: 0;
    background: radial-gradient(circle at center, rgba(30, 64, 232, .10), transparent 45%);
    opacity: .6;
    animation: breakdownBgPulse 4s ease-in-out infinite alternate;
    pointer-events: none;
}

@keyframes breakdownBgPulse {
    0%   { opacity: .55; transform: scale(1); }
    100% { opacity: 1;   transform: scale(1.05); }
}

.breakdown-ripple-container {
    position: relative;
    width: 220px;
    height: 220px;
    display: flex;
    align-items: center;
    justify-content: center;
}

/* Soft halo behind the magnifier — pulses counter-phase to iconPulse. */
.breakdown-icon-glow {
    position: absolute;
    width: 240px;
    height: 240px;
    border-radius: 50%;
    background: radial-gradient(circle at center, rgba(30, 64, 232, .22), transparent 55%);
    z-index: 0;
    animation: iconGlowPulse 1.4s ease-in-out infinite alternate;
}

@keyframes iconGlowPulse {
    0%   { transform: scale(0.95); opacity: .7; }
    100% { transform: scale(1.05); opacity: 1; }
}

.breakdown-ripple {
    position: absolute;
    border-radius: 50%;
    border: 2px solid var(--primary);
    opacity: 0;
    animation: rippleOut 1.8s ease-out infinite;
}

.breakdown-ripple.r1 { width: 60px; height: 60px; animation-delay: 0s; }
.breakdown-ripple.r2 { width: 60px; height: 60px; animation-delay: 0.4s; }
.breakdown-ripple.r3 { width: 60px; height: 60px; animation-delay: 0.8s; }
.breakdown-ripple.r4 { width: 60px; height: 60px; animation-delay: 1.2s; }

@keyframes rippleOut {
    0% { width: 60px; height: 60px; opacity: .6; }
    100% { width: 220px; height: 220px; opacity: 0; }
}

.breakdown-icon {
    position: relative;
    z-index: 1;
    color: var(--primary);
    animation: iconPulse 1s ease-in-out infinite alternate;
}

@keyframes iconPulse {
    0% { transform: scale(1); }
    100% { transform: scale(1.1); }
}

.breakdown-overlay-text {
    font-size: 1.4rem;
    font-weight: 700;
    color: var(--primary);
    text-align: center;
    animation: textFadeIn 0.5s ease 0.3s both;
}

/* Status pill — cycles through "Reading what you said" → "Finding the
   building blocks" → "Sketching out the steps" while Claude warms up. */
.breakdown-status-pill {
    display: inline-flex;
    align-items: center;
    gap: .55rem;
    padding: .5rem 1rem;
    border-radius: 999px;
    background: rgba(30, 64, 232, .08);
    border: 1px solid rgba(30, 64, 232, .20);
    color: var(--primary);
    font-size: .85rem;
    font-weight: 600;
    line-height: 1;
    animation: textFadeIn 0.5s ease 0.55s both;
}

.breakdown-status-pill-icon {
    display: inline-flex;
    width: 14px;
    height: 14px;
    color: var(--primary);
}

.breakdown-status-pill-icon svg {
    width: 14px;
    height: 14px;
}

.breakdown-status-pill-label {
    white-space: nowrap;
}

.breakdown-overlay-focus {
    margin-top: .15rem;
    max-width: min(560px, 80vw);
    font-size: .85rem;
    font-weight: 500;
    color: var(--text-muted);
    text-align: center;
    line-height: 1.4;
    animation: textFadeIn 0.5s ease 0.7s both;
}
.breakdown-focus-echo {
    color: var(--primary);
    font-weight: 600;
    font-style: italic;
}

@keyframes textFadeIn {
    from { opacity: 0; transform: translateY(10px); }
    to { opacity: 1; transform: translateY(0); }
}

/* Highlight-to-focus affordance: when the student has selected text inside
   the question, the Break it Down buttons shift to primary color to signal
   "I saw that — I'll focus on it." */
.btn-prebreak.is-focused {
    border-color: var(--primary);
    color: var(--primary);
    background: rgba(30, 64, 232, .06);
    box-shadow: 0 0 0 3px rgba(30, 64, 232, .12);
}
.wrong-action-primary.is-focused {
    box-shadow: 0 0 0 3px rgba(255, 255, 255, .25), 0 0 0 6px rgba(30, 64, 232, .25);
}

/* Gentle selection style inside questions — makes highlight-to-focus feel
   intentional rather than accidental. */
#study-question ::selection,
#study-question::selection {
    background: rgba(30, 64, 232, .18);
    color: inherit;
}

/* Focus-context panel — shown only when the student has selected text in
   the question. A floating "dock" at the bottom of the viewport, overlaying
   the math keyboard region so it doesn't shift existing layout. Slides up
   on appearance, down on hide. */
.focus-context-panel {
    position: fixed;
    left: 50%;
    bottom: 1.25rem;
    transform: translateX(-50%) translateY(18px);
    width: min(760px, calc(100vw - 2rem));
    margin: 0;
    padding: 1.1rem 1.25rem;
    border-radius: 16px;
    background: #fff;
    border: 1px solid rgba(30, 64, 232, .28);
    box-shadow:
        0 12px 32px rgba(30, 64, 232, .14),
        0 4px 10px rgba(0, 0, 0, .06);
    opacity: 0;
    pointer-events: none;
    z-index: 1200;
    transition: opacity .22s ease, transform .22s cubic-bezier(.2,.7,.2,1);
    display: flex;
    flex-direction: column;
    gap: .55rem;
}
.focus-context-panel.is-visible {
    opacity: 1;
    transform: translateX(-50%) translateY(0);
    pointer-events: auto;
}
.focus-context-input {
    width: 100%;
    min-height: 5.2rem;
    border: none;
    background: transparent;
    resize: none;
    outline: none;
    font-family: inherit;
    font-size: 1rem;
    color: var(--text);
    line-height: 1.55;
    padding: 0;
}
.focus-context-input::placeholder {
    color: var(--text-muted);
    font-style: italic;
}
.focus-context-panel:focus-within {
    border-color: rgba(30, 64, 232, .55);
    box-shadow:
        0 12px 32px rgba(30, 64, 232, .22),
        0 4px 10px rgba(0, 0, 0, .08),
        0 0 0 3px rgba(30, 64, 232, .1);
}

/* Inline "Break it down" submit — anchored bottom-right so the mouse
   doesn't have to travel to the action bar to trigger a breakdown. */
.focus-context-actions {
    display: flex;
    justify-content: flex-end;
}
.focus-context-submit {
    display: inline-flex;
    align-items: center;
    gap: .4rem;
    padding: .5rem 1rem;
    border: none;
    border-radius: 999px;
    background: var(--primary);
    color: #fff;
    font-family: inherit;
    font-size: .82rem;
    font-weight: 600;
    letter-spacing: -.003em;
    white-space: nowrap;
    cursor: pointer;
    transition: transform var(--transition), filter var(--transition), box-shadow var(--transition);
    box-shadow: 0 2px 8px rgba(30, 64, 232, .26);
}
.focus-context-submit:hover {
    transform: translateY(-1px);
    filter: brightness(1.06);
    box-shadow: 0 4px 14px rgba(30, 64, 232, .34);
}
.focus-context-submit:active { transform: translateY(0); }
.focus-context-submit svg { transition: transform var(--transition); }
.focus-context-submit:hover svg { transform: translateX(2px); }

@media (max-width: 600px) {
    .focus-context-panel {
        bottom: .75rem;
        width: calc(100vw - 1.25rem);
        padding: .9rem 1rem;
        border-radius: 14px;
    }
    .focus-context-input {
        font-size: .95rem;
        min-height: 4.2rem;
    }
    .focus-context-submit {
        padding: .45rem .85rem;
        font-size: .8rem;
    }
}

.correct-actions {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 1.25rem;
    width: 100%;
    padding: .5rem 1.25rem 1rem;
}

.correct-actions-buttons {
    display: inline-flex;
    align-items: center;
    gap: .5rem;
}

.btn-next-correct {
    display: inline-flex;
    align-items: center;
    gap: .4rem;
    padding: .55rem 1.3rem;
    background: var(--green);
    color: #fff;
    font-size: .88rem;
    font-weight: 600;
    font-family: inherit;
    border: none;
    border-radius: 999px;
    cursor: pointer;
    transition: background .15s ease;
}

.btn-next-correct:hover { background: #0A6B4D; }

.breakdown-link {
    display: inline-flex;
    align-items: center;
    gap: .3rem;
    background: none;
    border: none;
    color: var(--text-muted);
    font-size: .78rem;
    font-weight: 500;
    font-family: inherit;
    cursor: pointer;
    padding: .3rem 0;
    transition: color .15s ease;
}

.breakdown-link:hover { color: var(--primary); }

/* Gentle fade-in for elements that appear after the user answers a card.
   Browsers re-trigger CSS animations whenever an element transitions from
   `display: none` back into the render tree, so toggling display='' is
   enough — no JS needed to add/remove a class. */
@keyframes study-fade-in {
    from { opacity: 0; transform: translateY(6px); }
    to   { opacity: 1; transform: translateY(0);    }
}
.sr-rating,
#study-diff,
#match-banner,
#correct-actions,
#wrong-actions {
    animation: study-fade-in .22s cubic-bezier(.22, 1, .36, 1);
}

/* --- Spaced Repetition (within-session re-queue) --- */

.deck-info-card:has(.sr-toggle-switch) .deck-info-name,
.deck-info-card:has(.sr-toggle-switch) .deck-info-counter {
    padding-right: 9.5rem;
}

/* iOS-style toggle switch (label + sliding pill) */
.sr-toggle-switch {
    position: absolute;
    top: 50%;
    right: 1rem;
    transform: translateY(-50%);
    display: inline-flex;
    align-items: center;
    gap: .6rem;
    padding: 0;
    background: none;
    border: none;
    cursor: pointer;
    font-family: inherit;
    font-size: .76rem;
    font-weight: 600;
    color: var(--text-muted);
    letter-spacing: .01em;
    transition: color .15s ease;
    -webkit-tap-highlight-color: transparent;
}
.sr-toggle-switch:hover { color: var(--text); }
.sr-toggle-switch[aria-checked="true"] { color: var(--text); }

.sr-toggle-track {
    position: relative;
    display: inline-block;
    width: 32px;
    height: 18px;
    background: #d1d5db;
    border-radius: 999px;
    transition: background .2s ease;
}
.sr-toggle-thumb {
    position: absolute;
    top: 2px;
    left: 2px;
    width: 14px;
    height: 14px;
    background: #fff;
    border-radius: 50%;
    box-shadow: 0 1px 2px rgba(0,0,0,.18), 0 1px 3px rgba(0,0,0,.06);
    transition: transform .22s cubic-bezier(.22, 1, .36, 1);
}
.sr-toggle-switch[aria-checked="true"] .sr-toggle-track { background: var(--primary); }
.sr-toggle-switch[aria-checked="true"] .sr-toggle-thumb { transform: translateX(14px); }
.sr-toggle-switch:focus-visible { outline: none; }
.sr-toggle-switch:focus-visible .sr-toggle-track {
    box-shadow: 0 0 0 3px rgba(30, 64, 232, .25);
}

/* Rating panel — 4-button grid + integrated Break it Down */
.sr-rating {
    width: 100%;
    padding: .25rem 1.25rem 1rem;
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: .65rem;
}
.sr-rating-grid {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: .55rem;
}

.sr-btn {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: .15rem;
    padding: .6rem .75rem;
    background: var(--surface);
    border: 1.5px solid var(--border);
    border-radius: 12px;
    color: var(--text);
    font-family: inherit;
    cursor: pointer;
    transition: border-color .15s ease, background .15s ease, transform .08s ease;
}
.sr-btn:hover { transform: translateY(-1px); }
.sr-btn:active { transform: translateY(1px); }
.sr-btn-label { font-size: .92rem; font-weight: 600; }
.sr-btn-hint  { font-size: .72rem; color: var(--text-muted); font-weight: 500; }

/* Color-coded variants — apple-pastel feel, kachieve palette */
.sr-btn-soon  { background: #fef2f2; border-color: #fecaca; }
.sr-btn-soon:hover  { background: #fee2e2; border-color: #f87171; }
.sr-btn-soon  .sr-btn-label { color: #dc2626; }
.sr-btn-soon  .sr-btn-hint  { color: #ef4444; opacity: .75; }

.sr-btn-later { background: #fff7ed; border-color: #fed7aa; }
.sr-btn-later:hover { background: #ffedd5; border-color: #fb923c; }
.sr-btn-later .sr-btn-label { color: #ea580c; }
.sr-btn-later .sr-btn-hint  { color: #f97316; opacity: .75; }

.sr-btn-much  { background: #eff6ff; border-color: #bfdbfe; }
.sr-btn-much:hover  { background: #dbeafe; border-color: #60a5fa; }
.sr-btn-much  .sr-btn-label { color: #2563eb; }
.sr-btn-much  .sr-btn-hint  { color: #3b82f6; opacity: .75; }

.sr-btn-good  { background: #f0fdf4; border-color: #bbf7d0; }
.sr-btn-good:hover  { background: #dcfce7; border-color: #4ade80; }
.sr-btn-good  .sr-btn-label { color: #16a34a; }
.sr-btn-good  .sr-btn-hint  { color: #22c55e; opacity: .9; display: inline-flex; align-items: center; gap: .2rem; }

.sr-kbd {
    display: inline-block;
    padding: 0 .3rem;
    font-family: inherit;
    font-size: .68rem;
    line-height: 1.4;
    color: inherit;
    background: color-mix(in srgb, currentColor 14%, transparent);
    border: 1px solid color-mix(in srgb, currentColor 25%, transparent);
    border-radius: 4px;
}

.sr-btn-soon  .sr-btn-hint,
.sr-btn-later .sr-btn-hint,
.sr-btn-much  .sr-btn-hint {
    display: inline-flex;
    align-items: center;
    gap: .28rem;
}

/* Integrated Break it Down — primary, full width below the grid */
.sr-breakdown {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: .45rem;
    width: 100%;
    padding: .65rem 1rem;
    background: var(--primary);
    border: 1.5px solid var(--primary);
    border-radius: 12px;
    color: #fff;
    font-family: inherit;
    font-size: .9rem;
    font-weight: 600;
    cursor: pointer;
    transition: background .15s ease, border-color .15s ease, transform .08s ease;
}
.sr-breakdown:hover { background: #1632b8; border-color: #1632b8; }
.sr-breakdown:active { transform: translateY(1px); }
.sr-breakdown svg { flex-shrink: 0; }

.drill-badge {
    display: inline-flex;
    align-items: center;
    gap: .4rem;
    padding: .3rem .75rem;
    background: #fef3c7;
    color: #92400e;
    border-radius: 999px;
    font-size: .75rem;
    font-weight: 600;
}

/* ---- Language-drill inline chip ----
   Sits INSIDE the study-card (above the question) so the drill reads
   as a state OF the current card, not a separate card stacked above
   it. Cobalt-tinted to match the app's primary palette; minimal —
   no diff (would give away the answer to the next rung), no progress
   dots, just "↓ Drilling estudiante" or "↑ Try again estudiante". */
.lang-drill-chip {
    display: inline-flex;
    align-self: flex-start;
    align-items: center;
    gap: .45rem;
    padding: .3rem .75rem;
    margin: 0 0 .85rem;
    background: rgba(30, 64, 232, .07);
    border: 1px solid rgba(30, 64, 232, .16);
    border-radius: 999px;
    color: var(--primary);
    font-size: .76rem;
    font-weight: 600;
    line-height: 1;
}
.lang-drill-chip-arrow {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 14px;
    height: 14px;
    border-radius: 50%;
    background: rgba(30, 64, 232, .15);
    font-size: .62rem;
    font-weight: 700;
    line-height: 1;
}
.lang-drill-chip-label {
    text-transform: uppercase;
    letter-spacing: .06em;
    font-size: .65rem;
    opacity: .82;
}
.lang-drill-chip-target {
    font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
    font-size: .82rem;
    color: var(--primary);
}
/* Ascent — soft green to differentiate "climbing back" from "going
   deeper", still subtle enough to read as one chip family. */
.lang-drill-chip.is-ascend {
    background: rgba(34, 197, 94, .09);
    border-color: rgba(34, 197, 94, .22);
    color: #166534;
}
.lang-drill-chip.is-ascend .lang-drill-chip-arrow {
    background: rgba(22, 101, 52, .18);
}
.lang-drill-chip.is-ascend .lang-drill-chip-target { color: #166534; }

/* ---- Lang-drill wrong-answer interstitial ----
   The "Incorrect" pill + big purple "Drill the mistake" button shown
   between the wrong answer and the descent into drilling. One action,
   one path. Mirrors Anki_learning's adaptive_session.html answer-reveal
   state. */
.lang-drill-incorrect-pill {
    display: inline-flex;
    align-self: center;
    align-items: center;
    gap: .4rem;
    margin: .5rem auto;
    padding: .4rem .9rem;
    border-radius: 999px;
    background: #fee2e2;
    color: #b91c1c;
    font-size: .8rem;
    font-weight: 700;
    line-height: 1;
    animation: langDrillPillIn .28s ease-out;
}
.lang-drill-incorrect-pill svg { flex-shrink: 0; }
@keyframes langDrillPillIn {
    from { opacity: 0; transform: translateY(-4px); }
    to   { opacity: 1; transform: translateY(0); }
}

.lang-drill-interstitial {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: .55rem;
    margin: .4rem auto 0;
    max-width: 540px;
    animation: langDrillInterstitialIn .32s ease-out;
}
@keyframes langDrillInterstitialIn {
    from { opacity: 0; transform: translateY(8px); }
    to   { opacity: 1; transform: translateY(0); }
}
.lang-drill-start-btn {
    width: 100%;
    height: 52px;
    border: none;
    border-radius: 14px;
    background: var(--primary);
    color: #fff;
    font-size: 1.02rem;
    font-weight: 700;
    letter-spacing: .005em;
    cursor: pointer;
    box-shadow: 0 4px 14px rgba(30, 64, 232, .26);
    transition: background .12s ease, transform .08s ease, box-shadow .12s ease;
}
.lang-drill-start-btn:hover {
    background: #1632b8;
    box-shadow: 0 6px 18px rgba(30, 64, 232, .33);
}
.lang-drill-start-btn:active {
    transform: translateY(1px);
    box-shadow: 0 2px 8px rgba(30, 64, 232, .22);
}
.lang-drill-hint {
    margin: 0;
    font-size: .76rem;
    color: var(--text-muted);
}
.lang-drill-kbd {
    display: inline-block;
    padding: .12rem .42rem;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 5px;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: .72rem;
    font-weight: 600;
    color: var(--text);
}

/* ---- Right-answer landing (language cards) ----
   Mirrors Anki_learning's post-correct UX. Split across the card so the
   reader's eye flows top→down: pill at the very top, then the question,
   then the answer in green directly below it, then the Next button at
   the bottom. Replaces the redundant streak/match-banner + the
   "Still confused? Break it down" link when the answer was right. */
.lang-correct-interstitial {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: .55rem;
    margin: .25rem auto 0;
    max-width: 540px;
    animation: langDrillInterstitialIn .32s ease-out;
}
.lang-correct-pill {
    display: inline-flex;
    align-self: center;
    align-items: center;
    gap: .4rem;
    margin: 0 auto .55rem;
    padding: .42rem .95rem;
    border-radius: 999px;
    background: #d1fae5;
    color: #047857;
    font-size: .85rem;
    font-weight: 700;
    line-height: 1;
    animation: langDrillPillIn .28s ease-out;
}
.lang-correct-pill svg { flex-shrink: 0; }
.lang-correct-answer {
    /* Negative top margin pulls the translation up into the
       question's 1.75rem bottom-padding so the pair reads as one
       group (Gestalt proximity). Bottom margin tucks the Next
       button up too. Font-size sits just under the question's
       2.125rem so the answer feels paired-but-secondary, not a
       separate tier. */
    margin: -.5rem auto .85rem;
    max-width: 540px;
    color: #10b981;
    font-size: 1.85rem;
    font-weight: 600;
    text-align: center;
    word-break: break-word;
    line-height: 1.25;
    letter-spacing: -.01em;
    animation: langDrillInterstitialIn .32s ease-out;
}
.lang-correct-next-btn {
    width: 100%;
    height: 52px;
    border: none;
    border-radius: 14px;
    background: var(--primary);
    color: #fff;
    font-size: 1.02rem;
    font-weight: 700;
    cursor: pointer;
    box-shadow: 0 4px 14px rgba(30, 64, 232, .26);
    transition: background .12s ease, transform .08s ease, box-shadow .12s ease;
}
.lang-correct-next-btn:hover {
    background: #1632b8;
    box-shadow: 0 6px 18px rgba(30, 64, 232, .33);
}
.lang-correct-next-btn:active {
    transform: translateY(1px);
    box-shadow: 0 2px 8px rgba(30, 64, 232, .22);
}

/* ---- Compact diff card inside the wrong interstitial ----
   When the lang drill is about to fire, the existing #study-diff gets
   tightened into a single bordered card (You + separator + Correct)
   so the wrong-state reads as one diff block instead of two stretched
   rows. Scoped via .study-diff.is-lang-drill so non-drill paths keep
   their wider layout. */
.study-diff.is-lang-drill {
    margin: .5rem auto 1rem;
    padding: .85rem 1rem;
    background: rgba(0, 0, 0, .025);
    border: 1px solid var(--border);
    border-radius: 12px;
    /* Match the 540px column the input + actions live in. */
    max-width: 540px;
    border-top: 1px solid var(--border);
}
.study-diff.is-lang-drill .diff-row {
    padding: .25rem 0;
}
.study-diff.is-lang-drill .diff-row + .diff-row {
    border-top: 1px solid var(--border);
}
.study-diff.is-lang-drill .diff-label {
    text-transform: uppercase;
    letter-spacing: .06em;
    font-size: .68rem;
    color: var(--text-muted);
}

/* ---- Language-drill input feedback ----
   Red shake on wrong + green pulse on right, applied to the language input
   wrapper (the existing .study-input container). Matches Anki_learning's
   shake keyframe in spirit; tuned to the existing input padding. */
@keyframes langDrillShake {
    0%, 100% { transform: translateX(0); }
    20% { transform: translateX(-8px); }
    40% { transform: translateX(8px); }
    60% { transform: translateX(-5px); }
    80% { transform: translateX(5px); }
}
.lang-drill-shake { animation: langDrillShake .42s ease-in-out; }

@keyframes langDrillFlash {
    0%   { box-shadow: 0 0 0 0 rgba(34, 197, 94, .55); }
    60%  { box-shadow: 0 0 0 8px rgba(34, 197, 94, 0);   }
    100% { box-shadow: 0 0 0 0 rgba(34, 197, 94, 0);     }
}
.lang-drill-flash {
    animation: langDrillFlash .55s ease-out;
    border-radius: 12px;
}


/* Calc button on keyboard */
.kb-key-calc {
    background: rgba(224, 100, 73, .08);
    color: var(--primary);
}
.kb-key-calc:hover { background: rgba(224, 100, 73, .15); }

.kb-key-mode {
    background: var(--surface);
    border: 1.5px solid var(--border);
    color: var(--primary);
    font-size: .7rem;
    font-weight: 700;
    flex: 0 0 auto;
    width: 50px;
}
.kb-key-mode:hover { background: var(--bg); }



.study-card-divider {
    height: 1px;
    background: var(--border);
    margin: 0 1.5rem;
}

/* Hide divider when followed by math input (not MC) */
.study-card-divider:has(+ .study-input) {
    display: none;
}

.study-question-wrap {
    display: flex;
    /* Align to start so the speak icon hugs the first line on
       multi-line questions instead of vertically centering against
       the whole text block. */
    align-items: flex-start;
    justify-content: center;
    /* Card padding owns the outer rhythm now — only the gap to the
       input lives here. Tight so the input reads as the same beat
       as the question, not a separate block. */
    padding: 0 0 1rem;
    max-width: 540px;
    margin: 0 auto;
}
.study-question-graph {
    margin: 0 1.5rem 1.25rem;
    height: 320px;
    border-radius: 10px;
    overflow: hidden;
    border: 1px solid var(--border);
    background: var(--bg);
}
@media (max-width: 600px) {
    .study-question-graph { height: 240px; margin: 0 .75rem 1rem; }
}
.btn-speak {
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    /* Nudge down so the icon sits on the optical center of the first
       text line (question is 34px / 1.25 line-height = ~42px line;
       icon is 28px, so (42-28)/2 ≈ 7px top offset). */
    margin: 7px .65rem 0 0;
    padding: 0;
    background: transparent;
    border: none;
    border-radius: 50%;
    color: var(--text-muted);
    cursor: pointer;
    transition: all .15s ease;
    opacity: .38;
}
.btn-speak:hover {
    opacity: 1;
    color: var(--primary);
    background: rgba(30, 64, 232, .06);
}
.btn-speak.speaking {
    opacity: 1;
    color: var(--primary);
    border-color: var(--primary);
    animation: pulse-speak 1s ease-in-out infinite;
}
.btn-speak.loading {
    opacity: .7;
    pointer-events: none;
}
@keyframes pulse-speak {
    0%, 100% { transform: scale(1); }
    50% { transform: scale(1.08); }
}

.study-question {
    text-align: center;
    padding: 0;
    background: transparent;
    border: none;
    overflow-wrap: break-word;
    word-wrap: break-word;
    overflow: visible;
    /* ~24px / weight 600 / deeper navy. The question still leads the eye
       but reads at a calmer, more legible scale than the old hero size. */
    font-size: 1.5rem;
    font-weight: 600;
    color: #0F172A;
    line-height: 1.3;
    letter-spacing: -.012em;
}
@media (max-width: 720px) {
    .study-question { font-size: 1.4rem; }
}
.study-question .katex-display { margin: 0; overflow: visible; }
.study-question .katex-display > .katex { white-space: normal !important; text-align: center; }
.study-question .katex-html { white-space: normal !important; flex-wrap: wrap; justify-content: center; }
.study-question .katex { white-space: normal !important; word-wrap: break-word; }

/* "Directive + expression" layout (KatexRenderer.renderQuestion). When a
   prompt is an instruction followed by a tall expression (\frac, \sqrt, \int…),
   we stop flowing the equation inline through the sentence — that interleaved
   prose lines with half-height fraction stacks and was hard to read. Instead
   the instruction reads as a calm directive line and the expression sits below
   as one centered display equation (Khan / Brilliant / IXL convention). Plain
   prose and short inline-math prompts keep the flat path above. */
.study-question .sq-prose {
    font-size: 1.55rem;
    font-weight: 600;
    line-height: 1.3;
    letter-spacing: -.01em;
    margin: 0 0 .9rem;
}
.study-question .sq-expr {
    /* Hero scale moves to the equation — it's the thing being acted on. */
    font-size: 2.125rem;
    line-height: 1.1;
    /* A pathologically wide equation scrolls rather than wrapping mid-fraction
       or overflowing the card. */
    overflow-x: auto;
    overflow-y: hidden;
}
/* Keep the display equation on one centered line — the wrap rules above are
   only for the inline fallback. */
.study-question .sq-expr .katex-display { margin: 0; }
.study-question .sq-expr .katex-display > .katex { white-space: nowrap !important; text-align: center; }
.study-question .sq-expr .katex-html { white-space: nowrap !important; flex-wrap: nowrap !important; justify-content: center; }
@media (max-width: 720px) {
    .study-question .sq-prose { font-size: 1.3rem; }
    .study-question .sq-expr  { font-size: 1.75rem; }
}

/* The visible input chrome (border, radius, background, min-height,
   focus glow) lives on .study-input itself — NOT on .mq-editable-field
   or .language-input. This way the box is the right size and shape
   regardless of which input the shape decides to mount inside. */
.study-input {
    position: relative;
    /* width:100% + max-width caps at 540px while ensuring the box
       fills the column width even when MathQuill (its only child for
       math cards) is empty and has zero intrinsic width. */
    width: 100%;
    max-width: 540px;
    margin: 0 auto .65rem;
    min-height: 64px;
    background: var(--surface);
    border: 1.5px solid var(--border);
    border-radius: 14px;
    cursor: text;
    box-sizing: border-box;
    overflow: hidden;
    /* max-width is set inline by matchInputToQuestion() so the input
       morphs to match the question's rendered text width per card. */
    transition:
        border-color .15s ease,
        box-shadow .15s ease,
        max-width .35s cubic-bezier(.22, 1, .36, 1);
}
.study-actions {
    transition: max-width .35s cubic-bezier(.22, 1, .36, 1);
}
.study-input:focus-within {
    border-color: var(--primary);
    box-shadow: 0 0 0 3px rgba(30, 64, 232, .10);
}
/* Borderless interior — fills the chrome on .study-input. */
.language-input {
    width: 100%;
    height: 64px;
    padding: 0 1.4rem;
    /* Match the math input (1.5rem / 24px) so question→answer text
       sizing is consistent across subjects. Pairs at ~1.42x against
       the 34px question — Apple-style supportive-not-invisible ratio. */
    font-size: 1.5rem;
    line-height: 1.4;
    border: none;
    border-radius: 0;
    background: transparent;
    color: var(--text);
    outline: none;
    box-sizing: border-box;
}
.language-input::placeholder {
    color: var(--text-muted);
    opacity: .8;
}
.language-input:focus {
    border: none;
    box-shadow: none;
}
/* Language-card char-level diff. Monospaced so the Yours/Answer rows
   align character-for-character — the highlight color carries the
   signal, the alignment makes it readable in one glance. */
.lang-diff-line {
    font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo,
        Consolas, "Liberation Mono", monospace;
    font-size: 1.25rem;
    letter-spacing: .01em;
    white-space: pre-wrap;
    word-break: break-word;
    line-height: 1.6;
}
/* Match = clean green text, no chrome. The absence of background is
   the signal — anything visually "louder" is something the student
   needs to look at. */
.lang-diff-char--match { color: var(--green); font-weight: 600; }
/* Accent = right letter, wrong diacritic/case. Amber pill. */
.lang-diff-char--accent {
    color: var(--amber);
    background: rgba(245, 158, 11, .22);
    border-radius: 4px;
    padding: 1px 3px;
    margin: 0 1px;
    font-weight: 600;
}
/* Wrong = char the student typed that isn't in the answer here. */
.lang-diff-char--wrong {
    color: var(--toast-error-fg);
    background: var(--toast-error-bg);
    border-radius: 4px;
    padding: 1px 3px;
    margin: 0 1px;
    font-weight: 600;
    text-decoration: line-through;
    text-decoration-thickness: 1.5px;
}
/* Missing = char from the answer the student didn't type. */
.lang-diff-char--missing {
    color: var(--toast-success-fg);
    background: var(--toast-success-bg);
    border-radius: 4px;
    padding: 1px 3px;
    margin: 0 1px;
    font-weight: 700;
}

/* MathQuill dimensions inside the study card now match the language
   input (64px / 14px radius / 19px). The base rule is in style.css;
   no override here. */

.study-actions {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: .4rem;
    /* Card padding owns the outer gutter; this column matches the
       input width so primary action sits visually anchored to it. */
    max-width: 540px;
    margin: 0 auto;
    padding: 0;
    /* Breathing room above the buttons so Teach me/Check don't read as
       glued to the last multiple-choice option (or the input) above. */
    margin-top: 1.25rem;
}
/* Action row: Teach me on the left (ghost), Check on the right
   (primary). row-reverse renders the DOM-first Check on the right
   where the cursor naturally rests after typing. Breaks the
   "two stacked rectangles" pattern that made the input + button
   read as a single widget. */
.study-actions-row {
    display: flex;
    flex-direction: row-reverse;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
}
/* Primary "Check" — content-sized rather than column-spanning so it
   doesn't visually duplicate the input above. Stays loud via cobalt
   fill + soft shadow; eye lands on it as the next decision. */
.study-actions-row > #btn-reveal {
    width: auto;
    min-width: 160px;
    height: 60px;
    padding: 0 1.6rem;
    gap: .55rem;
    font-size: 1.0625rem;
    font-weight: 600;
    border-radius: 14px;
    background: var(--primary);
    color: #fff;
    border: none;
    box-shadow:
        0 1px 2px rgba(30, 64, 232, .14),
        0 4px 12px rgba(30, 64, 232, .18);
    transition: background .12s ease, transform .08s ease, box-shadow .12s ease;
}
.study-actions-row > #btn-reveal:hover {
    background: var(--primary-hover);
    box-shadow:
        0 1px 2px rgba(30, 64, 232, .18),
        0 6px 18px rgba(30, 64, 232, .24);
}
/* Inline kbd-style chip on the Check button — communicates that
   Enter is the keyboard shortcut without taking up a "Press Enter"
   text label's worth of space. Translucent on the cobalt fill. */
.study-actions-row > #btn-reveal .btn-key-hint {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 22px;
    margin-left: .15rem;
    padding: 0 .25rem;
    background: rgba(255, 255, 255, .18);
    border: 1px solid rgba(255, 255, 255, .25);
    border-radius: 6px;
    color: #fff;
    box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .08);
    transition: background .12s ease, border-color .12s ease;
}
.study-actions-row > #btn-reveal:hover .btn-key-hint {
    background: rgba(255, 255, 255, .24);
    border-color: rgba(255, 255, 255, .35);
}
.study-actions-row > #btn-reveal:active {
    transform: translateY(1px);
    box-shadow: 0 1px 4px rgba(30, 64, 232, .18);
}
/* Secondary "Teach me" — a plain hairline pill. Subtle 1px outline +
   faint cobalt tint at rest so it reads as a tap target without
   competing with the primary CTA. No magnetic pull or spotlight: it
   sits still like a normal button. */
.study-actions-row > #btn-prebreak {
    position: relative;
    /* Sibling-not-child to Check: ~48px tall (vs 60px), faint cobalt
       tint so they read as one family, deeper text color so the
       affordance isn't hiding. Stays clearly secondary via no fill
       and lower font-weight. */
    height: 48px;
    padding: 0 1.5rem;
    background: rgba(30, 64, 232, .045);
    border: 1px solid rgba(30, 64, 232, .18);
    border-radius: 999px;
    color: #475569;
    font-size: .95rem;
    font-weight: 500;
    letter-spacing: 0;
    cursor: pointer;
    transition:
        color .2s ease,
        border-color .2s ease,
        background .2s ease;
}
.study-actions-row > #btn-prebreak:hover {
    color: var(--primary);
    border-color: rgba(30, 64, 232, .4);
    background: rgba(30, 64, 232, .08);
}
.study-actions-row > #btn-prebreak:active {
    background: rgba(30, 64, 232, .12);
}
/* is-focused = student has selected text inside the question. Inherit
   the hover chrome plus a cobalt focus ring so the affordance is still
   signalled even before the cursor enters the button. */
.study-actions-row > #btn-prebreak.is-focused {
    color: var(--primary);
    border-color: var(--primary);
    background: rgba(30, 64, 232, .06);
    box-shadow:
        0 0 0 3px rgba(30, 64, 232, .12),
        0 1px 2px rgba(30, 64, 232, .06),
        0 8px 24px rgba(30, 64, 232, .12);
    text-decoration: underline;
    text-underline-offset: 3px;
}
/* Mobile: collapse the row back to a stack so Teach me doesn't get
   squeezed off-screen. Check goes full-width, Teach me sits below. */
@media (max-width: 480px) {
    .study-actions-row {
        flex-direction: column;
        align-items: stretch;
        gap: .5rem;
    }
    .study-actions-row > #btn-reveal {
        width: 100%;
        min-width: 0;
    }
    .study-actions-row > #btn-prebreak {
        align-self: center;
    }
}

/* --- Diff display ---
   Lives inside .study-card directly under the input — no double card
   chrome, just a thin top rule that visually peels the answer reveal
   off the input cell above it. */

.study-diff {
    padding: .75rem 1.25rem;
    /* Centered in the 540px column for math/MC paths too. */
    margin: .5rem auto 0;
    max-width: 540px;
    border-top: 1px solid var(--border);
}

.diff-row {
    display: flex;
    align-items: baseline;
    gap: .75rem;
    padding: .35rem 0;
}
.diff-row + .diff-row {
    border-top: 1px dashed var(--border);
}

.diff-label {
    font-size: .75rem;
    font-weight: 600;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: .03em;
    width: 56px;
    flex-shrink: 0;
}
.diff-math {
    flex: 1;
    min-width: 0;
    overflow-x: auto;
}
.diff-math .katex { font-size: 1.25rem; }

.diff-match-banner {
    text-align: center;
    padding: .6rem 1rem;
    border-radius: var(--radius);
    font-weight: 600;
    font-size: .9rem;
    margin-bottom: 1rem;
}
.diff-correct {
    background: #f0fdf4;
    color: var(--green);
    border: 1px solid #bbf7d0;
}

.banner-pop {
    animation: bannerPop 400ms ease;
}
@keyframes bannerPop {
    0% { transform: scale(0.8); opacity: 0; }
    50% { transform: scale(1.05); }
    100% { transform: scale(1); opacity: 1; }
}

/* ==========================================================
   Decomposition — depth indicator + loading
   ========================================================== */

/* --- Break it Down stepper --- */
.depth-indicator {
    display: flex;
    flex-direction: column;
    gap: .35rem;
    padding: .55rem .85rem .65rem;
    margin-bottom: .75rem;
    background: #EFF6FF;
    border: 1px solid #BFDBFE;
    border-radius: 8px;
    font-size: .8rem;
    font-weight: 500;
    color: #1D4ED8;
}

.depth-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    width: 100%;
    gap: .5rem;
}

.depth-label {
    display: flex;
    align-items: center;
    gap: .35rem;
    color: #1D4ED8;
    font-weight: 500;
    font-size: .75rem;
    min-width: 0;
}

button.depth-label {
    background: transparent;
    border: 1px solid transparent;
    padding: .15rem .4rem;
    margin: -.15rem -.4rem;
    border-radius: 6px;
    cursor: pointer;
    font: inherit;
    color: #1D4ED8;
    transition: background-color .15s ease, border-color .15s ease, color .15s ease;
}
button.depth-label:hover {
    background: #DBEAFE;
    border-color: #BFDBFE;
    color: #1E3A8A;
}
button.depth-label:focus-visible {
    outline: none;
    border-color: #1D4ED8;
    box-shadow: 0 0 0 2px rgba(29, 78, 216, .25);
}

.depth-q-preview {
    font-weight: 600;
    max-width: 200px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.depth-counter {
    color: #60A5FA;
    font-weight: 600;
    font-size: .72rem;
    white-space: nowrap;
}

.depth-stepper {
    position: relative;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    /* Only a row gap for wrapped rows; horizontal spacing comes from the
       stretchy connectors below, which spread the dots across the full
       width regardless of how many there are. */
    row-gap: 11px;
    width: 100%;
    padding: 2px;
    min-height: 24px;
}

.depth-step {
    flex: 0 0 auto;
    position: relative;
    z-index: 1;
    display: flex;
    align-items: center;
    justify-content: center;
}

/* Stretchy connector between two dots — `flex: 1` makes it grow to fill the
   space, spreading the dots edge-to-edge across the bar instead of bunching
   them to the left. Filled once the step it trails is completed. `.is-edge`
   (set in StudyDepth.js after layout) hides a connector stranded at the
   start/end of a wrapped row so it doesn't dangle. */
.depth-connector {
    flex: 1 1 auto;
    min-width: 10px;
    height: 3px;
    background: var(--border);
    border-radius: 2px;
    transition: background .25s ease;
}
.depth-connector.filled { background: var(--primary); }
.depth-connector.is-edge { display: none; }

.depth-step-dot {
    width: 16px;
    height: 16px;
    border-radius: 50%;
    border: 2px solid var(--border);
    background: var(--surface);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: .5rem;
    font-weight: 700;
    color: transparent;
    transition: all .25s ease;
}

.depth-step.completed .depth-step-dot {
    background: var(--primary);
    border-color: var(--primary);
    color: #fff;
}

.depth-step.current .depth-step-dot {
    border-color: var(--primary);
    background: var(--primary);
    color: #fff;
}

.depth-step.goal .depth-step-dot {
    width: 20px;
    height: 20px;
    font-size: .55rem;
}

.depth-step.goal.completed .depth-step-dot,
.depth-step.goal.current .depth-step-dot {
    background: var(--green);
    border-color: var(--green);
    color: #fff;
}

.depth-step.goal.current .depth-step-dot {
    box-shadow: none;
}
.depth-step.clickable {
    cursor: pointer;
}
.depth-step.clickable:hover .depth-step-dot {
    transform: scale(1.25);
    border-color: var(--primary);
}

/* Trailing "more coming" pulse shown while the ramp is still streaming in. */
.depth-step-incoming .depth-step-dot {
    border-style: dashed;
    animation: depth-incoming-pulse 1.1s ease-in-out infinite;
}

@keyframes depth-incoming-pulse {
    0%, 100% { opacity: .35; transform: scale(.78); }
    50%      { opacity: .9;  transform: scale(1); }
}

/* --- Breadcrumb trail for nested decomposition --- */
.depth-breadcrumbs {
    display: flex;
    align-items: center;
    gap: .25rem;
    flex-wrap: wrap;
    padding-bottom: .35rem;
    border-bottom: 1px solid #BFDBFE;
    margin-bottom: .25rem;
}
.depth-crumb {
    font-size: .68rem;
    font-weight: 500;
    max-width: 160px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.depth-crumb-ancestor {
    background: none;
    border: none;
    padding: .15rem .35rem;
    border-radius: 4px;
    color: #3B82F6;
    cursor: pointer;
    font-family: inherit;
    font-size: .68rem;
    font-weight: 500;
    transition: background .15s ease;
}
.depth-crumb-ancestor:hover {
    background: rgba(59, 130, 246, .1);
}
.depth-crumb-current {
    color: #1D4ED8;
    font-weight: 600;
    padding: .15rem .35rem;
}
.depth-crumb-sep {
    color: #93C5FD;
    font-size: .7rem;
    user-select: none;
}
.depth-badge {
    font-size: .6rem;
    font-weight: 600;
    background: #DBEAFE;
    color: #1D4ED8;
    padding: .1rem .4rem;
    border-radius: 999px;
    white-space: nowrap;
}

/* --- Pop-level celebration --- */
.pop-celebration {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: .6rem;
    padding: 2rem 1rem;
}

.pop-check-ring {
    width: 72px;
    height: 72px;
    border-radius: 50%;
    border: 3px solid;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--surface);
}

.pop-title {
    font-weight: 700;
    font-size: 1.1rem;
    color: var(--text);
    margin: 0;
}

.pop-sub {
    font-size: .85rem;
    color: var(--text-muted);
    margin: 0;
}

.study-loading {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: .75rem;
    padding: 2.5rem 1rem;
    background: var(--surface);
    border: 1.5px solid var(--border);
    border-radius: var(--radius);
    margin-bottom: 1rem;
    font-size: .95rem;
    font-weight: 500;
    color: var(--text);
}

/* --- Stream loader (animated loading experience) --- */

@keyframes pulse-glow {
    0%, 100% { transform: scale(1); opacity: 1; }
    50% { transform: scale(1.08); opacity: .85; }
}
@keyframes ring-expand {
    0% { transform: scale(.8); opacity: .6; }
    100% { transform: scale(2.2); opacity: 0; }
}
@keyframes float-up {
    0% { opacity: 0; transform: translateY(20px) scale(.95); }
    15% { opacity: 1; transform: translateY(0) scale(1); }
    85% { opacity: 1; transform: translateY(0) scale(1); }
    100% { opacity: 0; transform: translateY(-30px) scale(.95); }
}
@keyframes count-pop {
    0% { transform: scale(1); }
    50% { transform: scale(1.3); }
    100% { transform: scale(1); }
}


.btn-prebreak {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: .4rem;
    height: 40px;
    padding: 0 1.4rem;
    background: none;
    border: 1px solid var(--border);
    border-radius: 999px;
    color: var(--text);
    font-size: .9rem;
    font-weight: 600;
    font-family: inherit;
    cursor: pointer;
    transition: all .15s ease;
}
.btn-prebreak:hover {
    border-color: var(--primary);
    color: var(--primary);
    background: rgba(224, 100, 73, .04);
}

/* Subtle "skip" — tucked into the bottom-right corner of the study card.
   Low-contrast at rest so it reads as a quiet escape hatch (not a primary
   action) yet stays visible; firms up on hover. Removes the card from the
   queue with zero reward — see the skip handler in StudyCards.js. */
.btn-skip {
    position: absolute;
    right: 1.4rem;
    bottom: 1.15rem;
    display: inline-flex;
    align-items: center;
    gap: .3rem;
    padding: .3rem .5rem;
    background: none;
    border: none;
    border-radius: 8px;
    color: var(--text-muted);
    font-family: inherit;
    font-size: .82rem;
    font-weight: 600;
    letter-spacing: .01em;
    cursor: pointer;
    opacity: .6;
    transition: opacity .15s ease, color .15s ease, background .15s ease;
}
.btn-skip:hover {
    opacity: 1;
    color: var(--text-soft);
    background: rgba(15, 23, 42, .05);
}
.btn-skip svg { display: block; }
@media (max-width: 720px) {
    .btn-skip { right: .9rem; bottom: .8rem; }
}
@keyframes fade-in-up {
    from { opacity: 0; transform: translateY(12px); }
    to { opacity: 1; transform: translateY(0); }
}
@keyframes dots {
    0%, 20% { content: ''; }
    40% { content: '.'; }
    60% { content: '..'; }
    80%, 100% { content: '...'; }
}

.stream-loader {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 3rem 1.5rem;
    min-height: 50vh;
    text-align: center;
    animation: fade-in-up .5s ease-out;
}

.stream-loader-icon {
    position: relative;
    width: 80px;
    height: 80px;
    margin-bottom: 2rem;
}

.stream-loader-icon svg {
    width: 80px;
    height: 80px;
    animation: pulse-glow 2s ease-in-out infinite;
    filter: drop-shadow(0 0 12px rgba(30, 64, 232, .25));
}

.stream-loader-icon::before,
.stream-loader-icon::after {
    content: '';
    position: absolute;
    inset: 0;
    border-radius: 50%;
    border: 2px solid var(--primary);
    animation: ring-expand 2.5s ease-out infinite;
}
.stream-loader-icon::after {
    animation-delay: 1.25s;
}

.stream-loader-status {
    font-size: 1.1rem;
    font-weight: 600;
    color: var(--text);
    margin-bottom: .5rem;
    min-height: 1.6em;
    transition: opacity .4s ease;
}

.stream-loader-progress {
    width: 260px;
    height: 6px;
    background: var(--border);
    border-radius: 999px;
    margin-bottom: .75rem;
    overflow: hidden;
    position: relative;
}

.stream-loader-progress-bar {
    height: 100%;
    border-radius: 999px;
    background: linear-gradient(90deg, var(--primary), var(--border-focus), var(--primary));
    background-size: 200% 100%;
    animation: progress-shimmer 1.2s linear infinite;
    width: 0%;
    transition: width .6s cubic-bezier(.22, 1, .36, 1);
}

@keyframes progress-shimmer {
    0% { background-position: -200% 0; }
    100% { background-position: 200% 0; }
}

.stream-loader-milestones {
    display: flex;
    justify-content: space-between;
    width: 260px;
    margin-bottom: 2rem;
    position: relative;
}

.stream-milestone {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: .25rem;
    opacity: .3;
    transition: opacity .4s ease, transform .4s ease;
}

.stream-milestone.active {
    opacity: 1;
    transform: scale(1.1);
}

.stream-milestone.done {
    opacity: .6;
    transform: scale(1);
}

.stream-milestone-dot {
    width: 10px;
    height: 10px;
    border-radius: 50%;
    background: var(--border);
    transition: background .3s ease, box-shadow .3s ease;
}

.stream-milestone.active .stream-milestone-dot {
    background: var(--primary);
    box-shadow: 0 0 0 4px rgba(30, 64, 232, .2);
}

.stream-milestone.done .stream-milestone-dot {
    background: var(--green);
}

.stream-milestone-label {
    font-size: .65rem;
    font-weight: 600;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: .03em;
}

.stream-milestone.active .stream-milestone-label {
    color: var(--primary);
}

/* Particle burst */
@keyframes particle-burst {
    0% { transform: translate(0, 0) scale(1); opacity: 1; }
    100% { transform: translate(var(--px), var(--py)) scale(0); opacity: 0; }
}

.stream-particle {
    position: absolute;
    width: 6px;
    height: 6px;
    border-radius: 50%;
    pointer-events: none;
    animation: particle-burst .7s ease-out forwards;
}

/* Milestone check animation */
@keyframes check-draw {
    from { stroke-dashoffset: 20; }
    to { stroke-dashoffset: 0; }
}

.stream-milestone.done .stream-milestone-dot {
    position: relative;
}

.milestone-check {
    position: absolute;
    top: -3px;
    left: -3px;
    width: 16px;
    height: 16px;
}

.stream-loader-count {
    display: inline-flex;
    align-items: center;
    gap: .5rem;
    font-size: 1rem;
    font-weight: 600;
    color: var(--primary);
    background: rgba(30, 64, 232, .08);
    padding: .5rem 1.25rem;
    border-radius: 999px;
    opacity: 0;
    transition: opacity .3s ease;
}
.stream-loader-count.visible { opacity: 1; }

.stream-loader-count .count-num {
    font-size: 1.3rem;
    font-weight: 700;
    display: inline-block;
}
.stream-loader-count .count-num.pop {
    animation: count-pop .3s ease;
}


.stream-loader-dots::after {
    content: '';
    animation: dots 1.5s steps(4, end) infinite;
}

/* --- Progress HUD (study page) --- */
.progress-hud {
    background: var(--surface);
    border: 1.5px solid var(--border);
    border-radius: var(--radius);
    padding: 1rem 1.25rem;
    margin-bottom: 1rem;
}

.hud-deck-label {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    margin-bottom: .4rem;
}
.hud-deck-title {
    font-size: .75rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .06em;
    color: var(--text-muted);
}
.hud-deck-pct {
    font-size: 1rem;
    font-weight: 800;
    color: var(--green);
}

.hud-deck-bar {
    height: 10px;
    background: var(--border);
    border-radius: 999px;
    overflow: hidden;
    margin-bottom: .75rem;
    position: relative;
}
.hud-deck-fill {
    height: 100%;
    background: linear-gradient(90deg, #0E7C5A, #22A373, #4FB087);
    border-radius: 999px;
    transition: width .8s cubic-bezier(.22, 1, .36, 1);
    position: relative;
}
.hud-deck-fill::after {
    content: '';
    position: absolute;
    right: 0;
    top: 0;
    width: 20px;
    height: 100%;
    background: linear-gradient(90deg, transparent, rgba(255,255,255,.4));
    border-radius: 999px;
}

.hud-levels {
    display: flex;
    gap: .5rem;
    margin-bottom: .5rem;
}

.hud-level {
    flex: 1;
    min-width: 0;
}
.hud-level-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: .2rem;
}
.hud-level-name {
    font-size: .65rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .04em;
    color: var(--text-muted);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.hud-level-count {
    font-size: .65rem;
    font-weight: 600;
    color: var(--text-muted);
}

.hud-level-bar {
    height: 6px;
    background: var(--border);
    border-radius: 999px;
    overflow: hidden;
}

.hud-level-fill {
    height: 100%;
    border-radius: 999px;
    transition: width .8s cubic-bezier(.22, 1, .36, 1);
}
.hud-level:nth-child(1) .hud-level-fill { background: #1E40E8; }
.hud-level:nth-child(2) .hud-level-fill { background: #f59e0b; }
.hud-level:nth-child(3) .hud-level-fill { background: #ef4444; }

.hud-milestone {
    text-align: center;
    font-size: .8rem;
    font-weight: 700;
    color: #f59e0b;
    min-height: 1.2em;
}

@keyframes hud-pulse {
    0%, 100% { transform: scale(1); }
    50% { transform: scale(1.05); }
}
.hud-milestone.pulse {
    animation: hud-pulse .4s ease;
}

/* --- Mastery progress --- */
.mastery-section {
    background: var(--surface);
    border: 1.5px solid var(--border);
    border-radius: var(--radius);
    padding: 1.25rem;
    margin-bottom: 1.5rem;
}

.mastery-header {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    margin-bottom: .5rem;
}
.mastery-pct { font-size: 1.1rem; font-weight: 700; color: var(--text); }
.mastery-count { font-size: .8rem; color: var(--text-muted); font-weight: 500; }

.mastery-bar {
    height: 8px;
    background: var(--border);
    border-radius: 999px;
    overflow: hidden;
    margin-bottom: 1rem;
}
.mastery-fill {
    height: 100%;
    background: linear-gradient(90deg, var(--green), #22A373);
    border-radius: 999px;
    transition: width .6s cubic-bezier(.22, 1, .36, 1);
}

.mastery-levels {
    display: flex;
    flex-direction: column;
    gap: .75rem;
}


.mastery-level-header {
    display: flex;
    justify-content: space-between;
    margin-bottom: .25rem;
}
.mastery-level-name { font-size: .8rem; font-weight: 600; color: var(--text); }
.mastery-level-count { font-size: .75rem; color: var(--text-muted); font-weight: 500; }

.mastery-level-bar {
    height: 5px;
    background: var(--border);
    border-radius: 999px;
    overflow: hidden;
}
.mastery-level-fill {
    height: 100%;
    background: var(--primary);
    border-radius: 999px;
    transition: width .6s cubic-bezier(.22, 1, .36, 1);
}

.mastery-milestone {
    margin-top: 1rem;
    text-align: center;
    font-size: .88rem;
    font-weight: 600;
    color: #f59e0b;
}

/* Compact mastery bar on deck list cards */
.deck-mastery-bar {
    width: 100%;
    height: 4px;
    background: rgba(0,0,0,.06);
    border-radius: 999px;
    overflow: hidden;
    margin-top: .35rem;
}
.deck-mastery-fill {
    height: 100%;
    background: linear-gradient(90deg, var(--green), #22A373);
    border-radius: 999px;
}

/* --- Multiple choice --- */
.mc-choices {
    display: flex;
    flex-direction: column;
    gap: .5rem;
    padding: 0;
    /* Constrain to the same 540px column the input + actions live in. */
    max-width: 540px;
    margin: 0 auto;
}

.mc-choice {
    display: flex;
    align-items: center;
    gap: .75rem;
    width: 100%;
    padding: .65rem .85rem;
    background: var(--bg);
    border: 1.5px solid transparent;
    border-radius: 10px;
    cursor: pointer;
    font-size: .88rem;
    color: var(--text);
    text-align: left;
    transition: border-color .15s ease, background .15s ease;
}

.mc-choice:hover:not(:disabled) {
    border-color: var(--primary);
    background: rgba(224, 100, 73, .04);
}

.mc-label {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    border-radius: 50%;
    background: var(--bg);
    border: 1.5px solid var(--border);
    font-weight: 700;
    font-size: .78rem;
    color: var(--text-muted);
    flex-shrink: 0;
    transition: background .2s ease, border-color .2s ease, color .2s ease;
}

.mc-choice:hover:not(:disabled) .mc-label {
    border-color: var(--primary);
    color: var(--primary);
    background: rgba(224, 100, 73, .06);
}

.mc-text {
    flex: 1;
    line-height: 1.5;
}

.mc-choice:disabled {
    cursor: default;
    opacity: .85;
}

.mc-choice.mc-correct {
    background: #F0FDF4;
}
.mc-choice.mc-correct .mc-label {
    background: var(--green);
    border-color: var(--green);
    color: #fff;
}

.mc-choice.mc-wrong {
    background: #FEF2F2;
}
.mc-choice.mc-wrong .mc-label {
    background: var(--red);
    border-color: var(--red);
    color: #fff;
}

/* ==========================================================
   Reward Effects
   ========================================================== */

/* --- Confetti particles (CSS-based) --- */
.confetti-particle {
    position: fixed;
    pointer-events: none;
    z-index: var(--z-confetti);
    animation: confetti-fall var(--cd, 1.2s) cubic-bezier(0.25, 0.46, 0.45, 0.94) forwards;
}
@keyframes confetti-fall {
    0% { opacity: 1; transform: translate(0, 0) rotate(0deg) scale(1); }
    100% { opacity: 0; transform: translate(var(--cx), var(--cy)) rotate(var(--cr)) scale(0.4); }
}

/* --- Screen flash --- */
.screen-flash {
    position: fixed;
    inset: 0;
    z-index: var(--z-flash);
    pointer-events: none;
    animation: flash-fade 400ms ease-out forwards;
}
@keyframes flash-fade {
    0% { opacity: 0.35; }
    100% { opacity: 0; }
}

/* --- Hype message --- */
.hype-message {
    position: fixed;
    top: 30%;
    left: 50%;
    transform: translateX(-50%);
    z-index: var(--z-hype);
    font-size: 1.8rem;
    font-weight: 800;
    letter-spacing: .04em;
    color: var(--primary);
    text-shadow: 0 2px 12px rgba(30,64,232,.25);
    pointer-events: none;
    animation: hype-pop 1.1s ease forwards;
}
@keyframes hype-pop {
    0% { opacity: 0; transform: translateX(-50%) scale(0.3) translateY(20px); }
    25% { opacity: 1; transform: translateX(-50%) scale(1.15) translateY(-5px); }
    45% { transform: translateX(-50%) scale(1) translateY(0); }
    100% { opacity: 0; transform: translateX(-50%) scale(0.8) translateY(-40px); }
}

/* --- Side rail (persistent right column: Next-unlock card on top, Knowledge
   Map filling the rest, streak badge at bottom). Mirrors the left-side layout:
   the Next-unlock card lines up with the deck-info card; Knowledge Map lines
   up with the study/drill area. --- */
.study-side-rail {
    position: fixed;
    top: .5rem;
    right: 1.25rem;
    bottom: 1rem;
    width: var(--rail-w, 280px);
    z-index: var(--z-sticky);
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: .65rem;
    pointer-events: none;
    transform: translateX(0);
    opacity: 1;
    transition: transform .45s cubic-bezier(.22, 1, .36, 1),
                opacity .3s cubic-bezier(.22, 1, .36, 1);
    will-change: transform, opacity;
}
.study-side-rail > * { pointer-events: auto; }

/* --- Streak badge ---
   Lives inside the deck-info-card strip (top-right of the page,
   beside the deck name) instead of floating in the study-card
   surface. Keeps the card surface uncluttered. JS still targets
   #streak-badge; only the DOM location moves. */
.streak-badge {
    /* Pinned to the right of .deck-info-card, just left of the
       hamburger rail toggle (which sits at right: .6rem, 40px wide).
       Both elements are absolutely positioned siblings — no layout
       conflict. */
    position: absolute;
    top: 50%;
    right: 3.6rem;
    transform: translateY(-50%);
    padding: .32rem .7rem;
    border-radius: 99px;
    font-size: .85rem;
    font-weight: 700;
    background: var(--surface);
    border: 1.5px solid var(--border);
    color: var(--text);
    box-shadow: 0 1px 3px rgba(0, 0, 0, .04);
    white-space: nowrap;
    text-align: center;
    line-height: 1;
    z-index: 2;
}

.streak-pop { animation: bannerPop 400ms ease; }

/* Streak-badge punch — fires on each correct, synced with the bell sparkle. */
.streak-badge.punching { animation: streakPunch 220ms ease-out; }
@keyframes streakPunch {
    0%   { transform: scale(1) rotate(0deg); }
    35%  { transform: scale(1.22) rotate(-2deg); }
    65%  { transform: scale(1.04) rotate(1.5deg); }
    100% { transform: scale(1) rotate(0deg); }
}

/* --- Tier ladder (simple emoji + tinted chip) --- */
.streak-ember {
    background: linear-gradient(135deg, #FFFBEB, #FEF3C7);
    border-color: #FCD34D;
    color: #B45309;
}
.streak-storm {
    background: linear-gradient(135deg, #EFF6FF, #DBEAFE);
    border-color: #60A5FA;
    color: #1D4ED8;
}
.streak-inferno {
    background: linear-gradient(135deg, #FEF2F2, #FEE2E2);
    border-color: #F87171;
    color: #DC2626;
}
.streak-legendary {
    background: linear-gradient(135deg, #FFFBEB, #FDE68A);
    border-color: #F59E0B;
    color: #92400E;
    box-shadow: 0 0 12px rgba(245,158,11,.3);
}

.streak-broken {
    background: #FEF2F2;
    border-color: #FECACA;
    color: var(--red);
    animation: bannerPop 400ms ease;
}
.streak-muted {
    background: var(--surface);
    border-color: var(--border);
    color: var(--text-muted);
    font-weight: 600;
    font-size: .8rem;
}

/* ==========================================================
   Next-unlock card — sits at the top of the side rail, in the slot
   formerly occupied by the Goal HUD (replaced per Don Norman "only
   what is necessary"). Same shape/size as the old Goal HUD so the
   layout stays consistent. Schultz dopamine: a reliable cue produces
   bigger anticipation dopamine than the reward itself; making the
   next unlock visible at all times turns correct answers in relevant
   prereqs into purposeful progress.
   ========================================================== */
.next-unlock-card {
    width: 100%;
    display: grid;
    grid-template-columns: 1fr auto;
    grid-template-areas:
        "label  pill"
        "name   pill"
        "via    via"
        "bar    bar";
    column-gap: .65rem;
    row-gap: .15rem;
    padding: .7rem .85rem .7rem;
    background: var(--surface);
    border: 1.5px solid var(--border);
    border-radius: 18px;
    box-shadow:
        0 6px 24px rgba(30, 64, 232, 0.10),
        inset 0 1px 0 rgba(255,255,255,.6);
    align-items: center;
    transition: border-color 200ms ease, box-shadow 200ms ease;
}
.next-unlock-card .nu-label {
    grid-area: label;
    font-size: .68rem;
    font-weight: 800;
    letter-spacing: .12em;
    color: var(--text-muted);
    line-height: 1;
    text-transform: uppercase;
}
.next-unlock-card .nu-name {
    grid-area: name;
    font-family: Georgia, 'Times New Roman', serif;
    font-style: italic;
    font-weight: 700;
    font-size: 1.08rem;
    color: var(--text);
    line-height: 1.15;
    letter-spacing: -.005em;
    text-transform: lowercase;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    transition: color 200ms ease;
}
.next-unlock-card .nu-pill {
    grid-area: pill;
    margin: 0;
    align-self: center;
    padding: .22rem .55rem;
    border-radius: 999px;
    font-size: .72rem;
    font-weight: 800;
    background: var(--surface);
    border: 1px solid var(--border);
    color: var(--text-muted);
    line-height: 1;
    white-space: nowrap;
    transition: background 200ms, color 200ms, border-color 200ms;
}
.next-unlock-card .nu-bar {
    grid-area: bar;
    width: 100%;
    height: 6px;
    background: #e8ecf6;
    border-radius: 999px;
    overflow: hidden;
    margin-top: .35rem;
}
.next-unlock-card .nu-fill {
    height: 100%;
    width: calc(var(--nu-pct, 0) * 1%);
    background: linear-gradient(90deg, #4a6dfa, var(--primary));
    border-radius: 999px;
    box-shadow: 0 0 6px rgba(30, 64, 232, .45);
    transition: width 320ms cubic-bezier(.4, 0, .2, 1);
}
/* Imminent: ≤1 card from unlock — cobalt accent everywhere, same
   visual language as the active concept row + primary buttons. */
.next-unlock-card.is-glow {
    border-color: rgba(30,64,232,.45);
    box-shadow:
        0 6px 24px rgba(30, 64, 232, 0.18),
        0 0 14px rgba(30, 64, 232, 0.30),
        inset 0 1px 0 rgba(255,255,255,.6);
}
.next-unlock-card.is-glow .nu-name { color: var(--primary); }
.next-unlock-card.is-glow .nu-pill {
    background: var(--primary);
    border-color: var(--primary);
    color: white;
}
/* Topped: all concepts unlocked — celebratory green tint. */
.next-unlock-card.is-topped {
    border-color: rgba(14,124,90,.40);
    background: rgba(220,252,231,.55);
}
.next-unlock-card.is-topped .nu-name {
    color: var(--green);
    font-style: normal;
    text-transform: uppercase;
    letter-spacing: .08em;
    font-size: .85rem;
}
.next-unlock-card.is-topped .nu-pill {
    background: var(--green);
    border-color: var(--green);
    color: white;
}
.next-unlock-card.is-topped .nu-bar { display: none; }
.next-unlock-card.is-topped .nu-via { display: none; }

/* Sub-line under the concept name showing the gating prereq.
   Tells the user *which* prereq concept owns the blocking card —
   turns "stuck at 1 away" from passive to actionable. */
.next-unlock-card .nu-via {
    grid-area: via;
    font-family: Georgia, 'Times New Roman', serif;
    font-style: italic;
    font-size: .76rem;
    color: var(--text-muted);
    line-height: 1.2;
    letter-spacing: -.005em;
    text-transform: lowercase;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    margin-top: -.05rem;
    opacity: .85;
}
.next-unlock-card.is-glow .nu-via { color: var(--primary); opacity: .85; }

/* Brief gold pulse on the next-unlock card when the Card Cascade tiles
   converge into it — visualizes "the cards just landed here." This
   fires only during a discrete unlock event, not idle. */
.next-unlock-card.nu-arrival-pulse {
    animation: nu-arrival 0.55s ease-out;
}
@keyframes nu-arrival {
    0%   { box-shadow:
            0 6px 24px rgba(30, 64, 232, 0.18),
            inset 0 1px 0 rgba(255,255,255,.6); }
    40%  { box-shadow:
            0 8px 32px rgba(255, 196, 60, 0.55),
            0 0 26px rgba(255, 196, 60, 0.65),
            inset 0 1px 0 rgba(255,255,255,.7); }
    100% { box-shadow:
            0 6px 24px rgba(30, 64, 232, 0.18),
            inset 0 1px 0 rgba(255,255,255,.6); }
}

@media (prefers-reduced-motion: reduce) {
    .next-unlock-card.nu-arrival-pulse { animation: none; }
}

/* ==========================================================
   Card Cascade — beautiful unlock card-reveal
   Replaces the generic info-toast on concept unlock. Fires from
   Rewards.playCardCascade after the screen-level cinematic's
   concept reveal. Fixed-position stage above the study area.
   ========================================================== */

.unlock-cascade-stage {
    position: fixed;
    top: 22vh;
    left: 50%;
    transform: translateX(-50%);
    pointer-events: none;
    z-index: 9700;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 1.1rem;
    perspective: 900px;
}
.unlock-cascade-badge {
    font-family: Georgia, 'Times New Roman', serif;
    font-style: italic;
    font-weight: 700;
    font-size: 1.05rem;
    color: #B8860B;
    letter-spacing: -.005em;
    padding: .4rem .9rem;
    background: linear-gradient(
        180deg,
        rgba(255, 248, 220, 0.96),
        rgba(255, 240, 200, 0.92)
    );
    border: 1px solid rgba(255, 196, 60, 0.55);
    border-radius: 999px;
    box-shadow:
        0 6px 22px rgba(255, 196, 60, 0.30),
        inset 0 1px 0 rgba(255,255,255,.7);
    white-space: nowrap;
    max-width: 80vw;
    overflow: hidden;
    text-overflow: ellipsis;
}
.unlock-cascade-deck {
    position: relative;
    width: 0;
    height: 0;
    transform-style: preserve-3d;
}
.unlock-cascade-tile {
    position: absolute;
    left: -80px;
    top: -48px;
    width: 160px;
    height: 96px;
    border-radius: 14px;
    background: #ffffff;
    border: 1.5px solid rgba(255, 196, 60, 0.55);
    box-shadow:
        0 8px 28px rgba(0, 0, 0, 0.18),
        0 0 18px rgba(255, 196, 60, 0.35),
        inset 0 1px 0 rgba(255,255,255,.85);
    overflow: hidden;
    transform-style: preserve-3d;
    backface-visibility: hidden;
    will-change: transform, opacity;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: .55rem .7rem;
}
.unlock-cascade-tile .cascade-tile-rim {
    position: absolute;
    inset: 0;
    border-radius: inherit;
    background:
        radial-gradient(120% 100% at 50% 0%,
            rgba(255, 220, 130, 0.5) 0%,
            rgba(255, 220, 130, 0) 60%);
    pointer-events: none;
}
.unlock-cascade-tile .cascade-tile-body {
    position: relative;
    font-family: Georgia, 'Times New Roman', serif;
    font-size: .82rem;
    color: var(--text);
    line-height: 1.3;
    text-align: center;
    overflow: hidden;
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    word-break: break-word;
}
.unlock-cascade-tile.is-overflow {
    background: linear-gradient(
        135deg,
        rgba(255, 248, 220, 0.98),
        rgba(255, 230, 170, 0.95)
    );
    border-color: rgba(255, 170, 40, 0.70);
}
.unlock-cascade-tile .cascade-tile-overflow {
    font-family: Georgia, 'Times New Roman', serif;
    font-style: italic;
    font-weight: 700;
    font-size: 1rem;
    color: #8B6914;
    text-align: center;
}

/* Reduced-motion fallback: badge fades in/out, no flying tiles. */
.unlock-cascade-stage.is-reduced .unlock-cascade-deck { display: none; }
.unlock-cascade-stage.is-reduced { animation: cascade-reduced-in 280ms ease-out; }
.unlock-cascade-stage.is-reduced.is-leaving { animation: cascade-reduced-out 380ms ease-in forwards; }
@keyframes cascade-reduced-in {
    from { opacity: 0; transform: translate(-50%, -8px); }
    to   { opacity: 1; transform: translate(-50%, 0); }
}
@keyframes cascade-reduced-out {
    from { opacity: 1; transform: translate(-50%, 0); }
    to   { opacity: 0; transform: translate(-50%, -6px); }
}

/* --- Knowledge Map panel (always-visible right rail) --- */
.concept-map-panel {
    position: relative;
    width: 100%;
    flex: 1;
    min-height: 0;
    background: var(--surface);
    border: 1.5px solid var(--border);
    border-radius: 18px;
    box-shadow: 0 6px 24px rgba(30, 64, 232, 0.10), inset 0 1px 0 rgba(255,255,255,.6);
    padding: .85rem .85rem 2.4rem .85rem;
    display: flex;
    flex-direction: column;
}

.cm-header {
    display: flex;
    align-items: center;
    gap: .55rem;
    padding-bottom: .55rem;
    border-bottom: 1px solid var(--border);
}
.cm-title {
    font-size: .78rem;
    font-weight: 800;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--text-soft);
}
.cm-count {
    flex: 1 1 auto;
    font-size: .72rem;
    font-weight: 600;
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
    letter-spacing: .02em;
}
.cm-count:empty { display: none; }
.cm-refresh {
    appearance: none;
    background: transparent;
    border: none;
    color: var(--text-soft);
    cursor: pointer;
    padding: .25rem;
    border-radius: 6px;
    line-height: 0;
}
.cm-refresh:hover { color: var(--primary); background: var(--primary-light); }
.cm-close {
    appearance: none;
    background: transparent;
    border: none;
    color: var(--text-soft);
    cursor: pointer;
    padding: .25rem;
    border-radius: 6px;
    line-height: 0;
}
.cm-close:hover { color: var(--text); background: var(--bg); }
.cm-body {
    overflow-y: auto;
    padding-top: .55rem;
    padding-right: .15rem;
    margin-right: -.15rem;
    flex: 1;
    min-height: 0;
}
.cm-body::-webkit-scrollbar { width: 4px; }
.cm-body::-webkit-scrollbar-thumb { background: var(--border); border-radius: 4px; }

.cm-empty,
.cm-error,
.cm-skeleton-label {
    font-size: .76rem;
    color: var(--text-muted);
    margin: .35rem .15rem;
    line-height: 1.4;
}
.cm-skeleton {
    display: flex;
    flex-direction: column;
    gap: .35rem;
    margin-top: .25rem;
}
.cm-skeleton-row {
    height: 18px;
    border-radius: 6px;
    background: linear-gradient(90deg, #eef1f6 0%, #f6f8fb 50%, #eef1f6 100%);
    background-size: 200% 100%;
    animation: cmSkeletonShimmer 1.2s linear infinite;
}
@keyframes cmSkeletonShimmer {
    from { background-position: 200% 0; }
    to   { background-position: -200% 0; }
}

.cm-concept {
    margin-bottom: .15rem;
}
.cm-concept-head {
    width: 100%;
    appearance: none;
    background: transparent;
    border: none;
    cursor: pointer;
    text-align: left;
    padding: .3rem .35rem;
    border-radius: 7px;
    display: flex;
    align-items: center;
    gap: .45rem;
    transition: background-color 120ms ease;
}
.cm-concept-head:hover:not(:disabled) { background: var(--primary-light); }
.cm-concept-head:disabled { cursor: default; }
.cm-concept-head:focus-visible {
    outline: 2px solid var(--primary);
    outline-offset: 1px;
}

.cm-icon {
    flex: 0 0 14px;
    width: 14px;
    height: 14px;
    line-height: 0;
}
.cm-name {
    flex: 1 1 auto;
    font-size: .82rem;
    font-weight: 600;
    color: var(--text);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    transition: color 200ms ease;
}
.cm-bar {
    flex: 0 0 48px;
    height: 4px;
    border-radius: 999px;
    background: var(--border);
    overflow: hidden;
    position: relative;
}
.cm-bar-fill {
    display: block;
    height: 100%;
    background: var(--primary);
    border-radius: 999px;
    transition: width 250ms ease-out;
}

/* Status modifiers — applied on the row, cascade into icon + bar fill.
   Locked names render in full (muted color + lock icon still signal the
   gate) — students should be able to read the whole map. */
.cm-locked .cm-name {
    color: var(--text-muted);
}
.cm-locked .cm-icon { color: var(--text-muted); opacity: .7; }
.cm-locked .cm-bar-fill { background: var(--text-muted); }

.cm-unlocked .cm-icon { color: var(--text-soft); }
.cm-unlocked .cm-bar-fill { background: var(--text-soft); }

.cm-in_progress .cm-icon { color: var(--primary); }
.cm-in_progress .cm-bar-fill { background: var(--primary); }

.cm-mastered .cm-icon { color: var(--green); }
.cm-mastered .cm-bar-fill { background: var(--green); }
.cm-mastered .cm-name { color: var(--green); }

/* Active concept — the one the student is currently leveling up. Subtle
   left-border accent + slightly heavier name; the in-flight pulse below
   handles the "orbs just landed" beat. */
.cm-concept-active > .cm-concept-head {
    background: var(--primary-light);
    box-shadow: inset 3px 0 0 var(--primary);
}
.cm-concept-active .cm-name { font-weight: 700; }

.cm-row-pulsing > .cm-concept-head {
    animation: cmRowPulse 380ms ease-out;
}
@keyframes cmRowPulse {
    0%   { background: var(--primary-light); transform: scale(1); }
    35%  { background: rgba(30, 64, 232, 0.18); transform: scale(1.015); }
    100% { background: var(--primary-light); transform: scale(1); }
}

/* Concept unlock celebration — fires when a concept transitions from
   "locked" to "unlocked" via the prerequisite chain. JS handles the icon
   crossfade + sparks; CSS handles the gold sweep + glow on the row. */
.cm-concept-unlocking > .cm-concept-head {
    position: relative;
    overflow: hidden;
    animation: cmUnlockGlow 1.4s ease-out;
}
.cm-concept-unlocking > .cm-concept-head::before {
    content: '';
    position: absolute;
    inset: 0;
    background: linear-gradient(
        100deg,
        transparent 30%,
        rgba(255, 215, 0, 0.55) 50%,
        transparent 70%
    );
    transform: translateX(-100%);
    animation: cmUnlockSweep 0.9s ease-out 0.12s;
    pointer-events: none;
    border-radius: inherit;
}
@keyframes cmUnlockGlow {
    0%   { box-shadow: 0 0 0 0 rgba(255, 215, 0, 0); background-color: transparent; }
    25%  { box-shadow: 0 0 16px 2px rgba(255, 215, 0, 0.55); background-color: rgba(255, 215, 0, 0.12); }
    100% { box-shadow: 0 0 0 0 rgba(255, 215, 0, 0); background-color: transparent; }
}
@keyframes cmUnlockSweep {
    0%   { transform: translateX(-100%); }
    100% { transform: translateX(100%); }
}

.cm-caret {
    flex: 0 0 10px;
    width: 10px;
    height: 10px;
    line-height: 0;
    color: var(--text-muted);
    transition: transform 160ms ease;
}
.cm-concept.cm-expanded .cm-caret {
    transform: rotate(180deg);
}
.cm-cards {
    display: none;
    margin: .15rem 0 .35rem calc(14px + .8rem);
    flex-direction: column;
    gap: .1rem;
}
.cm-concept.cm-expanded .cm-cards {
    display: flex;
}
.cm-card-item {
    appearance: none;
    background: transparent;
    border: none;
    cursor: pointer;
    text-align: left;
    padding: .25rem .35rem;
    border-radius: 5px;
    display: flex;
    align-items: center;
    gap: .4rem;
    font-size: .75rem;
    color: var(--text-soft);
}
.cm-card-item:hover { background: var(--primary-light); color: var(--text); }
.cm-card-dot {
    flex: 0 0 6px;
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--text-muted);
}
.cm-card-mastered .cm-card-dot { background: var(--green); }
.cm-card-preview {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Rail width per breakpoint is driven by --rail-w (set on <html> above) so
   the reserved gutter on .study always matches the panel's real width. */

/* --- Floating "+XP" text --- */

.xp-floater {
    position: fixed;
    z-index: 9200;
    pointer-events: none;
    font-family: var(--font-display);
    font-weight: 900;
    font-size: 1.6rem;
    letter-spacing: .01em;
    text-shadow: 0 2px 8px rgba(0,0,0,.18), 0 0 14px currentColor;
    transform-origin: center;
}

.xp-floater-main {
    line-height: 1;
}

.xp-floater-details {
    display: flex;
    justify-content: center;
    gap: .25rem;
    flex-wrap: wrap;
    margin-top: .3rem;
    max-width: min(340px, calc(100vw - 2rem));
}

.xp-floater-pill {
    display: inline-flex;
    align-items: center;
    min-height: 18px;
    padding: .12rem .34rem;
    border-radius: 999px;
    background: rgba(255,255,255,.92);
    border: 1px solid rgba(255,255,255,.95);
    box-shadow: 0 2px 8px rgba(15,23,42,.14);
    color: #1f2937;
    font-family: var(--font-sans);
    font-size: .58rem;
    font-weight: 800;
    letter-spacing: .03em;
    text-shadow: none;
    white-space: nowrap;
}

.xp-floater-crit {
    font-size: 2.2rem;
    text-shadow: 0 0 18px #facc15, 0 0 36px #facc15, 0 2px 6px rgba(0,0,0,.25);
}
.xp-floater-crit::before {
    content: '';
    position: absolute;
    inset: -30%;
    background: radial-gradient(circle, rgba(250,204,21,.55), rgba(250,204,21,0) 65%);
    z-index: -1;
    border-radius: 50%;
    animation: xpCritBurst 600ms ease-out;
}
.xp-floater-crit-label {
    font-size: .7rem;
    font-weight: 800;
    letter-spacing: .14em;
    color: #facc15;
    margin-top: .15rem;
    text-shadow: 0 0 8px rgba(250,204,21,.85);
}

.xp-floater-spark {
    color: #7e22ce !important;
    text-shadow:
        0 0 14px rgba(168,85,247,.75),
        0 0 34px rgba(34,211,238,.55),
        0 2px 8px rgba(15,23,42,.22);
}
.xp-floater-spark::after {
    content: '';
    position: absolute;
    inset: -35% -25%;
    z-index: -1;
    border-radius: 50%;
    background:
        radial-gradient(circle at 35% 45%, rgba(255,255,255,.75), transparent 24%),
        radial-gradient(circle, rgba(168,85,247,.48), rgba(34,211,238,.20) 46%, transparent 70%);
    animation: xpSparkDropBurst 780ms ease-out forwards;
}

@keyframes xpCritBurst {
    0%   { transform: scale(0.4); opacity: 0; }
    35%  { transform: scale(1.25); opacity: 1; }
    100% { transform: scale(1.6); opacity: 0; }
}

@keyframes xpSparkDropBurst {
    0%   { transform: scale(0.45) rotate(0deg); opacity: 0; }
    25%  { transform: scale(1.1) rotate(10deg); opacity: 1; }
    100% { transform: scale(1.55) rotate(28deg); opacity: 0; }
}

/* --- Orbs that arc from answer-input into the tank --- */

.xp-orb {
    position: fixed;
    width: 12px;
    height: 12px;
    border-radius: 50%;
    z-index: 9100;
    pointer-events: none;
    background: radial-gradient(circle at 35% 30%, #ffffff 0%, #6a86fa 45%, var(--primary) 100%);
    box-shadow: 0 0 8px rgba(30, 64, 232, .85), 0 0 18px rgba(30, 64, 232, .45);
    transform: translate(-50%, -50%);
}

.xp-orb-crit {
    background: radial-gradient(circle at 35% 30%, #ffffff 0%, #fde68a 45%, #f59e0b 100%);
    box-shadow: 0 0 10px rgba(250, 204, 21, .9), 0 0 24px rgba(250, 204, 21, .6);
}

/* Orb impact flash — fires at the moment the thunk note plays, fades the
   orb out as part of the same animation so we don't fight GSAP transforms. */
.xp-orb-impact { animation: xpOrbImpact 120ms ease-out forwards; }
@keyframes xpOrbImpact {
    0%   { filter: brightness(1) saturate(1); opacity: 1; }
    50%  { filter: brightness(1.7) saturate(1.5); opacity: 1; }
    100% { filter: brightness(1.2) saturate(1.2); opacity: 0; }
}

/* --- Mobile: rail collapses; map hidden below 720px --- */

@media (max-width: 720px) {
    .study-side-rail {
        top: 1rem;
        right: 1rem;
        left: 1rem;
        bottom: auto;
        transform: none;
        flex-direction: row;
        align-items: center;
        gap: .5rem;
        width: auto;
    }
    .concept-map-panel { display: none; }
}

/* --- Session complete --- */

.study-done {
    text-align: center;
    padding: 3rem 1rem;
    background: var(--surface);
    border: 1.5px solid var(--border);
    border-radius: var(--radius);
}
.study-done h2 { margin-bottom: .5rem; }
.study-done p { color: var(--text-muted); margin-bottom: 1.25rem; }
.study-done .btn + .btn { margin-left: .5rem; }


