/* ═══════════════════════════════════════════════════════════════
   Aulas Guacurarí — Visor de contenidos (curso.php)
   ═══════════════════════════════════════════════════════════════ */

/* ═══════════════════════════════════════════════════════════════
   Visor de contenidos
   ═══════════════════════════════════════════════════════════════ */

/* Header del visor: eyebrow + título del curso a la izquierda, contador de
   avance + barra angosta a la derecha — una sola fila compacta (opción 1a). */
.visor-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    padding: 18px 24px;
    border-bottom: 1px solid var(--autoasistidos-border);
}
.visor-header-info { min-width: 0; }
.visor-header-eyebrow {
    display: block;
    font-size: 10px;
    font-weight: 700;
    color: var(--autoasistidos-text-muted);
    text-transform: uppercase;
    letter-spacing: .08em;
}
.visor-header-titulo {
    display: block;
    font-size: 17px;
    font-weight: 700;
    color: var(--autoasistidos-text);
    margin-top: 2px;
}
.visor-header-progreso { text-align: right; flex-shrink: 0; }
.visor-header-progreso-label {
    font-size: 12px;
    font-weight: 600;
    color: var(--autoasistidos-text-muted);
}

/* Barra de progreso: angosta, alineada a la derecha del header */
.visor-progress-track {
    width: 140px;
    height: 6px;
    background: var(--autoasistidos-primary-lt);
    border-radius: 10px;
    margin-top: 6px;
    overflow: hidden;
}
.visor-progress-fill {
    height: 100%;
    background: var(--autoasistidos-primary);
    border-radius: 10px;
    transition: width .4s ease;
}

/* Layout sidebar + área principal: alto ESTABLE basado en viewport, nunca
   crece/achica con el contenido. Sidebar y panel principal heredan ese alto
   por stretch del flex row y scrollean adentro si su contenido excede — la
   página nunca salta, solo el interior de la caja (fix de alto, desktop). */
.visor-layout {
    display: flex;
    border-top: 1px solid var(--autoasistidos-border);
    height: min(70vh, 680px);
    min-height: 460px;
}

/* Sidebar */
.visor-sidebar {
    width: 333px;
    flex-shrink: 0;
    border-right: 1px solid var(--autoasistidos-border);
    overflow-y: auto;
    /* Sin max-height propio: hereda el alto de .visor-layout por stretch del
       flex row (ver fix de alto arriba) y scrollea adentro si excede.
       Reserva el espacio de la barra siempre, haya o no overflow — sin esto,
       el ancho útil de las filas cambia de golpe apenas aparece el scroll
       (barra nativa ~15-17px en Windows) y todo reflowea. */
    scrollbar-gutter: stable;
    scrollbar-width: thin;
    scrollbar-color: #c7d3e0 transparent;
}
.visor-sidebar::-webkit-scrollbar { width: 8px; }
.visor-sidebar::-webkit-scrollbar-track { background: transparent; }
.visor-sidebar::-webkit-scrollbar-thumb { background: #c7d3e0; border-radius: 8px; }
.visor-sidebar::-webkit-scrollbar-thumb:hover { background: #aebccc; }

/* Fondo + agarre del bottom-sheet: solo existen visualmente en mobile (ver
   media query 680px). En desktop el sidebar es panel fijo, sin sheet. */
.visor-sheet-backdrop { display: none; }
.visor-sidebar-sheet-handle { display: none; }
.visor-sidebar-sheet-grip { width: 34px; height: 4px; border-radius: 2px; background: var(--autoasistidos-border); }
.visor-sidebar-sheet-titulo { font-size: 13px; font-weight: 700; color: var(--autoasistidos-text); }

/* Numeración de unidades: contador CSS puro (sin tocar el JS) que arma el
   "UNIDAD 01 / 02 / 03…" del eyebrow. Se resetea una vez en el contenedor. */
#visor-sidebar-list { counter-reset: visor-unidad; }

/* Contenedor por unidad: acota el rango en el que su header puede quedar
   sticky, evitando que se superponga con el header de la unidad siguiente
   cuando esta tiene poco contenido. Ver comentario en curso.js/renderSidebar. */
/* Card bordeada por unidad (mockup): borde neutro en reposo, azul cuando
   está abierta — reemplaza el fondo gris plano que se usaba antes para
   marcar el estado abierto/cerrado. */
.visor-unidad-grupo {
    position: relative;
    margin: 0 10px 10px 10px;
    border: 1.5px solid var(--autoasistidos-border);
    border-radius: var(--autoasistidos-radius-sm);
    overflow: hidden;
    transition: border-color var(--autoasistidos-transition);
}
.visor-unidad-grupo:first-child { margin-top: 10px; }
.visor-unidad-grupo--abierta { border-color: var(--autoasistidos-primary); }
/* Pulso de entrada: solo en la primera unidad, solo cuando el sidebar entra
   sin nada preseleccionado (ver renderSidebar) — insinúa "tocá acá" sin
   texto extra. Infinito a propósito: dura hasta que el usuario abre
   cualquier unidad (toggleUnidad limpia la clase ahí, sin importar cuál se
   haya tocado), no hay corte por tiempo/repeticiones. */
.visor-unidad-grupo--pulse {
    animation: visorUnidadPulso 1.6s ease-out infinite;
}
@keyframes visorUnidadPulso {
    0%   { box-shadow: 0 0 0 0 rgba(var(--autoasistidos-primary-rgb), .45); }
    70%  { box-shadow: 0 0 0 8px rgba(var(--autoasistidos-primary-rgb), 0); }
    100% { box-shadow: 0 0 0 0 rgba(var(--autoasistidos-primary-rgb), 0); }
}

/* Header de unidad (nivel 1, acordeón): clickeable, con anillo de progreso
   (conic-gradient armado/actualizado desde JS) + eyebrow "UNIDAD 0X" (via
   counter CSS) + título + chevron que rota al abrir. Fondo distinto cuando
   está abierta para reforzar el estado. */
.visor-unidad-header {
    counter-increment: visor-unidad;
    display: flex;
    /* flex-start (no center): el badge "X de Y completados" agrega una 3ra
       línea bajo el título (mockup) — ring/chevron se recentran vía
       align-self propio, mismo criterio que .visor-modulo-header. Sigue
       siendo compacto (altura fija según contenido real, no crece al
       scrollear) — la descripción va aparte, en .visor-unidad-desc-block. */
    align-items: flex-start;
    gap: 12px;
    padding: 13px 16px;
    border-bottom: 1px solid var(--autoasistidos-border);
    /* Jerarquía visual unidad > módulo > contenido vía escala de grises
       (no azul — el azul queda reservado 100% para .visor-item--activo, ver
       más abajo). Blanco en reposo, se oscurece con hover/abierta. */
    background: var(--autoasistidos-surface);
    cursor: pointer;
    transition: background var(--autoasistidos-transition);
    position: sticky;
    top: 0;
    z-index: 1;
}
.visor-unidad-header:hover { background: var(--autoasistidos-gray-unidad-hover); }
.visor-unidad-grupo--abierta .visor-unidad-header { background: var(--autoasistidos-primary-lt); border-bottom-color: var(--autoasistidos-primary); }

.visor-unidad-ring {
    flex-shrink: 0;
    width: 32px;
    height: 32px;
    border-radius: 50%;
    position: relative;
    align-self: center; /* header pasó a align-items:flex-start (ver arriba); el ring se recentra solo */
    /* Fondo (conic-gradient del % vs color claro de fondo) seteado inline
       desde actualizarProgreso() en curso.js — acá solo el tamaño/forma. */
}
.visor-unidad-ring-inner {
    position: absolute;
    inset: 3px;
    background: var(--autoasistidos-surface);
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
}
.visor-unidad-ring-pct {
    font-size: 8.5px;
    font-weight: 700;
    color: var(--autoasistidos-primary-dk);
    font-variant-numeric: tabular-nums;
}
/* 100% visto → anillo pasa a verde (color asignado desde JS via
   --visor-ring-color, misma var que usa el conic-gradient inline). */
.visor-unidad-ring--completo .visor-unidad-ring-pct { color: var(--autoasistidos-success); }
/* 100% completa (mockup): círculo relleno sólido, no anillo con centro
   blanco — el fondo conic-gradient ya llega sólido en verde desde JS (100%
   del mismo color), así que solo hace falta que el centro deje de taparlo
   con blanco y el tilde pase a blanco para leerse sobre el verde. */
.visor-unidad-ring--completo .visor-unidad-ring-inner {
    background: transparent;
}
.visor-unidad-ring--completo .visor-unidad-ring-inner::after {
    content: "\2713";
    color: #fff;
    font-size: 14px;
    font-weight: 700;
    line-height: 1;
}

.visor-unidad-info { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
/* Badge "X de Y completados": línea propia bajo el título (mockup), ya no
   comprimido a "N/N" a la derecha del header — mismo azul que el eyebrow. */
.visor-unidad-count {
    font-size: 11px;
    font-weight: 300;
    color: var(--autoasistidos-primary-dk);
    font-variant-numeric: tabular-nums;
}
.visor-unidad-eyebrow {
    font-size: 9.5px;
    font-weight: 700;
    color: var(--autoasistidos-primary-dk);
    text-transform: uppercase;
    letter-spacing: .07em;
}
.visor-unidad-eyebrow::before { content: "Unidad " counter(visor-unidad, decimal-leading-zero); }
.visor-unidad-titulo {
    font-size: 13.5px;
    font-weight: 500;
    line-height: 1.3;
    color: var(--autoasistidos-text);
    /* Clamp a 2 líneas con min-height reservado a 2 líneas siempre — un
       título corto de 1 línea no deja la fila "más baja" que una de 2, y
       -webkit-box-pack:center centra ese texto corto dentro de la caja
       reservada en vez de pegarlo arriba. El header es sticky, así que la
       altura tiene que quedar acotada o tapa contenido de unidades
       siguientes al scrollear (ver .visor-unidad-desc-block). */
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    -webkit-box-pack: center;
    overflow: hidden;
    min-height: 2.6em;
}
/* Título en azul cuando la unidad está abierta/seleccionada (mockup) — mismo
   tono que eyebrow/count, que ya son azules siempre; el título es el único
   que hasta ahora se quedaba en gris/negro sin reflejar la selección. */
.visor-unidad-grupo--abierta .visor-unidad-titulo { color: var(--autoasistidos-primary-dk); }
/* Chevron compartido entre header de unidad y de módulo: color/transición
   viven acá una sola vez; cada nivel solo agrega su propio modificador
   (tamaño) y su propio disparador de rotación (ver .visor-unidad-chevron /
   .visor-modulo-chevron más abajo), porque cada uno rota según el estado
   abierto/cerrado de un ancestro distinto. */
.visor-chevron {
    flex-shrink: 0;
    align-self: center; /* headers usan align-items:flex-start, el chevron se recentra */
    color: var(--autoasistidos-text-muted);
    transition: transform .2s;
}
.visor-unidad-grupo--abierta .visor-unidad-chevron { transform: rotate(180deg); color: var(--autoasistidos-primary-dk); }

/* Cuerpo de la unidad (sueltos + módulos): colapsado por default, se muestra
   solo cuando la unidad está en el set de abiertas (JS agrega el modificador
   al contenedor, sin re-renderizar el HTML). */
.visor-unidad-body {
    display: none;
    /* Numeración de módulos, reiniciada por unidad (mismo mecanismo que
       #visor-sidebar-list/visor-unidad más arriba) — cada unidad arma su
       propio "MÓDULO 01 / 02…" en vez de continuar una cuenta global. */
    counter-reset: visor-modulo;
}
.visor-unidad-grupo--abierta .visor-unidad-body { display: block; }

/* Descripción de la unidad: primer bloque del body (no del header sticky,
   que debe quedar compacto). Mismo tinte gris que usa el header de módulo en
   reposo (--autoasistidos-bg) — se lee como continuación del header, no
   como una fila más de contenido. Borde en 3 lados (sin top, para que se
   lea "colgando" del header de arriba, como una solapa) — se probó solo
   con border-left tipo blockquote y quedaba desparejo con el corner-radius
   asimétrico; margen simétrico izq/der para que el recuadro no se vea
   descentrado. Nada de azul: ese color queda 100% reservado para
   .visor-item--activo. */
.visor-unidad-desc-block {
    padding: 8px 16px 10px 16px;
    margin: 0 16px 10px 16px;
    background: var(--autoasistidos-bg);
    border: 2px solid var(--autoasistidos-border);
    border-top: none;
    border-radius: 0 0 var(--autoasistidos-radius-sm) var(--autoasistidos-radius-sm);
    font-size: 12px;
    font-style: italic;
    line-height: 1.5;
    text-align: justify;
    color: var(--autoasistidos-text-muted);
    cursor: default;
}

/* Módulo: ancho completo, sin indent — antes era una caja angosta con
   margin-left, achicaba el touch target y desalineaba el título respecto al
   resto del sidebar. Es el único nivel con contenedor propio (borde arriba
   y abajo, visible incluso cerrado): así no se confunde con una fila suelta
   de contenido, se lee como grupo antes de tocarlo. Gris, nunca azul — la
   jerarquía es el chip+eyebrow "MÓDULO", no un tinte que compita con la
   selección. Acordeón anidado (mismo mecanismo que .visor-unidad-header/
   -body, un nivel más adentro). */
/* Card bordeada por módulo (mockup), anidada dentro del body de la unidad —
   violeta en vez de azul (reservado a unidad) para distinguir el nivel de un
   vistazo. Reemplaza el divisor de línea completa que usaba antes. */
.visor-modulo-grupo {
    margin: 10px 12px;
    border: 1.5px solid var(--autoasistidos-border);
    border-radius: var(--autoasistidos-radius-sm);
    overflow: hidden;
    transition: border-color var(--autoasistidos-transition);
}
.visor-modulo-grupo--abierta { border-color: var(--autoasistidos-modulo); }
.visor-modulo-header {
    counter-increment: visor-modulo;
    display: flex;
    align-items: flex-start; /* mismo criterio que .visor-unidad-header: la info crece, chip/contador se recentran vía align-self */
    gap: 10px;
    padding: 10px 14px;
    background: var(--autoasistidos-surface);
    cursor: pointer;
    transition: background var(--autoasistidos-transition);
}
.visor-modulo-header:hover { background: var(--autoasistidos-gray-modulo-hover); }
.visor-modulo-grupo--abierta .visor-modulo-header { background: var(--autoasistidos-modulo-lt); }

/* Cuerpo del módulo (sus contenidos): igual que .visor-unidad-body, colapsado
   por default — no se ve nada hasta que se despliega desde el header. */
.visor-modulo-body { display: none; background: var(--autoasistidos-surface); }
.visor-modulo-grupo--abierta .visor-modulo-body { display: block; }
/* Chip cuadrado (no ícono suelto): marca visual propia del nivel 2, la
   misma en todo el árbol, para que "módulo" se reconozca de un vistazo aun
   antes de leer el eyebrow. */
/* Folder violeta (mockup) — antes era un chip cuadrado con borde gris; el
   violeta ya viene del token --autoasistidos-modulo, se ve siempre así (no
   solo al abrir), es la marca visual del nivel 2 en toda la jerarquía. */
.visor-modulo-icon {
    flex-shrink: 0;
    width: 20px;
    height: 20px;
    display: flex;
    align-items: center;
    justify-content: center;
    align-self: center; /* el header usa align-items:flex-start para que el título
        crezca a 2 líneas sin estirar el chip — sin esto queda pegado arriba
        cuando el título real ocupa 1 sola línea */
    color: var(--autoasistidos-modulo);
    font-size: 16px;
}
.visor-modulo-icon i {
    line-height: 1; /* sin esto hereda line-height:1.5 del body — el glyph
        queda descentrado dentro de la caja flex por el leading extra */
}
.visor-modulo-info { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.visor-modulo-eyebrow {
    font-size: 9px;
    font-weight: 700;
    letter-spacing: .07em;
    text-transform: uppercase;
    color: var(--autoasistidos-modulo-dk);
}
.visor-modulo-eyebrow::before { content: "Módulo " counter(visor-modulo, decimal-leading-zero); }
.visor-modulo-titulo {
    font-size: 12.5px;
    font-weight: 500;
    line-height: 1.3;
    color: var(--autoasistidos-text);
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    -webkit-box-pack: center;
    overflow: hidden;
    min-height: 2.6em;
}
/* Título violeta cuando el módulo está abierto/seleccionado — mismo criterio
   que unidad, mismo tono que eyebrow (--autoasistidos-modulo-dk). */
.visor-modulo-grupo--abierta .visor-modulo-titulo { color: var(--autoasistidos-modulo-dk); }
/* Descripción del módulo: mismo criterio que la de unidad — vive en el body,
   oculta hasta expandir (antes se mostraba siempre en el header, inconsistente
   con cómo se comporta la de unidad). Completa, sin truncar. Margen izq 34px
   (alinea con el indent del chip en .visor-modulo-header, eso sí queda bien)
   pero derecho también 34px — antes era 16px y el recuadro quedaba
   desparejo/descentrado al tener fondo visible (con solo texto sin fondo
   pasaba desapercibido, con caja se nota). Borde en 3 lados (sin top),
   mismo criterio que .visor-unidad-desc-block. */
.visor-modulo-desc {
    padding: 8px 12px 8px 12px;
    margin: 0 34px 8px 34px;
    background: var(--autoasistidos-bg);
    border: 2px solid var(--autoasistidos-border);
    border-top: none;
    border-radius: 0 0 var(--autoasistidos-radius-sm) var(--autoasistidos-radius-sm);
    font-size: 11px;
    font-style: italic;
    line-height: 1.4;
    text-align: justify;
    color: var(--autoasistidos-text-muted);
}
/* El propio border-bottom del recuadro de descripción (unidad o módulo) no
   se lee como renglón: queda pegado a un borde redondeado, angosto y
   separado del primer item por el margin-bottom del recuadro. .visor-item
   solo tiene border-bottom (para separarse del siguiente), nunca border-top
   — por eso el primer item tras una descripción quedaba sin línea arriba.
   Mismo color/grosor tenue que .visor-item usa entre sí (no el borde oscuro
   de módulo) para no romper la consistencia visual de la fila.
   .visor-modulo-grupo no necesita esta regla: ya trae su propio border-top. */
.visor-unidad-desc-block + .visor-item,
.visor-modulo-desc + .visor-item {
    border-top: 1px solid #f0f3f7;
}
/* Descripción de unidad/módulo en el nav de contenidos: solo mobile (ver
   media query max-width:600px más abajo), en desktop se saca a pedido. */
@media (min-width: 601px) {
    .visor-unidad-desc-block,
    .visor-modulo-desc {
        display: none;
    }
}
/* Ídem .visor-unidad-count, dentro de .visor-modulo-info (línea propia bajo el título). */
.visor-modulo-count {
    font-size: 10.5px;
    font-weight: 300;
    color: var(--autoasistidos-modulo-dk);
    font-variant-numeric: tabular-nums;
}
.visor-modulo-chevron { font-size: 11px; align-self: center; }
.visor-modulo-grupo--abierta .visor-modulo-chevron { transform: rotate(180deg); color: var(--autoasistidos-modulo-dk); }

.visor-item {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 16px 8px 34px;
    cursor: pointer;
    border-bottom: 1px solid #f0f3f7;
    border-left: 3px solid transparent; /* reservado siempre: --activo solo cambia el color, sin mover layout */
    transition: background var(--autoasistidos-transition);
    position: relative;
    z-index: 0; /* ancla stacking context propio: sin esto, el z-index:-1 de
        la línea conectora (ver .visor-item-icon) se escapa al contexto del
        ancestro más cercano que sí lo crea y queda tapada por el fondo
        blanco del sidebar entero en vez de solo el del propio item */
}
.visor-item--en-modulo { padding-left: 34px; }
/* Gris neutro, misma familia que unidad/módulo — hover en azul filtraba el
   color reservado a "activo" hacia un estado que ni siquiera es selección. */
.visor-item:hover { background: var(--autoasistidos-gray-item-hover); }
.visor-item--activo {
    background: rgba(var(--autoasistidos-primary-rgb), .09);
    border-left-color: var(--autoasistidos-primary);
}
.visor-item--visto .visor-item-titulo { color: var(--autoasistidos-text-muted); }
.visor-item--activo .visor-item-titulo { color: var(--autoasistidos-primary-dk); font-weight: 700; }
.visor-item-icon {
    flex-shrink: 0;
    width: 20px;
    height: 20px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 13px;
    color: #9fb3c8; /* pendiente, sin ver */
    position: relative; /* ancla el badge de "visto" (visor-item-badge-check) */
    background: var(--autoasistidos-surface); /* tapa el riel conector detrás:
        el glifo del ícono es solo trazo (outline), no cubre el círculo
        completo — sin este fondo opaco la línea se veía "atravesando" el
        ícono por los huecos del glifo en vez de quedar oculta detrás. */
    border-radius: 50%;
}
.visor-item--visto .visor-item-icon { color: var(--autoasistidos-success); }
/* Insignia de "visto": único lugar del árbol con el check verde — nunca se
   confunde con el círculo azul sólido de "activo" (ver abajo). */
.visor-item-badge-check {
    display: none;
    position: absolute;
    right: -4px;
    bottom: -4px;
    width: 11px;
    height: 11px;
    border-radius: 50%;
    background: var(--autoasistidos-success);
    border: 1.5px solid var(--autoasistidos-surface);
    color: #fff;
    font-size: 8px;
    line-height: 1;
    align-items: center;
    justify-content: center;
}
.visor-item--visto .visor-item-badge-check { display: flex; }
/* Línea conectora tipo timeline entre los íconos de estado de un mismo grupo
   (sueltos de la unidad, o contenidos de un módulo) — mockup. Dos mitades
   (arriba/abajo del centro del ícono) en vez de una sola línea de 100%: así
   el primer ítem del grupo no arrastra línea "colgando" hacia arriba (nada
   con qué conectar) y el último no la arrastra hacia abajo. z-index:-1 para
   que quede detrás del glifo del ícono (::before es positioned, pintaría
   encima del <i> normal-flow si no se empuja atrás explícitamente). Offset
   horizontal 47px = border-left reservado (3px) + 34px padding-left del
   item + mitad del ícono de 20px. Antes estaba en 44px (sin contar el
   border-left) y quedaba 3px corrido del centro real del círculo. */
.visor-item:not(.visor-item--primero-del-grupo)::before,
.visor-item:not(.visor-item--ultimo-del-grupo)::after {
    content: "";
    position: absolute;
    left: 47px;
    width: 2px;
    background: var(--autoasistidos-border);
    z-index: -1;
    transition: background var(--autoasistidos-transition);
}
.visor-item:not(.visor-item--primero-del-grupo)::before { top: 0; height: 50%; }
.visor-item:not(.visor-item--ultimo-del-grupo)::after   { top: 50%; height: 50%; }
/* Tramo recorrido en azul: NO es indicador de contenido "visto" (eso ya lo
   dice el check verde del ícono/badge) — es posición de navegación, dónde
   está parado el usuario dentro del grupo. Un ítem con data-idx menor al
   activo (--recorrido, seteada en JS por seleccionarPorIdx) pinta sus dos
   mitades; el activo mismo solo pinta la mitad de arriba (::before, tramo de
   "llegada") — la de abajo queda gris porque todavía no se avanzó más allá.
   Selector con .visor-item repetido a propósito: la regla base gris usa
   :not(...) que cuenta como selector de clase extra, así que con un solo
   ".visor-item--recorrido" esta regla pierde la guerra de especificidad y el
   gris gana pese a estar declarada antes en el archivo. */
.visor-item.visor-item--recorrido::before,
.visor-item.visor-item--recorrido::after,
.visor-item.visor-item--activo::before {
    background: var(--autoasistidos-primary);
}
/* Activo — el único estado en todo el árbol con riel + círculo relleno. El
   glifo NO cambia (sigue siendo el del tipo: video/pdf/audio/...) — solo
   cambian color y fondo, para no perder la info de qué tipo es justo en el
   que se está viendo ahora. */
/* Mismo diámetro que el resto (20px): agrandarlo corría el centro del
   círculo ~4px respecto al offset fijo del riel (left:44px, calculado para
   un ícono de 20px), y esa desalineación se veía como un corte/separación
   entre la línea y el círculo activo en vez de una unión limpia. */
.visor-item--activo .visor-item-icon {
    color: #fff;
    background: var(--autoasistidos-primary);
    border-radius: 50%;
}
/* La insignia de "activo" manda; el check de "visto" cede el lugar mientras
   el ítem está seleccionado (ambos estados conviven en el dato igual). */
.visor-item--activo.visor-item--visto .visor-item-badge-check { display: none; }
.visor-item-titulo {
    flex: 1;
    min-width: 0;
    font-size: 12.5px;
    line-height: 1.35;
    color: var(--autoasistidos-text);
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    -webkit-box-pack: center; /* fallback legado: Chrome moderno resuelve este
        display como flow-root para el clamping y lo ignora — el centrado real
        lo hace align-content de abajo */
    align-content: center; /* centra texto de 1 línea en la caja de 2 reservada */
    overflow: hidden;
    min-height: 2.7em;
}
/* Insignia "Ahora": único indicador de foco de teclado/lectura además del
   riel+círculo — nodo siempre presente en el DOM (mismo patrón que el badge
   ::after de "visto"), oculto por CSS salvo en el ítem --activo. */
.visor-item-now {
    display: none;
    flex-shrink: 0;
    font-size: 8.5px;
    font-weight: 400;
    letter-spacing: .05em;
    text-transform: uppercase;
    color: #fff;
    background: var(--autoasistidos-primary);
    padding: 2px 6px;
    border-radius: 5px;
}
.visor-item--activo .visor-item-now { display: inline-block; }
/* Autoevaluación = acción culminante del curso, no un ítem más de la lista:
   color exclusivo --autoasistidos-eval-cta (naranja) para diferenciarla del
   resto de acciones azules del portal. El sticky al fondo del panel (ver
   regla comentada más abajo) quedó desactivado a pedido — queda en su lugar
   natural al final de la lista. */
.visor-item--eval {
    padding: 15px 16px;
    gap: 12px;
    background: var(--autoasistidos-eval-cta);
    border-top: none;
    /* El border-left de 3px reservado en .visor-item base (línea 431) es
       para el acento de "activo" del riel de lista — este botón nunca lo usa
       (fondo entero ya es el estado, sin acento lateral), así que sobra acá
       en cualquier tamaño de pantalla; en mobile además rompía el radius de
       999px contra el box-shadow. */
    border-left: none;
}
/* El riel conector (::before/::after, línea ~495) no aplica acá: no es un
   ítem más de la secuencia sino el CTA final fuera del riel — se ve en
   desktop como una línea cortando el borde redondeado del botón. */
.visor-item--eval:not(.visor-item--primero-del-grupo)::before,
.visor-item--eval:not(.visor-item--ultimo-del-grupo)::after {
    display: none;
}
/* Sticky desactivado a pedido: dejaba el CTA flotando encima del contenido
   al scrollear. Comentado (no borrado) por si se quiere reactivar.
.visor-item--eval:not(.visor-item--bloqueado) {
    position: sticky;
    bottom: 0;
    z-index: 2;
}
*/
.visor-item--eval:hover { background: var(--autoasistidos-eval-cta-dk); }
.visor-item--eval .visor-item-icon {
    width: 28px;
    height: 28px;
    margin-top: 0;
    border-radius: 50%;
    background: rgba(255,255,255,.2);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 14px;
    color: #fff;
}
.visor-item--eval .visor-item-titulo { align-self: center; color: #fff; font-weight: 700; min-height: 0; -webkit-line-clamp: 3; }
.visor-item--eval.visor-item--activo {
    background: var(--autoasistidos-eval-cta-dk);
}
/* Bloqueado: gradiente pasa a gris neutro — el color ya comunica el estado,
   por eso pisa la opacity/hover genéricos de .visor-item--bloqueado (si no,
   el gradiente atenuado se ve azulado y confunde con el estado habilitado). */
.visor-item--eval.visor-item--bloqueado {
    background: linear-gradient(135deg, #90a4b8 0%, #b0c0d0 100%);
    opacity: 1;
}
.visor-item--eval.visor-item--bloqueado:hover { background: linear-gradient(135deg, #90a4b8 0%, #b0c0d0 100%); }
.visor-item--bloqueado {
    opacity: .55;
    cursor: not-allowed;
}
.visor-item--bloqueado:hover { background: transparent; }

/* Sidebar desktop — jerarquía por escala de grises + breadcrumb: un signo
   exclusivo por nivel (anillo/chip+eyebrow/riel-círculo, ver comentarios en
   cada regla base más arriba) en vez del riel de color + tinte compartido
   de antes (ver historial git). Las reglas de fondo/tipografía de unidad,
   módulo e ítem ya viven en las reglas base (mismo ancho 333px que en
   desktop) — acá solo lo que es 100% específico de este layout: el
   breadcrumb del panel principal se comprime a una sola línea con
   separador. Mobile conserva el mismo lenguaje visual, ajustado de tamaño
   (ver media query 680px). */
@media (min-width: 681px) {
    /* Cards bordeadas Unidad/Módulo (mockup definitivo): cada nivel de la
       jerarquía es una card propia, apiladas con separación, en vez del
       breadcrumb de una línea que había antes. Solo aparecen si esa
       unidad/módulo tiene descripción cargada (ver JS, seleccionarPorIdx). */
    .visor-content-breadcrumb.visor-content-breadcrumb { gap: 10px; }
    .visor-content-breadcrumb .visor-content-jerarquia-nivel {
        flex-direction: row;
        flex-wrap: wrap;
        align-items: baseline;
        column-gap: 8px;
        padding: 12px 16px;
        border: 1px solid var(--autoasistidos-primary);
        border-radius: var(--autoasistidos-radius-sm);
        background: var(--autoasistidos-primary-lt);
    }
    .visor-content-breadcrumb .visor-content-jerarquia-etiqueta,
    .visor-content-breadcrumb .visor-content-jerarquia-titulo {
        color: var(--autoasistidos-primary-dk);
    }
    .visor-content-breadcrumb .visor-content-jerarquia-etiqueta { font-size: 11px; }
    .visor-content-breadcrumb .visor-content-jerarquia-sep { display: inline; color: var(--autoasistidos-text-muted); }
    .visor-content-breadcrumb .visor-content-jerarquia-titulo { font-size: 13px; }
    .visor-content-breadcrumb .visor-content-jerarquia-desc { flex-basis: 100%; }
    /* Módulo: misma forma de card que unidad, en violeta (mockup definitivo
       — coincide con el acento violeta que ya usa "módulo" en el sidebar,
       ver --autoasistidos-modulo en theme.css). */
    .visor-content-breadcrumb .visor-content-jerarquia-nivel--modulo {
        border: 1px solid var(--autoasistidos-modulo);
        background: var(--autoasistidos-modulo-lt);
        padding-left: 16px;
    }
    .visor-content-breadcrumb .visor-content-jerarquia-nivel--modulo .visor-content-jerarquia-etiqueta,
    .visor-content-breadcrumb .visor-content-jerarquia-nivel--modulo .visor-content-jerarquia-titulo { color: var(--autoasistidos-modulo-dk); }

    /* Pedido: el card completo del visor (header + sidebar/contenido) ocupa
       el 100vh disponible, independiente de qué tan alto sea el hero/texto
       de arriba — 100vh mide contra el viewport, no contra el espacio
       restante de scroll. Header queda con su alto natural y .visor-layout
       (antes limitado a min(70vh,680px)) se estira al resto vía flex:1. */
    #curso-visor-area .curso-detalle-section {
        display: flex;
        flex-direction: column;
        height: 100vh;
    }
    .visor-layout {
        flex: 1;
        height: auto;
        min-height: 0;
    }
}

/* Área principal */
.visor-main {
    flex: 1;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    /* Sin esto un hijo flex no puede achicarse debajo de su contenido
       intrínseco — overflow:auto/hidden de los descendientes queda sin
       efecto real aunque el padre ya tenga alto fijo (ver fix de alto). */
    min-height: 0;
}

/* Breadcrumb "Unidad › Módulo" + título del contenido activo, arriba del
   renderer — muestra exactamente qué se está viendo (solo con selección). */
.visor-content-header {
    padding: 16px 22px;
    border-bottom: 1px solid var(--autoasistidos-border);
}
.visor-content-breadcrumb {
    display: flex;
    flex-direction: column;
    gap: 8px;
}
/* Un "nivel" = unidad o módulo, con su etiqueta + título + descripción
   completa (sin truncar). Convive con la descripción que ya se muestra en
   el sidebar (.visor-unidad-desc-block / .visor-modulo-desc) — es una
   prueba de ubicación en paralelo, no un reemplazo. */
.visor-content-jerarquia-nivel {
    display: flex;
    flex-direction: column;
    gap: 2px;
}
.visor-content-jerarquia-etiqueta {
    font-size: 10.5px;
    font-weight: 700;
    color: var(--autoasistidos-text-muted);
    text-transform: uppercase;
    letter-spacing: .04em;
}
.visor-content-jerarquia-titulo {
    font-size: 13px;
    font-weight: 700;
    color: var(--autoasistidos-text);
}
/* Truncado a 2 renglones fijos (sin -webkit-line-clamp, sin
   position:absolute/overlay): renglón 1 al 100% de ancho, renglón 2 a un
   ancho fijo del 75% con "…" seguido del botón "Ver más" como hermano flex
   del mismo renglón. El corte de palabra entre renglón 1 y 2 lo calcula JS
   con canvas (ver ajustarDescripcionesJerarquia en curso.js) — CSS solo no
   puede repartir texto en 2 líneas independientes con continuación. */
.visor-content-jerarquia-desc {
    margin: 0;
    min-width: 0;
    font-size: 12.5px;
    line-height: 1.5;
    color: var(--autoasistidos-text-muted);
}
.visor-content-jerarquia-desc-l1 {
    display: block;
    width: 100%;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}
.visor-content-jerarquia-desc-l2 {
    display: flex;
    align-items: baseline;
    width: 100%;
}
.visor-content-jerarquia-desc-l2-text {
    flex: none;
    width: 75%;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}
.visor-content-jerarquia-desc-full {
    display: none;
    overflow-wrap: break-word;
}
.visor-content-jerarquia-desc--expandida .visor-content-jerarquia-desc-full { display: block; }
.visor-content-jerarquia-ver-mas {
    flex: none;
    display: inline-flex;
    align-items: center;
    gap: 2px;
    margin-left: 4px;
    border: none;
    background: none;
    padding: 0;
    font-size: 11.5px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .02em;
    color: var(--autoasistidos-primary-dk);
    cursor: pointer;
    white-space: nowrap;
}
/* Expandida: se oculta el renglón 1 y el texto truncado de línea 2, se
   muestra el texto completo y el botón ("Ver menos") queda solo en su
   propio renglón, debajo. */
.visor-content-jerarquia-desc--expandida .visor-content-jerarquia-desc-l1 { display: none; }
.visor-content-jerarquia-desc--expandida .visor-content-jerarquia-desc-l2-text { display: none; }
.visor-content-jerarquia-desc--expandida .visor-content-jerarquia-desc-l2 { width: auto; margin-top: 4px; }
.visor-content-jerarquia-ver-mas .material-symbols-rounded { font-size: 13px; }
.visor-content-jerarquia-nivel--modulo .visor-content-jerarquia-ver-mas {
    color: var(--autoasistidos-modulo-dk);
}
.visor-content-jerarquia-sep { display: none; font-weight: 400; }
.visor-content-titulo {
    font-size: 17px;
    font-weight: 700;
    color: var(--autoasistidos-text);
    margin-top: 10px;
}
.visor-content-subtitulo {
    font-size: 13px;
    color: var(--autoasistidos-text-muted);
    margin-top: 2px;
}

/* Tira colapsable: una pill con color e ícono+texto, centrada. Antes flotaba
   a mitad de camino afuera de su fila (translateY -50%) para "montarse"
   sobre la línea divisoria — con el header colapsado esa fila queda pegada
   al borde superior de la card y la mitad de la pill se recortaba contra el
   overflow:hidden de .curso-detalle-section. Ahora vive adentro del flujo
   normal, sin salirse de su fila, con aire propio arriba/abajo. Se muestra
   siempre que hay contenido seleccionado (junto con visor-content-header),
   independiente de si está colapsado o no — es la única forma de volver a
   expandirlo. */
.visor-content-header-toggle-row {
    display: flex;
    justify-content: center;
    flex-shrink: 0;
    padding: 6px 0;
    background: var(--autoasistidos-bg);
    border-bottom: 1px solid var(--autoasistidos-border);
}
.visor-content-header-toggle {
    display: flex;
    align-items: center;
    gap: 4px;
    padding: 5px 14px;
    border: 1px solid var(--autoasistidos-primary);
    border-radius: 999px;
    background: var(--autoasistidos-primary);
    color: #fff;
    font-size: 12px;
    font-weight: 600;
    box-shadow: 0 2px 8px rgba(0, 0, 0, .14);
    cursor: pointer;
    white-space: nowrap;
    transition: background var(--autoasistidos-transition), transform var(--autoasistidos-transition), box-shadow var(--autoasistidos-transition);
}
.visor-content-header-toggle:hover {
    background: var(--autoasistidos-primary-dk);
    border-color: var(--autoasistidos-primary-dk);
    transform: scale(1.05);
    box-shadow: 0 4px 12px rgba(0, 0, 0, .2);
}
.visor-content-header-toggle .material-symbols-rounded { font-size: 16px; }

/* Flecha "atrás" + eyebrow de una línea: solo se ven en mobile (ver media
   query 680px), ahí reemplazan al breadcrumb apilado de arriba. En desktop
   quedan ocultos y .visor-content-header-text es un simple wrapper block
   transparente al layout existente. */
.visor-content-back-btn {
    display: none;
    flex-shrink: 0;
    border: none;
    background: transparent;
    color: var(--autoasistidos-text-muted);
    font-size: 1.1rem;
    padding: 4px;
    cursor: pointer;
}
.visor-content-header-text { min-width: 0; }
.visor-content-eyebrow-m {
    display: none;
    font-size: 10.5px;
    font-weight: 700;
    color: var(--autoasistidos-text-muted);
    letter-spacing: .04em;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.visor-placeholder {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    flex: 1;
    min-height: 0;
    padding: 40px;
    color: var(--autoasistidos-text-muted);
    font-size: .9rem;
}
.visor-placeholder-icon {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 76px;
    height: 76px;
    border-radius: 50%;
    background: radial-gradient(circle at 35% 30%, rgba(var(--autoasistidos-primary-rgb), .13), rgba(var(--autoasistidos-primary-rgb), .05));
    margin-bottom: 16px;
}
.visor-placeholder-icon i { font-size: 2rem; color: var(--autoasistidos-primary); margin: 0; }
.visor-placeholder-sheet-btn { display: none; }
.visor-eval-sheet-btn { display: none; }

/* Botón "cerrar pantalla completa" (solo mobile, ver media query 680px) —
   único punto de salida del frame position:fixed. Oculto por defecto: solo
   se muestra cuando #curso-visor-area tiene .visor-mobile-fullscreen. */
.visor-mobile-close-btn { display: none; }

.visor-renderer { flex: 1; overflow: auto; min-height: 0; }

.visor-nav {
    display: flex;
    align-items: center;
    padding: 12px 22px;
    border-top: 1px solid var(--autoasistidos-border);
    background: #f6f9fc;
    gap: 8px;
}
/* Fila con prev/stepper/next (+ toggle del sheet en mobile) — separada del
   progreso duplicado de abajo para poder apilarlos en dos líneas en mobile
   sin tocar el layout de una sola fila que ya tenía desktop. */
.visor-nav-row { display: flex; align-items: center; gap: 8px; flex: 1; min-width: 0; }
/* Progreso duplicado (ver .visor-nav-progreso en curso.php): oculto en
   desktop, ya está arriba en .visor-header-progreso. */
.visor-nav-progreso { display: none; align-items: center; gap: 10px; }
.visor-nav-progreso-label { font-size: 11px; color: var(--autoasistidos-text-muted); flex-shrink: 0; }
/* Columna central prev/[label+stepper]/next (mockup: "Contenido 2 de 6"
   arriba del stepper segmentado, sin barra continua aparte — el stepper ya
   hace de indicador de progreso). Oculta en mobile: ese ancho lo ocupa el
   botón "Contenidos del curso". */
.visor-stepper-col { display: none; }
@media (min-width: 681px) {
    .visor-stepper-col { display: flex; flex-direction: column; align-items: center; gap: 4px; flex: 1; min-width: 0; }
    .visor-content-progreso-label { font-size: 11.5px; font-weight: 600; color: var(--autoasistidos-text-muted); }
}
/* Botón "Contenidos del curso": solo mobile, reemplaza al stepper de puntos
   (ver media query 680px) dándole acceso directo al sheet completo. */
.visor-sheet-toggle-btn {
    display: none;
    align-items: center;
    justify-content: center;
    gap: 6px;
    flex: 1;
    height: 36px;
    border: 1px solid rgba(var(--autoasistidos-primary-rgb), .22);
    background: var(--autoasistidos-primary-lt);
    border-radius: 8px;
    padding: 0 10px;
    font-size: 12px;
    font-weight: 700;
    color: var(--autoasistidos-primary-dk);
    font-family: inherit;
    cursor: pointer;
    transition: background var(--autoasistidos-transition), border-color var(--autoasistidos-transition);
}
.visor-sheet-toggle-btn:active { background: rgba(var(--autoasistidos-primary-rgb), .18); }
/* Mockup (versionFinalVistaCursos.pdf): "Anterior" es un outline azul en
   reposo, no gris — el gris solo se usa cuando el botón está disabled. */
.visor-nav-btn {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    border: 1px solid var(--autoasistidos-primary);
    background: var(--autoasistidos-surface);
    color: var(--autoasistidos-primary);
    border-radius: 999px;
    padding: 6px 16px;
    font-size: 12px;
    font-weight: 600;
    font-family: inherit;
    line-height: 1.4;
    cursor: pointer;
    transition: background var(--autoasistidos-transition), border-color var(--autoasistidos-transition), color var(--autoasistidos-transition);
}
/* Excluye --primary: ese botón ya es fondo azul/ícono blanco, y en touch
   el :hover queda "pegado" tras el tap (WebKit/Chrome mobile no lo limpia
   sin mouse real) — sin la exclusión, esta regla gana por especificidad a
   .visor-nav-btn--primary y deja el ícono azul sobre fondo azul, invisible.
   El reposo ya es outline azul (ver .visor-nav-btn) — el hover ahora suma
   un tinte de fondo, no cambia border/color (ya están en azul). */
.visor-nav-btn:not(.visor-nav-btn--primary):hover:not(:disabled) {
    background: var(--autoasistidos-primary-lt);
}
/* Disabled pisa el azul de reposo con gris — no tiene sentido un outline
   azul en un botón que no se puede usar (p.ej. "Anterior" en el primer
   contenido). */
.visor-nav-btn:disabled {
    opacity: .6;
    cursor: not-allowed;
    border-color: var(--autoasistidos-border);
    color: var(--autoasistidos-text-muted);
}
/* Pill sólida azul (mockup) — antes solo se aplicaba en mobile (ver media
   680px más abajo), ahora también en desktop. */
.visor-nav-btn--primary {
    background: var(--autoasistidos-primary);
    color: #fff;
    border-color: var(--autoasistidos-primary);
}
.visor-nav-btn--primary:hover:not(:disabled) {
    background: var(--autoasistidos-primary-dk);
    border-color: var(--autoasistidos-primary-dk);
}

/* Stepper tipo carrusel: un segmento por contenido de _flatList, entre los
   botones Anterior/Siguiente. Clickeable (llama a seleccionarPorIdx, misma
   API que usan los ítems del sidebar) — no es solo indicador, es navegación. */
.visor-stepper {
    flex: 1;
    display: flex;
    align-items: center;
    /* Centrar el grupo, no estirarlo: con pocos segmentos, space-between los
       separaba a todo el ancho del contenedor dejando huecos enormes sin
       sentido visual. Con muchos, el grupo centrado se ve como un bloque
       compacto en vez de una fila desperdigada.
       "safe center" (con fallback a center simple para navegadores viejos)
       evita el bug clásico de flex: centrar + overflow-x corta el primer
       segmento fuera de vista al cargar — "safe" degrada a alineación desde
       el inicio si el contenido no entra, así el scroll siempre arranca
       mostrando el primer segmento. */
    justify-content: center;
    justify-content: safe center;
    gap: 6px;
    overflow-x: auto;
    scrollbar-width: none;
    padding: 2px;
}
.visor-stepper::-webkit-scrollbar { display: none; }
.visor-step {
    flex-shrink: 0;
    width: 18px;
    height: 5px;
    border-radius: 3px;
    border: none;
    padding: 0;
    background: var(--autoasistidos-border);
    cursor: pointer;
    transition: background .15s ease, width .15s ease;
}
.visor-step:hover { background: var(--autoasistidos-primary); opacity: .6; }
.visor-step--visto { background: var(--autoasistidos-primary-lt); }
.visor-step--activo,
.visor-step--activo:hover {
    width: 26px;
    background: var(--autoasistidos-primary);
    opacity: 1;
}

/* Tipos de contenido: la caja del renderer ahora tiene alto estable (ver fix
   arriba) — cada tipo llena ese alto exacto o, si su contenido es corto
   (audio/link/video con aire de sobra), se centra verticalmente en vez de
   quedar pegado arriba con el resto del espacio vacío abajo. */

/* Video: se centra en la caja, respetando el 16:9 SIN recortarse.
   Antes: padding-bottom 56.25% calculaba el alto solo en base al ancho,
   ignorando el alto real disponible del renderer — con la caja más alta
   (100vh), un video ancho pedía más alto del que había y quedaba cortado.
   Ahora el aspect-ratio va en el <iframe> (elemento reemplazado): con
   height:auto + max-height:100%, el motor recalcula ancho Y alto juntos
   al toparse con el límite (mismo principio que object-fit:contain en
   .visor-tipo-imagen img, pero via aspect-ratio porque object-fit en
   iframe no es soporte universal). */
.visor-tipo-video {
    padding: 16px;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
}
.visor-video-wrap {
    width: 100%;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
}
.visor-video-wrap iframe {
    aspect-ratio: 16 / 9;
    width: 100%;
    height: auto;
    max-width: 100%;
    max-height: 100%;
    border: none;
    border-radius: var(--autoasistidos-radius);
    background: #000;
}

/* PDF/embed/scorm: llenan EXACTO el alto disponible del renderer (ya no
   fuerzan un min-height propio — eso es lo que rompía la caja estable) */
.visor-tipo-pdf {
    display: flex;
    flex-direction: column;
    height: 100%;
}
.visor-tipo-pdf iframe {
    flex: 1;
    border: none;
    width: 100%;
}
.visor-tipo-pdf-footer {
    padding: 8px 16px;
    border-top: 1px solid var(--autoasistidos-border);
    background: var(--autoasistidos-bg);
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
}

/* Imagen: se centra y escala CONTAIN dentro de la caja, sin recortarse ni
   forzar scroll (antes: max-height fijo en px, no relativo al alto real) */
.visor-tipo-imagen {
    padding: 16px;
    text-align: center;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    min-height: 100%;
}
.visor-tipo-imagen img {
    max-width: 100%;
    max-height: 100%;
    object-fit: contain;
    border-radius: var(--autoasistidos-radius);
    box-shadow: var(--autoasistidos-shadow);
}

.visor-tipo-audio {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 100%;
    padding: 32px;
}
.visor-audio-card {
    text-align: center;
    background: var(--autoasistidos-surface);
    border: 1px solid var(--autoasistidos-border);
    border-radius: var(--autoasistidos-radius);
    padding: 32px;
    max-width: 400px;
    width: 100%;
}
.visor-audio-icon {
    font-size: 2.5rem;
    color: var(--autoasistidos-primary);
    margin-bottom: 12px;
    display: block;
}
.visor-audio-titulo { font-weight: 500; margin-bottom: 16px; }
.visor-audio-player { width: 100%; }

.visor-tipo-texto {
    padding: 24px 28px;
    font-size: .93rem;
    line-height: 1.7;
    color: var(--autoasistidos-text);
}
.visor-tipo-texto h1, .visor-tipo-texto h2, .visor-tipo-texto h3 {
    color: var(--autoasistidos-text);
    margin-top: 1.2em;
}
.visor-tipo-texto ul, .visor-tipo-texto ol { padding-left: 1.4em; }
.visor-tipo-texto a { color: var(--autoasistidos-primary); }
.visor-tipo-texto img { max-width: 100%; height: auto; border-radius: var(--autoasistidos-radius-sm); }
.visor-tipo-texto iframe { width: 100%; aspect-ratio: 16/9; border: none; }

.visor-tipo-link {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 100%;
    padding: 32px;
}
.visor-link-card {
    display: flex;
    align-items: flex-start;
    gap: 20px;
    background: var(--autoasistidos-surface);
    border: 1px solid var(--autoasistidos-border);
    border-radius: var(--autoasistidos-radius);
    padding: 28px;
    max-width: 480px;
    width: 100%;
}
.visor-link-icon {
    font-size: 2rem;
    color: var(--autoasistidos-primary);
    flex-shrink: 0;
}

.visor-tipo-embed { height: 100%; }
.visor-tipo-embed iframe {
    display: block;
    width: 100%;
    height: 100%;
    border: none;
}

/* SCORM: mismo comportamiento que embed — llena el alto exacto del renderer,
   sin min-height propio que compita con la caja estable. */
.visor-tipo-scorm { height: 100%; }
.visor-tipo-scorm iframe {
    width: 100%;
    height: 100%;
    border: none;
    background: #fff;
}

/* Autoevaluación como "contenido" más del visor (ver curso.php): mismo
   padding/scroll que .visor-renderer, del que es hermano — solo uno de los
   dos está visible a la vez. */
.visor-tipo-eval { flex: 1; overflow: auto; min-height: 0; padding: 24px 28px; }

/* Descripción breve debajo del contenido */
.visor-descripcion {
    font-size: .87rem;
    color: var(--autoasistidos-text-muted);
    margin: 10px 0 0;
    line-height: 1.5;
}
.visor-tipo-imagen .visor-descripcion,
.visor-tipo-embed .visor-descripcion {
    padding: 0 4px;
    text-align: center;
}

/* Responsive del visor */
@media (max-width: 680px) {
    /* Tipografía/paddings de desktop dejan casi sin lugar de scroll real
       dentro de los 260px del panel (header de unidad + CTA de evaluación
       se comían la mayor parte del alto fijo). Todo un escalón más chico
       acá para que el área de selección de contenidos quede usable. */
    .visor-progress-track { width: 100px; }

    .visor-unidad-header { padding: 10px 12px; gap: 10px; border-bottom: none; }
    .visor-unidad-ring { width: 26px; height: 26px; }
    .visor-unidad-ring-inner { inset: 3px; }
    .visor-unidad-ring-pct { font-size: 8px; }
    .visor-unidad-eyebrow { font-size: 9px; }
    .visor-unidad-titulo {
        font-size: 12.5px;
        line-height: 1.25;
        -webkit-line-clamp: 2; /* 3 líneas de desktop no entran en el presupuesto mobile */
    }
    .visor-unidad-count { font-size: 10px; }
    /* Mockup mobile: la descripción es continuación del header, no una caja
       aparte — mismo fondo celeste que .visor-unidad-header cuando la unidad
       está abierta (siempre lo está mientras esto es visible, ver
       .visor-unidad-body) y el borde que separa del primer item vive acá
       (border-bottom), no en el header — así header+desc se leen como un
       solo bloque celeste, en vez de un box cerrado seguido de una línea
       suelta. Indent 48px: 16px padding del header + 26px del ring + 10px de
       gap (ver .visor-unidad-header/-ring más abajo en este mismo media
       query), para que el texto arranque debajo del título, no del ícono. */
    .visor-unidad-desc-block {
        margin: 0;
        padding: 0 16px 10px 48px;
        font-size: 11.5px;
        font-style: normal;
        text-align: left;
        background: var(--autoasistidos-primary-lt);
        border: none;
        border-bottom: 1px solid var(--autoasistidos-primary);
        border-radius: 0;
    }

    /* "Ver más / ver menos": el texto arranca clampeado a 2 líneas (mockup
       mobile), el botón lo expande sin recargar nada — VisorCurso.toggleDesc
       solo togglea una clase, el ocultamiento del botón cuando no hace falta
       (texto corto que ya entra en 2 líneas) lo resuelve refreshDescToggles
       midiendo scrollHeight vs clientHeight en JS. */
    .visor-unidad-desc-block .visor-desc-texto,
    .visor-modulo-desc .visor-desc-texto {
        display: -webkit-box;
        -webkit-box-orient: vertical;
        -webkit-line-clamp: 2;
        overflow: hidden;
    }
    .visor-desc-expandida .visor-desc-texto {
        display: block;
        -webkit-line-clamp: unset;
        overflow: visible;
    }
    .visor-desc-toggle {
        display: inline;
        border: none;
        background: none;
        padding: 0;
        margin: 0;
        font: inherit;
        font-style: normal;
        font-size: .92em;
        font-weight: 700;
        text-transform: uppercase;
        letter-spacing: .3px;
        color: var(--autoasistidos-primary);
        cursor: pointer;
    }
    .visor-desc-toggle:hover { color: var(--autoasistidos-primary-dk); }
    .visor-modulo-desc .visor-desc-toggle { color: var(--autoasistidos-modulo); }
    .visor-modulo-desc .visor-desc-toggle:hover { color: var(--autoasistidos-modulo-dk); }

    /* El border-bottom propio de la desc (arriba) ya separa del primer item
       — la línea gris de la regla base (ver más arriba en el archivo) queda
       redundante acá y duplicaría el trazo. */
    .visor-unidad-desc-block + .visor-item,
    .visor-modulo-desc + .visor-item {
        border-top: none;
    }

    /* Módulo pasa a ancho completo (igual que desktop) — ya no hereda el
       indent de 28px de la vieja variante "caja anidada", el chip+eyebrow
       ya marcan que es un nivel intermedio sin necesidad de sangría. */
    .visor-modulo-header { padding: 8px 12px; gap: 8px; }
    .visor-modulo-icon { width: 20px; height: 20px; font-size: 11px; }
    .visor-modulo-eyebrow { font-size: 8.5px; }
    .visor-modulo-titulo { font-size: 11.5px; min-height: 2.4em; }
    /* Mismo criterio que .visor-unidad-desc-block: continuación del header
       de módulo (fondo lavanda), con el borde que separa del primer item acá
       (border-bottom) en vez de en el header — un solo bloque violeta, no
       header-box + línea suelta. Indent 40px para alinear con
       .visor-item--en-modulo (ícono 20px + gap 8px + padding-left 12px del
       header de módulo). */
    .visor-modulo-desc {
        margin: 0;
        padding: 0 12px 8px 40px;
        font-size: 11px;
        font-style: normal;
        text-align: left;
        background: var(--autoasistidos-modulo-lt);
        border: none;
        border-bottom: 1px solid var(--autoasistidos-modulo);
        border-radius: 0;
    }

    .visor-item { padding: 7px 12px 7px 28px; gap: 8px; font-size: .76rem; }
    /* 28px padding-left + mitad del ícono de 16px (ver .visor-item-icon abajo) */
    .visor-item:not(.visor-item--primero-del-grupo)::before,
    .visor-item:not(.visor-item--ultimo-del-grupo)::after { left: 36px; }
    .visor-item--en-modulo { padding-left: 40px; }
    .visor-item-titulo { min-height: 2.2em; }
    .visor-item-icon { width: 16px; height: 16px; font-size: 11px; }
    .visor-item--activo .visor-item-icon { width: 20px; height: 20px; }

    /* Mockup mobile: ya no es una fila de lista más (full-bleed, texto a la
       izquierda) sino un botón-píldora flotante, centrado, con ícono inline
       sin badge circular — separado del resto de la lista. */
    .visor-item--eval {
        margin: 8px 10px 6px;
        padding: 13px 18px;
        gap: 8px;
        justify-content: center;
        border-radius: 999px;
    }
    .visor-item--eval .visor-item-icon {
        width: auto;
        height: auto;
        background: transparent;
        color: #fff;
        font-size: 15px;
    }
    .visor-item--eval .visor-item-titulo {
        flex: none;
        font-size: 1rem;
        -webkit-line-clamp: 1;
        min-height: 0;
    }

    /* Header desktop "Contenidos del curso" con progreso propio queda
       reemplazado en mobile por el header compacto por-contenido + la
       barra de progreso duplicada del nav inferior (mockup no lo repite). */
    .visor-header { display: none; }

    /* ── Stage a pantalla completa (fix mobile, arquitectura del mockup) ──
       El wrapper del visor pasa de vivir en el flujo normal de la página
       (compitiendo con breadcrumb/header del curso/etc, todo scrolleando
       junto) a ocupar el viewport completo vía position:fixed + 100dvh: una
       app dentro de la app. 100dvh (con fallback 100vh) en vez de vh puro
       porque en mobile la barra de direcciones aparece/desaparece y cambia
       el alto visual real del viewport — vh se calcula contra el máximo
       posible y deja contenido tapado detrás de la barra cuando está
       visible; dvh se recalcula en vivo. transform:translateZ(0) fuerza a
       este frame a ser el "containing block" de sus descendientes
       position:fixed (sheet + backdrop), sin importar cuán anidados estén,
       para que se anclen a los bordes DEL FRAME (que ya llena la pantalla)
       y no al viewport real de la página, que sigue debajo con scroll
       propio. Header de unidad/módulo + nav quedan en flujo normal dentro
       de este flex column — nada de position:fixed anclado a la página.

       Gateado por .visor-mobile-fullscreen (JS la agrega en
       seleccionarPorIdx()/irEvaluacion(), la saca cerrarVisorMobile()): solo
       entra en pantalla completa cuando hay un contenido activo, no en la
       carga de la página — así el placeholder/browse inicial queda en
       flujo normal (alto de la regla base .visor-layout, arriba en este
       archivo) y el breadcrumb/título/descripción del curso siguen
       alcanzables por scroll. Sin este gate, el frame se activaba apenas
       cargaba la página (el wrapper se destapa siempre en curso.js) y no
       había forma de volver a ver lo de arriba — bug real en dispositivo. */
    #curso-visor-area.visor-mobile-fullscreen > .curso-detalle-section {
        position: fixed;
        inset: 0;
        z-index: 1040;
        height: 100vh;
        height: 100dvh;
        display: flex;
        flex-direction: column;
        border-radius: 0;
        box-shadow: none;
        background: var(--autoasistidos-surface);
        transform: translateZ(0);
    }
    #curso-visor-area.visor-mobile-fullscreen .visor-layout { flex: 1; min-height: 0; height: auto; display: block; position: relative; }
    #curso-visor-area.visor-mobile-fullscreen .visor-main { width: 100%; height: 100%; }

    /* Botón "X" de cierre — visible solo mientras el frame está en modo
       pantalla completa. Ancla arriba a la derecha DEL FRAME (fixed hace de
       containing block), z-index por debajo del backdrop/sheet (60/70) para
       que quede tapado mientras el sheet de contenidos está abierto. */
    #curso-visor-area.visor-mobile-fullscreen .visor-mobile-close-btn {
        display: flex;
        align-items: center;
        justify-content: center;
        position: absolute;
        top: 10px;
        right: 10px;
        z-index: 55;
        width: 32px;
        height: 32px;
        border-radius: 50%;
        border: none;
        background: rgba(15,23,42,.06);
        color: var(--autoasistidos-text-muted);
        font-size: 15px;
    }

    /* ── Sidebar → bottom sheet deslizable, anclado al frame de arriba ──── */
    .visor-sheet-backdrop {
        display: block;
        position: fixed;
        inset: 0;
        background: rgba(15,23,42,.42);
        z-index: 60;
    }
    .visor-sidebar {
        position: fixed;
        left: 0;
        right: 0;
        bottom: 0;
        top: auto;
        z-index: 70;
        width: 100%;
        height: 78dvh;
        height: 78vh;
        max-height: 78dvh;
        display: flex;
        flex-direction: column;
        background: var(--autoasistidos-surface);
        border-right: none;
        border-bottom: none;
        border-radius: 18px 18px 0 0;
        box-shadow: 0 -14px 40px rgba(15,23,42,.28);
        transform: translateY(105%);
        transition: transform .32s cubic-bezier(.32,.72,0,1);
        overflow-y: auto;
        scrollbar-gutter: stable;
        scrollbar-width: thin;
        scrollbar-color: #c7d3e0 transparent;
    }
    .visor-sidebar::-webkit-scrollbar { width: 8px; }
    .visor-sidebar::-webkit-scrollbar-track { background: transparent; }
    .visor-sidebar::-webkit-scrollbar-thumb { background: #c7d3e0; border-radius: 8px; }
    .visor-sidebar--sheet-open { transform: translateY(0); }
    /* Handle pegado arriba del sheet (sticky, no fixed aparte): #visor-eval-item
       vive en el DOM como hermano de #visor-sidebar-list (después), no como su
       último hijo — moverlo ahí en el HTML se pierde en cada render porque
       curso.js hace list.innerHTML = ... (reemplazo total). Para que el botón
       de evaluación deje de quedar pegado al fondo del sheet (fijo, tapando
       contenido) y pase a scrollear junto con el resto como "un ítem más al
       final", el scroll de arriba (overflow-y en .visor-sidebar) cubre ambos
       hermanos — el handle necesita sticky propio para no perderse arriba. */
    .visor-sidebar-sheet-handle {
        display: flex;
        flex-direction: column;
        align-items: center;
        gap: 8px;
        flex-shrink: 0;
        padding: 10px 0 8px;
        cursor: pointer;
        position: sticky;
        top: 0;
        z-index: 1;
        background: var(--autoasistidos-surface);
    }

    /* ── Header compacto: flecha volver + eyebrow "UNIDAD 0X · MÓDULO" ──────
       Ya no necesita sticky: vive en flujo normal dentro del frame flex
       column de arriba (flex-shrink:0, primer hijo de .visor-main), el
       contenido/nav de abajo son los que scrollean/se acomodan alrededor
       — el header nunca puede quedar tapado porque no hay scroll de
       página que lo deje atrás. */
    .visor-content-header {
        display: flex;
        align-items: center;
        gap: 10px;
        flex-shrink: 0;
        background: var(--autoasistidos-surface);
    }
    .visor-content-back-btn { display: inline-flex; align-items: center; justify-content: center; }
    .visor-content-eyebrow-m { display: block; }
    .visor-content-breadcrumb { display: none; }
    .visor-content-titulo { margin-top: 2px; }

    /* ── Nav inferior: progreso + prev/toggle/next ─────────────────────────
       Ya no position:fixed anclado al viewport real — es el último hijo del
       flex column de .visor-main (flex-shrink:0), queda pegado al fondo del
       frame de 100dvh por el propio layout, sin overlay sobre el contenido
       ni padding-bottom de compensación. */
    .visor-nav {
        flex-shrink: 0;
        flex-direction: column;
        align-items: stretch;
        gap: 8px;
        padding: 8px 10px;
        padding-bottom: max(8px, env(safe-area-inset-bottom));
        border-top: 1px solid var(--autoasistidos-border);
    }
    .visor-nav-progreso { display: flex; }
    .visor-stepper { display: none; }
    .visor-nav-btn-label { display: none; }
    /* Mockup mobile: prev/next son círculos sólidos azules (no outline) —
       a diferencia de desktop, acá los dos pesan igual, no hay jerarquía
       primary/secondary entre "Anterior" y "Siguiente". */
    .visor-nav-btn,
    .visor-nav-btn--primary {
        width: 44px;
        height: 44px;
        padding: 0;
        border-radius: 999px;
        flex-shrink: 0;
        justify-content: center;
        background: var(--autoasistidos-primary);
        color: #fff;
        border-color: var(--autoasistidos-primary);
        font-size: 15px;
    }
    .visor-nav-btn:disabled { background: var(--autoasistidos-border); }
    /* En mobile los círculos ya son fondo azul sólido + ícono blanco (no el
       outline azul de desktop) — el hover/active base (línea 968) los aclara
       a primary-lt, dejando el ícono blanco invisible. Acá se oscurece en
       vez de aclarar, igual que ya hacía --primary en desktop. */
    .visor-nav-btn:not(.visor-nav-btn--primary):hover:not(:disabled),
    .visor-nav-btn--primary:hover:not(:disabled),
    .visor-nav-btn:not(.visor-nav-btn--primary):active:not(:disabled),
    .visor-nav-btn--primary:active:not(:disabled) {
        background: var(--autoasistidos-primary-dk);
        border-color: var(--autoasistidos-primary-dk);
    }
    /* Pill sólida ancha (mockup) — reemplaza el outline celeste tenue que
       usaba antes, ahora es el CTA central entre los dos círculos. */
    .visor-sheet-toggle-btn {
        display: flex;
        height: 44px;
        border: none;
        background: var(--autoasistidos-primary);
        color: #fff;
        border-radius: 999px;
        font-size: 13.5px;
        font-weight: 700;
    }
    .visor-sheet-toggle-btn:active { background: var(--autoasistidos-primary-dk); }

    /* Único punto de entrada al sheet de contenidos mientras no hay nada
       seleccionado (.visor-nav sigue con d-none en ese estado — ver
       comentario en curso.php junto al botón). Pill sólida (no chip tenue)
       porque es la ÚNICA acción disponible en este estado — tiene que leer
       como CTA primario, no como control secundario. Sombra + halo de
       pulso (.portal-cta-pulse) le dan peso y guían el ojo sin depender
       de texto extra. Alto mínimo 48px = target táctil cómodo. */
    .visor-placeholder-sheet-btn {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        gap: 9px;
        min-height: 48px;
        margin-top: 22px;
        border: none;
        background: linear-gradient(155deg, var(--autoasistidos-primary), var(--autoasistidos-primary-dk));
        border-radius: 999px;
        padding: 13px 24px;
        font-size: 14px;
        font-weight: 700;
        letter-spacing: .01em;
        color: #fff;
        font-family: inherit;
        cursor: pointer;
        box-shadow: 0 8px 20px -6px rgba(var(--autoasistidos-primary-rgb), .55);
        transition: transform var(--autoasistidos-transition), box-shadow var(--autoasistidos-transition);
    }
    .visor-placeholder-sheet-btn i { font-size: 15px; }
    .visor-placeholder-sheet-btn-chevron { font-size: 12px; opacity: .8; }

    /* Botón "Ver contenidos del curso" dentro de la autoevaluación (ver
       curso.php, #curso-eval-area) — pill chica en vez del CTA grande del
       placeholder, va arriba del bloque acompañando al resto, no reemplazando
       la única acción disponible. */
    .visor-eval-sheet-btn {
        display: flex;
        align-items: center;
        justify-content: center;
        gap: 8px;
        width: 100%;
        height: 44px;
        margin-bottom: 16px;
        border: none;
        background: var(--autoasistidos-primary-lt);
        color: var(--autoasistidos-primary-dk);
        border-radius: 999px;
        font-size: 13px;
        font-weight: 700;
        font-family: inherit;
        cursor: pointer;
    }
    .visor-eval-sheet-btn:active { background: rgba(var(--autoasistidos-primary-rgb), .18); }
    .visor-placeholder-sheet-btn:active {
        transform: scale(.97);
        box-shadow: 0 4px 12px -4px rgba(var(--autoasistidos-primary-rgb), .5);
    }
}

