/* ---- Variables de tema (modo oscuro, el historico de la app) ----
     TODOS los colores de la app deberian salir de aqui (o de color-mix()
     a partir de estas variables) -- nada de hexadecimales sueltos en
     panel.css/index.php/panel.js. Asi el modo claro de mas abajo (y
     cualquier ajuste de paleta futuro) solo toca este bloque, y el resto
     de la hoja de estilos no se entera. */
  :root {
    /* Escalera de claridad deliberada, un escalon bien visible detras del
       otro (no solo 4-8 de diferencia por canal, que es lo que habia
       antes y se notaba demasiado poco): --bg (fondo de la PAGINA) mas
       claro que antes -- psicologicamente ayuda a leer mejor el resto de
       la interfaz -- pero sigue siendo el escalon MAS OSCURO de todos,
       para que la tarjeta .app-shell (--panel/--panel-2) destaque encima
       como superficie propia. --fondo-secundario (botones "secundario"/
       "icono", incluidos "Modo claro"/Creditos"/"Salir" en el pie de la
       barra lateral) tiene que quedar claramente MAS CLARO que --panel-2
       (el fondo sobre el que se ven, al ser la parte de ABAJO del
       gradiente de .app-shell) -- si no, el boton se funde con el fondo
       que tiene detras (como pasaba antes: quedaban casi al mismo tono).
       Todos "azulados" (canal B mas alto en proporcion a R/G) en vez del
       gris casi neutro original. */
    --bg: #181c28; --panel: #212636; --panel-2: #2a3145; --borde: #363f56;
    --texto: #e6e8ec; --texto-suave: #9aa2b1; --acento: #5b8cff; --acento-2: #7c5bff;
    --ok: #3ecf8e; --error: #ff5d6c; --error-2: #c73f4c; --aviso: #ffb648;
    /* Fondos "solidos" que en el modo oscuro son casi negros (editor de
       SQL, inputs...) y en el modo claro pasan a ser grises muy claros --
       no son la misma variable que --bg/--panel porque cumplen un papel
       distinto (superficie "hundida", no el fondo general del panel).
       --fondo-secundario es la excepcion: es un boton, tiene que ser mas
       CLARO que lo que tiene detras (ver comentario de arriba), no mas
       oscuro. */
    --fondo-editor: #0c0f18; --fondo-codigo-inline: #171b24;
    --fondo-secundario: #3c4660; --fondo-secundario-hover: #4a5678;
    --fondo-descarga: #1a2032; --fondo-descarga-hover: #212a42;
    --logo-fondo: #fff;
    /* Colores de sintaxis SQL -- necesitan version mas oscura en el modo
       claro para seguir siendo legibles sobre fondo blanco. */
    --codigo-reservada: #c792ea; --codigo-literal: #c3e88d; --codigo-numero: #f78c6c;
    /* Mancha de color de la esquina superior del fondo general -- un poco
       mas saturada que antes, a juego con el resto de la paleta ya
       azulada. */
    --gradiente-fondo: #202a49;
    /* Fondo semitransparente de todos los modales (siempre oscuro, aunque
       el tema sea claro, porque tiene que seguir contrastando con lo que
       tapa) -- tres intensidades porque algunos modales anidados o mas
       "criticos" ya usaban un punto mas de opacidad. */
    --overlay-modal-suave: rgba(0,0,0,.6); --overlay-modal: rgba(0,0,0,.65); --overlay-modal-fuerte: rgba(0,0,0,.75);
    /* Sombra de tarjetas/paneles/toasts -- mucho mas sutil en el modo
       claro (una sombra "oscura" tal cual quedaria como una mancha rara
       sobre fondo blanco). */
    --sombra-suave: rgba(0,0,0,.25); --sombra: rgba(0,0,0,.35); --sombra-fuerte: rgba(0,0,0,.4);
    /* Cursores personalizados de "ajustar ancho/alto arrastrando" (SVG
       propio en vez del icono nativo del sistema, que en muchos
       navegadores/pantallas sale pixelado): una raya solida en el centro
       con dos flechas, tambien solidas, que salen de su punto medio hacia
       los dos lados -- vectorial, nitido a cualquier zoom o densidad de
       pantalla, relleno negro con borde blanco fino para distinguirse
       sobre cualquier fondo. "-h" (horizontal, flechas izquierda/derecha)
       se usa en el manejador de ancho de columna (VistaAgrupadaSql, ver
       .manejador-ancho-columna-sql) y en el divisor VERTICAL entre panel
       de comando y panel de resultado (ver .split-sql-divisor); "-v"
       (vertical, flechas arriba/abajo) en ese mismo divisor cuando esta
       en orientacion horizontal (paneles apilados). Variables aqui (no
       repetidas en cada regla) para poder reutilizar el mismo cursor en
       todos los sitios sin duplicar el SVG entero. */
    --cursor-ajustar-h: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Crect x='11' y='2' width='2' height='20' fill='black' stroke='white' stroke-width='1'/%3E%3Cpolygon points='11,10 7,10 7,7 2,12 7,17 7,14 11,14' fill='black' stroke='white' stroke-width='1' stroke-linejoin='round'/%3E%3Cpolygon points='13,10 17,10 17,7 22,12 17,17 17,14 13,14' fill='black' stroke='white' stroke-width='1' stroke-linejoin='round'/%3E%3C/svg%3E") 12 12, col-resize;
    --cursor-ajustar-v: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Crect x='2' y='11' width='20' height='2' fill='black' stroke='white' stroke-width='1'/%3E%3Cpolygon points='10,11 10,7 7,7 12,2 17,7 14,7 14,11' fill='black' stroke='white' stroke-width='1' stroke-linejoin='round'/%3E%3Cpolygon points='10,13 10,17 7,17 12,22 17,17 14,17 14,13' fill='black' stroke='white' stroke-width='1' stroke-linejoin='round'/%3E%3C/svg%3E") 12 12, row-resize;
  }
  /* ---- Modo claro ---- Se activa poniendo data-tema="light" en <html>
     (ver aplicarTemaGuardado()/alternarTema() en panel.js). Redefine
     EXACTAMENTE las mismas variables de arriba -- ninguna regla del resto
     de este fichero necesita saber en que tema esta, todas siguen leyendo
     var(--texto), var(--fondo-editor), etc. como siempre. */
  html[data-tema="light"] {
    /* --bg mas gris (menos "blanco deslumbrante") que --panel, a proposito
       -- asi las tarjetas (fondo blanco de verdad) se distinguen del fondo
       general de la pagina, en vez de fundirse las dos en un blanco plano. */
    --bg: #dfe2e8; --panel: #ffffff; --panel-2: #eef0f4; --borde: #d3d8e0;
    --texto: #1b1f27; --texto-suave: #5b6472; --acento: #3763dc; --acento-2: #6a3fd6;
    --ok: #17864f; --error: #d63447; --error-2: #a3202f; --aviso: #b06d00;
    --fondo-editor: #eef0f5; --fondo-codigo-inline: #eef0f5;
    --fondo-secundario: #d2d4d8; --fondo-secundario-hover: #c2c5cb;
    --fondo-descarga: #e8edff; --fondo-descarga-hover: #d8e2ff;
    --logo-fondo: #fff;
    --codigo-reservada: #7c3aed; --codigo-literal: #15803d; --codigo-numero: #c2410c;
    --gradiente-fondo: #d3daea;
    --overlay-modal-suave: rgba(15,23,42,.4); --overlay-modal: rgba(15,23,42,.45); --overlay-modal-fuerte: rgba(15,23,42,.55);
    --sombra-suave: rgba(15,23,42,.08); --sombra: rgba(15,23,42,.12); --sombra-fuerte: rgba(15,23,42,.16);
  }
  * { box-sizing: border-box; }
  body {
    margin: 0; min-height: 100vh; background: radial-gradient(1200px 600px at 10% -10%, var(--gradiente-fondo) 0%, var(--bg) 55%);
    color: var(--texto); font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Arial, sans-serif;
    padding: 24px 20px; transition: background-color .2s ease, color .2s ease;
  }
  h1 { font-size: 20px; font-weight: 600; margin: 0 0 4px; }
  .subtitulo { color: var(--texto-suave); font-size: 13px; margin: 0 0 28px; }
  .contenedor { max-width: 1600px; margin: 0 auto; width: 100%; }
  @media (max-width: 1680px) { .contenedor { max-width: 96vw; } }
  .cabecera-tarjeta { display: flex; justify-content: space-between; align-items: center; gap: 12px; margin-bottom: 4px; flex-wrap: wrap; }
  .cabecera-tarjeta h1, .cabecera-tarjeta h2 { display: flex; align-items: center; }
  .cabecera-tarjeta h2 { font-size: 15px; font-weight: 600; margin: 0; }
  /* Icono copiado del boton del menu lateral (ver insertarIconoEnTituloSeccion() en panel.js), del mismo alto que la letra del titulo -- 1em toma el font-size del propio h1/h2 en el que se inserta. */
  .icono-titulo-seccion { width: 1em; height: 1em; margin-right: 8px; flex-shrink: 0; color: var(--texto-suave); }
  .icono-titulo-seccion svg { width: 100%; height: 100%; }
  button.icono { background: var(--fondo-secundario); padding: 8px 12px; display: inline-flex; align-items: center; gap: 6px; }
  button.icono:hover { background: var(--fondo-secundario-hover); opacity: 1; }
  button.icono .girando { display: inline-block; animation: girar .6s linear; }
  @keyframes girar { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
  table { table-layout: fixed; width: 100%; }
  th, td { overflow: hidden; text-overflow: ellipsis; }
  .contenedor-tabla { overflow-x: hidden; }

  .app-shell {
    display: flex; width: 100%; max-width: 1600px; margin: 0 auto;
    height: calc(100vh - 48px); min-height: 520px;
    background: linear-gradient(180deg, var(--panel), var(--panel-2));
    border: 1px solid var(--borde); border-radius: 16px;
    box-shadow: 0 8px 24px var(--sombra); overflow: hidden;
  }
  .barra-lateral {
    width: 200px; flex-shrink: 0; display: flex; flex-direction: column; gap: 3px;
    padding: 20px 14px; border-right: 1px solid var(--borde); overflow-y: auto;
  }
  .barra-lateral .logo { font-size: 13px; font-weight: 700; letter-spacing: .03em; color: var(--texto-suave); text-transform: uppercase; padding: 6px 8px 16px; }
  /* Marco blanco con esquinas redondeadas para el logo de la app -- se
     usa donde se muestre el logo (barra lateral, Configuración, Créditos)
     para que respire y no quede "pegado" al fondo oscuro del panel,
     independientemente de que el logo original tenga fondo transparente. */
  .logo-marco {
    display: inline-block; background: var(--logo-fondo); border-radius: 10px; padding: 8px 10px;
    box-shadow: 0 2px 8px var(--sombra-suave);
    /* content-box a proposito: el resto de la pagina usa border-box, pero
       aqui el "max-height"/"max-width" de cada uso (barra lateral, vista
       previa, creditos) tiene que medir la imagen en si -- con border-box
       el padding se comia parte de esa altura y el logo se veia encogido. */
    box-sizing: content-box;
  }
  .barra-lateral .logo-app { display: block; max-width: 100%; max-height: 40px; margin: 8px 8px 12px; object-fit: contain; }
  .panel-group {
    border: 1px solid var(--borde); border-radius: 12px; padding: 18px 20px;
    margin-bottom: 20px; background: color-mix(in srgb, var(--texto) 2%, transparent);
  }
  .panel-group:last-child { margin-bottom: 0; }
  .nav-separador {
    font-size: 11px; font-weight: 700; letter-spacing: .04em; color: var(--texto-suave);
    text-transform: uppercase; padding: 14px 8px 4px; border-top: 1px solid var(--borde); margin-top: 6px;
  }
  .nav-separador:first-child { border-top: none; margin-top: 0; }
  .nav-boton {
    display: flex; align-items: center; gap: 10px; width: 100%; text-align: left;
    background: transparent; color: var(--texto-suave); border: none; border-radius: 8px;
    padding: 10px 8px; font-size: 13px; font-weight: 600; cursor: pointer;
  }
  .nav-boton:hover { background: color-mix(in srgb, var(--texto) 5%, transparent); color: var(--texto); opacity: 1; }
  .nav-boton.activo { background: color-mix(in srgb, var(--acento) 15%, transparent); color: var(--acento); }
  /* Iconos SVG minimalistas de la barra lateral (sustituyen a los emojis
     de antes) -- "stroke=currentColor" en el SVG hace que el icono tome
     siempre el mismo color que el texto del boton (var(--texto-suave) en
     reposo, var(--texto) al pasar el raton, var(--acento) si esta activo),
     sin tener que duplicar esos colores aqui. */
  .nav-icono { display: inline-flex; flex-shrink: 0; }
  .nav-icono svg { display: block; }
  .barra-lateral-pie { border-top: 1px solid var(--borde); padding-top: 12px; margin-top: auto; }
  .contenido-principal {
    flex: 1; min-width: 0; padding: 20px 24px; overflow: hidden;
    display: flex; flex-direction: column;
  }

  /* Las secciones ya no van dentro de una "tarjeta" propia (con su
     borde/fondo/sombra) -- viven directamente sobre el panel general,
     asi el titulo de cada seccion queda alineado con el nav de la
     barra lateral en vez de quedar desplazado por un marco extra.
     Cada seccion es tambien una columna flex que ocupa toda la altura
     disponible, para que la lista interna pueda extenderse hasta el
     final del panel (como el menu de la barra lateral) en vez de
     quedarse con un hueco vacio debajo. */
  .vista-seccion {
    background: none; border: none; box-shadow: none; padding: 0; margin-bottom: 0;
    flex: 1; display: flex; flex-direction: column; min-height: 0;
  }
  .vista-seccion.oculto { display: none !important; }

  @media (max-width: 860px) {
    .app-shell { flex-direction: column; height: auto; min-height: 0; }
    .barra-lateral { width: 100%; flex-direction: row; flex-wrap: wrap; border-right: none; border-bottom: 1px solid var(--borde); overflow: visible; }
    .barra-lateral .logo { display: none; }
    .barra-lateral-pie { border-top: none; border-left: 1px solid var(--borde); padding-top: 0; padding-left: 12px; margin-top: 0; display: flex; align-items: center; gap: 8px; }
    .barra-lateral-pie button { width: auto !important; margin-top: 0 !important; }
  }

  /* Scroll "profesional" (delgado, con el acento del tema) en vez del
     scrollbar por defecto del navegador. Va en "*" (TODO elemento), no
     solo en .scroll-fino -- si no, cada textarea/div nuevo con overflow
     (p.ej. los textareas de los modales de "Campos") se queda con la
     barra "cutre" del navegador hasta que alguien se acuerda de añadirle
     la clase. .scroll-fino se mantiene igual (mismo aspecto) por si en
     algun sitio se necesita la clase explicitamente (p.ej. para el
     "sticky thead" de mas abajo, que si depende de ella). */
  * { scrollbar-width: thin; scrollbar-color: var(--borde) transparent; }
  *::-webkit-scrollbar { width: 10px; height: 10px; }
  *::-webkit-scrollbar-track { background: transparent; }
  *::-webkit-scrollbar-thumb { background: var(--borde); border-radius: 999px; border: 2px solid transparent; background-clip: padding-box; }
  *::-webkit-scrollbar-thumb:hover { background: var(--acento); background-clip: padding-box; }
  .scroll-fino { scrollbar-width: thin; scrollbar-color: var(--borde) transparent; }
  .scroll-fino::-webkit-scrollbar { width: 10px; height: 10px; }
  .scroll-fino::-webkit-scrollbar-track { background: transparent; }
  .scroll-fino::-webkit-scrollbar-thumb { background: var(--borde); border-radius: 999px; border: 2px solid transparent; background-clip: padding-box; }
  .scroll-fino::-webkit-scrollbar-thumb:hover { background: var(--acento); background-clip: padding-box; }

  .lista-ficheros-scroll { flex: 1; min-height: 0; overflow-y: auto; overflow-x: hidden; margin-top: 10px; }
  .pie-lista {
    display: flex; justify-content: space-between; align-items: center; gap: 12px;
    padding: 14px 4px 6px;
  }
  .pie-lista button { background: var(--fondo-secundario); }

  .acciones-fila { display: flex; flex-wrap: nowrap; gap: 6px; align-items: center; white-space: nowrap; }
  .acciones-fila button.secundario { padding: 7px 10px; font-size: 12px; flex: none; }

  .boton-x {
    background: color-mix(in srgb, var(--error) 12%, transparent); color: var(--error);
    border: 1px solid color-mix(in srgb, var(--error) 35%, transparent);
    width: 28px; height: 28px; padding: 0; font-weight: 800; font-size: 15px; line-height: 1;
    border-radius: 6px; display: inline-flex; align-items: center; justify-content: center;
  }
  .boton-x:hover { background: color-mix(in srgb, var(--error) 22%, transparent); opacity: 1; }
  /* En la fila de filtros de Ficheros, el boton "Quitar filtros" va junto
     a un <label> oculto (misma estructura que sus vecinos "Tipo"/"Realm"/
     "Fecha de subida", para que las cuatro columnas midan lo mismo de
     arriba a abajo) -- aqui se iguala tambien su alto al de los
     inputs/selects de esa fila (en vez del 28px fijo de .boton-x, pensado
     para las acciones de una fila de tabla) para que quede perfectamente
     alineado con ellos, sin el hueco/desnivel de antes. */
  #boton-quitar-filtros { width: 36px; height: 36px; }

  .celda-truncada { max-width: 220px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .tarjeta {
    background: linear-gradient(180deg, var(--panel), var(--panel-2));
    border: 1px solid var(--borde); border-radius: 14px; padding: 22px; margin-bottom: 20px;
    box-shadow: 0 8px 24px var(--sombra);
  }
  .fila { display: flex; gap: 10px; flex-wrap: wrap; align-items: center; }
  label { font-size: 12px; color: var(--texto-suave); display: block; margin-bottom: 6px; }
  input, select, textarea {
    background: var(--fondo-editor); border: 1px solid var(--borde); color: var(--texto);
    border-radius: 8px; padding: 9px 11px; font-size: 13px; outline: none;
    font-family: inherit;
  }
  input:focus, select:focus, textarea:focus { border-color: var(--acento); }
  /* El texto de placeholder es SOLO una invitacion a elegir/editar, nunca
     un dato de ejemplo -- para no confundirlo con el valor ya escrito,
     tiene que quedar claramente mas apagado que el texto real (var(--texto))
     e incluso algo mas apagado que las labels (var(--texto-suave)). Se basa
     en variables de tema, asi que si en el futuro se añade un modo claro
     (hoy la app solo tiene el oscuro de arriba) se adapta solo, sin tocar
     esta regla. Cubre TODOS los placeholders de la app (inputs normales,
     inputs con datalist tipo combobox, etc.) porque no lleva selector de id.*/
  ::placeholder { color: var(--texto-suave); opacity: .35; }
  button {
    background: linear-gradient(135deg, var(--acento), var(--acento-2)); color: white; border: none;
    border-radius: 8px; padding: 9px 16px; font-size: 13px; font-weight: 600; cursor: pointer;
    transition: opacity .15s;
  }
  button:hover { opacity: .88; }
  /* "color: white" del boton base solo tiene sentido sobre el degradado de
     acento -- button.secundario/icono usan un fondo gris que en el modo
     claro es CLARO, y texto blanco sobre gris claro queda ilegible (se ve
     "deshabilitado" aunque no lo este). Necesitan su propio color de
     texto, que sigue al tema en vez de heredar el blanco fijo. */
  button.secundario, button.icono { background: var(--fondo-secundario); color: var(--texto); }
  button.peligro { background: linear-gradient(135deg, var(--error), var(--error-2)); }
  button:disabled { opacity: .45; cursor: not-allowed; }
  table { width: 100%; border-collapse: collapse; font-size: 13px; margin-top: 14px; }
  th, td { text-align: left; padding: 10px 12px; border-bottom: 1px solid var(--borde); white-space: nowrap; }
  .scroll-fino thead th { position: sticky; top: 0; background: var(--panel-2); z-index: 1; }
  th { color: var(--texto-suave); font-weight: 600; font-size: 11px; text-transform: uppercase; letter-spacing: .04em; }
  tr:hover td { background: color-mix(in srgb, var(--texto) 2%, transparent); }
  .pill { display: inline-block; padding: 2px 8px; border-radius: 999px; font-size: 11px; font-weight: 700; background: var(--fondo-secundario); color: var(--texto-suave); }
  /* "si"/"no" necesitan destacar de un vistazo en tablas con muchas
     columnas booleanas (p.ej. Api Keys: POST/FICHEROS/ADMIN/ACTIVA) --
     fondo bastante mas solido que el resto de pills (no solo un tinte
     muy leve, que con el fondo de tarjeta ya mas claro quedaba deslavado)
     y un borde del mismo tono para rematar el contorno. */
  .pill.si {
    background: color-mix(in srgb, var(--ok) 28%, transparent); color: var(--ok);
    border: 1px solid color-mix(in srgb, var(--ok) 45%, transparent);
  }
  .pill.no {
    background: color-mix(in srgb, var(--error) 24%, transparent); color: var(--error);
    border: 1px solid color-mix(in srgb, var(--error) 45%, transparent);
  }
  /* Variantes de texto de color plano (sin fondo/pill), para estados
     puntuales dentro de una celda o una linea suelta (p.ej. "Activo" /
     "Revocado" en Api Keys, o un mensaje de error dentro de un detalle). */
  .texto-ok { color: var(--ok); }
  .texto-error { color: var(--error); }

  /* Interruptor tipo iOS -- reutilizable en cualquier tabla o formulario
     del panel (no solo en Schemas): <label class="interruptor">
       <input type="checkbox" ...>
       <span class="interruptor-pista"></span>
     </label> */
  .interruptor { position: relative; display: inline-block; width: 38px; height: 22px; flex: none; vertical-align: middle; }
  .interruptor input { position: absolute; opacity: 0; width: 100%; height: 100%; margin: 0; cursor: pointer; z-index: 1; }
  .interruptor-pista {
    position: absolute; inset: 0; background: var(--borde); border: 1px solid var(--borde);
    border-radius: 999px; transition: background .2s ease, border-color .2s ease; pointer-events: none;
  }
  .interruptor-pista::before {
    content: ""; position: absolute; height: 16px; width: 16px; left: 2px; top: 2px;
    background: var(--texto); border-radius: 50%; transition: transform .2s ease;
  }
  .interruptor input:checked + .interruptor-pista {
    background: linear-gradient(135deg, var(--acento), var(--acento-2)); border-color: transparent;
  }
  .interruptor input:checked + .interruptor-pista::before { transform: translateX(16px); background: #fff; }
  .interruptor input:disabled + .interruptor-pista { opacity: .5; }
  .interruptor input:disabled { cursor: not-allowed; }
  .interruptor input:focus-visible + .interruptor-pista { outline: 2px solid var(--acento); outline-offset: 2px; }
  .mensaje { font-size: 13px; padding: 10px 12px; border-radius: 8px; margin-top: 12px; display: none; }
  .mensaje.error { background: color-mix(in srgb, var(--error) 10%, transparent); color: var(--error); border: 1px solid color-mix(in srgb, var(--error) 30%, transparent); }
  .mensaje.ok { background: color-mix(in srgb, var(--ok) 10%, transparent); color: var(--ok); border: 1px solid color-mix(in srgb, var(--ok) 30%, transparent); }
  .oculto { display: none !important; }

  /* Fondo comun de TODOS los modales (antes repetido a mano, con
     "position:fixed;inset:0;background:rgba(0,0,0,.65);..." en el style=
     de cada uno, en index.php). El z-index si varia por modal (segun si
     puede abrirse "encima" de otro), asi que ese se deja inline en cada
     div; el resto -- posicion, centrado, fondo -- sale de aqui. Dos
     variantes de opacidad para los casos que ya la tenian distinta
     (modal-subida algo mas suave, modal-expresion-campo algo mas fuerte
     por abrirse encima de otro modal). */
  .modal-fondo { position: fixed; inset: 0; background: var(--overlay-modal); display: flex; align-items: center; justify-content: center; padding: 20px; }
  .modal-fondo.suave { background: var(--overlay-modal-suave); }
  .modal-fondo.fuerte { background: var(--overlay-modal-fuerte); }

  /* Bloque de codigo/ejemplo de una sola linea (ayuda de expresiones de
     Campos) -- antes con "style=" repetido en cada <p> de index.php. */
  .bloque-codigo { font-family: monospace; background: var(--fondo-codigo-inline); padding: 8px 10px; border-radius: 6px; }

  .icono-info-campo { color: var(--texto-suave); cursor: help; margin-left: 4px; }
  .icono-info-campo:hover { color: var(--acento); }
  .callout-descripcion-campo {
    position: fixed; z-index: 300; max-width: 280px;
    background: var(--panel-2); color: var(--texto); border: 1px solid var(--borde);
    border-radius: 8px; padding: 8px 12px; font-size: 12px; font-weight: normal;
    line-height: 1.4; box-shadow: var(--sombra); white-space: normal;
  }

  #toast-contenedor {
    position: fixed; right: 20px; bottom: 20px; z-index: 100;
    display: flex; flex-direction: column; gap: 10px; max-width: 420px;
  }
  .toast {
    display: flex; align-items: flex-start; gap: 10px;
    background: color-mix(in srgb, var(--ok) 22%, transparent); color: var(--ok);
    border: 1px solid color-mix(in srgb, var(--ok) 40%, transparent);
    border-radius: 8px; padding: 12px 14px; font-size: 13px; line-height: 1.4;
    box-shadow: 0 8px 24px var(--sombra);
    animation: toast-entrada .18s ease-out;
    /* Difumina lo que haya debajo (tabla, texto, lo que sea) para que el
       toast sea siempre legible sin necesidad de un fondo solido -- si el
       navegador no soporta backdrop-filter, se queda con el fondo de color
       de arriba tal cual (algo mas opaco que antes, por si acaso). */
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
  }
  .toast-texto { flex: 1; word-break: break-word; }
  .toast-cerrar {
    background: transparent; border: none; color: inherit; opacity: .7; cursor: pointer;
    font-size: 15px; line-height: 1; padding: 0; margin: 0;
  }
  .toast-cerrar:hover { opacity: 1; }
  @keyframes toast-entrada { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } }
  /* Variante roja del toast (errores) -- a diferencia del toast verde de
     "todo ok" (que se autodescarta a los 10s), este NUNCA se autodescarta:
     normalmente hay que corregir algo antes de repetir, asi que el propio
     boton de cerrar (heredado de .toast-cerrar) es la unica forma de
     quitarlo de en medio. */
  .toast.error { background: color-mix(in srgb, var(--error) 22%, transparent); color: var(--error); border-color: color-mix(in srgb, var(--error) 40%, transparent); }

  /* Fila clicable de la tabla de "Campos" -- toda la fila abre el modal
     de edicion (salvo los botones de Duplicar/Eliminar, que paran la
     propagacion del clic). */
  .fila-clicable { cursor: pointer; }
  .fila-clicable:hover { background: color-mix(in srgb, var(--texto) 3%, transparent); }
  /* Resaltado sutil de fila cuando hay una busqueda activa y esta fila
     coincide -- deliberadamente tenue (nada de amarillo chillon), solo
     para que destaque un poco sobre el resto mientras se busca. */
  .fila-coincide { background: color-mix(in srgb, var(--aviso) 5%, transparent); }
  .fila-coincide:hover { background: color-mix(in srgb, var(--aviso) 9%, transparent); }
  /* Resaltado del texto que coincide dentro de la celda -- mismo tono
     (--aviso) que la fila, pero mas visible al ser un fondo solido sobre
     texto puntual en vez de sobre toda la fila. */
  mark.resaltado-busqueda {
    background: color-mix(in srgb, var(--aviso) 32%, transparent); color: inherit; border-radius: 3px; padding: 0 2px;
  }

  /* Panel de referencia (campos de origen + funciones) dentro del editor
     grande de expresiones -- lista de consulta rapida, clicable para
     insertar en el cursor del textarea sin tener que escribirlo a mano. */
  .ref-item {
    cursor: pointer; padding: 6px 8px; border-radius: 6px; font-family: monospace;
    font-size: 11.5px; word-break: break-all; margin-bottom: 2px; color: var(--texto-suave);
  }
  .ref-item:hover { background: color-mix(in srgb, var(--texto) 6%, transparent); color: var(--texto); }
  .ref-separador { border: none; border-top: 1px solid var(--borde); margin: 12px 0; }
  .ref-titulo {
    font-weight: 600; color: var(--texto-suave); text-transform: uppercase;
    font-size: 11px; letter-spacing: .03em; margin-bottom: 8px;
  }
  .cabecera-app { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; }
  .badge-usuario { font-size: 12px; color: var(--texto-suave); }
  .paginacion { display: flex; gap: 8px; align-items: center; margin-top: 14px; font-size: 12px; color: var(--texto-suave); }
  a.enlace-descarga { color: var(--acento); text-decoration: none; font-size: 12px; margin-right: 10px; cursor: pointer; }
  a.enlace-descarga:hover { text-decoration: underline; }
  .boton-copiar {
    background: transparent; border: none; color: var(--texto-suave); cursor: pointer;
    padding: 2px 4px; display: inline-flex; align-items: center; vertical-align: middle;
    border-radius: 4px; margin-left: 4px;
  }
  .boton-copiar:hover { color: var(--acento); background: color-mix(in srgb, var(--texto) 6%, transparent); }
  .boton-copiar svg { display: block; }
  /* Botones de descarga (JSON/EXCEL) en la lista de Ficheros: icono de
     documento + etiqueta, en gris neutro (var(--texto-suave)) en vez del
     azul de acento -- para no competir visualmente con las acciones
     "de verdad" importantes (botones primarios como "Subir fichero", que
     si usan --acento). display:inline-flex + gap centra el icono SVG y el
     texto en la misma linea sin depender de vertical-align. */
  button.descarga {
    display: inline-flex; align-items: center; gap: 5px;
    background: var(--panel-2); color: var(--texto-suave); border: 1px solid var(--borde);
    padding: 6px 10px; font-size: 11px; font-weight: 700; letter-spacing: .03em; border-radius: 6px;
  }
  button.descarga svg { display: block; flex: none; }
  button.descarga:hover {
    background: color-mix(in srgb, var(--texto) 8%, var(--panel-2));
    color: var(--texto);
    border-color: color-mix(in srgb, var(--texto) 25%, var(--borde));
    opacity: 1;
  }
  /* SIN "align-items:center": con center, cada hijo conserva su propia
     altura de contenido (el interruptor 22px, el texto la altura de su
     linea) y flexbox los centra caja-contra-caja -- pero eso deja el
     TEXTO descolgado hacia abajo dentro de su propia caja cuando al lado
     hay un interruptor mas alto que una linea de texto normal. Sin
     align-items (por tanto "stretch", el valor por defecto), el <span>
     de texto se estira a la altura completa del interruptor, y ahi si el
     line-height de abajo (igual a esa altura) centra el texto de verdad. */
  .checkbox-linea { display: flex; gap: 6px; font-size: 13px; color: var(--texto); }
  .checkbox-linea .interruptor + span { line-height: 22px; }

  .selector-fichero {
    display: flex; align-items: center; gap: 12px; background: var(--fondo-editor); border: 1px solid var(--borde);
    border-radius: 8px; padding: 10px 12px;
  }
  .selector-fichero input[type=file] { display: none; }
  .selector-fichero label {
    background: var(--fondo-secundario); color: var(--texto); padding: 8px 16px; border-radius: 7px; cursor: pointer;
    font-size: 12px; font-weight: 600; white-space: nowrap; transition: background .15s;
  }
  .selector-fichero label:hover { background: var(--fondo-secundario-hover); }
  .selector-fichero .nombre-fichero {
    font-size: 12px; color: var(--texto-suave); overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }

  #barra-progreso-contenedor {
    background: var(--fondo-editor); border: 1px solid var(--borde); border-radius: 999px; height: 10px;
    overflow: hidden; margin-bottom: 10px;
  }
  #barra-progreso {
    height: 100%; width: 0%; background: linear-gradient(135deg, var(--acento), var(--acento-2));
    transition: width .15s ease;
  }
  #texto-progreso { font-size: 12px; color: var(--texto-suave); margin-bottom: 10px; }

  #json-subida {
    background: var(--fondo-editor); border: 1px solid var(--borde); border-radius: 8px; padding: 12px;
    font-size: 11px; line-height: 1.5; max-height: 240px; overflow: auto; white-space: pre-wrap;
    word-break: break-all; color: var(--texto-suave); margin-top: 4px;
  }

  /* ---- Consola SQL de "Clientes de API" (modal-sql-cliente-api) ---- */
  /* #contenedor-split-sql reparte el espacio entre el editor y el
     resultado con flex-grow (en vez de anchos/altos fijos en px) para que
     el "%" pedido por el usuario sea proporcional al espacio disponible
     de verdad, restando ya el hueco fijo del divisor arrastrable. */
  #contenedor-split-sql, .split-sql-contenedor { display: flex; flex: 1; min-height: 0; }
  #contenedor-split-sql.orientacion-vertical, .split-sql-contenedor.orientacion-vertical { flex-direction: row; }
  #contenedor-split-sql.orientacion-horizontal, .split-sql-contenedor.orientacion-horizontal { flex-direction: column; }
  #panel-sql-editor, #panel-sql-resultado, .split-sql-editor, .split-sql-panel-resultado { display: flex; flex-direction: column; min-width: 0; min-height: 0; overflow: hidden; }
  /* Editor SQL: UN SOLO <div contenteditable> hace a la vez de "input" Y de
     "pintado" del resaltado de sintaxis. Antes habia DOS elementos
     superpuestos (un <textarea> invisible encima de un <pre> coloreado) y,
     pese a compartir exactamente el mismo CSS, el cursor real del
     <textarea> y el texto coloreado del <pre> se iban desalineando --
     cada vez mas cuanto mas larga la linea -- porque un <textarea> y un
     <pre> usan internamente rutas de layout de texto DISTINTAS en el
     motor del navegador (confirmado: incluso con estilos computados
     identicos, su ancho util -- clientWidth -- podia diferir en 1px, y
     ademas el propio <textarea> redondea el avance de cada caracter de
     forma distinta a un <pre>). Ningun ajuste de CSS/JS lo resolvia de
     forma fiable porque el problema es arquitectonico, no de afinado.
     Con un unico elemento no existe ese problema por construccion: solo
     hay UN motor de renderizado de texto, asi que el cursor SIEMPRE cae
     exactamente donde se ve el texto. El contenido coloreado (con los
     <span> por token) se repinta en cada tecla via resaltarSqlHtml(), ver
     actualizarResaltadoEditorSql() en panel.js -- la posicion del cursor
     se guarda (en caracteres) antes de repintar y se restaura despues. */
  #envoltorio-editor-sql, .split-sql-envoltorio { flex: 1; min-height: 0; }
  .editor-sql {
    display: block; width: 100%; height: 100%; box-sizing: border-box;
    margin: 0; padding: 10px; font-family: 'SFMono-Regular', Consolas, monospace; font-size: 13px; line-height: 1.5;
    border: 1px solid var(--borde); border-radius: 8px;
    white-space: pre-wrap; word-wrap: break-word; overflow: auto;
    background: var(--fondo-editor); color: var(--texto); caret-color: var(--texto);
  }
  .editor-sql:empty::before { content: attr(data-placeholder); color: var(--texto-suave); pointer-events: none; }
  .editor-sql::selection { background: color-mix(in srgb, var(--texto) 28%, transparent); }
  .editor-sql:focus { outline: none; border-color: var(--acento); }
  /* Antes "font-weight:600" para las palabras reservadas y
     "font-style:italic" para los comentarios -- en una fuente de verdad
     monoespaciada la negrita/cursiva NO deberia cambiar el ancho de cada
     caracter, pero no todas las fuentes lo garantizan de forma identica en
     todos los sistemas (Consolas en Windows, en concreto, no siempre
     dibuja su variante en negrita exactamente al mismo ancho que la
     regular) -- y como aqui el texto se pinta dos veces (la capa de color
     de abajo y el cursor real, invisible, encima) cualquier diferencia de
     ancho entre ambas desalinea la una de la otra. Se distingue cada tipo
     de token solo por COLOR (que nunca cambia el ancho de un caracter),
     sin tocar peso ni estilo de letra. */
  .sql-tok-reservada { color: var(--codigo-reservada); }
  .sql-tok-literal { color: var(--codigo-literal); }
  .sql-tok-numero { color: var(--codigo-numero); }
  .sql-tok-comentario { color: var(--texto-suave); }
  #divisor-split-sql, .split-sql-divisor {
    flex: none; display: flex; align-items: center; justify-content: center; background: transparent;
    color: var(--texto-suave); position: relative;
  }
  #divisor-split-sql:hover, #divisor-split-sql.arrastrando, .split-sql-divisor:hover, .split-sql-divisor.arrastrando { color: var(--acento); }
  /* Mismo cursor SVG personalizado que el manejador de ancho de columna
     (ver --cursor-ajustar-h/--cursor-ajustar-v en :root) -- se aplica al
     divisor arrastrable entre panel de comando y panel de resultado, en
     TODOS los sitios donde aparece: la consola SQL de administracion
     (#divisor-split-sql) y el panel "API Test" (#prueba-api-divisor),
     ambos con la misma clase compartida .split-sql-divisor. */
  #contenedor-split-sql.orientacion-vertical #divisor-split-sql, .split-sql-contenedor.orientacion-vertical .split-sql-divisor { width: 14px; cursor: var(--cursor-ajustar-h); }
  #contenedor-split-sql.orientacion-horizontal #divisor-split-sql, .split-sql-contenedor.orientacion-horizontal .split-sql-divisor { height: 14px; cursor: var(--cursor-ajustar-v); }
  #divisor-split-sql::before, .split-sql-divisor::before {
    content: ''; position: absolute; background: var(--borde);
  }
  #contenedor-split-sql.orientacion-vertical #divisor-split-sql::before, .split-sql-contenedor.orientacion-vertical .split-sql-divisor::before { left: 50%; top: 0; bottom: 0; width: 1px; transform: translateX(-50%); }
  #contenedor-split-sql.orientacion-horizontal #divisor-split-sql::before, .split-sql-contenedor.orientacion-horizontal .split-sql-divisor::before { top: 50%; left: 0; right: 0; height: 1px; transform: translateY(-50%); }
  #divisor-split-sql svg, .split-sql-divisor svg { position: relative; z-index: 1; background: var(--panel); border-radius: 4px; }
  #contenedor-split-sql.orientacion-horizontal #divisor-split-sql svg, .split-sql-contenedor.orientacion-horizontal .split-sql-divisor svg { transform: rotate(90deg); }

  #panel-sql-resultado, .split-sql-panel-resultado { position: relative; }
  #scroll-sql-resultado { flex: 1; min-height: 0; overflow: auto; border: 1px solid var(--borde); border-radius: 8px; background: var(--fondo-editor); }
  /* Flota ENCIMA de la tabla (fuera del contenedor con scroll) en vez de
     empujarla hacia abajo -- asi mostrar u ocultar un error/aviso no
     mueve ni encoge el resto del layout, y no hace falta hacer scroll
     para verlo. */
  .mensaje-flotante-sql { position: absolute; top: 8px; left: 8px; right: 8px; z-index: 2; box-shadow: 0 4px 16px var(--sombra-fuerte); }
  /* Sin min-width:100% -- si el contenido cabe en menos ancho que el
     panel, la tabla NO debe repartir el sobrante entre las columnas (eso
     esparce mucho el texto); solo se ensancha lo que haga falta para el
     contenido, y el scroll horizontal entra en juego si no cabe. */
  .tabla-sql-resultado { table-layout: auto; width: auto; }
  .tabla-sql-resultado td { white-space: nowrap; padding: 6px 10px; }
  /* La cabecera va en UNA sola linea, igual que las celdas de datos --
     recorta con "..." si el nombre de columna no cabe en el ancho
     calculado (con el nombre completo disponible en el "title" al pasar
     el cursor). Se probo a partir el nombre en varias lineas por "_"
     para aprovechar mejor el espacio, pero un ancho de columna ajustado
     al contenido (a veces muy corto, p.ej. numeros) podia quedar mas
     estrecho que la propia palabra del nombre, y el navegador la forzaba
     a partirse a media palabra o incluso letra a letra -- con una sola
     linea y recorte por elipsis, ese problema desaparece del todo. */
  .tabla-sql-resultado th {
    padding: 6px 10px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
    vertical-align: middle; position: sticky; top: 0; background: var(--panel-2); z-index: 1;
  }
  /* El ancho real lo fija el <colgroup> que genera panel.js (medido a
     partir del contenido, con tope de 200px) -- aqui solo hace falta que
     la celda recorte con "..." si el contenido no cabe en ese ancho. */
  .celda-sql-valor { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .celda-sql-valor.valor-nulo { color: var(--texto-suave); font-style: italic; }
  /* Valor con saltos de linea REALES (p.ej. una direccion o una nota) --
     se muestran TODAS sus lineas en vez de recortar a una sola con "...".
     La fila crece de alto lo que haga falta (las celdas del resto de
     columnas de esa misma fila quedan arriba gracias al vertical-align). */
  .celda-sql-valor.valor-multilinea { white-space: pre-wrap; overflow: visible; text-overflow: clip; word-break: break-word; overflow-wrap: anywhere; }
  .tabla-sql-resultado td { vertical-align: top; }
  /* Las columnas sum(...) son numericas -- se alinean a la derecha tanto en
     la cabecera como en los valores, cabecera y celdas incluidas. */
  .tabla-sql-resultado th.columna-numerica { text-align: right; }
  .celda-sql-valor.valor-numerico { text-align: right; }
  /* Manejador de ajuste MANUAL de ancho de columna: vive DENTRO de su
     propia cabecera (right:0, sin salirse de ella hacia la columna
     vecina) -- antes se centraba a caballo entre las dos columnas
     (right:-7px), pero al invadir el rectangulo de la cabecera SIGUIENTE
     quedaba tapado por su fondo/pintado (cada <th> con position:sticky es
     su propio contexto de apilamiento, y en igualdad de z-index pinta
     encima el que va DESPUES en el documento) -- eso es lo que hacia que
     la zona de arrastre no se identificara bien ni respondiera al pasar
     el cursor en su mitad derecha. Con right:0 el manejador queda
     ENTERAMENTE dentro de su "th" y no hay ambigüedad de a que columna
     pertenece ni riesgo de que lo tape la vecina. El "position:sticky"
     que ya tiene .tabla-sql-resultado th (mas arriba) sirve de contenedor
     de posicionamiento para este "position:absolute", sin tener que
     tocarlo (cambiarlo a "relative" rompería el efecto pegajoso al hacer
     scroll). Area de agarre ANCHA (14px) para que sea facil de "pillar"
     con el raton; la marca VISIBLE dentro de esa zona es el tipico grupo
     de puntitos de "asa de arrastre" (2 columnas x 3 filas), siempre
     visible de forma tenue y que se ilumina con el color de acento al
     pasar el cursor encima o mientras se arrastra -- mucho mas facil de
     identificar de un vistazo que una simple linea. Funciona igual en la
     consola SQL y en API Test porque ambas comparten la misma clase
     VistaAgrupadaSql. */
  .manejador-ancho-columna-sql {
    position: absolute; top: 0; right: 0; bottom: 0; width: 14px; z-index: 2;
    display: flex; align-items: center; justify-content: center;
    /* Cursor personalizado (SVG en vez del icono nativo del sistema, que
       en muchos navegadores/pantallas sale pixelado) -- ver variable
       --cursor-ajustar-h (definida una sola vez en :root) para el
       detalle de la forma. */
    cursor: var(--cursor-ajustar-h);
  }
  /* Asa de puntitos, al estilo del manejador de reordenar una lista en
     iOS: una sola columna de 4 puntos REDONDOS, pequeños y bien separados
     entre si (no un grip apretado de dos columnas, que en una franja tan
     estrecha quedaba demasiado cargado) -- hecha con UN radial-gradient
     repetido en vertical, con "currentColor" para poder cambiar solo el
     "color" en hover/arrastre en vez de repetir todo el gradiente. Muy
     poco visible cuando el cursor no esta encima (opacity .3) -- no debe
     llamar la atencion como si fuera un dato mas de la cabecera, solo
     "estar ahi" para quien lo busque, y hacerse notar de verdad solo al
     pasar el cursor o arrastrar. */
  .manejador-ancho-columna-sql::after {
    content: ''; display: block; width: 3px; height: 22px; flex: none;
    color: var(--texto-suave);
    background-image: radial-gradient(circle at 1.5px 2px, currentColor 1px, transparent 1.3px);
    background-size: 3px 6px;
    background-repeat: repeat-y;
    background-position: center top;
    opacity: .3;
    transition: color .12s, opacity .12s;
  }
  .tabla-sql-resultado th:hover .manejador-ancho-columna-sql::after {
    color: var(--acento); opacity: 1;
  }
  .manejador-ancho-columna-sql.arrastrando::after {
    color: var(--acento); opacity: 1;
  }
  /* Mientras se arrastra, todo el cursor de la pagina usa el mismo icono
     personalizado (no solo sobre el manejador) para que no parpadee si el
     raton se adelanta un poco al movimiento del <col>, y se desactiva la
     seleccion de texto accidental del resto de la tabla. */
  body.arrastrando-columna-sql, body.arrastrando-columna-sql * {
    cursor: var(--cursor-ajustar-h) !important;
    user-select: none !important;
  }
  /* Fila de total general, siempre al final de la tabla. */
  .fila-total-sql td { border-top: 2px solid var(--acento); background: color-mix(in srgb, var(--texto) 5%, transparent); }
  .fila-total-sql .celda-sql-valor { font-weight: 700; }

  /* Icono +/- de agrupar/desagrupar (en cabeceras y en celdas de la
     primera columna de cada nivel de agrupacion automatica). Se destaca
     con color de acento para que sea facil de localizar entre los datos. */
  .icono-grupo-sql {
    display: inline-flex; align-items: center; justify-content: center; width: 15px; height: 15px;
    border: 1px solid var(--acento); border-radius: 4px; background: color-mix(in srgb, var(--acento) 22%, transparent);
    color: var(--acento); font-weight: 700; font-size: 12px; line-height: 1; cursor: pointer; user-select: none;
    flex: none; vertical-align: middle;
  }
  .icono-grupo-sql:hover { background: var(--acento); color: #fff; }
  /* Envoltorio de icono+valor en la celda de agrupacion: en LINEA, alineados
     verticalmente, sin que el <div> de valor (de bloque) empuje a una
     segunda linea. */
  .celda-grupo-sql-envoltorio { display: flex; align-items: center; gap: 6px; min-width: 0; }
  .celda-grupo-sql-envoltorio .celda-sql-valor { min-width: 0; flex: 1; }
  th .icono-grupo-sql { margin-right: 6px; }
  .fila-grupo-sql td { background: color-mix(in srgb, var(--texto) 3.5%, transparent); }
  .fila-grupo-sql .celda-sql-valor { font-weight: 600; }

  /* Altura reservada SIEMPRE (nunca se quita del flujo con "oculto") --
     asi mostrarla/ocultarla nunca encoge ni desplaza el resto del modal.
     Lo unico que cambia es la opacidad/animacion del relleno. */
  /* Sin actividad, el "carril" de la barra debe casi no notarse (antes
     tenia el mismo fondo oscuro #0d1015 que la tabla de resultados, que
     contrastaba con el fondo del panel y se veia como una linea siempre
     visible aunque no hubiera nada cargando) -- solo se oscurece de
     verdad mientras esta realmente activa, a la vez que aparece el
     relleno animado. */
  #barra-progreso-sql-infinita, .barra-progreso-infinita {
    flex: none; height: 4px; border-radius: 999px; overflow: hidden; margin-top: 10px; position: relative;
    background: color-mix(in srgb, var(--texto) 3%, transparent);
    transition: background-color .2s ease;
  }
  #barra-progreso-sql-infinita.activa, .barra-progreso-infinita.activa {
    background: var(--fondo-editor);
  }
  #barra-progreso-sql-infinita .relleno, .barra-progreso-infinita .relleno {
    position: absolute; top: 0; bottom: 0; width: 40%; border-radius: 999px;
    background: linear-gradient(135deg, var(--acento), var(--acento-2));
    opacity: 0;
  }
  #barra-progreso-sql-infinita.activa .relleno, .barra-progreso-infinita.activa .relleno {
    opacity: 1;
    animation: barra-progreso-sql-anim 1.1s ease-in-out infinite;
  }
  @keyframes barra-progreso-sql-anim {
    0% { left: -40%; }
    100% { left: 100%; }
  }

  /* ---- Documentación ("Wiki") de un cliente de API: contenido de un
     capítulo (modal de administración, vista pública "/?wiki=..." y el
     "espejo" de impresión #imprimir-documentacion -- mismas reglas los
     tres sitios, para que lo impreso se parezca a lo que se ve en pantalla). ---- */
  #contenido-capitulo-documentacion, #wiki-publica-contenido, #imprimir-documentacion {
    line-height: 1.55;
  }
  #contenido-capitulo-documentacion h2, #wiki-publica-contenido h2, #imprimir-documentacion h2 {
    font-size: 18px; margin: 0 0 12px;
  }
  #contenido-capitulo-documentacion h3, #wiki-publica-contenido h3, #imprimir-documentacion h3 {
    font-size: 14px; margin: 22px 0 6px; color: var(--texto);
  }
  #contenido-capitulo-documentacion p, #wiki-publica-contenido p, #imprimir-documentacion p {
    color: var(--texto-suave); margin: 0 0 10px;
  }
  #contenido-capitulo-documentacion code, #wiki-publica-contenido code, #imprimir-documentacion code {
    background: var(--panel-2); border: 1px solid var(--borde); border-radius: 4px;
    padding: 1px 5px; font-size: 12.5px; color: var(--texto);
    overflow-wrap: anywhere; word-break: break-word;
  }
  #contenido-capitulo-documentacion a, #wiki-publica-contenido a, #imprimir-documentacion a {
    color: var(--acento);
  }
  .doc-codigo {
    background: var(--fondo-editor); border: 1px solid var(--borde); border-radius: 6px;
    padding: 10px 12px; margin: 0 0 16px; overflow-x: auto;
    /* #contenido-capitulo-documentacion / #wiki-publica-contenido son
       "display:flex;flex-direction:column" con altura fija (ver mas abajo)
       -- al llevar overflow-x:auto, el navegador promociona tambien
       overflow-y a "auto" (regla del spec de CSS Overflow), y eso hace que
       el "automatic minimum size" del bloque como hijo flex pase a ser 0 en
       vez de su alto de contenido, así que en capitulos largos (como "Cómo
       conectarse" con varios ejemplos) flexbox lo encogia hasta casi 0px en
       vez de dejar que el contenedor hiciera scroll. flex-shrink:0 lo fija
       a su alto natural, que es lo que se quiere siempre para un bloque de
       código.
    */
    flex-shrink: 0;
  }
  .doc-codigo code {
    background: none; border: none; padding: 0; font-size: 12.5px; line-height: 1.7;
    white-space: pre-wrap; overflow-wrap: anywhere; word-break: break-word;
  }
  /* Coloreado de los bloques de ejemplo "curl" del capitulo "Como
     conectarse" (ver doc_tok_cmd/doc_tok_str/doc_colorear_json_curl en
     backend.php) -- misma paleta y mismo motivo que .sql-tok-* del editor
     SQL (solo color, nunca peso/estilo, ver comentario junto a esas
     reglas): comando/flags (curl, -X, -H, -d) en el mismo tono que las
     palabras reservadas SQL, cadenas entre comillas (URLs, cabeceras,
     claves/valores del JSON) en el mismo tono que los literales SQL, y
     numeros sueltos del JSON en el mismo tono que los numeros SQL. */
  .doc-tok-cmd { color: var(--codigo-reservada); }
  .doc-tok-str { color: var(--codigo-literal); }
  .doc-tok-num { color: var(--codigo-numero); }
  /* Scrollbar propia (mas visible) para la barra lateral del modal
     "Ejemplos SQL" -- la regla global "* { scrollbar-color: var(--borde)
     transparent; }" (ver mas arriba) practicamente no se ve aqui: el color
     del "thumb" (--borde) y el fondo del propio modal (gradiente
     --panel/--panel-2) son casi el mismo tono oscuro, asi que con la
     barra fina de por defecto el usuario no tenia forma de notar que la
     lista de ejemplos scrollea cuando hay mas de los que caben. Se usa
     --texto-suave (mismo color que el texto secundario, con contraste de
     sobra sobre el fondo del panel) y "overflow-y:scroll" en vez de
     "auto" en el elemento (ver index.php) para que el hueco de la barra
     se reserve siempre, en vez de aparecer/desaparecer segun haya o no
     contenido que scrollear. */
  #sidebar-ejemplos-sql-cliente-api { scrollbar-color: var(--texto-suave) transparent; }
  #sidebar-ejemplos-sql-cliente-api::-webkit-scrollbar-thumb { background: var(--texto-suave); }
  #sidebar-ejemplos-sql-cliente-api::-webkit-scrollbar-thumb:hover { background: var(--acento); }
  .doc-codigo-copiable {
    position: relative;
  }
  .doc-codigo-copiable .doc-codigo {
    padding-right: 70px;
  }
  .doc-codigo-copiable .doc-boton-copiar {
    position: absolute; top: 8px; right: 8px;
    background: var(--panel); border: 1px solid var(--borde);
  }
  .doc-tabla {
    width: 100%; border-collapse: collapse; margin: 6px 0 18px; font-size: 13px;
    table-layout: fixed;
  }
  .doc-tabla th, .doc-tabla td {
    text-align: left; padding: 6px 10px; border-bottom: 1px solid var(--borde);
    white-space: normal; overflow: visible; overflow-wrap: anywhere; word-break: break-word;
  }
  .doc-tabla th {
    color: var(--texto-suave); font-weight: 600; font-size: 12px;
  }
  .doc-tabla-resumen td:first-child {
    color: var(--texto-suave); width: 260px;
  }
  .doc-tabla-resumen-schema th:nth-child(2), .doc-tabla-resumen-schema td:nth-child(2),
  .doc-tabla-resumen-schema th:nth-child(3), .doc-tabla-resumen-schema td:nth-child(3) {
    width: 120px;
  }
  .doc-meta { color: var(--texto-suave); font-size: 12.5px; margin: 0 0 6px; }
  .doc-vacio { color: var(--texto-suave); font-style: italic; }
  /* Listas de viñetas de la guía de subida de ficheros ("Formato del
     fichero", "Limitaciones conocidas" -- ver
     construir_capitulos_documentacion_apikey() en backend.php). Mismo
     color de texto secundario que los párrafos de al lado (<p> de
     #contenido-capitulo-documentacion ya lo tiene, pero <ul>/<li> no
     heredan margin/color por defecto del navegador). */
  .doc-lista { color: var(--texto-suave); margin: 0 0 16px; padding-left: 20px; }
  .doc-lista li { margin-bottom: 8px; }
  .doc-lista li:last-child { margin-bottom: 0; }
  .doc-lista strong { color: var(--texto); }

  /* OJO: no poner aquí "height:100vh" a secas -- el body tiene
     "padding:24px 20px" (ver arriba), la misma regla base de .app-shell
     ya lo descuenta con "calc(100vh - 48px)"; un 100vh sin descontarlo
     hace que el app-shell entero se salga del viewport por esos 48px de
     más (bug real visto en la vista pública "wiki": el pie de la tarjeta
     -- y con él, el panel de resultados de "API Test" -- quedaba cortado
     por el borde de la ventana). Esta regla solo existía para asegurar
     que el shell ocupe SIEMPRE toda la altura disponible en esta vista
     (a diferencia del resto del panel, donde con poco contenido el
     shell podía quedarse más bajo) -- que es justo lo que ya hace la
     regla base, así que directamente no hace falta ningún override aquí. */

  /* ---- Impresión (Ctrl+P) de una documentación de cliente de API ----
     El contenido real vive siempre en #imprimir-documentacion (rellenado
     por construirImpresionDocumentacion() en panel.js con portada + TODOS
     los capítulos seguidos, generado tanto desde el modal de admin como
     desde la vista pública) -- en pantalla está oculto ("solo-impresion");
     al imprimir se oculta todo lo demás (todos los modales y vistas son
     hijos directos de <body>) y se fuerza el modo claro, sea cual sea el
     tema activo en pantalla en ese momento. */
  .solo-impresion { display: none; }
  /* Margen de pagina mas amplio (arriba/abajo/izquierda/derecha) que el que
     trae Chrome por defecto -- @page se aplica cuando el desplegable
     "Margenes" del dialogo de impresion esta en "Predeterminados". */
  @page {
    margin: 2.5cm 2cm;
  }
  @media print {
    :root {
      --bg: #ffffff; --panel: #ffffff; --panel-2: #f3f4f7; --borde: #d3d8e0;
      --texto: #14161a; --texto-suave: #4b5262; --acento: #2a4fc9; --acento-2: #5a34b5;
      --fondo-editor: #f3f4f7;
      /* Los tres colores de resaltado de los bloques "curl" (ver
         doc_tok_cmd/doc_tok_str/doc_colorear_json_curl en backend.php)
         se quedaban con sus valores del TEMA OSCURO (--codigo-reservada
         etc. de ":root" arriba, pensados para leerse sobre fondo oscuro,
         ver linea ~22) porque este bloque de impresion nunca los
         redefinia -- resultado: en el PDF/papel (fondo blanco) salian
         unos tonos pastel casi lavados, sin contraste. Mismos valores
         oscuros que ya usa el tema claro en pantalla (ver ":root[data-tema=claro]"
         mas arriba, linea ~51), para que impresion y tema claro se vean
         igual de legibles. */
      --codigo-reservada: #7c3aed; --codigo-literal: #15803d; --codigo-numero: #c2410c;
    }
    body > *:not(#imprimir-documentacion) { display: none !important; }
    body { background: #fff !important; padding: 0 !important; }
    .solo-impresion { display: block !important; max-width: 100%; margin: 0; padding: 0 28px; }
    .imprimir-portada {
      text-align: center; padding: 120px 20px 60px; page-break-after: always;
    }
    .imprimir-portada img { max-height: 110px; max-width: 300px; margin-bottom: 32px; }
    .imprimir-portada h1 { font-size: 26px; margin: 0 0 6px; }
    .imprimir-portada h2 { font-size: 18px; font-weight: 500; color: #4b5262; margin: 0 0 28px; }
    .imprimir-portada p { color: #4b5262; margin: 4px 0; }
    .imprimir-capitulo { page-break-before: always; padding-top: 20px; }
    .imprimir-capitulo:first-of-type { page-break-before: auto; }
    .imprimir-capitulo > h1 { font-size: 20px; border-bottom: 2px solid #d3d8e0; padding-bottom: 8px; margin-bottom: 16px; }
    #imprimir-documentacion a { color: #2a4fc9; text-decoration: none; }
    #imprimir-documentacion table, #imprimir-documentacion .doc-codigo { page-break-inside: avoid; }
  }
  #wiki-publica-contenido { padding: 20px 28px; }