/* ONE · estilos v0 — tokens mínimos, móvil primero (375 px) */
:root {
  --fondo: #0b0f14;
  --tarjeta: #151b23;
  --texto: #e8edf2;
  --acento: #4cc9f0;
  --ok: #3ddc84;
  --ko: #ff5d5d;
  --texto-suave: #8a97a6;

  --tam-1: 16px;
  --tam-2: 20px;
  --tam-3: 28px;
  --tam-4: 40px;

  /* Curva suave para el fondo animado y los pulsos de feedback. */
  --ease-suave: cubic-bezier(.16, 1, .3, 1);
}

* { box-sizing: border-box; }
/* Sin zoom por doble tap en iOS; el scroll y el pinch siguen funcionando. */
body, button { touch-action: manipulation; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--fondo);
  color: var(--texto);
  font-family: -apple-system, system-ui, sans-serif;
  font-size: var(--tam-1);
  /* Sensación de app, no de web: cada vista ocupa EXACTAMENTE la pantalla (con
     fallback para navegadores sin dvh) y la página en sí nunca hace scroll ni
     rebota; si algo no cabe, el scroll es interno a la vista (ver .vista). */
  height: 100vh;
  height: 100dvh;
  overflow: hidden;
  overscroll-behavior: none;
}

body {
  display: flex;
  flex-direction: column;
  padding-bottom: env(safe-area-inset-bottom);
  /* iOS instalada (standalone): con el body fijo a la pantalla desaparece el rebote de
     goma de la página entera y el menú de "copiar" al mantener pulsado; el único scroll
     que queda es el interno de cada vista (Carlos, 12-sep: "se siente como web"). */
  position: fixed;
  inset: 0;
  width: 100%;
  -webkit-touch-callout: none;
}

.vista {
  overscroll-behavior: contain;
}

button {
  font-family: inherit;
  font-size: var(--tam-1);
  color: inherit;
  cursor: pointer;
  /* Nada de resaltado gris de iOS al tocar, ni selección de texto accidental
     mientras se juega a golpe de tap. */
  -webkit-tap-highlight-color: transparent;
  -webkit-user-select: none;
  user-select: none;
}

/* Foco visible con teclado (spec "pantalla completa" 12-sep): igual en botones
   sueltos que en cada segmento de un control segmentado. */
button:focus-visible {
  outline: 2px solid var(--acento);
  outline-offset: 2px;
}

.cabecera {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 8px 16px;
  padding-top: max(8px, env(safe-area-inset-top));
}

/* Flecha de "volver a inicio" en la cabecera fija: visible en pregunta, resumen y
   progreso; oculta en inicio (no hay a dónde volver). Tap target >= 44px. */
.boton-volver {
  min-width: 44px;
  min-height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: none;
  border: none;
  color: var(--texto);
  font-size: 24px;
  padding: 0;
  margin-right: 4px;
}

.boton-volver[hidden] { display: none; }

.cabecera-logo {
  font-size: var(--tam-2);
  font-weight: 600;
}

.cabecera-modo-area {
  font-size: 13px;
  color: var(--acento);
}

.cabecera-estado {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 2px;
}

.cabecera-racha {
  font-size: var(--tam-1);
  color: var(--texto-suave);
}

.cabecera-nivel {
  font-size: 13px;
  color: var(--texto-suave);
}

main#app {
  flex: 1;
  min-height: 0; /* deja que .vista (con su propio scroll) pueda encogerse dentro del flex */
  display: flex;
  flex-direction: column;
  overflow: hidden;
  padding: 0 16px 12px;
}

.vista {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  /* El scroll, si hace falta, vive aquí (no en el body): así el fondo animado del
     inicio y la cabecera fija nunca se mueven, y el resto de vistas no arrastran
     rebote de goma al body. */
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
}

/* Los hijos directos de una vista nunca se encogen: en una columna flex con
   overflow, un botón con min-height explícito (44px) se comprimía y el texto de
   "Comenzar" (28px + 18px de relleno) salía cortado por abajo. */
.vista > * {
  flex-shrink: 0;
}

.vista[hidden] { display: none; }

/* Transición breve entre vistas (deslizamiento + fade, ~180ms). Se retriggerea en
   cada mostrarVista() quitando y volviendo a poner la clase (ver app.js). Bajo
   "reducir movimiento" queda neutralizada por la regla general de más abajo. */
.vista-entra {
  animation: vista-entra 0.18s var(--ease-suave);
}

@keyframes vista-entra {
  from { transform: translateX(12px); opacity: 0; }
  to { transform: translateX(0); opacity: 1; }
}

/* Sección inicio: contenedor con overflow oculto para que el fondo animado (que
   respira un poco más allá de sus bordes) nunca provoque scroll horizontal. */
.vista-inicio {
  position: relative;
  overflow: hidden;
}

.inicio-centro {
  position: relative;
  z-index: 1;
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  /* Los emojis caen en el tercio medio-bajo de la pantalla, no en el centro
     exacto: más cerca del pulgar (spec "pantalla completa" 12-sep). */
  padding-top: 12vh;
  gap: 20px;
}

.inicio-emoji {
  font-size: 72px;
  margin: 0;
  line-height: 1;
}

/* --- fondo dinámico del inicio (técnica adaptada de un fondo con "luces que
   respiran" de otro proyecto propio; colores y proporciones son los de ONE) ---
   Tres capas fijas al tamaño de la sección: dos luces radiales que se mueven muy
   lentamente y una viñeta que oscurece los bordes. Sin JS: solo CSS. */
.fondo-dinamico {
  position: absolute;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
}

.fondo-luz {
  position: absolute;
  inset: -20%;
  /* Las posiciones están calculadas para que, tras el inset:-20% (la capa mide
     1.4x la sección), los brillos caigan CENTRADOS en la zona visible (donde
     están los emojis), no en una esquina: comprobado con las coordenadas reales
     (getBoundingClientRect) a 375x812, no solo a ojo. */
  background:
    radial-gradient(48% 42% at 39% 36%, rgba(76, 201, 240, 0.20), transparent 80%),
    radial-gradient(52% 46% at 68% 64%, rgba(76, 201, 240, 0.13), transparent 80%),
    radial-gradient(60% 55% at 50% 93%, rgba(21, 27, 35, 0.9), transparent 72%);
  animation: fondo-respira 22s var(--ease-suave) infinite alternate;
}

@keyframes fondo-respira {
  from { transform: translate3d(0, 0, 0) scale(1); }
  to { transform: translate3d(-2%, 1.5%, 0) scale(1.08); }
}

.fondo-vineta {
  position: absolute;
  inset: 0;
  background: radial-gradient(120% 90% at 50% 35%, transparent 55%, rgba(11, 15, 20, 0.6) 100%);
}

.inicio-emojis {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 32px;
}

.inicio-emoji-boton {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  min-width: 44px;
  min-height: 44px;
  padding: 12px;
  background: none;
  border: none;
  transition: transform 0.15s ease;
}

.inicio-emoji-boton:active {
  transform: scale(0.97);
}

.inicio-emoji-boton--apagado {
  opacity: 0.35;
}

.inicio-etiqueta-pronto {
  font-size: 11px;
  color: var(--texto-suave);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.inicio-aviso {
  min-height: 20px;
  margin: 4px 0 0;
  color: var(--acento);
  font-size: var(--tam-1);
  text-align: center;
}

.inicio-mini-stats {
  display: flex;
  gap: 16px;
  color: var(--texto-suave);
  font-size: 13px;
}

.boton {
  min-height: 44px;
  min-width: 44px;
  padding: 12px 28px;
  border: none;
  border-radius: 12px;
  background: var(--tarjeta);
  color: var(--texto);
  font-size: var(--tam-2);
  font-weight: 600;
  transition: transform 0.1s ease;
}

.boton:active {
  transform: scale(0.97);
}

.boton-principal {
  background: var(--acento);
  color: #04121a;
}

/* Exportar/Importar en el pie del HUB: texto discreto, sin pastilla (spec
   "pantalla completa" 12-sep). */
.hub-pie-enlace {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  padding: 4px 6px;
  border: none;
  background: none;
  color: var(--texto-suave);
  font-size: 13px;
  text-decoration: none;
  transition: transform 0.1s ease;
}

.hub-pie-enlace:active {
  transform: scale(0.97);
}

.boton-archivo {
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

/* Fila de "esta pregunta está mal", sola encima de "Siguiente": alineada a la
   derecha, no al lado de nada (spec "pantalla completa" 12-sep, elimina "?"). */
.fila-esta-mal {
  display: flex;
  margin-top: 4px;
}

/* Fila de confianza: etiqueta a la izquierda, control segmentado ocupando el
   resto (spec "pantalla completa" 12-sep). */
.confianza-fila {
  display: flex;
  align-items: center;
  gap: 10px;
}

.confianza-fila[hidden] { display: none; }

.confianza-etiqueta {
  flex: none;
  font-size: 14px;
  font-weight: 500;
  color: var(--texto-suave);
}

/* Selector de confianza (spec "que se note" 12-sep, sustituye a IDK): control
   segmentado de 3, 44px de alto. Media por defecto; el segmento activo lleva
   relleno cian y texto oscuro (selección visible pero sobria). */
.confianza {
  flex: 1;
  display: flex;
  height: 44px;
  border-radius: 10px;
  overflow: hidden;
  background: var(--tarjeta);
}

.confianza[hidden] { display: none; }

.confianza-opcion {
  flex: 1;
  border: none;
  background: none;
  color: var(--texto-suave);
  font-size: 14px;
  font-weight: 600;
  transition: transform 0.1s ease, background-color 0.1s ease, color 0.1s ease;
}

.confianza-opcion:active {
  transform: scale(0.97);
}

.confianza-opcion--activa {
  background: var(--acento);
  color: #04121a;
}

/* "esta pregunta está mal": texto pequeño y discreto (es solo para depurar el
   banco, no es la acción principal). */
.enlace-discreto {
  margin-left: auto;
  min-height: 44px;
  padding: 0 4px;
  display: inline-flex;
  align-items: center;
  background: none;
  border: none;
  color: var(--texto-suave);
  text-decoration: underline;
  font-size: 12px;
}

/* --- pregunta --- */
.barra-progreso {
  height: 4px;
  background: var(--tarjeta);
  border-radius: 2px;
  margin: 6px 0 10px;
  overflow: hidden;
}

.barra-progreso-relleno {
  height: 100%;
  background: var(--acento);
  width: 100%;
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.2s ease;
}

/* ZONA MEDIA: lo que se lee (la tarjeta), centrada verticalmente en el espacio
   que quede (spec "pantalla completa" 12-sep). Especificidad igual a
   ".vista > *" (0,1,0): gana por ir después en la hoja, mismo patrón que
   .resumen-repaso más abajo. */
.zona-media {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
}

/* ZONA DE ACCIÓN: lo que se toca, anclada al borde inferior (donde llega el
   pulgar). El alto mínimo evita que la tarjeta salte entre preguntas con y sin
   fila de botones vf. */
.zona-accion {
  margin-top: auto;
  padding-bottom: env(safe-area-inset-bottom);
  display: flex;
  flex-direction: column;
  gap: 10px;
  min-height: 114px;
}

.tarjeta {
  background: var(--tarjeta);
  border-radius: 16px;
  padding: 14px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  touch-action: pan-y;
  transition: transform 0.15s ease, opacity 0.15s ease;
  -webkit-tap-highlight-color: transparent;
  -webkit-user-select: none;
  user-select: none;
}

.pregunta-cabecera {
  font-size: 13px;
  color: var(--texto-suave);
  margin: 0;
}

/* Tipografía fluida (clamp) y recorte elegante a 5 líneas: un enunciado largo
   nunca empuja la vista a hacer scroll. Un toque expande si estaba recortado
   (ver el listener en renderPreguntaActual, app.js). */
.enunciado {
  font-size: clamp(18px, 5.4vw, 26px);
  line-height: 1.3;
  margin: 0;
  display: -webkit-box;
  -webkit-line-clamp: 5;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.enunciado--expandido {
  -webkit-line-clamp: unset;
  overflow: visible;
}

.titulo-tarjeta {
  font-size: 15px;
  font-weight: 600;
  margin: 0;
}

/* Sustituye al enunciado genérico "Encuentra el dato erróneo en la tarjeta."
   cuando el banco trae exactamente ese texto (ver construirError en app.js). */
.instruccion-error {
  font-size: 13px;
  color: var(--texto-suave);
  margin: 0;
}

/* Pista de deslizamiento (vf): chevrones a los lados, siempre visibles; la
   frase central solo las primeras 5 preguntas vf del dispositivo (ver
   construirVf en app.js). */
.pista-swipe {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin-top: -2px;
}

.pista-swipe-texto {
  flex: 1;
  text-align: center;
  color: var(--texto-suave);
  font-size: 12px;
}

.pista-swipe-texto[hidden] { display: none; }

.pista-swipe-chevron {
  flex: none;
  color: var(--texto-suave);
  font-size: 16px;
  font-weight: 700;
  transition: color 0.15s ease;
}

.pista-swipe-chevron--ok { color: var(--ok); }
.pista-swipe-chevron--ko { color: var(--ko); }

/* FALSO/VERDADERO viven en la zona de acción (ver #botones-vf-accion en
   index.html), no en la tarjeta. Igual que .feedback/.vista/.boton-volver:
   hace falta el override explícito de [hidden], si no la cascada de origen
   "autor" (este display:flex) gana al "user agent" y el atributo no oculta
   nada. */
.botones-vf {
  display: flex;
  gap: 10px;
}

.botones-vf[hidden] { display: none; }

.botones-vf button {
  flex: 1;
  min-height: 56px;
  border: none;
  border-radius: 12px;
  font-size: var(--tam-2);
  font-weight: 600;
  transition: transform 0.1s ease;
}

.boton-ko { background: rgba(255, 93, 93, 0.15); color: var(--ko); }
.boton-ok { background: rgba(61, 220, 132, 0.15); color: var(--ok); }

.opciones, .items, .filas {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.opciones button, .items button, .filas button {
  min-height: 44px;
  padding: 12px 14px;
  border: none;
  border-radius: 12px;
  background: var(--fondo);
  color: var(--texto);
  text-align: left;
  font-size: clamp(13px, 3.8vw, 15px);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  transition: transform 0.1s ease;
}

.botones-vf button:active,
.opciones button:active,
.items button:active,
.filas button:active {
  transform: scale(0.97);
}

.items button.seleccionado {
  outline: 2px solid var(--acento);
  color: var(--acento);
}

.items .numero {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 24px;
  height: 24px;
  border-radius: 50%;
  background: var(--acento);
  color: #04121a;
  font-weight: 700;
  font-size: 14px;
}

/* Hallazgo al revisar 05-ordenar.png (spec "que se note"): con display:inline-flex
   arriba, el atributo hidden del navegador quedaba sin efecto (mismo patrón que
   .feedback[hidden] más abajo) y los círculos numerados se veían vacíos en los
   items todavía sin tocar. */
.items .numero[hidden] { display: none; }

/* "Encuentra el error": tabla de dos columnas, etiqueta con ancho fijo del 34%
   alineada arriba, valor a la izquierda (nunca a la derecha). Especificidad
   igual a la regla compartida de arriba (0,1,1): gana por ir después. */
.filas { gap: 6px; }

.filas button {
  align-items: flex-start;
  justify-content: flex-start;
  gap: 12px;
  min-height: 48px;
  padding: 10px 12px;
  border-radius: 10px;
}

.fila-etiqueta {
  flex: 0 0 34%;
  color: var(--texto-suave);
  text-align: left;
}

.fila-valor {
  flex: 1 1 auto;
  color: var(--texto);
  text-align: left;
}

/* Fila elegida/correcta tras responder (ver marcarFilasError en app.js): mismo
   relleno al 15% que ya usan los botones vf. */
.filas button.fila-ok { background: rgba(61, 220, 132, 0.15); }
.filas button.fila-ko { background: rgba(255, 93, 93, 0.15); }

.tarjeta.correcto { outline: 2px solid var(--ok); animation: tarjeta-pulso 0.35s ease; }
.tarjeta.incorrecto { outline: 2px solid var(--ko); animation: tarjeta-sacude 0.4s ease; }

@keyframes tarjeta-pulso {
  0% { transform: scale(1); }
  35% { transform: scale(1.045); }
  100% { transform: scale(1); }
}

@keyframes tarjeta-sacude {
  10%, 90% { transform: translateX(-2px); }
  20%, 80% { transform: translateX(3px); }
  30%, 50%, 70% { transform: translateX(-5px); }
  40%, 60% { transform: translateX(5px); }
}

.feedback {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

/* Fallo previo a este cambio (ya en el código base, no introducido ahora): al
   declarar display:flex aquí, la regla [hidden] del navegador (display:none)
   quedaba sin efecto por precedencia de cascada (origen "autor" gana al "user
   agent" a igual especificidad) y #contenedor-feedback NUNCA llegaba a
   ocultarse de verdad pese a tener el atributo. Mismo patrón que .vista[hidden]
   y .boton-volver[hidden], que ya lo tenían resuelto. */
.feedback[hidden] { display: none; }

.feedback-texto {
  font-size: 22px;
  font-weight: 600;
  margin: 0;
}

.feedback-texto--ok { color: var(--ok); }
.feedback-texto--ko { color: var(--ko); }

.feedback-combo {
  color: var(--acento);
  font-weight: 600;
  margin: 0;
  font-size: 13px;
}

.cambio-nivel {
  font-weight: 600;
  margin: 0;
  font-size: 13px;
}

.cambio-nivel-subida { color: var(--ok); }
.cambio-nivel-bajada { color: var(--ko); }

.cambio-nivel-area {
  color: var(--texto-suave);
  font-size: 12px;
  margin: 0;
}

/* Chips de feedback compacto (Recuperada, Estabas seguro, Misión completada,
   Frágil): una fila que se ajusta a los que apliquen, sin hueco cuando no hay
   ninguno visible. */
.feedback-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.feedback-chip {
  display: inline-flex;
  padding: 4px 9px;
  border-radius: 999px;
  background: var(--fondo);
  color: var(--texto-suave);
  font-size: 11px;
  font-weight: 600;
}

.feedback-chip[hidden] { display: none; }

.reportada {
  color: var(--texto-suave);
  font-size: 14px;
  margin: 0;
}

/* La explicación se muestra siempre, abierta (spec "pantalla completa"
   12-sep): texto principal, no suave. Si no cabe en ~5 líneas, hace scroll
   interno propio en vez de empujar el resto del feedback (y con él, la vista)
   fuera de pantalla. */
.explicacion {
  color: var(--texto);
  font-size: 15px;
  line-height: 1.45;
  margin: 0;
  max-height: 7.25em;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
}

.explicacion[hidden] { display: none; }

/* --- resumen / progreso --- */
.vista-resumen {
  gap: 8px;
}

/* Cabecera de resultado (spec "pantalla completa" 12-sep): aciertos y XP en una
   línea grande, áreas en 13px debajo. */
.resumen-cabecera {
  margin-top: 2px;
}

.resumen-resultado {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 10px;
}

.resumen-resultado-linea {
  margin: 0;
  font-size: 22px;
  font-weight: 600;
}

.resumen-areas-linea {
  margin: 4px 0 0;
  font-size: 13px;
  color: var(--texto-suave);
}

.resumen-acciones {
  display: flex;
  gap: 12px;
  margin-top: 10px;
}

.resumen-acciones .boton {
  flex: 1;
  min-height: 56px;
}

/* "Para repasar": ocupa el espacio restante del resumen (flex:1, contra la regla
   general ".vista > * { flex-shrink: 0 }": misma especificidad, gana por ir
   después en la hoja) para que el resumen entero quepa sin scroll vertical. */
.resumen-repaso {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  min-height: 0;
  gap: 6px;
  margin-top: 8px;
}

.resumen-repaso-titulo {
  margin: 0;
  font-size: 13px;
  font-weight: 600;
  color: var(--texto-suave);
}

.resumen-repaso-carrusel {
  display: flex;
  flex: 1 1 auto;
  min-height: 0;
  gap: 10px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  -webkit-overflow-scrolling: touch;
}

.resumen-repaso-carrusel[hidden] { display: none; }

.resumen-repaso-tarjeta {
  flex: 0 0 84%;
  scroll-snap-align: start;
  background: var(--tarjeta);
  border-radius: 14px;
  padding: 12px 14px;
  display: flex;
  flex-direction: column;
  gap: 6px;
  overflow-y: auto;
  min-height: 0;
}

.resumen-repaso-marca {
  margin: 0;
  font-weight: 700;
  font-size: 13px;
}

.resumen-repaso-marca--fallo { color: var(--ko); }
.resumen-repaso-marca--fragil { color: var(--texto-suave); }

.resumen-repaso-enunciado {
  margin: 0;
  font-size: 14px;
  font-weight: 600;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.resumen-repaso-respuesta {
  margin: 0;
  color: var(--acento);
  font-size: 13px;
  font-weight: 600;
}

.resumen-repaso-explicacion {
  margin: 0;
  color: var(--texto-suave);
  font-size: 13px;
}

.resumen-repaso-puntos {
  display: flex;
  justify-content: center;
  gap: 6px;
  padding-top: 2px;
}

.resumen-repaso-puntos[hidden] { display: none; }

.resumen-repaso-punto {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--tarjeta);
  transition: background 0.15s ease;
}

.resumen-repaso-punto--activo {
  background: var(--acento);
}

/* Sin nada que repasar: el mensaje se centra en el espacio libre en vez de
   quedarse pegado arriba (si no, medio resumen queda vacío debajo — el mismo
   defecto que motivó esta spec, reaparecido aquí). */
.resumen-repaso-vacio {
  margin: 0;
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  color: var(--texto-suave);
  font-size: 13px;
}

.resumen-repaso-vacio[hidden] { display: none; }

/* --- HUB (antes "Progreso"): siempre se empieza a jugar desde aquí --- */
.vista-hub {
  gap: 10px;
}

/* Radar tipo "panel de stats de videojuego": un eje por área. Contorno cian =
   puntuación (.radar-dato, como antes); relleno más opaco = solidez
   (.radar-solido, nuevo). Ver renderRadar() en app.js.
   Absorbe el espacio libre del HUB (spec "pantalla completa" 12-sep): flex:1
   entre min y max, así no queda hueco vacío entre la rejilla y "Comenzar".
   Especificidad igual a ".vista > *" (0,1,0): gana por ir después en la hoja. */
.hub-radar-envoltorio {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  flex: 1 1 auto;
  min-height: 150px;
  max-height: 280px;
  margin-top: 2px;
}

/* preserveAspectRatio="xMidYMid meet" (por defecto en SVG) escala el radar sin
   deformarlo dentro de la caja disponible, sea cual sea su proporción. */
.hub-radar {
  width: 100%;
  height: 100%;
  max-width: 280px;
}

.radar-anillo {
  fill: none;
  stroke: var(--tarjeta);
  stroke-width: 1;
}

.radar-eje {
  stroke: var(--tarjeta);
  stroke-width: 1;
}

.radar-dato {
  fill: rgba(76, 201, 240, 0.28);
  stroke: var(--acento);
  stroke-width: 1.5;
}

.radar-solido {
  fill: rgba(76, 201, 240, 0.55);
  stroke: none;
}

.radar-etiqueta {
  fill: var(--texto-suave);
  font-size: 13px;
}

.radar-vacio {
  margin: 0;
  color: var(--texto-suave);
  font-size: 13px;
  text-align: center;
}

/* Línea única "Hoy 11/20 · Recuperadas 0 · Confianza 82 %" (spec "pantalla
   completa" 12-sep): sin pastillas, cada segmento separado por "·" salvo el
   primero; "Confianza" se une solo cuando hay dato (queda oculto si no). */
.hub-kpis {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 6px;
  color: var(--texto-suave);
  font-size: 12.5px;
}

.hub-chip {
  padding: 0;
  background: none;
  color: inherit;
  font-size: inherit;
}

.hub-chip + .hub-chip::before {
  content: '· ';
}

/* Misión de hoy / Pendientes: fila de dos tarjetas tocables (o atenuadas +
   aria-disabled cuando no aplican, ver actualizarDestacados en app.js). */
.hub-destacados {
  display: flex;
  gap: 8px;
}

.hub-destacado {
  flex: 1;
  min-height: 44px;
  padding: 8px 10px;
  border: none;
  border-radius: 12px;
  background: var(--tarjeta);
  color: var(--texto);
  text-align: left;
  font-size: 12px;
  font-weight: 600;
  line-height: 1.3;
  transition: transform 0.1s ease;
}

.hub-destacado:not(.hub-destacado--inactivo):active {
  transform: scale(0.97);
}

.hub-destacado--inactivo {
  color: var(--texto-suave);
  opacity: 0.5;
}

.boton-comenzar {
  width: 100%;
  min-height: 56px;
  padding: 14px;
  font-size: var(--tam-2);
}

/* Los 8 niveles del videojuego: cuadrícula compacta de 4 columnas × 2 filas
   (hub "que se note"), tarjetas pequeñas y tocables (tap target >= 64px de alto). */
.hub-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 8px;
}

.tarjeta-area {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 4px;
  min-height: 64px;
  padding: 8px 8px 7px;
  border: none;
  border-radius: 12px;
  background: var(--tarjeta);
  color: var(--texto);
  text-align: left;
  transition: transform 0.12s ease;
}

.tarjeta-area:active {
  transform: scale(0.97);
}

.tarjeta-area:disabled {
  opacity: 0.4;
}

.tarjeta-area-cabecera {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
}

.tarjeta-area-emoji {
  font-size: 18px;
}

.tarjeta-area-nombre {
  width: 100%;
  font-size: 10.5px;
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Nota tipo videojuego (S+/S/A/B/C/D). Paleta ya existente: nada de colores nuevos. */
.tarjeta-area-nota {
  flex: none;
  font-size: 16px;
  font-weight: 800;
}

.tarjeta-area-nota--alta { color: var(--acento); }
.tarjeta-area-nota--media { color: var(--texto); }
.tarjeta-area-nota--baja { color: var(--texto-suave); }
.tarjeta-area-nota--vacia { color: var(--texto-suave); opacity: 0.5; }

/* Barra de progreso FINA con la puntuación 0..1 del área (antes era el acierto
   reciente; ahora es la misma métrica que alimenta el radar y la nota). */
.tarjeta-area-track {
  width: 100%;
  height: 3px;
  border-radius: 2px;
  background: var(--fondo);
  overflow: hidden;
}

.tarjeta-area-relleno {
  height: 100%;
  min-width: 2px;
  background: var(--acento);
}

/* "S N · R M": sólidas (caja >= 3) y recientes (respondidas hoy o ayer). */
.tarjeta-area-solido {
  color: var(--texto-suave);
  font-size: 9.5px;
}

/* Exportar/Importar: pie discreto, ya no son la acción principal del HUB. */
.hub-pie {
  display: flex;
  justify-content: center;
  gap: 12px;
  margin-top: 4px;
  font-size: 13px;
}

/* --- accesibilidad de movimiento ---
   Con "reducir movimiento" activo: sin fondo animado, sin pulso/sacudida de la
   tarjeta, y ninguna transición/animación del resto de la app (barra de
   progreso, transform de tarjeta al arrastrar, conteo del resumen se pinta ya
   resuelto por app.js). */
@media (prefers-reduced-motion: reduce) {
  .fondo-luz { animation: none; }
  .tarjeta.correcto, .tarjeta.incorrecto { animation: none; }

  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
}
