/* components.css — reusable UI: buttons, cards, figures, terms, read marks,
   feedback blocks, court diagram states. */

/* ---- Botones ------------------------------------------------------------ */

.boton {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 48px;
  padding-inline: var(--sp-5);
  border: 1px solid transparent;
  border-radius: var(--r-pill);
  font-size: var(--fs-small);
  font-weight: 600;
  text-decoration: none;
  text-align: center;
  transition: background var(--dur-fast) var(--ease-out),
              color var(--dur-fast) var(--ease-out);
}

.boton--primario {
  background: var(--c-accent);
  color: var(--c-card);
}

.boton--primario:hover {
  background: var(--c-accent-strong);
  color: var(--c-card);
}

.boton--fantasma {
  background: transparent;
  border-color: var(--c-border);
  color: var(--c-text);
}

.boton--fantasma:hover {
  background: var(--c-surface);
  color: var(--c-text);
}

/* Estado pressed: sin él, un toque en móvil no acusa recibo hasta que la acción
   termina, y el botón se siente muerto. */
.boton--primario:active { background: var(--c-accent-strong); }
.boton--fantasma:active { background: var(--c-accent-soft); }
.opcion:active:not(:disabled) { background: var(--c-accent-soft-hi); }

.boton:disabled {
  opacity: .45;
  cursor: not-allowed;
}

/* ---- Tarjetas ----------------------------------------------------------- */

.tarjeta {
  background: var(--c-card);
  border: 1px solid var(--c-border);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-card);
  padding: var(--sp-5);
}

.tarjeta > * + * { margin-block-start: var(--sp-4); }

/* ---- Términos ----------------------------------------------------------- */

dfn {
  font-style: normal;
  font-weight: 600;
  color: var(--c-accent-strong);
  border-block-end: 2px solid var(--c-accent-soft);
}

/* ---- Marca de leído ----------------------------------------------------- */

.marca {
  flex: none;
  width: 20px;
  height: 20px;
  border-radius: var(--r-pill);
  border: 2px solid var(--c-border);
  position: relative;
}

.marca[data-leido="si"] {
  background: var(--c-accent);
  border-color: var(--c-accent);
}

/* The check is a shape, not a colour — the read state must not rely on hue. */
.marca[data-leido="si"]::after {
  content: "";
  position: absolute;
  inset: 0;
  margin: auto;
  width: 5px;
  height: 9px;
  border: solid var(--c-card);
  border-width: 0 2px 2px 0;
  transform: translateY(-1px) rotate(45deg);
}

/* ---- Figuras y diagramas ------------------------------------------------ */

.diagrama {
  margin-block: var(--sp-7) var(--sp-6);
}

.diagrama figcaption {
  margin-block-start: var(--sp-3);
  max-width: 56ch;              /* algo más corto que la prosa: es un apoyo, no un párrafo */
  margin-inline: auto;
  font-size: var(--fs-small);
  line-height: 1.5;
  color: var(--c-text-muted);
  text-wrap: pretty;            /* sin viudas de una palabra al final del pie */
  text-align: center;
}

/* Cada diagrama lleva su proporción en su propio viewBox, así que aquí solo se
   limita el ancho. La cancha vertical se acota para que no crezca de más en
   pantallas medianas antes del cambio de orientación a 768px. */
.diagrama--cancha .cancha--vertical { max-width: 22rem; margin-inline: auto; }

/* ---- Opciones del test -------------------------------------------------- */

.opciones {
  list-style: none;
  padding: 0;
  display: grid;
  gap: var(--sp-3);
}

.opcion {
  width: 100%;
  min-height: 52px;
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-4);
  text-align: start;
  background: var(--c-card);
  border: 2px solid var(--c-border);
  border-radius: var(--r-md);
  transition: border-color var(--dur-fast) var(--ease-out),
              background var(--dur-fast) var(--ease-out);
}

.opcion:hover:not(:disabled) {
  border-color: var(--c-accent);
  background: var(--c-accent-soft);
}

.opcion__tecla {
  flex: none;
  width: 26px;
  height: 26px;
  display: grid;
  place-items: center;
  border-radius: var(--r-sm);
  background: var(--c-surface);
  color: var(--c-text-muted);
  font-size: 0.8125rem;
  font-weight: 600;
}

.opcion__txt { flex: 1 1 auto; }

/* Estados. Cada uno lleva además un glifo desde la Fase 9 — nunca solo color. */

.opcion.es-eliminada {
  border-color: var(--c-border);
  background: var(--c-surface);
  color: var(--c-text-muted);
  opacity: .8;
}

.opcion.es-eliminada .opcion__txt { text-decoration: line-through; }

.opcion.es-correcta {
  border-color: var(--c-correct);
  background: var(--c-correct-bg);
  color: var(--c-correct);
  font-weight: 600;
}

.opcion.es-incorrecta {
  border-color: var(--c-incorrect);
  background: var(--c-incorrect-bg);
  color: var(--c-incorrect);
}

/* El estado nunca se señala solo con color: cada uno lleva además una forma.
   La eliminada la lleva en el tachado; estas dos reciben un icono dibujado que
   quiz.js inserta como SVG real. No es un glifo unicode ni un data: URI: el
   primero no es un sistema de iconos y el segundo lo bloquearía img-src 'self'. */
.opcion__glifo {
  flex: none;
  width: 20px;
  height: 20px;
}

.opcion__glifo:empty { display: none; }
.opcion__icono { width: 20px; height: 20px; }

/* The outline has to stay visible on top of every state above, including the
   struck-through disabled one. */
.opcion:focus-visible {
  outline: 3px solid var(--c-accent);
  outline-offset: 2px;
  opacity: 1;
}

/* ---- Feedback ----------------------------------------------------------- */

.feedback {
  display: flex;
  gap: var(--sp-3);
  padding: var(--sp-4);
  border-radius: var(--r-md);
}

.feedback__icono {
  flex: none;
  width: 22px;
  height: 22px;
  margin-block-start: 2px;
}

.feedback__cuerpo > * + * { margin-block-start: var(--sp-2); }

.feedback__titulo { font-weight: 600; }

.feedback__exp {
  color: var(--c-text);
  font-size: var(--fs-small);
}

.feedback__link { font-size: var(--fs-small); }

.feedback--ok        { background: var(--c-correct-bg);   color: var(--c-correct); }
.feedback--mal       { background: var(--c-incorrect-bg); color: var(--c-incorrect); }
.feedback--reintento { background: var(--c-retry-bg);     color: var(--c-retry); }

.feedback--ok .feedback__link a        { color: var(--c-correct); }
.feedback--mal .feedback__link a       { color: var(--c-incorrect); }

/* ---- Cancha ------------------------------------------------------------- */

/* El sprite se esconde con tamaño cero y overflow, nunca con display:none:
   en algunos navegadores eso impide que los símbolos referenciados se pinten. */
.svg-sprite {
  position: absolute;
  width: 0;
  height: 0;
  overflow: hidden;
}

.cancha {
  display: block;
  width: 100%;
  height: auto;
  border-radius: var(--r-md);
  overflow: hidden;
}

.cancha__capa {
  transition: opacity var(--dur-base) var(--ease-out);
}

.cancha__capa.is-atenuado { opacity: .45; }

/* Los marcadores se dibujan encima de las zonas, así que sin esto se comen el
   clic justo donde está la bola — que es exactamente donde el lector apunta. */
.cancha use,
.cancha .trayectoria { pointer-events: none; }

/* Zonas: transparentes por defecto e inertes. La Fase 10 habilita el puntero
   solo en las que esa pregunta acepta como respuesta. */
.cancha .zona {
  fill: var(--c-line);
  fill-opacity: 0;
  stroke: none;
  pointer-events: none;
  transition: fill-opacity var(--dur-base) var(--ease-out),
              fill var(--dur-base) var(--ease-out);
}

.cancha .zona.is-destacado {
  fill: var(--c-line);
  fill-opacity: .28;
  stroke: var(--c-line);
  stroke-width: 1.4;
}

.cancha .zona.is-correcto {
  fill: var(--c-correct-bg);
  fill-opacity: .8;
  stroke: var(--c-correct);
  stroke-width: 1.6;
}

.cancha .zona.is-incorrecto {
  fill: var(--c-incorrect-bg);
  fill-opacity: .8;
  stroke: var(--c-incorrect);
  stroke-width: 1.6;
}

/* Tercer estado, ni correcto ni incorrecto: el azul de cancha dura pasa a ser
   el color de lo informativo. Lo pide el let, que no es falta ni es punto y al
   que marcar en verde o en rojo le enseñaría al lector algo falso. */
.cancha .zona.is-informativo {
  fill: var(--c-hard);
  fill-opacity: .28;
  stroke: var(--c-hard);
  stroke-width: 1.6;
}

/* Rótulos: siempre fuera de .cancha__capa, porque dentro rotarían.

   El tamaño va en px, no en rem: dentro de un SVG 1px equivale a una unidad de
   usuario, así que el texto escala junto con el viewBox. Un rem se resolvería a
   píxeles absolutos y luego se multiplicaría por la escala del viewBox, con lo
   que el rótulo saldría enorme. */
.cancha__rotulos text {
  font-family: var(--ff-body);
  font-size: 6px;
  font-weight: 600;
  fill: var(--c-text);
}

.cancha__rotulos .sobre-verde { fill: var(--c-line); }
.cancha__rotulos .atenuado { fill: var(--c-line); opacity: .7; font-weight: 400; }

/* Los nombres largos bajan un escalón para caber en su región sin invadir la
   vecina. Siguen legibles porque van sobre verde pleno, no sobre un dibujo. */
.cancha__rotulos .peq { font-size: 5px; }

/* Guías: dentro de la cancha van en cal; sobre el fuera, en tinta. */
.cancha__rotulos line {
  stroke: var(--c-line);
  stroke-width: 0.6;
  opacity: .85;
}

.cancha__rotulos line.fuera {
  stroke: var(--c-text);
  opacity: .5;
}

/* Rótulos secundarios: a 360px no entran nueve etiquetas. Debajo de 480px
   quedan solo línea de fondo, cuadro de saque, línea de servicio y red; los
   nombres que se caen siguen estando en la prosa. */
@media (max-width: 479px) {
  .cancha__rotulos .rotulo--sec { display: none; }
}

/* Realce suave de los dos cuadros de saque: hace ver de un vistazo que la
   cancha del saque es más chica que la del resto del punto. */
.cancha .tinte-saque { fill: var(--c-line); fill-opacity: .12; }

/* ---- Recortes de cancha ------------------------------------------------- */
/* Dos diagramas rompen a propósito el patrón de instancia compartida y usan su
   propio viewBox recortado: dentro/fuera y la falta de pie. En ambos la regla
   solo es visible de cerca. */

.recorte {
  display: block;
  width: 100%;
  height: auto;
  border-radius: var(--r-md);
}

.recorte text {
  font-family: var(--ff-body);
  font-size: 9px;
  font-weight: 700;
}

.recorte .veredicto--ok  { fill: var(--c-correct-bg); }
.recorte .veredicto--mal { fill: var(--c-incorrect-bg); }
.recorte .nota { font-size: 7px; font-weight: 400; fill: var(--c-text); }

/* ---- Cuadrículas de diagramas ------------------------------------------- */

.diagrama--doble,
.diagrama--cuadricula {
  margin-block: var(--sp-6);
}

.diagrama__par {
  display: grid;
  gap: var(--sp-4);
  grid-template-columns: 1fr;
}

.diagrama__celda { text-align: center; }

.diagrama__celda .cancha,
.diagrama__celda .recorte {
  max-width: 15rem;
  margin-inline: auto;
}

.diagrama__rotulo {
  margin-block-start: var(--sp-2);
  font-size: var(--fs-small);
  font-weight: 600;
}

.diagrama__rotulo small {
  display: block;
  font-weight: 400;
  color: var(--c-text-muted);
}

@media (min-width: 480px) {
  .diagrama__par { grid-template-columns: repeat(2, 1fr); }
}

@media (min-width: 1024px) {
  .diagrama--cuadricula .diagrama__par { grid-template-columns: repeat(4, 1fr); }
}

/* Trayectoria del saque: cruza la red, nunca la atraviesa recta. */
.cancha .trayectoria {
  fill: none;
  stroke: var(--c-ball);
  stroke-width: 2;
  stroke-linecap: round;
  stroke-dasharray: 5 4;
}

.cancha .trayectoria--corta { stroke-dasharray: 3 3; opacity: .9; }

/* ---- Gráficos que no son cancha ----------------------------------------- */
/* El marcador, la tira de juegos, el contador y el anidado. Todos llevan su
   proporción en su propio viewBox, así que no necesitan caja reservada. */

.diagrama--grafico > svg {
  display: block;
  width: 100%;
  height: auto;
  max-width: 34rem;
  margin-inline: auto;
}

.diagrama--recorte .recorte { max-width: 34rem; margin-inline: auto; }

/* Estados: en un diagrama que avanza por pasos solo se ve uno a la vez. El que
   trae .is-activo en el marcado es el que se muestra sin JavaScript.

   El cambio es un fundido cruzado, no un salto: los grupos comparten sistema de
   coordenadas, así que se superponen solos. Este ES el momento animado del
   proyecto — el marcador avanzando, la bola cambiando de sitio. Por eso no se
   resuelve con display, que no se puede transicionar. */
/* El ancla va en el <svg>, no en la <figure>: el test clona solo el svg, así que
   un atributo puesto en la figura no viaja y allí no se ocultaba nada (los ocho
   estados del marcador se pintaban encima unos de otros).

   Y tiene que ser opt-in, no global: el recorte de dentro/fuera también usa
   data-caso, pero muestra sus cuatro botes a la vez a propósito — es una
   comparación, no una secuencia. Sin data-estados, sus grupos no se tocan. */
[data-estados] [data-paso],
[data-estados] [data-caso],
[data-estados] [data-nivel] {
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--dur-base) var(--ease-out),
              visibility 0s linear var(--dur-base);
}

[data-estados] [data-paso].is-activo,
[data-estados] [data-caso].is-activo,
[data-estados] [data-nivel].is-activo {
  opacity: 1;
  visibility: visible;
  transition: opacity var(--dur-base) var(--ease-out), visibility 0s;
}

/* Marcador */
.marcador text { font-family: var(--ff-body); fill: var(--c-bg); }
.marcador .mk-nom { font-size: 11px; font-weight: 600; opacity: .75; }
.marcador .mk-cif { font-size: 22px; font-weight: 700; text-anchor: end; }
.marcador .mk-cif--gana { fill: var(--c-ball); font-size: 18px; }
.marcador .mk-eti { font-size: 9px; opacity: .7; text-anchor: middle; }

/* Tira de juegos */
.tira text { font-family: var(--ff-body); fill: var(--c-text); }
.tira .tira-eti { font-size: 9px; font-weight: 700; }
.tira .tira-nota { font-size: 7.5px; fill: var(--c-text-muted); }
.tira .tira-celdas rect { rx: 3; }
.tira .c-a { fill: var(--c-accent); }
.tira .c-b { fill: var(--c-surface); stroke: var(--c-border); stroke-width: 1; }
/* El quiebre se marca con una forma, no solo con color. */
.tira .c-q { stroke: var(--c-clay); stroke-width: 2.5; stroke-dasharray: 4 3; }

/* Contador de tie break */
.contador text { font-family: var(--ff-body); fill: var(--c-text); }
.contador .ct-cif { font-size: 22px; font-weight: 700; fill: var(--c-bg); }
.contador .ct-sub { font-size: 8.5px; fill: var(--c-text-muted); }
.contador .ct-eti { font-size: 8px; font-weight: 600; fill: var(--c-text-muted); }
.contador .ct-n { font-size: 8px; font-weight: 600; }
.contador .ct-nota { font-size: 7.5px; fill: var(--c-text-muted); }
.contador .ct-celdas rect { rx: 3; }
.contador .s-a { fill: var(--c-accent-soft); stroke: var(--c-accent); stroke-width: 1; }
.contador .s-b { fill: var(--c-card); stroke: var(--c-border); stroke-width: 1; }
/* Azul informativo, igual que el let: el cambio de lado no es un acierto ni un
   error, solo un dato. El terracota queda reservado para un hecho del partido
   (el quiebre), que sí es un evento. */
.contador .ct-cambio { stroke: var(--c-hard); stroke-width: 1.5; stroke-dasharray: 3 2; fill: none; }

/* Anidado */
.anidado text { font-family: var(--ff-body); fill: var(--c-text); }
.anidado .an-caja { fill: none; stroke: var(--c-border); stroke-width: 1.5; }
.anidado .an-caja--4 { fill: var(--c-surface); }
.anidado .an-caja--3 { fill: var(--c-accent-soft); }
.anidado .an-caja--2 { fill: var(--c-card); }
.anidado .an-caja--1 { fill: var(--c-accent); stroke: var(--c-accent-strong); }
.anidado .an-eti { font-size: 8.5px; font-weight: 600; }
.anidado .an-eti--dentro { fill: var(--c-card); font-size: 11px; }
.anidado .an-nota { font-size: 7.5px; fill: var(--c-text-muted); }
.anidado .an-puntos circle { fill: var(--c-ball); }

/* ---- Control de pasos --------------------------------------------------- */

.pasos {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-3);
  margin-block-start: var(--sp-3);
}

.pasos__btn {
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  background: var(--c-card);
  border: 1px solid var(--c-border);
  border-radius: var(--r-pill);
  color: var(--c-accent);
  transition: background var(--dur-fast) var(--ease-out),
              border-color var(--dur-fast) var(--ease-out);
}

.pasos__btn svg { width: 20px; height: 20px; }

.pasos__btn:hover:not(:disabled) {
  background: var(--c-accent-soft);
  border-color: var(--c-accent);
}

.pasos__btn:active:not(:disabled) { background: var(--c-accent-soft-hi); }

.pasos__btn:disabled { opacity: .4; cursor: not-allowed; }

.pasos__pos {
  min-width: 7.5rem;
  text-align: center;
  font-size: var(--fs-small);
  font-weight: 600;
  color: var(--c-text-muted);
}

/* ---- Reveal ------------------------------------------------------------- */
/* El estado oculto cuelga de .js-activo a propósito: sin JavaScript la página
   se ve entera. Y reveal.js además consulta prefers-reduced-motion por su
   cuenta, porque el guard global de base.css deja la transición en cero y un
   elemento en opacity 0 se quedaría invisible para siempre. */

/* Solo los diagramas entran, nunca el texto. El brief pide reveal-on-scroll y se
   respeta, pero esta página se lee con un partido en la tele: texto que aparece
   fundiéndose mientras scrolleas es una traba, no un detalle. El dibujo sí gana
   una entrada, porque es el contenido. */
.js-activo .seccion .diagrama {
  opacity: 0;
  transform: translateY(14px) scale(.985);
  transition: opacity var(--dur-slow) var(--ease-out),
              transform var(--dur-slow) var(--ease-out);
}

.js-activo .seccion .diagrama.is-visible {
  opacity: 1;
  transform: none;
}

/* ---- Test: cancha clicable ---------------------------------------------- */

.cancha--test { max-width: 17rem; margin-inline: auto; }

.cancha .zona.es-clicable {
  pointer-events: all;
  cursor: pointer;
  touch-action: manipulation;   /* que un doble toque no haga zoom en vez de responder */
  fill: var(--c-line);
  fill-opacity: .06;
}

.cancha .zona.es-clicable:hover {
  fill-opacity: .2;
  stroke: var(--c-line);
  stroke-width: 1;
  stroke-dasharray: 3 2;
}

/* El contorno por defecto es verde acento sobre una cancha verde: invisible.
   Por eso el foco lleva además un trazo claro sobre la propia zona. */
.cancha .zona.es-clicable:focus-visible {
  outline: none;
  fill-opacity: .28;
  stroke: var(--c-line);
  stroke-width: 2.5;
  stroke-dasharray: none;
}

.test__pista {
  font-size: var(--fs-small);
  font-weight: 600;
  color: var(--c-accent-strong);
  background: var(--c-accent-soft);
  padding: var(--sp-2) var(--sp-3);
  border-radius: var(--r-md);
  text-align: center;
}

.test__enunciado:focus-visible { outline-offset: 4px; }

/* Las dos orientaciones. Una sola está en el DOM visible a la vez; la otra
   además lleva aria-hidden para que no se anuncie dos veces. */
.cancha--horizontal { display: none; }

@media (min-width: 768px) {
  .cancha--vertical { display: none; }
  .cancha--horizontal { display: block; }
}

/* Teléfono acostado: el viewport queda ancho y bajo, que es la peor combinación
   posible para una cancha vertical. Aquí la orientación manda sobre el ancho,
   porque es lo que la geometría realmente pide. */
@media (orientation: landscape) and (max-height: 480px) {
  .cancha--vertical { display: none; }
  .cancha--horizontal { display: block; }
}
