/* Botones — dirección B del kit (src/primitives.jsx, Button).

   Tres diferencias con lo que había: el relleno es plano y no un degradado,
   el radio sube a --radius-md, y al pasar por encima cambia el color en vez
   de desplazarse un píxel. El kit no mueve nada al hacer hover: la
   retroalimentación es de color, no de posición. */
.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    height: 38px;
    padding: 0 14px;
    border-radius: var(--radius-md);
    font-family: var(--font-body);
    font-size: 14px;
    font-weight: 550;
    letter-spacing: -0.005em;
    white-space: nowrap;
    user-select: none;
    border: 1px solid rgb(var(--brand-strong-rgb));
    cursor: pointer;
    transition: background 120ms ease, border-color 120ms ease, color 120ms ease;
    background: rgb(var(--brand-strong-rgb));
    color: rgb(var(--brand-on-rgb));
}
.btn:hover { background: rgb(var(--brand-strong-hover-rgb)); border-color: rgb(var(--brand-strong-hover-rgb)); }
.btn:disabled { opacity: 0.5; cursor: not-allowed; }
.btn:focus-visible {
    outline: 2px solid rgb(var(--brand-strong-rgb));
    outline-offset: 2px;
}

.btn-sm { height: 32px; padding: 0 12px; font-size: 13px; gap: 6px; }
.btn-lg { height: 46px; padding: 0 20px; font-size: 15px; gap: 10px; }

/* El secundario es superficie con borde neutro, no un contorno de marca: en
   una pantalla con varios botones, dos en color de marca compiten. */
.btn-secondary {
    background: rgb(var(--surface-rgb));
    border-color: rgb(var(--line-strong-rgb));
    color: rgb(var(--ink-rgb));
}
.btn-secondary:hover {
    background: rgb(var(--surface-2-rgb));
    border-color: rgb(var(--line-strong-rgb));
}

.btn-ghost {
    background: transparent;
    border-color: transparent;
    color: rgb(var(--ink-rgb));
}
.btn-ghost:hover { background: rgb(var(--surface-2-rgb)); border-color: transparent; }

.btn-soft {
    background: rgb(var(--brand-tint-rgb));
    border-color: transparent;
    color: rgb(var(--brand-text-rgb));
}
.btn-soft:hover { background: rgb(var(--brand-tint-rgb)); filter: brightness(0.96); border-color: transparent; }

.btn-danger {
    background: rgb(var(--danger-rgb));
    border-color: rgb(var(--danger-rgb));
    color: rgb(var(--surface-rgb));
}
.btn-danger:hover {
    background: rgb(var(--danger-text-rgb));
    border-color: rgb(var(--danger-text-rgb));
}

.btn-success {
    background: rgb(var(--success-rgb));
    border-color: rgb(var(--success-rgb));
    color: rgb(var(--surface-rgb));
}
.btn-success:hover {
    background: rgb(var(--success-text-rgb));
    border-color: rgb(var(--success-text-rgb));
}

/* Links */
.link {
    color: rgb(var(--brand-rgb));
    font-weight: 500;
}
.link:hover { color: rgb(var(--brand-rgb)); }

/* Cards */
.card {
    background: rgb(var(--surface-rgb));
    border: var(--border-width) solid rgb(var(--line-rgb));
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-sm);
    padding: 20px;
    transition: box-shadow 160ms ease, border-color 160ms ease;
}

.surface-card {
    background: rgb(var(--surface-rgb));
    border: var(--border-width) solid rgb(var(--line-rgb));
    border-radius: var(--radius-md);
}

.surface-subtle {
    background: rgb(var(--surface-2-rgb));
    border: var(--border-width) solid rgb(var(--line-rgb));
    border-radius: var(--radius-sm);
}

.surface-elevated {
    background: rgb(var(--surface-rgb));
    border: var(--border-width) solid rgb(var(--line-strong-rgb));
    border-radius: var(--radius-md);
}

.text-title { color: rgb(var(--ink-rgb)); }
.text-body { color: rgb(var(--ink-muted-rgb)); }
.text-muted-ui { color: rgb(var(--ink-subtle-rgb)); }

.surface-box {
    background: rgb(var(--surface-2-rgb));
    border: var(--border-width) solid rgb(var(--line-rgb));
    border-radius: var(--radius-md);
}

.demo-card {
    background: rgb(var(--surface-2-rgb));
    border-radius: var(--radius-sm);
    padding: 12px;
}

.divider {
    width: 100%;
    height: 1px;
    background: rgb(var(--line-rgb));
    opacity: 0.7;
}

/* Inputs */
.input-field {
    width: 100%;
    padding: 10px 12px;
    border-radius: var(--radius-md);
    border: var(--border-width) solid rgb(var(--line-rgb));
    background: rgb(var(--surface-2-rgb));
    color: rgb(var(--ink-rgb));
    transition: border-color 0.2s, box-shadow 0.2s, background 0.2s;
}
.input-field:focus {
    outline: none;
    border-color: rgb(var(--brand-strong-rgb));
    box-shadow: 0 0 0 3px rgb(var(--brand-rgb) / 0.18);
}

/* Badges */
/* La dirección B usa una insignia rectangular de esquina suave, no una
   píldora: el radio completo pertenece a la dirección A. */
.badge {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    height: 22px;
    padding: 0 8px;
    border-radius: var(--radius-sm);
    font-size: 12px;
    font-weight: 550;
    letter-spacing: 0.01em;
}
.badge-primary { background: rgb(var(--brand-strong-rgb)); color: rgb(var(--brand-on-rgb)); }
.badge-success { background: rgb(var(--success-tint-rgb)); color: rgb(var(--success-rgb)); }
.badge-warning { background: rgb(var(--warning-tint-rgb)); color: rgb(var(--warning-text-rgb)); }
.badge-error { background: rgb(var(--danger-tint-rgb)); color: rgb(var(--danger-rgb)); }
.badge-info { background: rgb(var(--info-tint-rgb)); color: rgb(var(--info-rgb)); }

.state-success { color: rgb(var(--success-rgb)); }
.state-warning { color: rgb(var(--warning-rgb)); }
.state-danger { color: rgb(var(--danger-rgb)); }
.state-info { color: rgb(var(--info-rgb)); }

/* Progress */
.progress-bar {
    height: 6px;
    background: rgb(var(--line-rgb));
    border-radius: 999px;
    overflow: hidden;
}
.progress-bar-fill {
    height: 100%;
    background: rgb(var(--brand-strong-rgb));
    transition: width 0.4s ease;
}

/* Toast container */
#toastContainer { pointer-events: none; }
#toastContainer > div { pointer-events: auto; }

/* Tables - Option B (soft purple accent) */
.table-shell {
    border: var(--border-width) solid rgb(var(--line-rgb));
    border-radius: var(--radius-md);
    background: rgb(var(--surface-rgb));
    overflow-x: auto;
}

.table-soft {
    width: 100%;
    border-collapse: separate;
    border-spacing: 0;
}

.table-soft thead {
    background: rgb(var(--surface-2-rgb));
}

.table-soft th {
    text-align: left;
    font-size: 0.875rem;
    font-weight: 600;
    color: rgb(var(--ink-subtle-rgb));
    border-bottom: 1px solid rgb(var(--line-rgb));
    padding: 0.85rem 0.75rem;
}

.table-soft td {
    color: rgb(var(--ink-rgb));
    border-bottom: 1px solid rgb(var(--line-rgb));
    padding: 0.85rem 0.75rem;
    background: var(--table-row-bg);
}

.table-soft tbody tr:hover td {
    background: rgb(var(--brand-tint-rgb));
}

.table-soft tbody tr.is-active td {
    background: rgb(var(--brand-tint-rgb));
}

.table-soft-divider {
    border-top: 1px solid rgb(var(--line-rgb));
}

.table-soft-compact th,
.table-soft-compact td {
    padding-top: 0.55rem;
    padding-bottom: 0.55rem;
}

.table-empty-state {
    text-align: center;
    color: rgb(var(--ink-subtle-rgb));
    padding: 2rem 1rem;
}

/* ============================================================
   GLOWLAB-209: Estilos del chat del asistente Lumi
   ============================================================ */

.assistant-chat-container {
    /* Scroll suave + barra de scroll discreta */
    scroll-behavior: smooth;
    scrollbar-width: thin;
    scrollbar-color: rgb(var(--brand-rgb) / 0.4) transparent;
}

.assistant-chat-container::-webkit-scrollbar {
    width: 8px;
}

.assistant-chat-container::-webkit-scrollbar-track {
    background: transparent;
}

.assistant-chat-container::-webkit-scrollbar-thumb {
    background: rgb(var(--brand-rgb) / 0.35);
    border-radius: 4px;
}

.assistant-chat-container::-webkit-scrollbar-thumb:hover {
    background: rgb(var(--brand-rgb) / 0.55);
}

/* Animación sutil de entrada para cada burbuja */
@keyframes bubble-fade-in {
    from {
        opacity: 0;
        transform: translateY(4px);
    }
    to {
        opacity: 1;
        transform: translateY(0);
    }
}

.bubble {
    animation: bubble-fade-in 0.18s ease-out;
    line-height: 1.5;
    word-break: break-word;
}

/* Cuando el input del chat está disabled (mientras Lumi "piensa"),
   damos un cursor de espera para que el feedback sea claro. */
#assistantUserInput:disabled,
#assistantSendBtn:disabled {
    cursor: wait;
}

/* ===== Escala de puntaje del reporte =====
   Portado de report-parts.jsx (RPScoreScale) del UI Kit Habilidy v3.
   La marca del umbral sobre la barra es lo que hace legible la cifra: un 68
   solo no dice nada; un 68 con la aprobación señalada en 70 al lado, sí. */

.escala-puntaje {
    display: flex;
    flex-direction: column;
    gap: 12px;
}
.escala-puntaje.es-compacta { gap: 8px; }

.ep-cifra {
    display: flex;
    align-items: flex-end;
    gap: 12px;
}

.ep-numero {
    font-family: var(--font-display);
    font-weight: 600;
    font-size: 68px;
    line-height: 0.9;
    letter-spacing: -0.03em;
    font-variant-numeric: tabular-nums;
}
.es-compacta .ep-numero { font-size: 46px; }

.ep-total {
    font-family: var(--font-mono);
    font-size: 12px;
    font-weight: 600;
    color: rgb(var(--ink-subtle-rgb));
    padding-bottom: 6px;
}

.ep-delta {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    font-size: 13px;
    font-weight: 600;
    white-space: nowrap;
}
.ep-delta.es-sube  { color: rgb(var(--success-rgb)); }
.ep-delta.es-baja  { color: rgb(var(--danger-rgb)); }
.ep-delta.es-igual { color: rgb(var(--ink-muted-rgb)); }
/* La flecha apunta hacia abajo cuando el puntaje bajó. */
.ep-delta.es-baja svg { transform: rotate(180deg); }
.ep-delta.es-igual svg { display: none; }

/* La zona reserva altura por debajo para la etiqueta del umbral, que va en
   posición absoluta: sin ella, el texto se solaparía con lo que venga después. */
.ep-barra-zona {
    position: relative;
    padding-top: 4px;
    padding-bottom: 22px;
}

.ep-barra {
    height: 8px;
    border-radius: 999px;
    background: rgb(var(--surface-2-rgb));
    overflow: hidden;
}

.ep-relleno {
    height: 100%;
    border-radius: 999px;
    transition: width 0.4s ease;
}

.ep-umbral {
    position: absolute;
    top: 4px;
    width: 0;
}

.ep-umbral-marca {
    position: absolute;
    top: 0;
    width: 2px;
    height: 16px;
    background: rgb(var(--ink-rgb) / 0.55);
    transform: translateX(-1px);
}

.ep-umbral-texto {
    position: absolute;
    top: 18px;
    transform: translateX(-50%);
    white-space: nowrap;
    font-family: var(--font-mono);
    font-size: 9.5px;
    font-weight: 600;
    color: rgb(var(--ink-subtle-rgb));
    text-transform: uppercase;
    letter-spacing: 0.06em;
}

/* ===== Chip del reporte =====
   Portado de report-parts.jsx (RPChip). Monoespaciado y en versalitas: son
   datos, no prosa, y así se distinguen del texto de alrededor sin necesidad
   de más color. */

.chips-cabecera {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

.chip {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    height: 24px;
    padding: 0 9px;
    border-radius: var(--radius-sm);
    border: 1px solid transparent;
    font-family: var(--font-mono);
    font-size: 10.5px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    white-space: nowrap;
}

.chip-neutral {
    background: rgb(var(--surface-2-rgb));
    color: rgb(var(--ink-muted-rgb));
    border-color: rgb(var(--line-rgb));
}
.chip-accent {
    background: rgb(var(--brand-tint-rgb));
    color: rgb(var(--brand-text-rgb));
}
.chip-good {
    background: rgb(var(--success-rgb) / 0.12);
    color: rgb(var(--success-text-rgb));
    border-color: rgb(var(--success-rgb) / 0.26);
}
.chip-warn {
    background: rgb(var(--warning-rgb) / 0.14);
    color: rgb(var(--warning-text-rgb));
    border-color: rgb(var(--warning-rgb) / 0.30);
}
.chip-bad {
    background: rgb(var(--danger-rgb) / 0.10);
    color: rgb(var(--danger-text-rgb));
    border-color: rgb(var(--danger-rgb) / 0.26);
}

/* ===== Radar de criterios =====
   Portado de report-parts.jsx (RPRadar). La geometría la calcula
   app/radar_criterios.py; aquí solo van los colores y los grosores, para que
   cambiar la paleta no obligue a tocar Python. */

.radar-criterios {
    display: block;
    width: 100%;
    max-width: 340px;
    height: auto;
    margin: 0 auto;
    overflow: visible;
}

.rc-anillo,
.rc-eje {
    fill: none;
    stroke: rgb(var(--line-rgb));
    stroke-width: 1;
}

/* El umbral de aprobación va punteado para que no se confunda con los
   anillos de referencia, que solo marcan cuartos. */
.rc-umbral {
    fill: none;
    stroke: rgb(var(--ink-subtle-rgb));
    stroke-width: 1;
    stroke-dasharray: 3 3;
}

.rc-area {
    fill: rgb(var(--brand-rgb) / 0.22);
    stroke: rgb(var(--brand-text-rgb));
    stroke-width: 2;
    stroke-linejoin: round;
}

.rc-vertice {
    fill: rgb(var(--brand-text-rgb));
}

.rc-etiqueta {
    font-family: var(--font-sans);
    font-size: 10.5px;
    font-weight: 600;
    fill: rgb(var(--ink-muted-rgb));
}

.rc-cifra {
    font-family: var(--font-mono);
    font-size: 10px;
}

.rc-success { fill: rgb(var(--success-text-rgb)); }
.rc-warning { fill: rgb(var(--warning-text-rgb)); }
.rc-danger  { fill: rgb(var(--danger-text-rgb)); }
.rc-subtle  { fill: rgb(var(--ink-subtle-rgb)); }

/* ===== Severidad de un hallazgo =====
   Portado de report-parts.jsx (RPSeverity). Cinco barras: las llenas son el
   nivel. Los dos niveles altos avisan con el color de peligro, el tercero con
   el de atención y los dos bajos se quedan en gris — una severidad 1 no
   necesita alarmar a nadie. */

.severidad {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    flex-shrink: 0;
    vertical-align: middle;
}

.severidad .sv-titulo {
    font-family: var(--font-mono);
    font-size: 9.5px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: rgb(var(--ink-subtle-rgb));
}

.severidad .sv-barras {
    display: inline-flex;
    gap: 2px;
}

.severidad .sv-barra {
    width: 5px;
    height: 12px;
    border-radius: 1.5px;
    background: rgb(var(--surface-2-rgb));
    border: 1px solid rgb(var(--line-rgb));
}

.severidad .sv-barra.es-llena {
    border: none;
    background: rgb(var(--ink-muted-rgb));
}

.severidad.es-media .sv-barra.es-llena { background: rgb(var(--warning-rgb)); }
.severidad.es-alta  .sv-barra.es-llena { background: rgb(var(--danger-rgb)); }

/* ===== Marca de tiempo =====
   Portado de report-parts.jsx (RPTimeMark). Neutra a propósito: dice cuándo
   pasó algo, no si estuvo bien, así que no toma el color del hallazgo al que
   acompaña. */

.marca-tiempo {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    height: 20px;
    padding: 0 7px 0 6px;
    border-radius: 999px;
    background: rgb(var(--surface-2-rgb) / 0.7);
    border: 1px solid rgb(var(--line-rgb));
    color: rgb(var(--brand-text-rgb));
    font-family: var(--font-mono);
    font-size: 10.5px;
    font-weight: 600;
    letter-spacing: 0.02em;
    vertical-align: middle;
    flex-shrink: 0;
}

/* ===== Encabezado de sección =====
   Portado de report-parts.jsx (RPSectionHead). */

/* El "← Volver" de las pantallas de detalle y de formulario. Iba en la misma
   línea que el título, compitiendo con él; ahora va encima, como la miga. */
.volver {
    display: inline-block;
    font-size: 13px;
    color: rgb(var(--ink-muted-rgb));
    margin-bottom: -16px;
}
.volver:hover { color: rgb(var(--brand-text-rgb)); }

/* La miga de pan del catálogo de habilidades. Va pegada a la cabecera de la
   pantalla, no separada de ella: es de dónde vienes, no otro bloque. */
.miga {
    font-size: 13px;
    color: rgb(var(--ink-muted-rgb));
    margin-bottom: -20px;
}
.miga a:hover { color: rgb(var(--brand-text-rgb)); }

/* La cabecera de una pantalla. Es hermana de `.enc-seccion` pero de otro
   tamaño: esta es el título de la página, aquella la de un bloque de dentro.
   Antes el título de la página lo pintaba una barra fija en versalitas y
   además cada plantilla lo repetía debajo; ahora se dice una vez. */
.enc-pagina {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 20px;
    flex-wrap: wrap;
    margin-bottom: 28px;
}
.ep-texto { min-width: 0; }
.ep-titulo {
    margin: 0;
    font-family: var(--font-display);
    font-size: 32px;
    font-weight: 600;
    line-height: 1.15;
    letter-spacing: -0.02em;
    color: rgb(var(--ink-rgb));
}
.ep-nota {
    margin: 8px 0 0;
    font-size: 14px;
    line-height: 1.5;
    color: rgb(var(--ink-muted-rgb));
    max-width: 68ch;
}
.ep-aparte {
    display: flex;
    align-items: center;
    gap: 10px;
    /* Los botones de la cabecera se reparten en varias líneas cuando no caben
       en una, y el bloque entero puede encogerse. Con `flex-shrink: 0` y sin
       `wrap` eran, en el formulario de un entrenamiento, 848 px en fila que
       empujaban la página 472 px hacia la derecha. Mientras hay sitio esto no
       cambia nada: un elemento flexible solo se encoge cuando la línea se
       desborda. */
    flex-wrap: wrap;
    min-width: 0;
}

.enc-seccion {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 16px;
    margin-bottom: 16px;
}

.es-antetitulo {
    font-family: var(--font-mono);
    font-size: 10.5px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: rgb(var(--ink-subtle-rgb));
    margin-bottom: 6px;
}

.es-titulo {
    margin: 0;
    font-family: var(--font-display);
    font-size: 20px;
    font-weight: 600;
    letter-spacing: -0.01em;
    color: rgb(var(--ink-rgb));
}

/* La nota se corta a 560px porque a lo ancho de una tarjeta el texto llega a
   pasar de 110 caracteres por línea y se vuelve incómodo de leer. */
.es-nota {
    margin: 6px 0 0;
    font-size: 13px;
    line-height: 1.5;
    max-width: 560px;
    color: rgb(var(--ink-muted-rgb));
}

.es-aparte {
    flex-shrink: 0;
}

/* ===== Biblioteca: filtros por estado =====
   Portado de lib-parts.jsx (LBFilterBar). Chips que se prenden y apagan, con
   el conteo de cada estado. Frente a unas pestañas, esto deja visible en los
   propios controles cuál es la vista por defecto y permite combinarlos.

   El conteo se muestra encendido o apagado: si "Archivados 4" solo apareciera
   al encender el filtro, no habría forma de saber que hay algo ahí. */

.filtros-estado {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
}

.filtro-chip {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    height: 32px;
    padding: 0 12px;
    border-radius: 999px;
    border: var(--border-width) solid rgb(var(--line-rgb));
    background: rgb(var(--surface-rgb));
    color: rgb(var(--ink-subtle-rgb));
    font-size: 13px;
    font-weight: 500;
    white-space: nowrap;
    transition: border-color 120ms ease, background 120ms ease, color 120ms ease;
}

.filtro-chip:hover {
    color: rgb(var(--ink-rgb));
}

.fc-punto {
    width: 7px;
    height: 7px;
    border-radius: 999px;
    background: transparent;
    border: 1px solid rgb(var(--line-strong-rgb));
}

.fc-conteo {
    font-family: var(--font-mono);
    font-size: 11.5px;
    color: rgb(var(--ink-subtle-rgb));
}

.filtro-chip.es-encendido {
    color: rgb(var(--ink-rgb));
}

/* Cada estado enciende con su propio color, el mismo que lleva su insignia:
   así el filtro y lo que aparece en la lista se leen como lo mismo. */
.filtro-chip.es-active.es-encendido {
    border-color: rgb(var(--success-rgb) / 0.40);
    background: rgb(var(--success-rgb) / 0.10);
}
.filtro-chip.es-active.es-encendido .fc-punto {
    background: rgb(var(--success-rgb));
    border: none;
}

.filtro-chip.es-draft.es-encendido {
    border-color: rgb(var(--warning-rgb) / 0.40);
    background: rgb(var(--warning-rgb) / 0.10);
}
.filtro-chip.es-draft.es-encendido .fc-punto {
    background: rgb(var(--warning-rgb));
    border: none;
}

.filtro-chip.es-archived.es-encendido {
    border-color: rgb(var(--line-strong-rgb));
    background: rgb(var(--surface-2-rgb));
}
.filtro-chip.es-archived.es-encendido .fc-punto {
    background: rgb(var(--ink-subtle-rgb));
    border: none;
}

.filtro-todos {
    height: 32px;
    padding: 0 10px;
    display: inline-flex;
    align-items: center;
    font-size: 12.5px;
    font-weight: 500;
    color: rgb(var(--brand-text-rgb));
}

.filtro-todos.es-inerte {
    color: rgb(var(--ink-subtle-rgb));
    opacity: 0.5;
    pointer-events: none;
}


/* ===== Biblioteca: la fila de un entrenamiento =====
   Portado de lib-list.jsx (LBTrainingCard). Fila y no tarjeta: lo que importa
   de un entrenamiento es su nombre, con quién se practica y cuánto dura, y eso
   se lee en una línea. Una rejilla de tarjetas gasta el ancho en carátulas. */

.fila-entrenamiento {
    display: flex;
    gap: 16px;
    align-items: flex-start;
    padding: 16px;
    background: rgb(var(--surface-rgb));
    border: var(--border-width) solid rgb(var(--line-rgb));
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-sm);
}

/* Un borrador se dibuja distinto para que no haga falta leer su insignia:
   borde punteado, fondo cálido y sin sombra. Es lo que está a medias. */
.fila-entrenamiento.es-borrador {
    background: rgb(var(--warning-rgb) / 0.04);
    border: var(--border-width) dashed rgb(var(--warning-rgb) / 0.42);
    box-shadow: none;
}

.fe-portada {
    width: 104px;
    height: 70px;
    flex-shrink: 0;
    border-radius: var(--radius-md);
    border: var(--border-width) solid rgb(var(--line-rgb));
    background: rgb(var(--surface-2-rgb));
    overflow: hidden;
    display: flex;
    align-items: center;
    justify-content: center;
}

.fe-portada img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.fe-portada.es-vacia {
    border-style: dashed;
    border-color: rgb(var(--line-strong-rgb));
    color: rgb(var(--ink-subtle-rgb));
    font-family: var(--font-mono);
    font-size: 9.5px;
}

.fe-cuerpo {
    flex: 1;
    min-width: 0;
    display: grid;
    gap: 9px;
}

.fe-cabecera {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 12px;
}

.fe-titular { min-width: 0; }

.fe-titular h3 {
    margin: 0;
    font-size: 15.5px;
    font-weight: 600;
    letter-spacing: -0.01em;
    line-height: 1.35;
    color: rgb(var(--ink-rgb));
    text-wrap: pretty;
}

/* Dos líneas y corta: la descripción sitúa el escenario, no se lee entera
   desde el listado. Quien quiera el texto completo abre el entrenamiento. */
.fe-desc {
    margin: 5px 0 0;
    font-size: 13px;
    line-height: 1.55;
    max-width: 620px;
    color: rgb(var(--ink-muted-rgb));
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    text-wrap: pretty;
}

.fe-desc.es-vacia {
    color: rgb(var(--ink-subtle-rgb));
    font-style: italic;
}

.fe-meta {
    display: flex;
    align-items: center;
    gap: 14px;
    flex-wrap: wrap;
}

.fe-dato {
    font-size: 12.5px;
    color: rgb(var(--ink-muted-rgb));
    white-space: nowrap;
}

/* Sin avatar no es un dato más: es lo único que impide publicar. */
.fe-dato.es-alerta {
    color: rgb(var(--warning-text-rgb));
    font-weight: 500;
}

.fe-sep {
    width: 1px;
    height: 13px;
    background: rgb(var(--line-rgb));
}

/* Los datos llevan su icono delante: el ojo distingue "20 min" de "aprueba
   con 75" por la forma antes de leer, que es lo que hace escaneable una lista
   de ocho filas con seis datos cada una. */
.fe-dato svg {
    vertical-align: -2px;
    margin-right: 5px;
    color: rgb(var(--ink-subtle-rgb));
}

/* El avatar, con su círculo de iniciales. */
.fe-avatar {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    font-size: 12.5px;
    color: rgb(var(--ink-muted-rgb));
    white-space: nowrap;
}

.fa-iniciales {
    display: grid;
    place-items: center;
    width: 20px;
    height: 20px;
    border-radius: 999px;
    background: rgb(var(--brand-rgb) / 0.16);
    color: rgb(var(--brand-text-rgb));
    font-family: var(--font-mono);
    font-size: 9.5px;
    font-weight: 600;
    letter-spacing: 0.02em;
}

/* La acción del pie de un borrador se va a la derecha del todo: lo que falta
   se lee de izquierda a derecha y termina en lo que hay que hacer. */
.fe-pie-accion { margin-left: auto; }

/* ── Una ventana que no pasa del alto de la pantalla (requisito 407) ──
   La de "Compartir" pedía `max-h-[90vh]` a Tailwind, pero esa clase no está en
   el CSS precompilado: la ventana crecía con cada enlace hasta salirse de la
   pantalla. Lo de en medio (`.va-desplazable`) es lo que hace scroll; necesita
   `min-height: 0`, porque un hijo de una columna flex no encoge por debajo de
   su contenido si no se le dice. */

.ventana-acotada {
    max-height: 90vh;
    display: flex;
    flex-direction: column;
}
.ventana-acotada > .va-desplazable {
    min-height: 0;
    overflow-y: auto;
}

/* ── Pasar el ratón por encima: "esto se abre" (requisitos 405 y 406) ──
   Antes la fila no reaccionaba al ratón y solo se abría desde el "⋯", así que
   no había forma de saber que estaba ahí para pulsarla. Toda la fila es ahora
   un enlace a su edición: `.fe-abrir` la cubre entera por debajo, y lo que
   tiene acción propia —el "⋯", la pastilla, el botón del pie— se sube encima
   para no quedar tapado. */

.fila-entrenamiento {
    position: relative;
    transition: transform 0.18s ease, box-shadow 0.18s ease,
                border-color 0.18s ease, background-color 0.18s ease;
}

.fe-abrir {
    position: absolute;
    inset: 0;
    z-index: 0;
    border-radius: inherit;
}
.fe-abrir:focus-visible {
    outline: 2px solid rgb(var(--brand-rgb));
    outline-offset: 2px;
}

.fila-entrenamiento .fe-derecha,
.fila-entrenamiento .fe-pie-accion {
    position: relative;
    z-index: 1;
}

.fila-entrenamiento:hover,
.fila-entrenamiento:has(.fe-abrir:focus-visible) {
    transform: translateY(-2px);
    border-color: rgb(var(--brand-rgb) / 0.7);
    box-shadow: var(--shadow-md), 0 0 0 3px rgb(var(--brand-rgb) / 0.14);
}
.fila-entrenamiento.es-borrador:hover,
.fila-entrenamiento.es-borrador:has(.fe-abrir:focus-visible) {
    background: rgb(var(--brand-rgb) / 0.04);
}

.fe-titular h3 { transition: color 0.18s ease; }
.fila-entrenamiento:hover .fe-titular h3,
.fila-entrenamiento:has(.fe-abrir:focus-visible) .fe-titular h3 {
    color: rgb(var(--brand-text-rgb));
}

.fe-portada img { transition: transform 0.3s ease; }
.fila-entrenamiento:hover .fe-portada img { transform: scale(1.06); }

/* Con el menú abierto la fila va por encima de las siguientes: si no, la
   pastilla y el "⋯" de la fila de abajo tapaban el desplegable. */
.fila-entrenamiento:has(.menu-desplegable.es-abierto) { z-index: 40; }

@media (prefers-reduced-motion: reduce) {
    .fila-entrenamiento,
    .fe-portada img { transition: none; }
    .fila-entrenamiento:hover,
    .fila-entrenamiento:has(.fe-abrir:focus-visible),
    .fila-entrenamiento:hover .fe-portada img { transform: none; }
}

/* ── El menú de "⋯" ── */

.fe-menu { position: relative; flex-shrink: 0; }

.boton-menu {
    display: grid;
    place-items: center;
    width: 30px;
    height: 30px;
    border-radius: var(--radius-sm);
    border: var(--border-width) solid rgb(var(--line-rgb));
    background: rgb(var(--surface-rgb));
    color: rgb(var(--ink-muted-rgb));
    cursor: pointer;
}
.boton-menu:hover {
    border-color: rgb(var(--line-strong-rgb));
    color: rgb(var(--ink-rgb));
}

.menu-desplegable {
    display: none;
    position: absolute;
    top: calc(100% + 6px);
    right: 0;
    z-index: 30;
    min-width: 190px;
    padding: 6px;
    background: rgb(var(--surface-rgb));
    border: var(--border-width) solid rgb(var(--line-rgb));
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-soft);
}
.menu-desplegable.es-abierto { display: grid; }

/* El estilo de "opción de menú" para los hijos. Se acota con `:not(.es-panel)`
   porque el mismo desplegable sirve para un panel de lectura —el detalle del
   contrato, al pie de la barra lateral—, y ahí los hijos no son opciones: no se
   pulsan. Contrarrestarlo desde el panel no valía: `> *` gana en especificidad
   a las clases del propio contenido, así que le imponía `display: block` al
   bloque de las horas y le tumbaba la rejilla. */
.menu-desplegable:not(.es-panel) > * {
    display: block;
    width: 100%;
    padding: 8px 10px;
    border: 0;
    border-radius: var(--radius-sm);
    background: transparent;
    text-align: left;
    font-size: 13.5px;
    color: rgb(var(--ink-rgb));
    cursor: pointer;
}
.menu-desplegable:not(.es-panel) > *:hover { background: rgb(var(--surface-2-rgb)); }
.menu-desplegable > .es-peligro { color: rgb(var(--danger-text-rgb)); }
.menu-desplegable > [disabled] {
    color: rgb(var(--ink-subtle-rgb));
    cursor: not-allowed;
}
.menu-desplegable > [disabled]:hover { background: transparent; }

/* ── La cabecera de un grupo de la lista ── */

.enc-grupo {
    display: flex;
    align-items: baseline;
    gap: 10px;
    margin: 22px 0 8px;
}
.enc-grupo .es-antetitulo { margin-bottom: 0; }

.eg-nota {
    font-size: 12.5px;
    color: rgb(var(--ink-subtle-rgb));
}

.filtros-cuenta {
    margin-left: auto;
    font-size: 12.5px;
    color: rgb(var(--ink-subtle-rgb));
}

.fe-acciones {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
}

.fe-pie-borrador {
    display: flex;
    align-items: baseline;
    gap: 10px;
    flex-wrap: wrap;
    margin-top: 2px;
    padding-top: 10px;
    border-top: var(--border-width) dashed rgb(var(--warning-rgb) / 0.34);
}

.fe-pie-titulo {
    font-size: 12.5px;
    font-weight: 600;
    color: rgb(var(--warning-text-rgb));
}

.fe-pie-detalle {
    font-size: 12.5px;
    color: rgb(var(--ink-muted-rgb));
}


/* ===== Biblioteca: la fila de un archivado =====
   Portado de lib-list.jsx (LBArchivedRow). Compacta y sin fondo: se retiró de
   circulación a propósito, así que no compite por la atención con lo vivo. */

.fila-archivada {
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 11px 16px;
    background: transparent;
    border: var(--border-width) solid rgb(var(--line-rgb));
    border-radius: var(--radius-md);
}

.fa-punto {
    width: 7px;
    height: 7px;
    border-radius: 999px;
    background: rgb(var(--line-strong-rgb));
    flex-shrink: 0;
}

.fa-texto {
    min-width: 0;
    flex: 1;
}

.fa-nombre {
    font-size: 13.5px;
    font-weight: 500;
    color: rgb(var(--ink-muted-rgb));
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.fa-meta {
    margin-top: 2px;
    font-size: 11.5px;
    color: rgb(var(--ink-subtle-rgb));
}

/* ===== Insignia de nivel =====
   Portado de lib-parts.jsx (LBLevelChip). Las barritas ascendentes dicen lo
   que el texto no: que el nivel es ordinal. */

.nivel-chip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    height: 22px;
    padding: 0 9px;
    border-radius: var(--radius-sm);
    background: rgb(var(--surface-2-rgb));
    color: rgb(var(--ink-muted-rgb));
    font-size: 11.5px;
    font-weight: 600;
    white-space: nowrap;
}

.nc-barras {
    display: inline-flex;
    align-items: flex-end;
    gap: 2px;
}

.nc-barra {
    width: 3px;
    border-radius: 1px;
    background: rgb(var(--line-strong-rgb));
}

.nc-barra:nth-child(1) { height: 6px; }
.nc-barra:nth-child(2) { height: 8px; }
.nc-barra:nth-child(3) { height: 10px; }

.nc-barra.es-llena {
    background: rgb(var(--brand-text-rgb));
}

/* ===== Formulario por secciones =====
   Portado de lib-form.jsx (LBSection y LBField). */

/* La columna que contiene las secciones numeradas, y **el único sitio que
   decide cuánto aire hay entre ellas**.

   Hasta el 21 de septiembre de 2026 esta clase estaba en las dos plantillas que
   la usan —la de programar una convocatoria y la de la Biblioteca— y **no
   existía en ninguna hoja de estilo**: no pintaba nada. Las secciones quedaban
   una pegada a la siguiente, con el único hueco que dejaba el margen del título
   de la de abajo, así que el final de «Qué se practica» se leía como parte de
   «Disponibilidad». El dueño del producto lo describió como que una sección
   está «really close» de la siguiente.

   El hueco va aquí y no como un margen suelto en una sección: lo que se está
   separando son hermanas, y un margen en una de ellas es una regla que hay que
   repetir cada vez que se añade otra —y que se olvida en la última—. 32 px es
   el doble de los 16 que separan dos campos dentro de una sección
   (`.sf-cuerpo`), que es lo que hace que la jerarquía se vea sin leer: dentro
   de una sección se respira, entre secciones se corta. */
.columna-form {
    display: grid;
    gap: 32px;
}

.sec-form {
    display: grid;
    gap: 14px;
}

.sf-titulo {
    display: flex;
    align-items: center;
    gap: 9px;
}

.sf-numero {
    width: 22px;
    height: 22px;
    flex-shrink: 0;
    border-radius: 6px;
    background: rgb(var(--surface-2-rgb));
    color: rgb(var(--ink-muted-rgb));
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-family: var(--font-mono);
    font-size: 11px;
    font-weight: 600;
}

.sf-titulo h2 {
    margin: 0;
    font-family: var(--font-display);
    font-size: 19px;
    font-weight: 600;
    letter-spacing: -0.015em;
    color: rgb(var(--ink-rgb));
}

.sf-opcional {
    font-size: 12px;
    font-weight: 500;
    color: rgb(var(--ink-subtle-rgb));
}

/* Alineada con el título, no con el número: el número es un marcador de
   posición en la secuencia, no parte de la frase. */
.sf-sub {
    margin: 5px 0 0;
    padding-left: 31px;
    font-size: 13px;
    line-height: 1.55;
    max-width: 640px;
    color: rgb(var(--ink-muted-rgb));
    text-wrap: pretty;
}

.sf-cuerpo {
    display: grid;
    gap: 16px;
    padding: 18px;
    background: rgb(var(--surface-rgb));
    border: var(--border-width) solid rgb(var(--line-rgb));
    border-radius: var(--radius-lg);
}

.campo-form {
    display: grid;
    gap: 6px;
}

.cf-cabecera {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 10px;
}

.cf-cabecera label {
    font-size: 13px;
    font-weight: 600;
    color: rgb(var(--ink-rgb));
}

.cf-obligatorio {
    margin-left: 5px;
    font-size: 12px;
    font-weight: 500;
    color: rgb(var(--brand-text-rgb));
}

.cf-opcional {
    margin-left: 5px;
    font-size: 12px;
    font-weight: 500;
    color: rgb(var(--ink-subtle-rgb));
}

.cf-conteo {
    font-family: var(--font-mono);
    font-size: 11px;
    color: rgb(var(--ink-subtle-rgb));
    white-space: nowrap;
}

.cf-conteo.es-pasado {
    color: rgb(var(--danger-text-rgb));
}

.cf-pista {
    margin: 0;
    font-size: 12.5px;
    line-height: 1.5;
    max-width: 620px;
    color: rgb(var(--ink-muted-rgb));
    text-wrap: pretty;
}

/* ===== Medidor de la regla de comportamientos =====
   Portado de lib-skills.jsx (LBRuleMeter). Ocho casillas con una marca
   después de la cuarta: la regla se ve, no hay que leerla. */

.medidor-regla {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    flex-shrink: 0;
}

.mr-casillas {
    display: inline-flex;
    align-items: center;
    gap: 3px;
}

.mr-casilla {
    width: 14px;
    height: 6px;
    border-radius: 2px;
    background: rgb(var(--surface-2-rgb));
    border: 1px solid rgb(var(--line-rgb));
}

.mr-casilla.es-ok {
    background: rgb(var(--success-rgb));
    border: none;
}

.mr-casilla.es-corta {
    background: rgb(var(--warning-rgb) / 0.70);
    border: none;
}

.mr-marca {
    width: 1px;
    height: 12px;
    margin: 0 3px;
    background: rgb(var(--line-strong-rgb));
}

.mr-texto {
    font-size: 12.5px;
    font-weight: 600;
    white-space: nowrap;
}

.medidor-regla.es-vacio .mr-texto { color: rgb(var(--ink-subtle-rgb)); }
.medidor-regla.es-corta .mr-texto { color: rgb(var(--warning-text-rgb)); }
.medidor-regla.es-ok    .mr-texto { color: rgb(var(--success-text-rgb)); }

/* ===== Chat con Lumi =====
   Portado de lib-lumi.jsx (LMBubble, LMThinking).

   Esta pantalla se quedó fuera de la migración de colores: usaba `bg-card-bg`,
   `border-card-border`, `bg-input-bg` y `text-on-surface`, que no existen en
   ninguna hoja —el contenedor salía transparente y el campo de entrada, blanco
   sobre fondo oscuro—, y las burbujas del usuario seguían en `bg-purple-600`
   dentro del .js, donde el reemplazo no llegó. */

.caja-chat {
    padding: 16px;
    margin-bottom: 16px;
    overflow-y: auto;
    background: rgb(var(--canvas-rgb));
    border: var(--border-width) solid rgb(var(--line-rgb));
    border-radius: var(--radius-lg);
}

.burbuja {
    max-width: 76%;
    padding: 11px 14px;
    border-radius: 14px;
    font-size: 14px;
    line-height: 1.6;
    white-space: pre-wrap;
    text-wrap: pretty;
}

/* La esquina recortada apunta a quién habla, que es lo que distingue las dos
   burbujas incluso antes de mirar el color. */
.burbuja.es-mia {
    background: rgb(var(--brand-tint-rgb));
    color: rgb(var(--brand-text-rgb));
    border: var(--border-width) solid transparent;
    border-bottom-right-radius: 4px;
}

.burbuja.es-de-lumi {
    background: rgb(var(--surface-rgb));
    color: rgb(var(--ink-rgb));
    border: var(--border-width) solid rgb(var(--line-rgb));
    border-bottom-left-radius: 4px;
}

/* Tres puntos que suben por turnos. Dice que algo está pasando sin fingir un
   progreso que no se conoce: no se sabe cuánto va a tardar el modelo. */
.puntos-pensando {
    display: inline-flex;
    gap: 4px;
}

.puntos-pensando span {
    width: 6px;
    height: 6px;
    border-radius: 999px;
    background: rgb(var(--brand-rgb));
    animation: rebote-punto 1s infinite ease-in-out;
}

.puntos-pensando span:nth-child(2) { animation-delay: 0.15s; }
.puntos-pensando span:nth-child(3) { animation-delay: 0.30s; }

@keyframes rebote-punto {
    0%, 60%, 100% { transform: translateY(0);    opacity: 0.45; }
    30%           { transform: translateY(-3px); opacity: 1; }
}

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

/* ===== Chip con punto de color =====
   Portado de sc-parts.jsx (SCStatusChip). El punto hace el trabajo cuando la
   fila se escanea sin leer; la etiqueta lo confirma. */

.chip-punto {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    height: 22px;
    padding: 0 9px 0 8px;
    border-radius: 999px;
    font-size: 11.5px;
    font-weight: 600;
    white-space: nowrap;
    border: var(--border-width) solid transparent;
}

.cp-punto {
    width: 6px;
    height: 6px;
    border-radius: 999px;
    flex-shrink: 0;
}

.chip-punto.es-neutral {
    background: rgb(var(--surface-2-rgb));
    color: rgb(var(--ink-muted-rgb));
    border-color: rgb(var(--line-rgb));
}
.chip-punto.es-neutral .cp-punto { background: rgb(var(--ink-subtle-rgb)); }

.chip-punto.es-accent {
    background: rgb(var(--brand-rgb) / 0.10);
    color: rgb(var(--brand-text-rgb));
    border-color: rgb(var(--brand-rgb) / 0.32);
}
.chip-punto.es-accent .cp-punto { background: rgb(var(--brand-strong-rgb)); }

.chip-punto.es-good {
    background: rgb(var(--success-rgb) / 0.10);
    color: rgb(var(--success-text-rgb));
    border-color: rgb(var(--success-rgb) / 0.32);
}
.chip-punto.es-good .cp-punto { background: rgb(var(--success-rgb)); }

/* Un borrador no es un problema: está a medias y pide que alguien vuelva. */
.chip-punto.es-warn {
    background: rgb(var(--warning-rgb) / 0.12);
    color: rgb(var(--warning-text-rgb));
    border-color: rgb(var(--warning-rgb) / 0.35);
}
.chip-punto.es-warn .cp-punto { background: rgb(var(--warning-rgb)); }

.chip-punto.es-bad {
    background: rgb(var(--danger-rgb) / 0.10);
    color: rgb(var(--danger-text-rgb));
    border-color: rgb(var(--danger-rgb) / 0.32);
}
.chip-punto.es-bad .cp-punto { background: rgb(var(--danger-rgb)); }


/* ===== Señal de atención =====
   Portado de sc-parts.jsx (SCFlag). Sin borde y más pequeña que el chip de
   estado: acompaña, no compite. */

.senal {
    display: inline-flex;
    align-items: center;
    height: 20px;
    padding: 0 8px;
    border-radius: var(--radius-sm);
    font-size: 11px;
    font-weight: 600;
    white-space: nowrap;
}

.senal.es-bad {
    background: rgb(var(--danger-rgb) / 0.13);
    color: rgb(var(--danger-text-rgb));
}

.senal.es-warn {
    background: rgb(var(--warning-rgb) / 0.13);
    color: rgb(var(--warning-text-rgb));
}

.senal.es-neutral {
    background: rgb(var(--surface-2-rgb));
    color: rgb(var(--ink-subtle-rgb));
}


/* ===== Avance en puntos =====
   Portado de sc-parts.jsx (SCDots). Un punto por práctica. */

.puntos-avance {
    display: inline-flex;
    align-items: center;
    gap: 3px;
}

.pa-punto {
    width: 7px;
    height: 7px;
    border-radius: 999px;
    background: transparent;
    border: 1px solid rgb(var(--line-strong-rgb));
}

.pa-punto.es-hecha {
    background: rgb(var(--brand-strong-rgb));
    border: none;
}

/* ===== Escenarios: la fila de una asignación =====
   Portado de sc-list.jsx. */

.fila-asignacion {
    padding: 14px 16px;
    color: inherit;
    /* Blanco y no `surface-2`. La tarjeta vive dentro del cuerpo de un equipo,
       que ya es blanco, así que el gris la separaba del fondo justo al
       contrario de las capturas: ahí lo gris es la cabecera del equipo —lo que
       agrupa— y lo blanco es cada asignación —lo que se lee y se pulsa—. */
    background: rgb(var(--surface-rgb));
    border: var(--border-width) solid rgb(var(--line-rgb));
    border-radius: var(--radius-md);
    display: grid;
    gap: 10px;
    transition: border-color 140ms ease;
}

.fila-asignacion:hover {
    border-color: rgb(var(--brand-rgb) / 0.40);
}

.fa-cabecera {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 12px;
}

.fa-titulo {
    min-width: 0;
    font-size: 14px;
    font-weight: 500;
    color: rgb(var(--ink-rgb));
}

.fa-origen {
    display: block;
    margin-top: 2px;
    font-size: 12px;
    font-weight: 400;
    color: rgb(var(--ink-subtle-rgb));
}

/* La señal va antes del estado: es lo que hay que ver primero cuando existe. */
.fa-marcas {
    display: flex;
    align-items: center;
    gap: 6px;
    flex-shrink: 0;
}

.fa-meta {
    display: flex;
    align-items: center;
    gap: 14px;
    flex-wrap: wrap;
}

.fa-accion {
    margin-left: auto;
}

/* Los filtros de Escenarios encienden con el color de su estado, igual que los
   de la Biblioteca. Comparten `.filtro-chip`; solo cambian los nombres de tono
   porque allí son estados de entrenamiento y aquí de asignación. */
.filtro-chip.es-accent.es-encendido {
    border-color: rgb(var(--brand-rgb) / 0.40);
    background: rgb(var(--brand-rgb) / 0.10);
}
.filtro-chip.es-accent.es-encendido .fc-punto {
    background: rgb(var(--brand-strong-rgb));
    border: none;
}

.filtro-chip.es-good.es-encendido {
    border-color: rgb(var(--success-rgb) / 0.40);
    background: rgb(var(--success-rgb) / 0.10);
}
.filtro-chip.es-good.es-encendido .fc-punto {
    background: rgb(var(--success-rgb));
    border: none;
}

.filtro-chip.es-bad.es-encendido {
    border-color: rgb(var(--danger-rgb) / 0.40);
    background: rgb(var(--danger-rgb) / 0.10);
}
.filtro-chip.es-bad.es-encendido .fc-punto {
    background: rgb(var(--danger-rgb));
    border: none;
}

.filtro-chip.es-neutral.es-encendido {
    border-color: rgb(var(--line-strong-rgb));
    background: rgb(var(--surface-2-rgb));
}
.filtro-chip.es-neutral.es-encendido .fc-punto {
    background: rgb(var(--ink-subtle-rgb));
    border: none;
}

/* ===== Línea de evolución =====
   Portado de sc-parts.jsx (SCSpark). El eje vertical es siempre 0-100 para
   que dos criterios se comparen de un vistazo; la geometría la resuelve
   app/evolucion.py.

   El lienzo se estira a lo ancho (preserveAspectRatio="none") para que la
   línea llene la tarjeta sea cual sea su ancho. Eso ensancha un poco los
   puntos —un radio de 3px pasa a unos 4px—, que a este tamaño no se nota y es
   lo que hace el kit. */

.linea-evolucion {
    display: block;
    width: 100%;
    overflow: visible;
}

.le-umbral {
    stroke: rgb(var(--line-strong-rgb));
    stroke-width: 1;
    stroke-dasharray: 3 3;
}

/* Sin ninguna práctica: una raya más tenue y más separada que la del umbral,
   para que no se confundan. */
.le-hueco {
    stroke: rgb(var(--line-rgb));
    stroke-width: 1.5;
    stroke-dasharray: 2 5;
}

.le-trazo {
    stroke: rgb(var(--brand-strong-rgb));
    stroke-width: 2;
    stroke-linecap: round;
    stroke-linejoin: round;
}

.le-punto {
    fill: rgb(var(--surface-rgb));
    stroke: rgb(var(--brand-strong-rgb));
    stroke-width: 2;
}

/* El último es el puntaje que cuenta hoy; los de detrás son de dónde viene. */
.le-punto.es-ultimo {
    fill: rgb(var(--brand-strong-rgb));
}


/* ===== Tarjeta de un criterio =====
   Portado de sc-parts.jsx (SCCriterion). */

.rejilla-criterios {
    display: grid;
    gap: 11px;
    grid-template-columns: repeat(auto-fill, minmax(268px, 1fr));
}

/* Con más de cinco criterios las tarjetas se estrechan para que la rejilla no
   se vaya a cuatro filas. El kit lo llama `dense`. */
.rejilla-criterios.es-densa {
    grid-template-columns: repeat(auto-fill, minmax(234px, 1fr));
}

.tarjeta-criterio {
    display: grid;
    gap: 9px;
    min-width: 0;
    padding: 14px 15px;
    background: rgb(var(--surface-rgb));
    border: var(--border-width) solid rgb(var(--line-rgb));
    border-radius: var(--radius-md);
}

.rejilla-criterios.es-densa .tarjeta-criterio {
    padding: 12px 13px;
}

/* Por debajo del aprobado el borde se tiñe: la rejilla se lee sin recorrer
   las cifras una por una. */
.tarjeta-criterio.es-baja {
    border-color: rgb(var(--danger-rgb) / 0.30);
}

.tc-cabecera {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 10px;
}

.tc-nombre {
    margin: 0;
    min-width: 0;
    font-size: 13.5px;
    font-weight: 600;
    line-height: 1.35;
    color: rgb(var(--ink-rgb));
}

.tc-promedio {
    flex-shrink: 0;
    text-align: right;
    display: grid;
    gap: 3px;
}

.tc-cifra {
    font-family: var(--font-mono);
    font-size: 22px;
    font-weight: 650;
    line-height: 1;
    letter-spacing: -0.02em;
    color: rgb(var(--ink-rgb));
}

.tc-etiqueta {
    font-size: 10.5px;
    color: rgb(var(--ink-subtle-rgb));
}

.tc-pie {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
}

.tc-tendencia {
    font-size: 12px;
    font-weight: 500;
}

.tc-tendencia.es-good { color: rgb(var(--success-text-rgb)); }
.tc-tendencia.es-bad { color: rgb(var(--danger-text-rgb)); }
.tc-tendencia.es-warn { color: rgb(var(--warning-text-rgb)); }
.tc-tendencia.es-muted { color: rgb(var(--ink-subtle-rgb)); }

.tc-serie {
    font-family: var(--font-mono);
    font-size: 11px;
    color: rgb(var(--ink-subtle-rgb));
}


/* ===== Fila de datos =====
   Portado de sc-detail.jsx (SDStatRow). Una sola caja con separadores de un
   píxel, en lugar de una tarjeta con sombra por cifra: cuatro cifras no
   necesitan cuatro cajas.

   Las líneas divisorias son el fondo asomando por el `gap`; por eso el gap es
   de 1px y no de 0. */

.fila-datos {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
    gap: 1px;
    overflow: hidden;
    background: rgb(var(--line-rgb));
    border: var(--border-width) solid rgb(var(--line-rgb));
    border-radius: var(--radius-lg);
}

.fd-celda {
    padding: 13px 16px;
    background: rgb(var(--surface-rgb));
    min-width: 0;
}

.fd-etiqueta {
    font-family: var(--font-mono);
    font-size: 9.5px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.07em;
    color: rgb(var(--ink-subtle-rgb));
}

.fd-valor {
    margin-top: 6px;
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 13px;
    font-weight: 500;
    color: rgb(var(--ink-rgb));
}

.fd-cifra {
    font-family: var(--font-mono);
    font-size: 21px;
    font-weight: 650;
    letter-spacing: -0.02em;
    line-height: 1;
}

.fd-apunte {
    font-size: 11.5px;
    font-weight: 400;
    color: rgb(var(--ink-subtle-rgb));
}

.fd-valor.es-vencido {
    color: rgb(var(--danger-text-rgb));
}


/* ===== Detalle de una asignación =====
   Portado de sc-detail.jsx. */

/* Por dónde empezar: el criterio más flojo, dicho en una frase. La rejilla ya
   lo pone primero, pero el orden solo se nota si sabes que la rejilla está
   ordenada. */
.aviso-empezar {
    max-width: 340px;
    padding: 11px 14px;
    border-radius: var(--radius-md);
    background: rgb(var(--danger-rgb) / 0.08);
    border: var(--border-width) solid rgb(var(--danger-rgb) / 0.24);
}

.ae-titulo {
    font-size: 12.5px;
    font-weight: 600;
    margin-bottom: 3px;
    color: rgb(var(--ink-rgb));
}

.ae-texto {
    margin: 0;
    font-size: 12.5px;
    line-height: 1.5;
    color: rgb(var(--ink-muted-rgb));
}

/* El objetivo y las notas del líder. Las notas van sin borde y sobre el fondo
   hundido porque son secundarias respecto del objetivo, no porque sean
   privadas: el colaborador las ve. */
.nota-asignacion {
    padding: 14px 16px;
    background: rgb(var(--surface-rgb));
    border: var(--border-width) solid rgb(var(--line-rgb));
    border-radius: var(--radius-md);
}

.nota-asignacion.es-secundaria {
    background: rgb(var(--surface-2-rgb));
    border-color: transparent;
}

.na-etiqueta {
    font-family: var(--font-mono);
    font-size: 9.5px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.07em;
    color: rgb(var(--ink-subtle-rgb));
    margin-bottom: 6px;
}

.na-texto {
    margin: 0;
    font-size: 13.5px;
    line-height: 1.6;
    white-space: pre-line;
    color: rgb(var(--ink-rgb));
}

.nota-asignacion.es-secundaria .na-texto {
    color: rgb(var(--ink-muted-rgb));
}

/* Una práctica de la asignación. */
.fila-practica {
    display: grid;
    gap: 9px;
    padding: 13px 15px;
    background: rgb(var(--surface-rgb));
    border: var(--border-width) solid rgb(var(--line-rgb));
    border-radius: var(--radius-md);
}

/* Lo que aún no se ha hecho pesa menos que lo que ya tiene puntaje. */
.fila-practica.es-pendiente {
    opacity: 0.92;
}

.fp-cabecera {
    display: flex;
    align-items: flex-start;
    gap: 13px;
}

.fp-numero {
    width: 26px;
    height: 26px;
    flex-shrink: 0;
    border-radius: 8px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-family: var(--font-mono);
    font-size: 12px;
    font-weight: 600;
    background: rgb(var(--surface-2-rgb));
    color: rgb(var(--ink-subtle-rgb));
}

.fila-practica:not(.es-pendiente) .fp-numero {
    background: rgb(var(--brand-rgb) / 0.14);
    color: rgb(var(--brand-text-rgb));
}

.fp-cuerpo {
    min-width: 0;
    flex: 1;
}

.fp-titulo {
    margin: 0;
    font-size: 13.5px;
    font-weight: 600;
    line-height: 1.4;
    color: rgb(var(--ink-rgb));
}

.fp-objetivo {
    margin: 4px 0 0;
    font-size: 12.5px;
    line-height: 1.5;
    color: rgb(var(--ink-muted-rgb));
}

.fp-meta {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
    margin-top: 7px;
    font-size: 12.5px;
    color: rgb(var(--ink-muted-rgb));
}

.fp-puntaje {
    font-family: var(--font-mono);
    font-weight: 650;
}

.fp-veredicto {
    font-size: 11.5px;
    font-weight: 600;
}

.fp-veredicto.es-aprobada { color: rgb(var(--success-text-rgb)); }
.fp-veredicto.es-no-aprobada { color: rgb(var(--danger-text-rgb)); }

.fp-accion {
    flex-shrink: 0;
}

/* El intento anterior, cuando la práctica se repitió. */
.fp-intentos {
    display: grid;
    gap: 6px;
    padding-left: 39px;
}

.fp-intento {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
    padding: 7px 11px;
    background: rgb(var(--surface-2-rgb));
    border-radius: var(--radius-sm);
    font-size: 12px;
    color: rgb(var(--ink-subtle-rgb));
}

.fp-intento-titulo {
    font-weight: 600;
    color: rgb(var(--ink-muted-rgb));
}

/* Nota al pie de una sección: contexto, no alarma. */
.nota-plazo {
    margin: 0;
    padding: 11px 14px;
    font-size: 12.5px;
    line-height: 1.55;
    color: rgb(var(--ink-muted-rgb));
    background: rgb(var(--danger-rgb) / 0.07);
    border: var(--border-width) solid rgb(var(--danger-rgb) / 0.22);
    border-radius: var(--radius-md);
}

.pie-aclaracion {
    margin: 0;
    max-width: 700px;
    font-size: 12.5px;
    line-height: 1.55;
    color: rgb(var(--ink-subtle-rgb));
}


/* ===== Panel lateral =====
   Portado de sc-assign.jsx. El asistente de asignar era un diálogo centrado de
   ancho fijo con cuatro pasos dentro; en un formulario largo eso obliga a
   desplazar una caja pequeña dentro de una pantalla grande. Como panel a la
   derecha usa el alto completo y deja ver detrás dónde estabas. */

.panel-lateral {
    position: fixed;
    inset: 0;
    z-index: 50;
    display: flex;
    justify-content: flex-end;
    background: rgb(var(--overlay-rgb) / 0.5);
    backdrop-filter: blur(2px);
}

.pl-hoja {
    width: min(760px, 100%);
    display: flex;
    flex-direction: column;
    background: rgb(var(--canvas-rgb));
    border-left: var(--border-width) solid rgb(var(--line-rgb));
    box-shadow: var(--shadow-lg);
}

.pl-cabecera {
    padding: 18px 24px 14px;
    display: grid;
    gap: 13px;
    background: rgb(var(--surface-rgb));
    border-bottom: var(--border-width) solid rgb(var(--line-rgb));
}

.pl-cuerpo {
    flex: 1;
    overflow-y: auto;
    padding: 20px 24px 28px;
    display: grid;
    gap: 18px;
    align-content: start;
}

.pl-pie {
    padding: 14px 24px;
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
    background: rgb(var(--surface-rgb));
    border-top: var(--border-width) solid rgb(var(--line-rgb));
}

/* El resumen del pie está siempre visible: dice qué se va a crear sin tener
   que volver a los pasos anteriores a comprobarlo. */
.pl-resumen {
    min-width: 0;
    font-size: 12.5px;
    color: rgb(var(--ink-muted-rgb));
}

.pl-acciones {
    margin-left: auto;
    display: flex;
    gap: 9px;
}

.pl-cerrar {
    width: 30px;
    height: 30px;
    flex-shrink: 0;
    border-radius: var(--radius-md);
    border: var(--border-width) solid rgb(var(--line-rgb));
    background: rgb(var(--surface-rgb));
    color: rgb(var(--ink-muted-rgb));
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 18px;
    line-height: 1;
}

.pl-cerrar:hover { background: rgb(var(--surface-2-rgb)); }


/* ===== Pasos =====
   Portado de sc-assign.jsx (ASStepBar). Frente a los círculos unidos por una
   línea que había, cada paso es un chip con su nombre siempre visible: en la
   versión anterior los nombres se escondían por debajo de 640px y quedaban
   cuatro círculos numerados sin decir de qué. */

.pasos {
    display: flex;
    align-items: center;
    gap: 6px;
    flex-wrap: wrap;
}

.paso {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    height: 28px;
    padding: 0 11px 0 8px;
    border-radius: 999px;
    border: var(--border-width) solid rgb(var(--line-rgb));
    background: rgb(var(--surface-rgb));
    color: rgb(var(--ink-subtle-rgb));
    font-family: var(--font-sans);
    font-size: 12.5px;
    font-weight: 550;
    white-space: nowrap;
}

.paso-numero {
    width: 17px;
    height: 17px;
    flex-shrink: 0;
    border-radius: 999px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-family: var(--font-mono);
    font-size: 10px;
    font-weight: 600;
    background: rgb(var(--surface-2-rgb));
    color: rgb(var(--ink-subtle-rgb));
}

.paso.es-hecho {
    color: rgb(var(--ink-muted-rgb));
}
.paso.es-hecho .paso-numero {
    background: rgb(var(--success-rgb) / 0.16);
    color: rgb(var(--success-text-rgb));
}

.paso.es-actual {
    border-color: transparent;
    background: rgb(var(--brand-tint-rgb));
    color: rgb(var(--brand-text-rgb));
    font-weight: 600;
}
.paso.es-actual .paso-numero {
    background: rgb(var(--brand-strong-rgb));
    color: rgb(var(--brand-on-rgb));
}

.paso-union {
    width: 12px;
    height: 1px;
    flex-shrink: 0;
    background: rgb(var(--line-rgb));
}


/* ===== Tarjeta que se elige =====
   Portado de sc-assign.jsx. Sustituye al desplegable de entrenamientos y a los
   checkbox pelados de colaboradores: elegir un entrenamiento de una lista de
   nombres no deja ver cuánto dura, con quién es ni con cuánto se aprueba. */

.tarjeta-opcion {
    display: flex;
    gap: 12px;
    align-items: flex-start;
    width: 100%;
    padding: 13px 14px;
    text-align: left;
    cursor: pointer;
    background: rgb(var(--surface-rgb));
    border: var(--border-width) solid rgb(var(--line-rgb));
    border-radius: var(--radius-md);
    font-family: var(--font-sans);
    transition: border-color 140ms ease, background-color 140ms ease;
}

.tarjeta-opcion:hover { border-color: rgb(var(--brand-rgb) / 0.40); }

.tarjeta-opcion.es-elegida {
    background: rgb(var(--brand-rgb) / 0.07);
    border-color: rgb(var(--brand-rgb) / 0.45);
}

/* Redondo para "una de estas", cuadrado para "las que quieras": la forma dice
   si elegir una descarta las demás antes de pulsarla. */
.to-marca {
    width: 18px;
    height: 18px;
    margin-top: 2px;
    flex-shrink: 0;
    border-radius: 999px;
    border: 1.5px solid rgb(var(--line-strong-rgb));
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 11px;
    line-height: 1;
    /* La marca solo se ve cuando está elegida. El hueco se reserva igual para
       que la fila no se mueva al pulsarla. */
    color: transparent;
}

.to-marca.es-varias { border-radius: 5px; }

.tarjeta-opcion.es-elegida .to-marca {
    border-color: transparent;
    background: rgb(var(--brand-strong-rgb));
    color: rgb(var(--brand-on-rgb));
}

.to-cuerpo {
    min-width: 0;
    flex: 1;
    display: grid;
    gap: 6px;
}

.to-nombre {
    font-size: 14px;
    font-weight: 600;
    letter-spacing: -0.01em;
    color: rgb(var(--ink-rgb));
}

.to-linea {
    display: flex;
    gap: 12px;
    flex-wrap: wrap;
    align-items: center;
}

.to-nota {
    font-size: 12.5px;
    color: rgb(var(--ink-muted-rgb));
}

.to-aparte {
    margin-left: auto;
    flex-shrink: 0;
    align-self: center;
}


/* ===== Grupo de un paso ===== */

.grupo-eleccion {
    display: grid;
    gap: 7px;
}

.ge-titulo {
    font-family: var(--font-mono);
    font-size: 10px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.07em;
    color: rgb(var(--ink-subtle-rgb));
}


/* ===== Contador de cantidad =====
   Portado de sc-assign.jsx. */

.contador {
    display: inline-flex;
    align-items: center;
    gap: 2px;
    padding: 3px;
    background: rgb(var(--surface-rgb));
    border: var(--border-width) solid rgb(var(--line-rgb));
    border-radius: var(--radius-md);
}

.contador button {
    width: 28px;
    height: 28px;
    border: none;
    border-radius: 6px;
    background: transparent;
    color: rgb(var(--ink-muted-rgb));
    cursor: pointer;
    font-size: 15px;
    line-height: 1;
}

.contador button:hover:not(:disabled) { background: rgb(var(--surface-2-rgb)); }
.contador button:disabled { opacity: 0.4; cursor: not-allowed; }

.contador-cifra {
    width: 26px;
    text-align: center;
    font-family: var(--font-mono);
    font-size: 14px;
    font-weight: 650;
    color: rgb(var(--ink-rgb));
}


/* ===== Una práctica del asistente ===== */

.practica-form {
    display: grid;
    gap: 10px;
    padding: 14px;
    background: rgb(var(--surface-rgb));
    border: var(--border-width) solid rgb(var(--line-rgb));
    border-radius: var(--radius-md);
}

.pf-cabecera {
    display: flex;
    align-items: center;
    gap: 9px;
}

.pf-numero {
    width: 22px;
    height: 22px;
    flex-shrink: 0;
    border-radius: 6px;
    background: rgb(var(--surface-2-rgb));
    color: rgb(var(--ink-muted-rgb));
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-family: var(--font-mono);
    font-size: 11px;
    font-weight: 600;
}

.pf-titulo {
    font-size: 12.5px;
    font-weight: 600;
    color: rgb(var(--ink-muted-rgb));
}

.pf-marca {
    margin-left: auto;
    font-family: var(--font-mono);
    font-size: 10.5px;
    color: rgb(var(--ink-subtle-rgb));
}


/* ===== Entrenamientos del colaborador =====
   Portado de collab-parts.jsx (CBTrainingCard) y collab-scenarios.jsx. */

/* Terminar todo no es un vacío: es un resultado. */
.aviso-logro {
    display: flex;
    gap: 16px;
    align-items: flex-start;
    padding: 20px 22px;
    background: rgb(var(--success-rgb) / 0.08);
    border: var(--border-width) solid rgb(var(--success-rgb) / 0.26);
    border-radius: var(--radius-lg);
}

.al-titulo {
    margin: 0 0 6px;
    font-family: var(--font-display);
    font-size: 20px;
    font-weight: 600;
    letter-spacing: -0.01em;
    color: rgb(var(--ink-rgb));
}

.al-texto {
    margin: 0;
    max-width: 620px;
    font-size: 14px;
    line-height: 1.6;
    color: rgb(var(--ink-muted-rgb));
}

/* Los completados van dentro de una sola caja y sin separación entre ellos:
   se consultan, no se trabajan. */
.pila-terminados {
    display: grid;
    gap: 8px;
    padding: 8px;
    background: rgb(var(--surface-rgb));
    border: var(--border-width) solid rgb(var(--line-rgb));
    border-radius: var(--radius-lg);
}

.tarjeta-entrenamiento {
    display: grid;
    gap: 14px;
    padding: 20px 22px;
    background: rgb(var(--surface-rgb));
    border: var(--border-width) solid rgb(var(--line-rgb));
    border-radius: var(--radius-lg);
    text-decoration: none;
    transition: border-color 140ms ease, box-shadow 140ms ease;
}

.tarjeta-entrenamiento:hover {
    border-color: rgb(var(--line-strong-rgb));
    box-shadow: var(--shadow-md);
}

.tarjeta-entrenamiento.es-tranquila {
    padding: 16px 18px;
    background: transparent;
    border-color: transparent;
}

.tarjeta-entrenamiento.es-tranquila:hover {
    background: rgb(var(--surface-2-rgb));
    box-shadow: none;
}

/* Vencido se marca en el borde, no pintando la tarjeta entera de rojo: sigue
   siendo un entrenamiento que se puede hacer, no una alarma. */
.tarjeta-entrenamiento.es-vencida {
    border-color: rgb(var(--danger-rgb) / 0.32);
}

.te-arriba {
    display: flex;
    gap: 20px;
    align-items: flex-start;
}

.te-cuerpo {
    flex: 1;
    min-width: 0;
    display: grid;
    gap: 9px;
}

.te-marcas {
    display: flex;
    flex-wrap: wrap;
    gap: 7px;
    align-items: center;
}

.te-nombre {
    margin: 0;
    font-family: var(--font-display);
    font-size: 18.5px;
    font-weight: 600;
    line-height: 1.3;
    letter-spacing: -0.01em;
    color: rgb(var(--ink-rgb));
}

.es-tranquila .te-nombre { font-size: 16px; }

/* Dos líneas y corta: la descripción sitúa el escenario, no se lee entera
   desde el listado. */
.te-descripcion {
    margin: 0;
    font-size: 13.5px;
    line-height: 1.6;
    color: rgb(var(--ink-muted-rgb));
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.te-puntaje {
    flex-shrink: 0;
    display: grid;
    gap: 2px;
    text-align: right;
}

/* La flecha que dice que la tarjeta se abre. Discreta en reposo y con color
   al pasar por encima: es una pista, no una acción aparte. */
.te-ir {
    flex-shrink: 0;
    display: grid;
    place-items: center;
    align-self: center;
    color: rgb(var(--ink-subtle-rgb));
    transition: color .15s ease, transform .15s ease;
}

.tarjeta-entrenamiento:hover .te-ir {
    color: rgb(var(--brand-text-rgb));
    transform: translateX(2px);
}

.te-cifra {
    font-family: var(--font-display);
    font-size: 22px;
    font-weight: 600;
    letter-spacing: -0.02em;
}

.te-avance {
    display: flex;
    align-items: center;
    gap: 14px;
}

.te-barra {
    flex: 1;
    max-width: 260px;
    height: 5px;
    border-radius: 999px;
    overflow: hidden;
    background: rgb(var(--surface-2-rgb));
}

.te-relleno {
    display: block;
    height: 100%;
    border-radius: 999px;
    background: rgb(var(--brand-strong-rgb));
}

.te-relleno.es-hecha { background: rgb(var(--success-rgb)); }
.te-relleno.es-vencida { background: rgb(var(--danger-rgb)); }

.te-conteo {
    font-family: var(--font-mono);
    font-size: 11.5px;
    font-weight: 600;
    color: rgb(var(--ink-muted-rgb));
}

/* Lo que escribió el líder al asignar. Es el dato que esta pantalla no tenía:
   se veía el entrenamiento y no por qué te lo habían puesto. */
.te-objetivo {
    display: grid;
    gap: 4px;
    padding: 12px 14px;
    background: rgb(var(--surface-2-rgb));
    border-radius: var(--radius-md);
}

.te-objetivo p {
    margin: 0;
    font-size: 13px;
    line-height: 1.6;
    color: rgb(var(--ink-muted-rgb));
}


/* ─── Elegir cómo practicar, en la pantalla previa a la sesión ───
   Dos opciones que se eligen una sola vez y no se vuelven a tocar, así que
   van a la vista y no escondidas en un desplegable: la elección se ve entera
   antes de pulsar Comenzar. Requisito 66. */

.eleccion-modo {
    margin-bottom: 24px;
    padding: 0;
    border: 0;
    text-align: left;
}

.em-titulo {
    padding: 0;
    margin-bottom: 10px;
    font-size: 13px;
    font-weight: 600;
    color: rgb(var(--ink-rgb));
}

.em-opciones {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 10px;
}

@media (max-width: 480px) {
    .em-opciones { grid-template-columns: 1fr; }
}

.em-opcion {
    display: grid;
    grid-template-columns: auto 1fr;
    grid-template-areas:
        "icono nombre"
        "icono nota";
    align-items: center;
    column-gap: 11px;
    padding: 13px 15px;
    border-radius: var(--radius-md);
    border: var(--border-width) solid rgb(var(--line-rgb));
    background: rgb(var(--surface-rgb));
    cursor: pointer;
    transition: border-color .15s ease, background-color .15s ease;
}

.em-opcion:hover {
    border-color: rgb(var(--brand-rgb) / 0.5);
}

/* El radio de verdad sigue ahí, invisible pero enfocable: quien navegue con
   el teclado recorre las opciones con las flechas, como en cualquier otro
   grupo de radios. */
.em-opcion input {
    position: absolute;
    opacity: 0;
    pointer-events: none;
}

.em-opcion:has(input:checked) {
    border-color: rgb(var(--brand-rgb));
    background: rgb(var(--brand-rgb) / 0.08);
}

.em-opcion:has(input:focus-visible) {
    outline: 2px solid rgb(var(--brand-rgb));
    outline-offset: 2px;
}

.em-icono {
    grid-area: icono;
    font-size: 22px;
    line-height: 1;
}

.em-nombre {
    grid-area: nombre;
    font-size: 13.5px;
    font-weight: 600;
    color: rgb(var(--ink-rgb));
}

.em-nota {
    grid-area: nota;
    font-size: 12px;
    color: rgb(var(--ink-muted-rgb));
}


/* ─── Cierre de un entrenamiento, en la pantalla de resultados ───
   Ocupa el sitio donde habría estado el botón que no hay: terminaste, o no
   puedes repetir. Antes la pantalla se quedaba muda en los dos casos y no se
   sabía si faltaba pulsar algo. Requisito 72. */

.cierre-entrenamiento {
    padding: 15px 18px;
    margin-bottom: 20px;
    border-radius: var(--radius-md);
    border: var(--border-width) solid;
}

.cierre-entrenamiento.es-logro {
    background: rgb(var(--success-rgb) / 0.09);
    border-color: rgb(var(--success-rgb) / 0.28);
}

.cierre-entrenamiento.es-sin-intentos {
    background: rgb(var(--surface-2-rgb));
    border-color: rgb(var(--line-rgb));
}

.ce-titulo {
    margin: 0 0 4px;
    font-size: 14.5px;
    font-weight: 600;
    color: rgb(var(--ink-rgb));
}

.es-logro .ce-titulo {
    color: rgb(var(--success-text-rgb));
}

.ce-texto {
    margin: 0;
    font-size: 13px;
    line-height: 1.6;
    max-width: 68ch;
    color: rgb(var(--ink-muted-rgb));
}


/* ─── Con quién estás hablando, durante la sesión en vivo ───
   El avatar alterna entre coach y cliente en la misma conversación y la
   pantalla no lo decía: había que deducirlo de lo que decía. Requisito 67. */

.papel-avatar {
    position: absolute;
    top: 14px;
    left: 14px;
    z-index: 20;
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding: 6px 12px 6px 10px;
    border-radius: 999px;
    font-size: 12.5px;
    font-weight: 600;
    letter-spacing: .01em;
    backdrop-filter: blur(6px);
    background: rgb(var(--overlay-rgb) / 0.62);
    border: var(--border-width) solid rgb(var(--line-rgb) / 0.5);
    transition: background-color .2s ease, border-color .2s ease;
}

.pa-punto {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: currentColor;
}

.papel-avatar.es-coach {
    color: rgb(var(--brand-text-rgb));
    border-color: rgb(var(--brand-rgb) / 0.45);
}

.papel-avatar.es-cliente {
    color: rgb(var(--warning-text-rgb));
    border-color: rgb(var(--warning-rgb) / 0.45);
}

/* ─── Se cayó la conexión con el avatar ───
   La rueda de carga se quedaba girando indefinidamente. Requisito 67. */

.fallo-conexion {
    position: absolute;
    inset: 0;
    z-index: 30;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 20px;
    background: rgb(var(--overlay-rgb) / 0.88);
    backdrop-filter: blur(3px);
}

.fallo-conexion.hidden { display: none; }

.fc-caja {
    max-width: 420px;
    text-align: center;
}

.fc-icono {
    display: block;
    font-size: 34px;
    margin-bottom: 10px;
}

.fc-titulo {
    margin: 0 0 6px;
    font-size: 16px;
    font-weight: 700;
    color: rgb(var(--on-accent-rgb));
}

.fc-texto {
    margin: 0 0 18px;
    font-size: 13px;
    line-height: 1.6;
    color: rgb(var(--ink-subtle-rgb));
}

.fc-botones {
    display: flex;
    gap: 10px;
    justify-content: center;
    flex-wrap: wrap;
}


/* ─── El análisis de una práctica que todavía no está ───
   Cerrar la sesión y analizarla eran la misma petición, así que esta pantalla
   nunca podía abrirse sin resultados. Ahora sí: cerrar es inmediato y el
   análisis va aparte. Lo que no puede pasar es que se abra vacía, con la
   sesión ya cobrada y sin decir nada. Requisito 69. */

.analisis-pendiente {
    padding: 32px 28px;
    border-radius: var(--radius-lg, 14px);
    border: var(--border-width) solid rgb(var(--line-rgb));
    background: rgb(var(--surface-rgb));
    text-align: center;
}

.analisis-pendiente.es-fallido {
    background: rgb(var(--warning-rgb) / 0.07);
    border-color: rgb(var(--warning-rgb) / 0.3);
}

.ap-icono {
    display: block;
    font-size: 30px;
    margin-bottom: 12px;
}

/* La rueda dice "está pasando algo"; el texto de al lado dice cuánto. Sola no
   basta: quince segundos de rueda sin cifra se leen como que se colgó. */
.ap-rueda {
    display: block;
    width: 34px;
    height: 34px;
    margin: 0 auto 14px;
    border-radius: 50%;
    border: 3px solid rgb(var(--line-rgb));
    border-top-color: rgb(var(--brand-rgb));
    animation: ap-girar 900ms linear infinite;
}

@keyframes ap-girar {
    to { transform: rotate(360deg); }
}

@media (prefers-reduced-motion: reduce) {
    .ap-rueda {
        animation-duration: 2.4s;
    }
}

.ap-titulo {
    margin: 0 0 8px;
    font-size: 17px;
    font-weight: 700;
    color: rgb(var(--ink-rgb));
    text-wrap: balance;
}

.ap-texto {
    margin: 0 auto 6px;
    max-width: 56ch;
    font-size: 13.5px;
    line-height: 1.65;
    color: rgb(var(--ink-muted-rgb));
}

.ap-tranquiliza {
    color: rgb(var(--ink-subtle-rgb));
    font-size: 12.5px;
}

.ap-botones {
    display: flex;
    gap: 10px;
    justify-content: center;
    flex-wrap: wrap;
    margin-top: 18px;
}

/* ─── El título de una tarjeta ───────────────────────────────────────────
   Más bajo que .enc-seccion: aquel encabeza una pantalla, este el contenido
   de una caja. El icono se alinea con la primera línea del texto y no con el
   centro del bloque, que es lo que se ve raro cuando el título ocupa dos. */
.titulo-tarjeta {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 16px;
}
.titulo-tarjeta > .icono {
    color: rgb(var(--ink-subtle-rgb));
}
.titulo-tarjeta h3 {
    margin: 0;
    font-family: var(--font-display);
    font-size: 17px;
    font-weight: 600;
    color: rgb(var(--ink-rgb));
}
.titulo-tarjeta .tt-aparte {
    margin-left: auto;
    display: flex;
    align-items: center;
    justify-content: flex-end;
    /* Envuelve: "Progreso del equipo" metió dos desplegables aquí, y en un
       teléfono los tres controles sacaban el título fuera de la tarjeta. */
    flex-wrap: wrap;
    gap: 8px;
}

/* ─── Cuando no hay nada que enseñar ─────────────────────────────────────
   El icono va apagado a propósito: un vacío no es un error ni un logro, y
   pintarlo con el color de marca lo convierte en lo más llamativo de la
   pantalla. */
.vacio {
    text-align: center;
    padding: 48px 24px;
}
.vacio-icono {
    display: flex;
    justify-content: center;
    margin-bottom: 12px;
    color: rgb(var(--ink-subtle-rgb));
    opacity: 0.55;
}
.vacio-titulo {
    margin: 0;
    font-family: var(--font-display);
    font-size: 16px;
    font-weight: 600;
    color: rgb(var(--ink-rgb));
}
.vacio-detalle {
    margin: 6px 0 0;
    font-size: 14px;
    color: rgb(var(--ink-muted-rgb));
}
.vacio-accion {
    margin-top: 20px;
}


/* ═══════════════════════════════════════════════════════════════════════
   Escenarios: la tira de cifras, la barra de la lista y sus tres niveles.
   ═══════════════════════════════════════════════════════════════════════ */

/* Las cifras de cabecera. Se reparten a lo ancho sin decidir cuántas caben en
   cada fila: `auto-fit` con un mínimo lo resuelve solo, y así una pantalla
   puede llevar cinco y otra ocho sin tocar el CSS. */
.tira-metricas {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(128px, 1fr));
    gap: 12px;
}

.metrica {
    text-align: left;
    padding: 14px 16px;
    background: rgb(var(--surface-rgb));
    border: var(--border-width) solid rgb(var(--line-rgb));
    border-radius: var(--radius-md);
    transition: border-color 120ms ease, background 120ms ease;
}

.me-etiqueta {
    font-family: var(--font-mono);
    font-size: 10px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: rgb(var(--ink-subtle-rgb));
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.me-valor {
    margin-top: 8px;
    font-family: var(--font-mono);
    font-size: 26px;
    font-weight: 500;
    line-height: 1;
    letter-spacing: -0.02em;
    color: rgb(var(--ink-rgb));
}

.me-sufijo {
    font-size: 12px;
    font-weight: 400;
    color: rgb(var(--ink-subtle-rgb));
    letter-spacing: 0;
}

/* El tono solo tiñe el número, no la tarjeta entera: la tarjeta teñida pesa
   más que el dato y con cuatro seguidas la pantalla se vuelve un semáforo. */
.metrica.es-accent .me-valor { color: rgb(var(--brand-text-rgb)); }
.metrica.es-good   .me-valor { color: rgb(var(--success-text-rgb)); }
.metrica.es-bad    .me-valor { color: rgb(var(--danger-text-rgb)); }

/* Cuando además filtra. El borde es lo que dice cuál está encendida; el fondo
   se deja quieto para que el número siga siendo lo primero que se lee. */
button.metrica { cursor: pointer; }
button.metrica:hover { border-color: rgb(var(--line-strong-rgb)); }
button.metrica.es-encendido {
    border-color: rgb(var(--brand-rgb));
    box-shadow: inset 0 0 0 1px rgb(var(--brand-rgb));
}

/* La cifra contra su total (requisito 223).

   El total va pegado al número y más pequeño: la pareja se lee como una sola
   cosa ("128 de 200"), no como dos datos. Y en la misma fuente monoespaciada,
   para que la barra de abajo empiece siempre en el mismo sitio caiga el número
   que caiga. */
.md-total {
    font-size: 14px;
    font-weight: 400;
    color: rgb(var(--ink-subtle-rgb));
    letter-spacing: 0;
}

/* El avance en turquesa sobre el tinte de la marca. El canal se pinta con el
   tinte y no con la línea gris porque la barra es un dato, no un borde: con
   gris de fondo, una barra casi vacía se lee como una tarjeta rota. */
.md-barra {
    margin-top: 10px;
    height: 4px;
    border-radius: 999px;
    background: rgb(var(--brand-tint-rgb));
    overflow: hidden;
}

.md-avance {
    height: 100%;
    border-radius: 999px;
    background: rgb(var(--brand-rgb));
}

.md-porcentaje {
    margin-top: 6px;
    font-family: var(--font-mono);
    font-size: 11px;
    color: rgb(var(--ink-subtle-rgb));
}

/* En un teléfono caben dos por fila, y "Colaboradores activos" no entra en esa
   mitad: el recorte de `me-etiqueta` lo dejaba en "COLABORADORES ACTIV…". Aquí
   el rótulo se parte en dos líneas en vez de cortarse, que es lo contrario de
   lo que conviene en la tira de una sola línea de las otras pantallas. */
@media (max-width: 720px) {
    .metrica.es-doble .me-etiqueta { white-space: normal; overflow: visible; }
}

/* La tabla de avance del inicio del líder (requisito 221).

   Filas enlazadas, no una tabla con un botón al final: toda la fila lleva al
   perfil de quien nombra, que es lo único que se puede querer hacer con ella.
   Y enlaces de verdad, para que se abran en otra pestaña y el teclado llegue. */
.avance-fila {
    display: grid;
    grid-template-columns: minmax(130px, 1.6fr) minmax(90px, 1fr) 110px 1fr 1fr 88px 72px;
    align-items: center;
    gap: 12px;
    padding: 12px 4px;
    color: inherit;
    text-decoration: none;
}

.avance-fila + .avance-fila { border-top: var(--border-width) solid rgb(var(--line-rgb)); }
a.avance-fila:hover { background: rgb(var(--brand-tint-rgb)); }

/* Las filas que pasan del quinto puesto están en el HTML desde el principio y
   se descubren con una clase en la tabla, no fila a fila: así el botón cambia
   un solo atributo y no doce, y una fila nunca puede quedarse a medio abrir.

   `display: none` y no `visibility`: una fila invisible pero con altura dejaría
   el hueco de siete filas vacías debajo de la tabla. */
.avance-fila.es-de-mas { display: none; }
.es-completa .avance-fila.es-de-mas { display: grid; }

.mostrar-resto { margin-top: 12px; }
.mostrar-resto.es-oculta { display: none; }

/* Filtrada pesa más que "de más": una fila que el filtro descartó sigue fuera
   aunque se abra la tabla entera. Va después y con la misma especificidad que
   la regla de `es-completa`, que es lo que decide cuál gana. */
.avance-fila.es-filtrada,
.es-completa .avance-fila.es-filtrada { display: none; }

/* Los encabezados son botones, así que hay que devolverles el aspecto de
   rótulo: un botón trae fondo, borde y su propia tipografía. */
.av-orden {
    font: inherit;
    font-family: var(--font-mono);
    font-size: 10px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: rgb(var(--ink-subtle-rgb));
    background: none;
    border: 0;
    padding: 0;
    cursor: pointer;
    text-align: left;
    min-width: 0;
    display: flex;
    align-items: center;
    gap: 4px;
}
.av-orden.es-a-la-derecha { justify-content: flex-end; }
.av-orden:hover { color: rgb(var(--ink-rgb)); }
.av-orden.es-ordenada { color: rgb(var(--brand-text-rgb)); }

/* La flecha solo existe en la columna ordenada: una flecha apagada en las siete
   dice que todas se pueden ordenar, pero también hace ilegible cuál lo está. */
.av-orden.es-ordenada::after { content: '▲'; font-size: 8px; }
.av-orden.es-ordenada.es-al-reves::after { content: '▼'; }

.filtro-de-avance {
    font-family: var(--font-mono);
    font-size: 11px;
    color: rgb(var(--ink-rgb));
    background: rgb(var(--surface-rgb));
    border: var(--border-width) solid rgb(var(--line-rgb));
    border-radius: var(--radius-sm, 6px);
    padding: 4px 6px;
    max-width: 150px;
}

.av-sin-resultados {
    display: none;
    align-items: center;
    gap: 10px;
    padding: 18px 4px;
    font-size: 14px;
    color: rgb(var(--ink-subtle-rgb));
}
.av-sin-resultados.es-a-la-vista { display: flex; }

.avance-encabezado {
    font-family: var(--font-mono);
    font-size: 10px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: rgb(var(--ink-subtle-rgb));
    border-bottom: var(--border-width) solid rgb(var(--line-rgb));
}

.av-quien { display: flex; align-items: center; gap: 10px; min-width: 0; }

.av-nombre {
    font-weight: 500;
    color: rgb(var(--ink-rgb));
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* El par "hechos / total". Mismo idioma que la métrica doble de arriba, para
   que la tabla y la tira se lean igual. */
.av-par { font-family: var(--font-mono); font-size: 14px; color: rgb(var(--ink-rgb)); }
.av-par small { font-size: 11px; color: rgb(var(--ink-subtle-rgb)); }

.av-cumplimiento { display: flex; align-items: center; gap: 8px; justify-content: flex-end; }
.av-promedio { display: flex; align-items: center; justify-content: flex-end; }

/* La celda de equipos y la lista que abre el "+".

   `position: relative` en la celda y no en la fila: colgada de la fila, la
   lista se abriría en el borde izquierdo de la tabla y no debajo del nombre
   que la produjo. */
.av-equipo { position: relative; }

.av-equipos-abre { cursor: pointer; border-bottom: 1px dotted rgb(var(--line-rgb)); }
.av-equipos-abre:hover { color: rgb(var(--ink-rgb)); }
.av-equipos-abre:focus-visible { outline: 2px solid rgb(var(--brand-rgb)); outline-offset: 2px; }

.av-mas {
    font-family: var(--font-mono);
    font-weight: 600;
    color: rgb(var(--brand-text-rgb));
}

.av-equipos-lista {
    display: none;
    position: absolute;
    top: calc(100% + 6px);
    left: 0;
    z-index: 20;
    min-width: 160px;
    max-width: 240px;
    padding: 10px 12px;
    background: rgb(var(--surface-rgb));
    border: var(--border-width) solid rgb(var(--line-rgb));
    border-radius: var(--radius-sm, 6px);
    /* `--shadow-lg` y no un negro a mano: en tema oscuro un 12 % de negro
       sobre una superficie oscura no despega la lista de la tabla, y la
       hoja no puede llevar colores escritos a pelo (lo comprueba
       `test_colores_desde_tokens`). */
    box-shadow: var(--shadow-lg);
    white-space: normal;
}
.av-equipos-lista.es-a-la-vista { display: block; }

.av-equipos-titulo {
    display: block;
    font-family: var(--font-mono);
    font-size: 10px;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: rgb(var(--ink-subtle-rgb));
    margin-bottom: 6px;
}
.av-equipos-uno {
    display: block;
    font-size: 13px;
    color: rgb(var(--ink-rgb));
    padding: 2px 0;
}

/* El equipo se recorta con puntos suspensivos en vez de partir la fila: los
   nombres de equipo son largos y variables, y dejarlos crecer movía las cinco
   columnas de cifras de sitio en cada fila. */
.av-equipo {
    font-size: 13px;
    color: rgb(var(--ink-subtle-rgb));
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    min-width: 0;
}
.av-cifra { font-family: var(--font-mono); font-size: 14px; color: rgb(var(--ink-rgb)); }
.av-cifra.es-sin-dato { color: rgb(var(--ink-subtle-rgb)); }

/* En un teléfono la rejilla de siete columnas no cabe. Se apila, y cada celda
   lleva delante su rótulo: sin encabezado a la vista, "2/3" no dice de qué. */
@media (max-width: 720px) {
    .avance-encabezado { display: none; }
    .avance-fila {
        grid-template-columns: 1fr 1fr;
        gap: 6px 12px;
        padding: 14px 4px;
    }
    .av-quien { grid-column: 1 / -1; }
    .av-par::before, .av-cumplimiento::before, .av-equipo::before, .av-promedio::before {
        content: attr(data-rotulo) ' ';
        font-family: var(--font-mono);
        font-size: 10px;
        text-transform: uppercase;
        letter-spacing: 0.08em;
        color: rgb(var(--ink-subtle-rgb));
    }
    .av-cumplimiento, .av-promedio { justify-content: flex-start; }
}

/* Los filtros de una tarjeta con gráfico: el periodo y de quién.

   El ancho de los selectores vive aquí y no en un `style=` de la plantilla
   porque en un teléfono tiene que cambiar, y un estilo en línea gana a
   cualquier media query. Con el ancho suelto, los dos selectores sacaban la
   página nueve píxeles a la derecha en 390px y aparecía barra horizontal. */
.filtros-grafico {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
    margin-bottom: 16px;
}
.filtros-grafico select { width: auto; min-width: 160px; }

/* La nota de una tarjeta de gráfico se parte antes que su título. Sin esto, a
   media pantalla se partía "Habilidades más desarrolladas" —el nombre de la
   tarjeta, lo que hay que poder leer de un vistazo— para dejarle sitio a una
   aclaración. */
.card .titulo-tarjeta h3 { white-space: nowrap; }
@media (max-width: 520px) {
    .card .titulo-tarjeta h3 { white-space: normal; }
}

@media (max-width: 720px) {
    .filtros-grafico { width: 100%; }
    .filtros-grafico select { flex: 1 1 150px; min-width: 0; width: 100%; }
}

/* La aclaración de una tarjeta cuando no cabe al lado del título. Ocupa el
   sitio del margen inferior del título, no uno nuevo, para que la tarjeta no
   crezca por llevarla. */
.nota-tarjeta {
    margin: -10px 0 16px;
    font-size: 13px;
    color: rgb(var(--ink-subtle-rgb));
}

/* El aviso de "no hay periodo anterior con el que comparar". No es un error, así
   que no lleva color de error: es una nota al pie del gráfico. */
.nota-grafico {
    margin-top: 10px;
    font-size: 12px;
    color: rgb(var(--ink-subtle-rgb));
}

/* La barra de la lista: buscar, el filtro de atención y plegar. */
.barra-lista {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
}

.bl-busca {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    height: 34px;
    padding: 0 12px;
    border-radius: 999px;
    border: var(--border-width) solid rgb(var(--line-rgb));
    background: rgb(var(--surface-rgb));
    color: rgb(var(--ink-subtle-rgb));
    min-width: 260px;
}
.bl-busca input {
    border: none;
    background: none;
    outline: none;
    font-size: 13.5px;
    color: rgb(var(--ink-rgb));
    width: 100%;
}
.bl-busca input::placeholder { color: rgb(var(--ink-subtle-rgb)); }

.bl-aparte {
    margin-left: auto;
    display: flex;
    align-items: center;
    gap: 16px;
}
.bl-enlace {
    font-size: 13px;
    font-weight: 500;
    color: rgb(var(--ink-muted-rgb));
}
.bl-enlace:hover { color: rgb(var(--brand-text-rgb)); }

.lista-sin-resultados {
    padding: 40px 0;
    text-align: center;
    font-size: 14px;
    color: rgb(var(--ink-subtle-rgb));
}

/* ── Nivel 1: el equipo ── */
.lista-escenarios {
    display: flex;
    flex-direction: column;
    gap: 20px;
}

.grupo-equipo {
    border: var(--border-width) solid rgb(var(--line-rgb));
    border-radius: var(--radius-lg);
    overflow: hidden;
    background: rgb(var(--surface-rgb));
}

.ge-cabecera {
    width: 100%;
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 12px 16px;
    background: rgb(var(--surface-2-rgb));
    text-align: left;
}
.ge-cabecera:hover { background: rgb(var(--line-rgb) / 0.55); }

/* La flecha gira con el estado del botón y no con un `style` escrito desde el
   JavaScript: así "Plegar equipos" no tiene que acordarse de girarla. */
.ge-flecha, .gp-flecha {
    display: inline-flex;
    color: rgb(var(--ink-subtle-rgb));
    transition: transform 140ms ease;
}
[aria-expanded="false"] .ge-flecha,
[aria-expanded="false"] .gp-flecha { transform: rotate(-90deg); }

.ge-nombre {
    font-family: var(--font-display);
    font-size: 16px;
    font-weight: 600;
    color: rgb(var(--ink-rgb));
}

.ge-cuenta {
    font-family: var(--font-mono);
    font-size: 11.5px;
    color: rgb(var(--ink-subtle-rgb));
}

.ge-atencion { margin-left: auto; }

.ge-cuerpo {
    padding: 12px;
    display: flex;
    flex-direction: column;
    gap: 8px;
}

/* ── Nivel 2: la persona ── */
.gp-cabecera {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 4px 4px 4px 0;
}

.gp-quien {
    display: flex;
    align-items: center;
    gap: 10px;
    text-align: left;
    min-width: 0;
}

.avatar-inicial {
    width: 30px;
    height: 30px;
    flex-shrink: 0;
    border-radius: 50%;
    background: rgb(var(--brand-strong-rgb));
    color: rgb(var(--brand-on-rgb));
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.01em;
}

/* Un solo tono, y no el color por persona de las capturas.

   Ahí cada avatar tiene el suyo, sin ninguna regla visible detrás. Para
   reproducirlo harían falta cuatro pares de fondo y texto comprobados en los
   dos temas: `info` y `success` son oscuros en claro y claros en oscuro, así
   que el color del texto tendría que cambiar con el tema y por tono. Eso es
   decidir una paleta, no portar una captura, y con un par mal elegido el
   resultado son iniciales ilegibles.

   El par `brand-strong` / `brand-on` sí está definido para esto, y es el
   mismo con el que ya se pinta el avatar de quien entra en el pie de la barra
   lateral. */

.gp-texto { min-width: 0; }
.gp-nombre {
    display: block;
    font-size: 14px;
    font-weight: 600;
    color: rgb(var(--ink-rgb));
}
.gp-detalle {
    display: block;
    font-size: 12px;
    color: rgb(var(--ink-subtle-rgb));
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.gp-cuenta {
    margin-left: auto;
    font-family: var(--font-mono);
    font-size: 11.5px;
    color: rgb(var(--ink-subtle-rgb));
    white-space: nowrap;
}

.gp-cuerpo {
    padding-left: 42px;
    display: flex;
    flex-direction: column;
    gap: 8px;
}

/* ── Nivel 3: la asignación ── */
/* El borde de la izquierda solo aparece cuando hay algo que decir. Antes lo
   ponía un `style` en línea calculado en la plantilla; ahora son dos clases,
   y así el color sale de los mismos tokens que el resto. */
/* El promedio dice si llega al umbral. Ámbar y no rojo cuando no llega: es
   un puntaje bajo, no un fallo, y el rojo de esta pantalla ya está reservado
   para lo vencido. */
.fa-promedio.es-alto { color: rgb(var(--brand-text-rgb)); }
.fa-promedio.es-bajo { color: rgb(var(--warning-text-rgb)); }

/* "+ Asignar" queda pegado al borde derecho de la fila, después del recuento.
   El recuento crece con el número, así que empujarlo con un margen automático
   lo deja siempre en el mismo sitio y no bailando según diga "1 asignación" o
   "10 asignaciones". */
.gp-cuenta { margin-left: auto; }
.gp-asignar { flex-shrink: 0; }

.fila-asignacion.es-vencida { border-left: 3px solid rgb(var(--danger-rgb)); }
.fila-asignacion.es-justa   { border-left: 3px solid rgb(var(--warning-rgb)); }

.fa-flecha { color: rgb(var(--ink-subtle-rgb)); }
.fila-asignacion:hover .fa-flecha { color: rgb(var(--brand-text-rgb)); }

.fe-dato.es-apagado { color: rgb(var(--ink-subtle-rgb)); }
.fe-dato.es-tarde   { color: rgb(var(--danger-text-rgb)); }
.fe-dato b { font-weight: 600; color: rgb(var(--ink-rgb)); }

/* Una fila de chips suelta —los equipos de una persona, por ejemplo—. */
.fila-chips {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
}

/* Un montón de asignaciones seguidas, sin equipo ni persona por encima: es lo
   que enseña el perfil de una persona, donde la persona ya es el título. */
.lista-asignaciones {
    margin-top: 10px;
    display: flex;
    flex-direction: column;
    gap: 8px;
}


/* ── Un aviso con cuerpo ──
   El de "3 personas sin equipo" era una tarjeta de una línea con un icono al
   lado. Ahora dice además qué implica y trae el botón para verlas: un aviso
   que solo cuenta un problema obliga a buscarlo a mano. */
.aviso {
    display: flex;
    align-items: flex-start;
    gap: 12px;
    padding: 16px 18px;
    border-radius: var(--radius-md);
    border: var(--border-width) solid rgb(var(--line-rgb));
    background: rgb(var(--surface-rgb));
}
.aviso-warn {
    background: rgb(var(--warning-tint-rgb));
    border-color: rgb(var(--warning-rgb) / 0.45);
}
.av-icono { flex-shrink: 0; color: rgb(var(--warning-text-rgb)); }
.av-cuerpo { min-width: 0; }
.av-titulo {
    margin: 0;
    font-size: 14.5px;
    font-weight: 600;
    color: rgb(var(--ink-rgb));
}
.av-detalle {
    margin: 6px 0 12px;
    font-size: 13.5px;
    line-height: 1.55;
    color: rgb(var(--ink-muted-rgb));
    max-width: 72ch;
}

/* ── La tabla de gente ──
   Nombre, usuario y correo ocupaban tres columnas de identidad y no quedaba
   sitio para lo que se viene a mirar. Ahora la identidad es una sola celda de
   dos líneas y las otras cuatro columnas son números. */
.tg-nombre {
    font-size: 14px;
    font-weight: 600;
    color: rgb(var(--ink-rgb));
}
.tg-quien {
    margin-top: 2px;
    font-family: var(--font-mono);
    font-size: 11.5px;
    color: rgb(var(--ink-subtle-rgb));
}

.tg-actividad {
    margin-top: 3px;
    font-size: 12px;
    color: rgb(var(--ink-subtle-rgb));
}
/* Quien nunca entró se dice en ámbar: es lo único de esta columna sobre lo que
   hay algo que hacer. */
.tg-actividad.es-nunca { color: rgb(var(--warning-text-rgb)); font-weight: 500; }

.tabla-gente th.num, .tabla-gente td.num {
    text-align: center;
    font-family: var(--font-mono);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}
.tabla-gente td.num { font-size: 14px; color: rgb(var(--ink-rgb)); }

/* El cero apagado: con las cuatro columnas en tinta plena, una fila de ceros
   pesa lo mismo que una llena y hay que leer los números para distinguirlas. */
.es-cero { color: rgb(var(--ink-subtle-rgb)); font-weight: 400; }

.tg-promedio { color: rgb(var(--brand-text-rgb)); font-weight: 600; }

/* Los equipos de una persona van en texto y no en chips: un nombre propio como
   "Equipo de Ventas" en versalitas de monoespaciada se lee peor, y el chip
   estaba reservado para estados. */
.tg-equipos {
    display: flex;
    flex-direction: column;
    gap: 2px;
    font-size: 13.5px;
    color: rgb(var(--ink-muted-rgb));
}

/* "Colocar", junto al chip de "Sin equipo": es la acción que quita ese estado,
   y va donde está el problema y no al final de la fila. */
.tg-colocar {
    margin-left: 8px;
    font-size: 12.5px;
    font-weight: 500;
    color: rgb(var(--brand-text-rgb));
}
.tg-colocar:hover { text-decoration: underline; }


/* ── La tarjeta de un equipo ──
   Llevaba un círculo con un icono, el nombre, la descripción y un chip con el
   número de gente. El icono era el mismo en las cuatro tarjetas, así que solo
   ocupaba sitio; el pie ahora dice quiénes son, que es lo que distingue a un
   equipo de otro del mismo tamaño. */
.tarjeta-equipo {
    display: flex;
    flex-direction: column;
    background: rgb(var(--surface-rgb));
    border: var(--border-width) solid rgb(var(--line-rgb));
    border-radius: var(--radius-lg);
    cursor: pointer;
    transition: border-color 140ms ease;
}
.tarjeta-equipo:hover { border-color: rgb(var(--brand-rgb) / 0.45); }

.te-cabecera {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    padding: 18px 18px 0;
}
.te-nombre {
    margin: 0;
    flex: 1;
    font-family: var(--font-display);
    font-size: 17px;
    font-weight: 600;
    color: rgb(var(--ink-rgb));
}

/* Las acciones aparecen al pasar por encima. Estaban siempre a la vista, dos
   botones por tarjeta, y "Eliminar" en rojo pesaba más que el nombre. */
.te-acciones {
    display: flex;
    gap: 10px;
    opacity: 0;
    transition: opacity 140ms ease;
}
.tarjeta-equipo:hover .te-acciones,
.tarjeta-equipo:focus-within .te-acciones { opacity: 1; }
.te-accion {
    font-size: 12.5px;
    font-weight: 500;
    color: rgb(var(--ink-muted-rgb));
}
.te-accion:hover { color: rgb(var(--brand-text-rgb)); }
.te-accion.es-peligro:hover { color: rgb(var(--danger-text-rgb)); }

.te-descripcion {
    margin: 8px 18px 18px;
    font-size: 13.5px;
    line-height: 1.5;
    color: rgb(var(--ink-muted-rgb));
}
.te-descripcion.es-vacia { font-style: italic; color: rgb(var(--ink-subtle-rgb)); }

.te-pie {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-top: auto;
    padding: 12px 18px;
    border-top: var(--border-width) solid rgb(var(--line-rgb));
}
.te-cuantos {
    font-size: 13.5px;
    font-weight: 600;
    color: rgb(var(--ink-rgb));
    white-space: nowrap;
}
.te-quienes {
    min-width: 0;
    font-size: 13px;
    color: rgb(var(--ink-subtle-rgb));
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.te-flecha { margin-left: auto; color: rgb(var(--ink-subtle-rgb)); }
.tarjeta-equipo:hover .te-flecha { color: rgb(var(--brand-text-rgb)); }

/* El pie de la pantalla de equipos. */
.pie-equipos {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
    margin-top: 24px;
    padding: 14px 18px;
    background: rgb(var(--surface-rgb));
    border: var(--border-width) solid rgb(var(--line-rgb));
    border-radius: var(--radius-md);
}
.pe-total { font-size: 14px; font-weight: 600; color: rgb(var(--ink-rgb)); }
.pe-detalle { font-size: 13.5px; color: rgb(var(--ink-muted-rgb)); }
.pe-accion { margin-left: auto; }

/* ══════════════════════════════════════════════════════════════════════
   El detalle de un entrenamiento, visto por quien lo practica
   (capturas colaborador-04 y colaborador-05).

   Antes era una columna larga: cabecera, cuatro cifras, objetivo, gráfica,
   sesiones y feedback, uno detrás de otro. Lo único accionable —practicar la
   siguiente— quedaba arriba del todo y se perdía al bajar. Ahora lo que se
   consulta va a la izquierda y lo que se hace, a la derecha, fijo a la vista.
   ══════════════════════════════════════════════════════════════════════ */

.corte {
    border: 0;
    border-top: var(--border-width) solid rgb(var(--line-rgb));
    margin: 0 0 24px;
}

.detalle-cols {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 340px;
    gap: 20px;
    align-items: start;
}

.dc-principal,
.dc-lado {
    display: grid;
    gap: 16px;
    min-width: 0;
}

@media (max-width: 1100px) {
    .detalle-cols { grid-template-columns: minmax(0, 1fr); }
}

/* El aviso rojo. Hermano de `.aviso-warn`: mismo hueco, otro motivo. */
.aviso-bad {
    background: rgb(var(--danger-tint-rgb));
    border-color: rgb(var(--danger-rgb) / 0.45);
}
.aviso-bad .av-icono { color: rgb(var(--danger-text-rgb)); }

/* ── Las prácticas del programa ── */

.lista-sesiones {
    list-style: none;
    margin: 18px 0 0;
    padding: 0;
    display: grid;
}

.fila-sesion {
    display: flex;
    align-items: flex-start;
    gap: 14px;
    padding: 16px 0;
    border-top: var(--border-width) solid rgb(var(--line-rgb));
}
.lista-sesiones > .fila-sesion:first-child { border-top: 0; padding-top: 0; }

/* La marca de la izquierda: el número mientras espera, el visto cuando ya
   está. Es lo que permite contar de un vistazo cuánto queda. */
.fs-marca {
    flex-shrink: 0;
    width: 26px;
    height: 26px;
    display: grid;
    place-items: center;
    border-radius: 999px;
    font-family: var(--font-mono);
    font-size: 12px;
    font-weight: 600;
    background: rgb(var(--surface-2-rgb));
    color: rgb(var(--ink-subtle-rgb));
}
.fila-sesion.es-hecha .fs-marca {
    background: rgb(var(--success-tint-rgb));
    color: rgb(var(--success-text-rgb));
}
.fila-sesion.es-siguiente .fs-marca {
    background: rgb(var(--brand-tint-rgb));
    color: rgb(var(--brand-text-rgb));
}

.fs-cuerpo { flex: 1; min-width: 0; }

.fs-marcas {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 8px;
}

.fs-orden {
    font-family: var(--font-mono);
    font-size: 10.5px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: rgb(var(--ink-subtle-rgb));
}

.fs-titulo {
    margin: 6px 0 0;
    font-size: 14.5px;
    font-weight: 600;
    color: rgb(var(--ink-rgb));
}

.fs-nota {
    margin: 4px 0 0;
    font-size: 13.5px;
    line-height: 1.5;
    color: rgb(var(--ink-muted-rgb));
    max-width: 72ch;
}

.fs-cuando {
    margin: 6px 0 0;
    font-family: var(--font-mono);
    font-size: 11.5px;
    color: rgb(var(--ink-subtle-rgb));
}

.fs-salto { font-weight: 600; }
.fs-salto.es-sube { color: rgb(var(--success-text-rgb)); }
.fs-salto.es-baja { color: rgb(var(--danger-text-rgb)); }

.fs-derecha {
    flex-shrink: 0;
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    justify-content: flex-end;
}

.fs-puntaje {
    font-family: var(--font-display);
    font-size: 22px;
    font-weight: 600;
    letter-spacing: -0.02em;
    color: rgb(var(--ink-rgb));
}

/* La práctica previa no tiene nota (requisito 386): se dice en pequeño, no
   con la cifra grande de una sesión evaluada. */
.fs-puntaje.fs-sin-nota {
    font-family: inherit;
    font-size: 13px;
    font-weight: 500;
    letter-spacing: 0;
    color: rgb(var(--ink-muted-rgb));
}

/* ── El feedback de la última práctica ── */

.lista-hallazgos {
    list-style: none;
    margin: 10px 0 0;
    padding: 0;
    display: grid;
    gap: 10px;
}

.hallazgo {
    display: flex;
    align-items: flex-start;
    gap: 10px;
}

.ha-marca {
    flex-shrink: 0;
    margin-top: 2px;
    color: rgb(var(--success-text-rgb));
}

.ha-texto {
    margin: 0;
    flex: 1;
    font-size: 14px;
    line-height: 1.55;
    color: rgb(var(--ink-rgb));
}

.pila-mejoras {
    display: grid;
    gap: 14px;
    margin-top: 10px;
}

.mejora {
    border: var(--border-width) solid rgb(var(--line-rgb));
    border-radius: var(--radius-md);
    overflow: hidden;
}

.mj-cuerpo { padding: 14px 16px; }
.mj-momento { margin-bottom: 8px; }

.mj-texto {
    margin: 0;
    font-size: 14px;
    line-height: 1.55;
    color: rgb(var(--ink-rgb));
}

/* El consejo va pegado a la mejora que lo motiva y con otro fondo: es lo que
   hay que hacer, no otro hallazgo. */
.mj-consejo {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    padding: 12px 16px;
    background: rgb(var(--brand-tint-rgb));
    border-top: var(--border-width) solid rgb(var(--brand-rgb) / 0.25);
}
.pila-mejoras > .mj-consejo {
    border: var(--border-width) solid rgb(var(--brand-rgb) / 0.25);
    border-radius: var(--radius-md);
}
.mc-icono { flex-shrink: 0; margin-top: 2px; color: rgb(var(--brand-text-rgb)); }
.mj-consejo p {
    margin: 0;
    font-size: 13.5px;
    line-height: 1.55;
    color: rgb(var(--ink-rgb));
}

/* ── La columna de al lado ── */

.lado-titulo {
    margin: 6px 0 0;
    font-size: 15px;
    font-weight: 600;
    line-height: 1.4;
    color: rgb(var(--ink-rgb));
}

.lado-texto {
    margin: 8px 0 0;
    font-size: 13.5px;
    line-height: 1.6;
    color: rgb(var(--ink-muted-rgb));
}

.lado-cifra {
    margin: 4px 0 0;
    font-family: var(--font-display);
    font-size: 34px;
    font-weight: 600;
    letter-spacing: -0.02em;
    line-height: 1;
    color: rgb(var(--ink-rgb));
}
.lc-sobre {
    margin-left: 6px;
    font-family: var(--font-mono);
    font-size: 12px;
    font-weight: 400;
    color: rgb(var(--ink-subtle-rgb));
}
.lc-vacio {
    font-family: var(--font-body);
    font-size: 14px;
    font-weight: 400;
    color: rgb(var(--ink-subtle-rgb));
}

/* Cómo se reparte la nota. La barra no es decoración: dos criterios al 25 %
   y uno al 35 % se comparan por longitud sin leer los tres números. */
.lista-pesos {
    list-style: none;
    margin: 12px 0 0;
    padding: 0;
    display: grid;
    gap: 12px;
}

.pe-fila {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
}

.pe-nombre {
    font-size: 13.5px;
    color: rgb(var(--ink-rgb));
}

.pe-cifra {
    font-family: var(--font-mono);
    font-size: 12px;
    color: rgb(var(--ink-muted-rgb));
}

.pe-barra {
    display: block;
    height: 3px;
    margin-top: 6px;
    border-radius: 999px;
    background: rgb(var(--line-rgb));
    overflow: hidden;
}
.pe-relleno {
    display: block;
    height: 100%;
    border-radius: 999px;
    background: rgb(var(--brand-strong-rgb));
}

/* ══════════════════════════════════════════════════════════════════════
   Las pantallas de acceso (capturas acceso-01 a acceso-06).

   Antes eran una tarjeta ancha y centrada con el logotipo dentro y todo el
   texto al medio. El título alineado a la izquierda, encima de una tarjeta
   estrecha, hace que el ojo empiece donde empieza el formulario en vez de
   rebotar entre dos centros distintos.
   ══════════════════════════════════════════════════════════════════════ */

.acceso-barra {
    position: absolute;
    inset: 0 0 auto 0;
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 22px 32px;
}

.boton-tema {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    height: 34px;
    padding: 0 14px;
    border-radius: 999px;
    border: var(--border-width) solid rgb(var(--line-rgb));
    background: rgb(var(--surface-rgb));
    font-size: 13px;
    color: rgb(var(--ink-rgb));
    cursor: pointer;
}
.boton-tema:hover { border-color: rgb(var(--line-strong-rgb)); }
/* Se enseña el destino, no el estado: en claro la luna, en oscuro el sol. */
.bt-sol { display: none; }
[data-theme="dark"] .bt-luna { display: none; }
[data-theme="dark"] .bt-sol { display: inline-flex; }

.acceso { width: 372px; max-width: 100%; }

.ac-titulo {
    margin: 0;
    font-family: var(--font-display);
    font-size: 32px;
    font-weight: 600;
    letter-spacing: -0.02em;
    color: rgb(var(--ink-rgb));
}

.ac-nota {
    margin: 8px 0 0;
    font-size: 14px;
    line-height: 1.5;
    color: rgb(var(--ink-muted-rgb));
}

.ac-tarjeta {
    margin-top: 24px;
    padding: 22px;
    background: rgb(var(--surface-rgb));
    border: var(--border-width) solid rgb(var(--line-rgb));
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-sm);
}

.ac-pie {
    margin: 14px 0 0;
    text-align: center;
    font-size: 12.5px;
    line-height: 1.5;
    color: rgb(var(--ink-subtle-rgb));
}

.ac-forma { display: grid; gap: 16px; }

.ac-forma .btn { width: 100%; }

.ac-enlace {
    font-size: 13.5px;
    font-weight: 500;
    color: rgb(var(--brand-text-rgb));
}
.ac-enlace:hover { text-decoration: underline; }

.ac-acciones {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-top: 4px;
}
.ac-acciones .btn { width: auto; }

/* El error, dentro de la tarjeta y encima de los campos que hay que corregir.
   Como aviso flotante en otra esquina obligaba a mirar dos sitios. */
.ac-error {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    margin-bottom: 18px;
    padding: 13px 15px;
    border-radius: var(--radius-md);
    background: rgb(var(--danger-tint-rgb));
    border: var(--border-width) solid rgb(var(--danger-rgb) / 0.4);
}
.ae-icono { flex-shrink: 0; margin-top: 1px; color: rgb(var(--danger-text-rgb)); }
.ae-titulo {
    margin: 0;
    font-size: 13.5px;
    font-weight: 600;
    color: rgb(var(--danger-text-rgb));
}
.ae-detalle {
    margin: 3px 0 0;
    font-size: 13px;
    line-height: 1.5;
    color: rgb(var(--ink-muted-rgb));
}

/* ── Un campo con su etiqueta encima ── */

.campo { display: block; }

.ca-etiqueta {
    display: block;
    margin-bottom: 7px;
    font-size: 13.5px;
    font-weight: 600;
    color: rgb(var(--ink-rgb));
}

/* El motivo del rechazo, debajo del campo que hay que corregir. */
.ca-error {
    display: block;
    margin-top: 6px;
    font-size: 12.5px;
    line-height: 1.4;
    color: rgb(var(--danger-text-rgb));
}

.ca-caja { position: relative; display: block; }
.ca-caja .input-field { padding-right: 42px; }

.ca-ojo {
    position: absolute;
    top: 50%;
    right: 10px;
    transform: translateY(-50%);
    display: grid;
    place-items: center;
    width: 26px;
    height: 26px;
    border: 0;
    background: transparent;
    color: rgb(var(--ink-subtle-rgb));
    cursor: pointer;
}
.ca-ojo:hover { color: rgb(var(--ink-muted-rgb)); }
.ca-ojo.es-viendo { color: rgb(var(--brand-text-rgb)); }

.input-field.es-mal { border-color: rgb(var(--danger-rgb)); }

/* ── Las reglas de la contraseña ── */

.reglas-clave {
    list-style: none;
    margin: -6px 0 0;
    padding: 0;
    display: grid;
    gap: 5px;
}

.regla {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 12.5px;
    color: rgb(var(--ink-subtle-rgb));
}

.rc-marca {
    display: grid;
    place-items: center;
    width: 15px;
    height: 15px;
    border-radius: 999px;
    border: 1px solid rgb(var(--line-strong-rgb));
    color: transparent;
    transition: background .15s ease, border-color .15s ease, color .15s ease;
}

/* Cumplida se marca, no se tacha: lo que ya está bien deja de pedir atención
   pero sigue leyéndose. */
.regla.es-cumplida { color: rgb(var(--ink-muted-rgb)); }
.regla.es-cumplida .rc-marca {
    background: rgb(var(--success-rgb));
    border-color: rgb(var(--success-rgb));
    color: rgb(var(--surface-rgb));
}

/* ── Credenciales de demostración ── */

.ac-demo {
    margin-top: 20px;
    padding-top: 16px;
    border-top: var(--border-width) solid rgb(var(--line-rgb));
}

.ad-rotulo {
    margin: 0 0 8px;
    font-family: var(--font-mono);
    font-size: 10.5px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: rgb(var(--ink-subtle-rgb));
}

.ad-fila {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    font-size: 12.5px;
    color: rgb(var(--ink-muted-rgb));
    padding: 3px 0;
}
.ad-fila code {
    font-family: var(--font-mono);
    font-size: 11.5px;
    color: rgb(var(--ink-subtle-rgb));
}

/* Las acciones de una fila de la tabla de gente. "Perfil" primero y con borde,
   porque es a lo que se entra; editar y quitar en fantasma detrás. */
.tg-acciones {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 6px;
}

/* ── El panel de un modal ──
   (`.modal` ya existe en layout.css y es la capa oscura de fondo, no el panel.)
   Cabecera con título y una frase que dice qué va a pasar, cuerpo, y pie
   separado por una línea con las acciones a la derecha (captura equipos-11).
   Antes era una `.card` con un título y los botones flotando al final: nada
   decía que "Agregar Colaborador" fuese a crear una cuenta. */
.panel-modal {
    background: rgb(var(--surface-rgb));
    border: var(--border-width) solid rgb(var(--line-rgb));
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-soft);
    overflow: hidden;
}

.pm-cerrar {
    position: absolute;
    top: 14px;
    right: 16px;
    font-size: 22px;
    line-height: 1;
    border: 0;
    background: transparent;
    color: rgb(var(--ink-subtle-rgb));
    cursor: pointer;
}
.pm-cerrar:hover { color: rgb(var(--ink-rgb)); }

.pm-cabecera { padding: 22px 24px 0; }

.pm-titulo {
    margin: 0;
    font-family: var(--font-display);
    font-size: 20px;
    font-weight: 600;
    letter-spacing: -0.01em;
    color: rgb(var(--ink-rgb));
    padding-right: 28px;
}

.pm-nota {
    margin: 8px 0 0;
    font-size: 13.5px;
    line-height: 1.55;
    color: rgb(var(--ink-muted-rgb));
}

.pm-cuerpo {
    padding: 20px 24px 22px;
    display: grid;
    gap: 16px;
}

.pm-pie {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 10px;
    padding: 16px 24px;
    border-top: var(--border-width) solid rgb(var(--line-rgb));
    background: rgb(var(--surface-2-rgb));
}

/* El estado y el menú, arriba a la derecha de la fila (captura biblioteca-01).
   Las acciones estaban abajo, en una fila propia que hacía la tarjeta más
   alta y separaba el menú del título al que pertenece. */
.fe-derecha {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-shrink: 0;
}

/* ── Los minutos del contrato, al pie de la barra lateral ──
   (Captura escenarios-01.) Va con el resto de lo que es "tuyo" —quién eres,
   el tema, salir— y no arriba con la navegación: es un dato de la cuenta, no
   un sitio al que ir. */
.mi-caja {
    position: relative;
    margin-bottom: 12px;
}

.minutos {
    display: block;
    width: 100%;
    padding: 11px 12px;
    border-radius: var(--radius-md);
    background: rgb(var(--surface-2-rgb));
    border: var(--border-width) solid rgb(var(--line-rgb));
    /* Es un `button`: sin esto hereda la tipografía del agente de usuario y
       el texto de dentro cambia de fuente al pulsarse. */
    font: inherit;
    color: inherit;
    text-align: left;
    cursor: pointer;
}
.minutos:hover { border-color: rgb(var(--line-strong-rgb)); }
.minutos[aria-expanded="true"] { border-color: rgb(var(--brand-strong-rgb)); }

.mi-cabecera {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 10px;
}

.mi-etiqueta {
    font-size: 12px;
    color: rgb(var(--ink-muted-rgb));
}

.mi-cifra {
    font-family: var(--font-mono);
    font-size: 13.5px;
    font-weight: 600;
    color: rgb(var(--ink-rgb));
}

.mi-barra {
    display: block;
    height: 3px;
    margin: 8px 0 6px;
    border-radius: 999px;
    background: rgb(var(--line-rgb));
    overflow: hidden;
}

.mi-relleno {
    display: block;
    height: 100%;
    border-radius: 999px;
    background: rgb(var(--brand-strong-rgb));
}

.mi-nota {
    display: block;
    margin: 0;
    font-size: 11px;
    color: rgb(var(--ink-subtle-rgb));
}

/* ── El detalle del contrato, al pulsar los minutos ──

   Sube en vez de bajar: el bloque está pegado al borde inferior de la ventana
   y hacia abajo no hay sitio. Y se alinea a la izquierda porque la barra
   lateral mide 260 px: con `right: 0` el panel se saldría por el otro lado.

   `es-panel` es lo que deja fuera el estilo de "opción de menú" que reciben
   los hijos de un desplegable normal. Aquí los hijos no son opciones —no se
   pulsan— y con ese estilo se iluminaban al pasar el ratón como si llevaran a
   alguna parte. Ver la regla acotada más arriba. */
.mi-panel {
    top: auto;
    bottom: calc(100% + 8px);
    left: 0;
    right: auto;
    width: 236px;
    min-width: 0;
    padding: 12px;
    gap: 8px;
}

.mi-panel-titulo {
    margin: 0;
    font-family: var(--font-display);
    font-size: 13.5px;
    font-weight: 600;
    color: rgb(var(--ink-rgb));
}

/* ── Las horas del contrato ──
   El mismo bloque en dos sitios: esta tarjeta del Inicio del líder y el panel
   del pie de la barra lateral. Ver el macro `horas_del_contrato`. */
.hc-horas { display: grid; gap: 8px; }

.hc-disponibles {
    margin: 0;
    font-size: 13px;
    color: rgb(var(--ink-muted-rgb));
}

.hc-pie {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 10px;
}

.hc-consumidas {
    font-size: 12px;
    color: rgb(var(--ink-muted-rgb));
}

.hc-porcentaje {
    font-family: var(--font-mono);
    font-size: 13px;
    font-weight: 600;
    color: rgb(var(--ink-rgb));
}

/* Quedando poco, el número deja de informar y pasa a avisar. */
.minutos.es-poco { border-color: rgb(var(--warning-rgb) / 0.45); }
.minutos.es-poco .mi-cifra { color: rgb(var(--warning-text-rgb)); }
.minutos.es-poco .mi-relleno { background: rgb(var(--warning-rgb)); }
.minutos.es-poco .mi-nota { color: rgb(var(--warning-text-rgb)); }

/* ══════════════════════════════════════════════════════════════════════
   El reporte de una sesión (capturas reporte-01 a reporte-05).

   El puntaje estaba arriba a la derecha, pegado al botón de exportar, y lo
   que había pasado en la conversación aparecía varios bloques más abajo. Se
   juntan: si aprobaste, cuánto sacaste, cuánto te moviste y qué pasó, en una
   sola tarjeta y lo primero.
   ══════════════════════════════════════════════════════════════════════ */

.resultado .fila-chips { margin-bottom: 22px; }

.re-cuerpo {
    display: grid;
    grid-template-columns: 300px minmax(0, 1fr);
    gap: 34px;
    align-items: start;
}

@media (max-width: 860px) {
    .re-cuerpo { grid-template-columns: minmax(0, 1fr); gap: 22px; }
}

.re-aclara {
    margin: 12px 0 0;
    font-size: 12px;
    line-height: 1.5;
    color: rgb(var(--ink-subtle-rgb));
}

.re-relato p {
    margin: 0;
    font-size: 15px;
    line-height: 1.65;
    color: rgb(var(--ink-rgb));
    text-wrap: pretty;
}

.re-sin-relato { color: rgb(var(--ink-subtle-rgb)) !important; }

.re-objetivo {
    margin-top: 16px !important;
    padding-top: 14px;
    border-top: var(--border-width) solid rgb(var(--line-rgb));
    font-size: 13.5px !important;
    color: rgb(var(--ink-muted-rgb)) !important;
}
.re-objetivo .es-antetitulo { margin-bottom: 4px; }

/* Qué toca después. Estaba al final del todo, detrás de siete bloques. */
.re-siguiente {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 20px;
    flex-wrap: wrap;
    margin-top: 24px;
    padding-top: 20px;
    border-top: var(--border-width) solid rgb(var(--line-rgb));
}

.re-siguiente-titulo {
    margin: 4px 0 0;
    font-size: 15px;
    font-weight: 600;
    color: rgb(var(--ink-rgb));
}

.re-siguiente-nota {
    margin: 4px 0 0;
    font-size: 13.5px;
    line-height: 1.55;
    max-width: 68ch;
    color: rgb(var(--ink-muted-rgb));
}

/* ── Por criterio ── */

.criterios {
    display: grid;
    grid-template-columns: 300px minmax(0, 1fr);
    gap: 30px;
    align-items: start;
    margin-top: 18px;
}

@media (max-width: 860px) {
    .criterios { grid-template-columns: minmax(0, 1fr); }
}

.cr-lista { display: grid; }

.criterio {
    padding: 16px 0;
    border-top: var(--border-width) solid rgb(var(--line-rgb));
}
.cr-lista > .criterio:first-child { border-top: 0; padding-top: 0; }

.cr-fila {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 14px;
}

.cr-nombre {
    font-size: 14.5px;
    font-weight: 600;
    color: rgb(var(--ink-rgb));
}

.cr-peso {
    font-size: 12px;
    font-weight: 400;
    color: rgb(var(--ink-subtle-rgb));
}

.cr-cifra {
    font-family: var(--font-display);
    font-size: 17px;
    font-weight: 600;
    flex-shrink: 0;
}

.cr-barra {
    display: block;
    height: 3px;
    margin: 8px 0 0;
    border-radius: 999px;
    background: rgb(var(--line-rgb));
    overflow: hidden;
}

.cr-relleno { display: block; height: 100%; border-radius: 999px; }

.cr-texto {
    margin: 10px 0 0;
    font-size: 13.5px;
    line-height: 1.6;
    color: rgb(var(--ink-muted-rgb));
    text-wrap: pretty;
}
.cr-texto.es-apagado { color: rgb(var(--ink-subtle-rgb)); }

/* ── Los hallazgos ── */

.ha-detalle {
    margin: 4px 0 0;
    font-size: 13px;
    line-height: 1.55;
    color: rgb(var(--ink-muted-rgb));
}

/* El número de cada área de mejora. No es gravedad —eso no lo sabemos— sino
   orden: sirve para hablar de "la 03" sin repetir la frase entera. */
.mj-orden {
    font-family: var(--font-mono);
    font-size: 11.5px;
    font-weight: 600;
    color: rgb(var(--ink-subtle-rgb));
    margin-right: 8px;
}

.mj-detalle {
    margin: 6px 0 0;
    font-size: 13px;
    line-height: 1.55;
    color: rgb(var(--ink-muted-rgb));
}

.mj-consejo .es-antetitulo { margin-bottom: 3px; }

.es-nota {
    margin: 8px 0 0;
    font-size: 13.5px;
    line-height: 1.55;
    max-width: 72ch;
    color: rgb(var(--ink-muted-rgb));
}

/* ── El análisis detallado ── */

.analisis-texto {
    margin-top: 16px;
    font-size: 14px;
    line-height: 1.7;
    color: rgb(var(--ink-rgb));
    white-space: pre-wrap;
    text-wrap: pretty;
}

/* ── Temas a repasar ── */

.lista-temas { display: grid; gap: 10px; margin-top: 16px; }

.tema {
    display: flex;
    align-items: center;
    gap: 13px;
    padding: 13px 15px;
    border: var(--border-width) solid rgb(var(--line-rgb));
    border-radius: var(--radius-md);
    transition: border-color .15s ease;
}
a.tema:hover { border-color: rgb(var(--brand-rgb) / 0.45); }

.te-icono { flex-shrink: 0; color: rgb(var(--ink-subtle-rgb)); }
.te-cuerpo { flex: 1; min-width: 0; }

.te-titulo {
    margin: 0;
    font-size: 14px;
    font-weight: 600;
    color: rgb(var(--ink-rgb));
}

.te-fuente {
    margin: 2px 0 0;
    font-size: 12.5px;
    color: rgb(var(--ink-muted-rgb));
}

.tema .te-ir {
    flex-shrink: 0;
    color: rgb(var(--ink-subtle-rgb));
}
a.tema:hover .te-ir { color: rgb(var(--brand-text-rgb)); }

/* Un tema sin documento no promete un enlace que no existe. */
.tema.es-sin-documento { background: rgb(var(--surface-2-rgb)); }

/* ── La transcripción ── */

.tr-cabecera {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 16px;
    cursor: pointer;
    list-style: none;
}
.tr-cabecera::-webkit-details-marker { display: none; }

.tr-flecha {
    color: rgb(var(--ink-subtle-rgb));
    transition: transform .15s ease;
}
details[open] .tr-flecha { transform: rotate(180deg); }

.transcripcion {
    margin-top: 18px;
    padding-top: 16px;
    border-top: var(--border-width) solid rgb(var(--line-rgb));
    max-height: 480px;
    overflow-y: auto;
    display: grid;
    gap: 12px;
}

.tr-turno {
    margin: 0;
    font-size: 13.5px;
    line-height: 1.6;
    color: rgb(var(--ink-rgb));
    white-space: pre-wrap;
}

/* Una práctica que terminó sin material para evaluarla. El "—" gigante donde
   va la nota se leía como un fallo; aquí se dice qué pasó (captura
   reporte-14). */
/* La práctica previa completada no es un aviso (requisito 386): su marca
   va en el tono de lo hecho, no en el ámbar de «sin evaluar». */
.re-sin-evaluar.es-previa .rs-icono {
    background: rgb(var(--success-tint-rgb));
    color: rgb(var(--success-text-rgb));
}

.re-sin-evaluar {
    display: flex;
    align-items: flex-start;
    gap: 14px;
}

.rs-icono {
    flex-shrink: 0;
    display: grid;
    place-items: center;
    width: 38px;
    height: 38px;
    border-radius: var(--radius-md);
    background: rgb(var(--warning-tint-rgb));
    color: rgb(var(--warning-text-rgb));
}

.rs-titulo {
    margin: 0;
    font-family: var(--font-display);
    font-size: 22px;
    font-weight: 600;
    letter-spacing: -0.01em;
    color: rgb(var(--ink-rgb));
}

.rs-texto {
    margin: 8px 0 0;
    font-size: 14.5px;
    line-height: 1.6;
    max-width: 72ch;
    color: rgb(var(--ink-muted-rgb));
}

/* ══════════════════════════════════════════════════════════════════════
   El reporte de una sesión por niveles (requisito 372).

   Sin puntaje sobre 100: el nivel de la sesión con su nombre y una escala de
   cuatro pasos, y la tabla de ocasiones con su cita y su razón. Las marcas
   («tras sondeo», «duda», «no observada por tiempo») son chips.
   ══════════════════════════════════════════════════════════════════════ */

.rn-nivel {
    display: flex;
    align-items: baseline;
    gap: 12px;
    margin-top: 6px;
}

.rn-cifra {
    font-family: var(--font-display);
    font-size: 56px;
    font-weight: 600;
    line-height: 1;
    letter-spacing: -0.02em;
    color: rgb(var(--ink-rgb));
}

.rn-nombre {
    font-family: var(--font-display);
    font-size: 20px;
    font-weight: 600;
    color: rgb(var(--ink-muted-rgb));
}

.rn-escala {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 4px;
    margin-top: 14px;
}

.rn-paso {
    height: 6px;
    border-radius: 999px;
    background: rgb(var(--line-rgb));
}

.rn-paso.es-lleno { background: rgb(var(--brand-rgb)); }

.rn-motivos {
    margin: 10px 0 0;
    padding-left: 18px;
    font-size: 13.5px;
    line-height: 1.6;
    color: rgb(var(--ink-muted-rgb));
    list-style: disc;
}

.rn-ocasiones td { vertical-align: top; }

.rn-gancho {
    font-family: var(--font-mono);
    font-size: 12.5px;
    color: rgb(var(--ink-muted-rgb));
    white-space: nowrap;
}

.rn-celda-nivel { white-space: nowrap; }

.rn-nivel-ocasion {
    font-weight: 600;
    color: rgb(var(--ink-rgb));
}

.rn-marcas {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
    margin-top: 4px;
}

.rn-cita {
    margin: 0;
    font-size: 14px;
    line-height: 1.55;
    color: rgb(var(--ink-rgb));
}

.rn-razon {
    margin: 4px 0 0;
    font-size: 13px;
    line-height: 1.55;
    color: rgb(var(--ink-muted-rgb));
}

/* La revisión del líder (requisitos 391 y 392): al lado del nivel de la
   corrección y menos destacada. Sin cifra grande ni color de veredicto: el
   resultado es el de la corrección. */
.rn-revision {
    display: grid;
    gap: 14px;
    margin-top: 18px;
    padding: 14px 16px;
    border-radius: var(--radius-md);
    border: var(--border-width) dashed rgb(var(--line-rgb));
    background: rgb(var(--surface-2-rgb));
}
.rn-revision-nivel {
    margin: 4px 0 0;
    font-size: 15px;
    font-weight: 600;
    color: rgb(var(--ink-muted-rgb));
}
.rn-revision-quien { font-weight: 400; color: rgb(var(--ink-subtle-rgb)); }
.rn-revision-comentario {
    margin: 6px 0 0;
    font-size: 13.5px;
    line-height: 1.55;
    color: rgb(var(--ink-muted-rgb));
    white-space: pre-line;
}
.rn-revision-nota {
    margin: 6px 0 0;
    font-size: 12px;
    color: rgb(var(--ink-subtle-rgb));
}
.rn-revision-form { display: grid; gap: 12px; justify-items: start; }
.rn-revision-niveles {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 6px;
    width: 100%;
    margin: 0;
    padding: 0;
    border: 0;
}
.rn-revision-niveles legend { grid-column: 1 / -1; margin-bottom: 6px; padding: 0; }
.rn-revision-campo { display: grid; gap: 6px; width: 100%; }
@media (min-width: 721px) {
    .rn-revision-niveles { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

/* El análisis de cámara (requisito 393): lo que se vio, en texto. No es un
   resultado y no lleva cifra ni color de veredicto. */
.camara-texto p {
    margin: 0 0 8px;
    font-size: 14px;
    line-height: 1.6;
    color: rgb(var(--ink-rgb));
    max-width: 78ch;
}
.camara-texto p:last-child { margin-bottom: 0; }
.camara-nota {
    margin: 4px 0 0;
    font-size: 12.5px;
    color: rgb(var(--ink-subtle-rgb));
}
.camara-lista { display: grid; gap: 10px; margin-top: 12px; }
.camara-item {
    padding: 12px 14px;
    border-radius: var(--radius-md);
    border: var(--border-width) solid rgb(var(--line-rgb));
    background: rgb(var(--surface-2-rgb));
}
.camara-item .camara-texto p { font-size: 13.5px; }
/* Los niveles de cada sesión de una asignación por niveles, en lugar del
   promedio sobre 100 (tarea 4.17). */
.nps-lista { display: grid; gap: 6px; margin: 8px 0 0; padding: 0; list-style: none; }
.nps-fila {
    display: flex;
    justify-content: space-between;
    gap: 10px;
    font-size: 13.5px;
}
.nps-sesion { color: rgb(var(--ink-muted-rgb)); }
.nps-valor { font-weight: 600; color: rgb(var(--ink-rgb)); }
.nps-valor.es-apagado { font-weight: 400; color: rgb(var(--ink-subtle-rgb)); }
.mi-persona { min-width: 200px; }
.nps-compacto { display: flex; gap: 10px; align-items: baseline; }
.nps-par { display: inline-flex; gap: 3px; align-items: baseline; }
.nps-par small { font-family: var(--font-mono); font-size: 10.5px; color: rgb(var(--ink-subtle-rgb)); }
.nps-par b { font-size: 16px; color: rgb(var(--ink-rgb)); }

/* El informe individual (requisito 394): conductas en lista, sin cifra
   global. Se imprime con el mismo `impresion.css` que el reporte. */
.in-texto {
    margin: 8px 0 0;
    font-size: 14.5px;
    line-height: 1.6;
    max-width: 78ch;
    color: rgb(var(--ink-muted-rgb));
}
.in-pila { display: grid; gap: 10px; margin-top: 14px; }
.in-conducta {
    padding: 12px 14px;
    border-radius: var(--radius-md);
    border: var(--border-width) solid rgb(var(--line-rgb));
    background: rgb(var(--surface-2-rgb));
    break-inside: avoid;
}
.in-nombre {
    margin: 0;
    font-size: 15px;
    font-weight: 600;
    color: rgb(var(--ink-rgb));
}
.in-codigo {
    font-family: var(--font-mono);
    font-size: 12px;
    font-weight: 600;
    color: rgb(var(--brand-text-rgb));
    margin-right: 4px;
}
.in-descriptor, .in-siguiente {
    margin: 6px 0 0;
    font-size: 13.5px;
    line-height: 1.55;
    color: rgb(var(--ink-muted-rgb));
}
.in-siguiente .es-antetitulo { display: block; margin-bottom: 2px; }
.in-cita {
    margin: 8px 0 0;
    font-size: 14px;
    line-height: 1.55;
    color: rgb(var(--ink-rgb));
}
.in-evolucion {
    margin: 10px 0 0;
    padding-left: 18px;
    list-style: disc;
    display: grid;
    gap: 6px;
    font-size: 14px;
    line-height: 1.55;
    color: rgb(var(--ink-muted-rgb));
}
.in-evolucion b { color: rgb(var(--ink-rgb)); font-family: var(--font-mono); font-size: 12.5px; }

.camara-de {
    margin: 0 0 6px;
    font-family: var(--font-mono);
    font-size: 11px;
    letter-spacing: 0.04em;
    color: rgb(var(--ink-subtle-rgb));
}

/* La nota del reporte compartido (captura reporte-09). Quien lo abre no sabe
   si está viendo el reporte entero o un recorte. */
.nota-compartida {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 14px 16px;
    border: var(--border-width) dashed rgb(var(--line-rgb));
    border-radius: var(--radius-md);
    font-size: 12.5px;
    color: rgb(var(--ink-subtle-rgb));
}
.nota-compartida svg { flex-shrink: 0; }

/* ── El avatar de iniciales de la tabla de avance ───────────────────────────
   Se llamaba `tp-` por "Top performers", la tarjeta para la que nació y que ya
   no existe: su promedio es hoy una columna de la tabla de avance. El nombre
   de la clase se queda como está para no tocar la plantilla por un rótulo;
   el resto de las reglas `tp-` se fueron con la tarjeta. */
.tp-avatar {
    width: 32px;
    height: 32px;
    border-radius: 999px;
    display: grid;
    place-items: center;
    flex-shrink: 0;
    font-family: var(--font-mono);
    font-size: 11px;
    font-weight: 600;
    background: rgb(var(--brand-tint-rgb));
    color: rgb(var(--brand-text-rgb));
}

/* La métrica que además lleva a su sección (requisito 3). Es un enlace, así
   que hay que apagarle el subrayado y el color heredados. */
a.metrica { display: block; text-decoration: none; color: inherit; }
a.metrica:hover { border-color: rgb(var(--brand-rgb)); }


/* ══ Móvil ═══════════════════════════════════════════════════════════════ */

@media (max-width: 720px) {
    /* Una tabla de seis columnas metida en 390 px no se estrecha: parte cada
       celda en tantas líneas como haga falta y "Equipo de Ventas" acaba
       escrito en tres. Con un ancho mínimo las columnas conservan su forma y
       es la tabla la que se desplaza dentro de su marco, que ya tiene
       `overflow-x: auto`. */
    .table-shell .table-soft { min-width: 620px; }

    /* Las cifras del encabezado de una sección van en fila y no caben tres:
       la tercera empujaba la página. */
    .enc-seccion { flex-wrap: wrap; }

    /* Cada práctica del programa es una fila de tres piezas: la marca, el
       texto y los botones. Los botones no se encogen, y una práctica
       terminada con intentos de mejora trae tres —"Ver reporte", "Repetir" y
       "Dar por terminada"— más el puntaje. En 390 px eso dejaba al texto una
       columna de cuatro caracteres: el resumen de la práctica salía escrito
       con una palabra por línea.

       Los botones bajan a su propia línea, alineados con el texto, y se
       reparten entre ellas si tampoco caben. El puntaje se queda arriba, con
       el nombre de la práctica, que es donde se lee. */
    .fila-sesion { flex-wrap: wrap; }
    .fs-derecha {
        /* `flex-basis: 100%` con el margen de sangría suma más de la fila y se
           salía cinco píxeles: la base es lo que queda descontando la marca. */
        flex-basis: calc(100% - 40px);
        justify-content: flex-start;
        margin-left: 40px;
    }
    .fs-derecha .fs-puntaje {
        /* Se saca del grupo de botones y se sube junto al título. */
        position: absolute;
        right: 0;
        top: 0;
    }
    .fila-sesion { position: relative; }
    .fs-cuerpo { padding-right: 44px; }
}

/* ── Una opción de Ajustes ─────────────────────────────────────────────────
   Nombre y explicación a la izquierda, el control a la derecha. En un teléfono
   el control baja a su propia línea: con tres tarjetas y controles de ancho
   fijo, la explicación se quedaba con menos de la mitad del ancho. */
.aj-fila {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 24px;
}
.aj-fila > *:first-child { min-width: 0; }
.aj-fila > *:last-child { flex-shrink: 0; }

@media (max-width: 520px) {
    .aj-fila {
        flex-wrap: wrap;
        gap: 14px;
    }
    .aj-fila > *:first-child { flex-basis: 100%; }
}

/* ── El calendario, el selector de horas y el de días ──────────────────────
   Los tres componentes con los que se rellena el paso «Disponibilidad» del
   formulario de una convocatoria. Van juntos porque comparten el dibujo: la
   misma tarjeta, el mismo aviso de paso con su número, y el mismo tratamiento
   de «esto está elegido» —relleno de marca y texto sobre marca—.

   Se escriben aquí, a mano, y no con clases de Tailwind: el build de Tailwind
   está precompilado y una clase que no esté ya dentro no pinta nada. Además
   son componentes, no una composición de utilidades: el día elegido de un
   calendario tiene cuatro estados que se combinan (hoy, inicio, término,
   dentro del tramo) y eso escrito con utilidades es ilegible.

   Por qué un calendario propio en vez de `<input type="date">`: el desplegable
   nativo lo dibuja el navegador en el idioma del sistema y **no se puede
   forzar a DD/MM/YYYY**. Un equipo en inglés enseñaba 9/26/2026 en el mismo
   formulario en el que el resto de la aplicación escribe 26/09/2026
   (requisito 234). Con el calendario propio, el formato lo decide la
   aplicación. */

/* El campo que abre un componente: la caja con las dos mitades, inicio y
   término, y la flecha en medio. Es un botón, no un input: lo que se escribe
   dentro lo elige el panel, y un campo de texto invitaría a teclear un formato
   que luego habría que adivinar. */
/* **El ancho.** `width: 100%` a secas dejaba el campo de 1130 px en un
   escritorio de 1280: una fecha de diez caracteres con un metro de nada al
   lado, y el formulario con la mitad derecha vacía. Se corta con un
   `max-width` y no con un `width` fijo, que es lo que permite que en el
   teléfono no haya ninguna excepción que mantener: el `width: 100%` sigue
   mandando y solo deja de crecer al llegar al tope.

   El tope va dentro de una media query **medido, no por gusto**: en 390 px la
   columna del formulario mide 324, así que un `max-width: 300px` a secas le
   habría quitado 24 px al campo en un teléfono donde el dueño del producto dijo
   que se veía bien. Por debajo de 461 px —el mismo corte que ya usa el resto de
   este bloque— el campo llena su columna exactamente como antes. */
.campo-rango {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    padding: 8px 12px;
    border-radius: var(--radius-md);
    border: var(--border-width) solid rgb(var(--line-rgb));
    background: rgb(var(--surface-2-rgb));
    color: rgb(var(--ink-rgb));
    text-align: left;
    cursor: pointer;
    transition: border-color 0.2s, box-shadow 0.2s;
}
.campo-rango:hover:not(:disabled) { border-color: rgb(var(--line-strong-rgb)); }
.campo-rango:disabled { opacity: 0.5; cursor: not-allowed; }
.campo-rango.es-abierto,
.campo-rango:focus-visible {
    outline: none;
    border-color: rgb(var(--brand-rgb));
    box-shadow: 0 0 0 3px rgb(var(--brand-rgb) / 0.18);
}
.campo-rango > svg { flex-shrink: 0; color: rgb(var(--brand-text-rgb)); }

.cr-mitad { flex: 1; min-width: 0; }
.cr-rotulo {
    display: block;
    font-family: var(--font-mono);
    font-size: 9.5px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.1em;
    color: rgb(var(--ink-subtle-rgb));
}
.cr-valor {
    display: block;
    font-family: var(--font-mono);
    font-size: 14px;
    color: rgb(var(--ink-rgb));
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
/* Un hueco sin rellenar se escribe con los guiones del formato, no vacío: un
   campo en blanco no dice si falta ponerlo o si no hay nada que poner. */
.cr-valor.es-vacio { color: rgb(var(--ink-subtle-rgb)); }
.cr-flecha { flex-shrink: 0; color: rgb(var(--ink-subtle-rgb)); }

/* La caja que envuelve un campo y su panel. Existe para una sola cosa: ser el
   bloque contenedor del panel superpuesto. La pone el guion
   (`calendario_y_horas.js`) sobre el mismo nodo donde se monta el componente,
   así que los tres —el calendario, la hora límite y las horas de un periodo—
   la tienen sin que ninguna plantilla tenga que acordarse. */
.campo-con-panel { position: relative; }

/* La tarjeta de cualquiera de los tres paneles.

   **Superpuesta, no en el flujo.** Hasta el 21 de septiembre de 2026 el panel
   era un hermano más del campo: abrir el calendario metía 380 px de tarjeta en
   mitad del documento y empujaba hacia abajo el resto del paso 2, los periodos
   y los dos pasos siguientes. Elegir una fecha hacía bailar la página entera, y
   el sitio donde estaba el puntero al abrir ya no era el mismo al cerrar. El
   dueño del producto lo pidió como un «pop-up» que no mueva nada.

   Se coloca anclado debajo de su campo y no centrado con un velo oscuro por
   encima de la página: el diseño aprobado
   (`docs/calendario-hora-diseño/`) dibuja el panel colgando del campo, y un
   velo a pantalla completa para elegir la hora de un periodo tapa justo el
   formulario contra el que se está decidiendo esa hora.

   El ancho deja de depender del hueco: al salir del flujo, un bloque absoluto
   se encoge hasta su contenido, así que se fija en los mismos 340 px que antes
   era el tope, y se corta a lo que mida su columna para que en un teléfono no
   asome por el borde. */
.panel-elegir {
    position: absolute;
    z-index: 30;
    top: 100%;
    left: 0;
    margin-top: 8px;
    padding: 14px;
    border-radius: var(--radius-lg);
    border: var(--border-width) solid rgb(var(--line-rgb));
    background: rgb(var(--surface-rgb));
    box-shadow: var(--shadow-md);
    width: 340px;
    max-width: 100%;
}
.panel-elegir[hidden] { display: none; }

/* Las dos correcciones de sitio, que pone el guion después de medir el hueco
   que queda en la ventana. No son estados de gusto: un panel que se sale por
   abajo obliga a desplazar la página para ver la mitad del calendario, y uno
   que se sale por la derecha desplaza la página en horizontal. */
.panel-elegir.es-arriba {
    top: auto;
    bottom: 100%;
    margin-top: 0;
    margin-bottom: 8px;
}
.panel-elegir.es-a-la-izquierda {
    left: auto;
    right: 0;
}

/* La cabecera del calendario: el mes en la tipografía de titulares y el año
   debajo en mono, como el resto de los datos secundarios del producto. */
.cal-cabecera {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 12px;
}
.cal-mes {
    margin: 0;
    font-family: var(--font-display);
    font-size: 17px;
    font-weight: 600;
    letter-spacing: -0.01em;
    color: rgb(var(--ink-rgb));
    text-transform: capitalize;
}
.cal-anio {
    display: block;
    font-family: var(--font-mono);
    font-size: 10.5px;
    letter-spacing: 0.08em;
    color: rgb(var(--ink-subtle-rgb));
}
.cal-pasos { display: flex; gap: 6px; flex-shrink: 0; }
.cal-paso {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    border-radius: var(--radius-sm);
    border: var(--border-width) solid rgb(var(--line-rgb));
    background: rgb(var(--surface-rgb));
    color: rgb(var(--ink-muted-rgb));
    cursor: pointer;
    transition: background 120ms ease, border-color 120ms ease;
}
.cal-paso:hover:not(:disabled) {
    background: rgb(var(--surface-2-rgb));
    border-color: rgb(var(--line-strong-rgb));
}
.cal-paso:disabled { opacity: 0.4; cursor: not-allowed; }

/* El aviso del paso. Es la pieza que convierte un calendario en un rango: sin
   él, el segundo clic no se sabe si cambia el inicio o pone el término. */
.aviso-paso {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 6px 10px;
    margin-bottom: 10px;
    border-radius: var(--radius-sm);
    background: rgb(var(--brand-tint-rgb));
    color: rgb(var(--brand-text-rgb));
    font-size: 12.5px;
    font-weight: 550;
}
/* Sin número, el aviso es una sola frase: no hace falta el hueco del
   contador. */
.aviso-paso.es-sin-numero { display: block; }
.ap-numero {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 17px;
    height: 17px;
    flex-shrink: 0;
    border-radius: 4px;
    background: rgb(var(--brand-rgb));
    color: rgb(var(--brand-on-rgb));
    font-family: var(--font-mono);
    font-size: 10.5px;
    font-weight: 700;
}

.cal-rejilla {
    display: grid;
    grid-template-columns: repeat(7, 1fr);
    gap: 2px;
}
.cal-inicial {
    text-align: center;
    padding: 4px 0;
    font-family: var(--font-mono);
    font-size: 10px;
    font-weight: 600;
    letter-spacing: 0.06em;
    color: rgb(var(--ink-subtle-rgb));
}
.cal-dia {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 30px;
    border: 1px solid transparent;
    border-radius: var(--radius-sm);
    background: transparent;
    color: rgb(var(--ink-rgb));
    font-family: var(--font-mono);
    font-size: 12.5px;
    cursor: pointer;
    transition: background 120ms ease, color 120ms ease;
}
.cal-dia:hover:not(:disabled):not(.es-extremo) {
    background: rgb(var(--surface-2-rgb));
}
.cal-dia:disabled { cursor: not-allowed; }
/* Los días del mes de al lado se dibujan pero no se pulsan: están para que la
   semana no quede coja, no para elegirlos. */
.cal-dia.es-de-otro-mes { color: rgb(var(--ink-subtle-rgb)); opacity: 0.55; }
/* Un día que ya pasó se apaga más que uno del mes de al lado, y a propósito:
   el de al lado es "aquí no, en su mes sí", y este es "ya no". Se deja legible
   —no se esconde— porque el líder necesita leer el número para orientarse en la
   semana; lo que se le quita es cualquier señal de que se pueda pulsar. */
.cal-dia.es-pasado {
    color: rgb(var(--ink-subtle-rgb));
    opacity: 0.4;
    text-decoration: line-through;
    text-decoration-thickness: 1px;
}
/* Hoy va **delineado**, no relleno: el relleno es del día elegido, y si hoy
   también se rellenara no se distinguiría cuál de los dos es cuál. */
.cal-dia.es-hoy {
    border-color: rgb(var(--brand-rgb));
    color: rgb(var(--brand-text-rgb));
    font-weight: 600;
}
.cal-dia.es-dentro {
    background: rgb(var(--brand-tint-rgb));
    color: rgb(var(--brand-text-rgb));
    border-radius: 0;
}
.cal-dia.es-extremo {
    background: rgb(var(--brand-rgb));
    color: rgb(var(--brand-on-rgb));
    border-color: rgb(var(--brand-rgb));
    font-weight: 600;
}
.cal-dia.es-inicio { border-top-right-radius: 0; border-bottom-right-radius: 0; }
.cal-dia.es-termino { border-top-left-radius: 0; border-bottom-left-radius: 0; }
.cal-dia.es-inicio.es-termino { border-radius: var(--radius-sm); }
/* La previsualización del rango: lo que se vería si se pulsara donde está el
   ratón. Es el mismo dibujo que el rango de verdad —para que se entienda de
   inmediato qué va a pasar— pero sin rellenar del todo: el tramo va con el
   mismo tinte y el extremo queda delineado en vez de macizo. Así se distingue
   de un rango ya elegido sin tener que mirar dos veces. El `:hover` normal no
   debe pisarlo, de ahí que estas reglas vayan después. */
.cal-dia.es-previa {
    background: rgb(var(--brand-tint-rgb));
    color: rgb(var(--brand-text-rgb));
    border-radius: 0;
}
.cal-dia.es-previa-fin,
.cal-dia.es-previa-fin:hover {
    background: rgb(var(--brand-tint-rgb));
    border-color: rgb(var(--brand-rgb));
    color: rgb(var(--brand-text-rgb));
    font-weight: 600;
    border-top-left-radius: 0;
    border-bottom-left-radius: 0;
}
.cal-dia:focus-visible {
    outline: 2px solid rgb(var(--brand-strong-rgb));
    outline-offset: 1px;
}

/* El pie de los tres paneles: limpiar a la izquierda y el resumen a la
   derecha. El resumen es lo que hace que el rango se pueda comprobar sin
   contar los días a ojo en la rejilla. */
.panel-pie {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin-top: 12px;
    padding-top: 10px;
    border-top: var(--border-width) solid rgb(var(--line-rgb));
    font-size: 12.5px;
}
.pp-limpiar {
    background: none;
    border: none;
    padding: 0;
    color: rgb(var(--ink-subtle-rgb));
    font-size: 12.5px;
    cursor: pointer;
}
.pp-limpiar:hover { color: rgb(var(--ink-muted-rgb)); text-decoration: underline; }
.pp-resumen {
    font-family: var(--font-mono);
    font-size: 12px;
    font-weight: 600;
    color: rgb(var(--ink-rgb));
}
.pp-resumen .pp-suave { font-weight: 400; color: rgb(var(--ink-subtle-rgb)); }
.pp-accion {
    background: none;
    border: none;
    padding: 0;
    font-size: 12.5px;
    font-weight: 550;
    color: rgb(var(--brand-text-rgb));
    cursor: pointer;
}
.pp-accion:hover { text-decoration: underline; }

/* ── El selector de horas ── */
.hora-atajos { display: flex; gap: 6px; margin-bottom: 10px; }
.hora-atajo {
    flex: 1;
    height: 28px;
    border-radius: var(--radius-sm);
    border: var(--border-width) solid rgb(var(--line-rgb));
    background: rgb(var(--surface-rgb));
    color: rgb(var(--ink-muted-rgb));
    font-size: 12px;
    font-weight: 550;
    cursor: pointer;
    transition: background 120ms ease, border-color 120ms ease, color 120ms ease;
}
.hora-atajo:hover:not(:disabled) {
    background: rgb(var(--surface-2-rgb));
    border-color: rgb(var(--line-strong-rgb));
    color: rgb(var(--ink-rgb));
}
.hora-atajo:disabled { opacity: 0.4; cursor: not-allowed; }

/* La lista se desplaza dentro del panel: son 49 bloques de media hora —el día
   entero, más las 23:59— y sacarlos todos haría un panel más alto que
   cualquier pantalla. Desde el 21 de septiembre de 2026 cubre las 24 horas: la
   rejilla de 06:00 a 22:00 no podía representar un periodo de las 05:00 que el
   servidor sí acepta. */
.hora-lista {
    max-height: 190px;
    overflow-y: auto;
    border-radius: var(--radius-sm);
}
.hora-bloque {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    padding: 5px 10px;
    border: none;
    background: transparent;
    color: rgb(var(--ink-rgb));
    font-family: var(--font-mono);
    font-size: 12.5px;
    text-align: left;
    cursor: pointer;
    transition: background 120ms ease, color 120ms ease;
}
.hora-bloque:hover:not(:disabled) { background: rgb(var(--surface-2-rgb)); }
.hora-bloque:disabled { opacity: 0.35; cursor: not-allowed; }
/* La marca de la izquierda: da a la lista el ritmo de una regla horaria y
   sirve de ancla al color cuando el bloque está dentro del tramo. */
.hb-marca {
    flex-shrink: 0;
    width: 3px;
    height: 14px;
    border-radius: 2px;
    background: rgb(var(--line-strong-rgb));
}
.hb-etiqueta {
    margin-left: auto;
    font-family: var(--font-mono);
    font-size: 9.5px;
    font-weight: 700;
    letter-spacing: 0.1em;
}
.hora-bloque.es-dentro { background: rgb(var(--brand-tint-rgb)); }
.hora-bloque.es-dentro .hb-marca { background: rgb(var(--brand-rgb)); }
.hora-bloque.es-extremo {
    background: rgb(var(--brand-strong-rgb));
    color: rgb(var(--brand-on-rgb));
    font-weight: 600;
}
.hora-bloque.es-extremo .hb-marca { background: rgb(var(--brand-on-rgb) / 0.55); }
.hora-bloque:focus-visible {
    outline: 2px solid rgb(var(--brand-strong-rgb));
    outline-offset: -2px;
}

/* La casilla para escribir una hora exacta. La rejilla de media hora no puede
   representar las 08:15 y el servidor sí la acepta; la alternativa —1440
   entradas en la lista— es inservible. Va debajo de la lista y no encima
   porque el caso normal es elegir un bloque: lo excepcional no se pone
   primero. */
.hora-exacta {
    margin-top: 8px;
    padding-top: 8px;
    border-top: var(--border-width) solid rgb(var(--line-rgb));
}
.he-arriba { display: flex; align-items: flex-end; gap: 6px; }
.he-rotulo {
    flex: 1;
    min-width: 0;
    display: block;
    font-family: var(--font-mono);
    font-size: 9.5px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.1em;
    color: rgb(var(--ink-subtle-rgb));
}
.he-caja {
    display: block;
    width: 100%;
    margin-top: 3px;
    padding: 5px 8px;
    border-radius: var(--radius-sm);
    border: var(--border-width) solid rgb(var(--line-rgb));
    background: rgb(var(--surface-2-rgb));
    color: rgb(var(--ink-rgb));
    font-family: var(--font-mono);
    font-size: 12.5px;
    letter-spacing: 0.04em;
}
.he-caja:focus-visible {
    outline: none;
    border-color: rgb(var(--brand-rgb));
    box-shadow: 0 0 0 3px rgb(var(--brand-rgb) / 0.18);
}
.he-poner {
    flex-shrink: 0;
    height: 28px;
    padding: 0 10px;
    border-radius: var(--radius-sm);
    border: var(--border-width) solid rgb(var(--line-rgb));
    background: rgb(var(--surface-rgb));
    color: rgb(var(--ink-muted-rgb));
    font-size: 12px;
    font-weight: 550;
    cursor: pointer;
    transition: background 120ms ease, border-color 120ms ease, color 120ms ease;
}
.he-poner:hover:not(:disabled) {
    background: rgb(var(--surface-2-rgb));
    border-color: rgb(var(--line-strong-rgb));
    color: rgb(var(--ink-rgb));
}
.he-queja {
    margin: 6px 0 0;
    font-size: 11.5px;
    color: rgb(var(--danger-text-rgb));
}

/* ── El selector de días de la semana ──
   Siete casillas con la inicial. El miércoles es X: el martes ya se llevó la
   M, y con dos M nadie sabe cuál pulsó. Son botones con `aria-pressed` y no
   `<input type=checkbox>` porque lo que se dibuja es el estado, no la casilla,
   y una casilla real obligaría a esconderla para poder pintarla así. */
.dias-semana { display: flex; gap: 4px; flex-wrap: wrap; }
.ds-dia {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    border-radius: var(--radius-sm);
    border: var(--border-width) solid rgb(var(--line-rgb));
    background: rgb(var(--surface-2-rgb));
    color: rgb(var(--ink-muted-rgb));
    font-family: var(--font-mono);
    font-size: 12.5px;
    font-weight: 600;
    cursor: pointer;
    transition: background 120ms ease, border-color 120ms ease, color 120ms ease;
}
.ds-dia:hover:not(:disabled) { border-color: rgb(var(--line-strong-rgb)); }
.ds-dia[aria-pressed="true"] {
    background: rgb(var(--brand-rgb));
    border-color: rgb(var(--brand-rgb));
    color: rgb(var(--brand-on-rgb));
}
.ds-dia:disabled { opacity: 0.5; cursor: not-allowed; }
.ds-dia:focus-visible {
    outline: 2px solid rgb(var(--brand-strong-rgb));
    outline-offset: 2px;
}

/* ── La fila de un periodo ──
   Las horas mandan y ocupan el ancho; las vacantes son un número de dos
   dígitos y se les da el sitio de un número de dos dígitos. Antes era un
   `input` de ancho automático dentro de una fila de `flex-wrap`, y en cuanto
   la fila se partía el campo de vacantes se llevaba una línea entera para
   enseñar un «1». */
.periodo-fila { display: flex; flex-direction: column; gap: 10px; }
.pf-arriba { display: flex; align-items: flex-end; gap: 10px; }
/* No crece: con `flex: 1` el campo de horas se comía la fila entera y dejaba
   las vacantes y «Quitar» pegadas al borde derecho, con medio metro de nada en
   medio. Con una base de 300 px —el mismo ancho al que se corta el campo— las
   tres piezas de la fila quedan juntas y se leen como una sola cosa. */
.pf-horas { flex: 0 1 300px; min-width: 0; }
.pf-vacantes { flex-shrink: 0; width: 116px; }
.pf-vacantes .input-field { padding: 8px 10px; text-align: center; }
.pf-rotulo {
    display: block;
    font-size: 12px;
    font-weight: 550;
    color: rgb(var(--ink-muted-rgb));
    margin-bottom: 4px;
}

/* ── A quién se le abre: los equipos y las personas ──────────────────────────
   Eran dos columnas de casillas sueltas con el nombre al lado, y se leían como
   un formulario de los noventa en medio de un paso que ya tenía calendario y
   selector de horas propios. Lo que se elige aquí no es una opción abstracta:
   es un equipo con gente dentro o una persona con nombre, así que cada opción
   pasa a ser una tarjeta que **dice lo que es** —cuánta gente tiene el equipo,
   las iniciales de la persona— y que se marca entera, no solo en su cuadradito
   de 13 px.

   La casilla sigue siendo un `<input type=checkbox>` de verdad, con sus clases
   `cf-equipo` y `cf-persona` y su `data-personas`: está escondida a la vista,
   no sustituida. El aviso de aforo en vivo la lee con `:checked` y el cuerpo
   del pedido con `marcados()`, y cambiarla por un botón con `aria-pressed`
   habría obligado a reescribir las dos cosas y el teclado. */
/* `minmax(0, 1fr)` por lo mismo que `.dg-lista`: que una tarjeta de equipos o
   de personas no pueda pedir más ancho que el de su columna. */
.destinos { display: grid; grid-template-columns: minmax(0, 1fr); gap: 12px; }
.destinos-grupo {
    /* Cada tarjeta mide lo que mide su lista. Estiradas a la misma altura, la
       de dos equipos dejaba doscientos píxeles de nada debajo para igualar a la
       de doce personas: el mismo hueco vacío que el dueño del producto pidió
       quitar arriba, reaparecido aquí. */
    align-self: start;
    padding: 12px;
    border-radius: var(--radius-lg);
    border: var(--border-width) solid rgb(var(--line-rgb));
    background: rgb(var(--surface-rgb));
}
.dg-cabecera {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 8px;
    margin-bottom: 8px;
}
.dg-cabecera .es-antetitulo { margin: 0; }
/* Cuántos hay elegidos de cuántos. Lo escribe el guion al marcar, porque «2 de
   9» contestado sin contar es la única forma de saber si falta alguien sin
   recorrer la lista con el dedo. */
.dg-cuenta {
    font-family: var(--font-mono);
    font-size: 10.5px;
    letter-spacing: 0.06em;
    color: rgb(var(--ink-subtle-rgb));
    white-space: nowrap;
}
/* Se desplaza dentro de su tarjeta: una organización de sesenta colaboradores
   no puede empujar el botón de publicar tres pantallas hacia abajo.

   La columna es `minmax(0, 1fr)` y no la `auto` que pone el navegador sin
   decir nada: los nombres van en una sola línea (`.od-nombre`, con puntos
   suspensivos), y una columna `auto` mide lo que mide el nombre más largo
   entero. Eso ensanchaba la lista, la tarjeta, el paso 3 y todo el formulario
   del líder hasta 426 px en un teléfono de 360 —el scroll horizontal del
   requisito 544—. Con el mínimo en cero la columna mide lo que mide la tarjeta
   y el nombre se corta con «…», que es lo que su regla ya pedía. */
.dg-lista {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 6px;
    max-height: 264px;
    overflow-y: auto;
}
.dg-vacio { font-size: 12.5px; color: rgb(var(--ink-subtle-rgb)); margin: 0; }

.opcion-destino {
    position: relative;
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 10px;
    border-radius: var(--radius-md);
    border: var(--border-width) solid rgb(var(--line-rgb));
    background: rgb(var(--surface-2-rgb));
    cursor: pointer;
    transition: border-color 120ms ease, background 120ms ease;
}
.opcion-destino:hover { border-color: rgb(var(--line-strong-rgb)); }
/* **La casilla se pinta, no se esconde.** La primera versión de esto la
   escondía (1×1 y `opacity: 0`) y dibujaba el cuadradito en un `<span>` de al
   lado. Funcionaba a la vista y rompía dos cosas que importan más: un clic
   programático sobre `.cf-equipo` —lo que escribe cualquiera que automatice la
   pantalla— se lo comía el `<span>` de encima, y el estado quedaba contado en
   dos sitios. Con `appearance: none` la casilla **es** el cuadradito: recibe el
   clic, el foco y la barra espaciadora ella misma, y no hay nada superpuesto
   que intercepte nada. */
.od-casilla {
    appearance: none;
    -webkit-appearance: none;
    position: relative;
    flex-shrink: 0;
    width: 18px;
    height: 18px;
    margin: 0;
    border-radius: 5px;
    border: 1.5px solid rgb(var(--line-strong-rgb));
    background: rgb(var(--surface-rgb));
    cursor: inherit;
    transition: background 120ms ease, border-color 120ms ease;
}
/* El palito del visto, dibujado con dos bordes: un SVG por opción serían
   sesenta SVG en una lista de sesenta personas, y un `background-image` con el
   SVG en línea no puede leer el token del color. */
.od-casilla::after {
    content: '';
    position: absolute;
    left: 4.5px;
    top: 1.5px;
    width: 5px;
    height: 9px;
    border: solid rgb(var(--brand-on-rgb));
    border-width: 0 2px 2px 0;
    transform: rotate(45deg);
    opacity: 0;
    transition: opacity 120ms ease;
}
.od-casilla:checked {
    background: rgb(var(--brand-rgb));
    border-color: rgb(var(--brand-rgb));
}
.od-casilla:checked::after { opacity: 1; }
.od-casilla:focus-visible {
    outline: 2px solid rgb(var(--brand-strong-rgb));
    outline-offset: 2px;
}
/* La tarjeta entera dice que está elegida. `:has()` no es imprescindible: si
   el navegador no lo entiende, el visto y el nombre en negrita ya lo dicen. */
.opcion-destino:has(.od-casilla:checked) {
    border-color: rgb(var(--brand-rgb));
    background: rgb(var(--brand-tint-rgb));
}
.opcion-destino:has(.od-casilla:disabled) { cursor: not-allowed; opacity: 0.6; }
.od-inicial {
    flex-shrink: 0;
    width: 28px;
    height: 28px;
    border-radius: 999px;
    display: grid;
    place-items: center;
    font-family: var(--font-mono);
    font-size: 10.5px;
    font-weight: 600;
    background: rgb(var(--surface-rgb));
    border: var(--border-width) solid rgb(var(--line-rgb));
    color: rgb(var(--ink-muted-rgb));
}
.od-cuerpo { min-width: 0; }
.od-nombre {
    display: block;
    font-size: 13px;
    color: rgb(var(--ink-rgb));
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.od-casilla:checked ~ .od-cuerpo .od-nombre { font-weight: 600; }
.od-casilla:checked ~ .od-inicial {
    border-color: rgb(var(--brand-rgb) / 0.45);
    color: rgb(var(--brand-text-rgb));
}
.od-meta {
    display: block;
    font-family: var(--font-mono);
    font-size: 10.5px;
    letter-spacing: 0.04em;
    color: rgb(var(--ink-subtle-rgb));
}

/* ── Los controles del formulario de programar, sin aspecto nativo ──
   Ningún control del formulario se deja al dibujo del navegador: el
   `<select>` de entrenamiento, el `<input type="number">` de las vacantes, la
   casilla de la segunda inscripción y los radios de cómo se publica se veían
   distintos en cada máquina y al lado de un calendario propio. */

/* Una opción de fila entera con texto debajo del nombre: la casilla de la
   segunda inscripción y las dos maneras de publicar. Es `.opcion-destino` con
   el nombre que sí puede partirse y un párrafo de explicación. */
.opcion-fila { align-items: flex-start; padding: 10px 12px; }
.opcion-fila .od-casilla { margin-top: 1px; }
.opcion-fila .od-nombre { white-space: normal; font-weight: 600; }
.od-texto {
    display: block;
    margin-top: 2px;
    font-size: 12.5px;
    line-height: 1.45;
    color: rgb(var(--ink-muted-rgb));
}
.modos-de-publicar { display: grid; grid-template-columns: 1fr; gap: 8px; }
@media (min-width: 721px) {
    .modos-de-publicar { grid-template-columns: 1fr 1fr; }
}

/* El selector de una opción (`selectorDeOpciones`): el mismo campo y el mismo
   panel que el calendario, con una lista de opciones que dicen lo que son. */
@media (min-width: 461px) {
    .campo-entrenamiento { max-width: 420px; }
}
.panel-opciones { width: 380px; }
.oe-lista {
    display: grid;
    gap: 4px;
    max-height: 280px;
    overflow-y: auto;
    margin-top: 8px;
}
.oe-opcion {
    display: block;
    width: 100%;
    text-align: left;
    padding: 8px 10px;
    border-radius: var(--radius-md);
    border: var(--border-width) solid transparent;
    background: transparent;
    color: rgb(var(--ink-rgb));
    cursor: pointer;
    transition: background 120ms ease, border-color 120ms ease;
}
.oe-opcion:hover:not(:disabled) { background: rgb(var(--surface-2-rgb)); }
/* La que se ve y no se elige (un cliente inactivo en el alta de una cuenta). */
.oe-opcion:disabled { cursor: not-allowed; opacity: 0.55; }
.oe-opcion[aria-selected="true"] {
    border-color: rgb(var(--brand-rgb));
    background: rgb(var(--brand-tint-rgb));
}
.oe-opcion:focus-visible {
    outline: 2px solid rgb(var(--brand-strong-rgb));
    outline-offset: 1px;
}
.oe-nombre { display: block; font-size: 13.5px; font-weight: 550; }
.oe-meta {
    display: block;
    font-family: var(--font-mono);
    font-size: 10.5px;
    letter-spacing: 0.04em;
    color: rgb(var(--ink-subtle-rgb));
    margin-top: 2px;
}
.oe-vacio { font-size: 12.5px; color: rgb(var(--ink-subtle-rgb)); margin: 4px 0; }

/* El contador (`contadorDeNumero`): − 3 +. Sin flechas nativas y sin bajar
   del mínimo. */
.contador {
    display: flex;
    align-items: stretch;
    border-radius: var(--radius-md);
    border: var(--border-width) solid rgb(var(--line-rgb));
    background: rgb(var(--surface-2-rgb));
    overflow: hidden;
}
.contador:focus-within {
    border-color: rgb(var(--brand-strong-rgb));
    box-shadow: 0 0 0 3px rgb(var(--brand-rgb) / 0.18);
}
.ct-boton {
    flex: 0 0 34px;
    border: 0;
    background: transparent;
    color: rgb(var(--ink-rgb));
    font-size: 16px;
    line-height: 1;
    cursor: pointer;
}
.ct-boton:hover:not(:disabled) { background: rgb(var(--surface-rgb)); }
.ct-boton:disabled { opacity: 0.35; cursor: not-allowed; }
.ct-boton:focus-visible {
    outline: 2px solid rgb(var(--brand-strong-rgb));
    outline-offset: -2px;
}
.ct-valor {
    flex: 1;
    min-width: 0;
    width: 100%;
    padding: 8px 0;
    border: 0;
    background: transparent;
    color: rgb(var(--ink-rgb));
    font-family: var(--font-mono);
    font-size: 14px;
    text-align: center;
}
.ct-valor:focus { outline: none; }
.ct-valor:disabled { opacity: 0.6; }

/* ── Elegir periodo en la Agenda (requisitos 247 y 248) ──
   La misma opción entera y clicable que los destinatarios del formulario de
   programar (`.opcion-destino`), con un radio en vez de una casilla: se elige
   **un** periodo. El radio es el de verdad, pintado con `appearance: none`,
   por lo mismo que la casilla: recibe el clic, el foco y las flechas él
   mismo. Una columna en el teléfono, dos a partir de 721 px; nada tiene ancho
   fijo, así que no hay desplazamiento horizontal. */
.periodos { border: 0; padding: 0; margin-left: 0; margin-right: 0; min-width: 0; }
.periodos > legend { padding: 0; margin-bottom: 4px; }
.periodos-lista { display: grid; grid-template-columns: 1fr; gap: 8px; }
.opcion-periodo { align-items: flex-start; }
.opcion-periodo .od-casilla { margin-top: 1px; }
.opcion-periodo .od-nombre { white-space: normal; }
.od-radio { border-radius: 999px; }
.od-radio::after {
    left: 4px;
    top: 4px;
    width: 7px;
    height: 7px;
    border: 0;
    border-radius: 999px;
    background: rgb(var(--brand-on-rgb));
    transform: none;
}
@media (min-width: 721px) {
    .periodos-lista { grid-template-columns: 1fr 1fr; }
}

/* ── Elegir un slot en la Agenda ──
   Los slots de cada día van en un desplegable propio: una semana sin
   restricciones son decenas de slots por día, y una sola lista habría que
   recorrerla con el dedo. El `<details>` pierde su triángulo del navegador
   (`list-style: none` y el `::-webkit-details-marker`) y lleva la flecha de
   la casa, que gira al abrirse. Cada slot es una opción entera con su radio
   pintado (`.od-casilla.od-radio`), igual que los periodos. */
.slots-dia {
    border: var(--border-width) solid rgb(var(--line-rgb));
    border-radius: var(--radius-md);
    background: rgb(var(--surface-rgb));
}
.slots-dia + .slots-dia { margin-top: 8px; }
.hd-cabecera {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 10px 12px;
    cursor: pointer;
    list-style: none;
    color: rgb(var(--ink-rgb));
    border-radius: var(--radius-md);
}
.hd-cabecera::-webkit-details-marker { display: none; }
.hd-cabecera::marker { content: ''; }
.hd-cabecera:hover { background: rgb(var(--surface-2-rgb)); }
.hd-cabecera:focus-visible {
    outline: 2px solid rgb(var(--brand-strong-rgb));
    outline-offset: 2px;
}
.hd-dia { font-weight: 600; font-size: 14px; }
.hd-dia::first-letter { text-transform: uppercase; }
.hd-cuenta { font-size: 12.5px; color: rgb(var(--ink-muted-rgb)); }
.hd-flecha {
    margin-left: auto;
    display: inline-flex;
    color: rgb(var(--ink-subtle-rgb));
    transition: transform .15s ease;
}
.slots-dia[open] .hd-flecha { transform: rotate(180deg); }
.slots-lista {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(128px, 1fr));
    gap: 8px;
    padding: 0 12px 12px;
}
.opcion-slot { align-items: flex-start; }
.opcion-slot .od-casilla { margin-top: 1px; }
.opcion-slot .od-nombre { white-space: normal; }

/* ── Cómo se agenda, en el formulario de programar ──
   Las dos formas —por periodos o por slots— como opciones enteras, igual que
   los modos de publicar. */
.modos-de-agenda { display: grid; grid-template-columns: 1fr; gap: 8px; }
@media (min-width: 721px) {
    .modos-de-agenda { grid-template-columns: 1fr 1fr; }
}
.slots-config {
    display: grid;
    grid-template-columns: 1fr;
    gap: 16px;
}
/* Dos columnas solo con sitio de sobra: a 768 px (tableta) la columna del
   formulario deja ~340 px por campo, y las pistas largas se partían en
   renglones de tres palabras. */
@media (min-width: 1025px) {
    .slots-config { grid-template-columns: 1fr 1fr; }
}
/* Un número de dos o cuatro cifras no necesita media pantalla: el mismo tope
   que los campos de rango. */
.slots-config .contador { max-width: 300px; }
/* La duración final de cada slot, debajo del tiempo extra. Se parte donde
   haga falta: a 320 px no cabe en un renglón. */
.cf-slot-duracion {
    margin: 8px 0 0;
    font-size: 13px;
    font-weight: 600;
    line-height: 1.45;
    color: rgb(var(--ink-rgb));
    overflow-wrap: anywhere;
}
/* En el teléfono y la tableta, los controles del bloque se pulsan con el
   dedo: al menos 44 × 44 px (los botones − y + medían 34 × 28 y los días
   32 × 32). Los días ya saltan de renglón si no caben. */
@media (max-width: 1024px) {
    .slots-config .contador button { width: 44px; height: 44px; flex-basis: 44px; }
    .slots-config .ct-valor { min-height: 44px; }
    .slots-config .ds-dia { min-width: 44px; min-height: 44px; }
    .cf-publicar-acciones .btn { min-height: 44px; }
}
/* A lo más angosto, los dos botones de publicar se reparten el renglón. */
@media (max-width: 430px) {
    .cf-publicar-acciones .btn { flex: 1 1 0; }
}

/* Configuración técnica (admin de Glow) en el teléfono: los campos al ancho
   de la tarjeta, el aviso de error partiendo palabras largas y el botón
   Guardar a lo ancho, con 44 px de alto para el dedo. */
@media (max-width: 430px) {
    .config-tecnica .input-field { max-width: none; width: 100%; min-height: 44px; }
    .config-tecnica .aviso .av-cuerpo { overflow-wrap: anywhere; min-width: 0; }
    .config-tecnica .pie-form .btn { flex: 1 1 100%; min-height: 44px; }
}

@media (min-width: 721px) {
    .destinos { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* Fuera del teléfono, el campo deja de crecer. 300 px es lo que piden los dos
   datos más largos que escribe —«26/09/2026 → 26/09/2026» y «23:59»— con sitio
   de sobra, y es el ancho al que también se corta la fila de un periodo
   (`.pf-horas`), para que el campo y su fila no se corten en dos sitios
   distintos. */
@media (min-width: 461px) {
    .campo-rango { max-width: 300px; }
}

@media (max-width: 460px) {
    /* En 390 px, el panel no puede ser más ancho que su columna o la página
       entera se desplaza en horizontal. El tope vive ahora en la regla base
       —desde que el panel es absoluto, su ancho ya no lo decide el hueco— y
       aquí solo queda lo que sí es propio del teléfono. */
    /* Siete casillas de 32 px más sus huecos suman 248: caben. Lo que no cabe
       es la fila de arriba con el campo de horas y las vacantes al lado. */
    .pf-arriba { flex-wrap: wrap; }
    .pf-horas { flex-basis: 100%; }
}

/* ═══════════════════════════════════════════════════════════════════════
   El tablero del Manager (requisitos 252 a 259 y 261).

   Sigue el Inicio del líder: la tira de cifras, tarjetas con un gráfico, y
   tablas `table-soft` dentro de `table-shell`, que se desplazan dentro de su
   marco en un teléfono en vez de empujar la página (requisito 142). Todo con
   tokens: nada cambia de color a mano entre el tema claro y el oscuro.
   ═══════════════════════════════════════════════════════════════════════ */

.tablero-notas {
    display: grid;
    gap: 4px;
    font-size: 13px;
    color: rgb(var(--ink-muted-rgb));
}

/* El alto lo fija el contenedor y no el lienzo: Chart.js con
   `maintainAspectRatio: false` ocupa lo que le dejan, y sin alto propio un
   gráfico de barras en un teléfono se queda en una franja de 60 px. */
.tablero-grafico {
    position: relative;
    height: 280px;
    min-width: 0;
}

.tablero-cifra {
    font-family: var(--font-mono);
    font-size: 26px;
    line-height: 1;
    color: rgb(var(--ink-rgb));
}
.tablero-cifra span {
    font-size: 13px;
    color: rgb(var(--ink-subtle-rgb));
}

/* El reparto del consumo por tipo: tres filas con su barra. Una barra de CSS
   y no un gráfico: son tres porcentajes, y el lienzo obligaría a repetir en
   JavaScript los colores que ya están aquí. */
.tablero-reparto {
    margin-top: 10px;
    display: grid;
    gap: 6px;
    font-size: 13px;
    color: rgb(var(--ink-muted-rgb));
}
.tablero-reparto li {
    display: grid;
    grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr) auto;
    align-items: center;
    gap: 10px;
}
.tr-barra {
    display: block;
    height: 4px;
    border-radius: 999px;
    background: rgb(var(--brand-tint-rgb));
    overflow: hidden;
}
.tr-barra span {
    display: block;
    height: 100%;
    background: rgb(var(--brand-rgb));
}
.tr-cifra {
    font-family: var(--font-mono);
    font-size: 12px;
    white-space: nowrap;
}

.tablero-tabla th.num,
.tablero-tabla td.num {
    text-align: center;
    font-family: var(--font-mono);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}
.tablero-progreso { min-width: 96px; margin-bottom: 4px; }

/* La lista de atención: quién, por qué y a dónde ir. En un teléfono los
   motivos bajan debajo del nombre en vez de apretarlo. */
.tablero-atencion { display: grid; gap: 0; }
.tablero-atencion li {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto auto;
    align-items: center;
    gap: 12px;
    padding: 10px 0;
    border-bottom: 1px solid rgb(var(--line-rgb));
}
.tablero-atencion li:last-child { border-bottom: 0; }
.ta-motivos { display: flex; flex-wrap: wrap; gap: 6px; justify-content: flex-end; }

@media (max-width: 720px) {
    .tablero-atencion li { grid-template-columns: minmax(0, 1fr) auto; }
    .tablero-atencion .ta-motivos { grid-column: 1 / -1; justify-content: flex-start; }
    .tablero-reparto li { grid-template-columns: minmax(0, 1fr) auto; }
    .tablero-reparto .tr-barra { grid-column: 1 / -1; grid-row: 2; }
}

/* Los rótulos de la tira del Manager dicen su ventana —"(30 días)"— y cortados
   con puntos suspensivos perdían justo eso. Aquí se parten en dos líneas. */
.tablero-tira .me-etiqueta { white-space: normal; overflow: visible; }

/* El nombre no se aprieta hasta partirse palabra a palabra: la tabla ya se
   desplaza dentro de su marco en un teléfono. */
.tablero-tabla td:first-child { min-width: 150px; }

/* ── El desplegable con búsqueda (macros/combo.html) ──────────────────
   Sustituye al <select> nativo: la regla de controles
   (.claude/shared/controles-con-diseno-habilidy.md) no admite el diseño del
   navegador. Todo sale de los tokens, así que vale en los dos temas. */
.combo { position: relative; display: grid; gap: 4px; min-width: 260px; max-width: 360px; }
.combo-etiqueta { font-size: 13px; color: rgb(var(--ink-muted-rgb)); }
.combo-details { position: relative; }
.combo-boton {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    padding: 10px 12px;
    border-radius: var(--radius-md);
    border: var(--border-width) solid rgb(var(--line-rgb));
    background: rgb(var(--surface-2-rgb));
    color: rgb(var(--ink-rgb));
    cursor: pointer;
    list-style: none;
    transition: border-color 0.2s, box-shadow 0.2s;
}
.combo-boton::-webkit-details-marker { display: none; }
.combo-boton::marker { content: ''; }
.combo-boton:hover { border-color: rgb(var(--line-strong-rgb)); }
.combo-boton:focus-visible,
.combo-details[open] > .combo-boton {
    outline: none;
    border-color: rgb(var(--brand-strong-rgb));
    box-shadow: 0 0 0 3px rgb(var(--brand-rgb) / 0.18);
}
.combo-valor { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.combo-flecha {
    width: 16px; height: 16px; flex-shrink: 0;
    fill: none; stroke: rgb(var(--ink-muted-rgb)); stroke-width: 2;
    stroke-linecap: round; stroke-linejoin: round;
    transition: transform 0.2s;
}
.combo-details[open] .combo-flecha { transform: rotate(180deg); }
.combo-panel {
    position: absolute;
    z-index: 40;
    top: calc(100% + 6px);
    left: 0;
    right: 0;
    display: grid;
    gap: 8px;
    padding: 10px;
    border-radius: var(--radius-lg);
    border: var(--border-width) solid rgb(var(--line-rgb));
    background: rgb(var(--surface-rgb));
    box-shadow: var(--shadow-lg);
}
.combo-busqueda { display: grid; gap: 4px; }
.combo-busqueda[hidden] { display: none; }
.combo-busqueda-etiqueta { font-size: 12px; font-weight: 600; color: rgb(var(--ink-muted-rgb)); }
/* Un campo de texto normal: sin la "x" ni el aspecto de `type=search`. */
.combo-campo { appearance: none; -webkit-appearance: none; padding: 8px 10px; font-size: 14px; }
.combo-campo::placeholder { color: rgb(var(--ink-subtle-rgb)); }
.combo-lista {
    display: grid;
    gap: 2px;
    max-height: 280px;
    overflow-y: auto;
    margin: 0;
    padding: 0;
    list-style: none;
    /* La barra de desplazamiento también es un control: con tokens. */
    scrollbar-width: thin;
    scrollbar-color: rgb(var(--line-strong-rgb)) transparent;
}
.combo-lista::-webkit-scrollbar { width: 8px; }
.combo-lista::-webkit-scrollbar-track { background: transparent; }
.combo-lista::-webkit-scrollbar-thumb { background: rgb(var(--line-strong-rgb)); border-radius: 8px; }
.combo-rotulo {
    padding: 8px 10px 4px;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: rgb(var(--ink-subtle-rgb));
}
.combo-rotulo[hidden], .combo-opcion[hidden] { display: none; }
.combo-opcion > a {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    padding: 8px 10px;
    border-radius: var(--radius-md);
    color: rgb(var(--ink-rgb));
    font-size: 14px;
}
.combo-opcion > a:hover,
.combo-opcion.es-activa > a { background: rgb(var(--surface-2-rgb)); }
.combo-opcion > a:focus-visible { outline: 2px solid rgb(var(--brand-strong-rgb)); outline-offset: -2px; }
.combo-opcion.es-activa > a { box-shadow: inset 3px 0 0 rgb(var(--brand-strong-rgb)); }
.combo-opcion[aria-selected="true"] > a { color: rgb(var(--brand-text-rgb)); font-weight: 600; }
.combo-opcion[aria-selected="true"] > a::after { content: '✓'; }
.combo-vacio { padding: 6px 10px; font-size: 13px; color: rgb(var(--ink-muted-rgb)); }
.combo-vacio[hidden] { display: none; }

/* ── El calendario de Mis convocatorias, la sección del colaborador (requisito 295) ──
   De consulta: el rango en que se puede practicar, los días con periodos o slots y
   los del periodo o slot propio. Tres marcas que se distinguen también sin color
   —fondo, punto y borde—, para que el tema oscuro y quien no distingue el
   turquesa lean lo mismo. Solo tokens. */
.agenda-calendario { display: grid; gap: 16px; }
.ac-cabecera {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 12px;
    flex-wrap: wrap;
}
.ac-compacto { max-width: 420px; }
.ac-mes-cabecera {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 8px;
}
.ac-mes-titulo { font-weight: 600; text-transform: capitalize; color: rgb(var(--ink-rgb)); }
.ac-rejilla {
    display: grid;
    grid-template-columns: repeat(7, minmax(0, 1fr));
    gap: 4px;
}
.ac-inicial {
    text-decoration: none;
    cursor: default;
    text-align: center;
    font-size: 12px;
    color: rgb(var(--ink-subtle-rgb));
    padding: 2px 0;
}
.ac-dia {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    aspect-ratio: 1 / 1;
    min-width: 0;
    border-radius: var(--radius-sm);
    border: 1px solid transparent;
    font-size: 13px;
    color: rgb(var(--ink-muted-rgb));
    background: transparent;
}
.ac-dia.es-vacia { visibility: hidden; }
button.ac-dia { cursor: pointer; font: inherit; }
button.ac-dia:hover { background: rgb(var(--surface-2-rgb)); }
button.ac-dia:focus-visible {
    outline: 2px solid rgb(var(--brand-rgb));
    outline-offset: 2px;
}
.ac-dia.es-en-rango {
    background: rgb(var(--brand-tint-rgb));
    color: rgb(var(--ink-rgb));
}
.ac-dia.es-con-horario::after {
    content: '';
    position: absolute;
    bottom: 4px;
    width: 5px;
    height: 5px;
    border-radius: 999px;
    background: rgb(var(--brand-text-rgb));
}
.ac-dia.es-mio {
    border-color: rgb(var(--brand-strong-rgb));
    font-weight: 600;
}
.ac-dia.es-hoy { box-shadow: inset 0 0 0 2px rgb(var(--ink-subtle-rgb)); }
.ac-dia.es-elegido {
    background: rgb(var(--brand-strong-rgb));
    color: rgb(var(--brand-on-rgb));
}
.ac-mes.es-grande .ac-dia { font-size: 15px; }
.ac-leyenda {
    display: flex;
    flex-wrap: wrap;
    gap: 8px 16px;
    font-size: 13px;
    color: rgb(var(--ink-muted-rgb));
}
.ac-leyenda li { display: inline-flex; align-items: center; gap: 6px; }
.ac-muestra {
    position: relative;
    display: inline-block;
    width: 16px;
    height: 16px;
    border-radius: 4px;
    border: 1px solid rgb(var(--line-rgb));
}
.ac-muestra.es-en-rango { background: rgb(var(--brand-tint-rgb)); }
.ac-muestra.es-con-horario::after {
    content: '';
    position: absolute;
    left: 5px;
    top: 5px;
    width: 5px;
    height: 5px;
    border-radius: 999px;
    background: rgb(var(--brand-text-rgb));
}
.ac-muestra.es-mio { border: 2px solid rgb(var(--brand-strong-rgb)); }

body.con-emergente { overflow: hidden; }
.ec-cabecera {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 16px;
}

/* El pop-up grande: el mes a un lado y el detalle del día al otro; en un
   teléfono, uno debajo del otro. */
.emergente-calendario { max-width: 960px; padding: 20px; }
.ec-cuerpo {
    display: grid;
    grid-template-columns: minmax(0, 1.3fr) minmax(0, 1fr);
    gap: 24px;
}
.ec-dia { font-weight: 600; margin-bottom: 8px; color: rgb(var(--ink-rgb)); }
.ec-dia::first-letter { text-transform: uppercase; }
.ec-lista { display: grid; gap: 12px; }
.ec-item {
    padding: 12px;
    border: 1px solid rgb(var(--line-rgb));
    border-radius: var(--radius-md);
    background: rgb(var(--surface-2-rgb));
}
.ec-periodos { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
.ec-periodo {
    font-size: 13px;
    padding: 2px 8px;
    border-radius: 999px;
    border: 1px solid rgb(var(--line-rgb));
    background: rgb(var(--surface-rgb));
    color: rgb(var(--ink-rgb));
}
.ec-periodo.es-mio {
    border-color: rgb(var(--brand-strong-rgb));
    color: rgb(var(--brand-text-rgb));
    font-weight: 600;
}
/* «Reservar slot» (detalle del entrenamiento): el mismo pop-up del calendario,
   con las horas libres del día elegido a la derecha. Un día sin slots libres
   se ve apagado y no se elige. */
button.ac-dia:disabled { cursor: not-allowed; opacity: 0.45; }
button.ac-dia:disabled:hover { background: transparent; }
.rs-horas .slots-lista { padding: 0; margin-top: 8px; }
.rs-nota { font-size: 13px; color: rgb(var(--ink-muted-rgb)); margin-top: 8px; }
.rs-pie { display: flex; justify-content: flex-end; gap: 8px; margin-top: 16px; }
.lado-cabecera {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
}
@media (max-width: 720px) {
    .ec-cuerpo { grid-template-columns: minmax(0, 1fr); }
    .emergente-calendario { padding: 16px; }
    .ac-compacto { max-width: none; }
}

/* Las horas que ya pasaron, en el selector de horas (requisito 293): igual que
   los días pasados del calendario, apagadas y sin elegir. */
.hora-bloque.es-pasado { opacity: 0.45; cursor: not-allowed; }

/* «Ver más» de Mis convocatorias (requisito 332): la flecha mira hacia abajo plegado y
   hacia arriba desplegado, igual que los días de slots. */
.ver-mas .vm-flecha { display: inline-flex; transition: transform .15s ease; }
.ver-mas[aria-expanded="true"] .vm-flecha { transform: rotate(180deg); }

/* ── Los controles nativos que se quedan debajo de uno con diseño ──
   `controles_con_diseno.js` monta el selector o el calendario de la casa
   encima de un `<select>` o un `<input type="date">` y deja el nativo en su
   sitio, que es lo que se envía. No se le pone `display: none`: un `required`
   escondido así no puede enseñar su aviso y el navegador bloquea el envío sin
   decir por qué. Se queda en la página, de un píxel y transparente. */
.control-nativo-oculto {
    position: absolute !important;
    width: 1px !important;
    height: 1px !important;
    padding: 0 !important;
    margin: 0 !important;
    border: 0 !important;
    opacity: 0;
    pointer-events: none;
}
.campo-rango.es-mal { border-color: rgb(var(--danger-rgb)); }

/* ── Las pantallas del Admin de Glow ── */

/* Dos campos por fila en un formulario ancho, uno en un teléfono. */
.rejilla-campos {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 16px;
}
@media (min-width: 721px) {
    .rejilla-campos { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .rejilla-campos > .es-ancho { grid-column: 1 / -1; }
}

/* El pie de un formulario: cancelar y guardar, a la derecha. */
.pie-form {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    gap: 10px;
}

/* Las acciones de una fila de tabla: botones pequeños en fila que se
   reparten en dos líneas antes que ensanchar la tabla. */
.acciones-fila {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    gap: 6px;
}
.acciones-fila form { display: contents; }
.btn-peligro-suave { color: rgb(var(--danger-text-rgb)); }
.btn-peligro-suave:hover { border-color: rgb(var(--danger-rgb) / 0.45); }

/* El aviso informativo. Hermano de `.aviso-warn` y `.aviso-bad`: no es un
   problema, es algo que falta por hacer. */
.aviso-info {
    background: rgb(var(--info-tint-rgb));
    border-color: rgb(var(--info-rgb) / 0.45);
}
.aviso-info .av-icono { color: rgb(var(--info-rgb)); }
.av-cuerpo .av-detalle:last-child { margin-bottom: 0; }

/* Una cifra con signo en una tabla: lo que entra en verde, lo que sale en
   rojo, y el cero apagado. */
.cifra-mas { color: rgb(var(--success-text-rgb)); }
.cifra-menos { color: rgb(var(--danger-text-rgb)); }

/* Agregar una traducción de rol: los dos campos y el botón en una fila, con
   el botón al pie de los campos; en un teléfono, uno debajo de otro. */
.rejilla-roles {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 12px;
    align-items: end;
}
@media (min-width: 721px) {
    .rejilla-roles { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) auto; }
}

/* El selector de cliente de la barra de Cuentas: ancho propio, no el de la
   fila entera. */
.barra-lista .control-con-diseno { min-width: 220px; }
@media (max-width: 720px) {
    .barra-lista .control-con-diseno { flex: 1 1 100%; min-width: 0; }
}

/* El selector que sustituye a un `<select>` de formulario: ocupa su columna
   como cualquier otro campo —el tope de 300 px es del calendario—, escribe en
   la letra del texto y no en la de las cifras, y lleva la flecha a la derecha
   en vez del icono de lista, que es lo que se espera de un desplegable. */
.control-con-diseno.es-select .campo-rango {
    max-width: none;
    min-height: 44px;
}
.control-con-diseno.es-select .campo-rango > svg { display: none; }
.control-con-diseno.es-select .campo-rango::after {
    content: '';
    flex-shrink: 0;
    width: 8px;
    height: 8px;
    margin: -4px 4px 0 0;
    border: solid rgb(var(--ink-subtle-rgb));
    border-width: 0 1.5px 1.5px 0;
    transform: rotate(45deg);
    transition: transform 120ms ease;
}
.control-con-diseno.es-select .campo-rango.es-abierto::after { transform: rotate(-135deg); margin-top: 4px; }
.control-con-diseno.es-select .cr-valor { font-family: var(--font-body); font-size: 15px; }
.control-con-diseno.con-etiqueta .cr-rotulo { display: none; }

/* ── El documento de una política (requisitos 441 y 450) ──
   El texto de la política de privacidad y la de manejo de datos, tal como
   llega del Markdown, del Word o del PDF convertido (ya saneado: solo
   títulos, párrafos, listas, énfasis, tablas, citas, código y enlaces). La
   página de la persona y la vista previa del administrador lo pintan igual,
   para que lo que se revisa sea lo que se publica. */
.documento-politica {
    color: rgb(var(--ink-rgb));
    font-size: 15px;
    line-height: 1.65;
    overflow-wrap: anywhere;
}
.documento-politica > * + * { margin-top: 0.9em; }
.documento-politica h1,
.documento-politica h2,
.documento-politica h3,
.documento-politica h4 {
    font-family: var(--font-display);
    font-weight: 600;
    line-height: 1.25;
    letter-spacing: -0.01em;
    color: rgb(var(--ink-rgb));
    margin-top: 1.6em;
}
.documento-politica > :first-child { margin-top: 0; }
.documento-politica h1 { font-size: 26px; }
.documento-politica h2 { font-size: 21px; }
.documento-politica h3 { font-size: 17px; }
.documento-politica h4 { font-size: 15px; }
.documento-politica p,
.documento-politica li { color: rgb(var(--ink-rgb)); }
.documento-politica ul { list-style: disc; padding-left: 1.4em; }
.documento-politica ol { list-style: decimal; padding-left: 1.4em; }
.documento-politica li + li { margin-top: 0.3em; }
.documento-politica a {
    color: rgb(var(--brand-text-rgb));
    text-decoration: underline;
    text-underline-offset: 2px;
}
.documento-politica strong,
.documento-politica b { font-weight: 600; }
.documento-politica hr {
    border: 0;
    border-top: var(--border-width) solid rgb(var(--line-rgb));
    margin: 1.6em 0;
}
.documento-politica blockquote {
    border-left: 3px solid rgb(var(--brand-rgb));
    padding: 2px 0 2px 14px;
    color: rgb(var(--ink-muted-rgb));
}
.documento-politica code {
    font-family: var(--font-mono);
    font-size: 0.9em;
    padding: 1px 5px;
    border-radius: var(--radius-sm);
    background: rgb(var(--surface-2-rgb));
}
.documento-politica pre {
    padding: 12px 14px;
    border-radius: var(--radius-md);
    background: rgb(var(--surface-2-rgb));
    overflow-x: auto;
}
.documento-politica pre code { padding: 0; background: transparent; }
/* Las tablas del documento: se desplazan dentro de su caja en un teléfono en
   vez de ensanchar la página. */
.documento-politica table {
    display: block;
    max-width: 100%;
    overflow-x: auto;
    border-collapse: collapse;
    font-size: 13.5px;
}
.documento-politica th,
.documento-politica td {
    border: var(--border-width) solid rgb(var(--line-rgb));
    padding: 7px 10px;
    text-align: left;
    vertical-align: top;
    min-width: 120px;
}
.documento-politica th {
    background: rgb(var(--surface-2-rgb));
    font-weight: 600;
}

/* El aviso de las políticas: el enlace a cada una, dentro de la fila de su
   casilla, y el error de enviar. */
.adp-opcion { align-items: flex-start; }
.adp-opcion .od-casilla { margin-top: 2px; }
.adp-enlace {
    color: rgb(var(--brand-text-rgb));
    text-decoration: underline;
    text-underline-offset: 2px;
}
.adp-error {
    margin: 0;
    font-size: 13.5px;
    color: rgb(var(--danger-text-rgb));
}

/* El campo de texto para editar una política: monoespaciado, porque es
   Markdown, y alto para leer un documento entero. */
.campo-politica {
    width: 100%;
    min-height: 360px;
    font-family: var(--font-mono);
    font-size: 13px;
    line-height: 1.55;
    resize: vertical;
}

/* ── La ficha de una versión de un paquete (requisitos 461-464) ──
   El contenido del paquete, legible: cada parte en una tarjeta plegable
   (rúbrica, una por sesión, personaje y guardrails). Los textos del paquete
   traen saltos de línea y se respetan. */
.tg-enlace { display: inline-block; text-decoration: none; }
.tg-enlace:hover { color: rgb(var(--brand-text-rgb)); text-decoration: underline; text-underline-offset: 2px; }

.fp-bloque > summary { align-items: center; }
.fp-bloque > summary .enc-seccion { margin: 0; flex: 1; min-width: 0; }
.fp-cuerpo {
    margin-top: 18px;
    padding-top: 16px;
    border-top: var(--border-width) solid rgb(var(--line-rgb));
    display: grid;
    gap: 12px;
}
.fp-texto { white-space: pre-line; overflow-wrap: anywhere; }
.fp-etiqueta {
    margin-top: 6px;
    display: flex;
    align-items: center;
    gap: 5px;
    font-family: var(--font-mono);
    font-size: 10.5px;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: rgb(var(--ink-subtle-rgb));
}
.fp-titulo {
    margin: 0;
    font-size: 15px;
    font-weight: 600;
    color: rgb(var(--ink-rgb));
}
.fp-lista {
    margin: 0;
    padding-left: 1.2em;
    list-style: disc;
    font-size: 13.5px;
    line-height: 1.55;
    color: rgb(var(--ink-rgb));
}
.fp-campos { margin: 0; display: grid; gap: 8px; }
.fp-campos > div {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 2px;
}
@media (min-width: 721px) {
    .fp-campos > div { grid-template-columns: 200px minmax(0, 1fr); gap: 12px; }
}
.fp-campos dt {
    font-size: 13px;
    font-weight: 600;
    color: rgb(var(--ink-muted-rgb));
    overflow-wrap: anywhere;
}
.fp-campos dd {
    margin: 0;
    font-size: 13.5px;
    line-height: 1.55;
    color: rgb(var(--ink-rgb));
}

.fp-conducta {
    padding: 14px 16px;
    border-radius: var(--radius-md);
    border: var(--border-width) solid rgb(var(--line-rgb));
    background: rgb(var(--surface-2-rgb));
    display: grid;
    gap: 8px;
}
.fp-conducta-cabecera { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 10px; }
.fp-niveles {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 8px;
}
@media (min-width: 721px) {
    .fp-niveles { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (min-width: 1200px) {
    .fp-niveles { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}
.fp-nivel {
    padding: 10px 12px;
    border-radius: var(--radius-sm);
    background: rgb(var(--surface-rgb));
    border: var(--border-width) solid rgb(var(--line-rgb));
}
.fp-nivel .fp-etiqueta { margin-top: 0; }
.fp-nivel .fp-texto { margin: 4px 0 0; font-size: 13px; line-height: 1.5; color: rgb(var(--ink-rgb)); }

.fp-ganchos { margin: 0; padding: 0; list-style: none; display: grid; gap: 8px; }
.fp-gancho {
    padding: 10px 12px;
    border-left: 3px solid rgb(var(--brand-rgb));
    background: rgb(var(--surface-2-rgb));
    border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
    display: grid;
    gap: 4px;
}
.fp-gancho p { margin: 0; }

.fp-variante {
    padding: 12px 14px;
    border-radius: var(--radius-md);
    border: var(--border-width) solid rgb(var(--line-rgb));
    display: grid;
    gap: 10px;
}
.fp-variante-nombre { display: flex; align-items: center; gap: 8px; }
.fp-variante-partes {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 12px;
}
@media (min-width: 1000px) {
    .fp-variante-partes { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
.fp-variante-partes .fp-campos > div { grid-template-columns: minmax(0, 1fr); gap: 2px; }
/* Lo que nunca llega al avatar, marcado para que no se confunda. */
.fp-solo-correccion {
    padding: 10px 12px;
    border-radius: var(--radius-sm);
    background: rgb(var(--warning-tint-rgb));
    border: var(--border-width) solid rgb(var(--warning-rgb) / 0.35);
}
.fp-solo-correccion .fp-etiqueta { margin-top: 0; color: rgb(var(--warning-text-rgb)); }

/* El editor del paquete: el archivo entero, así que más alto que el de una
   política. */
.campo-paquete { min-height: 520px; font-size: 12.5px; }

/* El mensaje verde de que algo salió bien (requisito 473). Hermano de la
   nota de marca de siempre y del aviso rojo. */
.aviso-ok {
    background: rgb(var(--success-tint-rgb));
    border-color: rgb(var(--success-rgb) / 0.45);
}
.aviso-ok .av-icono { color: rgb(var(--success-text-rgb)); }


/* ===== Mis convocatorias: la ficha de una convocatoria =====
   La de la abierta y la de la inscrita son la misma. La inscrita entera es un
   enlace al detalle: se marca al pasar el ratón y al llegar con el teclado, y
   su flecha se enciende como la de las filas de Prácticas. */

.fc-cabecera + .fila-datos { margin-top: 12px; }
.fc-aparte { display: flex; align-items: center; gap: 10px; flex-shrink: 0; }

.ficha-enlace {
    display: block;
    color: inherit;
    text-decoration: none;
    transition: border-color 140ms ease, box-shadow 160ms ease;
}
.ficha-enlace:hover { border-color: rgb(var(--brand-rgb) / 0.40); }
.ficha-enlace:focus-visible {
    outline: 2px solid rgb(var(--brand-rgb));
    outline-offset: 2px;
}
.ficha-enlace .fa-flecha { color: rgb(var(--ink-subtle-rgb)); display: inline-flex; }
.ficha-enlace:hover .fa-flecha,
.ficha-enlace:focus-visible .fa-flecha { color: rgb(var(--brand-text-rgb)); }
/* El avance y el promedio de la inscrita, con las piezas de la fila de
   Prácticas, y su mismo borde de aviso: rojo vencida, ámbar por vencer. */
.fc-avance { margin-top: 10px; gap: 8px 14px; }
.ficha-enlace.es-vencida { border-left: 3px solid rgb(var(--danger-rgb)); }
.ficha-enlace.es-justa   { border-left: 3px solid rgb(var(--warning-rgb)); }

/* ===== Reservar slot: el modal tiene un tamaño fijo =====
   Con un día de 40 horas el modal crecía y con uno de tres encogía, y el botón
   «Reservar» cambiaba de sitio. Ahora el alto es el mismo siempre (el del
   viewport si este es más bajo) y lo que sobra se recorre dentro del área de
   horas. */
.rs-modal {
    display: flex;
    flex-direction: column;
    height: min(620px, calc(100vh - 40px));
    height: min(620px, calc(100dvh - 40px));
    max-height: none;
    overflow: hidden;
}
.rs-modal .ec-cuerpo {
    flex: 1 1 auto;
    min-height: 0;
    grid-template-rows: minmax(0, 1fr);
}
.rs-modal .ec-cuerpo > * { min-height: 0; overflow-y: auto; }
.rs-modal .rs-horas { display: flex; flex-direction: column; overflow: hidden; }
.rs-modal .rs-grupo {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-height: 0;
    min-width: 0;
    border: 0;
    padding: 0;
    margin: 0;
}
.rs-scroll {
    flex: 1 1 auto;
    min-height: 0;
    overflow-x: hidden;
    overflow-y: auto;
    overscroll-behavior: contain;
}
.rs-scroll:focus-visible {
    outline: 2px solid rgb(var(--brand-rgb));
    outline-offset: 2px;
}
@media (max-width: 720px) {
    /* Una columna: el mes arriba, las horas en un panel de alto fijo debajo.
       Si el viewport es bajo, el cuerpo entero se recorre y el pie queda. */
    .rs-modal .ec-cuerpo { grid-template-rows: none; overflow-y: auto; }
    .rs-modal .ec-cuerpo > * { overflow-y: visible; }
    .rs-modal .rs-horas { height: 240px; flex: none; overflow: hidden; }
}

/* ===== El colaborador en el teléfono: Mis convocatorias, el detalle y
   «Reservar slot» =====
   Nada de esto cambia el escritorio. En un teléfono se pulsa con el dedo: los
   botones de este flujo miden al menos 44 px de alto, los días del calendario
   también, y las acciones de una ficha se apilan a lo ancho en vez de
   quedar como botoncitos sueltos. */

/* Un título sin espacios —un código, una URL— se parte antes que empujar la
   página de lado: en 390 px el del detalle del entrenamiento hacía aparecer
   el scroll horizontal. */
.ep-titulo { overflow-wrap: anywhere; }

/* Lo mismo a cualquier ancho, no solo en el teléfono: el título y el objetivo
   de la ficha de Mis convocatorias (un título de 90 caracteres sin espacios
   ponía la página en 823 px en una tableta de 768 y en 1109 en 1024), el
   objetivo bajo el título del detalle del líder y del Manager, y los valores
   de su franja de datos («Heredado de «…»»), que se cortaban a la derecha de
   la celda. Solo parte la palabra que no cabe entera; el resto del texto se
   sigue partiendo por los espacios. */
.fc-cabecera > .min-w-0,
.ep-nota,
.fd-valor { overflow-wrap: anywhere; }
.fd-valor { flex-wrap: wrap; }
.fd-valor > * { min-width: 0; }

/* El nombre del entrenamiento como chip en la cabecera del detalle de una
   convocatoria (líder y Manager). Es un texto libre y puede ser largo: el chip
   de siempre va en una línea y, con un nombre largo, empujaba la página a
   443 px en un teléfono de 320. Este se parte en varias líneas cuando no cabe
   y nunca es más ancho que su fila; con un nombre corto se ve igual que antes
   (24 px de alto, una línea). */
.chip.chip-se-parte {
    height: auto;
    min-height: 24px;
    max-width: 100%;
    padding-block: 4px;
    white-space: normal;
    overflow-wrap: anywhere;
    line-height: 1.35;
}

/* Las horas de un slot no se parten en dos líneas («20:00–» / «20:30»): la
   columna nunca es más estrecha que lo que pide la hora, y si no caben dos,
   va una. */
.slots-lista { grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); }
.opcion-slot .od-nombre { white-space: nowrap; overflow: visible; }

@media (max-width: 520px) {
    /* La cabecera de la ficha: el título arriba y, debajo y a lo ancho, lo de
       la derecha — el estado con la flecha al final de la fila en la
       inscrita, el botón «Inscribirme» entero en la abierta. */
    .fc-cabecera { gap: 12px; }
    .fc-cabecera > .min-w-0 { flex: 1 1 100%; }
    .fc-aparte { flex: 1 1 100%; }
    .fc-aparte > .btn { flex: 1 1 auto; height: auto; min-height: 44px; }
    .ficha-enlace .fc-aparte .fa-flecha { margin-left: auto; }
    .fc-acciones { flex-direction: column; align-items: stretch; }
    .fc-acciones > .btn { width: 100%; height: auto; min-height: 44px; }
    [data-call-id] > .periodos .btn { width: 100%; height: auto; min-height: 44px; }

    /* El detalle: «Reservar slot» —o «Cambiar slot»— va a todo el ancho de la
       tarjeta, como «Practicar» (requisito 543), en su propia línea debajo
       del rótulo «Siguiente práctica»; a 127 px de ancho junto al rótulo se
       leía como un botón secundario más y no como el paso que toca. */
    .lado-cabecera { flex-wrap: wrap; }
    .lado-cabecera > [data-abrir-reservar-slot] { flex: 1 1 100%; height: auto; min-height: 44px; }
    .dc-lado #btn-start-session { height: auto; min-height: 44px; }

    /* Los botones pequeños del detalle —«Preparar», «Ver reporte», «Repetir»
       de cada práctica, «Tu informe individual» y «Cancelar en Mis
       convocatorias» del aviso del slot— miden 32 px: se quedan con su
       aspecto de botón pequeño y suben a 44 de alto para el dedo. */
    .fs-derecha > .btn,
    .dc-lado [data-testid="ver-informe"],
    [data-testid="aviso-slot"] .btn { height: auto; min-height: 44px; }
}

/* Lo mismo en una tableta táctil (de 521 a 1023 px): solo si el puntero es el
   dedo, para no cambiar la pantalla de quien usa ratón en una ventana
   estrecha. Solo el alto: la disposición es la de la tableta. */
@media (min-width: 521px) and (max-width: 1023px) and (pointer: coarse) {
    .fc-aparte > .btn,
    .fc-acciones > .btn,
    [data-call-id] > .periodos .btn,
    .lado-cabecera > [data-abrir-reservar-slot],
    .dc-lado #btn-start-session,
    .fs-derecha > .btn,
    .dc-lado [data-testid="ver-informe"],
    [data-testid="aviso-slot"] .btn,
    .rs-modal .rs-pie .btn { height: auto; min-height: 44px; }
}

/* `layout.css` se carga después y su `.modal-content` topa el alto en 90vh:
   sin esto, el alto fijo de `.rs-modal` no valía en una pantalla baja. */
.rs-modal.modal-content { max-height: none; }

/* «Reservar slot» en un teléfono: ocupa la pantalla entera. Con los 20 px de
   margen del modal, siete días en 320 px no llegaban a 32 px por casilla. */
@media (max-width: 480px) {
    .modal:has(> .rs-modal) { padding: 0; }
    .rs-modal.modal-content {
        max-width: none;
        height: 100vh;
        height: 100dvh;
        border-radius: 0;
        border: 0;
        padding: 12px;
    }
    .rs-modal .ec-cabecera { margin-bottom: 8px; }
    .rs-modal .ac-rejilla { gap: 2px; }
    .rs-modal .ac-dia { min-height: 44px; }
    .rs-modal .rs-pie { margin-top: 10px; }
}
/* Por debajo de 360 px siete días de 44 no caben con los 12 px de margen y los
   2 de separación: en 320 px son 320 − 24 = 296 px, y 7 × 44 + 6 × 2 = 320.
   Se quitan la separación entre días y la mitad del margen del calendario
   —7 × 44 = 308 = 320 − 2 × 6— y el día queda en 44 × 44 en vez de 40,6. El
   resto de la ventana (el título, las horas, la nota y los botones) conserva
   sus 12 px: los 6 que le faltan los pone cada uno. */
@media (max-width: 359px) {
    .rs-modal.modal-content { padding-inline: 6px; }
    .rs-modal.modal-content > :not(.ec-cuerpo),
    .rs-modal .ac-mes-cabecera,
    .rs-modal .rs-horas { padding-inline: 6px; }
    .rs-modal .ac-rejilla { gap: 0; }
}
@media (max-width: 720px) {
    /* Una columna: cada fila mide lo que su contenido. Con `min-height: 0` en
       los hijos, en una pantalla baja la rejilla encogía las filas y las horas
       se montaban encima del mes; ahora el cuerpo se recorre entero. */
    .rs-modal .ec-cuerpo { grid-auto-rows: max-content; }
    .rs-modal [data-cerrar-reservar].btn-sm,
    .rs-modal .cal-paso { width: 44px; height: 44px; }
    .rs-modal .rs-pie .btn { flex: 1 1 0; height: auto; min-height: 44px; }
    .rs-modal .opcion-slot { min-height: 44px; }
}
/* El teléfono de lado: poca altura y ancho de sobra. El mes y las horas van
   uno al lado del otro, cada uno con su scroll, y el pie no se mueve. */
@media (max-height: 500px) and (min-width: 560px) {
    .modal:has(> .rs-modal) { padding: 8px; }
    .rs-modal.modal-content { height: calc(100vh - 16px); height: calc(100dvh - 16px); padding: 12px 16px; }
    .rs-modal .ec-cabecera { margin-bottom: 6px; }
    .rs-modal .ec-cuerpo {
        grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
        grid-template-rows: minmax(0, 1fr);
        gap: 16px;
        overflow: hidden;
    }
    .rs-modal .ec-cuerpo > * { overflow-y: auto; }
    .rs-modal .rs-horas { height: auto; overflow: hidden; }
    .rs-modal .rs-nota { margin-top: 6px; font-size: 12px; }
    .rs-modal .rs-pie { margin-top: 8px; }
}
