/* =========================================================================
 * HBase — hoja de estilos principal
 * Metodología: BEM (Block, Element, Modifier)
 *   .block             → componente raíz
 *   .block__element    → parte interna del componente
 *   .block--modifier   → variante del bloque entero
 *   .block__element--modifier → variante de un elemento
 *
 * Convenciones:
 *   - kebab-case dentro de cada parte (.pdf-list, .pdf-list__item)
 *   - sin selectores descendentes entre bloques (.foo .bar  ❌)
 *   - los modificadores SE ENCADENAN en el HTML, no se anidan en CSS:
 *       <li class="pdf-list__item pdf-list__item--locked">
 *   - variables de diseño en :root para mantener bajo el ruido
 * ========================================================================= */

:root {
    --color-bg: #ffffff;
    --color-surface: #f9fafb;
    --color-text: #1a1a1a;
    --color-muted: #6b7280;
    --color-primary: #2962ff;
    --color-primary-hover: #1d4ed8;
    --color-danger: #b91c1c;
    --color-success: #15803d;
    --color-pending: #f59e0b;
    --color-locked: #d4d4d8;
    --color-border: #e5e7eb;

    --radius: 8px;

    /* Tamaño de las flechas del slider de miniaturas (+10% sobre las 2rem
     * originales). ⚙️ Para agrandarlas más adelante, basta tocar AQUÍ:
     * el icono interior escala en proporción. */
    --carousel-nav-size: 2.2rem;
    --space-1: 0.25rem;
    --space-2: 0.5rem;
    --space-3: 0.75rem;
    --space-4: 1rem;
    --space-5: 1.25rem;
    --space-6: 1.5rem;

    --font-stack: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
}

* {
    box-sizing: border-box;
}

/* El atributo [hidden] es display:none por defecto del navegador, pero CUALQUIER
   regla nuestra con display (p.ej. .button{display:inline-block}) lo pisa por
   especificidad — el elemento se ve aunque tenga hidden puesto. Reafirmar aquí,
   con !important, para que "hidden" siempre gane sea cual sea su clase. */
[hidden] {
    display: none !important;
}

body {
    margin: 0;
    font-family: var(--font-stack);
    background: var(--color-bg);
    color: var(--color-text);
    line-height: 1.5;
}

/* =========================================================================
 * Bloque: page — layout general
 * ========================================================================= */
.page {
    min-height: 100vh;
    display: flex;
    flex-direction: column;
}

.page__main {
    flex: 1 0 auto;
    max-width: 1200px;
    width: 100%;
    margin: 0 auto;
    padding: var(--space-6) var(--space-4);
}

.page__footer {
    padding: var(--space-4);
    text-align: center;
    color: var(--color-muted);
    border-top: 1px solid var(--color-border);
}

.page__footer-legal {
    margin-top: var(--space-2);
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-1) var(--space-4);
    justify-content: center;
}

.page__footer-link {
    color: var(--color-muted);
    font-size: 0.8125rem;
    text-decoration: none;
}

.page__footer-link:hover {
    color: var(--color-primary);
    text-decoration: underline;
}

/* =========================================================================
 * Bloque: header — barra superior
 * ========================================================================= */
.header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: var(--space-3) var(--space-4);
    border-bottom: 1px solid var(--color-border);
    background: var(--color-surface);
}

/* Cabeceras fijas: la barra de HBase + una segunda con el título del curso
 * se quedan arriba al hacer scroll. El conjunto se pega como una unidad. */
.topbars {
    position: sticky;
    top: 0;
    z-index: 20;
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
}

.subheader {
    background: var(--color-bg);
    border-bottom: 1px solid var(--color-border);
    /* Aire bajo la tira de progreso para que el contenido no "pegue"
     * contra ella al hacer scroll. */
    padding-bottom: var(--space-2);
}

.subheader__row {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-2) var(--space-4);
}

/* Tira de progreso integrada en el borde inferior de la barra fija. */
.subheader__bar {
    height: 10px;
    background: var(--color-border);
}

.subheader__fill {
    height: 100%;
    background: var(--color-success);
    transition: width 0.4s ease;
}

/* Insignias compactas al final de la barra (las pendientes, apagadas). */
.subheader__badges {
    display: flex;
    gap: var(--space-1);
    flex-shrink: 0;
    font-size: 1.05rem;
    cursor: default;
}

.subheader__badge {
    filter: grayscale(1);
    opacity: 0.4;
}

.subheader__badge--done {
    filter: none;
    opacity: 1;
}

.subheader__back {
    color: var(--color-primary);
    text-decoration: none;
    font-size: 0.875rem;
    font-weight: 500;
    flex-shrink: 0;
}

.subheader__back:hover {
    text-decoration: underline;
}

.subheader__title {
    margin: 0;
    font-size: 1.05rem;
    font-weight: 700;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    flex: 1 1 auto;
    min-width: 0;
}

/* Resumen de progreso en la barra fija (derecha). */
.subheader__meta {
    margin: 0;
    font-size: 0.8125rem;
    color: var(--color-muted);
    white-space: nowrap;
    flex-shrink: 0;
}

.subheader__pct {
    font-size: 1rem;
    font-weight: 700;
    color: var(--color-success);
}

/* En pantallas estrechas el resumen no cabe: lo ocultamos (la barra visual
 * de progreso sigue en el contenido). */
@media (max-width: 640px) {
    .subheader__meta {
        display: none;
    }
    .subheader__badges {
        font-size: 0.9rem;
        gap: 2px;
    }
}

/* En la página del visor de PDF, la cabecera se queda fija arriba al hacer
   scroll por las páginas. Modificador a nivel de body para no afectar al
   resto del sitio. */
.page--viewer .header {
    position: sticky;
    top: 0;
    z-index: 10;
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
}

.header__brand {
    font-weight: 700;
    color: var(--color-text);
    text-decoration: none;
    font-size: 1.125rem;
    flex-shrink: 0;
}

/* Back link siempre visible en pages tipo visor (vive en el header sticky). */
.header__back {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    color: var(--color-primary);
    text-decoration: none;
    font-size: 0.9375rem;
    font-weight: 500;
    padding: var(--space-1) var(--space-2);
    border-radius: var(--radius);
    flex-shrink: 0;
    transition: background 0.15s;
}

.header__back:hover {
    background: rgba(41, 98, 255, 0.08);
}

.header__back-label {
    /* En pantallas estrechas mostramos solo la flecha. */
    max-width: 14ch;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

@media (max-width: 640px) {
    .header__back-label {
        display: none;
    }
}

.header__doc {
    flex: 1 1 auto;
    display: flex;
    align-items: baseline;
    justify-content: center;
    gap: var(--space-2);
    min-width: 0;
    padding: 0 var(--space-3);
}

.header__doc-title {
    font-weight: 600;
    font-size: 0.9375rem;
    color: var(--color-text);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    min-width: 0;
}

.header__doc-subtitle {
    color: var(--color-muted);
    font-size: 0.8125rem;
    flex-shrink: 0;
}

.header__nav {
    display: flex;
    gap: var(--space-3);
    align-items: center;
}

.header__user {
    color: var(--color-muted);
    font-size: 0.875rem;
}

.header__link {
    color: var(--color-primary);
    text-decoration: none;
    font-size: 0.875rem;
}

.header__link:hover {
    text-decoration: underline;
}

/* =========================================================================
 * Bloque: auth-card — tarjeta de formulario de login/registro
 * ========================================================================= */
.auth-card {
    max-width: 400px;
    margin: 0 auto;
    padding: var(--space-6);
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
}

.auth-card__title {
    margin: 0 0 var(--space-3);
}

.auth-card__intro {
    margin: 0 0 var(--space-4);
    color: var(--color-muted);
    font-size: 0.9375rem;
}

/* =========================================================================
 * Bloque: form — formularios genéricos
 * ========================================================================= */
.form__field {
    margin-bottom: var(--space-4);
}

.form__label {
    display: block;
    margin-bottom: var(--space-1);
    font-weight: 500;
    font-size: 0.875rem;
}

.form__input {
    width: 100%;
    padding: var(--space-2) var(--space-3);
    font-size: 1rem;
    font-family: inherit;
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    background: #fff;
}

.form__input:focus {
    outline: 2px solid var(--color-primary);
    outline-offset: 1px;
    border-color: var(--color-primary);
}

.form__hint {
    display: block;
    margin-top: var(--space-1);
    color: var(--color-muted);
    font-size: 0.8125rem;
}

/* Campo de contraseña con botón "ojo" para mostrar/ocultar. */
.form__password {
    position: relative;
}

.form__password .form__input {
    padding-right: 2.75rem;
}

.form__password-toggle {
    position: absolute;
    top: 0;
    right: 0;
    width: 2.75rem;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    border: 0;
    background: transparent;
    color: var(--color-muted);
    cursor: pointer;
}

.form__password-toggle:hover {
    color: var(--color-text);
}

.form__password-toggle:focus-visible {
    outline: 2px solid var(--color-primary);
    outline-offset: -2px;
    border-radius: var(--radius);
}

.form__password-toggle .fa-solid {
    font-size: 1rem;
    line-height: 1;
}

.form__actions {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    margin-top: var(--space-4);
}

.form__link {
    color: var(--color-primary);
    text-decoration: none;
    font-size: 0.875rem;
}

.form__link:hover {
    text-decoration: underline;
}

/* Casilla de aceptación (política de privacidad, etc.): checkbox + texto
 * alineados arriba para que el texto pueda ocupar varias líneas. */
.form__check {
    display: flex;
    align-items: flex-start;
    gap: var(--space-2);
    font-weight: 400;
    cursor: pointer;
}

.form__check-input {
    flex: 0 0 auto;
    margin-top: 0.2em;
}

.form__check-text {
    font-size: 0.875rem;
    line-height: 1.4;
    color: var(--color-text);
}

/* =========================================================================
 * Bloque: button
 * ========================================================================= */
.button {
    display: inline-block;
    padding: var(--space-2) var(--space-4);
    font-size: 1rem;
    font-family: inherit;
    text-decoration: none;
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    background: #fff;
    color: var(--color-text);
    cursor: pointer;
}

.button:hover {
    background: var(--color-surface);
}

.button--primary {
    background: var(--color-primary);
    color: #fff;
    border-color: var(--color-primary);
}

.button--primary:hover {
    background: var(--color-primary-hover);
    border-color: var(--color-primary-hover);
}

.button--danger {
    background: var(--color-danger);
    color: #fff;
    border-color: var(--color-danger);
}

/* =========================================================================
 * Bloque: flash-list — avisos flash (errores, éxito)
 * ========================================================================= */
.flash-list {
    list-style: none;
    margin: 0 0 var(--space-4);
    padding: 0;
}

.flash-list__item {
    padding: var(--space-2) var(--space-3);
    margin-bottom: var(--space-2);
    border-radius: var(--radius);
    border: 1px solid var(--color-border);
    background: var(--color-surface);
}

.flash-list__item--error {
    background: #fee2e2;
    border-color: #fecaca;
    color: var(--color-danger);
}

.flash-list__item--success {
    background: #dcfce7;
    border-color: #bbf7d0;
    color: var(--color-success);
}

/* =========================================================================
 * Bloque: dashboard
 * ========================================================================= */
.dashboard__title {
    margin: 0 0 var(--space-2);
}

.dashboard__intro {
    color: var(--color-muted);
    margin: 0;
}

/* =========================================================================
 * Bloque: error-page
 * ========================================================================= */
.error-page {
    text-align: center;
    padding: var(--space-6) 0;
}

.error-page__title {
    font-size: 4rem;
    margin: 0 0 var(--space-2);
    color: var(--color-muted);
}

.error-page__message {
    margin: 0 0 var(--space-4);
    color: var(--color-muted);
}

/* =========================================================================
 * Bloque: legal — páginas de texto largo (política de privacidad, etc.)
 * ========================================================================= */
.legal {
    max-width: 46rem;
    margin: 0 auto;
    line-height: 1.6;
}

.legal__title {
    margin: 0 0 var(--space-1);
}

.legal__updated {
    margin: 0 0 var(--space-5);
    color: var(--color-muted);
    font-size: 0.875rem;
}

.legal__heading {
    margin: var(--space-5) 0 var(--space-2);
    font-size: 1.125rem;
}

.legal__list {
    margin: 0 0 var(--space-3);
    padding-left: var(--space-5);
}

.legal__code {
    padding: 0.05rem 0.3rem;
    border: 1px solid var(--color-border);
    border-radius: 3px;
    background: var(--color-surface);
    font-family: 'Courier New', Courier, monospace;
    font-size: 0.9em;
}

.legal__back {
    margin-top: var(--space-6);
}

/* =========================================================================
 * Bloque: faq — preguntas frecuentes (desplegables con <details>)
 * ========================================================================= */
.faq {
    max-width: 46rem;
    margin: 0 auto;
    line-height: 1.6;
}

.faq__title {
    margin: 0 0 var(--space-5);
}

.faq__item {
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    background: var(--color-surface);
    margin-bottom: var(--space-3);
}

.faq__question {
    padding: var(--space-3) var(--space-4);
    font-weight: 600;
    cursor: pointer;
}

.faq__answer {
    padding: 0 var(--space-4) var(--space-3);
}

.faq__steps {
    margin: 0 0 var(--space-3);
    padding-left: var(--space-5);
}

.faq__back {
    margin-top: var(--space-6);
}

/* =========================================================================
 * Bloque: admin-nav — sub-navegación del panel admin
 * ========================================================================= */
.admin-nav {
    display: flex;
    gap: var(--space-1);
    margin-bottom: var(--space-4);
    padding-bottom: var(--space-2);
    border-bottom: 1px solid var(--color-border);
}

.admin-nav__link {
    padding: var(--space-2) var(--space-3);
    text-decoration: none;
    color: var(--color-muted);
    border-radius: var(--radius);
    font-size: 0.9375rem;
}

.admin-nav__link:hover {
    background: var(--color-surface);
    color: var(--color-text);
}

.admin-nav__link--active {
    background: var(--color-primary);
    color: #fff;
}

.admin-nav__link--active:hover {
    background: var(--color-primary-hover);
    color: #fff;
}

/* =========================================================================
 * Bloque: admin-actions — barra de acciones (botones + filtros)
 * ========================================================================= */
.admin-actions {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    flex-wrap: wrap;
    margin-bottom: var(--space-4);
}

/* =========================================================================
 * Bloque: admin-section — subsección dentro de una página admin
 * ========================================================================= */
.admin-section {
    margin-top: var(--space-6);
    padding-top: var(--space-4);
    border-top: 1px solid var(--color-border);
}

.admin-section__title {
    margin: 0 0 var(--space-3);
    font-size: 1.125rem;
}

.admin-section__subtitle {
    margin: var(--space-4) 0 var(--space-2);
    font-size: 0.9375rem;
    font-weight: 600;
    color: var(--color-muted);
}

.admin-section__subtitle small {
    font-weight: 400;
}

/* =========================================================================
 * Bloque: chart-wrap — contenedor de gráficos Chart.js
 * ========================================================================= */
.chart-wrap {
    margin: var(--space-2) 0 var(--space-4);
    padding: var(--space-3);
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
}

/* =========================================================================
 * Bloque: event-pill — etiqueta de tipo de evento
 * ========================================================================= */
.event-pill {
    display: inline-block;
    padding: 2px 8px;
    font-size: 0.75rem;
    font-weight: 600;
    border-radius: 999px;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

.event-pill--login   { background: #dcfce7; color: #15803d; }
.event-pill--logout  { background: #fee2e2; color: #b91c1c; }
.event-pill--pdf_view { background: #dbeafe; color: #1e40af; }
.event-pill--quiz    { background: #f3e8ff; color: #7e22ce; }

.event-pill--pending   { background: #fef3c7; color: #92400e; }
.event-pill--consumed  { background: #dcfce7; color: #15803d; }
.event-pill--cancelled { background: #e5e7eb; color: #4b5563; }
.event-pill--expired   { background: #fee2e2; color: #b91c1c; }

/* =========================================================================
 * Bloque: admin-stats — tarjetas de resumen
 * ========================================================================= */
.admin-stats {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
    gap: var(--space-3);
    margin-bottom: var(--space-4);
}

.stat-card {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    padding: var(--space-4);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    background: var(--color-surface);
}

.stat-card__label {
    color: var(--color-muted);
    font-size: 0.8125rem;
    text-transform: uppercase;
    letter-spacing: 0.02em;
}

.stat-card__value {
    font-size: 2rem;
    font-weight: 700;
}

.stat-card__meta {
    color: var(--color-muted);
    font-size: 0.8125rem;
}

/* Enlace de acción dentro de una tarjeta (p. ej. abrir el modal de
   conexiones). Botón sin chrome, con aspecto de enlace. */
.stat-card__link {
    align-self: flex-start;
    margin-top: var(--space-2);
    padding: 0;
    border: 0;
    background: transparent;
    color: var(--color-primary);
    font-size: 0.8125rem;
    font-weight: 600;
    text-align: left;
    cursor: pointer;
}

.stat-card__link:hover {
    text-decoration: underline;
}

/* =========================================================================
 * Bloque: scope-bar — deja claro qué filtro está activo en Actividad
 * ========================================================================= */
.scope-bar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
    margin: 0 0 var(--space-4);
    font-size: 0.875rem;
}

.scope-bar__intro {
    color: var(--color-muted);
}

.scope-bar__chip {
    display: inline-block;
    padding: 2px 10px;
    border-radius: 999px;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    color: var(--color-muted);
    text-decoration: none;
}

/* Chips de un filtro ACTIVO: resaltados (alumno, curso y módulo). */
.scope-bar__chip--user,
.scope-bar__chip--course,
.scope-bar__chip--module {
    font-weight: 600;
    color: var(--color-text);
    border-color: var(--color-primary);
}

a.scope-bar__chip:hover {
    background: var(--color-bg);
}

/* =========================================================================
 * Bloque: presence-dot — punto de estado "en línea ahora" (en stat-cards)
 * ========================================================================= */
/* Gris (desconectado) por defecto. */
.presence-dot {
    display: inline-block;
    width: 9px;
    height: 9px;
    border-radius: 50%;
    background: var(--color-muted);
    vertical-align: middle;
}

/* Verde + halo cuando está en línea. */
.presence-dot--on {
    background: var(--color-success);
    box-shadow: 0 0 0 3px rgba(21, 128, 61, 0.18);
}

/* =========================================================================
 * Bloque: table — tablas de listados admin
 * ========================================================================= */
.table {
    width: 100%;
    border-collapse: collapse;
    margin-bottom: var(--space-4);
    background: var(--color-bg);
}

.table__th {
    text-align: left;
    padding: var(--space-2) var(--space-3);
    border-bottom: 2px solid var(--color-border);
    font-weight: 600;
    font-size: 0.875rem;
    color: var(--color-muted);
}

.table__td {
    padding: var(--space-2) var(--space-3);
    border-bottom: 1px solid var(--color-border);
    vertical-align: middle;
}

.table__row--inactive {
    opacity: 0.5;
}

.table__row:hover {
    background: var(--color-surface);
}

/* Alineación a la derecha para columnas numéricas (rankings de actividad). */
.table__th--num,
.table__td--num {
    text-align: right;
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}

/* =========================================================================
 * Bloque: meter — barra de progreso compacta (% completado de lectura).
 * ========================================================================= */
.meter {
    display: inline-block;
    width: 80px;
    height: 8px;
    border-radius: 999px;
    background: var(--color-border);
    overflow: hidden;
    vertical-align: middle;
    margin-right: var(--space-1);
}

.meter__fill {
    display: block;
    height: 100%;
    background: var(--color-primary, #2563eb);
    border-radius: inherit;
}

/* =========================================================================
 * Bloque: filter-tabs — pestañas para filtrar listados
 * ========================================================================= */
.filter-tabs {
    display: flex;
    gap: var(--space-1);
    margin-left: auto;
}

.filter-tabs__link {
    padding: var(--space-1) var(--space-2);
    font-size: 0.875rem;
    text-decoration: none;
    color: var(--color-muted);
    border: 1px solid transparent;
    border-radius: var(--radius);
}

.filter-tabs__link:hover {
    background: var(--color-surface);
    color: var(--color-text);
}

.filter-tabs__link--active {
    border-color: var(--color-border);
    background: var(--color-bg);
    color: var(--color-text);
}

/* =========================================================================
 * Bloque: form--inline — formulario en una sola línea (acciones rápidas)
 * ========================================================================= */
.form--inline {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
}

.form--inline .form__input {
    width: auto;
    min-width: 240px;
}

/* =========================================================================
 * Bloque: danger-zone — sección de acciones destructivas
 * ========================================================================= */
.danger-zone {
    border-top-color: #fecaca;
    background: #fef2f2;
    padding: var(--space-4);
    border-radius: var(--radius);
    border: 1px solid #fecaca;
}

.danger-zone__help {
    margin: 0 0 var(--space-3);
    color: #7f1d1d;
    font-size: 0.9375rem;
}

.danger-zone__list {
    margin: 0 0 var(--space-3);
    padding-left: var(--space-4);
    color: #7f1d1d;
    font-size: 0.9375rem;
}

.danger-zone__list li {
    margin-bottom: var(--space-1);
}

/* =========================================================================
 * Bloque: import-box — caja de importación CSV
 * ========================================================================= */
.import-box {
    padding: var(--space-3) var(--space-4);
    margin-bottom: var(--space-4);
    background: #eef2ff;
    border: 1px solid #c7d2fe;
    border-radius: var(--radius);
}

.import-box__help {
    margin: 0 0 var(--space-3);
    font-size: 0.875rem;
    color: #3730a3;
}

/* =========================================================================
 * Bloque: empty-state — placeholder cuando un listado está vacío
 * ========================================================================= */
.empty-state {
    padding: var(--space-6);
    text-align: center;
    color: var(--color-muted);
    border: 1px dashed var(--color-border);
    border-radius: var(--radius);
}

/* =========================================================================
 * Bloque: info-banner — aviso suave de información
 * ========================================================================= */
.info-banner {
    padding: var(--space-2) var(--space-3);
    margin-bottom: var(--space-4);
    border-radius: var(--radius);
    background: #eef2ff;
    color: #3730a3;
    border: 1px solid #c7d2fe;
    font-size: 0.9375rem;
}

/* =========================================================================
 * Bloque: course-list — listado de cursos en el dashboard del alumno
 * ========================================================================= */
.course-list {
    list-style: none;
    margin: var(--space-3) 0 0;
    padding: 0;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
    gap: var(--space-3);
}

.course-list__item {
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    background: var(--color-surface);
}

.course-list__link {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    padding: var(--space-4);
    color: var(--color-text);
    text-decoration: none;
}

.course-list__link:hover {
    background: var(--color-bg);
}

.course-list__name {
    font-weight: 600;
    font-size: 1.0625rem;
}

.course-list__meta {
    color: var(--color-muted);
    font-size: 0.875rem;
}

.course-list__meta small {
    display: block;
    font-size: 0.75rem;
}

.course-list__progress {
    display: block;
    height: 6px;
    background: var(--color-border);
    border-radius: 999px;
    overflow: hidden;
    margin-top: var(--space-2);
}

.course-list__progress-bar {
    display: block;
    height: 100%;
    background: var(--color-success);
    transition: width 0.3s ease;
}

/* =========================================================================
 * Bloque: course-header — cabecera de la vista de curso
 * ========================================================================= */
.course-header {
    margin-bottom: var(--space-4);
}

.course-header__title {
    margin: var(--space-2) 0 var(--space-1);
}

.course-header__code {
    margin: 0;
    color: var(--color-muted);
    font-size: 0.875rem;
}

/* =========================================================================
 * Bloque: pdf-list — listado de PDFs dentro de un curso
 * ========================================================================= */
.pdf-list {
    list-style: none;
    margin: 0;
    padding: 0;
}

.pdf-list__item {
    padding: var(--space-4);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    margin-bottom: var(--space-3);
    background: var(--color-surface);
}

.pdf-list__item--locked {
    background: var(--color-locked);
    opacity: 0.85;
}

.pdf-list__item--viewed {
    border-left: 4px solid var(--color-success);
}

.pdf-list__tick {
    display: inline-block;
    color: var(--color-success);
    font-weight: 800;
    margin-right: var(--space-1);
}

.pdf-list__new {
    color: var(--color-primary);
    font-weight: 600;
}

.pdf-list__title {
    margin: 0 0 var(--space-1);
    font-weight: 600;
}

.pdf-list__meta {
    color: var(--color-muted);
    font-size: 0.875rem;
    margin: var(--space-1) 0;
}

.pdf-list__actions {
    margin-top: var(--space-3);
    display: flex;
    gap: var(--space-2);
    flex-wrap: wrap;
}

/* =========================================================================
 * Bloque: timeline — ruta de aprendizaje (PDFs como pasos secuenciales).
 * Rejilla [nodo | contenido]; la línea conectora va tras los nodos.
 * ========================================================================= */
.timeline {
    /* Lado del nodo cuadrado; la franja del título usa la MISMA medida
     * como min-height, así nodo y barra quedan siempre a la par. */
    --node-size: 3.25rem;
    list-style: none;
    margin: 0;
    padding: 0;
}

.timeline__item {
    position: relative;
    display: grid;
    grid-template-columns: var(--node-size) 1fr;
    gap: var(--space-3);
    padding-bottom: var(--space-5);
    /* Al volver del visor saltamos a #pdf-<id>: dejamos hueco arriba para que
     * la tarjeta no quede tapada por la cabecera fija (.topbars). */
    scroll-margin-top: 140px;
}

.timeline__marker {
    position: relative;
    display: flex;
    justify-content: center;
}

/* Línea conectora: arranca bajo el nodo y baja hasta el siguiente. */
.timeline__marker::before {
    content: '';
    position: absolute;
    top: var(--node-size);
    bottom: calc(-1 * var(--space-5));
    left: 50%;
    width: 2px;
    transform: translateX(-50%);
    background: var(--color-border);
}

.timeline__item:last-child .timeline__marker::before {
    content: none;
}

/* Cuando un paso está completado, el tramo de línea que sale de él va verde. */
.timeline__item--done .timeline__marker::before {
    background: var(--color-success);
}

/* Separador de módulo: encabezado de bloque dentro de la timeline. */
.timeline__section {
    list-style: none;
    display: flex;
    align-items: center;
    gap: var(--space-3);
    margin: var(--space-4) 0 var(--space-5);
}

.timeline__section-title {
    margin: 0;
    font-size: 1.1rem;
    font-weight: 700;
    color: var(--color-muted);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    white-space: nowrap;
}

/* Regla horizontal que completa el encabezado hasta el borde derecho. */
.timeline__section::after {
    content: '';
    flex: 1;
    height: 2px;
    background: var(--color-border);
}

.timeline__node {
    position: relative;
    z-index: 1;
    width: var(--node-size);
    height: var(--node-size);
    border-radius: 6px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-weight: 700;
    font-size: 1.05rem;
    background: var(--color-bg);
    border: 2px solid var(--color-border);
    color: var(--color-muted);
}

.timeline__item--done .timeline__node {
    background: var(--color-success);
    border-color: var(--color-success);
    color: #fff;
}

.timeline__item--current .timeline__node {
    border-color: var(--color-primary);
    color: var(--color-primary);
    box-shadow: 0 0 0 4px rgba(41, 98, 255, 0.12);
}

.timeline__item--locked .timeline__node {
    background: var(--color-locked);
    border-color: var(--color-locked);
}

.timeline__body {
    min-width: 0; /* permite que el contenido largo no desborde la rejilla */
}

/* Tarjeta del paso: borde lateral izquierdo coloreado según el estado. */
.timeline__card {
    border: 1px solid var(--color-border);
    border-left: 5px solid var(--color-border);
    border-radius: var(--radius);
    background: var(--color-bg);
    overflow: hidden;
}

/* Franja de título: centrada, grande, con fondo tintado por estado. */
.timeline__titlebar {
    position: relative;
    min-height: var(--node-size); /* misma altura que el nodo cuadrado */
    display: flex;
    align-items: center;
    justify-content: center;
    padding: var(--space-2) var(--space-3);
    text-align: center;
    background: var(--color-surface);
    border-bottom: 1px solid var(--color-border);
}

.timeline__title {
    margin: 0;
    font-size: 1.38rem; /* ~20% más grande que el tamaño anterior (1.15rem) */
    font-weight: 700;
}

/* "estás aquí": segmento azul integrado en el extremo derecho de la franja
 * del título, a toda su altura (texto en blanco). */
.timeline__here {
    position: absolute;
    right: 0;
    top: 0;
    bottom: 0;
    display: flex;
    align-items: center;
    padding: 0 var(--space-3);
    margin: 0;
    font-size: 0.6875rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    font-weight: 700;
    background: var(--color-primary);
    color: #fff;
}

.timeline__inner {
    padding: var(--space-3);
}

/* Fila central: slider (~70%) + botones en vertical (~30%), con una línea
 * separadora vertical entre ambos y otra horizontal debajo. */
.timeline__main {
    display: flex;
    gap: var(--space-3);
    align-items: stretch;
    padding-bottom: var(--space-3);
    border-bottom: 1px solid var(--color-border);
}

.timeline__actions-primary {
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    gap: var(--space-2);
    flex: 0 0 30%;
    min-width: 0;
    padding-left: var(--space-3);
    border-left: 1px solid var(--color-border);
}

/* El botón principal ocupa ~80% del ancho de su columna. */
.timeline__actions-primary .button {
    width: 80%;
}

/* En pantallas estrechas, slider y botones se apilan; el separador pasa
 * a ser horizontal. El nodo cuadrado y el título se reducen a la par. */
@media (max-width: 520px) {
    .timeline {
        --node-size: 2.5rem;
    }
    .timeline__title {
        font-size: 1.1rem;
    }
    .timeline__main {
        flex-direction: column;
    }
    .timeline__actions-primary {
        flex-basis: auto;
        width: 100%;
        padding-left: 0;
        padding-top: var(--space-3);
        border-left: 0;
        border-top: 1px solid var(--color-border);
    }
}

.timeline__actions-secondary {
    margin-top: var(--space-3);
    display: flex;
    gap: var(--space-2);
    flex-wrap: wrap;
    align-items: center;
}

.timeline__desc {
    margin: var(--space-3) 0 0;
    padding-top: var(--space-3);
    border-top: 1px solid var(--color-border);
    color: var(--color-text);
}

.timeline__meta {
    margin: var(--space-2) 0 0;
    font-size: 0.875rem;
    color: var(--color-muted);
}

.timeline__history {
    margin: var(--space-2) 0 0;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-2);
    font-size: 0.875rem;
    color: var(--color-muted);
}

.timeline__history-text {
    min-width: 0;
}

.timeline__new {
    color: var(--color-primary);
    font-weight: 500;
}

/* Chip de relevancia para el examen (Esencial / Recomendado / Ampliación). */
.rel-chip {
    display: inline-block;
    margin: 0 0 var(--space-2);
    padding: 0.15rem 0.6rem;
    border-radius: 999px;
    font-size: 0.75rem;
    font-weight: 700;
    border: 1px solid transparent;
}

.rel-chip--esencial {
    background: #fee2e2;
    color: #b91c1c;
    border-color: #fecaca;
}

.rel-chip--recomendado {
    background: #fef3c7;
    color: #92400e;
    border-color: #fde68a;
}

.rel-chip--ampliacion {
    background: #e0f2fe;
    color: #075985;
    border-color: #bae6fd;
}

/* Aviso (solo admin) de que un PDF está bloqueado para los alumnos, aunque
 * el admin vea la tarjeta completa en preview. */
/* Versión nueva de un PDF que el alumno ya había abierto. */
.timeline__update {
    margin: 0 0 var(--space-2);
    padding: var(--space-2);
    background: #ecfdf5;
    border-left: 3px solid #059669;
    border-radius: var(--radius);
    font-size: 0.875rem;
}
.timeline__update-title {
    margin: 0;
    color: #065f46;
    font-weight: 600;
}
.timeline__update-notes {
    margin: var(--space-1) 0 0;
    color: var(--color-text);
    white-space: pre-line;
}
.timeline__update-hint {
    margin: var(--space-1) 0 0;
    color: var(--color-muted);
    font-size: 0.8125rem;
}

.timeline__locked-note {
    margin: 0 0 var(--space-2);
    padding: var(--space-1) var(--space-2);
    background: #fef3c7;
    color: #92400e;
    border-radius: var(--radius);
    font-size: 0.8125rem;
    font-weight: 600;
}

/* --- Colores por estado: borde lateral de la tarjeta + fondo del título --- */
.timeline__item--done .timeline__card    { border-left-color: var(--color-success); }
.timeline__item--done .timeline__titlebar { background: #dcfce7; }

.timeline__item--current .timeline__card    { border-left-color: var(--color-primary); }
.timeline__item--current .timeline__titlebar { background: #dbeafe; }

.timeline__item--pending .timeline__card    { border-left-color: #f59e0b; }
.timeline__item--pending .timeline__titlebar { background: #fef3c7; }

.timeline__item--locked .timeline__card    { border-left-color: #4b5563; }
.timeline__item--locked .timeline__titlebar { background: #e5e7eb; }
.timeline__item--locked .timeline__card {
    opacity: 0.6;
    filter: grayscale(0.4);
}

/* Botón a lo ancho de su columna (pila vertical de acciones). */
.button--block {
    display: block;
    width: 100%;
    text-align: center;
}

/* Botón secundario, discreto (estadísticas, enlaces…). */
.button--ghost {
    background: transparent;
    border-color: transparent;
    color: var(--color-muted);
    padding-left: var(--space-2);
    padding-right: var(--space-2);
}

.button--ghost:hover {
    background: var(--color-surface);
    color: var(--color-text);
}

/* "Ver más / Ver menos": enlace inline al final del propio texto. */
.timeline__more {
    padding: 0;
    border: 0;
    background: transparent;
    color: var(--color-primary);
    font-size: inherit;
    font-weight: 500;
    cursor: pointer;
    white-space: nowrap;
}

.timeline__more:hover {
    text-decoration: underline;
}

/* =========================================================================
 * Bloque: carousel — mini-slide de vista previa del PDF (primeras páginas).
 * ========================================================================= */
.carousel {
    position: relative;
    margin: var(--space-2) 0;
}

.carousel__track {
    display: flex;
    gap: var(--space-2);
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scroll-behavior: smooth;
    list-style: none;
    margin: 0;
    padding: var(--space-1) 0;
    /* Sin barra de scroll: la navegación va por puntitos y flechas. */
    scrollbar-width: none;
}

.carousel__track::-webkit-scrollbar {
    display: none;
}

/* Puntitos de paginación del carrusel. */
.carousel__dots {
    display: flex;
    gap: 6px;
    justify-content: center;
    margin-top: var(--space-2);
}

.carousel__dot {
    width: 8px;
    height: 8px;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: var(--color-border);
    cursor: pointer;
}

.carousel__dot.is-active {
    background: var(--color-primary);
}

.carousel__slide {
    flex: 0 0 auto;
    scroll-snap-align: start;
}

.carousel__img {
    display: block;
    height: 160px;
    width: auto;
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    background: #fff;
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
}

/* Variante de una sola diapositiva: el visor ocupa el ancho de UNA página
 * y se avanza con las flechas (scroll-snap por página). */
/* Una sola diapositiva, ocupando ~70% de la fila (su columna flex). */
.carousel--single {
    flex: 0 0 68%;
    min-width: 0;
}

.carousel--single .carousel__track {
    gap: 0;
}

.carousel--single .carousel__slide {
    flex: 0 0 100%;
    display: flex;
    justify-content: center;
}

.carousel--single .carousel__img {
    height: 240px;
    width: auto;
    max-width: 100%;
    /* Si max-width recorta el ancho, que la página no se deforme. */
    object-fit: contain;
}

@media (max-width: 520px) {
    .carousel--single {
        flex-basis: auto;
        width: 100%;
    }
}

/* Flechas de navegación, superpuestas a los lados. El tamaño sale de
 * --carousel-nav-size (:root); el icono escala en proporción. */
.carousel__nav {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    z-index: 2;
    width: var(--carousel-nav-size);
    height: var(--carousel-nav-size);
    border-radius: 50%;
    border: 1px solid var(--color-border);
    background: var(--color-bg);
    color: var(--color-text);
    font-size: calc(var(--carousel-nav-size) * 0.625);
    line-height: 1;
    cursor: pointer;
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.15);
}

.carousel__nav:hover {
    background: var(--color-surface);
}

.carousel__nav--prev { left: calc(-1 * var(--space-2)); }
.carousel__nav--next { right: calc(-1 * var(--space-2)); }

/* En pantallas táctiles pequeñas, ocultamos las flechas: se desliza con el dedo. */
@media (hover: none) {
    .carousel__nav { display: none; }
}

/* En ventanas estrechas (escritorio pequeño), flechas algo más compactas
 * para que no invadan la tarjeta. */
@media (max-width: 520px) {
    :root { --carousel-nav-size: 2rem; }
}

/* =========================================================================
 * Bloque: viewer-header — botón volver + título "real" del PDF.
 * El mismo título aparece también en la cabecera sticky pero oculto;
 * se hace visible al hacer scroll y dejar fuera este bloque (ver JS).
 * ========================================================================= */
.viewer-header {
    margin-bottom: var(--space-3);
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    flex-wrap: wrap;
}

.viewer-header__title {
    margin: var(--space-2) 0 var(--space-3);
}

/* En el visor, el "doc title" del header sticky empieza invisible
   (porque el título grande de abajo ya se está viendo). La clase
   .is-title-out se añade vía IntersectionObserver cuando el título
   grande sale de pantalla. */
.page--viewer .header__doc {
    opacity: 0;
    transform: translateY(-4px);
    transition: opacity 0.18s ease, transform 0.18s ease;
    pointer-events: none;
}

.page--viewer.is-title-out .header__doc {
    opacity: 1;
    transform: translateY(0);
}

.viewer-links {
    display: flex;
    gap: var(--space-2);
    flex-wrap: wrap;
    margin-bottom: var(--space-3);
}

/* =========================================================================
 * Bloque: pdf-viewer — contenedor del visor con páginas y watermark
 * Se sale del max-width de .page__main para usar todo el ancho del viewport.
 * ========================================================================= */
.pdf-viewer {
    background: #2a2a2a;
    padding: var(--space-4);
    border-radius: var(--radius);
    overflow: auto;
    /* Full-bleed: anular el ancho máximo del contenedor padre */
    margin-left: calc(50% - 50vw);
    margin-right: calc(50% - 50vw);
    max-width: 100vw;
    box-sizing: border-box;
}

/* En la página del visor, el truco de full-bleed (calc 50% - 50vw + max-width
   100vw) puede generar un pelín de scroll horizontal porque 100vw incluye el
   scrollbar vertical. Lo cortamos aquí — el contenido nunca debe rebasar el
   viewport en esta página. */
.page--viewer {
    overflow-x: hidden;
}

/* Ese mismo overflow-x:hidden, sin embargo, RECORTA el truco de full-bleed de
   .pdf-viewer/.html-viewer contra el borde de .page__main (max-width 1200px):
   el margen negativo intenta escapar del contenedor pero se corta ahí mismo,
   así que en pantallas anchas el visor se queda encajado en esos 1200px en
   vez de ocupar el ancho real. Ensanchamos el contenedor SOLO en esta página
   para que no haga falta escapar de nada. */
.page--viewer .page__main {
    max-width: none;
}

.pdf-viewer__pages {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-3);
}

.pdf-viewer__status {
    text-align: center;
    color: #d4d4d8;
    padding: var(--space-6);
}

/* =========================================================================
 * Bloque: pdf-page — página individual con overlay de watermark
 * ========================================================================= */
.pdf-page {
    position: relative;
    background: #fff;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
    /* Evitar selección/copia del canvas. No es perfecto pero suma. */
    -webkit-user-select: none;
    user-select: none;
}

.pdf-page canvas {
    display: block;
}

/* Sello base — usado por las dos posiciones */
.pdf-page__stamp {
    position: absolute;
    color: rgba(60, 60, 60, 0.55);
    font-size: 0.8125rem;
    font-weight: 600;
    pointer-events: none;
    letter-spacing: 0.03em;
    text-shadow: 0 0 2px rgba(255, 255, 255, 0.6);
}

.pdf-page__stamp--top-right {
    top: 12px;
    right: 16px;
}

.pdf-page__stamp--footer {
    left: 0;
    right: 0;
    bottom: 12px;
    text-align: center;
}

/* =========================================================================
 * Bloque: pdf-slides — modo diapositiva a pantalla completa.
 * Overlay fijo que cubre todo el viewport (funciona en iOS, donde la
 * Fullscreen API no aplica a elementos arbitrarios). Una página por pantalla.
 * ========================================================================= */
.pdf-slides {
    position: fixed;
    inset: 0;
    z-index: 1000;
    background: #000;
    display: flex;
    align-items: center;
    justify-content: center;
    /* 100dvh evita el salto por la barra de direcciones de iOS. */
    height: 100dvh;
    width: 100vw;
    -webkit-user-select: none;
    user-select: none;
}

.pdf-slides[hidden] {
    display: none;
}

.pdf-slides__stage {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    /* Los gestos táctiles (doble toque, pan, swipe) los gestiona el JS del
       visor; sin esto el navegador aplicaría su propio zoom/scroll nativo. */
    touch-action: none;
    /* Al ampliar (doble toque) el canvas desborda el escenario. */
    overflow: hidden;
}

.pdf-slides__canvas {
    display: block;
    max-width: 100%;
    max-height: 100%;
    box-shadow: 0 2px 16px rgba(0, 0, 0, 0.6);
}

.pdf-slides__nav {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    z-index: 2;
    width: 3rem;
    height: 4rem;
    border: 0;
    border-radius: var(--radius);
    background: rgba(255, 255, 255, 0.12);
    color: #fff;
    font-size: 2rem;
    line-height: 1;
    cursor: pointer;
}

.pdf-slides__nav:hover {
    background: rgba(255, 255, 255, 0.25);
}

.pdf-slides__nav--prev { left: var(--space-2); }
.pdf-slides__nav--next { right: var(--space-2); }

.pdf-slides__close {
    position: absolute;
    top: var(--space-2);
    right: var(--space-2);
    z-index: 2;
    width: 2.5rem;
    height: 2.5rem;
    border: 0;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.12);
    color: #fff;
    font-size: 1.25rem;
    line-height: 1;
    cursor: pointer;
}

.pdf-slides__close:hover {
    background: rgba(255, 255, 255, 0.25);
}

.pdf-slides__counter {
    position: absolute;
    bottom: var(--space-2);
    left: 50%;
    transform: translateX(-50%);
    z-index: 2;
    padding: 0.25rem 0.75rem;
    border-radius: 999px;
    background: rgba(0, 0, 0, 0.5);
    color: #fff;
    font-size: 0.875rem;
}

.pdf-slides__hint {
    position: absolute;
    top: var(--space-2);
    left: 50%;
    transform: translateX(-50%);
    z-index: 2;
    padding: 0.4rem 0.9rem;
    border-radius: 999px;
    background: rgba(255, 255, 255, 0.92);
    color: #1a1a1a;
    font-size: 0.875rem;
    font-weight: 600;
}

.pdf-slides__hint[hidden] {
    display: none;
}

/* =========================================================================
 * Bloque: html-viewer — modo primario para PDFs con acompañante HTML/CSS
 * (Módulo 2). Una diapositiva a la vez en un iframe aislado (su propio
 * deck.css, sin colisión con el CSS del sitio). El modo pantalla completa
 * reutiliza el overlay .pdf-slides ya existente (ver viewer.php).
 * ========================================================================= */
.html-viewer {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-3);
    background: #2a2a2a;
    padding: var(--space-4);
    border-radius: var(--radius);
    margin-left: calc(50% - 50vw);
    margin-right: calc(50% - 50vw);
    max-width: 100vw;
    box-sizing: border-box;
}

.html-viewer[hidden] {
    display: none;
}

/* Vista por defecto (fuera de pantalla completa): TODAS las diapositivas
   apiladas, scroll normal — igual que .pdf-viewer__pages fuera de pantalla
   completa. Sin botones de anterior/siguiente aquí, no hacen falta. */
.html-viewer__list {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
    width: 100%;
}

.html-viewer__list-item {
    display: block;
    width: 100%;
    aspect-ratio: 18288000 / 10287000;
    border: 0;
    border-radius: var(--radius);
    background: #fff;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
}

/* El stage define él mismo la proporción 16:9 — antes la heredaba del único
   iframe que contenía, pero con dos iframes superpuestos en position:absolute
   (para el deslizamiento lateral) ya no aportan tamaño intrínseco al stage. */
.html-viewer__stage {
    position: relative;
    width: 100%;
    aspect-ratio: 18288000 / 10287000;
    overflow: hidden;
}

.html-viewer__frame {
    position: absolute;
    inset: 0;
    display: block;
    width: 100%;
    height: 100%;
    border: 0;
    border-radius: var(--radius);
    /* Mismo tono que el cromado de .html-viewer (no blanco): mientras la
       diapositiva nueva carga, el iframe muestra este fondo un instante —
       en blanco se veía como un parpadeo claro durante el deslizamiento. */
    background: #2a2a2a;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
}

/* Anterior/Siguiente a los lados del contenido. Fondo OSCURO semitransparente
   a propósito (no claro): flota sobre la propia diapositiva, que puede ser
   clara (el deck es de fondo crema) — un fondo claro se camuflaría ahí. */
/* Tamaño responsive con clamp(): un mínimo (como en móvil, sin cambios) y
   un máximo, creciendo con el ancho de la ventana entre medias — en un
   portátil grande o un monitor, estos botones se quedaban con el mismo
   tamaño fijo de siempre y se veían pequeños en proporción. */
.html-viewer__nav {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    z-index: 2;
    width: clamp(3rem, 5vw, 5.5rem);
    height: clamp(4rem, 7vw, 7.5rem);
    border: 0;
    border-radius: var(--radius);
    background: rgba(0, 0, 0, 0.5);
    color: #fff;
    font-size: clamp(2rem, 3vw, 3.5rem);
    line-height: 1;
    cursor: pointer;
}

.html-viewer__nav:hover {
    background: rgba(0, 0, 0, 0.65);
}

.html-viewer__nav--prev { left: var(--space-2); }
.html-viewer__nav--next { right: var(--space-2); }

/* Contador y botón de pantalla completa: controles FLOTANTES sobre el
   contenido (no una barra aparte) — así en pantalla completa el contenido
   ocupa de verdad el 100% del alto, sin reservar espacio fijo para nada. */
.html-viewer__counter {
    position: absolute;
    bottom: var(--space-2);
    left: 50%;
    transform: translateX(-50%);
    z-index: 2;
    padding: 0.25rem 0.75rem;
    border-radius: 999px;
    background: rgba(0, 0, 0, 0.5);
    color: #fff;
    font-size: 0.875rem;
}

.html-viewer__fullscreen-toggle {
    position: fixed;
    top: calc(3.5rem + var(--space-2));
    right: var(--space-2);
    z-index: 3;
    width: 2.5rem;
    height: 2.5rem;
    border: 0;
    border-radius: 50%;
    background: rgba(0, 0, 0, 0.5);
    color: #fff;
    font-size: 1.25rem;
    line-height: 1;
    cursor: pointer;
}

.html-viewer__fullscreen-toggle:hover {
    background: rgba(0, 0, 0, 0.65);
}

.html-viewer__theme-toggle {
    position: fixed;
    top: calc(3.5rem + var(--space-2));
    right: calc(2.5rem + var(--space-2) * 2);
    z-index: 3;
    width: 2.5rem;
    height: 2.5rem;
    border: 0;
    border-radius: 50%;
    background: rgba(0, 0, 0, 0.5);
    color: #fff;
    font-size: 1.1rem;
    line-height: 1;
    cursor: pointer;
}

.html-viewer__theme-toggle:hover {
    background: rgba(0, 0, 0, 0.65);
}

/* Pantalla completa nativa (donde el navegador la soporte en un elemento
   arbitrario; en iOS Safari no aplica y el modo inline sigue funcionando).
   Sin barra que reservar: el stage ocupa el alto real de la pantalla. */
.html-viewer:fullscreen {
    width: 100vw;
    height: 100vh;
    max-width: 100vw;
    justify-content: center;
    background: #000;
}

/* "Contain" con proporción 16:9 fija por fórmula explícita, NO dejando
   width/height los dos en auto: aspect-ratio necesita que al menos un eje
   esté fijado para calcular el otro — con los dos en auto no tiene de dónde
   partir y el iframe cae a su tamaño por defecto (300×150, minúsculo). Aquí
   calculamos las dos candidatas (ancho si manda el alto, alto si manda el
   ancho) y nos quedamos con la más pequeña de cada una — así funciona igual
   de bien en pantallas anchas que en un móvil en vertical. */
.html-viewer:fullscreen .html-viewer__stage {
    width: min(100vw, calc(100vh * 18288000 / 10287000));
    height: min(100vh, calc(100vw * 10287000 / 18288000));
}

.html-viewer:fullscreen .html-viewer__frame {
    width: 100%;
    height: 100%;
}

/* Respaldo para iPhone (Safari no admite la Fullscreen API en elementos
   arbitrarios): overlay fijo que tapa toda la página, como .pdf-slides.
   Mismo "contain" 16:9 que arriba, pero con dvh: en iOS 100vh incluye la
   zona tapada por las barras del navegador. Regla aparte (no en lista con
   :fullscreen) para que un selector no soportado no invalide el otro. */
.html-viewer--fullscreen {
    position: fixed;
    inset: 0;
    z-index: 1000;
    margin: 0;
    padding: 0;
    border-radius: 0;
    width: 100%;
    height: 100%;
    max-width: none;
    justify-content: center;
    background: #000;
}

.html-viewer--fullscreen .html-viewer__stage {
    width: min(100vw, calc(100vh * 18288000 / 10287000));
    height: min(100vh, calc(100vw * 10287000 / 18288000));
    width: min(100vw, calc(100dvh * 18288000 / 10287000));
    height: min(100dvh, calc(100vw * 10287000 / 18288000));
}

.html-viewer--fullscreen .html-viewer__theme-toggle,
.html-viewer--fullscreen .html-viewer__fullscreen-toggle {
    top: calc(var(--space-2) + env(safe-area-inset-top, 0px));
}

/* El zoom táctil de pantalla completa transforma .slide DENTRO del propio
   iframe (ver viewer.php) — no necesita CSS aquí, deck.css ya define esa
   clase y el transform se aplica inline desde JS. */

/* Botón para entrar al modo diapositiva, en la cabecera del visor. */
.viewer-header__slides {
    flex-shrink: 0;
}

/* Mientras el modo diapositiva está activo, evitamos scroll del fondo. */
body.is-slides {
    overflow: hidden;
}

@media print {
    /* Aún imprimiendo, dejamos los sellos visibles. */
    .pdf-page__stamp {
        color: rgba(0, 0, 0, 0.7);
        text-shadow: none;
    }
    .header, .page__footer, .viewer-header, .viewer-links {
        display: none !important;
    }
    .pdf-viewer {
        background: #fff;
        padding: 0;
    }
}

/* =========================================================================
 * Bloque: dropzone — zona para arrastrar y soltar archivos.
 * ========================================================================= */
.dropzone {
    border: 2px dashed var(--color-border);
    border-radius: var(--radius);
    background: var(--color-surface);
    padding: var(--space-6);
    text-align: center;
    color: var(--color-muted);
    cursor: pointer;
    transition: background 0.15s, border-color 0.15s;
    user-select: none;
}

.dropzone:hover {
    background: #f3f4f6;
    border-color: var(--color-primary);
}

.dropzone--active {
    background: rgba(41, 98, 255, 0.08);
    border-color: var(--color-primary);
    color: var(--color-primary);
}

.dropzone__icon {
    display: block;
    font-size: 2.5rem;
    line-height: 1;
    margin-bottom: var(--space-2);
}

.dropzone__label {
    display: block;
    font-size: 1rem;
    color: var(--color-text);
    margin-bottom: var(--space-1);
}

.dropzone__hint {
    display: block;
    font-size: 0.875rem;
}

/* =========================================================================
 * Bloque: bulk-wizard — pasos del wizard de subida masiva.
 * ========================================================================= */
.bulk-wizard {
    margin-top: var(--space-6);
    padding: var(--space-4);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    background: var(--color-bg);
}

.bulk-wizard__header {
    display: flex;
    align-items: baseline;
    gap: var(--space-3);
    flex-wrap: wrap;
    margin-bottom: var(--space-4);
    padding-bottom: var(--space-3);
    border-bottom: 1px solid var(--color-border);
}

.bulk-wizard__step {
    font-weight: 600;
    color: var(--color-primary);
}

.bulk-wizard__filename {
    font-weight: 500;
    color: var(--color-text);
    word-break: break-all;
}

.bulk-wizard__filesize {
    color: var(--color-muted);
    font-size: 0.875rem;
}

.bulk-wizard__nav {
    display: flex;
    justify-content: space-between;
    gap: var(--space-2);
    margin-top: var(--space-4);
    padding-top: var(--space-3);
    border-top: 1px solid var(--color-border);
    flex-wrap: wrap;
}

.bulk-wizard__nav-spacer {
    flex: 1;
}

.bulk-warnings {
    margin-top: var(--space-3);
    padding: var(--space-3);
    background: #fef3c7;
    border: 1px solid #fbbf24;
    border-radius: var(--radius);
    color: #92400e;
    font-size: 0.875rem;
}

.bulk-submit-bar {
    margin-top: var(--space-6);
    padding-top: var(--space-4);
    border-top: 1px solid var(--color-border);
    text-align: right;
}

/* =========================================================================
 * Bloque: overlay — modal reutilizable (estadísticas, enlaces…)
 * ========================================================================= */
.overlay {
    display: none;
    position: fixed;
    inset: 0;
    z-index: 100;
    background: rgba(17, 24, 39, 0.55);
    padding: var(--space-4);
    /* Centrado del panel. */
    align-items: flex-start;
    justify-content: center;
    overflow-y: auto;
}

.overlay--open {
    display: flex;
}

/* Bloquea el scroll del fondo mientras hay un overlay abierto. */
.overlay-lock {
    overflow: hidden;
}

.overlay__panel {
    position: relative;
    width: 100%;
    max-width: 480px;
    margin: auto;
    background: var(--color-bg);
    border-radius: var(--radius);
    padding: 2rem;
    box-shadow: 0 10px 40px rgba(0, 0, 0, 0.25);
}

/* Variante ancha: para tablas (p. ej. el listado de conexiones del curso),
   que no caben cómodas en los 480px por defecto. */
.overlay__panel--wide {
    max-width: 880px;
}

@media (max-width: 520px) {
    .overlay__panel {
        padding: var(--space-4);
    }
}

.overlay__close {
    position: absolute;
    top: var(--space-2);
    right: var(--space-3);
    border: 0;
    background: transparent;
    font-size: 1.75rem;
    line-height: 1;
    color: var(--color-muted);
    cursor: pointer;
}

.overlay__close:hover {
    color: var(--color-text);
}

.overlay__title {
    margin: 0 var(--space-5) var(--space-4) 0;
    font-size: 1.125rem;
}

.overlay__subtitle {
    margin: var(--space-4) 0 var(--space-2);
    font-size: 0.875rem;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: var(--color-muted);
}

/* Lista de estadísticas: etiqueta a la izquierda, valor a la derecha. */
.stat-list {
    list-style: none;
    margin: 0;
    padding: 0;
}

.stat-list__item {
    display: flex;
    justify-content: space-between;
    gap: var(--space-3);
    padding: var(--space-2) 0;
    border-bottom: 1px solid var(--color-border);
}

.stat-list__item:last-child {
    border-bottom: 0;
}

/* Nombre de PDF en el desglose "Por PDF" (truncado). */
.stat-list__name {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 0;
}

/* Evolución de intentos: fecha · barra de nota · % · ✅/✖ */
.attempt-list {
    list-style: none;
    margin: 0;
    padding: 0;
}

.attempt-list__item {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-1) 0;
    font-size: 0.8125rem;
}

.attempt-list__when {
    flex: 0 0 9.5rem;
    color: var(--color-muted);
}

.attempt-list__bar {
    flex: 1;
    height: 8px;
    background: var(--color-border);
    border-radius: 999px;
    overflow: hidden;
}

.attempt-list__fill {
    display: block;
    height: 100%;
    background: #f59e0b; /* ámbar: intento no aprobado */
    border-radius: 999px;
}

.attempt-list__fill--passed {
    background: var(--color-success);
}

.attempt-list__score {
    flex: 0 0 2.6rem;
    text-align: right;
}

/* Avance sobre el banco de preguntas, coloreado por tramo:
 * <40% rojo · 40-89% ámbar · ≥90% verde. */
.qprogress__pct--low  { color: var(--color-danger); }
.qprogress__pct--mid  { color: #d97706; }
.qprogress__pct--high { color: var(--color-success); }

/* Detalle "qué fallé": preguntas del último test. */
.qdetail {
    margin-top: var(--space-2);
    padding-top: var(--space-2);
    border-top: 1px solid var(--color-border);
    font-size: 0.875rem;
}

.qdetail__list {
    list-style: none;
    margin: 0;
    padding: 0;
}

.qdetail__item {
    padding: var(--space-1) 0;
}

.qdetail__item--ok { color: var(--color-success); }
.qdetail__item--ko { color: var(--color-danger); }

.qdetail__explanation {
    margin: 0.15rem 0 0 1.2rem;
    color: var(--color-muted);
    font-size: 0.8125rem;
}

.stat-banner {
    background: #dcfce7;
    color: var(--color-success);
    border: 1px solid #bbf7d0;
    border-radius: var(--radius);
    padding: var(--space-2) var(--space-3);
    margin: 0 0 var(--space-3);
    font-size: 0.875rem;
}

/* Lista de enlaces dentro del overlay. */
.link-list {
    list-style: none;
    margin: 0;
    padding: 0;
}

.link-list__item {
    padding: var(--space-3) 0;
    border-bottom: 1px solid var(--color-border);
}

.link-list__item:last-child {
    border-bottom: 0;
}

.link-list__link {
    font-weight: 600;
    color: var(--color-primary);
    text-decoration: none;
}

.link-list__link:hover {
    text-decoration: underline;
}

.link-list__desc {
    margin: var(--space-1) 0 0;
    font-size: 0.875rem;
    color: var(--color-muted);
}

/* =========================================================================
 * Bloque: student-report — ficha desplegable de un alumno en Actividad.
 * <details>/<summary> nativo: una línea de resumen con la barra de progreso
 * y las métricas y, al abrir, la tabla de detalle PDF a PDF.
 * ========================================================================= */
.student-report {
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    background: var(--color-surface);
    margin-bottom: var(--space-2);
    /* Acento izquierdo neutro que se colorea al abrir. */
    border-left: 3px solid var(--color-border);
    transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.student-report:hover {
    border-color: var(--color-muted);
}

.student-report[open] {
    background: var(--color-bg);
    border-left-color: var(--color-primary);
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06);
}

.student-report__summary {
    display: grid;
    grid-template-columns: var(--report-cols);
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-3) var(--space-4);
    cursor: pointer;
    list-style: none;
}
.student-report__summary:hover { background: var(--color-surface); }
.student-report[open] .student-report__summary:hover { background: transparent; }

/* Oculta el triángulo por defecto y pone uno propio (primera celda de la rejilla). */
.student-report__summary::-webkit-details-marker { display: none; }
.student-report__summary::before {
    content: '▸';
    color: var(--color-muted);
    text-align: center;
    transition: transform 0.15s ease;
}
.student-report[open] .student-report__summary::before {
    transform: rotate(90deg);
    color: var(--color-primary);
}

.student-report__name {
    font-weight: 600;
    min-width: 0;              /* permite el ellipsis dentro de la rejilla */
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.student-report__name a { text-decoration: none; color: var(--color-text); }
.student-report__name a:hover { text-decoration: underline; }

.student-report .table {
    margin: 0;
    padding: 0 var(--space-4) var(--space-3);
    background: transparent;
}

/* -------------------------------------------------------------------------
 * Barra de progreso segmentada: reparte los PDFs del curso del alumno en
 * leídos · abiertos (sin terminar) · pendientes · bloqueados/no disponibles.
 * Da la foto de avance de un vistazo, sin desplegar la ficha.
 * ------------------------------------------------------------------------- */
.progress-bar {
    display: flex;
    width: 100%;
    height: 10px;
    border-radius: 999px;
    overflow: hidden;
    background: var(--color-border);
}

.progress-bar__seg { height: 100%; }
.progress-bar__seg--complete { background: var(--color-success); }
.progress-bar__seg--opened   { background: var(--color-primary); }
.progress-bar__seg--pending  { background: #f59e0b; }
.progress-bar__seg--rest     { background: transparent; }

/* Leyenda de colores de la barra. */
.progress-legend {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-1) var(--space-3);
    margin: 0 0 var(--space-3);
    font-size: 0.8125rem;
    color: var(--color-muted);
}
.progress-legend__item { display: inline-flex; align-items: center; gap: 6px; }
.progress-legend__swatch {
    width: 10px;
    height: 10px;
    border-radius: 3px;
    display: inline-block;
}
.progress-legend__swatch--complete { background: var(--color-success); }
.progress-legend__swatch--opened   { background: var(--color-primary); }
.progress-legend__swatch--pending  { background: #f59e0b; }
.progress-legend__swatch--rest     { background: var(--color-border); }

/* -------------------------------------------------------------------------
 * report — "tabla" de alumnos: cabecera + fichas desplegables alineadas por
 * una rejilla compartida (--report-cols) para que las columnas cuadren sin
 * meter <details> dentro de <table>.
 * ------------------------------------------------------------------------- */
.report-scroll { overflow-x: auto; }

.report {
    min-width: 720px;
    /* Plantilla de columnas compartida por la cabecera y cada fila:
       caret · alumno · progreso · abiertos · leídos · pend. · tests · tiempo · media */
    --report-cols:
        1.25rem minmax(13rem, 2fr) 140px
        minmax(4.5rem, .7fr) minmax(4rem, .6fr) minmax(4rem, .6fr)
        minmax(3.5rem, .5fr) minmax(4.5rem, .7fr) minmax(5.5rem, .8fr);
}

.report__head {
    display: grid;
    grid-template-columns: var(--report-cols);
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-2) var(--space-4);
    border-left: 3px solid transparent;   /* alinea con el acento de las fichas */
    border-bottom: 2px solid var(--color-border);
    font-size: 0.75rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.02em;
    color: var(--color-muted);
}

.report__col--num,
.report__cell--num { text-align: right; }

.report__cell--num {
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}
.report__cell-sub { color: var(--color-muted); }

/* Estado de un PDF para el alumno (en la tabla de detalle). */
.state-pill {
    display: inline-block;
    padding: 2px 8px;
    font-size: 0.75rem;
    font-weight: 600;
    border-radius: 999px;
}

.state-pill--complete    { background: #dcfce7; color: #15803d; }
.state-pill--opened      { background: #dbeafe; color: #1e40af; }
.state-pill--pending     { background: #fef3c7; color: #92400e; }
.state-pill--locked      { background: #e5e7eb; color: #4b5563; }
.state-pill--unavailable { background: #f3f4f6; color: #9ca3af; }

.student-report__hint {
    margin: 0 0 var(--space-2);
    font-size: 0.875rem;
    color: var(--color-muted);
}

/* =========================================================================
 * Bloque: section-cards — rejilla de tarjetas que abren cada sección de
 * Actividad en un overlay.
 * ========================================================================= */
.section-cards {
    display: grid;
    /* auto-fit + 1fr: las tarjetas presentes se estiran para ocupar todo el
       ancho disponible en lugar de dejar huecos (auto-fill). */
    grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
    gap: var(--space-4);
    margin-bottom: var(--space-5);
}

.section-card {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-2);
    text-align: left;
    min-height: 170px;
    padding: var(--space-6);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    background: var(--color-surface);
    cursor: pointer;
    transition: border-color 0.15s ease, box-shadow 0.15s ease, transform 0.05s ease;
}
.section-card:hover {
    border-color: var(--color-primary);
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
    transform: translateY(-2px);
}
.section-card:active { transform: translateY(0); }

.section-card__icon  { font-size: 2.25rem; line-height: 1; }
.section-card__title { font-weight: 700; font-size: 1.25rem; color: var(--color-text); }
.section-card__teaser { color: var(--color-muted); font-size: 0.875rem; }
/* El CTA se ancla abajo para que todas las tarjetas queden alineadas. */
.section-card__cta {
    margin-top: auto;
    padding-top: var(--space-2);
    color: var(--color-primary);
    font-size: 0.875rem;
    font-weight: 600;
}

/* Pie de navegación entre overlays de sección (← anterior / siguiente →). */
.overlay-nav {
    display: flex;
    justify-content: space-between;
    gap: var(--space-2);
    margin-top: var(--space-4);
    padding-top: var(--space-3);
    border-top: 1px solid var(--color-border);
}

/* -------------------------------------------------------------------------
 * Cabecera ordenable de la tabla de alumnos: cada columna es un botón con
 * una flecha (↕ inactiva · ↑/↓ según el sentido activo).
 * ------------------------------------------------------------------------- */
.report__sort {
    font: inherit;
    color: inherit;
    text-transform: inherit;
    letter-spacing: inherit;
    background: none;
    border: 0;
    padding: 0;
    cursor: pointer;
    white-space: nowrap;
}
.report__sort:hover { color: var(--color-text); }
.report__sort::after {
    content: '↕';
    margin-left: 4px;
    font-size: 0.85em;
    opacity: 0.4;
}
.report__sort.is-asc::after  { content: '↑'; opacity: 1; color: var(--color-primary); }
.report__sort.is-desc::after { content: '↓'; opacity: 1; color: var(--color-primary); }

/* Valores con color en las celdas del resumen (recuperado): abiertos (azul),
 * leídos (verde) y pendientes (ámbar); en 0 quedan neutros. Coherente con la
 * barra de progreso y con las state-pill del detalle. */
.report__val {
    display: inline-block;
    min-width: 1.6rem;
    padding: 1px 8px;
    border-radius: 999px;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    text-align: center;
}
.report__val-sub { font-weight: 400; opacity: 0.7; }
.report__val--opened   { background: #dbeafe; color: #1e40af; }
.report__val--complete { background: #dcfce7; color: #15803d; }
.report__val--pending  { background: #fef3c7; color: #92400e; }
.report__val--zero     { background: transparent; color: var(--color-muted); }

/* =========================================================================
 * Overlay de "Lectura y acceso": variante XL y tarjetas "hero" (más grandes
 * y con acento superior) para que resulte más vistoso.
 * ========================================================================= */
.overlay__panel--xl { max-width: 1040px; }
/* Variante para la tabla de "Detalle por alumno": lo más ancha posible para
   que quepan los nombres completos y las 9 columnas sin apreturas. */
.overlay__panel--xxl { max-width: min(1280px, 96vw); }

.overlay__title--hero {
    font-size: 1.4rem;
    padding-bottom: var(--space-3);
    border-bottom: 2px solid var(--color-border);
}

.admin-stats--hero {
    grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
    gap: var(--space-4);
}
.admin-stats--hero .stat-card {
    padding: var(--space-5);
    border-top: 3px solid var(--color-primary);
}
.admin-stats--hero .stat-card__value { font-size: 2.4rem; }

/* =========================================================================
 * Eventos recientes: estado del rango + separadores de lote + centinela de
 * la paginación asíncrona por scroll.
 * ========================================================================= */
.events-status {
    font-weight: 400;
    font-size: 0.8125rem;
    color: var(--color-muted);
}

/* Fila-separador que anuncia el rango de cada lote ("11 – 20"). */
.events-batch__cell {
    padding: var(--space-1) var(--space-3);
    background: var(--color-surface);
    border-bottom: 1px solid var(--color-border);
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    color: var(--color-muted);
    text-transform: uppercase;
}

/* Objetivo del IntersectionObserver: sin alto propio, solo un punto que, al
   entrar en el área visible del overlay, dispara la carga del siguiente lote. */
.events-sentinel {
    height: 1px;
}

/* =========================================================================
 * chart-toggle — control segmentado Líneas/Columnas del gráfico de actividad,
 * y chart-tall — contenedor que da altura al gráfico (con maintainAspectRatio
 * a false el canvas rellena esta caja, así se ve mucho más grande).
 * ========================================================================= */
.chart-toggle {
    display: inline-flex;
    border: 1px solid var(--color-border);
    border-radius: 999px;
    overflow: hidden;
    margin-bottom: var(--space-2);
}
.chart-toggle__btn {
    border: 0;
    background: var(--color-bg);
    color: var(--color-muted);
    padding: 4px 16px;
    font: inherit;
    font-size: 0.875rem;
    cursor: pointer;
}
.chart-toggle__btn + .chart-toggle__btn { border-left: 1px solid var(--color-border); }
.chart-toggle__btn.is-active {
    background: var(--color-primary);
    color: #fff;
    font-weight: 600;
}

.chart-tall .chart-wrap {
    height: 56vh;
    min-height: 300px;
    max-height: 500px;
}

/* =========================================================================
 * Página "Por alumno" (/admin/students-activity)
 * Bloques nuevos en paralelo: no tocan nada de /admin/activity.
 * Listado = fichas de alumno (student-card) de mejor a peor; detalle =
 * overlay lateral (drawer) o página propia (fallback sin JS).
 * ========================================================================= */

/* El buscador crece para ocupar el hueco libre de la barra de filtros. */
.form__input--grow {
    flex: 1 1 200px;
    min-width: 160px;
}

/* Bloque: summary-strip — franja de stat-cards compactas sobre las fichas. */
.summary-strip {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    gap: var(--space-2);
    margin-bottom: var(--space-5);
}

.summary-strip .stat-card {
    padding: var(--space-3) var(--space-4);
    gap: 2px;
}

.summary-strip .stat-card__value {
    font-size: 1.375rem;
    font-variant-numeric: tabular-nums;
}

.summary-strip .stat-card__value small {
    font-size: 0.8125rem;
    font-weight: 400;
    color: var(--color-muted);
}

.stat-card--attention {
    border-color: var(--color-pending);
}

/* Bloque: roster-tools — chips de filtro rápido + nota de orden. */
.roster-tools {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2) var(--space-4);
    margin-bottom: var(--space-3);
}

.roster-tools__sort {
    margin-left: auto;
    display: flex;
    align-items: center;
    gap: var(--space-2);
}

.roster-tools__label {
    font-size: 0.875rem;
    color: var(--color-muted);
}

/* Bloque: chip-filter — filtro rápido tipo píldoras. */
.chip-filter {
    display: flex;
    gap: var(--space-1);
}

.chip-filter__btn {
    padding: 4px 12px;
    border-radius: 999px;
    border: 1px solid var(--color-border);
    background: var(--color-bg);
    color: var(--color-muted);
    font-size: 0.875rem;
    font-family: inherit;
    cursor: pointer;
}

.chip-filter__btn:hover {
    background: var(--color-surface);
}

.chip-filter__btn--active {
    background: var(--color-primary);
    border-color: var(--color-primary);
    color: #fff;
    font-weight: 600;
}

/* Bloque: student-card — ficha de un alumno (esbozo: solo lo importante).
 * Es un <a> entero: sin JS navega a la página de detalle; con JS abre el
 * drawer. El nº de posición (mejor a peor) va en la esquina. */
.student-card {
    display: grid;
    grid-template-columns: minmax(200px, 1.3fr) auto minmax(190px, 1fr) auto;
    gap: var(--space-3) var(--space-5);
    align-items: center;
    padding: var(--space-4);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    background: var(--color-bg);
    margin-bottom: var(--space-2);
    cursor: pointer;
    position: relative;
    text-decoration: none;
    color: inherit;
}

.student-card:hover {
    background: var(--color-surface);
    border-color: var(--color-primary);
}

.student-card:hover .donut__hole {
    background: var(--color-surface);
}

.student-card__rank {
    position: absolute;
    top: 8px;
    left: 10px;
    font-size: 0.8125rem;
    font-weight: 700;
    color: var(--color-muted);
    font-variant-numeric: tabular-nums;
}

.student-card__who {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
    padding-left: 14px;
}

.student-card__name {
    font-weight: 700;
    font-size: 1.25rem;
    display: flex;
    align-items: center;
    gap: 7px;
    flex-wrap: wrap;
}

.student-card__email {
    font-size: 0.875rem;
    color: var(--color-muted);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.student-card__conn {
    font-size: 1rem;
    color: var(--color-muted);
}

.student-card__conn--now {
    color: var(--color-success);
    font-weight: 600;
}

.student-card__charts {
    display: flex;
    gap: var(--space-5);
}

.student-card__chart {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 3px;
    font-size: 0.8125rem;
    color: var(--color-muted);
    text-align: center;
}

.student-card__chart b {
    color: var(--color-text);
    font-weight: 600;
}

.student-card__time {
    display: flex;
    flex-direction: column;
    gap: 1px;
}

.student-card__time-val {
    font-size: 1.5rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    line-height: 1.2;
}

.student-card__time-meta {
    font-size: 0.875rem;
    color: var(--color-muted);
}

.student-card__delta { font-size: 0.875rem; font-weight: 600; }
.student-card__delta--up   { color: var(--color-success); }
.student-card__delta--down { color: #92400e; }
.student-card__delta--even { color: var(--color-muted); font-weight: 400; }

.student-card__cta {
    color: var(--color-primary);
    font-size: 1rem;
    white-space: nowrap;
    justify-self: end;
}

.student-card:hover .student-card__cta {
    text-decoration: underline;
}

@media (max-width: 760px) {
    .student-card { grid-template-columns: 1fr auto; }
    .student-card__time { grid-column: 1; }
    .student-card__cta { grid-column: 2; grid-row: 1; align-self: start; }
}

/* Bloque: donut — anillo de % con conic-gradient (sin librerías). El color
 * se pinta inline (conic-gradient con vars); aquí solo la geometría. */
.donut {
    position: relative;
    width: 72px;
    height: 72px;
    border-radius: 50%;
    display: inline-grid;
    place-items: center;
    background: var(--color-border);
}

.donut__hole {
    position: absolute;
    inset: 8px;
    border-radius: 50%;
    background: var(--color-bg);
    display: grid;
    place-items: center;
    font-size: 0.9375rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    line-height: 1;
    white-space: nowrap;
}

.donut--lg {
    width: 108px;
    height: 108px;
}

.donut--lg .donut__hole {
    inset: 13px;
    font-size: 1.25rem;
}

/* Bloque: flag-pill — señal de atención junto al nombre del alumno. */
.flag-pill {
    display: inline-block;
    padding: 2px 9px;
    border-radius: 999px;
    font-size: 0.75rem;
    font-weight: 600;
    white-space: nowrap;
}

.flag-pill--warn   { background: #fef3c7; color: #92400e; }
.flag-pill--danger { background: #fee2e2; color: #b91c1c; }

/* Bloque: drawer — overlay lateral de detalle ("pasando la página"). */
.drawer {
    position: fixed;
    inset: 0;
    z-index: 40;
    visibility: hidden;
}

.drawer--open { visibility: visible; }

.drawer__backdrop {
    position: absolute;
    inset: 0;
    background: rgba(0, 0, 0, 0.35);
    opacity: 0;
    transition: opacity 0.25s;
}

.drawer--open .drawer__backdrop { opacity: 1; }

.drawer__panel {
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    width: min(860px, 96vw);
    background: var(--color-bg);
    border-left: 1px solid var(--color-border);
    box-shadow: -12px 0 32px rgba(0, 0, 0, 0.18);
    transform: translateX(100%);
    transition: transform 0.28s ease;
    overflow-y: auto;
    padding: var(--space-5);
}

.drawer--open .drawer__panel { transform: translateX(0); }

@media (prefers-reduced-motion: reduce) {
    .drawer__panel,
    .drawer__backdrop { transition: none; }
}

.drawer__top {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    margin-bottom: var(--space-4);
}

.drawer__close {
    border: 1px solid var(--color-border);
    background: var(--color-bg);
    color: var(--color-muted);
    border-radius: var(--radius);
    font-size: 1.125rem;
    line-height: 1;
    padding: 6px 10px;
    cursor: pointer;
}

.drawer__close:hover {
    background: var(--color-surface);
    color: var(--color-text);
}

.drawer__pager {
    margin-left: auto;
    display: flex;
    gap: var(--space-1);
    align-items: center;
}

.drawer__pager-pos {
    font-size: 0.8125rem;
    color: var(--color-muted);
    margin-right: var(--space-2);
    font-variant-numeric: tabular-nums;
}

/* Bloque: detail-head — cabecera del panel de detalle (drawer y página). */
.detail-head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-4) var(--space-6);
    margin-bottom: var(--space-4);
    padding: var(--space-4);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    background: var(--color-surface);
}

.detail-head .donut__hole {
    background: var(--color-surface);
}

.detail-head__who {
    min-width: 200px;
    flex: 1 1 220px;
}

.detail-head__name {
    font-size: 1.25rem;
    font-weight: 700;
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
}

.detail-head__meta {
    font-size: 0.875rem;
    color: var(--color-muted);
}

.detail-head__meta--now {
    color: var(--color-success);
    font-weight: 600;
}

.detail-head__donuts {
    display: flex;
    gap: var(--space-6);
}

.detail-head__donut-box {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-1);
    font-size: 0.75rem;
    color: var(--color-muted);
    text-align: center;
}

.detail-head__stats {
    display: flex;
    gap: var(--space-5);
    flex-wrap: wrap;
    margin: 0;
}

.detail-head__stat dt {
    font-size: 0.6875rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--color-muted);
}

.detail-head__stat dd {
    margin: 0;
    font-size: 1.125rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

.detail-head__stat dd small {
    font-size: 0.75rem;
    font-weight: 400;
    color: var(--color-muted);
}

/* La barra de progreso ocupa todo el ancho de la cabecera del detalle
 * (reutiliza el bloque .progress-bar existente). */
.detail-head .progress-bar,
.detail-head .progress-legend {
    flex: 1 1 100%;
}

/* Bloque: detail-page — enlace de vuelta en la página de detalle (fallback). */
.detail-page__back {
    display: inline-block;
    margin-bottom: var(--space-4);
    color: var(--color-primary);
    text-decoration: none;
    font-size: 0.9375rem;
}

.detail-page__back:hover {
    text-decoration: underline;
}

/* Baja por curso (user_course.dropped_at): pill gris + ficha atenuada. El
 * alumno sigue visible con sus estadísticas pero fuera de medias y ranking. */
.flag-pill--baja {
    background: var(--color-border);
    color: var(--color-muted);
}

.student-card--baja {
    opacity: 0.62;
}

.student-card--baja:hover {
    opacity: 1;
}

/* =========================================================================
 * Bloque: module-tabs — pestañas por módulo en el curso del alumno.
 * Renderizadas ocultas (hidden); module-tabs.js las muestra si hay >1 módulo.
 * ========================================================================= */
.module-tabs {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-1);
    margin-bottom: var(--space-5);
    border-bottom: 2px solid var(--color-border);
    padding-bottom: var(--space-2);
}

.module-tabs__tab {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding: var(--space-2) var(--space-4);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    background: var(--color-surface);
    color: var(--color-muted);
    font-family: inherit;
    font-size: 1rem;
    font-weight: 600;
    cursor: pointer;
}

.module-tabs__tab:hover {
    background: var(--color-bg);
    color: var(--color-text);
}

.module-tabs__tab--active {
    background: var(--color-primary);
    border-color: var(--color-primary);
    color: #fff;
}

.module-tabs__count {
    font-size: 0.8125rem;
    font-weight: 400;
    padding: 0 7px;
    border-radius: 999px;
    background: rgba(0, 0, 0, 0.08);
}

.module-tabs__tab--active .module-tabs__count {
    background: rgba(255, 255, 255, 0.22);
}

/* Punto "estás aquí": marca la pestaña del módulo con trabajo pendiente. */
.module-tabs__dot {
    width: 9px;
    height: 9px;
    border-radius: 50%;
    background: var(--color-primary);
    box-shadow: 0 0 0 3px rgba(41, 98, 255, 0.2);
}

.module-tabs__tab--active .module-tabs__dot {
    background: #fff;
    box-shadow: 0 0 0 3px rgba(255, 255, 255, 0.3);
}

/* =========================================================================
 * Bloque: wizard — asistente guiado de subida de material
 * (/admin/pdfs/wizard, ver src/controllers/admin/pdf_wizard.php).
 *
 * Bloque aparte de .bulk-wizard, que es el de la subida masiva: comparten
 * nombre en castellano pero no pantalla ni estilos.
 * ========================================================================= */
.wizard {
    max-width: 44rem;
    margin: 0 auto var(--space-6);
}

.wizard__title {
    margin: 0 0 var(--space-2);
    font-size: 1.375rem;
}

.wizard__hint {
    margin: 0 0 var(--space-5);
    color: var(--color-muted);
}

.wizard__form {
    padding: var(--space-5);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    background: var(--color-bg);
}

/* --- Raíl de pasos --------------------------------------------------- */
.wizard__steps {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: var(--space-2);
    max-width: 44rem;
    margin: 0 auto var(--space-5);
    padding: 0;
    list-style: none;
}

.wizard__step {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding-top: var(--space-2);
    border-top: 3px solid var(--color-border);
    color: var(--color-muted);
}

.wizard__step--current {
    border-top-color: var(--color-primary);
    color: var(--color-text);
}

.wizard__step--done {
    border-top-color: var(--color-success);
}

.wizard__step-link {
    display: flex;
    flex-direction: column;
    gap: 2px;
    color: inherit;
    text-decoration: none;
}

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

.wizard__step-num {
    font-size: 0.75rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

.wizard__step-name {
    font-weight: 600;
    font-size: 0.875rem;
    line-height: 1.25;
}

/* --- Zonas de archivo ------------------------------------------------ */
.wizard__drop {
    margin-bottom: var(--space-5);
    padding: var(--space-4);
    border: 1px dashed var(--color-border);
    border-radius: var(--radius);
    background: var(--color-surface);
    position: relative;   /* ancla del cartel de «suelta aquí» */
    transition: transform 0.15s ease, background-color 0.15s ease,
                border-color 0.15s ease, box-shadow 0.15s ease;
}

.wizard__drop--filled {
    border-style: solid;
    border-color: var(--color-primary);
    background: rgba(41, 98, 255, 0.05);
}

/* Arrastrar y soltar. Las dos zonas están muy juntas, así que solo se marca
   UNA a la vez: la que tiene el puntero dentro (--over, crecida del todo) o,
   mientras se acerca, la más cercana (--near, un empujón). Así se ve dónde
   va a caer el archivo antes de soltarlo.

   Crecen con transform, NO con padding: el padding recolocaría la caja de
   abajo y el sitio al que apuntas se movería bajo el cursor justo cuando
   vas a soltar. El transform no toca el flujo, solo pinta más grande. */

.wizard__drop--near {
    position: relative;
    z-index: 1;
    transform: scale(1.02);
    border-color: var(--color-primary);
    background: rgba(41, 98, 255, 0.05);
}

.wizard__drop--over {
    position: relative;
    z-index: 2;
    transform: scale(1.05);
    border-color: var(--color-primary);
    background: rgba(41, 98, 255, 0.12);
    box-shadow: 0 0 0 4px rgba(41, 98, 255, 0.15);
}

.wizard__drop--reject {
    border-color: var(--color-danger);
    background: rgba(185, 28, 28, 0.08);
    box-shadow: 0 0 0 4px rgba(185, 28, 28, 0.10);
}

/* El cartel va fuera del flujo a propósito: si ocupara sitio, al aparecer
   crecería la caja y empujaría a la de abajo — que es justo la otra zona de
   subida, moviéndose bajo el cursor. */

.wizard__drop-hint {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    margin: 0;
    padding: var(--space-2);
    border-radius: var(--radius);
    background: rgba(255, 255, 255, 0.84);
    color: var(--color-primary);
    font-weight: 600;
    text-align: center;
    opacity: 0;
    pointer-events: none;   /* no estorba al soltar */
    transition: opacity 0.15s ease;
}

/* Al acercarse se intuye; dentro, se lee. */
.wizard__drop--near .wizard__drop-hint {
    opacity: 0.5;
}

.wizard__drop--over .wizard__drop-hint,
.wizard__drop--reject .wizard__drop-hint {
    opacity: 1;
}

.wizard__drop--reject .wizard__drop-hint {
    color: var(--color-danger);
}

@media (prefers-reduced-motion: reduce) {
    .wizard__drop,
    .wizard__drop-hint { transition: none; }
}

.wizard__drop-top {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-1) var(--space-3);
    align-items: baseline;
    margin-bottom: var(--space-2);
}

.wizard__drop-kind {
    font-weight: 600;
}

.wizard__drop-tag {
    font-size: 0.75rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--color-muted);
}

.wizard__drop-body {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2) var(--space-3);
    align-items: center;
    margin-bottom: var(--space-3);
}

.wizard__file {
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 0.875rem;
    word-break: break-all;
}

/* --- Distintivos ----------------------------------------------------- */
.wizard__chips {
    display: inline-flex;
    flex-wrap: wrap;
    gap: var(--space-1);
}

.wizard__chip {
    display: inline-flex;
    align-items: center;
    padding: 1px 9px;
    border-radius: 999px;
    border: 1px solid var(--color-border);
    background: var(--color-bg);
    font-size: 0.8125rem;
    font-weight: 500;
    color: var(--color-muted);
}

.wizard__chip--ok {
    border-color: transparent;
    background: #dcfce7;
    color: #166534;
}

.wizard__chip--info {
    border-color: transparent;
    background: #fef3c7;
    color: #92400e;
}

/* --- Avisos ---------------------------------------------------------- */
/* Asistente: "¿material nuevo o versión nueva?" a mano, plegado. */
.wizard__target {
    margin: 0 0 var(--space-4);
}
.wizard__target-summary {
    cursor: pointer;
    color: var(--color-muted);
    font-size: 0.875rem;
}

/* Asistente: ventana de confirmación de versión nueva. */
.wizard__confirm {
    max-width: 520px;
}
.wizard__confirm-text {
    margin: 0 0 var(--space-2);
}
.wizard__confirm-why {
    margin: 0 0 var(--space-4);
    color: var(--color-muted);
    font-size: 0.875rem;
}
.wizard__confirm-option {
    display: block;
    margin: 0 0 var(--space-2);
}

.wizard__banner {
    margin: 0 0 var(--space-5);
    padding: var(--space-3);
    border-radius: var(--radius);
    font-size: 0.9375rem;
}

.wizard__banner--ok {
    background: #dcfce7;
    color: #166534;
}

.wizard__banner--info {
    background: #fef3c7;
    color: #92400e;
}

.wizard__warning {
    margin: 0 0 var(--space-3);
    padding: var(--space-3);
    border-radius: var(--radius);
    background: #fef3c7;
    color: #92400e;
    font-size: 0.9375rem;
}

.wizard__note {
    margin: var(--space-3) 0 0;
    color: var(--color-muted);
    font-size: 0.8125rem;
}

/* --- Vista previa del orden dentro del módulo ------------------------ */
.wizard__slot {
    margin: 0;
    padding: 0;
    list-style: none;
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    overflow: hidden;
}

.wizard__slot-item {
    display: flex;
    gap: var(--space-3);
    align-items: baseline;
    padding: var(--space-2) var(--space-3);
    border-top: 1px solid var(--color-border);
    font-size: 0.9375rem;
    color: var(--color-muted);
}

.wizard__slot-item:first-child {
    border-top: 0;
}

.wizard__slot-item--new {
    background: rgba(41, 98, 255, 0.08);
    color: var(--color-text);
    font-weight: 600;
}

.wizard__slot-order {
    flex: none;
    width: 2.2em;
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 0.8125rem;
}

.wizard__order {
    max-width: 7rem;
}

/* --- Vía manual: pedirle la ficha a Claude desde tu propia cuenta ----- */
.wizard__aside {
    margin: var(--space-5) 0;
    padding: var(--space-4);
    border: 1px solid var(--color-border);
    border-left: 3px solid var(--color-pending);
    border-radius: var(--radius);
    background: var(--color-surface);
}

.wizard__aside-head {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-1) var(--space-3);
    align-items: baseline;
    margin-bottom: var(--space-1);
}

.wizard__aside-title {
    font-weight: 600;
}

.wizard__aside-tag {
    font-size: 0.75rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--color-success);
}

.wizard__aside-text {
    margin: 0 0 var(--space-3);
    color: var(--color-muted);
    font-size: 0.9375rem;
}

.wizard__prompt {
    margin: 0;
    padding: var(--space-3);
    overflow-x: auto;
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    background: var(--color-bg);
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 0.8125rem;
    line-height: 1.6;
    color: var(--color-text);
    white-space: pre-wrap;
}

.wizard__json {
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 0.8125rem;
}

/* --- Resumen del paso 4 ---------------------------------------------- */
.wizard__summary {
    display: grid;
    grid-template-columns: minmax(8rem, 11rem) 1fr;
    gap: 0;
    margin: 0 0 var(--space-5);
    padding: var(--space-4) var(--space-5);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    background: var(--color-surface);
}

.wizard__summary-key {
    padding: var(--space-2) var(--space-3) var(--space-2) 0;
    border-top: 1px solid var(--color-border);
    font-weight: 600;
    font-size: 0.875rem;
    color: var(--color-muted);
}

.wizard__summary-value {
    margin: 0;
    padding: var(--space-2) 0;
    border-top: 1px solid var(--color-border);
}

.wizard__summary-value--empty {
    color: var(--color-muted);
}

/* --- Barra de acciones ----------------------------------------------- */
.wizard__actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    align-items: center;
    margin-top: var(--space-5);
    padding-top: var(--space-4);
    border-top: 1px solid var(--color-border);
}

.wizard__spacer {
    flex: 1;
}

@media (max-width: 40rem) {
    .wizard__steps {
        grid-template-columns: repeat(2, 1fr);
        gap: var(--space-2) var(--space-3);
    }

    .wizard__summary {
        grid-template-columns: 1fr;
        padding: var(--space-3) var(--space-4);
    }

    .wizard__summary-value {
        border-top: 0;
        padding-top: 0;
    }

    .wizard__summary-key {
        padding-bottom: 0;
    }
}
