/* =========================================================
   Concurso de escaparates del Zinemaldia 2026 · San Sebastián Shops
   Hoja de estilos única. Móvil primero, sin dependencias.
   ========================================================= */

:root {
  /* Azul de acción sobre fondo claro (el --azul del tema está pensado para fondo oscuro). */
  --azul-sobre-claro: #0b57c7;
  /* Fondo: azul profundo arriba, negro abajo */
  --noche: #0a1c38;
  --noche-2: #05101f;
  --negro: #000000;

  /* Superficies translúcidas sobre el fondo (materiales, no cajas opacas) */
  --fondo-suave: rgba(255, 255, 255, .055);
  --superficie-alta: rgba(255, 255, 255, .09);
  --linea: rgba(255, 255, 255, .1);
  --linea-fuerte: rgba(255, 255, 255, .2);

  --acento: #ffc629;        /* amarillo de la campaña: solo la acción principal */
  --acento-oscuro: #ffd75e;
  --tinta-acento: #14181f;  /* texto sobre el amarillo */

  --texto: #f4f6fa;
  --texto-suave: rgba(236, 241, 250, .62);
  --azul: #7fb0ff;          /* enlaces */
  --azul-oscuro: #a9c9ff;   /* hover: sobre oscuro se aclara */
  --azul-tinta: #ffffff;    /* titulares */
  --azul-claro: rgba(255, 255, 255, .08);

  --rojo: #ff9d92;          /* errores sobre fondo oscuro */
  --rojo-input: #d13a2e;    /* errores sobre el blanco de los campos */
  --rojo-fondo: rgba(190, 45, 36, .16);
  --rojo-linea: rgba(255, 157, 146, .32);
  --verde: #7fe0a9;
  --verde-fondo: rgba(38, 130, 86, .18);

  /* Tipografía del sistema: en Mac y iPhone es San Francisco, que ya trae el ajuste óptico */
  --fuente: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Segoe UI", Roboto, "Helvetica Neue", Helvetica, Arial, sans-serif;
  --fuente-display: -apple-system, BlinkMacSystemFont, "SF Pro Display", "Segoe UI", Roboto, "Helvetica Neue", Helvetica, Arial, sans-serif;

  --radio: 18px;
  --radio-s: 12px;
  --wrap: 1120px;
  --alto-cabecera: 72px;
  --pad-main: 32px; /* separación superior del contenido; el hero la descuenta para llegar al borde */
  --sombra: 0 4px 16px rgba(0, 0, 0, .3), 0 24px 60px rgba(0, 0, 0, .35);
}

/* ---------- Base ---------- */

*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  background: var(--negro); /* el rebote de scroll en iOS no debe dejar ver blanco */
  /* El hero a sangre mide 100vw, que en Windows incluye el ancho de la barra de scroll y
     asomaría en horizontal. "clip" lo recorta sin crear contenedor de scroll, así que la
     cabecera pegajosa sigue funcionando (a diferencia de overflow: hidden). */
  overflow-x: clip;
}

body {
  margin: 0;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  background: var(--negro);
  /* Dos capas. La de abajo (segunda) es el degradado de siempre: azul profundo arriba que se
     apaga hacia el negro, con el tramo en píxeles para que no se estire distinto en cada página.
     La de encima (primera) va anclada al pie y devuelve el azul al final del recorrido, de modo
     que la página cierra con el mismo tono con el que abre. Su alto es fijo, así que el efecto
     es igual en una página larga que en una corta. */
  background-image:
    linear-gradient(to top, var(--noche) 0, var(--noche-2) 46%, rgba(5, 16, 31, 0) 100%),
    linear-gradient(180deg, var(--noche) 0px, var(--noche-2) 620px, var(--negro) 1100px);
  background-repeat: no-repeat, no-repeat;
  background-position: bottom center, top center;
  background-size: 100% 560px, 100% 100%;
  color: var(--texto);
  font-family: var(--fuente);
  font-size: 1.0625rem; /* 17px, la medida de texto de iOS */
  line-height: 1.5;
  letter-spacing: -.01em;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

img, svg { display: block; max-width: 100%; }
img { height: auto; }

[hidden] { display: none !important; }

/* El interletrado se aprieta a medida que el texto crece: a tamaño grande, el espaciado normal
   se lee suelto. El interlineado hace lo contrario, se abre en el texto corrido. */
h1, h2, h3 {
  font-family: var(--fuente-display);
  color: var(--azul-tinta);
  margin: 0 0 .4em;
  overflow-wrap: anywhere;
  font-weight: 700;
}
h1 { font-size: clamp(2.125rem, 4.5vw + .8rem, 3.5rem); line-height: 1.06; letter-spacing: -.035em; }
h2 { font-size: clamp(1.375rem, 1.8vw + .7rem, 1.875rem); line-height: 1.15; letter-spacing: -.025em; }
h3 { font-size: 1.0625rem; line-height: 1.3; letter-spacing: -.015em; }
p { margin: 0 0 1em; }

a { color: var(--azul); }
a:hover { color: var(--azul-oscuro); }

button, input { font: inherit; color: inherit; }
button { cursor: pointer; }

:focus-visible {
  outline: 3px solid var(--azul);
  outline-offset: 3px;
  border-radius: 4px;
}

.visually-hidden {
  position: absolute !important;
  width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
}

.wrap {
  width: 100%;
  max-width: var(--wrap);
  margin-inline: auto;
  padding-inline: 20px;
}

main.wrap {
  flex: 1 0 auto;
  padding-top: var(--pad-main);
  padding-bottom: 72px;
}

/* Enlace de salto: solo visible con foco */
.skip {
  position: absolute;
  top: -100px;
  left: 12px;
  z-index: 100;
  padding: 10px 16px;
  background: var(--acento);
  color: var(--tinta-acento);
  border-radius: var(--radio-s);
  font-weight: 700;
  text-decoration: none;
}
.skip:focus { top: 12px; outline-color: #fff; }

/* ---------- Cabecera ---------- */

/* Testigo del scroll: ocupa 8 px y los recupera con el margen, para no mover nada de sitio.
   Al desaparecer de la pantalla, la cabecera pasa a translúcida (así no parpadea con el rebote). */
.header-sentinel { height: 8px; margin-bottom: -8px; }

/* Arriba del todo la cabecera es transparente: al desplazar aparece el material translúcido,
   con el contenido pasando por debajo en lugar de chocar con una franja opaca. */
.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  background: transparent;
  /* La línea inferior va como sombra, no como borde: así la cabecera mide exactamente
     --alto-cabecera y el hero puede subir hasta el borde de la pantalla sin descuadres. */
  box-shadow: 0 1px 0 rgba(255, 255, 255, 0);
  backdrop-filter: blur(0px);
  -webkit-backdrop-filter: blur(0px);
  transition: background-color .3s ease, box-shadow .3s ease,
              backdrop-filter .3s ease, -webkit-backdrop-filter .3s ease;
}
.site-header.is-scrolled {
  background: rgba(7, 16, 32, .62);
  backdrop-filter: saturate(180%) blur(22px);
  -webkit-backdrop-filter: saturate(180%) blur(22px);
  box-shadow: 0 1px 0 rgba(255, 255, 255, .08);
}
@media (prefers-reduced-transparency: reduce) {
  .site-header.is-scrolled { background: #08111f; backdrop-filter: none; -webkit-backdrop-filter: none; }
}
.header-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  min-height: var(--alto-cabecera);
}
.brand { display: inline-flex; align-items: center; min-height: 44px; text-decoration: none; }
.brand img { height: 52px; width: auto; }
.brand-text { font-weight: 800; color: var(--azul); letter-spacing: -.01em; }

.lang { display: flex; align-items: center; gap: 2px; font-size: .875rem; font-weight: 700; color: var(--texto-suave); }
.lang a {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 44px; min-height: 44px;
  color: var(--texto-suave);
  text-decoration: none;
  border-radius: var(--radio-s);
}
.lang a:hover { color: var(--azul-tinta); background: rgba(255, 255, 255, .12); }
.lang a[aria-current="true"] {
  color: var(--azul-tinta);
  text-decoration: underline;
  text-decoration-thickness: 2px;
  text-underline-offset: 5px;
  text-decoration-color: var(--acento);
}

/* ---------- Hero a pantalla completa ---------- */

/*
 * La foto ocupa la primera pantalla y sube por detrás de la cabecera transparente; el contenido
 * del concurso empieza al desplazar. El texto va abajo a la izquierda, como en el cartel.
 */
.hero-full {
  position: relative;
  width: 100vw;
  margin-left: calc(50% - 50vw);
  margin-top: calc(-1 * (var(--alto-cabecera) + var(--pad-main)));
  margin-bottom: 4px;
  min-height: 100vh;
  min-height: 100svh; /* en móvil, la altura sin la barra del navegador: evita saltos al desplazar */
  display: flex;
  align-items: flex-end;
}

.hero-full-media {
  position: absolute;
  inset: 0;
  /* El final se desvanece con una máscara en vez de con un degradado opaco: así empalma con el
     fondo de la página sin costura, caiga donde caiga el degradado. */
  -webkit-mask-image: linear-gradient(to bottom, #000 84%, transparent 100%);
  mask-image: linear-gradient(to bottom, #000 84%, transparent 100%);
}
.hero-full-media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 64% center; /* deja el escaparate a la vista y el paseo bajo el texto */
}
/* Veladuras (dentro de la máscara, para que se desvanezcan con ella): abajo para que el texto
   se lea sobre el pavimento iluminado, arriba para el logo y el selector de idioma. */
.hero-full-media::after {
  content: "";
  position: absolute;
  inset: 0;
  background:
    linear-gradient(to top, rgba(2, 8, 18, .97) 0, rgba(2, 8, 18, .95) 32%, rgba(2, 8, 18, .92) 58%, rgba(2, 8, 18, .78) 80%, rgba(2, 8, 18, .25) 95%, rgba(2, 8, 18, 0) 100%),
    linear-gradient(to bottom, rgba(2, 8, 18, .5) 0, rgba(2, 8, 18, 0) 22%);
}

.hero-full-inner {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  padding-top: calc(var(--alto-cabecera) + 14px);
  padding-bottom: 12px;
}
.hero-full-texto { max-width: 34rem; text-align: center; }
/* El antetítulo del hero es el nombre del concurso: pide más cuerpo que el de las páginas
   interiores, donde solo acompaña. */
.hero-full .eyebrow { margin-bottom: 10px; font-size: .875rem; letter-spacing: .05em; }
.hero-full-texto > *:last-child { margin-bottom: 0; }

/* Titular al tamaño del cartel, con un reflejo dorado que recorre las letras.
   El degradado solo se aplica si el navegador sabe recortarlo contra el texto; si no,
   el titular se queda blanco (que es el color base) en lugar de volverse invisible. */
.hero-full h1 {
  /* El degradado del titular se recorta contra la caja del elemento (background-clip: text), así
     que la tinta que sobresale por debajo de la última línea se quedaba fuera: en euskera se veía
     cortada la "g" de "gogokoena". El relleno mete esa tinta dentro de la caja y se descuenta del
     margen, para que el bloque siga ocupando lo mismo. */
  padding-bottom: .1em;
  margin-bottom: max(0px, calc(12px - .1em));
  font-size: clamp(3.25rem, 15vw, 5rem);
  line-height: 1.02;
  letter-spacing: -.035em;
}
@supports ((background-clip: text) or (-webkit-background-clip: text)) {
  .hero-full h1 {
    background-image: linear-gradient(100deg,
      #fff 0%, #fff 26%, var(--acento) 42%, #fff3cd 50%, var(--acento) 58%, #fff 74%, #fff 100%);
    background-size: 260% 100%;
    background-position: 130% 0;
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
    -webkit-text-fill-color: transparent;
    animation: titular-reflejo 7s linear infinite;
  }
}
@keyframes titular-reflejo {
  from { background-position: 130% 0; }
  to   { background-position: -130% 0; }
}
.hero-full .lead { margin-bottom: 14px; color: rgba(255, 255, 255, .82); }

/* Firma institucional del hero: el Gobierno Vasco, que promueve el concurso junto a Shops,
   con más presencia aquí que en la franja del pie. */
.hero-institucional { margin-top: 26px; }
.hero-institucional-logo {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  opacity: .95;
  transition: opacity .15s ease;
}
.hero-institucional-logo:hover { opacity: 1; }
.hero-institucional-logo img { width: 158px; height: auto; }

/* Indicador de que el contenido continúa abajo: centrado bajo el texto, en blanco y
   con la rueda bajando dentro del ratón para imitar el gesto de desplazar. */
.hero-cue {
  align-self: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 9px;
  padding: 2px 10px 0;
  color: #fff;
  font-size: .875rem;
  font-weight: 700;
  letter-spacing: .01em;
  text-align: center;
  text-decoration: none;
  text-shadow: 0 1px 10px rgba(2, 8, 18, .8);
}
.hero-cue-raton {
  position: relative;
  width: 26px;
  height: 42px;
  flex: none;
  border: 2px solid #fff;
  border-radius: 999px;
  box-shadow: 0 2px 12px rgba(2, 8, 18, .55);
  animation: hero-cue-bajar 2.6s ease-in-out infinite;
}
.hero-cue-rueda {
  --viaje: 15px; /* lo que baja la rueda: el alto libre del ratón menos su propio alto */
  position: absolute;
  top: 7px;
  left: 50%;
  width: 4px;
  height: 8px;
  margin-left: -2px;
  border-radius: 2px;
  background: #fff;
  animation: hero-cue-rueda 2.6s cubic-bezier(.45, 0, .2, 1) infinite;
}
.hero-cue:hover .hero-cue-raton,
.hero-cue:focus-visible .hero-cue-raton { box-shadow: 0 0 0 4px rgba(255, 255, 255, .22); }
/* La rueda arranca arriba, baja hasta el fondo del ratón y se desvanece para volver a empezar. */
@keyframes hero-cue-rueda {
  0%        { transform: translateY(0);                  opacity: 0; }
  16%       { transform: translateY(2px);                 opacity: 1; }
  62%       { transform: translateY(var(--viaje));        opacity: 1; }
  84%, 100% { transform: translateY(var(--viaje));        opacity: 0; }
}
@keyframes hero-cue-bajar {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(4px); }
}

/* Solo cuando la pantalla es bastante más ancha que el bloque de texto tiene sentido la
   veladura lateral: oscurece la izquierda, donde va el texto, y deja limpio el escaparate de la
   derecha. Por debajo de eso (móviles y tabletas en vertical) el texto ocupa casi todo el ancho
   y la que cubre es la de abajo arriba, que es la del bloque base. */
@media (min-width: 1000px) {
  .hero-full-media::after {
    background:
      linear-gradient(to right, rgba(2, 8, 18, .95) 0, rgba(2, 8, 18, .92) 38%, rgba(2, 8, 18, .84) 58%, rgba(2, 8, 18, .38) 74%, rgba(2, 8, 18, 0) 92%),
      linear-gradient(to top, rgba(2, 8, 18, .62) 0, rgba(2, 8, 18, 0) 42%),
      linear-gradient(to bottom, rgba(2, 8, 18, .45) 0, rgba(2, 8, 18, 0) 20%);
  }
}

/* El ancla no debe quedar tapada por la cabecera pegada. */
#escaparates { scroll-margin-top: calc(var(--alto-cabecera) + 16px); }

/* Móviles que no llegan a la altura del iPhone X: el bloque no cabe holgado en una pantalla,
   así que se recortan los espaciados y el indicador para que la primera pantalla siga completa. */
@media (max-width: 699px) and (max-height: 810px) {
  .hero-full-inner {
    gap: 14px;
    padding-top: calc(var(--alto-cabecera) + 14px);
    padding-bottom: 14px;
  }
  .hero-institucional { margin-top: 18px; }
  .hero-institucional-logo { min-height: 0; }
  .hero-institucional-logo img { width: 132px; }
  .hero-cue { gap: 6px; font-size: .8125rem; }
  .hero-cue-raton { width: 22px; height: 34px; }
  .hero-cue-rueda { top: 5px; height: 7px; --viaje: 12px; }
}

/* Pantallas muy bajas (iPhone SE de primera generación y Android antiguos): ahí no cabe el
   titular grande, y el bloque se aprieta lo justo para que el indicador de desplazamiento no
   quede por debajo del borde. */
@media (max-width: 699px) and (max-height: 620px) {
  .hero-full-inner { padding-bottom: 6px; }
  .hero-full .eyebrow { margin-bottom: 8px; font-size: .8125rem; }
  .hero-full h1 { font-size: clamp(2.25rem, 8.6vw, 2.75rem); }
  .hero-full .lead { font-size: .9375rem; }
  .hero-institucional { margin-top: 10px; }
  .hero-institucional-logo img { width: 112px; }
}

@media (min-width: 700px) {
  /* El texto solo se centra en móvil; en escritorio va alineado a la izquierda, como el cartel.
     El indicador de desplazamiento sigue centrado (align-self en su propia regla). */
  .hero-full-inner { align-items: flex-start; padding-top: calc(var(--alto-cabecera) + 12px); padding-bottom: 18px; gap: 16px; }
  .hero-full-texto { max-width: 38rem; text-align: left; }
  /* El titular crece con el ancho, pero nunca más de lo que deja libre la altura de la ventana:
     la resta en vh es el sitio que ocupa el resto del bloque (entradilla, fecha, firma e
     indicador) y el divisor, las líneas que ocupa el titular. Así llena la pantalla en un monitor
     y no se desborda en un portátil de 768 px. */
  .hero-full .eyebrow { font-size: .9375rem; }
  .hero-full h1 { font-size: clamp(3.5rem, min(8.8vw, (100vh - 470px) / 3.06), 8rem); }
  /* En euskera las palabras son mucho más largas: pasado cierto cuerpo, "erakusleiho" no cabe en la
     columna, el navegador la parte por la mitad y el titular se va a cinco líneas que ya no caben en
     la pantalla (a 1440x900 se salía 208 px). El tope de cuerpo es por eso más bajo. */
  :lang(eu) .hero-full h1 { font-size: clamp(3.5rem, min(8.8vw, (100vh - 470px) / 3.06), 6.5rem); }
  .hero-institucional { margin-top: 28px; }
  .hero-institucional-logo img { width: 196px; }
}

/* ---------- Hero ---------- */

.hero { padding: 8px 0 20px; max-width: 46rem; }
/* En la home la acción es la cuadrícula: el hero cede altura para que entren tarjetas sin desplazar. */
.hero-home { padding-bottom: 12px; }
.hero-compact { padding-bottom: 8px; }
.eyebrow {
  margin: 0 0 12px;
  font-size: .75rem;
  font-weight: 600;
  letter-spacing: .06em; /* el texto pequeño en mayúsculas necesita algo de aire */
  text-transform: uppercase;
  color: var(--acento);
  text-wrap: balance; /* si parte en dos líneas, que queden parejas y no caiga una palabra sola */
}
.lead { font-size: 1.0625rem; line-height: 1.5; color: var(--texto-suave); max-width: 38rem; letter-spacing: -.012em; }
.hero .lead:last-child { margin-bottom: 0; }
.nowrap { white-space: nowrap; }

.cierre {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin: 2px 0 0;
  padding: 6px 12px;
  border-radius: 999px;
  background: var(--azul-claro);
  color: var(--azul-tinta);
  font-size: .875rem;
  font-weight: 600;
}
.cierre svg { flex: none; }

.card {
  margin-top: 24px;
  padding: 24px 20px;
  border: 1px solid var(--linea);
  border-radius: var(--radio);
  background: var(--fondo-suave);
}
.card h2 { margin-bottom: 4px; }


/* Escaparates en la previa: la misma cuadrícula que la home, precedida del aviso de cuándo se
   podrá votar. Mismo lenguaje que la pastilla del cierre en el hero, con el icono en el amarillo
   de la campaña para que el aviso se vea antes que las fotos. */
.previa-escaparates { margin-top: 28px; }
.previa-escaparates > h2 { margin-bottom: 10px; }
.aviso-apertura {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin: 0;
  padding: 8px 14px;
  border: 1px solid var(--linea-fuerte);
  border-radius: 999px;
  background: var(--azul-claro);
  color: var(--azul-tinta);
  font-size: .9375rem;
  font-weight: 600;
}
.aviso-apertura svg { flex: none; color: var(--acento); }

.prose { max-width: 44rem; }
.prose p { margin-bottom: 1em; }

/* ---------- Avisos ---------- */

.alert {
  margin: 0 0 20px;
  padding: 12px 16px;
  border: 1px solid;
  border-radius: var(--radio-s);
  font-weight: 500;
}
.alert-error { background: var(--rojo-fondo); border-color: var(--rojo-linea); color: #ffe3df; }
.alert-info { background: var(--azul-claro); border-color: rgba(255, 255, 255, .22); color: var(--azul-tinta); }

.vacio {
  margin: 24px 0 0;
  padding: 40px 20px;
  border: 1px dashed var(--linea);
  border-radius: var(--radio);
  text-align: center;
  color: var(--texto-suave);
}

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

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: 48px;
  padding: 12px 24px;
  border: 1px solid var(--linea-fuerte);
  border-radius: 999px;
  background: rgba(255, 255, 255, .09);
  color: #fff;
  font-weight: 600;
  font-size: 1.0625rem;
  line-height: 1.2;
  letter-spacing: -.01em;
  text-decoration: none;
  text-align: center;
  transition: background-color .2s ease, border-color .2s ease, color .2s ease, transform .1s ease-out;
}
.btn:hover { background: rgba(255, 255, 255, .16); border-color: rgba(255, 255, 255, .3); color: #fff; }
/* La respuesta va en la pulsación, no al soltar: es lo que hace que se sienta directo. */
.btn:active { transform: scale(.97); }
.btn svg { flex: none; }

/* El amarillo del cartel es la acción principal: votar y enviar el voto. */
.btn-primary { background: var(--acento); border-color: var(--acento); color: var(--tinta-acento); }
.btn-primary:hover { background: var(--acento-oscuro); border-color: var(--acento-oscuro); color: var(--tinta-acento); }

.btn-secondary { background: transparent; color: #fff; border-color: var(--linea-fuerte); }
.btn-secondary:hover { background: rgba(255, 255, 255, .12); color: #fff; border-color: rgba(255, 255, 255, .32); }

.btn-block { width: 100%; }

.link-arrow {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  min-height: 44px;
  font-weight: 700;
  text-decoration: none;
}
.link-arrow:hover { text-decoration: underline; }

/* ---------- Cuadrícula de escaparates ---------- */

.grid {
  list-style: none;
  margin: 16px 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
}

.tarjeta {
  display: flex;
  flex-direction: column;
  height: 100%;
  border: 1px solid var(--linea);
  border-radius: var(--radio);
  overflow: hidden;
  background: var(--fondo-suave);
  color: inherit;
  text-decoration: none;
  transition: transform .2s ease, box-shadow .2s ease, border-color .2s ease;
}
.tarjeta:hover { color: inherit; background: var(--superficie-alta); border-color: var(--linea-fuerte); transform: translateY(-3px); box-shadow: 0 10px 30px rgba(0, 0, 0, .35); }

/* El nombre lleva el enlace y su ::after se estira hasta cubrir la tarjeta entera: así toda la
   ficha es clicable sin anidar un <a> dentro de otro, y la etiqueta del barrio puede ser su
   propio enlace por encima. */
.tarjeta-enlace {
  color: inherit;
  text-decoration: none;
}
.tarjeta-enlace::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  border-radius: var(--radio);
}
.tarjeta-enlace:focus-visible { outline: none; }
.tarjeta-enlace:focus-visible::after {
  outline: 3px solid var(--azul);
  outline-offset: 2px;
}

.tarjeta-media {
  /* 3:2 es la proporción habitual de una foto de escaparate: recorta menos que 4:3 */
  aspect-ratio: 3 / 2;
  overflow: hidden;
  background: #0a0f18;
}
.tarjeta-media img, .tarjeta-media .placeholder { width: 100%; height: 100%; object-fit: cover; }
/* Foto vertical: el recorte 3:2 centrado se comería el rótulo del escaparate. Se sube el encuadre. */
.tarjeta-media.media-vertical img { object-position: 50% 30%; }
.ganador-foto.media-vertical img { object-position: 50% 30%; }

/* Pie de la tarjeta sobre blanco: separa el texto de la foto y hace que la ficha
   se lea como una diapositiva, igual que el escenario del carrusel. */
.tarjeta-body {
  display: flex;
  flex-direction: column;
  flex: 1;
  gap: 2px;
  padding: 12px 14px 14px;
  background: #fff;
  color: var(--tinta-acento);
}
.tarjeta-title {
  margin: 0;
  /* Hereda el color del cuerpo blanco: los encabezados del sitio son claros por defecto. */
  color: inherit;
  font-family: var(--fuente);
  font-weight: 600;
  font-size: 1rem;
  line-height: 1.3;
  letter-spacing: -.015em;
}
.tarjeta-meta { margin: 0; font-size: .8125rem; color: rgba(20, 24, 31, .66); }
/* Dirección: el dato que necesita quien quiere ir a ver el escaparate. */
.tarjeta-dir {
  display: flex;
  align-items: flex-start;
  gap: 5px;
  margin: 2px 0 0;
  color: rgba(20, 24, 31, .66);
  font-size: .8125rem;
  line-height: 1.35;
}
.tarjeta-dir svg { flex: none; margin-top: 2px; opacity: .75; }

/* Pie de la tarjeta: barrio a la izquierda, llamada a la acción a la derecha. */
.tarjeta-pie {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin-top: auto;
  padding-top: 10px;
}
/* La etiqueta del barrio filtra la cuadrícula. Va por encima del enlace que cubre la tarjeta
   (z-index 2 contra el 1 de .tarjeta-enlace::after), que si no se la comería. */
.tarjeta-barrio {
  position: relative;
  z-index: 2;
  display: inline-flex;
  align-items: center;
  min-height: 28px;
  padding: 3px 10px;
  border: 1px solid rgba(20, 24, 31, .16);
  border-radius: 999px;
  background: rgba(20, 24, 31, .04);
  color: rgba(20, 24, 31, .72);
  font-size: .75rem;
  font-weight: 600;
  text-decoration: none;
  transition: background-color .15s ease, border-color .15s ease, color .15s ease;
}
/* El chip mide 28 px de alto para no dominar la tarjeta, pero el área pulsable se amplía
   hasta los 44 px recomendados para el dedo, sin cambiar su aspecto. */
.tarjeta-barrio::before {
  content: "";
  position: absolute;
  inset: -8px -6px;
  border-radius: 999px;
}
.tarjeta-barrio:hover {
  border-color: var(--azul-sobre-claro);
  background: rgba(11, 87, 199, .08);
  color: var(--azul-sobre-claro);
}
.tarjeta-barrio.es-activo {
  border-color: var(--azul-sobre-claro);
  background: var(--azul-sobre-claro);
  color: #fff;
}
.tarjeta-barrio:focus-visible { outline-color: var(--azul-sobre-claro); }
/* En la cuadrícula de dos columnas del móvil no caben el barrio y "Ver escaparate" en la misma
   línea: el texto se partía en dos. Ahí se queda solo la flecha, que ya indica que se puede abrir. */
@media (max-width: 480px) {
  .tarjeta-cta-texto { display: none; }
  .tarjeta-pie { padding-top: 8px; }
}
.tarjeta-cta {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  font-size: .8125rem;
  font-weight: 700;
  color: var(--azul-sobre-claro);
}

/* Filtro por barrio activo: qué se está viendo y cómo volver a verlo todo. */
.filtro-activo {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 8px 16px;
  margin: 18px 0 0;
  padding: 12px 16px;
  border: 1px solid var(--linea);
  border-radius: var(--radio-s);
  background: var(--fondo-suave);
}
.filtro-activo p { margin: 0; color: var(--texto-suave); font-size: .9375rem; }
.filtro-activo b { color: var(--texto); font-weight: 700; }
.filtro-quitar {
  display: inline-flex;
  align-items: center;
  min-height: 32px;
  color: var(--azul);
  font-size: .875rem;
  font-weight: 600;
  text-decoration: none;
}
.filtro-quitar:hover { text-decoration: underline; }

/* ---------- Ficha de comercio ---------- */

.ficha { display: grid; gap: 20px; }

.ficha-head { display: flex; flex-direction: column; align-items: flex-start; gap: 6px; }
.ficha-head h1 { margin: 2px 0 0; font-size: clamp(1.5rem, 3.5vw + .5rem, 2.25rem); }

.back {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  min-height: 44px;
  margin-left: -4px;
  font-weight: 700;
  text-decoration: none;
}
.back:hover { text-decoration: underline; }

.ficha-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 16px;
  margin: 0;
  color: var(--texto-suave);
}
.meta-item { display: inline-flex; align-items: center; gap: 6px; }
.meta-item svg { flex: none; color: var(--azul); }
a.meta-item { color: var(--azul); font-weight: 600; text-decoration: none; min-height: 32px; }
a.meta-item:hover { text-decoration: underline; }

/* Va debajo de las fotos (se pide el voto después de ver el escaparate) y ocupa el ancho, como en el modal. */
.btn-ancla { margin-top: 0; }

.badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin: 0 0 4px;
  padding: 6px 12px;
  border-radius: 999px;
  background: var(--acento);
  color: #2a1d00;
  font-size: .75rem;
  font-weight: 800;
  letter-spacing: .06em;
  text-transform: uppercase;
}

/* Carrusel */
/* La foto manda: la caja adopta la proporción real de cada imagen en vez de forzar una única
   forma. La proporción viaja en los atributos width/height del <img> (los escribe PHP en la ficha
   y el JS en el modal), así que la caja tiene su tamaño definitivo antes de que lleguen los bytes:
   sin salto de maquetación y sin depender de JavaScript.
   La diapositiva sigue siendo blanca: ahora se ciñe en alto a cada foto y, en las verticales, el
   sobrante lateral lee como el margen de una diapositiva sobre el degradado oscuro. */
.carrusel {
  /* Tope de altura de la foto: la ÚNICA perilla de tamaño del visor. El par vh/dvh no se puede
     centralizar declarándolo dos veces dentro de la variable: en una custom property la
     declaración inválida no se descarta al analizar sino al calcular, y max-height acabaría
     valiendo 'none', es decir SIN TOPE. Por eso la versión dvh va dentro de @supports. */
  --foto-alto: min(62vh, 620px);
  border-radius: var(--radio);
  background: transparent;
}
@supports (height: 1dvh) { .carrusel { --foto-alto: min(62dvh, 620px); } }
.carrusel-stage { position: relative; background: #fff; border-radius: var(--radio); overflow: hidden; }

.carrusel-viewport {
  overflow-x: auto;
  overflow-y: hidden;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
}
.carrusel-viewport::-webkit-scrollbar { display: none; }
.carrusel.is-ready .carrusel-viewport {
  overflow: hidden;
  scroll-snap-type: none;
  touch-action: pan-y pinch-zoom;
  cursor: grab;
}
.carrusel.is-dragging .carrusel-viewport { cursor: grabbing; }

.carrusel-track {
  display: flex;
  transition: transform .35s cubic-bezier(.22, .61, .36, 1);
}
.carrusel.is-dragging .carrusel-track { transition: none; }

.carrusel-slide {
  position: relative; /* referencia del relleno desenfocado */
  flex: 0 0 100%;
  min-width: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  /* Suelo: protege las panorámicas extremas y el caso de imagen rota, que con este mecanismo
     colapsaría a 0 px de alto. */
  min-height: 180px;
  scroll-snap-align: start;
}
/* Relleno de los márgenes: cuando la foto no llena la caja (una vertical deja banda a los lados,
   una apaisada arriba y abajo), el hueco se cubre con la propia foto ampliada y desenfocada en vez
   de con blanco plano. Es una segunda <img> y no un background-image porque la CSP prohíbe los
   estilos en línea y la ficha tiene que funcionar sin JavaScript.
   Va con más especificidad que .carrusel-slide img para poder anular su geometría. */
.carrusel-slide .carrusel-fondo {
  position: absolute;
  inset: 0;
  z-index: 0;
  width: 100%;
  height: 100%;
  max-height: none;
  object-fit: cover;
  /* La escala esconde el borde transparente que el desenfoque deja alrededor. */
  transform: scale(1.18);
  filter: blur(26px) saturate(115%);
  opacity: .88;
  pointer-events: none;
}
.carrusel-slide .carrusel-foto { position: relative; z-index: 1; }
/* Sin transparencias, el margen vuelve a ser la diapositiva blanca de siempre. */
@media (prefers-reduced-transparency: reduce) {
  .carrusel-slide .carrusel-fondo { display: none; }
}

.carrusel-slide img {
  /* Un solo eje definido. El ancho lo pone la diapositiva y la altura sale de la proporción de los
     atributos width/height, recortada por el tope. Con los DOS ejes en auto la caja mediría 0x0
     hasta que llegara la imagen: salto de maquetación de cientos de píxeles. */
  width: 100%;
  height: auto;
  max-height: var(--foto-alto);
  object-fit: contain;
  user-select: none;
  -webkit-user-select: none;
  -webkit-user-drag: none;
}
.carrusel-vacio .placeholder { width: 100%; aspect-ratio: 4 / 3; border-radius: var(--radio); }

.carrusel-btn {
  position: absolute;
  top: 50%;
  z-index: 2;
  display: none;
  align-items: center;
  justify-content: center;
  width: 44px; height: 44px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  /* Círculo oscuro sobre la diapositiva blanca: se ve tanto sobre la foto como sobre el margen. */
  background: rgba(12, 18, 30, .58);
  color: #fff;
  box-shadow: none;
  transform: translateY(-50%);
  transition: background-color .15s ease;
}
.carrusel-btn:hover { background: rgba(12, 18, 30, .82); color: #fff; }
.carrusel-btn:focus-visible { outline-color: var(--acento); }
.carrusel-btn.prev { left: 10px; }
.carrusel-btn.next { right: 10px; }
.carrusel.is-ready .carrusel-btn { display: flex; }
/* En móvil las flechas taparían la foto: se navega deslizando y con los puntos (44 px de alto). */
@media (max-width: 699px) {
  .carrusel.is-ready .carrusel-btn { display: none; }
}

.carrusel-dots {
  display: none;
  justify-content: center;
  gap: 2px;
  padding: 2px 0 0;
}
.carrusel.is-ready .carrusel-dots { display: flex; }
.carrusel-dots button {
  display: grid;
  place-items: center;
  width: 32px; height: 44px;
  padding: 0;
  border: 0;
  background: transparent;
}
.carrusel-dots button::before {
  content: "";
  width: 9px; height: 9px;
  border-radius: 50%;
  background: rgba(255, 255, 255, .34);
  transition: transform .15s ease, background-color .15s ease;
}
.carrusel-dots button:hover::before { background: rgba(255, 255, 255, .7); }
.carrusel-dots button[aria-current="true"]::before { background: var(--acento); transform: scale(1.3); }

/* Formulario de voto */
.votar { margin-top: 8px; scroll-margin-top: 16px; }
.votar h2 { margin-bottom: 14px; }

.form-card {
  padding: 20px 18px 22px;
  border: 1px solid var(--linea);
  border-radius: var(--radio);
  background: var(--fondo-suave);
}

.field { margin-bottom: 18px; }
.field > label { display: block; margin-bottom: 6px; font-weight: 700; }

/* Los campos se quedan en blanco con texto oscuro: es lo que esperan el teclado y el autorrelleno del móvil. */
.input {
  width: 100%;
  min-height: 48px;
  padding: 10px 14px;
  border: 1.5px solid #b9c2cf;
  border-radius: var(--radio-s);
  background: #fff;
  color: #16233d;
  font-size: 16px; /* evita el zoom automático en iOS */
  transition: border-color .15s ease, box-shadow .15s ease;
}
.input:focus {
  outline: none;
  border-color: var(--acento);
  box-shadow: 0 0 0 3px rgba(255, 198, 41, .45);
}
.input[aria-invalid="true"] { border-color: var(--rojo-input); }
.input[aria-invalid="true"]:focus { box-shadow: 0 0 0 3px rgba(209, 58, 46, .4); }

.field-error {
  display: flex;
  gap: 6px;
  margin: 6px 0 14px;
  color: var(--rojo);
  font-size: .875rem;
  font-weight: 600;
}
.field-error::before { content: "\26A0"; flex: none; }
.field .field-error { margin-bottom: 0; }

.check {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  margin-bottom: 14px;
}
.check input {
  flex: none;
  width: 22px; height: 22px;
  margin: 2px 0 0;
  accent-color: var(--acento);
}
.check label { font-size: .9375rem; line-height: 1.45; }
.check-error { margin-bottom: 0; }
.check-error label { color: var(--rojo); font-weight: 600; }
/* La casilla también se marca: el cambio de color del texto solo se percibe poco en pantalla pequeña. */
.check-error input { outline: 2px solid var(--rojo); outline-offset: 2px; border-radius: 4px; }

.hp {
  position: absolute;
  left: -10000px;
  top: auto;
  width: 1px; height: 1px;
  overflow: hidden;
}

.field-turnstile { margin-top: 4px; }
.cf-turnstile { min-height: 65px; }

.form-nota { margin: 14px 0 16px; font-size: .8125rem; color: var(--texto-suave); }
.form-card .btn-block { font-size: 1.0625rem; min-height: 52px; }

.ganador-nota {
  padding: 20px;
  border: 2px solid var(--acento);
  border-radius: var(--radio);
  background: rgba(255, 198, 41, .14);
}
.ganador-nota h2 { margin-bottom: 4px; color: var(--acento); }
.ganador-nota p { margin: 0; color: #fff; }

/* ---------- Gracias ---------- */

.gracias {
  max-width: 36rem;
  margin: 16px auto 0;
  text-align: center;
}
.gracias .lead { margin-inline: auto; }
/* La regla del voto único: se enseña a todo el mundo, así que va en tono de nota, no de aviso. */
.gracias-unico {
  max-width: 28rem;
  margin: -6px auto 22px;
  color: var(--texto-suave);
  font-size: .875rem;
  line-height: 1.5;
}
.gracias-icon {
  display: grid;
  place-items: center;
  width: 76px; height: 76px;
  margin: 8px auto 20px;
  border-radius: 50%;
  background: var(--verde-fondo);
  color: var(--verde);
}

.share { display: flex; flex-direction: column; align-items: center; gap: 12px; margin: 28px 0 8px; }
.share-fallback { display: flex; flex-wrap: wrap; justify-content: center; gap: 12px; }
.copy-status { min-height: 1.5em; margin: 0; font-size: .9375rem; font-weight: 600; color: var(--verde); }
.js-copy.is-done { border-color: var(--verde); color: var(--verde); }
.gracias-volver { margin-top: 8px; }

/* ---------- Ganador (portada cerrada) ---------- */

.ganador {
  margin-top: 28px;
  border: 2px solid var(--acento);
  border-radius: var(--radio);
  overflow: hidden;
  background: var(--fondo-suave);
  box-shadow: var(--sombra);
}
.ganador-foto { display: block; background: #0a0f18; }
.ganador-foto img, .ganador-foto .placeholder { width: 100%; aspect-ratio: 4 / 3; object-fit: cover; }
.ganador-body { padding: 20px; }
.ganador-body h2 { margin: 8px 0 6px; font-size: clamp(1.5rem, 3vw + .5rem, 2rem); }
.ganador-body .ficha-meta { margin-bottom: 12px; }
.ganador-texto { color: var(--texto-suave); }

/* ---------- Pie ---------- */

.site-footer {
  margin-top: auto;
  padding: 56px 0 40px;
  border-top: 1px solid rgba(255, 255, 255, .07);
  font-size: .875rem;
  color: var(--texto-suave);
}
.footer-org { max-width: 44rem; margin: 0 auto 24px; text-align: center; }

/* Franja institucional como en el cartel: los logotipos en blanco directamente sobre el fondo,
   sin placa. --alto-logo es la altura del mayor (Shops) y cada logotipo la escala con su --f,
   que es su altura relativa en el cartel: así se conserva la proporción entre ellos. */
.logos {
  --alto-logo: 44px;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 20px 34px;
  max-width: 760px;
  margin: 0 auto 30px;
}
.logo-link {
  /* flex: none — si no, al no caber los cuatro en una línea el navegador los encoge
     en vez de pasarlos a la siguiente, y las imágenes colapsan a cero. */
  flex: none;
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 4px;
  border-radius: var(--radio-s);
  opacity: .92;
  transition: opacity .15s ease;
}
.logo-link:hover { opacity: 1; }
.logo-link img {
  height: calc(var(--alto-logo) * var(--f, 1));
  width: auto;
  object-fit: contain;
}
.logo-gobierno-vasco { --f: .834; }
.logo-ayuntamiento   { --f: .838; }
.logo-fomento        { --f: .383; }
.logo-shops          { --f: 1; }
.logo-zinemaldia     { --f: .42; }
.logo-text { font-weight: 700; color: var(--texto); }
/* En pantallas estrechas caben tres y el cuarto se queda solo en la línea de abajo:
   estrechando la franja quedan dos y dos, como en el cartel. */
@media (max-width: 480px) {
  .logos { max-width: 260px; gap: 18px 30px; }
}

.footer-links { display: flex; flex-wrap: wrap; justify-content: center; gap: 4px 28px; margin-bottom: 12px; }
.footer-links a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  color: var(--texto);
  font-weight: 600;
  text-decoration: none;
}
.footer-links a:hover { text-decoration: underline; }
.footer-small { margin: 0; text-align: center; font-size: .8125rem; }
.footer-small a { color: inherit; font-weight: 600; }

/* Vuelta al inicio: aparece cuando el hero ya no está a la vista. Por debajo del modal (z 60)
   para no flotar sobre él, y separado del borde inferior seguro en los móviles con gesto. */
.ir-arriba {
  position: fixed;
  right: 16px;
  bottom: calc(16px + env(safe-area-inset-bottom, 0px));
  z-index: 40;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  border: 1px solid var(--linea-fuerte);
  border-radius: 50%;
  background: rgba(10, 18, 32, .62);
  -webkit-backdrop-filter: saturate(180%) blur(18px);
  backdrop-filter: saturate(180%) blur(18px);
  color: var(--texto);
  text-decoration: none;
  opacity: 0;
  visibility: hidden;
  transform: translateY(10px);
  transition: opacity .2s ease, transform .2s ease, visibility .2s, background-color .15s ease;
}
.ir-arriba.is-visible { opacity: 1; visibility: visible; transform: none; }
.ir-arriba:hover { background: rgba(10, 18, 32, .85); color: #fff; }
.ir-arriba:active { transform: scale(.94); }
/* Con el modal abierto el fondo queda inerte: el botón no debe seguir flotando encima. */
body.modal-open .ir-arriba { opacity: 0; visibility: hidden; }
@media (prefers-reduced-transparency: reduce) {
  .ir-arriba { background: #0d1626; -webkit-backdrop-filter: none; backdrop-filter: none; }
}

/* ---------- Tablet y escritorio ---------- */

@media (min-width: 700px) {
  :root { --pad-main: 36px; } /* el hero descuenta este valor para llegar al borde de la pantalla */
  main.wrap { padding-bottom: 72px; }
  .hero { padding-bottom: 28px; }
  .lead { font-size: 1.125rem; }
  .grid { margin-top: 24px; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 20px; }
  /* Mientras haya menos escaparates que columnas, la rejilla se ciñe a los que hay en vez de
     dejar un hueco a la derecha. En cuanto se inscriban más, vuelve sola al diseño completo.
     Sin :has() (navegadores antiguos) simplemente no se aplica y queda como antes. */
  .grid:has(> li:nth-child(2):last-child) { max-width: 680px; margin-inline: auto; grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .grid:has(> li:only-child) { max-width: 360px; margin-inline: auto; grid-template-columns: minmax(0, 1fr); }
  .tarjeta-body { padding: 12px 14px 14px; }
  .tarjeta-title { font-size: 1rem; }
  .card { padding: 28px; }
  .form-card { padding: 26px 24px 28px; }
  .logos { --alto-logo: 52px; gap: 22px 38px; max-width: 880px; }
  .ir-arriba { right: 24px; bottom: 24px; width: 52px; height: 52px; }
}

@media (min-width: 800px) {
  .ganador { display: grid; grid-template-columns: 1.25fr 1fr; }
  .ganador-foto img, .ganador-foto .placeholder { height: 100%; aspect-ratio: auto; }
  .ganador-body { display: flex; flex-direction: column; justify-content: center; align-items: flex-start; padding: 32px; }
}

@media (min-width: 960px) {
  .ficha {
    grid-template-columns: minmax(0, 1fr) 400px;
    column-gap: 48px;
    align-items: start;
  }
  .ficha-head { grid-column: 1 / -1; }
  .btn-ancla { display: none; }
  .votar { margin-top: 0; }
}

@media (min-width: 1024px) {
  .grid { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 24px; }
  .grid:has(> li:nth-child(3):last-child) { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

/* Solo se eleva la tarjeta cuando hay puntero real */
@media (hover: none) {
  .tarjeta:hover { transform: none; box-shadow: none; }
}

/* ---------- Movimiento reducido ---------- */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .hero-full h1 {
    background-image: none;
    color: var(--texto);
    -webkit-text-fill-color: currentColor;
  }
  *, *::before, *::after {
    transition-duration: .01ms !important;
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
  }
  .tarjeta:hover { transform: none; }
}

/* =========================================================
   Modal de la home: ficha (lightbox), voto y gracias sin cambiar de página
   ========================================================= */

/* ---------- Tarjetas: invitan a tocar ---------- */

.tarjeta { position: relative; cursor: pointer; -webkit-tap-highlight-color: transparent; }
.tarjeta-media { position: relative; }
.tarjeta-media img { transition: transform .35s ease; }
.tarjeta:hover .tarjeta-media img { transform: scale(1.04); }
.tarjeta:active { transform: scale(.985); border-color: var(--azul); box-shadow: none; }
.tarjeta-fotos {
  position: absolute;
  right: 8px; top: 8px;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 3px 8px;
  border-radius: 999px;
  background: rgba(15, 20, 32, .72);
  color: #fff;
  font-size: .75rem;
  font-weight: 700;
  line-height: 1.2;
}

/* ---------- Contenedor ---------- */

body.modal-open {
  position: fixed;
  left: 0; right: 0;
  width: 100%;
  overflow: hidden;
}

.modal {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: flex;
  align-items: stretch;
  justify-content: center;
}
.modal-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, .72);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
  opacity: 0;
  transition: opacity .25s ease;
}
.modal.is-open .modal-backdrop { opacity: 1; }

.modal-dialog {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  width: 100%;
  height: 100vh;
  height: 100dvh;
  overflow: hidden;
  background: var(--noche-2);
  color: var(--texto);
  opacity: 0;
  transform: translateY(28px);
  transition: opacity .22s ease, transform .3s cubic-bezier(.22, .61, .36, 1);
}
.modal.is-open .modal-dialog { opacity: 1; transform: none; }

.modal-close {
  position: absolute;
  top: calc(10px + env(safe-area-inset-top, 0px));
  right: calc(10px + env(safe-area-inset-right, 0px));
  z-index: 5;
  display: grid;
  place-items: center;
  width: 44px; height: 44px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: rgba(255, 255, 255, .94);
  color: #16233d;
  box-shadow: 0 2px 10px rgba(0, 0, 0, .28);
  transition: background-color .15s ease, color .15s ease;
}
.modal-close:hover { background: #fff; color: #16233d; }
.modal-close:focus-visible { outline-color: var(--acento); }

.modal-panel {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
}

/* ---------- (a) Fotos: lightbox sobre fondo oscuro, botón de votar fijo abajo ---------- */

.modal-panel-fotos { background: #000; color: #fff; }

/*
 * La foto manda: el escenario toma la altura de su proporción (4:3 del ancho) en lugar de estirarse a todo
 * el hueco libre, que dejaba bandas negras de 300 px con fotos horizontales. El espacio sobrante lo absorbe
 * .modal-info, que empuja los datos del comercio hacia el botón de votar.
 */
.modal-media {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  justify-content: center; /* la foto queda centrada en el hueco libre, no pegada a la cabecera */
  padding-top: calc(56px + env(safe-area-inset-top, 0px)); /* deja libre la esquina del botón de cerrar */
}
.carrusel-modal {
  display: flex;
  flex-direction: column;
  flex: none; /* la altura la marca la proporción de la foto; el hueco lo reparte .modal-media */
  min-height: 0;
  border-radius: 0;
  background: transparent;
}
/* Mismo mecanismo que la ficha; solo cambia el tope. 56dvh es el valor de hoy, así que el
   presupuesto vertical del modal no se toca. El viewport vuelve al flujo: en absoluto, el
   escenario se quedaría sin contenido en flujo y colapsaría a 0 px. */
.carrusel-modal { --foto-alto: 56vh; }
@supports (height: 1dvh) { .carrusel-modal { --foto-alto: 56dvh; } }
.carrusel-modal .carrusel-stage { flex: none; border-radius: 0; background: #fff; }
/* Las flechas ya son un círculo oscuro en el estilo base; sobre la diapositiva blanca el foco
   se marca en amarillo, porque el blanco no se vería. */
.carrusel-modal .carrusel-btn:focus-visible { outline-color: var(--acento); }
.carrusel-modal .carrusel-dots { padding: 0; }
/* La foto entra con un fundido: evita el destello de escenario vacío mientras carga en red móvil.
   El relleno desenfocado hace lo mismo, pero vuelve a su propia opacidad, no a 1. */
.carrusel-modal .carrusel-slide .carrusel-foto { opacity: 0; transition: opacity .2s ease; }
.carrusel-modal .carrusel-slide .carrusel-foto.is-loaded { opacity: 1; }
.carrusel-modal .carrusel-slide .carrusel-fondo { opacity: 0; transition: opacity .2s ease; }
.carrusel-modal .carrusel-slide .carrusel-fondo.is-loaded { opacity: .88; }
.carrusel-modal .carrusel-dots button::before { background: rgba(255, 255, 255, .38); }
.carrusel-modal .carrusel-dots button:hover::before { background: rgba(255, 255, 255, .72); }
.carrusel-modal .carrusel-dots button[aria-current="true"]::before { background: var(--acento); }
.carrusel-modal .carrusel-dots button:focus-visible { outline-color: #fff; }
.carrusel-modal.carrusel-vacio {
  display: grid;
  place-items: center;
  padding: 24px;
}
.carrusel-modal.carrusel-vacio .placeholder { width: min(100%, 520px); aspect-ratio: 4 / 3; border-radius: var(--radio); }

.modal-info { flex: none; padding: 12px 16px 0; }
.modal-nombre { margin: 0 0 4px; font-size: clamp(1.25rem, 2vw + .75rem, 1.75rem); color: #fff; }
.modal-nombre:focus { outline: none; }
.modal-meta { color: rgba(255, 255, 255, .82); }
.modal-meta .meta-item svg { color: #9fc0ff; }
.modal-meta a.meta-item { color: #cfe0ff; }
.modal-meta a.meta-item:hover { color: #fff; }
.modal-meta a.meta-item:focus-visible { outline-color: #fff; }

.modal-actions {
  position: sticky;
  bottom: 0;
  z-index: 3;
  margin-top: auto;
  padding: 14px 16px calc(14px + env(safe-area-inset-bottom, 0px));
  background: linear-gradient(to top, #000 68%, rgba(0, 0, 0, 0));
}
.modal-votar { min-height: 52px; font-size: 1.0625rem; }
.modal-votar:focus-visible { outline-color: #fff; }
.modal-aviso {
  margin: 0;
  padding: 12px 16px;
  border: 1px solid rgba(255, 255, 255, .24);
  border-radius: var(--radio-s);
  background: rgba(255, 255, 255, .1);
  color: #fff;
  font-weight: 600;
  text-align: center;
}

/* ---------- (b) Voto y (c) gracias ---------- */

.modal-panel-body { padding: 8px 16px calc(24px + env(safe-area-inset-bottom, 0px)); }

/* Formulario compacto: con Turnstile activo el botón de enviar debe seguir entrando en pantalla. */
.modal-form.form-card { padding: 16px 14px 18px; }
.modal-form .field { margin-bottom: 14px; }
.modal-form .form-nota { margin: 10px 0 12px; font-size: .75rem; }

/* En el formulario y en el "gracias" el aspa se suaviza: la salida principal es "Volver" o "Seguir viendo". */
.modal[data-panel-activo="voto"] .modal-close,
.modal[data-panel-activo="gracias"] .modal-close {
  background: rgba(255, 255, 255, .16);
  color: #fff;
  box-shadow: none;
}

.modal-volver {
  padding: 0 8px 0 4px;
  border: 0;
  background: transparent;
  color: var(--azul);
  margin-left: -4px;
}
.modal-volver:hover { color: var(--azul-oscuro); text-decoration: underline; }
.modal-voto-title { margin: 4px 56px 14px 0; font-size: clamp(1.25rem, 2vw + .6rem, 1.5rem); }
.modal-voto-title:focus, .gracias-modal h2:focus { outline: none; }
.modal-error-general { margin-bottom: 16px; }
.modal-turnstile { min-height: 65px; }

.gracias-modal { margin: 0 auto; padding-top: 44px; }
.gracias-modal .gracias-icon { margin-top: 0; }
.gracias-modal .share { margin-top: 24px; }
.modal-seguir { margin-top: 16px; }

/* ---------- Escritorio: diálogo centrado ---------- */

@media (min-width: 720px) {
  .modal { align-items: center; padding: 24px; }
  .modal-dialog {
    width: 100%;
    max-width: 760px;
    height: auto;
    max-height: calc(100vh - 48px);
    max-height: calc(100dvh - 48px);
    border: 1px solid rgba(255, 255, 255, .1);
    border-radius: 22px;
    box-shadow: 0 30px 90px rgba(0, 0, 0, .6);
    transform: translateY(16px) scale(.98);
  }
  .modal.is-open .modal-dialog { transform: none; }
  .modal-close { top: 12px; right: 12px; }
  .modal-media { flex: none; min-height: 0; padding-top: 0; }
  /* El clamp de hoy deja de ser altura fija y pasa a ser el tope de la foto. El suelo de 320 px
     protege el móvil apaisado, que entra por esta misma rama. */
  .carrusel-modal { --foto-alto: clamp(320px, 56vh, 520px); }
  @supports (height: 1dvh) { .carrusel-modal { --foto-alto: clamp(320px, 56dvh, 520px); } }
  .carrusel-modal.carrusel-vacio { min-height: 320px; }
  .modal-info { flex: none; display: block; padding: 14px 24px 0; }
  .modal-actions { padding: 16px 24px 20px; }
  .modal-panel-body { padding: 20px 28px 28px; }
  .gracias-modal { padding-top: 44px; }
}

/* ---------- Movimiento reducido: sin escalados ni desplazamientos ---------- */

@media (prefers-reduced-motion: reduce) {
  .tarjeta:hover .tarjeta-media img, .tarjeta:active { transform: none; }
  .modal-dialog { transform: none; }
}
