/* Core layout and component styles for the Staples Education ODE Roadmap. */

* {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
}

body {
    font-family: 'Segoe UI', 'Inter', system-ui, sans-serif;
    min-height: 100vh;
    display: flex;
    flex-direction: column;
}

/* Global Header */

.global-header {
    background-color: var(--header-bg);
    border-bottom: 1px solid var(--panel-border);
    padding: 1.5rem 2rem;
}

.header-inner {
    max-width: 1200px;
    margin: 0 auto;
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: 1.5rem;
    flex-wrap: wrap;
}

/* Campus bar (standardized header topography, 2026-07-12): the shared top
   row of every shell. Brand and Explore on the left, the identity cluster
   on the right, one flex row with space-between, wrap-ready so narrow
   viewports stack the clusters instead of scrolling horizontally. */
.campus-bar {
    max-width: 1200px;
    margin: 0 auto 1.1rem;
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 0.75rem 1rem;
    flex-wrap: wrap;
    padding-bottom: 0.85rem;
    border-bottom: 1px solid var(--panel-border);
}

.campus-left {
    display: flex;
    align-items: center;
    gap: 0.9rem;
    min-width: 0;
}

.campus-brand {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    text-decoration: none;
    color: inherit;
}

.campus-logo {
    width: 26px;
    height: 26px;
    border-radius: 6px;
    display: block;
    flex-shrink: 0;
}

.campus-brand-name {
    font-size: 0.95rem;
    font-weight: 700;
    letter-spacing: -0.01em;
    color: var(--text-color);
    white-space: nowrap;
}

.campus-brand:hover .campus-brand-name,
.campus-brand:focus-visible .campus-brand-name {
    color: var(--accent-text);
}

/* Explore menu items: the active classroom links out; locked streams read
   as muted labels wearing a Coming Soon badge, never as dead links. */
.nav-dropdown-menu .explore-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    white-space: nowrap;
}

.explore-item.explore-active {
    color: var(--accent-text);
    font-weight: 600;
}

span.explore-item.explore-locked {
    padding: 0.5rem 0.75rem;
    color: var(--locked-color);
    font-size: 0.85rem;
    cursor: default;
}

.explore-badge {
    border: 1px solid var(--locked-color);
    color: var(--locked-color);
    border-radius: 999px;
    padding: 0.05rem 0.5rem;
    font-size: 0.68rem;
    font-weight: 600;
    flex-shrink: 0;
}

/* The signed-in cluster's doorway back to the apex hub. */
.auth-portal-link {
    color: var(--accent-text);
    text-decoration: none;
    font-size: 0.85rem;
    font-weight: 600;
    padding: 0.35rem 0.6rem;
    border-radius: 8px;
    white-space: nowrap;
}

.auth-portal-link:hover,
.auth-portal-link:focus-visible {
    background: var(--accent-soft);
    outline: none;
}

.app-title {
    font-size: 1.8rem;
    font-weight: 700;
    margin-top: 0.25rem;
}

.app-subtitle {
    color: var(--text-secondary);
    margin-top: 0.25rem;
    font-size: 0.95rem;
}

.header-controls {
    display: flex;
    align-items: center;
    gap: 1rem;
    flex-wrap: wrap;
}

/* Google account sync controls. The sign-in button itself is rendered by the
   Identity Services SDK inside an iframe, so only its container and the
   signed-in status chip are styled here; both read live theme tokens so
   Light and Dark render natively. */
.auth-controls {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    min-height: 32px;
}

/* The hidden attribute state.js sets on the slot for signed-in students must
   always win over any future display/flex rule that targets the slot, or the
   GIS button iframe inside would resurface next to the sync status chip. */
#auth-signin-slot[hidden] {
    display: none !important;
}

/* Signed-in identity cluster: circular avatar + gear icon. The avatar is a
   nav-dropdown trigger, so hovering or focusing it opens the compact account
   menu through the same CSS-only mechanics as the Browse menu. */
.auth-identity {
    display: flex;
    align-items: center;
    gap: 0.4rem;
}

.auth-identity[hidden] {
    display: none;
}

.auth-avatar-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    padding: 0;
    background: var(--panel-bg);
    border: 2px solid var(--panel-border);
    border-radius: 50%;
    cursor: pointer;
    overflow: hidden;
    transition: border-color 0.2s ease, box-shadow 0.2s ease;
}

.auth-dropdown:hover .auth-avatar-btn,
.auth-dropdown:focus-within .auth-avatar-btn {
    border-color: var(--accent-color);
    box-shadow: 0 0 0 3px var(--accent-soft);
}

.auth-avatar-btn:focus-visible {
    outline: 2px solid var(--accent-color);
    outline-offset: 2px;
}

/* The avatar image is masked to a circle by its clipping container above
   and its own radius, so any square Google photo renders as a clean disc. */
.auth-avatar {
    width: 100%;
    height: 100%;
    border-radius: 50%;
    object-fit: cover;
    display: block;
}

.auth-avatar[hidden] {
    display: none;
}

/* Initial-letter badge shown when no picture claim exists or the photo
   fails to load. */
.auth-avatar-fallback {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    height: 100%;
    background: var(--accent-soft);
    color: var(--accent-text, var(--accent-color));
    font-size: 0.9rem;
    font-weight: 700;
}

.auth-avatar-fallback[hidden] {
    display: none;
}

/* The account menu opens under the avatar, right-aligned so it never
   overflows the viewport from the header's right edge. Scoped through the
   dropdown container so it outranks the base .nav-dropdown-menu left
   anchor regardless of source order. */
.auth-dropdown .nav-dropdown-menu {
    left: auto;
    right: 0;
    min-width: 13rem;
}

.auth-menu-identity {
    display: flex;
    flex-direction: column;
    gap: 0.1rem;
    padding: 0.5rem 0.75rem;
    border-bottom: 1px solid var(--panel-border);
    margin-bottom: 0.25rem;
}

.auth-status-label {
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--text-color);
    overflow-wrap: anywhere;
}

.auth-status-email {
    font-size: 0.78rem;
    color: var(--text-secondary);
    overflow-wrap: anywhere;
}

.auth-status-email[hidden] {
    display: none;
}

.auth-signout {
    color: var(--accent-color);
}

/* Minimalist gear, a quiet doorway to the settings view. */
.auth-gear {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    border-radius: 50%;
    color: var(--text-secondary);
    transition: color 0.2s ease, background-color 0.2s ease, transform 0.3s ease;
}

.auth-gear:hover,
.auth-gear:focus-visible {
    color: var(--accent-color);
    background: var(--accent-soft);
    transform: rotate(30deg);
    outline: none;
}

/* Mobile auth adjustments live in the unified 768px block at the end of this
   sheet, alongside the rest of the header's responsive rules. */

/* Learning mode is selected through the shared .nav-dropdown component (see the
   Global navigation dropdown block below), so it carries no dedicated styling. */

/* The color theme control is selected through the shared .nav-dropdown
   component (see the Global navigation dropdown block below), so it carries no
   dedicated styling, matching the learning mode control. */

/* Global navigation dropdown, CSS-only via :hover and :focus-within */

.nav-dropdown {
    position: relative;
    display: inline-block;
}

.nav-dropdown-trigger {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    background: var(--panel-bg);
    color: var(--text-color);
    border: 1px solid var(--panel-border);
    border-radius: 8px;
    padding: 0.5rem 1rem;
    font-size: 0.85rem;
    font-family: inherit;
    cursor: pointer;
    transition: background-color 0.2s ease;
}

.nav-dropdown-trigger:hover,
.nav-dropdown:focus-within .nav-dropdown-trigger {
    background: var(--accent-soft);
}

.nav-dropdown-trigger:focus-visible {
    outline: 2px solid var(--accent-color);
    outline-offset: 2px;
}

/* Indicator arrow, rotates on expansion */

.nav-dropdown-arrow {
    width: 0;
    height: 0;
    border-left: 4px solid transparent;
    border-right: 4px solid transparent;
    border-top: 5px solid currentColor;
    transition: transform 0.2s ease;
}

.nav-dropdown:hover .nav-dropdown-arrow,
.nav-dropdown:focus-within .nav-dropdown-arrow {
    transform: rotate(180deg);
}

/* The menu panel, hidden until hover or focus-within */

.nav-dropdown-menu {
    position: absolute;
    top: calc(100% + 0.4rem);
    left: 0;
    z-index: 1100;
    min-width: 12rem;
    margin: 0;
    padding: 0.35rem;
    list-style: none;
    background: var(--panel-bg);
    border: 1px solid var(--panel-border);
    border-radius: 10px;
    box-shadow: 0 8px 24px var(--shadow-color);
    opacity: 0;
    transform: translateY(-6px);
    pointer-events: none;
    visibility: hidden;
    transition: opacity 0.2s ease, transform 0.2s ease, visibility 0s linear 0.2s;
}

/* Transparent hover bridge spanning the 0.4rem gap below the trigger, so the
   cursor never leaves a hoverable descendant while crossing into the panel.
   Inherits the menu's pointer-events, so it stays inert while the menu is hidden. */
.nav-dropdown-menu::before {
    content: "";
    position: absolute;
    top: -0.4rem;
    left: 0;
    right: 0;
    height: 0.4rem;
}

.nav-dropdown:hover .nav-dropdown-menu,
.nav-dropdown:focus-within .nav-dropdown-menu {
    opacity: 1;
    transform: translateY(0);
    pointer-events: auto;
    visibility: visible;
    transition: opacity 0.2s ease, transform 0.2s ease, visibility 0s linear 0s;
}

.nav-dropdown-menu li {
    margin: 0;
}

.nav-dropdown-menu a,
.nav-dropdown-menu button {
    display: block;
    width: 100%;
    text-align: left;
    padding: 0.5rem 0.75rem;
    border: none;
    border-radius: 6px;
    background: none;
    color: var(--text-color);
    text-decoration: none;
    font-size: 0.85rem;
    font-family: inherit;
    cursor: pointer;
    transition: background-color 0.2s ease, color 0.2s ease;
}

.nav-dropdown-menu a:hover,
.nav-dropdown-menu a:focus-visible,
.nav-dropdown-menu button:hover,
.nav-dropdown-menu button:focus-visible {
    background: var(--accent-soft);
    color: var(--accent-color);
    outline: none;
}

/* The rightmost header dropdown opens right-aligned: with the identity
   cluster collapsing completely while signed out, the theme trigger can sit
   flush against the header's right edge, and a left-aligned panel there
   would widen the document past the viewport. */
.theme-dropdown .nav-dropdown-menu {
    left: auto;
    right: 0;
}

/* The active learning mode option, marked so the open menu shows the selection. */
.nav-dropdown-menu button.active {
    background: var(--accent-soft);
    color: var(--accent-color);
    font-weight: 600;
}

/* Static navigation pages (Practice Sets, Cheat Sheets, and other scaffolded
   routes). The container inherits the app-container width from #app-content. */

.static-page {
    width: 100%;
}

.static-page-title {
    font-size: 1.8rem;
    font-weight: 700;
    color: var(--text-color);
    border-bottom: 2px solid var(--accent-color);
    padding-bottom: 0.5rem;
    margin: 0 0 1rem;
}

.static-page-placeholder {
    color: var(--text-secondary);
    font-size: 1rem;
}

/* Reusable primary action button for downloadable PDF links. Style an anchor
   to look like a primary button, inheriting the theme accent and shadow. */

.pdf-download-btn {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    background: var(--accent-color);
    color: var(--bg-color);
    border: 1px solid var(--accent-color);
    border-radius: 8px;
    padding: 0.6rem 1.1rem;
    font-size: 0.9rem;
    font-family: inherit;
    font-weight: 600;
    text-decoration: none;
    cursor: pointer;
    transition: background-color 0.2s ease, box-shadow 0.2s ease, transform 0.1s ease;
}

.pdf-download-btn:hover {
    background: var(--accent-soft);
    color: var(--accent-color);
    box-shadow: 0 4px 14px var(--shadow-color);
}

.pdf-download-btn:focus-visible {
    outline: 2px solid var(--accent-color);
    outline-offset: 2px;
}

.pdf-download-btn:active {
    transform: translateY(1px);
}

/* Materials index pages (Cheat Sheets and Practice Sets), rendered by router.js.
   The cards reuse the Table of Contents grid for responsive layout, and mirror
   the unit card look as a static container that holds its own action buttons. */

.materials-card {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
    /* Pack every content block at the top so the title, description, button, and
       topic guides sit flush together. The grid stretches cards to a shared row
       height, and flex-start collects any leftover space at the bottom of the
       card, beneath the last subtopic, keeping a clean baseline across the row. */
    justify-content: flex-start;
    background: var(--panel-bg);
    border: 1px solid var(--panel-border);
    border-radius: 14px;
    padding: 1.5rem;
    box-shadow: 0 2px 12px var(--shadow-color);
}

.materials-card-title {
    font-size: 1.15rem;
    font-weight: 700;
}

.materials-card-desc {
    color: var(--text-secondary);
    font-size: 0.9rem;
    line-height: 1.4;
}

/* The primary action button hugs its content rather than stretching the card,
   and sits directly below the description on every card. The card no longer
   grows the description to fill height, so a short unit and a long unit place
   their button at the same tight offset under the text. */
.materials-card .pdf-download-btn {
    align-self: flex-start;
}

/* The topic guides block sits naturally right below the primary action button,
   separated only by the card flex gap and its own top border and padding. The
   card itself collects any leftover space at the bottom (see .materials-card),
   so there is no artificial gap between the button and this list. */
.materials-subtopics {
    border-top: 1px solid var(--panel-border);
    padding-top: 0.75rem;
}

.materials-subtopics-label {
    font-size: 0.8rem;
    font-weight: 600;
    color: var(--text-secondary);
    margin-bottom: 0.4rem;
}

.materials-subtopics-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
}

/* A lighter link for each topic guide PDF, set apart from the solid primary
   button above it by a small accent marker rather than a filled background. */
.pdf-download-link {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    color: var(--accent-color);
    text-decoration: none;
    font-size: 0.88rem;
    font-weight: 600;
    padding: 0.3rem 0.5rem;
    border-radius: 6px;
    transition: background-color 0.15s ease;
}

.pdf-download-link::before {
    content: "";
    width: 0.5rem;
    height: 0.5rem;
    border-radius: 2px;
    background: var(--accent-color);
    flex-shrink: 0;
}

.pdf-download-link:hover {
    background: var(--accent-soft);
}

.pdf-download-link:focus-visible {
    outline: 2px solid var(--accent-color);
    outline-offset: 2px;
}

/* A plain text topic guide entry, used on the Practice Sets and Interactives
   hubs where the topic is not a downloadable PDF. It mirrors the link spacing
   and accent marker without the interactive affordance. */
.materials-subtopic-text {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    color: var(--text-secondary);
    font-size: 0.88rem;
    padding: 0.3rem 0.5rem;
}

.materials-subtopic-text::before {
    content: "";
    width: 0.5rem;
    height: 0.5rem;
    border-radius: 2px;
    background: var(--accent-color);
    flex-shrink: 0;
}

/* Practice Set sub-view (problems and toggleable solutions), rendered by
   router.js. Layout only, all themed visuals come from the reused classes
   (module-title, static-page-placeholder, pdf-download-btn). The flex column
   with a flex-start cross axis lets the toggle button hug its content while the
   problem and solution bodies still stretch to the full width. */
.practice-set-section {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 0.75rem;
}

.practice-set-problems,
.practice-set-solutions {
    align-self: stretch;
}

/* Action row holding the cheat sheet download button, wraps on narrow screens. */
.practice-action-row {
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem;
}

/* Practice problem list, a plain numbered list with comfortable spacing. */
.practice-problem-list {
    margin: 0;
    padding-left: 1.5rem;
}

.practice-problem-list li {
    margin-bottom: 0.85rem;
    line-height: 1.55;
}

/* The solutions block sits behind the toggle and is set apart with an accent
   top edge so it reads as a clearly separate section from the problems above. */
.practice-set-solutions {
    border-top: 2px solid var(--accent-color);
    padding-top: 1rem;
}

/* Each solution becomes a soft panel with an accent left bar, so a revealed
   solution is visually distinct from the practice problems. */
.practice-solution-list {
    list-style-position: inside;
    margin: 0;
    padding-left: 0;
}

.practice-solution-list li {
    margin-bottom: 0.85rem;
    line-height: 1.55;
    padding: 0.6rem 0.85rem;
    border-left: 3px solid var(--accent-color);
    background: var(--panel-bg);
    border-radius: 0 8px 8px 0;
}

/* Semantic text spans emitted by the content compiler's HTML macro lowering
   (\highlight / \work / \warn in canonical prose). Hues mirror the print
   palette in ode/assets/markdowns/preamble.tex, lightened in dark mode to
   keep AA contrast on the dark panel background. */
.tx-highlight { color: #e27a1e; font-weight: 600; }
.tx-work      { color: #a020f0; }
.tx-warn      { color: #c0392b; font-weight: 600; }

[data-theme="dark"] .tx-highlight { color: #f5a05a; }
[data-theme="dark"] .tx-work      { color: #c77bff; }
[data-theme="dark"] .tx-warn      { color: #ef7a6d; }

/* Progress banner */

/* The unified sticky header (2026-07-13): one row holding the course
   progress readout, the Back control, and the annotation controls, pinned to
   the top of the window as the reader scrolls. z-index sits above the page
   content but below the header dropdown menus (1100), the quiz modal (1000
   base), and the annotation chrome, so open menus and focused practice keep
   painting over it.

   Two states. Unpinned it is a normal strip under the brand header. Pinned
   (is-stuck, set by the IntersectionObserver in router.js) it is the page's
   only navigation, so it compacts: the padding tightens, the track thins,
   and the Back control appears. The paddings are the whole reason the bar
   can carry three controls without growing tall. */
.progress-banner {
    position: sticky;
    top: 0;
    z-index: 900;
    background: var(--header-bg);
    border-bottom: 1px solid var(--panel-border);
    box-shadow: 0 2px 10px var(--shadow-color);
    padding: 0.4rem 2rem;
    transition: padding 0.18s ease, box-shadow 0.18s ease;
}

.progress-banner.is-stuck {
    padding: 0.2rem 2rem;
    box-shadow: 0 3px 14px var(--shadow-color);
}

/* A zero height marker at the bar's natural position. It must not stick, or
   it could never leave the viewport and the bar would never learn it pinned. */
.sticky-sentinel {
    height: 0;
}

.progress-banner-inner {
    max-width: 1200px;
    margin: 0 auto;
    display: flex;
    align-items: center;
    gap: 1rem;
}

/* Back to Table of Contents and Browse belong to the frozen header only.
   Unpinned, the view's own nav row still carries the back button a few
   hundred pixels below and the real header still carries Browse, so showing
   either here would just be the same control twice. On the Table of Contents
   there is nothing to go back to, so Back stays out there; Browse has
   somewhere to go from every route, so it does not. */
.utility-back-btn,
.utility-browse {
    display: none;
}

.progress-banner.is-stuck:not(.at-toc) .utility-back-btn {
    display: inline-flex;
}

.progress-banner.is-stuck .utility-browse {
    display: inline-block;
}

/* The Browse control is the header component at the slim bar's scale, matched
   to the pill buttons beside it rather than to the full size header trigger. */
.utility-controls .nav-dropdown-trigger {
    font-size: 0.76rem;
    padding: 0.28rem 0.7rem;
    border-radius: 8px;
    white-space: nowrap;
}

/* The bar's controls sit at its right edge, so the menu hangs from the right
   or it would run off the viewport on a narrow window. */
.utility-controls .nav-dropdown-menu {
    left: auto;
    right: 0;
}

.progress-title {
    font-size: 0.68rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-secondary);
    white-space: nowrap;
}

.progress-percentage {
    font-size: 0.82rem;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/* Slot annotate.js fills with the Annotate Page and Whiteboard buttons. */
.utility-controls {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-left: 0.5rem;
}

.progress-track-bg {
    flex-grow: 1;
    min-width: 4rem;
    height: 8px;
    background: var(--bg-color);
    border: 1px solid var(--panel-border);
    border-radius: 10px;
    overflow: hidden;
    transition: height 0.18s ease;
}

/* Frozen, the track is a readout and not a feature: it gives its height back
   to the row so the pinned header stays slim. */
.progress-banner.is-stuck .progress-track-bg {
    height: 5px;
}

.progress-bar-fill {
    height: 100%;
    width: 0%;
    background: var(--accent-color);
    border-radius: 10px;
    transition: width 0.4s ease;
}

/* Main content area */

.app-container {
    max-width: 1200px;
    width: 100%;
    margin: 2rem auto;
    padding: 0 2rem;
    flex-grow: 1;
    display: flex;
    flex-direction: column;
    gap: 2rem;
}

/* Table of Contents view, rendered by router.js */

.toc-intro {
    border-bottom: 2px solid var(--accent-color);
    padding-bottom: 0.75rem;
}

.toc-heading {
    font-size: 1.6rem;
    font-weight: 700;
}

.toc-subhead {
    color: var(--text-secondary);
    margin-top: 0.35rem;
    font-size: 0.95rem;
}

.toc-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
    gap: 1.25rem;
}

/* The Interactive Visualizers dashboard, rendered by router.js. The grid mirrors
   the responsive layout of the curriculum cards; the cards reuse .materials-card
   chrome and add a context badge plus a launch action. Every color resolves
   through the theme custom properties, so light and dark modes both stay on
   palette. */

/* Two-column dashboard split: a sticky unit-navigation sidebar locked to the
   left while the unit sections scroll on the right. One flex row inside the app
   container; align-items: flex-start lets the sidebar stay short enough to
   stick rather than stretching to the content's full height. */
.interactives-layout,
.unit-detail-layout {
    display: flex;
    align-items: flex-start;
    gap: 1.5rem;
    width: 100%;
}

/* The left sidebar. Sticks 2rem below the viewport top through the whole scroll.
   Its panel wears the framework's light lavender wash (--accent-soft) with the
   --panel-border and 14px radius, so it reads as a soft violet rail in light mode
   and a muted violet-tinted panel in dark. A touch wider than the bare-number
   version so full unit titles wrap cleanly; height-capped and internally
   scrollable so a tall unit list never runs past the viewport. */
.interactives-sidebar,
.unit-toc-sidebar {
    position: sticky;
    top: 2rem;
    flex: 0 0 232px;
    display: flex;
    flex-direction: column;
    gap: 0.3rem;
    background: var(--accent-soft);
    border: 1px solid var(--panel-border);
    border-radius: 14px;
    padding: 1rem 0.85rem;
    max-height: calc(100vh - 4rem);
    overflow-y: auto;
}

.interactives-sidebar-title,
.unit-toc-title {
    font-size: 0.72rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--accent-text);
    padding: 0.1rem 0.65rem 0.5rem;
}

/* A unit anchor link carrying its full descriptive title. The brand purple text
   token (--accent-text, lightened for dark mode) is the resting label color; the
   text wraps over multiple lines with relaxed line-height and generous side
   padding so the longer strings sit beautifully. Hover/focus/active lifts it onto
   a clean page-background pill with
   a purple outline while the text stays purple, so the active state reads clearly
   against the lavender panel in both themes. */
.interactives-sidebar-link,
.unit-toc-link {
    text-align: left;
    font: inherit;
    font-size: 0.85rem;
    font-weight: 600;
    line-height: 1.35;
    color: var(--accent-text);
    background: transparent;
    border: 1px solid transparent;
    border-radius: 9px;
    padding: 0.5rem 0.75rem;
    cursor: pointer;
    white-space: normal;
    overflow-wrap: anywhere;
    transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}

.interactives-sidebar-link:hover,
.interactives-sidebar-link.active,
.unit-toc-link:hover,
.unit-toc-link.active {
    background: var(--bg-color);
    color: var(--accent-text);
    border-color: var(--accent-color);
}

.interactives-sidebar-link:focus-visible,
.unit-toc-link:focus-visible {
    outline: 2px solid var(--accent-color);
    outline-offset: 2px;
}

/* The right content column. min-width: 0 lets the inner card grid shrink inside
   the flex row instead of forcing horizontal overflow. */
.interactives-content,
.unit-detail-main {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
}

/* Per-unit bounded sections. Each unit's visualizer cards are framed in a
   solid-bordered container so the dashboard reads as distinct unit groups. The
   frame uses the page background (cards are --panel-bg) so the gray cards stand
   out cleanly inside the lighter/darker section, matching the 14px radius used
   across the framework's card chrome. scroll-margin-top keeps a section clear of
   the viewport top when a sidebar link scrolls to it. */
.unit-section-container {
    background: var(--bg-color);
    border: 1px solid var(--panel-border);
    border-radius: 14px;
    padding: 1.25rem;
    margin-bottom: 1.75rem;
    scroll-margin-top: 1rem;
}

.unit-section-container:last-child {
    margin-bottom: 0;
}

/* The lavender header box topping each unit section. Built from the accent-soft
   token (a soft violet tint over white in light mode, a muted violet over
   near-black in dark mode) with bold accent-colored text, so it reads as an
   elegant full-width lavender band with guaranteed contrast in both themes. */
.unit-lavender-header {
    background: var(--accent-soft);
    color: var(--accent-text);
    border: 1px solid var(--panel-border);
    border-radius: 10px;
    padding: 0.7rem 1rem;
    margin-bottom: 1.25rem;
    text-align: center;
    font-size: 1.05rem;
    font-weight: 700;
    letter-spacing: 0.01em;
}

.interactives-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
    gap: 1.25rem;
}

.interactive-badge {
    align-self: flex-start;
    display: inline-block;
    background: var(--accent-soft);
    color: var(--accent-text);
    border: 1px solid var(--panel-border);
    border-radius: 999px;
    padding: 0.2rem 0.7rem;
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.01em;
}

/* Cards are flex columns (inherited from .materials-card). The whole card is a
   <button>, matching the Table of Contents unit cards: clicking anywhere on the
   frame launches the tool, with no inner launch chip. The resets neutralize the
   user-agent button chrome so .materials-card's panel styling shows through
   unchanged, and the hover lift mirrors .toc-card for the same instant visual
   feedback in both themes. */
.interactive-card {
    display: flex;
    flex-direction: column;
    font: inherit;
    text-align: left;
    color: inherit;
    cursor: pointer;
    transition: transform 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease;
}

.interactive-card:hover {
    transform: translateY(-3px);
    border-color: var(--accent-color);
    box-shadow: 0 6px 18px var(--shadow-color);
}

.interactive-card:focus-visible {
    outline: 2px solid var(--accent-color);
    outline-offset: 2px;
}

/* With no launch chip below it, the description grows to absorb the card's
   leftover height (mirroring .toc-card-desc), so cards sharing a grid row keep
   flush bottom edges. */
.interactive-card .materials-card-desc {
    flex-grow: 1;
}

/* The framed panel that holds the live visualizer once it is mounted. A solid
   one-pixel border and rounded corners give the embedded checkpoint a clean,
   self-contained workspace, distinct from the dashed in-unit checkpoint frame. */
.interactive-workspace-card {
    margin-top: 1.25rem;
    background: var(--panel-bg);
    border: 1px solid var(--panel-border);
    border-radius: 14px;
    padding: 1.5rem;
}

.toc-card {
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
    text-align: left;
    font: inherit;
    color: inherit;
    cursor: pointer;
    background: var(--panel-bg);
    border: 1px solid var(--panel-border);
    border-radius: 14px;
    padding: 1.5rem;
    box-shadow: 0 2px 12px var(--shadow-color);
    transition: transform 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease;
}

.toc-card:hover {
    transform: translateY(-3px);
    border-color: var(--accent-color);
    box-shadow: 0 6px 18px var(--shadow-color);
}

.toc-card:focus-visible {
    outline: 2px solid var(--accent-color);
    outline-offset: 2px;
}

.toc-card-title {
    font-size: 1.2rem;
    font-weight: 700;
}

.toc-card-desc {
    color: var(--text-secondary);
    font-size: 0.9rem;
    line-height: 1.4;
    flex-grow: 1;
}

.toc-card-progress-track {
    height: 8px;
    background: var(--bg-color);
    border: 1px solid var(--panel-border);
    border-radius: 10px;
    overflow: hidden;
    margin-top: 0.4rem;
}

.toc-card-progress-fill {
    height: 100%;
    width: 0%;
    background: var(--accent-color);
    border-radius: 10px;
    transition: width 0.4s ease;
}

.toc-card-progress-label {
    font-size: 0.8rem;
    color: var(--text-secondary);
}

/* Unit Detail navigation, rendered by router.js. On unit pages the row holds
   the back button on the left and the compact prev/next pager on the right;
   directory views keep only the back button, unaffected by the extras. */

.unit-detail-nav {
    display: flex;
    align-items: stretch;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 0.75rem;
    width: 100%;
}

/* Previous / Next unit pager (buildUnitPager in router.js). The header variant
   sits compact at the right of the nav row; the footer variant spreads across
   the full content width below the readings block, its spacer pushing a lone
   Next button to the right edge when Unit 0 has no Previous. */
.unit-pager {
    display: flex;
    align-items: stretch;
    gap: 0.75rem;
}

.unit-pager-footer {
    width: 100%;
    margin-top: 2rem;
}

.unit-pager-spacer {
    flex: 1 1 auto;
}

/* Each pager button stacks a small directional kicker over the target unit's
   full title, wearing the same pill chrome as the back button so the nav row
   reads as one family. Titles cap at a comfortable width and wrap. */
.unit-pager-btn {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    max-width: 22rem;
    font: inherit;
    cursor: pointer;
    text-align: left;
    color: var(--text-color);
    background: var(--panel-bg);
    border: 1px solid var(--panel-border);
    border-radius: 10px;
    padding: 0.55rem 1rem;
    transition: border-color 0.15s ease, background 0.15s ease;
}

.unit-pager-btn.next {
    text-align: right;
    align-items: flex-end;
}

.unit-pager-btn:hover {
    border-color: var(--accent-color);
}

.unit-pager-btn:focus-visible {
    outline: 2px solid var(--accent-color);
    outline-offset: 2px;
}

.unit-pager-kicker {
    font-size: 0.72rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--accent-text);
}

.unit-pager-label {
    font-size: 0.85rem;
    font-weight: 600;
    line-height: 1.3;
}

/* Unit-page table of contents (unit-sidebar.js). The rail itself reuses the
   interactives sidebar chrome through the shared .unit-toc-* aliases above;
   these rules add the nested lesson / quiz / checkpoint level. */

.unit-toc-sublink {
    margin-left: 0.9rem;
    font-size: 0.78rem;
    font-weight: 500;
    padding: 0.35rem 0.65rem;
}

/* Muted note under a locked module's link, mirroring the module status text. */
.unit-toc-locked-note {
    margin: 0 0 0.2rem 1.55rem;
    font-size: 0.72rem;
    color: var(--text-secondary);
}

/* Tiny purple tag marking a lesson that carries a Micro Practice quiz. */
.unit-toc-quiz-badge {
    display: inline-block;
    margin-left: 0.4rem;
    font-size: 0.62rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--accent-text);
    border: 1px solid var(--accent-color);
    border-radius: 6px;
    padding: 0.05rem 0.3rem;
    vertical-align: 0.1em;
}

/* Sidebar scroll targets stay clear of the viewport top when jumped to. */
.module-section,
.video-card,
.checkpoint-panel,
.unit-mastery-host,
.unit-master-resource-row {
    scroll-margin-top: 1.25rem;
}

.back-to-toc-btn {
    font: inherit;
    font-weight: 600;
    font-size: 0.9rem;
    cursor: pointer;
    color: var(--accent-color);
    background: var(--panel-bg);
    border: 1px solid var(--panel-border);
    border-radius: 10px;
    padding: 0.55rem 1rem;
    transition: border-color 0.15s ease, background 0.15s ease;
}

.back-to-toc-btn:hover {
    border-color: var(--accent-color);
}

.back-to-toc-btn:focus-visible {
    outline: 2px solid var(--accent-color);
    outline-offset: 2px;
}

/* Unit sections, rendered by router.js */

.unit-section {
    display: flex;
    flex-direction: column;
    gap: 1.25rem;
}

.unit-header {
    border-bottom: 2px solid var(--accent-color);
    padding-bottom: 0.75rem;
}

.unit-title {
    font-size: 1.5rem;
    font-weight: 700;
}

.unit-desc {
    color: var(--text-secondary);
    margin-top: 0.35rem;
    font-size: 0.95rem;
}

.unit-modules {
    display: flex;
    flex-direction: column;
    gap: 1.25rem;
}

/* Module sections, rendered by router.js */

.module-section {
    background: var(--panel-bg);
    border: 1px solid var(--panel-border);
    border-radius: 14px;
    padding: 1.5rem;
    box-shadow: 0 2px 12px var(--shadow-color);
}

.module-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 1rem;
    flex-wrap: wrap;
}

.module-title {
    font-size: 1.25rem;
    font-weight: 700;
}

.module-status {
    font-size: 0.8rem;
    font-weight: 600;
    padding: 0.3rem 0.75rem;
    border-radius: 20px;
    background: var(--accent-soft);
    color: var(--accent-color);
}

.module-section.locked {
    opacity: 0.55;
}

.module-section.locked .module-status {
    background: transparent;
    border: 1px solid var(--locked-color);
    color: var(--locked-color);
}

.video-list {
    list-style: none;
    margin-top: 1rem;
    display: grid;
    /* Single column stack so each video card spans the full module width,
       giving the embedded players room to grow without full screen mode. */
    grid-template-columns: 1fr;
    gap: 2rem;
}

.video-card {
    background: var(--bg-color);
    border: 1px solid var(--panel-border);
    border-radius: 10px;
    padding: 1rem;
    /* Allow the card to fill the full width of the stacked column. */
    width: 100%;
    max-width: 100%;
}

.video-card a {
    color: var(--accent-color);
    text-decoration: none;
    font-weight: 600;
}

.video-card a:hover {
    text-decoration: underline;
}

.video-title {
    font-weight: 600;
    margin-bottom: 0.6rem;
    line-height: 1.35;
}

/* Responsive 16:9 frame. The padding-bottom of 56.25 percent is nine
   divided by sixteen, so the box keeps a true widescreen ratio at any
   width while the iframe fills it absolutely. */
.video-embed {
    position: relative;
    width: 100%;
    height: 0;
    padding-bottom: 56.25%;
    border-radius: 10px;
    overflow: hidden;
    background: var(--bg-color);
}

.video-embed iframe {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    border: 0;
}

.video-fallback-link {
    display: inline-block;
    margin-top: 0.6rem;
    font-size: 0.85rem;
    font-weight: 500;
    color: var(--text-secondary);
}

.video-watched-toggle {
    display: block;
    margin-top: 0.5rem;
}

/* Checkpoint container, populated by the checkpoint registry */

.checkpoint-panel {
    margin-top: 1.25rem;
    border: 1px dashed var(--panel-border);
    border-radius: 10px;
    padding: 1.25rem;
}

.checkpoint-heading {
    font-size: 0.95rem;
    font-weight: 700;
    margin-bottom: 0.5rem;
}

.checkpoint-placeholder {
    color: var(--text-secondary);
    font-size: 0.9rem;
}

.checkpoint-intro {
    color: var(--text-secondary);
    font-size: 0.92rem;
    margin-bottom: 0.85rem;
}

.checkpoint-begin-btn,
.check-btn {
    background: var(--accent-color);
    color: var(--bg-color);
    border: none;
    border-radius: 8px;
    padding: 0.55rem 1.2rem;
    font-size: 0.9rem;
    font-weight: 600;
    font-family: inherit;
    cursor: pointer;
    transition: opacity 0.2s ease;
}

.checkpoint-begin-btn:hover,
.check-btn:hover {
    opacity: 0.85;
}

.check-btn {
    margin-top: 1rem;
}

.checkpoint-body {
    margin-top: 0.75rem;
}

.checkpoint-prompt {
    font-size: 0.95rem;
    font-weight: 600;
    margin-bottom: 0.75rem;
}

.desmos-frame {
    /* The native Desmos expressions sidebar stays hidden; checkpoints that need
       parameter controls inject their own .slider-panel just below this frame. */
    width: 100%;
    height: 360px;
    border: 1px solid var(--panel-border);
    border-radius: 10px;
    overflow: hidden;
    margin-bottom: 0.75rem;
    background: var(--bg-color);
}

.math-canvas {
    display: block;
    width: 100%;
    height: auto;
    border: 1px solid var(--panel-border);
    border-radius: 10px;
    margin-bottom: 0.75rem;
    background: var(--bg-color);
}

/* Range slider controls for Desmos and canvas-based widgets */

/* Groups the native HTML sliders into a tidy control panel beneath a graph. */
.slider-panel {
    margin: 0 0 1rem;
    padding: 0.85rem 1rem;
    background: var(--panel-bg);
    border: 1px solid var(--panel-border);
    border-radius: 10px;
}

.slider-row {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    margin: 0.6rem 0 1rem;
}

/* Inside a panel the rows sit closer together and need no outer margins. */
.slider-panel .slider-row {
    margin: 0.55rem 0;
}

.slider-panel .slider-row:first-child {
    margin-top: 0;
}

.slider-panel .slider-row:last-child {
    margin-bottom: 0;
}

.slider-label {
    font-weight: 700;
    font-size: 0.95rem;
    /* A shared width keeps every slider track left-aligned in the column. */
    min-width: 2.25rem;
    flex-shrink: 0;
}

.slider-row input[type="range"] {
    flex: 1 1 auto;
    /* min-width: 0 lets the track shrink so it never overflows a narrow card. */
    min-width: 0;
    accent-color: var(--accent-color);
    cursor: pointer;
}

.slider-readout {
    font-family: Consolas, Monaco, monospace;
    font-size: 0.9rem;
    min-width: 3.5rem;
    text-align: right;
    flex-shrink: 0;
}

/* Fixed point iteration widget */

.iteration-display {
    font-family: Consolas, Monaco, monospace;
    font-size: 1rem;
    font-weight: 700;
    padding: 0.6rem 0.8rem;
    background: var(--bg-color);
    border: 1px solid var(--panel-border);
    border-radius: 8px;
    margin-bottom: 0.6rem;
}

.iteration-log {
    font-family: Consolas, Monaco, monospace;
    font-size: 0.82rem;
    color: var(--text-secondary);
    margin-bottom: 0.75rem;
    min-height: 1rem;
}

/* Feedback and the guiding question failure state */

.checkpoint-feedback {
    margin-top: 0.9rem;
    border-radius: 10px;
    font-size: 0.92rem;
}

.checkpoint-feedback.success {
    border: 1px solid var(--success-color);
    color: var(--success-color);
    padding: 0.8rem 1rem;
    font-weight: 600;
}

.checkpoint-feedback.failure {
    border: 1px solid var(--accent-color);
    padding: 0.8rem 1rem;
}

.guiding-question {
    font-style: italic;
    margin-top: 0.4rem;
    color: var(--accent-color);
    font-weight: 600;
}

.feedback-extra {
    margin-top: 0.4rem;
    color: var(--text-secondary);
    font-size: 0.85rem;
}

/* Matching game */

.match-board {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 1rem;
}

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

.match-item {
    position: relative;
    background: var(--bg-color);
    color: var(--text-color);
    border: 1px solid var(--panel-border);
    border-radius: 8px;
    padding: 0.65rem 0.8rem;
    font-size: 0.88rem;
    font-family: inherit;
    text-align: left;
    cursor: pointer;
    transition: border-color 0.15s ease;
}

.match-item:hover {
    border-color: var(--accent-color);
}

.match-item.selected {
    border-color: var(--accent-color);
    background: var(--accent-soft);
}

.pair-badge {
    position: absolute;
    top: -8px;
    right: -8px;
    background: var(--accent-color);
    color: var(--bg-color);
    font-size: 0.7rem;
    font-weight: 700;
    width: 20px;
    height: 20px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
}

/* Category sorter */

.sorter-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    padding: 0.5rem 0;
    border-bottom: 1px solid var(--panel-border);
}

.sorter-text {
    font-size: 0.9rem;
}

.sorter-select {
    background: var(--bg-color);
    color: var(--text-color);
    border: 1px solid var(--panel-border);
    border-radius: 8px;
    padding: 0.45rem 0.6rem;
    font-size: 0.85rem;
    font-family: inherit;
}

/* Expression tasks */

.expr-row {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    margin-bottom: 0.6rem;
    flex-wrap: wrap;
}

.expr-label {
    font-size: 0.9rem;
    font-weight: 600;
    min-width: 120px;
}

.expr-input {
    flex-grow: 1;
    min-width: 200px;
    background: var(--bg-color);
    color: var(--text-color);
    border: 1px solid var(--panel-border);
    border-radius: 8px;
    padding: 0.55rem 0.75rem;
    font-size: 0.9rem;
    font-family: Consolas, Monaco, monospace;
}

.expr-input:focus {
    outline: none;
    border-color: var(--accent-color);
}

/* Multiple choice logic gate */

.mcq-question {
    font-size: 0.95rem;
    margin-bottom: 0.75rem;
}

.mcq-option {
    display: block;
    width: 100%;
    background: var(--bg-color);
    color: var(--text-color);
    border: 1px solid var(--panel-border);
    border-radius: 8px;
    padding: 0.65rem 0.9rem;
    margin-bottom: 0.5rem;
    font-size: 0.9rem;
    font-family: inherit;
    text-align: left;
    cursor: pointer;
    transition: border-color 0.15s ease, background 0.15s ease;
}

.mcq-option:hover {
    border-color: var(--accent-color);
    background: var(--accent-soft);
}

/* Quiz, Micro Practice (per video) and Unit Mastery (per unit).
   Micro Practice renders inline beside the video in a split layout. Unit
   Mastery keeps a launch card that opens a full screen modal overlay. */

/* Split layout, the video on the left and its Micro Practice on the right, so
   the student can watch and practice at the same time. The video column takes
   roughly two thirds of the width, the quiz column the remaining third. */
.video-lesson-split {
    display: grid;
    grid-template-columns: 2fr 1fr;
    gap: 1.5rem;
    align-items: start;
}

.video-lesson-main {
    min-width: 0;
}

.video-quiz-host {
    min-width: 0;
}

.unit-mastery-host {
    margin-top: 1.25rem;
}

/* Inline Micro Practice panel, the questions live directly in the column. */
.quiz-inline-panel {
    background: var(--panel-bg);
    border: 1px solid var(--panel-border);
    border-radius: 10px;
    padding: 0.9rem 1.1rem;
}

.quiz-inline-header {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 0.75rem;
}

.quiz-inline-title {
    font-size: 1rem;
    margin: 0;
}

.quiz-inline-body {
    margin-top: 0.85rem;
}

.quiz-inline-footer {
    margin-top: 0.85rem;
    display: flex;
    justify-content: flex-end;
    gap: 0.6rem;
    min-height: 1rem;
}

/* Launch card */

.quiz-launch-card {
    background: var(--panel-bg);
    border: 1px solid var(--panel-border);
    border-radius: 10px;
    padding: 0.9rem 1.1rem;
}

.unit-mastery-host .quiz-launch-card {
    border-color: var(--accent-color);
}

.quiz-title {
    font-size: 1rem;
    margin: 0;
}

.quiz-intro {
    font-size: 0.85rem;
    color: var(--text-secondary);
    margin: 0.4rem 0 0;
}

.quiz-progress {
    font-size: 0.8rem;
    color: var(--text-secondary);
    font-variant-numeric: tabular-nums;
    margin: 0.55rem 0 0.7rem;
}

.quiz-launch-btn {
    background: var(--accent-color);
    color: var(--bg-color);
    border: none;
    border-radius: 8px;
    padding: 0.55rem 1.1rem;
    font-size: 0.9rem;
    font-family: inherit;
    font-weight: 600;
    cursor: pointer;
    transition: opacity 0.15s ease;
}

.quiz-launch-btn:hover {
    opacity: 0.9;
}

/* Modal overlay */

body.quiz-modal-open {
    overflow: hidden;
}

.quiz-modal-overlay {
    position: fixed;
    inset: 0;
    z-index: 1000;
    background: rgba(0, 0, 0, 0.55);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 1.25rem;
}

.quiz-modal {
    background: var(--bg-color);
    color: var(--text-color);
    border: 1px solid var(--panel-border);
    border-radius: 12px;
    box-shadow: 0 18px 50px var(--shadow-color);
    width: 100%;
    max-width: 640px;
    max-height: 90vh;
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

.quiz-modal-header {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 1rem 1.25rem;
    border-bottom: 1px solid var(--panel-border);
}

.quiz-modal-title {
    font-size: 1.05rem;
    margin: 0;
    flex: 1;
}

.quiz-score {
    font-size: 0.85rem;
    font-variant-numeric: tabular-nums;
    color: var(--text-secondary);
    white-space: nowrap;
}

.quiz-modal-close {
    background: transparent;
    color: var(--text-secondary);
    border: 1px solid var(--panel-border);
    border-radius: 8px;
    padding: 0.4rem 0.75rem;
    font-size: 0.8rem;
    font-family: inherit;
    cursor: pointer;
    transition: border-color 0.15s ease, color 0.15s ease;
}

.quiz-modal-close:hover {
    border-color: var(--error-color);
    color: var(--error-color);
}

.quiz-modal-body {
    padding: 1.25rem;
    overflow-y: auto;
}

.quiz-counter {
    font-size: 0.78rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--text-secondary);
    margin: 0 0 0.6rem;
}

.quiz-prompt {
    font-size: 1rem;
    margin: 0 0 0.9rem;
}

/* General hint toggle */

.quiz-hint-toggle {
    background: transparent;
    color: var(--accent-color);
    border: 1px solid var(--panel-border);
    border-radius: 6px;
    padding: 0.3rem 0.7rem;
    font-size: 0.8rem;
    font-family: inherit;
    cursor: pointer;
    margin-bottom: 0.85rem;
    transition: border-color 0.15s ease;
}

.quiz-hint-toggle:hover {
    border-color: var(--accent-color);
}

.quiz-hint {
    background: var(--accent-soft);
    border-radius: 8px;
    padding: 0.6rem 0.85rem;
    margin: 0 0 0.9rem;
}

.quiz-hint-text {
    font-size: 0.88rem;
    margin: 0;
    color: var(--text-color);
}

/* Options and their inline rationales */

.quiz-option-row {
    margin-bottom: 0.55rem;
}

.quiz-option {
    display: block;
    width: 100%;
    background: var(--bg-color);
    color: var(--text-color);
    border: 1px solid var(--panel-border);
    border-radius: 8px;
    padding: 0.7rem 0.95rem;
    font-size: 0.92rem;
    font-family: inherit;
    text-align: left;
    cursor: pointer;
    transition: border-color 0.15s ease, background 0.15s ease;
}

.quiz-option:hover:not(:disabled) {
    border-color: var(--accent-color);
    background: var(--accent-soft);
}

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

.quiz-option.correct {
    border-color: var(--success-color);
    background: var(--accent-soft);
    color: var(--success-color);
    font-weight: 600;
}

.quiz-option.incorrect {
    border-color: var(--error-color);
    color: var(--error-color);
    opacity: 0.85;
}

.quiz-rationale {
    background: var(--accent-soft);
    border-radius: 6px;
    padding: 0.55rem 0.8rem;
    margin: 0.4rem 0 0.2rem 0.6rem;
}

.quiz-rationale.incorrect {
    border-left: 3px solid var(--error-color);
}

.quiz-rationale.incorrect .quiz-rationale-text {
    color: var(--error-color);
}

.quiz-rationale.correct {
    border-left: 3px solid var(--success-color);
}

.quiz-rationale.correct .quiz-rationale-text {
    color: var(--success-color);
}

.quiz-rationale-text {
    font-size: 0.88rem;
    margin: 0;
}

/* Practice complete summary */

.quiz-summary {
    text-align: center;
    padding: 1.25rem 0.5rem 0.5rem;
}

.quiz-summary-title {
    font-size: 1.2rem;
    margin: 0 0 0.6rem;
}

.quiz-summary-score {
    font-size: 1.05rem;
    font-weight: 600;
    color: var(--success-color);
    font-variant-numeric: tabular-nums;
    margin: 0 0 0.6rem;
}

.quiz-summary-message {
    font-size: 0.9rem;
    color: var(--text-secondary);
    margin: 0;
    line-height: 1.5;
}

.quiz-modal-footer {
    padding: 1rem 1.25rem;
    border-top: 1px solid var(--panel-border);
    display: flex;
    justify-content: flex-end;
    gap: 0.6rem;
    min-height: 1rem;
}

.quiz-retry-btn {
    background: transparent;
    color: var(--accent-color);
    border: 1px solid var(--accent-color);
    border-radius: 8px;
    padding: 0.55rem 1.25rem;
    font-size: 0.9rem;
    font-family: inherit;
    font-weight: 600;
    cursor: pointer;
    transition: background 0.15s ease;
}

.quiz-retry-btn:hover {
    background: var(--accent-soft);
}

.quiz-next-btn {
    background: var(--accent-color);
    color: var(--bg-color);
    border: none;
    border-radius: 8px;
    padding: 0.55rem 1.25rem;
    font-size: 0.9rem;
    font-family: inherit;
    font-weight: 600;
    cursor: pointer;
    transition: opacity 0.15s ease;
}

.quiz-next-btn:hover {
    opacity: 0.9;
}

@media (max-width: 600px) {
    .quiz-modal {
        max-height: 94vh;
    }
}

/* Passed status badge */

.module-status.passed {
    background: transparent;
    border: 1px solid var(--success-color);
    color: var(--success-color);
}

@media (max-width: 600px) {
    .match-board {
        grid-template-columns: 1fr;
    }
}

/* Global Footer */

.global-footer {
    background-color: var(--header-bg);
    border-top: 1px solid var(--panel-border);
    text-align: center;
    padding: 1.5rem 2rem;
    color: var(--text-secondary);
    font-size: 0.9rem;
}

.footer-note {
    font-size: 0.8rem;
    margin-top: 0.35rem;
}

/* Responsive adjustments */

/* On narrower screens the split layout stacks vertically, the video on top and
   the Micro Practice below, so neither column gets crushed. */
@media (max-width: 800px) {
    .video-lesson-split {
        grid-template-columns: 1fr;
    }
}

/* The unified mobile breakpoint. Everything structural collapses here: the
   header stacks into a single column, the control dropdowns become a wrap-ready
   flex matrix, the interactives dashboard folds to one column with a full-width
   navigation panel on top, and the progress banner stays bounded inside the
   viewport. All colors keep resolving through the theme tokens, so light and
   dark both render natively. */
@media (max-width: 768px) {
    .global-header {
        padding: 1.25rem 1rem;
    }

    .header-inner {
        flex-direction: column;
        align-items: stretch;
    }

    /* min-width: 0 releases each stacked block from its content's min-content
       width, so a wide child (like the sign-in chip row) can never push the
       whole header past the viewport edge. */
    .brand-block,
    .header-controls,
    .auth-controls {
        min-width: 0;
        max-width: 100%;
    }

    .app-title {
        font-size: 1.4rem;
        overflow-wrap: break-word;
    }

    /* The action dropdown row (Browse, Exploration Mode, Color Theme) as a
       wrap-ready flex matrix: triggers flow onto new lines instead of crowding
       or overlapping. */
    .header-controls {
        display: flex;
        flex-direction: row;
        flex-wrap: wrap;
        align-items: center;
        gap: 0.75rem;
    }

    /* Narrow-viewport dropdown sheets: every panel re-anchors from its
       trigger to the header row itself. The dropdown container goes static,
       so the absolutely positioned panel resolves against the positioned
       row (.campus-bar / .header-controls) and spans it edge to edge,
       which means no trigger position can ever push a panel, visible or
       hidden, past the viewport and force a horizontal scrollbar. */
    .campus-bar,
    .header-controls {
        position: relative;
    }

    .nav-dropdown {
        position: static;
    }

    .nav-dropdown-menu {
        left: 0;
        right: 0;
        min-width: 0;
        max-width: none;
    }

    .auth-dropdown .nav-dropdown-menu {
        left: 0;
        right: 0;
    }

    .nav-dropdown-menu .explore-item {
        white-space: normal;
    }

    /* The sign-in button and the identity cluster wrap as independent rows
       rather than forcing one wide line. */
    .auth-controls {
        flex-wrap: wrap;
    }

    /* Progress banner: stacked metrics bounded to the viewport width. */
    .progress-banner {
        padding: 0.4rem 1rem;
    }

    /* The pinned rule outside this query carries a second class, so it wins
       on specificity regardless of the media query. It has to be restated
       here or the frozen bar would take its wide desktop gutters back. */
    .progress-banner.is-stuck {
        padding: 0.2rem 1rem;
    }

    .progress-banner-inner {
        flex-wrap: wrap;
        gap: 0.5rem;
    }

    .progress-title {
        display: none;
    }

    .app-container {
        padding: 0 1rem;
    }

    /* The interactives dashboard collapses to a single column: the sticky
       sidebar un-sticks and sits full-width above the content, pushing it
       beneath. Its links stay stacked vertically, since the full descriptive
       titles read better as wrapped rows than as cramped horizontal chips. */
    .interactives-layout,
    .unit-detail-layout {
        flex-direction: column;
    }

    .interactives-sidebar,
    .unit-toc-sidebar {
        position: static;
        flex-basis: auto;
        width: 100%;
        max-height: none;
        overflow-y: visible;
    }

    /* Stacked pager buttons keep their full unit titles readable. */
    .unit-pager {
        flex-wrap: wrap;
    }
}

/* ============================================================================
   Day 3 capstone surfaces (Sprint Recs 3, 4, and the #settings view).
   Statistics dashboard, adaptive session branching, remediation detours,
   the profile and settings split interface, and the tutor admin console.
   Every color rides the Pillar 4 theme tokens so Light and Dark both
   render natively.
   ============================================================================ */

/* ---- Statistics dashboard ---- */

.dashboard-tiles {
    display: flex;
    flex-wrap: wrap;
    gap: 1rem;
    margin: 1.5rem 0;
}

.dashboard-tile {
    flex: 1 1 140px;
    background: var(--panel-bg);
    border: 1px solid var(--panel-border);
    border-radius: 10px;
    padding: 1rem 1.25rem;
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
}

.dashboard-tile-value {
    font-size: 1.6rem;
    font-weight: 700;
    color: var(--accent-text);
}

.dashboard-tile-label {
    font-size: 0.8rem;
    color: var(--text-secondary);
}

.dashboard-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 1rem;
    margin-bottom: 1.5rem;
}

.chart-card {
    background: var(--panel-bg);
    border: 1px solid var(--panel-border);
    border-radius: 10px;
    padding: 1rem 1.25rem;
    min-width: 0;
}

.chart-card-title {
    margin: 0 0 0.75rem;
    font-size: 1rem;
    color: var(--text-color);
}

.chart-canvas {
    display: block;
    width: 100%;
}

.dashboard-empty {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 1rem;
    margin: 2rem 0;
}

.dashboard-suggestions {
    margin: 0.5rem 0 2rem;
}

.suggestion-row {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 1rem;
}

.suggestion-card {
    background: var(--panel-bg);
    border: 1px solid var(--panel-border);
    border-left: 4px solid var(--accent-color);
    border-radius: 10px;
    padding: 1rem 1.25rem;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    align-items: flex-start;
}

.suggestion-title {
    margin: 0;
    font-size: 1rem;
    color: var(--text-color);
}

.suggestion-body {
    margin: 0;
    font-size: 0.85rem;
    color: var(--text-secondary);
    flex-grow: 1;
}

/* ---- Adaptive branching panel and remediation detours ---- */

.branch-panel {
    margin-top: 1.25rem;
    padding-top: 1rem;
    border-top: 1px solid var(--panel-border);
}

.branch-panel-title {
    margin: 0 0 0.75rem;
    font-weight: 600;
    color: var(--text-color);
}

.branch-panel-row {
    display: flex;
    flex-wrap: wrap;
    gap: 0.6rem;
}

.branch-btn {
    display: inline-flex;
    flex-direction: column;
    gap: 0.15rem;
    background: var(--accent-soft);
    color: var(--accent-text);
    border: 1px solid var(--panel-border);
    border-radius: 8px;
    padding: 0.5rem 0.9rem;
    text-decoration: none;
    transition: transform 0.15s ease, box-shadow 0.15s ease;
}

.branch-btn:hover {
    transform: translateY(-1px);
    box-shadow: 0 2px 8px var(--shadow-color);
}

.branch-btn-label {
    font-weight: 600;
    font-size: 0.9rem;
}

.branch-btn-detail {
    font-size: 0.75rem;
    color: var(--text-secondary);
}

.remediation-panel {
    background: var(--accent-soft);
    border: 1px solid var(--panel-border);
    border-left: 4px solid var(--accent-color);
    border-radius: 10px;
    padding: 1rem 1.25rem;
    margin: 0 0 1.5rem;
}

.remediation-title {
    margin: 0 0 0.5rem;
    font-size: 1.05rem;
    color: var(--text-color);
}

.remediation-text {
    margin: 0 0 0.5rem;
    font-size: 0.9rem;
    color: var(--text-secondary);
}

.remediation-skill-list {
    margin: 0 0 0.9rem;
    padding-left: 1.25rem;
    font-size: 0.9rem;
    color: var(--text-color);
}

.session-quiz-host {
    max-width: 860px;
    margin: 0 auto 2rem;
}

/* ---- Profile and settings ---- */

.settings-grid {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 1rem;
    margin: 1.5rem 0;
}

.settings-card {
    background: var(--panel-bg);
    border: 1px solid var(--panel-border);
    border-radius: 10px;
    padding: 1.1rem 1.25rem;
    min-width: 0;
}

.settings-card-title {
    margin: 0 0 0.9rem;
    font-size: 1.05rem;
    color: var(--text-color);
}

.settings-row {
    display: flex;
    justify-content: space-between;
    gap: 0.75rem;
    margin: 0;
    padding: 0.45rem 0;
    border-top: 1px solid var(--panel-border);
    font-size: 0.88rem;
}

.settings-row-label {
    color: var(--text-secondary);
}

.settings-row-value {
    color: var(--text-color);
    text-align: right;
    overflow-wrap: anywhere;
}

.settings-group-label {
    display: block;
    margin: 0.75rem 0 0.4rem;
    border-top: none;
    font-size: 0.85rem;
}

.settings-toggle-row {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
}

.settings-toggle-btn {
    background: transparent;
    color: var(--text-color);
    border: 1px solid var(--panel-border);
    border-radius: 999px;
    padding: 0.35rem 0.9rem;
    font-size: 0.85rem;
    cursor: pointer;
}

.settings-toggle-btn.active {
    background: var(--accent-color);
    border-color: var(--accent-color);
    color: var(--bg-color);
    font-weight: 600;
}

.settings-note {
    margin: 0 0 0.9rem;
    font-size: 0.83rem;
    color: var(--text-secondary);
}

.settings-danger-btn,
.settings-secondary-btn {
    display: inline-block;
    background: transparent;
    border-radius: 8px;
    padding: 0.45rem 0.9rem;
    font-size: 0.85rem;
    cursor: pointer;
    margin: 0 0.5rem 0.5rem 0;
}

.settings-danger-btn {
    border: 1px solid var(--error-color);
    color: var(--error-color);
}

.settings-danger-btn.armed {
    background: var(--error-color);
    color: var(--bg-color);
    font-weight: 600;
}

.settings-secondary-btn {
    border: 1px solid var(--panel-border);
    color: var(--text-color);
}

.settings-secondary-btn:hover {
    border-color: var(--accent-color);
    color: var(--accent-text);
}

/* The tutor admin console and package listing styles moved to the apex hub
   (portal/index.html inline styles) with the Hub-and-Spoke split of
   2026-07-11 — this spoke's settings surface is pedagogical-only. */

/* Narrow screens: every capstone grid collapses to a single column. */
@media (max-width: 800px) {
    .dashboard-grid,
    .suggestion-row,
    .settings-grid {
        grid-template-columns: 1fr;
    }
}

/* ---- Custom Quiz Factory (#quiz-builder) ---- */

.quiz-builder-panel {
    background: var(--panel-bg);
    border: 1px solid var(--panel-border);
    border-radius: 12px;
    padding: 1.25rem 1.5rem 1.5rem;
    margin: 1.5rem 0 2rem;
}

.quiz-builder-heading {
    margin: 1.25rem 0 0.75rem;
    font-size: 1rem;
    color: var(--text-color);
}

.quiz-builder-heading:first-child {
    margin-top: 0;
}

.builder-unit-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
    gap: 0.6rem;
}

.builder-unit-option {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    background: var(--bg-color);
    border: 1px solid var(--panel-border);
    border-radius: 8px;
    padding: 0.55rem 0.75rem;
    font-size: 0.85rem;
    cursor: pointer;
    transition: border-color 0.15s ease, background-color 0.15s ease;
}

.builder-unit-option:hover {
    border-color: var(--accent-color);
}

.builder-unit-option.selected {
    border-color: var(--accent-color);
    background: var(--accent-soft);
    color: var(--accent-text);
    font-weight: 600;
}

.builder-unit-check {
    accent-color: var(--accent-color);
    flex-shrink: 0;
}

.builder-count-row {
    display: flex;
    flex-wrap: wrap;
    gap: 0.6rem;
}

.builder-count-btn {
    background: var(--bg-color);
    color: var(--text-color);
    border: 1px solid var(--panel-border);
    border-radius: 999px;
    padding: 0.45rem 1.1rem;
    font-size: 0.85rem;
    font-family: inherit;
    cursor: pointer;
    transition: border-color 0.15s ease, background-color 0.15s ease;
}

.builder-count-btn:hover {
    border-color: var(--accent-color);
}

.builder-count-btn.active {
    background: var(--accent-color);
    border-color: var(--accent-color);
    color: var(--bg-color);
    font-weight: 600;
}

.builder-submit-btn {
    background: var(--accent-color);
    color: var(--bg-color);
    border: none;
    border-radius: 8px;
    padding: 0.65rem 1.5rem;
    font-size: 0.95rem;
    font-weight: 600;
    font-family: inherit;
    cursor: pointer;
    transition: transform 0.15s ease, box-shadow 0.15s ease;
}

.builder-submit-btn:hover:not(:disabled) {
    transform: translateY(-1px);
    box-shadow: 0 3px 12px var(--shadow-color);
}

.builder-submit-btn:disabled {
    opacity: 0.6;
    cursor: wait;
}

.builder-status {
    margin: 0.75rem 0 0;
    font-size: 0.85rem;
    color: var(--text-secondary);
    min-height: 1.1em;
}

.builder-status.error {
    color: var(--error-color);
}
