/* =========================================================================
   Sistema de diseño del panel — derivado del landing de Buckingham English.

   Los colores están en variables a propósito: son una lectura aproximada
   del diseño y se ajustan aquí, en un solo lugar, sin tocar plantillas.
   ========================================================================= */

:root {
    /* Marca */
    --bk-navy:        #2e4663;  /* barra superior, pie, títulos */
    --bk-navy-700:    #24374e;
    --bk-navy-900:    #1a2838;
    --bk-lime:        #d7e02b;  /* acción principal, aros del logo */
    --bk-lime-600:    #c3cc1f;
    --bk-lime-soft:   #f5f2a3;  /* círculos de iconos */

    /* Superficies.

       El lienzo no es gris neutro sino navy muy lavado, y encima lleva dos
       manchas de color de la marca. Con un gris plano detrás de tarjetas
       blancas no hay nada que empuje el fondo hacia atrás y todo se lee a la
       misma distancia; con el lienzo teñido, el blanco de la tarjeta *es* la
       señal de que ahí hay algo. */
    --bk-canvas:      #e9edf3;
    --bk-bg:          #ffffff;
    --bk-surface:     #f1f4f8;
    --bk-surface-2:   #f8fafc;
    --bk-border:      rgba(46, 70, 99, .11);

    /* Texto */
    --bk-text:        #22303f;
    --bk-muted:       #64748b;

    /* Estado */
    --bk-ok:          #1a7f37;
    --bk-warn:        #b45309;
    --bk-danger:      #b42318;

    /* ---------------------------------------------------------------------
       Colores de los gráficos.

       No son los de la marca tal cual: el lima #d7e02b sobre blanco queda en
       1.6:1 de contraste y una barra pintada así no se ve. Estos son la misma
       familia de tonos llevada a un paso más oscuro, y pasaron las
       comprobaciones de rango de luminosidad, croma, separación bajo
       daltonismo (protanopía y deuteranopía) y contraste sobre blanco.
       Cambiarlos a ojo rompe alguna de esas cuatro cosas.

       Un módulo conserva su color en todos los gráficos: si Cursos es azul en
       uno, lo es en todos. El color identifica la entidad, nunca su tamaño.
       --------------------------------------------------------------------- */
    --viz-cursos:        #3a6ea5;  /* navy de la marca, aclarado a un paso legible */
    --viz-certificados:  #8a961c;  /* lima de la marca, oscurecido hasta 3:1 */
    --viz-convenios:     #a8386b;

    /* Estados de la inscripción: significan «cómo va», no «cuál es», así que
       van en una escala reservada y nunca se reutilizan como color de serie.

       Verde y ámbar se confunden bajo deuteranopía y no hay forma de evitarlo
       sin dejar de ser una escala de severidad. Por eso el gráfico de estados
       rotula cada barra con su nombre en el eje y su cifra en la punta: el
       color acompaña, nunca es lo único que distingue una barra de otra. */
    --viz-abierta:    #0ca30c;
    --viz-recargo:    #b26a00;
    --viz-completa:   #b42318;
    --viz-cerrada:    #64748b;  /* gris a propósito: «cerrada» es ausencia de estado */

    /* Color del módulo en el que se está.

       El panel se pone del color de lo que se está tocando: la raya bajo el
       título, el foco de los campos, el tinte de la tabla. Es la señal de
       «dónde estoy» más barata que hay, y son los mismos tres colores de los
       gráficos, así que Cursos es del mismo azul en el dashboard y dentro.

       Fuera de esos tres módulos el acento es el navy: el dashboard y la
       sección de horarios *mezclan* las tres ofertas, y darles un cuarto
       color sería inventar una identidad que no tienen. No hay además un
       cuarto tono que se separe de estos tres bajo daltonismo. */
    --bk-accent:      var(--bk-navy);

    /* Forma */
    --bk-radius:      18px;
    --bk-radius-sm:   12px;
    --bk-radius-pill: 999px;
    --bk-sidebar-w:   248px;
    --bk-sidebar-min: 4.75rem;  /* menú comprimido: solo iconos */

    /* Dos alturas nada más: apoyado y levantado. La sombra es difusa y de
       color navy, no negra: un gris neutro sobre lienzo teñido ensucia. */
    --bk-shadow:      0 1px 2px rgba(46, 70, 99, .04), 0 6px 18px rgba(46, 70, 99, .07);
    --bk-shadow-lg:   0 2px 6px rgba(46, 70, 99, .05), 0 18px 44px rgba(46, 70, 99, .14);

    /* Movimiento. Una sola curva para todo el panel: la salida suave hace que
       lo que aparece parezca que se posa en vez de dar un tirón. */
    --bk-ease:        cubic-bezier(.22, 1, .36, 1);
    --bk-rapido:      .16s;
    --bk-normal:      .26s;
}

/* El atributo lo pone el layout con la entrada de menú activa. */
[data-modulo="cursos"]       { --bk-accent: var(--viz-cursos); }
[data-modulo="certificados"] { --bk-accent: var(--viz-certificados); }
[data-modulo="convenios"]    { --bk-accent: var(--viz-convenios); }

/* -------------------------------------------------------------- Base --- */

/* Dos lavados enormes y muy tenues —lima arriba a la izquierda, azul arriba a
   la derecha— sobre el lienzo teñido. Fijos, para que no se muevan al hacer
   scroll y se lean como luz de la sala y no como un elemento de la página. */
body {
    font-family: 'Poppins', system-ui, -apple-system, 'Segoe UI', sans-serif;
    background:
        radial-gradient(1100px 560px at 12% -12%, rgba(215, 224, 43, .20), transparent 62%),
        radial-gradient(900px 520px at 96% -6%, rgba(58, 110, 165, .16), transparent 58%),
        var(--bk-canvas);
    background-attachment: fixed;
    color: var(--bk-text);
    font-size: .95rem;
}

h1, h2, h3, h4, h5, h6 {
    font-weight: 600;
    color: var(--bk-navy);
    letter-spacing: -.01em;
}

a { color: var(--bk-navy); }
a:hover { color: var(--bk-navy-700); }

code {
    background: var(--bk-surface);
    padding: .1rem .35rem;
    border-radius: 6px;
    color: var(--bk-navy-700);
}

/* --------------------------------------------------- Armazón lateral --- */

.bk-app {
    display: flex;
    min-height: 100vh;
}

/* El navy va en degradado y con un resplandor lima arriba, donde está la
   marca: un bloque de color liso de 248px de ancho y toda la altura es la
   superficie más grande de la pantalla y la que más se nota si está muerta. */
.bk-sidebar {
    width: var(--bk-sidebar-w);
    flex: 0 0 var(--bk-sidebar-w);
    background:
        radial-gradient(420px 260px at 20% -8%, rgba(215, 224, 43, .16), transparent 70%),
        linear-gradient(180deg, var(--bk-navy) 0%, var(--bk-navy-900) 100%);
    display: flex;
    flex-direction: column;
    position: sticky;
    top: 0;
    height: 100vh;
    overflow-y: auto;
    overflow-x: hidden;  /* al comprimir, las etiquetas no deben asomar */
    transition: width .18s ease, flex-basis .18s ease;
}

.bk-main {
    flex: 1 1 auto;
    min-width: 0;  /* sin esto, una tabla ancha desborda el flex */
}

/* Sin tope de ancho: el contenido ocupa todo lo que le deja el menú. Con un
   tope, en una pantalla grande quedaba una franja muerta a la derecha. Las
   pantallas que sí necesitan una medida de lectura cómoda —los formularios—
   se la ponen ellas con su propio max-width. */
.bk-contenido {
    padding: 2rem;
}

@media (min-width: 1600px) {
    .bk-contenido { padding: 2.25rem 2.75rem; }
}

/* La marca y el botón de plegado comparten fila: el borde inferior es de la
   fila, no del enlace, para que la raya cruce los dos. */
.bk-sidebar-cabeza {
    display: flex;
    align-items: center;
    gap: .5rem;
    padding: 1.35rem 1.25rem;
    border-bottom: 1px solid rgba(255, 255, 255, .08);
}

.bk-brand {
    display: flex;
    align-items: center;
    gap: .6rem;
    flex: 1 1 auto;
    min-width: 0;
    color: #fff;
    font-weight: 700;
    letter-spacing: .02em;
    text-decoration: none;
}

.bk-brand:hover { color: #fff; }

/* ------------------------------------------------------------- Menú --- */

.bk-menu {
    flex: 1 1 auto;
    padding: 1rem .75rem;
}

.bk-menu ul {
    list-style: none;
    margin: 0 0 1.25rem;
    padding: 0;
}

.bk-menu-grupo {
    margin: 0 0 .4rem;
    padding: 0 .6rem;
    font-size: .66rem;
    font-weight: 700;
    letter-spacing: .12em;
    text-transform: uppercase;
    color: rgba(255, 255, 255, .38);
}

.bk-menu a {
    display: flex;
    align-items: center;
    gap: .7rem;
    padding: .6rem .65rem;
    margin-bottom: .15rem;
    border-radius: var(--bk-radius-sm);
    color: rgba(255, 255, 255, .78);
    font-size: .855rem;
    font-weight: 500;
    text-decoration: none;
    transition: background var(--bk-rapido), color var(--bk-rapido);
}

.bk-menu a svg {
    width: 18px;
    height: 18px;
    flex: 0 0 auto;
    fill: currentColor;
    opacity: .85;
    transition: transform var(--bk-normal) var(--bk-ease);
}

.bk-menu a:hover {
    background: rgba(255, 255, 255, .09);
    color: #fff;
}

/* El icono se adelanta un pelo al pasar por encima. Es el movimiento más
   pequeño que confirma que la fila responde antes de pulsarla. */
.bk-menu a:hover svg { transform: translateX(2px); }

/* La pastilla lima lleva su propio resplandor: sin él, sobre el navy en
   degradado, la entrada activa se veía pegada y no encendida. */
.bk-menu a.is-active {
    background: var(--bk-lime);
    color: var(--bk-navy-900);
    font-weight: 600;
    box-shadow: 0 4px 16px rgba(215, 224, 43, .30);
}

.bk-menu a.is-active svg { opacity: 1; }

/* ------------------------------------------------- Pie de la barra --- */

.bk-sidebar-pie {
    padding: .9rem 1.25rem 1.25rem;
    border-top: 1px solid rgba(255, 255, 255, .08);
}

.bk-sidebar-usuario {
    display: flex;
    align-items: center;
    gap: .55rem;
    color: rgba(255, 255, 255, .85);
    font-size: .82rem;
    margin-bottom: .6rem;
}

.bk-avatar {
    width: 30px;
    height: 30px;
    flex: 0 0 auto;
    border-radius: 50%;
    display: grid;
    place-items: center;
    background: var(--bk-lime);
    color: var(--bk-navy-900);
    font-weight: 700;
    font-size: .8rem;
}

.bk-salir {
    width: 100%;
    background: transparent;
    border: 1px solid rgba(255, 255, 255, .22);
    color: rgba(255, 255, 255, .85);
    border-radius: var(--bk-radius-pill);
    padding: .4rem .9rem;
    font-size: .78rem;
    font-weight: 500;
    transition: background .15s;
}

.bk-salir:hover { background: rgba(255, 255, 255, .1); color: #fff; }

/* ------------------------------------------------- Menú comprimido --- */

/* El botón que lo alterna. Va junto a la marca, arriba del todo: es lo
   primero que se busca cuando el menú estorba. */
.bk-comprimir {
    flex: 0 0 auto;
    display: grid;
    place-items: center;
    width: 34px;
    height: 34px;
    background: transparent;
    border: 0;
    color: rgba(255, 255, 255, .6);
    border-radius: var(--bk-radius-sm);
    cursor: pointer;
    transition: background .15s, color .15s;
}

.bk-comprimir:hover { background: rgba(255, 255, 255, .1); color: #fff; }

.bk-lineas {
    display: grid;
    gap: 4px;
    width: 18px;
}

.bk-lineas span {
    display: block;
    height: 2px;
    border-radius: 2px;
    background: currentColor;
    transition: width .18s ease;
}

/* Plegado, la línea del medio se acorta: la misma pieza indica hacia dónde
   va el gesto sin cambiar de icono. */
.bk-comprimido .bk-lineas span:nth-child(2) { width: 60%; }

/* La clase vive en <html> y la pone un script en el <head>: si esperara al
   final del documento, el menú se pintaría ancho y daría un salto. */
.bk-comprimido .bk-sidebar {
    width: var(--bk-sidebar-min);
    flex-basis: var(--bk-sidebar-min);
}

/* Con 4.75rem no caben la marca y el botón en la misma fila, así que se
   apilan. El botón sigue estando, que es lo que permite volver. */
.bk-comprimido .bk-sidebar-cabeza {
    flex-direction: column;
    gap: .6rem;
    padding-left: .55rem;
    padding-right: .55rem;
}

.bk-comprimido .bk-brand { justify-content: center; }

/* El avatar queda: es un `span` más dentro del bloque de usuario, pero es la
   única señal de quién tiene la sesión abierta cuando no cabe el nombre. */
.bk-comprimido .bk-brand-text,
.bk-comprimido .bk-menu a span,
.bk-comprimido .bk-sidebar-usuario span:not(.bk-avatar) {
    display: none;
}

/* El título del grupo se sustituye por una raya: sin él las secciones se
   pegarían unas a otras y el menú se leería como una lista sola. */
.bk-comprimido .bk-menu-grupo {
    height: 1px;
    margin: .75rem .5rem;
    padding: 0;
    overflow: hidden;
    text-indent: -999px;
    background: rgba(255, 255, 255, .12);
}

.bk-comprimido .bk-menu {
    padding-left: .55rem;
    padding-right: .55rem;
}

.bk-comprimido .bk-menu a {
    justify-content: center;
    padding-left: 0;
    padding-right: 0;
}

.bk-comprimido .bk-sidebar-pie {
    padding-left: .55rem;
    padding-right: .55rem;
}

.bk-comprimido .bk-sidebar-usuario { justify-content: center; }
.bk-comprimido .bk-comprimir { justify-content: center; }
.bk-comprimido .bk-comprimir svg { transform: rotate(180deg); }

/* El botón de salir se queda en icono; el texto no cabe. */
.bk-comprimido .bk-salir {
    padding: .4rem 0;
    font-size: 1rem;
}

.bk-comprimido .bk-salir-texto { display: none; }
.bk-salir-icono { display: none; }
.bk-comprimido .bk-salir-icono { display: inline; }

/* ------------------------------------------- Barra móvil y overlay --- */

.bk-mobilebar {
    display: none;
    align-items: center;
    gap: .9rem;
    padding: .85rem 1rem;
    background: var(--bk-navy);
    color: #fff;
    position: sticky;
    top: 0;
    z-index: 30;
}

.bk-burger {
    background: none;
    border: 0;
    padding: .25rem;
    display: grid;
    gap: 4px;
}

.bk-burger span {
    display: block;
    width: 20px;
    height: 2px;
    background: #fff;
    border-radius: 2px;
}

/* Desenfoca lo de detrás en vez de solo oscurecerlo: el cajón se lee como
   una capa por encima y no como un recorte pegado sobre la tabla. */
.bk-overlay {
    position: fixed;
    inset: 0;
    background: rgba(16, 25, 36, .42);
    backdrop-filter: blur(3px);
    z-index: 40;
    animation: bk-aparecer var(--bk-normal) var(--bk-ease) both;
}

/* Aro del logotipo: el círculo lima abierto de la marca. */
.bk-brand-mark {
    width: 34px;
    height: 34px;
    border-radius: 50%;
    border: 4px solid var(--bk-lime);
    border-right-color: transparent;
    transform: rotate(-45deg);
    flex: 0 0 auto;
}

.bk-brand-text { line-height: 1.05; }
.bk-brand-text small {
    display: block;
    font-size: .62rem;
    font-weight: 500;
    letter-spacing: .22em;
    opacity: .75;
}

/* ------------------------------------------------- Cabecera de página --- */

/* Solo una línea de separación. Hubo aquí una raya corta de color bajo el
   título y hubo que quitarla: una barra que crece de izquierda a derecha se
   lee como progreso, y esta pantalla no está cargando nada. El color del
   módulo se ve donde sí ayuda —el foco de los campos, la cabecera de la
   tabla, el filo de las tarjetas—. */
.bk-page-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
    padding-bottom: 1.15rem;
    margin-bottom: 1.5rem;
    border-bottom: 1px solid var(--bk-border);
}

.bk-page-head h1 {
    font-size: 1.6rem;
    margin: 0;
}

.bk-page-head p {
    margin: .3rem 0 0;
    color: var(--bk-muted);
    font-size: .875rem;
    max-width: 62ch;
}

/* El rótulo de encima del título: de dónde cuelga esta pantalla, y la vuelta.
   Hace el trabajo de un botón «Volver» ocupando una línea de texto, y además
   informa —«Cursos» dice dónde estás—. */
.bk-page-contexto {
    display: inline-flex;
    align-items: center;
    gap: .35rem;
    margin-bottom: .15rem;
    font-size: .72rem;
    font-weight: 700;
    letter-spacing: .09em;
    text-transform: uppercase;
    color: var(--bk-muted);
    text-decoration: none;
    transition: color var(--bk-rapido) var(--bk-ease);
}

.bk-page-contexto:hover { color: var(--bk-accent); }

/* La flecha, dibujada con dos lados de un cuadrado girado: una entidad «←» se
   desalinea con la versalita y cada tipografía la dibuja de un tamaño. */
.bk-page-contexto-flecha {
    width: .38rem;
    height: .38rem;
    border-left: 1.5px solid currentColor;
    border-bottom: 1.5px solid currentColor;
    transform: rotate(45deg);
    transition: transform var(--bk-rapido) var(--bk-ease);
}

.bk-page-contexto:hover .bk-page-contexto-flecha { transform: rotate(45deg) translate(1px, -1px); }

/* ------------------------------------------------------------- Card --- */

/* Sin marco: sobre el lienzo teñido, la sombra difusa ya separa la tarjeta
   del fondo, y el borde de 1px solo añadía una retícula gris. */
.bk-card {
    background: var(--bk-bg);
    border: 0;
    border-radius: var(--bk-radius);
    box-shadow: var(--bk-shadow);
    overflow: hidden;
}

.bk-card-body { padding: 1.5rem; }

/* Una tarjeta con `h-100` la estira su vecina más alta de la fila. Un gráfico
   de dos barras se quedaba pegado arriba con todo el sobrante debajo, y ese
   hueco se lee como que falta algo. El cuerpo toma el alto libre y el gráfico
   se centra en él.
   Solo cuando el cuerpo es el gráfico y nada más: una lista o una tabla se
   leen desde arriba y centrarlas sería peor. Si el navegador no entiende
   `:has()`, se queda como estaba. */
.bk-card.h-100 { display: flex; flex-direction: column; }
.bk-card.h-100 > .bk-card-body { flex: 1; }

.bk-card.h-100 > .bk-card-body:has(> .bk-grafico:only-child),
.bk-card.h-100 > .bk-card-body:has(> .bk-empty:only-child) {
    display: grid;
    align-content: center;
}

.bk-card-head {
    padding: 1.1rem 1.5rem;
    border-bottom: 1px solid var(--bk-border);
    font-weight: 600;
    color: var(--bk-navy);
}

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

.btn {
    border-radius: var(--bk-radius-pill);
    font-weight: 600;
    font-size: .875rem;
    padding: .55rem 1.4rem;
    border: 1px solid transparent;
    transition: background var(--bk-rapido), border-color var(--bk-rapido),
                color var(--bk-rapido), box-shadow var(--bk-rapido),
                transform var(--bk-rapido);
}

/* Se hunde al pulsar. Sin esto un botón se siente una imagen; con 1px basta
   para que se sienta un botón. */
.btn:active { transform: translateY(1px); }

.btn-bk {
    background: var(--bk-lime);
    color: var(--bk-navy-900);
    box-shadow: 0 2px 10px rgba(215, 224, 43, .40);
}
.btn-bk:hover {
    background: var(--bk-lime-600);
    color: var(--bk-navy-900);
    box-shadow: 0 5px 18px rgba(215, 224, 43, .55);
}

.btn-bk-navy {
    background: var(--bk-navy);
    color: #fff;
    box-shadow: 0 2px 10px rgba(46, 70, 99, .22);
}
.btn-bk-navy:hover {
    background: var(--bk-navy-700);
    color: #fff;
    box-shadow: 0 5px 18px rgba(46, 70, 99, .30);
}

/* El botón secundario se tiñe del color del módulo al pasar por encima: es
   donde el acento aparece sin que haya que pintar nada de fondo. */
.btn-bk-ghost {
    background: var(--bk-bg);
    border-color: var(--bk-border);
    color: var(--bk-text);
}
.btn-bk-ghost:hover {
    background: color-mix(in srgb, var(--bk-accent) 8%, #fff);
    border-color: color-mix(in srgb, var(--bk-accent) 35%, transparent);
    color: var(--bk-accent);
}

.btn-bk-danger {
    background: transparent;
    border-color: #f0c4c0;
    color: var(--bk-danger);
}
.btn-bk-danger:hover { background: #fdf0ef; color: var(--bk-danger); }

.btn-sm { padding: .35rem .9rem; font-size: .8rem; }

/* Acción textual dentro de tablas. */
.bk-link-btn {
    background: none;
    border: 0;
    padding: 0;
    font-size: .8rem;
    font-weight: 500;
    color: var(--bk-muted);
    text-decoration: underline;
    text-underline-offset: 2px;
}
.bk-link-btn:hover { color: var(--bk-navy); }
.bk-link-btn.is-danger:hover { color: var(--bk-danger); }

/* ------------------------------------------------------- Formularios --- */

.form-label {
    font-size: .82rem;
    font-weight: 600;
    color: var(--bk-navy);
    margin-bottom: .35rem;
}

.form-control, .form-select {
    border-radius: var(--bk-radius-sm);
    border-color: var(--bk-border);
    padding: .55rem .85rem;
    font-size: .9rem;
    transition: border-color var(--bk-rapido), box-shadow var(--bk-rapido);
}

/* El aro del foco toma el color del módulo. El campo activo es lo único que
   se mira mientras se escribe; que además diga en qué sección se está sale
   gratis. */
.form-control:focus, .form-select:focus {
    border-color: var(--bk-accent);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--bk-accent) 18%, transparent);
}

.form-check-input:focus {
    border-color: var(--bk-accent);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--bk-accent) 18%, transparent);
}

.form-text { font-size: .78rem; color: var(--bk-muted); }

.form-check-input:checked {
    background-color: var(--bk-navy);
    border-color: var(--bk-navy);
}

/* -------------------------------------------------------------- Tabla --- */

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

.bk-table thead th {
    background: var(--bk-surface-2);
    border-bottom: 1px solid var(--bk-border);
    padding: .8rem 1.5rem;
    font-size: .72rem;
    font-weight: 700;
    letter-spacing: .07em;
    text-transform: uppercase;
    color: var(--bk-muted);
    white-space: nowrap;
}

/* La primera celda de una fila es a veces `th` —el nombre de la persona, el
   del módulo—: es su encabezado, no un dato. Estas reglas iban solo a `td`,
   así que esa celda se quedaba sin relleno y sin raya: el contenido salía
   pegado al borde izquierdo mientras su cabecera empezaba 1,5rem más adentro,
   y el separador de filas arrancaba en la segunda columna. */
.bk-table tbody td,
.bk-table tbody th {
    padding: .9rem 1.5rem;
    border-bottom: 1px solid var(--bk-border);
    vertical-align: middle;
}

.bk-table tbody tr:last-child td,
.bk-table tbody tr:last-child th { border-bottom: 0; }
.bk-table tbody tr:hover { background: var(--bk-surface-2); }

.bk-empty {
    padding: 3rem 1.5rem;
    text-align: center;
    color: var(--bk-muted);
}

/* ------------------------------------------------------------ Badges --- */

.bk-badge {
    display: inline-block;
    padding: .28rem .7rem;
    border-radius: var(--bk-radius-pill);
    font-size: .74rem;
    font-weight: 600;
    line-height: 1.3;
}

.bk-badge-ok      { background: #e7f5ec; color: var(--bk-ok); }
.bk-badge-warn    { background: #fff4e0; color: var(--bk-warn); }
.bk-badge-off     { background: var(--bk-surface); color: var(--bk-muted); }
.bk-badge-closed  { background: #fdecea; color: var(--bk-danger); }
.bk-badge-neutral { background: #eef1f5; color: var(--bk-navy); }

/* ------------------------------------------------------------ Avisos --- */

.bk-alert {
    border: 0;
    border-left: 4px solid;
    border-radius: var(--bk-radius-sm);
    padding: .85rem 1.1rem;
    font-size: .875rem;
    margin-bottom: 1rem;
}

.bk-alert-success { background: #e7f5ec; border-color: var(--bk-ok);     color: #14532d; }
.bk-alert-danger  { background: #fdecea; border-color: var(--bk-danger); color: #7f1d1d; }
.bk-alert-warning { background: #fff7e6; border-color: var(--bk-warn);   color: #78350f; }

/* ----------------------------------------------------------- Utilidad --- */

.bk-muted { color: var(--bk-muted); }
.bk-mono  { font-family: ui-monospace, 'Cascadia Code', Consolas, monospace; }

/* ------------------------------------------------------------- Login --- */

.bk-login-wrap {
    min-height: 100vh;
    display: grid;
    place-items: center;
    background: var(--bk-navy);
    padding: 1.5rem;
}

.bk-login-card {
    width: 100%;
    max-width: 25rem;
    background: #fff;
    border-radius: var(--bk-radius);
    box-shadow: var(--bk-shadow-lg);
    padding: 2.25rem;
}

/* --------------------------------------------------------- Dashboard --- */

.bk-tiles {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
    gap: 1rem;
    margin-bottom: 1.5rem;
}

.bk-tile {
    position: relative;
    background: var(--bk-bg);
    border: 0;
    border-radius: var(--bk-radius);
    box-shadow: var(--bk-shadow);
    padding: 1.15rem 1.25rem;
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: .15rem;
    overflow: hidden;
    text-decoration: none;
    color: inherit;
    transition: box-shadow var(--bk-normal) var(--bk-ease),
                transform var(--bk-normal) var(--bk-ease);
}

/* La cifra que encabeza el panel: una sola, y en el mismo tipo que el resto. */
.bk-tile-hero {
    grid-column: span 2;
    background: var(--bk-navy);
    border-color: transparent;
}

.bk-tile-hero .bk-tile-etiqueta { color: rgba(255, 255, 255, .78); }

.bk-tile-cifra-hero {
    font-size: 3rem;
    font-weight: 700;
    line-height: 1;
    color: var(--bk-lime);
}

@media (max-width: 575.98px) {
    .bk-tile-hero { grid-column: span 1; }
}

a.bk-tile:hover {
    box-shadow: var(--bk-shadow-lg);
    transform: translateY(-3px);
    color: inherit;
}

/* El color del módulo va en la cifra y en un filo sólido a la izquierda.
   Nada de degradados ni de rayas que crecen: en una cifra de resumen
   cualquier cosa que se mueva o se aclare se lee como que el dato aún está
   cargando, y aquí el dato ya está. */
a.bk-tile[data-modulo] {
    border-left: 3px solid var(--bk-accent);
}

a.bk-tile[data-modulo] .bk-tile-cifra { color: var(--bk-accent); }

.bk-tile-cifra {
    font-size: 1.55rem;
    font-weight: 700;
    line-height: 1.1;
    color: var(--bk-navy);
}

.bk-tile-etiqueta {
    font-size: .78rem;
    color: var(--bk-muted);
    line-height: 1.3;
}

/* Aviso de "aún no hay nada configurado aquí". */
.bk-vacio-guia {
    background: var(--bk-bg);
    border: 1px dashed var(--bk-border);
    border-radius: var(--bk-radius);
    padding: 2.5rem 1.5rem;
    text-align: center;
}

.bk-vacio-guia h2 {
    font-size: 1.05rem;
    margin: 0 0 .4rem;
}

.bk-vacio-guia p {
    color: var(--bk-muted);
    font-size: .875rem;
    max-width: 46ch;
    margin: 0 auto 1.1rem;
}

/* ---------------------------------------------------------- Gráficos --- */

/* El alto incluye el eje: si se recorta al área de trazado, la tarjeta acaba
   con una barra de desplazamiento diminuta para leer las etiquetas. */
.bk-grafico {
    position: relative;
    width: 100%;
}

.bk-grafico canvas { display: block; }

.bk-grafico-anillo { display: grid; place-items: center; }

.bk-anillo-centro {
    position: absolute;
    text-align: center;
    line-height: 1.1;
    pointer-events: none;  /* el tooltip del anillo tiene que seguir alcanzable */
}

.bk-anillo-centro strong {
    display: block;
    font-size: 2rem;
    font-weight: 700;
    color: var(--bk-navy);
}

.bk-anillo-centro span {
    font-size: .74rem;
    color: var(--bk-muted);
}

/* Subtítulo de la cabecera de tarjeta: dice de qué recorte son las cifras. */
.bk-card-sub {
    display: block;
    font-size: .76rem;
    font-weight: 400;
    color: var(--bk-muted);
    margin-top: .1rem;
}

/* Leyenda propia en HTML: el color queda en el punto y el nombre en tinta
   de texto, que es legible; un rótulo pintado del color de la serie no lo es. */
.bk-leyenda {
    list-style: none;
    margin: 1.25rem 0 0;
    padding: 0;
    display: grid;
    gap: .5rem;
}

.bk-leyenda li {
    display: flex;
    align-items: center;
    gap: .55rem;
    font-size: .82rem;
}

.bk-leyenda-nombre { color: var(--bk-text); }
.bk-leyenda-cifra {
    margin-left: auto;
    font-weight: 600;
    color: var(--bk-navy);
    font-variant-numeric: tabular-nums;
}

.bk-leyenda-horizontal {
    display: flex;
    flex-wrap: wrap;
    gap: .35rem 1.25rem;
    margin-top: 1rem;
}

.bk-punto {
    width: 9px;
    height: 9px;
    border-radius: 50%;
    flex: 0 0 auto;
}

.bk-punto-cursos       { background: var(--viz-cursos); }
.bk-punto-certificados { background: var(--viz-certificados); }
.bk-punto-convenios    { background: var(--viz-convenios); }

/* Tabla equivalente de un gráfico, plegada. Ningún dato queda solo dentro
   de un tooltip. */
.bk-datos { margin-top: 1.1rem; }

.bk-datos summary {
    cursor: pointer;
    font-size: .78rem;
    color: var(--bk-muted);
    list-style: none;
}

.bk-datos summary::-webkit-details-marker { display: none; }
.bk-datos summary::before { content: '▸ '; }
.bk-datos[open] summary::before { content: '▾ '; }
.bk-datos summary:hover { color: var(--bk-navy); }

.bk-table-datos {
    margin-top: .75rem;
    font-size: .8rem;
    font-variant-numeric: tabular-nums;
}

.bk-table-datos thead th,
.bk-table-datos tbody td { padding: .45rem .75rem; }

/* ---------------------------------------------------------- Medidores --- */

.bk-medidor { margin-bottom: 1.1rem; }

.bk-medidor-cabeza {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    font-size: .82rem;
    margin-bottom: .4rem;
}

.bk-medidor-cifra {
    color: var(--bk-muted);
    font-size: .76rem;
    font-variant-numeric: tabular-nums;
}

.bk-medidor-pista {
    height: 8px;
    border-radius: var(--bk-radius-pill);
    background: var(--bk-surface);
    overflow: hidden;
}

.bk-medidor-relleno {
    height: 100%;
    border-radius: var(--bk-radius-pill);
    transition: width .3s ease;
}

.bk-relleno-cursos       { background: var(--viz-cursos); }
.bk-relleno-certificados { background: var(--viz-certificados); }
.bk-relleno-convenios    { background: var(--viz-convenios); }

/* -------------------------------------------------- Fichas y usuarios --- */

/* El distintivo de color va en un punto, no en un borde lateral: sobre una
   píldora, un borde de 3px se curva y se lee como un defecto de dibujo. */
.bk-chip {
    display: inline-flex;
    align-items: center;
    gap: .4rem;
    padding: .22rem .65rem;
    border-radius: var(--bk-radius-pill);
    font-size: .72rem;
    font-weight: 600;
    background: var(--bk-surface);
    color: var(--bk-navy);
    text-decoration: none;
}

.bk-chip::before {
    content: '';
    width: 7px;
    height: 7px;
    border-radius: 50%;
    flex: 0 0 auto;
    background: currentColor;
}

.bk-chip-cursos::before       { background: var(--viz-cursos); }
.bk-chip-certificados::before { background: var(--viz-certificados); }
.bk-chip-convenios::before    { background: var(--viz-convenios); }

.bk-chip-pendiente {
    transition: background .15s, color .15s;
}

.bk-chip-pendiente::before { background: var(--bk-warn); }

.bk-chip-pendiente:hover { background: #fff4e0; color: var(--bk-warn); }

.bk-badge-admin { background: var(--bk-navy); color: #fff; }

.bk-avatar-sm {
    width: 30px;
    height: 30px;
    font-size: .78rem;
    flex: 0 0 auto;
}

.bk-empty-ok { color: var(--bk-ok); padding: 2rem 1rem; }

.bk-sep { border-color: var(--bk-border); margin: .25rem 0; }

.bk-nota {
    background: var(--bk-surface-2);
    border: 1px dashed var(--bk-border);
    border-radius: var(--bk-radius-sm);
    padding: 1rem 1.25rem;
    font-size: .82rem;
    color: var(--bk-muted);
}

.bk-sidebar-rol {
    font-size: .68rem;
    color: rgba(255, 255, 255, .55);
    text-transform: uppercase;
    letter-spacing: .06em;
}

/* --------------------------------------------- Superficies planas --- */

/* Sin sombra ni marco: lo que separa es el aire. Una pantalla llena de
   tarjetas con borde y sombra se lee como un collage; con una sola línea fina
   donde de verdad hay un corte, se lee de un vistazo. */
.bk-bloque-plano {
    background: var(--bk-bg);
    border-radius: var(--bk-radius);
    padding: 1.75rem;
}

.bk-bloque-plano-suelto { padding: 0; overflow: hidden; }

/* Familia de certificados: un encabezado, no una tarjeta. No se administra
   aquí, solo agrupa. */
.bk-familia { margin-bottom: 2.75rem; }

.bk-familia-cuenta {
    font-size: .7rem;
    font-weight: 600;
    letter-spacing: 0;
    color: var(--bk-muted);
    background: var(--bk-surface);
    border-radius: var(--bk-radius-pill);
    padding: .05rem .45rem;
}

/* Resumen de una linea bajo la cabecera: dos cifras, sin caja. */
.bk-resumen-linea {
    margin: -.35rem 0 1.25rem;
    font-size: .85rem;
    color: var(--bk-muted);
}

.bk-resumen-linea strong {
    color: var(--bk-navy);
    font-variant-numeric: tabular-nums;
}

/* ------------------------------------------ Rejilla de formularios --- */

/* Los formularios no llevan un ancho fijo: reparten los campos por el espacio
   que haya. Cada campo pide un mínimo cómodo y la fila se rellena con los que
   quepan, así que la misma marca sirve en un portátil y en un monitor ancho
   sin media queries por pantalla.

   Sustituye a `row` + `col-md-*` de Bootstrap, que reparte en doceavos fijos:
   con doce columnas, un campo «Orden» acaba tan ancho como el de «Nombre» o
   se queda en una franja de 200px según la pantalla. */
/* Dos columnas y no las que quepan.

   Esto era `auto-fit` con un mínimo de 15rem, así que el número de columnas
   dependía del ancho de la ventana: en una pantalla grande salían cinco, un
   campo marcado «doble» ocupaba dos de cinco y cada fila cortaba por un sitio
   distinto. De ahí venía la sensación de desalineado. Con dos columnas fijas,
   una fila es una fila y «doble» quiere decir la fila entera.

   El tope de ancho es aparte: un formulario no se rellena mejor por medir
   1600px, y un campo de correo de esa anchura solo aleja la etiqueta del
   dato. Las tablas y las tarjetas sí siguen ocupando todo. */
.bk-form-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: 1.15rem 1.5rem;
    align-items: start;
    max-width: 64rem;
}

@media (min-width: 48rem) {
    .bk-form-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }

    /* Los dos nombres conviven: `full` se lee mejor en un bloque de casillas
       y `2` en un campo que pide sitio. En dos columnas significan lo mismo. */
    .bk-form-grid > .bk-campo-2 { grid-column: 1 / -1; }
}

/* Ocupa la fila entera: descripciones, avisos y bloques de casillas. */
.bk-form-grid > .bk-campo-full { grid-column: 1 / -1; }

/* Un campo que no debe estirarse aunque le sobre sitio: un selector de color
   de 700px de ancho no es más útil que uno de 120px. */
.bk-form-grid > .bk-campo-corto { max-width: 14rem; }

/* Una ficha corta: un nombre largo y un número de dos cifras.
   Con dos columnas iguales, el número se llevaba media fila y a su derecha
   quedaba el resto en blanco. Aquí la segunda columna mide lo que mide un
   orden y el nombre se queda con todo lo demás. */
@media (min-width: 48rem) {
    .bk-form-grid.es-ficha { grid-template-columns: minmax(0, 1fr) 11rem; }

    /* En esta rejilla `bk-campo-2` deja de significar «toda la fila»: la fila
       ya es un campo ancho y uno estrecho, que es justo lo que se quería. */
    .bk-form-grid.es-ficha > .bk-campo-2 { grid-column: auto; }
}

/* El formulario termina donde termina su contenido.
   La rejilla ya se topaba en 64rem, pero la tarjeta seguía hasta el borde y
   la mitad derecha quedaba vacía: parecía que faltaba algo por poner. Un
   formulario más ancho tampoco se lee mejor —una caja de texto de mil
   píxeles es incómoda—, así que lo que sobra se quita, no se rellena. */
.bk-form-ficha { max-width: 64rem; }

/* Un botón en la rejilla se alinea con la caja de al lado, no con su etiqueta:
   sin esto queda pegado arriba, a la altura del rótulo del campo vecino. */
.bk-form-grid > .bk-campo-boton {
    display: flex;
    align-items: flex-start;
    padding-top: 1.85rem;
}

@media (max-width: 47.98rem) {
    .bk-form-grid > .bk-campo-boton { padding-top: 0; }
}

/* Una casilla no lleva etiqueta encima, así que sin esto flota arriba de la
   fila mientras los campos vecinos empiezan más abajo. */
.bk-form-grid > .align-items-end {
    align-self: end;
    padding-bottom: .45rem;
}

/* Las opciones de sí/no se sacan de la lista de campos y se presentan como
   tarjetas con su explicación: una casilla suelta con una etiqueta corta
   obliga a adivinar qué pasa al marcarla. */
.bk-interruptores {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 18rem), 1fr));
    gap: .75rem;
}

.bk-interruptor {
    display: flex;
    align-items: flex-start;
    gap: .65rem;
    padding: .8rem .95rem;
    border: 1px solid var(--bk-border);
    border-radius: var(--bk-radius-sm);
    cursor: pointer;
    transition: border-color .15s, background .15s;
}

.bk-interruptor:hover { border-color: var(--bk-navy); }
.bk-interruptor:has(input:checked) {
    border-color: var(--bk-navy);
    background: var(--bk-surface-2);
}

.bk-interruptor .form-check-input { margin-top: .15rem; flex: 0 0 auto; }
.bk-interruptor-nombre { display: block; font-weight: 600; font-size: .875rem; }
.bk-interruptor-pie {
    display: block;
    font-size: .75rem;
    color: var(--bk-muted);
    line-height: 1.35;
}
/* Barra de acciones del formulario. La acción de avanzar se separa a la
   derecha: no compite con Guardar, que es lo que se busca por defecto. */
.bk-form-acciones {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .6rem;
    margin-top: 1.25rem;
}

.bk-accion-derecha { margin-left: auto; }

@media (max-width: 575.98px) {
    .bk-accion-derecha { margin-left: 0; }
}

/* ------------------------------------------- Tarjetas de oferta (card) --- */

.bk-rejilla-cards {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 20rem), 1fr));
    gap: 1.25rem;
}

/* En una pantalla con varios grupos, `auto-fit` haría que la misma tarjeta
   midiera cuatro anchos distintos según cuántas tenga cada grupo. Ahí manda la
   consistencia: todas iguales, aunque el último grupo deje hueco. */
.bk-rejilla-cards.is-compacta {
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 19.5rem), 1fr));
}

/* Sin borde y con esquinas muy redondeadas: lo que despega la tarjeta del
   fondo es una sombra difusa y muy baja, no un marco. Veinte tarjetas con
   borde de 1px se leen como una cuadrícula; así respiran.

   En columna y con el cuerpo creciendo, para que en una rejilla todas midan lo
   mismo y los botones queden a la misma altura pase lo que pase con el texto
   de arriba. */
.bk-oferta {
    position: relative;
    display: flex;
    flex-direction: column;
    background: var(--bk-bg);
    border-radius: 24px;
    box-shadow: var(--bk-shadow);
    overflow: hidden;
    text-align: center;
    transition: transform .18s var(--bk-ease), box-shadow .18s var(--bk-ease);
}

.bk-oferta:hover {
    transform: translateY(-3px);
    box-shadow: var(--bk-shadow-lg);
}

/* ---- La banda ---- */

/* Del color de la oferta, con un degradado hacia su tono oscuro. Es lo que
   distingue una tarjeta de otra al recorrer la lista, y el mismo color con el
   que la oferta sale en el sitio. */
.bk-oferta-banda {
    position: relative;
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: .5rem;
    min-height: 5.5rem;
    padding: .85rem 1rem;
    background: linear-gradient(135deg, var(--pc-desde), var(--pc-hasta));
}

/* Las dos esquinas se levantan sobre el enlace que cubre la tarjeta; sin esto
   quedarían debajo y no se podrían pulsar. */
.bk-oferta-estado,
.bk-oferta-borrar {
    position: relative;
    z-index: 2;
    display: flex;
    flex-wrap: wrap;
    gap: .3rem;
}

/* Los distintivos, sobre color. Fondo propio y no transparencia: el color de
   la banda lo pone cada oferta y no se puede garantizar el contraste contra
   algo que todavía no se conoce. */
.bk-oferta-estado .bk-badge {
    background: var(--bk-bg);
    box-shadow: var(--bk-shadow);
}

/* Eliminar, discreto pero legible. En la esquina contraria al estado y sin
   depender del cursor: escondido tras el hover no existe en una tableta. */
/* Fondo propio, no la banda.
   El color de la banda lo elige quien crea la oferta, así que no se puede
   garantizar contraste contra algo que todavía no existe: en blanco sobre el
   amarillo de Linguaskill esto daba 1.6:1, ilegible, y ni un velo oscuro al
   45% llegaba al 4.5 mínimo. Con fondo blanco y `--bk-danger` son 6.6:1 sea cual
   sea el color de detrás, hoy y el día que alguien elija otro. */
.bk-oferta-borrar .btn {
    padding: .18rem .6rem;
    font-size: .68rem;
    font-weight: 700;
    color: var(--bk-danger);
    background: var(--bk-bg);
    border-color: transparent;
    box-shadow: var(--bk-shadow);
}

.bk-oferta-borrar .btn:hover {
    background: var(--bk-danger);
    border-color: transparent;
    color: var(--bk-bg);
}

/* ---- El círculo ---- */

/* A caballo entre la banda y el cuerpo. El margen negativo es la mitad de su
   alto, para que quede repartido exacto a los dos lados. */
.bk-oferta-tile {
    position: relative;
    z-index: 1;
    align-self: center;
    display: grid;
    place-items: center;
    width: 5.5rem;
    height: 5.5rem;
    margin: -2.75rem 0 0;
    border-radius: 50%;
    background: color-mix(in srgb, var(--pc-desde) 22%, var(--bk-bg));
    box-shadow: 0 0 0 6px var(--bk-bg);
    color: color-mix(in srgb, var(--pc-hasta) 72%, var(--bk-navy-900));
    font-weight: 800;
    font-size: 1.35rem;
    letter-spacing: .02em;
    transition: transform .18s var(--bk-ease);
}

.bk-oferta:hover .bk-oferta-tile { transform: scale(1.05); }

.bk-oferta-tile img { max-width: 3rem; max-height: 3rem; object-fit: contain; }

/* ---- El cuerpo ---- */

/* Crece con lo que sobre para que las acciones queden abajo del todo. */
.bk-oferta-cuerpo {
    flex: 1 1 auto;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: .3rem;
    padding: .9rem 1.4rem 1.1rem;
}

.bk-oferta-etiqueta {
    font-size: .66rem;
    font-weight: 700;
    letter-spacing: .09em;
    text-transform: uppercase;
    color: var(--bk-muted);
}

.bk-oferta-titulo {
    margin: 0;
    font-size: 1.3rem;
    font-weight: 700;
    line-height: 1.2;
    color: var(--bk-navy);
}

/* El enlace del título se estira por toda la tarjeta: se sigue pudiendo pulsar
   entera, que es el gesto natural, sin meter los botones dentro de un <a>. */
.bk-oferta-enlace { color: inherit; text-decoration: none; }

.bk-oferta-enlace::after {
    content: '';
    position: absolute;
    inset: 0;
    z-index: 0;
}

.bk-oferta-enlace:hover { color: var(--bk-accent-oscuro, var(--bk-navy)); }

.bk-oferta:focus-within {
    outline: 2px solid var(--bk-accent);
    outline-offset: 2px;
}

.bk-oferta-subtitulo {
    font-size: .8rem;
    color: var(--bk-muted);
}

/* Tres líneas y luego puntos suspensivos. Una descripción larga no puede
   desalinear una tarjeta respecto a la de al lado. */
.bk-oferta-desc {
    margin: .25rem 0 0;
    font-size: .86rem;
    line-height: 1.5;
    color: var(--bk-text);
    display: -webkit-box;
    -webkit-line-clamp: 3;
    line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.bk-oferta-datos {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: .3rem;
    margin-top: .55rem;
}

.bk-oferta-dato {
    padding: .2rem .6rem;
    border-radius: 999px;
    background: var(--bk-surface-2);
    font-size: .72rem;
    font-weight: 600;
    color: var(--bk-muted);
}

/* ---- Las acciones ---- */

.bk-oferta-acciones {
    position: relative;
    z-index: 2;   /* por encima del enlace que cubre la tarjeta */
    display: flex;
    justify-content: center;
    gap: .5rem;
    padding: 0 1.4rem 1.35rem;
}

.bk-oferta-acciones .btn { min-width: 6.5rem; }

.bk-oferta-acciones strong { font-weight: 800; margin-right: .15rem; }

/* Sin fechas cargadas el botón no promete un número que no hay. */
.bk-oferta-acciones .is-vacia { color: var(--bk-muted); }

/* ------------------------------------------------------ Desplegables --- */

/* El <select> real sigue en el DOM: es el que envía el formulario. Se le quita
   de la vista sin `display:none` ni `visibility:hidden`, que en algunos
   navegadores le impedirían recibir el foco al validar un campo obligatorio. */
.bk-sel { position: relative; }

.bk-sel-nativo {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    opacity: 0;
    pointer-events: none;
    appearance: none;
    border: 0;
}

.bk-sel-boton {
    display: flex;
    align-items: center;
    gap: .5rem;
    width: 100%;
    text-align: left;
    cursor: pointer;
    background-image: none;  /* la flecha del `form-select` de Bootstrap */
}

.bk-sel-texto {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.bk-sel-texto.is-vacio { color: var(--bk-muted); }

/* Flecha dibujada con dos bordes: un carácter tipográfico cambia de forma y de
   peso con la fuente que acabe cargando. */
.bk-sel-flecha {
    flex: 0 0 auto;
    width: 7px;
    height: 7px;
    margin-right: .15rem;
    border-right: 2px solid currentColor;
    border-bottom: 2px solid currentColor;
    border-radius: 1px;
    opacity: .45;
    transform: translateY(-2px) rotate(45deg);
    transition: transform var(--bk-rapido) var(--bk-ease), opacity var(--bk-rapido);
}

.bk-sel-boton:hover .bk-sel-flecha { opacity: .8; }
.bk-sel.is-abierto .bk-sel-flecha { transform: translateY(1px) rotate(225deg); opacity: .9; }

.bk-sel-boton:disabled { cursor: not-allowed; color: var(--bk-muted); }
.bk-sel-boton:disabled .bk-sel-flecha { opacity: .2; }

.bk-sel-boton:focus-visible {
    outline: none;
    border-color: var(--bk-accent);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--bk-accent) 18%, transparent);
}

/* La lista cuelga del <body> con posición fija: dentro de la celda se la
   comería el `overflow` de la tabla, que es donde más se usa. */
.bk-sel-lista {
    position: fixed;
    z-index: 80;
    max-height: 16rem;
    overflow-y: auto;
    padding: .3rem;
    background: var(--bk-bg);
    border-radius: 14px;
    box-shadow: 0 2px 8px rgba(46, 70, 99, .08), 0 16px 40px rgba(46, 70, 99, .18);
    animation: bk-subir .14s var(--bk-ease) both;
}

.bk-sel-opcion {
    padding: .45rem .7rem;
    border-radius: 9px;
    font-size: .85rem;
    line-height: 1.35;
    color: var(--bk-text);
    cursor: pointer;
    white-space: nowrap;
}

/* Resaltado y elegido son dos cosas distintas: uno es dónde está el cursor,
   el otro qué hay puesto. Si fueran el mismo color, al recorrer la lista con
   las flechas se perdería de vista cuál era el valor actual. */
.bk-sel-opcion.is-activa { background: var(--bk-surface); }

.bk-sel-opcion[aria-selected="true"] {
    font-weight: 600;
    color: var(--bk-accent);
    background: color-mix(in srgb, var(--bk-accent) 10%, #fff);
}

.bk-sel-opcion.is-activa[aria-selected="true"] {
    background: color-mix(in srgb, var(--bk-accent) 17%, #fff);
}

.bk-sel-opcion[aria-disabled="true"] { color: var(--bk-muted); cursor: not-allowed; }

/* Dentro de la rejilla el control es una celda más: sin marco en reposo. */
.bk-sel-celda .bk-sel-boton { padding: .45rem .5rem; font-size: .85rem; }

/* ---------------------------------------------------------- Contador --- */

/* La cifra que acompaña a una etiqueta —«Niveles 3»—. Va en pastilla y no
   entre paréntesis para que se lea de un vistazo sin competir con el texto. */
.bk-contador {
    font-size: .7rem;
    font-weight: 700;
    background: var(--bk-surface);
    color: var(--bk-muted);
    border-radius: var(--bk-radius-pill);
    padding: .05rem .45rem;
    margin-left: .3rem;
}

/* -------------------------------------------------- Barra de filtros --- */

.bk-filtros {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
    margin-bottom: 1.5rem;
}

.bk-filtro-grupo {
    display: flex;
    align-items: center;
    gap: .4rem;
    flex-wrap: wrap;
}

/* Pastillas y no un desplegable: son cuatro opciones y se cambia de una a
   otra a menudo; un select añadiría dos clics a cada cambio. */
.bk-filtro {
    padding: .35rem .9rem;
    border-radius: var(--bk-radius-pill);
    font-size: .8rem;
    font-weight: 600;
    color: var(--bk-muted);
    text-decoration: none;
    background: var(--bk-bg);
    transition: background .15s, color .15s;
}

.bk-filtro:hover { background: var(--bk-surface); color: var(--bk-navy); }

.bk-filtro.is-activo {
    background: var(--bk-navy);
    color: #fff;
}

.bk-punto-oferta {
    display: inline-block;
    width: 7px;
    height: 7px;
    border-radius: 50%;
    flex: 0 0 auto;
    background: linear-gradient(135deg, var(--pc-desde), var(--pc-hasta));
}

/* Rango de fechas: dos calendarios nativos con su rótulo encima. */
.bk-rango {
    display: flex;
    align-items: flex-end;
    gap: .5rem;
    flex-wrap: wrap;
    margin: 0;
}

.bk-rango-campo {
    display: grid;
    gap: .15rem;
}

.bk-rango-campo > span {
    font-size: .66rem;
    font-weight: 700;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--bk-muted);
}

.bk-rango-campo .form-control { width: 9.5rem; }

/* Los filtros de un listado, sobre su propia tarjeta.
   Sueltos sobre el fondo se leían como un trozo de página sin dueño, y su base
   no casaba con la de la tabla que gobiernan. */
.bk-filtros-panel {
    background: var(--bk-bg);
    border-radius: var(--bk-radius);
    box-shadow: var(--bk-shadow);
    padding: 1rem 1.25rem;
}

/* El campo que se queda con el espacio sobrante.
   Los demás tienen un largo previsible —una fecha, un desplegable de tres
   opciones— y 9.5rem les sobra. Buscar no: ahí se escribe un nombre completo o
   un correo, y en 9.5rem no cabía ni el texto de ayuda, que salía cortado en
   «Nombre, correc».

   La base va en `auto` y no en un ancho: con una base grande, el navegador
   reparte las líneas contando ese ancho y empujaba el botón «Filtrar» a una
   segunda fila él solo. Con `auto` el campo entra en la línea por lo que
   ocupa y crece después, con lo que sobre. */
.bk-rango-crece {
    flex: 1 1 auto;
    min-width: 11rem;
}

.bk-rango-crece .form-control { width: 100%; }

/* ------------------------------------- Registrar un pago a mano --- */

/* Va plegado. Es la excepción —la mayoría de los cobros entran solos por la
   tienda— y desplegado empujaría la tabla, que es a lo que se entra. */
.bk-registro-abrir {
    display: flex;
    align-items: baseline;
    gap: .6rem;
    flex-wrap: wrap;
    padding: 1rem 1.25rem;
    font-weight: 600;
    color: var(--bk-navy);
    cursor: pointer;
    list-style: none;
}

.bk-registro-abrir::-webkit-details-marker { display: none; }

/* La flecha, dibujada aquí para que gire al abrir. Con el triángulo del
   navegador no se puede, y sin ninguna marca no se ve que esto se abre. */
.bk-registro-abrir::before {
    content: '';
    width: .5rem;
    height: .5rem;
    border-right: 2px solid var(--bk-accent);
    border-bottom: 2px solid var(--bk-accent);
    transform: rotate(-45deg);
    transition: transform .18s var(--bk-ease);
}

details[open] > .bk-registro-abrir::before { transform: rotate(45deg); }

.bk-registro-abrir .bk-muted { font-weight: 400; font-size: .78rem; }

.bk-registro-abrir + .bk-card-body { border-top: 1px solid var(--bk-border); }

/* Los campos, en una rejilla que se reparte sola. Con `auto-fit` no hay que
   decidir cuántas columnas caben: se recolocan según el ancho, y en un móvil
   quedan una debajo de otra sin escribir una media consulta. */
.bk-registro {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
    gap: .85rem;
    align-items: end;
}

.bk-registro-campo { display: grid; gap: .15rem; min-width: 0; }

.bk-registro-campo > span {
    font-size: .66rem;
    font-weight: 700;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--bk-muted);
}

/* Un nombre completo o una fecha con su oferta necesitan el doble; unas plazas
   y un importe, la mitad. */
.bk-registro-ancho { grid-column: span 2; }
.bk-registro-corto { grid-column: span 1; }

@media (max-width: 640px) {
    .bk-registro-ancho { grid-column: span 1; }
}

/* La cifra que reclama atención: hay pagos esperando a que alguien los mire. */
.bk-tile-aviso {
    background: color-mix(in srgb, var(--bk-warn) 9%, var(--bk-bg));
    box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--bk-warn) 28%, transparent);
}

/* La cifra, un punto por debajo de `--bk-warn`. El ámbar tal cual se queda en
   4.46:1 sobre su propio fondo lavado, justo por debajo del 4.5 mínimo;
   mezclado al 75% con el navy oscuro sube a 6.03 y sigue saliendo de la
   ficha, no de un hex elegido a ojo. */
.bk-tile-aviso .bk-tile-cifra {
    color: color-mix(in srgb, var(--bk-warn) 75%, var(--bk-navy-900));
}

/* Dinero cobrado. Mismo patrón que el aviso —fondo lavado, filo del propio
   color y la cifra teñida—, con el verde de «esto está bien» en vez del ámbar
   de «esto hay que mirarlo». El verde `--bk-ok` da 4.9:1 sobre su fondo lavado
   y no hace falta oscurecerlo como al ámbar. */
.bk-tile-dinero {
    background: color-mix(in srgb, var(--bk-ok) 8%, var(--bk-bg));
    box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--bk-ok) 26%, transparent);
}
.bk-tile-dinero .bk-tile-cifra { color: color-mix(in srgb, var(--bk-ok) 88%, var(--bk-navy-900)); }

/* Dinero devuelto. En rojo apagado: un reembolso es una cosa normal que hay
   que poder ver, no una avería. */
.bk-tile-devuelto {
    background: color-mix(in srgb, var(--bk-danger) 7%, var(--bk-bg));
    box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--bk-danger) 22%, transparent);
}
.bk-tile-devuelto .bk-tile-cifra { color: color-mix(in srgb, var(--bk-danger) 85%, var(--bk-navy-900)); }

/* Dentro de la tarjeta, el formulario toma todo el ancho. Sin esto se
   encogía a lo que ocupan sus campos y dejaba media tarjeta vacía, con el
   campo que debía crecer sin sitio donde hacerlo. */
.bk-filtros-panel .bk-rango { flex: 1 1 auto; }

/* Buscar crece, pero no sin freno: un campo de sesenta caracteres de ancho
   para escribir un nombre se lee como un error de maquetación. */
.bk-filtros-panel .bk-rango-crece { max-width: 26rem; }

/* Y el botón al extremo, no pegado al último campo: separa lo que se rellena
   de lo que se pulsa.

   Solo el primero se va al extremo. La regla se escribió cuando no había más
   que un botón, y con dos cada uno se llevaba su parte del hueco: «Filtrar» y
   «Descargar» acababan en esquinas distintas, como si no tuvieran nada que
   ver. Van juntos porque son la misma decisión —qué mirar y qué llevarse. */
.bk-rango .btn { margin-left: auto; }
.bk-rango .btn ~ .btn { margin-left: 0; }

/* ------------------------------------------------------------ Agenda --- */

.bk-mes-bloque { margin-bottom: 2rem; }

.bk-mes-titulo {
    display: flex;
    align-items: center;
    gap: .6rem;
    margin: 0 0 .75rem;
    font-size: .78rem;
    font-weight: 700;
    letter-spacing: .09em;
    text-transform: uppercase;
    color: var(--bk-muted);
}

.bk-agenda {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    gap: .5rem;
}

/* Una fila por fecha, no una tabla: las columnas de una tabla obligan a un
   ancho fijo por celda, y aquí lo que pesa —el nombre de la oferta— varía
   mucho. En rejilla cada pieza pide lo que necesita. */
.bk-agenda-fila {
    display: grid;
    grid-template-columns: auto minmax(12rem, 2fr) minmax(8rem, 1fr) auto auto;
    align-items: center;
    gap: 1rem;
    padding: .7rem 1.1rem .7rem .7rem;
    background: var(--bk-bg);
    border-radius: 16px;
    box-shadow: 0 1px 2px rgba(46, 70, 99, .05);
    transition: box-shadow var(--bk-rapido) ease, transform var(--bk-rapido) ease;
}

/* Filo del color de la oferta. Es lo que permite recorrer una lista larga
   buscando «los de certificados» sin leer el rótulo de cada fila. */
.bk-agenda-fila {
    border-left: 3px solid var(--pc-desde, var(--bk-border));
}

.bk-agenda-fila:hover {
    box-shadow: 0 6px 20px color-mix(in srgb, var(--pc-desde, #2e4663) 22%, transparent);
    transform: translateX(2px);
}

.bk-agenda-fila.is-pasada { opacity: .55; }

/* La fecha, como la hojita de un calendario: es el dato por el que se
   recorre la lista, así que es lo que más pesa. */
.bk-agenda-fecha {
    display: grid;
    place-items: center;
    width: 46px;
    height: 46px;
    border-radius: 14px;
    background: color-mix(in srgb, var(--pc-desde, #2e4663) 13%, #fff);
    line-height: 1;
}

.bk-agenda-fecha strong {
    font-size: 1.15rem;
    font-weight: 700;
    color: color-mix(in srgb, var(--pc-desde, #2e4663) 75%, #16232f);
    font-variant-numeric: tabular-nums;
}

.bk-agenda-fecha span {
    font-size: .62rem;
    text-transform: uppercase;
    letter-spacing: .06em;
    color: var(--bk-muted);
}

.bk-agenda-oferta { min-width: 0; }

.bk-agenda-nombre {
    display: block;
    font-size: .92rem;
    font-weight: 600;
    color: var(--bk-navy);
    line-height: 1.3;
    overflow: hidden;
    text-overflow: ellipsis;
}

.bk-agenda-origen {
    display: flex;
    align-items: center;
    gap: .35rem;
    margin-top: .1rem;
    font-size: .74rem;
    color: var(--bk-muted);
}

.bk-agenda-donde {
    display: grid;
    gap: .1rem;
    min-width: 0;
    font-size: .82rem;
}

.bk-agenda-lugar { color: var(--bk-text); }
.bk-agenda-horario { font-size: .74rem; color: var(--bk-muted); }

.bk-agenda-abrir {
    padding: .3rem .85rem;
    border-radius: var(--bk-radius-pill);
    background: var(--bk-surface);
    color: var(--bk-navy);
    font-size: .78rem;
    font-weight: 600;
    text-decoration: none;
    white-space: nowrap;
}

.bk-agenda-abrir:hover { background: var(--bk-lime); color: var(--bk-navy-900); }

/* En estrecho la fila se pliega en dos líneas en vez de comprimir las
   columnas hasta que el nombre deje de leerse. */
@media (max-width: 767.98px) {
    .bk-agenda-fila {
        grid-template-columns: auto 1fr;
        row-gap: .5rem;
    }

    .bk-agenda-donde,
    .bk-agenda-estado,
    .bk-agenda-abrir { grid-column: 2; }

    .bk-agenda-abrir { justify-self: start; }
}

/* ------------------------------------------------ Barra de mes y nivel --- */

.bk-barra-mes {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
    margin-bottom: 1.25rem;
}

.bk-barra-mes-acciones {
    display: flex;
    align-items: center;
    gap: .6rem;
    flex-wrap: wrap;
}

/* Un bloque por nivel dentro de la rejilla. La cabecera es lo que convierte
   una lista larga de fechas en «A2, y debajo lo suyo». */
.bk-bloque-nivel + .bk-bloque-nivel { border-top: 8px solid var(--bk-surface); }

.bk-bloque-cabeza {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 1rem;
    padding: .85rem 1.5rem;
    background: var(--bk-surface-2);
    border-bottom: 1px solid var(--bk-border);
}

.bk-bloque-cabeza h3 {
    margin: 0;
    font-size: .95rem;
    font-weight: 600;
}

.bk-bloque-cuenta {
    font-size: .76rem;
    color: var(--bk-muted);
    font-variant-numeric: tabular-nums;
}

.bk-bloque-vacio {
    margin: 0;
    padding: 1.25rem 1.5rem 0;
    font-size: .82rem;
    color: var(--bk-muted);
}

.bk-bloque-pie { padding: .85rem 1.5rem; }

/* ------------------------------------------------- Rejilla de horarios --- */

.bk-rejilla-scroll { max-height: 68vh; }

.bk-rejilla {
    width: 100%;
    border-collapse: separate;
    border-spacing: 0;
    font-size: .85rem;
}

/* Fondo neutro y una línea del color del módulo debajo.
   Teñir toda la cabecera con el acento daba un beige sucio en Certificados
   —el acento es un verde oliva y al 7% sobre blanco tira a crema—. La línea
   dice lo mismo y no ensucia. */
.bk-rejilla thead th {
    position: sticky;
    top: 0;
    z-index: 2;
    background: var(--bk-surface-2);
    box-shadow: inset 0 -2px 0 color-mix(in srgb, var(--bk-accent) 45%, transparent);
    padding: .75rem .65rem;
    text-align: left;
    font-size: .66rem;
    text-transform: uppercase;
    letter-spacing: .07em;
    color: var(--bk-muted);
    font-weight: 700;
    white-space: nowrap;
}

/* Lo que no puede quedar vacío se dice con el peso del rótulo, no con un
   asterisco rojo: eran doce chinchetas rojas repartidas por la cabecera de
   una tabla que aún está en blanco. Quien se salte uno se entera al guardar,
   con el motivo escrito en su fila. */
.bk-rejilla thead th.is-obligatoria { color: var(--bk-navy); }

/* Una hairline entre columnas: en una tabla de ocho campos por fila, sin
   ellas la vista se pierde de celda en celda. Muy tenue, para que separe sin
   dibujar un enrejado. */
.bk-rejilla thead th + th,
.bk-rejilla tbody td + td { box-shadow: inset 1px 0 0 rgba(46, 70, 99, .05); }

/* Las columnas añadidas desde el panel se distinguen de las fijas: al mirar
   la tabla hay que poder decir qué desaparece si se borra una columna. */
/* Las columnas añadidas desde el panel se distinguen de las fijas por un
   tinte del color del módulo, ahora suave: con la cabecera ya neutra, un 12%
   se leía como una mancha. */
.bk-rejilla thead th.bk-rejilla-anadida {
    color: var(--bk-navy);
    background: color-mix(in srgb, var(--bk-accent) 7%, var(--bk-surface-2));
}

/* -------------------------------------- Columnas desde la cabecera --- */

/* El nombre de una columna añadida se escribe en su sitio. En reposo el campo
   no parece un campo —sin marco, con la misma letra versalita que las demás
   cabeceras—; solo al pasar por encima o al escribir se comporta como tal. */
.bk-col-edicion {
    display: flex;
    align-items: center;
    gap: .15rem;
}

.bk-col-titulo {
    flex: 1 1 auto;
    min-width: 0;
    border: 1px solid transparent;
    border-radius: 7px;
    padding: .1rem .3rem;
    background: transparent;
    font: inherit;
    color: inherit;
    text-transform: inherit;
    letter-spacing: inherit;
}

.bk-col-titulo:hover { border-color: rgba(46, 70, 99, .18); }

.bk-col-titulo:focus {
    outline: none;
    border-color: var(--bk-accent);
    background: #fff;
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--bk-accent) 15%, transparent);
}

.bk-col-ok,
.bk-col-quitar {
    flex: 0 0 auto;
    display: grid;
    place-items: center;
    width: 20px;
    height: 20px;
    padding: 0;
    border: 0;
    border-radius: 6px;
    background: transparent;
    font-size: .9rem;
    line-height: 1;
    cursor: pointer;
}

/* El ✓ solo existe cuando hay algo que guardar; lo enciende el script al
   cambiar el nombre. */
.bk-col-ok {
    display: none;
    color: var(--bk-navy-900);
    background: var(--bk-lime);
}

.bk-col-ok.is-visible { display: grid; }

.bk-col-quitar {
    color: var(--bk-muted);
    opacity: 0;
    transition: opacity var(--bk-rapido), color var(--bk-rapido);
}

/* La × aparece al pasar por la columna: doce columnas con una × permanente
   son doce invitaciones a borrar algo sin querer. */
th:hover > .bk-col-edicion > .bk-col-quitar,
.bk-col-edicion:focus-within > .bk-col-quitar { opacity: 1; }
.bk-col-quitar:hover { color: var(--bk-danger); background: #fdecea; opacity: 1; }

/* Las flechas de orden. Se apagan en reposo y se encienden sobre la columna:
   con nueve columnas hay dieciocho, y encendidas todas a la vez la fila de
   cabeceras se lee como una botonera y no como los nombres de las columnas. */
.bk-col-orden {
    flex: 0 0 auto;
    display: flex;
    gap: 1px;
    opacity: 0;
    transition: opacity var(--bk-rapido);
}

th:hover > .bk-col-edicion > .bk-col-orden,
.bk-col-edicion:focus-within > .bk-col-orden { opacity: 1; }

.bk-col-flecha {
    display: grid;
    place-items: center;
    width: 17px;
    height: 20px;
    padding: 0;
    border: 0;
    border-radius: 5px;
    background: transparent;
    color: var(--bk-muted);
    font-size: 1rem;
    line-height: 1;
    cursor: pointer;
}

.bk-col-flecha:hover {
    color: var(--bk-accent);
    background: color-mix(in srgb, var(--bk-accent) 14%, #fff);
}

.bk-col-flecha[disabled] { opacity: .25; cursor: not-allowed; }
.bk-col-flecha[disabled]:hover { color: var(--bk-muted); background: transparent; }

/* El título de una columna fija no es un campo, pero ocupa el mismo sitio que
   el de una añadida para que las flechas queden a la misma altura en todas. */
.bk-col-fija {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.bk-rejilla-ayuda {
    display: block;
    margin-top: .1rem;
    font-size: .62rem;
    font-weight: 400;
    text-transform: none;
    letter-spacing: 0;
    color: var(--bk-muted);
}

.bk-rejilla tbody td {
    padding: .15rem .3rem;
    border-bottom: 1px solid rgba(46, 70, 99, .06);
    vertical-align: middle;
}

/* Bandas alternas: en una hoja larga son lo que evita saltar de fila al
   recorrerla de izquierda a derecha. */
/* La columna pegada al borde derecho se queda fuera: lleva su propio fondo,
   y sin él se transparentaría al desplazar la tabla. */
.bk-rejilla tbody tr:nth-child(even) > td:not(.bk-rejilla-acciones):not(.bk-rejilla-num) {
    background: rgba(46, 70, 99, .02);
}

.bk-rejilla tbody tr:hover > td:not(.bk-rejilla-acciones):not(.bk-rejilla-num) {
    background: rgba(215, 224, 43, .12);
}

/* La fila en la que se está escribiendo se queda encendida en el color del
   módulo. En una hoja de doce filas y ocho columnas, saber en cuál se está
   sin mirar el cursor es la diferencia entre teclear y buscar. */
.bk-rejilla tbody tr:focus-within > td:not(.bk-rejilla-acciones):not(.bk-rejilla-num) {
    background: color-mix(in srgb, var(--bk-accent) 9%, #fff);
}

/* El número de la fila que se está tocando, encendido: es la contrapartida
   del filo de color de la izquierda. */
.bk-rejilla tbody tr:focus-within > td.bk-rejilla-num {
    color: var(--bk-accent);
    font-weight: 700;
}

.bk-rejilla tbody tr:focus-within > td:first-child {
    box-shadow: inset 3px 0 0 var(--bk-accent);
}

/* La columna de números se queda pegada a la izquierda, igual que la de
   quitar lo está a la derecha: con nueve columnas, al llegar al costo ya no
   se sabía qué fila se estaba tocando. */
.bk-rejilla-num {
    position: sticky;
    left: 0;
    z-index: 1;
    width: 2.75rem;
    text-align: right;
    padding-right: .7rem !important;
    background: var(--bk-surface-2);
    color: var(--bk-muted);
    font-size: .72rem;
    font-variant-numeric: tabular-nums;
}

.bk-rejilla thead th.bk-rejilla-num { z-index: 3; }

/* Una raya a la derecha la separa del área que se escribe: el margen de la
   hoja, no una columna más. */
.bk-rejilla-num { box-shadow: inset -1px 0 0 var(--bk-border); }

/* La columna de quitar se queda pegada al borde derecho mientras la tabla se
   desplaza. Con nueve columnas, la × se iba fuera de la pantalla y había que
   arrastrar hasta el final para marcar una fila. */
.bk-rejilla-acciones {
    position: sticky;
    right: 0;
    z-index: 1;
    width: 2.75rem;
    text-align: center;
}

/* Una celda pegada necesita fondo propio: sin él se ve pasar por debajo lo
   que se desplaza. Por eso queda fuera de las bandas y del resaltado, que
   pintan el fondo de las demás. */
.bk-rejilla tbody td.bk-rejilla-acciones {
    background: var(--bk-bg);
    box-shadow: inset 1px 0 0 rgba(46, 70, 99, .05);
}

.bk-rejilla thead th.bk-rejilla-acciones { z-index: 3; }

/* Celdas sin marco: el marco es la propia rejilla. Un borde por celda sobre
   veinte filas es un enrejado que tapa los datos. */
.bk-celda {
    width: 100%;
    border: 1px solid transparent;
    border-radius: 8px;
    padding: .45rem .5rem;
    font: inherit;
    font-size: .85rem;
    color: var(--bk-text);
    background: transparent;
}

.bk-celda:hover { border-color: rgba(46, 70, 99, .14); }

.bk-celda:focus {
    outline: none;
    border-color: var(--bk-navy);
    background: var(--bk-bg);
    box-shadow: 0 0 0 3px rgba(46, 70, 99, .1);
    position: relative;
    z-index: 1;
}

.bk-celda:disabled { color: var(--bk-muted); }

/* El icono de calendario y el «dd/mm/aaaa» de un campo de fecha vacío pesan
   más que el dato en una tabla con cuatro columnas de fecha. Se atenúan y
   recuperan su tono al pasar por encima o al escribir. */
.bk-celda[type="date"]::-webkit-calendar-picker-indicator,
.bk-celda[type="time"]::-webkit-calendar-picker-indicator {
    opacity: .35;
    cursor: pointer;
    transition: opacity .15s;
}

.bk-celda[type="date"]:hover::-webkit-calendar-picker-indicator,
.bk-celda[type="time"]:hover::-webkit-calendar-picker-indicator,
.bk-celda[type="date"]:focus::-webkit-calendar-picker-indicator,
.bk-celda[type="time"]:focus::-webkit-calendar-picker-indicator { opacity: .9; }

.bk-celda[type="date"]:not(:focus)::-webkit-datetime-edit,
.bk-celda[type="time"]:not(:focus)::-webkit-datetime-edit { color: var(--bk-text); }

/* El desplegable lleva su punta: sin ella parece texto normal y nadie
   descubre que se puede cambiar. */
select.bk-celda {
    appearance: none;
    cursor: pointer;
    padding-right: 1.6rem;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 6'%3E%3Cpath fill='%2364748b' d='M0 0h10L5 6z'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right .55rem center;
    background-size: 8px 5px;
}

/* Fila rechazada: se marca sin borrarla, para poder corregirla en el sitio.
   El motivo va debajo, a todo lo ancho: en una celda no cabría. */
.bk-rejilla-fila.is-invalida > td { background: #fdf3f2; }

.bk-rejilla-fila.is-invalida .bk-celda:not(:focus) {
    border-color: rgba(180, 35, 24, .35);
}

.bk-rejilla-error > td {
    padding: .3rem .75rem .55rem 3.4rem !important;
    background: #fdf3f2;
    font-size: .76rem;
    font-weight: 600;
    color: var(--bk-danger);
    box-shadow: none !important;
}

.bk-rejilla-fila.is-quitada {
    opacity: .45;
    text-decoration: line-through;
}

.bk-quitar {
    cursor: pointer;
    color: var(--bk-border);
    font-size: 1.05rem;
    line-height: 1;
    display: inline-grid;
    place-items: center;
    width: 26px;
    height: 26px;
    border-radius: 50%;
    transition: background .15s, color .15s;
}

.bk-rejilla-fila:hover .bk-quitar { color: var(--bk-muted); }
.bk-quitar:hover { background: #fdecea; color: var(--bk-danger) !important; }
.bk-quitar input { position: absolute; opacity: 0; width: 0; height: 0; }
.bk-quitar:has(input:checked) { background: #fdecea; color: var(--bk-danger) !important; }

.bk-rejilla-pie {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
    padding: 1rem 1.5rem;
    border-top: 1px solid var(--bk-border);
    background: var(--bk-surface-2);
}

.bk-bloque-pie {
    padding: .8rem 1.5rem;
    border-top: 1px solid rgba(46, 70, 99, .06);
}

/* ------------------------------------------------------ Cajón lateral --- */

.bk-panel-lateral {
    position: fixed;
    top: 0;
    right: 0;
    z-index: 60;
    width: min(29rem, 100vw);
    height: 100vh;
    background: var(--bk-bg);
    box-shadow: -12px 0 48px rgba(16, 25, 36, .22);
    display: flex;
    flex-direction: column;

    /* Entra deslizando desde el borde. Que venga de la derecha dice de dónde
       salió y por dónde se va, y hace obvio que la tabla sigue detrás. */
    animation: bk-cajon var(--bk-normal) var(--bk-ease) both;
}

.bk-panel-lateral-cabeza { background: color-mix(in srgb, var(--bk-accent) 6%, #fff); }

.bk-panel-lateral-cabeza {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 1rem;
    padding: 1.25rem 1.5rem;
    border-bottom: 1px solid var(--bk-border);
    color: var(--bk-navy);
}

.bk-panel-lateral-cuerpo {
    padding: 1.5rem;
    overflow-y: auto;
}

.bk-cerrar {
    border: 0;
    background: transparent;
    font-size: 1.5rem;
    line-height: 1;
    color: var(--bk-muted);
    cursor: pointer;
}

.bk-cerrar:hover { color: var(--bk-navy); }

.bk-columnas-lista {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    gap: 1rem;
}

.bk-columnas-lista li {
    padding-bottom: 1rem;
    border-bottom: 1px solid var(--bk-border);
}

.bk-columnas-lista li:last-child { border-bottom: 0; padding-bottom: 0; }

.bk-columnas-orden {
    display: flex;
    align-items: center;
    gap: .75rem;
    margin-top: .4rem;
    font-size: .72rem;
}

.bk-columnas-orden .bk-mono { margin-right: auto; }
.bk-link-btn[disabled] { opacity: .3; cursor: not-allowed; }

/* ------------------------------------------------ Catálogo de niveles --- */

/* Cada nivel es una ficha, no una fila de formulario. Dentro del cajón, tres
   campos con su botón y sus flechas en línea se leían como un formulario de
   tres partes; agrupados en bloques con fondo propio se leen como tres cosas
   de la misma clase, que es lo que son. */
.bk-niveles {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    gap: .5rem;
}

.bk-nivel {
    background: var(--bk-surface-2);
    border: 1px solid transparent;
    border-radius: 14px;
    padding: .6rem .65rem .5rem;
    transition: background var(--bk-rapido), border-color var(--bk-rapido);
}

.bk-nivel:hover,
.bk-nivel:focus-within {
    background: #fff;
    border-color: var(--bk-border);
}

.bk-nivel-cuerpo {
    display: flex;
    align-items: center;
    gap: .5rem;
    margin: 0;
}

.bk-nivel-cuerpo .form-control {
    flex: 1 1 auto;
    min-width: 0;
    background: #fff;
}

/* Guardar apagado hasta que la ficha se toca: tres botones encendidos a la
   vez dicen que hay tres cambios pendientes cuando no hay ninguno. Sin
   JavaScript se queda visible, que es el comportamiento correcto. */
.bk-nivel-guardar {
    flex: 0 0 auto;
    opacity: .5;
    transition: opacity var(--bk-rapido);
}

.bk-nivel:hover .bk-nivel-guardar { opacity: .75; }

.bk-nivel.is-tocada .bk-nivel-guardar {
    opacity: 1;
    background: var(--bk-lime);
    border-color: var(--bk-lime);
    color: var(--bk-navy-900);
}

/* Pie de la ficha: el recuento a la izquierda, lo que se puede hacer con
   ella a la derecha. Las acciones se aclaran al pasar por encima; en reposo
   son cuatro controles idénticos por nivel compitiendo con el nombre. */
.bk-nivel-pie {
    display: flex;
    align-items: center;
    gap: .75rem;
    margin-top: .4rem;
    padding: 0 .15rem;
    font-size: .72rem;
    color: var(--bk-muted);
}

.bk-nivel-fechas {
    margin-right: auto;
    font-variant-numeric: tabular-nums;
}

.bk-nivel-pie .bk-link-btn {
    opacity: .6;
    transition: opacity var(--bk-rapido);
}

.bk-nivel:hover .bk-nivel-pie .bk-link-btn,
.bk-nivel:focus-within .bk-nivel-pie .bk-link-btn { opacity: 1; }
.bk-nivel-pie .bk-link-btn:focus-visible { opacity: 1; }
.bk-nivel-pie .bk-link-btn[disabled] { opacity: .15; }

/* La apariencia de un nivel: una muestra de cómo saldrá, su color y su
   icono. Va en su propia línea porque es otro trabajo que el de nombrarlo. */
/* Bloque y no flex: dentro hay una fila de controles y debajo la cuadrícula
   del catálogo. Como elemento flexible, la cuadrícula se encogía a su ancho
   mínimo y los iconos salían en una sola columna. */
.bk-nivel-sitio {
    margin: .5rem 0 0;
    padding-top: .5rem;
    border-top: 1px dashed var(--bk-border);
}

.bk-nivel-sitio-fila {
    display: flex;
    align-items: center;
    gap: .5rem;
    margin-bottom: .45rem;
}

.bk-nivel-sitio-fila .bk-muted { margin-right: auto; }

.bk-color-mini { width: 34px; height: 30px; padding: 2px; }

/* El catálogo: cada icono ya teñido con el color del nivel, así que lo que se
   elige es lo que se verá y no hay que imaginárselo. */
.bk-iconos {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(34px, 1fr));
    gap: .3rem;
}

.bk-icono-op input {
    position: absolute;
    opacity: 0;
    width: 0;
    height: 0;
}

.bk-icono-caja {
    display: grid;
    place-items: center;
    height: 34px;
    border-radius: 10px;
    border: 1px solid transparent;
    background: color-mix(in srgb, var(--nivel) 12%, #fff);
    color: color-mix(in srgb, var(--nivel) 72%, #16232f);
    cursor: pointer;
    transition: border-color var(--bk-rapido), transform var(--bk-rapido);
}

.bk-icono-caja svg { width: 17px; height: 17px; fill: currentColor; }
.bk-icono-nada { color: var(--bk-muted); background: var(--bk-surface); font-size: .8rem; }

.bk-icono-op:hover .bk-icono-caja { transform: translateY(-1px); }

.bk-icono-op input:checked + .bk-icono-caja {
    border-color: color-mix(in srgb, var(--nivel) 70%, transparent);
    box-shadow: 0 0 0 2px color-mix(in srgb, var(--nivel) 22%, transparent);
}

.bk-icono-op input:focus-visible + .bk-icono-caja {
    border-color: var(--bk-accent);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--bk-accent) 25%, transparent);
}

/* Interruptor de «Ofertable».

   Un interruptor y no una casilla con la palabra al lado: la palabra ocupaba
   un tercio del ancho de la ficha para decir algo que la posición ya dice, y
   el estado se lee de un vistazo en una lista de ocho niveles. El nombre
   sigue ahí para quien navegue por lector de pantalla. */
.bk-conmutador {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    cursor: pointer;
}

.bk-conmutador input {
    position: absolute;
    opacity: 0;
    width: 0;
    height: 0;
}

.bk-conmutador-pista {
    display: block;
    position: relative;
    width: 36px;
    height: 20px;
    border-radius: 999px;
    background: #cfd7e0;
    transition: background var(--bk-rapido);
}

.bk-conmutador-pista::after {
    content: '';
    position: absolute;
    top: 2px;
    left: 2px;
    width: 16px;
    height: 16px;
    border-radius: 50%;
    background: #fff;
    box-shadow: 0 1px 3px rgba(16, 25, 36, .3);
    transition: transform var(--bk-normal) var(--bk-ease);
}

.bk-conmutador input:checked + .bk-conmutador-pista { background: var(--bk-accent); }
.bk-conmutador input:checked + .bk-conmutador-pista::after { transform: translateX(16px); }

.bk-conmutador input:focus-visible + .bk-conmutador-pista {
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--bk-accent) 25%, transparent);
}

/* ------------------------------------------------------- Diálogo --- */

/* Sustituye a `window.confirm`, que dibuja el navegador y sale con el nombre
   del servidor arriba. Se usa <dialog> y no un div: trae hechos el cierre con
   Escape, el foco atrapado dentro y la devolución del foco al salir. */
.bk-dialogo {
    width: min(26rem, calc(100vw - 2rem));
    padding: 1.5rem;
    border: 0;
    border-radius: var(--bk-radius);
    box-shadow: var(--bk-shadow-lg);
    background: var(--bk-bg);
    color: var(--bk-text);
}

.bk-dialogo::backdrop {
    background: rgba(16, 25, 36, .45);
    backdrop-filter: blur(3px);
}

.bk-dialogo[open] { animation: bk-subir .18s var(--bk-ease) both; }

.bk-dialogo-titulo {
    margin: 0 0 .5rem;
    font-size: 1.1rem;
    font-weight: 600;
    color: var(--bk-navy);
}

.bk-dialogo-texto {
    margin: 0 0 1.4rem;
    font-size: .875rem;
    line-height: 1.55;
    color: var(--bk-muted);
}

.bk-dialogo-pie {
    display: flex;
    justify-content: flex-end;
    gap: .6rem;
}

/* Un diálogo con un formulario dentro, no con una pregunta. Los 26rem de una
   confirmación dejarían el nombre de una oferta en una caja de dos palabras.
   Y con tope de alto: en una pantalla baja, o en un convenio —que lleva más
   campos—, el pie con «Guardar» tiene que seguir alcanzable. */
.bk-dialogo-ancho {
    width: min(46rem, calc(100vw - 2rem));
    max-height: calc(100vh - 3rem);
    padding: 1.35rem 1.5rem 1.5rem;
    overflow: auto;
}

.bk-dialogo-cabeza {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 1rem;
    margin-bottom: 1.1rem;
}

.bk-dialogo-cabeza .bk-dialogo-titulo { margin: 0; }

.bk-dialogo-ancho .bk-dialogo-pie {
    margin-top: 1.35rem;
    padding-top: 1.1rem;
    border-top: 1px solid var(--bk-border);
}

/* El botón que borra va en rojo lleno. En `window.confirm` los dos botones
   pesan lo mismo aunque uno de ellos borre datos. */
.btn-bk-peligro {
    background: var(--bk-danger);
    color: #fff;
    box-shadow: 0 2px 10px rgba(180, 35, 24, .28);
}

.btn-bk-peligro:hover {
    background: #96190f;
    color: #fff;
    box-shadow: 0 5px 18px rgba(180, 35, 24, .38);
}

/* ------------------------------------------------------ Clave nueva --- */

/* La clave recién generada. Es lo único de todo el panel que solo existe en
   esta pantalla y esta vez —en la base va su huella, no ella—, así que ocupa
   su propio bloque en lima y no un aviso más de los de siempre. */
.bk-clave-nueva {
    background: color-mix(in srgb, var(--bk-lime) 16%, #fff);
    border-left: 4px solid var(--bk-lime);
    border-radius: var(--bk-radius-sm);
    padding: 1.1rem 1.25rem;
    margin-bottom: 1.5rem;
}

.bk-clave-nueva-cabeza {
    display: flex;
    align-items: baseline;
    gap: .75rem;
    flex-wrap: wrap;
    margin-bottom: .7rem;
    color: var(--bk-navy);
    font-size: .875rem;
}

.bk-clave-nueva-cabeza .bk-muted { font-size: .8rem; }

.bk-clave-caja {
    display: flex;
    gap: .5rem;
    max-width: 44rem;
}

.bk-clave-caja .form-control { background: #fff; }

/* ------------------------------------------------- Cómo se ve fuera --- */

/* El lienzo: la tabla y su vista previa comparten sitio y se turnan. Ver las
   dos a la vez era leer lo mismo dos veces y una pantalla el doble de larga. */
/* El lienzo ya no es el recuadro: es el trozo de pantalla que se turna entre
   editar y ver. Lo blanco es la caja de dentro, y la barra queda fuera. */
.bk-lienzo { display: block; }

.bk-lienzo-caja {
    background: var(--bk-bg);
    border-radius: var(--bk-radius);
    box-shadow: var(--bk-shadow);
    overflow: hidden;
}

/* La barra, sobre el fondo de la página y no dentro de la caja. Dentro parecía
   una fila más de la tabla y le robaba su primera línea. */
.bk-lienzo-cabeza {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
    margin-bottom: .85rem;
    padding: 0;
    background: transparent;
    border: 0;
}

.bk-lienzo-acciones {
    display: flex;
    align-items: center;
    gap: .6rem;
    flex-wrap: wrap;
}

/* ---- Botón de icono y menú de acciones ---- */

/* Un cuadrado con el icono dentro. Del tamaño de las pastillas de al lado para
   que la barra no quede escalonada. */
.bk-ico-btn {
    display: grid;
    place-items: center;
    width: 2.15rem;
    height: 2.15rem;
    padding: 0;
    border: 1px solid var(--bk-border);
    border-radius: var(--bk-radius-pill);
    background: var(--bk-bg);
    color: var(--bk-navy);
    cursor: pointer;
    transition: background var(--bk-rapido) var(--bk-ease),
                color var(--bk-rapido) var(--bk-ease),
                border-color var(--bk-rapido) var(--bk-ease);
}

.bk-ico-btn:hover,
.bk-ico-btn[aria-expanded="true"] {
    background: color-mix(in srgb, var(--bk-accent) 8%, var(--bk-bg));
    border-color: color-mix(in srgb, var(--bk-accent) 35%, transparent);
    color: var(--bk-accent);
}

/* La rueda gira al abrirse: dice que el botón hizo algo, sin necesidad de una
   flecha aparte que ocuparía sitio en un botón de 34 píxeles. */
.bk-ico-btn svg { transition: transform var(--bk-normal) var(--bk-ease); }
.bk-ico-btn[aria-expanded="true"] svg { transform: rotate(60deg); }

.bk-ico { width: 16px; height: 16px; fill: currentColor; flex: 0 0 auto; }

.bk-menu { position: relative; }

/* Anclado a la derecha del botón: abierto hacia la izquierda no se sale de la
   pantalla, que es de donde se saldría si creciera hacia fuera. */
.bk-menu-lista {
    position: absolute;
    top: calc(100% + .4rem);
    right: 0;
    z-index: 30;
    min-width: 14rem;
    padding: .35rem;
    background: var(--bk-bg);
    border-radius: var(--bk-radius-sm);
    box-shadow: var(--bk-shadow-lg);
    animation: bk-menu-entra .16s var(--bk-ease);
}

@keyframes bk-menu-entra {
    from { opacity: 0; transform: translateY(-4px); }
    to   { opacity: 1; transform: none; }
}

.bk-menu-lista > button,
.bk-menu-lista > a {
    display: flex;
    align-items: center;
    gap: .6rem;
    width: 100%;
    padding: .5rem .65rem;
    border: 0;
    border-radius: var(--bk-radius-sm);
    background: transparent;
    color: var(--bk-text);
    font: inherit;
    font-size: .86rem;
    text-align: left;
    text-decoration: none;
    cursor: pointer;
}

.bk-menu-lista > button:hover,
.bk-menu-lista > a:hover,
.bk-menu-lista > button:focus-visible,
.bk-menu-lista > a:focus-visible {
    background: color-mix(in srgb, var(--bk-accent) 8%, var(--bk-bg));
    color: var(--bk-accent);
    outline: none;
}

.bk-menu-lista .bk-ico { color: var(--bk-muted); }

.bk-menu-lista > button:hover .bk-ico,
.bk-menu-lista > a:hover .bk-ico { color: inherit; }

/* El contador empujado al final: la cifra se lee en columna con las demás. */
.bk-menu-lista .bk-contador { margin-left: auto; }


/* Dos pastillas y no dos pestañas subrayadas: aquí no se cambia de pantalla,
   se cambia de manera de mirar la misma. */
.bk-vistas {
    display: inline-flex;
    gap: .2rem;
    padding: .2rem;
    background: var(--bk-surface);
    border-radius: var(--bk-radius-pill);
}

.bk-vista {
    display: inline-flex;
    align-items: center;
    gap: .4rem;
    padding: .4rem 1rem;
    border: 0;
    border-radius: var(--bk-radius-pill);
    background: transparent;
    color: var(--bk-muted);
    font-size: .84rem;
    font-weight: 600;
    cursor: pointer;
    transition: background var(--bk-rapido), color var(--bk-rapido);
}

.bk-vista:hover { color: var(--bk-navy); }

.bk-vista.is-activa {
    background: var(--bk-bg);
    color: var(--bk-navy);
    box-shadow: 0 1px 3px rgba(46, 70, 99, .12);
}

.bk-vista.is-activa .bk-contador { background: var(--bk-surface); }

/* La vista previa manda y los controles la acompañan: el ancho fijo de la
   derecha es el de un formulario corto, no la mitad de la pantalla. */
/* A todo lo ancho. Antes había un panel de mandos de 19rem al lado y la tabla
   del sitio se cortaba en la columna de inscribirse; y como el panel era más
   alto que la tabla, debajo de esta quedaba media pantalla en blanco. Los
   mandos se abren ahora desde la rueda. */
.bk-sitio-cuerpo { display: block; }

/* El fondo de una página del sitio, con sus esquinas. Sin él, la tarjeta
   blanca del bloque cae sobre el blanco del panel y no se ve dónde empieza. */
.bk-marco-sitio {
    padding: 1.75rem;
    background: var(--bk-canvas);
    border-radius: var(--bk-radius);
    overflow-x: auto;
}

.bk-color {
    width: 100%;
    height: 40px;
    padding: 3px;
    border: 1px solid var(--bk-border);
    border-radius: var(--bk-radius-sm);
    background: #fff;
    cursor: pointer;
}

/* Opciones en fila, con su explicación: «Plano» a secas no dice cuándo usarlo,
   y la frase corta evita tener que probar los dos para averiguarlo. */
.bk-opciones {
    border: 0;
    padding: 0;
    margin: 0 0 1.25rem;
}

.bk-opcion {
    display: flex;
    align-items: flex-start;
    gap: .55rem;
    padding: .55rem .65rem;
    border: 1px solid transparent;
    border-radius: var(--bk-radius-sm);
    cursor: pointer;
    transition: background var(--bk-rapido), border-color var(--bk-rapido);
}

.bk-opcion:hover { background: #fff; }

.bk-opcion:has(input:checked) {
    background: #fff;
    border-color: color-mix(in srgb, var(--bk-accent) 40%, transparent);
}

.bk-opcion input { margin-top: .2rem; flex: 0 0 auto; accent-color: var(--bk-accent); }
.bk-opcion-nombre { display: block; font-size: .85rem; font-weight: 600; color: var(--bk-navy); }
.bk-opcion-pie { display: block; font-size: .74rem; line-height: 1.4; color: var(--bk-muted); }

/* ------------------------------------------------- Código para copiar --- */

/* Un trozo de código que se copia entero. Va en un <textarea> y no en un
   campo de una línea: lo que hay que reconocer —el slug de la oferta— está al
   final, y en una línea se queda justo fuera del borde. El botón debajo y a
   la derecha, donde acaba de leerse. */
.bk-codigo {
    display: grid;
    justify-items: end;
    gap: .4rem;
}

.bk-codigo-texto {
    width: 100%;
    resize: none;
    padding: .6rem .75rem;
    border: 1px solid var(--bk-border);
    border-radius: var(--bk-radius-sm);
    background: var(--bk-surface-2);
    color: var(--bk-navy-700);
    font-size: .78rem;
    line-height: 1.5;
}

.bk-codigo-texto:focus {
    outline: none;
    border-color: var(--bk-accent);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--bk-accent) 18%, transparent);
}

/* Acuse de copiado en el propio botón: se pone en lima y vuelve solo. */
.btn.is-hecho {
    background: var(--bk-lime);
    border-color: var(--bk-lime);
    color: var(--bk-navy-900);
}

/* Las acciones de una fila de tabla, siempre en la misma línea y al mismo
   sitio: sueltas, cada formulario se colocaba por su cuenta y los botones de
   dos filas seguidas no coincidían. */
.bk-fila-acciones {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: .9rem;
    flex-wrap: nowrap;
    white-space: nowrap;
}

/* --------------------------------------------- Matriz de permisos --- */

/* La vista de conjunto: quince columnas, así que las cabeceras van abreviadas
   y el nombre completo en el `title`. */
.bk-matriz-modulo {
    border-left: 1px solid var(--bk-border);
    font-size: .68rem !important;
}

.bk-matriz-accion {
    font-size: .6rem !important;
    letter-spacing: .04em !important;
    padding-left: .3rem !important;
    padding-right: .3rem !important;
}

.bk-matriz-celda { padding: .5rem .3rem !important; }

/* El «no» es una raya tenue y no un hueco: una celda vacía se confunde con
   una columna que no existe, y con quince seguidas hace falta ver que ahí
   había algo que decir. Tenue, pero visible. */
.bk-marca {
    color: rgba(46, 70, 99, .28);
    font-size: .8rem;
    cursor: default;
}

.bk-marca.is-si { font-size: .7rem; }

.bk-marca-cursos       { color: var(--viz-cursos); }
.bk-marca-certificados { color: var(--viz-certificados); }
.bk-marca-convenios    { color: var(--viz-convenios); }

.bk-permisos-persona {
    display: flex;
    align-items: center;
    gap: .55rem;
    text-decoration: none;
    color: inherit;
}

.bk-permisos-persona:hover .fw-semibold { color: var(--bk-navy); text-decoration: underline; }
.bk-fila-apagada { opacity: .55; }

.bk-matriz th[scope="row"] { font-weight: 400; }
.bk-matriz td { vertical-align: middle; }
.bk-matriz .form-check-input { margin: 0; cursor: pointer; }

/* La matriz que se edita: el módulo se lleva un tercio y las acciones se
   reparten el resto por igual. Sin `fixed`, cada columna medía lo que medía
   su título —«Planificar horarios» contra «Ver»— y las casillas quedaban a
   distancias distintas, que es lo que se veía torcido. */
.bk-matriz-edicion { table-layout: fixed; }
.bk-matriz-edicion th:first-child { width: 26%; }
.bk-matriz-edicion th:last-child  { width: 5.5rem; }

/* Con el ancho repartido, un título largo como «Planificar horarios» ya no
   cabe en una línea: se le deja partir en vez de salirse encima del vecino. */
.bk-matriz-edicion thead th {
    white-space: normal;
    line-height: 1.25;
    vertical-align: bottom;
}

.bk-matriz-edicion tbody tr:hover > * { background: var(--bk-surface-2); }

/* Toda la celda es zona de pulsación, no los 16px de la casilla: en una
   cuadrícula de quince, apuntar al cuadradito es trabajo. */
.bk-matriz-edicion tbody td { padding: 0; }

.bk-matriz-casilla-zona {
    display: grid;
    place-items: center;
    padding: .9rem 0;
    cursor: pointer;
}

.bk-matriz-casilla-zona:hover { background: color-mix(in srgb, var(--bk-accent) 7%, transparent); }

/* La última celda no lleva casilla, así que recupera el relleno que se le
   quitó a las demás para que la zona de pulsación llegue al borde. */
.bk-matriz-edicion tbody td:last-child { padding: .9rem 0; }

/* La raya que separa un módulo del siguiente baja también por el cuerpo: sin
   ella, quince columnas de puntos son una sola mancha y hay que contar de
   cinco en cinco para saber de qué módulo es cada una. */
.bk-matriz-grupo { box-shadow: inset 1px 0 0 var(--bk-border); }

.bk-permisos-resumen {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    gap: .3rem;
    font-size: .78rem;
}

.bk-permisos-resumen li {
    display: flex;
    align-items: center;
    gap: .5rem;
    flex-wrap: wrap;
}

/* --------------------------------------------------------- Responsive --- */

@media (max-width: 991px) {
    .bk-app { display: block; }

    .bk-sidebar {
        position: fixed;
        top: 0;
        left: 0;
        z-index: 50;
        transform: translateX(-100%);
        transition: transform .2s ease;
    }

    .bk-sidebar.is-open { transform: translateX(0); }

    .bk-mobilebar { display: flex; }
    .bk-contenido { padding: 1.25rem 1rem; }

    /* En móvil el menú ya es un cajón que se abre y se cierra: comprimirlo no
       gana espacio y dejaría un cajón de iconos sin nombres. Se ignora la
       preferencia y se muestra entero. */
    .bk-comprimido .bk-sidebar {
        width: var(--bk-sidebar-w);
        flex-basis: var(--bk-sidebar-w);
    }

    .bk-comprimido .bk-brand-text,
    .bk-comprimido .bk-menu a span,
    .bk-comprimido .bk-sidebar-usuario span,
    .bk-comprimido .bk-salir-texto { display: inline; }

    .bk-comprimido .bk-brand { justify-content: flex-start; }
    .bk-comprimido .bk-menu a { justify-content: flex-start; padding: .6rem .65rem; }
    .bk-comprimido .bk-sidebar-usuario { justify-content: flex-start; }
    .bk-comprimido .bk-salir-icono { display: none; }

    .bk-comprimido .bk-sidebar-cabeza {
        flex-direction: row;
        padding: 1.35rem 1.25rem;
    }

    /* El plegado no se ofrece en móvil: el menú ya es un cajón que se abre y
       se cierra, y estrecharlo no gana nada. */
    .bk-comprimir { display: none; }

    .bk-comprimido .bk-menu-grupo {
        height: auto;
        margin: 0 0 .4rem;
        padding: 0 .6rem;
        text-indent: 0;
        background: transparent;
        overflow: visible;
    }

    .bk-table thead th,
    .bk-table tbody td { padding-left: 1rem; padding-right: 1rem; }
}

/* El fondo del menú móvil no pinta nada en escritorio, donde el menú está
   siempre desplegado. Va por id y no por clase: el cajón lateral usa la misma
   clase para su propio fondo y ese sí hace falta —es lo que se pulsa para
   cerrarlo—. Cuando esto decía `.bk-overlay`, el cajón se abría sin fondo y
   solo se podía cerrar con la × o con Escape. */
@media (min-width: 992px) {
    #bk-overlay { display: none; }
}

/* ========================================================================
   Movimiento

   Todo el movimiento del panel está aquí junto, y todo se apaga de golpe si
   el sistema pide menos animación. Son entradas cortas y de una sola
   propiedad compuesta —opacidad y desplazamiento—: lo justo para que algo
   que aparece parezca que llega, sin que haya que esperarlo.
   ======================================================================== */

@keyframes bk-subir {
    from { opacity: 0; transform: translateY(10px); }
    to   { opacity: 1; transform: none; }
}

@keyframes bk-aparecer {
    from { opacity: 0; }
    to   { opacity: 1; }
}

@keyframes bk-cajon {
    from { transform: translateX(100%); }
    to   { transform: none; }
}

/* Las tarjetas entran escalonadas. El retardo se corta a la sexta: pasada
   esa, esperar a que aparezca la número veinte deja de ser una entrada y
   empieza a ser una espera. */
.bk-oferta,
.bk-tile {
    /* `backwards` y no `both`.
       Con `both`, la animación conserva su fotograma final para siempre, y ese
       fotograma fija `transform: none`, que le gana al levantamiento del hover.
       Para esquivarlo se cancelaba la animación al pasar el ratón, y ahí venía
       el fallo: al salir, la animación volvía a dispararse desde cero y la
       tarjeta desaparecía y reaparecía.
       Con `backwards` solo se adelanta el primer fotograma durante el retardo
       —que es lo único que hace falta para que no parpadee al cargar— y en
       cuanto termina manda el CSS normal, hover incluido. */
    animation: bk-subir .42s var(--bk-ease) backwards;
}

.bk-oferta:nth-child(1), .bk-tile:nth-child(1) { animation-delay: 0s; }
.bk-oferta:nth-child(2), .bk-tile:nth-child(2) { animation-delay: .04s; }
.bk-oferta:nth-child(3), .bk-tile:nth-child(3) { animation-delay: .08s; }
.bk-oferta:nth-child(4), .bk-tile:nth-child(4) { animation-delay: .12s; }
.bk-oferta:nth-child(5), .bk-tile:nth-child(5) { animation-delay: .16s; }
.bk-oferta:nth-child(n+6), .bk-tile:nth-child(n+6) { animation-delay: .2s; }

.bk-alert { animation: bk-subir .3s var(--bk-ease) backwards; }

@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: .001ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: .001ms !important;
        scroll-behavior: auto !important;
    }
}
/* Aprobar y rechazar, bajo el estado que cambian. En vertical y con letra
   pequeña: son dos acciones dentro de una celda de tabla, no una barra de
   herramientas. */
.bk-decidir {
    display: flex;
    flex-direction: column;
    gap: .3rem;
    margin-top: .45rem;
}

/* --- Los datos del inscrito -------------------------------------------------
   Teléfono, sexo, nacimiento y dirección, en fila y a la vista. Cada uno lleva
   su etiqueta dentro porque cuatro valores sueltos —un número, una palabra, una
   fecha, una calle— no dicen cuál es cuál en una fila a la que le falte alguno.

   El color sale de `--bk-accent`, que la fila hereda de su módulo: los datos de
   un curso salen en el azul de Cursos y los de un certificado en su verde. Sin
   módulo, `--bk-accent` cae al de la marca y siguen legibles. */
.bk-datos-fila {
    display: flex;
    flex-wrap: wrap;
    gap: .25rem;
    margin-top: .4rem;
}

.bk-dato {
    display: inline-flex;
    align-items: baseline;
    gap: .25rem;
    max-width: 100%;
    padding: .14rem .42rem;
    border-radius: .45rem;
    background: color-mix(in srgb, var(--bk-accent) 9%, #fff);
    border: 1px solid color-mix(in srgb, var(--bk-accent) 18%, #fff);
    font-size: .69rem;
    line-height: 1.3;
}

.bk-dato-que {
    flex: none;
    font-size: .57rem;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
    /* Al 60% por lo mismo que el distintivo: con más color, el verde de
       Certificados no llega a 4.5:1 sobre su fondo. Peor caso, 5.17:1. */
    color: color-mix(in srgb, var(--bk-accent) 60%, var(--bk-text));
}

.bk-dato-valor {
    color: var(--bk-text);
    font-weight: 500;
    /* Una dirección larga se corta con puntos suspensivos en vez de ensanchar
       la columna: el valor entero sigue estando en el archivo descargado. */
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* El filo de color del módulo, en la primera celda. Tres píxeles dicen de qué
   es cada cobro sin gastar una columna: el mismo color que ese módulo lleva en
   el dashboard y en los gráficos. */
.bk-informe tbody tr[data-modulo] td:first-child {
    box-shadow: inset 3px 0 0 var(--bk-accent);
}

/* --- El color de la tarjeta de una oferta ---------------------------------- */

.bk-color-fila {
    display: flex;
    align-items: center;
    gap: .65rem;
    flex-wrap: wrap;
}

/* El selector nativo, al ancho de la banda de una tarjeta: es a la vez el
   control y la vista previa. Un color que parece discreto en el cuadradito de
   dos centímetros que trae de serie puede gritar en una banda entera.

   Se le quita el relleno que trae por defecto para que el color llegue hasta el
   borde: con él se ve un color pequeño dentro de un botón grande, que parece un
   control deshabilitado. */
.bk-color-selector {
    width: 6rem;
    height: 2.5rem;
    flex: none;
    padding: 0;
    border: 1px solid var(--bk-border);
    border-radius: .55rem;
    background: none;
    cursor: pointer;
}
.bk-color-selector::-webkit-color-swatch-wrapper { padding: 3px; }
.bk-color-selector::-webkit-color-swatch {
    border: 0;
    border-radius: .4rem;
}
.bk-color-selector::-moz-color-swatch {
    border: 0;
    border-radius: .4rem;
}

/* --- Quién, con su distintivo --------------------------------------------- */

.bk-persona {
    display: flex;
    align-items: flex-start;
    gap: .6rem;
}

.bk-persona-texto { min-width: 0; }

/* Las iniciales, en el color del módulo. Dos letras en un círculo tiñen la
   columna y dan por dónde agarrar la lista: una columna de «Persona de prueba
   4/5/6» se recorre por la inicial antes que por la palabra.

   El color viene de `--bk-accent`, que la fila hereda de su módulo; sin módulo
   cae al navy de la marca y sigue leyéndose. */
.bk-avatar {
    display: grid;
    place-items: center;
    flex: none;
    width: 2rem;
    height: 2rem;
    border-radius: 50%;
    background: color-mix(in srgb, var(--bk-accent) 14%, #fff);
    /* 60% y no más color: el verde de Certificados es el más claro de los tres
       y al 82% se quedaba en 3.65:1 sobre su propio fondo lavado, por debajo
       del 4.5 mínimo. Al 60% el peor de los cuatro casos da 5.12:1. El número
       está calculado, no elegido a ojo; subirlo vuelve a romperlo. */
    color: color-mix(in srgb, var(--bk-accent) 60%, var(--bk-navy-900));
    font-size: .72rem;
    font-weight: 700;
    letter-spacing: .02em;
    /* Un pelo más abajo que la línea del nombre: centrado con ella se ve
       subido, porque el nombre tiene dos líneas de texto debajo. */
    margin-top: .1rem;
}

/* El nombre del módulo, con su punto. El punto es lo que nombra el color: sin
   él, el filo de la izquierda es un adorno que hay que adivinar. */
.bk-informe-modulo {
    display: inline-flex;
    align-items: center;
    gap: .3rem;
    white-space: nowrap;
}

/* Al pasar por encima, la fila se tiñe de su módulo en vez del gris de
   siempre. Es la misma señal otra vez y sin coste: ya se está mirando ahí. */
.bk-informe tbody tr[data-modulo]:hover {
    background: color-mix(in srgb, var(--bk-accent) 6%, var(--bk-bg));
}

/* La compra que no pasó por el formulario. En gris y sin adorno: no es un
   error, es una fila a la que habrá que pedirle los datos. */
.bk-sin-ficha {
    margin-top: .3rem;
    font-size: .68rem;
    font-style: italic;
    color: var(--bk-muted);
}

/* --- Un botón con dibujo delante ------------------------------------------
   La palabra dice qué hace y el dibujo en qué formato: «Descargar» no dice si
   sale una hoja de cálculo o un PDF, y quien busca este botón lo busca porque
   quiere abrirlo en Excel. */
.btn-bk-icono {
    display: inline-flex;
    align-items: center;
    gap: .45rem;
}

.btn-bk-icono svg {
    width: 1.05rem;
    height: 1.05rem;
    flex: none;
}

/* El verde de la hoja de cálculo, no el del panel: es lo que lo hace
   reconocible antes de leer la palabra. Se mantiene al pasar por encima —el
   botón cambia de fondo, el dibujo no—, porque un icono que cambia de color
   deja de ser el mismo icono. */
.bk-icono-excel { color: #1d7044; }

/* --- La tabla del informe --------------------------------------------------
   Las tweaks van bajo `.bk-informe` y no en `.bk-table`: esta tabla tiene
   celdas de tres líneas y columnas de números, y lo que le conviene rompería
   las tablas de una sola línea del resto del panel. */
.bk-informe tbody td {
    /* Arriba y no en medio: con la ficha desplegada la celda crece, y centrado
       el nombre de la persona se despegaba de su fila. */
    vertical-align: top;
    padding-top: .8rem;
    padding-bottom: .8rem;
}

/* Los números, en cifras de ancho fijo. Una columna de importes con la
   tipografía proporcional no alinea las unidades con las unidades, y es justo
   lo que se hace al mirarla: comparar de arriba abajo. */
.bk-informe-cifra {
    font-variant-numeric: tabular-nums;
    font-weight: 600;
}

/* «14 ago, 15:24» entero o nada: partido en dos líneas, la hora queda debajo
   del mes y se lee como si fueran dos datos. Con el importe pasa igual: la
   moneda debajo de la cifra se lee como si fuera otro dato. */
.bk-informe-cuando,
.bk-informe-importe { white-space: nowrap; }

.bk-informe-moneda {
    font-size: .7rem;
    color: var(--bk-muted);
    margin-left: .15rem;
}

/* Un importe que se devolvió. La pastilla del estado ya lo dice; esto lo dice
   otra vez donde la vista suma. */
.bk-importe-anulado {
    text-decoration: line-through;
    text-decoration-thickness: 1px;
    color: var(--bk-muted);
    font-weight: 500;
}

/* La segunda línea de una celda: el correo bajo el nombre, el módulo bajo la
   oferta, el código bajo el número de pedido. Siempre lo mismo y siempre
   igual, para que se lea como un pie y no como otro dato. */
.bk-informe-sub {
    margin-top: .15rem;
    font-size: .72rem;
    line-height: 1.35;
    color: var(--bk-muted);
}

.bk-decidir .btn {
    padding: .2rem .6rem;
    font-size: .74rem;
}

/* --- La ficha de una inscripción, en su diálogo -----------------------------
   El nombre de la lista es un botón, pero no debe parecerlo: en una columna de
   nombres, un botón con marco por fila haría de la lista un formulario. Se
   queda como el texto que era y avisa de que se pulsa al pasar por encima. */
.bk-persona-nombre {
    display: block;
    padding: 0;
    border: 0;
    background: none;
    font: inherit;
    font-weight: 600;
    color: var(--bk-text);
    text-align: left;
    cursor: pointer;
}
.bk-persona-nombre:hover { color: var(--bk-accent); text-decoration: underline; }
.bk-persona-nombre:focus-visible {
    outline: 2px solid var(--bk-accent);
    outline-offset: 2px;
    border-radius: .25rem;
}

/* El módulo, encima del nombre y en pequeño: dice de qué es esta inscripción
   antes de leer nada más. */
.bk-dialogo-encima {
    margin: 0 0 .15rem;
    font-size: .7rem;
    font-weight: 700;
    letter-spacing: .09em;
    text-transform: uppercase;
    color: var(--bk-muted);
}
.bk-dialogo-encima[hidden] { display: none; }

.bk-ficha-grupos {
    display: grid;
    gap: 1.1rem;
    padding: 1.15rem 1.4rem .25rem;
}

.bk-ficha-grupo h3 {
    margin: 0 0 .4rem;
    font-size: .72rem;
    font-weight: 700;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--bk-muted);
}

/* Las mismas filas de rótulo y valor que la ficha del sitio: una sola letra y
   una raya fina, que es lo que deja leer diez datos seguidos sin cansarse. */
.bk-ficha-lista {
    margin: 0;
    display: grid;
    /* El rótulo, con tope: «Correo electrónico» es el más largo que hay, y sin
       límite se comía media fila dejando el valor en una columna donde un
       correo no cabe entero. */
    grid-template-columns: minmax(0, 10rem) minmax(0, 1fr);
    align-items: baseline;
    font-size: .86rem;
}

.bk-ficha-lista dt,
.bk-ficha-lista dd {
    margin: 0;
    padding: .45rem 0;
    line-height: 1.35;
    border-top: 1px solid var(--bk-border);
}

/* La separación entre rótulo y valor se hace con relleno y no con `gap`: con
   `gap`, la raya de arriba se corta por la mitad y la lista se lee como dos
   columnas sueltas en vez de como filas. */
.bk-ficha-lista dd { padding-left: 1rem; }

.bk-ficha-lista dt:first-of-type,
.bk-ficha-lista dt:first-of-type + dd { border-top: 0; }

.bk-ficha-lista dt { font-weight: 600; color: var(--bk-text); }

.bk-ficha-lista dd {
    text-align: right;
    color: var(--bk-muted);
    overflow-wrap: anywhere;
}

/* Este diálogo lleva diez datos con valores largos —un correo, una dirección—.
   Con el ancho de un aviso corto, la mitad se parte en dos líneas. */
#bk-inscrito { width: min(34rem, calc(100vw - 2rem)); }
