/* Sistema visual - Academia Ainwater (PRD §6.2).
   Tokens alineados al Ainwater Design System (azul Ainwater + Montserrat/Roboto
   Mono), fuentes self-hosted (sin build de frontend, R7). Mobile-first (§6.1):
   columna única ≤640px, targets táctiles ≥44px, tipografía ≥14px; el contenido
   de curso limita su ancho de lectura desde tablet en adelante. */

:root {
    --tinta: #1E2A32;
    --cuerpo: #3A4852;
    --tinta-suave: #4B5563;
    --tinta-tenue: #8A98A3;
    --primario: #0068F8;
    --primario-oscuro: #0A4FD0;
    --niebla: #E2E9F1;
    --borde: #E2E9F1;
    --azul-palido: #EEF4FF;
    --azul-palido-borde: #DCE7FB;
    --papel: #F4F7FB;
    --superficie: #fff;
    --pizarra: #22303A;
    --texto-en-oscuro: #B8C4CC;
    --ambar: #E8A33D;
    --ambar-fondo: #FCF3E3;
    --ok: #1FA971;
    --ok-fondo: #E7F6EF;
    --error: #E0533D;
    --error-fondo: #FBEAE6;
    --foco: rgba(0, 104, 248, 0.28);

    /* Colores de rol en la navegación: distinguen responsabilidades.
       Academia (AdminAcademia: Gestión, Fábrica) y Empresa (Panel). */
    --rol-academia: #6D28D9;
    --rol-academia-fondo: #F3EEFC;
    --rol-empresa: #0F766E;
    --rol-empresa-fondo: #E6F4F2;

    --fuente-display: "Montserrat", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
    --fuente-texto: "Montserrat", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
    --fuente-mono: "Roboto Mono", ui-monospace, "SFMono-Regular", Menlo, monospace;

    --radio: 9px;
    --radio-tarjeta: 14px;
    --radio-panel: 16px;
    --sombra: 0 1px 2px rgba(30, 42, 50, 0.04);
    --sombra-hover: 0 4px 12px rgba(0, 104, 248, 0.08);
    --sombra-boton: 0 6px 16px rgba(0, 104, 248, 0.22);
    --transicion: cubic-bezier(.22, .61, .36, 1);
}

/* Modo oscuro (D0xx): el atributo lo fija JS (static/js/tema.js), leído de
   localStorage o, a falta de eso, de prefers-color-scheme - ver el script
   inline en base.html que lo aplica ANTES del primer paint (evita el
   flash del tema equivocado). --superficie es lo único que separa "fondo
   de página" de "fondo de tarjeta/input" - antes ambos eran el mismo
   #fff hardcodeado, lo que hacía imposible oscurecer uno sin el otro. */
html[data-tema="oscuro"] {
    --tinta: #E8ECEF;
    --cuerpo: #C3CDD5;
    --tinta-suave: #A8B3BD;
    --tinta-tenue: #6B7680;
    --primario: #3B8CFF;
    --primario-oscuro: #6BA8FF;
    --niebla: #2A3540;
    --borde: #2A3540;
    --azul-palido: #17242F;
    --azul-palido-borde: #223142;
    --papel: #0F1620;
    --superficie: #182430;
    --texto-en-oscuro: #B8C4CC;
    --ambar: #E8A33D;
    --ambar-fondo: #2E2412;
    --ok: #34D399;
    --ok-fondo: #123024;
    --error: #F87171;
    --error-fondo: #351515;
    --foco: rgba(59, 140, 255, 0.35);
    --rol-academia: #A78BFA;
    --rol-academia-fondo: #241B3D;
    --rol-empresa: #34D3C4;
    --rol-empresa-fondo: #12302C;
}

/* Fuentes self-hosted (RF-41: precacheadas por el service worker). OFL,
   Google Fonts - subset latin, variable en peso. Montserrat = voz editorial
   (títulos + cuerpo); Roboto Mono = voz de datos (cifras, etiquetas, código). */
@font-face {
    font-family: "Montserrat";
    src: url("/static/fuentes/montserrat-400-800.311d352d9323.woff2") format("woff2");
    font-weight: 400 800;
    font-display: swap;
}

@font-face {
    font-family: "Roboto Mono";
    src: url("/static/fuentes/roboto-mono-400-700.877722deef76.woff2") format("woff2");
    font-weight: 400 700;
    font-display: swap;
}

/* Urbanist: tipografía del wordmark de marca Ainwater (landing-page-ainwater,
   clase .wordmark-text) - solo para "Academia Ainwater" en la cabecera (.marca),
   no reemplaza a Montserrat como fuente del sistema de diseño. */
@font-face {
    font-family: "Urbanist";
    src: url("/static/fuentes/urbanist-700.3cd3faa59443.woff2") format("woff2");
    font-weight: 700;
    font-display: swap;
}

* {
    box-sizing: border-box;
}

html {
    /* Evita scroll horizontal accidental en cualquier ancho (§6.1). */
    overflow-x: hidden;
}

body {
    margin: 0;
    font-family: var(--fuente-texto);
    font-size: 16px;
    color: var(--cuerpo);
    background: var(--papel);
    line-height: 1.5;
}

h1, h2, h3 {
    font-family: var(--fuente-display);
    font-weight: 700;
    color: var(--tinta);
    line-height: 1.25;
    letter-spacing: -0.01em;
}

h1 { font-size: 1.9rem; }
h2 { font-size: 1.25rem; margin-top: 2rem; }

a {
    color: var(--primario);
}

a:hover {
    color: var(--primario-oscuro);
}

:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px var(--foco);
    border-radius: var(--radio);
}

/* --- Cabecera y navegación ------------------------------------------------ */

.cabecera {
    position: sticky;
    top: 0;
    z-index: 10;
    background: var(--superficie);
    border-bottom: 1px solid var(--niebla);
    box-shadow: var(--sombra);
}

.cabecera__inner {
    max-width: 1100px;
    margin: 0 auto;
    padding: 0.5rem 1rem;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.25rem 1.25rem;
}

.marca {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    font-family: "Urbanist", var(--fuente-display);
    font-weight: 700;
    font-size: 1.1rem;
    color: var(--tinta);
    text-decoration: none;
    min-height: 44px;
}

.marca__icono {
    width: 32px;
    height: auto;
    flex-shrink: 0;
}

.nav-principal,
.nav-usuario {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.15rem;
}

.nav-usuario {
    margin-left: auto;
}

.nav-principal a,
.nav-usuario a,
.boton--enlace {
    min-height: 44px;
    display: inline-flex;
    align-items: center;
    font-size: 0.95rem;
    font-weight: 500;
    color: var(--tinta-suave);
    text-decoration: none;
    background: none;
    border: none;
    border-radius: var(--radio);
    padding: 0 0.7rem;
    cursor: pointer;
    transition: background var(--transicion) 120ms, color var(--transicion) 120ms;
}

.nav-principal a:hover,
.nav-usuario a:hover,
.boton--enlace:hover {
    background: var(--papel);
    color: var(--tinta);
}

.nav-principal a.activo,
.nav-usuario a.activo {
    color: var(--primario-oscuro);
    font-weight: 600;
    background: var(--azul-palido);
}

/* --- Pestañas con color por rol: no solo color (hay punto indicador y
       texto oculto para lectores de pantalla) --------------------------- */

.rol-punto {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    margin-left: 0.35rem;
    display: inline-block;
    background: currentColor;
    opacity: 0.75;
}

.visualmente-oculto {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
    border: 0;
}

.nav-principal a.rol-academia {
    color: var(--rol-academia);
}

.nav-principal a.rol-academia:hover {
    background: var(--rol-academia-fondo);
    color: var(--rol-academia);
}

.nav-principal a.rol-academia.activo {
    background: var(--rol-academia-fondo);
    color: var(--rol-academia);
    font-weight: 600;
}

.nav-principal a.rol-empresa {
    color: var(--rol-empresa);
}

.nav-principal a.rol-empresa:hover {
    background: var(--rol-empresa-fondo);
    color: var(--rol-empresa);
}

.nav-principal a.rol-empresa.activo {
    background: var(--rol-empresa-fondo);
    color: var(--rol-empresa);
    font-weight: 600;
}

/* .nav-usuario a ya vistió cualquier <a>, incluido un .boton (RF-01 header),
   como enlace de texto plano - sin esto el CTA "Ingresar" del header queda
   invisible (blanco sobre blanco). */
.nav-usuario a.boton {
    color: #fff;
    background: var(--primario);
    border: 1px solid var(--primario);
}

.nav-usuario a.boton:hover {
    background: var(--primario-oscuro);
    border-color: var(--primario-oscuro);
    color: #fff;
}

/* Menú de Ajustes (tema, tamaño de letra y, en desarrollo, "Ver como"):
   siempre en la cabecera, incluso sin sesión (login, portada) - por eso
   vive fuera del bloque {% if user.is_authenticated %} en base.html, con el
   mismo patrón disparador/panel que el menú de cuenta (navbar.js). .nav-usuario
   ya trae su propio margin-left:auto para pegarse a la derecha - si este
   dropdown tuviera el suyo también, flexbox repartiría el espacio libre
   entre los dos márgenes automáticos en vez de dárselo a uno solo, dejando
   un salto enorme entre ambos. Solo hace falta empujarlo cuando es lo único
   después de .marca (login/recuperar, sin nav-usuario). */
.marca + .dropdown-ajustes {
    margin-left: auto;
}

.menu-ajustes__etiqueta {
    font-family: var(--fuente-mono);
    font-size: 0.7rem;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--tinta-tenue);
    margin: 0.5rem 0.75rem 0.25rem;
}

.menu-ajustes__fila {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.4rem;
    padding: 0.3rem 0.75rem 0.5rem;
}

/* Los botones de esta fila son <button> dentro de .dropdown-cuenta__panel,
   así que heredan su regla genérica ".dropdown-cuenta__panel button"
   (ancho 100%, alto 40px, padding propio) con más especificidad que
   .control-fuente__boton/.boton-tema solas - se repone acá, calificado por
   .menu-ajustes__fila, para que gane. */
.menu-ajustes__fila .control-fuente__boton,
.menu-ajustes__fila .boton-tema {
    width: 36px;
    min-width: 36px;
    height: 36px;
    min-height: 36px;
    padding: 0;
    flex: none;
}

/* Fila "Lectura biónica" del menú de Ajustes: mismo patrón fila+interruptor
   que .campo-checkbox--seleccionar-todos, pero con el texto a la izquierda
   y el interruptor a la derecha (más natural dentro de un menú). */
.menu-ajustes__opcion {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    padding: 0.3rem 0.75rem 0.5rem;
    font-size: 0.92rem;
    color: var(--tinta-suave);
}

/* Lectura biónica (static/js/bionic.js): el <b> inyectado puede caer
   dentro de cualquier contenido existente de la app (títulos, tarjetas,
   etc.), incluidas reglas que ya estilan "strong"/"b" a secas para ese
   contexto puntual (ej. .tarjeta-enlace__texto strong con display:block,
   pensada para un título completo, no para media palabra suelta adentro).
   !important es intencional: sin él, cualquier selector de tag existente
   -o uno nuevo que se agregue después sin saber que esto existe- puede
   volver a romper el flujo del texto en una palabra por línea. */
.bionic-negrita {
    display: inline !important;
    font-weight: 700 !important;
}

.control-fuente {
    display: inline-flex;
    align-items: center;
    gap: 0.1rem;
}

.control-fuente__boton {
    min-width: 36px;
    min-height: 36px;
    width: 36px;
    height: 36px;
    padding: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: none;
    border: none;
    box-shadow: none;
    color: var(--tinta-suave);
    font-family: var(--fuente-display);
    font-weight: 700;
    border-radius: var(--radio);
    cursor: pointer;
    flex-shrink: 0;
    transition: background var(--transicion) 120ms, color var(--transicion) 120ms;
}

.control-fuente__boton:hover {
    background: var(--papel);
    color: var(--tinta);
}

.control-fuente__boton--menos {
    font-size: 0.75rem;
}

.control-fuente__boton--mas {
    font-size: 1.1rem;
}

.boton-tema {
    min-width: 44px;
    min-height: 44px;
    width: 44px;
    height: 44px;
    padding: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: none;
    border: none;
    box-shadow: none;
    color: var(--tinta-suave);
    border-radius: var(--radio);
    cursor: pointer;
    flex-shrink: 0;
    transition: background var(--transicion) 120ms, color var(--transicion) 120ms;
}

.boton-tema:hover {
    background: var(--papel);
    color: var(--tinta);
}

.boton-tema svg {
    width: 20px;
    height: 20px;
}

.boton-tema__icono--sol {
    display: none;
}

html[data-tema="oscuro"] .boton-tema__icono--sol {
    display: block;
}

html[data-tema="oscuro"] .boton-tema__icono--luna {
    display: none;
}

/* --- Menú de cuenta: clic en el nombre despliega Mi perfil, Mis
   certificaciones y, si corresponde, Gestión/Fábrica. --------------------- */
.dropdown-cuenta {
    position: relative;
}

.dropdown-cuenta__disparador {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    min-height: 44px;
    min-width: 0;
    font-family: inherit;
    font-size: 0.95rem;
    font-weight: 500;
    color: var(--tinta-suave);
    background: none;
    border: none;
    box-shadow: none;
    border-radius: var(--radio);
    padding: 0 0.7rem;
    cursor: pointer;
    transition: background var(--transicion) 120ms, color var(--transicion) 120ms;
}

.dropdown-cuenta__disparador:hover {
    background: var(--papel);
    color: var(--tinta);
}

.dropdown-cuenta__caret {
    width: 0.75rem;
    height: 0.75rem;
    transition: transform var(--transicion) 150ms;
}

.dropdown-cuenta__disparador[aria-expanded="true"] .dropdown-cuenta__caret {
    transform: rotate(180deg);
}

.dropdown-cuenta__panel {
    position: absolute;
    top: calc(100% + 0.4rem);
    right: 0;
    min-width: 13rem;
    background: var(--superficie);
    border: 1px solid var(--niebla);
    border-radius: var(--radio-tarjeta);
    box-shadow: var(--sombra-hover);
    padding: 0.4rem;
    z-index: 20;
}

.dropdown-cuenta__panel[hidden] {
    display: none;
}

.dropdown-cuenta__panel a,
.dropdown-cuenta__panel button {
    display: flex;
    align-items: center;
    gap: 0.55rem;
    width: 100%;
    min-height: 40px;
    margin: 0;
    padding: 0 0.75rem;
    border: none;
    box-shadow: none;
    border-radius: var(--radio);
    background: none;
    color: var(--tinta-suave);
    text-decoration: none;
    font-family: inherit;
    font-size: 0.92rem;
    font-weight: 500;
    text-align: left;
    cursor: pointer;
}

.dropdown-cuenta__icono {
    flex: none;
    width: 1.05rem;
    height: 1.05rem;
    color: var(--tinta-tenue);
}

.dropdown-cuenta__panel a.rol-academia .dropdown-cuenta__icono,
.dropdown-cuenta__panel a[aria-current="page"] .dropdown-cuenta__icono {
    color: currentColor;
}

/* El ícono del engranaje va en el disparador, no en un ítem del panel -
   ahí currentColor (que sigue al botón, incluido su :hover) se ve mejor
   que el tinta-tenue fijo pensado para íconos de fila. */
.dropdown-cuenta__disparador .dropdown-cuenta__icono {
    color: currentColor;
}

.dropdown-cuenta__panel a:hover,
.dropdown-cuenta__panel button:hover {
    background: var(--papel);
    color: var(--tinta);
}

.dropdown-cuenta__panel a[aria-current="page"],
.dropdown-cuenta__panel button[aria-current="page"] {
    color: var(--primario-oscuro);
    font-weight: 600;
    background: var(--azul-palido);
}

.dropdown-cuenta__panel a.rol-academia {
    color: var(--rol-academia);
}

.dropdown-cuenta__panel a.rol-academia:hover,
.dropdown-cuenta__panel a.rol-academia[aria-current="page"] {
    background: var(--rol-academia-fondo);
    color: var(--rol-academia);
}

.dropdown-cuenta__divisor {
    height: 1px;
    background: var(--niebla);
    margin: 0.35rem 0.25rem;
}

.dropdown-cuenta__salir {
    appearance: none;
    display: flex;
    align-items: center;
    justify-content: flex-start;
    gap: 0.55rem;
    width: 100%;
    margin: 0;
    min-height: 40px;
    min-width: 0;
    padding: 0 0.75rem;
    border: none;
    box-shadow: none;
    border-radius: var(--radio);
    background: none;
    color: var(--tinta-suave);
    font-family: inherit;
    font-size: 0.92rem;
    font-weight: 500;
    text-align: left;
    cursor: pointer;
}

.dropdown-cuenta__salir:hover {
    background: var(--papel);
    color: var(--tinta);
}

/* En móvil la navegación baja a su propia fila, deslizable. */
@media (max-width: 640px) {
    .nav-principal {
        order: 3;
        width: 100%;
        overflow-x: auto;
        flex-wrap: nowrap;
        -webkit-overflow-scrolling: touch;
    }
}

main {
    padding: 1rem;
    max-width: 100%;
}

/* Tablet (641–1024px) y PC (>1024px): ancho de lectura acotado (~72ch). */
@media (min-width: 641px) {
    main {
        max-width: 72ch;
        margin: 0 auto;
        padding: 2rem 1rem 3rem;
    }
    main.ancho-panel {
        max-width: 1100px;
    }
}

/* --- Encabezado de página: título + acción principal a la derecha. -------- */

.encabezado-pagina {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem 1rem;
    margin-bottom: 0.5rem;
}

.encabezado-pagina h1 {
    margin: 0.25rem 0;
}

.descripcion-pagina {
    color: var(--tinta-suave);
    margin-top: 0;
    max-width: 65ch;
}

/* Vista previa de AdminAcademia (/my-path): la nota es de apoyo, no cuerpo de
   página - un poco más chica que el uso general de .descripcion-pagina. */
.descripcion-pagina--compacta {
    font-size: 0.85rem;
    max-width: none;
    margin-bottom: 0.5rem;
}

/* Etiqueta "opcional" junto a un título de tarjeta - informativa, no un
   estado (por eso no reusa .etiqueta-estado, que siempre lleva un tinte
   semántico azul/ok/error/ámbar). */
.etiqueta-opcional {
    /* .tarjeta-form__titulo es flex sin gap propio (pensado para el ícono
       de ayuda, que sigue al texto sin separación visible) - sin este
       margen, la etiqueta queda pegada al título. */
    margin-left: 0.5rem;
    font-size: 0.7rem;
    font-weight: 600;
    color: var(--tinta-tenue);
    background: var(--papel);
    border: 1px solid var(--borde);
    border-radius: var(--radio);
    padding: 0.1rem 0.5rem;
}

/* Editor de "Temario sugerido" (spec_form.html): input + botón para
   agregar una sección a la vez, en vez de editar todo el bloque de texto. */
.fila-agregar-item {
    display: flex;
    gap: 0.6rem;
    margin-bottom: 0.75rem;
}

.fila-agregar-item__caja {
    flex: 1;
    max-width: none;
}

/* 3 secciones visibles (54px c/u + 0.5rem de gap) y sin scroll propio -
   mismo criterio que .grupo-opciones--lista de Fuentes: lo que no entra se
   alcanza con el buscador de arriba (data-temario-buscar), no scrolleando. */
.lista-temario {
    list-style: none;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    margin: 0 0 0.75rem;
    padding: 0;
    max-height: 11.125rem;
    overflow: hidden;
}

.item-temario {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0.5rem 0.5rem 0.5rem 0.75rem;
    border: 1px solid var(--borde);
    border-radius: var(--radio);
    background: var(--papel);
}

.item-temario--arrastrando {
    opacity: 0.4;
}

.item-temario__agarre {
    display: inline-flex;
    align-items: center;
    flex-shrink: 0;
    color: var(--tinta-tenue);
    cursor: grab;
}

.item-temario__agarre svg {
    width: 1rem;
    height: 1rem;
}

.item-temario__agarre:active {
    cursor: grabbing;
}

.item-temario__indice {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.5rem;
    height: 1.5rem;
    flex-shrink: 0;
    border-radius: var(--radio);
    background: var(--azul-palido);
    color: var(--primario-oscuro);
    font-family: var(--fuente-mono);
    font-size: 0.78rem;
    font-weight: 700;
}

.item-temario__texto {
    flex: 1;
    min-width: 0;
    font-size: 0.92rem;
    color: var(--tinta);
    word-break: break-word;
}

.fila-pie-temario {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    font-size: 0.85rem;
    color: var(--tinta-suave);
}

/* Migas de pan para volver un nivel sin usar el botón atrás. */
.migas {
    font-size: 0.9rem;
    color: var(--tinta-suave);
    margin: 0 0 0.25rem;
}

.migas a {
    color: var(--tinta-suave);
}

/* --- Formularios ------------------------------------------------------------
   Cubre el render por defecto de Django ({{ form.as_p }}): <p><label>…<input>,
   ul.errorlist y span.helptext quedan vestidos sin tocar cada plantilla. */

button, input, select, textarea {
    font-family: inherit;
    font-size: 1rem;
}

form p {
    margin: 0 0 1rem;
}

form p label,
.campo label {
    display: block;
    font-weight: 600;
    font-size: 0.95rem;
    margin-bottom: 0.3rem;
}

input[type="text"],
input[type="email"],
input[type="password"],
input[type="number"],
input[type="date"],
input[type="url"],
select,
textarea {
    width: 100%;
    max-width: 34rem;
    min-height: 44px;
    padding: 0.5rem 0.75rem;
    border: 1px solid var(--borde);
    border-radius: var(--radio);
    background: var(--superficie);
    color: var(--tinta);
    transition: border-color var(--transicion) 120ms, box-shadow var(--transicion) 120ms;
}

/* El padding derecho parejo de la regla anterior no reserva espacio para la
   flecha nativa del <select> - con una opción larga que se corta, el texto
   queda pegado (o encima) de la flecha. */
select {
    padding-right: 2rem;
}

textarea {
    max-width: 100%;
    line-height: 1.45;
}

/* Campo numérico con botones -/+ a los lados (Evaluación en spec_form.html):
   el <input type="number"> real sigue siendo el campo que se envía -
   stepper_numero.js solo le suma/resta 1 y respeta min/max. */
.campo-stepper__caja {
    display: flex;
    align-items: stretch;
    max-width: 34rem;
    border: 1px solid var(--borde);
    border-radius: var(--radio);
    overflow: hidden;
}

.campo-stepper__caja input[type="number"] {
    flex: 1;
    min-width: 0;
    max-width: none;
    border: none;
    border-left: 1px solid var(--borde);
    border-right: 1px solid var(--borde);
    border-radius: 0;
    text-align: center;
    font-family: var(--fuente-mono);
    font-weight: 700;
    font-size: 1.1rem;
    -moz-appearance: textfield;
}

.campo-stepper__caja input[type="number"]::-webkit-outer-spin-button,
.campo-stepper__caja input[type="number"]::-webkit-inner-spin-button {
    -webkit-appearance: none;
    margin: 0;
}

.campo-stepper__boton {
    flex-shrink: 0;
    min-width: 44px;
    min-height: 44px;
    padding: 0;
    background: var(--papel);
    color: var(--tinta-suave);
    border: none;
    border-radius: 0;
    box-shadow: none;
    font-family: var(--fuente-mono);
    font-size: 1.2rem;
    font-weight: 700;
}

.campo-stepper__boton:hover {
    background: var(--azul-palido);
    color: var(--primario-oscuro);
}

/* Curso/perfil ya guardados en una ruta (gestion/ruta_form.html): se
   deshabilitan por JS hasta que se pulsa "Editar esta fila" - sin la
   flecha nativa no parecen un dropdown accionable mientras están así. */
select:disabled {
    appearance: none;
    -webkit-appearance: none;
    -moz-appearance: none;
    padding-right: 0.75rem;
    background: none;
    border-color: transparent;
    color: var(--tinta);
    cursor: default;
}

input:focus, select:focus, textarea:focus {
    outline: none;
    box-shadow: 0 0 0 3px var(--foco);
    border-color: var(--primario);
}

input[type="checkbox"], input[type="radio"] {
    width: 1.15rem;
    height: 1.15rem;
    accent-color: var(--primario);
}

input[type="file"] {
    font-size: 0.9rem;
    color: var(--tinta-suave);
}

/* Botón nativo del selector de archivo - mismo look que .boton--secundario
   (borde azul, relleno blanco) en vez del botón gris de fábrica del navegador. */
input[type="file"]::file-selector-button,
input[type="file"]::-webkit-file-upload-button {
    margin-right: 0.75rem;
    min-height: 38px;
    padding: 0.5rem 1rem;
    background: var(--superficie);
    color: var(--primario);
    font-family: var(--fuente-display);
    font-weight: 600;
    font-size: 0.9rem;
    border: 1px solid var(--primario);
    border-radius: var(--radio);
    cursor: pointer;
    transition: background var(--transicion) 120ms, color var(--transicion) 120ms;
}

input[type="file"]::file-selector-button:hover,
input[type="file"]::-webkit-file-upload-button:hover {
    background: var(--azul-palido);
    color: var(--primario-oscuro);
}

.helptext {
    display: block;
    font-size: 0.85rem;
    color: var(--tinta-suave);
    margin-top: 0.25rem;
}

.helptext--error {
    color: var(--error);
}

/* Fila de chips de filtro (ej. Fuentes en spec_form.html): atajos rápidos
   sobre una lista ya visible, distinto de .atajo-fecha (esos rellenan un
   campo, estos filtran una lista) - mismo tratamiento de píldora. */
.fila-chips-filtro {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
    margin: 0.75rem 0;
}

.chip-filtro {
    display: inline-flex;
    align-items: center;
    min-height: 32px;
    padding: 0.25rem 0.8rem;
    border-radius: 999px;
    border: 1px solid var(--borde);
    background: var(--superficie);
    color: var(--tinta-suave);
    font-family: inherit;
    font-size: 0.82rem;
    font-weight: 600;
    box-shadow: none;
    cursor: pointer;
    transition: background var(--transicion) 120ms, color var(--transicion) 120ms, border-color var(--transicion) 120ms;
}

.chip-filtro:hover {
    background: var(--azul-palido);
    color: var(--primario-oscuro);
}

.chip-filtro--activo,
.chip-filtro--activo:hover {
    background: var(--azul-palido);
    color: var(--primario-oscuro);
    border-color: var(--primario);
}

.fila-chips-filtro__contador {
    margin-left: auto;
    font-family: var(--fuente-mono);
    font-size: 0.8rem;
    color: var(--tinta-suave);
}

ul.errorlist {
    list-style: none;
    margin: 0 0 0.35rem;
    padding: 0;
    color: var(--error);
    font-size: 0.9rem;
    font-weight: 600;
}

/* --- Botones ---------------------------------------------------------------- */

button, .boton {
    min-height: 44px;
    min-width: 44px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.4rem;
    padding: 0.6rem 1.2rem;
    background: var(--primario);
    color: #fff;
    font-family: var(--fuente-display);
    font-weight: 600;
    border: 1px solid var(--primario);
    border-radius: var(--radio);
    cursor: pointer;
    text-decoration: none;
    box-shadow: var(--sombra-boton);
    transition: background var(--transicion) 120ms, transform var(--transicion) 120ms, box-shadow var(--transicion) 120ms;
}

/* Sin esto, un <svg> suelto dentro de un .boton (ej. "+ Agregar nueva
   fuente") no tiene ancho/alto propios y el navegador le aplica su tamaño
   por defecto de reemplazo (~300×150px) - infla el botón entero. */
button svg, .boton svg {
    width: 1.1rem;
    height: 1.1rem;
    flex-shrink: 0;
}

button:hover, .boton:hover {
    background: var(--primario-oscuro);
    border-color: var(--primario-oscuro);
    /* Sin esto, la regla global "a:hover { color }" le gana en especificidad
       al color:#fff base (el selector de tipo "a" suma un punto), y el botón
       queda con letras azul oscuro sobre fondo azul oscuro. */
    color: #fff;
}

button:not(:disabled):active, .boton:not(:disabled):active {
    transform: translateY(1px);
}

.boton--secundario {
    background: var(--superficie);
    color: var(--primario);
    border: 1px solid var(--primario);
    box-shadow: none;
}

.boton--secundario:hover {
    background: var(--azul-palido);
    color: var(--primario-oscuro);
}

.boton--peligro {
    background: var(--error);
    border-color: var(--error);
}

.boton--peligro:hover {
    background: #C24631;
    border-color: #C24631;
}

.boton--enlace {
    background: none;
    color: var(--tinta-suave);
    font-family: var(--fuente-texto);
    font-weight: 500;
    padding: 0 0.7rem;
    box-shadow: none;
    border: none;
}

.boton--enlace:hover {
    background: var(--papel);
    color: var(--tinta);
}

/* Fila de acciones al pie de un formulario. */
.acciones {
    display: flex;
    flex-wrap: wrap;
    gap: 0.6rem;
    margin-top: 1.25rem;
}

/* Wizard de spec_form.html: un paso visible a la vez sobre el mismo
   <form> de siempre - el envío sigue siendo un único POST, la navegación
   es 100% cliente (spec_wizard.js). En móvil la fila de pasos scrollea
   horizontal en vez de amontonarse (mismo criterio que .nav-principal). */
.wizard-pasos {
    position: relative;
    display: flex;
    justify-content: space-between;
    gap: 0.25rem;
    margin-bottom: 2rem;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    padding-top: 0.25rem;
    padding-bottom: 0.35rem;
    flex-shrink: 0;
}

.wizard-pasos__barra {
    position: absolute;
    top: 1.35rem;
    left: 2.5%;
    width: 95%;
    height: 2px;
    background: var(--niebla);
    z-index: 0;
}

.wizard-pasos__relleno {
    height: 100%;
    background: var(--primario);
    width: 0%;
    transition: width var(--transicion) 200ms;
}

.wizard-pasos__nodo {
    position: relative;
    z-index: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.4rem;
    background: var(--papel);
    border: none;
    box-shadow: none;
    padding: 0 0.35rem;
    min-width: 0;
    min-height: 0;
    flex-shrink: 0;
    cursor: pointer;
}

/* Sin esto, "button:hover, .boton:hover" (más específico que .wizard-pasos__nodo
   solo) le pinta el fondo azul primario detrás del círculo/etiqueta al pasar
   el mouse. */
.wizard-pasos__nodo:hover {
    background: var(--papel);
}

.wizard-pasos__circulo {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.2rem;
    height: 2.2rem;
    border-radius: 50%;
    background: var(--superficie);
    border: 2px solid var(--niebla);
    color: var(--tinta-suave);
    font-family: var(--fuente-mono);
    font-weight: 700;
    font-size: 0.85rem;
    transition: background var(--transicion) 150ms, border-color var(--transicion) 150ms, color var(--transicion) 150ms;
}

.wizard-pasos__etiqueta {
    font-size: 0.72rem;
    font-weight: 600;
    color: var(--tinta-suave);
    white-space: nowrap;
}

.wizard-pasos__nodo--activo .wizard-pasos__circulo {
    border-color: var(--primario);
    color: var(--primario-oscuro);
    box-shadow: 0 0 0 3px var(--foco);
}

.wizard-pasos__nodo--activo .wizard-pasos__etiqueta {
    color: var(--tinta);
}

.wizard-pasos__nodo--completo .wizard-pasos__circulo {
    background: var(--primario);
    border-color: var(--primario);
    color: #fff;
}

.wizard-footer {
    display: flex;
    justify-content: space-between;
    gap: 0.75rem;
    margin-top: 1.5rem;
    flex-shrink: 0;
}

/* spec_wizard.js fija max-height en [data-wizard] con lo que queda de alto
   de ventana debajo de la cabecera/migas - así el paso activo scrollea
   internamente si su contenido no cabe, en vez de scrollear toda la
   página. Sin JS no hay max-height y todo se apila normal (R7). */
[data-wizard] {
    display: flex;
    flex-direction: column;
    min-height: 0;
}

[data-wizard] form {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-height: 0;
}

/* overflow-x: hidden explícito - sin él, "overflow-y: auto" con overflow-x
   en su valor inicial (visible) hace que el spec de CSS compute overflow-x
   a auto igual (no puede quedar visible+scroll mezclado). Eso convertía
   cualquier desborde horizontal incidental - ej. el globo de .icono-info__tooltip,
   que aunque invisible (opacity:0) sigue maquetado con position:absolute y
   pesa en el scrollWidth - en una barra de scroll horizontal real. */
[data-wizard] [data-paso-wizard] {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    overflow-x: hidden;
}

/* Fuentes (paso 3): la lista de fuentes ya viene acotada a 3 filas fijas y
   sin scroll propio (.grupo-opciones--lista) - el resto del paso (buscador,
   chips, botón) es de alto fijo, así que el contenido nunca desborda el
   alto disponible. El scroll interno genérico de arriba no hace falta acá.
   Los dos ejes se pisan juntos a "visible": el spec de overflow no permite
   mezclar visible en un eje con un valor no-visible en el otro (lo mismo que
   forzó el overflow-x:hidden de la regla genérica) - dejar solo overflow-y
   en visible con el overflow-x:hidden heredado hace que el navegador
   recompute overflow-y de vuelta a auto. */
[data-wizard] [data-paso-wizard="3"] {
    overflow-y: visible;
    overflow-x: visible;
}

/* Varios campos cortos en una fila (versión + nivel + duración, etc.). */
.fila-campos {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: 0.6rem 1.25rem;
}

/* Varios .fila-campos apilados (ej. Identidad del curso) no comparten
   columnas entre sí: cada fila reparte su ancho según cuántos campos tiene
   ESA fila, así que una fila de 2 y otra de 3 no alinean sus bordes. Una
   sola grilla con columnas fijas y áreas explícitas sí - y de paso fija el
   orden visual (Nivel bajo Slug; Nivel/Duración/Versión en una sola fila). */
.grid-campos {
    display: grid;
    grid-template-columns: 1.3fr 1.3fr 0.9fr 0.9fr 0.8fr;
    grid-template-areas: "slug eje nivel duracion version";
    gap: 0.6rem 1.25rem;
    margin-bottom: 1rem;
}

.grid-campos .campo--slug { grid-area: slug; }
.grid-campos .campo--eje { grid-area: eje; }
.grid-campos .campo--nivel { grid-area: nivel; }
.grid-campos .campo--duracion { grid-area: duracion; }
.grid-campos .campo--version { grid-area: version; }

@media (max-width: 900px) {
    .grid-campos {
        grid-template-columns: repeat(3, 1fr);
        grid-template-areas:
            "slug eje eje"
            "nivel duracion version";
    }
}

@media (max-width: 640px) {
    .grid-campos {
        grid-template-columns: 1fr;
        grid-template-areas:
            "slug"
            "eje"
            "nivel"
            "duracion"
            "version";
    }
}

/* Cuando todos los campos de la fila son etiqueta + control simple (sin
   texto de ayuda ni casos donde una etiqueta pueda envolver a dos líneas),
   alinear arriba deja las etiquetas siempre a la misma altura - flex-end
   las desalinea si una columna termina siendo más alta que otra. */
.fila-campos--inicio {
    align-items: flex-start;
}

/* Fecha límite (asignar_ruta.html): no necesita el mismo ancho que un
   <select> de ruta al lado - el propio input[type=date] ya define un ancho
   natural cómodo para "dd-mm-aaaa" + ícono. */
.fila-campos > .campo--fecha {
    flex: 0 1 auto;
}

.campo--fecha input[type="date"] {
    width: auto;
    min-width: 11rem;
}

/* Atajos rápidos de fecha límite: rellenan el date picker con hoy + N días
   sin obligar a calcular la fecha exacta a mano. */
.atajos-fecha {
    display: flex;
    flex-wrap: wrap;
    gap: 0.35rem;
    margin-top: 0.4rem;
}

.atajo-fecha {
    min-height: 30px;
    min-width: 0;
    padding: 0.2rem 0.7rem;
    font-family: var(--fuente-texto);
    font-size: 0.78rem;
    font-weight: 600;
    border-radius: 999px;
    border: 1px solid var(--azul-palido-borde);
    background: var(--azul-palido);
    color: var(--primario-oscuro);
    box-shadow: none;
    cursor: pointer;
}

.atajo-fecha:hover {
    background: var(--azul-palido-borde);
}

.fila-campos > .campo {
    flex: 1 1 16rem;
}

/* Opciones avanzadas (spec_form.html): 4 campos cortos (proveedor, nombre
   de modelo, un número...) - con la base de 16rem de arriba no entran los
   4 en una fila dentro del ancho de la tarjeta y el último salta solo a una
   segunda línea, sin verse como una grilla sino como un campo suelto.
   min-width:0 es la parte que realmente evita el desborde: un ítem flex por
   defecto no encoge por debajo del ancho de SU contenido (min-width:auto),
   así que aunque bajemos la base a 12rem, sin esto el input/select seguía
   empujando el ancho real y forzando scroll horizontal en la tarjeta. */
.fila-campos--compacta > .campo {
    flex-basis: 12rem;
    min-width: 0;
}

/* Nombre/Empresa de una ruta: 50%/50% en desktop, apilados en pantallas
   angostas. */
.fila-nombre-empresa {
    display: grid;
    grid-template-columns: 1fr;
    gap: 1rem;
}

@media (min-width: 700px) {
    .fila-nombre-empresa {
        grid-template-columns: 1fr 1fr;
        gap: 1.25rem;
    }
}

.fila-campos p {
    flex: 1 1 12rem;
}

/* Grupo de opciones (checkboxes con descripción, ej. perfiles y fuentes). */
.grupo-opciones {
    display: grid;
    gap: 0.5rem;
    margin-bottom: 1rem;
}

.grupo-opciones--fila {
    grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
}

.opcion-caja {
    display: flex;
    align-items: flex-start;
    gap: 0.6rem;
    padding: 0.6rem 0.75rem;
    border: 1px solid var(--borde);
    border-radius: var(--radio);
    background: var(--papel);
    cursor: pointer;
}

/* El "display: flex" de arriba empata en especificidad con la regla
   [hidden]{display:none} del navegador - al ser ambas del mismo peso, gana
   la de acá por venir después en cascada, y el atributo hidden que pone el
   JS de filtros (asignar_ruta.js) deja de ocultar la tarjeta. Se repone acá
   con selector más específico. */
.opcion-caja[hidden] {
    display: none;
}

.opcion-caja:has(input:checked) {
    border-color: var(--primario);
    background: var(--azul-palido);
}

/* Fuentes en spec_form.html: filas pegadas en un solo bloque (como una
   tabla) en vez de tarjetas sueltas con espacio entre sí - mismo contenido
   y mismos estados de cada .opcion-caja, solo cambia el envoltorio. */
.grupo-opciones--lista {
    display: block;
    gap: 0;
    border: 1px solid var(--borde);
    border-radius: var(--radio-tarjeta);
    background: var(--superficie);
    /* 3 filas visibles (cada una ronda los 4.2rem con su padding) y sin
       scroll propio - a diferencia del resto del wizard, acá no se navega
       con scroll sino acotando con el buscador/chips de arriba; lo que no
       entra en las 3 filas queda recortado, no scrolleable. */
    max-height: 12.6rem;
    overflow: hidden;
}

.grupo-opciones--lista .opcion-caja {
    border: none;
    border-radius: 0;
    border-bottom: 1px solid var(--borde);
    background: transparent;
}

.grupo-opciones--lista .opcion-caja:last-child {
    border-bottom: none;
}

.grupo-opciones--lista .opcion-caja:hover {
    background: var(--papel);
}

/* El fondo azul de "seleccionada" sigue, pero sin el borde de color propio
   de una tarjeta suelta - acá rompería la línea divisoria con la fila de
   al lado. */
.grupo-opciones--lista .opcion-caja:has(input:checked) {
    border-color: var(--borde);
    background: var(--azul-palido);
}

/* Trabajadores de asignar_ruta.html: sin checkbox visible - el borde/fondo
   de arriba ya avisa la selección, así que el input queda oculto pero
   accesible (mismo truco de .interruptor: fuera de flujo, no display:none,
   para que Tab y lectores de pantalla lo sigan viendo). No se toca la clase
   base .opcion-caja porque fabricacion/spec_form.html la usa con checkbox
   visible (perfiles, sectores, fuentes). */
.opcion-caja--trabajador {
    position: relative;
    min-height: 4.5rem;
    /* La base alinea arriba (align-items:flex-start) para calzar un checkbox
       chico con la primera línea de un <small> largo - acá el ícono es
       grande y fijo, así que si el texto envuelve a 2 líneas queda pegado
       arriba en vez de centrado contra todo el bloque de texto. */
    align-items: center;
}

/* Sectores (spec_form.html): una palabra corta junto al ícono, sin nada más
   - el mínimo de 4.5rem de la base (pensado para el nombre + cargo/planta
   de asignar_ruta.html) le queda grande y deja la tarjeta con aire de más. */
.opcion-caja--sector {
    min-height: 0;
}

/* Perfiles (spec_form.html): tarjeta con cabecera (ícono + nombre), badge y
   lista de rasgos - demasiado contenido para la fila ícono/texto genérica
   de .opcion-caja--trabajador, así que pasa a columna: cabecera arriba,
   badge, lista debajo. El ícono queda junto al nombre, no separado de él. */
.opcion-caja--perfil {
    flex-direction: column;
    align-items: stretch;
}

.opcion-caja__cabecera {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    margin-bottom: 0.25rem;
}

.opcion-caja__divisor {
    display: block;
    height: 1px;
    background: var(--borde);
    margin: 0.1rem 0 0.35rem;
}

.opcion-caja--perfil .etiqueta-estado {
    display: block;
    width: fit-content;
    margin-bottom: 0.25rem;
}

.opcion-caja--perfil .explicador__lista {
    margin-top: 0.25rem;
    /* Con 4 tarjetas por fila el texto envuelve seguido (columnas de ~15rem)
       - achicar interlineado y espacio entre viñetas es lo que realmente
       gana alto acá, más que el padding de la tarjeta. */
    line-height: 1.3;
}

.opcion-caja--perfil .explicador__lista li + li {
    margin-top: 0.2rem;
}

.opcion-caja--trabajador input[type="checkbox"] {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: 0;
    opacity: 0;
}

.opcion-caja--trabajador:has(input:focus-visible) {
    box-shadow: 0 0 0 3px var(--foco);
}

.opcion-caja input {
    margin-top: 0.2rem;
    flex-shrink: 0;
}

.opcion-caja small {
    display: block;
    color: var(--tinta-suave);
}

.opcion-caja:has(input:disabled) {
    opacity: 0.6;
    cursor: not-allowed;
}

/* Sección avanzada plegada por defecto. */
details.avanzado {
    margin-bottom: 1rem;
}

details.avanzado summary {
    cursor: pointer;
    color: var(--primario);
    font-weight: 600;
    min-height: 44px;
    display: flex;
    align-items: center;
    gap: 0.4rem;
}

/* display:flex oculta el marcador nativo del <summary>: se repone a mano
   para que se note que es desplegable. */
details.avanzado summary::before {
    content: "▸";
    color: var(--primario);
    transition: transform 0.15s;
}

details.avanzado[open] summary::before {
    transform: rotate(90deg);
}

details.avanzado summary::-webkit-details-marker {
    display: none;
}

/* Editor de revisión experta (contenido/quiz del paquete). */
.editor-md {
    font-family: var(--fuente-mono);
    font-size: 0.9rem;
    line-height: 1.5;
}

/* Atajos de formato markdown sobre el editor de una sección (D088):
   envuelven la selección (negrita) o anteponen a la línea (título, lista). */
.barra-formato-md {
    display: flex;
    gap: 0.35rem;
    margin-bottom: 0.35rem;
}

.barra-formato-md[hidden] {
    display: none;
}

.barra-formato-md button {
    min-height: 30px;
    padding: 0.2rem 0.6rem;
    font-size: 0.8rem;
    font-weight: 600;
    background: var(--papel);
    color: var(--tinta-suave);
    border: 1px solid var(--borde);
    box-shadow: none;
}

.barra-formato-md button:hover {
    background: var(--azul-palido);
    color: var(--primario-oscuro);
}

/* Bloque de video de una sección (D088): sube video + subtítulos por
   idioma en un solo paso, sin el flujo de subir aparte y pegar un snippet
   copiado a mano. */
.bloque-video-seccion {
    margin-top: 0.75rem;
}

.bloque-video-seccion .campo {
    margin-bottom: 0.6rem;
}

/* .campo ya trae "display: flex" (misma especificidad que [hidden]{display:
   none} del navegador) - sin esto, "revisada" (origen distinto a generada_ia)
   queda visible aunque tenga el atributo hidden. Mismo patrón que
   .opcion-caja[hidden] más abajo. */
.bloque-video-seccion .campo[hidden] {
    display: none;
}

/* --- Gamificación (D059) ---------------------------------------------------- */

/* Racha de días seguidos aprendiendo. */
.racha {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    font-family: var(--fuente-display);
    font-weight: 600;
    background: var(--ambar-fondo);
    border: 1px solid var(--ambar);
    color: #9A6A15;
    border-radius: 999px;
    padding: 0.35rem 0.9rem;
}

/* Barra + leyenda de avance de una ruta o curso. */
.resumen-ruta {
    margin: 0.25rem 0 1rem;
}

.resumen-ruta .kpi-detalle {
    margin-top: 0.3rem;
}

/* Celebración al aprobar un quiz. */
.celebracion {
    text-align: center;
    background: var(--ok-fondo);
    border: 1px solid var(--ok);
    border-radius: var(--radio-tarjeta);
    padding: 1.5rem 1rem;
    margin: 1rem 0 1.5rem;
}

.celebracion__icono {
    font-size: 2.5rem;
    margin: 0;
}

.celebracion h2 {
    margin: 0.25rem 0 0.5rem;
    color: var(--ok);
}

/* Certificados como insignias. */
.insignia {
    text-align: center;
}

.insignia__icono {
    font-size: 2rem;
    margin: 0;
}

.insignia .acciones {
    justify-content: center;
    margin-top: 0.75rem;
}

details.avanzado[open] {
    border: 1px solid var(--borde);
    border-radius: var(--radio);
    padding: 0 1rem;
    background: var(--superficie);
}

/* Pasos del flujo de la Fábrica. */
.pasos {
    list-style: none;
    display: flex;
    flex-wrap: wrap;
    /* justify-content:center + tarjetas de ancho fijo (sin flex-grow): si la
       última fila queda con un solo elemento (2+1), el espacio sobrante se
       reparte a ambos lados y ese elemento queda centrado solo, sin media
       queries ni nth-child. Con las 3 tarjetas cabiendo en una fila (~900px
       de panel en adelante) el centrado casi no se nota. */
    justify-content: center;
    gap: 0.75rem;
    padding: 0;
    margin: 1rem 0 1.5rem;
}

.paso {
    /* 19.5rem en vez de 18rem: a 18rem el texto más largo ("Definir el curso
       y fabricarlo con IA") quedaba muy justo contra el número + padding y
       envolvía en fragmentos de 1-2 palabras. Sigue cabiendo holgado en una
       fila desde ~900px de panel. */
    flex: 0 1 19.5rem;
    display: flex;
    align-items: flex-start;
    gap: 0.6rem;
    background: var(--superficie);
    border: 1px solid var(--niebla);
    border-radius: var(--radio-tarjeta);
    padding: 0.75rem 1rem;
    box-shadow: var(--sombra);
    position: relative;
}

.paso__texto {
    /* reparte el texto envuelto en líneas de largo parejo en vez de dejar
       la última línea con una sola palabra suelta. */
    text-wrap: balance;
}

.paso__numero {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2rem;
    height: 2rem;
    border-radius: 50%;
    background: var(--primario);
    color: #fff;
    font-family: var(--fuente-display);
    font-weight: 700;
    flex-shrink: 0;
    /* alinea con la primera línea de texto en vez de con el bloque
       completo - con align-items:center el número quedaba a mitad de un
       texto envuelto en varias líneas cortas, partiendo palabras sueltas. */
    margin-top: 0.1rem;
}

.paso__texto a {
    color: var(--cuerpo);
    text-decoration: none;
}

.paso__texto a:hover {
    color: var(--primario);
}

/* Toda la tarjeta es clicable: el enlace se estira sobre ella. */
.paso__texto a::after {
    content: "";
    position: absolute;
    inset: 0;
    border-radius: inherit;
}

.paso__flecha {
    width: 1.1rem;
    height: 1.1rem;
    margin-left: auto;
    align-self: flex-end;
    flex-shrink: 0;
    fill: none;
    stroke: var(--tinta-tenue);
    stroke-width: 2;
    stroke-linecap: round;
    stroke-linejoin: round;
    transition: transform 0.15s, stroke 0.15s;
}

.paso:hover .paso__flecha {
    stroke: var(--primario);
    transform: translateX(3px);
}

.paso__numero svg {
    width: 1.1rem;
    height: 1.1rem;
    fill: none;
    stroke: currentColor;
    stroke-width: 2;
    stroke-linecap: round;
    stroke-linejoin: round;
}

.paso__conteo {
    margin-left: 0.25rem;
    padding: 0.05rem 0.5rem;
    border-radius: 999px;
    background: var(--papel);
    color: var(--tinta-suave);
    font-size: 0.8rem;
    font-weight: 600;
}

/* Acciones dentro de una celda de tabla. */
.celda-acciones {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.4rem;
}

.celda-acciones .boton,
.celda-acciones button {
    min-height: 38px;
    padding: 0.35rem 0.8rem;
    font-size: 0.9rem;
}

button:disabled {
    background: var(--borde);
    color: var(--tinta-suave);
    border-color: var(--borde);
    box-shadow: none;
    cursor: not-allowed;
}

/* Log de la corrida de fabricación: estilo terminal, scroll propio. */
.log-corrida {
    font-family: var(--fuente-mono);
    font-size: 0.85rem;
    line-height: 1.4;
    background: var(--pizarra);
    color: var(--texto-en-oscuro);
    border-radius: var(--radio-panel);
    padding: 1rem;
    overflow-x: auto;
    max-height: 60vh;
    overflow-y: auto;
    white-space: pre-wrap;
    word-break: break-word;
}

img, video {
    max-width: 100%;
    height: auto;
}

/* Mensajes (django.contrib.messages) */
.mensajes {
    list-style: none;
    max-width: 1100px;
    margin: 0.75rem auto 0;
    padding: 0 1rem;
}

.mensajes li {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.6rem 0.9rem;
    border-radius: var(--radio);
    margin-bottom: 0.5rem;
    background: var(--azul-palido);
    color: var(--primario-oscuro);
    opacity: 1;
    transition: opacity var(--transicion) 250ms;
}

.mensajes li svg {
    width: 18px;
    height: 18px;
    flex-shrink: 0;
}

.mensajes li.error {
    background: var(--error-fondo);
    color: var(--error);
}

.mensajes li.success {
    background: var(--ok-fondo);
    color: var(--ok);
}

.mensajes li.mensajes__oculto {
    opacity: 0;
}

/* Estado vacío: qué falta y qué hacer a continuación, en vez de una fila gris. */
.vacio {
    text-align: center;
    padding: 2.5rem 1rem;
    border: 2px dashed var(--borde);
    border-radius: var(--radio-tarjeta);
    color: var(--tinta-suave);
    background: var(--superficie);
}

.vacio .boton {
    margin-top: 0.75rem;
}

.vacio svg {
    width: 40px;
    height: 40px;
    margin-bottom: 0.5rem;
    color: var(--borde);
}

/* Chip de cita de fuente - elemento firma del sistema visual (§6.2). Puede
   ser <span> (sin enlace) o <a> (con cita_url, RF-XX): mismo aspecto en
   ambos casos, sin el subrayado por defecto del link. */
.chip-cita {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    font-family: var(--fuente-mono);
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--primario-oscuro);
    background: var(--azul-palido);
    border: 1px solid var(--azul-palido-borde);
    border-radius: 999px;
    padding: 0.2rem 0.75rem;
    margin: 0.25rem 0.35rem 0.25rem 0;
    text-decoration: none;
}

a.chip-cita:hover {
    background: var(--azul-palido-borde);
    color: var(--primario-oscuro);
}

.chip-cita::before {
    content: "⌖";
    color: var(--primario);
}

/* --- Página de sección de curso (lectura) ----------------------------------- */

.seccion-cabecera {
    margin-bottom: 1.25rem;
}

.seccion-cabecera__fila {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
}

/* Botón de lectura en voz alta: flotante en la esquina superior derecha de
   la propia tarjeta de contenido (.contenido-seccion abajo lleva
   position:relative para anclarlo). */
.podcast {
    position: absolute;
    top: 0;
    right: 0;
    pointer-events: none;
}

.podcast__boton,
.podcast__opciones {
    pointer-events: auto;
}

.podcast__boton {
    position: relative;
    z-index: -1;
    min-width: 44px;
    min-height: 44px;
    width: 44px;
    height: 44px;
    padding: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: none;
    color: var(--primario);
    border: none;
    border-radius: 0 var(--radio-tarjeta) 0 0;
    box-shadow: none;
    cursor: pointer;
    transition: background var(--transicion) 120ms, color var(--transicion) 120ms;
}

html[data-tema="oscuro"] .podcast__boton {
    background: var(--azul-palido);
}

.podcast__boton:hover {
    background: var(--azul-palido-borde);
    color: var(--primario-oscuro);
}

.podcast__boton[aria-expanded="true"] {
    background: var(--primario);
    color: #fff;
    border-color: var(--primario);
}

.podcast__icono {
    width: 20px;
    height: 20px;
}

/* Panel de opciones de lectura: se abre/cierra al clic sobre el engranaje
   (navbar.js, mismo patrón que los menús de cuenta/ajustes del header). */
.podcast__opciones {
    position: absolute;
    top: calc(100% + 0.4rem);
    right: 0;
    z-index: 20;
    width: 14rem;
    background: var(--superficie);
    border: 1px solid var(--niebla);
    border-radius: var(--radio-tarjeta);
    box-shadow: var(--sombra-hover);
    padding: 0.6rem 0.7rem;
    text-align: center;
}

.podcast__opciones .menu-ajustes__etiqueta {
    text-align: center;
    margin: 0.2rem 0 0.4rem;
}

.podcast__accion {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    width: 100%;
    min-height: 38px;
    margin: 0 0 0.2rem;
    padding: 0 0.4rem;
    background: none;
    border: none;
    box-shadow: none;
    border-radius: var(--radio);
    color: var(--tinta-suave);
    font-family: var(--fuente-texto);
    font-weight: 600;
    font-size: 0.88rem;
    text-align: left;
    cursor: pointer;
    transition: background var(--transicion) 120ms, color var(--transicion) 120ms;
}

.podcast__accion:hover {
    background: var(--papel);
    color: var(--tinta);
}

.podcast__accion[aria-pressed="true"] {
    background: var(--azul-palido);
    color: var(--primario-oscuro);
}

.podcast__accion-icono {
    flex: none;
    width: 1.1rem;
    height: 1.1rem;
}

.podcast__velocidad-actual {
    margin: 0 0 0.5rem;
    font-family: var(--fuente-display);
    font-size: 1.3rem;
    font-weight: 700;
    color: var(--tinta);
}

.podcast__slider-fila {
    display: flex;
    align-items: center;
    gap: 0.45rem;
    margin-bottom: 0.55rem;
}

.podcast__paso {
    flex: none;
    min-width: 24px;
    min-height: 24px;
    width: 24px;
    height: 24px;
    padding: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: var(--papel);
    color: var(--tinta-suave);
    font-family: var(--fuente-display);
    font-weight: 700;
    font-size: 0.85rem;
    border: 1px solid var(--borde);
    border-radius: 999px;
    box-shadow: none;
    cursor: pointer;
    transition: background var(--transicion) 120ms, color var(--transicion) 120ms;
}

.podcast__paso:hover {
    background: var(--azul-palido);
    color: var(--primario-oscuro);
}

.podcast__opciones input[type="range"] {
    flex: 1;
    min-height: 0;
    width: auto;
    max-width: none;
    height: 2px;
    padding: 0;
    accent-color: var(--primario);
}

.podcast__velocidades {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 0.3rem;
}

.podcast__velocidad-boton {
    min-width: 0;
    min-height: 26px;
    padding: 0.2rem 0.55rem;
    background: var(--papel);
    color: var(--tinta-suave);
    font-family: var(--fuente-texto);
    font-size: 0.75rem;
    font-weight: 600;
    border: 1px solid var(--borde);
    border-radius: 999px;
    box-shadow: none;
    cursor: pointer;
    transition: background var(--transicion) 120ms, color var(--transicion) 120ms, border-color var(--transicion) 120ms;
}

.podcast__velocidad-boton:hover {
    background: var(--azul-palido);
    color: var(--primario-oscuro);
    border-color: var(--azul-palido-borde);
}

.podcast__velocidad-boton--activo,
.podcast__velocidad-boton--activo:hover {
    background: var(--primario);
    color: #fff;
    border-color: var(--primario);
}

/* Fila de avance: cifra a la izquierda, barra angosta al centro, módulo
   actual a la derecha - todo en la misma línea desde tablet en adelante. */
.seccion-progreso {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    flex: 1;
    max-width: 20rem;
}

.seccion-progreso__cifra,
.seccion-progreso__modulo {
    font-family: var(--fuente-mono);
    font-size: 0.8rem;
    line-height: 1;
    color: var(--tinta-suave);
    white-space: nowrap;
}

.barra-avance.barra-avance--seccion {
    flex: 1;
    height: 2px;
}

/* Cuerpo de la sección: tipografía de lectura más generosa que la del resto
   de la app (tarjetas de listado, formularios) porque acá el texto es el
   producto, no un dato de apoyo.
   Selector compuesto ".tarjeta.contenido-seccion" a propósito: en el markup
   real esta clase vive junto con ".tarjeta" en el mismo elemento, y
   ".tarjeta { padding: 1rem }" tiene la MISMA especificidad (0,1,0) - sin el
   compuesto (0,2,0), .tarjeta gana por venir después en el archivo y este
   padding queda muerto en la práctica (bug real: el video de la sección,
   calculado para escapar exactamente este padding, se salía de la página
   entera en viewports angostos porque compensaba un padding que nunca se
   aplicó). El padding-right extra reserva espacio para el ícono flotante de
   .podcast (position:absolute, arriba a la derecha). */
.tarjeta.contenido-seccion {
    position: relative;
    z-index: 0;
    font-size: 1.05rem;
    line-height: 1.7;
    padding: 3rem;
    padding-right: 5.5rem;
}

/* Ragged-right, no justify: sin hyphenation nativo el justify deja "ríos" de
   espacio irregulares entre palabras, sobre todo en párrafos largos a 72ch. */
.contenido-seccion p {
    text-align: left;
    margin: 1.5rem;
}

.contenido-seccion > :first-child:not(h1) {
    margin-top: 0;
}

/* #texto-seccion (lectura sincronizada, RF-16+) envuelve el cuerpo para que
   el JS pueda resaltar cues sin tocar el markdown - el selector de arriba ya
   no alcanza al párrafo real un nivel más adentro, así que se repite acá. */
.contenido-seccion #texto-seccion > :first-child:not(h1) {
    margin-top: 0;
}

.contenido-seccion h1 {
    margin: 1rem 1.5rem 1.5rem;
}

.contenido-seccion h2,
.contenido-seccion h3 {
    margin-top: 1.75rem;
}

.citas {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.15rem 0;
    margin: 1.25rem 0;
}

.citas__etiqueta {
    font-family: var(--fuente-mono);
    font-size: 0.75rem;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--tinta-tenue);
    margin-right: 0.6rem;
}

.seccion-acciones {
    margin-top: 1.75rem;
}

/* Media en secciones (RF-16): responsiva, el texto siempre carga primero. */
.contenido-seccion img {
    max-width: 100%;
    height: auto;
    display: block;
    border-radius: var(--radio);
    margin: 1rem 0 0.25rem;
}

.video-seccion {
    margin: 1.25rem 0;
}

/* Video antes del cuerpo, dentro de la misma tarjeta (D089): rompe el
   padding de .contenido-seccion (3rem / 5.5rem a la derecha) para que el
   video quede a todo el ancho, igual que cuando vivía afuera de la tarjeta. */
.contenido-seccion > .video-seccion {
    margin-left: -3rem;
    margin-right: -5.5rem;
    width: calc(100% + 3rem + 5.5rem);
}

.video-seccion video {
    width: 100%;
    max-height: 70vh;
    border-radius: var(--radio);
    background: var(--pizarra);
    /* Borde sutil: sin él, un video oscuro se funde con la tarjeta oscura y
       flota sin borde definido (evidente sobre todo en modo oscuro). */
    border: 1px solid var(--niebla);
}

.video-embed {
    aspect-ratio: 16 / 9;
    width: 100%;
}

/* Lectura sincronizada tipo karaoke (RF-16+): resalta en el cuerpo la frase
   que se está hablando en ese instante del video, usando los mismos cues del
   .vtt que ya alimenta el <track> nativo - ver seccion.html. Solo un cambio
   de fondo/color, sin mover texto, para no generar saltos de layout en cada
   cambio de cue. */
.lectura-sincronizada__cue {
    border-radius: 0.2em;
    transition: background-color 0.15s ease, color 0.15s ease;
}

.lectura-sincronizada__cue--activo {
    background: color-mix(in srgb, var(--primario) 20%, transparent);
}

.video-embed iframe {
    width: 100%;
    height: 100%;
    border: 0;
    border-radius: var(--radio);
}

/* Etiqueta de media generada por IA (§6.2): visible y discreta. */
.etiqueta-ia {
    display: block;
    font-family: var(--fuente-mono);
    font-size: 0.75rem;
    color: var(--primario);
    margin: 0.15rem 0 0.75rem;
}

/* Tutor IA (RF-33): chat simple server-rendered. */
.tutor-disclaimer {
    font-size: 0.9rem;
    background: var(--azul-palido);
    border-left: 3px solid var(--primario);
    padding: 0.6rem 0.9rem;
    border-radius: 0 var(--radio) var(--radio) 0;
}

.tutor-conversacion {
    margin: 1rem 0;
}

.tutor-turno {
    max-width: 44rem;
    padding: 0.6rem 0.9rem;
    border-radius: var(--radio-tarjeta);
    margin: 0.5rem 0;
}

.tutor-turno--pregunta {
    background: var(--azul-palido);
    margin-left: 2rem;
}

.tutor-turno--respuesta {
    display: flex;
    align-items: flex-start;
    gap: 0.5rem;
    background: var(--superficie);
    border: 1px solid var(--niebla);
    margin-right: 2rem;
}

.tutor-turno__texto {
    flex: 1;
}

.tutor-turno--respuesta {
    flex-wrap: wrap;
}

.tutor-turno__fuentes {
    flex-basis: 100%;
    margin: 0.25rem 0 0;
    font-size: 0.85rem;
    color: var(--tinta-suave);
}

.tutor-turno__escuchar {
    flex: none;
    width: 28px;
    height: 28px;
    padding: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: none;
    color: var(--tinta-suave);
    border: none;
    box-shadow: none;
    border-radius: var(--radio);
    cursor: pointer;
    transition: background var(--transicion) 120ms, color var(--transicion) 120ms;
}

.tutor-turno__escuchar:hover {
    background: var(--papel);
    color: var(--tinta);
}

.tutor-turno__escuchar[aria-pressed="true"] {
    background: var(--azul-palido);
    color: var(--primario-oscuro);
}

.tutor-turno__escuchar svg {
    width: 1rem;
    height: 1rem;
}

.tutor-form textarea {
    width: 100%;
    padding: 0.6rem;
    border: 1px solid var(--borde);
    border-radius: var(--radio);
    font: inherit;
}

.tutor-cuota,
.tutor-vacio {
    font-family: var(--fuente-mono);
    font-size: 0.8rem;
    color: var(--tinta-suave);
}

/* Barra de avance tipo indicador de nivel. */
.barra-avance {
    width: 100%;
    height: 10px;
    background: var(--niebla);
    border-radius: 999px;
    overflow: hidden;
}

.barra-avance__relleno {
    height: 100%;
    background: var(--primario);
}

.tarjeta {
    background: var(--superficie);
    border: 1px solid var(--niebla);
    border-radius: var(--radio-tarjeta);
    padding: 1rem;
    margin-bottom: 1rem;
    box-shadow: var(--sombra);
    transition: box-shadow var(--transicion) 200ms, transform var(--transicion) 200ms;
}

/* --- Mi perfil: cabecera con avatar y edición de nombre in-place --------- */
.perfil-cabecera {
    display: flex;
    align-items: flex-start;
    gap: 1.1rem;
}

.avatar {
    flex: none;
    width: 3.4rem;
    height: 3.4rem;
    border-radius: 999px;
    background: linear-gradient(155deg, var(--primario), var(--primario-oscuro));
    color: #fff;
    display: flex;
    align-items: center;
    justify-content: center;
    font-family: var(--fuente-display);
    font-weight: 700;
    font-size: 1.25rem;
    box-shadow: var(--sombra-boton);
}

/* Versión miniatura del avatar: junto al nombre en el disparador del navbar. */
.avatar--mini {
    width: 1.65rem;
    height: 1.65rem;
    font-size: 0.7rem;
    box-shadow: none;
}

.perfil-cabecera__cuerpo {
    flex: 1;
    min-width: 0;
}

.perfil-nombre-fila {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.5rem 0.75rem;
    margin-bottom: 0.4rem;
}

.perfil-nombre-fila h1 {
    margin: 0;
    font-size: 1.5rem;
    border-radius: 0.4rem;
    padding: 0.1rem 0.35rem;
    margin-left: -0.35rem;
    outline: none;
    transition: background var(--transicion) 150ms, box-shadow var(--transicion) 150ms;
}

/* Estado editable: el propio h1 se vuelve el campo de texto - sin
   formulario aparte debajo (D - feedback de producto: editar en el lugar). */
.perfil-nombre-fila h1[contenteditable="true"] {
    background: var(--azul-palido);
    box-shadow: 0 0 0 2px var(--azul-palido-borde);
    cursor: text;
}

.perfil-nombre-fila h1[contenteditable="true"]:focus-visible {
    box-shadow: 0 0 0 3px var(--foco);
}

.btn-editar {
    appearance: none;
    border: none;
    background: none;
    box-shadow: none;
    min-width: 0;
    min-height: 0;
    color: var(--tinta-suave);
    font-family: inherit;
    font-size: 0.82rem;
    font-weight: 600;
    cursor: pointer;
    padding: 0.25rem 0.5rem;
    border-radius: 999px;
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    transition: background var(--transicion) 150ms, color var(--transicion) 150ms, opacity var(--transicion) 150ms;
}

.btn-editar:hover {
    background: var(--azul-palido);
    color: var(--primario-oscuro);
}

.btn-editar svg {
    width: 0.85rem;
    height: 0.85rem;
}

/* Mientras se edita, el lápiz se retira: la salida es Enter o clic afuera. */
.perfil-nombre-fila.editando .btn-editar {
    opacity: 0;
    pointer-events: none;
}

.nombre-estado {
    font-size: 0.78rem;
    color: var(--tinta-tenue);
    opacity: 0;
    transition: opacity var(--transicion) 150ms;
}

.nombre-estado.visible {
    opacity: 1;
}

.perfil-correo {
    margin: 0 0 0.6rem;
    color: var(--tinta-suave);
}

.perfil-empresa {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.4rem 0.6rem;
    margin: 0.75rem 0 0;
    padding-top: 0.75rem;
    border-top: 1px solid var(--niebla);
    font-size: 0.88rem;
    color: var(--tinta-suave);
}

.perfil-empresa svg {
    width: 0.95rem;
    height: 0.95rem;
    flex: none;
    color: var(--tinta-tenue);
}

.perfil-empresa strong {
    color: var(--tinta);
    font-weight: 600;
}

.perfil-empresa .sep {
    color: var(--tinta-tenue);
}

.perfil-empresa--vacia {
    font-style: italic;
    color: var(--tinta-tenue);
}

.metrica--progreso {
    text-align: left;
}

.metrica--progreso .barra-avance {
    margin-top: 0.5rem;
}

.metrica--racha .kpi-cifra {
    color: var(--ambar);
}

a.tarjeta {
    display: block;
    text-decoration: none;
    color: inherit;
}

a.tarjeta:hover {
    border-color: var(--primario);
    box-shadow: var(--sombra-hover);
    transform: translateY(-2px);
}

.tarjeta h3 {
    margin-top: 0.25rem;
}

/* Tarjeta de acción con ícono grande a la izquierda del texto (ej. hub de
   Gestión) - a diferencia de las tarjetas de curso, el ícono no va arriba
   sino al costado, así lee como un enlace destacado y no como contenido.
   Selector con `.tarjeta` repetido a propósito: por especificidad, si no,
   pierde contra `a.tarjeta { display: block }` de más arriba. */
.tarjeta.tarjeta--accion {
    display: flex;
    align-items: center;
    gap: 0.9rem;
}

/* Tarjeta angosta centrada (recuperar clave, confirmaciones). */
.tarjeta--angosta {
    max-width: 26rem;
    margin: 2rem auto;
    padding: 1.5rem;
}

/* Login en dos columnas: imagen de marca a un lado, formulario al otro
   (mismo formato que el login de Poseidón). En móvil la imagen se oculta y
   solo queda el formulario. */
.ingreso {
    display: flex;
    max-width: 860px;
    margin: 2rem auto;
    background: var(--superficie);
    border: 1px solid var(--niebla);
    border-radius: var(--radio-tarjeta);
    box-shadow: var(--sombra);
    overflow: hidden;
}

.ingreso__imagen {
    flex: 1 1 45%;
    min-height: 480px;
    background: linear-gradient(135deg, var(--primario), var(--primario-oscuro));
    background-size: cover;
    background-position: center;
}

.ingreso__panel {
    flex: 1 1 55%;
    padding: 2.5rem 2rem;
}

.ingreso__panel h1 {
    margin-top: 0;
}

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

.boton--bloque {
    width: 100%;
}

.tarjeta-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--gap-default, 18px);
}

@media (min-width: 641px) {
    .tarjeta-grid {
        grid-template-columns: repeat(2, 1fr);
    }
}

@media (min-width: 1025px) {
    .tarjeta-grid {
        grid-template-columns: repeat(3, 1fr);
    }
}

/* Elegir entre pocas opciones grandes (ej. Contenido/Quiz en la revisión
   experta): siempre 2 columnas, nunca 3 aunque haya espacio de sobra. */
.tarjeta-grid--decision {
    max-width: 40rem;
}

@media (min-width: 1025px) {
    .tarjeta-grid--decision {
        grid-template-columns: repeat(2, 1fr);
    }
}

.tarjeta-grid--decision .tarjeta {
    padding: 1.75rem;
    text-align: center;
}

.tarjeta-grid--decision h3 {
    font-size: 1.3rem;
}

.etiqueta-estado {
    display: inline-block;
    font-family: var(--fuente-mono);
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.03em;
    text-transform: uppercase;
    padding: 0.2rem 0.65rem;
    border-radius: 999px;
    background: var(--niebla);
    color: var(--tinta-suave);
}

.etiqueta-estado--ok {
    background: var(--ok-fondo);
    color: var(--ok);
}

.etiqueta-estado--ambar {
    background: var(--ambar-fondo);
    color: #9A6A15;
}

.etiqueta-estado--error {
    background: var(--error-fondo);
    color: var(--error);
}

.etiqueta-estado--acento {
    background: var(--azul-palido);
    color: var(--primario-oscuro);
}

/* Ruta "a medida" de una empresa (vista previa admin, D081): morado de rol
   Academia, no ámbar - el ámbar de esta pantalla queda reservado para
   alertas reales (Sin ruta, Borrador); una ruta personalizada no es una. */
.etiqueta-estado--academia {
    background: var(--rol-academia-fondo);
    color: var(--rol-academia);
}

/* Separador vertical inline entre elementos cortos en una misma línea (ej.
   etiqueta de estado + link de acción) que si no quedan pegados. */
.separador-vertical {
    display: inline-block;
    width: 1px;
    height: 0.9em;
    background: var(--borde);
    vertical-align: middle;
    margin: 0 0.3rem;
}

/* Separador horizontal entre bloques de una página (ej. el aviso de vista
   previa y el contenido de abajo), cuando el espaciado normal entre
   elementos no alcanza para distinguirlos. */
.divisor {
    height: 1px;
    background: var(--niebla);
    margin: 1.1rem 0;
    border: none;
}

/* --- Dashboard "Mi ruta" (alumno) ------------------------------------------- */

/* Card de "continuar/empezar curso": la única acción primaria de la
   página, así que se distingue del resto de tarjetas con un borde acento. */
.tarjeta-continuar {
    border-color: var(--primario);
    margin-bottom: 1.25rem;
}

.etiqueta-mini {
    display: block;
    font-family: var(--fuente-mono);
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.03em;
    text-transform: uppercase;
    color: var(--primario);
    margin-bottom: 0.25rem;
}

.tarjeta-continuar .boton {
    margin-top: 0.75rem;
}

/* Resumen de rutas asignadas: da de vuelta la identidad de "ruta" a la
   página (el catálogo de abajo aplana los cursos de todas las rutas en una
   sola grilla). Lista compacta, no tarjetas - es contexto de apoyo, no la
   acción principal de la página (esa es .tarjeta-continuar). */
.rutas-resumen {
    margin-bottom: 1.5rem;
}

/* Eyebrow, no un título de sección: es un resumen sobre las secciones reales
   de abajo ("Ruta demo", etc.) - si tuviera el mismo tamaño que esos <h2>,
   se leería como una sección más y no como su resumen. */
.rutas-resumen__titulo {
    font-family: var(--fuente-mono);
    font-size: 0.75rem;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--tinta-suave);
    margin: 0 0 0.6rem;
    margin-top: 0;
}

.rutas-resumen__lista {
    list-style: none;
    margin: 0;
    padding: 0;
    background: var(--superficie);
    border: 1px solid var(--niebla);
    border-radius: var(--radio-tarjeta);
    box-shadow: var(--sombra);
}

.rutas-resumen__item {
    padding: 0.75rem 1.1rem;
}

.rutas-resumen__item + .rutas-resumen__item {
    border-top: 1px solid var(--niebla);
}

.rutas-resumen__cabecera {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 0.75rem;
    margin-bottom: 0.4rem;
}

.rutas-resumen__nombre {
    font-weight: 600;
    color: var(--tinta);
}

/* --- Vista previa de AdminAcademia (D058/D081): tarjetas de ruta y de
   curso con un círculo por curso/sección en vez de un listado plano. Clases
   propias (no .tarjeta-curso del dashboard del alumno) porque acá conviven
   estados que el alumno nunca ve (borrador, sin ruta). --------------------- */

/* Cifra junto al título de cada sección (Sin ruta / Rutas activas / Cursos
   asignados): reemplaza a los antiguos tiles de KPI sueltos arriba de la
   página - el número vive pegado a lo que cuenta. La variante --alerta
   (mismo ámbar que .etiqueta-estado--ambar) es solo para "Sin ruta": es la
   única cifra accionable, las otras dos son conteo informativo. */
.contador-seccion {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 1.6rem;
    height: 1.6rem;
    padding: 0 0.4rem;
    margin-left: 0.4rem;
    border-radius: 999px;
    background: var(--niebla);
    color: var(--tinta-suave);
    font-family: var(--fuente-mono);
    font-size: 0.85rem;
    font-weight: 700;
    vertical-align: middle;
}

.contador-seccion--alerta {
    background: var(--ambar-fondo);
    color: #9A6A15;
}

/* Título de sección + buscador alineado a la derecha (Sin ruta / Rutas
   activas / Cursos asignados) - filtro en vivo por JS, ver buscador_secciones.js. */
.bloque-cabecera {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem 1rem;
    margin-bottom: 0.9rem;
}

/* Sin este reset, el margin-top:2rem del h2 global infla la caja de margen
   del título por sobre la del buscador y el align-items:center del flex
   los centra en ejes distintos - quedan descalzados verticalmente. */
.bloque-cabecera h2 {
    margin: 0;
}

.buscador-envoltorio {
    position: relative;
    display: inline-flex;
    align-items: center;
}

.buscador-envoltorio__icono {
    position: absolute;
    left: 0.75rem;
    width: 1rem;
    height: 1rem;
    color: var(--tinta-tenue);
    pointer-events: none;
}

.buscador-seccion {
    min-height: 38px;
    width: auto;
    max-width: 16rem;
    padding: 0.4rem 0.75rem 0.4rem 2.2rem;
    font-size: 0.9rem;
    border: 1px solid var(--borde);
    border-radius: 999px;
    background: var(--superficie);
    color: var(--tinta);
}

/* Cards más allá de las primeras 3: el buscador las revela quitando este
   display:none inline (ver buscador_secciones.js) - CSS puro, sin recortar
   el DOM, para que buscar alcance también lo que el cupo esconde. */
.tarjeta-oculta-por-limite {
    display: none;
}

/* Grilla de las 3 secciones de /my-path: 4 columnas en vez de las 3 genéricas
   de .tarjeta-grid - el cupo visible siempre es como máximo 3 cards reales
   + la tarjeta "+", así nunca sobra una sola en una fila nueva. */
@media (min-width: 1025px) {
    .tarjeta-grid.tarjeta-grid--catalogo-admin {
        grid-template-columns: repeat(4, 1fr);
    }
}

/* Tarjeta "+": mismo tamaño que las de curso/ruta para no romper la grilla,
   pero con borde punteado - es una salida hacia /management/, no contenido.
   Selector "a.tarjeta.tarjeta-mas" a propósito: "a.tarjeta { display:
   block }" (más arriba) es tipo+clase (0,1,1) y le gana a ".tarjeta-mas"
   sola (0,1,0) sin importar el orden - con las dos clases empatamos y
   ganamos por venir después. */
a.tarjeta.tarjeta-mas {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.3rem;
    text-align: center;
    border-style: dashed;
    color: var(--tinta-suave);
}

.tarjeta-mas:hover {
    color: var(--primario);
}

.tarjeta-mas__simbolo {
    font-family: var(--fuente-mono);
    font-size: 2.4rem;
    line-height: 1;
    font-weight: 700;
}

.tarjeta-mas__texto {
    font-size: 0.85rem;
    font-weight: 600;
}

.tarjeta-ruta-admin__cabecera {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 0.4rem;
    margin-bottom: 0.7rem;
}

.tarjeta-ruta-admin__cabecera h3 {
    margin: 0;
    font-size: 1.02rem;
}

.fila-circulos {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
    margin-bottom: 0.6rem;
}

.circulo-curso {
    width: 1.6rem;
    height: 1.6rem;
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-family: var(--fuente-mono);
    font-size: 0.65rem;
    font-weight: 700;
    text-decoration: none;
    border: 2px solid var(--ok);
    color: var(--ok);
    background: var(--ok-fondo);
}

a.circulo-curso:hover {
    background: var(--ok);
    color: #fff;
}

.circulo-curso--borrador {
    border-style: dashed;
    border-color: var(--tinta-tenue);
    color: var(--tinta-tenue);
    background: transparent;
    cursor: default;
}

.tarjeta-ruta-admin__pie {
    padding-top: 0.7rem;
    margin-bottom: 0.5rem;
    border-top: 1px solid var(--niebla);
}

.tarjeta-curso-admin__conteo {
    display: block;
    font-family: var(--fuente-mono);
    font-size: 0.75rem;
    color: var(--tinta-tenue);
    margin-top: 0.35rem;
}

.tarjeta-curso-admin__eje {
    font-family: var(--fuente-mono);
    font-size: 0.72rem;
    letter-spacing: 0.03em;
    text-transform: uppercase;
    color: var(--tinta-tenue);
    margin: 0 0 0.25rem;
}

/* Sin esto el h3 cae al tamaño por defecto del navegador (~1.17rem) en vez
   del 1.02rem que ya usa .tarjeta-ruta-admin__cabecera h3 - mismo tamaño en
   las tres secciones de /my-path. */
.tarjeta-curso-admin h3 {
    margin: 0;
    font-size: 1.02rem;
}

.tarjeta-curso-admin__sectores {
    display: flex;
    flex-wrap: wrap;
    gap: 0.3rem;
    margin: 0.55rem 0 0.15rem;
}

.chip-sector {
    font-family: var(--fuente-mono);
    font-size: 0.68rem;
    font-weight: 700;
    color: var(--tinta-suave);
    background: var(--papel);
    border: 1px solid var(--borde);
    border-radius: 999px;
    padding: 0.1rem 0.5rem;
}

.fila-circulos--modulo {
    margin-top: 0.7rem;
    margin-bottom: 0;
}

.circulo-modulo {
    width: 0.75rem;
    height: 0.75rem;
    border-radius: 50%;
    background: var(--primario);
    opacity: 0.8;
}

.tarjeta-curso-admin .etiqueta-estado {
    margin-top: 0.6rem;
    margin-right: 0.3rem;
}

.tarjeta-curso-admin--borrador {
    cursor: default;
}

.tarjeta-curso-admin--sin-ruta {
    border-color: var(--ambar);
}

.tooltip-info:hover .tooltip-info__globo,
.tooltip-info:focus-within .tooltip-info__globo {
    display: block;
}

/* Card de acción con ícono grande: un link a otra sección que se quiere
   destacar más que un simple <a> de texto (ej. "Gestión de rutas" desde la
   vista previa de AdminAcademia). */
.tarjeta-enlace {
    display: flex;
    align-items: center;
    gap: 0.9rem;
    background: var(--superficie);
    border: 1px solid var(--niebla);
    border-radius: var(--radio-tarjeta);
    padding: 0.9rem 1.1rem;
    margin-bottom: 1.5rem;
    text-decoration: none;
    color: inherit;
    transition: box-shadow var(--transicion) 200ms, transform var(--transicion) 200ms, border-color var(--transicion) 200ms;
}

.tarjeta-enlace:hover {
    border-color: var(--primario);
    box-shadow: var(--sombra-hover);
    transform: translateY(-2px);
}

.tarjeta-enlace + .tarjeta-enlace {
    margin-top: -1rem;
}

.tarjeta-enlace__icono {
    flex-shrink: 0;
    width: 44px;
    height: 44px;
    border-radius: var(--radio);
    background: var(--rol-academia-fondo);
    color: var(--rol-academia);
    display: flex;
    align-items: center;
    justify-content: center;
}

.tarjeta-enlace__icono svg {
    width: 24px;
    height: 24px;
}

.tarjeta-enlace__texto {
    flex: 1;
    min-width: 0;
}

.tarjeta-enlace__texto strong {
    display: block;
    color: var(--tinta);
    font-size: 0.98rem;
    margin-bottom: 0.15rem;
}

.tarjeta-enlace__texto span {
    display: block;
    font-size: 0.85rem;
    color: var(--tinta-suave);
}

.tarjeta-enlace__flecha {
    flex-shrink: 0;
    width: 18px;
    height: 18px;
    color: var(--tinta-tenue);
}

/* Panel explicador plegable (D058, vista previa de AdminAcademia): resume la
   relación Ruta ↔ Curso para quien todavía no la tiene clara. Es un <details>
   nativo - sin JS, en línea con R7. */
.explicador {
    background: var(--azul-palido);
    border: 1px solid var(--azul-palido-borde);
    border-radius: var(--radio-tarjeta);
    margin-bottom: 1.5rem;
    overflow: hidden;
}

.explicador summary {
    list-style: none;
    cursor: pointer;
    padding: 0.85rem 1.1rem;
    display: flex;
    align-items: center;
    gap: 0.6rem;
    font-weight: 700;
    color: var(--primario-oscuro);
}

.explicador summary::-webkit-details-marker {
    display: none;
}

.explicador summary::before {
    content: "";
    width: 8px;
    height: 8px;
    border-right: 2px solid currentColor;
    border-bottom: 2px solid currentColor;
    transform: rotate(-45deg);
    transition: transform var(--transicion) 150ms;
    flex-shrink: 0;
}

.explicador[open] summary::before {
    transform: rotate(45deg);
}

.explicador__cuerpo {
    padding: 0 1.1rem 1.1rem;
    border-top: 1px solid var(--azul-palido-borde);
    padding-top: 0.9rem;
}

.explicador__cuerpo p {
    margin: 0 0 0.85rem;
    color: var(--cuerpo);
    font-size: 0.9rem;
}

/* Opciones independientes dentro de un explicador (ej. hub de Gestión): a
   diferencia de los chevrones, no hay progresión entre ellas, así que van en
   tarjetas planas sin forma de flecha ni numeración. */
.explicador__opciones {
    display: grid;
    grid-template-columns: 1fr;
    gap: 0.9rem;
    margin: 0 0 0.9rem;
}

@media (min-width: 641px) {
    .explicador__opciones {
        grid-template-columns: repeat(3, 1fr);
    }
}

.explicador__opcion {
    background: var(--superficie);
    border: 1px solid var(--niebla);
    border-radius: var(--radio);
    padding: 0.85rem 1rem;
}

.explicador__lista {
    margin: 0;
    padding-left: 1.1rem;
    font-size: 0.76rem;
    line-height: 1.5;
    color: var(--cuerpo);
}

.explicador__lista li + li {
    margin-top: 0.3rem;
}

/* Flujo de 4 pasos en "chevrons" (flechas encadenadas). Progresión tonal propia
   (tinte de --primario, no arcoíris) para leerse como un único proceso que
   avanza hacia el paso 4. En pantallas angostas pierde el recorte en punta
   (clip-path no lee bien apilado) y se vuelve una lista vertical de tarjetas. */
.explicador__chevrones {
    display: flex;
    margin: 0 0 0.9rem;
}

.explicador__chevron {
    flex: 1;
    min-width: 0;
    position: relative;
    display: flex;
    flex-direction: row;
    align-items: flex-start;
    justify-content: flex-start;
    gap: 0.5rem;
    padding: 0.85rem 2.6rem 0.85rem 2.3rem;
    margin-left: -8px;
    clip-path: polygon(0 0, 90% 0, 100% 50%, 90% 100%, 0 100%, 9% 50%);
}

.explicador__chevron:first-child {
    margin-left: 0;
    clip-path: polygon(0 0, 90% 0, 100% 50%, 90% 100%, 0 100%);
    padding-left: 1.1rem;
}

.explicador__chevron--2 {
    margin-left: -4px;
}

.explicador__chevron:last-child {
    padding-right: 2.6rem;
}

.explicador__chevron-numero {
    font-family: var(--fuente-mono);
    font-size: 1.1rem;
    font-weight: 700;
    line-height: 1.3;
    flex-shrink: 0;
}

.explicador__chevron-contenido {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    min-width: 0;
}

.explicador__chevron-titulo {
    display: block;
    margin-bottom: 0.2rem;
    font-size: 0.85rem;
    font-weight: 700;
}

.explicador__chevron-desc {
    display: block;
    font-size: 0.76rem;
    line-height: 1.4;
}

.explicador__icono-editar {
    width: 0.85em;
    height: 0.85em;
    vertical-align: -0.1em;
}

.explicador__chevron--1 {
    background: var(--superficie);
}

.explicador__chevron--2 {
    background: var(--azul-palido-borde);
}

.explicador__chevron--1 .explicador__chevron-numero,
.explicador__chevron--1 .explicador__chevron-titulo,
.explicador__chevron--2 .explicador__chevron-numero,
.explicador__chevron--2 .explicador__chevron-titulo {
    color: var(--primario-oscuro);
}

.explicador__chevron--1 .explicador__chevron-desc,
.explicador__chevron--2 .explicador__chevron-desc {
    color: var(--tinta-suave);
}

.explicador__chevron--3 {
    background: #A9CCFB;
}

.explicador__chevron--3 .explicador__chevron-numero,
.explicador__chevron--3 .explicador__chevron-titulo {
    color: #0A3E8F;
}

/* .explicador__lista repite el rol de .explicador__chevron-desc (texto
   secundario del chevron) cuando el detalle no cabe en una sola línea - el
   fondo de --3/--4 es fijo en ambos temas, así que su texto también debe
   serlo: sin esto hereda var(--cuerpo), que en oscuro es gris claro e
   ilegible sobre este celeste fijo. */
.explicador__chevron--3 .explicador__chevron-desc,
.explicador__chevron--3 .explicador__lista {
    color: #1E3A5F;
}

.explicador__chevron--4 {
    background: var(--primario);
}

.explicador__chevron--4 .explicador__chevron-numero,
.explicador__chevron--4 .explicador__chevron-titulo {
    color: #fff;
}

.explicador__chevron--4 .explicador__chevron-desc,
.explicador__chevron--4 .explicador__lista {
    color: rgba(255, 255, 255, 0.85);
}

@media (max-width: 640px) {
    .explicador__chevrones {
        flex-direction: column;
        gap: 0.5rem;
    }

    .explicador__chevron,
    .explicador__chevron:first-child,
    .explicador__chevron:last-child,
    .explicador__chevron--2 {
        clip-path: none;
        margin-left: 0;
        padding: 0.75rem 1rem;
        border-radius: var(--radio);
    }
}

/* Fila de métricas rápidas (4 cards). */
.fila-metricas {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
    gap: 0.75rem;
    margin-bottom: 1.5rem;
}

.metrica {
    margin-bottom: 0;
}

.metrica__etiqueta {
    font-size: 0.8rem;
    color: var(--tinta-suave);
    margin: 0;
}

/* Aviso "BORRADOR - pendiente de revisión legal" (RF-39). */
.aviso-borrador {
    display: inline-block;
    background: var(--ambar-fondo);
    color: var(--ambar);
    border: 1px solid var(--ambar);
    border-radius: var(--radio);
    padding: 0.5rem 0.75rem;
    font-weight: 600;
}

/* Panel Empresa (RF-24): cifras destacadas y tabla comparativa por planta. */
.kpi-cifra {
    font-family: var(--fuente-mono);
    font-weight: 700;
    font-size: 2rem;
    color: var(--tinta);
    margin: 0.25rem 0;
}

.kpi-detalle {
    font-size: 0.85rem;
    color: var(--tinta-suave);
    margin: 0;
}

/* Sin max-height propio, la tabla siempre cabe verticalmente (crece la
   página) - solo el ancho necesita scroll. overflow-y: hidden explícito
   evita que el navegador lo convierta en "auto" por el eje X (regla del
   spec: si un eje no es "visible", el otro deja de serlo también), que
   mostraba una barra vertical fantasma incluso con la tabla vacía. */
.tabla-scroll {
    overflow-x: auto;
    overflow-y: hidden;
    background: var(--superficie);
    border: 1px solid var(--niebla);
    border-radius: var(--radio-tarjeta);
    box-shadow: var(--sombra);
}

.tabla-panel {
    width: 100%;
    border-collapse: collapse;
}

.tabla-panel th, .tabla-panel td {
    text-align: left;
    padding: 0.6rem 0.9rem;
    border-bottom: 1px solid var(--niebla);
}

.tabla-panel th {
    font-family: var(--fuente-mono);
    font-size: 0.75rem;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--tinta-suave);
    background: var(--papel);
}

.tabla-panel tbody tr:last-child td {
    border-bottom: none;
}

.tabla-panel tbody tr:hover td {
    background: var(--papel);
}

.tabla-panel td.num {
    font-family: var(--fuente-mono);
}

/* Columna "Acciones" de tablas de gestión: iconos en vez de links/formularios
   de texto sueltos por columna. "Clonar" necesita elegir una empresa, así que
   es un <details> - revela el formulario debajo del icono, sin JS ni popover
   posicionado (la tabla ya scrollea horizontal, un absolute se recortaría). */
.acciones-tabla {
    display: flex;
    align-items: center;
    gap: 0.15rem;
    white-space: nowrap;
}

.acciones-tabla form {
    display: flex;
    align-items: center;
    gap: 0.3rem;
}

/* La columna de acciones nunca cede espacio a las de curso/perfil: si no
   entran todas, la tabla scrollea horizontal (.tabla-scroll) en vez de
   achicar los botones - sin esto, .tabla-panel { width: 100% } los aplasta
   hasta volverlos casi invisibles.
   .acciones-tabla es un <div> DENTRO del <td> (nunca la clase en el <td>
   mismo): un <td> con display:flex deja de comportarse como celda de tabla
   para el cálculo de alto de fila del navegador y su borde inferior queda
   dibujado más arriba de donde termina el contenido - se ve "cortado". */
.tabla-panel td:has(.acciones-tabla) {
    width: 1%;
    white-space: nowrap;
}

.accion-icono {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    min-width: 36px;
    min-height: 36px;
    flex-shrink: 0;
    padding: 0;
    border-radius: var(--radio);
    background: none;
    border: none;
    box-shadow: none;
    color: var(--tinta-suave);
    cursor: pointer;
    text-decoration: none;
    list-style: none;
}

.accion-icono::-webkit-details-marker {
    display: none;
}

.accion-icono svg {
    width: 18px;
    height: 18px;
}

/* Mover arriba/abajo (cursos de una ruta): sin acción posible en el primer/
   último renglón - atenuado, y el clic no hace nada (guard en JS). */
.tabla-panel tbody tr:first-child [data-mover="arriba"],
.tabla-panel tbody tr:last-child [data-mover="abajo"] {
    opacity: 0.35;
}

.accion-icono:hover {
    background: var(--papel);
    color: var(--primario-oscuro);
}

.accion-icono--peligro {
    background: none;
    border: none;
    cursor: pointer;
    font: inherit;
}

/* .accion-icono como <span> (no <a>, no <button>): para una acción sin
   destino todavía (ej. previsualizar un curso que aún no se publicó) -
   mismo tamaño que sus vecinas en .acciones-tabla, pero sin invitar al clic. */
.accion-icono--deshabilitada {
    opacity: 0.4;
    cursor: not-allowed;
}

.accion-icono--peligro:hover {
    background: var(--error-fondo);
    color: var(--error);
}

.accion-clonar__form {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-top: 0.5rem;
}

.alerta-item {
    list-style: none;
    padding: 0.5rem 0;
    border-bottom: 1px solid var(--niebla);
}

footer {
    margin-top: 1.5rem;
    padding: 1.5rem 1rem 2rem;
    border-top: 1px solid var(--niebla);
    text-align: center;
    font-size: 0.85rem;
    color: var(--tinta-suave);
}

.footer__copy {
    margin: 0 0 0.5rem;
}

footer a {
    color: var(--tinta-suave);
}

fieldset {
    border: 1px solid var(--borde);
    border-radius: var(--radio);
    padding: 1rem;
    margin: 0 0 1rem;
    background: var(--superficie);
}

fieldset legend {
    font-family: var(--fuente-mono);
    font-size: 0.75rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    font-weight: 600;
    padding: 0 0.4rem;
}

.opcion-quiz {
    display: block;
    padding: 0.6rem 0.5rem;
    min-height: 44px;
}

.pregunta-resultado {
    border-left: 4px solid var(--ok);
    padding-left: 0.75rem;
    margin-bottom: 1rem;
}

.pregunta-resultado.incorrecta {
    border-left-color: var(--error);
}

/* Justificación del quiz: tarjeta informativa en ámbar - el "por qué"
   detrás de la respuesta correcta, no un párrafo suelto entre el resultado
   y la cita. Mismo par ambar/ambar-fondo que .racha (gamificación). */
.nota-justificacion {
    background: var(--ambar-fondo);
    border-left: 4px solid var(--ambar);
    border-radius: var(--radio);
    padding: 0.7rem 1rem;
    margin: 0.6rem 0;
}

.nota-justificacion__etiqueta {
    margin: 0 0 0.3rem;
    font-size: 0.72rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    font-weight: 700;
    color: #9A6A15;
}

.nota-justificacion p:last-child {
    margin: 0;
    color: var(--tinta);
}

/* Aviso fijo (no tooltip) para una convención de UI que aplica a toda la
   pantalla - se lee siempre, no depende de que alguien pase el mouse por
   un ícono. Mismo par ambar/ambar-fondo que .nota-justificacion/.racha. */
.aviso-ambar {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    background: var(--ambar-fondo);
    border: 1px solid var(--ambar);
    border-radius: var(--radio);
    padding: 0.7rem 1rem;
    color: #9A6A15;
    font-size: 0.88rem;
    margin: 1.5rem 0 1rem;
}

.portada__logo {
    display: block;
    width: auto;
    margin: 0.5rem 0 1.5rem;
}

/* --- Portada (RF-01): hero de bienvenida + tarjetas de valor. ------------- */

main.portada {
    position: relative;
    z-index: 1;
}

@media (min-width: 900px) {
    main.portada {
        margin-top: -95px;
    }
}

.hero {
    position: relative;
    display: flex;
    min-height: 560px;
    overflow: hidden;
    background-color: var(--papel);
    background-image:
        radial-gradient(ellipse 620px 480px at 74% 42%, rgba(0, 104, 248, 0.12), transparent 70%),
        linear-gradient(135deg, var(--azul-palido) 0%, var(--papel) 65%),
        url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='72' height='72' viewBox='0 0 24 24'%3E%3Cpath d='M12 2C12 2 5 10.5 5 15a7 7 0 0 0 14 0c0-4.5-7-13-7-13z' fill='%230068F8' fill-opacity='0.06'/%3E%3C/svg%3E");
    background-repeat: no-repeat, no-repeat, repeat;
}

.hero__texto {
    position: relative;
    z-index: 1;
    width: 100%;
    max-width: 1100px;
    margin: 0 auto;
    padding: 2.75rem 1rem;
}

.hero__texto > * {
    max-width: 34rem;
}

.hero__texto h1 {
    margin-top: 0;
    line-height: 1.35;
}

.hero__subtitulo {
    font-family: var(--fuente-display);
    font-weight: 700;
    color: var(--tinta);
    margin: 0.25rem 0 0.75rem;
}

.hero__texto > .descripcion-pagina:not(.hero__nota) {
    color: var(--cuerpo);
}

.hero__nota {
    font-size: 0.85rem;
    margin-top: 2.5rem;
    margin-bottom: 0.5rem;
}

.hero__nota + .acciones {
    margin-top: 0;
}

.hero__nota + .acciones .boton--secundario {
    padding: 0.45rem 0.9rem;
    font-size: 0.9rem;
    min-height: 38px;
}

.boton__icono {
    width: 1.2rem;
    height: 1.2rem;
    flex-shrink: 0;
}

/* Certificado ilustrativo (aria-hidden, ejemplo - no es un certificado
   real). Va dentro de .hero__texto, pegado justo a la derecha del bloque
   de texto (que mide 34rem + 1rem de padding) y alineado a su misma altura
   superior - como en la referencia. */
.hero__certificado {
    display: block;
    position: absolute;
    top: 6rem;
    left: 44rem;
    width: 17rem;
    height: auto;
    border-radius: var(--radio-tarjeta);
    box-shadow: 0 20px 40px -12px rgba(30, 42, 50, 0.28), var(--sombra-hover);
    z-index: 2;
    animation: flotar-certificado 6s ease-in-out infinite;
}

@keyframes flotar-certificado {
    0%, 100% { transform: rotate(-2deg) translateY(0); }
    50% { transform: rotate(-2deg) translateY(-10px); }
}

@media (prefers-reduced-motion: reduce) {
    .hero__certificado {
        animation: none;
    }
}

@media (max-width: 1100px) {
    .hero__certificado {
        display: none;
    }
}

@media (max-width: 640px) {
    .hero {
        min-height: 0;
    }

    .hero__texto {
        padding: 2rem 1rem;
    }

    .hero__texto > * {
        max-width: none;
    }
}

/* Tarjetas de valor de la portada: ícono + título + descripción. No son
   enlaces (RF-01, solo texto informativo), así que el hover es decorativo:
   sombra más marcada, sin desplazamiento ni cursor de puntero que sugiera
   una acción que no existe. */
.tarjeta-grid .tarjeta {
    transition: box-shadow var(--transicion) 200ms;
}

.tarjeta-grid .tarjeta:hover {
    box-shadow: var(--sombra-hover);
}

.tarjeta__icono-fondo {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.75rem;
    height: 2.75rem;
    border-radius: 50%;
    background: var(--azul-palido);
    margin-bottom: 0.75rem;
}

.tarjeta__icono {
    width: 1.4rem;
    height: 1.4rem;
    color: var(--primario);
}

/* === Tarjetas de sección con miniatura (portada del curso) ============== */

.tarjeta-grid--secciones {
    margin: 1rem 0 1.5rem;
}

.tarjeta-seccion {
    padding: 0;
    overflow: hidden;
    display: flex;
    flex-direction: column;
}

.tarjeta-seccion__miniatura {
    width: 100%;
    height: 120px;
    object-fit: cover;
    display: block;
    background: var(--papel);
}

.tarjeta-seccion__miniatura--fallback {
    display: flex;
    align-items: center;
    justify-content: center;
    font-family: var(--fuente-display);
    font-size: 2.4rem;
    font-weight: 700;
    color: #fff;
    background: linear-gradient(135deg, var(--primario), var(--primario-oscuro));
}

.tarjeta-seccion--completada .tarjeta-seccion__miniatura--fallback {
    background: linear-gradient(135deg, var(--ok), #157a52);
}

.tarjeta-seccion__cuerpo {
    padding: 0.9rem 1.1rem 1.1rem;
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
}

.tarjeta-seccion__cuerpo h3 {
    margin: 0;
    font-size: 1.02rem;
}

.tarjeta-seccion__cuerpo .etiqueta-estado {
    align-self: flex-start;
}

/* Miniatura en las tarjetas de curso del dashboard */
.tarjeta-curso {
    padding-top: 0;
    overflow: hidden;
}

.tarjeta-curso__miniatura {
    width: calc(100% + 2.4rem);
    margin: 0 -1.2rem 0.8rem;
    height: 110px;
    object-fit: cover;
    display: block;
    background: var(--papel);
}

/* === Tutor IA como burbuja de chat (RF-33) ============================== */

.tutor-burbuja {
    position: fixed;
    right: 1.1rem;
    bottom: 1.1rem;
    z-index: 60;
    width: 56px;
    height: 56px;
    border-radius: 50%;
    border: none;
    background: var(--primario);
    color: #fff;
    font-size: 1.5rem;
    cursor: pointer;
    box-shadow: var(--sombra-boton);
    transition: transform var(--transicion) 120ms, background var(--transicion) 120ms;
}

.tutor-burbuja:hover {
    background: var(--primario-oscuro);
    transform: translateY(-2px);
}

/* Gana a "button svg" (1.1em): el ícono del tutor es el protagonista. */
.tutor-burbuja svg {
    width: 28px;
    height: 28px;
}

.tutor-panel {
    position: fixed;
    right: 1.1rem;
    bottom: 5.4rem;
    z-index: 60;
    width: min(380px, calc(100vw - 2.2rem));
    max-height: min(560px, calc(100vh - 7rem));
    display: flex;
    flex-direction: column;
    background: var(--superficie);
    border: 1px solid var(--niebla);
    border-radius: var(--radio-panel);
    box-shadow: 0 12px 32px rgba(30, 42, 50, 0.18);
    overflow: hidden;
}

/* display: flex le gana al [hidden] del navegador; sin esto el panel no se cierra. */
.tutor-panel[hidden] {
    display: none;
}

.tutor-panel__cabecera {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.7rem 0.9rem;
    border-bottom: 1px solid var(--niebla);
    background: var(--azul-palido);
}

.tutor-panel__cerrar {
    margin-left: auto;
    border: none;
    background: none;
    font-size: 1rem;
    cursor: pointer;
    color: var(--tinta-suave);
    min-width: 32px;
    min-height: 32px;
}

.tutor-panel .tutor-disclaimer {
    margin: 0;
    padding: 0.5rem 0.9rem;
    font-size: 0.8rem;
}

.tutor-panel .tutor-conversacion {
    flex: 1;
    overflow-y: auto;
    padding: 0.7rem 0.9rem;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    min-height: 140px;
}

.tutor-panel__form {
    display: flex;
    gap: 0.5rem;
    padding: 0.6rem 0.9rem;
    border-top: 1px solid var(--niebla);
}

.tutor-panel__form textarea {
    flex: 1;
    resize: none;
    font: inherit;
    font-size: 0.9rem;
    padding: 0.45rem 0.6rem;
    border: 1px solid var(--borde);
    border-radius: var(--radio);
}

.tutor-panel .tutor-cuota {
    margin: 0;
    padding: 0.35rem 0.9rem 0.7rem;
    font-size: 0.78rem;
    color: var(--tinta-tenue);
}

/* Móvil: el panel ocupa casi toda la pantalla */
@media (max-width: 640px) {
    .tutor-panel {
        right: 0.6rem;
        left: 0.6rem;
        width: auto;
        bottom: 4.9rem;
        max-height: calc(100vh - 6rem);
    }
}

/* === Fábrica: galería de media y revisión por tarjetas ================== */

.galeria-media {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
    gap: 0.8rem;
    margin: 0.8rem 0;
}

.galeria-media__item {
    margin: 0;
    border: 1px solid var(--niebla);
    border-radius: var(--radio);
    overflow: hidden;
    background: var(--superficie);
}

.galeria-media__preview {
    width: 100%;
    height: 100px;
    object-fit: cover;
    display: block;
    background: var(--papel);
}

.galeria-media__item figcaption {
    padding: 0.4rem 0.6rem;
    font-size: 0.78rem;
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    word-break: break-all;
}

.ayuda-campo {
    font-size: 0.82rem;
    color: var(--tinta-tenue);
    margin-top: 0.35rem;
}

.avanzado--inline {
    display: inline-block;
}

/* Tarjeta de sección/pregunta en la revisión experta (D054/D075-UX): cabecera
   separada del cuerpo por un borde, para que cada tarjeta se lea como una
   unidad - antes las secciones eran solo un textarea suelto dentro de una
   tarjeta genérica, sin distinguirse de la página. El modificador --acento
   (tinte azul) marca las tarjetas de pregunta frente a las de contenido. */
.tarjeta-revision-item {
    background: var(--superficie);
    border: 1px solid var(--borde);
    border-radius: var(--radio-tarjeta);
    box-shadow: var(--sombra);
    margin-bottom: 1.5rem;
    overflow: hidden;
    /* La cabecera es sticky (position:sticky, ~60px) - sin esto, saltar a un
       ancla (navegador de preguntas, "ir directo a lo marcado") deja la
       tarjeta tapada detrás. */
    scroll-margin-top: 5rem;
}

.tarjeta-revision-item__cabecera {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.6rem;
    flex-wrap: wrap;
    padding: 0.9rem 1.2rem;
    border-bottom: 1px solid var(--niebla);
}

.tarjeta-revision-item__cabecera--acento {
    background: linear-gradient(180deg, rgba(0, 104, 248, 0.035), transparent);
}

.tarjeta-revision-item__cabecera h3 {
    margin: 0;
    font-size: 1.02rem;
}

.tarjeta-revision-item__cuerpo {
    padding: 1.2rem 1.2rem 1.4rem;
    display: flex;
    flex-direction: column;
    gap: 1.1rem;
}

.tarjeta-revision-item__cuerpo textarea.editor-md {
    width: 100%;
    box-sizing: border-box;
    font-size: 0.9rem;
    line-height: 1.55;
    padding: 0.5rem 0.65rem;
    border: 1px solid var(--borde);
    border-radius: var(--radio);
    font-family: inherit;
    resize: none;
    overflow: hidden;
}

.tarjeta-revision-item__cuerpo textarea.editor-md:focus {
    outline: none;
    border-color: var(--primario);
}

/* Título de sección: sin caja por defecto - se ve como el <h1> real de
   catalogo/seccion.html, no como un campo de formulario. El borde solo
   aparece al enfocar (edición) o si quedó modificado sin guardar. */
.campo--titulo-seccion input[type="text"] {
    display: block;
    width: 100%;
    box-sizing: border-box;
    border: 1px solid transparent;
    border-radius: var(--radio);
    padding: 0.2rem 0.3rem;
    margin: -0.2rem -0.3rem;
    font-family: var(--fuente-display);
    font-size: 1.5rem;
    font-weight: 700;
    letter-spacing: -0.01em;
    color: var(--tinta);
    background: transparent;
}

.campo--titulo-seccion input[type="text"]:focus {
    outline: none;
    border-color: var(--primario);
}

.campo--titulo-seccion input[type="text"].campo-modificado {
    border-color: var(--ambar);
}

/* Contenido de sección: vista previa tal como la ve el alumno
   (catalogo/seccion.html, misma clase .contenido-seccion) en vez de dejar
   el markdown crudo a la vista - "Editar" revela el textarea de abajo con
   el markdown fuente. Sin marco: es el mismo bloque de texto, no una caja
   de formulario aparte. */
/* Flex-columna en vez de position:relative + botón flotante encima: con el
   video ahora antes del texto (D089), un "Editar" absoluto con top:0 quedaba
   montado sobre la esquina del video en vez de sobre el texto. En flujo
   normal, alineado a la derecha, siempre cae después del último bloque
   (video, texto o subtítulos), sin superponerse a nada. */
.campo--contenido-seccion .vista-previa-seccion {
    display: flex;
    flex-direction: column;
}

/* Mismo bug de especificidad de siempre: "[hidden]" (0,1,0) pierde contra
   el "display:flex" de la regla de arriba (0,2,0) sin este override - al
   activar la edición, el bloque de vista previa (con el placeholder de
   "sin contenido todavía") se quedaba visible en vez de esconderse. */
.campo--contenido-seccion .vista-previa-seccion[hidden] {
    display: none;
}

.campo--contenido-seccion .contenido-seccion {
    font-size: 0.94rem;
}

.campo--contenido-seccion .contenido-seccion > *:first-child {
    margin-top: 0;
}

.campo--contenido-seccion .contenido-seccion > *:last-child {
    margin-bottom: 0;
}

.vista-previa-seccion__editar {
    align-self: flex-end;
    margin-top: 0.5rem;
    min-height: 0;
    min-width: 0;
    padding: 0.3rem 0.7rem;
    font-size: 0.78rem;
    box-shadow: none;
}

.campo {
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
}

.campo > label {
    font-size: 0.72rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    font-weight: 600;
    color: var(--tinta-tenue);
}

/* Interruptor on/off (ej. "Activa" de una ruta): un checkbox nativo con
   posición absoluta e invisible, no display:none, para que siga siendo
   enfocable con teclado y el lector de pantalla lo anuncie como checkbox.
   min-height 44px: mismo alto que el input/select del resto del form. */
.interruptor {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    gap: 0.5rem;
    cursor: pointer;
}

.interruptor input[type="checkbox"] {
    position: absolute;
    width: 1px;
    height: 1px;
    opacity: 0;
    margin: 0;
}

.interruptor__pista {
    position: relative;
    display: inline-block;
    width: 2.5rem;
    height: 1.4rem;
    flex-shrink: 0;
    background: var(--niebla);
    border-radius: 999px;
    transition: background var(--transicion) 120ms;
}

.interruptor__perilla {
    position: absolute;
    top: 2px;
    left: 2px;
    width: calc(1.4rem - 4px);
    height: calc(1.4rem - 4px);
    background: var(--superficie);
    border-radius: 50%;
    box-shadow: var(--sombra);
    transition: transform var(--transicion) 120ms;
}

.interruptor input:checked ~ .interruptor__pista {
    background: var(--primario);
}

.interruptor input:checked ~ .interruptor__pista .interruptor__perilla {
    transform: translateX(calc(2.5rem - 1.4rem));
}

.interruptor input:focus-visible ~ .interruptor__pista {
    outline: 2px solid var(--primario);
    outline-offset: 2px;
}

/* Formularios agrupados en cards (ej. editar Ruta de Aprendizaje): separa
   "datos generales" de "cursos de la ruta" en vez de un solo bloque largo de
   form.as_p sin jerarquía visual. */
/* Dos tarjeta-form lado a lado en pantallas anchas (ej. empresa_form: "Datos
   generales" y "Estado y Tutor IA" en una sola fila). */
.dos-tarjetas-form {
    display: grid;
    grid-template-columns: 1fr;
    gap: 1.25rem;
}

@media (min-width: 700px) {
    .dos-tarjetas-form {
        grid-template-columns: 1fr 1fr;
    }
}

.dos-tarjetas-form .tarjeta-form {
    margin-bottom: 0;
}

.tarjeta-form {
    background: var(--superficie);
    border: 1px solid var(--niebla);
    border-radius: var(--radio-tarjeta);
    box-shadow: var(--sombra);
    padding: 1.25rem 1.4rem;
    margin-bottom: 1.25rem;
}

.tarjeta-form .campo {
    margin-bottom: 1rem;
}

/* Identidad del curso (spec_form.html): la tarjeta es ancha (input hasta
   34rem por defecto, pensado para campos cortos como un slug) y con la
   grilla de 3 columnas cada celda mide más que eso - sin esto, el input le
   queda corto a su columna/fila y sobra un espacio vacío a la derecha. */
.tarjeta-form--ancho-completo input,
.tarjeta-form--ancho-completo select {
    max-width: none;
}

/* Dentro de .grid-campos el espaciado entre filas ya lo da el gap de la
   grilla - el margin-bottom de arriba duplicaría ese espacio. min-width:0
   porque un .campo es item de grid: sin esto, su ancho mínimo lo fija el
   min-content del <input> (el tamaño nativo de ~20 caracteres), y con 5
   columnas en una fila esa suma supera el ancho disponible y desborda
   horizontal en vez de encogerse con el fr de la columna. */
.grid-campos .campo {
    margin-bottom: 0;
    min-width: 0;
}

/* Perfiles/sectores de spec_form.html: el grupo va dentro de un .campo, que
   ya separa del siguiente campo con su propio margin-bottom (1rem) - el
   margin-bottom propio de .grupo-opciones (pensado para cuando va suelto,
   ej. asignar_ruta.html) duplicaba ese espacio dentro del mismo campo. */
.tarjeta-form .campo > .grupo-opciones {
    margin-bottom: 0;
}

.paginacion {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.4rem;
    margin-top: 1rem;
}

.paginacion__flecha,
.paginacion__numero {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 36px;
    height: 36px;
    padding: 0 0.4rem;
    border-radius: var(--radio);
    border: 1px solid var(--niebla);
    background: var(--superficie);
    color: var(--primario);
    font-family: var(--fuente-display);
    font-weight: 600;
    text-decoration: none;
}

.paginacion__flecha svg {
    width: 20px;
    height: 20px;
}

.paginacion__flecha:hover,
.paginacion__numero:hover {
    background: var(--azul-palido);
    border-color: var(--primario);
    color: var(--primario-oscuro);
}

.paginacion__flecha--deshabilitada {
    color: var(--tinta-tenue);
    border-color: var(--niebla);
    background: var(--papel);
    cursor: default;
}

.paginacion__flecha--deshabilitada:hover {
    background: var(--papel);
    color: var(--tinta-tenue);
}

.paginacion__numero--activo,
.paginacion__numero--activo:hover {
    background: var(--primario);
    border-color: var(--primario);
    color: #fff;
    cursor: default;
}

.paginacion__elipsis {
    color: var(--tinta-tenue);
    padding: 0 0.2rem;
}

/* Card de confirmación explícita antes de una importación (nómina, etc.):
   separada del contenido anterior y con acento de marca para que no se
   confunda con una tarjeta-form cualquiera - es el último paso, no uno más. */
.tarjeta-confirmacion {
    margin-top: 2rem;
    border-left: 4px solid var(--primario);
}

/* Chat conversacional de spec_chat.html: la tira de progreso arriba ya
   reusa .wizard-pasos tal cual (mismo look, sin CSS nuevo) - acá solo lo
   propio del chat: log de mensajes + burbujas + input. */
.tarjeta-form--chat {
    display: flex;
    flex-direction: column;
    gap: 0.9rem;
}

.chat-log {
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
    max-height: 26rem;
    overflow-y: auto;
    padding-right: 0.25rem;
}

.msg {
    display: flex;
    /* columna: la fila (avatar+burbuja) y, debajo, los chips/tarjetas de
       opciones si las trae - todo dentro del mismo ancho máximo. */
    flex-direction: column;
    gap: 0.5rem;
    max-width: 80%;
}

.msg--agente {
    align-self: flex-start;
    align-items: flex-start;
}

.msg--usuario {
    align-self: flex-end;
    align-items: flex-end;
}

.msg__fila {
    display: flex;
    align-items: flex-end;
    gap: 0.5rem;
    min-width: 0;
}

.msg--usuario .msg__fila {
    flex-direction: row-reverse;
}

.msg__avatar {
    flex-shrink: 0;
    width: 1.8rem;
    height: 1.8rem;
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 0.8rem;
    font-weight: 700;
}

.msg--agente .msg__avatar {
    background: var(--azul-palido);
    color: var(--primario-oscuro);
    border: 1px solid var(--azul-palido-borde);
}

.msg--usuario .msg__avatar {
    background: var(--tinta);
    color: var(--superficie);
    font-size: 0.62rem;
}

.msg__burbuja {
    min-width: 0;
    padding: 0.6rem 0.9rem;
    border-radius: var(--radio-tarjeta);
    font-size: 0.92rem;
    line-height: 1.48;
}

.msg--agente .msg__burbuja {
    background: var(--papel);
    border: 1px solid var(--borde);
    color: var(--cuerpo);
    border-top-left-radius: 4px;
}

.msg--usuario .msg__burbuja {
    background: var(--primario);
    color: #fff;
    border-top-right-radius: 4px;
}

/* Formato mínimo de las respuestas del agente (spec_chat.js::formatearMensaje
   convierte **negrita**/listas "- " a estas etiquetas) - sin esto, <p>/<ul>
   heredan el margen de 1em del navegador y la burbuja queda con aire de más. */
.msg__burbuja p {
    margin: 0;
}

.msg__burbuja p + p {
    margin-top: 0.5rem;
}

.msg__burbuja ul {
    margin: 0.3rem 0;
    padding-left: 1.1rem;
}

.msg__burbuja li + li {
    margin-top: 0.2rem;
}

.msg__burbuja strong {
    color: inherit;
}

/* Indicador "escribiendo" mientras se espera al agente - reemplaza el
   placeholder de texto por tres puntos que rebotan en cascada. */
.escribiendo {
    display: inline-flex;
    gap: 0.22rem;
    padding: 0.15rem 0;
}

.escribiendo span {
    width: 5px;
    height: 5px;
    border-radius: 50%;
    background: var(--tinta-tenue);
    animation: chat-rebote 1.1s infinite ease-in-out;
}

.escribiendo span:nth-child(2) {
    animation-delay: 0.15s;
}

.escribiendo span:nth-child(3) {
    animation-delay: 0.3s;
}

@keyframes chat-rebote {
    0%, 60%, 100% { transform: translateY(0); opacity: 0.5; }
    30% { transform: translateY(-4px); opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
    .escribiendo span {
        animation: none;
        opacity: 0.7;
    }
}

/* Chips de opciones bajo una respuesta del agente (spec_chat.js): mismo
   lenguaje visual que .chip-filtro (fuentes de spec_form.html), pero el
   estado "activo" acá refleja si el valor ya está en el input, no un
   filtro aplicado. */
.chips-opciones {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
    margin-top: 0.5rem;
}

.chip-opcion {
    display: inline-flex;
    align-items: center;
    min-height: 32px;
    padding: 0.25rem 0.8rem;
    border-radius: 999px;
    border: 1px solid var(--borde);
    background: var(--superficie);
    color: var(--tinta-suave);
    font-family: inherit;
    font-size: 0.82rem;
    font-weight: 600;
    box-shadow: none;
    cursor: pointer;
    transition: background var(--transicion) 120ms, color var(--transicion) 120ms, border-color var(--transicion) 120ms;
}

.chip-opcion:hover {
    background: var(--azul-palido);
    color: var(--primario-oscuro);
}

.chip-opcion--activo,
.chip-opcion--activo:hover {
    background: var(--primario);
    color: #fff;
    border-color: var(--primario);
}

/* Tarjetas de nivel (spec_chat.js/html): a diferencia de los chips (multi-
   selección, texto corto), el nivel es un valor único con descripción - una
   fila por opción, no una grilla, para que la descripción tenga ancho para
   respirar. Reusa botones reales (form="id_chat_form") igual que los chips. */
.tarjetas-nivel {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    width: 100%;
}

.tarjeta-nivel {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    width: 100%;
    padding: 0.65rem 0.9rem;
    border: 1px solid var(--borde);
    border-radius: var(--radio-tarjeta);
    background: var(--superficie);
    text-align: left;
    cursor: pointer;
    font-family: inherit;
    box-shadow: none;
    transition: background var(--transicion) 120ms, border-color var(--transicion) 120ms;
}

.tarjeta-nivel:hover {
    background: var(--azul-palido);
    border-color: var(--azul-palido-borde);
}

.tarjeta-nivel__numero {
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.9rem;
    height: 1.9rem;
    border-radius: 50%;
    background: var(--azul-palido);
    color: var(--primario-oscuro);
    font-family: var(--fuente-mono);
    font-weight: 700;
    font-size: 0.85rem;
    transition: background var(--transicion) 120ms, color var(--transicion) 120ms;
}

.tarjeta-nivel__texto {
    display: flex;
    flex-direction: column;
    gap: 0.1rem;
    min-width: 0;
    color: var(--tinta);
    font-size: 0.86rem;
}

.tarjeta-nivel__texto span {
    color: var(--tinta-suave);
    font-size: 0.8rem;
    font-weight: 400;
}

.tarjeta-nivel--activo {
    border-color: var(--primario);
    background: var(--azul-palido);
    box-shadow: 0 0 0 1px var(--primario);
}

.tarjeta-nivel--activo .tarjeta-nivel__numero {
    background: var(--primario);
    color: #fff;
}

/* Resumen final del chat (spec_chat.html/js) - mismo tratamiento de "listo
   para revisar" en vez de la tarjeta con borde de color de .tarjeta-confirmacion
   (esa es para confirmaciones dentro de un formulario clásico, no de un chat). */
.tarjeta-resumen-chat {
    margin-top: 1rem;
    padding: 1.1rem 1.3rem;
    background: var(--azul-palido);
    border: 1px solid var(--azul-palido-borde);
    border-radius: var(--radio-tarjeta);
}

.tarjeta-resumen-chat__titulo {
    margin: 0 0 0.6rem;
    font-size: 1rem;
    font-weight: 700;
    color: var(--primario-oscuro);
}

.tarjeta-resumen-chat .explicador__lista {
    color: var(--tinta);
}

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

.chat-form__fila {
    display: flex;
    gap: 0.6rem;
    align-items: flex-end;
}

.chat-form__fila textarea {
    flex: 1;
    max-width: none;
    resize: vertical;
}

/* Selector de proveedor/modelo de IA, pegado a la casilla de texto (D083):
   deliberadamente más chico que un <select>/<input> normal - es una
   preferencia rápida, no un campo del formulario que pida atención. */
.chat-selector-ia {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    flex-wrap: wrap;
}

.chat-selector-ia label {
    display: flex;
    align-items: center;
    gap: 0.35rem;
    font-size: 0.78rem;
    font-weight: 600;
    color: var(--tinta-suave);
}

.chat-selector-ia select,
.chat-selector-ia input[type="text"] {
    width: auto;
    max-width: none;
    min-height: 34px;
    padding: 0.25rem 0.5rem;
    font-size: 0.82rem;
    color: var(--tinta);
}

.chat-selector-ia select {
    padding-right: 1.6rem;
}

.chat-selector-ia input[type="text"] {
    width: 12ch;
}

.chat-pie {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    flex-wrap: wrap;
}

.campo-checkbox {
    display: flex;
    flex-direction: row;
    align-items: center;
    justify-content: flex-start;
    gap: 0.5rem;
}

.campo-checkbox input[type="checkbox"] {
    width: 20px;
    height: 20px;
}

/* Envuelve el <div id="id_xxx"> nativo de un CheckboxSelectMultiple (ej.
   sectores/perfiles de estudio/curso_form.html: un <div><label><input>...
   </label></div> por opción) - Django no deja ponerle clase a ese div. Sin
   JS queda como lista de checkboxes normal (fallback funcional); con JS,
   selector_multiple.js lo oculta y arma el selector con chips de abajo. */
.checkbox-list > div {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem 1.25rem;
}

/* selector_multiple.js oculta este div con el atributo `hidden` - sin esto,
   `display: flex` de arriba le gana en especificidad al `display: none` de
   [hidden] y el fallback sin JS queda visible a la vez que el selector. */
.checkbox-list > div[hidden] {
    display: none;
}

.checkbox-list label {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    font-weight: 400;
}

/* Selector desplegable con chips (selector_multiple.js) - reemplaza visualmente
   al <ul> de checkboxes de .checkbox-list cuando hay JS. */
.multi-select {
    position: relative;
}

.multi-select__trigger {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
    width: 100%;
    min-height: 44px;
    padding: 0.5rem 0.75rem;
    border: 1px solid var(--borde);
    border-radius: var(--radio);
    background: var(--superficie);
    color: var(--tinta);
    font: inherit;
    text-align: left;
    cursor: pointer;
}

.multi-select__trigger:hover {
    border-color: var(--primario);
}

.multi-select--open .multi-select__trigger {
    border-color: var(--primario);
    box-shadow: 0 0 0 3px var(--foco);
}

.multi-select__summary {
    display: flex;
    flex-wrap: wrap;
    gap: 0.35rem;
    flex: 1;
    min-width: 0;
}

.multi-select__placeholder {
    color: var(--tinta-tenue);
}

.multi-select__chip {
    display: inline-flex;
    align-items: center;
    padding: 0.2rem 0.65rem;
    border-radius: 999px;
    background: var(--azul-palido);
    color: var(--primario-oscuro);
    font-size: 0.8rem;
    font-weight: 600;
    white-space: nowrap;
}

.multi-select__arrow {
    width: 18px;
    height: 18px;
    flex-shrink: 0;
    color: var(--tinta-suave);
    transition: transform var(--transicion) 120ms;
}

.multi-select--open .multi-select__arrow {
    transform: rotate(180deg);
}

.multi-select__panel[hidden] {
    display: none;
}

.multi-select__panel {
    position: absolute;
    top: calc(100% + 6px);
    left: 0;
    right: 0;
    z-index: 20;
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    padding: 0.4rem;
    background: var(--superficie);
    border: 1px solid var(--borde);
    border-radius: var(--radio-tarjeta);
    box-shadow: var(--sombra-hover);
}

.multi-select__row {
    display: flex;
    align-items: center;
    gap: 0.65rem;
    width: 100%;
    padding: 0.55rem 0.6rem;
    border: none;
    border-radius: var(--radio);
    background: none;
    color: var(--tinta);
    font: inherit;
    text-align: left;
    cursor: pointer;
}

.multi-select__row:hover {
    background: var(--papel);
}

.multi-select__row--active {
    background: var(--azul-palido);
}

.multi-select__dot {
    width: 11px;
    height: 11px;
    flex-shrink: 0;
    border-radius: 50%;
    border: 1.5px solid var(--tinta-tenue);
    background: transparent;
    transition: background var(--transicion) 120ms, border-color var(--transicion) 120ms;
}

.multi-select__row--active .multi-select__dot {
    background: var(--primario);
    border-color: var(--primario);
}

/* Variante más espaciada de .tarjeta-form (estudio/curso_form.html): un
   formulario corto y de una sola tarjeta se ve apretado con el padding/gap
   compacto pensado para tarjetas con muchos campos (spec_form.html, etc.) -
   modificador local en vez de tocar `.tarjeta-form` global. */
.tarjeta-form.tarjeta-form--espaciada {
    padding: 2rem 2.25rem;
}

.tarjeta-form.tarjeta-form--espaciada .campo {
    margin-bottom: 1.75rem;
}

.tarjeta-form.tarjeta-form--espaciada .campo:last-child {
    margin-bottom: 0;
}

.tarjeta-form.tarjeta-form--espaciada .tarjeta-form__titulo {
    margin-bottom: 0.5rem;
}

.course-form > button[type="submit"] {
    margin-top: 0.5rem;
}

.tarjeta-form .campo:last-child {
    margin-bottom: 0;
}

.tarjeta-form__encabezado {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    margin-bottom: 0.75rem;
}

/* Cuando el encabezado no vive dentro de una .tarjeta-form (ej. "Plantas" y
   "Trabajadores" en empresa_detalle, secciones sueltas de la página) el
   título pierde el margin-top:2rem de h2 - se repone acá para no quedar
   pegado al bloque anterior. */
.tarjeta-form__encabezado--seccion {
    margin-top: 2rem;
}

/* Cuando el lado derecho de .tarjeta-form__encabezado lleva más de un
   control (ej. "+" y el buscador de fabricacion/*_lista.html) - envuelve
   para no romper el layout en móvil, donde no entran los tres juntos. */
.tarjeta-form__acciones {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    flex-wrap: wrap;
    justify-content: flex-end;
}

.tarjeta-form__titulo {
    display: flex;
    align-items: center;
    margin-top: 0;
}

/* Bajo el título de una .tarjeta-form (ej. "Identidad del curso"): una
   línea de contexto + un separador antes de los campos, en vez de que el
   primer campo quede pegado directo al título. */
.tarjeta-form__subtitulo {
    margin: 0.15rem 0 0.6rem;
    padding-bottom: 0.6rem;
    border-bottom: 1px solid var(--niebla);
    font-size: 0.85rem;
    color: var(--tinta-suave);
}

.tarjeta-form .tabla-scroll {
    box-shadow: none;
}

.tarjeta-form .tabla-panel td {
    vertical-align: middle;
}

/* Cursos de la ruta: Curso se lleva el espacio que sobra, Perfil y Acciones
   se achican al contenido (el <select> de perfil fija su propio ancho para
   no saltar de tamaño según qué perfil esté elegido en cada fila). */
.tarjeta-form .tabla-panel .th-curso,
.tarjeta-form .tabla-panel .td-curso {
    width: 100%;
}

.tarjeta-form .tabla-panel .td-curso select {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Tooltip propio (no el nativo del navegador) con el nombre completo del
   curso elegido, para cuando .td-curso select lo corta con "…". El texto lo
   llena JS (static/js/formset_cursos_ruta.js) según la opción seleccionada. */
.campo-curso-tooltip {
    position: relative;
    display: block;
    width: 100%;
}

.campo-curso-tooltip__globo {
    position: fixed;
    max-width: 24rem;
    width: max-content;
    white-space: normal;
    background: var(--superficie);
    border: 1px solid var(--borde);
    color: var(--tinta-suave);
    font-size: 0.78rem;
    line-height: 1.45;
    padding: 0.4rem 0.6rem;
    border-radius: var(--radio);
    display: none;
    pointer-events: none;
    z-index: 30;
}

.campo-curso-tooltip__globo:empty {
    display: none;
}

.campo-curso-tooltip__globo.visible {
    display: block;
}

.tarjeta-form .tabla-panel .th-perfil,
.tarjeta-form .tabla-panel .td-perfil {
    width: 1%;
    white-space: nowrap;
}

.tarjeta-form .tabla-panel .td-perfil select {
    width: auto;
    min-width: 11rem;
}

/* Botón cuadrado "+" para agregar una fila al formset de cursos (JS en
   formset_cursos_ruta.js - clona formset.empty_form, sin framework). Sin JS,
   las filas vacías ya renderizadas (extra=1) siguen siendo el fallback. */
/* Truco de checkbox oculto (mismo patrón que .accion-icono--eliminar): el
   checkbox va justo antes de .seccion-plegable en el DOM y no se ve, pero
   el <label for="..."> que hace de botón "+" la muestra u oculta sin JS. */
.seccion-plegable {
    display: none;
}

input[type="checkbox"]:checked + .seccion-plegable {
    display: block;
}

.boton-agregar-fila {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    padding: 0;
    flex-shrink: 0;
    background: var(--azul-palido);
    border: 1px solid var(--azul-palido-borde);
    border-radius: var(--radio);
    color: var(--primario-oscuro);
    box-shadow: none;
}

.boton-agregar-fila:hover {
    background: var(--azul-palido-borde);
    border-color: var(--primario);
    color: var(--primario-oscuro);
}

.boton-agregar-fila svg {
    width: 24px;
    height: 24px;
}

/* Checkbox DELETE del formset, disfrazado de botón de tacho: el input queda
   invisible pero funcional debajo del ícono (mismo truco de <label> que
   envuelve un <input> nativo, sin JS). */
.accion-icono--eliminar {
    position: relative;
}

.accion-icono--eliminar input[type="checkbox"] {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    margin: 0;
    opacity: 0;
    cursor: pointer;
}

.accion-icono--eliminar:has(input:checked) {
    background: var(--error-fondo);
    color: var(--error);
}

/* Mismo truco que .accion-icono--eliminar (input nativo tapado, sin
   opacity:0 en el ÍCONO, solo en el input): clic en el ícono abre el
   selector de archivos nativo y, al elegir uno, el onchange manda el
   formulario - sin botón "Subir" ni el texto "Ningún archivo…" del
   navegador ocupando la celda. */
.accion-icono--subir {
    position: relative;
    cursor: pointer;
}

.accion-icono--subir input[type="file"] {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    margin: 0;
    opacity: 0;
    cursor: pointer;
}

/* Icono "i" con tooltip propio (no el del navegador) - evita un párrafo de
   ayuda fijo ocupando espacio cuando el dato solo aplica a veces (ej. cita
   compartida entre preguntas). */
.icono-info {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1rem;
    height: 1rem;
    border-radius: 50%;
    background: var(--niebla);
    color: var(--tinta-suave);
    font-size: 0.65rem;
    font-weight: 700;
    font-style: normal;
    text-transform: none;
    letter-spacing: normal;
    margin-left: 0.3rem;
    cursor: help;
    vertical-align: middle;
}

.icono-info:hover,
.icono-info:focus-visible {
    background: var(--primario);
    color: #fff;
    outline: none;
}

.icono-info__tooltip {
    position: absolute;
    bottom: calc(100% + 0.55rem);
    left: 50%;
    transform: translateX(-50%) translateY(4px);
    width: max-content;
    max-width: 16rem;
    white-space: normal;
    background: var(--superficie);
    border: 1px solid var(--borde);
    color: var(--tinta-suave);
    font-size: 0.78rem;
    font-weight: 500;
    text-transform: none;
    letter-spacing: normal;
    line-height: 1.45;
    padding: 0.55rem 0.75rem;
    border-radius: var(--radio);
    box-shadow: var(--sombra-hover);
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transition: opacity var(--transicion) 120ms, transform var(--transicion) 120ms;
    z-index: 20;
}

.icono-info__tooltip::before,
.icono-info__tooltip::after {
    content: "";
    position: absolute;
    top: 100%;
    left: 50%;
    transform: translateX(-50%);
    border: 6px solid transparent;
    border-top-color: var(--borde);
}

.icono-info__tooltip::after {
    top: calc(100% - 1px);
    border-width: 5px;
    border-top-color: #fff;
}

.icono-info:hover .icono-info__tooltip,
.icono-info:focus-visible .icono-info__tooltip {
    opacity: 1;
    visibility: visible;
    transform: translateX(-50%) translateY(0);
}

/* Para un ícono pegado al borde derecho de su contenedor (ej. "Versión" en
   la grilla de 5 columnas de spec_form.html): centrado el globo se corta
   contra el overflow-x:hidden del paso del wizard. Este modificador lo
   ancla por la derecha (abre hacia la izquierda) en vez de centrarlo. */
.icono-info__tooltip--izquierda {
    left: auto;
    right: 0;
    transform: translateY(4px);
}

.icono-info__tooltip--izquierda::before,
.icono-info__tooltip--izquierda::after {
    left: auto;
    right: 0.5rem;
    transform: none;
}

.icono-info:hover .icono-info__tooltip--izquierda,
.icono-info:focus-visible .icono-info__tooltip--izquierda {
    transform: translateY(0);
}

/* Dentro de .tabla-scroll el globo se recorta en dos ejes: overflow-x auto
   obliga a overflow-y auto (regla del spec), así que uno hacia arriba se
   corta en vez de flotar encima; y uno centrado en el ícono, que en un <th>
   está pegado al borde izquierdo de la tabla, se corta por la izquierda con
   el mismo overflow-x que habilita el scroll horizontal. En los <th> lo
   abrimos hacia abajo (hay espacio) y alineado a la izquierda del ícono
   (no centrado) para que quede dentro del área visible. */
.tabla-scroll th .icono-info__tooltip {
    bottom: auto;
    top: calc(100% + 0.55rem);
    left: 0;
    transform: translateY(-4px);
}

.tabla-scroll th .icono-info__tooltip::before,
.tabla-scroll th .icono-info__tooltip::after {
    top: auto;
    bottom: 100%;
    left: 0.5rem;
    transform: none;
    border-top-color: transparent;
    border-bottom-color: var(--borde);
}

.tabla-scroll th .icono-info__tooltip::after {
    bottom: calc(100% - 1px);
    border-bottom-color: #fff;
}

.tabla-scroll th .icono-info:hover .icono-info__tooltip,
.tabla-scroll th .icono-info:focus-visible .icono-info__tooltip {
    transform: translateY(0);
}

/* Enunciado (quiz) / título de sección (contenido): mismo campo con borde
   que el resto del formulario, pero con tipografía más grande - se edita
   haciendo click directo (cursor parpadeando), sin asa de resize. Cubre
   tanto textarea (enunciado) como input de una sola línea (título). */
.campo.campo--enunciado textarea,
.campo.campo--enunciado input[type="text"] {
    display: block;
    width: 100%;
    box-sizing: border-box;
    border: 1px solid var(--borde);
    border-radius: var(--radio);
    padding: 0.6rem 0.8rem;
    font-family: inherit;
    font-size: 1.05rem;
    font-weight: 600;
    line-height: 1.4;
    color: var(--tinta);
    background: transparent;
    resize: none;
    overflow: hidden;
}

.campo.campo--enunciado textarea:focus,
.campo.campo--enunciado input[type="text"]:focus {
    outline: none;
    border-color: var(--primario);
}

.campo.campo--enunciado textarea.campo-modificado,
.campo.campo--enunciado input[type="text"].campo-modificado {
    border-color: var(--ambar);
}

/* Justificación y cita: se editan sobre el formato final con el que las ve
   el alumno (progreso/resultado.html) - la justificación como párrafo
   plano, la cita como el chip .chip-cita real, no un input genérico. Los
   encabezados "Justificación"/"Cita de la fuente" (`.campo > label`) se
   mantienen arriba sin cambios. */
.campo--justificacion .nota-justificacion {
    transition: box-shadow var(--transicion) 120ms;
}

.campo.campo--justificacion textarea {
    display: block;
    width: 100%;
    box-sizing: border-box;
    border: none;
    padding: 0;
    font-family: inherit;
    font-size: 0.94rem;
    line-height: 1.55;
    color: var(--tinta);
    background: transparent;
    resize: none;
}

.campo.campo--justificacion textarea:focus {
    outline: none;
}

.campo--justificacion .nota-justificacion:has(textarea:focus) {
    box-shadow: 0 0 0 2px rgba(0, 104, 248, 0.25);
}

.campo--justificacion .nota-justificacion:has(textarea.campo-modificado) {
    box-shadow: 0 0 0 2px var(--ambar);
}

.chip-cita--editable {
    width: fit-content;
    max-width: 100%;
    border-color: var(--azul-palido-borde);
    transition: border-color var(--transicion) 120ms, box-shadow var(--transicion) 120ms;
}

.chip-cita--editable:focus-within {
    border-color: var(--primario);
}

.chip-cita--editable:has(input.campo-modificado) {
    box-shadow: 0 0 0 2px var(--ambar);
}

.campo.campo--cita .chip-cita--editable input {
    border: none;
    background: transparent;
    color: inherit;
    font: inherit;
    padding: 0;
    width: 20ch;
    max-width: 100%;
}

.campo.campo--cita .chip-cita--editable input:focus {
    outline: none;
}

/* Enlace al documento: pill secundaria y punteada junto al chip de cita -
   mismo lenguaje visual (icono + texto en línea), pero discreta porque es
   opcional. Sin esto quedaba como un input suelto sin relación visual con
   la cita de al lado. */
.campo--cita-url {
    flex: 1;
    min-width: 0;
}

.campo--cita-url .campo-cita-url__caja {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    width: 100%;
    box-sizing: border-box;
    border: 1px dashed var(--borde);
    border-radius: 999px;
    padding: 0.2rem 0.75rem;
    color: var(--tinta-tenue);
    transition: border-color var(--transicion) 120ms, box-shadow var(--transicion) 120ms, color var(--transicion) 120ms;
}

.campo--cita-url .campo-cita-url__caja:focus-within {
    border-style: solid;
    border-color: var(--primario);
    color: var(--tinta);
}

.campo--cita-url .campo-cita-url__caja:has(input.campo-modificado) {
    border-style: solid;
    border-color: var(--ambar);
    color: var(--tinta);
}

.campo.campo--cita-url .campo-cita-url__caja input {
    flex: 1;
    border: none;
    background: transparent;
    color: inherit;
    font-size: 0.85rem;
    font-family: inherit;
    padding: 0;
    width: 100%;
    min-width: 0;
}

.campo.campo--cita-url .campo-cita-url__caja input:focus {
    outline: none;
}

.campo.campo--cita-url .campo-cita-url__caja input::placeholder {
    color: var(--tinta-tenue);
}

.campo textarea,
.campo input[type="text"],
.campo input[type="url"] {
    width: 100%;
    box-sizing: border-box;
    font-size: 0.94rem;
    line-height: 1.5;
    padding: 0.65rem 0.8rem;
    border: 1px solid var(--borde);
    border-radius: var(--radio);
    font-family: inherit;
    resize: none;
    overflow: hidden;
}

.fila-meta {
    display: flex;
    gap: 1.2rem;
    align-items: flex-end;
    padding-top: 1.1rem;
    border-top: 1px dashed var(--niebla);
}

.fila-meta .campo {
    flex: 1;
}

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

.opcion {
    display: flex;
    align-items: center;
    gap: 0.7rem;
    padding: 0.55rem 0.7rem;
    border: 1px solid var(--borde);
    border-radius: var(--radio);
    transition: border-color var(--transicion) 120ms, background var(--transicion) 120ms;
}

.opcion:has(input:checked) {
    border-color: var(--primario);
    background: rgba(0, 104, 248, 0.045);
}

.opcion__letra {
    flex: 0 0 auto;
    width: 1.6rem;
    height: 1.6rem;
    border-radius: 50%;
    background: var(--niebla);
    color: var(--tinta-suave);
    font-size: 0.78rem;
    font-weight: 700;
    display: flex;
    align-items: center;
    justify-content: center;
}

.opcion:has(input:checked) .opcion__letra {
    background: var(--primario);
    color: #fff;
}

.campo .opcion textarea {
    flex: 1;
    display: block;
    box-sizing: border-box;
    border: 1px solid transparent;
    border-radius: var(--radio);
    padding: 0.45rem 0.6rem;
    font-size: 0.94rem;
    line-height: 1.5;
    font-family: inherit;
    color: var(--tinta);
    background: transparent;
    resize: none;
    overflow: hidden;
}

.campo .opcion textarea:focus {
    outline: none;
    border-color: var(--primario);
}

.opcion__marcar {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    gap: 0.35rem;
    font-size: 0.72rem;
    color: var(--tinta-tenue);
    white-space: nowrap;
    cursor: pointer;
}

.opcion__marcar input {
    accent-color: var(--primario);
}

/* Cambio sin guardar (revisar_contenido.html / revisar_quiz.html, JS
   vanilla): el campo distinto de su valor original al cargar la pantalla
   se marca en ámbar hasta que se guarde. Al enfocar sigue viéndose el azul
   de foco de cada campo - solo se nota en reposo. Los dos últimos
   selectores igualan la especificidad de `.editor-md`/`.opcion textarea`
   para poder ganarles. */
textarea.campo-modificado,
input.campo-modificado,
.tarjeta-revision-item__cuerpo textarea.editor-md.campo-modificado,
.opcion textarea.campo-modificado {
    border-color: var(--ambar);
}

/* Navegador de preguntas (revisar_quiz.html), estilo Moodle: grilla de
   números fija a la derecha para saltar entre preguntas sin scrollear una
   por una. Sticky en pantallas anchas; se apila arriba del quiz en angostas. */
.quiz-layout {
    display: grid;
    grid-template-columns: 1fr;
    gap: 2rem;
    align-items: start;
}

@media (min-width: 900px) {
    .quiz-layout {
        grid-template-columns: 1fr 13rem;
    }

    .navegador-preguntas {
        position: sticky;
        top: 5.5rem;
    }
}

.quiz-layout__form {
    min-width: 0;
}

.navegador-preguntas {
    background: var(--superficie);
    border: 1px solid var(--borde);
    border-radius: var(--radio-tarjeta);
    box-shadow: var(--sombra);
    padding: 1rem;
}

.navegador-preguntas h2 {
    margin: 0 0 0.75rem;
    font-size: 0.78rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--tinta-tenue);
    font-weight: 600;
}

.navegador-preguntas__grid {
    display: grid;
    grid-template-columns: repeat(5, 1fr);
    gap: 0.4rem;
}

.navegador-preguntas__item {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 2.2rem;
    border: 1px solid var(--borde);
    border-radius: var(--radio);
    font-weight: 600;
    font-size: 0.85rem;
    color: var(--tinta-suave);
    text-decoration: none;
    transition: border-color var(--transicion) 120ms, color var(--transicion) 120ms;
}

.navegador-preguntas__item:hover {
    border-color: var(--primario);
    color: var(--primario-oscuro);
}

.navegador-preguntas__item--marca {
    border-color: var(--error);
    color: var(--error);
    background: var(--error-fondo);
}

.navegador-preguntas__leyenda {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    font-size: 0.78rem;
    color: var(--tinta-tenue);
    margin: 0.75rem 0 0;
}

.navegador-preguntas__item--muestra {
    flex: 0 0 auto;
    width: 1.4rem;
    height: 1.4rem;
}

.navegador-preguntas__item--activo {
    border-color: var(--primario);
    background: var(--primario);
    color: #fff;
}

/* Índice de secciones (revisar_contenido.html): lista vertical con número +
   título - a diferencia del quiz, cada sección tiene un título propio con
   sentido, así que una grilla de números pelados es menos útil que un
   índice legible. Ensancha la columna lateral para que el título entre. */
.quiz-layout:has(.navegador-preguntas--indice) {
    grid-template-columns: 1fr;
}

@media (min-width: 900px) {
    .quiz-layout:has(.navegador-preguntas--indice) {
        grid-template-columns: 1fr 22rem;
    }
}

.indice-secciones {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 0.3rem;
}

.indice-secciones__item {
    display: flex;
    align-items: flex-start;
    gap: 0.6rem;
    padding: 0.4rem 0.5rem;
    border-radius: var(--radio);
    text-decoration: none;
    transition: background var(--transicion) 120ms;
}

.indice-secciones__item:hover {
    background: var(--papel);
}

.indice-secciones__numero {
    flex: 0 0 auto;
    width: 1.5rem;
    height: 1.5rem;
    border-radius: 50%;
    background: var(--niebla);
    color: var(--tinta-suave);
    font-size: 0.72rem;
    font-weight: 700;
    display: flex;
    align-items: center;
    justify-content: center;
    margin-top: 0.05rem;
}

.indice-secciones__titulo {
    font-size: 0.85rem;
    line-height: 1.35;
    color: var(--tinta-suave);
}

.indice-secciones__item:hover .indice-secciones__titulo {
    color: var(--tinta);
}

.indice-secciones__item--marca .indice-secciones__numero {
    background: var(--error-fondo);
    color: var(--error);
}

.indice-secciones__item--activo {
    background: var(--azul-palido);
}

.indice-secciones__item--activo .indice-secciones__numero {
    background: var(--primario);
    color: #fff;
}

.indice-secciones__item--activo .indice-secciones__titulo {
    color: var(--primario-oscuro);
    font-weight: 600;
}

.indice-secciones__numero--marca {
    background: var(--error-fondo);
    color: var(--error);
    width: 1.4rem;
    height: 1.4rem;
}

/* Buscador con lupa (gestion/asignar_ruta.html): ícono superpuesto al input,
   sin depender de la lupa nativa de type="search" (Chrome no la dibuja). El
   borde/radio/alto vive en la propia caja (no en el input) para calzar con
   el disparador de .dropdown-multi de al lado - mismo aspecto en los tres
   filtros de la fila (planta, cargo, buscar). */
.campo-buscador__caja {
    position: relative;
    display: flex;
    align-items: center;
    min-height: 44px;
    border: 1px solid var(--borde);
    /* El mismo --radio que .boton-agregar-fila (9px) se ve casi recto acá:
       la caja es mucho más ancha que alta, así que el radio absoluto pesa
       menos visualmente que en un botón casi cuadrado de 44×44. */
    border-radius: var(--radio-tarjeta);
    background: var(--superficie);
    transition: border-color var(--transicion) 120ms, box-shadow var(--transicion) 120ms;
}

.campo-buscador__caja:focus-within {
    border-color: var(--primario);
    box-shadow: 0 0 0 3px var(--foco);
}

.campo-buscador__caja svg {
    position: absolute;
    left: 0.75rem;
    width: 1rem;
    height: 1rem;
    color: var(--tinta-tenue);
    pointer-events: none;
}

.campo-buscador__caja input[type="search"] {
    width: 100%;
    background: var(--superficie);
    color: var(--tinta);
    border: none;
    box-shadow: none;
    min-height: 42px;
    padding-left: 2.25rem;
}

.campo-buscador__caja input[type="search"]:focus {
    border-color: transparent;
    box-shadow: none;
}

/* Buscador standalone de una tabla (fabricacion/*_lista.html vía
   tabla_buscable.js): en asignar_ruta.html el ancho lo da la fila de
   filtros de al lado; acá no hay fila, así que se fija uno propio. */
.tabla-buscable__buscador {
    max-width: 22rem;
    margin-bottom: 1rem;
}

/* Dentro de .tarjeta-form__acciones (junto al "+") va en la misma fila, sin
   el margen inferior pensado para cuando está solo arriba de la tabla. */
.tarjeta-form__acciones .tabla-buscable__buscador {
    max-width: 16rem;
    margin-bottom: 0;
}

/* Acción secundaria de texto junto a un botón principal (ej. "Prefiero el
   formulario clásico" junto al "+ Nuevo curso" del chat) - un link, no otro
   botón, para no competir visualmente con la acción primaria. */
.enlace-discreto {
    font-size: 0.85rem;
    color: var(--tinta-suave);
    text-decoration: underline;
    text-underline-offset: 2px;
}

.enlace-discreto:hover {
    color: var(--primario-oscuro);
}

/* Dropdown de selección múltiple (planta): <details> nativo, mismo patrón
   que .acciones-tabla "Clonar" y .dropdown-cuenta - sin JS de posicionamiento
   ni librería, solo togglear [open]. El disparador comparte alto/borde/radio
   con el resto de los campos de la fila (input, select, buscador). */
.dropdown-multi {
    position: relative;
}

.dropdown-multi__disparador {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
    min-height: 44px;
    padding: 0.5rem 0.75rem;
    border: 1px solid var(--borde);
    border-radius: var(--radio);
    background: var(--superficie);
    color: var(--tinta);
    cursor: pointer;
    list-style: none;
}

.dropdown-multi__disparador::-webkit-details-marker {
    display: none;
}

.dropdown-multi__disparador:hover {
    border-color: var(--primario);
}

.dropdown-multi[open] .dropdown-multi__disparador {
    border-color: var(--primario);
    box-shadow: 0 0 0 3px var(--foco);
}

.dropdown-multi__texto {
    color: var(--tinta-suave);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.dropdown-multi__caret {
    width: 0.85rem;
    height: 0.85rem;
    flex-shrink: 0;
    color: var(--tinta-tenue);
    transition: transform var(--transicion) 150ms;
}

.dropdown-multi[open] .dropdown-multi__caret {
    transform: rotate(180deg);
}

.dropdown-multi__panel {
    position: absolute;
    top: calc(100% + 0.35rem);
    left: 0;
    z-index: 15;
    min-width: 100%;
    width: max-content;
    max-width: 20rem;
    max-height: 14rem;
    overflow-y: auto;
    background: var(--superficie);
    border: 1px solid var(--niebla);
    border-radius: var(--radio-tarjeta);
    box-shadow: var(--sombra-hover);
    padding: 0.4rem;
}

.dropdown-multi__opcion {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    min-height: 38px;
    padding: 0 0.6rem;
    border-radius: var(--radio);
    cursor: pointer;
    font-size: 0.9rem;
    color: var(--tinta-suave);
}

.dropdown-multi__opcion:hover {
    background: var(--papel);
    color: var(--tinta);
}

/* Chips de plantas elegidas, debajo del dropdown. */
.chips-seleccion {
    display: flex;
    flex-wrap: wrap;
    gap: 0.35rem;
    margin-top: 0.5rem;
}

.chip-seleccion {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    font-size: 0.8rem;
    font-weight: 600;
    color: var(--primario-oscuro);
    background: var(--azul-palido);
    border: 1px solid var(--azul-palido-borde);
    border-radius: 999px;
    padding: 0.15rem 0.5rem 0.15rem 0.7rem;
}

.chip-seleccion__quitar {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1rem;
    height: 1rem;
    min-width: 0;
    min-height: 0;
    padding: 0;
    border: none;
    box-shadow: none;
    background: none;
    color: inherit;
    cursor: pointer;
}

.chip-seleccion__quitar svg {
    width: 0.7rem;
    height: 0.7rem;
}

/* Checkbox "Seleccionar todos", entre los filtros y la grilla de
   trabajadores - alineado a la izquierda, como el resto de los campos. */
.campo-checkbox--seleccionar-todos {
    margin: 0.75rem 0;
}

/* Ícono que distingue visualmente el cargo de cada trabajador en la lista
   de asignar_ruta.html - categoría amplia (ver filtro position_category),
   no el perfil pedagógico exacto de RF-05. */
.icono-cargo {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.75rem;
    height: 1.75rem;
    border-radius: 50%;
    flex-shrink: 0;
    background: var(--niebla);
    color: var(--tinta-suave);
}

.icono-cargo svg {
    width: 1rem;
    height: 1rem;
}

.icono-cargo--operador {
    background: var(--azul-palido);
    color: var(--primario-oscuro);
}

.icono-cargo--supervisor {
    /* Naranja: no hay token propio en el sistema de color (§6.2 solo define
       ambar/ok/error/rol-*), así que va hardcodeado como el resto de los
       pares fondo+texto de esta lista. */
    background: #FDEEE1;
    color: #B75C10;
}

.icono-cargo--ingeniero {
    background: var(--ambar-fondo);
    color: #9A6A15;
}

/* Avisos de la vista previa de nómina (gestion/nomina_preview.html): banner
   de ancho completo con ícono, en vez de una etiqueta-estado suelta - el
   color (info/warning) es la señal principal, el ícono la refuerza para
   quien no distingue el color. */
.aviso-banner {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    padding: 0.75rem 1rem;
    border-radius: var(--radio-tarjeta);
    font-weight: 600;
    margin-bottom: 1rem;
}

.aviso-banner svg {
    width: 1.3rem;
    height: 1.3rem;
    flex-shrink: 0;
}

.aviso-banner code {
    font-family: var(--fuente-mono);
    font-size: 0.85em;
    font-weight: 700;
    background: rgba(0, 0, 0, 0.08);
    padding: 0.1rem 0.4rem;
    border-radius: 4px;
}

.aviso-banner--info {
    background: var(--azul-palido);
    color: var(--primario-oscuro);
    border: 1px solid var(--azul-palido-borde);
}

.aviso-banner--warning {
    background: var(--ambar-fondo);
    color: #9A6A15;
    border: 1px solid var(--ambar);
}

/* Aviso informativo dentro de una sección exclusiva de AdminAcademia
   (Gestión, Fábrica): mismo morado que .tarjeta-enlace__icono en esos hubs,
   en vez del azul --info genérico del resto del Campus. */
.aviso-banner--academia {
    background: var(--rol-academia-fondo);
    color: var(--rol-academia);
    border: 1px solid var(--rol-academia);
}

/* Columna Avance de "Rutas asignadas" (gestion/trabajador_detalle.html):
   barra + detalle con su propio ritmo vertical y ancho mínimo, en vez de
   tocar .barra-avance/.kpi-detalle globales (los usan otras páginas
   apretados a propósito, ej. dentro de una tarjeta angosta). */
.avance-ruta {
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
    min-width: 9rem;
    padding: 0.2rem 0;
}

/* Grilla de trabajadores de asignar_ruta.html: alto fijo para 2 filas de
   .opcion-caja--trabajador (4.5rem c/u + 0.5rem de gap entre ambas) - no
   crece con más resultados (esos se paginan, ver asignar_ruta.js) ni se
   achica con menos (align-content: start deja el sobrante vacío abajo, en
   vez de estirar las tarjetas para llenar el alto). */
.grupo-opciones--fila#grupo-trabajadores {
    height: 9.5rem;
    overflow: hidden;
    align-content: start;
}

/* El "display: grid" de .grupo-opciones empata en especificidad con
   [hidden]{display:none} del navegador (mismo caso que .opcion-caja más
   arriba) - sin esto, ocultar la grilla entera cuando no hay resultados
   (asignar_ruta.js) no tendría efecto visual. */
.grupo-opciones[hidden] {
    display: none;
}

/* Reutiliza el aspecto de _paginacion.html (RF, tablas de gestión) para la
   paginación client-side de trabajadores, armada con <button> en vez de
   <a href="?page=">. box-shadow/min-height se anulan acá porque si no los
   hereda el <button>, .boton genérico (sombra azul, min-height 44px). */
#paginacion-trabajadores .paginacion__flecha {
    box-shadow: none;
    min-height: 0;
    background: var(--superficie);
}

.paginacion__info {
    font-size: 0.85rem;
    color: var(--tinta-suave);
    padding: 0 0.5rem;
}

/* Utilidad genérica: centrar un título/descripción sueltos (páginas
   públicas de un solo propósito, ej. verificación de certificados). */
.titulo-centrado {
    text-align: center;
}

/* Verificación pública de certificados (progreso/verificar.html,
   verificar_portal.html): la ve cualquiera con el folio impreso en un
   certificado, sin sesión - tiene que leerse como un resultado oficial
   inequívoco, no como una notificación in-app de éxito/error. */
.verificacion {
    max-width: 30rem;
    margin: 0 auto 1.5rem;
    text-align: center;
    padding: 2rem 1.5rem;
    border: 1px solid var(--niebla);
    border-radius: var(--radio-tarjeta);
    box-shadow: var(--sombra);
}

.verificacion__icono {
    width: 3.5rem;
    height: 3.5rem;
    margin: 0 auto 0.75rem;
    border-radius: 50%;
    background: var(--superficie);
    display: flex;
    align-items: center;
    justify-content: center;
}

.verificacion__icono svg {
    width: 2rem;
    height: 2rem;
}

.verificacion__estado {
    font-family: var(--fuente-display);
    font-weight: 700;
    font-size: 1.15rem;
    margin: 0 0 0.25rem;
}

.verificacion__titulo {
    margin: 0 0 1.25rem;
}

.verificacion--valido {
    border-color: var(--ok);
    background: var(--ok-fondo);
}

.verificacion--valido .verificacion__icono,
.verificacion--valido .verificacion__estado {
    color: var(--ok);
}

.verificacion--invalido {
    border-color: var(--error);
    background: var(--error-fondo);
}

.verificacion--invalido .verificacion__icono,
.verificacion--invalido .verificacion__estado {
    color: var(--error);
}

.verificacion--invalido .descripcion-pagina {
    max-width: none;
}

/* Ficha de datos del certificado, dentro de .verificacion. */
.ficha-certificado {
    text-align: left;
    margin: 0;
    background: var(--superficie);
    border: 1px solid var(--niebla);
    border-radius: var(--radio);
    overflow: hidden;
}

.ficha-certificado__fila {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 1rem;
    padding: 0.65rem 1rem;
}

.ficha-certificado__fila + .ficha-certificado__fila {
    border-top: 1px solid var(--niebla);
}

.ficha-certificado__fila dt {
    color: var(--tinta-suave);
    font-size: 0.85rem;
    flex-shrink: 0;
}

.ficha-certificado__fila dd {
    margin: 0;
    font-weight: 600;
    color: var(--tinta);
    text-align: right;
}

/* Formulario de folio del portal de validación: input + botón centrados,
   angosto (no todo el ancho de .ancho-panel). */
.buscar-folio {
    max-width: 26rem;
    margin: 0 auto 1.5rem;
    display: flex;
    align-items: flex-end;
    gap: 0.75rem;
}

.buscar-folio .campo {
    flex: 1;
}

/* --- Editor de sección del Estudio (Fábrica 2.0, D089) ----------------------
   Look de "editor de bloques" (riel de secciones + toolbar + panel de video)
   con los mismos tokens de siempre - nada de colores nuevos, así respeta el
   modo claro/oscuro del propio sitio en vez de forzar un tema aparte. */

.editor-estudio {
    max-width: 1200px;
}

.editor-estudio__cabecera {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.6rem 1rem;
    margin-bottom: 1.25rem;
}

.editor-estudio__titulo {
    margin: 0;
    flex: 1 1 auto;
}

.editor-estudio__cuerpo {
    display: flex;
    align-items: flex-start;
    gap: 1.5rem;
}

/* min-width:0 a propósito: un flex-item con flex-basis fijo igual puede
   crecer más allá de ese ancho si su contenido (acá, el título en negrita
   de la sección activa) no cabe - min-width:0 le saca el piso de "auto" y
   deja que .editor-estudio__riel-texto trunque con ellipsis en vez de
   empujar el riel entero más ancho. */
.editor-estudio__riel {
    flex: 0 0 280px;
    min-width: 0;
    position: sticky;
    top: 4.5rem;
    z-index: 5; /* el submenú de "agregar" se abre sobre el panel central */
    background: var(--superficie);
    border: 1px solid var(--niebla);
    border-radius: var(--radio-tarjeta);
    padding: 0.9rem 0.6rem;
    box-shadow: var(--sombra);
}

.editor-estudio__riel-etiqueta {
    font-family: var(--fuente-mono);
    font-size: 0.7rem;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--tinta-tenue);
    margin: 0 0.3rem 0.6rem;
}

/* La "card" es la fila entera (fondo/borde/padding/estado activo), no el
   link - así el botón de eliminar vive adentro de la misma caja, en vez de
   flotar aparte al lado. El link queda transparente, solo layout interno. */
.editor-estudio__riel-fila {
    display: flex;
    align-items: center;
    gap: 0.3rem;
    padding: 0.65rem 0.75rem;
    border: 1px solid transparent;
    border-radius: var(--radio);
    margin-bottom: 0.35rem;
    color: var(--tinta-suave);
}

.editor-estudio__riel-fila:hover {
    background: var(--papel);
    color: var(--tinta);
}

.editor-estudio__riel-fila--activo {
    background: var(--azul-palido);
    border-color: var(--azul-palido-borde);
    color: var(--tinta);
    font-weight: 600;
}

.editor-estudio__riel-item {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    flex: 1;
    min-width: 0;
    text-decoration: none;
    color: inherit;
}

.editor-estudio__riel-eliminar {
    flex-shrink: 0;
    min-height: 0;
    min-width: 0;
    width: 28px;
    height: 28px;
    padding: 0;
    background: none;
    border: none;
    box-shadow: none;
    color: var(--tinta-tenue);
    opacity: 0;
    transition: opacity var(--transicion) 120ms, color var(--transicion) 120ms;
}

.editor-estudio__riel-fila:hover .editor-estudio__riel-eliminar,
.editor-estudio__riel-eliminar:focus-visible {
    opacity: 1;
}

.editor-estudio__riel-eliminar:hover {
    background: none;
    color: var(--error);
}

.editor-estudio__riel-eliminar svg {
    width: 16px;
    height: 16px;
}

.editor-estudio__riel-numero {
    width: 22px;
    height: 22px;
    border-radius: 50%;
    background: var(--niebla);
    color: var(--tinta-suave);
    font-family: var(--fuente-mono);
    font-size: 0.72rem;
    font-weight: 700;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
}

.editor-estudio__riel-fila--activo .editor-estudio__riel-numero {
    background: var(--primario);
    color: #fff;
}

.editor-estudio__riel-texto {
    flex: 1;
    min-width: 0;
    font-size: 0.82rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Mismo look que .editor-estudio__riel-item (ancho completo, alineado a la
   izquierda), no un botón genérico centrado. */
.editor-estudio__riel-agregar {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.6rem;
    width: 100%;
    min-height: 0;
    min-width: 0;
    padding: 0.5rem 0.6rem;
    border-radius: var(--radio);
    border: 1px dashed var(--niebla);
    background: none;
    box-shadow: none;
    color: var(--tinta-suave);
    font-family: var(--fuente-texto);
    font-weight: 400;
    font-size: 0.82rem;
}

.editor-estudio__riel-agregar span[aria-hidden] {
    width: 22px;
    height: 22px;
    border-radius: 50%;
    background: var(--niebla);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    font-family: var(--fuente-mono);
    font-weight: 700;
}

.editor-estudio__riel-agregar:hover {
    background: var(--papel);
    border-color: var(--primario);
    color: var(--tinta);
}

.editor-estudio__agregar-envoltorio {
    position: relative;
}

.editor-estudio__layout-menu {
    position: absolute;
    top: calc(100% + 0.35rem);
    left: 0;
    right: 0;
    z-index: 10;
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
    background: var(--superficie);
    border: 1px solid var(--niebla);
    border-radius: var(--radio-tarjeta);
    box-shadow: var(--sombra-hover);
    padding: 0.5rem;
}

/* Mismo bug de especificidad de siempre: "[hidden]" (0,1,0) empata con
   ".editor-estudio__layout-menu { display:flex }" (0,1,0) y pierde por
   venir antes en el archivo - el dropdown quedaba abierto por defecto en
   vez de cerrado. */
.editor-estudio__layout-menu[hidden] {
    display: none;
}

/* Submenú a la derecha ("Contenido generado con IA"): se abre con hover o
   foco del teclado/toque sobre la opción padre. */
.editor-estudio__submenu-envoltorio {
    position: relative;
}

.editor-estudio__submenu-flecha {
    font-size: 1.2rem;
    color: var(--tinta-suave);
}

.editor-estudio__layout-submenu {
    display: none;
    top: 0;
    left: calc(100% + 0.35rem);
    right: auto;
    width: 15rem;
}

/* Puente invisible sobre el hueco: sin él el hover se pierde al cruzar. */
.editor-estudio__layout-submenu::before {
    content: "";
    position: absolute;
    top: 0;
    bottom: 0;
    left: -1rem;
    width: 1rem;
}

.editor-estudio__submenu-envoltorio:hover > .editor-estudio__layout-submenu,
.editor-estudio__submenu-envoltorio:focus-within > .editor-estudio__layout-submenu {
    display: flex;
}

.editor-estudio__layout-opcion {
    display: flex;
    align-items: center;
    justify-content: flex-start;
    gap: 0.7rem;
    width: 100%;
    min-height: 0;
    min-width: 0;
    padding: 0.5rem;
    background: none;
    border: 1px solid transparent;
    box-shadow: none;
    border-radius: var(--radio);
    color: var(--tinta);
    font-family: var(--fuente-texto);
    text-align: left;
}

.editor-estudio__layout-opcion:hover {
    background: var(--papel);
    border-color: var(--niebla);
    color: var(--tinta);
}

.editor-estudio__layout-texto {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 0.1rem;
    font-size: 0.8rem;
    color: var(--tinta-suave);
}

.editor-estudio__layout-texto strong {
    font-size: 0.85rem;
    color: var(--tinta);
}

/* Bosquejo: mini-diagrama del layout, no una miniatura real - solo bloques
   planos que insinúan dónde va el título/video/texto. */
.editor-estudio__layout-bosquejo {
    flex-shrink: 0;
    display: flex;
    flex-direction: column;
    gap: 0.2rem;
    width: 4.5rem;
    height: 3.4rem;
    padding: 0.3rem;
    background: var(--papel);
    border: 1px solid var(--niebla);
    border-radius: 6px;
}

.bosquejo-linea {
    height: 5px;
    border-radius: 2px;
    background: var(--tinta-tenue);
}

.bosquejo-titulo {
    width: 60%;
}

.bosquejo-video {
    flex: 1;
    min-height: 0;
    border-radius: 3px;
    background: var(--azul-palido-borde);
}

.bosquejo-texto {
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: 3px;
}

.bosquejo-texto span {
    height: 3px;
    border-radius: 2px;
    background: var(--niebla);
}

.bosquejo-texto span:last-child {
    width: 60%;
}

.bosquejo-columnas {
    flex: 1;
    min-height: 0;
    display: flex;
    gap: 0.25rem;
}

.bosquejo-columnas .bosquejo-video {
    flex: 1;
}

.bosquejo-columnas .bosquejo-texto {
    flex: 1;
}

/* Layout "dos columnas" (Section.layout, D090) en catalogo/seccion.html:
   mismo video + texto de siempre, lado a lado en vez de apilados. */
.contenido-seccion__columnas {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 1.5rem;
    align-items: start;
}

.contenido-seccion__col-video .video-seccion {
    margin: 0;
}

@media (max-width: 640px) {
    .contenido-seccion__columnas {
        grid-template-columns: 1fr;
    }
}

/* Layout "refuerzo" (Section.layout): flashcards en catalogo/seccion.html.
   Sin JS ambas caras se ven apiladas; con .flashcards--js es una tarjeta
   por vez que gira al tocarla. */
.bosquejo-tarjetas {
    flex: 1;
    min-height: 0;
    display: flex;
    gap: 0.25rem;
    align-items: center;
    justify-content: center;
}

.bosquejo-tarjetas span {
    width: 40%;
    height: 70%;
    border-radius: 3px;
    background: var(--azul-palido-borde);
}

.flashcards {
    margin-top: 1.5rem;
}

.flashcard__cuerpo {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
    width: 100%;
    padding: 1.25rem;
    text-align: left;
    font: inherit;
    color: var(--cuerpo);
    background: var(--superficie);
    border: 1px solid var(--niebla);
    border-radius: var(--radio);
    cursor: default;
}

.flashcard + .flashcard {
    margin-top: 1rem;
}

.flashcard__cara--frente {
    color: var(--tinta);
    font-weight: 600;
}

.flashcards--js .flashcard {
    perspective: 1200px;
}

/* Efecto de giro: el botón rota en Y y cada cara se esconde por detrás
   (backface-visibility); el fondo vive en las caras, no en el botón. */
.flashcards--js .flashcard__cuerpo {
    position: relative;
    display: block;
    min-height: 16rem;
    padding: 0;
    background: none;
    border: 0;
    cursor: pointer;
    transform-style: preserve-3d;
    transition: transform 0.6s cubic-bezier(0.4, 0.2, 0.2, 1);
}

.flashcards--js .flashcard--girada .flashcard__cuerpo {
    transform: rotateY(180deg);
}

.flashcards--js .flashcard__cara {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 1.25rem;
    overflow-y: auto;
    text-align: center;
    background: var(--superficie);
    border: 1px solid var(--niebla);
    border-radius: var(--radio);
    -webkit-backface-visibility: hidden;
    backface-visibility: hidden;
}

.flashcards--js .flashcard__cara--frente {
    font-size: 1.15rem;
}

.flashcards--js .flashcard__cara--reverso {
    background: var(--azul-palido);
    border-color: var(--azul-palido-borde);
    transform: rotateY(180deg);
}

@media (prefers-reduced-motion: reduce) {
    .flashcards--js .flashcard__cuerpo {
        transition: none;
    }
}

.flashcards__nav {
    display: none;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    margin-top: 1rem;
}

.flashcards--js .flashcards__nav {
    display: flex;
}

.flashcards__contador {
    color: var(--tinta-suave);
    font-size: 0.9rem;
}

/* Editor de tarjetas (layout "refuerzo") en el Studio. */
.editor-estudio__generar-ia {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: 0.75rem;
    margin-top: 1rem;
}

.editor-estudio__generar-ia label {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
    font-size: 0.85rem;
    color: var(--tinta-tenue);
}

.editor-estudio__progreso-ia {
    flex-basis: 100%;
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
    font-size: 0.85rem;
    color: var(--tinta-suave);
}

.editor-estudio__progreso-ia[hidden] {
    display: none;
}

.editor-estudio__progreso-ia small {
    color: var(--tinta-tenue);
}

.editor-estudio__progreso-barra {
    height: 6px;
    overflow: hidden;
    border-radius: 999px;
    background: var(--niebla);
}

.editor-estudio__progreso-barra span {
    display: block;
    width: 35%;
    height: 100%;
    border-radius: inherit;
    background: var(--primario);
    animation: progreso-ia-deslizar 1.4s ease-in-out infinite;
}

@keyframes progreso-ia-deslizar {
    0% { transform: translateX(-100%); }
    100% { transform: translateX(290%); }
}

@media (prefers-reduced-motion: reduce) {
    .editor-estudio__progreso-barra span {
        animation: none;
        width: 100%;
        opacity: 0.6;
    }
}

/* Tarjetas con IA: no hay subtítulo ni audio, solo el código del idioma. */
/* Tarjetas con IA: sin subtítulo ni audio; cada chip lleva un globo en su lugar. */
.editor-estudio__chips-idioma--solo-codigo .editor-estudio__chip-idioma svg {
    display: none;
}

.editor-estudio__chips-idioma--solo-codigo .editor-estudio__chip-idioma::after {
    content: "";
    width: 14px;
    height: 14px;
    flex-shrink: 0;
    background-color: var(--tinta-tenue);
    -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpath d='M2 12h20'/%3E%3Cpath d='M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z'/%3E%3C/svg%3E") center / contain no-repeat;
    mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpath d='M2 12h20'/%3E%3Cpath d='M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z'/%3E%3C/svg%3E") center / contain no-repeat;
}

.editor-estudio__chips-idioma--solo-codigo .editor-estudio__chip-idioma--activo::after {
    background-color: var(--primario);
}

.editor-estudio__tarjetas {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
    margin-top: 1rem;
}

.editor-estudio__tarjetas-lista {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
}

.editor-estudio__tarjeta {
    padding: 0.75rem 1rem 1rem;
    background: var(--papel);
    border: 1px solid var(--niebla);
    border-radius: 12px;
}

.editor-estudio__tarjeta-cabecera {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 0.5rem;
}

.editor-estudio__tarjeta-titulo {
    font-size: 0.8rem;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--tinta-suave);
}

.editor-estudio__tarjeta-cabecera .icono-circular {
    font-size: 1.25rem;
    line-height: 1;
}

.editor-estudio__tarjeta-caras {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 0.75rem;
}

@media (max-width: 640px) {
    .editor-estudio__tarjeta-caras {
        grid-template-columns: 1fr;
    }
}

/* Cada cara es una mini tarjeta: el frente destaca como en el alumno,
   el reverso lleva el tinte azul de la cara girada. */
.editor-estudio__tarjeta-cara {
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
    padding: 0.75rem;
    background: var(--superficie);
    border: 1px solid var(--niebla);
    border-radius: var(--radio);
}

.editor-estudio__tarjeta-cara--reverso {
    background: var(--azul-palido);
    border-color: var(--azul-palido-borde);
}

.editor-estudio__tarjeta-rotulo {
    font-size: 0.7rem;
    font-weight: 700;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: var(--tinta-tenue);
}

.editor-estudio__tarjeta-cara textarea {
    width: 100%;
    min-height: 6rem;
    font: inherit;
    resize: vertical;
    background: transparent;
    border: 0;
    padding: 0;
}

.editor-estudio__tarjeta-cara--frente textarea {
    font-weight: 600;
}

.editor-estudio__tarjeta-cara textarea:focus {
    outline: none;
}

.editor-estudio__tarjeta-cara:focus-within {
    border-color: var(--primario);
    box-shadow: 0 0 0 3px var(--foco);
}

.editor-estudio__tarjetas > .boton {
    align-self: flex-start;
}

.editor-estudio__form {
    flex: 1;
    min-width: 0;
}

.editor-estudio__seccion {
    background: var(--superficie);
    border: 1px solid var(--niebla);
    border-radius: var(--radio-tarjeta);
    box-shadow: var(--sombra);
    padding: 1.5rem;
    margin-bottom: 1.5rem;
    scroll-margin-top: 4.5rem;
}

/* Selector "input.editor-estudio__titulo-campo" a propósito: por
   especificidad, "input[type=\"text\"]" (elemento + atributo) empata con una
   clase sola y gana por venir antes en el archivo - el border:none quedaba
   sin efecto. Con "input" + clase igualamos esa especificidad y ganamos por
   venir después. */
input.editor-estudio__titulo-campo {
    width: 100%;
    max-width: none;
    min-height: 0;
    border: none;
    background: none;
    font-family: var(--fuente-display);
    font-weight: 700;
    font-size: 1.5rem;
    color: var(--tinta);
    padding: 0.3rem 0.4rem;
    margin-bottom: 0.75rem;
    border-radius: var(--radio);
}

input.editor-estudio__titulo-campo:hover,
input.editor-estudio__titulo-campo:focus {
    background: var(--papel);
}

/* Contenedor del toolbar + textarea: el toolbar flota DENTRO del campo de
   texto (position:absolute anclado arriba), no como una barra aparte
   encima - un solo campo de edición, no dos cajas apiladas. El hidden vive
   acá (no en el toolbar ni el textarea por separado) para esconder ambos
   de una. */
.editor-estudio__editor-md {
    position: relative;
}

.editor-estudio__editor-md textarea.editor-md {
    padding-top: 3.5rem;
    min-height: 12rem;
}

.editor-estudio__toolbar {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    z-index: 1;
    display: flex;
    align-items: center;
    gap: 0.1rem;
    flex-wrap: wrap;
    border: none;
    border-bottom: 1px solid var(--niebla);
    border-radius: var(--radio) var(--radio) 0 0;
    background: var(--papel);
    box-shadow: none;
    padding: 0.4rem 0.5rem;
}

.editor-estudio__toolbar button {
    width: 30px;
    height: 30px;
    min-width: 30px;
    min-height: 30px;
    padding: 0;
    border: none;
    box-shadow: none;
    background: none;
    color: var(--tinta-suave);
    border-radius: 6px;
    font-family: var(--fuente-display);
    font-size: 0.85rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}

.editor-estudio__toolbar button:hover {
    background: var(--azul-palido);
    color: var(--primario-oscuro);
}

.editor-estudio__toolbar svg {
    width: 15px;
    height: 15px;
}

.editor-estudio__toolbar-separador {
    width: 1px;
    height: 20px;
    background: var(--niebla);
    margin: 0 0.35rem;
    flex-shrink: 0;
}

.editor-estudio__cuerpo-campo {
    border: 1px solid var(--niebla);
    border-top: none;
    border-radius: 0 0 var(--radio) var(--radio);
    background: var(--papel);
    padding: 1.25rem;
}

/* Dentro de la vista previa de lectura (no debajo de la barra de formato
   oculta, que es donde vive la variante de arriba): es una caja aparte, no
   la mitad inferior de otra, así que necesita los 4 bordes propios. */
.vista-previa-seccion .editor-estudio__cuerpo-campo {
    border-top: 1px solid var(--niebla);
    border-radius: var(--radio);
}

.editor-estudio__cuerpo-campo .contenido-seccion {
    padding: 0;
    font-size: 0.95rem;
}

.editor-estudio__cuerpo-campo .contenido-seccion p {
    text-align: left;
    margin: 0 0 1rem;
}

.editor-estudio__cuerpo-vacio {
    color: var(--tinta-tenue);
    font-style: italic;
}

/* Traducir con IA (placeholder): ícono flotante arriba a la derecha del
   panel de idioma, mismo lugar que el engranaje de la card pero un nivel
   más abajo (por idioma, no por sección) - solo aparece sin traducción. */
.editor-estudio__idioma-panel {
    position: relative;
}

.editor-estudio__traduccion-ia {
    position: absolute;
    top: 0;
    right: 0;
}

/* Girando mientras Claude responde (D093) - único indicador de progreso del
   botón, que no tiene texto propio. prefers-reduced-motion: se queda quieto
   pero con opacidad reducida, misma señal de "ocupado" sin animación. */
@keyframes editor-estudio__girar-sparkles {
    to {
        transform: rotate(360deg);
    }
}

.editor-estudio__traduccion-ia--cargando svg {
    animation: editor-estudio__girar-sparkles 0.9s linear infinite;
}

@media (prefers-reduced-motion: reduce) {
    .editor-estudio__traduccion-ia--cargando svg {
        animation: none;
        opacity: 0.5;
    }
}

/* Transcribir con IA (placeholder): mismo criterio que traducir-ia, pero
   junto al bloque de texto en sí (no en el modal) - es la acción que llena
   ese mismo texto a partir del audio del video, así que vive donde está el
   texto, no escondida en la configuración. */
.editor-estudio__cuerpo-envoltorio {
    position: relative;
}

.editor-estudio__transcripcion-ia {
    position: absolute;
    top: 8px;
    right: 8px;
}

/* Contador de "Transcribiendo... 0:0X" mientras espera a Gemini - flota a
   la izquierda del ícono, mismo contenedor con position:relative. */
/* Flota ARRIBA del recuadro entero (no "a la izquierda del ícono" adentro
   del mismo) - puesta adentro se superponía con el placeholder vacío o con
   la barra de formato del editor, según cuál de los dos estuviera visible
   en ese momento (mismo contenedor, ambos ocupan esa esquina). */
.editor-estudio__transcripcion-ia-estado {
    position: absolute;
    bottom: 100%;
    right: 0;
    margin-bottom: 8px;
    max-width: 100%;
    background: var(--superficie);
    border: 1px solid var(--niebla);
    border-radius: 999px;
    padding: 4px 10px;
    font-size: 11px;
    font-weight: 600;
    color: var(--tinta-suave);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    box-shadow: var(--sombra-hover);
    z-index: 2;
}

/* Mismo spinner que el botón de traducir (D093) - reusa el keyframe
   "editor-estudio__girar-sparkles" ya definido más arriba. Sin esto la
   clase --cargando se agregaba/quitaba bien (JS ok) pero no se veía nada
   distinto mientras esperaba a Gemini. */
.editor-estudio__transcripcion-ia--cargando svg {
    animation: editor-estudio__girar-sparkles 0.9s linear infinite;
}

@media (prefers-reduced-motion: reduce) {
    .editor-estudio__transcripcion-ia--cargando svg {
        animation: none;
        opacity: 0.5;
    }
}

/* Genérico: cualquier otro ícono circular de IA (hoy, "Generar con IA" de
   doblaje/subtítulos en el modal) que quiera el mismo spin sin necesitar su
   propia clase con nombre. */
.icono-circular--cargando svg {
    animation: editor-estudio__girar-sparkles 0.9s linear infinite;
}

/* Editor bloqueado mientras la IA transcribe (D095): el texto está a punto
   de reemplazarse, así que se ve claramente "no tocar todavía" en vez de
   dejar que se seleccione/edite un contenido que va a desaparecer solo. */
.editor-estudio__editor-md--bloqueado {
    opacity: 0.55;
    pointer-events: none;
    cursor: not-allowed;
}

@media (prefers-reduced-motion: reduce) {
    .icono-circular--cargando svg {
        animation: none;
        opacity: 0.5;
    }
}

/* Dropzone (mockup Main.dc.html): ocupa el lugar del video mientras la
   sección no tiene ninguno - subir o grabar quedan a un clic, sin pasar por
   el engranaje. */
.editor-estudio__video-vacio {
    display: flex;
    border: 2px dashed var(--niebla);
    border-radius: var(--radio-tarjeta);
    overflow: hidden;
    margin-bottom: 1rem;
    background: var(--papel);
}

/* Compuesto (no ".editor-estudio__video-vacio-opcion" solo) para ganarle en
   especificidad a ".campo label" (0,1,1) - esta opción es un <label>, y sin
   esto el "display: block" de esa regla gana y descuadra todo (mismo patrón
   de bug de especificidad que ya salió varias veces en este editor). */
.editor-estudio__video-vacio .editor-estudio__video-vacio-opcion {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.6rem;
    padding: 2.5rem 1rem;
    background: none;
    border: none;
    color: var(--tinta-suave);
    font-size: 13px;
    font-weight: 600;
    cursor: pointer;
    margin: 0;
}

.editor-estudio__video-vacio-opcion:hover {
    color: var(--tinta);
}

.editor-estudio__video-vacio-opcion svg {
    width: 26px;
    height: 26px;
    stroke: var(--primario);
}

/* "Reemplazar video" bajo el reproductor. Compuesto para ganarle a
   ".campo label" (mismo bug de especificidad que la dropzone). */
.editor-estudio__video-acciones {
    display: flex;
    justify-content: flex-end;
    gap: 1.25rem;
    margin-top: 0.5rem;
}

.editor-estudio__video-acciones [hidden] {
    display: none;
}

.editor-estudio__video-acciones .editor-estudio__video-reemplazar {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    margin: 0;
    font-size: 13px;
    font-weight: 600;
    color: var(--tinta-suave);
    cursor: pointer;
}

.editor-estudio__video-acciones .editor-estudio__video-reemplazar {
    text-decoration: none;
}

.editor-estudio__video-acciones .editor-estudio__video-reemplazar:hover {
    color: var(--tinta);
}

.editor-estudio__video-reemplazar svg {
    width: 16px;
    height: 16px;
    stroke: var(--primario);
}

.editor-estudio__video-acciones.editor-estudio__subida--activa {
    justify-content: stretch;
}

/* Avance de subida de video/audio: ocupa la dropzone (o el texto de la
   fila del modal) mientras sube, así no parece que no pasó nada. */
.editor-estudio__video-vacio.editor-estudio__subida--activa {
    align-items: center;
    padding: 2.5rem 1.5rem;
}
.editor-estudio__video-vacio-divisor {
    width: 1px;
    background: var(--niebla);
}

/* Mismo criterio que el título (input.editor-estudio__titulo-campo): clic
   directo para editar, sin botón aparte - el hover/focus es la única pista
   de que es editable. */
.editor-estudio__cuerpo-campo--clicable {
    cursor: text;
    transition: background var(--transicion) 120ms;
}

.editor-estudio__cuerpo-campo--clicable:hover,
.editor-estudio__cuerpo-campo--clicable:focus-visible {
    background: var(--azul-palido);
    outline: none;
}

.editor-estudio__idioma-panel textarea.editor-md {
    min-height: 8rem;
}

/* Bloque de video como "chip" (mismo criterio visual que el mockup): miniatura
   + nombre + estado de subtítulos, con la acción de editar/insertar debajo. */
.editor-estudio__bloque-video {
    margin-top: 1rem;
}

.editor-estudio__bloque-video-chip {
    display: flex;
    align-items: center;
    gap: 0.9rem;
    border: 1px solid var(--azul-palido-borde);
    background: var(--azul-palido);
    border-radius: var(--radio);
    padding: 0.9rem;
    margin-bottom: 0.75rem;
}

.editor-estudio__bloque-video-icono {
    width: 56px;
    height: 40px;
    border-radius: 6px;
    background: var(--pizarra);
    color: #fff;
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: center;
}

.editor-estudio__bloque-video-icono svg {
    width: 16px;
    height: 16px;
}

.editor-estudio__bloque-video-texto {
    flex: 1;
    min-width: 0;
}

.editor-estudio__bloque-video-texto p {
    margin: 0;
}

.editor-estudio__bloque-video-nombre {
    font-size: 0.85rem;
    color: var(--tinta);
    font-weight: 600;
}

.editor-estudio__bloque-video-subtitulos {
    font-size: 0.78rem;
    color: var(--tinta-suave);
}

.editor-estudio__bloque-video-subtitulos .ok {
    color: var(--ok);
}

.editor-estudio__panel {
    border: 1px solid var(--niebla);
    background: var(--papel);
    border-radius: var(--radio-tarjeta);
    padding: 1rem;
}

.editor-estudio__panel summary {
    font-size: 0.85rem;
}

/* En flujo normal, sin sticky ni fixed: es el cierre del formulario, no un
   elemento que flota sobre el contenido mientras se hace scroll (eso fue lo
   que se vio raro tanto con position:fixed como con position:sticky - en
   ambos casos tapaba el video/texto de arriba antes de llegar al final). */
.editor-estudio__acciones {
    background: var(--superficie);
    border: 1px solid var(--niebla);
    border-radius: var(--radio-tarjeta);
    box-shadow: var(--sombra-hover);
    padding: 1rem 1.25rem;
    margin-top: 0.5rem;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.6rem 0.75rem;
}

.editor-estudio__acciones-aviso {
    flex: 1 1 16rem;
    font-size: 0.82rem;
    color: var(--tinta-suave);
    margin-right: auto;
}

.editor-estudio__quitar-archivo {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: auto;
    height: auto;
    min-width: 0;
    min-height: 0;
    margin-left: 0.4rem;
    padding: 0;
    border: 0;
    border-radius: 0;
    background: transparent;
    box-shadow: none;
    color: var(--tinta-suave);
    cursor: pointer;
    flex-shrink: 0;
    /* Solo aparece al pasar el mouse por el nombre del archivo. */
    opacity: 0;
    transition: opacity 0.15s ease;
}

.editor-estudio__fila-valor:hover .editor-estudio__quitar-archivo,
.editor-estudio__quitar-archivo:focus-visible {
    opacity: 1;
}

.editor-estudio__quitar-archivo:hover {
    color: var(--error);
    background: transparent;
}

.editor-estudio__quitar-archivo--confirmar {
    opacity: 1;
    color: var(--error);
    font-size: 0.75rem;
    font-weight: 600;
}

/* En pantallas táctiles no hay hover: la x queda siempre visible. */
@media (hover: none) {
    .editor-estudio__quitar-archivo {
        opacity: 1;
    }
}

.editor-estudio__archivo-descarga {
    color: inherit;
    text-decoration: none;
    overflow: hidden;
    text-overflow: ellipsis;
}

.editor-estudio__archivo-descarga:hover,
.editor-estudio__archivo-descarga:focus-visible {
    text-decoration: underline;
}

/* Dos líneas: arriba la barra (con el botón del extracto), abajo el mensaje
   de la etapa con % y tiempo - así el texto largo no aprieta la barra. */
.editor-estudio__cronometro-ia {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    column-gap: 0.5rem;
    row-gap: 0.2rem;
    width: 100%;
    min-width: 0;
    font-size: 0.75rem;
    font-variant-numeric: tabular-nums;
    color: var(--tinta-suave);
}

.editor-estudio__barra-ia {
    position: relative;
    flex: 1 1 0;
    min-width: 4rem;
    height: 6px;
    border-radius: 3px;
    background: var(--borde);
    overflow: hidden;
}

.editor-estudio__barra-ia-relleno {
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    width: 0;
    background: var(--primario);
    border-radius: 3px;
    transition: width 0.4s ease;
}

/* Sin avance real todavía: una franja que va y viene (no un % inventado). */
.editor-estudio__barra-ia--indeterminada .editor-estudio__barra-ia-relleno {
    width: 30%;
    animation: barra-ia-indeterminada 1.4s ease-in-out infinite;
}

@keyframes barra-ia-indeterminada {
    0% { left: -30%; }
    100% { left: 100%; }
}

@media (prefers-reduced-motion: reduce) {
    .editor-estudio__barra-ia--indeterminada .editor-estudio__barra-ia-relleno {
        animation: none;
        opacity: 0.5;
    }
}

.editor-estudio__barra-ia-cabezal {
    position: absolute;
    top: 0;
    bottom: 0;
    width: 2px;
    margin-left: -1px;
    background: var(--texto-en-oscuro);
}

.editor-estudio__cronometro-ia-texto {
    order: 3;
    flex: 1 0 100%;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.editor-estudio__extracto-ia {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    width: 1.6rem;
    height: 1.6rem;
    min-width: 0;
    min-height: 0;
    padding: 0;
    border: 1px solid var(--primario);
    border-radius: 50%;
    background: transparent;
    box-shadow: none;
    color: var(--primario);
    cursor: pointer;
}

.editor-estudio__extracto-ia:hover,
.editor-estudio__extracto-ia:focus-visible {
    background: var(--primario);
    color: var(--superficie);
}

.editor-estudio__extracto-ia[hidden] {
    display: none;
}

.editor-estudio__extracto-ia svg {
    width: 0.8rem;
    height: 0.8rem;
}

/* D102: botón de IA mientras dobla - al pasarle el mouse deja de girar y
   se tiñe de error para ofrecer "Detener". */
.icono-circular[data-detenible="1"]:hover,
.icono-circular[data-detenible="1"]:focus-visible {
    animation: none;
    color: var(--error);
    border-color: var(--error);
}

.icono-circular[data-detenible="1"]:hover svg,
.icono-circular[data-detenible="1"]:focus-visible svg {
    animation: none;
}

.editor-estudio__acciones-aviso--error {
    color: var(--error);
}

/* Los botones nunca se achican ni parten el texto en dos líneas (el aviso de
   al lado sí puede envolver, es texto libre): sin esto, en un ancho medio
   los tres se repartían el espacio por igual y "Guardar contenido"/"Volver
   sin guardar" quedaban cortados a la mitad. */
.editor-estudio__acciones .boton {
    flex-shrink: 0;
    white-space: nowrap;
}

@media (max-width: 900px) {
    .editor-estudio__cuerpo {
        flex-direction: column;
    }

    .editor-estudio__riel {
        position: static;
        flex: 1 1 auto;
        width: 100%;
    }
}

/* ===== Port del mockup de Fábrica 2.0 (D090+): selector de idioma como
   dropdown, engranaje con modal por idioma, chips de estado, grabación con
   cámara + telepronter. Reusa las mismas custom properties de :root que el
   resto del editor - solo el telepronter define sus propios 4 temas de
   color (paleta ajena a la del theme claro/oscuro de la app, es una
   preferencia de lectura en pantalla completa, no del sitio). ===== */

.editor-estudio__cabecera-seccion {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 0.75rem;
    margin-bottom: 0.5rem;
}

/* D098: el <select> de idioma que vivía acá se quitó (los chips debajo del
   video lo reemplazan) - el engranaje queda solo en la cabecera, así que
   sin esto space-between lo pegaría a la izquierda en vez de a la derecha. */
.editor-estudio__cabecera-seccion .editor-estudio__engranaje {
    margin-left: auto;
}

/* Ícono circular reutilizable (botón "Subir otro archivo", "Grabar con
   cámara", "Generar con IA", etc. del modal de engranaje). */
.icono-circular {
    flex-shrink: 0;
    min-height: 0;
    min-width: 0;
    width: 32px;
    height: 32px;
    padding: 0;
    border-radius: 50%;
    background: var(--azul-palido);
    border: 1px solid var(--azul-palido-borde);
    box-shadow: none;
    color: var(--primario);
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
}

.icono-circular:hover {
    background: var(--azul-palido-borde);
}

.icono-circular svg {
    width: 15px;
    height: 15px;
}

.editor-estudio__engranaje {
    flex-shrink: 0;
}

/* Chips de estado por idioma (reemplazan el resumen de texto plano
   "Subtitles: ES ✓ · EN - · PT-BR -"): un chip por idioma con su código y
   dos íconos (subtítulo, audio), verdes si existen, grises si faltan. */
.editor-estudio__chips-idioma {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin-top: 0.75rem;
    margin-bottom: 1rem;
}

/* D098: era un <span> puramente informativo, ahora es el <button> que
   cambia el idioma previsualizado (reemplaza al <select> de arriba) -
   min-height/min-width/box-shadow puntuales para pisar el estilo de botón
   genérico (min 44x44, sombra), que le queda enorme a una píldora chica. */
.editor-estudio__chip-idioma {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    background: var(--papel);
    border: 1px solid var(--niebla);
    border-radius: 20px;
    padding: 3px 8px 3px 3px;
    min-height: 0;
    min-width: 0;
    box-shadow: none;
    cursor: pointer;
    transition: border-color var(--transicion) 120ms, background var(--transicion) 120ms;
}

.editor-estudio__chip-idioma:hover {
    background: var(--azul-palido);
    border-color: var(--primario);
    color: inherit;
}

.editor-estudio__chip-idioma--activo,
.editor-estudio__chip-idioma--activo:hover {
    background: var(--azul-palido);
    border-color: var(--primario);
}

.editor-estudio__chip-idioma-codigo {
    font-size: 10px;
    font-weight: 700;
    background: var(--superficie);
    border: 1px solid var(--niebla);
    border-radius: 12px;
    padding: 1px 6px;
    color: var(--tinta-suave);
}

.editor-estudio__chip-idioma svg {
    width: 14px;
    height: 14px;
    stroke: var(--tinta-tenue);
    flex-shrink: 0;
}

.editor-estudio__chip-idioma svg.ok {
    stroke: var(--ok);
}

/* Modal de engranaje: configuración de video/audio/subtítulo por idioma,
   sin pie de "Guardar"/"Cancelar" - cada fila sube al tiro. */
.editor-estudio__modal {
    position: fixed;
    inset: 0;
    z-index: 60;
    display: flex;
    align-items: flex-start;
    justify-content: center;
    padding: 48px 24px;
}

.editor-estudio__modal[hidden] {
    display: none;
}

/* Aviso flotante (RF-16+): reemplaza a window.alert() para errores de IA -
   algunos navegadores embebidos (incluido el que usa Claude para
   previsualizar) suprimen los diálogos nativos y hacen que alert() no
   muestre nada, dejando el botón "sin reaccionar" a los ojos de quien
   prueba. Vive fuera de cualquier modal para poder mostrarse encima de
   todo, con auto-dismiss - no bloquea la interacción como alert() sí lo
   hacía. */
.editor-estudio__aviso {
    position: fixed;
    left: 50%;
    bottom: 24px;
    transform: translateX(-50%) translateY(8px);
    max-width: min(480px, calc(100vw - 32px));
    background: var(--superficie);
    border: 1px solid var(--niebla);
    border-left: 3px solid var(--error);
    border-radius: var(--radio-panel);
    box-shadow: 0 24px 60px rgba(20, 30, 40, 0.35);
    padding: 14px 18px;
    font-size: 0.9rem;
    color: var(--tinta);
    z-index: 1000;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.2s ease, transform 0.2s ease;
}

.editor-estudio__aviso--visible {
    opacity: 1;
    transform: translateX(-50%) translateY(0);
}

.editor-estudio__modal-fondo {
    position: absolute;
    inset: 0;
    background: rgba(20, 28, 34, 0.45);
}

.editor-estudio__modal-caja {
    position: relative;
    width: min(640px, 100%);
    max-height: calc(100vh - 96px);
    overflow: auto;
    background: var(--superficie);
    border-radius: var(--radio-panel);
    box-shadow: 0 24px 60px rgba(20, 30, 40, 0.35);
}

.editor-estudio__modal-cabecera {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    padding: 20px 24px;
    border-bottom: 1px solid var(--niebla);
    position: sticky;
    top: 0;
    background: var(--superficie);
    border-radius: var(--radio-panel) var(--radio-panel) 0 0;
}

.editor-estudio__modal-titulo {
    font-weight: 700;
    font-size: 1.1rem;
    color: var(--tinta);
    margin: 0;
}

.editor-estudio__modal-subtitulo {
    font-size: 0.82rem;
    color: var(--tinta-suave);
    margin: 0.15rem 0 0;
}

.editor-estudio__modal-cerrar {
    flex-shrink: 0;
    width: 32px;
    height: 32px;
    border-radius: 50%;
    background: none;
    border: 1px solid var(--niebla);
    color: var(--tinta-suave);
    display: flex;
    align-items: center;
    justify-content: center;
}

.editor-estudio__modal-cuerpo {
    padding: 20px 24px 28px;
    display: flex;
    flex-direction: column;
    gap: 26px;
}

/* D105: cabecera del idioma con el botón único de IA a la derecha. */
.editor-estudio__modal-idioma-cabecera {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
}

.editor-estudio__modal-idioma-cabecera .etiqueta-seccion {
    margin: 0;
}

.editor-estudio__modal-idioma + .editor-estudio__modal-idioma {
    border-top: 1px solid var(--niebla);
    padding-top: 20px;
}

.editor-estudio__fila-campo {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-top: 8px;
}

.editor-estudio__fila-nombre {
    width: 78px;
    flex-shrink: 0;
    font-size: 13px;
    font-weight: 600;
    color: var(--tinta);
}

.editor-estudio__fila-valor {
    flex: 1;
    min-width: 0;
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 13px;
    color: var(--tinta-tenue);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.editor-estudio__fila-valor--ok {
    color: var(--ok);
}

.editor-estudio__fila-valor svg {
    width: 13px;
    height: 13px;
    flex-shrink: 0;
}

/* Vista de grabación con cámara + telepronter: pantalla completa sobre el
   editor, marco de cámara en vivo y overlay semitransparente con el texto
   de la sección en el idioma que se está grabando. */
.editor-estudio__grabacion {
    position: fixed;
    inset: 0;
    z-index: 70;
    background: var(--papel);
    display: flex;
    flex-direction: column;
}

.editor-estudio__grabacion[hidden] {
    display: none;
}

.editor-estudio__grabacion-cabecera {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 16px 24px;
}

.editor-estudio__grabacion-estado {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 13px;
    font-weight: 600;
    color: var(--tinta);
}

.editor-estudio__punto-en-vivo {
    width: 9px;
    height: 9px;
    border-radius: 50%;
    background: var(--error);
}

.editor-estudio__grabacion-marco {
    flex: 1;
    margin: 0 24px;
    border-radius: var(--radio-tarjeta);
    background: #1b242b;
    position: relative;
    overflow: hidden;
}

.editor-estudio__grabacion-video {
    width: 100%;
    height: 100%;
    object-fit: cover;
    background: #1b242b;
}

/* Regrabar solo audio (D092): reemplaza el <video> mientras esa toma no
   necesita cámara - mismo marco, un ícono de micrófono centrado en vez de
   la imagen. */
.editor-estudio__grabacion-audio-marca {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    color: #3a4852;
}

.editor-estudio__grabacion-audio-marca[hidden] {
    display: none;
}

.editor-estudio__grabacion-audio-marca svg {
    width: 72px;
    height: 72px;
}

.editor-estudio__grabacion-error {
    position: absolute;
    inset: auto 24px 24px;
    background: var(--error-fondo);
    color: var(--error);
    border-radius: var(--radio);
    padding: 0.75rem 1rem;
    font-size: 0.85rem;
}

.editor-estudio__grabacion-pie {
    padding: 22px 24px 30px;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 10px;
}

.editor-estudio__grabacion-nota {
    font-size: 12.5px;
    color: var(--tinta-suave);
    margin: 0;
    text-align: center;
    max-width: 520px;
}

.editor-estudio__grabacion-boton {
    width: 64px;
    height: 64px;
    border-radius: 50%;
    background: var(--error);
    border: 4px solid var(--azul-palido-borde);
}

.editor-estudio__grabacion-boton--activo {
    border-radius: 12px;
}

/* Telepronter: 4 temas de color propios (no son tokens del theme claro/
   oscuro de la app - son una preferencia de lectura en pantalla completa,
   pensada para funcionar igual sin importar el theme del sitio, así que
   van con sus valores literales en vez de las custom properties de :root). */
.editor-estudio__telepronter {
    position: absolute;
    top: 24px;
    left: 24px;
    right: 24px;
    max-height: 55%;
    overflow: auto;
    border-radius: var(--radio-tarjeta);
    padding: 24px 28px;
    box-shadow: var(--sombra-hover);
    background: rgba(255, 255, 255, 0.92);
    color: #1e2a32;
}

.editor-estudio__telepronter[data-estilo-prompter="oscuro"] {
    background: rgba(20, 28, 34, 0.9);
    color: #fff;
}

.editor-estudio__telepronter[data-estilo-prompter="sepia"] {
    background: rgba(241, 230, 206, 0.95);
    color: #4a3b23;
}

.editor-estudio__telepronter[data-estilo-prompter="contraste"] {
    background: rgba(0, 0, 0, 0.95);
    color: #ffe24a;
}

.editor-estudio__telepronter-cabecera {
    position: sticky;
    top: -24px;
    margin: -24px -28px 14px;
    padding: 24px 28px 10px;
    background: inherit;
    display: flex;
    align-items: center;
    justify-content: space-between;
    z-index: 1;
}

.editor-estudio__telepronter-acciones {
    display: flex;
    align-items: center;
    gap: 8px;
}

.editor-estudio__telepronter-boton {
    width: 28px;
    height: 28px;
    border-radius: 50%;
    background: var(--azul-palido);
    border: 1px solid var(--azul-palido-borde);
    color: var(--primario);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    min-height: 0;
    min-width: 0;
}

.editor-estudio__telepronter-boton svg {
    width: 12px;
    height: 12px;
}

.editor-estudio__telepronter-paleta-envoltorio {
    position: relative;
}

.editor-estudio__telepronter-paleta {
    position: absolute;
    top: 34px;
    right: 0;
    display: flex;
    gap: 8px;
    background: var(--superficie);
    border: 1px solid var(--niebla);
    border-radius: 20px;
    padding: 6px;
    box-shadow: var(--sombra-hover);
    z-index: 1;
}

.editor-estudio__telepronter-paleta button {
    width: 26px;
    height: 26px;
    border-radius: 50%;
    border: 2px solid var(--niebla);
    font-size: 11px;
    font-weight: 700;
    min-height: 0;
    min-width: 0;
    padding: 0;
}

.editor-estudio__telepronter-paleta button[data-telepronter-estilo="claro"] { background: #fff; color: #1e2a32; }
.editor-estudio__telepronter-paleta button[data-telepronter-estilo="oscuro"] { background: #1b242b; color: #fff; }
.editor-estudio__telepronter-paleta button[data-telepronter-estilo="sepia"] { background: #f1e6ce; color: #5b4527; }
.editor-estudio__telepronter-paleta button[data-telepronter-estilo="contraste"] { background: #000; color: #ffe24a; }

.editor-estudio__telepronter-texto {
    font-size: 19px;
    line-height: 2;
    letter-spacing: 0.01em;
    word-spacing: 0.06em;
    margin: 0;
}

.editor-estudio__telepronter-vacio {
    font-size: 14px;
    line-height: 1.6;
    margin: 0;
    font-style: italic;
    opacity: 0.85;
}


/* D114: card de refuerzo que pausa el video. Se posiciona sobre el <video>
   dentro de su <figure>; en pantallas angostas deja de ser overlay y se apila
   bajo el video para no tapar los controles. */
.video-seccion {
    position: relative;
}

/* Marcas de las preguntas de refuerzo, bajo el video (mismo ancho que su línea de tiempo). */
.video-marcas {
    position: relative;
    height: 1.25rem;
    margin-top: 0.25rem;
    border-bottom: 2px solid var(--borde);
}

.video-marcas__marca {
    position: absolute;
    bottom: -0.45rem;
    width: 0.9rem;
    height: 0.9rem;
    margin-left: -0.45rem;
    padding: 0;
    border: 2px solid var(--superficie);
    border-radius: 50%;
    background: var(--primario);
    cursor: pointer;
}

.video-marcas__marca--pendiente {
    background: transparent;
    border-color: var(--primario);
}

.video-marcas__marca:hover,
.video-marcas__marca:focus-visible {
    transform: scale(1.3);
}

.video-checkpoint {
    position: absolute;
    inset: 0;
    z-index: 5;
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
    padding: 1.25rem;
    overflow-y: auto;
    background: var(--superficie);
    color: var(--cuerpo);
    border: 1px solid var(--azul-palido-borde);
    border-radius: var(--radio);
}

.video-checkpoint__etiqueta {
    margin: 0;
    font-size: 0.8rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--primario);
}

.video-checkpoint__pendiente {
    margin: 0;
    padding: 0.25rem 0.5rem;
    align-self: flex-start;
    font-size: 0.8rem;
    background: var(--ambar-fondo);
    border-radius: var(--radio);
}

.video-checkpoint__enunciado {
    margin: 0;
    font-weight: 600;
    color: var(--tinta);
}

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

.video-checkpoint__opcion {
    padding: 0.6rem 0.85rem;
    text-align: left;
    font: inherit;
    color: var(--tinta);
    background: var(--superficie);
    border: 1px solid var(--borde);
    border-radius: var(--radio);
    cursor: pointer;
}

.video-checkpoint__opcion:hover:not(:disabled),
.video-checkpoint__opcion:focus-visible {
    border-color: var(--primario);
    outline: 2px solid var(--foco);
}

.video-checkpoint__opcion:disabled {
    cursor: default;
}

.video-checkpoint .video-checkpoint__opcion--correcta,
.video-checkpoint .video-checkpoint__opcion--correcta:disabled {
    background: var(--ok-fondo);
    border-color: var(--ok);
    opacity: 1;
}

.video-checkpoint .video-checkpoint__opcion--incorrecta,
.video-checkpoint .video-checkpoint__opcion--incorrecta:disabled {
    background: var(--error-fondo);
    border-color: var(--error);
    opacity: 1;
}

.video-checkpoint__resultado {
    margin: 0;
    font-weight: 600;
}

.video-checkpoint__resultado.es-correcta {
    color: var(--ok);
}

.video-checkpoint__resultado.es-incorrecta {
    color: var(--error);
}

.video-checkpoint__justificacion {
    margin: 0.25rem 0 0;
}

.video-checkpoint__acciones {
    display: flex;
    gap: 0.5rem;
    margin-top: auto;
}

@media (max-width: 600px) {
    .video-checkpoint {
        position: static;
        margin-top: 0.75rem;
    }
}

/* Panel de preguntas de refuerzo en el editor de contenido (Studio): video a la
   izquierda, preguntas a la derecha; en pantallas angostas el panel baja del video.
   Los puntitos van en una barra propia bajo el video, alineados con su duración. */
.editor-estudio__video-fila--con-panel {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(260px, 340px);
    gap: 1.25rem;
    align-items: start;
}

@media (max-width: 900px) {
    .editor-estudio__video-fila--con-panel {
        grid-template-columns: minmax(0, 1fr);
    }
}

.refuerzos-barra {
    position: relative;
    height: 22px;
    margin-top: 0.4rem;
    border-radius: 999px;
    background: var(--azul-palido);
    border: 1px solid var(--azul-palido-borde);
}

.refuerzos-barra__punto {
    position: absolute;
    top: 50%;
    width: 16px;
    height: 16px;
    margin: -8px 0 0 -8px;
    padding: 0;
    border-radius: 50%;
    border: 2px solid var(--superficie);
    background: var(--primario);
    cursor: pointer;
}

/* Preguntas sin aprobar: punto ámbar, el alumno no las ve. */
.refuerzos-barra__punto--pendiente {
    background: var(--ambar);
}

.refuerzos-barra__punto--activo,
.refuerzos-barra__punto:focus-visible {
    box-shadow: 0 0 0 3px var(--foco);
}

.refuerzos-panel {
    border: 1px solid var(--borde);
    border-radius: var(--radio-tarjeta);
    background: var(--superficie);
    padding: 1rem;
    max-height: 70vh;
    overflow-y: auto;
}

.refuerzos-panel__titulo {
    margin: 0 0 0.75rem;
    font-size: 0.95rem;
}

.refuerzos-panel__lista {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 0.9rem;
}

.refuerzos-panel__item {
    padding: 0.75rem;
    border: 1px solid var(--borde);
    border-radius: var(--radio);
}

.refuerzos-panel__item--activo {
    border-color: var(--primario);
    background: var(--azul-palido);
}

.refuerzos-panel__minuto {
    font-family: var(--fuente-mono);
    font-size: 0.8rem;
    padding: 0.15rem 0.6rem;
    border-radius: 999px;
    border: 1px solid var(--azul-palido-borde);
    background: var(--azul-palido);
    color: var(--primario);
    cursor: pointer;
}

.refuerzos-panel__pendiente {
    margin-left: 0.4rem;
    font-size: 0.75rem;
    color: var(--ambar);
}

.refuerzos-panel__enunciado {
    margin: 0.5rem 0;
    font-weight: 600;
}

.refuerzos-panel__opciones {
    margin: 0;
    padding-left: 1.1rem;
    font-size: 0.9rem;
    color: var(--cuerpo);
}

.refuerzos-panel__opciones .es-correcta {
    color: var(--ok);
    font-weight: 600;
}

.refuerzos-panel__nota {
    margin: 0.5rem 0 0;
    font-size: 0.8rem;
    color: var(--tinta-suave);
}

.refuerzos-panel__cita {
    font-style: italic;
}
