/* ===================================================================
   TEMA
   Tres estados: por defecto se sigue al sistema (`prefers-color-scheme`);
   si la persona elige a mano, `<html>` lleva data-theme="light|dark" y esa
   elección manda sobre el sistema en ambas direcciones.

   Regla al tocar esto: NINGÚN color puede definirse SOLO dentro del bloque
   oscuro o de la media query. Todo se declara aquí, en :root, y allí solo se
   redefine. Si no, el tema claro se queda sin ese color.

   Los tonos de texto cumplen el contraste AA (4,5:1) al tamaño pequeño en que
   se usan: `muted` aparece a 11-12 px y `ok`/`warn` van además sobre los fondos
   tintados de los badges, que reducen el contraste respecto al fondo.
   =================================================================== */
:root {
    color-scheme: light;
    --bg: #f4f6f8;
    --panel: #ffffff;
    --surface: #ffffff;       /* campos, tablas, desplegables */
    --surface-2: #f0f4f8;     /* cabeceras de tabla, encabezados suaves */
    --surface-3: #f7fafd;     /* fila al pasar el ratón, citas */
    --surface-hover: #eef6fc; /* botón fantasma y opción de autocompletado */
    --ink: #1c2733;
    --on-accent: #ffffff;     /* texto sobre un fondo de color (botones) */
    --muted: #5b6b7b;         /* 5,5:1 sobre blanco */
    --line: #dde3e9;
    --line-soft: #eef2f6;     /* separadores internos de tabla */
    --focus-ring: #bcd8f0;
    --accent: #0a6ebd;        /* 5,3:1 */
    --accent-dark: #075a99;
    --ok: #177a44;            /* 5,4:1 sobre blanco · 4,7:1 sobre el verde del badge */
    --warn: #96610a;          /* 5,2:1 */
    --danger: #c0392b;        /* 5,4:1 sobre blanco · 4,6:1 sobre el rojo del badge */
    --tint-ok: #e2f5ea;
    --tint-err: #fbe7e5;
    --tint-warn: #fdf9ef;
    --tint-na: #eef1f4;
    --tint-sel: #fbe1de;      /* fila seleccionada (tabla ↔ mapa) */
    --tint-pk: #dcecfa;
    --tint-fk: #f3e8fb;
    --ink-fk: #7a3fa0;
    --ink-sin: #7d6a2f;       /* «sin descripción» del esquema */
    --sombra: rgba(0,0,0,.12);
    --radius: 8px;
}

/* Paleta oscura. Se aplica por sistema salvo que se haya elegido «claro» a mano. */
@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) {
        color-scheme: dark;
        --bg: #121a21;
        --panel: #1a242e;
        --surface: #1a242e;
        --surface-2: #22303c;
        --surface-3: #1f2b36;
        --surface-hover: #26323e;
        --ink: #e4ebf1;          /* 14,6:1 sobre el fondo */
        --on-accent: #0b1620;    /* el acento claro pide texto OSCURO encima */
        --muted: #9aacbd;        /* 7,5:1 */
        --line: #33434f;
        --line-soft: #2a3742;
        --focus-ring: #2b6ea8;
        --accent: #4da3e8;       /* 6,5:1 · el azul oscuro no se lee sobre fondo oscuro */
        --accent-dark: #7cc0f5;
        --ok: #4cc98a;
        --warn: #e0a63c;
        --danger: #ef7d70;
        --tint-ok: #14301f;
        --tint-err: #35201d;
        --tint-warn: #33290f;
        --tint-na: #232f3a;
        --tint-sel: #3d2422;
        --tint-pk: #16304a;
        --tint-fk: #2e2140;
        --ink-fk: #c9a4e8;
        --ink-sin: #c2ab63;
        --sombra: rgba(0,0,0,.5);
    }
}

/* Elección manual de «oscuro»: gana también si el sistema está en claro. */
:root[data-theme="dark"] {
    color-scheme: dark;
    --bg: #121a21;
    --panel: #1a242e;
    --surface: #1a242e;
    --surface-2: #22303c;
    --surface-3: #1f2b36;
    --surface-hover: #26323e;
    --ink: #e4ebf1;
    --on-accent: #0b1620;
    --muted: #9aacbd;
    --line: #33434f;
    --line-soft: #2a3742;
    --focus-ring: #2b6ea8;
    --accent: #4da3e8;
    --accent-dark: #7cc0f5;
    --ok: #4cc98a;
    --warn: #e0a63c;
    --danger: #ef7d70;
    --tint-ok: #14301f;
    --tint-err: #35201d;
    --tint-warn: #33290f;
    --tint-na: #232f3a;
    --tint-sel: #3d2422;
    --tint-pk: #16304a;
    --tint-fk: #2e2140;
    --ink-fk: #c9a4e8;
    --ink-sin: #c2ab63;
    --sombra: rgba(0,0,0,.5);
}

* { box-sizing: border-box; }

body {
    margin: 0;
    font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
    color: var(--ink);
    background: var(--bg);
    font-size: 15px;
    line-height: 1.5;
}

a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }

/* Topbar */
/* `min-height` y no `height`: el menú tiene 10 entradas y envuelve en ventanas
   estrechas; con altura fija la segunda línea se salía y pisaba el contenido. */
/* La barra superior es oscura en los dos temas a propósito: es el ancla visual de
   la aplicación y así el cambio de tema no la hace «saltar». Por eso sus colores
   NO son variables de tema. */
.topbar {
    display: flex; align-items: center; gap: 24px; flex-wrap: wrap;
    background: #0e2233; color: #fff;
    padding: 6px 20px; min-height: 54px;
}
.brand { font-weight: 700; color: #fff; }
.brand:hover { text-decoration: none; }

/* Primer tabulador de la página: permite saltarse el menú de 10 entradas.
   Fuera de pantalla hasta que recibe el foco. */
/* `fixed` y no `absolute`: con absolute, al tabular con la página desplazada el
   enlace aparecería en la parte superior del DOCUMENTO, es decir, fuera de la vista. */
/* Se esconde con translateY(-100%) en vez de un `top` negativo fijo: así no hay
   que acertar la altura del enlace (con `top:-60px` asomaban 5px en cada página,
   y cualquier cambio de tipografía volvería a descuadrarlo). */
.skip-link {
    position: fixed; left: 8px; top: 0; z-index: 100;
    transform: translateY(-110%);
    background: var(--accent); color: var(--on-accent); padding: 10px 14px;
    border-radius: 0 0 6px 6px; transition: transform .12s;
}
.skip-link:focus { transform: translateY(0); text-decoration: none; }
.mainnav { display: flex; gap: 4px; flex-wrap: wrap; }
.mainnav a {
    color: #cdd8e2; padding: 8px 12px; border-radius: 6px; font-size: 14px;
}
.mainnav a:hover { background: rgba(255,255,255,.1); text-decoration: none; }
.mainnav a.active { background: var(--accent); color: var(--on-accent); }

/* Botón «☰ Menú». Nunca se ve en pantalla ancha; en estrecha lo enciende la
   media query de más abajo, y solo si el JS ha marcado `js-nav`. Comparte
   aspecto con el botón de tema: van juntos sobre el fondo oscuro fijo de la
   barra, así que sus colores tampoco salen de las variables de tema. */
.nav-toggle {
    display: none; align-items: center; gap: 6px;
    background: rgba(255,255,255,.1); border: 1px solid rgba(255,255,255,.18);
    color: #fff; cursor: pointer; font-size: 14px; line-height: 1;
    padding: 8px 12px; border-radius: 6px;
}
.nav-toggle:hover { background: rgba(255,255,255,.18); }

/* ---- Menú plegable en pantallas estrechas -------------------------------
   Todo cuelga de `.js-nav` (la pone initMenuMovil). Sin JS no se aplica nada de
   esto y el menú sigue envolviéndose en varias líneas: preferible a esconderlo
   sin dejar botón para abrirlo.
   El umbral es 760 px, el mismo que usan los formularios. Entre 760 y ~950 el
   menú de 10 entradas todavía envuelve en dos líneas, y eso se acepta: para una
   herramienta interna en una tablet es razonable, y bajar el umbral pondría una
   hamburguesa a quien solo tiene tres entradas visibles por permisos. */
@media (max-width: 760px) {
    .topbar { gap: 10px; }
    /* `min-height` y no más relleno: es el control principal en un móvil y debe
       llegar a los 44px de objetivo táctil sin engordar el texto. */
    .js-nav .nav-toggle { display: inline-flex; min-height: 44px; }
    .js-nav .mainnav { display: none; }
    /* Al abrirse ocupa una fila entera y se apila: diez enlaces en horizontal en
       un móvil son inpulsables. No se reordena nada con `order` a propósito —
       el orden de tabulación sigue al DOM, no a la vista, y separarlos dejaría
       el foco saltando por la pantalla. */
    .js-nav .mainnav.abierto {
        display: flex; flex-direction: column; width: 100%; gap: 2px; padding-bottom: 6px;
    }
    /* 12px arriba y abajo dejan el enlace en 45px de alto: con 10px se quedaba en
       41 y el objetivo táctil recomendado son 44. Con el dedo se nota. */
    .js-nav .mainnav.abierto a { padding: 12px; }
}

/* Botón de tema (barra superior). Va sobre el fondo oscuro fijo de la barra, así
   que sus colores tampoco son variables de tema. */
.btn-tema {
    background: rgba(255,255,255,.1); border: 1px solid rgba(255,255,255,.18);
    color: #fff; cursor: pointer; font-size: 15px; line-height: 1;
    padding: 6px 9px; border-radius: 6px;
}
.btn-tema:hover { background: rgba(255,255,255,.2); }
.btn-tema .tema-icono { display: inline-block; }

/* Caja de usuario (derecha de la barra) */
.userbox { margin-left: auto; display: flex; align-items: center; gap: 10px; }
.userbox .uname { color: #cdd8e2; font-size: 13px; white-space: nowrap; padding: 6px 8px; border-radius: 6px; }
.userbox a.uname:hover { background: rgba(255,255,255,.1); text-decoration: none; }

/* Login / arranque */
.login-wrap { min-height: 100vh; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 14px; padding: 20px; }
.login-card { background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius); padding: 26px; width: 100%; max-width: 380px; box-shadow: 0 8px 30px var(--sombra); }
.login-brand { font-weight: 700; color: var(--ink); margin-bottom: 14px; }
.login-card h1 { font-size: 20px; margin: 0 0 6px; }
.login-card .field { margin-bottom: 14px; }
.login-card .field input { width: 100%; }
.login-foot { font-size: 12px; }

.container { max-width: 1200px; margin: 0 auto; padding: 22px 20px 60px; }
.page-title { margin: 4px 0 18px; font-size: 22px; }
.intro { margin: -10px 0 20px; color: var(--muted); font-size: 15px; max-width: 70ch; }

.footer { text-align: center; color: var(--muted); padding: 20px; font-size: 13px; }

/* Cards / panels */
.panel {
    background: var(--panel); border: 1px solid var(--line);
    border-radius: var(--radius); padding: 16px; margin-bottom: 18px;
}

/* Dashboard tiles */
.tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 14px; }
.tile {
    background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius);
    padding: 18px; text-align: center;
}
.tile .num { font-size: 30px; font-weight: 700; color: var(--accent); }
.tile .lbl { color: var(--muted); font-size: 13px; margin-top: 4px; }
/* Los KPI usan grid y no arrastran margen inferior: hay que separarlos de lo que sigue. */
.panel-tras-tiles { margin-top: 22px; }

/* Tablas resumen del panel de inicio */
.resumen-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 16px; align-items: start; }
.resumen-grid .panel { margin-bottom: 0; }
.resumen-grid h2 { font-size: 16px; margin: 0 0 2px; }
table.mini { width: 100%; border-collapse: collapse; font-size: 13px; }
table.mini td { padding: 6px 4px; border-bottom: 1px solid var(--line-soft); vertical-align: top; }
table.mini tr:last-child td { border-bottom: 0; }
.mini-k { white-space: nowrap; font-family: ui-monospace, "Consolas", monospace; width: 1%; }
.mini-v { width: 100%; }
.mini-n { text-align: right; white-space: nowrap; color: var(--accent-dark); }

/* Toolbar / filters */
.toolbar { display: flex; flex-wrap: wrap; gap: 10px; align-items: end; margin-bottom: 14px; }
.field { display: flex; flex-direction: column; gap: 4px; }
.field label { font-size: 12px; color: var(--muted); }
/* Hueco que alinea los botones de la toolbar con los campos etiquetados. Antes era
   un <label> vacío, que un lector de pantalla anuncia como una etiqueta sin nombre. */
.field .lbl-hueco { font-size: 12px; line-height: 1.5; }
input, select, textarea {
    font: inherit; padding: 7px 9px; border: 1px solid var(--line);
    border-radius: 6px; background: var(--surface); color: var(--ink);
}
/* El ancho mínimo es para campos de texto: aplicarlo también a casillas y a los
   selectores de archivo obligaba a parchear con `style="min-width:auto"`. */
input:not([type="checkbox"]):not([type="radio"]):not([type="file"]),
select, textarea { min-width: 140px; }
textarea { min-height: 60px; resize: vertical; width: 100%; }
input:focus, select:focus, textarea:focus { outline: 2px solid var(--focus-ring); border-color: var(--accent); }

/* Sin esto, tabular por la página no muestra dónde estás: los campos ya tenían
   indicador de foco, pero los botones y el menú no. */
a:focus-visible, .btn:focus-visible, button:focus-visible,
summary:focus-visible, [tabindex]:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
    border-radius: 4px;
}
.topbar a:focus-visible { outline-color: #fff; }

/* Buttons */
.btn {
    display: inline-block; cursor: pointer; border: 1px solid var(--accent);
    background: var(--accent); color: var(--on-accent); padding: 8px 14px; border-radius: 6px;
    font-size: 14px; text-decoration: none;
}
.btn:hover { background: var(--accent-dark); text-decoration: none; }
.btn.ghost { background: var(--surface); color: var(--accent); }
.btn.ghost:hover { background: var(--surface-hover); }
.btn.danger { background: var(--danger); border-color: var(--danger); }
.btn.small { padding: 4px 9px; font-size: 13px; }
/* Paginación en los extremos: antes parecían pulsables y no hacían nada. */
.btn:disabled, .btn[disabled] { opacity: .45; cursor: default; }
/* Un <a> no admite `disabled`; se marca con una clase (p. ej. exportar sin resultados). */
.btn.disabled { opacity: .45; pointer-events: none; }
.btn.ghost:disabled:hover { background: var(--surface); }

/* Texto solo para lectores de pantalla (encabezados de columnas de acciones, etc.). */
.sr-only {
    position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* Tables */
.table-wrap { overflow-x: auto; border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface); }
/* El `position: sticky` de los <th> no hacía NADA: solo funciona respecto a un
   contenedor que scrollee, y .table-wrap no tenía límite de altura. Los listados
   largos usan además .table-alta, que sí se lo da. */
/* El suelo de 320px no es decorativo: con una ventana muy baja (o un viewport que
   reporte altura 0), `70vh` deja el contenedor colapsado y la tabla desaparece. */
.table-alta { max-height: max(320px, 70vh); overflow-y: auto; }
table.data { border-collapse: collapse; width: 100%; font-size: 14px; }
table.data th, table.data td { padding: 8px 10px; border-bottom: 1px solid var(--line); text-align: left; white-space: nowrap; }
table.data th { background: var(--surface-2); position: sticky; top: 0; z-index: 1; }
table.data tr:hover td { background: var(--surface-3); }

/* Cabecera ordenable: un <button> real (lo construye initListado) que hereda el
   aspecto del <th> para que la tabla siga leyéndose como una tabla. Ocupa toda la
   celda —incluido el relleno, de ahí los márgenes negativos— para que el objetivo
   de clic sea la cabecera entera y no solo el texto. */
th .th-sort {
    all: unset;
    box-sizing: border-box;
    display: flex; align-items: center; gap: 6px;
    width: calc(100% + 20px); margin: -8px -10px; padding: 8px 10px;
    cursor: pointer;
}
th .th-sort:hover { background: var(--surface-3); }
/* El foco global de los botones va con `outline-offset: 2px`, por fuera; aquí el
   botón llena la celda, así que ese anillo lo recortaría el contenedor con
   overflow de `.table-alta` (misma trampa que las filas seleccionables). Dentro. */
th .th-sort:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
/* La flecha inactiva («↕») es un indicio de que se puede ordenar, no un dato:
   apagada para no competir con el nombre de la columna, pero con un color del
   tema y NO con `opacity`. Motivo: `tools/contraste.js` mide el color calculado,
   y la opacidad se aplica al componer, así que no la ve — un `opacity:.35` daba
   13,7:1 en la medición y ~2:1 en la pantalla, colándose por el auditor. */
.sort-ind { font-size: 11px; color: var(--muted); }
th[aria-sort="ascending"] .sort-ind,
th[aria-sort="descending"] .sort-ind { opacity: 1; color: var(--accent); }
th[aria-sort="ascending"], th[aria-sort="descending"] { color: var(--accent); }
table.data td.wrap { white-space: normal; max-width: 320px; }
/* Filas seleccionables (tabla de registros de la ficha de especie) */
table.data tbody.selectable tr { cursor: pointer; }
/* Son enfocables con tabulador (ver filasSeleccionables en app.js): sin un foco
   visible no se sabría sobre cuál se está. El outline por fuera se recortaría
   dentro del contenedor con overflow, así que se marca con un borde interior. */
table.data tbody.selectable tr:focus-visible {
    outline: none;
    box-shadow: inset 0 0 0 2px var(--accent);
}
table.data tbody.selectable tr.sel td,
table.data tbody.selectable tr.sel:hover td { background: var(--tint-sel); }

/* Cabecera de panel con acción a la derecha */
.panel-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap; }
.panel-head h2 { margin: 0; }
.ph-actions { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }

/* Fichas de lectura (especie_view / referencia_view) */
.view-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 14px; flex-wrap: wrap; margin-bottom: 8px; }
.view-head .sci { margin: 0 0 4px; font-size: 22px; }
.view-actions { display: flex; gap: 8px; flex-wrap: wrap; }
.subhead { margin: 18px 0 8px; font-size: 14px; text-transform: uppercase; letter-spacing: .04em; color: var(--accent-dark); }
.info-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: 10px 20px; }
.info-grid .kv { display: flex; flex-direction: column; gap: 2px; padding: 8px 0; border-bottom: 1px solid var(--line); }
.info-grid .kv .k { font-size: 12px; color: var(--muted); text-transform: uppercase; letter-spacing: .03em; }
.info-grid .kv .v { font-size: 15px; word-break: break-word; }
.cite { margin: 0; padding: 10px 12px; background: var(--surface-3); border-left: 3px solid var(--accent); border-radius: 4px; }

/* Pagination */
.pager { display: flex; gap: 8px; align-items: center; margin-top: 12px; flex-wrap: wrap; }
.pager .info { color: var(--muted); font-size: 13px; }
/* Selector de tamaño de página (lo crea initListado). `margin-left: auto` lo
   empuja al extremo opuesto de los botones: es un ajuste de la vista, no un paso
   de la navegación, y mezclarlo con «Anterior/Siguiente» invita a pulsarlo por error. */
.por-pagina {
    margin-left: auto; display: flex; align-items: center; gap: 6px;
    color: var(--muted); font-size: 13px; white-space: nowrap;
}
.por-pagina select { padding: 4px 6px; font-size: 13px; }

/* Badges */
.badge { display: inline-block; padding: 1px 8px; border-radius: 20px; font-size: 12px; }
.badge.si { background: var(--tint-ok); color: var(--ok); }
.badge.no { background: var(--tint-err); color: var(--danger); }
.badge.na { background: var(--tint-na); color: var(--muted); }

/* Forms */
.form-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 14px; }
.form-grid .full { grid-column: 1 / -1; }
@media (max-width: 760px) { .form-grid { grid-template-columns: 1fr; } }
fieldset { border: 1px solid var(--line); border-radius: var(--radius); padding: 14px; margin: 0 0 16px; }
legend { font-weight: 600; color: var(--accent-dark); padding: 0 6px; }

/* Dos fieldsets lado a lado (escritorio) */
.fieldset-row { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; align-items: start; }
.fieldset-row fieldset { margin-bottom: 16px; }
.fieldset-row .field { margin-bottom: 12px; }
.fieldset-row .field input { width: 100%; }
@media (max-width: 760px) { .fieldset-row { grid-template-columns: 1fr; } }
.form-actions { display: flex; gap: 10px; margin-top: 8px; }

/* Autocomplete */
/* El input queda envuelto en .ac-wrap, que corta el `stretch` del .field flex:
   sin esto se queda al ancho por defecto y desentona con los demás campos. */
.ac-wrap { position: relative; }
.ac-wrap input { width: 100%; }
.ac-list {
    position: absolute; z-index: 20; left: 0; right: 0; top: 100%;
    background: var(--surface); border: 1px solid var(--line); border-radius: 6px;
    max-height: 240px; overflow-y: auto; box-shadow: 0 6px 20px var(--sombra);
}
.ac-list div { padding: 7px 10px; cursor: pointer; font-size: 14px; }
.ac-list div:hover, .ac-list div.sel { background: var(--surface-hover); }

/* Map */
#map { height: clamp(320px, 65vh, 640px); border-radius: var(--radius); border: 1px solid var(--line); }
/* Leaflet no disponible (ver `_avisarSinMapa()` en map.js): el hueco se encoge al aviso. */
#map[data-off] { height: auto; border: 0; }
.map-off {
    margin: 0; padding: 22px; text-align: center; color: var(--muted);
    background: var(--panel); border: 1px dashed var(--line); border-radius: var(--radius);
}

/* Coordenadas del formulario de registro: barra de acciones, minimapa y
   diagnóstico de ecorregión (registro_form.php). */
.coord-barra { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-top: 12px; }
.mini-mapa { height: 300px; margin-top: 10px; border-radius: var(--radius); border: 1px solid var(--line); }
.mini-mapa[data-off] { height: auto; border: 0; }
.eco-box { margin-top: 12px; padding: 10px 12px; border-radius: 6px; font-size: 14px; border-left: 3px solid var(--line); background: var(--surface-3); }
.eco-box.ok       { border-left-color: var(--ok); background: var(--tint-ok); }
.eco-box.fuera    { border-left-color: var(--danger); background: var(--tint-err); }
.eco-box.pendiente { border-left-color: var(--muted); background: var(--surface-3); }

/* Estadísticas / gráficos */
.charts-grid { display: grid; grid-template-columns: repeat(6, 1fr); gap: 18px; margin-top: 18px; }
.chart-card {
    grid-column: span 2;                 /* por defecto: 1/3 del ancho */
    background: var(--panel); border: 1px solid var(--line);
    border-radius: var(--radius); padding: 16px;
}
.chart-card.chart-wide { grid-column: 1 / -1; }          /* ancho completo */
.chart-card.chart-phylum { grid-column: span 3; }         /* mitad del ancho (~1,5×) */
.chart-card h2 { margin: 0 0 2px; font-size: 16px; }
.chart-card .sub { color: var(--muted); font-size: 12px; margin-bottom: 12px; }
.chart-box { position: relative; height: 300px; }
.chart-card.chart-wide .chart-box { height: 340px; }
.chart-card.chart-phylum .chart-box { height: 380px; }     /* también más alto (~2× área) */
@media (max-width: 900px) {
    .charts-grid { grid-template-columns: 1fr; }
    .chart-card, .chart-card.chart-wide, .chart-card.chart-phylum { grid-column: 1 / -1; }
}

/* Esquema de la base de datos (esquema.php) */
.esq-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(340px, 1fr)); gap: 16px; align-items: start; }
.esq-card { background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden; }
.esq-card:target { border-color: var(--accent); box-shadow: 0 0 0 3px var(--focus-ring); }
.esq-head { display: flex; justify-content: space-between; align-items: baseline; gap: 8px;
            background: var(--surface-2); border-bottom: 1px solid var(--line); padding: 9px 12px; }
.esq-nombre { font-weight: 700; font-family: ui-monospace, "Consolas", monospace; }
.esq-filas { color: var(--muted); font-size: 12px; white-space: nowrap; }
.esq-cols { width: 100%; border-collapse: collapse; font-size: 13px; }
.esq-cols td { padding: 6px 10px; border-bottom: 1px solid var(--line-soft); vertical-align: top; }
.esq-cols tr:last-child td { border-bottom: 0; }
.esq-k { width: 46px; white-space: nowrap; }
.esq-n { font-family: ui-monospace, "Consolas", monospace; }
.esq-pk { font-weight: 700; }
.esq-fk { font-style: italic; }
.esq-ref { font-size: 11px; margin-left: 6px; font-family: system-ui, sans-serif; }
.esq-desc { font-family: system-ui, sans-serif; font-size: 11px; color: var(--muted);
            max-width: 210px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; margin-top: 1px; }
.esq-desc.sin { font-style: italic; color: var(--ink-sin); }
.esq-t { color: var(--muted); font-size: 11px; white-space: nowrap; text-align: right; }
.esq-p { text-align: right; width: 46px; }
.kbadge { display: inline-block; font-size: 10px; font-weight: 700; padding: 1px 4px; border-radius: 3px; margin-right: 2px; }
.kbadge.pk { background: var(--tint-pk); color: var(--accent-dark); }
.kbadge.fk { background: var(--tint-fk); color: var(--ink-fk); }
.pct { font-size: 11px; color: var(--ok); }
.pct.medio { color: var(--warn); }
.pct.bajo { color: var(--danger); }
.mermaid { background: transparent; }

/* Estado del sistema (salud.php) */
.chk-lista { display: flex; flex-direction: column; gap: 2px; }
.chk { display: flex; gap: 12px; padding: 11px 12px; border-radius: 6px; align-items: flex-start; }
.chk + .chk { border-top: 1px solid var(--line); }
.chk-icono { flex: 0 0 22px; height: 22px; border-radius: 50%; display: flex; align-items: center;
             justify-content: center; font-weight: 700; font-size: 13px; color: #fff; }
.chk-ok    .chk-icono { background: var(--ok); }
.chk-aviso .chk-icono { background: var(--warn); }
.chk-error .chk-icono { background: var(--danger); }
.chk-error { background: var(--tint-err); }
.chk-aviso { background: var(--tint-warn); }
.chk-titulo { font-weight: 600; }
.chk-detalle { color: var(--muted); font-size: 13px; margin-top: 2px; }
.chk-accion { font-size: 13px; margin-top: 6px; }
.chk-accion code { background: var(--line-soft); padding: 1px 5px; border-radius: 3px; }

/* Misc */
.muted { color: var(--muted); }
/* Familia de notas explicativas. Existen porque el mismo párrafo apagado estaba
   escrito a mano con márgenes ligeramente distintos en ~17 sitios: cada uno
   inventaba su espaciado y ninguno coincidía con el de al lado.
   - `.nota`       va DESPUÉS del contenido (nota al pie de un panel), a 12 px.
   - `.nota-intro` va ANTES: bajo un encabezado y sobre lo que explica. **Conserva
     el tamaño del cuerpo (15 px) a propósito**: son párrafos de dos o tres líneas
     con enlaces, que se leen de verdad. Apagarlos de color ya los pone en segundo
     plano; encogerlos además a 12 px sería empeorar lo que veníamos a arreglar.
   - `.nota-top`   modificador para pegarla a lo que tiene encima. */
.nota { color: var(--muted); font-size: 12px; margin: 10px 0 0; }
.nota-intro { color: var(--muted); margin: 2px 0 12px; }
.nota-top { margin-top: 0; }
/* Texto secundario en línea (dentro de una celda, junto a un nombre). Unifica en
   12 px los `font-size:11px` y `:12px` sueltos que había; 11 px era demasiado
   pequeño para un dato que se lee. `font-weight` normal porque alguno vive
   dentro de un `<th>`, que va en negrita. */
.muted-sm { color: var(--muted); font-size: 12px; font-weight: 400; }
/* Fila que separa grupos de permisos en la matriz de roles. Llevaba el color
   escrito a mano (`background:#f0f4f8`), que es el valor CLARO de --surface-2:
   en tema oscuro quedaba texto claro sobre fondo casi blanco, 1,09:1, ilegible.
   La tokenización del modo oscuro barrió el CSS pero no los `style=` del PHP. */
.fila-grupo { background: var(--surface-2); }
.right { text-align: right; }
.flash { padding: 10px 14px; border-radius: 6px; margin-bottom: 14px; }
.flash.ok { background: var(--tint-ok); color: var(--ok); }
.flash.err { background: var(--tint-err); color: var(--danger); }
/* Aviso intermedio (ni error ni todo correcto). Era un `style=` inline con dos
   colores fijos, que en tema oscuro quedaba ilegible. */
.flash.aviso { background: var(--tint-warn); color: var(--warn); }
/* Texto de alerta dentro de una tabla (hipótesis de lat/lon invertidas). */
.aviso-rojo { color: var(--danger); }
.spinner { color: var(--muted); font-size: 14px; padding: 20px; text-align: center; }

/* ===================================================================
   CURADURÍA DE DATOS
   Tarjetas de familia con su botón «Analizar» y la línea de estado del último
   análisis. Todos los colores salen de las variables de :root, así que el
   tema oscuro funciona sin un solo color propio (ver la advertencia del
   CLAUDE.md: nunca definir un color solo dentro del bloque oscuro).
   =================================================================== */
.cur-familias { display: flex; flex-direction: column; gap: 16px; }
/* La intro ocupa el ancho útil y deja el botón a la derecha sin estrujarlo. */
.view-head .nota-intro { max-width: 80ch; flex: 1 1 320px; }
.cur-familias .panel { margin-bottom: 0; }

/* Cabecera de la tarjeta: título + botón a la derecha. En móvil el botón cae
   debajo, alineado a la izquierda, en vez de comprimir el título. */
.cur-cab { display: flex; gap: 14px; align-items: flex-start; justify-content: space-between; flex-wrap: wrap; }
.cur-cab h2 { margin: 0 0 2px; }
.cur-cab .nota-intro { margin-bottom: 8px; max-width: 70ch; }

/* La letra de la familia (A..G) como distintivo. */
.cur-letra {
    display: inline-block; min-width: 24px; text-align: center;
    background: var(--tint-pk); color: var(--accent-dark);
    border-radius: 5px; padding: 0 6px; margin-right: 6px; font-size: 15px;
}

.cur-estado { font-size: 13px; color: var(--muted); margin-bottom: 10px; }
.cur-fecha b { color: var(--ink); font-weight: 600; }
.cur-nunca { font-style: italic; }
.cur-desact { color: var(--warn); font-weight: 600; }

/* Tabla de reglas dentro de la tarjeta: más apretada que una tabla de datos y
   sin cabecera pegajosa (aquí no hay scroll propio que la justifique). */
table.cur-reglas { font-size: 13px; }
table.cur-reglas th { position: static; }
table.cur-reglas td { padding: 6px 10px; vertical-align: top; }
table.cur-reglas .num-col { text-align: right; }
table.cur-reglas th.num-col { text-align: right; }
.cur-titulo { font-weight: 600; color: var(--ink); }
.cur-que { color: var(--muted); font-size: 12px; margin-top: 1px; max-width: 80ch; }
/* Una regla con casos pesa más que una en cero: el número en negrita basta,
   sin tintar la fila entera (serían siete tablas a rayas de colores). */
.cur-reglas tr.cur-hay .cur-n { font-weight: 700; color: var(--ink); }
.cur-reglas .cur-n { color: var(--muted); }

/* Marca de severidad: mismo lenguaje visual que los chequeos de salud.php. */
.cur-sev {
    display: inline-flex; align-items: center; justify-content: center;
    width: 18px; height: 18px; border-radius: 50%;
    font-size: 11px; font-weight: 700; color: var(--on-accent);
}
.cur-sev-error { background: var(--danger); }
.cur-sev-aviso { background: var(--warn); }
.cur-sev-info  { background: var(--muted); }
/* En la cabecera de la vista de casos la marca acompaña al <h2>. */
.cur-cab h2 .cur-sev, .view-head h2 .cur-sev { vertical-align: 2px; margin-right: 4px; }
/* La explicación de la regla, a tamaño de cuerpo: aquí es el contexto principal,
   no una nota al margen como en la tarjeta del resumen. */
.cur-que-largo { margin: 0 0 10px; max-width: 90ch; }
/* El conteo enlazado no debe parecer un enlace de texto suelto. */
.cur-n a { font-weight: 700; }
/* Nota del triaje: el motivo por el que alguien dio por bueno un caso. */
.cur-nota { color: var(--muted); font-size: 12px; margin-top: 2px; max-width: 40ch; }
/* Los botones de acción de una fila no deben partirse en dos líneas. */
table.data td.nowrap { white-space: nowrap; }
/* «13 de 24» cuando parte de los casos ya se han dado por buenos. */
.cur-de-total { color: var(--muted); font-weight: 400; font-size: 11px; }

/* ===================================================================
   IMPRESIÓN
   Pensado sobre todo para las fichas de lectura (especie y referencia), que son
   las páginas que tiene sentido llevarse en papel o en PDF a una reunión.
   Las reglas generales (ocultar barra y botones, tema claro) no estorban en el
   resto, así que se aplican a todo.
   =================================================================== */
@media print {
    /* Tema claro SIEMPRE. Sin esto, quien tenga el modo oscuro puesto imprime
       una página negra: ilegible en papel y un desperdicio de tinta.
       Solo se fuerzan los tokens que afectan a superficies y texto.

       ⚠️ Los tres selectores son necesarios y no sobra ninguno: `@media print`
       NO añade especificidad, así que un `:root` a secas PIERDE contra
       `:root:not([data-theme="light"])` de la media query oscura —que sigue
       activa al imprimir, porque `prefers-color-scheme` no cambia— y contra
       `:root[data-theme="dark"]`. Resultado sin esto: papel blanco con texto
       casi blanco. */
    :root,
    :root:not([data-theme="light"]),
    :root[data-theme="dark"] {
        color-scheme: light;
        --bg: #fff; --panel: #fff; --surface: #fff;
        --surface-2: #f2f2f2; --surface-3: #fafafa; --surface-hover: #fff;
        --ink: #000; --muted: #444; --line: #999; --line-soft: #ccc;
        --accent: #000; --accent-dark: #000; --on-accent: #fff;
        --sombra: transparent;
        /* Los tonos de estado también, o los badges salen como pastillas
           oscuras: un manchón de tinta y un texto claro ilegible en papel. */
        --ok: #157a43; --warn: #8a5a09; --danger: #b02a1c;
        --tint-ok: #eaf5ee; --tint-err: #fbecea; --tint-warn: #fdf6e8;
        --tint-na: #f0f0f0; --tint-sel: transparent;
        --tint-pk: #e8eef5; --tint-fk: #efe8f7;
        --ink-fk: #5b3480; --ink-sin: #6b5b28;
    }

    @page { margin: 1.5cm; }

    body { background: #fff; font-size: 11pt; }
    .container { max-width: none; padding: 0; }

    /* Fuera todo lo que no es contenido: navegar, editar o filtrar no se puede
       hacer en papel. */
    .topbar, .skip-link, .footer, .toolbar, .pager,
    .btn, .view-actions, .ph-actions button, .panel-head button,
    .leaflet-control-zoom, .leaflet-control-layers, #map-info,
    .instruccion-ui {                    /* «Haz clic en una fila…»: no aplica en papel */
        display: none !important;
    }

    /* Los paneles pasan a ser secciones sin caja, y no se parten a mitad. */
    .panel, .esq-card, .chart-card {
        border: 0; padding: 0; margin: 0 0 14pt;
        break-inside: avoid;
    }

    /* Las tablas sueltan el contenedor con altura limitada: en pantalla scrollea,
       en papel debe salir entera. */
    .table-wrap, .table-alta {
        max-height: none !important; overflow: visible !important;
        border: 0; border-radius: 0;
    }
    table.data { font-size: 9.5pt; }
    table.data th { position: static; background: var(--surface-2); }
    /* El indicador de ordenación es un control, no un dato: en papel sobra. El
       nombre de la columna se queda (el <button> solo aporta el clic). */
    .sort-ind { display: none; }
    th .th-sort { display: inline; margin: 0; padding: 0; width: auto; }
    /* La cabecera se repite en cada página del listado. */
    table.data thead { display: table-header-group; }
    table.data tr { break-inside: avoid; }
    table.data td.wrap { white-space: normal; max-width: none; }

    /* El mapa sí es contenido en una ficha de especie: se conserva, pero con una
       altura de papel y sin los controles. La atribución de OpenStreetMap se
       mantiene: su licencia la exige. */
    #map { height: 10cm; border: 1px solid var(--line); }
    .mini-mapa { display: none; }        /* ese es una ayuda de edición, no un dato */

    .chart-box { height: 7cm; }

    /* En papel un enlace no se puede pulsar: se escribe la dirección al lado.
       Solo los externos (DOI, WoRMS) y solo en las zonas de metadatos —cabecera
       de la ficha, rejilla de datos y cita—, o el texto se vuelve ilegible. */
    .view-head a[href^="http"]::after,
    .info-grid a[href^="http"]::after,
    .cite a[href^="http"]::after {
        content: " (" attr(href) ")";
        font-size: 8.5pt; color: var(--muted); word-break: break-all;
    }

    /* Las filas seleccionadas en pantalla no significan nada impresas. */
    table.data tbody.selectable tr.sel td { background: transparent; }
    a { color: #000; text-decoration: none; }
    .badge { border: 1px solid var(--line); }
}

/* Formulario de carga de capa geográfica (salud.php) */
.capa-form { display: flex; flex-wrap: wrap; gap: 14px; align-items: end; }
.capa-form label { display: flex; flex-direction: column; gap: 4px; font-size: 12px; color: var(--muted); }
.capa-form .capa-check { flex-direction: row; align-items: center; gap: 6px; font-size: 14px; color: var(--ink); }

/* ── Reporte por área ──────────────────────────────────────────────────
   Pestañas de las tres tablas de resultado y el anexo plegable. El resto
   de la página reutiliza .panel / .toolbar / .table-wrap / .tiles, así que
   aquí solo hay lo que de verdad es nuevo.
   Todo el color sale de variables de :root; nada se define solo dentro del
   bloque oscuro (ver documentacion-tecnica §6).                          */
.area-tabs { display: flex; gap: 4px; flex-wrap: wrap; margin: 18px 0 0; border-bottom: 2px solid var(--line); }
.area-tab {
    background: transparent; border: 1px solid transparent; border-bottom: 0;
    border-radius: var(--radius) var(--radius) 0 0;
    padding: 8px 16px; font: inherit; color: var(--muted); cursor: pointer;
    margin-bottom: -2px;
}
.area-tab:hover { color: var(--text); background: var(--surface-2); }
.area-tab.activa {
    color: var(--accent-dark); font-weight: 600;
    background: var(--surface); border-color: var(--line); border-bottom: 2px solid var(--surface);
}
.area-tab:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.area-anexo { margin-top: 22px; border-top: 1px solid var(--line); padding-top: 14px; }
.area-anexo > summary { cursor: pointer; font-weight: 600; color: var(--accent-dark); }
.area-anexo > summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.area-informe { margin-top: 24px; padding-top: 16px; border-top: 1px solid var(--line); }
.area-informe textarea { width: 100%; max-width: 640px; font: inherit; }
.area-informe label { display: inline-flex; gap: 6px; align-items: baseline; }

.area-opciones { margin: 16px 0; border: 1px solid var(--line); border-radius: var(--radius);
                 padding: 10px 14px; background: var(--surface-3); }
.area-opciones > summary { cursor: pointer; font-weight: 600; color: var(--accent-dark); }
.area-opciones > summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.area-opciones .toolbar { margin-bottom: 6px; }
.op-check { display: inline-flex; gap: 6px; align-items: baseline; font-size: 14px; }
