/* ============================================================
   HUB DE PARTIDOS — Club Voleibol Villalba

   Portada a todo el ancho, pestañas por equipo y carruseles
   horizontales.

   Depende de styles.css (tokens, .btn, .eyebrow) y de
   teams-matches.css (.chip, .mcard, .season-picker). Cada bloque
   hereda --accent y --grad de su clase de tema.

   Mejora progresiva: sin JavaScript se ven todas las categorías y
   todas sus temporadas, una detrás de otra. La clase .is-enhanced
   la pone matches-hub.js.
   ============================================================ */

/* ---------------- Portada -----------------------------------
   Miniatura del vídeo a todo el ancho con el texto encima, abajo
   a la izquierda. La categoría se sortea en el servidor en cada
   carga: no rota, así que no hay nada que pausar ni que esperar.
   ------------------------------------------------------------ */

.hub-hero {
  position: relative;
  /* No llega a los bordes de la ventana: el bloque acaba donde acaban las
     tarjetas de los carruseles (--maxw menos los 1.5rem de margen lateral),
     así que la portada y las pestañas comparten el mismo ancho útil.
     Al dejar de ir a sangre, la cabecera fija ya no la tapa: de ahí el
     margen superior de 76px (alto de .site-header__bar) más aire. */
  width: calc(100% - 3rem);
  max-width: calc(var(--maxw) - 3rem);
  margin: calc(76px + 1.5rem) auto 0;
  height: clamp(30rem, 78vh, 47.5rem);
  display: flex; align-items: flex-end;
  border: 1px solid var(--color-line); border-radius: 1.25rem;
  background: var(--color-ink-2);
  overflow: hidden;
}
/* La miniatura de YouTube es 16/9 y aquí manda el alto, así que se
   recorta por los lados y se ancla arriba, donde suele estar la acción. */
.hub-hero__img {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover; object-position: center 30%;
}
.hub-hero__img--ph {
  display: block;
  background: linear-gradient(135deg, var(--grad-a), var(--grad-b));
  opacity: 0.5;
}
/* Dos capas, lo justo para leer el texto sin apagar la miniatura: la
   imagen tiene que seguir pareciendo un vídeo que se puede ver, no un
   fondo decorativo. El grueso del contraste lo pone la sombra del tipo.
   Ya no hace falta la franja de arriba: la portada no va a sangre, así que
   la cabecera fija no se le monta encima. */
.hub-hero__scrim {
  position: absolute; inset: 0;
  background:
    linear-gradient(to top,
      rgb(var(--color-ink-rgb) / 0.85) 0%,
      rgb(var(--color-ink-rgb) / 0.6) 16%,
      rgb(var(--color-ink-rgb) / 0.22) 42%,
      rgb(var(--color-ink-rgb) / 0) 64%),
    linear-gradient(to right,
      rgb(var(--color-ink-rgb) / 0.7) 0%,
      rgb(var(--color-ink-rgb) / 0.45) 22%,
      rgb(var(--color-ink-rgb) / 0.14) 46%,
      rgb(var(--color-ink-rgb) / 0) 66%);
}
.hub-hero__inner {
  position: relative; z-index: 2;
  width: 100%; margin: 0 auto; max-width: var(--maxw);
  padding: 0 1.5rem 3.5rem;
}
.hub-hero__title {
  max-width: 24ch;
  font-family: var(--font-display); font-weight: 400; text-transform: uppercase;
  /* Anton apretado a 0.94 se comía las tildes de las mayúsculas, que el
     recorte a dos líneas cortaba por arriba: «¡ALLÁ VAMOS!» salía sin tilde. */
  line-height: 1.05; font-size: clamp(2.25rem, 5.2vw, 4.25rem);
  text-wrap: balance;
  text-shadow: 0 2px 6px rgb(var(--black-rgb) / 0.6), 0 4px 30px rgb(var(--black-rgb) / 0.7);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.hub-hero__meta {
  margin-top: 1.125rem;
  display: flex; align-items: center; flex-wrap: wrap; gap: 0.5rem 0.75rem;
  font-size: 0.75rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.18em;
  color: rgb(var(--color-bone-rgb) / 0.82);
  text-shadow: 0 1px 4px rgb(var(--black-rgb) / 0.7), 0 2px 18px rgb(var(--black-rgb) / 0.7);
}
.hub-hero__sep {
  width: 4px; height: 4px; border-radius: 999px; flex: 0 0 auto;
  background: var(--accent);
}
.hub-hero__actions {
  margin-top: 1.75rem;
  display: flex; align-items: center; gap: 0.875rem; flex-wrap: wrap;
}
.hub-hero__actions .btn--ghost {
  border-color: rgb(var(--color-bone-rgb) / 0.35);
  background: rgb(var(--color-ink-rgb) / 0.45);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}


/* Buscador: mismo trato que el de la vista anterior (.filters__search). */
.hub-search {
  flex: 0 0 auto;
  display: flex; align-items: center; gap: 0.625rem;
  border: 1px solid var(--color-line); border-radius: 999px;
  padding: 0.5rem 1.125rem; width: min(20rem, 34vw);
  color: var(--color-mute);
  transition: border-color var(--duration-fast) ease;
}
.hub-search[hidden] { display: none; }
.hub-search:focus-within { border-color: rgb(var(--accent-rgb) / 0.6); }
.hub-search input {
  flex: 1; min-width: 0; border: 0; background: none; outline: none;
  font: inherit; font-size: 0.875rem; color: var(--color-bone);
}
.hub-search input::placeholder { color: var(--color-mute); }
.hub-search__count {
  margin: 0 auto; max-width: var(--maxw);
  padding: 0 1.5rem 0.75rem;
  font-size: 0.6875rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.18em;
  color: var(--color-mute);
}
.hub-search__count:empty { display: none; }

/* En modo búsqueda se ven todas las categorías a la vez: lo que importa
   es el resultado, no en qué pestaña estaba el visitante. */
.hub-buscando .hub-tab { opacity: 0.4; pointer-events: none; }
.hub-buscando .hub-archive__head { display: none; }
/* Con varias temporadas abiertas a la vez hay que decir cuál es cuál. */
.hub-buscando .hub-archive.is-enhanced [data-archive-season] .hub-row__heading { display: contents; }
.hub-panel__marca {
  margin: 0 auto; max-width: var(--maxw); padding: 2.5rem 1.5rem 0;
  display: none;
}
.hub-panel__marca-in {
  display: inline-flex; align-items: center; gap: 0.75rem;
  border-radius: 999px; padding: 0.3125rem 0.875rem;
  margin-left: -0.875rem;
  background: var(--hub-plate-strong);
  font-family: var(--font-display); font-size: 1.125rem;
  text-transform: uppercase; letter-spacing: 0.04em; color: var(--accent);
}
.hub-buscando .hub-panel__marca { display: block; }
.hub-buscando .mcard[hidden] { display: none; }

/* ---------------- Panel de categoría ------------------------ */

.hub-panel { scroll-margin-top: 140px; }
.hub-panel[hidden] { display: none; }

/* ---------------- Fondo del panel --------------------------- */

/* Cada categoria lleva su propio degradado, generado como imagen en vez de
   apilar radiales en CSS: las capas de gradiente daban bandas y no llegaban al
   acabado que se buscaba. Son WebP de 1920 px, entre 12 y 21 kB, lisos y sin
   grano.

   Van con background-attachment: fixed porque un panel abierto mide varios
   miles de pixeles: anclada a su caja la imagen se estiraba, y anclada al
   viewport se ve entera se mire donde se mire. Las rutas son relativas a este
   archivo, que es lo que hace que funcionen igual en la raiz del dominio y en
   un subdirectorio. */
.hub-panel {
  position: relative; overflow: hidden;
  background-color: var(--color-ink);
  background-image: var(--hub-mesh);
  background-size: cover;
  background-position: center center;
  background-repeat: no-repeat;
  background-attachment: fixed;
}
.hub-panel > * { position: relative; z-index: 1; }

/* Superficie oscura para el texto que va sobre la malla.
   La imagen de fondo va de casi negro (0,01 de luminancia en Primera
   Nacional y Junior) a lima y amarillo (0,77 y 0,87 en Superliga 2 y
   Primera Nacional), y con background-attachment: fixed cualquier texto
   puede acabar sobre cualquiera de esas zonas: no hay un solo color de
   letra que llegue al 4,5:1 de AA en las cuatro categorías. Mismo
   recurso que .team-block en teams-matches.css: cada pieza de texto
   lleva su propio fondo de tinta y vuelve al hueso, que sobre el peor
   punto de la malla da 10:1. La versión 'strong' es para el texto
   pequeño y para el que va en color de acento, donde el margen es
   menor (el rosa de Senior Autonómica es el más justo: 5:1). */
.hub-panel {
  --hub-plate: rgb(var(--color-ink-rgb) / 0.78);
  --hub-plate-strong: rgb(var(--color-ink-rgb) / 0.92);
}

/* El fondo anclado al viewport se desplaza respecto al contenido al hacer
   scroll, y eso es movimiento. A quien lo tenga desactivado se le ancla a la
   caja del panel. */
@media (prefers-reduced-motion: reduce) {
  .hub-panel { background-attachment: scroll; }
}

/* Verde esmeralda a lima, sin negro: la franja entera es de color. */
.hub-panel.theme-sf2 { --hub-mesh: url("../img/gradients/sf2.webp"); }
/* Negro con el haz lima cruzando en diagonal y el cian abajo a la izquierda. */
.hub-panel.theme-pn { --hub-mesh: url("../img/gradients/pn.webp"); }
/* Amarillo y rosa con el embudo magenta subiendo por el centro. */
.hub-panel.theme-senior { --hub-mesh: url("../img/gradients/senior.webp"); }
/* Ambar a la izquierda, turquesa arriba y azul marino a la derecha. */
.hub-panel.theme-junior { --hub-mesh: url("../img/gradients/junior.webp"); }

/* ---------------- Fila / carrusel --------------------------- */

.hub-row {
  position: relative;
  margin: 0 auto; max-width: var(--maxw); padding: 1.5rem 1.5rem 0;
}
.hub-row:last-child { padding-bottom: 2.5rem; }
.hub-row[hidden] { display: none; }
/* Rotulo, distintivo de temporada y flechas van en la misma linea. El
   envoltorio del rotulo se disuelve con display: contents para que sus
   dos hijos sean piezas de esta misma fila; estrecho, el titulo ocupa el
   ancho entero y empuja al resto a una segunda linea. */
.hub-row__head {
  display: flex; align-items: center; justify-content: flex-start;
  gap: 0.75rem 1rem; flex-wrap: wrap; margin-bottom: 0.875rem;
}
.hub-row__heading { display: contents; }
.hub-row__title {
  flex: 0 0 100%;
  font-family: var(--font-display); font-weight: 400; font-size: 1.5rem;
  text-transform: uppercase; letter-spacing: 0.04em;
  color: var(--color-ink);
}
.hub-row__note {
  margin-top: 0;
  display: flex; align-items: center; gap: 0.625rem; flex-wrap: wrap;
}
.hub-row__notetext { font-size: 0.75rem; line-height: 1.5; color: var(--color-mute); max-width: 42rem; }
/* El distintivo de temporada comparte línea con el rótulo, y desde que el
   archivo trae su desplegable al lado conviene que los dos digan lo mismo
   con la misma letra: 0.875rem, la del select. */
.hub-row__note .chip--sm {
  padding: 0.375rem 0.875rem;
  font-size: 0.875rem; letter-spacing: 0.1em;
}
/* El acento necesita el fondo más opaco: sobre la placa normal el rosa de
   Senior se queda en 3,2:1. */
.chip--accent {
  border-color: rgb(var(--accent-rgb) / 0.55); color: var(--accent);
  background: var(--hub-plate-strong, rgb(var(--accent-rgb) / 0.1));
}

.hub-row__arrows { display: flex; align-items: center; gap: 0.5rem; margin-left: auto; }
.hub-row__arrows[hidden] { display: none; }
.hub-arrow {
  display: grid; place-items: center; width: 2.75rem; height: 2.75rem;
  border-radius: 999px; border: 1px solid rgb(var(--color-bone-rgb) / 0.22);
  background: var(--hub-plate);
  color: var(--color-bone);
  transition: border-color var(--duration-fast) ease, color var(--duration-fast) ease;
}
.hub-arrow:hover:not(:disabled) { border-color: rgb(var(--accent-rgb) / 0.6); color: var(--accent); }
/* Apagar la flecha entera la dejaba de fantasma sobre la malla: se apaga
   el icono y el disco se queda, que es lo que la mantiene legible. */
.hub-arrow:disabled {
  cursor: default;
  border-color: rgb(var(--color-bone-rgb) / 0.1);
  color: rgb(var(--color-bone-rgb) / 0.32);
}

/* El carrusel es scroll nativo: dedo, rueda y teclado funcionan sin JS.
   Las flechas son un añadido. */
.hub-track {
  display: flex; gap: 1.5rem;
  overflow-x: auto; overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
  padding-bottom: 0.5rem;
  scrollbar-width: none;
}
.hub-track::-webkit-scrollbar { display: none; }
.hub-track:focus-visible { outline: 2px solid var(--accent); outline-offset: 6px; border-radius: 4px; }
.hub-track > .mcard { flex: 0 0 17rem; scroll-snap-align: start; }

/* Desvanecido del borde derecho mientras queda carrusel por recorrer. Es una
   mascara, no una capa de tinta encima: sobre la malla del panel la capa se
   veia como una banda negra en vertical. Asi se difuminan las tarjetas y lo
   que asoma detras es el propio fondo de la categoria. */
.hub-row__viewport { position: relative; }
.hub-row.has-more .hub-row__viewport {
  -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 5rem), transparent);
  mask-image: linear-gradient(to right, #000 calc(100% - 5rem), transparent);
}

/* ---------------- Archivo de temporadas --------------------- */

/* Misma linea que cierra el bloque de otras categorias: separa el archivo
   de la fila de la temporada en curso con el mismo aire arriba y abajo. */
.hub-archive {
  margin-top: 1.5rem;
  border-top: 2px solid var(--color-ink);
}
.hub-archive__head {
  margin: 0 auto; max-width: var(--maxw); padding: 1.5rem 1.5rem 0;
  /* El desplegable va pegado al rótulo, no al otro extremo de la fila:
     separados, no se leía que uno mandaba sobre el otro. */
  display: flex; align-items: center; justify-content: flex-start;
  gap: 1rem; flex-wrap: wrap;
}
.hub-archive__head[hidden] { display: none; }
/* Con JavaScript la cabecera se muda dentro de la fila de la temporada
   elegida (matches-hub.js): ahi se disuelve para que el rotulo, el
   desplegable y las flechas de esa fila sean piezas de la misma linea.
   Buscando se ven todas las temporadas y la cabecera sobra, asi que la
   regla de .hub-buscando sigue mandando. */
body:not(.hub-buscando) .hub-row__head > .hub-archive__head { display: contents; }
/* Con el selector encendido, el título propio de cada fila del archivo
   sobra: lo dice el desplegable. */
.hub-archive.is-enhanced [data-archive-season] .hub-row__heading { display: none; }
.hub-archive.is-enhanced [data-archive-season] .hub-row { padding-top: 1.5rem; }
.hub-archive.is-enhanced [data-archive-season] .hub-row__head { margin-bottom: 0.75rem; }
/* La fila del archivo es hija única de su temporada, así que heredaba el
   colchón de «última fila del panel» y abría un hueco muerto antes de la
   tira de otras categorías. Ese colchón solo le toca a la última de verdad. */
.hub-archive [data-archive-season] .hub-row:last-child { padding-bottom: 0; }

.hub-panel .season-picker__chevron { color: rgb(var(--color-bone-rgb) / 0.7); }

/* ---------------- Tira de las otras categorías -------------- */

/* Cierra el bloque, así que se separa del archivo con una línea y
   pierde el acento de la categoría del panel: lo que hay dentro es
   de otras, y cada tarjeta lleva el suyo. */
.hub-otras {
  margin-top: 1.5rem;
  border-top: 2px solid var(--color-ink);
}
/* Buscando estorba: son recomendaciones, no resultados. */
.hub-buscando .hub-otras { display: none; }

/* ---------------- Estado vacío ------------------------------ */


/* ---------------- Cabeceras en una sola linea --------------- */

/* Con sitio de sobra el rotulo, el distintivo o el desplegable y las
   flechas caben en la misma horizontal. */
@media (min-width: 1024px) {
  .hub-row__title { flex: 0 1 auto; }
}

/* ---------------- Adaptación a pantallas pequeñas ----------- */

@media (max-width: 1023px) {
  .hub-archive__head .hub-row__title { align-self: flex-start; }
  .season-picker { flex-wrap: wrap; }
}

@media (max-width: 767px) {
  .hub-hero__inner, .hub-row, .hub-archive__head { padding-inline: 1rem; }
  /* En vertical la foto se ve poco y el texto se come la pantalla:
     menos alto, y el degradado inferior sube para que quepan las
     tres piezas sin tapar del todo la imagen. */
  .hub-hero {
    width: calc(100% - 2rem); max-width: none;
    margin-top: calc(76px + 1rem); border-radius: 1rem;
    height: clamp(26rem, 62vh, 34rem);
  }
  .hub-hero__inner { padding-bottom: 2.25rem; }
  .hub-hero__title { max-width: none; font-size: clamp(1.75rem, 8vw, 2.5rem); }
  .hub-hero__meta { margin-top: 0.875rem; font-size: 0.6875rem; letter-spacing: 0.14em; }
  .hub-hero__actions { margin-top: 1.25rem; flex-direction: column; align-items: stretch; }
  .hub-hero__actions .btn { width: 100%; }
  .hub-row__head { flex-direction: column; align-items: flex-start; }
  .hub-row__arrows { display: none; }
  .hub-row__viewport::after { width: 3rem; }
  .hub-track { gap: 1rem; }
  .hub-track > .mcard { flex-basis: 16rem; }
  .hub-tabs__bar { padding-inline: 1rem; }
  .hub-search__count { padding-inline: 1rem; }
}

/* ---------------- Barra de pestañas y buscador -------------- */

/* Mientras quepa todo en una línea, categorías a la izquierda y buscador
   a la derecha. En cuanto deja de caber se apilan: el buscador baja y la
   franja de pestañas se queda con el ancho entero, que es lo que les
   permite seguir en una sola fila un buen rato más. Apilados, la pestaña
   activa ya no apoya en el borde inferior de la barra, así que su bloque
   se pinta entero en vez de quedar abierto por abajo. */
@media (max-width: 1279px) {
  .hub-tabs__bar { flex-direction: column; align-items: stretch; gap: 0; }
  .hub-tabs__inner { width: 100%; padding-block: 0.5rem; }
  .hub-search { width: 100%; margin-bottom: 0.875rem; }
  .hub-tab::after { top: 0; border-radius: 10px; }
}
