/* ═══════════════════════════════════════════════════════════════════════
   Star Acuario · Design V1 · estilos del mockup
   Tokens y componentes extraídos. Tailwind se carga vía CDN en el HTML;
   este archivo solo aporta lo que Tailwind no cubre (animations, custom
   shapes orgánicos, gradients firma, SweetAlert theme).
   ═══════════════════════════════════════════════════════════════════════ */

/* ── Tipografía base + fondo body (gradient vertical blanco → celeste) ── */
body {
  font-family:'Outfit',system-ui,sans-serif;
  font-feature-settings:"ss01","cv11";
  background-image:
    /* tinte verde primary-400 en la transición celeste→blanco superior izq (alpha reducido) */
    radial-gradient(ellipse 55vw 35vh at 25% 22%, rgba(168, 213, 197, 0.20) 0%, transparent 80%),
    /* tinte amarillo secondary-200 en la transición blanco→celeste inferior dcha (alpha reducido) */
    radial-gradient(ellipse 55vw 35vh at 75% 78%, rgba(250, 235, 200, 0.25) 0%, transparent 80%),
    /* radial central celeste (más suave) */
    radial-gradient(circle 25vw at 50% 50%, rgba(201, 222, 232, 0.15) 0%, transparent 100%),
    /* base linear celeste suave → blanco → celeste suave (tono más claro) */
    linear-gradient(180deg, #E1EBF1 0%, #FFFFFF 30%, #FFFFFF 90%, #E1EBF1 100%);
  background-attachment: fixed, fixed, fixed, fixed;
  background-size: 100% 100vh, 100% 100vh, 100% 100vh, 100% 100vh;
  background-repeat: no-repeat, no-repeat, no-repeat, no-repeat;
  min-height: 100vh;
}
.font-mono { font-family:'JetBrains Mono',monospace; }

/* ── Gradients firma de la variante ──────────────────────────────── */
.grad-primary   { background: linear-gradient(180deg, #D9EBE4 0%, #F2F8F5 100%); }
.grad-secondary { background: linear-gradient(180deg, #FAEBC8 0%, #FFF6E0 100%); }
.grad-neutral   { background: linear-gradient(180deg, #F2F4F6 0%, #FAFBFC 100%); }
.grad-hero      { background: linear-gradient(135deg, #BCDFD0 0%, #D9EBE4 50%, #FAEBC8 100%); }
.grad-info      { background: linear-gradient(180deg, #D5E9F1 0%, #F0F7FA 100%); }
.grad-warning   { background: linear-gradient(180deg, #FAE6BD 0%, #FFF6E0 100%); }
.grad-danger    { background: linear-gradient(180deg, #F7D6CF 0%, #FFEDE8 100%); }
.grad-success   { background: linear-gradient(180deg, #C9EAD6 0%, #E5F5EC 100%); }

/* ════════════════════════════════════════════════════════════════════
   COLORES SEMÁNTICOS · fallback para Tailwind CDN
   Tailwind CDN no siempre resuelve bien colores custom de la paleta
   (bg-success, text-danger, etc.). Definimos las clases aquí como CSS
   plano para garantizar que siempre se apliquen, sin depender del
   parser runtime del CDN. Usa !important para ganar a cualquier utility
   generada después por el CDN.
   ════════════════════════════════════════════════════════════════════ */
:root {
  --color-success: #6CCB95;
  --color-warning: #F0B650;
  --color-danger:  #E68B7C;
  --color-info:    #5BA9C9;
  --color-success-rgb: 108 203 149;
  --color-warning-rgb: 240 182  80;
  --color-danger-rgb:  230 139 124;
  --color-info-rgb:     91 169 201;
}

/* ── Fondos sólidos ────────────────────────────────────────────────── */
.bg-success { background-color: var(--color-success) !important; }
.bg-warning { background-color: var(--color-warning) !important; }
.bg-danger  { background-color: var(--color-danger)  !important; }
.bg-info    { background-color: var(--color-info)    !important; }

/* ── Texto ─────────────────────────────────────────────────────────── */
.text-success { color: var(--color-success) !important; }
.text-warning { color: var(--color-warning) !important; }
.text-danger  { color: var(--color-danger)  !important; }
.text-info    { color: var(--color-info)    !important; }

/* ── Borders ───────────────────────────────────────────────────────── */
.border-success { border-color: var(--color-success) !important; }
.border-warning { border-color: var(--color-warning) !important; }
.border-danger  { border-color: var(--color-danger)  !important; }
.border-info    { border-color: var(--color-info)    !important; }

/* ── Fondos con opacidad (estilo Tailwind /10, /15, /20…) ──────────── */
.bg-success\/5   { background-color: rgb(var(--color-success-rgb) / 0.05) !important; }
.bg-success\/10  { background-color: rgb(var(--color-success-rgb) / 0.10) !important; }
.bg-success\/15  { background-color: rgb(var(--color-success-rgb) / 0.15) !important; }
.bg-success\/20  { background-color: rgb(var(--color-success-rgb) / 0.20) !important; }
.bg-success\/30  { background-color: rgb(var(--color-success-rgb) / 0.30) !important; }

.bg-warning\/5   { background-color: rgb(var(--color-warning-rgb) / 0.05) !important; }
.bg-warning\/10  { background-color: rgb(var(--color-warning-rgb) / 0.10) !important; }
.bg-warning\/15  { background-color: rgb(var(--color-warning-rgb) / 0.15) !important; }
.bg-warning\/20  { background-color: rgb(var(--color-warning-rgb) / 0.20) !important; }

.bg-danger\/5    { background-color: rgb(var(--color-danger-rgb)  / 0.05) !important; }
.bg-danger\/10   { background-color: rgb(var(--color-danger-rgb)  / 0.10) !important; }
.bg-danger\/15   { background-color: rgb(var(--color-danger-rgb)  / 0.15) !important; }
.bg-danger\/20   { background-color: rgb(var(--color-danger-rgb)  / 0.20) !important; }
.bg-danger\/30   { background-color: rgb(var(--color-danger-rgb)  / 0.30) !important; }

.bg-info\/5      { background-color: rgb(var(--color-info-rgb)    / 0.05) !important; }
.bg-info\/10     { background-color: rgb(var(--color-info-rgb)    / 0.10) !important; }
.bg-info\/15     { background-color: rgb(var(--color-info-rgb)    / 0.15) !important; }
.bg-info\/20     { background-color: rgb(var(--color-info-rgb)    / 0.20) !important; }

/* ── Borders con opacidad ──────────────────────────────────────────── */
.border-success\/20  { border-color: rgb(var(--color-success-rgb) / 0.20) !important; }
.border-success\/30  { border-color: rgb(var(--color-success-rgb) / 0.30) !important; }
.border-success\/40  { border-color: rgb(var(--color-success-rgb) / 0.40) !important; }

.border-warning\/20  { border-color: rgb(var(--color-warning-rgb) / 0.20) !important; }
.border-warning\/30  { border-color: rgb(var(--color-warning-rgb) / 0.30) !important; }
.border-warning\/40  { border-color: rgb(var(--color-warning-rgb) / 0.40) !important; }

.border-danger\/20   { border-color: rgb(var(--color-danger-rgb)  / 0.20) !important; }
.border-danger\/30   { border-color: rgb(var(--color-danger-rgb)  / 0.30) !important; }
.border-danger\/40   { border-color: rgb(var(--color-danger-rgb)  / 0.40) !important; }

.border-info\/20     { border-color: rgb(var(--color-info-rgb)    / 0.20) !important; }
.border-info\/30     { border-color: rgb(var(--color-info-rgb)    / 0.30) !important; }
.border-info\/40     { border-color: rgb(var(--color-info-rgb)    / 0.40) !important; }

/* ── Hover/focus de fondos con opacidad ────────────────────────────── */
.hover\:bg-success\/10:hover { background-color: rgb(var(--color-success-rgb) / 0.10) !important; }
.hover\:bg-warning\/10:hover { background-color: rgb(var(--color-warning-rgb) / 0.10) !important; }
.hover\:bg-danger\/10:hover  { background-color: rgb(var(--color-danger-rgb)  / 0.10) !important; }
.hover\:bg-info\/10:hover    { background-color: rgb(var(--color-info-rgb)    / 0.10) !important; }
.hover\:text-success:hover { color: var(--color-success) !important; }
.hover\:text-warning:hover { color: var(--color-warning) !important; }
.hover\:text-danger:hover  { color: var(--color-danger)  !important; }
.hover\:text-info:hover    { color: var(--color-info)    !important; }

/* ── Sparklines & charts SVG inline ──────────────────────────────── */
.sparkline path { fill:none; stroke:currentColor; stroke-width:2; stroke-linecap:round; stroke-linejoin:round; }
.chart-grid line { stroke:#E5E8EC; stroke-width:1; }
.chart-axis text { font-family:'JetBrains Mono',monospace; font-size:10px; fill:#6B7785; }
.chart-line { fill:none; stroke-width:2.5; stroke-linecap:round; stroke-linejoin:round; }
.chart-area { stroke:none; opacity:0.35; }
.chart-dot { stroke:white; stroke-width:2; }

/* ── Spec-card layout (icon chip top-right, big number, label bottom) ── */
.spec-card { position:relative; aspect-ratio: 5/4; }
.spec-card .chip { position:absolute; top:1rem; right:1rem; }
.spec-card .bottom { position:absolute; bottom:1.25rem; left:1.25rem; }

/* ── Toggle switch ───────────────────────────────────────────────── */
.toggle { width:44px; height:24px; background:#CCD1D8; border-radius:9999px; position:relative; cursor:pointer; transition:background 200ms; flex-shrink:0; }
.toggle.on { background:#A8D5C5; }
.toggle::after { content:''; position:absolute; width:20px; height:20px; background:white; border-radius:50%; top:2px; left:2px; transition:transform 200ms cubic-bezier(0.16,1,0.3,1); box-shadow:0 1px 3px rgba(0,0,0,0.15); }
.toggle.on::after { transform:translateX(20px); }

/* ── Toggle switch declarativo (input:checked nativo, sin JS) ────── */
.toggle-switch { position:relative; display:inline-block; flex-shrink:0; width:40px; height:24px; }
.toggle-switch input { position:absolute; inset:0; width:100%; height:100%; opacity:0; margin:0; cursor:pointer; z-index:2; }
.toggle-switch input:disabled { cursor:not-allowed; }
.toggle-switch__track { display:block; position:absolute; inset:0; background:#CCD1D8; border-radius:9999px; transition:background 200ms; pointer-events:none; }
.toggle-switch__track::after { content:''; position:absolute; top:2px; left:2px; width:20px; height:20px; border-radius:50%; background:#fff; box-shadow:0 1px 3px rgba(0,0,0,0.15); transition:transform 200ms cubic-bezier(0.16,1,0.3,1); }
.toggle-switch input:checked + .toggle-switch__track { background:#A8D5C5; }
.toggle-switch input:checked + .toggle-switch__track::after { transform:translateX(16px); }
.toggle-switch input:focus-visible + .toggle-switch__track { box-shadow:0 0 0 3px rgba(168,213,197,0.45); }
.toggle-switch input:disabled + .toggle-switch__track { opacity:0.55; }

/* ── Single range slider rebrand ─────────────────────────────────── */
input[type=range].brand { -webkit-appearance:none; appearance:none; width:100%; height:6px; background:linear-gradient(90deg, #8FC5B3 var(--v,50%), #E5E8EC var(--v,50%)); border-radius:9999px; outline:none; }
input[type=range].brand::-webkit-slider-thumb { -webkit-appearance:none; width:20px; height:20px; background:white; border:3px solid #6FAA98; border-radius:50%; cursor:pointer; box-shadow:0 2px 6px rgba(31,60,70,0.15); }
input[type=range].brand::-moz-range-thumb { width:20px; height:20px; background:white; border:3px solid #6FAA98; border-radius:50%; cursor:pointer; box-shadow:0 2px 6px rgba(31,60,70,0.15); }

/* ── Dual range slider (2 thumbs sobre mismo track) ──────────────── */
.dual-slider { position:relative; }
.dual-slider input[type=range] { position:absolute; left:0; top:0; width:100%; height:100%; appearance:none; -webkit-appearance:none; background:none; pointer-events:none; margin:0; }
.dual-slider input[type=range]::-webkit-slider-thumb { -webkit-appearance:none; pointer-events:auto; width:20px; height:20px; background:white; border:3px solid #6FAA98; border-radius:50%; cursor:pointer; box-shadow:0 2px 6px rgba(31,60,70,0.15); }
.dual-slider input[type=range]::-moz-range-thumb { pointer-events:auto; width:20px; height:20px; background:white; border:3px solid #6FAA98; border-radius:50%; cursor:pointer; box-shadow:0 2px 6px rgba(31,60,70,0.15); }

/* ── Range "thumb-only" sobre track decorativo (pH, valor único) ─── */
input[type=range].thumb-only { -webkit-appearance:none; appearance:none; background:transparent; outline:none; }
input[type=range].thumb-only::-webkit-slider-thumb { -webkit-appearance:none; width:12px; height:30px; background:#1A2333; border-radius:9999px; cursor:pointer; box-shadow:0 2px 6px rgba(31,60,70,0.2); }
input[type=range].thumb-only::-moz-range-thumb { width:12px; height:30px; background:#1A2333; border-radius:9999px; cursor:pointer; border:none; box-shadow:0 2px 6px rgba(31,60,70,0.2); }

/* ── Botón "expand-left" ────────────────────────────────────────────
   Botón pill que en reposo muestra SOLO el icono (forma circular) y al
   hacer hover se expande hacia la izquierda mostrando el label. Útil
   para barras de acciones que queremos compactas pero descubribles.

   HTML esperado:
     <button class="btn-expand-left ...rounded-full grad-primary...">
       <span data-collapsible-label>Texto del botón</span>
       <i data-lucide="plus" class="w-4 h-4"></i>
     </button>

   El texto va ANTES del icono → al expandirse crece hacia la izquierda
   y el icono permanece fijo en su posición visual (derecha del botón). */
.btn-expand-left {
  gap: 0 !important;
  padding-left: 0.75rem !important;
  padding-right: 0.75rem !important;
  transition: padding 0.25s ease;
}
.btn-expand-left > [data-collapsible-label] {
  /* `inline-flex` + altura fija = el label NUNCA cambia su contribución a
     la altura del botón al pasar de colapsado a expandido. Esto evita el
     desplazamiento vertical de 1-2px que producía el cambio max-height
     0 → 3rem (el flex padre recalculaba el centro vertical del icono al
     crecer el botón). Ahora solo cambia max-width / opacity / margin. */
  display: inline-flex;
  align-items: center;
  height: 1.25rem;                /* matchea line-height del text-sm */
  line-height: 1.25rem;
  max-width: 0;
  overflow: hidden;
  white-space: nowrap;
  opacity: 0;
  margin-right: 0;
  transition: max-width 0.25s ease, opacity 0.2s ease, margin-right 0.25s ease;
}
.btn-expand-left:hover > [data-collapsible-label],
.btn-expand-left:focus-visible > [data-collapsible-label],
.btn-expand-left.is-keep-expanded > [data-collapsible-label] {
  max-width: 320px;
  opacity: 1;
  margin-right: 0.5rem;
}
/* La clase `.is-keep-expanded` la añade el JS al botón cuando su menú
   dropdown está visible. Mantiene el botón expandido SOLO mientras el
   menú esté abierto (no por hover sobre el wrapper, que causaba
   rebotes con espacios entre elementos). Ver app.js → initDropdownExpandSync. */
/* Si el label contiene un flex interno (Región, Mis acuarios con
   contador+chevron), forzamos nowrap para que NUNCA wrappee a 2 líneas
   incluso si max-width se quedara corto. */
.btn-expand-left > [data-collapsible-label] > .flex {
  flex-wrap: nowrap;
  white-space: nowrap;
}
/* Tailwind preflight aplica `svg { display: block }` que rompe el flow
   inline del label colapsible (chevron, etc. saltan a otra línea).
   Restauramos a inline-block dentro del label SOLO. */
.btn-expand-left > [data-collapsible-label] svg {
  display: inline-block;
  vertical-align: middle;
}

/* Toggles tipo .btn-expand-left con checkbox interno (sr-only): cuando
   está checked, el botón cambia a verde success. Aplica también si el
   icono es un corazón (se rellena para indicar "guardado/deseado"). */
.btn-expand-left:has(:checked) {
  color: var(--color-success) !important;
  background-color: rgba(108, 203, 149, 0.08) !important;
  border-color: rgba(108, 203, 149, 0.4) !important;
}
/* Cuando el toggle está activo, forzamos el color del icono a verde
   anulando el text-primary-700 inline para mantener coherencia visual. */
.btn-expand-left:has(:checked) i,
.btn-expand-left:has(:checked) svg {
  color: var(--color-success) !important;
}
.btn-expand-left:has(:checked) svg.lucide-heart {
  fill: currentColor;
}

/* ── Select estilizado ──────────────────────────────────────────────
   Por defecto el browser renderiza la flecha nativa pegada al borde
   derecho, sin "vuelo". Reemplazamos por una flecha SVG custom (chevron
   neutral-500) con padding adecuado para que respire. Aplicamos a TODOS
   los <select> single (no multiple/size) con !important para pisar el
   padding-right de utilities Tailwind (px-4 etc.). */
select:not([multiple]):not([size]) {
  -webkit-appearance: none;
  -moz-appearance: none;
  appearance: none;
  background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236B7785' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.75' d='M6 8l4 4 4-4'/%3e%3c/svg%3e");
  background-position: right 0.875rem center;
  background-repeat: no-repeat;
  background-size: 1rem 1rem;
  padding-right: 2.5rem !important;
}
/* Edge legacy: quitar flecha duplicada */
select::-ms-expand { display: none; }

/* ── Heatmap cells ───────────────────────────────────────────────── */
.hm { width:14px; height:14px; border-radius:3px; }
.hm-0 { background:#F2F4F6; } .hm-1 { background:#D9EBE4; } .hm-2 { background:#A8D5C5; } .hm-3 { background:#6FAA98; } .hm-4 { background:#357066; }

/* ── Skeleton loading shimmer ────────────────────────────────────── */
@keyframes shimmer { 0%{background-position:-200% 0} 100%{background-position:200% 0} }
.skel { background:linear-gradient(90deg, #F2F4F6 0%, #FAFBFC 50%, #F2F4F6 100%); background-size:200% 100%; animation:shimmer 1.5s ease-in-out infinite; border-radius:8px; }

/* ── Spinner (más lento que estándar, sensación calmada) ─────────── */
@keyframes spin { to { transform: rotate(360deg); } }
.spin { animation: spin 1.4s linear infinite; }
@keyframes bounce-dot { 0%, 80%, 100% { transform: scale(0.6); opacity:0.6 } 40% { transform: scale(1); opacity:1 } }
.bounce-dot { animation: bounce-dot 1.8s ease-in-out infinite both; }

/* ── Tooltip CSS-only (sin JS) ───────────────────────────────────── */
.tip { position:relative; }
.tip > .tip-content { position:absolute; bottom:calc(100% + 8px); left:50%; transform:translateX(-50%) translateY(4px); opacity:0; pointer-events:none; background:#1A2333; color:white; font-size:11px; padding:6px 10px; border-radius:6px; white-space:nowrap; transition:all 200ms cubic-bezier(0.16,1,0.3,1); z-index:50; }
.tip > .tip-content::after { content:''; position:absolute; top:100%; left:50%; transform:translateX(-50%); border:5px solid transparent; border-top-color:#1A2333; }
.tip:hover > .tip-content,
.tip:focus-visible > .tip-content { opacity:1; transform:translateX(-50%) translateY(0); }

/* Tooltip de GLOSARIO (helper glossary_term() en includes/_glossary.php).
   Visual: el término lleva border-bottom punteado + cursor help para
   indicar que es definido. Tooltip permite texto largo (multiline). */
.tip-glossary { border-bottom: 1px dotted currentColor; cursor: help; }
.tip-glossary > .tip-content {
  white-space: normal;
  width: max-content;
  max-width: 280px;
  text-align: left;
  font-weight: 400;
  line-height: 1.4;
}

/* ── Tooltip · PORTAL al body (escape overflow:hidden) ─────────────
   El .tip-content original dentro del DOM se OCULTA cuando JS está
   activo (body.tip-portal-active). Un overlay global #tip-overlay
   vive en body y se posiciona via position:fixed al hover de cada
   .tip — esto escapa de cualquier padre con overflow:hidden. */
body.tip-portal-active .tip > .tip-content { display: none !important; }

#tip-overlay {
  position: fixed;
  top: 0; left: 0;
  opacity: 0;
  pointer-events: none;
  background: #1A2333;
  color: #fff;
  font-size: 11px;
  padding: 6px 10px;
  border-radius: 6px;
  z-index: 9999;
  white-space: nowrap;
  transition: opacity 200ms cubic-bezier(0.16,1,0.3,1);
}
/* Variante para tooltips de glossary: texto largo, multilínea */
#tip-overlay.tip-overlay-glossary {
  white-space: normal;
  width: max-content;
  max-width: 280px;
  text-align: left;
  line-height: 1.4;
}
/* Flecha (apunta al término) · arriba o abajo según orientación */
#tip-overlay::after {
  content: '';
  position: absolute;
  left: var(--tip-arrow-left, 50%);
  top: 100%;
  transform: translateX(-50%);
  border: 5px solid transparent;
  border-top-color: #1A2333;
}
#tip-overlay.tip-overlay-below::after {
  top: auto;
  bottom: 100%;
  border-top-color: transparent;
  border-bottom-color: #1A2333;
}

/* Variantes semánticas tooltip */
.tip-success > .tip-content { background:#3B9268; }
.tip-success > .tip-content::after { border-top-color:#3B9268; }
.tip-warning > .tip-content { background:#C68A2F; }
.tip-warning > .tip-content::after { border-top-color:#C68A2F; }
.tip-danger > .tip-content { background:#C95542; }
.tip-danger > .tip-content::after { border-top-color:#C95542; }
.tip-info > .tip-content { background:#2F7F9A; }
.tip-info > .tip-content::after { border-top-color:#2F7F9A; }

/* ── Section spacing + TOC ───────────────────────────────────────── */
section.section { scroll-margin-top: 24px; }
.section h2.section-title { font-size:1.875rem; font-weight:700; letter-spacing:-0.025em; color:#1A2333; }
.section h2.section-title .num { font-family:'JetBrains Mono',monospace; color:#A8B0BB; font-weight:400; font-size:0.65em; margin-right:0.5rem; }
.comp-label { font-size:10px; font-weight:600; letter-spacing:0.1em; text-transform:uppercase; color:#A8B0BB; margin-bottom:0.5rem; }
.toc-link:hover { color:#357066; }
.toc-link.active { background:#E5F0EB; color:#357066; font-weight:600; }

/* ═══════════════════════════════════════════════════════════════════════
   NUEVOS · Design V1
   ═══════════════════════════════════════════════════════════════════════ */

/* ── Avatares squircle (forma orgánica, herencia visual de V4 con
       colores V1b). Reemplazo a `rounded-full` para los avatares. ── */
.avatar-squircle { border-radius: 32% 68% 70% 30% / 30% 30% 70% 70%; }
.avatar-squircle-2 { border-radius: 60% 40% 30% 70% / 40% 50% 50% 60%; }

/* ── Cursor en círculos numéricos no interactivos (stepper paso pendiente,
       avatar con inicial) — no debe mostrar selector de texto al hover ── */
.cursor-num { cursor: default; user-select: none; }

/* ── Gauge needle con animación de rebote suave al cargar ────────── */
@keyframes needle-bounce {
  0%   { transform: rotate(-90deg); }      /* arranca al inicio */
  60%  { transform: rotate(45deg); }       /* overshoot ligero */
  75%  { transform: rotate(33deg); }       /* rebota hacia atrás */
  88%  { transform: rotate(37deg); }       /* segundo rebote */
  100% { transform: rotate(35deg); }       /* posición final */
}
.gauge-needle { transform-origin: 100px 100px; animation: needle-bounce 1.4s cubic-bezier(0.34, 1.56, 0.64, 1) both; }

/* ── Chart hover overlay (tooltip sobre puntos de gráficos SVG) ──── */
.chart-tip { position:absolute; pointer-events:none; background:#1A2333; color:white; font-size:11px; padding:6px 10px; border-radius:8px; transform:translate(-50%, calc(-100% - 8px)); white-space:nowrap; opacity:0; transition:opacity 150ms; z-index:60; box-shadow:0 4px 12px rgba(0,0,0,0.15); }
.chart-tip::after { content:''; position:absolute; top:100%; left:50%; transform:translateX(-50%); border:5px solid transparent; border-top-color:#1A2333; }
.chart-tip.show { opacity:1; }

/* ── uPlot theme override · alinear con paleta Star Acuario ──────── */
.uplot { font-family:'Outfit',system-ui,sans-serif; }
.uplot .u-legend { font-family:'Outfit',system-ui,sans-serif; font-size:12px; color:#4D5764; }
.uplot .u-axis { color:#6B7785; }
.uplot .u-cursor-pt { box-shadow:0 0 0 3px rgba(168,213,197,0.4); }
.uplot .u-tooltip,
.uplot-tooltip { background:#1A2333; color:white; padding:8px 12px; border-radius:8px; font-size:12px; box-shadow:0 4px 12px rgba(0,0,0,0.2); }

/* ── Tag identificadores de componentes · invisibles por defecto,
       visibles cuando body.show-tags está activo (toggle en topbar) ── */
[data-comp] { position: relative; }
body.show-tags [data-comp] { outline: 1px dashed rgba(111,170,152,0.55); outline-offset: 2px; border-radius: 6px; }
body.show-tags [data-comp]::before {
  content: attr(data-comp);
  position: absolute;
  top: -10px;
  left: 4px;
  background: #1A2333;
  color: #A8D5C5;
  font-family: 'JetBrains Mono', monospace;
  font-size: 9px;
  font-weight: 500;
  padding: 2px 7px;
  border-radius: 4px;
  z-index: 80;
  pointer-events: none;
  letter-spacing: 0.02em;
  white-space: nowrap;
  box-shadow: 0 1px 3px rgba(0,0,0,0.15);
}
/* botón toggle activo */
#toggle-tags.active { background: #1A2333 !important; color: #A8D5C5 !important; }

/* swatch de paleta · click copia HEX al portapapeles */
.swatch { transition: transform 200ms cubic-bezier(0.16,1,0.3,1), box-shadow 200ms; cursor: pointer; }
.swatch:hover { transform: translateY(-2px); box-shadow: 0 4px 12px rgba(31,60,70,0.10); }

/* ════════════════════════════════════════════════════════════════════
   CURSOR POINTER GLOBAL para botones
   Regla del proyecto Star Acuario: TODO elemento clickable que actúe
   como botón debe mostrar el cursor de mano. Cubrir aquí evita tener
   que recordar añadir `cursor-pointer` a cada botón nuevo.
   ════════════════════════════════════════════════════════════════════ */
button:not(:disabled),
[role="button"]:not(:disabled),
input[type="submit"]:not(:disabled),
input[type="button"]:not(:disabled),
input[type="reset"]:not(:disabled),
.toggle,
[data-stepper-plus]:not(:disabled),
[data-stepper-minus]:not(:disabled) {
    cursor: pointer;
}
/* Disabled siempre con not-allowed para feedback visual claro */
button:disabled,
input[type="submit"]:disabled,
input[type="button"]:disabled,
input[type="reset"]:disabled {
    cursor: not-allowed;
}

/* ════════════════════════════════════════════════════════════════════
   CALENDARIO · marca "hecho" sobre chips/cards
   Aplica un check verde redondo arriba-derecha sobre cualquier
   elemento con clase .is-done. Funciona en:
     - .cal-chip       (chips compactos de la vista semanal/mensual)
     - .cal-task-card  (cards grandes de la vista día)
     - .cal-agenda-card (cards del listado agenda)
   El elemento padre necesita position relative (las 3 clases base
   lo definen).
   ════════════════════════════════════════════════════════════════════ */
.cal-chip,
.cal-task-card,
.cal-agenda-card { position: relative; }

.cal-chip.is-done::after,
.cal-task-card.is-done::after,
.cal-agenda-card.is-done::after {
    content: "✓";
    position: absolute;
    top: 50%;
    right: 0.35rem;
    transform: translateY(-50%);
    font-size: 0.85rem;
    line-height: 1;
    color: rgb(22, 163, 74);
    width: 14px;
    height: 14px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-weight: 800;
    pointer-events: none;
    background: rgb(255, 255, 255);
    border: 1.5px solid rgb(22, 163, 74);
    border-radius: 50%;
    text-decoration: none;
}

/* ════════════════════════════════════════════════════════════════════
   STICKY LAYOUT · backoffice V2
   Garantiza que el sidebar (aside) y el topbar (header) se queden
   fijos al hacer scroll, independientemente de cómo Tailwind ordene
   las utility classes. align-self:flex-start previene que el flex
   container estire al aside verticalmente (síntoma clásico de "el
   sticky no funciona").
   ════════════════════════════════════════════════════════════════════ */
@media (min-width: 1024px) {
  aside[data-comp="sidebar"] {
    position: sticky !important;
    top: 0 !important;
    height: 100vh !important;
    max-height: 100vh !important;
    align-self: flex-start !important;
    flex-shrink: 0 !important;
    overflow-y: auto !important;
  }
}
header[data-comp="topbar"] {
  position: sticky !important;
  top: 0 !important;
  z-index: 20 !important;
}

/* ── Cabeceras de listado · sticky bajo el topbar ──────────────────
   Aplica a cualquier <header> hijo directo de <section data-comp="*.list">.
   Mantiene visible la cabecera (título + filtros + buscador + toggle +
   botón nuevo) mientras se hace scroll. El topbar va en z-20 top:0;
   este header va debajo con z-10 y top desplazado por la altura del
   topbar (64px mobile · 72px lg).
   Negative margins para que el background full-width cubra también el
   padding lateral del main (px-4 lg:px-8) y no se vea contenido detrás
   asomando por los lados al hacer scroll. ───────────────────────── */
section[data-comp$=".list"] > header {
  position: sticky;
  top: 4rem;            /* 64px = topbar mobile (py-3 + h-10) */
  z-index: 10;
  margin-left: -1rem;
  margin-right: -1rem;
  padding: 0.75rem 1rem;
  /* Transition para el fade in/out del bg al hacer scroll. Las
     propiedades visuales (bg, blur, sombra) las activa la clase
     `.is-scrolled` que initStickyHeaderBg() añade al <section>. */
  transition: background-color 0.25s ease,
              backdrop-filter 0.25s ease,
              -webkit-backdrop-filter 0.25s ease,
              box-shadow 0.25s ease;
}
section[data-comp$=".list"].is-scrolled > header {
  background-color: rgba(250, 250, 250, 0.85);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  box-shadow: 0 1px 0 rgb(245 245 245);  /* simula border-bottom sin layout shift */
}
@media (min-width: 1024px) {
  section[data-comp$=".list"] > header {
    top: 4.5rem;        /* 72px = topbar lg (py-4 + h-10) */
    margin-left: -2rem;
    margin-right: -2rem;
    padding: 1rem 2rem;
  }
}

/* ── Thead sticky de tablas de listado (vista lista) ───────────────
   Aplica a la tabla principal dentro de wrappers `*-list-view`
   (fish-list-view, best-list-view, aq-list-view…).
   Sólo en md+: en mobile el header de listado puede crecer mucho
   (flex-col con muchos filtros) y calcular el top exacto es frágil.
   Para que el sticky se pegue al VIEWPORT (debajo del header del
   listado) y no al wrapper interno, debemos anular los overflows
   del wrapper externo (`overflow-hidden` para clipear el radius)
   y del wrapper interno (`overflow-x-auto` para scroll horizontal).
   Como perdemos el clip del border-radius del wrapper externo,
   re-aplicamos el radius a las esquinas de la tabla con `border-
   collapse: separate` + `border-radius` por celda esquina.
   ──────────────────────────────────────────────────────────────── */
section[data-comp$=".list"] [class*="-list-view"] {
  overflow: visible !important;
}
section[data-comp$=".list"] [class*="-list-view"] > .overflow-x-auto {
  overflow: visible !important;
}
section[data-comp$=".list"] [class*="-list-view"] table {
  border-collapse: separate;
  border-spacing: 0;
}
section[data-comp$=".list"] [class*="-list-view"] thead th:first-child {
  border-top-left-radius: 1.5rem;   /* = rounded-3xl del wrapper */
  transition: border-top-left-radius 0.25s ease;
}
section[data-comp$=".list"] [class*="-list-view"] thead th:last-child {
  border-top-right-radius: 1.5rem;
  transition: border-top-right-radius 0.25s ease;
}
/* Al hacer scroll, el thead queda sticky y las filas del tbody pasan
   por detrás. Las esquinas redondas dejan ver "picos blancos" del bg
   de las filas. Al activarse `.is-scrolled` (sincronizado con el
   fade-in del bg del header), las esquinas se cuadran y el problema
   desaparece. En la transición de vuelta (al volver al top) se vuelven
   a redondear suave. */
section[data-comp$=".list"].is-scrolled [class*="-list-view"] thead th:first-child {
  border-top-left-radius: 0;
}
section[data-comp$=".list"].is-scrolled [class*="-list-view"] thead th:last-child {
  border-top-right-radius: 0;
}
section[data-comp$=".list"] [class*="-list-view"] tbody tr:last-child td:first-child {
  border-bottom-left-radius: 1.5rem;
}
section[data-comp$=".list"] [class*="-list-view"] tbody tr:last-child td:last-child {
  border-bottom-right-radius: 1.5rem;
}
@media (min-width: 768px) {
  section[data-comp$=".list"] [class*="-list-view"] thead th {
    position: sticky;
    /* El top exacto lo calcula initStickyTheadOffset() (app.js) midiendo
       el topbar + el header del listado y publicándolo como variable CSS
       --bo-thead-top en el <section>. Si por algún motivo el JS no
       corre, los fallbacks (11rem md / 12rem lg) cubren el peor caso. */
    top: var(--bo-thead-top, 11rem);
    z-index: 5;         /* < header listado (10) < topbar (20) */
    background-color: rgb(250 250 250);  /* neutral-50, opaco */
  }
}
@media (min-width: 1024px) {
  section[data-comp$=".list"] [class*="-list-view"] thead th {
    top: var(--bo-thead-top, 12rem);
  }
}

/* ── Cabecera de listados · altura uniforme de chips/botones ──────
   Los chips de filtros, buscador, "Solo los míos" y botones de
   acción ya son 40px (gracias a `py-2.5` + text-sm). El toggle
   Cards/Lista usa `p-1` + botones `py-1.5` y se queda en ~34px,
   rompiendo la simetría visual de la fila. Fuerza 40px para que
   todos los elementos de la cabecera estén a la misma altura. */
section[data-comp$=".list"] > header > div.flex.items-center.gap-2.flex-wrap > [role="group"] {
  height: 2.5rem;
}

/* ── Buscadores colapsables ────────────────────────────────────────
   Patrón aplicado por initCollapsibleSearch() (app.js) a todo
   <input type="search"> que NO esté dentro de un dropdown.
   Estado por defecto = círculo 40x40 con icono lupa centrado.
   Al click expande con slide horizontal a su ancho natural y recibe
   focus. Al blur con valor vacío se vuelve a plegar.
   ──────────────────────────────────────────────────────────────── */
.search-collapsible {
  flex: none !important;       /* anula flex-1 / md:flex-none del wrapper */
  width: 14rem;                /* ancho cuando expandido (=w-56) */
  transition: width 0.25s ease;
}
.search-collapsible.is-collapsed {
  width: 2.5rem;               /* círculo 40x40 */
  height: 2.5rem;              /* fuerza cuadrado por si el input no llega a 40px exactos */
  cursor: pointer;
}
.search-collapsible.is-collapsed input[type="search"] {
  width: 100% !important;
  height: 2.5rem;
  padding: 0 !important;
  border-radius: 9999px;
  color: transparent !important;
  caret-color: transparent;
  cursor: pointer;
  pointer-events: none;        /* el click va al wrap */
  transition: padding 0.25s ease;
}
.search-collapsible.is-collapsed input[type="search"]::placeholder {
  color: transparent;
}
/* Centrar el icono lupa cuando colapsado (sobreescribe el left-4 del
   patrón actual). Lucide reemplaza el <i> por <svg> y según versión
   puede no preservar `data-lucide`, así que matcheamos AMBOS tags
   directos del wrap (solo hay un icono ahí, no afecta a otros).
   Sobre el translateY: el `top: 50%` original junto al `height: 2.5rem`
   del wrap deja el icono ya casi alineado; en la práctica la mitad
   inferior queda mejor visualmente sin compensar la Y (translate Y=0).
   Solo centramos horizontalmente con translate X=-50%. */
.search-collapsible.is-collapsed > i,
.search-collapsible.is-collapsed > svg {
  left: 50% !important;
  transform: translate(-50%, 0%) !important;
}

/* ── SweetAlert2 custom theme (sobreescribe estilos por defecto) ── */
.swal2-popup.swal2-toast,
.swal2-popup { font-family:'Outfit',system-ui,sans-serif !important; border-radius:24px !important; padding:1.5rem 1.5rem 1.25rem !important; }
.swal2-title { font-weight:700 !important; color:#1A2333 !important; }
.swal2-html-container { color:#4D5764 !important; font-size:0.95rem !important; }
.swal2-confirm.swal2-styled { background:#8FC5B3 !important; color:#1A2333 !important; font-weight:600 !important; border-radius:9999px !important; padding:0.6rem 1.5rem !important; box-shadow:0 4px 16px rgba(168,213,197,0.30) !important; }
.swal2-confirm.swal2-styled:hover { background:#6FAA98 !important; }
.swal2-cancel.swal2-styled { background:white !important; color:#4D5764 !important; border:1px solid #E5E8EC !important; font-weight:500 !important; border-radius:9999px !important; padding:0.6rem 1.5rem !important; }
.swal2-deny.swal2-styled { background:#E68B7C !important; color:white !important; font-weight:600 !important; border-radius:9999px !important; padding:0.6rem 1.5rem !important; }
.swal2-icon.swal2-success [class^=swal2-success-line] { background-color:#6CCB95 !important; }
.swal2-icon.swal2-success .swal2-success-ring { border-color:rgba(108,203,149,0.3) !important; }
.swal2-icon.swal2-warning { color:#F0B650 !important; border-color:#F0B650 !important; }
.swal2-icon.swal2-error [class^=swal2-x-mark-line] { background-color:#E68B7C !important; }
.swal2-icon.swal2-error { border-color:#E68B7C !important; }
.swal2-icon.swal2-info { color:#5BA9C9 !important; border-color:#5BA9C9 !important; }
.swal2-icon.swal2-question { color:#A8B0BB !important; border-color:#A8B0BB !important; }

/* ── Rich HTML render (output del editor Summernote en páginas de
   solo lectura · bestiario_view.php, futuros fish_view, etc.) ─────
   Estos estilos los necesitan SIEMPRE (no solo cuando se carga el
   editor). Por eso van aquí en styles.css, no en _richtext.php que
   se carga sólo cuando $useRichText=true. */
.rich-html > *:first-child { margin-top: 0; }
.rich-html > *:last-child  { margin-bottom: 0; }
.rich-html p          { margin: .35rem 0; }
.rich-html ul, .rich-html ol { margin: .35rem 0 .35rem 1.25rem; }
.rich-html ul         { list-style: disc; }
.rich-html ol         { list-style: decimal; }
.rich-html h2, .rich-html h3, .rich-html h4, .rich-html h5, .rich-html h6 {
  margin: .8rem 0 .35rem; font-weight: 600; color: #1A2333;
}
.rich-html h2 { font-size: 1.15rem; }
.rich-html h3 { font-size: 1.05rem; }
.rich-html h4 { font-size: .95rem; }
.rich-html blockquote {
  margin: .5rem 0; padding: .35rem .75rem;
  border-left: 3px solid #3D7E69;  /* primary-container */
  color: #6D716F;                  /* ink-500 */
  background: #F0FAF6;             /* turq-50 */
  border-radius: 4px;
}
.rich-html pre, .rich-html code {
  background: #F0FAF6; border-radius: 4px; padding: .15rem .35rem;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: .85em;
}
.rich-html pre { padding: .55rem .75rem; overflow-x: auto; }
.rich-html hr { border: 0; border-top: 1px solid #E5E7E6; margin: .75rem 0; }
.rich-html a  { color: #216551; text-decoration: underline; }
.rich-html strong, .rich-html b { font-weight: 600; }

/* ── Botones de "cierre de ciclo" ──────────────────────────────────
   Acciones de compromiso que cierran un ciclo de nuestra involucración
   (asumir una incompatibilidad, descartar un aviso, aceptar un consejo…).
   El futuro sistema de niveles de involucración engancha por esta clase
   para pedir DOBLE CHECK según el nivel del usuario. Marcador semántico:
   el estilo lo define cada botón; aquí solo un realce sutil para que se
   identifiquen como decisiones importantes. */
.commit-action {
  position: relative;
  letter-spacing: 0.01em;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.12);
}
.commit-action:active { transform: translateY(1px); }

/* ── Avatares del slider de parámetros (stack solapado) ────────────
   Al hover, el avatar sube al frente y se agranda para ver su imagen
   completa aunque esté tapado por los de delante. */
.nat-avatar { transition: transform .12s ease, box-shadow .12s ease; }
.nat-avatar:hover {
  z-index: 60 !important;
  transform: scale(1.22);
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.4);
  cursor: pointer;
}

/* ── Dos columnas para cards emparejadas (Cuidados ↔ Parámetros) ───
   Mobile-first: una sola columna por defecto (tablet y móvil, para que las
   cards densas no queden apretadas) y dos columnas desde escritorio amplio. */
.nat-two-col {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1.25rem;
  align-items: start;
}
@media (min-width: 1024px) {
  .nat-two-col { grid-template-columns: 1fr 1fr; }
}

/* Colapsable genérico (cards plegables · data-collapsible) */
[data-collapsible-chevron] { transition: transform .2s ease; }
[data-collapsible][data-collapsed="true"] [data-collapsible-body]    { display: none; }
[data-collapsible][data-collapsed="true"] [data-collapsible-chevron] { transform: rotate(-90deg); }

/* ── Reducir movimiento (ajuste de accesibilidad del SO) ───────────
   Con prefers-reduced-motion activo se paran las animaciones
   decorativas en toda la app (WCAG 2.3.3). Las transiciones de
   feedback (hover/focus) se mantienen. */
@media (prefers-reduced-motion: reduce) {
  .animate-ping { display: none !important; }
  .animate-pulse, .spin, .bounce-dot, .gauge-needle { animation: none !important; }
}

/* ── Foco de teclado visible en el shell (topbar + sidebar) ────────
   Los botones-icono y links del shell no tienen focus:ring de Tailwind;
   sin esto el foco al navegar con Tab es invisible (WCAG 2.4.7). */
[data-comp="topbar"] a:focus-visible,
[data-comp="topbar"] button:focus-visible,
[data-comp="sidebar"] a:focus-visible,
[data-comp="sidebar"] button:focus-visible {
  outline: 2px solid #6FAA98;
  outline-offset: 2px;
}

/* ── #46 · Especie "no_recomendar" (regulada en tu jurisdicción) ──────────
   NO se apaga como una inactiva (antes usaba opacity:.6, idéntica a la
   desactivada → se confundían). En su lugar: foto desaturada + anillo/borde
   ámbar de precaución, a plena opacidad. Distinta de la activa (normal) y de
   la desactivada (opacity-60 + sello INACTIVO). El atributo lo pinta el PHP. */
[data-oferta="no_recomendar"] img { filter: grayscale(0.6); }
article[data-oferta="no_recomendar"] { position: relative; }
article[data-oferta="no_recomendar"]::after {
  content: ""; position: absolute; inset: 0; border-radius: inherit;
  box-shadow: inset 0 0 0 1.5px rgba(217, 119, 6, 0.45); /* ámbar warning */
  pointer-events: none;
}
tr[data-oferta="no_recomendar"] td:first-child {
  box-shadow: inset 3px 0 0 rgba(217, 119, 6, 0.55);
}

/* ═══ Modales de EVENTOS (SweetAlert) · campos con tokens del sistema ═══
   El popup de Swal cuelga de <body> (fuera del alcance de las utilidades
   compiladas) → componente CSS a mano. Usado por Población (eventos de
   fauna) y reutilizable por la gemela de flora. Sustituye a los antiguos
   style= inline con hex fuera de paleta. */
.swal-label { display:block; font-size:11px; font-weight:600; color:#4D5764; margin-bottom:4px; text-align:left; }
.swal-field {
  width:100%; box-sizing:border-box; padding:9px 12px; font-family:inherit; font-size:14px;
  border:1px solid #E5E8EC; border-radius:12px; background:#FAFBFC; color:#1A2333;
}
.swal-field:focus {
  outline:none; border-color:#A8D5C5; background:#fff;
  box-shadow:0 0 0 4px #E5F0EB;
}
.swal-field[readonly], .swal-field:disabled {
  background:#F2F4F6; color:#6B7785; cursor:not-allowed;
}
.swal-hint { font-size:10px; color:#6B7785; margin:4px 0 0; text-align:left; }
.swal-note {
  margin:6px 0 0; padding:8px 10px; font-size:11px; line-height:1.5; text-align:left;
  background:rgba(240,182,80,.10); border:1px solid rgba(240,182,80,.30);
  border-radius:12px; color:#333B47;
}
/* Menú del select custom (p. ej. Motivo del evento) dentro del Swal */
.swal-menu {
  position:absolute; left:0; right:0; top:100%; margin-top:6px; z-index:10;
  background:#fff; border:1px solid #E5E8EC; border-radius:12px;
  box-shadow:0 8px 24px rgba(31,60,70,.08); overflow-y:auto; max-height:220px;
  padding:4px; text-align:left;
}
.swal-opt {
  display:flex; align-items:center; gap:8px; width:100%;
  padding:8px 10px; border:0; background:transparent; border-radius:8px;
  font-family:inherit; font-size:13px; color:#333B47; cursor:pointer; text-align:left;
}
.swal-opt:hover  { background:#F2F8F5; }
.swal-opt.is-sel { background:#E5F0EB; font-weight:600; }
/* Días de la semana (L-M-X…) del modal "Añadir al calendario" · checkbox
   accesible (focusable, no display:none) + estado seleccionado en info */
.swal-wd {
  flex:1; text-align:center; padding:6px 0; position:relative;
  border:1px solid #E5E8EC; border-radius:8px; background:#fff;
  font-size:12px; font-weight:600; color:#333B47; cursor:pointer;
}
.swal-wd input { position:absolute; opacity:0; pointer-events:none; }
.swal-wd:focus-within { outline:2px solid #A8D5C5; outline-offset:2px; }
.swal-wd.is-on { background:#5BA9C9; border-color:#5BA9C9; color:#fff; }
/* Popups Swal con select custom desplegable: dejar que el menú sobresalga
   del modal en vez de generar scroll interno (el html-container de swal2
   recorta con overflow:auto por defecto). El html-container se eleva por
   encima de .swal2-actions (z-index 1 en swal2) para que el menú abierto
   no quede DETRÁS de los botones Confirmar/Cancelar. */
.swal-has-dropdown,
.swal-has-dropdown .swal2-html-container { overflow: visible !important; }
.swal-has-dropdown .swal2-html-container { position: relative; z-index: 3; }
.swal-has-dropdown .swal-menu { z-index: 30; }
