/* ALDS · sitio público y área de socios.

   Los valores de diseño (paleta, estados, fuentes) viven en shared/css/tokens.css, que se carga
   siempre antes que esta hoja: aquí solo se usan con var(), no se redefinen. Reglas de uso en
   docs/CLAUDE.md. En corto: el pistacho es para superficies grandes con tinta oscura encima (nunca
   texto ni relleno con texto blanco), el verde hondo para texto, enlaces y botones secundarios, y
   el rojo solo para la acción principal. */

* { box-sizing: border-box; }

/* El atributo hidden tiene que ganar siempre, aunque el elemento lleve
   una clase con su propio display (ambos tienen la misma especificidad
   que el hidden del user-agent, y sin esto gana quien se declare
   después) — si no, el JS que hace el.hidden = true no oculta nada. */
[hidden] { display: none !important; }

body {
  margin: 0;
  background: var(--page-bg);
  color: var(--ink);
  font-family: var(--font-body);
  line-height: 1.5;
  /* Columna que llena la pantalla: en una página corta (Contacto, la 404, el aviso legal) el
     contenido crece y el pie se queda abajo, en vez de flotar a media altura con el fondo
     crema por debajo. */
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  min-height: 100dvh;
}

main { flex: 1 0 auto; }

h1, h2, h3 { font-family: var(--font-display); text-wrap: balance; }

/* Los enlaces de texto son verde hondo, en todas las zonas; el rojo queda solo para la acción
   principal (un botón: "Hazte socio", "Entrar", "Guardar"). Así el verde de identidad tiene
   presencia real y el rojo llama la atención donde toca. */
a { color: var(--brand-green-deep); text-decoration: none; }
a:hover { color: var(--brand-green-deep-dark); }

button, input, select, textarea { font-family: inherit; }

/* Anillo de foco de teclado: el mismo en todas partes (el azul por defecto del navegador no es de
   la marca). Verde hondo sobre claro; sobre las bandas pistacho y sobre lo oscuro se cambia la
   variable para que siga dando 3:1 (WCAG 2.4.11). */
:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }
.hero, .page-header, .cta-band, .error-page, .about-teaser--bg-green { --focus-ring: var(--ink); }
.site-footer { --focus-ring: var(--brand-green); }
.cookie-banner { --focus-ring: #fff; }

.text-link, .back-link { color: var(--brand-green-deep); font-weight: 700; transition: color .15s ease; }
.text-link:hover, .back-link:hover { color: var(--brand-green-deep-dark); }

/* Enlaces de texto sueltos ("Leer más", "Ver todas", "Ver pagos →", "¿Olvidaste tu contraseña?", las
   redes de Contacto): medían 15-21px de alto. Un pseudo-elemento invisible amplía 6px por arriba y
   por abajo el área que responde al toque (24px como mínimo, WCAG 2.5.8) sin tocar el diseño: pasar
   estos enlaces a inline-block movía la línea que los contiene. Los enlaces dentro de una frase están
   exentos y no se tocan. */
.text-link, .back-link, .auth-card .auth-links a, .contact-social-links a { position: relative; }
.text-link::after, .back-link::after, .auth-card .auth-links a::after, .contact-social-links a::after {
  content: "";
  position: absolute;
  inset-block: -6px;
  inset-inline: 0;
}

img { max-width: 100%; display: block; }

/* "Saltar al contenido": aparece al recibir el foco con el teclado, para no recorrer la cabecera
   y el menú en cada página. El <main> recibe el foco al saltar y no necesita anillo. */
.skip-link {
  position: absolute;
  left: 16px;
  top: -100px;
  z-index: 100;
  padding: 12px 16px;
  border-radius: var(--radius-sm);
  background: var(--ink);
  color: #fff;
  font-size: var(--text-base);
  font-weight: 700;
}
.skip-link:hover { color: #fff; }
.skip-link:focus { top: 16px; outline: 2px solid var(--brand-green); outline-offset: 2px; }
main:focus { outline: none; }

.container { max-width: 1080px; margin: 0 auto; padding: 0 var(--gutter); }

/* --- Cabecera --- */
.site-header {
  position: sticky;
  top: 0;
  z-index: 30;
  background: var(--surface);
  border-bottom: 1px solid var(--border);
}

.site-header .container {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  min-height: 72px;
}

.brand {
  display: flex;
  align-items: center;
  gap: 12px;
  color: var(--ink);
  font-family: var(--font-display);
  font-weight: 800;
  font-size: var(--text-lg);
  letter-spacing: -.01em;
  white-space: nowrap;
  flex-shrink: 0;
}

.brand img { height: 42px; width: auto; transition: transform .2s ease; }
.brand:hover img { transform: rotate(-6deg) scale(1.05); }

/* Botón de menú (hamburguesa): oculto en escritorio, solo aparece por
   debajo del breakpoint de .main-nav de más abajo. */
.nav-toggle {
  display: none;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  padding: 0;
  border: none;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--ink);
  cursor: pointer;
  flex-shrink: 0;
}
.nav-toggle:hover { background: var(--page-bg); }
.nav-toggle svg { width: 24px; height: 24px; }

.main-nav {
  display: flex;
  align-items: center;
  gap: 24px;
}

.main-nav a {
  position: relative;
  color: var(--ink-medium);
  font-weight: 600;
  font-size: var(--text-base);
  padding-bottom: 4px;
  white-space: nowrap;
}

.main-nav a::after {
  content: "";
  position: absolute;
  left: 0;
  right: 100%;
  bottom: 0;
  height: 2px;
  background: var(--brand-green-deep);
  transition: right .2s ease;
}

.main-nav a:hover { color: var(--ink); }
.main-nav a:hover::after { right: 0; }

.nav-cta {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 12px 16px;
  border-radius: var(--radius-sm);
  background: var(--brand-red);
  color: #fff !important;
  font-weight: 700;
  font-size: var(--text-base);
  white-space: nowrap;
  flex-shrink: 0;
}

.nav-cta:hover { background: var(--brand-red-dark); }

/* Copia de "Acceso socios" dentro del propio .main-nav — oculta salvo en
   el breakpoint de teléfono de más abajo, donde sustituye al .nav-cta de
   la cabecera (que a ese ancho ya no cabe junto al logo y la hamburguesa
   en una sola fila, y el flex-wrap del header lo bajaba a una segunda
   fila en vez de quedar dentro del menú desplegable). */
.nav-cta-in-menu { display: none; }

.member-chip {
  display: flex;
  align-items: center;
  gap: 12px;
  font-size: var(--text-sm);
  color: var(--ink-medium);
  white-space: nowrap;
  flex-shrink: 0;
}

.member-chip strong { color: var(--ink); }

/* Objetivos táctiles: el área pulsable llega a 44px (WCAG 2.5.8 pide 24 como mínimo) y los
   márgenes negativos hacen que cada pieza siga ocupando en la cabecera el mismo sitio de siempre. */
.member-chip .logout-link { display: inline-flex; align-items: center; min-height: 44px; margin-block: -11px; color: var(--status-critical-fg); font-weight: 600; }

.notif-bell { position: relative; display: inline-flex; align-items: center; justify-content: center; min-width: 44px; min-height: 44px; margin: -11px; color: var(--ink-medium); }
.notif-bell:hover { color: var(--ink); }
.notif-bell svg { width: 22px; height: 22px; }

.notif-bell-badge {
  position: absolute;
  top: 5px;
  right: 3px;
  min-width: 16px;
  height: 16px;
  padding: 0 4px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius-pill);
  background: var(--brand-red);
  color: #fff;
  font-size: var(--text-xs);
  font-weight: 800;
  line-height: 1;
}

/* --- Pie --- */
/* Sin margin-top: las secciones ya llevan su propio relleno inferior (56px, y 64px en el área de
   socios) y, con una banda a sangre como última sección (Contacto, "Hazte socio", la
   portada), el margen dejaba una franja crema suelta entre la banda y el pie. */
.site-footer {
  padding: 32px 0;
  background: var(--ink);
  color: var(--on-dark);
  font-size: var(--text-sm);
}

.site-footer .container {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 12px;
}

.footer-nav { display: flex; align-items: center; gap: 24px; flex-wrap: wrap; }
.footer-links { display: flex; gap: 24px; flex-wrap: wrap; }
.footer-links a { padding-block: 12px; margin-block: -12px; }

.site-footer a { color: var(--brand-green); font-weight: 600; }
.site-footer a:hover { color: #fff; }

.footer-social { display: flex; gap: 8px; }

.footer-social a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  background: rgb(255 255 255 / 8%);
  color: var(--on-dark) !important;
  transition: background .15s ease, color .15s ease, transform .15s ease;
}

.footer-social a:hover { background: var(--brand-green); color: var(--ink) !important; transform: translateY(-2px); }
.footer-social svg { width: 17px; height: 17px; }

/* --- Hero --- */
.hero {
  position: relative;
  background: var(--brand-green);
  color: var(--ink);
  padding: 64px 0 96px;
  overflow: hidden;
}

/* Con foto: overlay oscuro en degradado para que el texto siga legible sobre
   cualquier imagen, sin depender de que la foto tenga una zona "vacía". */
.hero--photo {
  background-size: cover;
  background-position: center;
  color: #fff;
  padding: 96px 0;
}

.hero--photo::before {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, color-mix(in srgb, var(--ink) 45%, transparent), color-mix(in srgb, var(--ink) 78%, transparent));
}

.hero .container { position: relative; z-index: 1; max-width: 760px; text-align: center; }


.hero h1 {
  margin: 0 0 16px;
  font-size: var(--text-4xl);
  font-weight: 800;
  letter-spacing: -.02em;
  line-height: 1.12;
}

.hero p {
  margin: 0 auto 32px;
  max-width: 560px;
  font-size: var(--text-lg);
  color: var(--ink);
}

.hero--photo p { color: rgb(255 255 255 / 92%); }

.hero-actions { display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; }

/* Hero dividido: texto a un lado, ilustración de marca al otro. Nada de
   overlay — el texto va sobre el verde sólido de siempre (ya cumple
   contraste) y la ilustración se ve completa, sin oscurecer. El fondo de la
   ilustración es el mismo verde pistacho que --brand-green (comprobado
   píxel a píxel), así que encaja sin marco ni salto de color visible. */
.hero--split { padding: 64px 0; }
.hero--split .container {
  max-width: 1080px;
  display: grid;
  grid-template-columns: 1.05fr 1fr;
  align-items: center;
  gap: 48px;
  text-align: left;
}
.hero--split .hero-copy { max-width: 480px; }
.hero--split p { margin-left: 0; margin-right: 0; }
.hero--split .hero-actions { justify-content: flex-start; }

/* --- Ilustración del hero, por capas ---
   El dibujo original (1047 x 964) se cortó en seis piezas con fondo transparente: el título en negro, el «STOP»
   rojo, la base (señal y tres mascotas) y, sueltos, la barca, el paracaídas y el coche. Sumadas en su sitio dan el
   dibujo de siempre, píxel a píxel; separadas, cada una se mueve a su manera. Las coordenadas (--x, --y, --w) son
   píxeles del dibujo original: el lienzo (.hero-art) mantiene su proporción y todo escala con él.
   Solo se animan transform y opacity. La parallax del puntero (hero.js) usa la propiedad «translate», que es
   independiente de «transform»: las dos se suman sin pisarse. */
.hero--split { --hero-out: cubic-bezier(.22, 1, .36, 1); --hero-bounce: cubic-bezier(.34, 1.56, .64, 1); }
.hero-illustration { position: relative; }
/* Rayos de sol y un resplandor detrás de la señal, suaves y girando despacio: le dan profundidad al verde liso
   sin salirse de la paleta (blanco de la tarjeta al 8-20%). */
.hero-illustration::before {
  content: "";
  position: absolute;
  inset: -20%;
  pointer-events: none;
  background:
    radial-gradient(circle at 48% 58%, color-mix(in srgb, var(--surface) 22%, transparent), transparent 42%),
    repeating-conic-gradient(from 0deg at 48% 58%, color-mix(in srgb, var(--surface) 15%, transparent) 0 7.5deg, transparent 7.5deg 15deg);
  -webkit-mask-image: radial-gradient(circle at 48% 58%, black 10%, transparent 62%);
  mask-image: radial-gradient(circle at 48% 58%, black 10%, transparent 62%);
  transform-origin: 48% 58%;
  animation: hero-rays 140s linear infinite;
}
.hero-art { position: relative; width: 100%; aspect-ratio: 1047 / 964; animation: hero-impact .32s linear 1.16s; }
.hero-layer {
  position: absolute;
  left: calc(var(--x) / 10.47 * 1%);
  top: calc(var(--y) / 9.64 * 1%);
  width: calc(var(--w) / 10.47 * 1%);
  height: auto;
  max-width: none;
  display: block;
  translate: calc(var(--px, 0) * var(--depth, 0) * 1px) calc(var(--py, 0) * var(--depth, 0) * 1px);
  transition: translate .4s ease-out;
}
.hero-layer--title { --x: 191; --y: 8; --w: 801; --depth: 9; animation: hero-title-in .6s var(--hero-out) .55s backwards; }
.hero-layer--stop { --x: 344; --y: 171; --w: 453; --depth: 11; transform-origin: 50% 60%; animation: hero-stop-slam .6s var(--hero-out) .85s backwards; }
.hero-layer--base { --x: 168; --y: 248; --w: 665; --depth: 4; transform-origin: 50% 70%; animation: hero-pop .7s var(--hero-bounce) backwards; }
.hero-layer--boat {
  --x: 13; --y: 453; --w: 360; --depth: 14;
  transform-origin: 49% 89%;
  animation: hero-boat-in .85s var(--hero-out) .2s backwards, hero-boat-rock 4.6s ease-in-out 1.2s infinite;
}
.hero-layer--chute {
  --x: 765; --y: 205; --w: 267; --depth: 16;
  transform-origin: 50% 7%;
  animation: hero-chute-in .9s var(--hero-out) .33s backwards, hero-chute-swing 5.8s ease-in-out 1.3s infinite;
}
.hero-layer--car {
  --x: 588; --y: 588; --w: 413; --depth: 12;
  transform-origin: 50% 70%;
  animation: hero-car-in .8s var(--hero-out) .46s backwards, hero-car-bump 7s ease-in-out 1.4s infinite;
}
/* El texto entra escalonado, como preparando la llegada de la ilustración. */
.hero--split:has(.hero-art) .hero-copy > * { animation: hero-rise .6s var(--hero-out) backwards; }
.hero--split:has(.hero-art) .hero-copy > :nth-child(2) { animation-delay: .1s; }
.hero--split:has(.hero-art) .hero-copy > :nth-child(3) { animation-delay: .2s; }

@keyframes hero-rise { from { opacity: 0; transform: translateY(16px); } }
@keyframes hero-pop { from { opacity: 0; transform: translateY(24px) scale(.82); } }
@keyframes hero-boat-in { from { opacity: 0; transform: translate(-14%, 8%) rotate(-9deg); } }
@keyframes hero-chute-in { from { opacity: 0; transform: translateY(-38%) rotate(7deg); } }
@keyframes hero-car-in { from { opacity: 0; transform: translate(28%, -16%) rotate(4deg); } }
@keyframes hero-title-in { from { opacity: 0; transform: translateY(-16%); } }
@keyframes hero-stop-slam {
  from { opacity: 0; transform: scale(1.9); }
  45% { opacity: 1; transform: scale(.93); }
  70% { transform: scale(1.04); }
}
/* El golpe del «STOP» al caer sacude un instante todo el dibujo. */
@keyframes hero-impact {
  20% { transform: translate(-3px, 2px); }
  40% { transform: translate(3px, -2px); }
  60% { transform: translate(-2px, 1px); }
  80% { transform: translate(1px, 0); }
}
/* Movimiento continuo: la barca se mece, el paracaídas oscila colgando del dosel y el coche da un tirón de vez en cuando. */
@keyframes hero-boat-rock { 25% { transform: translateY(-5px) rotate(1.5deg); } 75% { transform: translateY(-5px) rotate(-1.5deg); } }
@keyframes hero-chute-swing { 25% { transform: translateY(4px) rotate(3.2deg); } 75% { transform: translateY(4px) rotate(-3.2deg); } }
@keyframes hero-car-bump { 88% { transform: none; } 91% { transform: translate(3px, -1px) rotate(.8deg); } 95% { transform: translate(-2px, 0) rotate(-.5deg); } }
@keyframes hero-rays { to { transform: rotate(1turn); } }

@media (prefers-reduced-motion: reduce) {
  .hero-art, .hero-layer, .hero-illustration::before, .hero--split:has(.hero-art) .hero-copy > * { animation: none; }
  .hero-layer { translate: none; transition: none; }
}

/* --- Desvanecimiento por scroll (portada, debajo del hero) ---
   Cada sección va perdiendo opacidad y color cuanto más se aleja del centro de la pantalla, y los recupera
   al acercarse: la de encima se apaga a la vez que la siguiente cobra vida. scroll_fade.js escribe --fade-o
   (de 0 a 1, según la posición real de la sección) en cada una de las marcadas con esta clase; el hero no
   lleva la clase, porque ya tiene su propia entrada (arriba). Sin JavaScript la variable no se toca y el
   valor de reserva (1) deja la sección a la vista y a todo color, como el resto del sitio. */
.scroll-fade {
  opacity: var(--fade-o, 1);
  filter: saturate(calc(.35 + var(--fade-o, 1) * .65));
  transform: translateY(calc((1 - var(--fade-o, 1)) * 28px));
  will-change: opacity, filter, transform;
}

@media (prefers-reduced-motion: reduce) {
  .scroll-fade { opacity: 1; filter: none; transform: none; }
}

@media (max-width: 900px) {
  .hero--split .container { grid-template-columns: 1fr; text-align: center; }
  .hero--split .hero-copy { max-width: 480px; margin: 0 auto; }
  .hero--split .hero-actions { justify-content: center; }
  /* width: 100% — las capas van en absoluto y no dan ancho propio: sin él la caja se quedaba en 0 (antes lo daba la imagen). */
  .hero--split .hero-illustration { order: -1; width: 100%; max-width: 320px; margin: 0 auto; }
}

/* --- Página de contacto: hero partido con una tarjeta flotante para el
   formulario, en vez del texto/ilustración centrado de siempre. --- */
.contact-hero .container { align-items: start; }

.contact-details { list-style: none; margin: 32px 0 0; padding: 0; display: flex; flex-direction: column; gap: 16px; }
.contact-details li { display: flex; align-items: center; gap: 12px; }
.contact-details a { color: var(--ink); font-weight: 700; }
.contact-details a:hover { color: var(--ink-medium); }
.contact-social-links a:not(:last-child) { margin-right: 4px; }
.contact-icon {
  display: flex; align-items: center; justify-content: center; flex-shrink: 0;
  width: 38px; height: 38px; border-radius: 50%;
  background: color-mix(in srgb, var(--ink) 10%, transparent); color: var(--ink);
}
.contact-icon svg { width: 18px; height: 18px; }

.contact-card {
  background: var(--surface);
  border-radius: var(--radius-md);
  padding: 32px;
  box-shadow: var(--shadow-lift);
}
.contact-card .form-row:last-of-type { margin-bottom: 24px; }
.contact-submit { padding: 16px 24px; font-size: var(--text-base); }

@media (max-width: 900px) {
  .contact-card { max-width: 480px; margin: 0 auto; }
}

/* --- Página de error 404 (templates/404.html) ---
   Banda pistacho a sangre, como el hero y Contacto: las ilustraciones de la peña llevan el
   mismo pistacho de fondo (#96b722, a una unidad de --brand-green) y se funden con ella. */
.error-page { background: var(--brand-green); color: var(--ink); padding: 64px 0; text-align: center; }
.error-page-art { width: 220px; height: auto; margin: 0 auto 24px; }
.error-page h1 { margin: 0 0 16px; font-size: var(--text-3xl); font-weight: 800; letter-spacing: -.02em; }
.error-page p { max-width: 520px; margin: 0 auto 32px; font-size: var(--text-lg); }
.error-page-actions { display: flex; flex-wrap: wrap; justify-content: center; gap: 12px; }

/* --- Banda de llamada a la acción ---
   Cierra una página que tiene que convertir (Hazte socio): pistacho a sangre, como la
   cabecera de las páginas interiores, con un solo botón. */
.cta-band { background: var(--brand-green); color: var(--ink); padding: 48px 0; text-align: center; }
.cta-band h2 { margin: 0 0 12px; font-size: var(--text-2xl); font-weight: 800; letter-spacing: -.01em; }
.cta-band p { max-width: 520px; margin: 0 auto 24px; font-size: var(--text-lg); }

/* --- Cabecera de página interior (Historia, Hazte socio...) --- */
.page-header { background: var(--brand-green); color: var(--ink); padding: 48px 0; text-align: center; }
.page-header h1 { margin: 0; font-size: var(--text-3xl); font-weight: 800; letter-spacing: -.02em; }

.button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 12px 24px;
  border-radius: var(--radius-sm);
  font-weight: 700;
  font-size: var(--text-base);
  border: none;
  cursor: pointer;
  transition: transform .15s ease, box-shadow .15s ease, opacity .15s ease;
}

.button:disabled {
  opacity: .5;
  cursor: not-allowed;
  box-shadow: none;
  transform: none;
}

.button-primary {
  background: var(--brand-red);
  color: #fff;
  box-shadow: var(--shadow-button);
}

.button-primary:hover { background: var(--brand-red-dark); color: #fff; transform: translateY(-1px); }

.button-outline {
  background: rgb(255 255 255 / 10%);
  color: var(--ink);
  border: 1px solid color-mix(in srgb, var(--ink) 35%, transparent);
}

.button-outline:hover { color: var(--ink); background: color-mix(in srgb, var(--ink) 8%, transparent); transform: translateY(-1px); }

/* Variante para usar fuera del hero, sobre fondo claro. */
.button-outline-green {
  background: transparent;
  color: var(--brand-green-deep);
  border: 1.5px solid var(--brand-green-deep);
}

.button-outline-green:hover {
  background: var(--brand-green-deep);
  color: #fff;
  transform: translateY(-1px);
}

/* Misma familia que .button-outline-green, para acciones destructivas
   sobre fondo claro (p. ej. eliminar la foto de perfil). */
.button-outline-critical {
  background: transparent;
  color: var(--status-critical-fg);
  border: 1.5px solid var(--status-critical-fg);
}

.button-outline-critical:hover {
  background: var(--status-critical-fg);
  color: #fff;
  transform: translateY(-1px);
}

.button-solid {
  background: var(--brand-red);
  color: #fff !important;
  width: 100%;
}

.button-solid:hover { background: var(--brand-red-dark); color: #fff; }

/* --- Cuenta atrás de la Festa da Dorna (portada) --- */
.festa-countdown { background: var(--ink); color: #fff; padding: 32px 0; text-align: center; }
.festa-countdown-kicker { margin: 0 0 8px; color: var(--brand-green); font-size: var(--text-xs); font-weight: 800; text-transform: uppercase; letter-spacing: .1em; }
.festa-countdown-text { margin: 0; font-family: var(--font-display); font-size: var(--text-2xl); font-weight: 700; letter-spacing: -.01em; }
.festa-countdown-text strong { color: var(--brand-green); font-weight: 800; }

@media (max-width: 480px) {
  .festa-countdown-text { font-size: var(--text-xl); }
}

/* --- Secciones genéricas --- */
.section { padding: 64px 0; }
.section-heading { display: flex; align-items: baseline; justify-content: space-between; gap: 16px; margin-bottom: 24px; }
.section-heading h1, .section-heading h2 { margin: 0; font-size: var(--text-2xl); font-weight: 800; letter-spacing: -.01em; }
.section-heading .text-link { font-weight: 700; font-size: var(--text-sm); white-space: nowrap; }

/* --- Tarjetas de noticias --- */
.news-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 24px; }

.news-card {
  display: block;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  overflow: hidden;
  box-shadow: var(--shadow-soft);
  transition: transform .15s ease, box-shadow .15s ease;
}

.news-card:hover { transform: translateY(-3px); box-shadow: var(--shadow-lift); }

.news-card-media { display: block; aspect-ratio: 16 / 10; overflow: hidden; background: linear-gradient(135deg, var(--brand-green), var(--brand-green-dark)); }
.news-card-media img { width: 100%; height: 100%; object-fit: contain; display: block; transition: transform .35s ease; }
.news-card:hover .news-card-media img { transform: scale(1.05); }

.news-card-body { padding: 24px; }
.news-card time { display: block; color: var(--ink-quiet); font-size: var(--text-xs); font-weight: 700; text-transform: uppercase; letter-spacing: .06em; margin-bottom: 8px; }
.news-card .pill { margin-bottom: 8px; }
.article .pill { margin-left: 8px; }
.news-card h3 { margin: 0 0 8px; font-size: var(--text-lg); line-height: 1.3; }
.news-card p { margin: 0; color: var(--ink-medium); font-size: var(--text-sm); }
.news-card .text-link { display: inline-block; margin-top: 16px; font-weight: 700; font-size: var(--text-sm); }

.empty-note { color: var(--ink-quiet); font-size: var(--text-base); padding: 24px 0; }

/* Estado vacío de una pantalla del área de socios (templates/portal/members/_empty_state.html): la
   mascota, qué falta y cuándo aparecerá. Junto a la ilustración en pantallas anchas y debajo en móvil. */
.empty-state { display: flex; align-items: center; gap: 24px; padding: 8px 0; }
.empty-state img { flex-shrink: 0; width: 128px; height: auto; border-radius: var(--radius-md); }
.empty-state h3 { margin: 0 0 4px; font-size: var(--text-lg); }
.empty-state p { margin: 0; color: var(--ink-medium); }
.empty-state .button { margin-top: 16px; }

/* --- "Quiénes somos" (teaser en la home) --- */
.about-teaser { background: var(--surface); border-top: 1px solid var(--border); border-bottom: 1px solid var(--border); padding: 64px 0; }

.about-teaser .container { display: grid; grid-template-columns: 1fr 1fr; gap: 48px; align-items: center; }

.about-teaser .about-photo {
  border-radius: var(--radius-md);
  overflow: hidden;
  box-shadow: var(--shadow-lift);
  aspect-ratio: 4 / 3;
}

.about-teaser .about-photo img { width: 100%; height: 100%; object-fit: cover; }

/* Posición de la imagen elegida por página (izquierda por defecto). */
.about-teaser .about-photo { order: 1; }
.about-teaser .container > div:last-child { order: 2; }
.about-teaser--reverse .about-photo { order: 2; }
.about-teaser--reverse .container > div:last-child { order: 1; }

/* Dos teasers seguidos comparten un único borde en vez de duplicarlo. */
.about-teaser + .about-teaser { border-top: none; }

/* Fondo elegido por página (blanco por defecto). El verde usa el botón
   outline "de hero" (ink sobre traslúcido) en vez del outline-green, que
   está pensado para fondo claro y pierde contraste sobre este verde. */
.about-teaser--bg-page { background: var(--page-bg); }
.about-teaser--bg-green { background: var(--brand-green); }

.about-teaser h2 { margin: 0 0 16px; font-size: var(--text-2xl); font-weight: 800; letter-spacing: -.01em; }
.about-teaser p { margin: 0 0 24px; color: var(--ink-medium); font-size: var(--text-base); }

/* --- Galería (solo socios) --- */
.gallery-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 24px; }

.gallery-card {
  display: block;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  overflow: hidden;
  box-shadow: var(--shadow-soft);
  transition: transform .15s ease, box-shadow .15s ease;
}

.gallery-card:hover { transform: translateY(-3px); box-shadow: var(--shadow-lift); }

.gallery-card-cover { aspect-ratio: 4 / 3; overflow: hidden; background: linear-gradient(135deg, var(--brand-green), var(--brand-green-dark)); }
.gallery-card-cover img { width: 100%; height: 100%; object-fit: cover; display: block; transition: transform .35s ease; }
.gallery-card:hover .gallery-card-cover img { transform: scale(1.05); }

.gallery-card-body { padding: 16px; }
.gallery-card-body h3 { margin: 0 0 4px; font-size: var(--text-base); }
.gallery-card-body p { margin: 0; font-size: var(--text-sm); color: var(--ink-quiet); }

.photo-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; }

.photo-grid figure {
  margin: 0;
  border-radius: var(--radius-md);
  overflow: hidden;
  background: var(--surface);
  border: 1px solid var(--border);
  box-shadow: var(--shadow-soft);
}

.photo-grid img { width: 100%; aspect-ratio: 4 / 3; object-fit: cover; display: block; }
.photo-grid figcaption { padding: 8px 12px; font-size: var(--text-xs); color: var(--ink-quiet); }

/* Texto de página + ilustraciones decorativas flotando junto al párrafo
   que les corresponda (cualquier página, no solo Historia) —
   overflow:hidden contiene los floats para que la sección no se quede
   sin alto. */
/* Medida de lectura: el contenido escrito en el admin ocupaba los 1032px del contenedor (unos 120 caracteres
   por línea, demasiado largos para leerse). Ahora una columna de 760px, centrada, como la de una noticia. */
.page-body { max-width: calc(760px + 2 * var(--gutter)); overflow: hidden; }
.page-body p { margin: 0 0 24px; font-size: var(--text-base); line-height: 1.7; color: var(--ink-medium); text-wrap: pretty; }
.page-body p:last-child { margin-bottom: 0; }

/* Contenido escrito en el admin (aviso legal, Hazte socio...): puede traer títulos y listas, y sin estas
   reglas salían con el tamaño y los márgenes por defecto del navegador (24px, fuera de la escala). */
.page-body h2 { margin: 32px 0 16px; font-size: var(--text-xl); font-weight: 800; letter-spacing: -.01em; line-height: 1.25; }
.page-body h3 { margin: 24px 0 8px; font-size: var(--text-lg); font-weight: 700; line-height: 1.3; }
.page-body h2:first-child, .page-body h3:first-child { margin-top: 0; }
.page-body ul, .page-body ol { margin: 0 0 24px; padding-left: 24px; color: var(--ink-medium); line-height: 1.7; }
.page-body li { margin-bottom: 8px; }
.page-body li:last-child { margin-bottom: 0; }

/* Justificado solo en Historia y Hazte Socio, a petición expresa — el
   resto de páginas de contenido (política de privacidad, cookies...) se
   quedan en alineación normal. */
/* Con guiones: sin ellos, el justificado abre huecos enormes entre palabras (más en móvil, con líneas cortas). */
.page-justify .page-body p { text-align: justify; hyphens: auto; }

/* Línea de tiempo de una página (los hitos se escriben en el admin): el año a un lado, con un punto sobre una
   línea fina de 1px, y al otro la foto, el título y el texto. Sin rayas de color: el hilo es del borde. */
.timeline-section { background: var(--surface); border-top: 1px solid var(--border); }
.timeline-wrap { max-width: calc(760px + 2 * var(--gutter)); }
.timeline-wrap h2 { margin: 0 0 32px; font-size: var(--text-2xl); font-weight: 800; letter-spacing: -.01em; }
.timeline { list-style: none; margin: 0; padding: 0; }
.timeline-item { position: relative; display: grid; grid-template-columns: 96px minmax(0, 1fr); gap: 0 32px; padding-bottom: 48px; }
.timeline-item:last-child { padding-bottom: 0; }
.timeline-item::before { content: ""; position: absolute; top: 12px; bottom: 0; left: 111px; width: 1px; background: var(--border); }
.timeline-item:last-child::before { display: none; }
.timeline-item::after { content: ""; position: absolute; top: 8px; left: 106px; width: 12px; height: 12px; border-radius: 50%; background: var(--brand-green); }
.timeline-year { font-family: var(--font-display); font-size: var(--text-xl); font-weight: 800; color: var(--brand-green-deep); line-height: 1.2; }
.timeline-body img { width: 100%; max-width: 420px; height: auto; margin: 0 0 16px; border-radius: var(--radius-md); }
.timeline-body h3 { margin: 0 0 8px; font-size: var(--text-lg); }
.timeline-body p { margin: 0; color: var(--ink-medium); line-height: 1.6; }

/* Se queda el fondo verde pistacho de la ilustración (no se recorta):
   cada personaje va enmarcado como una pegatina, con aire alrededor y
   sombra, en vez de ir a sangre contra el texto. */
.page-character {
  display: block;
  box-sizing: border-box;
  padding: 16px;
  background: var(--surface);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-lift);
}

.page-character--right { float: right; width: 180px; margin: 4px 0 24px 32px; }
.page-character--left { float: left; width: 180px; margin: 4px 32px 24px 0; }

@media (max-width: 700px) {
  .timeline-item { grid-template-columns: 1fr; padding-left: 32px; }
  .timeline-item::before { left: 5px; top: 12px; }
  .timeline-item::after { left: 0; }
  .timeline-year { margin-bottom: 8px; }
  .page-character { float: none; width: 200px; margin: 0 auto 24px; }
}

/* --- Artículo --- */
.article { --article-pad: 48px; background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-md); padding: var(--article-pad); max-width: 760px; margin: 0 auto; overflow: hidden; }
/* La foto sale a sangre: el ancho y los márgenes negativos se calculan con el mismo relleno del artículo, para que no se desalineen si cambia. */
.article-media { display: block; width: calc(100% + 2 * var(--article-pad)); margin: calc(-1 * var(--article-pad)) calc(-1 * var(--article-pad)) 32px; max-width: none; aspect-ratio: 16 / 9; overflow: hidden; background: linear-gradient(135deg, var(--brand-green), var(--brand-green-dark)); }
.article-media img { width: 100%; height: 100%; object-fit: contain; display: block; }
.article time { color: var(--ink-quiet); font-size: var(--text-sm); font-weight: 700; text-transform: uppercase; letter-spacing: .06em; }
.article h1 { margin: 8px 0 24px; font-size: var(--text-3xl); letter-spacing: -.02em; }
/* El cuerpo es HTML de verdad desde el editor de texto enriquecido (párrafos, títulos, listas...
   ya con su propio margen): reutiliza las reglas de .page-body en vez de duplicarlas. */
.article .body { font-size: var(--text-base); color: var(--ink-medium); }
.back-link { display: inline-block; margin-bottom: 24px; font-weight: 600; }

/* --- Mensajes flash --- */
.messages { list-style: none; margin: 24px auto 0; padding: 0; width: 100%; max-width: 1080px; padding-inline: var(--gutter); }
.messages li { padding: 12px 16px; border-radius: var(--radius-sm); font-size: var(--text-base); font-weight: 600; margin-bottom: 8px; }
.messages .success { background: var(--status-good-bg); color: var(--status-good-fg); }
.messages .error { background: var(--status-critical-bg); color: var(--status-critical-fg); }
.messages .info { background: var(--status-info-bg); color: var(--status-info-fg); }

/* --- Autenticación (tarjeta centrada, sin cabecera ni pie) ---
   Pantallas de acceso en la marca: banda pistacho a sangre con tarjeta blanca, como
   Contacto. Hasta la fase 1 del rediseño (docs/roadmap/rediseno.md) copiaban el login del
   admin en petróleo, y el socio pasaba de la portada verde a una paleta que no es la peña. */
/* El cuerpo ya llena la pantalla (columna flexible, arriba): el bloque de acceso ocupa lo que
   queda, sea con aviso o sin él, y el fondo de la página es el mismo pistacho, así un aviso
   flash queda dentro de la banda y no en una franja crema. */
.auth-page { background: var(--brand-green); }
.auth-page main { display: flex; }
.auth-wrap { flex: 1; display: flex; align-items: center; justify-content: center; padding: 24px var(--gutter); background: var(--brand-green); }
.auth-card { width: 100%; max-width: 420px; background: var(--surface); border-radius: var(--radius-md); box-shadow: var(--shadow-lift); padding: 48px 32px; box-sizing: border-box; }
.auth-card img.logo { display: block; height: 84px; width: auto; margin: 0 auto 16px; }
.auth-card h1 { margin: 0; color: var(--ink); font-size: var(--text-xl); text-align: center; font-weight: 800; letter-spacing: -.02em; }
.auth-card .subtitle { margin: 8px 0 24px; text-align: center; color: var(--ink-quiet); font-size: var(--text-base); }
.auth-card .subtitle p { margin: 0 0 8px; }
.auth-card .subtitle p:last-child { margin-bottom: 0; }
.auth-card .button { margin-top: 4px; }
.auth-card .auth-links { margin: 4px 0 0; text-align: center; font-size: var(--text-sm); }
.auth-card .auth-links a { color: var(--brand-green-deep); font-weight: 600; }
.auth-card .errorlist { list-style: none; margin: 0 0 8px; padding: 0; color: var(--status-critical-fg); font-size: var(--text-sm); font-weight: 600; }

.auth-card .form-row label::after { content: ":"; }

/* El botón principal es el rojo de siempre (.button-solid); aquí solo se le da altura. */
.auth-card .button-solid { min-height: 44px; }

/* --- Verificar carnet (pública, al escanear el QR del Wallet) --- */
.verify-photo {
  width: 96px; height: 96px; margin: 0 auto 16px; border-radius: 50%; overflow: hidden;
  background: var(--brand-green-deep); display: grid; place-items: center;
}
.verify-photo img { display: block; width: 100%; height: 100%; object-fit: cover; }
.verify-photo--fallback span { font-family: var(--font-display); font-size: var(--text-2xl); font-weight: 800; color: #fff; }
.verify-code { margin: 4px 0 24px; text-align: center; color: var(--ink-quiet); font-size: var(--text-sm); letter-spacing: .04em; }
.verify-status {
  margin: 0 0 8px; padding: 12px; border-radius: var(--radius-sm); text-align: center;
  font-size: var(--text-lg); font-weight: 800; text-transform: uppercase; letter-spacing: .02em;
}
.verify-status--good { background: var(--status-good-bg); color: var(--status-good-fg); }
.verify-status--bad { background: var(--status-critical-bg); color: var(--status-critical-fg); }

.form-row { margin-bottom: 16px; }
.form-row label { display: block; margin-bottom: 8px; color: var(--ink-medium); font-size: var(--text-sm); font-weight: 700; }
.form-row input, .form-row select, .form-row textarea {
  width: 100%;
  padding: 12px;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  font-size: var(--text-base);
  background: var(--field-bg);
  transition: border-color .15s ease, box-shadow .15s ease;
}

.form-row input:focus, .form-row select:focus, .form-row textarea:focus {
  outline: none;
  border-color: var(--brand-green-deep);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--brand-green-deep) 28%, transparent);
  background: #fff;
}

.hint { display: block; margin-top: 4px; color: var(--ink-quiet); font-size: var(--text-xs); }
.hint-warning { color: var(--status-warning-fg); font-weight: 700; }

.form-row input.member-field-incomplete { border-color: var(--status-warning); background: var(--status-warning-bg); }
.form-row input.member-field-incomplete:focus { border-color: var(--brand-green-deep); background: #fff; }

/* Error de un campo, junto a él (p. ej. teléfono ya registrado en otro socio). */
.form-row input.member-field-error { border-color: var(--status-critical); background: var(--status-critical-bg); }
.form-row input.member-field-error:focus { background: #fff; }
.field-error { margin: 4px 0 0; color: var(--status-critical-fg); font-size: var(--text-sm); font-weight: 700; }
.field-error a { color: inherit; text-decoration: underline; }

.form-row-checkbox label {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 0;
  color: var(--ink-medium);
  font-size: var(--text-base);
  font-weight: 600;
  cursor: pointer;
}
.form-row-checkbox input[type="checkbox"] {
  appearance: none;
  -webkit-appearance: none;
  flex-shrink: 0;
  width: 20px;
  height: 20px;
  margin: 0;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: var(--field-bg) no-repeat center / 13px;
  cursor: pointer;
  transition: background-color .15s ease, border-color .15s ease;
}
.form-row-checkbox input[type="checkbox"]:checked {
  border-color: var(--brand-green-deep);
  background-color: var(--brand-green-deep);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'/%3E%3C/svg%3E");
}
/* 20px de casilla + 12px de hueco: la ayuda queda alineada bajo el texto de la etiqueta. */
.form-row-checkbox .hint { margin-left: 32px; }

.member-account-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 4px 24px; }
.member-account-grid p { margin: 0; }

.member-form-grid { display: grid; grid-template-columns: 1fr auto; gap: 24px; align-items: start; }

.member-form-fields { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0 24px; min-width: 0; }
.member-form-fields .form-row-checkbox { align-self: start; }

.member-form-photo { display: flex; flex-direction: column; align-items: flex-start; gap: 8px; }
.member-form-photo-label { color: var(--ink-medium); font-size: var(--text-sm); font-weight: 700; }
/* Subir/cambiar/eliminar y el texto de ayuda van juntos, en su propia columna: el botón encima y el
   texto debajo, nunca uno al lado del otro (en fila, se lo repartían y el botón se veía obligado a
   partir "Subir foto" en dos líneas). */
.member-photo-meta { display: flex; flex-direction: column; align-items: flex-start; gap: 8px; }
.member-form-photo .hint { max-width: 150px; }
.member-photo-actions { display: flex; flex-wrap: wrap; gap: 8px; }

.member-photo-preview {
  width: 110px;
  height: 140px;
  /* No se encoge: en la fila de móvil (más abajo), sin esto perdía su proporción de foto de
     carnet y salía más estrecha de lo que mide de verdad. */
  flex-shrink: 0;
  border-radius: var(--radius-sm);
  border: 1px dashed var(--border);
  background: var(--brand-green);
  overflow: hidden;
}
.member-photo-preview img { display: block; width: 100%; height: 100%; object-fit: cover; }

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}
/* Subir, cambiar o eliminar la foto son acciones secundarias (el botón principal del formulario es
   "Guardar cambios"): botón de contorno verde, no el rojo. El campo de fichero está oculto y es él
   quien recibe el foco del teclado, así que el anillo se dibuja en la etiqueta que hace de botón. */
.visually-hidden:focus-visible + .photo-upload-button,
.visually-hidden:focus-visible + .member-photo-actions label { outline: 2px solid var(--focus-ring); outline-offset: 2px; }

.button-auto { width: auto; }

@media (max-width: 860px) {
  .member-form-fields { grid-template-columns: repeat(2, 1fr); }
}

@media (max-width: 640px) {
  .member-account-grid { grid-template-columns: 1fr; }
  .member-form-grid { grid-template-columns: 1fr; }
  .member-form-fields { grid-template-columns: 1fr; }
  .member-form-photo { order: -1; flex-direction: row; align-items: flex-start; }
  .member-form-photo-label { display: none; }
}

/* --- Área de socios --- */
/* Solo el relleno vertical: con la abreviatura "padding: 32px 0 64px" se pisaba el
   padding: 0 24px de .container y en móvil y tablet (hasta 1024px, donde el
   contenedor ocupa todo el ancho) el contenido quedaba pegado a los bordes. */
.member-shell { padding-top: 32px; padding-bottom: 64px; }

.member-subnav {
  position: relative;
  display: flex;
  gap: 8px;
  margin-bottom: 24px;
  border-bottom: 1px solid var(--border);
  overflow-x: auto;
}

.member-subnav a {
  padding: 12px 16px;
  color: var(--ink-medium);
  font-weight: 600;
  font-size: var(--text-sm);
  border-bottom: 2px solid transparent;
  white-space: nowrap;
}

.member-subnav a:hover { color: var(--ink); }
.member-subnav a.active { color: var(--ink); border-bottom-color: var(--brand-green-deep); }

/* En pantallas estrechas las siete pestañas no caben y se deslizan en horizontal:
   el desvanecido del borde derecho avisa de que hay más, y _subnav.html centra la
   pestaña activa al cargar. Sin desbordamiento (escritorio) el desvanecido cae
   sobre espacio vacío y no se nota. */
@media (max-width: 700px) {
  .member-subnav {
    scrollbar-width: none;
    -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 40px), transparent);
    mask-image: linear-gradient(to right, #000 calc(100% - 40px), transparent);
  }
  .member-subnav::-webkit-scrollbar { display: none; }
  /* Espacio al final para que la última pestaña salga limpia del desvanecido. */
  .member-subnav::after { content: ""; flex: 0 0 32px; }
}

.member-heading { margin-bottom: 24px; }
.member-heading h1 { margin: 0; font-size: var(--text-2xl); font-weight: 800; letter-spacing: -.01em; }

.member-heading-with-photo { display: flex; align-items: center; justify-content: space-between; gap: 16px; flex-wrap: wrap; }
.member-heading-info { display: flex; align-items: center; gap: 16px; }
.member-heading-photo { width: 56px; height: 56px; border-radius: 50%; object-fit: cover; flex-shrink: 0; }

/* Panel del socio: lo primero es la cuota (qué hay que pagar y cómo), con el carnet al lado. Con algo
   pendiente, el panel entero se tiñe de aviso (borde completo y fondo del estado, nunca una barra de
   color a un lado: la guía de diseño la prohíbe); al día, es una tarjeta más. */
.dash-top { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 24px; align-items: start; margin-bottom: 24px; }
.fee-panel { padding: 24px; border: 1px solid var(--border); border-radius: var(--radius-md); background: var(--surface); box-shadow: var(--shadow-soft); }
.fee-panel--pending { border-color: var(--status-warning); background: var(--status-warning-bg); box-shadow: none; }
.fee-panel h2 { margin: 0 0 16px; font-size: var(--text-xl); font-weight: 800; }
.fee-panel p { margin: 0 0 16px; color: var(--ink-medium); }
.fee-list { list-style: none; margin: 0 0 16px; padding: 0; }
.fee-list li { display: flex; justify-content: space-between; gap: 16px; padding: 8px 0; border-bottom: 1px solid color-mix(in srgb, var(--status-warning) 35%, transparent); }
.fee-list li:last-child { border-bottom: none; }
.fee-list strong { white-space: nowrap; }
.dash-card { display: flex; flex-direction: column; align-items: center; gap: 16px; }

/* "Tu ficha de socio": una lista de datos, no una cuadrícula de tarjetas con números grandes. */
.member-summary { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 16px 24px; margin: 0; }
.member-summary dt { color: var(--ink-quiet); font-size: var(--text-sm); }
.member-summary dd { margin: 4px 0 0; font-weight: 600; overflow-wrap: anywhere; }
.member-summary dd a { font-weight: 700; }

.panel-heading { display: flex; align-items: baseline; justify-content: space-between; gap: 16px; margin-bottom: 16px; }
.panel .panel-heading h2 { margin: 0; }
.news-list { list-style: none; margin: 0; padding: 0; }
.news-list li { display: flex; align-items: baseline; gap: 16px; padding: 12px 0; border-bottom: 1px solid var(--border); }
.news-list li:last-child { border-bottom: none; }
.news-list time { flex: 0 0 96px; color: var(--ink-quiet); font-size: var(--text-sm); }
.news-list a { color: var(--ink); font-weight: 700; }
.news-list a:hover { color: var(--brand-green-deep-dark); }

/* Aviso suelto de ancho completo (la cuota sin pagar en Mis pagos, los datos que faltan): borde completo
   y fondo del estado, sin barra de color a un lado. */
.alert-panel {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 16px;
  margin-bottom: 24px;
  padding: 16px 24px;
  border: 1px solid var(--status-warning);
  border-radius: var(--radius-md);
  background: var(--status-warning-bg);
}
.alert-panel-title { margin: 0 0 4px; font-weight: 800; font-size: var(--text-base); }
.alert-panel-meta { margin: 0; color: var(--ink-medium); font-size: var(--text-sm); }

.pill { display: inline-flex; align-items: center; padding: 4px 8px; border-radius: var(--radius-pill); font-size: var(--text-xs); font-weight: 800; }
/* Estado (reparto) + Pagado pueden salir los dos a la vez en la misma
   celda de "Cuotas, renovaciones y pedidos" — son cosas independientes
   para un pedido (ver portal/views.py, is_paid). */
.pill + .pill { margin-left: 8px; }
.pill-good { background: var(--status-good-bg); color: var(--status-good-fg); }
.pill-warning { background: var(--status-warning-bg); color: var(--status-warning-fg); }
.pill-critical { background: var(--status-critical-bg); color: var(--status-critical-fg); }
.pill-idle { background: var(--status-idle-bg); color: var(--status-idle-fg); }

.panel { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-md); padding: 24px; margin-bottom: 24px; box-shadow: var(--shadow-soft); }
.panel h2 { margin: 0 0 16px; font-size: var(--text-lg); font-weight: 800; }
/* Una tabla con varias columnas puede ser más ancha que una pantalla de
   móvil: en vez de ensanchar la página entera (que se salía por la derecha),
   hace scroll horizontal dentro de su propio panel. Solo los paneles cuya
   hija directa es una tabla, para no tocar el resto (p. ej. el formulario de
   pedido, cuyo enlace de ayuda va posicionado fuera del panel). */
.panel:has(> table.data-table) { overflow-x: auto; }
.contact-panel { max-width: 560px; margin-left: auto; margin-right: auto; }

/* En Mis pagos e Historial de pedidos, el botón que despliega las líneas va al final de la fila, en la
   columna de fecha — con varias columnas antes (nº, concepto, importe, método/estado…) el scroll horizontal
   de arriba dejaba el botón fuera de la pantalla en un móvil. Probado y descartado: fijar solo esa columna
   al borde derecho del panel (position: sticky) hacía que se solapara con Estado/Entregado a mientras no se
   hubiera deslizado del todo, tapándolas — un problema de fondo de las columnas fijas «desde la derecha»
   (la de la izquierda no lo tiene: ya empieza pegada a su sitio). En su lugar, toda la fila resumen es el
   objetivo del toque, no solo el chevron: se puede tocar cualquier celda visible sin deslizar nada (el nº de
   pago/pedido, siempre visible) y el chevron sigue ahí como pista y accesible por teclado (payments.html,
   orders.html). */
tr.order-summary-row { cursor: pointer; }
tr.order-summary-row:hover > td, tr.order-summary-row:active > td { background: var(--page-bg); }

.survey-panel { border-color: var(--brand-green-deep); }
.survey-panel p { margin: -8px 0 16px; color: var(--ink-medium); font-size: var(--text-sm); }
.survey-options { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 16px; margin-bottom: 24px; }
.survey-option {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  padding: 16px;
  border: 2px solid var(--border);
  border-radius: var(--radius-md);
  text-align: center;
  cursor: pointer;
  transition: border-color .15s ease, background .15s ease;
}
.survey-option:has(input:checked) { border-color: var(--brand-green-deep); background: color-mix(in srgb, var(--brand-green-deep) 6%, transparent); }
.survey-option input[type="radio"] { width: auto; margin: 0; accent-color: var(--brand-green-deep); }
.survey-option img { width: 100%; aspect-ratio: 4 / 3; object-fit: cover; border-radius: var(--radius-sm); }
.survey-option span { font-weight: 600; font-size: var(--text-base); }

table.data-table { width: 100%; border-collapse: collapse; font-size: var(--text-sm); }
table.data-table th { text-align: left; padding: 12px; color: var(--ink-quiet); font-size: var(--text-xs); text-transform: uppercase; letter-spacing: .04em; border-bottom: 1px solid var(--border); }
table.data-table td { padding: 12px; border-bottom: 1px solid var(--border); color: var(--ink-medium); }
table.data-table tr:last-child td { border-bottom: none; }

/* Fecha + botón para desplegar las líneas del pedido, en el historial de
   pedidos y en Mis pagos — el botón siempre pegado al borde derecho de
   la celda, junto a la fecha. */
.date-with-toggle { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.order-lines-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 26px;
  height: 26px;
  padding: 0;
  border: none;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--ink-quiet);
  cursor: pointer;
}
.order-lines-toggle:hover { background: var(--page-bg); color: var(--brand-green-deep); }
.order-lines-toggle svg { width: 16px; height: 16px; transition: transform .15s ease; }
.order-lines-toggle[aria-expanded="true"] svg { transform: rotate(180deg); }

/* La fila resumen del pedido (no sus líneas) se pone en negrita mientras
   está desplegada, para que destaque frente a las líneas anidadas que
   cuelgan justo debajo. */
tr.order-summary-expanded > td { font-weight: 700; }

/* Líneas de un pedido desplegado: fondo distinto al de la fila resumen
   (para que se lean como contenido anidado, no como una fila más) y
   columnas de ancho fijo — iguales en todos los pedidos, no solo dentro
   de cada uno, para que Producto/Talla/Cantidad/Importe queden alineadas
   entre un pedido y el siguiente en vez de ajustarse cada una a su
   propio contenido. */
.order-lines-row > td { padding: 0; background: var(--page-bg); }
table.order-lines-table { table-layout: fixed; margin: 0; }
table.order-lines-table th, table.order-lines-table td { background: transparent; }
table.order-lines-table th:first-child, table.order-lines-table td:first-child { padding-left: 32px; }
table.order-lines-table th:last-child, table.order-lines-table td:last-child { padding-right: 32px; }
table.order-lines-table th:nth-child(1), table.order-lines-table td:nth-child(1) { width: 40%; }
table.order-lines-table th:nth-child(2), table.order-lines-table td:nth-child(2) { width: 20%; }
table.order-lines-table th:nth-child(3), table.order-lines-table td:nth-child(3) { width: 20%; }
table.order-lines-table th:nth-child(4), table.order-lines-table td:nth-child(4) { width: 20%; }
/* Las líneas de un pago solo tienen dos columnas (concepto e importe). */
table.order-lines-table.payment-lines-table th:nth-child(1), table.order-lines-table.payment-lines-table td:nth-child(1) { width: 70%; }
table.order-lines-table.payment-lines-table th:nth-child(2), table.order-lines-table.payment-lines-table td:nth-child(2) { width: 30%; }

.order-form-layout { display: flex; gap: 24px; align-items: start; }
.order-image-preview { width: 140px; flex-shrink: 0; }
.order-image-preview img { width: 100%; height: auto; border-radius: var(--radius-sm); border: 1px solid var(--border); }

.order-form { flex: 1; min-width: 0; display: grid; grid-template-columns: 2fr 1fr 1fr auto; gap: 12px; align-items: end; margin-bottom: 24px; }
.order-form .form-row { margin-bottom: 0; position: relative; }
/* select/input/button no miden lo mismo de alto por defecto (el
   select nativo no respeta el padding igual que un input en todos
   los navegadores) — se fija la misma altura a los tres para que
   la fila quede alineada. */
.order-form select, .order-form input, .order-form button { height: 44px; }
/* La fila de Talla es la única con un enlace de ayuda bajo el campo
   (.size-guide-toggle) — al ser el contenido más alto de las 4 columnas,
   "align-items: end" desplazaba las demás columnas hacia abajo para
   igualar esa altura, descuadrando los selects entre sí. Sacando el
   enlace del flujo con position: absolute, las 4 columnas vuelven a medir
   lo mismo y los campos quedan alineados solos. */
.order-form .size-guide-toggle { position: absolute; top: 100%; left: 0; margin-top: 4px; white-space: nowrap; }

.size-guide-toggle a { color: var(--brand-green-deep); font-weight: 700; }
.size-guide {
  display: flex;
  /* Del ancho de su contenido (imagen + tabla), no de toda la fila, y
     centrado (margen lateral automático); en pantallas estrechas max-width
     evita que se salga. */
  width: fit-content;
  max-width: 100%;
  flex-wrap: wrap;
  gap: 16px;
  align-items: center;
  /* 8px de margen superior: el enlace "Ver guía de tallas" cuelga por debajo
     del formulario (position: absolute, no ocupa sitio) y con el margen
     negativo que había aquí antes el borde del panel lo pisaba. */
  margin: 8px auto 24px;
  padding: 16px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--page-bg);
}
.size-guide img { width: 120px; height: auto; flex-shrink: 0; }
.size-guide table.data-table { flex: 0 1 auto; width: auto; }
/* Sin width:100% las columnas se pegan al texto: algo más de aire entre ellas. */
.size-guide table.data-table th, .size-guide table.data-table td { padding-right: 32px; }
.size-guide table.data-table th:last-child, .size-guide table.data-table td:last-child { padding-right: 12px; }

.cart-summary { display: flex; align-items: center; justify-content: flex-end; gap: 16px; margin-top: 16px; }

.event-card { display: flex; align-items: center; justify-content: space-between; gap: 16px; padding: 16px 0; border-bottom: 1px solid var(--border); }
.event-card:last-child { border-bottom: none; }

/* --- Carnet de socio --- */
/* Tamaño real de una tarjeta ID-1 (85.6 x 53.98mm) para que, impresa a
   escala 100%, salga al tamaño de un carnet físico de verdad. */
.member-card-wrap { display: flex; justify-content: center; margin-bottom: 24px; }
.member-card {
  width: 85.6mm;
  height: 53.98mm;
  border-radius: 3.5mm;
  padding: 5mm;
  box-sizing: border-box;
  background: linear-gradient(135deg, var(--brand-green), var(--brand-green-dark));
  color: #fff;
  display: flex;
  gap: 3mm;
  box-shadow: var(--shadow-lift);
}
.member-card-main { flex: 1; min-width: 0; display: flex; flex-direction: column; justify-content: space-between; }
.member-card-photo {
  flex-shrink: 0;
  align-self: center;
  /* Tamaño real de una foto tipo carnet española (26 x 32 mm), no solo
     su proporción escalada. */
  width: 26mm;
  height: 32mm;
  border-radius: 2mm;
  overflow: hidden;
  background: rgb(255 255 255 / 20%);
  border: .3mm solid rgb(255 255 255 / 50%);
}
.member-card-photo img { display: block; width: 100%; height: 100%; object-fit: cover; }

/* Sin foto propia: las iniciales sobre verde claro, no el logo — se guarda para el sello de la
   cabecera, más pequeño, junto al nombre de la peña. */
.member-card-photo--fallback { background: var(--brand-green-dark); display: grid; place-items: center; }
.member-card-initials { font-family: var(--font-display); font-size: 8mm; font-weight: 800; color: #fff; }
.member-card-header { display: flex; align-items: center; gap: 2mm; }
.member-card-header img { height: 14.5mm; width: auto; flex-shrink: 0; }
.member-card-club { display: flex; flex-direction: column; line-height: 1.15; min-width: 0; }
.member-card-club strong { font-family: var(--font-display); font-size: 4mm; letter-spacing: -.02em; white-space: nowrap; }
.member-card-club span { font-size: 2.8mm; font-weight: 700; opacity: 1; text-transform: uppercase; letter-spacing: .04em; }
.member-card-body { display: flex; flex-direction: column; }
.member-card-code-label { font-size: 3.2mm; font-weight: 800; text-transform: uppercase; letter-spacing: .06em; opacity: 1; }
.member-card-code { font-size: 2.8mm; font-weight: 400; letter-spacing: .06em; opacity: .85; margin-bottom: 2mm; }
.member-card-name { font-family: var(--font-display); font-size: 4mm; font-weight: 700; line-height: 1.2; }
.member-card-footer { font-size: 2.8mm; opacity: .9; }
.member-card-actions { display: flex; flex-wrap: wrap; justify-content: center; gap: 8px; }

/* QR de verificación, para guardar el carnet en el Wallet (members/wallet.py). Va debajo de
   .member-card, no dentro: esa mide el tamaño real de un carnet físico (fijo, lo que también
   captura "Guardar") y el QR no forma parte de eso — su propia tarjeta blanca, con el mismo ancho,
   en vez de fundirse con el verde de encima. */
.member-card-frame { display: flex; flex-direction: column; align-items: center; gap: 12px; }
.member-card-qr-strip {
  display: flex; flex-direction: column; align-items: center; gap: 4px;
  width: 85.6mm; box-sizing: border-box; padding: 4mm;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-md);
  box-shadow: var(--shadow-soft);
}
.member-card-qr-strip img { width: 24mm; height: 24mm; }
.member-card-qr-strip span { font-size: var(--text-xs); font-weight: 700; color: var(--ink-quiet); text-transform: uppercase; letter-spacing: .04em; }

/* --- Llévalo en el Wallet (Mi carnet) --- */
.wallet-panel { max-width: 85.6mm; margin: 0 auto; text-align: center; }
.wallet-panel h2 { margin: 0 0 12px; font-size: var(--text-base); font-weight: 800; }
.wallet-steps { margin: 16px 0 0; padding-left: 16px; text-align: left; color: var(--ink-medium); font-size: var(--text-sm); line-height: 1.5; }
.wallet-steps li + li { margin-top: 4px; }
.wallet-badges-label { margin: 16px 0 8px; color: var(--ink-quiet); font-size: var(--text-xs); font-weight: 700; text-transform: uppercase; letter-spacing: .04em; }
.wallet-badges { display: flex; justify-content: center; gap: 12px; }
.wallet-badges img { height: 40px; width: auto; }
.event-card h3 { margin: 0 0 4px; font-size: var(--text-base); }
.event-card small { color: var(--ink-quiet); }
.event-card-description { margin: 0 0 8px; color: var(--ink-medium); font-size: var(--text-sm); line-height: 1.5; }

.notification-list { list-style: none; margin: 0; padding: 0; }
.notification-item { padding: 16px 0; border-bottom: 1px solid var(--border); }
.notification-item:last-child { border-bottom: none; }
.notification-item.is-unread { background: color-mix(in srgb, var(--status-critical) 5%, transparent); margin: 0 -24px; padding: 16px 24px; }
.notification-item-head { display: flex; align-items: center; gap: 8px; margin-bottom: 4px; }
.notification-item-head strong { flex: 1; font-size: var(--text-base); }
.notification-item-body { margin: 0 0 8px; color: var(--ink-medium); font-size: var(--text-sm); line-height: 1.5; }
.notification-item small { color: var(--ink-quiet); }

.notification-item-actions { display: flex; gap: 4px; }
.notification-action { display: inline-flex; align-items: center; justify-content: center; width: 28px; height: 28px; border: none; border-radius: var(--radius-sm); background: transparent; color: var(--ink-quiet); cursor: pointer; }
.notification-action svg { width: 16px; height: 16px; }
.notification-action:hover { background: var(--border); color: var(--ink); }
.notification-delete:hover { color: var(--status-critical-fg); }

/* --- Responsive --- */

/* Cabecera: por debajo de este ancho ya no caben en una fila el nombre de
   la peña, los 4 enlaces del menú y el bloque de socio ("Hola, X" +
   campana + cerrar sesión) sin apretarse — en vez de dejar que el texto
   se parta solo (que es lo que pasaba antes en ese hueco intermedio,
   entre este punto y los 700px de abajo, donde el menú simplemente
   desaparecía sin ningún sustituto), el menú público pasa a un panel
   desplegable con botón de hamburguesa. El bloque de socio y el CTA de
   "Acceso socios" nunca se ocultan, solo dejan de partirse (white-space:
   nowrap, más arriba) y, en el caso extremo de que ni así quepan junto al
   logo, el .flex-wrap de aquí abajo los baja a su propia fila en vez de
   recortarlos o solaparlos. */
@media (max-width: 1024px) {
  /* flex-start en vez de space-between: con el menú fuera de la fila
     (pasa a su propio panel más abajo) solo quedan 3 huecos —logo,
     hamburguesa, bloque de socio/CTA— y space-between dejaría la
     hamburguesa flotando a media fila en vez de pegada al logo. El
     margin-left:auto de la propia hamburguesa (no del bloque de
     socio/CTA, que va justo detrás sin margen propio) es quien empuja
     ese hueco hacia la derecha, no justify-content — así la hamburguesa
     queda siempre pegada al borde derecho, con el CTA/member-chip justo
     a su lado, tanto si ese bloque está visible como si no (en teléfono
     se oculta aparte, más abajo). */
  .site-header .container { position: relative; flex-wrap: wrap; row-gap: 8px; justify-content: flex-start; }
  .nav-toggle { display: inline-flex; margin-left: auto; }
  /* El panel se superpone al contenido en vez de ocupar una segunda fila de
     la cabecera (que la agrandaba y empujaba todo lo de debajo): sale del
     flujo con position: absolute, colgando del borde inferior del .container
     (que ya queda por encima del contenido gracias al z-index de la propia
     .site-header). Cerrado no usa display: none, para poder animarlo con
     opacity y transform; visibility: hidden lo mantiene fuera del tabulador
     y de los lectores de pantalla, con el retardo justo para que el
     desvanecimiento termine antes de ocultarlo. El fondo es translúcido
     pero de opacidad alta (70%): con más transparencia el texto del menú
     quedaría ilegible sobre el contenido. Decisión de diseño: medido sobre
     la parte más oscura de la portada, el gris del menú se queda en 5,3:1 y
     el rojo de "Acceso socios" (más oscuro que el de marca, ver
     .nav-cta-in-menu) en 4,9:1: ambos por encima del AA (4,5:1). Con el
     rojo de marca sin oscurecer, se cumplía solo hasta ~92%. Funciona igual
     sin backdrop-filter.
     Al no ocupar alto real, nada garantiza que quepa (móvil en horizontal,
     letra del sistema grande): max-height es lo que queda de pantalla bajo
     la cabecera (el 100% de un elemento absoluto es el alto de su bloque
     contenedor, el .container) y, si no cabe, el panel hace scroll por su
     cuenta sin arrastrar la página. dvh sigue a la barra del navegador
     móvil; la línea de vh es el respaldo para quien no lo entienda. */
  .main-nav {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    max-height: calc(100vh - 100%);
    max-height: calc(100dvh - 100%);
    overflow-y: auto;
    overscroll-behavior: contain;
    flex-direction: column;
    align-items: flex-start;
    gap: 4px;
    padding: 12px var(--gutter) 16px;
    border-top: 1px solid var(--border);
    background: rgb(255 255 255 / 70%);
    -webkit-backdrop-filter: blur(10px);
    backdrop-filter: blur(10px);
    box-shadow: var(--shadow-lift);
    opacity: 0;
    visibility: hidden;
    transform: translateY(-8px);
    transition: opacity .18s ease, transform .18s ease, visibility 0s linear .18s;
  }
  .main-nav.is-open {
    opacity: 1;
    visibility: visible;
    transform: none;
    transition-delay: 0s;
  }
  .main-nav a { padding: 8px 0; }
  .main-nav a::after { display: none; }
}

@media (max-width: 1024px) and (prefers-reduced-motion: reduce) {
  .main-nav { transition: none; }
}

/* En teléfono (a diferencia del breakpoint de arriba, pensado para
   tablet/anchos intermedios) el logo + la hamburguesa ya no dejan hueco
   para el .nav-cta "Acceso socios" en la misma fila — el flex-wrap del
   header lo bajaba a una segunda fila suelta. En vez de eso, se oculta el
   de la cabecera y aparece la copia de dentro de .main-nav, como una
   opción más del menú desplegable (en rojo, para que siga destacando
   como llamada a la acción entre los enlaces normales). */
@media (max-width: 480px) {
  .nav-cta { display: none; }
  /* Rojo más oscuro que el de marca, solo aquí: sobre el fondo translúcido
     del panel, el rojo normal no llega ni a 3:1 de contraste (2,8:1 medido
     en el peor caso); este da 4,9:1 en ese mismo caso. */
  .nav-cta-in-menu {
    display: inline-block;
    color: #8f0709 !important;
    font-weight: 700;
  }
}

@media (max-width: 900px) {
  .news-grid { grid-template-columns: repeat(2, 1fr); }
  .gallery-grid, .photo-grid { grid-template-columns: repeat(2, 1fr); }
  .dash-top { grid-template-columns: 1fr; }
}

@media (max-width: 640px) {
  .empty-state { flex-direction: column; text-align: center; }
  .member-summary { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .member-summary-wide { grid-column: 1 / -1; }
}

@media (max-width: 700px) {
  .hero h1 { font-size: var(--text-3xl); }
  .article h1 { font-size: var(--text-2xl); }
  .news-grid { grid-template-columns: 1fr; }
  .gallery-grid, .photo-grid { grid-template-columns: 1fr; }
  .order-form { grid-template-columns: 1fr; }
  .order-form-layout { flex-direction: column; }
  /* Con una sola columna cada campo ya ocupa su propia fila del grid, así
     que no hace falta sacar el enlace de ayuda del flujo (ni hay con qué
     descuadrarlo) — se revierte a estático para que no se solape con el
     campo Cantidad de debajo. */
  .order-form .size-guide-toggle { position: static; margin-top: 8px; }
  /* Aquí el enlace ya está en el flujo y no cuelga sobre el panel: se
     mantiene el hueco de antes entre el formulario y la guía. */
  .size-guide { margin-top: -8px; }
  .order-image-preview { width: 160px; }
  .article { --article-pad: 24px; }
  .article-media { margin-bottom: 24px; }
  .about-teaser .container { grid-template-columns: 1fr; }
  .about-teaser .about-photo { order: -1; }
}

@media print {
  .site-header, .site-footer, .messages, .member-subnav, .member-heading, .no-print, .cookie-banner { display: none !important; }
  body { background: #fff; }
  .member-card-wrap { margin: 0; }
  .member-card { box-shadow: none; page: member-card; }

  /* Sin esto, el padding normal del contenedor (pensado para pantalla)
     desplaza la tarjeta fuera de una página ya recortada a su mismo
     tamaño, y sale en blanco o cortada. */
  .member-card-page { padding: 0; margin: 0; }

  /* Página con nombre ("member-card", referenciada arriba via la
     propiedad page) en vez de @page a secas: así el tamaño ID-1 solo
     afecta a esta tarjeta, no a la impresión de cualquier otra página
     del sitio que use la misma hoja de estilos. */
  @page member-card {
    size: 85.6mm 53.98mm;
    margin: 0;
  }
}

/* --- Aviso de cookies --- */
.cookie-banner {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 40;
  background: color-mix(in srgb, var(--ink) 55%, transparent);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  color: #fff;
  box-shadow: 0 -8px 24px rgb(0 0 0 / 15%);
}
.cookie-banner-inner { display: flex; align-items: center; justify-content: space-between; gap: 16px; flex-wrap: wrap; padding: 16px var(--gutter); }
.cookie-banner p { margin: 0; font-size: var(--text-sm); line-height: 1.5; }
/* El fondo del aviso es semitransparente, así que se superpone a
   contenido de la página con distinto brillo según la sección — el
   verde de marca no llega a 2:1 de contraste ahí (comprobado con la
   fórmula de WCAG), y oscurecerlo lo empeora todavía más porque el
   propio fondo del aviso ya es oscuro. El blanco sí da un contraste
   fiable (4:1 o más) en cualquier sección, y el subrayado marca que es
   un enlace sin depender del color. */
.cookie-banner a { color: #fff; font-weight: 800; font-size: var(--text-sm); text-decoration: underline; text-decoration-thickness: 2px; text-underline-offset: 3px; }
.cookie-banner a:hover { color: var(--brand-green); }
.cookie-banner .button { flex-shrink: 0; }
