﻿/* ============================================================================
   COMPONENTES — Elecciones SEN
   Ver docs/09-sistema-diseno.md §5

   Nomenclatura BEM en español: .bloque, .bloque__elemento, .bloque--variante
   ========================================================================== */

/* ============================================================================
   BOTONES
   Altura mínima 44px: objetivo táctil accesible en móvil.
   ========================================================================== */

.boton {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--e-2);
  min-height: 2.75rem;
  padding: var(--e-3) var(--e-5);
  border: 1px solid transparent;
  border-radius: var(--radio-md);
  font-size: var(--texto-sm);
  font-weight: var(--peso-semi);
  line-height: 1.2;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  transition: background-color var(--transicion-rapida),
              border-color var(--transicion-rapida),
              color var(--transicion-rapida),
              box-shadow var(--transicion-rapida),
              transform var(--transicion-rapida);
}

.boton:active:not(:disabled) { transform: translateY(1px); }

.boton:disabled,
.boton[aria-disabled="true"] {
  opacity: 0.55;
  cursor: not-allowed;
  transform: none;
}

.boton--primario {
  background-color: var(--primario);
  color: var(--sobre-primario);
  box-shadow: var(--sombra-sm);
}

.boton--primario:hover:not(:disabled) {
  background-color: var(--primario-hover);
  color: var(--sobre-primario);
}

.boton--secundario {
  background-color: var(--fondo-elevado);
  border-color: var(--borde-fuerte);
  color: var(--texto);
  box-shadow: var(--sombra-sm);
}

.boton--secundario:hover:not(:disabled) {
  background-color: var(--fondo-sutil);
  color: var(--texto);
}

.boton--fantasma {
  background-color: transparent;
  color: var(--texto-suave);
}

.boton--fantasma:hover:not(:disabled) {
  background-color: var(--fondo-sutil);
  color: var(--texto);
}

/* Acciones destructivas o irreversibles. */
.boton--peligro {
  background-color: var(--error-fuerte);
  color: #fff;
  box-shadow: var(--sombra-sm);
}

.boton--peligro:hover:not(:disabled) {
  background-color: var(--error-texto);
  color: #fff;
}

.boton--sm {
  min-height: 2.25rem;
  padding: var(--e-2) var(--e-3);
  font-size: var(--texto-xs);
}

.boton--lg {
  min-height: 3.25rem;
  padding: var(--e-4) var(--e-8);
  font-size: var(--texto-base);
}

/* En móvil, el botón principal de un formulario ocupa todo el ancho. */
.boton--bloque { width: 100%; }

@media (max-width: 639px) {
  .boton--bloque-movil { width: 100%; }
}

/* Estado de espera: se activa con aria-busy, no con una clase, para que
   los lectores de pantalla también lo anuncien. */
.boton[aria-busy="true"] {
  pointer-events: none;
  opacity: 0.7;
}

/* ============================================================================
   CAMPOS DE FORMULARIO
   ========================================================================== */

.campo {
  display: grid;
  gap: var(--e-2);
}

.campo__etiqueta {
  font-size: var(--texto-sm);
  font-weight: var(--peso-medio);
  color: var(--texto);
}

.campo__obligatorio {
  color: var(--error-texto);
  margin-left: 0.15em;
}

.campo__control {
  width: 100%;
  min-height: 2.75rem;
  padding: var(--e-3) var(--e-4);
  background-color: var(--fondo-elevado);
  border: 1px solid var(--borde-fuerte);
  border-radius: var(--radio-md);
  color: var(--texto);
  transition: border-color var(--transicion-rapida),
              box-shadow var(--transicion-rapida);
}

.campo__control::placeholder { color: var(--texto-tenue); }

.campo__control:hover:not(:disabled) { border-color: var(--n-400); }

.campo__control:focus {
  outline: none;
  border-color: var(--primario);
  box-shadow: var(--sombra-foco);
}

.campo__control:disabled {
  background-color: var(--fondo-sutil);
  color: var(--texto-tenue);
  cursor: not-allowed;
}

.campo__control[aria-invalid="true"] {
  border-color: var(--error-fuerte);
}

.campo__control[aria-invalid="true"]:focus {
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--error-fuerte) 30%, transparent);
}

textarea.campo__control {
  min-height: 8rem;
  resize: vertical;
  line-height: var(--interlineado);
}

select.campo__control {
  appearance: none;
  padding-right: var(--e-10);
  /* Flecha dibujada con un degradado cónico para no depender de una imagen
     externa (la CSP bloquea recursos de otros orígenes). */
  background-image:
    linear-gradient(45deg, transparent 50%, currentColor 50%),
    linear-gradient(135deg, currentColor 50%, transparent 50%);
  background-position:
    calc(100% - 1.25rem) center,
    calc(100% - 0.85rem) center;
  background-size: 0.4rem 0.4rem, 0.4rem 0.4rem;
  background-repeat: no-repeat;
}

.campo__ayuda {
  font-size: var(--texto-sm);
  color: var(--texto-suave);
}

.campo__error {
  display: flex;
  align-items: flex-start;
  gap: var(--e-2);
  font-size: var(--texto-sm);
  font-weight: var(--peso-medio);
  color: var(--error-texto);
}

/* Formularios: una columna en móvil, dos donde tenga sentido a partir de 640px. */
.formulario {
  display: grid;
  gap: var(--e-5);
}

@media (min-width: 640px) {
  .formulario--dos-columnas {
    grid-template-columns: 1fr 1fr;
  }

  .formulario__ancho-completo { grid-column: 1 / -1; }
}

.formulario__acciones {
  display: flex;
  flex-wrap: wrap;
  gap: var(--e-3);
  padding-top: var(--e-2);
}

@media (max-width: 639px) {
  /* En móvil las acciones se apilan y la principal queda arriba. */
  .formulario__acciones { flex-direction: column-reverse; }
  .formulario__acciones .boton { width: 100%; }
}

/* Casilla de verificación con etiqueta pulsable. */
.casilla {
  display: flex;
  align-items: flex-start;
  gap: var(--e-3);
  cursor: pointer;
  padding: var(--e-2) 0;
}

.casilla__control {
  flex-shrink: 0;
  width: 1.25rem;
  height: 1.25rem;
  margin-top: 0.15rem;
  accent-color: var(--primario);
  cursor: pointer;
}

/* ============================================================================
   TARJETAS
   ========================================================================== */

.tarjeta {
  background-color: var(--fondo-elevado);
  border: 1px solid var(--borde);
  border-radius: var(--radio-lg);
  box-shadow: var(--sombra-sm);
  overflow: hidden;
}

.tarjeta__cabecera {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--e-4);
  flex-wrap: wrap;
  padding: var(--e-5) var(--e-6);
  border-bottom: 1px solid var(--borde);
  background-color: var(--fondo-elevado);
}

.tarjeta__titulo {
  font-size: var(--texto-lg);
  font-weight: var(--peso-semi);
  margin: 0;
}

.tarjeta__descripcion {
  font-size: var(--texto-sm);
  color: var(--texto-suave);
  margin-top: var(--e-1);
}

.tarjeta__cuerpo { padding: var(--e-6); }

.tarjeta__pie {
  padding: var(--e-4) var(--e-6);
  border-top: 1px solid var(--borde);
  background-color: var(--fondo-sutil);
}

@media (max-width: 639px) {
  .tarjeta__cabecera,
  .tarjeta__cuerpo { padding: var(--e-4); }
  .tarjeta__pie    { padding: var(--e-3) var(--e-4); }
}

/* ============================================================================
   ALERTAS
   ========================================================================== */

.alerta {
  display: flex;
  align-items: flex-start;
  gap: var(--e-3);
  padding: var(--e-4) var(--e-5);
  border: 1px solid;
  border-radius: var(--radio-md);
  font-size: var(--texto-sm);
}

.alerta__icono {
  flex-shrink: 0;
  width: 1.25rem;
  height: 1.25rem;
  margin-top: 0.1rem;
}

.alerta__titulo {
  font-weight: var(--peso-semi);
  margin-bottom: var(--e-1);
}

.alerta__contenido > * + * { margin-top: var(--e-2); }

.alerta--exito { background-color: var(--exito-fondo); border-color: var(--exito-borde); color: var(--exito-texto); }
.alerta--error { background-color: var(--error-fondo); border-color: var(--error-borde); color: var(--error-texto); }
.alerta--aviso { background-color: var(--aviso-fondo); border-color: var(--aviso-borde); color: var(--aviso-texto); }
.alerta--info  { background-color: var(--info-fondo);  border-color: var(--info-borde);  color: var(--info-texto); }

/* ----------------------------------------------------------------------------
   RESUMEN DE VALIDACIÓN VACÍO

   El tag helper asp-validation-summary pinta SIEMPRE su contenedor, haya
   errores o no, y le añade la clase validation-summary-valid cuando no los hay.
   Como las clases de estilo del contenedor son fijas, sin esta regla el
   recuadro rojo aparece nada más entrar en la pantalla, vacío.

   Se detectó el 18/08/2026 al hacer las capturas de los manuales: la papeleta
   salía con un aviso rojo sin texto. Afectaba a las ocho pantallas con
   formulario, incluidas las tres del recorrido de voto y la de establecer
   contraseña. Un error rojo sin mensaje en la pantalla de votar hace dudar de
   si el voto se ha emitido bien.

   No se usa display:none sobre el contenido, sino sobre el bloque entero,
   porque el borde y el fondo son lo que se ve.
   -------------------------------------------------------------------------- */

.alerta.validation-summary-valid { display: none; }

/* La lista del resumen no lleva viñetas fuera del recuadro. */
.alerta .validation-summary-errors ul { margin: 0; padding-left: 1.25rem; }

/* ============================================================================
   ETIQUETAS DE ESTADO
   La información no se transmite solo por color: cada estado lleva texto.
   ========================================================================== */

.estado {
  display: inline-flex;
  align-items: center;
  gap: var(--e-2);
  padding: 0.2rem var(--e-3);
  border: 1px solid;
  border-radius: var(--radio-full);
  font-size: var(--texto-xs);
  font-weight: var(--peso-medio);
  white-space: nowrap;
}

.estado::before {
  content: "";
  width: 0.4rem;
  height: 0.4rem;
  border-radius: 50%;
  background-color: currentColor;
  flex-shrink: 0;
}

.estado--neutro   { background-color: var(--fondo-sutil);  border-color: var(--borde-fuerte); color: var(--texto-suave); }
.estado--exito    { background-color: var(--exito-fondo);  border-color: var(--exito-borde);  color: var(--exito-texto); }
.estado--error    { background-color: var(--error-fondo);  border-color: var(--error-borde);  color: var(--error-texto); }
.estado--aviso    { background-color: var(--aviso-fondo);  border-color: var(--aviso-borde);  color: var(--aviso-texto); }
.estado--info     { background-color: var(--info-fondo);   border-color: var(--info-borde);   color: var(--info-texto); }
.estado--primario { background-color: var(--primario-suave); border-color: var(--primario-borde); color: var(--primario); }

/* ============================================================================
   TABLAS
   Por debajo de 768px cada fila se convierte en una tarjeta y cada celda
   muestra su encabezado mediante el atributo data-etiqueta. Es la solución
   accesible para los listados largos de censo y participación.
   ========================================================================== */

.tabla-contenedor {
  overflow-x: auto;
  border-radius: var(--radio-lg);
  -webkit-overflow-scrolling: touch;
}

.tabla {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--texto-sm);
}

.tabla th,
.tabla td {
  padding: var(--e-3) var(--e-4);
  text-align: left;
  border-bottom: 1px solid var(--borde);
}

.tabla thead th {
  background-color: var(--fondo-sutil);
  font-weight: var(--peso-semi);
  font-size: var(--texto-xs);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--texto-suave);
  white-space: nowrap;
  position: sticky;
  top: 0;
  z-index: 1;
}

.tabla tbody tr:hover { background-color: var(--fondo-sutil); }

.tabla tbody tr:last-child td { border-bottom: 0; }

.tabla__numero {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

.tabla__acciones {
  display: flex;
  gap: var(--e-2);
  justify-content: flex-end;
}

@media (max-width: 767px) {
  .tabla--apilable thead {
    /* Se oculta visualmente pero permanece para los lectores de pantalla. */
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
  }

  .tabla--apilable tbody tr {
    display: block;
    margin-bottom: var(--e-3);
    background-color: var(--fondo-elevado);
    border: 1px solid var(--borde);
    border-radius: var(--radio-md);
    padding: var(--e-2);
  }

  .tabla--apilable tbody td {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: var(--e-4);
    padding: var(--e-2) var(--e-3);
    border-bottom: 1px solid var(--borde);
    text-align: right;
  }

  .tabla--apilable tbody td:last-child { border-bottom: 0; }

  .tabla--apilable tbody td::before {
    content: attr(data-etiqueta);
    font-size: var(--texto-xs);
    font-weight: var(--peso-semi);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--texto-suave);
    text-align: left;
    flex-shrink: 0;
  }

  .tabla--apilable .tabla__acciones { justify-content: flex-end; }
}

/* ============================================================================
   PAPELETA  ★ componente crítico
   Ver docs/09-sistema-diseno.md §6

   Tarjetas grandes pulsables en lugar de un <select>. Un desplegable en móvil,
   con nombres de candidatura largos, es una fuente real de error de voto.
   Funciona sin JavaScript: son radios dentro de un formulario.
   ========================================================================== */

.papeleta {
  display: grid;
  gap: var(--e-3);
}

.papeleta__opcion {
  position: relative;
  display: flex;
  align-items: flex-start;
  gap: var(--e-4);
  padding: var(--e-5);
  background-color: var(--fondo-elevado);
  border: 2px solid var(--borde);
  border-radius: var(--radio-lg);
  cursor: pointer;
  transition: border-color var(--transicion-rapida),
              background-color var(--transicion-rapida),
              box-shadow var(--transicion-rapida);
}

.papeleta__opcion:hover {
  border-color: var(--primario-borde);
  background-color: var(--primario-suave);
}

.papeleta__radio {
  flex-shrink: 0;
  width: 1.5rem;
  height: 1.5rem;
  margin-top: 0.1rem;
  accent-color: var(--primario);
  cursor: pointer;
}

/* Selección marcada por borde, fondo Y marca de verificación:
   nunca solo por color (WCAG 1.4.1). */
.papeleta__opcion:has(.papeleta__radio:checked) {
  border-color: var(--primario);
  background-color: var(--primario-suave);
  box-shadow: var(--sombra-md);
}

.papeleta__opcion:has(.papeleta__radio:checked)::after {
  content: "✓";
  position: absolute;
  top: var(--e-3);
  right: var(--e-4);
  font-size: var(--texto-lg);
  font-weight: var(--peso-fuerte);
  color: var(--primario);
}

.papeleta__opcion:has(.papeleta__radio:focus-visible) {
  outline: 3px solid var(--foco);
  outline-offset: 2px;
}

.papeleta__texto { display: grid; gap: var(--e-1); }

.papeleta__nombre {
  font-size: var(--texto-lg);
  font-weight: var(--peso-semi);
  color: var(--texto);
}

.papeleta__detalle {
  font-size: var(--texto-sm);
  color: var(--texto-suave);
}

/* El voto en blanco se separa visualmente de las candidaturas para que no se
   elija por descuido al recorrer la lista. */
.papeleta__separador {
  display: flex;
  align-items: center;
  gap: var(--e-4);
  margin-block: var(--e-2);
  font-size: var(--texto-xs);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--texto-tenue);
}

.papeleta__separador::before,
.papeleta__separador::after {
  content: "";
  flex: 1;
  border-top: 1px solid var(--borde);
}

/* ============================================================================
   PAGINACIÓN — enlaces reales, funciona sin JavaScript
   ========================================================================== */

.paginacion {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--e-1);
  flex-wrap: wrap;
  padding: var(--e-4) 0;
}

.paginacion__enlace {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 2.5rem;
  min-height: 2.5rem;
  padding: 0 var(--e-2);
  border: 1px solid transparent;
  border-radius: var(--radio-md);
  color: var(--texto-suave);
  font-size: var(--texto-sm);
  font-weight: var(--peso-medio);
  text-decoration: none;
  transition: background-color var(--transicion-rapida);
}

.paginacion__enlace:hover {
  background-color: var(--fondo-sutil);
  color: var(--texto);
}

.paginacion__enlace[aria-current="page"] {
  background-color: var(--primario);
  border-color: var(--primario);
  color: var(--sobre-primario);
}

/* ============================================================================
   PROGRESO — envío masivo de credenciales
   ========================================================================== */

.progreso {
  display: grid;
  gap: var(--e-2);
}

/* Se usa el <progress> nativo en lugar de dos divs con un ancho en línea:
   la CSP estricta bloquea los atributos style, y además el elemento nativo
   ya es accesible (los lectores de pantalla anuncian el porcentaje). */
.progreso__nativo {
  appearance: none;
  width: 100%;
  height: 0.625rem;
  border: 0;
  border-radius: var(--radio-full);
  background-color: var(--fondo-sutil);
  overflow: hidden;
}

.progreso__nativo::-webkit-progress-bar {
  background-color: var(--fondo-sutil);
  border-radius: var(--radio-full);
}

.progreso__nativo::-webkit-progress-value {
  background-color: var(--primario);
  border-radius: var(--radio-full);
  transition: inline-size var(--transicion-lenta);
}

.progreso__nativo::-moz-progress-bar {
  background-color: var(--primario);
  border-radius: var(--radio-full);
}

.progreso__texto {
  display: flex;
  justify-content: space-between;
  font-size: var(--texto-sm);
  color: var(--texto-suave);
  font-variant-numeric: tabular-nums;
}

/* ============================================================================
   MIGAS DE PAN
   ========================================================================== */

.migas {
  display: flex;
  align-items: center;
  gap: var(--e-2);
  flex-wrap: wrap;
  font-size: var(--texto-sm);
  color: var(--texto-tenue);
  padding-block: var(--e-2);
}

.migas__enlace { color: var(--texto-suave); text-decoration: none; }
.migas__enlace:hover { color: var(--primario); text-decoration: underline; }
.migas__separador { color: var(--borde-fuerte); }
.migas__actual { color: var(--texto); font-weight: var(--peso-medio); }

/* ============================================================================
   ESTADO VACÍO
   ========================================================================== */

.vacio {
  display: grid;
  gap: var(--e-3);
  justify-items: center;
  text-align: center;
  padding: var(--e-16) var(--e-6);
  color: var(--texto-suave);
}

.vacio__titulo {
  font-size: var(--texto-lg);
  font-weight: var(--peso-semi);
  color: var(--texto);
}

.vacio__descripcion { max-width: 36ch; }

/* ============================================================================
   MÉTRICAS — contadores de participación
   ========================================================================== */

.metrica {
  display: grid;
  gap: var(--e-1);
  padding: var(--e-5);
  background-color: var(--fondo-elevado);
  border: 1px solid var(--borde);
  border-radius: var(--radio-lg);
}

.metrica__etiqueta {
  font-size: var(--texto-sm);
  color: var(--texto-suave);
}

.metrica__valor {
  font-size: var(--texto-3xl);
  font-weight: var(--peso-fuerte);
  line-height: 1.1;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.02em;
}

.metrica__detalle {
  font-size: var(--texto-sm);
  color: var(--texto-tenue);
}

/* Métrica cuyo valor es un texto y no una cifra: el tamaño de las cifras
   grandes deja los textos largos desbordando la tarjeta. */
.metrica__valor--texto {
  font-size: var(--texto-xl);
  font-weight: var(--peso-semi);
  letter-spacing: normal;
}

/* ============================================================================
   LISTA DE DATOS  (dl/dt/dd)
   Pares etiqueta–valor de las fichas de detalle: ficha de socio, resumen de
   proceso, datos de una candidatura.

   En móvil apila etiqueta sobre valor; a partir de tablet los pone en dos
   columnas, con la etiqueta de ancho fijo para que los valores queden
   alineados aunque las etiquetas midan distinto.
   ========================================================================== */

.lista-datos {
  display: grid;
  gap: var(--e-4);
}

.lista-datos__par {
  display: grid;
  gap: var(--e-1);
  padding-bottom: var(--e-4);
  border-bottom: 1px solid var(--borde);
}

.lista-datos__par:last-child {
  padding-bottom: 0;
  border-bottom: 0;
}

.lista-datos dt {
  font-size: var(--texto-sm);
  font-weight: var(--peso-medio);
  color: var(--texto-tenue);
}

.lista-datos dd {
  margin: 0;
  color: var(--texto);
  /* Los correos largos no deben desbordar la tarjeta en móvil. */
  overflow-wrap: anywhere;
}

@media (min-width: 768px) {
  .lista-datos__par {
    grid-template-columns: 12rem 1fr;
    gap: var(--e-4);
    align-items: baseline;
  }
}

/* ============================================================================
   RECIBO DE VOTO
   Código que se muestra UNA sola vez tras votar. Hay quien lo copia a mano en un
   papel y quien lo dicta por teléfono a la Secretaría, así que prima la
   legibilidad sobre la estética: monoespaciado, grande y con mucho interletraje
   para que no se confundan caracteres parecidos.
   ========================================================================== */

.recibo {
  font-family: ui-monospace, "Cascadia Mono", "SF Mono", Menlo, Consolas, monospace;
  font-size: clamp(1.25rem, 5vw, 1.75rem);
  font-weight: var(--peso-semi);
  letter-spacing: 0.12em;
  line-height: 1.5;
  text-align: center;
  color: var(--texto);
  background-color: var(--fondo-sutil);
  border: 2px dashed var(--borde-fuerte);
  border-radius: var(--radio-lg);
  padding: var(--e-5) var(--e-3);
  margin: 0;
  /* Que se pueda seleccionar de un triple clic sin arrastrar medio párrafo. */
  user-select: all;
  overflow-wrap: anywhere;
}

/* ============================================================================
   RESULTADO DE ESCRUTINIO
   Barra por opción con <meter>, que es HTML nativo: se entiende sin CSS, lo
   anuncian los lectores de pantalla y no necesita JavaScript. La cifra va
   SIEMPRE al lado de la barra, nunca solo el color (WCAG 1.4.1).
   ========================================================================== */

.resultado + .resultado { margin-top: var(--e-4); }

.resultado__cabecera {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--e-2);
  margin-bottom: var(--e-1);
}

.resultado__nombre { font-weight: var(--peso-medio); }

.resultado__cifra {
  color: var(--texto-tenue);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.resultado__barra {
  display: block;
  width: 100%;
  height: 0.75rem;
  /* Firefox y los navegadores basados en Chromium pintan <meter> de forma
     distinta, así que se fija el fondo en ambos motores. */
  background: var(--fondo-sutil);
  border: 1px solid var(--borde);
  border-radius: var(--radio-sm);
}

.resultado__barra::-webkit-meter-bar {
  background: var(--fondo-sutil);
  border-radius: var(--radio-sm);
}

.resultado__barra::-webkit-meter-optimum-value {
  background: var(--primario);
  border-radius: var(--radio-sm);
}

.resultado__barra::-moz-meter-bar {
  background: var(--primario);
  border-radius: var(--radio-sm);
}

/* ── Controles en línea dentro de una tabla ──────────────────────────────────
   La mesa electoral trabaja sobre el listado de electores y necesita marcar,
   deshacer y escribir el motivo sin salir de la fila. Estos dos modificadores
   existen solo para eso: una fila de acciones que no rompa la altura de la
   celda, y un control de formulario que quepa a su lado. */
.fila--compacta {
  gap: var(--e-2);
  flex-wrap: wrap;
}

.campo__control--sm {
  padding: var(--e-1) var(--e-2);
  font-size: var(--texto-sm);
  min-width: 12rem;
}

/* ============================================================================
   AYUDA DESPLEGABLE

   Explicaciones que no caben en una etiqueta y que no todo el mundo necesita
   leer cada vez: qué implica cada fase de una convocatoria, por qué el documento
   no admite búsquedas parciales.

   ⚠ SE USA <details> NATIVO Y NO UN TOOLTIP. Un tooltip depende del ratón: no
   aparece con teclado, no aparece en táctil, y los lectores de pantalla lo
   anuncian de forma desigual. <details> funciona sin JavaScript, se abre con
   Intro y el navegador lo anuncia como lo que es.

   Importa más de lo habitual porque quien administra estas elecciones no es
   personal técnico, y lo que se explica aquí decide qué puede hacer el sistema o
   por qué una búsqueda no encuentra a quien se está buscando.

   Nació como «ayuda-fases», atada a una pantalla. Al hacer falta lo mismo en el
   censo se generalizó en lugar de copiarse: dos copias de un componente acaban
   divergiendo, y entonces la misma ayuda se ve distinta según dónde se abra.
   ========================================================================== */

.ayuda-desplegable {
  border: 1px solid var(--borde);
  border-radius: var(--radio-md);
  background-color: var(--fondo-elevado);
}

.ayuda-desplegable > summary {
  cursor: pointer;
  padding: var(--e-3) var(--e-4);
  font-weight: 600;
  color: var(--primario);
  list-style-position: inside;
}

.ayuda-desplegable > summary:hover {
  background-color: var(--fondo-sutil);
}

.ayuda-desplegable > summary:focus-visible {
  outline: 2px solid var(--primario);
  outline-offset: -2px;
}

.ayuda-desplegable[open] > summary {
  border-bottom: 1px solid var(--borde);
}

.ayuda-desplegable .tabla { font-size: var(--texto-sm); }

/* Contenido en prosa, para las ayudas que no son una tabla. El <details> no trae
   relleno propio, y sin esto el texto queda pegado al borde. */
.ayuda-desplegable__cuerpo {
  padding: var(--e-4);
  font-size: var(--texto-sm);
}

/* `code` ya tiene su estilo en base.css y no se repite aquí: dos definiciones
   del mismo elemento acaban discrepando y entonces un ejemplo se ve distinto
   según en qué ayuda aparezca. */
.ayuda-desplegable__cuerpo p { margin: 0; }

/* ============================================================================
   FILA DE MIEMBRO DE UNA CANDIDATURA

   Sustituye a una tabla de doce filas fijas. Se usa rejilla y no <table> porque
   las filas se añaden y se quitan, y porque en móvil cada fila tiene que poder
   apilarse — una tabla con cuatro columnas no cabe.
   ========================================================================== */

.miembro {
  display: grid;
  grid-template-columns: auto 1fr auto auto auto;
  gap: var(--e-3);
  align-items: start;
  padding: var(--e-3);
  border: 1px solid var(--borde);
  border-radius: var(--radio-md);
  background-color: var(--fondo-elevado);
  margin-bottom: var(--e-2);
}

.miembro__posicion {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 1.75rem;
  height: 1.75rem;
  margin-top: 1.9rem;            /* a la altura del control, no de la etiqueta */
  border-radius: 50%;
  background-color: var(--fondo-sutil);
  font-variant-numeric: tabular-nums;
  font-weight: 600;
}

.miembro .campo { margin: 0; }

.miembro__suplente { align-self: center; padding-top: 1.6rem; }

.miembro__quitar {
  align-self: center;
  margin-top: 1.4rem;
  font-size: 1.5rem;
  line-height: 1;
  padding: 0 var(--e-2);
}

/* En pantallas estrechas cada control ocupa su propia línea: con cinco columnas
   el buscador quedaba en dos centímetros y no se podía leer lo que se escribía. */
@media (max-width: 48rem) {
  .miembro {
    grid-template-columns: 1fr;
  }

  .miembro__posicion,
  .miembro__suplente,
  .miembro__quitar { margin-top: 0; padding-top: 0; }
}

/* ============================================================================
   PANEL DE CLAVES DE PRUEBA

   Solo aparece en desarrollo y con la casilla encendida (ver
   OpcionesClavesDePrueba). Se le da el aspecto más estridente de la aplicación
   a propósito: si algún día se ve donde no debe, tiene que saltar a la vista
   antes de que nadie lea la tabla.
   ========================================================================== */

.claves-prueba {
  border-width: 3px;
  border-style: dashed;
  margin-top: var(--e-6);
}

.claves-prueba code {
  font-size: var(--texto-sm);
  user-select: all;          /* un clic selecciona la clave entera */
}

/* ============================================================================
   DATOS EN CRUDO DE LA AUDITORÍA

   El registro guarda los detalles de cada acción como JSON, y el navegador que
   la ejecutó como una cadena larga. Los dos se muestran TAL CUAL, sin
   reformatear: ante una reclamación lo que vale es el dato literal que se
   guardó, no una versión bonita que haya que creerse.

   De ahí el <pre>: conserva los saltos de línea que traiga el propio dato. Y de
   ahí el desbordamiento con barra propia, porque un JSON largo dentro de una
   celda de tabla ensancharía la fila hasta sacar la tabla de la pantalla.
   ========================================================================== */

.datos-crudos {
  font-family: var(--fuente-mono);
  font-size: var(--texto-xs);
  background-color: var(--fondo-sutil);
  border: 1px solid var(--borde);
  border-radius: var(--radio-sm);
  padding: var(--e-2) var(--e-3);
  margin: var(--e-2) 0 0;
  max-width: 32rem;
  max-height: 12rem;
  overflow: auto;
  white-space: pre-wrap;     /* parte las líneas largas en lugar de estirarse */
  word-break: break-word;
}

/* ============================================================================
   CELDA QUE OCUPA UNA FILA ENTERA PARA DESPLEGAR ALGO

   Una fila de tabla que no muestra datos sino un <details> con acciones de la
   fila anterior: corregir o eliminar una condición de socio, por ejemplo.

   Va sin relleno propio y sin la línea inferior porque no es una fila más del
   listado: pertenece a la de arriba, y una línea entre las dos las haría
   parecer dos registros distintos.
   ========================================================================== */

.celda-plegable {
  padding: 0 !important;
  border-bottom: 1px solid var(--borde);
  background: var(--fondo-suave, #f7f8fa);
}

.celda-plegable .ayuda-desplegable {
  margin: 0;
  border-radius: 0;
  border-left: 0;
  border-right: 0;
}

/* ============================================================================
   INTERRUPTOR CON CERROJO

   Un conmutador que se arrastra de izquierda a derecha y que, en el sentido
   peligroso, no se mueve hasta que se escribe una palabra.

   POR QUÉ NO ES UNA CASILLA NORMAL: lo usa el modo de envío de correo, donde la
   pregunta no es «¿está marcado?» sino «¿a quién se le puede escribir ahora
   mismo?». Una casilla marcada no dice de qué lado está; un conmutador con las
   dos posiciones rotuladas, sí — y el gesto de empujarlo hacia la derecha
   comunica que se está abriendo algo.

   LA POSICIÓN IZQUIERDA ES LA SEGURA, y no es decoración: lo restrictivo queda
   a la izquierda, en verde, y es el estado de reposo. Moverse a la derecha es
   lo que hay que hacer a propósito.

   DEBAJO HAY UN <input type="checkbox"> DE VERDAD. Se oculta visualmente pero
   no para el lector de pantalla ni para el teclado: se marca con espacio y se
   navega con tabulador como cualquier casilla. Un div con clics encima habría
   dejado fuera a quien no usa ratón.
   ========================================================================== */

.interruptor {
  display: inline-flex;
  align-items: center;
  gap: var(--e-3);
  cursor: pointer;
}

/* La casilla real: invisible, pero presente para el teclado y el lector de
   pantalla. No se usa display:none, que la sacaría del orden de tabulación. */
.interruptor__control {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.interruptor__pista {
  position: relative;
  flex-shrink: 0;
  width: 4rem;
  height: 2rem;
  border-radius: 999px;
  /* Reposo = derecha = abierto = rojo. Ver la nota de arriba. */
  background-color: var(--error-fuerte);
  border: 1px solid var(--error-fuerte);
  transition: background-color 120ms ease-in-out, border-color 120ms ease-in-out;
}

.interruptor__mando {
  position: absolute;
  top: 0.1875rem;
  /* Sin marcar = a la derecha. */
  left: 2.1875rem;
  width: 1.5rem;
  height: 1.5rem;
  border-radius: 50%;
  background-color: #fff;
  box-shadow: var(--sombra-sm);
  transition: left 120ms ease-in-out;
}

/* Marcado = modo restrictivo = mando a la IZQUIERDA, en verde.

   ⚠ EL COMBINADOR ES «~» Y NO «+», Y NO ES INDIFERENTE. Entre la casilla y la
   pista hay un <input type="hidden"> —el que permite enviar «desmarcado»— así
   que no son hermanos ADYACENTES. Con «+» estas reglas no casaban nunca: el
   interruptor se pintaba rojo y a la derecha estando en modo pruebas, es decir,
   enseñando exactamente lo contrario de lo que pasaba. En un control cuyo único
   trabajo es decir a quién se le puede escribir, eso es peor que no tenerlo. */
.interruptor__control:checked ~ .interruptor__pista {
  background-color: var(--exito-fuerte);
  border-color: var(--exito-fuerte);
}

.interruptor__control:checked ~ .interruptor__pista .interruptor__mando {
  left: 0.1875rem;
}

.interruptor__control:focus-visible ~ .interruptor__pista {
  outline: 3px solid var(--foco);
  outline-offset: 2px;
}

/* ⚠ EL CERROJO ES SOLO VISUAL. Lo pone el JavaScript mientras falte la palabra
   de confirmación, y su única función es avisar antes de intentarlo. Quien
   tenga el JavaScript desactivado mueve el interruptor sin problema: quien lo
   rechaza de verdad es el servidor, que exige la palabra igualmente. */
.interruptor--cerrado .interruptor__pista {
  opacity: 0.55;
}

.interruptor--cerrado {
  cursor: not-allowed;
}

.interruptor__textos {
  display: flex;
  flex-direction: column;
  gap: 0.125rem;
}

.interruptor__estado {
  font-weight: 600;
}

.interruptor__detalle {
  font-size: 0.875rem;
  color: var(--texto-tenue);
}

@media (prefers-reduced-motion: reduce) {
  /* Quien ha pedido que no se mueva nada sigue viendo el cambio de color y de
     posición; lo que desaparece es la animación entre los dos estados. */
  .interruptor__pista,
  .interruptor__mando { transition: none; }
}

/* ── Lista de etiquetas ──────────────────────────────────────────────────────
   Una tira de distintivos que fluye a varias líneas. La usa el desglose por tipo
   de la cola de correo: «3 · Credenciales de acceso», «2 · Recuperación».

   Es una <ul> de verdad y no un montón de <span> sueltos porque eso es lo que
   es —una lista de cosas contadas— y el lector de pantalla anuncia cuántas hay
   antes de leerlas, que es justo el dato que se está mirando. Los marcadores se
   quitan a la vista, no a la semántica. */
.lista-etiquetas {
  display: flex;
  flex-wrap: wrap;
  gap: var(--e-2);
  margin: 0;
  padding: 0;
  list-style: none;
}

/* ── Cuerpo de un correo archivado ───────────────────────────────────────────
   El texto de un mensaje tal como quedó guardado, para leerlo entero.

   NO REUTILIZA .datos-crudos, que está acotado a 32rem de ancho y 12rem de alto
   a propósito: aquello son volcados técnicos de dos líneas dentro de una fila de
   la auditoría. Un correo de credenciales ocupa una pantalla, y meterlo en una
   ventanita de doce líneas obliga a leerlo a trozos justo cuando se está
   comprobando si el texto que le llegó al socio era el correcto.

   Se respetan los saltos de línea del original y se parten las palabras largas:
   una URL de enlace de acceso —aunque salga tachada— desbordaría la tarjeta y
   arrastraría toda la página a lo ancho. */
.cuerpo-correo {
  font-family: var(--fuente-mono);
  font-size: var(--texto-sm);
  line-height: 1.6;
  background-color: var(--fondo-sutil);
  border: 1px solid var(--borde);
  border-radius: var(--radio-sm);
  padding: var(--e-3);
  margin: 0;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

/* ── Editor del programa electoral ────────────────────────────────────────
   Barra de botones + lienzo editable + vista de código.

   El lienzo lleva también la clase .contenido, la misma con la que el programa
   se pinta al elector: así lo que se ve al escribir es lo que se verá después.
   ─────────────────────────────────────────────────────────────────────── */

.editor {
  border: 1px solid var(--borde-fuerte);
  border-radius: var(--radio-md);
  background: var(--fondo-elevado);
  overflow: hidden;
}

.editor:focus-within {
  border-color: var(--foco);
  box-shadow: 0 0 0 3px var(--primario-suave);
}

.editor__barra {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--e-1);
  padding: var(--e-2);
  background: var(--fondo-sutil);
  border-bottom: 1px solid var(--borde);
}

.editor__boton {
  min-width: 2.25rem;
  min-height: 2.25rem;
  padding: 0 var(--e-2);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--fondo-elevado);
  border: 1px solid var(--borde);
  border-radius: var(--radio-sm);
  color: var(--texto);
  font-family: var(--fuente);
  font-size: var(--texto-sm);
  line-height: 1;
  cursor: pointer;
}

.editor__boton:hover { background: var(--primario-suave); border-color: var(--primario-borde); }
.editor__boton:active { background: var(--primario-borde); }
.editor__boton:focus-visible { outline: 2px solid var(--foco); outline-offset: 1px; }

.editor__boton--ancho { padding: 0 var(--e-3); }
.editor__boton--derecha { margin-left: auto; }

.editor__boton--activo {
  background: var(--primario);
  border-color: var(--primario);
  color: var(--sobre-primario);
}
.editor__boton--activo:hover { background: var(--primario-hover); }

.editor__separador {
  width: 1px;
  align-self: stretch;
  margin: 0 var(--e-1);
  background: var(--borde-fuerte);
}

.editor__lienzo {
  min-height: 18rem;
  max-height: 32rem;
  overflow-y: auto;
  padding: var(--e-4);
  /* max-width lo impone .contenido para que la medida de lectura coincida con
     la del sitio; aquí se suelta para aprovechar el ancho del formulario. */
  max-width: none;
}

.editor__lienzo:focus { outline: none; }

/* El textarea original sigue ahí: es lo que se envía, y es la vista de código.
   Oculto no, porque un campo oculto no se puede enfocar al pulsar «Código». */
.editor__fuente {
  display: none;
  width: 100%;
  min-height: 18rem;
  padding: var(--e-4);
  border: 0;
  background: var(--fondo-elevado);
  color: var(--texto);
  font-family: var(--fuente-mono);
  font-size: var(--texto-sm);
  line-height: 1.6;
  resize: vertical;
}

.editor__fuente:focus { outline: none; }

.editor--codigo .editor__lienzo { display: none; }
.editor--codigo .editor__fuente { display: block; }

/* ── Alineación del texto dentro de un contenido ──────────────────────────
   Estas cuatro clases son las ÚNICAS que el saneador deja pasar en el
   programa electoral (ver SaneadorHtml.ClasesDeAlineacion). Si se renombra
   alguna aquí, hay que renombrarla allí: si no, la alineación se guarda y no
   se ve, o se ve y no se guarda.
   ─────────────────────────────────────────────────────────────────────── */

.texto-izquierda   { text-align: left; }
.texto-centro      { text-align: center; }
.texto-derecha     { text-align: right; }
.texto-justificado { text-align: justify; }

/* ── Vídeo incrustado en un contenido ─────────────────────────────────── */

.contenido iframe,
.editor__lienzo iframe {
  display: block;
  width: 100%;
  max-width: 40rem;
  aspect-ratio: 16 / 9;
  height: auto;
  border: 0;
  border-radius: var(--radio-md);
  background: var(--n-900);
}

/* Dentro del editor el vídeo no se puede reproducir ni hace falta: lo que
   importa es ver que está y poder colocarlo. Sin esto, el puntero se lo come
   el iframe y no hay forma de poner el cursor al lado para seguir escribiendo. */
.editor__lienzo iframe { pointer-events: none; }
