/* style.css — Identidad Suite Centinela.
   Tema por defecto: OSCURO OCÉANO (body.dark). El claro usa la paleta papel de
   los 9 reportes.

   TIPOGRAFÍA — Geist (Vercel), la misma de ui.shadcn.com.
   Geist Sans para todo el texto y Geist Mono para las cifras: es un dúo pensado
   para interfaz densa, con figuras tabulares y una x-height alta que aguanta
   los 11-12 px del menú, que es donde vive casi todo este visor.

   Licencia SIL OFL 1.1, así que se autoaloja en /static/fonts (5 archivos,
   ~141 KB) y la regla dura de productos autocontenidos se mantiene: no hay CDN
   ni Google Fonts. Sustituye a Switzer, que a su vez sustituyó al serif Iowan
   Old Style. NO se usa ES Rebond Grotesque (le.mu): es de Extraset y su
   licencia cubre solo el dominio de Lemu.

   La variable sigue llamándose --display por el ROL (titular), no por la
   familia: la jerarquía se resuelve con peso y tracking, no cambiando de tipo.
*/

@font-face {
  font-family: 'Geist'; font-style: normal; font-weight: 300;
  font-display: swap; src: url('/static/fonts/geist-300.woff2') format('woff2');
}
@font-face {
  font-family: 'Geist'; font-style: normal; font-weight: 400;
  font-display: swap; src: url('/static/fonts/geist-400.woff2') format('woff2');
}
@font-face {
  font-family: 'Geist'; font-style: normal; font-weight: 500;
  font-display: swap; src: url('/static/fonts/geist-500.woff2') format('woff2');
}
@font-face {
  font-family: 'Geist'; font-style: normal; font-weight: 600;
  font-display: swap; src: url('/static/fonts/geist-600.woff2') format('woff2');
}
@font-face {
  font-family: 'Geist Mono'; font-style: normal; font-weight: 400;
  font-display: swap; src: url('/static/fonts/geist-mono-400.woff2') format('woff2');
}

:root {
  color-scheme: light;
  /* --- Neutros cálidos (papel de los reportes) --- */
  --paper: #F2EFE7;
  --bg: #F2EFE7;
  --fg: #17211F;            /* ink */
  --fg2: #3A423F;
  --muted: #5C584D;         /* ink-soft */
  --faint: #8F8A7E;
  --border: #D9D4C7;        /* line */
  --divider: #ECE7DB;       /* line-2 */
  --card-bg: #FBFAF5;
  --inner-card: #FBFAF5;
  --inner-border: #ECE7DB;
  --status-bg: #ECE7DB;
  --panel-bg: rgba(251, 250, 245, 0.96);
  --chip-bg: #E6EDE8;
  --zero-line: #D9D4C7;
  --eyebrow: #8F8A7E;
  --shadow: 0 1px 2px rgba(19,34,41,.05), 0 14px 34px rgba(19,34,41,.07);
  /* --- Los tres productos de la suite --- */
  --fan: #1E6E68;
  --o2: #1C5F8C;
  --enos: #4B4B8F;
  /* Meteo: arena tostada. Los otros tres productos son fríos (teal, azul,
     violeta) y un cuarto frío se confundiría con ellos; el ámbar del riesgo
     FAN queda lejos porque este es mucho menos saturado y no se usa en el
     mapa, solo en el menú. */
  --meteo: #8A6A3B;
  /* Centinela DOCS: grafito. Es el único producto cuyo objeto no es un dato del
     agua —son documentos— y un color de dato lo pondría a competir con los
     cuatro que sí pintan el mapa. */
  --docs: #55636B;
  /* Centinela BIO: verde musgo. Se separa del teal de FAN —que es agua— y del
     verde de RECICLA, que aún no tiene color por ser previsto. */
  --bio: #4F7A46;
  /* Los productos PREVISTOS (FISH, GEI, FLOW, RILes, RECICLA, FINANCE) no
     llevan color: el color de producto es lo que distingue una capa encendida
     en el mapa, y sin datos no hay nada que distinguir. Pintarlos los pondría
     al mismo nivel visual que los cinco que sí funcionan. El color se asigna
     cuando el producto tenga dato, no antes. */
  --accent: #1E6E68;
  --accent-hover: #2A8A82;
  /* --- Hero oceánico (constante en ambos temas) --- */
  --ocean-0: #0a2a2f;
  --ocean-1: #0b1620;
  --ocean-ink: #eaf3f2;
  /* --- Semáforo institucional (el mismo de los reportes) --- */
  --good: #2f8f5b; --warn: #c98a1a; --bad: #A63A2C; --deep: #3a5a8c;
  --nino: #A63A2C;   /* cálido / El Niño */
  --nina: #3a5a8c;   /* frío / La Niña */
  --neutral: #2f8f5b;
  /* Semáforo de riesgo FAN: es semántica del dato, no del chrome — se conserva */
  --risk-bajo: #22c55e; --risk-medio: #eab308; --risk-alto: #f59e0b;
  --risk-muy: #f97316; --risk-crit: #ef4444;
  /* --- Menú de capas (handoff design_handoff_menu_capas) ---------------
     Paleta propia del menú, no reemplaza la del resto de la app: el handoff
     define un tema completo pero solo especifica este componente, y tocar
     --fg/--border globalmente repintaría popups, paneles y gráficos sin que
     nadie lo haya revisado. */
  --nav: #FBFAF5;      /* fondo de riel y panel */
  --sunk: #ECE8DC;     /* fondo del buscador */
  --ink: #17211F;      /* texto principal */
  --nav-muted: #6C6759;/* texto secundario e iconos inactivos */
  --line: #DED8CA;     /* bordes y separadores */
  --teal: #1E6E68;     /* acento y estado activo */
  --onbg: #E4EDE9;     /* fondo de fila activa */
  --crit: #A63A2C;     /* punto de alerta — solo estado crítico */
  --nav-shadow: 0 20px 50px rgba(0,0,0,.3);
  /* --- Tipografía de marca: un grotesco titula y etiqueta, mono cifra ---
     --display sustituye al antiguo --serif: el rol (titular) sigue existiendo,
     lo que cambia es que ahora se resuelve con PESO y TRACKING sobre la misma
     familia, no con un cambio de familia. */
  --display: 'Geist', ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --font-ui: 'Geist', ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --font-mono: 'Geist Mono', ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-family: var(--font-ui);
}

/* --- Modo oscuro: el océano de la marca (gradiente del hero de los brochures) --- */
body.dark {
  color-scheme: dark;
  --paper: #0E1614;
  --bg: #0b1620;
  --bg-gradient: linear-gradient(165deg, #0a2a2f 0%, #0b1620 100%);
  --fg: #E9E3D6;
  --fg2: #C6CFC9;
  --muted: #98A09B;
  --faint: #7C837A;
  --border: #27302E;
  --divider: #1E2725;
  --card-bg: #15211E;
  --inner-card: rgba(255, 255, 255, 0.03);
  --inner-border: #27302E;
  --status-bg: rgba(255, 255, 255, 0.03);
  --panel-bg: rgba(11, 26, 29, 0.92);
  --chip-bg: rgba(127, 211, 201, 0.14);
  --zero-line: #2C3A38;
  --eyebrow: #7C837A;
  --shadow: 0 1px 2px rgba(0,0,0,.3), 0 18px 44px rgba(0,0,0,.42);
  --fan: #58B7AF;
  --o2: #5FB0DD;
  --enos: #9A9AD8;
  --meteo: #C4A87C;
  --accent: #7fd3c9;
  --accent-hover: #A5E3DB;
  --good: #5cc189; --warn: #e0ad55; --bad: #E0715F; --deep: #8fb0e0;
  --nino: #E0715F; --nina: #8fb0e0; --neutral: #5cc189;
  /* Menú de capas, tema oscuro (handoff) */
  --nav: #0F2126;
  --sunk: #0A1618;
  --ink: #EAF1EF;
  --nav-muted: #8CA0A2;
  --line: #1D3B40;
  --teal: #5FC3BA;
  --onbg: #123840;
  --crit: #E0715F;
}
body.dark { background: var(--bg-gradient), var(--bg); }

* { box-sizing: border-box; }
html, body { margin: 0; height: 100%; color: var(--fg); background: var(--bg); }

/* ==========================================================================
   Barra superior — identidad + filtros de la capa activa
   El mapa se DESPLAZA, no se tapa: una barra flotante sobre el lienzo dejaría
   los controles de Mapbox y la mitad del fiordo debajo de un vidrio, y aquí
   la barra es cromo permanente, no un panel que se abre y se cierra.
   ========================================================================== */
:root { --topbar-h: 52px; }

#topbar {
  position: absolute; top: 0; left: 0; right: 0; height: var(--topbar-h);
  z-index: 10; display: flex; align-items: center; gap: 18px;
  padding: 0 16px; box-sizing: border-box;
  background: var(--nav); border-bottom: 1px solid var(--line);
}
.tb-marca { display: flex; align-items: center; gap: 9px; text-decoration: none;
  flex: 0 0 auto; }
/* Ya no hay caja que redondear: el símbolo va suelto y toma el teal de la
   marca, que contrasta tanto sobre la barra clara como sobre la oscura. */
.tb-logo { width: 26px; height: 26px; flex: 0 0 auto; color: var(--teal); }
.tb-nom { font-family: var(--display); font-size: 17px; font-weight: 300;
  letter-spacing: -.022em; color: var(--ink); white-space: nowrap; }

/* Los filtros crecen desde la derecha: la marca queda anclada a la izquierda y
   la fila de controles no salta de sitio al aparecer o desaparecer uno. */
#tb-filtros { margin-left: auto; display: flex; align-items: center; gap: 10px;
  flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; }
#tb-filtros::-webkit-scrollbar { display: none; }

.tb-f { display: flex; align-items: center; gap: 6px; flex: 0 0 auto; }
.tb-disp {
  display: flex; align-items: center; gap: 6px;
  font-family: var(--font-ui); font-size: 12px; color: var(--ink);
  background: var(--sunk); border: 1px solid var(--line); border-radius: 7px;
  padding: 5px 8px; max-width: 150px; cursor: pointer; height: 28px;
}
.tb-disp > span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tb-disp-ch { width: 12px; height: 12px; flex: 0 0 auto; margin-left: auto;
  color: var(--nav-muted); }
.tb-disp:hover { border-color: var(--nav-muted); }
.tb-disp:focus-visible { outline: 2px solid var(--teal); outline-offset: 1px; }
/* Filtro con valor distinto de «todos»: se marca, para que no quede un filtro
   activo invisible escondiendo centros del mapa. */

/* Etiqueta del producto al que pertenecen los filtros mostrados. */
.tb-capa { font-family: var(--font-ui); font-size: 9px; font-weight: 600;
  letter-spacing: .14em; text-transform: uppercase; color: var(--nav-muted);
  white-space: nowrap; flex: 0 0 auto; }
.tb-sep { width: 1px; height: 18px; background: var(--line); flex: 0 0 auto; }

/* Botón de limpiar: solo existe si hay algún filtro puesto. */
#tb-limpiar { font-family: var(--font-ui); font-size: 11px; color: var(--nav-muted);
  background: none; border: none; cursor: pointer; padding: 4px 6px; border-radius: 7px;
  flex: 0 0 auto; }
#tb-limpiar:hover { color: var(--crit); background: rgba(166, 58, 44, .08); }

#map { position: absolute; inset: var(--topbar-h) 0 0 0; }

/* Selector de mapa base (flotante, arriba-centro) */
#basemap-switch { position: absolute; top: calc(var(--topbar-h) + 12px); left: 50%; transform: translateX(-50%);
  z-index: 5; display: flex; align-items: center; gap: 6px; padding: 5px 8px 5px 10px;
  background: var(--panel-bg); border: 1px solid rgba(56,189,248,.28); border-radius: 999px;
  box-shadow: 0 8px 24px rgba(0,0,0,.45); backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px); }
#basemap-switch .bm-ic { font-size: 13px; line-height: 1; opacity: .85; }
#basemap-switch select { background: transparent; color: var(--fg); border: none; outline: none;
  font-size: 12px; font-weight: 600; cursor: pointer; padding-right: 2px; }
#basemap-switch select option { background: var(--panel-bg); color: var(--fg); }

/* Canvas de partículas de corriente: sobre el mapa, no captura clics.
   Opacidad <1 para que la costa, etiquetas y centros respiren por debajo. */
.particle-canvas { position: absolute; inset: 0; pointer-events: none; z-index: 3; opacity: 0.9; }

/* --- Paneles genéricos --- */
.panel {
  position: absolute;
  background: var(--panel-bg);
  color: var(--fg);
  border: 1px solid var(--border);
  border-radius: 16px;
  box-shadow: var(--shadow);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  padding: 16px 16px;
  z-index: 5;
}
.panel h2 { font-family: var(--display); margin: 0 0 8px; font-size: 16px; font-weight: 500; letter-spacing: -.01em; }
/* Encabezado de sección estilo "eyebrow" */
.panel h3 { margin: 14px 0 8px; font-size: 10px; font-weight: 600; text-transform: uppercase; letter-spacing: .16em; color: var(--eyebrow); }

/* Cifras en fuente monoespaciada (jerarquía tipográfica del handoff) */
.enso-v, #time-label, #mosa-label,
.cp-row b, .cp-row em, .drv b, .meteo-wind, .obs b,
.gauge-num, .metric-v, .lg-pill { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }

/* Cabecera de controles: título + botón de tema */
.controls-head { display: flex; align-items: center; justify-content: space-between; }
.controls-head h3 { margin: 0; }
#theme-toggle {
  border: 1px solid var(--border); background: var(--card-bg); color: var(--fg);
  border-radius: 6px; padding: 3px 7px; font-size: 15px; line-height: 1; cursor: pointer;
}
#theme-toggle:hover { border-color: var(--accent); }


/* La barra superior anterior (#topbar + .tb-box/.tb-live/.tb-title/.tb-sub/
   .tb-updated/.tb-k) se eliminó: ningún HTML la usaba desde hace tiempo, y su
   `pointer-events: none` con z-index 6 ganaba por orden a la barra nueva y
   dejaba los selectores de filtro sin recibir el clic. */
#controls label { display: flex; align-items: center; gap: 8px; font-size: 12px; color: var(--fg2, var(--fg)); margin: 5px 0; cursor: pointer; }
#controls input[type="checkbox"] { accent-color: var(--accent); width: 14px; height: 14px; flex: 0 0 auto; }
.panel-eyebrow { margin: 0 !important; }

/* Grupos de capas colapsables (panel izquierdo) */
.lg-group { margin-bottom: 8px; border: 1px solid var(--inner-border); border-radius: 11px; overflow: hidden; }
.lg-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 10px 12px; cursor: pointer; background: var(--inner-card); user-select: none; }
.lg-head:hover { border-color: var(--accent); }
.lg-titles { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.lg-name { font-size: 12px; font-weight: 600; color: var(--fg); }
.lg-sub { font-size: 10px; color: var(--muted); }
.lg-meta { display: flex; align-items: center; gap: 9px; flex: 0 0 auto; }
.lg-pill { font-size: 10px; color: var(--muted); background: rgba(127,162,180,.14); border-radius: 20px; padding: 2px 8px; }
.lg-pill.on { color: var(--accent); background: var(--chip-bg); }
.lg-caret { font-size: 10px; color: var(--muted); transition: transform .2s; }
.lg-group.collapsed .lg-caret { transform: rotate(-90deg); }
.lg-body { padding: 6px 10px 10px; }
.lg-cap { margin: 7px 0 2px; font-size: 9px; font-weight: 600; letter-spacing: .06em; text-transform: uppercase; color: var(--muted); }
/* Fuente del dato entre paréntesis, después del nombre de cada capa (línea propia).
   Las filas de capa dejan de ser flex: con sangría francesa (padding + text-indent
   negativo) el nombre largo se parte bajo sí mismo en vez de saltar bajo la casilla. */
#controls .lg-body label { display: block; padding-left: 22px; text-indent: -22px; line-height: 1.35; }
#controls .lg-body label > input[type="checkbox"] { margin-right: 8px; vertical-align: middle; }
.lg-src { display: block; text-indent: 0; font-size: 10px; line-height: 1.3; color: var(--muted); }
.ecmwf-ctl { display: flex; gap: 6px; margin: 4px 0 2px; }
.ecmwf-ctl select { flex: 1; min-width: 0; font-size: 11px; padding: 3px 4px; }

/* Línea de tiempo de la animación (estilo Windy), abajo-centro */
/* Modo mundial (capas de Análisis Globales): el mapa queda fijo en zoom 1.
   Los gestos se desactivan por JS; aquí se apagan los botones +/− de Mapbox y
   se quita el cursor de arrastre para que se vea que no es navegable.
   (La atribución NO es .mapboxgl-ctrl-group: sigue visible y clickeable.) */
#map.world-locked .mapboxgl-canvas-container,
#map.world-locked .mapboxgl-canvas { cursor: default; }
#map.world-locked .mapboxgl-ctrl-group { opacity: .4; pointer-events: none; }
/* Sin regla propia el `.hidden` no aplicaría: en este proyecto no hay una
   `.hidden` genérica, cada componente define la suya. */
#world-lock.hidden, #local-zoom-lock.hidden, #ssta-zoom-note.hidden { display: none; }
#world-lock, #local-zoom-lock, #ssta-zoom-note { color: var(--accent); }

/* Sin capa animada activa no hay línea de tiempo que mostrar. Va con el id
   delante: `#anim-timeline` fija `display:flex` y una `.hidden` suelta perdería
   por especificidad (era el motivo de que la barra saliera siempre). */
#anim-timeline.hidden { display: none; }
/* Zócalo abajo-centro: línea de tiempo + leyenda apiladas. */
#bottom-dock {
  position: absolute; bottom: 16px; left: 50%; transform: translateX(-50%);
  z-index: 7; display: flex; flex-direction: column; align-items: center; gap: 8px;
  max-width: min(760px, calc(100vw - 560px)); pointer-events: none;
}
#bottom-dock > * { pointer-events: auto; }

#anim-timeline, #mosa-timeline {
  display: flex; align-items: center; gap: 12px;
  width: min(580px, 64vw); padding: 9px 16px;
  background: var(--panel-bg); border: 1px solid var(--border); border-radius: 14px;
  box-shadow: var(--shadow); backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
}
#anim-timeline #ecmwf-play, #mosa-timeline #mosa-play {
  flex: 0 0 auto; width: 34px; height: 34px; border-radius: 50%;
  border: 1px solid var(--border); background: var(--inner-card); color: var(--fg);
  font-size: 13px; cursor: pointer;
}
#anim-timeline #ecmwf-play:hover, #mosa-timeline #mosa-play:hover { border-color: var(--accent); }
/* Estado cargando: spinner girando + play deshabilitado */
#anim-timeline #ecmwf-play.loading { color: transparent; cursor: progress; position: relative; }
#anim-timeline #ecmwf-play.loading::after {
  content: ''; position: absolute; inset: 0; margin: auto; width: 15px; height: 15px;
  border: 2px solid var(--muted); border-top-color: var(--accent); border-radius: 50%;
  animation: atl-spin 0.7s linear infinite;
}
@keyframes atl-spin { to { transform: rotate(360deg); } }
.atl-track { flex: 1; min-width: 0; }
.atl-track input[type="range"] { width: 100%; display: block; }
.atl-ticks { display: flex; justify-content: space-between; margin-top: 2px; font-size: 9px; color: var(--muted); }
.atl-label { flex: 0 0 auto; font-size: 11px; font-weight: 700; color: var(--fg); font-variant-numeric: tabular-nums; min-width: 108px; text-align: right; line-height: 1.15; }
.atl-label small { display: block; font-size: 9px; font-weight: 500; color: var(--muted); }

/* Comparación de modelos Stormglass (card "Modelos (ahora)") */
.mdl-row { padding: 4px 0; border-top: 1px solid var(--inner-border); }
.mdl-row:first-of-type { border-top: 0; }
.mdl-var { font-size: 11px; color: var(--muted); }
.mdl-var em { font-style: normal; font-size: 9px; }
.mdl-sg { float: right; font-size: 11px; font-weight: 700; color: var(--fg); }
.mdl-chips { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 3px; }
.mdl-chip { font-size: 9px; color: var(--muted); background: var(--inner-card); border: 1px solid var(--inner-border); border-radius: 6px; padding: 1px 5px; }
.mdl-chip b { color: var(--fg); font-weight: 600; margin-left: 3px; }
.lg-group.collapsed .lg-body { display: none; }
.lg-body .time-row { margin-top: 8px; }
#controls input[type="date"] { width: 100%; padding: 4px 5px; border: 1px solid var(--border); border-radius: 6px; font: inherit; font-size: 11px; background: var(--card-bg); color: var(--fg); }
#controls input[type="range"] { width: 100%; }
#controls select { width: 100%; padding: 4px 5px; border: 1px solid var(--border); border-radius: 6px; font: inherit; font-size: 11px; background: var(--card-bg); color: var(--fg); }
#controls .hint { font-size: 11px; color: var(--muted); margin: 6px 0 0; }
.time-row { display: flex; align-items: center; gap: 8px; }
.time-row input[type="range"] { flex: 1; }
#time-play {
  flex: 0 0 auto; width: 30px; height: 26px; cursor: pointer; font-size: 13px;
  border: 1px solid var(--border); border-radius: 6px; background: var(--card-bg); color: var(--fg);
}
#time-play:hover { border-color: var(--accent); }
#time-label { font-weight: 700; font-variant-numeric: tabular-nums; }

/* --- Panel ENOS --- */
#enso-panel { top: 12px; right: 12px; width: 280px; max-height: calc(100% - 24px); overflow: auto; }
#enso-panel .controls-head h2 { margin: 0; }
#enso-toggle { border: 1px solid var(--border); background: var(--card-bg); color: var(--fg); border-radius: 6px; padding: 1px 8px; font-size: 13px; line-height: 1.3; cursor: pointer; transition: transform .2s; }
#enso-toggle:hover { border-color: var(--accent); }
#enso-panel.collapsed #enso-toggle { transform: rotate(-90deg); }
#enso-panel.collapsed #enso-body { display: none; }
.enso-status {
  font-weight: 700; font-size: 15px; padding: 8px 10px; border-radius: 8px;
  background: var(--status-bg); text-align: center; margin-bottom: 10px;
}
.enso-status.nino { background: #fbe6e6; color: var(--nino); }
.enso-status.nina { background: #e3eefb; color: var(--nina); }
.enso-status.neutral { background: #e7f4ea; color: var(--neutral); }
/* Estados con fondo tenue propio en modo oscuro (mantienen el color de acento) */
body.dark .enso-status.nino { background: #3a1e22; }
body.dark .enso-status.nina { background: #16283f; }
body.dark .enso-status.neutral { background: #16301f; }
body.dark .enso-status.nino { color: #f08a8a; }
body.dark .enso-status.nina { color: #7db4ec; }
body.dark .enso-status.neutral { color: #74c98a; }

.enso-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.enso-card {
  display: flex; flex-direction: column; gap: 2px;
  background: var(--card-bg); border: 1px solid var(--border); border-radius: 8px; padding: 8px 10px;
}
.enso-k { font-size: 11px; color: var(--muted); text-transform: uppercase; letter-spacing: .03em; }
.enso-v { font-size: 20px; font-weight: 700; font-variant-numeric: tabular-nums; }

.enso-chart-title { margin: 14px 0 4px; font-size: 12px; color: var(--muted); }
#enso-chart svg { width: 100%; height: auto; display: block; }
#enso-chart .zero-line { stroke: var(--zero-line); }
#enso-chart .spark-line { stroke: var(--accent); }

/* --- Leyenda --- */
.legend-title { font-size: 11px; color: var(--muted); margin: 8px 0 4px; }
/* Leyenda de riesgo FAN (puntos de color) */
.risk-legend { display: flex; flex-direction: column; gap: 3px; margin-bottom: 4px; }
.risk-legend span { display: flex; align-items: center; gap: 6px; font-size: 11px; }
.risk-legend i {
  width: 11px; height: 11px; border-radius: 50%;
  border: 1px solid var(--border); flex: 0 0 auto;
}
.legend-bar { height: 12px; border-radius: 4px; border: 1px solid var(--border); }
.legend-scale { display: flex; justify-content: space-between; font-size: 10px; color: var(--muted); margin-top: 2px; }
/* Paleta divergente frío→cálido (aprox. la de GIBS MUR anomalías) */
.tsm-bar { background: linear-gradient(90deg, #3b4cc0, #7aa0ff, #eaeaea, #ff9a6b, #b40426); }
.wind-bar { background: linear-gradient(90deg, #86a3ab, #0f93a7, #39a339, #c2863e, #c8420d, #d20032); }

/* Leyendas Copernicus (SVG de GetLegend), una por capa activa */
.cmems-legend { margin-top: 8px; display: flex; flex-direction: column; gap: 6px; }
.cmems-legend-row { display: flex; flex-direction: column; gap: 2px; }
.cmems-legend-row span { font-size: 11px; color: var(--muted); }
.cmems-legend-row img {
  max-width: 100%; height: auto; border-radius: 4px;
  background: #fff; /* las leyendas SVG asumen fondo claro */
  padding: 2px; border: 1px solid var(--border);
}

/* --- Lectura de coordenadas --- */
/* Barra de estado (abajo-izq, una sola fila): actualizado · zoom · lat/lon */
#statusbar b { color: var(--eyebrow); font-weight: 600; }

.muted { color: var(--muted); font-size: 11px; margin-top: 8px; }

/* --- Popup de estaciones --- */
.station-popup { font-size: 13px; line-height: 1.5; }
.station-popup strong { font-size: 14px; }
.station-popup .tag {
  display: inline-block; font-size: 10px; text-transform: uppercase; letter-spacing: .03em;
  background: #eef2f8; color: var(--accent); border-radius: 4px; padding: 1px 6px; margin-top: 3px;
}

/* Popup de puntos de referencia (SHOA / DIRECTEMAR) */
.pt-pop { font-size: 12px; line-height: 1.5; min-width: 160px; }
.pt-pop strong { font-size: 14px; display: block; margin-bottom: 4px; }
.pt-eyebrow { font-size: 9px; text-transform: uppercase; letter-spacing: .12em; color: var(--accent); margin-bottom: 6px; }
.pt-r { display: flex; justify-content: space-between; gap: 12px; }
.pt-r > span { color: var(--muted); }
.pt-r > b { font-weight: 600; }


/* Análisis ENOS (IA) */
.ia-actions { display: flex; gap: 6px; margin-bottom: 8px; }
.ia-actions button { flex: 1; padding: 6px 0; border: 1px solid var(--border); background: var(--card-bg); color: var(--fg); border-radius: 8px; font: inherit; font-size: 11px; cursor: pointer; }
.ia-actions button:hover:not(:disabled) { border-color: var(--accent); }
.ia-actions button:disabled { opacity: .5; cursor: default; }
.ia-out { font-size: 12px; line-height: 1.5; }
.ia-out h5 { margin: 8px 0 4px; font-size: 12px; color: var(--fg); }
.ia-out p { margin: 6px 0; }
.ia-out ul { margin: 6px 0; padding-left: 18px; }
.ia-out code { font-family: var(--font-mono); font-size: 11px; }
.ia-src { margin-top: 8px; font-size: 9px; color: var(--eyebrow); text-transform: uppercase; letter-spacing: .04em; }

/* Reporte NOAA */
.noaa-out { font-size: 12px; line-height: 1.5; }
.noaa-meta { font-family: var(--font-mono); font-size: 10px; color: var(--muted); margin-bottom: 3px; }
.noaa-syn { margin: 3px 0; font-weight: 500; }
.noaa-more { background: none; border: none; color: var(--accent); font: inherit; font-size: 11px; cursor: pointer; padding: 2px 0; }
.noaa-disc p { margin: 6px 0; font-size: 11px; color: var(--fg2, var(--fg)); }
.noaa-link { display: inline-block; margin-top: 6px; font-size: 10px; }

/* Análisis El Niño 2026 · sur */
.an-mapa img { width: 100%; border-radius: 8px; border: 1px solid var(--inner-border); display: block; }
.an-cap { font-size: 9px; color: var(--muted); margin: 4px 0 8px; line-height: 1.35; }
.an-chart-t { font-size: 10px; color: var(--eyebrow); text-transform: uppercase; letter-spacing: .04em; margin: 6px 0 2px; }
.an-leg { display: flex; gap: 14px; font-size: 10px; color: var(--muted); margin-top: 2px; }
.an-leg i { display: inline-block; width: 10px; height: 3px; border-radius: 2px; margin-right: 4px; vertical-align: middle; }
.an-nota { font-size: 11px; color: var(--fg2, var(--fg)); line-height: 1.4; margin: 8px 0 0; }

/* Chat / asistente IA (popup abajo-derecha) */
/* --- Avatar "IA" reutilizable --- */
.chat-av, .fab-ia { font-family: var(--font-mono); font-weight: 700; letter-spacing: .06em; color: var(--accent);
  display: inline-flex; align-items: center; justify-content: center; background: rgba(56,189,248,.12);
  border: 1px solid rgba(56,189,248,.45); box-shadow: 0 0 0 3px rgba(56,189,248,.08), inset 0 0 12px rgba(56,189,248,.12); }
.chat-av { width: 34px; height: 34px; border-radius: 10px; font-size: 12px; flex: 0 0 auto; }
/* El icono hereda el color del contenedor y se dimensiona por su caja. El robot
   lleva antena/orejas/ojos, así que necesita algo más de caja que un glifo. */
.ic-ia { width: 68%; height: 68%; display: block; }


/* --- Panel --- */
/* Ancho: 460px, pero sin invadir el panel ENOS de la derecha ni salirse en
   pantallas chicas — el chat arranca en left:268px y aquel mide ~300px. */
/* El asistente es parte del menú: misma superficie, mismo borde, mismo radio
   y misma sombra que el riel y el panel (tokens del handoff). */
#chat-panel { position: absolute; left: 362px; z-index: 8;
  width: min(460px, calc(100vw - 600px)); min-width: 320px;
  /* Mismo alto que el menú: top y bottom idénticos a #nav, para que las dos
     piezas se lean como una sola superficie y no como paneles sueltos. */
  top: 18px; bottom: 34px; display: flex; flex-direction: column;
  background: var(--nav); border: 1px solid var(--line); border-radius: 22px;
  box-shadow: var(--nav-shadow); overflow: hidden; }
#chat-panel.hidden { display: none; }
.chat-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 13px 15px; border-bottom: 1px solid var(--line); }
.chat-id { display: flex; align-items: center; gap: 10px; min-width: 0; }
.chat-hd-txt { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.chat-hd-txt strong { font-family: var(--display); font-size: 14.5px; font-weight: 500; color: var(--ink); white-space: nowrap; }
.chat-sub { display: flex; align-items: center; gap: 6px; font-family: var(--font-mono); font-size: 9px;
  letter-spacing: .06em; text-transform: uppercase; color: var(--nav-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.chat-dot { width: 7px; height: 7px; border-radius: 50%; background: #22c55e; box-shadow: 0 0 7px #22c55e; flex: 0 0 auto; }
/* Espejo del botón colapsar del panel: 34×34, radio 11, borde --line. */
.chat-head #chat-close { border: 1px solid var(--line); background: transparent; color: var(--nav-muted);
  width: 28px; height: 28px; border-radius: 9px; font-size: 13px; line-height: 1; cursor: pointer; flex: 0 0 auto;
  transition: background .15s, color .15s; }
.chat-head #chat-close:hover { background: color-mix(in srgb, var(--onbg) 45%, transparent); color: var(--ink); }

.chat-msgs { flex: 1; overflow-y: auto; padding: 14px; display: flex; flex-direction: column; gap: 12px; }
/* fila del mensaje (avatar + burbuja) */
.chat-row { display: flex; gap: 9px; align-items: flex-start; max-width: 92%; }
.chat-row.user { align-self: flex-end; flex-direction: row-reverse; }
.chat-row.assistant { align-self: flex-start; }
.chat-row .chat-av { width: 28px; height: 28px; border-radius: 8px; font-size: 10px; margin-top: 2px; }
.chat-msg { font-size: 12.5px; line-height: 1.55; padding: 10px 13px; border-radius: 13px; }
.chat-row.user .chat-msg { background: var(--onbg); color: var(--teal); border: 1px solid var(--line); border-bottom-right-radius: 5px; }
.chat-row.assistant .chat-msg { background: var(--sunk); color: var(--ink); border: 1px solid var(--line); border-bottom-left-radius: 5px; }
.chat-msg p { margin: 4px 0; } .chat-msg p:first-child { margin-top: 0; } .chat-msg p:last-child { margin-bottom: 0; }
.chat-msg h5 { margin: 6px 0 3px; font-size: 12px; }
.chat-msg ul { margin: 4px 0; padding-left: 16px; }
.chat-msg code { font-family: var(--font-mono); font-size: 11px; }
.chat-msg a { color: var(--teal); }

/* chips de acciones sugeridas */
.chat-chips { display: flex; flex-direction: column; align-items: flex-start; gap: 8px; margin: 2px 0 2px 37px; }
.chat-chip { text-align: left; font: inherit; font-size: 11.5px; color: var(--nav-muted); background: transparent;
  border: 1px solid var(--line); border-radius: 11px; padding: 7px 11px; cursor: pointer; transition: background .15s, color .15s; }
.chat-chip:hover { background: var(--onbg); color: var(--teal); }

.chat-form { display: flex; gap: 9px; align-items: center; padding: 12px 14px 14px; border-top: 1px solid var(--line); }
.chat-form input { flex: 1; padding: 10px 13px; border: 1px solid var(--line); border-radius: 12px; background: var(--sunk); color: var(--ink); font: inherit; font-size: 12.5px; }
.chat-form input:focus { outline: none; border-color: var(--teal); }
.chat-form input:disabled { opacity: .6; }
.chat-form button { border: none; background: var(--teal); color: var(--nav); border-radius: 12px; width: 34px; height: 34px; flex: 0 0 auto;
  display: flex; align-items: center; justify-content: center; cursor: pointer; font-size: 14px; }
.chat-form button:hover { filter: brightness(1.08); }

/* Panel de boletines IFOP */
.boletines { display: flex; flex-direction: column; gap: 5px; }
.boletines a { font-size: 11px; color: var(--fg); text-decoration: none; line-height: 1.25; }
.boletines a:hover { color: var(--accent); }
.bol-tipo { display: block; font-size: 9px; text-transform: uppercase; letter-spacing: .03em; color: var(--muted); }

/* Panel de detalle del centro (derecha, como ENOS) */
.center-panel { top: 62px; right: 304px; width: 300px; max-height: calc(100% - 74px); overflow-y: auto; }
.center-panel.hidden { display: none; }
.center-panel h2 { margin: 0; font-size: 15px; }
#cp-close { border: 1px solid var(--border); background: var(--card-bg); color: var(--fg); border-radius: 6px; font-size: 16px; line-height: 1; cursor: pointer; padding: 1px 8px; }
#cp-close:hover { border-color: var(--accent); }
.cp-card { background: var(--inner-card); border: 1px solid var(--inner-border); border-radius: 11px; padding: 12px 13px; margin-top: 10px; }
.cp-card h3 { margin: 0 0 8px; font-size: 10px; text-transform: uppercase; letter-spacing: .16em; font-weight: 600; color: var(--eyebrow); }
.cp-sub { font-size: 11px; color: var(--muted); margin-bottom: 5px; }
.cp-card .tag { display: inline-block; font-size: 10px; text-transform: uppercase; letter-spacing: .03em; background: var(--chip-bg); color: var(--accent); border-radius: 4px; padding: 2px 7px; margin-bottom: 4px; }
.cp-row { display: grid; grid-template-columns: 1fr auto auto; align-items: baseline; gap: 8px; font-size: 12px; padding: 2px 0; }
.cp-row > span { color: var(--muted); }
.cp-row > b { font-variant-numeric: tabular-nums; }
.cp-row > em { font-style: normal; font-size: 10px; color: var(--muted); }
.cp-row .sem { display: inline-block; width: 9px; height: 9px; border-radius: 50%; margin-right: 3px; vertical-align: middle; }
.cp-tend { display: grid; grid-template-columns: 72px 1fr auto; align-items: center; gap: 6px; font-size: 11px; padding: 2px 0; }
.cp-tend > span { color: var(--muted); }
.spark { display: block; }

/* Pestaña FAN: monitoreo de floraciones algales */
.cp-fan.fan-nociva > span { color: var(--fg); }
.fan-dot { display: inline-block; width: 7px; height: 7px; border-radius: 50%; background: #ef4444; margin-right: 5px; vertical-align: middle; }
.fan-badge { display: inline-block; font-size: 10px; font-weight: 600; color: #fca5a5; background: rgba(239,68,68,.16); border: 1px solid rgba(239,68,68,.4); border-radius: 999px; padding: 1px 7px; margin-left: 6px; vertical-align: middle; }

/* Popup de la capa normativa Alexandrium (Sernapesca) */
.alex-pop { min-width: 220px; }
.alex-pop .cp-sub { font-size: 10px; color: var(--muted); margin-bottom: 6px; }
.alex-row { display: grid; grid-template-columns: 68px 1fr; gap: 8px; font-size: 11px; padding: 2px 0; }
.alex-row > span { color: var(--muted); }
.alex-links { margin-top: 8px; display: flex; flex-direction: column; gap: 3px; }
.alex-links a { font-size: 11px; color: #7dd3fc; text-decoration: none; }
.alex-links a:hover { text-decoration: underline; }

/* --- Popup de centro en pestañas: FAN · SNIFA · SUBPESCA --- */
.cdos .cp-sub { color: var(--ink); }
.cdos .cp-sub > span { color: var(--muted); }
.cdos-sug { font-size: 10.5px; line-height: 1.4; color: var(--ink); margin-top: 7px;
  padding: 6px 8px; border-radius: 7px; background: rgba(224,163,62,.12);
  border-left: 2px solid #E0A33E; }
.cdos-sug b { color: #E0A33E; }
.cdos-coord { font-size: 11px; color: var(--muted); margin-top: 3px; }
.cdos-titular { font-size: 10.5px; color: var(--accent); letter-spacing: .01em; margin: 1px 0 2px; }
.cdos-tabs { display: flex; gap: 2px; margin: 9px 0 8px; border-bottom: 1px solid var(--divider); }
.cdos-tab {
  flex: 1; appearance: none; background: none; border: none; cursor: pointer;
  font-family: inherit; font-size: 9.5px; letter-spacing: .1em; text-transform: uppercase;
  color: var(--muted); padding: 5px 2px 6px; border-bottom: 2px solid transparent;
  margin-bottom: -1px; transition: color .12s, border-color .12s;
}
.cdos-tab:hover { color: var(--ink); }
.cdos-tab.on { color: var(--accent); border-bottom-color: var(--accent); font-weight: 600; }
/* El panel manda el alto: sin tope, el expediente de un centro con muchas
   fiscalizaciones haría un popup más alto que la ventana. */
.cdos-pane { max-height: 340px; overflow-y: auto; }
.cdos-pane.hid { display: none; }
.cdos-empty { font-size: 11px; color: var(--muted); line-height: 1.45; padding: 6px 0; }
.cdos-wait { font-size: 11px; color: var(--faint); padding: 6px 0; }
.cdos-tabla { display: flex; flex-direction: column; gap: 3px; }
.cdos-tabla > div { font-size: 10.5px; line-height: 1.35; color: var(--ink); }
.cdos-tabla a { color: #7dd3fc; text-decoration: none; }
.cdos-tabla a:hover { text-decoration: underline; }

/* Estado de dos tonos (relleno=última fecha, borde=peor semana) en el popup */
.fan-2tone { margin: 8px 0 2px; display: flex; flex-direction: column; gap: 4px; }
.fan-2t { display: grid; grid-template-columns: 96px 1fr; align-items: baseline; gap: 8px; font-size: 11px; }
.fan-2t > span { color: var(--muted); }

/* Tira de muestreo 7 días (popup de Otros centros) */
.fan-strip-t { font-size: 10px; color: var(--muted); text-transform: uppercase; letter-spacing: .5px; margin: 8px 0 4px; }
.fan-strip { display: flex; gap: 4px; }
.fan-day { display: flex; flex-direction: column; align-items: center; gap: 2px; flex: 1; }
.fan-day > i { width: 14px; height: 14px; border-radius: 50%; box-sizing: border-box; }
.fan-day > span { font-size: 8px; color: var(--muted); }
.fan-day.on { cursor: pointer; }
.fan-day.on:hover > i { outline: 2px solid rgba(255,255,255,.5); outline-offset: 1px; }
.fan-day.sel > i { outline: 2px solid #fff; outline-offset: 1px; }
.fan-day-detail { margin-top: 7px; font-size: 11px; color: var(--fg); line-height: 1.5;
  padding: 6px 8px; background: rgba(148,163,184,.1); border-radius: 7px; }
.fan-tag { display: inline-block; font-size: 9px; padding: 1px 6px; border-radius: 999px;
  text-transform: uppercase; letter-spacing: .4px; vertical-align: middle; }
.fan-tag.rojo { background: rgba(239,68,68,.22); color: #fca5a5; }
.fan-tag.amarillo { background: rgba(245,158,11,.22); color: #fbbf24; }
.fan-tag.plomo { background: rgba(148,163,184,.25); color: #cbd5e1; }
.fan-tag.verde { background: rgba(34,197,94,.2); color: #86efac; }

/* Ficha de detalle del wellboat (popup al hacer click en la nave) */
.wb-pop .mapboxgl-popup-content { padding: 0; }
.wb-card { min-width: 268px; font-size: 12px; }
.wb-head { display: flex; align-items: flex-start; justify-content: space-between;
  gap: 10px; padding: 14px 16px 10px; border-bottom: 1px solid rgba(148,163,184,.16); }
.wb-name { font-size: 15px; font-weight: 700; line-height: 1.15; }
.wb-type { font-size: 10.5px; color: var(--muted); margin-top: 2px; }
.wb-compass { display: flex; flex-direction: column; align-items: center; gap: 2px;
  min-width: 46px; }
.wb-needle { font-size: 17px; color: var(--accent); line-height: 1; display: inline-block;
  filter: drop-shadow(0 0 4px rgba(56,189,248,.55)); transition: transform .3s ease; }
.wb-deg { font-size: 9.5px; color: var(--muted); letter-spacing: .3px; }
.wb-strip { display: flex; flex-wrap: wrap; gap: 5px; padding: 10px 16px; }
.wb-pill { font-size: 10.5px; padding: 2px 8px; border-radius: 999px;
  background: rgba(148,163,184,.16); color: var(--fg); white-space: nowrap; }
.wb-pill.on { background: rgba(56,189,248,.2); color: #7dd3fc; }
.wb-pill.load { background: rgba(245,158,11,.2); color: #fbbf24; }
.wb-voyage { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center;
  gap: 8px; padding: 4px 16px 8px; }
.wb-leg span { display: block; font-size: 9.5px; color: var(--muted); text-transform: uppercase;
  letter-spacing: .4px; }
.wb-leg b { font-size: 12px; }
.wb-arrow { color: var(--accent); font-size: 15px; }
.wb-sec { font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: .6px;
  color: var(--muted); padding: 9px 16px 3px; border-top: 1px solid rgba(148,163,184,.12);
  margin-top: 4px; }
.wb-row { display: grid; grid-template-columns: 96px 1fr auto; align-items: center;
  gap: 8px; font-size: 11.5px; padding: 2.5px 16px; }
.wb-row > span { color: var(--muted); }
.wb-row > b { font-weight: 600; }
.wb-row > b.crit { color: #fca5a5; }
.wb-bar { height: 6px; border-radius: 3px; background: rgba(148,163,184,.22); overflow: hidden; }
.wb-bar > i { display: block; height: 100%; background: linear-gradient(90deg, #f59e0b, #fbbf24); }
.wb-fan { margin: 5px 16px 2px; padding: 6px 10px; border-radius: 8px; font-size: 11px;
  font-weight: 600; text-align: center; }
.wb-fan-ok { background: rgba(52,211,153,.15); color: #6ee7b7; }
.wb-fan-info { background: rgba(56,189,248,.15); color: #7dd3fc; }
.wb-fan-warn { background: rgba(245,158,11,.16); color: #fbbf24; }
.wb-foot { font-size: 10px; color: var(--muted); padding: 9px 16px 13px; margin-top: 4px;
  border-top: 1px solid rgba(148,163,184,.12); }

/* Card flotante de la estación meteo (encima del punto del centro) */
.meteo-pop .mapboxgl-popup-content { background: var(--panel-bg); color: var(--fg); border: 1px solid rgba(56,189,248,.28); border-radius: 14px; padding: 14px 16px; box-shadow: 0 18px 44px rgba(0,0,0,.55); backdrop-filter: blur(14px); }
.meteo-pop .mapboxgl-popup-tip { display: none; }
.meteo-pop.mapboxgl-popup-anchor-bottom .mapboxgl-popup-content::after {
  content: ""; position: absolute; left: 50%; bottom: -8px; width: 15px; height: 15px;
  transform: translateX(-50%) rotate(45deg);
  background: var(--panel-bg); border-right: 1px solid rgba(56,189,248,.28); border-bottom: 1px solid rgba(56,189,248,.28);
}
.meteo-card { min-width: 312px; font-size: 11px; }
/* Mini-dashboard: grid de tiles + mini-pronóstico */
.mt-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; margin-top: 4px; }
.mt-tile { background: var(--inner-card); border: 1px solid var(--inner-border); border-radius: 9px; padding: 7px 9px; }
.mt-tile > span { display: block; font-size: 9px; text-transform: uppercase; letter-spacing: .04em; color: var(--muted); margin-bottom: 2px; }
.mt-tile > b { font-family: var(--font-mono); font-size: 15px; font-weight: 600; }
.mt-tile > b em { font-size: 10px; font-weight: 400; font-style: normal; color: var(--muted); margin-left: 2px; }
.mt-syn { position: relative; }
.mt-syn::after { content: "sint"; position: absolute; top: 5px; right: 7px; font-size: 7px; color: var(--eyebrow); letter-spacing: .04em; }
.mt-fc { margin-top: 8px; }
.mt-fc > span { display: block; font-size: 9px; text-transform: uppercase; letter-spacing: .05em; color: var(--muted); margin-bottom: 2px; }
.meteo-hd { display: flex; justify-content: space-between; align-items: baseline; font-size: 10px; text-transform: uppercase; letter-spacing: .16em; color: var(--eyebrow); font-weight: 600; margin-bottom: 10px; }
.meteo-hd span { font-family: var(--font-mono); letter-spacing: 0; font-size: 10px; color: var(--muted); }
.meteo-main { display: flex; align-items: center; gap: 14px; margin-bottom: 12px; }
.meteo-wind { font-family: var(--font-mono); font-size: 26px; font-weight: 600; line-height: 1; }
.meteo-wind em { font-size: 12px; font-weight: 400; font-style: normal; color: var(--muted); margin-left: 3px; }
.meteo-dir { font-size: 11px; color: var(--muted); margin-top: 4px; }
.meteo-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 8px 16px; }
.meteo-grid > div { display: flex; justify-content: space-between; gap: 6px; border-top: 1px solid var(--divider); padding-top: 7px; }
.meteo-grid span { color: var(--muted); }
.meteo-grid b { font-family: var(--font-mono); }

/* Rosa de los vientos del popup meteo */
.wrose { position: relative; width: 58px; height: 58px; flex-shrink: 0; border-radius: 50%; border: 1.5px solid rgba(255,255,255,.14); background: radial-gradient(circle, rgba(56,189,248,.10), transparent 68%); }
.wr-c { position: absolute; font-family: var(--font-mono); font-size: 8px; color: var(--muted); }
.wr-n { left: 50%; top: 5px; transform: translateX(-50%); color: var(--accent); font-weight: 600; }
.wr-s { left: 50%; bottom: 4px; transform: translateX(-50%); }
.wr-o { top: 50%; left: 5px; transform: translateY(-50%); }
.wr-e { top: 50%; right: 5px; transform: translateY(-50%); }
.wr-needle { position: absolute; inset: 0; }
.wr-arrow { position: absolute; left: 50%; top: 10px; transform: translateX(-50%); width: 0; height: 0; border-left: 5px solid transparent; border-right: 5px solid transparent; border-bottom: 10px solid var(--accent); }
.wr-tail { position: absolute; left: 50%; top: 20px; transform: translateX(-50%); width: 2.5px; height: 18px; border-radius: 2px; background: linear-gradient(180deg, var(--accent), rgba(56,189,248,0)); }
.wr-hub { position: absolute; left: 50%; top: 50%; transform: translate(-50%,-50%); width: 5px; height: 5px; border-radius: 50%; background: var(--fg); }

/* Gauge de riesgo (panel de detalle) */
.gauge { display: flex; align-items: flex-end; gap: 12px; margin: 4px 0 10px; }
.gauge-num { font-family: var(--font-mono); font-size: 44px; font-weight: 600; line-height: .85; }
.gauge-bar-wrap { flex: 1; padding-bottom: 4px; }
.gauge-pill { display: inline-block; font-size: 9px; letter-spacing: .08em; border: 1px solid; border-radius: 20px; padding: 2px 9px; margin-bottom: 7px; text-transform: uppercase; font-weight: 600; }
.gauge-bar { height: 8px; border-radius: 5px; background: linear-gradient(90deg,#7fd3c9,#22c55e,#eab308,#f97316,#ef4444); position: relative; }
.gauge-mark { position: absolute; top: 50%; transform: translate(-50%,-50%); width: 4px; height: 16px; border-radius: 2px; background: #fff; box-shadow: 0 0 8px rgba(0,0,0,.6); }
.gauge-scale { display: flex; justify-content: space-between; font-size: 9px; color: var(--muted); margin-top: 5px; }

/* Card DIRECTEMAR (capitanía): mismo cristal/blur que la card de meteo + pestañas */
.dm-pop .mapboxgl-popup-content { background: var(--panel-bg); color: var(--fg); border: 1px solid rgba(56,189,248,.28); border-radius: 14px; padding: 14px 16px; box-shadow: 0 18px 44px rgba(0,0,0,.55); backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px); }
.dm-pop .mapboxgl-popup-tip { display: none; }
.dm-pop.mapboxgl-popup-anchor-bottom .mapboxgl-popup-content::after { content: ""; position: absolute; left: 50%; bottom: -8px; width: 15px; height: 15px; transform: translateX(-50%) rotate(45deg); background: var(--panel-bg); border-right: 1px solid rgba(56,189,248,.28); border-bottom: 1px solid rgba(56,189,248,.28); }
.dm-card { min-width: 440px; font-size: 12px; }
.dm-card > strong { font-size: 14px; display: block; margin-top: 2px; }
.dm-tabs { display: flex; gap: 4px; margin: 10px 0 8px; }
.dm-tabs button { flex: 1; padding: 6px 0; border: 1px solid var(--border); background: transparent; color: var(--muted); border-radius: 8px; font: inherit; font-size: 11px; cursor: pointer; }
.dm-tabs button.active { background: var(--chip-bg); color: var(--accent); border-color: transparent; }
.dm-pane .pt-r { display: flex; justify-content: space-between; gap: 12px; padding: 2px 0; }
.dm-pane .pt-r > span { color: var(--muted); }
.dm-pane[data-pane="bahias"] { max-height: 220px; overflow-y: auto; }
.dm-bahia { border-top: 1px solid var(--divider); padding: 7px 0; }
.dm-bahia:first-child { border-top: 0; }
.dm-bahia-hd { display: flex; justify-content: space-between; gap: 8px; align-items: baseline; }
.dm-bahia-hd span { font-size: 10px; white-space: nowrap; }
.dm-detalle { font-size: 11px; color: var(--fg2, var(--muted)); margin-top: 3px; line-height: 1.35; }

/* Card SHOA (marea): mismo cristal/blur, con gráfico de mareas */
.sh-pop .mapboxgl-popup-content { background: var(--panel-bg); color: var(--fg); border: 1px solid rgba(56,189,248,.28); border-radius: 14px; padding: 14px 16px; box-shadow: 0 18px 44px rgba(0,0,0,.55); backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px); }
.sh-pop .mapboxgl-popup-tip { display: none; }
.sh-pop.mapboxgl-popup-anchor-bottom .mapboxgl-popup-content::after { content: ""; position: absolute; left: 50%; bottom: -8px; width: 15px; height: 15px; transform: translateX(-50%) rotate(45deg); background: var(--panel-bg); border-right: 1px solid rgba(56,189,248,.28); border-bottom: 1px solid rgba(56,189,248,.28); }
.sh-card { min-width: 440px; font-size: 12px; }
.sh-card > strong { font-size: 14px; display: block; margin-top: 2px; }
.sh-today { font-size: 12px; color: var(--muted); margin: 4px 0 2px; }
.sh-today b { font-family: var(--font-mono); }
.tide-chart { display: block; margin: 8px 0 2px; }

/* Popup único del centro (header + gauge + pestañas), cristal como los demás */
.cpop-pop .mapboxgl-popup-content { background: var(--panel-bg); color: var(--fg); border: 1px solid rgba(56,189,248,.28); border-radius: 14px; padding: 14px 16px; box-shadow: 0 18px 44px rgba(0,0,0,.55); backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px); max-height: 78vh; overflow-y: auto; }
.cpop-pop .mapboxgl-popup-tip { display: none; }
.cpop-pop.mapboxgl-popup-anchor-bottom .mapboxgl-popup-content::after { content: ""; position: absolute; left: 50%; bottom: -8px; width: 15px; height: 15px; transform: translateX(-50%) rotate(45deg); background: var(--panel-bg); border-right: 1px solid rgba(56,189,248,.28); border-bottom: 1px solid rgba(56,189,248,.28); }
.cpop { min-width: 328px; font-size: 12px; }
.cpop-name { font-size: 15px; font-weight: 700; margin: 1px 0 2px; }
.cpop-tabs { flex-wrap: nowrap; margin: 8px 0; }
.cpop-tabs button { font-size: 10px; padding: 5px 3px; }
.mt-syn-note { font-size: 9px; color: var(--eyebrow); text-transform: uppercase; letter-spacing: .04em; margin-bottom: 6px; }
.fc-grid { display: grid; grid-template-columns: repeat(5, 1fr); gap: 5px; margin-top: 10px; }
.fc-day { background: var(--inner-card); border: 1px solid var(--inner-border); border-radius: 9px; padding: 7px 2px; text-align: center; }
.fc-day > span { display: block; font-size: 9px; color: var(--muted); }
.fc-ic { font-size: 16px; margin: 2px 0; }
.fc-day > b { font-family: var(--font-mono); font-size: 13px; }
.fc-day > em { font-family: var(--font-mono); font-size: 10px; font-style: normal; color: var(--muted); margin-left: 2px; }

/* Datos observados (in-situ / BD) en el popup */
.obs { margin-top: 6px; font-size: 11px; line-height: 1.5; }
.obs .sem { display: inline-block; width: 9px; height: 9px; border-radius: 50%; vertical-align: middle; margin-right: 2px; }

/* Desglose de drivers del riesgo FAN en el popup del centro
   (barra azul = dato in-situ observado; naranja = modelado) */
.drivers { margin-top: 6px; display: flex; flex-direction: column; gap: 3px; }
.drv { display: grid; grid-template-columns: 76px 1fr 32px; align-items: center; gap: 6px; font-size: 10px; }
.drv > span { color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.drv > i { height: 7px; min-width: 2px; border-radius: 3px; background: #f59e0b; display: block; }
.drv > b { text-align: right; font-variant-numeric: tabular-nums; font-weight: 600; }
.drv-cap { display: block; margin: -1px 0 2px 82px; font-size: 9px; color: var(--muted); font-style: italic; }
.drv-cap.drv-tox { color: #fca5a5; font-style: normal; font-weight: 600; }

/* --- Aviso de token faltante --- */
.alert {
  position: absolute; inset: 0; z-index: 20;
  display: flex; align-items: center; justify-content: center;
  background: var(--panel-bg);
}
.alert.hidden { display: none; }
.alert-box {
  max-width: 420px; text-align: center; background: var(--bg); color: var(--fg);
  border: 1px solid var(--border); border-radius: 12px; padding: 28px; box-shadow: var(--shadow);
}
.alert-box h2 { margin: 0 0 10px; color: var(--nino); }
code { background: var(--chip-bg); color: var(--fg); padding: 1px 5px; border-radius: 4px; font-size: 90%; }

/* Popup de Mapbox en modo oscuro */
body.dark .mapboxgl-popup-content {
  background: var(--card-bg); color: var(--fg);
  box-shadow: 0 1px 8px rgba(0, 0, 0, 0.5);
}
body.dark .mapboxgl-popup-anchor-top .mapboxgl-popup-tip,
body.dark .mapboxgl-popup-anchor-top-left .mapboxgl-popup-tip,
body.dark .mapboxgl-popup-anchor-top-right .mapboxgl-popup-tip { border-bottom-color: var(--card-bg); }
body.dark .mapboxgl-popup-anchor-bottom .mapboxgl-popup-tip,
body.dark .mapboxgl-popup-anchor-bottom-left .mapboxgl-popup-tip,
body.dark .mapboxgl-popup-anchor-bottom-right .mapboxgl-popup-tip { border-top-color: var(--card-bg); }
body.dark .mapboxgl-popup-anchor-left .mapboxgl-popup-tip { border-right-color: var(--card-bg); }
body.dark .mapboxgl-popup-anchor-right .mapboxgl-popup-tip { border-left-color: var(--card-bg); }
body.dark .mapboxgl-popup-close-button { color: var(--fg); }

/* --- Responsive básico --- */
@media (max-width: 900px) {
  #nav-panel { width: 210px; flex-basis: 210px; }
  #enso-panel { width: 210px; }
  /* El chat ya no flota junto al menú: su izquierda y su ancho salen de
     --nav-w y --chat-w, y el máximo lo acota el propio arrastre. */
}

/* --- Leyenda dinámica (bajo la línea de tiempo) --------------------------- */
#map-legend {
  display: flex; flex-wrap: wrap; gap: 8px 18px; align-items: flex-start;
  padding: 8px 14px; background: var(--panel-bg); border: 1px solid var(--border);
  border-radius: 12px; box-shadow: var(--shadow);
  backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
}
#map-legend.hidden { display: none; }
.ml-item { min-width: 104px; }
.ml-title { font-size: 10px; color: var(--muted); margin-bottom: 4px; white-space: nowrap; }
.ml-bar { height: 8px; border-radius: 4px; border: 1px solid var(--inner-border); }
.ml-scale { display: flex; justify-content: space-between; margin-top: 2px;
  font-family: var(--font-mono); font-size: 9px; color: var(--muted); }
.ml-chips { display: flex; flex-wrap: wrap; gap: 4px 9px; }
.ml-chips span { display: flex; align-items: center; gap: 4px; font-size: 10px; color: var(--fg2, var(--fg)); }
.ml-chips i { width: 9px; height: 9px; border-radius: 50%; flex: 0 0 auto; }

/* ==========================================================================
   Navegación Suite Centinela — rail de iconos + panel de sección
   ========================================================================== */
#nav {
  /* El borde inferior se detiene sobre la franja de atribución de Mapbox: su
     logo es obligatorio por licencia y el rail lo tapaba. */
  /* 18 px de margen como pide el handoff, salvo abajo: la franja de atribución
     de Mapbox es obligatoria por licencia y con 18 px el riel la tapaba. */
  /* Por encima del chat (z-index 8): #nav crea contexto de apilamiento, así que
     el z-index 7 del flotante de capas y del menú de cuenta es interno y no los
     levanta por sí solo — con el chat abierto quedaban tapados. */
  position: absolute; top: calc(var(--topbar-h) + 14px); left: 18px; bottom: 34px; z-index: 9;
  /* Riel y panel son una sola pieza: sin separación, con el borde, el radio y
     la sombra puestos aquí. Antes eran dos tarjetas flotando juntas y se leían
     como dos menús distintos. */
  display: flex; align-items: stretch; gap: 0; pointer-events: none;
}
#nav > * { pointer-events: auto; }
/* El borde, el radio y el recorte viven en el panel, no en #nav: con
   `overflow:hidden` aquí el menú flotante de capas —que es hijo de #nav y sale
   por el costado— quedaba recortado y no se veía al pasar el cursor. */
#nav-panel {
  border: 1px solid var(--line); border-radius: 22px;
  box-shadow: var(--nav-shadow); overflow: hidden;
}
/* Un solo menú en dos anchos. El riel dejó de existir como pieza aparte: al
   colapsar, este mismo panel se estrecha a la columna de iconos. Antes eran dos
   componentes con dos aspectos y el paso de uno a otro no se leía como el mismo
   objeto. */
#nav-rail { display: none; }

#nav.collapsed #nav-panel { width: 72px; flex-basis: 72px; }
/* Colapsado: sobrevive el icono, se va la palabra. */
#nav.collapsed .np-brand,
#nav.collapsed .np-sec-head h2,
#nav.collapsed .np-sec-head::before,
#nav.collapsed .np-sec-sub,
#nav.collapsed .np-pie-b span,
#nav.collapsed #statusbar { display: none; }
/* Colapsado no cabe el logo Y el botón: se montaban uno sobre otro. El logo
   pasa a ser el control de expandir —toda la cabecera es clicable— y el botón
   se retira. */
#nav.collapsed .np-head { padding: 16px 0 12px; justify-content: center;
  cursor: pointer; border-radius: 12px; transition: background .14s; }
#nav.collapsed .np-head:hover { background: rgba(255,255,255,.05); }
/* (El selector de hijo directo de #nav ya no casa: el botón vive en el pie.) */
/* El 0 de arriba pegaba el primer producto a la cabecera. Se iguala al
   expandido: la separación no depende del ancho del panel. */
#nav.collapsed .np-body { padding: 6px 8px; overflow: visible; }
/* Solo los encabezados: las capas viven detrás del flotante. */
#nav.collapsed #controls > .lg-group > *:not(.np-sec-head) { display: none; }
#nav.collapsed .np-sec-head { justify-content: center; padding: 11px 0; margin: 2px 0; }
#nav.collapsed .np-pie { flex-direction: column; gap: 2px; padding: 8px 8px 10px; }
#nav.collapsed .np-pie-b { padding: 10px 0; }

/* Pie del panel: los accesos que en el riel van bajo el separador. */
.np-pie { display: flex; gap: 6px; padding: 8px 12px 10px;
  border-top: 1px solid var(--line); }
.np-pie-b { flex: 1; display: flex; align-items: center; justify-content: center;
  gap: 8px; padding: 8px; border: 0; border-radius: 10px; background: transparent;
  color: var(--nav-muted); font: inherit; font-size: 11px; cursor: pointer;
  transition: background .14s, color .14s; }
.np-pie-b:hover { background: rgba(255,255,255,.05); color: var(--ink); }
.np-pie-b .ic { width: 21px; height: 21px; flex: 0 0 auto; }

/* --- Rail: retirado. Sus botones siguen en el DOM porque el pie del panel
   delega en ellos, pero la columna de iconos la dibuja ahora el propio panel
   colapsado. La regla que lo ocultaba vivía antes de esta y perdía por orden. */
#nav-rail { display: none !important; }
.rail-logo { width: 44px; height: 44px; border: none; background: none; padding: 0;
  cursor: pointer; margin-bottom: 10px; display: flex; align-items: center;
  justify-content: center; }
.rail-logo .ic-logo { width: 27px; height: 27px; display: block; }
.rail-sep { width: 26px; height: 1px; background: rgba(127,211,201,.22); margin: auto 0 6px; }

.rail-btn {
  position: relative; width: 44px; height: 44px; border-radius: 14px; cursor: pointer;
  border: 0; background: transparent; color: var(--nav-muted);
  display: flex; align-items: center; justify-content: center;
  transition: background .15s, color .15s;
}
.rail-btn .ic { width: 21px; height: 21px; display: block; }
.rail-btn:hover { background: color-mix(in srgb, var(--onbg) 45%, transparent); color: var(--ink); }
/* Módulo seleccionado: píldora rellena, sin borde (handoff) */
.rail-btn.on { background: var(--onbg); color: var(--teal); }

/* Badge con el nº de capas activas: se ve incluso con el panel colapsado */
.rail-badge {
  position: absolute; top: 4px; right: 4px; min-width: 15px; height: 15px; padding: 0 3px;
  border-radius: 999px; font-family: var(--font-mono); font-size: 9px; font-style: normal;
  /* Mismo acento para todos los productos: el color del badge señalaba «hay
     capas activas», no de qué producto, y tres colores distintos lo hacían
     leer como tres estados diferentes. */
  line-height: 15px; text-align: center; color: var(--nav); background: var(--teal);
  display: none;
}
.rail-badge.on { display: block; }

/* --- Panel de la sección activa --- */
#nav-panel {
  width: 318px; flex: 0 0 318px; display: flex; flex-direction: column; min-height: 0;
  background: var(--nav);
  border: 1px solid var(--line); border-radius: 22px; box-shadow: var(--nav-shadow);
  overflow: hidden;
}
/* ==========================================================================
   Card de centro tipo «Otro» (registro público). Sustituye al popup de
   pestañas: una sola lectura vertical, de la identidad al consejo.
   ========================================================================== */
/* Mismo fondo y sombra que el panel de capas: la card y el menú se ven juntos
   en pantalla, así que comparten superficie (--nav, no --card-bg, que es el
   verde neutro de los popups viejos). */
.cc-pop .mapboxgl-popup-content {
  width: 430px; max-width: 430px; padding: 0; border-radius: 14px;
  background: var(--nav); border: 1px solid var(--line);
  box-shadow: var(--nav-shadow);
}
.cc-pop .mapboxgl-popup-tip { display: none; }
/* El cierre por defecto de Mapbox es un glifo suelto contra el borde. Se le da
   la misma caja que a los botones del menú (34px, radio 11, hover teñido). */
.cc-pop .mapboxgl-popup-close-button {
  top: 7px; right: 7px; width: 26px; height: 26px; padding: 0;
  border: 0; border-radius: 9px; background: transparent;
  color: var(--nav-muted); font-family: var(--font-ui); font-size: 17px;
  /* flex en vez de line-height: el glifo × no se apoya en la línea base como
     una letra y con line-height quedaba descolgado dentro de la caja. */
  display: flex; align-items: center; justify-content: center; line-height: 1;
  transition: background .15s, color .15s;
}
.cc-pop .mapboxgl-popup-close-button:hover {
  background: color-mix(in srgb, var(--onbg) 55%, transparent); color: var(--ink);
}
.cc-pop .mapboxgl-popup-close-button:focus-visible {
  outline: 2px solid var(--teal); outline-offset: 1px;
}
/* Misma escala tipográfica del menú: sans de UI para el texto, mono para las
   cifras y serif solo en el nombre, que cumple aquí el papel que «Suite
   Centinela» cumple en el panel. */
.cc { padding: 18px 20px 16px; font-family: var(--font-ui); color: var(--ink); }

/* Colores de estado: el gradiente y los tonos vienen del handoff. */
.cc [data-t="teal"]  { color: var(--teal); }
.cc [data-t="warn"]  { color: var(--warn); }
.cc [data-t="crit"]  { color: var(--crit); }
.cc [data-t="muted"] { color: var(--nav-muted); }

/* El pill va centrado contra el bloque de identidad, no pegado arriba: en la
   esquina superior derecha vive el botón de cierre y se estorbaban. */
.cc-hd { display: flex; justify-content: space-between; align-items: center; gap: 14px; }
.cc-id { min-width: 0; }
/* Titular + RUT. En mono y sin versalitas: la razón social viene en Title Case
   del padrón y el RUT se lee como cifra, no como rótulo. */
.cc-rot { font-size: 10px; color: var(--nav-muted); line-height: 1.5; }
/* 20px serif: exactamente el título del panel de capas. */
.cc-id h2 { margin: 4px 0 3px; font-family: var(--display); font-size: 20px; letter-spacing: -.022em;
  font-weight: 600; line-height: 1.05; color: var(--ink); }
.cc-id h2 span { font-size: 13px; font-weight: 400; color: var(--nav-muted); }
.cc-meta { font-size: 10px; color: var(--nav-muted); line-height: 1.5; }
/* La coordenada es cifra: mono, al mismo tamaño que la línea del SIEP. */
.cc-coord { font-family: var(--font-mono); font-size: 10px; color: var(--nav-muted);
  line-height: 1.5; }
/* El color lo pone el estado (RIESGO_COLOR) por style inline, igual que la
   barra. Sin estado el pill va punteado: «Sin dato» y «Bajo» comparten gris y
   la línea es lo único que los distingue. */
.cc-pill { flex: 0 0 auto; font-size: 9.5px; font-weight: 700; letter-spacing: .1em;
  text-transform: uppercase; padding: 4px 10px; border-radius: 99px;
  background: transparent; border: 1px solid currentColor; color: var(--nav-muted); }
.cc-pill[data-vacio] { border-style: dashed; }

/* De dónde viene el nivel: medición o modelo. */
.cc-fuente { margin-top: 7px; font-size: 9.5px; color: var(--nav-muted); }

/* Barra de severidad. Los cinco colores son los de RIESGO_COLOR (app.js), los
   mismos con que se pintan los puntos y la leyenda del mapa; cada parada cae en
   el centro de su etiqueta, y entre ellas el degradado es continuo porque el
   riesgo tampoco tiene escalones. Sin monitoreo se apaga y el marcador
   desaparece. */
.cc-bar { position: relative; height: 9px; border-radius: 99px; margin-top: 16px;
  background: linear-gradient(90deg,
    #94a3b8 0%, #94a3b8 10%, #22c55e 30%, #eab308 50%, #f97316 70%,
    #ef4444 90%, #ef4444 100%); }
.cc-bar[data-off] { opacity: .22; }
.cc-mark { position: absolute; top: -3px; width: 3px; height: 15px; border-radius: 2px;
  background: var(--nav); transform: translateX(-50%);
  box-shadow: 0 0 0 1.5px currentColor; }
/* Los tres tramos van tal cual se leen: son nombres de estado, no rótulos de
   sección, y en versalitas competían con el título. */
.cc-esc { display: flex; justify-content: space-between; margin-top: 6px;
  font-size: 10px; color: var(--nav-muted); }

.cc-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 3px 22px;
  border-top: 1px solid var(--line); padding-top: 11px; margin-top: 13px; }
.cc-row { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
/* 10px es el cuerpo de la card: etiquetas, valores, tira, nota y pie usan el
   mismo tamaño que «última muestra». Solo los rótulos en versalitas bajan a
   9.5, porque la caja alta y el tracking los agrandan ópticamente. */
.cc-row > span { font-size: 10px; color: var(--nav-muted); white-space: nowrap; }
.cc-row > b { font-size: 10px; font-weight: 600;
  text-align: right; color: var(--ink); overflow: hidden; text-overflow: ellipsis;
  white-space: nowrap; }
/* Cifras y fechas: exactamente la tipografía de la línea de coordenadas —mono
   sin engrosar—. En negrita, la monoespaciada pesa más que el texto que la
   rodea y la grilla se lee desbalanceada. */
.cc-row > b[data-num] { font-family: var(--font-mono); font-weight: 400; }

.cc-7d { border-top: 1px solid var(--line); padding-top: 13px; margin-top: 15px; }
.cc-7d-hd { display: flex; justify-content: space-between; align-items: baseline;
  margin-bottom: 9px; }
.cc-7d-hd span { font-size: 9.5px; font-weight: 600; letter-spacing: .12em;
  text-transform: uppercase; color: var(--nav-muted); }
.cc-7d-hd em { font-style: normal; font-family: var(--font-mono); font-size: 10px;
  color: var(--nav-muted); }
.cc-dias { display: flex; gap: 6px; }
.cc-d { flex: 1; display: flex; flex-direction: column; align-items: center; gap: 5px; }
.cc-d i { width: 11px; height: 11px; border-radius: 50%; border: 1.5px solid var(--line);
  background: transparent; }
/* Un día sin muestra queda hueco; con conteo cero, relleno. No es lo mismo. */
.cc-d i[data-n="1"] { background: var(--teal); border-color: var(--teal); }
.cc-d i[data-n="2"] { background: #8FBE72; border-color: #8FBE72; }
.cc-d i[data-n="3"] { background: var(--warn); border-color: var(--warn); }
.cc-d i[data-n="4"] { background: var(--crit); border-color: var(--crit); }
.cc-d span { font-family: var(--font-mono); font-size: 10px; color: var(--nav-muted); }

/* La nota es una lectura de lo de arriba, no un aviso aparte: en vez de una
   caja con borde y fondo opacos, una barra del color del estado y un tinte
   apenas perceptible de ese mismo color. */
.cc-nota { margin-top: 15px; padding: 11px 14px; border-radius: 0 9px 9px 0;
  border: 0; border-left: 2px solid currentColor;
  background: color-mix(in srgb, currentColor 7%, transparent); }
.cc-nota p { margin: 0; font-size: 10px; line-height: 1.6; color: var(--ink); }

/* Tres fuentes con rótulos largos no caben en una línea de 430px: se dejan
   envolver en vez de recortarlas. */
.cc-reg { display: flex; flex-wrap: wrap; gap: 6px 18px;
  border-top: 1px solid var(--line); padding-top: 12px; margin-top: 13px; }
.cc-reg > span { display: flex; align-items: baseline; gap: 7px; }
/* Sin versalitas: son nombres, no rótulos de sección. */
.cc-reg-k { font-size: 10px; color: var(--nav-muted); }
/* Superficie y toneladas también son cifras. */
.cc-reg b { font-family: var(--font-mono); font-size: 10px; font-weight: 400;
  color: var(--ink); }

/* Pantalla de arranque del visor. Mismo lenguaje que la espera del login. */
#boot {
  position: fixed; inset: 0; z-index: 40; background: var(--bg);
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 18px; transition: opacity .35s ease;
}
#boot.fuera { opacity: 0; pointer-events: none; }
#boot .boot-logo { width: 46px; height: 46px; color: var(--teal); }
#boot .boot-sp { width: 17px; height: 17px; border: 2px solid var(--teal);
  border-right-color: transparent; border-radius: 50%;
  animation: boot-spin .7s linear infinite; }
#boot .boot-txt { font-family: var(--font-mono); font-size: 10.5px; letter-spacing: .14em;
  text-transform: uppercase; color: var(--nav-muted); }
@keyframes boot-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { #boot .boot-sp { animation-duration: 3s; } }

/* El riel está siempre a la vista: los productos deben poder verse y cambiarse
   sin colapsar el panel. Lo que se monta o desmonta es solo el panel. (Se
   aparta del handoff, que los quería excluyentes.) */
/* El panel ya no se oculta al colapsar: se estrecha (ver arriba). */
/* Con el panel abierto, el botón expandir del riel no tiene función. */
#nav:not(.collapsed) #nav-expand { display: none; }
/* Pegado al menú: 18 de borde + 72 del riel (+14 de hueco y 318 del panel si
   está abierto) + 10 de separación. Junto a los anchos para que no se separen. */
/* Estas dos reglas colocaban el chat FLOTANDO a un lado del menú, con 18 px
   de aire (114 = 72+18+24, 446 = 318+18+110). Ahora el chat va pegado, así que
   su posición la fija `left: var(--nav-w)`; se conservan neutralizadas porque
   su especificidad —`body:has(#nav…)` es 1-1-1— le ganaba a `#chat-panel`. */
body:has(#nav.collapsed) #chat-panel { left: var(--nav-w-min); }
body:has(#nav:not(.collapsed)) #chat-panel { left: var(--nav-w); }

/* Menú flotante del riel (hover con el panel colapsado). Es el mismo panel,
   asomado: reutiliza .lay y .lg-cap para que las filas se vean idénticas a las
   del panel expandido — icono, nombre, fuente debajo y punto de estado. */
#rail-flyout {
  position: absolute; left: 82px; width: 288px; max-height: calc(100% - 24px);
  overflow-y: auto; z-index: 7; padding: 12px 12px 14px;
  background: var(--nav); border: 1px solid var(--line); border-radius: 18px;
  box-shadow: var(--nav-shadow);
}
#rail-flyout.hidden { display: none; }
#rail-flyout .fly-tit { font-size: 10px; font-weight: 700; letter-spacing: .16em;
  text-transform: uppercase; color: var(--teal); padding: 2px 9px 10px; }
#rail-flyout .lg-cap { margin: 12px 2px 4px; font-size: 9px; font-weight: 600;
  letter-spacing: .14em; text-transform: uppercase; color: var(--nav-muted); padding: 0 7px; }
#rail-flyout .lg-cap:first-of-type { margin-top: 2px; }

#rail-flyout .lay {
  display: grid; grid-template-columns: 19px 1fr 8px; align-items: center; gap: 10px;
  width: 100%; text-align: left; padding: 7px 9px; margin: 1px 0; border-radius: 10px;
  cursor: pointer; border: 1px solid transparent; background: transparent;
  font-family: inherit; line-height: 1.25; transition: background .14s, border-color .14s;
}
#rail-flyout .lay:hover { background: rgba(255,255,255,.05); }
#rail-flyout .lay:focus-visible { outline: 2px solid var(--teal); outline-offset: 1px; }
/* Activa: el mismo tratamiento que en el panel — color, sin caja. */
#rail-flyout .lay.on .lay-ic { color: var(--teal); }
#rail-flyout .lay.on .lay-tx b { color: var(--teal); font-weight: 600; }
#rail-flyout .lay.on .lay-dot { background: var(--teal); box-shadow: 0 0 7px var(--teal); }
#rail-flyout .fly-vacio { font-family: var(--display); font-size: 13px; color: var(--nav-muted);
  padding: 14px 10px; line-height: 1.45; }

/* Menú de cuenta: misma superficie que el flotante de capas, anclado abajo. */
#user-menu {
  position: absolute; left: 82px; bottom: 12px; width: 214px; z-index: 7;
  padding: 8px; background: var(--nav); border: 1px solid var(--line);
  border-radius: 16px; box-shadow: var(--nav-shadow);
}
#user-menu.hidden { display: none; }
.um-row { display: flex; align-items: center; gap: 11px; width: 100%; text-align: left;
  border: 0; border-radius: 11px; padding: 10px 11px; cursor: pointer;
  font-family: inherit; font-size: 13px; background: transparent; color: var(--nav-muted);
  transition: background .15s, color .15s; }
.um-row:hover { background: color-mix(in srgb, var(--onbg) 45%, transparent); color: var(--ink); }
.um-row svg { width: 18px; height: 18px; flex: 0 0 auto; }

/* Botón expandir del riel: espejo exacto del colapsar del panel. */
#nav-expand { width: 34px; height: 34px; flex: 0 0 auto; border-radius: 11px;
  border: 1px solid var(--line); background: transparent; color: var(--nav-muted);
  cursor: pointer; padding: 0; margin-bottom: 6px;
  display: flex; align-items: center; justify-content: center;
  transition: background .15s, color .15s; }
#nav-expand:hover { background: color-mix(in srgb, var(--onbg) 45%, transparent);
  color: var(--ink); }
.ic-chev { width: 15px; height: 15px; display: block; }

.np-head { display: flex; align-items: center; gap: 12px; padding: 22px 20px 16px; }
.np-logo { width: 30px; height: 30px; flex: 0 0 auto; color: var(--teal); }
.np-brand { display: flex; flex-direction: column; gap: 3px; min-width: 0; flex: 1; }
/* nowrap es requisito del handoff: el nombre del producto nunca parte en dos. */
.np-brand b { font-family: var(--display); font-size: 20px; font-weight: 300; letter-spacing: -.022em;
  line-height: 1; color: var(--ink); white-space: nowrap; text-transform: none;
  letter-spacing: 0; }
.np-brand span { font-family: var(--font-mono); font-size: 9.5px; letter-spacing: .06em;
  text-transform: uppercase; color: var(--nav-muted); white-space: nowrap; }
/* El botón de plegar era un cuadrado de 34 px en la cabecera del panel. Esa
   cabecera ya no existe y el botón es una fila del pie, que hereda su forma de
   `.np-pie-b`: aquí solo quedaría el margen automático y la caja fija
   rompiéndola. */

.np-body { flex: 1 1 auto; min-height: 0; overflow-y: auto; padding: 0 14px 8px; }

/* Una sección por producto: el panel expandido muestra solo el módulo elegido
   en el riel. Para cambiar de producto se colapsa y se elige otro. */
/* Acordeón: los productos conviven en la lista y cada uno pliega su contenido.
   El encabezado siempre se ve —es el control—, lo que se oculta es el resto. */
.np-body > .lg-group { display: block; margin: 0 0 2px; border: none;
  border-radius: 0; background: none; }
/* Calificada con #controls: las filas se declaran en `#controls label.lay`
   (1-1-1) y una regla de clase no alcanza a ocultarlas. */
#controls > .lg-group:not(.on) > *:not(.np-sec-head) { display: none; }
.np-body > .lg-group.on { margin-bottom: 16px; }

.np-sec-head { display: flex; align-items: center; gap: 8px;
  padding: 8px 10px 8px 8px; border: none; margin: 0; cursor: pointer;
  border-radius: 9px; transition: background .14s; user-select: none; }
.np-sec-head:hover { background: rgba(255,255,255,.045); }
.np-sec-head:focus-visible { outline: 2px solid var(--teal); outline-offset: 1px; }
.np-sec-head h2 { font-family: var(--font-ui); font-size: 9.5px; font-weight: 700;
  letter-spacing: .16em; text-transform: uppercase; margin: 0; color: var(--nav-muted); }
/* El mismo icono que el producto tiene en el riel: al plegarse la sección, el
   icono es lo único que queda para reconocerla. */
/* 21px en los dos estados: el icono del producto es el mismo objeto abierto o
   cerrado, y encogerlo al expandir rompía la continuidad entre las dos vistas. */
.np-sec-ic { width: 21px; height: 21px; flex: 0 0 auto; color: var(--nav-muted);
  transition: color .14s; }
/* El icono lleva el color del producto SIEMPRE, no solo con la sección
   abierta. Es lo único que queda del producto en el riel colapsado, y con el
   rótulo ya coloreado un icono gris rompía la pareja. Los productos previstos
   siguen sin color: no tienen dato que distinguir. */
/* :not(.lg-proximo) — la regla genérica pintaba de teal el icono de cualquier
   sección abierta, y eso devolvía el color a los productos previstos en cuanto
   se desplegaban, que es justo lo contrario de lo que se decidió. */
.lg-group.on:not(.lg-proximo) > .np-sec-head .np-sec-ic { color: var(--teal); }
#controls .lg-group[data-prod="fan"]   .np-sec-head .np-sec-ic { color: var(--fan); }
#controls .lg-group[data-prod="o2"]    .np-sec-head .np-sec-ic { color: var(--o2); }
#controls .lg-group[data-prod="enos"]  .np-sec-head .np-sec-ic { color: var(--enos); }
#controls .lg-group[data-prod="meteo"] .np-sec-head .np-sec-ic { color: var(--meteo); }
#controls .lg-group[data-prod="docs"]  .np-sec-head .np-sec-ic { color: var(--docs); }
/* Y en el riel colapsado, donde el icono ES el producto. */
.rail-btn[data-prod="fan"]   .ic { color: var(--fan); }
.rail-btn[data-prod="o2"]    .ic { color: var(--o2); }
.rail-btn[data-prod="enos"]  .ic { color: var(--enos); }
.rail-btn[data-prod="meteo"] .ic { color: var(--meteo); }
.rail-btn[data-prod="docs"]  .ic { color: var(--docs); }

/* Contador de capas encendidas del producto. */
.np-sec-badge { margin-left: auto; min-width: 15px; height: 15px; padding: 0 4px;
  border-radius: 999px; font-family: var(--font-mono); font-size: 9px;
  font-style: normal; line-height: 15px; text-align: center;
  color: var(--nav); background: var(--teal); display: none; }
.np-sec-badge.on { display: block; }
#nav.collapsed .np-sec-head { position: relative; }
#nav.collapsed .np-sec-badge { position: absolute; top: 4px; right: 12px; margin: 0; }
/* Chevron por CSS: un glifo más en el sprite para algo que es pura geometría
   sería una pieza que mantener. Gira 90° al desplegarse. */
.np-sec-head::before {
  content: ''; flex: 0 0 auto; width: 5px; height: 5px; margin-left: 2px;
  border-right: 1.5px solid var(--nav-muted); border-bottom: 1.5px solid var(--nav-muted);
  transform: rotate(-45deg); transition: transform .16s, border-color .14s;
}
.lg-group.on > .np-sec-head::before { transform: rotate(45deg); }
.lg-group.on > .np-sec-head h2 { color: var(--teal); }
.lg-group.on > .np-sec-head::before { border-color: var(--teal); }
/* La bajada de sección es ruido para el handoff: la fuente vive en el title. */
.np-sec-sub { display: none; }
/* Calificadas con #controls: la regla shadcn `#controls .np-sec-head h2`
   (1-1-1) le ganaba a estas (0-2-1) y los cuatro productos originales salían
   en tinta mientras los nuevos sí llevaban su color. */
#controls .lg-group[data-prod="fan"]  .np-sec-head h2 { color: var(--fan); }
#controls .lg-group[data-prod="o2"]   .np-sec-head h2 { color: var(--o2); }
#controls .lg-group[data-prod="enos"] .np-sec-head h2 { color: var(--enos); }
#controls .lg-group[data-prod="meteo"] .np-sec-head h2 { color: var(--meteo); }

/* --- Contraste del menú en MODO CLARO ------------------------------------
   En oscuro el menú funciona como una superficie continua: el contraste lo da
   el propio fondo negro. En claro esa misma superficie plana se lava —panel
   #FBFAF5 sobre papel #F2EFE7 son dos cremas casi idénticos— y las secciones
   dejan de leerse como piezas separadas.

   La solución es la de los brochures de marca: el panel vuelve al papel y cada
   producto se levanta como TARJETA BLANCA con su filete de color arriba. El
   color deja de ser solo el rótulo y pasa a ser el borde que separa un producto
   del siguiente.

   Solo cuando el menú está expandido: colapsado a 72 px las tarjetas serían
   seis rectángulos apilados alrededor de un icono, que es justo el ruido que
   el riel evita. */
/* Se deja apuntando a --sb-bg, que en claro vale lo mismo (#F2EFE7): así el
   menú y el asistente cambian juntos desde una sola variable. */
body:not(.dark) #nav-panel { background: var(--sb-bg); }

body:not(.dark) #nav:not(.collapsed) .np-body > .lg-group {
  background: #FFFFFF;
  border: 1px solid var(--border);
  border-top: 2px solid var(--faint);   /* filete; el color lo pone el producto */
  border-radius: 11px;
  margin: 0 0 7px;
  overflow: hidden;
  box-shadow: 0 1px 2px rgba(19, 34, 41, .04);
}
body:not(.dark) #nav:not(.collapsed) .np-body > .lg-group.on { margin-bottom: 14px; }
body:not(.dark) #nav:not(.collapsed) .np-body > .lg-group[data-prod="fan"]   { border-top-color: var(--fan); }
body:not(.dark) #nav:not(.collapsed) .np-body > .lg-group[data-prod="o2"]    { border-top-color: var(--o2); }
body:not(.dark) #nav:not(.collapsed) .np-body > .lg-group[data-prod="enos"]  { border-top-color: var(--enos); }
body:not(.dark) #nav:not(.collapsed) .np-body > .lg-group[data-prod="meteo"] { border-top-color: var(--meteo); }

/* El hover con blanco translúcido es invisible sobre una tarjeta blanca. */
body:not(.dark) .np-sec-head:hover { background: rgba(19, 34, 41, .04); }
/* (La regla que cuadraba el encabezado se retiró con las tarjetas: en el menú
   shadcn la fila lleva el mismo radio que «Colapsar menú», y dejarla a 0
   hacía que el único fondo cuadrado del panel fuera el del producto activo.) */

.np-note { font-size: 10.5px; line-height: 1.5; color: #8fa8a4; margin: 10px 2px 0; }
.np-empty { font-size: 11.5px; line-height: 1.55; color: #8fa8a4; margin: 6px 2px;
  padding: 12px; border: 1px dashed rgba(127,211,201,.25); border-radius: 10px; }
.np-empty b { color: var(--o2); font-weight: 600; }
.np-btn { width: 100%; padding: 7px 10px; border-radius: 9px; cursor: pointer; font: inherit;
  font-size: 12px; color: var(--ocean-ink); background: rgba(255,255,255,.05);
  border: 1px solid rgba(127,211,201,.22); }
.np-btn:hover { border-color: var(--accent); }

/* Resultado del buscador: muestra de qué sección viene cada capa */

/* Barra de estado: pie del panel */
#statusbar {
  flex: 0 0 auto; display: flex; flex-direction: column; gap: 3px; align-items: flex-start;
  padding: 9px 14px 12px; margin: 0; border-top: 1px solid rgba(127,211,201,.14);
  background: rgba(0,0,0,.18); color: var(--muted);
  /* Misma tipografía que el card del centro: la barra es texto de estado, no
     una tabla de cifras que necesite ancho fijo. */
  font-size: 11px; box-shadow: none; border-radius: 0;
}
#statusbar b { color: var(--eyebrow); font-weight: 600; }

/* El panel ENOS lleva el acento de su producto */
#enso-panel { border-top: 3px solid var(--enos); }

/* El asistente se abre desde el rail; su botón se ilumina mientras está abierto. */
.rail-btn[data-panel="chat"].on { background: rgba(127,211,201,.15); color: var(--accent);
  border-color: rgba(127,211,201,.3); }

/* ==========================================================================
   Panel ENOS con la identidad Centinela (producto ENOS, acento --enos)
   ========================================================================== */
#enso-panel {
  background: linear-gradient(165deg, var(--ocean-0), var(--ocean-1));
  border: 1px solid var(--border); border-top: 3px solid var(--enos);
  border-radius: 18px; padding: 14px 16px 16px;
}
#enso-panel .controls-head h2 {
  font-family: var(--display); font-size: 17px; font-weight: 400; letter-spacing: -.015em;
  letter-spacing: -.01em; color: var(--enos);
}
#enso-panel h3 {
  font-size: 10px; font-weight: 600; letter-spacing: .16em; text-transform: uppercase;
  color: var(--eyebrow); margin: 16px 0 8px;
}
#enso-toggle { border: 1px solid rgba(154,154,216,.3); background: rgba(154,154,216,.1);
  color: var(--enos); border-radius: 50%; width: 24px; height: 24px; padding: 0; }
#enso-toggle:hover { background: rgba(154,154,216,.2); border-color: var(--enos); }

/* Estado del ciclo. Sin rojo de alarma dominante: El Niño toma el cálido de la
   marca (--bad) sobre un fondo tenue, no un bloque rojo. */
.enso-status {
  font-family: var(--font-ui); font-weight: 600; font-size: 14px; letter-spacing: .01em;
  padding: 9px 10px; border-radius: 10px; border: 1px solid transparent;
  background: rgba(255,255,255,.04); color: var(--fg);
}
.enso-status.nino,    body.dark .enso-status.nino    { background: rgba(224,113,95,.12);  border-color: rgba(224,113,95,.3);  color: var(--bad); }
.enso-status.nina,    body.dark .enso-status.nina    { background: rgba(143,176,224,.12); border-color: rgba(143,176,224,.3); color: var(--deep); }
.enso-status.neutral, body.dark .enso-status.neutral { background: rgba(92,193,137,.12);  border-color: rgba(92,193,137,.3);  color: var(--good); }

/* Tarjetas de índice: cifra en mono, clave en eyebrow */
.enso-card {
  background: rgba(255,255,255,.04); border: 1px solid rgba(154,154,216,.16);
  border-radius: 11px; padding: 9px 11px;
}
.enso-k { font-size: 9px; font-weight: 600; letter-spacing: .14em; text-transform: uppercase;
  color: var(--eyebrow); }
.enso-v { font-family: var(--font-mono); font-size: 19px; font-weight: 600; }

.enso-chart-title { font-size: 10px; font-weight: 600; letter-spacing: .14em;
  text-transform: uppercase; color: var(--eyebrow); margin: 16px 0 6px; }
#enso-chart .spark-line { stroke: var(--enos); }
#enso-chart .zero-line { stroke: rgba(154,154,216,.3); }

/* Botones y salidas de IA / NOAA */
.ia-actions button {
  border: 1px solid rgba(154,154,216,.28); background: rgba(255,255,255,.04);
  color: var(--fg2, var(--fg)); border-radius: 9px; font-size: 11px; padding: 7px 0;
}
.ia-actions button:hover:not(:disabled) { border-color: var(--enos); color: var(--enos); }
.noaa-more { color: var(--enos); }
.noaa-out, .ia-out { font-family: var(--font-ui); }
.ia-out h5 { font-family: var(--font-ui); font-weight: 600; color: var(--fg); }

/* La ficha de centro comparte la superficie de la marca */
.center-panel { background: linear-gradient(165deg, var(--ocean-0), var(--ocean-1));
  border-top: 3px solid var(--fan); border-radius: 18px; }
.center-panel h2 { font-family: var(--display); color: var(--fan); }

/* .hint estaba limitada a #controls; fuera de ahí heredaba el cuerpo y se veía
   enorme (p. ej. la nota de Calibración FAN del panel ENOS). */
.hint { font-size: 11px; line-height: 1.5; color: var(--muted); margin: 6px 0 8px; }
.muted { color: var(--muted); }
#enso-meta { font-size: 10px; line-height: 1.45; color: var(--faint, var(--muted)); }
.noaa-out, .ia-out, .noaa-disc p { font-size: 11.5px; line-height: 1.55; }
.noaa-syn { font-size: 12px; }

/* ==========================================================================
   Filas de capa: icono + nombre + fuente, una por línea (limpias, sin glifos
   sueltos). El estado activo se lee por el color del producto, como los ítems
   de una barra de navegación — la simbología del mapa la explica la leyenda.
   ========================================================================== */
.lg-group { --ac: var(--accent); }
.lg-group[data-prod="fan"]  { --ac: var(--fan); }
.lg-group[data-prod="o2"]   { --ac: var(--o2); }
.lg-group[data-prod="enos"] { --ac: var(--enos); }
.lg-group[data-prod="meteo"] { --ac: var(--meteo); }

#controls label.lay {
  display: grid; grid-template-columns: 19px 1fr 8px; align-items: center; gap: 10px;
  padding: 7px 9px; margin: 1px 0; border-radius: 10px; cursor: pointer;
  border: 1px solid transparent; background: transparent;
  text-indent: 0; line-height: 1.25; transition: background .14s, border-color .14s;
}
.lay input[type="checkbox"] { position: absolute; width: 1px; height: 1px; opacity: 0; margin: 0; }
.lay-ic { width: 19px; height: 19px; display: block; color: var(--faint); transition: color .14s; }
.lay-tx { min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.lay-tx b { font-size: 12px; font-weight: 500; color: var(--fg2, var(--fg));
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.lay-tx em { font-style: normal; font-size: 9.5px; color: var(--faint);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.lay-dot { width: 7px; height: 7px; border-radius: 50%; background: rgba(233,227,214,.16); transition: .14s; }

.lay:hover { background: rgba(255,255,255,.05); }
/* El contorno solo con teclado: con :focus-within quedaba marcado el ítem
   después de cada clic. :focus-visible mantiene la accesibilidad sin el borde. */
.lay:has(input:focus-visible) { outline: 2px solid var(--ac); outline-offset: 1px; }
/* Activa: sin píldora. El estado se lee por el color del texto, el icono y el
   punto —lo mismo en el panel y en el flotante—; la caja rellena competía con
   el propio contenido de la fila. */
.lay:has(input:checked) .lay-ic { color: var(--teal); }
.lay:has(input:checked) .lay-tx b { color: var(--teal); font-weight: 600; }
.lay:has(input:checked) .lay-dot { background: var(--teal); box-shadow: 0 0 7px var(--teal); }

/* Encabezados de bloque dentro de la sección */
.np-body .lg-cap { margin: 12px 2px 4px; font-size: 9px; font-weight: 600;
  letter-spacing: .14em; text-transform: uppercase; color: var(--eyebrow); }
.np-body .lg-cap:first-of-type { margin-top: 6px; }

/* Ajustes: el botón de tema con etiqueta, no solo el glifo */
#theme-toggle.np-btn { display: flex; align-items: center; justify-content: center; gap: 8px; }
.boletines { margin-top: 2px; }

/* El panel de índices arranca oculto: se abre desde la sección Centinela ENOS.
   Necesita regla propia porque en este proyecto no hay una `.hidden` genérica. */
#enso-panel.hidden { display: none; }
.np-btn.on { border-color: var(--ac); color: var(--ac); background: color-mix(in srgb, var(--ac) 12%, transparent); }

/* Leyenda de concesiones */

/* Línea de tiempo del fiordo: misma caja que la de ECMWF (arriba comparten las
   reglas). Lo propio es el selector de fecha, que MOSA sí tiene porque su
   pronóstico se pide por corrida. */
#mosa-timeline.hidden, #mosa-legend.hidden { display: none; }
#mosa-timeline #mosa-slider { width: 100%; }
/* Salto directo a un día del pronóstico: el eje del fiordo abarca dos semanas y
   arrastrar el deslizador hasta una fecha concreta es incómodo. */
#mosa-timeline #mosa-date {
  flex: 0 0 auto; border: 1px solid var(--border); border-radius: 8px;
  background: var(--inner-card); color: var(--fg); font: inherit; font-size: 10.5px;
  padding: 4px 6px;
}


/* ==========================================================================
   CAPA MÓVIL
   --------------------------------------------------------------------------
   Va al final del archivo a propósito. Este CSS ya arrastra dos media queries
   con reglas muertas —`#nav-panel{width:210px}` de la de 900px pierde contra la
   declaración de 318px que aparece después, y `#chat-panel{left:296px}` pierde
   contra los `body:has(...)`—, así que aquí todo se declara al final y, donde
   compite con un `body:has(...)`, se califica igual o más.

   Dos dimensiones separadas y ortogonales:

     · COMPACTO  (max-width:820px), (max-height:520px)  → LAYOUT
       La segunda condición captura el teléfono en horizontal (844×390), que
       por ancho pasaría por escritorio con 390 px de alto.

     · TÁCTIL    (pointer: coarse)                      → ERGONOMÍA
       Áreas de 44 px y campos de 16 px. Independiente del ancho: un iPad de
       1024 px necesita esto y no lo otro.
   ========================================================================== */

/* Los tiradores solo tienen sentido cuando la superficie es una hoja
   arrastrable: en escritorio son un asa que no arrastra nada. */
.cc-grab, .np-grab { display: none; }

/* El velo solo existe en móvil. Fuera de compacto no debe ni ocupar sitio: es
   hijo flex de #nav y, al desplegar el panel, entraba en la fila con ancho 0. */
#nav-velo { display: none; }

:root {
  --barra: 58px;               /* alto de la barra de productos */
  --seguro-abajo: env(safe-area-inset-bottom, 0px);
  --barra-total: calc(var(--barra) + var(--seguro-abajo));
  --hoja: 72dvh;               /* alto máximo de una hoja inferior */
}

/* ===================== COMPACTO: layout ===================== */
@media (max-width: 820px), (max-height: 520px) {

  /* Nada debe empujar el documento, ni a lo ancho ni a lo alto: sin esto iOS
     hace rebotar la página entera sobre un mapa que ya ocupa la pantalla. */
  html, body { overflow: hidden; overscroll-behavior: none; }
  /* El destello gris del toque delata cada fila del menú como si fuera un
     enlace roto. Mapbox ya lo quita en su lienzo; aquí falta en el resto. */
  .np-sec-head, .np-pie-b, .um-row, #controls label.lay, .cc-pop button {
    -webkit-tap-highlight-color: transparent;
  }

  /* ---- Menú: barra de productos abajo + hoja inferior ---- */
  #nav {
    top: auto; left: 0; right: 0; bottom: 0;
    display: block; border-radius: 0;
  }

  /* Colapsado = barra de pestañas. Reutiliza el panel tal cual: sus hijos ya
     son los 6 productos con su icono, y el manejador de `.np-sec-head` ya
     expande el panel abriendo esa sección. No hace falta marcado nuevo. */
  #nav.collapsed #nav-panel {
    width: 100%; flex-basis: auto; flex-direction: row; align-items: stretch;
    height: var(--barra-total); padding-bottom: var(--seguro-abajo);
    border-radius: 0; border-left: 0; border-right: 0; border-bottom: 0;
  }
  #nav.collapsed .np-head { display: none; }
  #nav.collapsed .np-body {
    display: flex; flex-direction: row; flex: 1 1 auto;
    overflow-x: auto; overflow-y: hidden; padding: 0;
    scrollbar-width: none;
  }
  #nav.collapsed .np-body::-webkit-scrollbar { display: none; }
  #nav.collapsed #controls > .lg-group { flex: 1 0 auto; margin: 0; }
  #nav.collapsed .np-sec-head {
    height: 100%; min-width: 56px; padding: 0 12px; margin: 0; border-radius: 0;
  }
  /* En columna el contador se anclaba arriba-derecha del icono; en fila el
     icono está centrado y el ancla tiene que seguirlo. */
  #nav.collapsed .np-sec-badge { top: 8px; right: 8px; }
  #nav.collapsed .np-pie {
    flex: 0 0 auto; flex-direction: row; gap: 0;
    border-top: 0; border-left: 1px solid var(--line); padding: 0;
  }
  #nav.collapsed .np-pie-b { padding: 0 14px; }

  /* Expandido = hoja inferior. */
  #nav:not(.collapsed) #nav-panel {
    width: 100%; flex-basis: auto; max-height: var(--hoja);
    border-radius: 18px 18px 0 0; border-bottom: 0;
    padding-bottom: var(--seguro-abajo);
  }
  #nav-velo {
    display: block; position: fixed; inset: 0; z-index: -1;
    background: rgba(6, 14, 18, .55);
    -webkit-backdrop-filter: blur(2px); backdrop-filter: blur(2px);
  }
  #nav-velo[hidden] { display: none; }

  /* ---- Superficies que no caben en un teléfono (decisión de producto) ---- */
  #enso-panel, .center-panel { display: none !important; }

  /* ---- Asistente: pantalla completa. Los `body:has(...)` de más arriba fijan
     `left` con especificidad (2,0,1); hay que igualarla para vencerlos. ---- */
  body:has(#nav.collapsed) #chat-panel,
  body:has(#nav:not(.collapsed)) #chat-panel,
  #chat-panel {
    position: fixed; inset: 0; left: 0; top: 0; right: 0; bottom: 0;
    width: 100%; min-width: 0; max-width: none; border-radius: 0;
    padding-bottom: var(--seguro-abajo);
    /* Por encima de la barra de productos (12). El asistente a pantalla
       completa es una superficie propia: si la barra le queda delante, tapa
       justo el campo de escritura, que vive abajo. Se sale con su aspa. */
    z-index: 14;
  }
  /* El texto del asistente se lee, no se ojea: 12,5 px es poco en un teléfono. */
  .chat-msg { font-size: 14px; }
  .chat-chip { font-size: 13px; padding: 10px 14px; }
  #chat-msgs { overscroll-behavior: contain; }

  /* ---- Zócalo: encima de la barra, y nunca de ancho negativo ---- */
  #bottom-dock {
    left: 0; right: 0; transform: none;
    /* Tres franjas apiladas de abajo arriba: barra de productos, franja de
       atribución de Mapbox (~24 px) y zócalo. Sin el hueco de la atribución la
       leyenda se sentaba justo encima del logotipo. */
    bottom: calc(var(--barra-total) + 30px);
    max-width: none; width: 100%; padding: 0 10px;
    align-items: stretch;
  }
  #anim-timeline, #mosa-timeline { width: 100%; }
  .atl-label { min-width: 0; }
  .ml-item { min-width: 0; }
  /* Con una hoja abierta la leyenda quedaba flotando por encima de ella. */
  body:has(#nav:not(.collapsed)) #bottom-dock,
  body:has(.cc-pop) #bottom-dock { display: none; }

  /* ---- Logotipo y atribución de Mapbox: obligatorios por licencia. La barra
     inferior los tapaba; se suben por encima de ella. ---- */
  .mapboxgl-ctrl-bottom-left,
  .mapboxgl-ctrl-bottom-right { bottom: var(--barra-total); }

  /* ---- Popups: ninguno puede ser más ancho que la pantalla ---- */
  .mapboxgl-popup-content { max-width: calc(100vw - 20px); }
  .dm-card, .sh-card, .cpop, .meteo-card, .wb-card, .alex-pop, .pt-pop {
    min-width: 0;
  }
  .cpop-pop .mapboxgl-popup-content,
  .dm-pop .mapboxgl-popup-content,
  .sh-pop .mapboxgl-popup-content,
  .meteo-pop .mapboxgl-popup-content {
    max-height: 70dvh; overflow-y: auto; overscroll-behavior: contain;
  }

  /* ---- Apilamiento de las hojas ----
     `.mapboxgl-popup` no declara z-index y vive dentro de #map, que al no tener
     z-index propio NO crea contexto de apilamiento: el popup compite en la raíz
     contra el zócalo (7), el chat (8), el menú (9), el lienzo de partículas (3)
     y las esquinas de control de Mapbox (2). Sin esto, encender las corrientes
     dibuja las partículas por encima de la ficha. */
  .cc-pop.mapboxgl-popup { z-index: 10; }
  #nav { z-index: 12; }                       /* barra y hoja, sobre la ficha */
  .mapboxgl-ctrl-top-right { z-index: 11; }   /* controles siempre alcanzables */

  /* ---- Tarjeta de centro: hoja inferior.
     Mapbox reescribe el `transform` inline del popup en cada render; la hoja de
     estilos con !important lo vence y sobrevive al pan del mapa (comprobado). -- */
  .cc-pop.mapboxgl-popup {
    position: fixed !important;
    left: 0 !important; right: 0 !important;
    top: auto !important; bottom: var(--barra-total) !important;
    transform: none !important;
    width: 100% !important; max-width: none !important;
  }
  .cc-pop .mapboxgl-popup-content {
    width: 100%; max-width: none; max-height: var(--hoja);
    /* Sin `contain`, al terminar el scroll de la tarjeta el gesto sigue como
       pan del mapa y la ficha se va de las manos. */
    overflow-y: auto; overscroll-behavior: contain;
    border-radius: 18px 18px 0 0;
  }
  .cc-pop .mapboxgl-popup-tip { display: none; }
  /* ---- Maqueta propia de la ficha en móvil ----
     No es la de escritorio estirada: a 390 px las dos columnas dejaban 175 px
     por celda y la etiqueta se comía el valor con puntos suspensivos. */

  .cc-grab {
    display: block; padding: 10px 0 6px; cursor: grab;
    /* El navegador no debe interpretar el arrastre vertical como scroll: el
       gesto es nuestro. */
    touch-action: none;
  }
  .cc-grab i {
    display: block; width: 38px; height: 4px; margin: 0 auto;
    border-radius: 99px; background: var(--line);
  }
  .cc-grab:active { cursor: grabbing; }
  .cc { padding: 0 18px 18px; }

  /* Etiqueta encima del valor: cabe el nombre científico entero, que es de lo
     que más se lee aquí. */
  .cc-grid { gap: 13px 16px; padding-top: 14px; margin-top: 13px; }
  .cc-row { flex-direction: column; align-items: stretch; gap: 1px; }
  .cc-row > span { font-size: 10.5px; letter-spacing: .04em; }
  .cc-row > b { font-size: 13px; text-align: left; white-space: normal; }
  .cc-row > b[data-num] { font-size: 12.5px; }

  .cc-rot, .cc-meta, .cc-coord { font-size: 11.5px; }
  .cc-id h2 { font-size: 23px; }
  .cc-esc { font-size: 11px; }
  .cc-fuente { font-size: 11px; }
  .cc-nota p { font-size: 12.5px; line-height: 1.55; }
  .cc-nota { padding: 13px 15px; }
  .cc-7d-hd span, .cc-7d-hd em { font-size: 11px; }
  .cc-d span { font-size: 10px; }
  .cc-d i { width: 13px; height: 13px; }
  .cc-reg { gap: 8px 20px; }
  .cc-reg-k, .cc-reg b { font-size: 11.5px; }
  /* La píldora de estado y el nombre compiten por la misma línea; con el
     nombre a 23px hay que dejarle sitio. */
  .cc-pill { font-size: 10.5px; padding: 5px 11px; }
}

/* ===================== TÁCTIL: ergonomía ===================== */
@media (pointer: coarse) {

  /* Campos por debajo de 16px: Safari iOS hace zoom al enfocarlos y deja el
     visor descuadrado, sin forma de volver. */
  #controls select, #controls input[type="date"], .ecmwf-ctl select,
  #mosa-timeline #mosa-date, .chat-form input, .lgn-campo input {
    font-size: 16px;
  }

  /* Objetivo táctil mínimo. */
  .np-sec-head, .np-pie-b, .um-row, #controls label.lay, #rail-flyout .lay {
    min-height: 44px;
  }
  #nav-collapse, #nav-expand, .chat-head #chat-close, .chat-form button,
  #enso-toggle, #anim-timeline #ecmwf-play, #mosa-timeline #mosa-play,
  .cc-pop .mapboxgl-popup-close-button, .lgn-ver, .lgn-tema {
    width: 44px; height: 44px;
  }
  .cc-pop .mapboxgl-popup-close-button { top: 4px; right: 4px; font-size: 20px; }

  /* El pulgar nativo del deslizador ronda los 16px: con el dedo no se agarra. */
  input[type="range"]::-webkit-slider-thumb {
    -webkit-appearance: none; appearance: none;
    width: 24px; height: 24px; border-radius: 50%;
    background: var(--teal); border: 2px solid var(--nav); cursor: pointer;
  }
  input[type="range"]::-moz-range-thumb {
    width: 24px; height: 24px; border-radius: 50%;
    background: var(--teal); border: 2px solid var(--nav); cursor: pointer;
  }
  input[type="range"] { height: 24px; }
}

/* Sin puntero fino no hay hover: el flotante de capas es una afordancia que no
   existe. Se apaga por CSS además de por JS, para que no aparezca por un
   `focus` accidental. */
@media (hover: none) {
  #rail-flyout { display: none !important; }
}

/* En pantallas táctiles se retira el desenfoque de fondo de los paneles: obliga
   a releer el framebuffer en cada fotograma, sobre un lienzo WebGL que ya está
   repintando a 60 fps. En GPU móvil suele costar más que las propias partículas.
   El fondo pasa a opaco, que además se lee mejor sobre imagen satelital. */
@media (pointer: coarse) {
  #anim-timeline, #mosa-timeline, #map-legend, .panel, #nav-panel, #chat-panel {
    -webkit-backdrop-filter: none; backdrop-filter: none;
  }
  #anim-timeline, #mosa-timeline, #map-legend { background: var(--nav); }
}

/* ==========================================================================
   Tipografía de rótulos — unificada con la fila de capa
   --------------------------------------------------------------------------
   La fila «Mis Centros de Cultivo» usa Switzer en caja normal a 12 px con peso
   medio, y es lo más legible del menú. El resto de los rótulos venía en
   versalita de 9-10 px con tracking de .14-.16em: una convención de eyebrow que
   a ese tamaño obliga a descifrar letra por letra y, ahora que hay una sola
   familia, pelea con el propio texto que rotula.

   Se unifican todos los RÓTULOS (encabezados de producto, subgrupos, títulos de
   panel, leyendas del flotante y de la barra superior) a ese mismo tratamiento:
   caja normal, tracking neutro, jerarquía por peso y color.

   Lo que NO se toca son las PÍLDORAS y ETIQUETAS —badges, tags, chips—: ahí la
   versalita no rotula, forma parte de la figura, y bajarla a caja normal las
   convertiría en texto suelto dentro de una cápsula.
   ========================================================================== */

.np-sec-head h2,
#rail-flyout .fly-tit {
  font-family: var(--font-ui); font-size: 12.5px; font-weight: 500;
  letter-spacing: -.005em; text-transform: none;
}
.lg-cap,
/* .np-body .lg-cap (0-2-0) gana a la clase suelta: hay que igualar la
   especificidad o el subgrupo se queda en versalita. */
.np-body .lg-cap,
#rail-flyout .lg-cap,
.panel h3,
.cc-7d-hd span,
.tb-f > span,
.tb-capa,
.np-brand span,
#boot .boot-txt {
  font-family: var(--font-ui); font-size: 11px; font-weight: 500;
  letter-spacing: 0; text-transform: none;
}
/* El subtítulo de la marca es el único que conserva algo de aire: es una
   bajada, no un rótulo de sección, y sin tracking se pega al nombre. */
.np-brand span, .tb-nom + span { letter-spacing: .01em; }

/* La fila de filtros se desplaza en horizontal cuando hay varias capas
   encendidas; el degradado del borde derecho es el único aviso, porque la
   barra de desplazamiento está oculta (aparecería y desaparecería al filtrar,
   moviendo toda la fila un par de píxeles). */
#tb-filtros.desborda {
  -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 26px), transparent);
  mask-image: linear-gradient(to right, #000 calc(100% - 26px), transparent);
}
#topbar > #tb-limpiar { margin-left: 10px; }
/* Selectores algo más estrechos: con diez en pantalla, 190 px cada uno no
   caben en un portátil de 1280. */

/* Sin marca dentro, el encabezado del panel solo aloja el botón de colapsar:
   los 22 px de aire de arriba eran el sitio del logo y ahora son una franja
   vacía sobre la primera capa. */
.np-head { padding: 10px 12px 4px; min-height: 0; }

/* ==========================================================================
   Estructura de la pantalla — barra arriba, menú a la izquierda, mapa al resto
   --------------------------------------------------------------------------
   Antes el menú FLOTABA sobre el mapa: una tarjeta con márgenes, radio y
   sombra. Se ve bien en una captura, pero significa que el mapa se extiende
   por debajo y hay 318 px de fiordo que nunca se pueden ver ni pinchar. Con el
   menú anclado al borde y el mapa empezando a su derecha, todo el lienzo es
   utilizable y el menú deja de tapar dato.

   Consecuencia que hay que atender en JS: el mapa cambia de ANCHO al colapsar
   el menú, no solo de zona visible. Mapbox necesita un resize().
   ========================================================================== */
:root { --nav-w: 318px; --nav-w-min: 72px; }

#topbar {
  position: fixed; top: 0; left: 0; right: 0; width: 100%;
  border-radius: 0; z-index: 20;
}

#nav {
  position: fixed; top: var(--topbar-h); left: 0; bottom: 0;
  margin: 0; z-index: 9;
}
/* Pegado al borde: sin radio, sin sombra y sin bordes exteriores. El único que
   queda es el derecho, que es el que separa el menú del mapa. */
#nav-panel {
  border: none; border-right: 1px solid var(--line);
  border-radius: 0; box-shadow: none;
  width: var(--nav-w); flex-basis: var(--nav-w);
}
#nav.collapsed #nav-panel { width: var(--nav-w-min); flex-basis: var(--nav-w-min); }

/* El mapa arranca a la derecha del menú y por debajo de la barra. */
#map { position: fixed; top: var(--topbar-h); left: var(--nav-w); right: 0; bottom: 0; }
body.nav-min #map { left: var(--nav-w-min); }

/* Las tarjetas de producto pierden el margen lateral que las separaba del
   borde del panel flotante; ahora el borde es la pantalla. */
body:not(.dark) #nav:not(.collapsed) .np-body > .lg-group { margin-left: 0; margin-right: 0; }

/* En COMPACTO el menú vuelve a ser hoja inferior, no columna: el mapa recupera
   todo el ancho. Va después de la capa móvil para ganarle por orden, igual que
   el resto de las reglas de estructura. */
@media (max-width: 820px), (max-height: 520px) {
  #map, body.nav-min #map { left: 0; }
  #nav { position: absolute; top: auto; }
  #nav-panel { width: auto; flex-basis: auto; border-right: none; }
  #topbar { position: absolute; }
}

/* ==========================================================================
   MENÚ ESTILO SHADCN
   --------------------------------------------------------------------------
   Sustituye a las tarjetas por producto. Aquellas separaban bien, pero cada
   sección quedaba encerrada en su propio recuadro y el menú se leía como seis
   objetos sueltos en vez de un árbol. El patrón de shadcn resuelve lo mismo
   con jerarquía en lugar de contorno: rótulo de grupo tenue, ítems de 32 px con
   realce redondeado al pasar, chevron a la DERECHA y —lo que realmente ordena—
   una guía vertical que marca el nivel de los hijos.

   El color del producto se conserva, pero solo en el icono y en el ítem activo:
   como acento, no como marco.
   ========================================================================== */

:root {
  --sb-bg: #F7F5EF;        /* papel apenas más apagado que la tarjeta */
  --sb-item: rgba(19, 34, 41, .055);
  --sb-radio: 7px;
}
body.dark {
  --sb-bg: #0D1D22;
  --sb-item: rgba(255, 255, 255, .06);
}

#nav-panel { background: var(--sb-bg); }
.np-body { padding: 6px 8px; }

/* Se anula el tratamiento de tarjeta del modo claro. */
body:not(.dark) #nav:not(.collapsed) .np-body > .lg-group {
  background: none; border: none; border-radius: 0;
  margin: 0 0 1px; box-shadow: none; overflow: visible;
}
body:not(.dark) #nav:not(.collapsed) .np-body > .lg-group.on { margin-bottom: 6px; }
.np-body > .lg-group { position: relative; margin: 0 0 1px; }
.np-body > .lg-group.on { margin-bottom: 6px; }

/* Rótulo de grupo: «Platform» / «Projects» en shadcn. */
.lg-cap, .np-body .lg-cap {
  font-size: 11.5px; font-weight: 500; letter-spacing: 0; text-transform: none;
  color: var(--nav-muted); margin: 10px 0 2px; padding: 0 8px;
}

/* Ítem de primer nivel = producto. */
#controls .np-sec-head {
  height: 32px; padding: 0 8px; gap: 8px; border-radius: var(--sb-radio);
  margin: 0;
}
#controls .np-sec-head:hover { background: var(--sb-item); }
#controls .np-sec-head h2 {
  font-size: 13.5px; font-weight: 400; letter-spacing: 0; text-transform: none;
  color: var(--ink); flex: 1 1 auto; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.np-sec-ic { width: 16px; height: 16px; }
/* Chevron al final de la fila, no pegado al texto. */
#controls .np-sec-head::before { order: 9; margin-left: 4px; opacity: .6; }
#controls .lg-group.on > .np-sec-head { background: var(--sb-item); }
#controls .lg-group.on > .np-sec-head h2 { font-weight: 500; }

/* Guía vertical de los hijos: es lo que convierte una lista plana en árbol. */
.np-body > .lg-group.on::before {
  content: ''; position: absolute; left: 15px; top: 34px; bottom: 2px;
  width: 1px; background: var(--line); pointer-events: none;
}
#controls > .lg-group.on > *:not(.np-sec-head) { margin-left: 24px; }

/* Filas de capa: un solo escalón por debajo del producto. */
#controls label.lay { border-radius: var(--sb-radio); padding: 5px 8px; }
#controls label.lay:hover { background: var(--sb-item); }
.lay-tx b { font-size: 13px; font-weight: 400; }
.lay:has(input:checked) .lay-tx b { font-weight: 500; }
.lay-tx em { font-size: 10.5px; }

/* Botón del menú en la barra, con la misma caja que un ítem del panel. */
/* (El botón tampoco vive ya en la barra superior: sus reglas se retiran.) */

/* ==========================================================================
   Pie del menú y marca de la barra — shadcn
   ========================================================================== */

/* Marca con bajada: dos líneas apretadas, la bajada en tenue. La barra sube a
   56 px para que las dos respiren sin empujar el mapa. */
:root { --topbar-h: 56px; }
.tb-tx { display: flex; flex-direction: column; gap: 0; min-width: 0; line-height: 1.12; }
.tb-nom { font-family: var(--display); font-size: 15px; font-weight: 500;
  letter-spacing: -.018em; color: var(--ink); white-space: nowrap; }
.tb-baj { font-family: var(--font-ui); font-style: normal; font-size: 10.5px;
  font-weight: 400; letter-spacing: .01em; color: var(--nav-muted); white-space: nowrap; }
.tb-logo { width: 28px; height: 28px; }

/* El pie deja de ser una fila de dos botones iguales y pasa a ser una pila:
   acciones arriba, identidad abajo, como el sidebar de shadcn. */
.np-pie {
  flex-direction: column; gap: 1px; padding: 6px 8px 8px;
  border-top: 1px solid var(--line);
}
#controls ~ .np-pie .np-pie-b, .np-pie > .np-pie-b {
  flex: 0 0 auto; width: 100%; justify-content: flex-start;
  height: 32px; padding: 0 8px; gap: 8px; border-radius: var(--sb-radio);
  font-size: 13.5px; font-weight: 400; color: var(--ink);
}
.np-pie > .np-pie-b:hover { background: var(--sb-item); }
.np-pie > .np-pie-b .ic { width: 16px; height: 16px; color: var(--nav-muted); }

/* Tarjeta de usuario. */
.np-user {
  display: flex; align-items: center; gap: 8px; width: 100%;
  margin-top: 5px; padding: 6px 8px; border: none; background: none;
  border-radius: var(--sb-radio); cursor: pointer; text-align: left;
  font-family: var(--font-ui);
}
.np-user:hover { background: var(--sb-item); }
.np-user-av {
  width: 28px; height: 28px; flex: 0 0 auto; border-radius: 7px;
  display: grid; place-items: center;
  background: var(--teal); color: #fff;
  font-size: 10.5px; font-weight: 600; letter-spacing: .02em; text-transform: uppercase;
}
.np-user-tx { display: flex; flex-direction: column; min-width: 0; flex: 1 1 auto; line-height: 1.25; }
.np-user-tx b { font-size: 12.5px; font-weight: 500; color: var(--ink);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.np-user-tx em { font-style: normal; font-size: 10.5px; color: var(--nav-muted);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.np-user-ch { width: 14px; height: 14px; flex: 0 0 auto; color: var(--nav-muted); }

/* Colapsado: sobrevive el avatar y el icono; se va la palabra. */
#nav.collapsed .np-pie { padding: 6px 6px 8px; }
#nav.collapsed .np-user { justify-content: center; padding: 6px 0; }
#nav.collapsed .np-user-tx, #nav.collapsed .np-user-ch { display: none; }
#nav.collapsed .np-pie > .np-pie-b { justify-content: center; padding: 0; }

/* Desplegable de filtro multiselección. Va en <body> y posicionado a mano
   porque la barra recorta en horizontal (`overflow-x: auto`) y dentro del
   carril el popover quedaría cortado por su propio contenedor. */
.tb-pop {
  position: fixed; z-index: 40; min-width: 200px; max-width: 300px;
  background: var(--nav); border: 1px solid var(--line); border-radius: 9px;
  box-shadow: 0 10px 30px rgba(0, 0, 0, .18); padding: 4px;
}
.tb-pop-lista { max-height: 320px; overflow-y: auto; }
.tb-pop-f {
  display: flex; align-items: center; gap: 8px; padding: 6px 8px;
  border-radius: var(--sb-radio); cursor: pointer;
  font-size: 12.5px; color: var(--ink); line-height: 1.3;
}
.tb-pop-f:hover { background: var(--sb-item); }
.tb-pop-f.on { color: var(--teal); font-weight: 500; }
.tb-pop-f input { width: 14px; height: 14px; flex: 0 0 auto; accent-color: var(--teal);
  margin: 0; cursor: pointer; }
.tb-pop-f span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tb-pop-todos {
  width: 100%; margin-top: 4px; padding: 6px 8px; border: none; background: none;
  border-top: 1px solid var(--line); border-radius: 0 0 6px 6px;
  font-family: var(--font-ui); font-size: 11.5px; color: var(--nav-muted);
  cursor: pointer; text-align: left;
}
.tb-pop-todos:hover { color: var(--crit); }
/* El filtro con selección se marca en el disparador: un filtro activo que no se
   ve es dato escondido sin explicación. */
.tb-f.activo .tb-disp { border-color: var(--teal); color: var(--teal); font-weight: 500; }

/* --- Tamaño de los iconos del menú --------------------------------------
   Dos correcciones. Una de escala: a 16 px los glifos de producto quedaban
   tímidos, y COLAPSADO son lo único que hay en pantalla —ahí el icono no
   acompaña al nombre, ES el nombre—, así que crecen más.

   Otra de jerarquía: el icono de capa medía 19 px y el de producto 16, o sea
   el hijo pesaba más que el padre. Ahora el producto manda (18) y la capa
   acompaña (17). */
.np-sec-ic { width: 18px; height: 18px; }
.lay-ic { width: 17px; height: 17px; }
.np-pie > .np-pie-b .ic { width: 18px; height: 18px; }

#nav.collapsed .np-sec-ic { width: 22px; height: 22px; }
#nav.collapsed .np-pie > .np-pie-b .ic { width: 22px; height: 22px; }
#nav.collapsed .np-user-av { width: 30px; height: 30px; border-radius: 8px; font-size: 11px; }
/* Filas más altas al colapsar: un icono de 22 px en una caja de 32 lo deja sin
   aire y las seis filas se leen como una columna continua. */
#nav.collapsed #controls .np-sec-head { height: 40px; }

/* ==========================================================================
   Asistente acoplado — tercera columna entre el menú y el mapa
   --------------------------------------------------------------------------
   Antes flotaba sobre el mapa con margen, radio y sombra. Eso significa que
   460 px de fiordo quedaban debajo del panel: ni se ven ni se pinchan, justo
   mientras se le pregunta al asistente por lo que hay ahí. Ahora es una
   columna: se pega al menú, comparte su borde y EMPUJA el mapa.
   ========================================================================== */
:root { --chat-w: 400px; }

#chat-panel {
  position: fixed; top: var(--topbar-h); bottom: 0; z-index: 9;
  left: var(--nav-w); width: var(--chat-w);
  min-width: 0; max-width: none;
  margin: 0; border: none; border-right: 1px solid var(--line);
  border-radius: 0; box-shadow: none;
  background: var(--nav); display: flex; flex-direction: column; overflow: hidden;
}
body.nav-min #chat-panel { left: var(--nav-w-min); }

/* El mapa empieza después de las columnas que haya abiertas. */
body.chat-abierto #map { left: calc(var(--nav-w) + var(--chat-w)); }
body.chat-abierto.nav-min #map { left: calc(var(--nav-w-min) + var(--chat-w)); }

/* Tirador: 6 px reales sobre el borde, ampliados a 14 con el pseudo-elemento.
   Un borde de 1 px es imposible de agarrar; 14 px de blanco de clic sin 14 px
   de línea visible es el compromiso habitual. */
.chat-tirador {
  /* -4px y no -3: `right` se mide desde la caja de RELLENO, y el panel lleva
     `border-right: 1px`, así que -3 dejaba la pastilla 4 px sobre el chat y
     solo 2 sobre el mapa. Con -4 monta 3 y 3, centrada en la junta. */
  position: absolute; top: 0; right: -4px; bottom: 0; width: 6px;
  cursor: col-resize; z-index: 2; background: none; border: none; padding: 0;
}
.chat-tirador::before {
  content: ''; position: absolute; inset: 0 -4px;
}
/* Guincha visible: una pastilla centrada en el borde. La línea que se
   encendía al pasar por encima obligaba a descubrir la zona antes de saber que
   se podía arrastrar; el asa se ve siempre y dice sola lo que hace. Va a media
   altura porque ahí cae la mano, no en el extremo. */
.chat-tirador::after {
  content: ''; position: absolute; top: 50%; left: 0;
  transform: translateY(-50%);
  width: 6px; height: 42px; border-radius: 999px;
  /* Siempre en el teal del producto. En reposo iba del color del panel y se
     confundía con el borde: había que pasar el cursor por encima para
     descubrir que existía, que es justo lo que un asa no puede pedir. */
  background: var(--teal); border: none;
  box-shadow: 0 1px 5px rgba(0, 0, 0, .18);
  transition: height .12s, box-shadow .12s;
}
.chat-tirador:hover::after, .chat-tirador:focus-visible::after,
body.redimensionando .chat-tirador::after {
  height: 60px; box-shadow: 0 0 0 3px rgba(30, 110, 104, .22), 0 1px 5px rgba(0, 0, 0, .18);
}
.chat-tirador:focus-visible { outline: none; }

/* Durante el arrastre: sin selección de texto y con el cursor fijo en toda la
   página, incluido el lienzo del mapa. */
body.redimensionando { cursor: col-resize; user-select: none; }
body.redimensionando * { cursor: col-resize !important; }

/* En COMPACTO el chat vuelve a ser hoja: no hay ancho que repartir. */
@media (max-width: 820px), (max-height: 520px) {
  body.chat-abierto #map, body.chat-abierto.nav-min #map { left: 0; }
  #chat-panel { position: absolute; }
  .chat-tirador { display: none; }
}

/* ==========================================================================
   Flotantes anclados al MAPA, no a la ventana
   --------------------------------------------------------------------------
   Todo lo que se superpone al mapa —leyenda, líneas de tiempo, panel ENOS,
   ficha de centro, selector de base— se posicionaba respecto al viewport, que
   era correcto cuando el mapa ocupaba la pantalla entera. Ya no: con el menú y
   el asistente como columnas, `left: 50%` centra sobre el chat y `top: 12px`
   mete los paneles debajo de la barra.

   Una sola variable define dónde empieza el mapa y todos la usan. Cambia sola
   al colapsar el menú o abrir el asistente, así que los flotantes acompañan sin
   que nadie los recalcule.
   ========================================================================== */
:root { --izq-mapa: var(--nav-w); }
body.nav-min { --izq-mapa: var(--nav-w-min); }
body.chat-abierto { --izq-mapa: calc(var(--nav-w) + var(--chat-w)); }
body.chat-abierto.nav-min { --izq-mapa: calc(var(--nav-w-min) + var(--chat-w)); }

#map, body.nav-min #map,
body.chat-abierto #map, body.chat-abierto.nav-min #map {
  left: var(--izq-mapa);
}

/* Zócalo inferior: en vez de centrarse con `left:50%` + translate —que toma la
   mitad de la VENTANA— ocupa el ancho del mapa y centra a sus hijos dentro. */
#bottom-dock {
  position: fixed; left: var(--izq-mapa); right: 0; transform: none;
  max-width: none; align-items: center;
}
#bottom-dock > * { max-width: min(760px, calc(100% - 32px)); }

#basemap-switch {
  position: fixed; left: var(--izq-mapa); right: 0; transform: none;
  margin: 0 auto; width: fit-content;
}

/* Paneles del borde derecho: el `right` ya era correcto, lo que fallaba era el
   `top` —quedaban bajo la barra— y el alto disponible. */
#enso-panel { position: fixed; top: calc(var(--topbar-h) + 12px);
  max-height: calc(100dvh - var(--topbar-h) - 24px); }
.center-panel { position: fixed; top: calc(var(--topbar-h) + 12px);
  max-height: calc(100dvh - var(--topbar-h) - 24px); }

/* ==========================================================================
   Pila de herramientas del mapa
   --------------------------------------------------------------------------
   Botones circulares sueltos en columna, no la cápsula segmentada de Mapbox.
   Sobre imagen satelital el círculo blanco se recorta contra cualquier fondo,
   mientras que una cápsula gris se pierde en el gris del agua.
   ========================================================================== */
.herr-mapa {
  background: none !important; border: none !important; box-shadow: none !important;
  border-radius: 0 !important; overflow: visible !important;
  display: flex; flex-direction: column; gap: 7px; margin: 10px 12px 0 0 !important;
}
/* La hoja de Mapbox se carga antes que esta, pero apunta más fino
   —`.mapboxgl-ctrl-group button` es 0-2-1 y `…:first-child` 0-3-1—, así que
   dejaba los botones transparentes, de 29 px y con las esquinas de su cápsula.
   Se igualan las tres formas del selector para ganarle por orden, sin
   !important. */
.herr-mapa button.herr-b,
.herr-mapa button.herr-b:first-child,
.herr-mapa button.herr-b:last-child {
  width: 34px; height: 34px; flex: 0 0 auto; display: grid; place-items: center;
  border: 1px solid var(--line); border-radius: 50%; cursor: pointer; padding: 0;
  background-color: var(--nav); color: var(--ink);
  box-shadow: 0 2px 8px rgba(0, 0, 0, .16);
  font-family: var(--font-ui); font-size: 11.5px; font-weight: 600;
  transition: background-color .12s, color .12s, border-color .12s;
}
/* Botones sueltos, no apilados: fuera la línea divisoria de la cápsula. */
.herr-mapa button.herr-b + button.herr-b { border-top: 1px solid var(--line); }
.herr-mapa button.herr-b:hover { background-color: var(--sunk); }
.herr-b:focus-visible { outline: 2px solid var(--teal); outline-offset: 2px; }
.herr-b svg { width: 17px; height: 17px; display: block; transition: transform .2s; }
/* Estado activo: 3D puesto, mapa girado, o el elector de base abierto. */
.herr-mapa button.herr-b.on { background-color: var(--teal); border-color: var(--teal); color: #fff; }
/* El de capas va siempre marcado: no es un modo que se enciende, es el que
   revela con qué fondo se está mirando. */
.herr-mapa button.herr-capas { border-color: var(--teal); color: var(--teal); }
.herr-mapa button.herr-capas:hover { background-color: var(--onbg); }

/* (El ScaleControl de Mapbox se retiró: su cifra vive ahora en la guincha de
   lectura, junto a la coordenada, y su barra no aportaba sobre el número.) */

/* Elector de mapa base, a la izquierda del botón. */
.herr-pop {
  position: fixed; z-index: 40; padding: 4px; min-width: 122px;
  background: var(--nav); border: 1px solid var(--line); border-radius: 9px;
  box-shadow: 0 10px 30px rgba(0, 0, 0, .18);
}
.herr-pop-f {
  display: block; width: 100%; text-align: left; padding: 6px 9px;
  border: none; background: none; border-radius: var(--sb-radio); cursor: pointer;
  font-family: var(--font-ui); font-size: 12.5px; color: var(--ink);
}
.herr-pop-f:hover { background: var(--sb-item); }
.herr-pop-f.on { color: var(--teal); font-weight: 500; background: var(--onbg); }

/* El geolocalizador de Mapbox comparte la forma de la pila. */
.mapboxgl-ctrl-group:has(.mapboxgl-ctrl-geolocate) {
  background: none !important; border: none !important; box-shadow: none !important;
  margin: 7px 12px 0 0 !important;
}
.mapboxgl-ctrl-geolocate {
  width: 34px !important; height: 34px !important; border-radius: 50% !important;
  background: var(--nav) !important; border: 1px solid var(--line) !important;
  box-shadow: 0 2px 8px rgba(0, 0, 0, .16);
}

/* ==========================================================================
   Dos superficies, no tres
   --------------------------------------------------------------------------
   Había tres tonos conviviendo en el tema claro: el menú en #F2EFE7, el
   asistente en #FBFAF5 y la leyenda en #FBFAF5 traslúcido con OTRO borde. El
   menú y el asistente son columnas contiguas de la misma pieza de cromo, así
   que el escalón entre ambos se veía como una junta; y la leyenda usaba
   --border mientras los botones del mapa que la acompañan usan --line.

   Queda así:
     · CROMO   (menú + asistente): opaco, pegado al borde, sin translucidez.
     · FLOTANTE (leyenda, líneas de tiempo, botones): la misma piel entre sí,
       traslúcida y con sombra, porque van ENCIMA del mapa y tienen que
       distinguirse de él sin taparlo del todo.
   ========================================================================== */
:root { --sb-bg: #F2EFE7; --flot-bg: rgba(251, 250, 245, .94); }
body.dark { --sb-bg: #0D1D22; --flot-bg: rgba(15, 33, 38, .92); }

/* El asistente NO comparte superficie con el menú: se queda a medio camino
   entre este y la superficie clara de los flotantes, tirando hacia el claro:
   #F2EFE7 · #F9F8F3 · #FBFAF5. Tres escalones cortos que separan las tres
   columnas sin dibujar una sola línea de más, y el ojo lee «menú, conversación,
   mapa» antes de leer nada.

   El punto medio exacto (#F6F4EE) quedaba corto: contra el crema del menú un
   salto de 4 unidades por canal no se distingue de un artefacto de
   compresión. Este está al ~78 % del recorrido y sigue por debajo del
   flotante, que es lo que mantiene el orden de las tres superficies.

   En oscuro el recorrido entre menú y flotante es de 2 unidades —ahí no cabe
   un tercer tono—, así que el chat se sale por arriba: #12262B aclara lo
   suficiente para leerse como panel propio sin acercarse al gris del cromo. */
:root { --chat-bg: #F9F8F3; }
body.dark { --chat-bg: #12262B; }
#chat-panel { background: var(--chat-bg); }

/* Flotantes del mapa: mismo fondo y mismo borde que los botones de la pila. */
#map-legend, #anim-timeline, #mosa-timeline, #mosa-legend {
  background: var(--flot-bg); border-color: var(--line);
}
.mapboxgl-ctrl-scale { background: var(--flot-bg) !important; }
.herr-mapa button.herr-b,
.herr-mapa button.herr-b:first-child,
.herr-mapa button.herr-b:last-child { background-color: var(--flot-bg); }
.herr-mapa button.herr-b:hover { background-color: var(--nav); }

/* ==========================================================================
   Avatar del asistente
   --------------------------------------------------------------------------
   Venía de la paleta anterior: cian #38BDF8 escrito a mano en tres sitios y un
   DOBLE resplandor —halo exterior de 3 px más un `inset 0 0 12px`—. Ese brillo
   era el efecto de un visor de ciencia ficción; en una interfaz de papel cálido
   y una sola familia tipográfica se lee como un adorno pegado.

   Se resuelve igualándolo al avatar del usuario que ya vive en el pie del menú:
   cuadrado macizo en el teal del producto, esquina redondeada, sin borde y sin
   sombra. Los dos interlocutores de la conversación pasan a compartir la misma
   forma, que es lo que un chat debería decir sin explicarlo.
   ========================================================================== */
/* Solo contorno: caja vacía con borde de 1 px y el glifo dentro, ambos en el
   gris de los iconos del menú. El cuadrado macizo de color competía con el
   mensaje que acompaña —en una conversación de veinte turnos son veinte
   manchas de teal bajando por la columna—, y el glifo suelto se quedaba sin
   ancla. El contorno da presencia sin peso, y es el mismo borde --line que
   usan los desplegables de la barra y los botones del mapa. */
.chat-av, .fab-ia {
  font-family: var(--font-ui); font-weight: 600; letter-spacing: 0;
  background: none; color: var(--nav-muted);
  border: 1px solid var(--line); box-shadow: none;
}
.chat-av { width: 30px; height: 30px; border-radius: 9px; font-size: 11px; }
.chat-row .chat-av { width: 25px; height: 25px; border-radius: 8px; font-size: 10px; }
.ic-ia { width: 62%; height: 62%; }

/* La bajada de la cabecera arrastraba la misma versalita de 9 px con tracking
   que ya se retiró del resto de los rótulos. */
.chat-sub { font-family: var(--font-ui); font-size: 11px; letter-spacing: 0;
  text-transform: none; }
/* El punto de estado se queda, pero sin el halo: marca «en línea», no alarma. */
.chat-dot { width: 6px; height: 6px; box-shadow: none; background: var(--good); }

/* ==========================================================================
   Asa de plegado del menú
   --------------------------------------------------------------------------
   Estaba arriba a la izquierda, en la barra: lejos del objeto sobre el que
   actúa y compitiendo con la marca por la primera posición de lectura. Ahora
   vive en la JUNTA entre el menú y lo que haya a su derecha, que es donde se
   ve el efecto, y comparte lenguaje con el asa del asistente —pieza teal sobre
   la junta, visible en reposo—.

   Se diferencia de aquella a propósito: la del chat es una pastilla lisa
   (arrastrar es continuo), esta es un círculo con chevron (plegar es binario y
   el chevron dice hacia dónde).
   ========================================================================== */
/* Plegar el menú es ahora una fila del pie, no una pastilla en el borde: se
   agrupa con las otras acciones del panel en vez de flotar sobre la junta, y
   deja de competir con el asa de ancho del asistente, que sí es un arrastre.
   El chevron gira 180° al plegar y dice hacia dónde se va el panel. */
#nav-collapse .ic { transition: transform .16s; }
#nav.collapsed #nav-collapse .ic { transform: scaleX(-1); }
/* Colapsado no cabe la palabra; el chevron solo sigue siendo el control. */
#nav.collapsed #nav-collapse { display: flex; }

/* --- Plegar el menú, sobre la línea del pie ------------------------------
   Fuera del grupo de accesos (asistente, tema, cuenta) y por encima de su
   filete: aquellos abren algo, este pliega el panel que los contiene. El fondo
   va SIEMPRE encendido, no solo al pasar el cursor — es el control que hace
   volver desde el estado colapsado y no puede depender de que alguien lo
   descubra pasando por encima. */
/* El 0 de abajo dejaba el botón pegado al filete del pie. */
.np-plegar { padding: 8px 8px 10px; }
.np-plegar > .np-pie-b {
  width: 100%; justify-content: flex-start;
  height: 32px; padding: 0 8px; gap: 8px; border-radius: var(--sb-radio);
  font-size: 13.5px; font-weight: 400; color: var(--ink);
  background: var(--sb-item);
}
.np-plegar > .np-pie-b:hover { background: var(--onbg); color: var(--teal); }
.np-plegar > .np-pie-b .ic { width: 18px; height: 18px; color: var(--nav-muted); }
.np-plegar > .np-pie-b:hover .ic { color: var(--teal); }
#nav.collapsed .np-plegar { padding: 8px 6px 10px; }
#nav.collapsed .np-plegar > .np-pie-b { justify-content: center; padding: 0; }
#nav.collapsed .np-plegar > .np-pie-b .ic { width: 22px; height: 22px; }

/* --- Guincha de lectura del mapa: coordenada y zoom ----------------------
   Misma piel que la barra de escala, con la que hace pareja: son los dos
   indicadores de «dónde estás y a qué escala». Salieron del pie del menú, que
   era el sitio equivocado —es estado del mapa, y con el menú colapsado
   desaparecían justo cuando más mapa hay en pantalla—. */
.lectura-mapa {
  display: flex; align-items: center; gap: 7px;
  background: var(--flot-bg); border: 1px solid var(--line);
  border-radius: 7px;
  color: var(--ink); font-family: var(--font-mono); font-size: 10px;
  padding: 3px 8px; margin: 10px 12px 0 0 !important;
  box-shadow: 0 2px 8px rgba(0, 0, 0, .14);
  white-space: nowrap;
}
.lm-sep { width: 1px; height: 10px; background: var(--line); flex: 0 0 auto; }

/* --- Avisos de bloqueo del mapa -----------------------------------------
   Explican por qué la vista está limitada (mundo fijo, zoom tope del modelo).
   Vivían en el pie del menú y se iban con él; van al zócalo, que es donde ya
   vive el mensaje de nivel mapa. */
#map-avisos { display: flex; flex-wrap: wrap; gap: 6px; justify-content: center; }
#map-avisos:not(:has(> :not(.hidden))) { display: none; }
#map-avisos > span {
  font-family: var(--font-ui); font-size: 10.5px; color: var(--ink);
  background: var(--flot-bg); border: 1px solid var(--line);
  border-radius: 999px; padding: 3px 10px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, .12);
}
#map-avisos > span.hidden { display: none; }

/* ==========================================================================
   Menú de cuenta — el desplegable convencional de usuario
   ========================================================================== */
.um-id { display: flex; align-items: center; gap: 9px; padding: 8px 9px 9px; }
.um-av {
  width: 30px; height: 30px; flex: 0 0 auto; border-radius: 8px;
  display: grid; place-items: center; background: var(--teal); color: #fff;
  font-family: var(--font-ui); font-size: 11px; font-weight: 600;
  text-transform: uppercase; letter-spacing: .02em;
}
.um-tx { display: flex; flex-direction: column; min-width: 0; line-height: 1.25; }
.um-tx b { font-size: 12.5px; font-weight: 500; color: var(--ink);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.um-tx em { font-style: normal; font-size: 10.5px; color: var(--nav-muted);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.um-sep { height: 1px; background: var(--line); margin: 3px 0; }
#user-menu .um-row {
  display: flex; align-items: center; gap: 9px; width: 100%;
  height: 32px; padding: 0 9px; border: none; background: none;
  border-radius: var(--sb-radio); cursor: pointer; text-align: left;
  font-family: var(--font-ui); font-size: 13px; color: var(--ink);
}
#user-menu .um-row:hover { background: var(--sb-item); }
#user-menu .um-row svg { width: 16px; height: 16px; flex: 0 0 auto; color: var(--nav-muted); }
/* Cerrar sesión es destructiva: se marca en el color de alerta, no en teal. */
#user-menu .um-salir, #user-menu .um-salir svg { color: var(--crit); }
#user-menu .um-salir:hover { background: rgba(166, 58, 44, .09); }
/* Maquetado, sin conectar todavía: se ve pero no promete. Sin esto, cuatro
   filas que no hacen nada se leen como cuatro funciones rotas. */
#user-menu .um-row[data-pendiente] { opacity: .5; cursor: default; }
#user-menu .um-row[data-pendiente]:hover { background: none; }
#user-menu .um-row[data-pendiente]::after {
  content: 'pronto'; margin-left: auto;
  font-size: 9.5px; letter-spacing: .04em; color: var(--nav-muted);
}

/* --- Lucecita de «en línea» del asistente -------------------------------
   El color lo pone el estado real de /api/ia/status, no una decoración fija:
   verde con el modelo disponible, ámbar sin él. Una luz siempre verde sobre un
   asistente caído es peor que no tener luz. */
.pie-luz {
  width: 6px; height: 6px; border-radius: 50%; flex: 0 0 auto; margin-left: auto;
  background: var(--faint); transition: background-color .2s;
}
#pie-ia.en-linea .pie-luz { background: var(--good); }
#pie-ia.sin-linea .pie-luz { background: var(--warn); }
#nav.collapsed .pie-luz { position: absolute; top: 6px; right: 8px; margin: 0; }
#nav.collapsed .np-pie > .np-pie-b { position: relative; }

/* --- Producto con capas encendidas --------------------------------------
   Mismo fondo que el botón de colapsar: es el mismo grado de «esto está
   activo» y no había razón para que se dijeran distinto. Antes solo cambiaba
   el color del rótulo, que a 13 px es una señal muy débil para responder
   «¿qué tengo encendido?» de un vistazo. */
#controls .lg-group:has(input:checked) > .np-sec-head { background: var(--sb-item); }
#controls .lg-group:has(input:checked) > .np-sec-head h2 { font-weight: 500; }

/* --- Ajustes, ahora en el pie -------------------------------------------
   Se mudó desde la lista de productos: es configuración del visor —mapa base,
   tema, calibración, boletines—, no una capa que se enciende. Conserva su
   acordeón, así que hay que repetir para `.np-pie` las reglas que estaban
   calificadas con `#controls >` y que ahí ya no casan. */
.np-pie > .lg-group { position: relative; margin: 1px 0 0; }
.np-pie > .lg-group:not(.on) > *:not(.np-sec-head) { display: none; }
.np-pie > .lg-group > .np-sec-head {
  height: 32px; padding: 0 8px; gap: 8px; border-radius: var(--sb-radio); margin: 0;
}
.np-pie > .lg-group > .np-sec-head:hover { background: var(--sb-item); }
.np-pie > .lg-group > .np-sec-head h2 {
  font-size: 13.5px; font-weight: 400; letter-spacing: 0; text-transform: none;
  color: var(--ink); flex: 1 1 auto; min-width: 0;
}
.np-pie > .lg-group > .np-sec-head::before { order: 9; margin-left: 4px; opacity: .6; }
.np-pie > .lg-group.on > .np-sec-head { background: var(--sb-item); }
/* Desplegado crece hacia arriba dentro del pie, con la guía de los hijos y un
   alto máximo: la calibración y los boletines son largos y no pueden empujar
   la tarjeta de usuario fuera de la pantalla. */
.np-pie > .lg-group.on > *:not(.np-sec-head) { margin-left: 24px; }
.np-pie > .lg-group.on::before {
  content: ''; position: absolute; left: 15px; top: 34px; bottom: 2px;
  width: 1px; background: var(--line); pointer-events: none;
}
.np-pie > .lg-group.on { max-height: 46dvh; overflow-y: auto; margin-bottom: 6px; }
#nav.collapsed .np-pie > .lg-group > *:not(.np-sec-head) { display: none; }
#nav.collapsed .np-pie > .lg-group > .np-sec-head { justify-content: center; padding: 0; height: 40px; }
#nav.collapsed .np-pie > .lg-group > .np-sec-head h2,
#nav.collapsed .np-pie > .lg-group > .np-sec-head::before { display: none; }
#nav.collapsed .np-pie > .lg-group .np-sec-ic { width: 22px; height: 22px; }


/* Centinela DOCS en el menú y el riel, como los otros cuatro productos. */
/* Calificado con #controls: `#controls .np-sec-head h2` (1-1-1) le gana a una
   regla de atributo suelta, y el rótulo salía en tinta en vez de su color. */
#controls .lg-group[data-prod="docs"] .np-sec-head h2 { color: var(--docs); }
.lg-group[data-prod="docs"].on > .np-sec-head .np-sec-ic { color: var(--docs); }
.rail-btn[data-prod="docs"].on { color: var(--docs); }
body:not(.dark) #nav:not(.collapsed) .np-body > .lg-group[data-prod="docs"] { border-top-color: var(--docs); }

/* ==========================================================================
   Centinela DOCS — árbol documental
   Mismo lenguaje que el árbol de capas: guía vertical, chevron a la izquierda
   y filas de 26-28 px. Un gestor documental que se ve distinto del resto del
   menú se lee como otra aplicación metida dentro.
   ========================================================================== */
.docs-arbol { display: flex; flex-direction: column; gap: 1px; }
.dt-rama { position: relative; }
.dt-cab {
  display: flex; align-items: center; gap: 7px; width: 100%;
  height: 28px; padding: 0 8px 0 4px; border: none; background: none;
  border-radius: var(--sb-radio); cursor: pointer; text-align: left;
  font-family: var(--font-ui); font-size: 12.5px; color: var(--ink);
}
.dt-cab:hover { background: var(--sb-item); }
/* Chevron por CSS, igual que el de los productos: gira 90° al abrirse. */
.dt-chev {
  width: 5px; height: 5px; flex: 0 0 auto; margin: 0 3px;
  border-right: 1.5px solid var(--nav-muted); border-bottom: 1.5px solid var(--nav-muted);
  transform: rotate(-45deg); transition: transform .16s;
}
.dt-rama.on > .dt-cab .dt-chev { transform: rotate(45deg); }
.dt-carp { width: 15px; height: 15px; flex: 0 0 auto; color: var(--nav-muted); }
.dt-rama.on > .dt-cab .dt-carp { color: var(--docs); }
.dt-nom { flex: 1 1 auto; min-width: 0; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap; }
.dt-meta { font-style: normal; font-family: var(--font-mono); font-size: 9.5px;
  color: var(--nav-muted); flex: 0 0 auto; }
.dt-hijos { display: none; }
.dt-rama.on > .dt-hijos { display: block; margin-left: 14px; }
/* Guía vertical del nivel, como en el árbol de capas. */
.dt-rama.on > .dt-hijos { border-left: 1px solid var(--line); padding-left: 6px; }
.dt-fuente > .dt-cab { font-size: 12px; color: var(--nav-muted); }
.dt-fuente.on > .dt-cab { color: var(--ink); }
/* El centro es el tercer nivel: mismo peso que la fuente pero un punto más
   chico, para que la sangría no sea lo único que distinga los niveles. */
.dt-centro > .dt-cab { font-size: 11.5px; height: 26px; }
.dt-centro > .dt-cab .dt-carp { width: 13px; height: 13px; }

.dt-hoja {
  display: flex; align-items: center; gap: 7px;
  padding: 4px 8px 4px 4px; border-radius: var(--sb-radio);
  font-size: 11.5px; color: var(--fg2, var(--ink)); text-decoration: none;
}
.dt-hoja:hover { background: var(--sb-item); color: var(--teal); }
.dt-ic { width: 13px; height: 13px; flex: 0 0 auto; color: var(--faint); }
.dt-hoja:hover .dt-ic { color: var(--teal); }
.dt-corte { margin: 4px 0 2px 4px; font-size: 10px; color: var(--nav-muted); }
.dt-vacio { font-size: 11.5px; color: var(--nav-muted); margin: 6px 4px; }

/* --- Ajustes de Sistema: filas maquetadas, no conectadas ---------------- */
.sis-row {
  display: flex; align-items: center; gap: 8px; width: 100%;
  height: 30px; padding: 0 8px; border: none; background: none;
  border-radius: var(--sb-radio); text-align: left;
  font-family: var(--font-ui); font-size: 12.5px; color: var(--ink);
  opacity: .5; cursor: default;
}
.sis-row svg { width: 15px; height: 15px; flex: 0 0 auto; color: var(--nav-muted); }
.sis-row[data-pendiente]::after {
  content: 'pronto'; margin-left: auto;
  font-size: 9.5px; letter-spacing: .04em; color: var(--nav-muted);
}


/* --- Productos previstos: maquetados, sin datos --------------------------
   Se listan porque el menú es también el mapa del producto: ver los nueve
   Centinelas dice hacia dónde va la suite. Pero se marcan, porque una sección
   que se abre y no muestra nada se lee como una función rota, no como una
   promesa. */

/* El encabezado va atenuado incluso cerrado: la señal de «todavía no» tiene
   que verse ANTES de abrirlo, no después. */
#controls .lg-proximo > .np-sec-head { opacity: .62; }
#controls .lg-proximo > .np-sec-head:hover { opacity: .85; }
.prox-nota {
  margin: 2px 0 4px 24px; font-size: 10.5px; line-height: 1.4;
  color: var(--nav-muted);
}
.prox-row {
  display: flex; align-items: center; gap: 8px;
  padding: 4px 8px; margin-left: 24px; border-radius: var(--sb-radio);
  font-size: 12px; color: var(--ink); opacity: .5;
}
.prox-row svg { width: 15px; height: 15px; flex: 0 0 auto; color: var(--nav-muted); }
.prox-row[data-pendiente]::after {
  content: 'pronto'; margin-left: auto;
  font-size: 9.5px; letter-spacing: .04em; color: var(--nav-muted);
}

#controls .lg-group[data-prod="bio"] .np-sec-head h2 { color: var(--bio); }
#controls .lg-group[data-prod="bio"] .np-sec-head .np-sec-ic { color: var(--bio); }
.rail-btn[data-prod="bio"] .ic { color: var(--bio); }

/* --- Biodiversidad en la card del centro ---------------------------------
   Mismo lenguaje que el bloque de condiciones autorizadas (.cc-reg): dos filas
   etiqueta/valor sobre el fondo hundido. Va al final porque es contexto
   ambiental del sitio, no el estado FAN que trae al usuario a la card. */
.cc-bio {
  margin-top: 10px; padding: 9px 11px; border-radius: 10px;
  background: var(--status-bg); border: 1px solid var(--inner-border);
}
.cc-bio-hd {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 8px; margin-bottom: 6px;
}
.cc-bio-hd span { font-size: 11px; font-weight: 500; color: var(--ink); }
.cc-bio-hd em { font-style: normal; font-family: var(--font-mono);
  font-size: 9.5px; color: var(--nav-muted); }
.cc-bio-f {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 10px; padding: 2px 0; font-size: 11px;
}
.cc-bio-f > span { color: var(--nav-muted); flex: 0 0 auto; }
.cc-bio-f > b { font-family: var(--font-mono); font-size: 10.5px;
  font-weight: 500; color: var(--ink); font-variant-numeric: tabular-nums;
  text-align: right; }
/* Los taxones dominantes en cursiva: son nombres científicos y el género va en
   binomio, no es texto corriente. */
.cc-bio-top { margin: 1px 0 4px; font-size: 10px; font-style: italic;
  color: var(--faint); line-height: 1.35; }

/* ==========================================================================
   CAPA MÓVIL · RECONCILIACIÓN
   --------------------------------------------------------------------------
   La capa móvil original sigue siendo correcta, pero quedó por delante de todo
   lo que se añadió después —barra superior, menú anclado, asistente como
   columna, `--izq-mapa`—, y esas reglas la pisaban por orden. El resultado en
   un teléfono era un menú convertido en franja lateral de 75 px y el mapa
   empezando a su derecha.

   Aquí se re-afirma el layout de teléfono contra lo nuevo. Va al final por la
   misma razón que la capa original: en este archivo el orden es la única
   herramienta fiable cuando compiten `body:has(...)` y medias antiguas.

   El principio de diseño no cambia: en compacto NO hay columnas. Hay un mapa a
   pantalla completa y superficies que suben desde abajo — que es exactamente
   lo que hace un sheet de shadcn.
   ========================================================================== */
@media (max-width: 820px), (max-height: 520px) {

  /* --- Sin columnas: el mapa ocupa todo bajo la barra ------------------- */
  :root, body, body.nav-min, body.chat-abierto, body.chat-abierto.nav-min {
    --izq-mapa: 0px;
  }
  #map, body.nav-min #map,
  body.chat-abierto #map, body.chat-abierto.nav-min #map {
    position: fixed; top: var(--topbar-h); left: 0; right: 0; bottom: 0;
  }

  /* --- El menú vuelve a ser hoja inferior ------------------------------- */
  /* `top: auto` es lo que la regla de escritorio le robaba: sin esto el panel
     se anclaba bajo la barra y se estiraba hasta abajo como columna. */
  #nav {
    position: fixed; top: auto; left: 0; right: 0; bottom: 0;
    display: block; border-radius: 0; z-index: 12;
  }
  /* Los dos estados se declaran con la MISMA especificidad que las reglas de
     escritorio (`#nav.collapsed #nav-panel`), o el panel se queda en los 72 px
     del riel y la barra de productos aparece como una pastilla en la esquina. */
  #nav-panel,
  #nav.collapsed #nav-panel,
  #nav:not(.collapsed) #nav-panel {
    width: 100%; flex-basis: auto; border-right: none;
  }
  /* Colapsado en teléfono NO es un riel vertical: es la barra de productos,
     una fila de iconos a lo ancho. */
  #nav.collapsed #nav-panel {
    flex-direction: row; align-items: stretch;
    height: var(--barra-total); border-radius: 0;
  }
  #nav:not(.collapsed) #nav-panel {
    max-height: var(--hoja); border-radius: 18px 18px 0 0;
  }
  /* El asa de ancho y la fila «Colapsar menú» son gestos de escritorio: aquí
     la hoja se cierra tocando el velo o arrastrándola. */
  .np-plegar, .chat-tirador { display: none; }

  /* Tirador de la hoja. La cabecera del panel quedó vacía al mudar la marca a
     la barra superior; aquí recupera un oficio: ser el asa que dice que esto
     es un sheet y se puede arrastrar. Es el mismo trazo que el de la ficha de
     centro (.cc-grab), para que las dos hojas se lean como la misma pieza. */
  #nav:not(.collapsed) .np-grab {
    display: flex; justify-content: center; align-items: center;
    height: 20px; padding: 8px 0 4px; flex: 0 0 auto; cursor: grab;
  }
  #nav:not(.collapsed) .np-grab::before {
    content: ''; width: 38px; height: 4px; border-radius: 99px;
    background: var(--line);
  }
  #nav:not(.collapsed) .np-grab:active { cursor: grabbing; }

  /* --- Asistente: hoja a pantalla completa ------------------------------ */
  #chat-panel,
  body:has(#nav.collapsed) #chat-panel,
  body:has(#nav:not(.collapsed)) #chat-panel {
    position: fixed; inset: 0; left: 0; top: 0; right: 0; bottom: 0;
    width: 100%; max-width: none; border: none; border-radius: 0; z-index: 14;
  }

  /* --- Barra superior: la marca cede sitio a los filtros ---------------- */
  /* A 390 px la marca y su bajada se comen 150 px y los filtros se salen. El
     logotipo solo basta: la identidad ya está en la pestaña del navegador. */
  #topbar { padding: 0 10px; gap: 10px; }
  .tb-tx { display: none; }
  #tb-filtros { gap: 8px; margin-left: 0; }
  .tb-disp { max-width: 132px; height: 30px; }
  .tb-capa { display: none; }     /* el grupo se infiere del filtro visible */

  /* --- Flotantes del mapa ----------------------------------------------- */
  #bottom-dock, #basemap-switch { left: 0; right: 0; }

  /* La pila de herramientas baja POR DEBAJO de las hojas. La capa móvil la
     había puesto en 11 «para que los controles sigan alcanzables», y era
     cierto cuando la ficha ocupaba solo la mitad inferior. Ahora la hoja llega
     hasta 128 px del borde superior y los botones se le montaban encima: le
     cortaban la píldora de estado y quedaban sobre un contenido que, con un
     sheet abierto, ya no es el que se está operando. Se cierra la hoja y
     vuelven a estar delante. */
  .mapboxgl-ctrl-top-right { z-index: 9; }
  /* La pila de herramientas encoge: seis botones de 34 px ocupan un tercio de
     la altura útil de un teléfono. */
  .herr-mapa { gap: 5px; margin: 8px 8px 0 0 !important; }
  .herr-mapa button.herr-b,
  .herr-mapa button.herr-b:first-child,
  .herr-mapa button.herr-b:last-child { width: 30px; height: 30px; }
  .herr-mapa button.herr-b svg { width: 15px; height: 15px; }
  .lectura-mapa { font-size: 9px; padding: 2px 6px; margin: 8px 8px 0 0 !important; }

  /* --- Árbol documental: la sangría de cuatro niveles no cabe ------------ */
  .dt-rama.on > .dt-hijos { margin-left: 9px; padding-left: 5px; }
  .dt-hoja { padding: 6px 6px 6px 4px; }   /* 32 px de alto táctil */
}

/* ===================== TÁCTIL: ergonomía ===================== */
/* Independiente del ancho: un iPad de 1024 px necesita esto y no lo otro. */
@media (pointer: coarse) {
  /* Las filas nuevas también necesitan blanco de toque de 44 px. */
  .dt-cab, .dt-hoja, .prox-row, .sis-row, .tb-pop-f, .herr-pop-f {
    min-height: 40px;
  }
  .tb-disp { min-height: 40px; }
  /* El popover de filtro se ancla al borde inferior: desplegado hacia abajo
     desde la barra, en un teléfono queda bajo el pulgar y tapa el mapa. */
  .tb-pop { max-height: 50dvh; }
}

/* --- Pantalla BAJA (teléfono en horizontal) ------------------------------
   Con 390 px de alto —y menos aún descontando el cromo del navegador— una
   barra de 56 px se lleva más de una cuarta parte de lo poco que hay. Se
   recorta a 44 y con ella todo lo que se mide desde arriba, porque `--topbar-h`
   es lo que posiciona el mapa, el menú y los flotantes. */
@media (max-height: 520px) {
  :root { --topbar-h: 44px; --hoja: 80dvh; }
  #topbar { gap: 8px; }
  .tb-logo { width: 24px; height: 24px; }
  .tb-disp { height: 26px; padding: 3px 7px; }
  /* La barra de productos también: en horizontal el pulgar llega de sobra y
     58 px de iconos sobre 213 de alto es desproporcionado. */
  :root { --barra: 48px; }
  .herr-mapa { gap: 4px; }
  .herr-mapa button.herr-b,
  .herr-mapa button.herr-b:first-child,
  .herr-mapa button.herr-b:last-child { width: 27px; height: 27px; }
  .herr-mapa button.herr-b svg { width: 14px; height: 14px; }
}

/* ==========================================================================
   FICHA DE CENTRO EN MÓVIL — implementación propia, no un panel encogido
   --------------------------------------------------------------------------
   Medido en un iPhone: 777 px de contenido en 478 visibles, con la NOTA —que
   es la interpretación, o sea la respuesta— empezando en el píxel 523. El
   usuario abría la ficha y veía identidad, barra y ocho campos de los que seis
   decían «—». Para leer qué significa el nivel había que desplazarse.

   Tres cambios, en orden de impacto:

     1. La nota SUBE. En escritorio el panel es alto y la rejilla se lee de un
        vistazo antes que la nota; en un teléfono la rejilla es una pantalla
        entera de por medio. La nota es la conclusión: va pegada a la barra.
     2. Los campos vacíos se agrupan (lo hace el JS): seis filas de «—» pasan a
        una línea, y se recuperan ~150 px.
     3. La hoja abre a media altura y sube al arrastrarla, que es el patrón de
        Drawer con puntos de anclaje.
   ========================================================================== */
@media (max-width: 820px), (max-height: 520px) {
  .cc { display: flex; flex-direction: column; }
  .cc-grab   { order: 0; }
  .cc-hd     { order: 1; }
  .cc-bar    { order: 2; }
  .cc-esc    { order: 3; }
  .cc-fuente { order: 4; }
  .cc-nota   { order: 5; margin-top: 12px; }
  .cc-grid   { order: 6; }
  .cc-7d     { order: 7; }
  .cc-reg    { order: 8; }
  .cc-bio    { order: 9; }

  /* Resumen de los campos sin dato. Sustituye a N filas de guiones por una
     línea que dice cuáles faltan — la ausencia sigue informando, pero deja de
     costar una pantalla. */
  .cc-vacios {
    order: 6; margin-top: 12px; padding-top: 12px;
    border-top: 1px solid var(--inner-border);
    font-size: 11.5px; line-height: 1.5; color: var(--nav-muted);
  }
  .cc-vacios b { font-weight: 500; color: var(--fg2, var(--ink)); }

  /* --- Dos alturas ------------------------------------------------------
     Abre a media altura: identidad, barra y nota caben sin desplazar, que es
     la lectura de un vistazo. Se sube arrastrando el tirador para el detalle. */
  .cc-pop .mapboxgl-popup-content { transition: max-height .22s; }
  /* (El degradado de «hay más» se retiró: en plegado la hoja ya no recorta
     contenido, lo oculta por completo, y el aviso lo da el propio tirador.) */
}

/* ==========================================================================
   BARRA DE PESTAÑAS — solo móvil
   --------------------------------------------------------------------------
   En un teléfono los trece módulos no son navegación: son el CONTENIDO de una
   pestaña. Una barra con trece iconos que se desplaza no es una barra, es una
   lista tumbada — y ninguno queda a tiro del pulgar salvo los tres primeros.

   Cuatro destinos y una acción. El asistente va elevado al centro porque no es
   un lugar al que se va sino algo que se hace, y porque el centro-abajo es el
   punto más cómodo de la pantalla.
   ========================================================================== */
#tabbar { display: none; }

@media (max-width: 820px), (max-height: 520px) {
  /* La tira de módulos deja de ser la barra: ahora es el contenido de «Capas». */
  #nav.collapsed { display: none; }

  #tabbar {
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 13;
    display: grid; grid-template-columns: repeat(5, 1fr);
    grid-template-rows: 1fr;
    align-items: end; justify-items: center;
    height: var(--barra-total); padding-bottom: var(--seguro-abajo);
    background: var(--nav); border-top: 1px solid var(--line);
    /* El botón central sobresale por arriba: sin esto el recorte lo decapita. */
    overflow: visible;
  }
  /* Colocación EXPLÍCITA de las cinco ranuras. Con auto-flow, el rótulo del
     botón central —que comparte celda con él— desplazaba a ENOS y a «Más» a
     una segunda fila invisible. */
  #tabbar > * { grid-row: 1; }
  /* La ranura central agrupa el botón y su rótulo: como dos hijos sueltos, el
     rótulo caía fuera de la barra y quedaba cortado por el borde inferior. */
  .tb-centro {
    display: flex; flex-direction: column; align-items: center; gap: 2px;
    height: var(--barra); justify-content: flex-end; padding-bottom: 5px;
  }
  .tb-item {
    display: flex; flex-direction: column; align-items: center; gap: 3px;
    width: 100%; height: var(--barra); padding: 8px 0 0;
    border: none; background: none; cursor: pointer; position: relative;
    color: var(--nav-muted); font-family: var(--font-ui); font-size: 10px;
  }
  .tb-item svg { width: 20px; height: 20px; }
  .tb-item.on { color: var(--teal); }
  /* Punto de estado: capas encendidas o filtros puestos. Es la única forma de
     saber, con la hoja cerrada, que hay algo activo debajo. */
  .tb-badge {
    position: absolute; top: 6px; left: 50%; margin-left: 6px;
    width: 6px; height: 6px; border-radius: 50%; background: var(--teal);
  }

  /* El asistente: círculo elevado que rompe la línea de la barra. */
  .tb-fab {
    /* El margen negativo es lo que lo eleva sobre la línea de la barra: sin
       él es un icono más y deja de leerse como la acción principal. */
    width: 50px; height: 50px; margin-top: -24px; flex: 0 0 auto;
    display: grid; place-items: center; position: relative;
    border: 3px solid var(--nav); border-radius: 50%;
    background: var(--teal); color: #fff; cursor: pointer; padding: 0;
    box-shadow: 0 4px 14px rgba(30, 110, 104, .35);
  }
  .tb-fab svg { width: 24px; height: 24px; }
  .tb-fab:active { transform: scale(.94); }
  /* La lucecita de en línea, la misma que la fila del menú. */
  .tb-fab-luz {
    position: absolute; top: 3px; right: 3px;
    width: 9px; height: 9px; border-radius: 50%;
    border: 2px solid var(--nav); background: var(--faint);
  }
  #tabbar.ia-en-linea .tb-fab-luz { background: var(--good); }
  #tabbar.ia-sin-linea .tb-fab-luz { background: var(--warn); }
  .tb-fab-tx {
    font-family: var(--font-ui); font-size: 10px; color: var(--nav-muted);
    pointer-events: none; line-height: 1;
  }

  /* Las hojas se levantan por encima de la barra, no debajo. */
  #nav:not(.collapsed) #nav-panel { padding-bottom: calc(var(--barra-total) + 8px); }
  .cc-pop .mapboxgl-popup-content { padding-bottom: var(--barra-total); }
  #bottom-dock { bottom: calc(var(--barra-total) + 30px); }
}

/* --- Ficha de centro: más compacta en móvil ------------------------------
   La escala de escritorio venía de un panel de 470 px que se leía a un brazo
   de distancia. En un teléfono, a 30 cm, el mismo cuerpo de letra sobra: se
   reduce un escalón y la hoja pasa de 666 a ~520 px, con lo que la respuesta
   completa cabe sin desplazar. */
@media (max-width: 820px), (max-height: 520px) {
  .cc { padding: 0 14px 14px; }
  .cc-id h2 { font-size: 19px; letter-spacing: -.02em; }
  .cc-rot, .cc-meta, .cc-coord { font-size: 10.5px; }
  .cc-pill { font-size: 10px; padding: 3px 9px; }
  .cc-grid { gap: 9px 14px; padding-top: 10px; margin-top: 10px; }
  .cc-row > span { font-size: 9.5px; }
  .cc-row > b { font-size: 12px; }
  .cc-row > b[data-num] { font-size: 11.5px; }
  .cc-esc, .cc-fuente { font-size: 10px; }
  .cc-nota p { font-size: 11.5px; line-height: 1.45; }
  .cc-nota { padding: 9px 11px; }
  .cc-7d { margin-top: 10px; }
  .cc-reg { font-size: 10.5px; }
  .cc-bio { margin-top: 8px; padding: 8px 10px; }
  /* --- Estado PLEGADO: solo la respuesta -------------------------------
     La hoja debe contestar «¿cómo está este centro?» y nada más. Todo lo
     demás —titular, coordenada, etiquetas de la escala, procedencia del
     nivel, campos, tira, concesión, biodiversidad— es evidencia, y la
     evidencia se pide, no se impone. Sube al arrastrar.

     Queda: nombre + píldora, SIEP·Barrio, barra de riesgo y nota. Cuatro
     líneas y un gráfico, en un tercio de pantalla. */
  .cc:not(.cc-alto) .cc-rot,
  .cc:not(.cc-alto) .cc-coord,
  .cc:not(.cc-alto) .cc-esc,
  .cc:not(.cc-alto) .cc-fuente,
  .cc:not(.cc-alto) .cc-grid,
  .cc:not(.cc-alto) .cc-vacios,
  .cc:not(.cc-alto) .cc-7d,
  .cc:not(.cc-alto) .cc-reg,
  .cc:not(.cc-alto) .cc-bio { display: none; }

  .cc:not(.cc-alto) { padding-bottom: 6px; }
  /* El relleno que reserva sitio para la barra de pestañas solo hace falta
     cuando la hoja se desplaza por debajo de ella. Plegada no lo hace, y ahí
     son 58 px de vacío al pie. */
  .mapboxgl-popup-content:not(:has(.cc-alto)) { padding-bottom: 8px; }
  .cc:not(.cc-alto) .cc-nota { margin-top: 10px; margin-bottom: 2px; }
  /* Sin scroll interno no hace falta altura fija: la hoja mide lo que mide su
     contenido, que es el comportamiento correcto de un peek. */
  .mapboxgl-popup-content:not(:has(.cc-alto)) { max-height: none; }
  .mapboxgl-popup-content:has(.cc-alto) { max-height: 88dvh; }

  /* Pista de que hay más: la propia hoja invita a subir. */
  .cc:not(.cc-alto) .cc-grab::after {
    content: 'Deslizar para ver el detalle';
    position: absolute; left: 0; right: 0; top: 22px;
    text-align: center; font-family: var(--font-ui); font-size: 9.5px;
    color: var(--nav-muted); pointer-events: none;
  }
  .cc:not(.cc-alto) .cc-grab { position: relative; padding-bottom: 14px; }
}

/* ==========================================================================
   Transición de las columnas
   El mapa, el menú y el chat empujan al mapa cambiando `left`/`width`. Sin
   transición eso es un salto de 400 px en un solo cuadro, y como Mapbox
   reasigna el lienzo justo después, se ve como un fogonazo.
   Animando la propiedad, el lienzo se redimensiona en pasos pequeños —el JS
   llama a resize() en cada cuadro mientras dura— y el corte desaparece.
   La curva y los 240 ms son los del resto de la interfaz.
   ========================================================================== */
@media (prefers-reduced-motion: no-preference) {
  #map,
  #bottom-dock { transition: left .24s cubic-bezier(.4, 0, .2, 1); }
  #nav-panel { transition: width .24s cubic-bezier(.4, 0, .2, 1),
                           flex-basis .24s cubic-bezier(.4, 0, .2, 1); }
  #chat-panel { transition: left .24s cubic-bezier(.4, 0, .2, 1); }

  /* El chat pasa de `display:none` a visible, y eso no se puede transicionar.
     Una animación sí corre al aparecer el elemento, así que entra deslizándose
     desde el borde del menú en vez de materializarse de golpe. */
  #chat-panel:not(.hidden) { animation: chat-entra .24s cubic-bezier(.4, 0, .2, 1); }
  @keyframes chat-entra {
    from { opacity: 0; transform: translateX(-16px); }
    to   { opacity: 1; transform: none; }
  }
}

/* ==========================================================================
   El MENÚ, sin color por producto
   Cada producto operativo llevaba el suyo —FAN teal, METEO arena, O₂ azul,
   ENOS violeta, BIO musgo, DOCS grafito— mientras los siete previstos iban en
   tinta. Con seis colores a la vez, la lista parecía un muestrario y el color,
   que debería significar «esto está encendido», no significaba nada: estaba
   puesto siempre.

   Ahora el nombre y el icono van en `--ink`, el mismo tono que «Asistente IA»,
   «Modo oscuro» y «Ajustes de Sistema» del pie. El color queda libre para lo
   único que necesita distinguirse de un vistazo: qué capa está activa.

   Se sobrescribe en vez de editar las reglas originales porque están repartidas
   en cuatro puntos del archivo —el bloque general, el de DOCS y el de BIO— y
   tocarlas todas haría difícil volver atrás. Las variables `--fan`, `--o2` y
   compañía siguen intactas: las usan el panel de ENOS, la ficha de centro y el
   `--ac` que colorea el estado activo.
   ========================================================================== */
#controls .lg-group[data-prod] .np-sec-head h2,
#controls .lg-group[data-prod] .np-sec-head .np-sec-ic,
.lg-group[data-prod].on > .np-sec-head .np-sec-ic {
  color: var(--ink);
}
.rail-btn[data-prod] .ic { color: var(--nav-muted); }
/* En el riel colapsado sí hay una excepción: el botón ACTIVO. Es la única
   pista de qué producto está encendido cuando no se ven los nombres. */
.rail-btn[data-prod].on .ic,
.rail-btn[data-prod].on { color: var(--accent); }
