/* ============================================================================
   FERIAM — Sistema de diseño McKinsey
   Navy #003A70 · Fondo blanco · Texto #1A1A1A
   ============================================================================ */

/* ── Variables ───────────────────────────────────────────────────────────── */
:root {
  --navy:         #003A70;
  --navy-light:   #004e97;
  --navy-dark:    #002855;
  --text:         #1A1A1A;
  --text-muted:   #6B6B6B;
  --border:       #D0D0D0;
  --bg:           #FFFFFF;
  --bg-alt:       #F7F7F7;
  --success:      #1A6E3A;
  --success-bg:   #EAF5EE;
  --error:        #8B0000;
  --error-bg:     #FBEAEA;
  --warning:      #7B5800;
  --warning-bg:   #FFF8E6;
  --info:         #003A70;
  --info-bg:      #E6EEF7;
  --radius:       4px;
  --radius-sm:    2px;
  --shadow-sm:    0 1px 3px rgba(0,0,0,.08);
  --sidebar-w:    260px;
  --font:         system-ui, -apple-system, 'Segoe UI', sans-serif;
  --transition:   150ms ease;
  /* ── Variables de contraste (sobrescritas por el tema del ayuntamiento) ── */
  --on-navy:    #fff;                     /* texto sobre fondo navy */
  --on-navy-80: rgba(255,255,255,.8);    /* texto atenuado (80%) */
  --on-navy-60: rgba(255,255,255,.6);    /* texto atenuado (60%) */
  --on-navy-45: rgba(255,255,255,.45);   /* texto muy atenuado (45%) */
}

/* ── Reset ───────────────────────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

html { font-size: 16px; -webkit-text-size-adjust: 100%; }

body {
  font-family: var(--font);
  font-size: 0.9375rem;
  line-height: 1.5;
  color: var(--text);
  background: var(--bg);
}

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

img { max-width: 100%; height: auto; }

/* ── Tipografía ──────────────────────────────────────────────────────────── */
h1 { font-size: 1.625rem; font-weight: 700; line-height: 1.2; }
h2 { font-size: 1.25rem;  font-weight: 700; line-height: 1.3; }
h3 { font-size: 1.0625rem; font-weight: 600; }
h4 { font-size: 0.9375rem; font-weight: 600; }
h5, h6 { font-size: 0.875rem; font-weight: 600; }

/* ── Layout principal ────────────────────────────────────────────────────── */
.layout {
  display: flex;
  min-height: 100vh;
}

/* ── Sidebar ─────────────────────────────────────────────────────────────── */
.sidebar {
  width: var(--sidebar-w);
  background: var(--navy);
  color: var(--on-navy, #fff);
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  position: fixed;
  top: 0; left: 0; bottom: 0;
  z-index: 100;
  overflow-y: auto;
  transition: transform var(--transition);
}

.sidebar__logo {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 20px 20px 16px;
  border-bottom: 1px solid rgba(255,255,255,.15);
  text-decoration: none;
}
.sidebar__logo-text {
  font-size: 1.25rem;
  font-weight: 800;
  letter-spacing: 1.5px;
  color: var(--on-navy, #fff);
  text-transform: uppercase;
}
.sidebar__logo-sub {
  font-size: 0.625rem;
  color: var(--on-navy-60, rgba(255,255,255,.6));
  text-transform: uppercase;
  letter-spacing: 1px;
}

.sidebar__nav { flex: 1; padding: 12px 0; }

.sidebar__section {
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 1.5px;
  text-transform: uppercase;
  color: var(--on-navy-45, rgba(255,255,255,.45));
  padding: 16px 20px 4px;
}

.sidebar__link {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 20px;
  color: var(--on-navy-80, rgba(255,255,255,.8));
  font-size: 0.875rem;
  text-decoration: none;
  transition: background var(--transition), color var(--transition);
  border-left: 3px solid transparent;
}
.sidebar__link:hover {
  background: rgba(255,255,255,.1);
  color: var(--on-navy, #fff);
  text-decoration: none;
}
.sidebar__link.is-active {
  background: rgba(255,255,255,.12);
  color: var(--on-navy, #fff);
  border-left-color: var(--on-navy, #fff);
  font-weight: 600;
}
.sidebar__link svg, .sidebar__link .icon {
  width: 18px; height: 18px; flex-shrink: 0; opacity: .8;
}

.sidebar__footer {
  padding: 16px 20px;
  border-top: 1px solid rgba(255,255,255,.15);
  font-size: 0.8125rem;
  color: var(--on-navy-60, rgba(255,255,255,.6));
}
.sidebar__footer a { color: var(--on-navy-80, rgba(255,255,255,.8)); }

/* ── Contenido principal ─────────────────────────────────────────────────── */
.main {
  flex: 1;
  margin-left: var(--sidebar-w);
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  /* Un elemento flex tiene min-width:auto por defecto y NO encoge por debajo
     del ancho de su contenido: una tabla ancha empujaba toda la página hacia
     la derecha y dejaba los botones de la última columna fuera de pantalla,
     incluso en monitores grandes. Con min-width:0 el contenido se adapta y
     son los contenedores con overflow los que scrollean. */
  min-width: 0;
}

.topbar {
  position: sticky;
  top: 0;
  z-index: 90;
  background: var(--bg);
  border-bottom: 1px solid var(--border);
  padding: 0 32px;
  height: 56px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
}

.topbar__title {
  font-size: 1.0625rem;
  font-weight: 700;
  color: var(--text);
}

.topbar__actions {
  display: flex;
  align-items: center;
  gap: 12px;
}

.hamburger {
  display: none;
  background: none;
  border: none;
  cursor: pointer;
  padding: 6px;
  color: var(--text);
}

.page {
  flex: 1;
  padding: 28px 32px;
  max-width: 1400px;
  width: 100%;
}

.page-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 24px;
  /* Sin `wrap`, el bloque de acciones de la derecha se sale de la pantalla y
     se recorta. En /admin/mercados un admin_unico tiene OCHO controles en esa
     fila (investigación, selector + retraducir, aviso, duplicados, nombres
     sospechosos, textos, direcciones sugeridas y «Nuevo mercado») y el que se
     pierde por el borde es el último — justo el botón primario. */
  flex-wrap: wrap;
}

/* Las plantillas montan el bloque de acciones con un `style="display:flex;
   gap:8px"` en línea (105 veces en 63 ficheros). El estilo en línea fija
   `display` y `gap`, pero no `flex-wrap`, así que esta regla sí se aplica y
   arregla las 63 de una vez sin tocar ninguna plantilla. */
.page-header > div:last-child {
  flex-wrap: wrap;
  justify-content: flex-end;
}

/* Un hijo de flex no baja de su ancho de contenido salvo que se le permita:
   sin esto, un título largo empuja las acciones fuera en lugar de partirse. */
.page-header > div { min-width: 0; }

.page-header h1 { margin-bottom: 2px; }

.breadcrumb {
  font-size: 0.8125rem;
  color: var(--text-muted);
  margin-top: 4px;
}
.breadcrumb a { color: var(--navy); }
.breadcrumb a::after { content: ' /'; margin: 0 4px; color: var(--text-muted); }

/* ── Tarjetas ─────────────────────────────────────────────────────────────── */
.card {
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 24px;
}

.card-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 20px;
  padding-bottom: 16px;
  border-bottom: 1px solid var(--border);
}

.card-title {
  font-size: 1rem;
  font-weight: 700;
}

/* ── KPI cards ───────────────────────────────────────────────────────────── */
.kpi-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 16px;
  margin-bottom: 24px;
}

.kpi {
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 20px;
}
.kpi__label {
  font-size: 0.75rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .5px;
  color: var(--text-muted);
  margin-bottom: 6px;
}
.kpi__value {
  font-size: 2rem;
  font-weight: 800;
  line-height: 1;
  color: var(--navy);
  margin-bottom: 4px;
}
.kpi__sub {
  font-size: 0.75rem;
  color: var(--text-muted);
}
.kpi--accent { border-left: 4px solid var(--navy); }

/* ── Tablas ───────────────────────────────────────────────────────────────── */
.table-wrapper { overflow-x: auto; }

.table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.875rem;
}
.table th {
  text-align: left;
  padding: 10px 14px;
  background: var(--navy);
  color: var(--on-navy, #fff);
  font-size: 0.75rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .5px;
  white-space: nowrap;
}
.table td {
  padding: 10px 14px;
  border-bottom: 1px solid var(--border);
  vertical-align: middle;
}
.table tbody tr:nth-child(even) td { background: var(--bg-alt); }
.table tbody tr:hover td { background: #edf2f7; }

.table--compact th,
.table--compact td { padding: 7px 12px; }

/* Botón de ordenar dentro de la cabecera.
   El JS del layout envuelve el texto del <th> en un <button> de verdad en vez
   de poner role="button" sobre el propio <th>: con el rol encima, la celda
   deja de ser `columnheader` y el lector de pantalla pierde las cabeceras de
   toda la tabla. Aquí el botón se disfraza de cabecera para que no se note. */
.th-sort {
  display: inline-flex;
  align-items: center;
  width: 100%;
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  color: inherit;
  letter-spacing: inherit;
  text-transform: inherit;
  text-align: inherit;
  cursor: pointer;
}
.th-sort:focus-visible { outline-offset: 1px; }
/* El <th> ya centra o alinea a la derecha con .text-center / .text-right;
   el botón hereda esa alineación desde `text-align: inherit`, pero como es
   flex hay que decírselo también en el eje principal. */
.text-center > .th-sort { justify-content: center; }
.text-right  > .th-sort { justify-content: flex-end; }

/* ── Tabla de pares candidatos a duplicado ────────────────────────────────
   /admin/mercados/duplicados tenía nueve columnas de ancho FIJO: sólo los
   anchos declarados sumaban 1.140px y, con el municipio y los tres botones
   de acciones en línea, la tabla pedía ~1.620. `.page` da como mucho 1.336
   (max-width 1400 menos el relleno) y en un portátil de 1366 quedan ~1.040
   descontando la barra lateral de 260. Resultado: había que arrastrar la
   tabla de lado para llegar a los botones, en cualquier pantalla.

   Con `table-layout: fixed` y los anchos en porcentaje la tabla vale
   exactamente lo que mide su contenedor —ni más ni menos— y el contenido se
   reparte y envuelve en vez de empujar. Deja de depender de cuánto ocupe el
   nombre de un municipio o la etiqueta de un botón traducida al alemán.

   El `min-width` es el suelo por debajo del cual la pantalla ya no es
   legible y sí conviene que `.table-wrapper` scrollee (móvil, ventana
   partida). Por encima de eso no scrollea nunca. */
.tabla-duplicados { table-layout: fixed; min-width: 880px; }

/* Con ancho fijo una cabecera larga ya no puede ensanchar su columna: o
   envuelve, o se sale. Y algo más pequeña para que quepan las de una sola
   palabra («Distancia», «Municipio») sin invadir la de al lado. */
.tabla-duplicados th {
  white-space: normal;
  font-size: 0.7rem;
  letter-spacing: .2px;
}

/* Un slug, unas coordenadas o una URL canónica no llevan espacios donde
   partir: sin esto desbordarían su celda. */
.tabla-duplicados td { overflow-wrap: break-word; }

/* Los tres botones de la última columna, apilados. En línea pedían ~310px
   —más que cualquiera de las dos fichas— para tres etiquetas cortas, y eran
   la mayor parte del desbordamiento. Van en un <div> dentro de la celda:
   `display:flex` sobre un <td> lo saca de la maquetación de la tabla. */
.tabla-duplicados .acciones-par {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.tabla-duplicados .acciones-par .btn {
  width: 100%;
  justify-content: center;
  text-align: center;
}

/* ── Botones ──────────────────────────────────────────────────────────────── */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 9px 18px;
  font-size: 0.875rem;
  font-weight: 600;
  line-height: 1;
  border-radius: var(--radius);
  border: 1.5px solid transparent;
  cursor: pointer;
  text-decoration: none;
  transition: background var(--transition), border-color var(--transition), color var(--transition);
  white-space: nowrap;
}

.btn-primary {
  background: var(--navy);
  color: var(--on-navy, #fff);
  border-color: var(--navy);
}
.btn-primary:hover { background: var(--navy-dark); border-color: var(--navy-dark); color: var(--on-navy, #fff); text-decoration: none; }

.btn-secondary {
  background: transparent;
  color: var(--navy);
  border-color: var(--navy);
}
.btn-secondary:hover { background: var(--navy); color: var(--on-navy, #fff); text-decoration: none; }

.btn-danger {
  background: var(--error);
  color: #fff;
  border-color: var(--error);
}
.btn-danger:hover { background: #6b0000; border-color: #6b0000; color: #fff; text-decoration: none; }

.btn-ghost {
  background: transparent;
  color: var(--text-muted);
  border-color: transparent;
}
.btn-ghost:hover { background: var(--bg-alt); color: var(--text); }

.btn-sm { padding: 5px 12px; font-size: 0.8125rem; }
.btn-lg { padding: 13px 28px; font-size: 1rem; }

/* ── Formularios ─────────────────────────────────────────────────────────── */
.form-group { margin-bottom: 18px; }

.form-label {
  display: block;
  font-size: 0.8125rem;
  font-weight: 600;
  margin-bottom: 5px;
  color: var(--text);
}
.form-label .required { color: var(--error); margin-left: 2px; }

.form-control {
  width: 100%;
  padding: 9px 12px;
  font-size: 0.9375rem;
  font-family: var(--font);
  color: var(--text);
  background: var(--bg);
  border: 1.5px solid var(--border);
  border-radius: var(--radius);
  transition: border-color var(--transition);
  line-height: 1.4;
}
.form-control:focus {
  border-color: var(--navy);
}
/* #b0b0b0 sobre blanco daba 2,17:1. El placeholder es texto y entra en 1.4.3:
   necesita 4,5:1. Se pasa a --text-muted, que es el gris del propio tema y ya
   está calculado por encima del umbral (5,51:1 sobre blanco en mediterráneo,
   4,97:1 en institucional). Sigue distinguiéndose del valor escrito, que usa
   --text (#2C2417). */
.form-control::placeholder,
.search-bar input::placeholder { color: var(--text-muted, #6B6B6B); opacity: 1; }
.form-control:disabled { background: var(--bg-alt); color: var(--text-muted); cursor: not-allowed; }

select.form-control { cursor: pointer; }
textarea.form-control { resize: vertical; min-height: 90px; }

.form-hint {
  font-size: 0.8rem;
  color: var(--text-muted);
  margin-top: 4px;
}
.form-error {
  font-size: 0.8rem;
  color: var(--error);
  margin-top: 4px;
}

.form-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
}
.form-row.cols-3 { grid-template-columns: 1fr 1fr 1fr; }
.form-row.cols-4 { grid-template-columns: repeat(4, 1fr); }

/* Checkbox / Radio */
.form-check {
  display: flex;
  align-items: center;
  gap: 8px;
  cursor: pointer;
  font-size: 0.9rem;
}
.form-check input { width: 16px; height: 16px; accent-color: var(--navy); cursor: pointer; }

/* ── Alertas ──────────────────────────────────────────────────────────────── */
.alert {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 12px 16px;
  border-radius: var(--radius);
  font-size: 0.9rem;
  margin-bottom: 16px;
  border: 1px solid transparent;
}
.alert__icon { flex-shrink: 0; margin-top: 1px; font-size: 1rem; }

.alert--success { background: var(--success-bg); border-color: #b8dfc7; color: var(--success); }
.alert--danger  { background: var(--error-bg);   border-color: #e8b8b8; color: var(--error); }
.alert--warning { background: var(--warning-bg); border-color: #f0d98c; color: var(--warning); }
.alert--info    { background: var(--info-bg);    border-color: #b8cfe8; color: var(--info); }

/* ── Badges ───────────────────────────────────────────────────────────────── */
.badge {
  display: inline-flex;
  align-items: center;
  padding: 2px 8px;
  border-radius: 20px;
  font-size: 0.75rem;
  font-weight: 700;
  white-space: nowrap;
  text-transform: uppercase;
  letter-spacing: .3px;
}
.badge-success  { background: var(--success-bg); color: var(--success); }
.badge-danger   { background: var(--error-bg);   color: var(--error); }
.badge-warning  { background: var(--warning-bg); color: var(--warning); }
.badge-info     { background: var(--info-bg);    color: var(--info); }
.badge-navy     { background: var(--navy);       color: var(--on-navy, #fff); }
.badge-muted    { background: var(--bg-alt);     color: var(--text-muted); border: 1px solid var(--border); }

/* ── Modales ──────────────────────────────────────────────────────────────── */
.modal-overlay {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(0,0,0,.45);
  z-index: 200;
  align-items: center;
  justify-content: center;
  padding: 20px;
}
.modal-overlay.is-open { display: flex; }

.modal {
  background: var(--bg);
  border-radius: var(--radius);
  width: 100%;
  max-width: 560px;
  max-height: 90vh;
  overflow-y: auto;
}

.modal-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 20px 24px 16px;
  border-bottom: 1px solid var(--border);
}
.modal-title { font-size: 1.0625rem; font-weight: 700; }
.modal-close { background: none; border: none; font-size: 1.25rem; cursor: pointer; color: var(--text-muted); line-height: 1; padding: 4px; }

.modal-body { padding: 24px; }
.modal-footer {
  display: flex;
  justify-content: flex-end;
  gap: 10px;
  padding: 16px 24px;
  border-top: 1px solid var(--border);
}

/* ── Paginación ───────────────────────────────────────────────────────────── */
.pagination {
  display: flex;
  align-items: center;
  gap: 4px;
  margin-top: 20px;
}
.pagination a, .pagination span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px; height: 34px;
  border: 1.5px solid var(--border);
  border-radius: var(--radius);
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--text);
  text-decoration: none;
  transition: background var(--transition), border-color var(--transition);
}
.pagination a:hover { background: var(--bg-alt); text-decoration: none; }
.pagination .current { background: var(--navy); border-color: var(--navy); color: var(--on-navy, #fff); }
.pagination .disabled { opacity: .4; pointer-events: none; }

/* ── Buscador ─────────────────────────────────────────────────────────────── */
.search-bar {
  display: flex;
  align-items: center;
  gap: 8px;
  background: var(--bg-alt);
  border: 1.5px solid var(--border);
  border-radius: var(--radius);
  padding: 0 12px;
  max-width: 360px;
}
.search-bar input {
  border: none;
  background: transparent;
  padding: 8px 0;
  font-size: 0.9rem;
  outline: none;
  width: 100%;
  font-family: var(--font);
}

/* ── Tabs ─────────────────────────────────────────────────────────────────── */
.tabs {
  display: flex;
  gap: 0;
  border-bottom: 2px solid var(--border);
  margin-bottom: 24px;
  /* Fichas como la del mercado tienen nueve pestañas o más. Sin esto la
     barra crece hasta empujar la página entera en horizontal. Que scrollee
     ella y no el documento. */
  max-width: 100%;

  /* Se parte en varias filas en vez de scrollear.
     La ficha del mercado tiene trece pestañas, que necesitan unos 1.500px;
     `.page` da como mucho 1.336 (max-width 1400 menos el relleno). No caben,
     y no van a caber: cada pestaña nueva empeora el problema.

     Antes esto scrolleaba en horizontal, y estaba mal por dos motivos. Uno,
     un índice de navegación que esconde la mitad de sus opciones obliga a
     descubrirlas; nadie busca lo que no sabe que existe. Y dos, la barra se
     cortaba dejando margen blanco a la derecha —el de la página, no el de la
     barra—, así que parecía un fallo de maquetación aunque funcionara.

     Partiendo en filas se ven las trece de golpe y sobra el scroll. */
  flex-wrap: wrap;
  row-gap: 2px;
}
/* La barra no debe encoger las pestañas hasta partir sus palabras. */
.tabs > * { flex: 0 0 auto; }
.tabs__tab {
  padding: 10px 20px;
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--text-muted);
  cursor: pointer;
  border-bottom: 2px solid transparent;
  margin-bottom: -2px;
  text-decoration: none;
  transition: color var(--transition), border-color var(--transition);
  white-space: nowrap;
}
.tabs__tab:hover { color: var(--text); text-decoration: none; }
.tabs__tab.is-active { color: var(--navy); border-bottom-color: var(--navy); }

/* ── Utilidades ───────────────────────────────────────────────────────────── */
.d-flex { display: flex; }
.align-center { align-items: center; }
.justify-between { justify-content: space-between; }
.gap-8  { gap: 8px; }
.gap-12 { gap: 12px; }
.gap-16 { gap: 16px; }
.gap-24 { gap: 24px; }
.mt-8   { margin-top: 8px; }
.mt-16  { margin-top: 16px; }
.mt-24  { margin-top: 24px; }
.mb-8   { margin-bottom: 8px; }
.mb-16  { margin-bottom: 16px; }
.mb-24  { margin-bottom: 24px; }
.text-muted  { color: var(--text-muted); }
.text-navy   { color: var(--navy); }
.text-right  { text-align: right; }
.text-center { text-align: center; }
.font-bold   { font-weight: 700; }
.font-mono   { font-family: 'Courier New', monospace; }
.w-full  { width: 100%; }
.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; }

/* ── Accesibilidad ───────────────────────────────────────────────────────── */

/* Skip link (visible solo al recibir foco con teclado) */
.skip-link {
  position: absolute;
  top: -200%;
  left: 12px;
  z-index: 10000;
  background: var(--navy);
  color: var(--on-navy, #fff);
  padding: 10px 20px;
  border-radius: 0 0 var(--radius) var(--radius);
  font-size: .875rem;
  font-weight: 700;
  text-decoration: none;
  box-shadow: 0 4px 12px rgba(0,0,0,.3);
  transition: top .15s ease;
}
.skip-link:focus { top: 0; }

/* Suprimir el outline de ratón (no de teclado) */
:focus:not(:focus-visible) { outline: none; }

/* Anillo de foco para navegación por teclado — WCAG 2.1 SC 2.4.7 */
:focus-visible {
  outline: 3px solid var(--navy);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

/* Form controls: conservar borde de color + anillo de foco */
.form-control:focus-visible {
  outline: 3px solid var(--navy);
  outline-offset: -2px;
}

/* Botones: offset ligeramente mayor para legibilidad */
.btn:focus-visible { outline-offset: 3px; }

/* Sidebar: anillo sobre fondo oscuro */
.sidebar__link:focus-visible,
.sidebar__logo:focus-visible {
  outline: 2px solid rgba(255,255,255,.85);
  outline-offset: -2px;
  border-radius: 2px;
}

/* Paginación y tabs */
.pagination a:focus-visible,
.tabs__tab:focus-visible { outline-offset: -2px; }

/* Modal: close button */
.modal-close:focus-visible { outline-offset: 3px; }

/* ── Overlay de carga ─────────────────────────────────────────────────────── */
.spinner {
  width: 24px; height: 24px;
  border: 3px solid var(--border);
  border-top-color: var(--navy);
  border-radius: 50%;
  animation: spin .7s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

.loading-overlay {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(255,255,255,.7);
  z-index: 300;
  align-items: center;
  justify-content: center;
}
.loading-overlay.is-visible { display: flex; }

/* ── Responsive ──────────────────────────────────────────────────────────── */
@media (max-width: 768px) {
  .sidebar {
    transform: translateX(-100%);
    /* `transform` saca el menú de la pantalla pero NO del orden de tabulación:
       los 40+ enlaces del panel seguían siendo enfocables fuera del viewport, y
       con teclado había que atravesarlos a ciegas antes de llegar al contenido
       (2.4.3 / 2.4.7). `visibility:hidden` sí los saca. El JS del layout añade
       además `inert`, que es lo que lo esconde también del lector de pantalla;
       esto es el cinturón por si el JS no llega a ejecutarse. */
    visibility: hidden;
    transition: transform var(--transition), visibility var(--transition);
  }
  .sidebar.is-open {
    transform: translateX(0);
    visibility: visible;
  }
  .main {
    margin-left: 0;
  }
  .hamburger { display: block; }
  .page { padding: 20px 16px; }
  .topbar { padding: 0 16px; }
  .form-row { grid-template-columns: 1fr; }
  .form-row.cols-3, .form-row.cols-4 { grid-template-columns: 1fr; }
  .kpi-grid { grid-template-columns: 1fr 1fr; }
  .page-header { flex-direction: column; align-items: flex-start; }
  /* El `flex-wrap: wrap` de `.page-header > div:last-child` (línea 225) no
     llega a los flex ANIDADOS dentro de ese bloque: /admin/mercados monta el
     selector + botón de "Encolar retraducción" en un
     `<form style="display:inline-flex;gap:6px">` propio, que en 375px de
     ancho no cabe y se corta por el borde de la pantalla (medido el
     20/09/2026 en /admin/mercados). Con 105 apariciones de flex en línea
     repartidas en 63 plantillas, es más seguro envolver cualquier flex
     anidado dentro de la cabecera que perseguirlas una a una. */
  .page-header [style*="flex"] { flex-wrap: wrap; }
}

@media (max-width: 480px) {
  .kpi-grid { grid-template-columns: 1fr; }
  h1 { font-size: 1.375rem; }
}

/* ── Aliases de componentes (templates usan nomenclatura BEM --) ─────────── */

/* Tarjetas de estadísticas */
.stats-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 16px; margin-bottom: 24px; }
.stat-card  { background: var(--bg); border: 1px solid var(--border); border-radius: var(--radius); padding: 20px; }
.stat-card__value { font-size: 2rem; font-weight: 800; line-height: 1; color: var(--navy); margin-bottom: 4px; }
.stat-card__label { font-size: 0.75rem; font-weight: 700; text-transform: uppercase; letter-spacing: .5px; color: var(--text-muted); margin-bottom: 6px; }
.stat-card__sub   { font-size: 0.75rem; color: var(--text-muted); }

/* Subcomponentes de card */
.card__header { display: flex; align-items: center; justify-content: space-between; gap: 16px; padding: 16px 20px; border-bottom: 1px solid var(--border); }
.card__body   { padding: 20px; }
.card__title  { font-size: 1rem; font-weight: 700; margin: 0; }
.card.mb-4, .card { margin-bottom: 0; }

/* Cuadrícula de detalles clave-valor */
.detail-grid  { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 12px 24px; }
.detail-item  { display: flex; flex-direction: column; gap: 2px; }
.detail-label { font-size: 0.72rem; font-weight: 700; text-transform: uppercase; letter-spacing: .4px; color: var(--text-muted); }
.detail-value { font-size: 0.9rem; color: var(--text); }

/* Tabs con nomenclatura .tab / .tab--active */
.tab { display: inline-block; padding: 10px 20px; font-size: 0.875rem; font-weight: 600; color: var(--text-muted); cursor: pointer; border-bottom: 2px solid transparent; margin-bottom: -2px; text-decoration: none; transition: color var(--transition), border-color var(--transition); white-space: nowrap; }
.tab:hover     { color: var(--text); text-decoration: none; }
.tab--active   { color: var(--navy); border-bottom-color: var(--navy); }

/* Badges con doble guión */
.badge--success  { background: var(--success-bg); color: var(--success); }
.badge--danger   { background: var(--error-bg);   color: var(--error); }
.badge--warning  { background: var(--warning-bg); color: var(--warning); }
.badge--info     { background: var(--info-bg);    color: var(--info); }
.badge--primary  { background: var(--navy);       color: var(--on-navy, #fff); }
.badge--secondary{ background: var(--bg-alt);     color: var(--text-muted); border: 1px solid var(--border); }

/* Botones con doble guión */
.btn--primary   { background: var(--navy); border-color: var(--navy); color: var(--on-navy, #fff); }
.btn--primary:hover { background: var(--navy-dark); border-color: var(--navy-dark); color: var(--on-navy, #fff); text-decoration: none; }
.btn--secondary { background: var(--bg); border-color: var(--border); color: var(--text); }
.btn--secondary:hover { background: var(--navy); color: var(--on-navy, #fff); text-decoration: none; }
.btn--danger    { background: #7b0000; border-color: #7b0000; color: #fff; }
.btn--danger:hover   { background: #6b0000; border-color: #6b0000; color: #fff; text-decoration: none; }
.btn--ghost     { background: transparent; border-color: transparent; color: var(--navy); }
.btn--ghost:hover    { background: var(--bg-alt); color: var(--text); text-decoration: none; }
.btn--xs  { padding: 3px 10px; font-size: 0.75rem; }
.btn--sm  { padding: 5px 12px; font-size: 0.8125rem; }
.btn--lg  { padding: 13px 28px; font-size: 1rem; }

/* Layout de formulario con sidebar */
.form-page     { display: contents; }
.form-grid     { display: grid; grid-template-columns: 1fr 300px; gap: 24px; align-items: start; }
.form-main     { display: flex; flex-direction: column; gap: 24px; }
.form-sidebar  { display: flex; flex-direction: column; gap: 24px; }
.form-group--lg { grid-column: 1 / -1; }

/* Espaciado rem-based */
.mb-1 { margin-bottom: 0.25rem; } .mb-2 { margin-bottom: 0.5rem; }
.mb-3 { margin-bottom: 0.75rem; } .mb-4 { margin-bottom: 1rem; }
.mb-5 { margin-bottom: 1.25rem; } .mb-6 { margin-bottom: 1.5rem; }
.mt-1 { margin-top: 0.25rem; }   .mt-2 { margin-top: 0.5rem; }
.mt-3 { margin-top: 0.75rem; }   .mt-4 { margin-top: 1rem; }
.py-2 { padding-top: 0.5rem; padding-bottom: 0.5rem; }
.py-4 { padding-top: 1rem;   padding-bottom: 1rem; }
.py-6 { padding-top: 1.5rem; padding-bottom: 1.5rem; }
.px-4 { padding-left: 1rem;  padding-right: 1rem; }
.p-0  { padding: 0 !important; }

/* Títulos y acciones de página */
.page-title   { font-size: 1.5rem; font-weight: 800; margin: 0; display: flex; align-items: center; gap: .75rem; }
.page-actions { display: flex; gap: 8px; align-items: center; }

/* ── Paradistas: Estilos de acciones compactas ────────────────────────────── */
.action-btn-view,
.action-btn-edit {
  transition: all 150ms cubic-bezier(0.4, 0, 0.2, 1);
}
.action-btn-view:hover {
  background: #0369a1 !important;
  color: #fff !important;
  border-color: #0369a1 !important;
  transform: translateY(-1px);
  box-shadow: 0 2px 6px rgba(3, 105, 161, 0.2);
}
.action-btn-edit:hover {
  background: #92400e !important;
  color: #fff !important;
  border-color: #92400e !important;
  transform: translateY(-1px);
  box-shadow: 0 2px 6px rgba(146, 64, 14, 0.2);
}

/* ── Botones inline con iconos mejorados ─────────────────────────────────── */
.btn svg {
  transition: transform 150ms ease, opacity 150ms ease;
}
.btn:hover svg {
  transform: scale(1.1);
}

/* ── Tabla compacta con hover ─────────────────────────────────────────────── */
.table tbody tr {
  transition: background-color 150ms ease, box-shadow 150ms ease;
}
.table tbody tr:hover {
  background: #f9fafb;
  box-shadow: inset 0 0 0 1px #f0f4f8;
}

/* ── Filtros en línea ────────────────────────────────────────────────────── */
.form-control:focus {
  border-color: var(--navy);
  box-shadow: 0 0 0 3px rgba(0, 58, 112, 0.08);
}

/* ── Badges con mayor presencia visual ────────────────────────────────────── */
.badge-success,
.badge-warning,
.badge-danger,
.badge-info,
.badge-muted {
  transition: background-color 150ms ease, box-shadow 150ms ease;
}
/* Antes esto redefinía `.badge-success` con `background:#dbeafe;color:#0369a1`
   —azul, literal, sin usar var(--success)— más abajo en el MISMO fichero que
   la define en verde arriba (línea 550). Misma especificidad, gana la última:
   TODO "badge-success" del sitio —admin y portal— salía azul. No era un
   despiste de una plantilla suelta, era este bloque. Se mantiene el borde y
   el tamaño que añadía esta segunda pasada, pero con las variables de color
   correctas en vez de un valor fijo que contradice al de arriba. */
.badge-success {
  border: 1px solid var(--success);
  font-weight: 600;
  font-size: 0.7rem;
}
.badge-warning {
  border: 1px solid var(--warning);
  font-weight: 600;
  font-size: 0.7rem;
}
.badge-danger {
  border: 1px solid var(--error);
  font-weight: 600;
  font-size: 0.7rem;
}

@media (max-width: 768px) {
  .form-grid  { grid-template-columns: 1fr; }
  .stats-grid { grid-template-columns: 1fr 1fr; }
  .detail-grid { grid-template-columns: 1fr; }
  .page-actions { flex-direction: column; width: 100%; }
  .page-actions .btn { width: 100%; }
}
@media (max-width: 480px) {
  .stats-grid { grid-template-columns: 1fr; }
  .table { font-size: 0.8rem; }
  .table th, .table td { padding: 6px 8px; }
}

/* ── Suelo móvil por ancho de viewport ────────────────────────────────────
   El bloque grande de `body.is-mobile-app` vive en el layout y sólo se
   enciende cuando el servidor reconoce el User-Agent como móvil REAL. Se
   quedan fuera el iPad, el Android en «versión para ordenador», los
   navegadores embebidos (Instagram, Gmail), una ventana partida en el
   escritorio y —esto es lo importante— las pantallas de /login, /portal y
   /pago, que cargan esta hoja pero NO el layout del panel.

   Esto es el suelo para todos ésos. Mide por ancho de viewport, que es lo
   que de verdad determina si algo cabe, en vez de por quién dice ser el
   navegador. */
@media (max-width: 768px) {

  /* iOS Safari amplía la página al enfocar un campo de menos de 16px, y al
     desenfocar NO la devuelve: el usuario se queda con la pantalla corrida y
     tiene que pellizcar para recolocarla. `.form-control` declara
     0.9375rem — medido en /login: 15px reales en los dos campos. 1rem es el
     umbral exacto por debajo del cual Safari hace zoom. */
  .form-control,
  .search-bar input,
  input[type="text"], input[type="email"], input[type="number"],
  input[type="tel"],  input[type="url"],   input[type="search"],
  input[type="password"], input[type="date"], input[type="time"],
  input[type="datetime-local"], input[type="month"],
  select, textarea {
    font-size: 1rem;
  }

  /* Objetivo de pulsación (WCAG 2.5.5 / 2.5.8). Medido en /login: el botón
     primario «Iniciar sesión» daba 34px de alto, y los enlaces del pie 19px.
     `min-height` no rompe la maqueta porque .btn ya es inline-flex centrado. */
  .btn { min-height: 44px; }
  .btn-sm, .btn--sm, .btn--xs { min-height: 40px; }
  .pagination a, .pagination span { width: 44px; height: 44px; }
  .modal-close { min-width: 44px; min-height: 44px; }

  /* El buscador topaba en 360px y dejaba un hueco muerto a la derecha en
     cuanto la pantalla era algo mayor. */
  .search-bar { max-width: none; }

  /* Modales. Tres cosas: los 20px de relleno del overlay a cada lado se
     comen el 11% de un móvil; centrado en vertical, un modal alto se corta
     por arriba en vez de por abajo; y el pie alineado a la derecha empuja el
     botón secundario fuera de pantalla cuando hay dos y las etiquetas son
     largas (alemán, catalán). */
  .modal-overlay { padding: 12px; align-items: flex-start; }
  .modal         { max-height: calc(100vh - 24px); }
  .modal-header,
  .modal-footer  { padding-left: 16px; padding-right: 16px; }
  .modal-body    { padding: 16px; }
  .modal-footer  { flex-wrap: wrap; }
  .modal-footer .btn { flex: 1 1 auto; justify-content: center; }
}

/* ── Rejillas de columnas fijas escritas en el atributo `style` ───────────
   El panel monta unas 80 rejillas con `style="display:grid;
   grid-template-columns:…"` sobre <div> sin clase: `1fr 1fr` (48 veces),
   `repeat(4,1fr)`, `repeat(3,1fr)`, `1fr 340px` (el dashboard)… No las
   alcanza ninguna clase, así que ninguna media query las tocaba y llegaban
   al móvil con todas sus columnas. Se las alcanza por el propio atributo.

   Las de `repeat(auto-fit|auto-fill, minmax(Npx,1fr))` NO entran aquí a
   propósito: ésas ya colapsan solas, que es justo para lo que existe
   auto-fit. Sólo se corrigen las que declaran un suelo que no cabe.

   El escalón está en dos tramos porque no todas rompen a la vez: tres
   columnas o más, y las de barra lateral en píxeles, ya no valen por debajo
   de 600px; dos columnas aguantan hasta 480 (unos 150px por columna). */
@media (max-width: 600px) {
  [style*="repeat(3,"], [style*="repeat(3, "],
  [style*="repeat(4,"], [style*="repeat(4, "],
  [style*="repeat(5,"], [style*="repeat(5, "],
  [style*="repeat(6,"], [style*="repeat(6, "],
  [style*="1fr 1fr 1fr"],
  [style*="1fr 300px"], [style*="1fr 320px"], [style*="1fr 340px"],
  [style*="300px 1fr"], [style*="320px 1fr"], [style*="340px 1fr"],
  [style*="180px 1fr"], [style*="160px 1fr"], [style*="130px 1fr"] {
    grid-template-columns: 1fr !important;
  }
}
@media (max-width: 480px) {
  [style*="1fr 1fr"],
  [style*="2fr 1fr"],
  [style*="1fr 2fr"],
  [style*="repeat(2,"], [style*="repeat(2, "],
  /* Un suelo de minmax es un mínimo duro: la columna no baja de ahí y
     desborda. En 375px el ancho útil dentro de una card son ~315px, así que
     cualquier suelo de 320 para arriba se sale. */
  [style*="minmax(320px"], [style*="minmax(340px"],
  [style*="minmax(360px"], [style*="minmax(380px"],
  [style*="minmax(400px"] {
    grid-template-columns: 1fr !important;
  }
}
