@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&family=Oswald:wght@500;600;700&display=swap');

:root {
  --color-primary: #E8562B; /* Naranja balón */
  --color-primary-hover: #cf431b;
  --color-tinta: #201A16; /* Texto principal */
  --color-amber: #F2A900; /* Apoyo, acentos */
  --color-gray: #6B7280; /* Texto secundario / bordes */
  --color-background: #FFF9F2; /* Lienzo */
  --color-surface: #FFFFFF; /* Tarjetas */
  --color-border: #F0DFCB;
  --color-teal: #0E7C6B; /* Estado "confirmado" y CTA secundaria */
  --color-tint: #FFE4D6; /* Fondos de icono y hover */

  /* Estados */
  --bg-por-revisar: #FFFBEB;
  --text-por-revisar: #D97706;
  --bg-duplicado: #FEF3C7;
  --text-duplicado: #D97706;
  --bg-aprobada: #ECFDF5;
  --text-aprobada: #059669;
  --bg-rechazada: #FEF2F2;
  --text-rechazada: #DC2626;
  --bg-archivado: #F3F4F6;
  --text-archivado: #4B5563;
  --bg-confirmado: #E3F6F3; /* Distinto de --bg-aprobada: "confirmado" (asistente) y "aprobada" (ficha) son estados distintos */

  /* Fijos: a diferencia de --color-tinta/--color-background, NO se invierten
     en modo oscuro (bloques @media/:root[data-tema] de arriba). Los usa la
     cabecera de .tarjeta-lista (Convocados, Coches, Partidos... y la maqueta
     de la portada, Fase 37) y .comparativa-col--callup -- con --color-tinta
     normal, en modo oscuro se leerían como una tarjeta CLARA sobre fondo
     oscuro, el efecto contrario al buscado. */
  --tinta-fija: #201A16;
  --crema-fija: #FFF9F2;

  /* Paleta de identidad de avatar (Fase 38): color determinista por nombre en
     .tarjeta-lista-avatar, misma paleta que ya usaba la maqueta estática de
     la portada (naranja/ámbar/marrón/arena) más dos tonos de marca para dar
     variedad en listas largas. Fijos por el mismo motivo que --tinta-fija: es
     identidad de persona, no un estado que deba invertirse con el tema. */
  --avatar-1: #E8562B;
  --avatar-2: #F2A900;
  --avatar-3: #7A6A5D;
  --avatar-4: #C4B8AC;
  --avatar-5: #0E7C6B;
  --avatar-6: #6B7280;

  --font-title: 'Oswald', sans-serif;
  --font-body: 'Inter', sans-serif;
  --shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
  --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
  --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
  --shadow-warm-md: 0 8px 16px -4px rgba(232, 86, 43, 0.18), 0 4px 6px -2px rgba(232, 86, 43, 0.12);
  --shadow-warm-lg: 0 14px 24px -6px rgba(232, 86, 43, 0.22), 0 6px 10px -3px rgba(232, 86, 43, 0.14);
  --radius-md: 12px;
  --radius-lg: 16px;
  --radius-2xl: 1.5rem;
  --radius-3xl: 1.75rem;
  --transition-all: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
}

/* Modo oscuro: automático según preferencia del sistema operativo, salvo que
   el usuario haya elegido explícitamente un tema con el botón del header
   (data-tema en <html>, persistido en localStorage por app.js). */
@media (prefers-color-scheme: dark) {
  :root {
    --color-tinta: #F2F1EC;
    --color-gray: #9CA3AF;
    --color-background: #14171B;
    --color-surface: #1C2126;
    --color-border: #2B3037;
    --color-teal: #2DD4BF; /* Variante clara: la del tema claro (#0E7C6B) no llega a 4.5:1 sobre fondo oscuro */
    --color-tint: rgba(255, 228, 214, 0.12);

    --bg-por-revisar: rgba(251, 191, 36, 0.14);
    --text-por-revisar: #FBBF24;
    --bg-duplicado: rgba(251, 191, 36, 0.2);
    --text-duplicado: #FCD34D;
    --bg-aprobada: rgba(52, 211, 153, 0.14);
    --text-aprobada: #34D399;
    --bg-rechazada: rgba(248, 113, 113, 0.14);
    --text-rechazada: #F87171;
    --bg-archivado: rgba(156, 163, 175, 0.14);
    --text-archivado: #D1D5DB;
    --bg-confirmado: rgba(45, 212, 191, 0.14);

    --shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.3);
    --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.4), 0 2px 4px -1px rgba(0, 0, 0, 0.3);
    --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.45), 0 4px 6px -2px rgba(0, 0, 0, 0.3);
    --shadow-warm-md: 0 8px 16px -4px rgba(232, 86, 43, 0.32), 0 4px 6px -2px rgba(232, 86, 43, 0.22);
    --shadow-warm-lg: 0 14px 24px -6px rgba(232, 86, 43, 0.4), 0 6px 10px -3px rgba(232, 86, 43, 0.26);
  }
}

:root[data-tema="oscuro"] {
  --color-tinta: #F2F1EC;
  --color-gray: #9CA3AF;
  --color-background: #14171B;
  --color-surface: #1C2126;
  --color-border: #2B3037;
  --color-teal: #2DD4BF; /* Variante clara: la del tema claro (#0E7C6B) no llega a 4.5:1 sobre fondo oscuro */
  --color-tint: rgba(255, 228, 214, 0.12);

  --bg-por-revisar: rgba(251, 191, 36, 0.14);
  --text-por-revisar: #FBBF24;
  --bg-duplicado: rgba(251, 191, 36, 0.2);
  --text-duplicado: #FCD34D;
  --bg-aprobada: rgba(52, 211, 153, 0.14);
  --text-aprobada: #34D399;
  --bg-rechazada: rgba(248, 113, 113, 0.14);
  --text-rechazada: #F87171;
  --bg-archivado: rgba(156, 163, 175, 0.14);
  --text-archivado: #D1D5DB;
  --bg-confirmado: rgba(45, 212, 191, 0.14);

  --shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.3);
  --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.4), 0 2px 4px -1px rgba(0, 0, 0, 0.3);
  --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.45), 0 4px 6px -2px rgba(0, 0, 0, 0.3);
  --shadow-warm-md: 0 8px 16px -4px rgba(232, 86, 43, 0.32), 0 4px 6px -2px rgba(232, 86, 43, 0.22);
  --shadow-warm-lg: 0 14px 24px -6px rgba(232, 86, 43, 0.4), 0 6px 10px -3px rgba(232, 86, 43, 0.26);
}

:root[data-tema="claro"] {
  --color-tinta: #201A16;
  --color-gray: #6B7280;
  --color-background: #FFF9F2;
  --color-surface: #FFFFFF;
  --color-border: #F0DFCB;
  --color-teal: #0E7C6B;
  --color-tint: #FFE4D6;

  --bg-por-revisar: #FFFBEB;
  --text-por-revisar: #D97706;
  --bg-duplicado: #FEF3C7;
  --text-duplicado: #D97706;
  --bg-aprobada: #ECFDF5;
  --text-aprobada: #059669;
  --bg-rechazada: #FEF2F2;
  --text-rechazada: #DC2626;
  --bg-archivado: #F3F4F6;
  --text-archivado: #4B5563;
  --bg-confirmado: #E3F6F3;

  --shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
  --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
  --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
  --shadow-warm-md: 0 8px 16px -4px rgba(232, 86, 43, 0.18), 0 4px 6px -2px rgba(232, 86, 43, 0.12);
  --shadow-warm-lg: 0 14px 24px -6px rgba(232, 86, 43, 0.22), 0 6px 10px -3px rgba(232, 86, 43, 0.14);
}

* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

/* Respeta la preferencia de reducir movimiento del sistema operativo:
   neutraliza transiciones, animaciones y scroll suave (rediseño visual,
   Paso 3 y Paso 4 — botones, .card-ticket, ancla "Entra y pruébalo"). */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

html {
  scroll-behavior: smooth;
}

body {
  font-family: var(--font-body);
  background-color: var(--color-background);
  color: var(--color-tinta);
  line-height: 1.5;
  padding: 2rem 1rem;
  min-height: 100vh;
}

.container {
  max-width: 768px;
  margin: 0 auto;
}

/* Header & Logo styling */
header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 2.5rem;
  border-bottom: 1px solid var(--color-border);
  padding-bottom: 0.9rem;
}

/* Fase 27.C.3: en la vista de evento el header global se reduce al isotipo
   (sin wordmark ni eslogan) -- la cabecera compacta del propio evento
   (.appbar, más abajo) ya da contexto de dónde está el usuario. */
header.header-compacto {
  margin-bottom: 1rem;
  padding-bottom: 0.6rem;
}

/* Fase 37 (37.B.4): el claim vive en .marca-lockup-texto (wordmark + claim
   juntos) -- ocultarlo entero basta para dejar la cabecera interna de la app
   en una sola fila, sin claim. Los selectores .logo-text/.logo-slogan sueltos
   se conservan por si algún día se reutiliza header-compacto sobre un header
   que no lleve el lockup nuevo (p. ej. frontend/admin.html, sin tocar en esta
   fase, sigue con el <svg> suelto de antes). */
header.header-compacto .marca-lockup-texto,
header.header-compacto .logo-text,
header.header-compacto .logo-slogan {
  display: none;
}

.logo-container {
  display: flex;
  align-items: center;
  gap: 0.75rem;
}

.logo-container svg {
  color: var(--color-tinta);
}

/* Fase 37 (37.C.1): nombre de marca en texto corrido. ".marca" fija la
   familia display sobre el peso de cuerpo; ".up" colorea el segmento "-Up"
   siempre en --color-primary (D37.4), tanto en el wordmark de cabecera/pie
   (.logo-text ya trae su propia tipografía -- ".marca" ahí es redundante a
   propósito, por coherencia con "aplicada a todas las apariciones") como en
   cualquier mención dentro de un párrafo normal. */
.marca {
  font-family: var(--font-title);
  font-weight: 600;
}

.marca .up,
.logo-text .up {
  color: var(--color-primary);
}

.logo-text {
  font-family: var(--font-title);
  font-size: 1.5rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: -0.02em;
  color: var(--color-tinta);
  /* Sin esto, el guion de "CALL-UP" es un punto de ruptura válido: al
     compartir fila con .header-acciones en móvil, un flex item puede encoger
     hasta ahí (min-content) antes que desbordar, partiendo la marca en dos
     líneas ("CALL-" / "UP") en vez de dejar que .header-acciones ceda sitio. */
  white-space: nowrap;
}

/* Fase 37 (37.B.2): el claim baja de "Estás convocado." (voz de producto,
   singular, docs/MARCA.md) al plural de marca "estáis convocados" (D37.5),
   en versalitas -- letra normal minúscula + font-variant:small-caps, en vez
   de un text-transform:uppercase que igualaría todas las letras al mismo
   tamaño. Color: --color-gray en vez de la "tinta al 40%" que describe el
   documento de la fase -- un tinta al 40% sobre --color-background mide
   ~2.5:1 de contraste en tema claro, por debajo del 4.5:1 que exige AA
   (criterio de aceptación 8); --color-gray es el token de texto secundario
   ya auditado en el resto de la app y sí llega a AA sobre ambos fondos. */
.logo-slogan {
  font-family: var(--font-title);
  font-size: 0.78rem;
  color: var(--color-gray);
  font-weight: 600;
  letter-spacing: 1.8px;
  font-variant: small-caps;
}

/* Fase 37 (37.B.1/37.B.2): tile redondeado --color-primary con el silbato en
   blanco (D37.12, sustituye al isotipo "Check libre" suelto que llevaba el
   header). Los dos círculos interiores del SVG usan var(--color-primary), no
   currentColor: son un "hueco" que debe leerse siempre del mismo naranja que
   el tile de fondo, en los dos temas (--color-primary no cambia entre temas). */
.marca-lockup {
  display: flex;
  align-items: center;
  gap: 0.65rem;
}

.marca-isotipo {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 36px;
  height: 36px;
  border-radius: var(--radius-md);
  background: var(--color-primary);
  box-shadow: var(--shadow-warm-md);
}

.marca-lockup-texto {
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
}

/* Fase 37 (37.B.3): mismo lockup en el pie, a escala menor y sin sombra. */
.marca-lockup--pie {
  gap: 0.6rem;
}

.marca-lockup--pie .marca-isotipo {
  width: 30px;
  height: 30px;
  border-radius: var(--radius-md);
  box-shadow: none;
}

.marca-lockup--pie .logo-text {
  font-size: 1.15rem;
}

.marca-lockup--pie .logo-slogan {
  font-size: 0.66rem;
  letter-spacing: 1.4px;
}

/* Grupo de acciones a la derecha del header: toggle de tema + panel de admin */
.header-acciones {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  flex-wrap: wrap;
}

.btn-tema {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.25rem;
  height: 2.25rem;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: 50%;
  font-size: 1.1rem;
  line-height: 1;
  cursor: pointer;
  transition: var(--transition-all);
  flex-shrink: 0;
}

.btn-tema:hover {
  border-color: var(--color-primary);
}

/* Fase 29: los tres formularios de acceso que usaban esta clase se retiran
   con el panel del header. Sigue viva solo para #banner-vincular-convocatorias
   (el "¿son tuyas?" de la Fase 12). */
.admin-form {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}

.admin-form[hidden] {
  display: none;
}

.admin-form input {
  padding: 0.5rem 0.75rem;
  border: 1px solid var(--color-gray);
  border-radius: 6px;
  font-size: 0.875rem;
  flex: 1 1 140px;
  min-width: 0;
}

.admin-form-error {
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--text-rechazada);
}

/* Cabecera compacta en móvil. Hasta la Fase 29 esto apilaba el logo y las
   acciones en dos filas (flex-direction: column): con el header de entonces
   -- dos paneles de formulario completos (entrar / crear cuenta / recuperar)
   -- ponerlos junto al logo en la misma fila no cabía en un iPhone normal.
   Desde la Fase 29 el header solo lleva el toggle de tema y "Entrar" (o el
   nombre + "Salir"): cabe de sobra junto al logo, así que se apila mismo
   layout de fila que en escritorio (justify-content: space-between del
   selector "header" base) y se gana una fila entera de alto de cabecera. */
@media (max-width: 480px) {
  body {
    padding: 1.25rem 1rem;
  }

  header {
    margin-bottom: 1.25rem;
    padding-bottom: 0.65rem;
    gap: 0.5rem;
  }

  .logo-container svg {
    width: 28px;
    height: 28px;
  }

  .logo-text {
    font-size: 1.35rem;
    line-height: 1;
  }

  .logo-slogan {
    font-size: 0.7rem;
  }

  .header-acciones {
    gap: 0.4rem;
    flex-wrap: nowrap;
  }

  .btn-tema {
    width: 1.9rem;
    height: 1.9rem;
    font-size: 0.95rem;
  }

  .acceso-discreto,
  .sesion-nombre {
    font-size: 0.78rem;
  }
}

/* Sections */
section {
  margin-bottom: 2.5rem;
}

h2 {
  font-family: var(--font-title);
  font-size: 1.75rem;
  font-weight: 600;
  text-transform: uppercase;
  margin-bottom: 1.25rem;
  color: var(--color-tinta);
  border-left: 4px solid var(--color-primary);
  padding-left: 0.75rem;
}

h3 {
  font-family: var(--font-title);
  font-size: 1.25rem;
  font-weight: 500;
  text-transform: uppercase;
  margin: 1.5rem 0 1rem;
  color: var(--color-tinta);
}

/* Forms */
form {
  background: var(--color-surface);
  border-radius: var(--radius-md);
  padding: 1.5rem;
  box-shadow: var(--shadow-md);
  display: grid;
  gap: 1rem;
}

form > div {
  display: grid;
  gap: 0.35rem;
}

/* Fase 25 (25.A.6, AUD-09): mismo bug de cascada que ".admin-form[hidden]" --
   "form > div { display: grid }" de arriba gana al [hidden] del user-agent,
   así que #fijar-password-consentimiento-grupo (oculto solo al recuperar
   contraseña, ver mostrarFijarPassword() en app.js) se quedaba visible y
   presente en el árbol de accesibilidad aunque tuviera el atributo hidden.
   Confirmado con Playwright: era el único caso sin este parche en toda la
   página -- el resto de "hidden" del documento ya computan display:none. */
#fijar-password-consentimiento-grupo[hidden] {
  display: none;
}

/* Mismo bug de cascada que .admin-form[hidden] / .banner-confirmar[hidden]:
   el "display: grid" de arriba gana al [hidden] del user-agent por origen de
   la regla, aunque tenga menor especificidad — hay que apagarlo a mano. Cubre
   los 3 pasos del asistente de creación de evento (Fase 17), no solo el de
   convocados (que conserva la clase .paso-evento). */
.paso-evento[hidden] {
  display: none;
}

label {
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--color-tinta);
}

/* `email` faltaba en esta lista desde siempre, pero no se notaba: los únicos
   campos de email vivían en el panel del header y en landing.html, que
   tenían estilos propios. Al mudarse a #vista-acceso (Fase 29) quedaba como
   una caja blanca sin borde -- ilegible en modo oscuro. */
input[type="text"],
input[type="email"],
input[type="url"],
input[type="number"],
input[type="date"],
input[type="password"],
select,
textarea {
  font-family: var(--font-body);
  font-size: 0.95rem;
  padding: 0.65rem 0.85rem;
  border: 1px solid var(--color-border);
  border-radius: 8px;
  background-color: var(--color-background);
  color: var(--color-tinta);
  transition: var(--transition-all);
  width: 100%;
}

input:focus,
select:focus,
textarea:focus {
  outline: none;
  border-color: var(--color-teal);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-teal) 15%, transparent);
}

input[type="checkbox"] {
  width: auto;
  margin-right: 0.5rem;
  accent-color: var(--color-primary);
}

button {
  font-family: var(--font-title);
  font-size: 1.1rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  padding: 0.65rem 1.25rem;
  border: none;
  border-radius: 8px;
  cursor: pointer;
  transition: var(--transition-all);
}

button[type="submit"],
.btn-primary {
  background-color: var(--color-primary);
  color: var(--color-surface);
  border-radius: 999px;
}

button[type="submit"]:hover,
.btn-primary:hover {
  background-color: var(--color-primary-hover);
  transform: translateY(-1px);
  box-shadow: var(--shadow-warm-md);
}

/* :not() excluye los botones con una clase de jerarquía explícita (D3): sin
   esto, `button[type="button"]` (selector de atributo, más específico que una
   sola clase) ganaba siempre sobre `.btn-primary`/`.btn-secondary`/`.btn-ghost`
   en cualquier <button type="button" class="...">, dejándolos con el aspecto
   gris genérico en vez del que pedía su clase. `.btn-cerrar-categoria` (Fase
   25.C) se añade a la lista por el mismo motivo: sin la exclusión, "Cerrar
   alojamiento"/"Cerrar restaurante" quedaban visualmente idénticos a "Votar",
   incumpliendo el criterio de acción primaria distinguible. Fase 27: mismo
   caso real con `.btn-icono` (volver/chevron de la cabecera compacta, 27.C)
   y `.hoja-mas-item` (filas de la hoja "Más", 27.B) -- sin añadirlas aquí,
   salían con fondo/borde grises en vez de planas/fantasma. Ajuste visual
   Fase 27: mismo caso con `.fila-nombre-boton` (nombre de un convocado,
   ajuste visual) y `.mapa-abrir` (enlace superpuesto al mapa completo,
   sustituye a `.mapa-miniatura`, retirada). Fase 29: `.landing-cta` (el CTA
   de la portada pasa de <a> a <button>, así que ahora le aplica esta regla y
   perdía su píldora), `.acceso-tab` y `.enlace-discreto` (nuevos), y
   `.acceso-discreto` -- esta última llevaba desde la Fase 9 con el mismo
   problema sin detectar: pedía `background: none; border: none` para
   parecer un enlace y salía con la caja gris genérica, porque estos nueve
   `:not()` suman más especificidad que una sola clase. */
/* Fase 38: `.fila-nombre-boton` pasa a `.tarjeta-lista-nombre-boton` (mismo
   botón, dentro de la nueva tarjeta de lista) -- se mantiene en esta lista de
   exclusión por el mismo motivo. */
/* Depuración de cabecera (2026-08-08): mismo caso real con `.link-chip`
   (Grupo de WhatsApp/Tricount/"Añadir al calendario") -- el botón .ics es un
   <button type="button">, así que sin esta exclusión salía con el aspecto
   genérico grande (mayúsculas, fondo, borde) encima de su propia clase,
   incumpliendo la especificidad ya documentada arriba para el resto de
   casos. Los enlaces (<a>) de WhatsApp/Tricount no les afecta esta regla
   (solo aplica a <button>), por eso no se había notado antes en ellos. */
button[type="button"]:not(.btn-primary):not(.btn-secondary):not(.btn-ghost):not(.btn-cerrar-categoria):not(.btn-icono):not(.hoja-mas-item):not(.mini-accion):not(.tarjeta-lista-nombre-boton):not(.mapa-abrir):not(.landing-cta):not(.acceso-tab):not(.enlace-discreto):not(.acceso-discreto):not(.link-chip) {
  background-color: var(--color-background);
  color: var(--color-tinta);
  border: 1px solid var(--color-border);
}

button[type="button"]:not(.btn-primary):not(.btn-secondary):not(.btn-ghost):not(.btn-cerrar-categoria):not(.btn-icono):not(.hoja-mas-item):not(.mini-accion):not(.tarjeta-lista-nombre-boton):not(.mapa-abrir):not(.landing-cta):not(.acceso-tab):not(.enlace-discreto):not(.acceso-discreto):not(.link-chip):hover {
  background-color: var(--color-border);
}

button:disabled,
input:disabled,
select:disabled,
textarea:disabled {
  opacity: 0.5;
  cursor: not-allowed;
  transform: none;
}

/* Jerarquía visual de botones (backlog Fase 9, quick win D3):
   .btn-primary = acción principal del contexto, .btn-secondary = acción
   secundaria pero visible (cancelar, descartar), .btn-ghost = acción
   terciaria de bajo énfasis (volver, salir de un modo). */
.btn-secondary {
  background-color: var(--color-surface);
  color: var(--color-tinta);
  border: 1px solid var(--color-border);
  border-radius: 999px;
}

.btn-secondary:hover {
  background-color: var(--color-background);
  border-color: var(--color-gray);
  box-shadow: var(--shadow-warm-md);
}

.btn-ghost {
  background: none;
  color: var(--color-gray);
  border: none;
  border-radius: 999px;
}

.btn-ghost:hover {
  background: none;
  color: var(--color-primary);
  transform: none;
}

/* Modal de creación de evento (ver #btn-nuevo-evento en app.js) */
.modal-evento {
  padding: 2rem;
  border-radius: var(--radius-md);
  border: 1px solid var(--color-border);
  background: var(--color-surface);
  color: var(--color-tinta);
  width: min(560px, 90vw);
  max-height: 85vh;
  overflow-y: auto;
  margin: auto;
  box-shadow: var(--shadow-lg);
}

.modal-evento::backdrop {
  background: rgba(0, 0, 0, 0.5);
}

.modal-evento-acciones {
  display: flex;
  justify-content: flex-end;
  gap: 1rem;
  margin-top: 1rem;
}

/* Indicador de progreso del asistente de 3 pasos al crear evento (Fase 17) */
.progreso-pasos {
  display: flex;
  gap: 0.5rem;
  margin-bottom: 1.5rem;
}

/* Mismo bug de cascada de origen que .admin-form[hidden] (9.B.5): el
   "display: flex" de arriba gana al [hidden] del user-agent aunque no debiera. */
.progreso-pasos[hidden] {
  display: none;
}

.paso-punto {
  flex: 1;
  text-align: center;
  padding-bottom: 0.5rem;
  border-bottom: 3px solid var(--color-border);
  color: var(--color-gray);
  font-size: 0.85rem;
  font-weight: 600;
}

.paso-punto.paso-activo {
  border-color: var(--color-primary);
  color: var(--color-primary);
}

.paso-punto.paso-completado {
  border-color: var(--color-teal);
  color: var(--color-teal);
}

/* Event List styling */
#lista-eventos {
  display: grid;
  gap: 1rem;
  margin-bottom: 2rem;
}

.evento-card {
  background: var(--color-surface);
  border-radius: var(--radius-md);
  padding: 1.25rem;
  box-shadow: var(--shadow-sm);
  border: 1px solid var(--color-border);
  cursor: pointer;
  transition: var(--transition-all);
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.evento-card:hover {
  transform: translateY(-2px);
  box-shadow: var(--shadow-md);
  border-color: var(--color-primary);
}

.evento-info {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
}

.evento-nombre {
  font-size: 1.15rem;
  font-weight: 600;
  color: var(--color-tinta);
}

.evento-detalles {
  font-size: 0.85rem;
  color: var(--color-gray);
}

/* Ficha card styling */
.ficha-grid {
  display: grid;
  gap: 1.25rem;
  margin-bottom: 2rem;
}

.ficha-card {
  background: var(--color-surface);
  border-radius: var(--radius-md);
  border: 1px solid var(--color-border);
  padding: 1.25rem;
  box-shadow: var(--shadow-sm);
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  transition: var(--transition-all);
}

.ficha-card:hover {
  box-shadow: var(--shadow-md);
}

/* Ajuste visual Fase 27: resalte de "elegida" (Fase 15) con un borde de
   marca, como hace el prototipo -- antes solo se comunicaba con el badge. */
.ficha-card[data-elegida="true"] {
  border-color: var(--color-teal);
  border-width: 2px;
}

.ficha-header {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 0.5rem;
}

/* Icono de categoría (Fase 27, ajuste visual): mismo símbolo que los pines
   del mapa y el menú -- decorativo, aria-hidden en el propio icono. */
.ficha-icono {
  width: 26px;
  height: 26px;
  flex-shrink: 0;
  border-radius: 7px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--color-background);
  border: 1px solid var(--color-border);
}

.ficha-icono .icono-tab {
  width: 15px;
  height: 15px;
}

.ficha-nombre-wrapper {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
}

.ficha-nombre {
  font-size: 1.2rem;
  font-weight: 600;
  color: var(--color-tinta);
}

.ficha-link {
  font-size: 0.85rem;
  color: var(--color-primary);
  text-decoration: none;
  font-weight: 500;
}

.ficha-link:hover {
  text-decoration: underline;
}

.ficha-observaciones {
  font-size: 0.9rem;
  color: var(--color-tinta);
  background: var(--color-background);
  padding: 0.75rem;
  border-radius: 6px;
  border-left: 3px solid var(--color-gray);
}

/* Fila de datos duros por tipo (Fase 27.D.2): precio, distancia, plazas/aforo,
   régimen -- el dato que decide, en vez de texto libre dentro de observaciones. */
.ficha-datos {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
}

.ficha-dato {
  display: inline-flex;
  align-items: center;
  font-size: 0.82rem;
  font-weight: 500;
  color: var(--color-tinta);
  background: var(--color-background);
  border: 1px solid var(--color-border);
  border-radius: 6px;
  padding: 0.3rem 0.55rem;
}

.ficha-dato-fuerte {
  font-weight: 700;
  color: var(--color-primary);
}

/* Restricciones dietéticas / alérgenos de un restaurante (Fase 27.D.4: antes
   fijado con element.style.* desde JS, ahora una clase). */
.ficha-restricciones {
  font-size: 0.9rem;
  margin-top: 0.25rem;
  border-left: 3px solid var(--color-primary);
  padding-left: 0.5rem;
  color: var(--color-primary);
}

/* Botón "Cómo llegar" a Google Maps (Fase 27.H), en toda ficha con ubicación. */
.btn-google-maps {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  align-self: flex-start;
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--color-primary);
  text-decoration: none;
  border: 1px solid var(--color-border);
  border-radius: 999px;
  padding: 0.4rem 0.75rem;
}

.btn-google-maps:hover {
  border-color: var(--color-primary);
}

/* Botón "Buscar restaurantes" (Fase 27.D.4: antes backgroundColor/color
   fijados desde JS con el naranja de marca; #E8562B es --color-primary). */
.btn-buscar-restaurantes {
  background-color: var(--color-primary);
  color: #fff;
}

/* Comidas por día y servicio dentro de la ficha de restaurante (Fase 27.F) */
.franjas {
  border-top: 1px dashed var(--color-border);
  padding-top: 0.6rem;
}

.franjas-titulo {
  font-size: 0.72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--color-gray);
  margin: 0 0 0.5rem;
}

.franja {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-wrap: wrap;
  padding: 0.45rem 0.6rem;
  border-radius: 8px;
  background: var(--color-background);
  border: 1px solid var(--color-border);
  margin-bottom: 0.4rem;
  font-size: 0.85rem;
}

.franja[data-elegida="true"] {
  border-color: var(--color-teal);
  background: color-mix(in srgb, var(--color-teal) 8%, var(--color-background));
}

.franja-cuando {
  font-weight: 600;
  color: var(--color-tinta);
}

.franja-votos {
  margin-left: auto;
  font-size: 0.78rem;
  color: var(--color-gray);
  white-space: nowrap;
}

.franja-estado {
  font-size: 0.66rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  padding: 0.15rem 0.4rem;
  border-radius: 5px;
}

.franja-estado.ok {
  background: var(--color-teal);
  color: #fff;
}

.franja-estado.vot {
  background: var(--color-tint, var(--color-border));
  color: var(--color-primary);
}

.form-franja {
  display: flex;
  gap: 0.4rem;
  flex-wrap: wrap;
  margin-top: 0.5rem;
}

.form-franja select,
.form-franja input {
  font-family: inherit;
  font-size: 0.82rem;
  padding: 0.4rem 0.5rem;
  border: 1px solid var(--color-border);
  border-radius: 8px;
  background: var(--color-surface);
  color: var(--color-tinta);
  flex: 1 1 28%;
  min-width: 0;
}

.form-franja .btn-secondary {
  flex: 1 1 100%;
}

.mini-accion {
  background: none;
  border: none;
  font-family: inherit;
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--color-primary);
  cursor: pointer;
  padding: 0.1rem 0;
}

/* Fase 25.B.1: etiqueta de categoría de la ficha (Alojamiento/Restauración/...),
   visible en reposo -- necesaria sobre todo en la cola de Moderación, que
   mezcla fichas de varios tipos. Paleta neutra a propósito: no es un estado
   (aprobada/rechazada/...), es solo una clasificación. */
.badge-tipo {
  background-color: var(--color-border);
  color: var(--color-tinta);
}

/* Badges for status */
.badge {
  display: inline-flex;
  align-items: center;
  padding: 0.25rem 0.65rem;
  border-radius: 9999px;
  font-size: 0.75rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.badge-por-revisar {
  background-color: var(--bg-por-revisar);
  color: var(--text-por-revisar);
}

.badge-posible-duplicado {
  background-color: var(--bg-duplicado);
  color: var(--text-duplicado);
}

.badge-aprobada {
  background-color: var(--bg-aprobada);
  color: var(--text-aprobada);
}

.badge-rechazada {
  background-color: var(--bg-rechazada);
  color: var(--text-rechazada);
}

/* Fase 15: cierre de decisión -- reutiliza los tonos ya existentes de
   "aprobada" (verde, opción ganadora) y "archivado" (gris, descartada sin
   ser un error) en vez de crear variables de color nuevas. */
.badge-elegida {
  background-color: var(--bg-aprobada);
  color: var(--text-aprobada);
}

.badge-no-elegida {
  background-color: var(--bg-archivado);
  color: var(--text-archivado);
}

/* Interactions (Valoraciones, Comentarios, Votos). Ajuste visual Fase 27:
   borde discontinuo (antes sólido), como la fila social del prototipo. */
.interacciones {
  border-top: 1px dashed var(--color-border);
  padding-top: 0.75rem;
  margin-top: 0.5rem;
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.resumen-interacciones {
  font-size: 0.85rem;
  color: var(--color-gray);
  font-weight: 500;
}

.interacciones-acciones {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  align-items: center;
}

/* Objetivo táctil de 44x44px (criterio 6 de la Fase 25): estos dos botones
   son de los pocos que se salían de esa medida con el tamaño compacto
   heredado del botón "Valorar" original. */
.interacciones-acciones button {
  min-height: 44px;
  padding: 0.5rem 0.85rem;
  font-size: 0.85rem;
}

/* Ajuste visual Fase 27: el toggle de comentarios se separa a la derecha,
   como el botón "Ver comentarios" del prototipo (a la derecha de la fila
   social), en vez de ir pegado a estrellas/votar. */
.btn-comentarios-toggle {
  margin-left: auto;
}

/* Fase 25.B.2: cinco estrellas pulsables (radios nativos + <label>), sustituyen
   al desplegable de puntuación + botón "Valorar". Se quita el borde/margen
   por defecto del <fieldset>; el orden en el DOM va de 5 a 1 con row-reverse
   para que la selección "hasta aquí" se pueda colorear con el combinador ~ en
   CSS puro (ver input:checked ~ label más abajo). */
.estrellas-valorar {
  display: flex;
  flex-direction: row-reverse;
  border: none;
  margin: 0;
  padding: 0;
  gap: 0.1rem;
}

/* Oculto visualmente pero SIN position:absolute (a diferencia de .sr-only):
   dentro de un contenedor flex, la posición estática de un hijo absolute es
   siempre el origen del contenedor (spec de Flexbox), así que los 5 radios
   quedarían apilados en el mismo punto y las flechas del teclado del grupo
   nativo (que en Chromium resuelven "el siguiente radio" por posición en
   pantalla) perderían el foco en vez de moverlo. Quedarse en el flujo normal,
   aunque sea a 1x1px, les da una posición distinta a cada uno. */
.estrellas-valorar input {
  width: 1px;
  height: 1px;
  padding: 0;
  margin: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.estrellas-valorar label {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 44px;
  min-height: 44px;
  font-size: 1.4rem;
  line-height: 1;
  color: var(--color-gray);
  cursor: pointer;
  border-radius: 8px;
  transition: var(--transition-all);
}

/* var(--color-primary), no --color-amber: contraste insuficiente (~2:1) sobre
   --color-surface para un icono con significado (WCAG 1.4.11); el naranja de
   marca sí llega a 3:1 en ambos temas. */
.estrellas-valorar input:checked ~ label,
.estrellas-valorar label:hover,
.estrellas-valorar label:hover ~ label {
  color: var(--color-primary);
}

.estrellas-valorar input:focus-visible + label {
  outline: 2px solid var(--color-primary);
  outline-offset: 2px;
}

.estrellas-valorar input:disabled + label {
  opacity: 0.5;
  cursor: not-allowed;
}

/* Fase 25.B.3: envoltorio de la lista de comentarios + formulario, oculto por
   defecto hasta que se pulsa "Comentarios (n)". La regla [hidden] es
   necesaria pese a parecer redundante: sin ella, el `display: flex` de abajo
   -- una regla de autor -- gana siempre al `display: none` del atributo
   `hidden` -- una regla de user-agent -- da igual la especificidad, porque el
   origen de la hoja de estilos se decide antes que la especificidad. */
.comentarios-panel {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.comentarios-panel[hidden] {
  display: none;
}

.comentarios-list {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  max-height: 150px;
  overflow-y: auto;
  background: var(--color-background);
  padding: 0.5rem;
  border-radius: 6px;
}

.comentarios-list li {
  font-size: 0.85rem;
  padding: 0.25rem 0.5rem;
  border-radius: 4px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
}

.comentario-autor {
  font-weight: 600;
  color: var(--color-primary);
  margin-left: 0.25rem;
}

.comentario-form {
  display: flex;
  gap: 0.5rem;
  background: none;
  padding: 0;
  box-shadow: none;
}

.comentario-form input {
  font-size: 0.85rem;
  padding: 0.45rem 0.75rem;
  min-height: 44px;
}

.comentario-form button {
  font-size: 0.85rem;
  padding: 0.45rem 0.75rem;
  min-height: 44px;
}

/* Ajuste visual Fase 27: barra de acciones al pie de la ficha (Google Maps,
   y para quien tenga acceso de Gestor, moderar/buscar restaurantes) --
   antes cada botón quedaba suelto y apilado dentro del cuerpo de la
   tarjeta. Sangra hasta el borde de `.ficha-card` (que tiene su propio
   padding) con márgenes negativos, como el pie de ficha del prototipo. */
.ficha-acciones {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  margin: 0 -1.25rem -1.25rem;
  padding: 0.6rem 1.25rem 0.75rem;
  background: var(--color-background);
  border-top: 1px dashed var(--color-border);
}

.ficha-acciones button,
.ficha-acciones a {
  flex: 1;
  min-width: 8rem;
  justify-content: center;
  font-size: 0.8rem;
  padding: 0.4rem 0.5rem;
  text-align: center;
}

.btn-aprobar {
  background-color: var(--bg-aprobada);
  color: var(--text-aprobada);
  border: 1px solid var(--text-aprobada);
}

.btn-aprobar:hover {
  background-color: var(--text-aprobada);
  color: var(--color-surface);
}

.btn-rechazar {
  background-color: var(--bg-rechazada);
  color: var(--text-rechazada);
  border: 1px solid var(--text-rechazada);
}

.btn-rechazar:hover {
  background-color: var(--text-rechazada);
  color: var(--color-surface);
}

.btn-restaurar {
  background-color: var(--color-background);
  color: var(--color-tinta);
  border: 1px solid var(--color-gray);
}

.btn-restaurar:hover {
  background-color: var(--color-gray);
  color: var(--color-surface);
}

.aviso {
  font-style: italic;
  color: var(--color-gray);
  text-align: center;
  padding: 1rem;
}

/* Acceso visualmente oculto pero disponible para lectores de pantalla (9.C.1) */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* Acceso discreto de Gestor (ver docs/FASE_9_ROLES_Y_NAVEGACION.md, 9.B.5): un
   enlace de texto, no un botón destacado, para no invitar a los participantes a tocarlo. */
.acceso-discreto {
  background: none;
  border: none;
  color: var(--color-gray);
  font-family: var(--font-body);
  font-size: 0.85rem;
  font-weight: 500;
  text-transform: none;
  letter-spacing: normal;
  text-decoration: underline;
  padding: 0.25rem 0;
  cursor: pointer;
}

.acceso-discreto:hover {
  color: var(--color-primary);
}

/* Enlace de texto puro, sin caja: "Entrar" de la portada, "¿Olvidaste tu
   contraseña?" y "Volver a entrar" de #vista-acceso (Fase 29). Se distingue
   de .acceso-discreto en que usa el color de acento, no el gris: aquí sí
   queremos que se vea que se puede pulsar. */
.enlace-discreto {
  background: none;
  border: none;
  padding: 0.25rem 0;
  color: var(--color-teal);
  font-family: var(--font-body);
  font-size: 0.9rem;
  font-weight: 600;
  text-transform: none;
  letter-spacing: normal;
  text-decoration: underline;
  cursor: pointer;
}

.enlace-discreto:hover {
  color: var(--color-primary);
}

/* Estado de sesión en el header (Fase 29, A-11 del informe): antes el nombre
   ERA el botón de cerrar sesión y el "Salir" de verdad vivía dentro de un
   panel que con sesión activa se ocultaba, así que nunca se veía. */
.acceso-header {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  /* Sin esto, el "overflow: hidden" que deja encoger a #sesion-nombre no
     sirve de nada un nivel más arriba: .acceso-header es a su vez un item
     flex de "header", y sin min-width:0 aquí su tamaño mínimo automático se
     calcula como si ninguno de sus hijos pudiera encoger -- header empuja el
     ancho real más allá del viewport (scroll horizontal) en vez de dejar que
     el nombre se trunque. */
  min-width: 0;
}

.sesion-nombre {
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--color-tinta);
  /* Fase 29 (ajuste de cabecera): sin tope, un nombre real más largo que
     "Marta Prueba" envolvía a dos líneas y volvía a ensanchar la cabecera
     que este ajuste existe para reducir -- se corta con puntos suspensivos
     en vez de partirse. */
  max-width: 9rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Va DESPUÉS de la regla base (misma especificidad, 1 clase): puesta antes
   -- p. ej. junto al resto de ajustes de "Cabecera compacta en móvil" más
   arriba -- el orden de aparición en cascada hacía ganar siempre a la regla
   base de más abajo (9rem) sobre esta, aunque el viewport cumpliera la
   media query. Encontrado verificando con un nombre real largo a 360-390px:
   el nombre no se truncaba y la cabecera desbordaba con scroll horizontal. */
@media (max-width: 480px) {
  .sesion-nombre {
    max-width: 6rem;
  }
}

/* Con nombre real largo, 6rem seguía desbordando por 16px en el móvil más
   estrecho que sigue viéndose de verdad (320px, iPhone SE de 1ª generación) --
   mismo motivo de cascada que el bloque de arriba: debe ir después para
   ganarle a los 480px cuando los dos aplican a la vez. */
@media (max-width: 340px) {
  .sesion-nombre {
    max-width: 4.5rem;
  }
}

.sesion-nombre[hidden] {
  display: none;
}

/* Navegación por pestañas dentro de un evento (9.B.1). Fase 27.B: el fondo
   era el mismo que el lienzo (var(--color-background)) -- en móvil, donde
   esta barra pasa a ser fija en la parte inferior (más abajo), eso la
   dejaba indistinguible del contenido que tiene detrás; con solo 5 destinos
   fijos tampoco hace falta scroll horizontal. */
.tabs-nav {
  display: flex;
  gap: 0.25rem;
  border-bottom: 2px solid var(--color-border);
  margin-bottom: 1.5rem;
  background: var(--color-surface);
}

.tab-btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  font-family: var(--font-title);
  font-size: 0.95rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  background: none;
  border: none;
  border-bottom: 3px solid transparent;
  color: var(--color-gray);
  padding: 0.75rem 1rem;
  cursor: pointer;
  white-space: nowrap;
  transition: var(--transition-all);
}

.icono-tab {
  width: 20px;
  height: 20px;
  flex-shrink: 0;
}

/* Contador de pendientes sobre el destino "Más" de la barra inferior
   (Fase 27.B, D27.2) -- solo visible con acceso de Gestor y pendientes > 0. */
.tab-badge {
  position: absolute;
  top: 0.2rem;
  right: 0.35rem;
  min-width: 16px;
  height: 16px;
  border-radius: 999px;
  background: var(--color-primary);
  color: #fff;
  font-family: var(--font-body, inherit);
  font-size: 0.62rem;
  font-weight: 700;
  text-transform: none;
  letter-spacing: normal;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 3px;
}

/* Mismo patrón de bug de cascada [hidden] ya conocido en este CSS (Fase
   16/25.A/25.B): una regla de autor con `display` propio (aquí `flex`, para
   centrar el número) gana siempre al `[hidden]` de user-agent, así que hace
   falta este override explícito -- confirmado en verificación real con
   Playwright, el badge se veía con "0" pese a `hidden`. */
.tab-badge[hidden] {
  display: none;
}

.tab-btn:hover {
  color: var(--color-tinta);
}

.tab-btn-activo {
  color: var(--color-surface);
  background: var(--color-tinta);
  border-bottom-color: transparent;
  border-radius: 999px;
}

.tab-panel {
  animation: aparecer-pestana 0.15s ease-in;
}

@keyframes aparecer-pestana {
  from { opacity: 0; }
  to { opacity: 1; }
}

/* Filtro de categorías por chips (Propuestas, 9.B.1/9.B.2) */
.chips-filtro {
  display: flex;
  gap: 0.5rem;
  flex-wrap: wrap;
  margin-bottom: 1.25rem;
}

.chip {
  font-family: var(--font-body);
  font-size: 0.85rem;
  font-weight: 600;
  text-transform: none;
  letter-spacing: normal;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  color: var(--color-tinta);
  padding: 0.4rem 0.9rem;
  border-radius: 9999px;
  cursor: pointer;
  transition: var(--transition-all);
}

.chip:hover {
  border-color: var(--color-primary);
}

.chip-activo {
  background: var(--color-primary);
  border-color: var(--color-primary);
  color: var(--color-surface);
}

/* Tarjetas de estado de la pestaña Resumen (backlog Fase 9, sección 5) */
.stats-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1rem;
  margin-bottom: 1.5rem;
}

/* Igual que .stat-card[hidden] más abajo: display:grid gana por origen de
   cascada al [hidden] del user-agent aunque empaten en especificidad, así que
   hay que apagarlo explícitamente (quick win E2, al ocultar el grid entero). */
.stats-grid[hidden] {
  display: none;
}

@media (min-width: 560px) {
  .stats-grid {
    grid-template-columns: 1fr 1fr;
  }
}

.stat-card {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-left: 4px solid var(--color-border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-sm);
  padding: 1.1rem 1.25rem;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  width: 100%;
  text-align: left;
  cursor: pointer;
  transition: var(--transition-all);
  color: inherit;
  font-family: var(--font-body);
}

.stat-card:hover {
  box-shadow: var(--shadow-md);
  transform: translateY(-1px);
  border-left-color: var(--color-primary);
}

.stat-card[data-tone="warn"] {
  border-left-color: var(--text-por-revisar);
}

.stat-card[data-tone="alert"] {
  border-left-color: var(--text-rechazada);
}

.stat-card[hidden] {
  display: none;
}

.stat-card h3 {
  font-family: var(--font-title);
  font-size: 0.85rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--color-gray);
  margin: 0;
}

.stat-main {
  display: flex;
  align-items: baseline;
  gap: 0.4rem;
}

.stat-number {
  font-family: var(--font-title);
  font-size: 2.1rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  line-height: 1;
}

.stat-unit {
  font-size: 0.82rem;
  color: var(--color-gray);
  font-weight: 500;
}

.stat-breakdown {
  display: flex;
  gap: 0.4rem;
  flex-wrap: wrap;
}

.stat-chip {
  font-size: 0.72rem;
  font-weight: 600;
  padding: 0.2rem 0.55rem;
  border-radius: 999px;
  text-transform: uppercase;
  letter-spacing: 0.03em;
}

.stat-chip-ok {
  background: var(--bg-aprobada);
  color: var(--text-aprobada);
}

.stat-chip-pending {
  background: var(--bg-por-revisar);
  color: var(--text-por-revisar);
}

.stat-chip-off {
  background: var(--color-background);
  color: var(--color-gray);
  border: 1px solid var(--color-border);
}

.stat-detail {
  font-size: 0.82rem;
  color: var(--color-gray);
  margin: 0;
}

.stat-cta {
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--color-primary);
  margin-top: auto;
  padding-top: 0.4rem;
}

.stat-card:hover .stat-cta {
  text-decoration: underline;
}

/* Banner "te falta confirmar" (backlog Fase 9, quick win B2): visible solo si
   el usuario actual tiene una fila de asistente en estado Pendiente. */
.banner-confirmar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  background: var(--bg-por-revisar);
  border: 1px solid var(--text-por-revisar);
  border-radius: var(--radius-md);
  padding: 0.9rem 1.25rem;
  margin-bottom: 1.5rem;
}

/* `display: flex` de arriba gana por origen de cascada al `[hidden] { display:
   none }` del user-agent aunque tengan la misma especificidad (mismo bug ya
   documentado en 9.B.5 para .admin-form): hay que apagarlo explícitamente. */
.banner-confirmar[hidden] {
  display: none;
}

.banner-confirmar-texto {
  color: var(--text-por-revisar);
  font-weight: 600;
  font-size: 0.95rem;
}

/* Aviso de bloqueo de interacciones (quick win E1): explica por qué votar,
   comentar o proponer están deshabilitados, no solo el estado inactivo. */
.aviso-bloqueo {
  background: var(--bg-por-revisar);
  color: var(--text-por-revisar);
  border: 1px solid var(--text-por-revisar);
  border-radius: var(--radius-md);
  padding: 0.75rem 1rem;
  font-size: 0.88rem;
  font-weight: 600;
  margin-bottom: 1.25rem;
}

/* Modificador para el bloqueo de vista de una Baja (#bloqueo-baja): mismo
   aviso, pero más grande y centrado -- sustituye por completo el hero, no es
   un aviso inline como el resto de usos de .aviso-bloqueo. */
.aviso-bloqueo-destacado {
  padding: 1.5rem;
  text-align: center;
  font-size: 1.05rem;
}

/* Resumen final del evento decidido (quick win E2): sustituye a las tarjetas
   de cifras en vivo una vez ya no tiene sentido seguir votando/proponiendo. */
.resumen-final {
  background: var(--bg-aprobada);
  border: 1px solid var(--text-aprobada);
  border-radius: var(--radius-md);
  padding: 1.25rem 1.5rem;
  margin-bottom: 1.5rem;
}

.resumen-final h3 {
  margin: 0 0 1rem;
  color: var(--text-aprobada);
  font-family: var(--font-title);
  text-transform: uppercase;
}

.resumen-final-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0.9rem;
}

@media (min-width: 560px) {
  .resumen-final-grid {
    grid-template-columns: 1fr 1fr;
  }
}

.resumen-final-item {
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
}

.resumen-final-label {
  font-family: var(--font-title);
  font-size: 0.75rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--color-gray);
}

.resumen-final-valor {
  font-size: 0.95rem;
  font-weight: 600;
  color: var(--color-tinta);
}

/* Cabecera compacta del evento (Fase 27.C): una sola fila fija (volver +
   nombre truncado + pill de estado + chevron) con los detalles (plazo,
   lugar/fechas/convocados, enlaces, editar evento) plegables debajo. Antes
   era un .hero de 5 líneas siempre desplegado que, sumado al resto de la
   cabecera, dejaba 400-500px antes de la primera pestaña en móvil. */
.appbar {
  /* Fijado explícito: sin esto, el "display: flex; justify-content:
     space-between" del selector genérico "header {}" (pensado solo para la
     cabecera global del sitio) se cuela igual aquí -- .appbar es también un
     <header> -- y coloca .appbar-fila y .appbar-detalles uno junto al otro
     en vez de apilados, dejando el bloque de detalles comprimido contra el
     borde derecho en cualquier ancho >480px (bug encontrado en auditoría,
     2026-08-03). */
  display: block;
  position: sticky;
  top: 0;
  z-index: 20;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-2xl);
  box-shadow: var(--shadow-md);
  margin-bottom: 1.5rem;
  overflow: hidden;
}

.appbar-fila {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  padding: 0.6rem 0.8rem;
  min-height: 48px;
}

.btn-icono {
  width: 36px;
  height: 36px;
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: none;
  border: none;
  border-radius: 50%;
  color: var(--color-tinta);
  cursor: pointer;
  transition: background 0.15s ease;
}

.btn-icono:hover {
  background: var(--color-background);
}

.appbar-titulo {
  flex: 1;
  min-width: 0;
  font-family: var(--font-title);
  font-weight: 700;
  font-size: 1.05rem;
  text-transform: uppercase;
  letter-spacing: 0.005em;
  line-height: 1.25;
  margin: 0;
  color: var(--color-tinta);
  overflow: hidden;
  /* Hasta 2 líneas en la vista expandida -- antes truncaba a una sola línea
     con elipsis incluso ahí, donde sobra alto de sobra, dejando nombres
     largos casi ilegibles (depuración de cabecera, 2026-08-08). La vista
     colapsada (scroll) vuelve a 1 línea, ver más abajo -- ahí sí interesa
     compacta. */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  white-space: normal;
  word-break: break-word;
}

.appbar[data-colapsada="true"] .appbar-titulo {
  /* Vuelve al recorte clásico de una sola línea -- combinar line-clamp con
     una segunda regla que solo cambia el número de líneas dio un recorte
     inconsistente (menos texto visible que en la vista expandida, pese a
     tener más ancho libre al ocultar el icono de editar), así que la vista
     colapsada usa su propio modelo de una línea en vez de heredar el de
     "hasta 2 líneas". */
  display: block;
  -webkit-line-clamp: unset;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.appbar-chevron .icono-tab {
  transition: transform 0.2s ease;
}

.appbar[data-colapsada="true"] .appbar-chevron .icono-tab {
  transform: rotate(-90deg);
}

/* Vista reducida (cabecera colapsada al hacer scroll): solo el nombre del
   evento, sin el icono de editar -- volver y el chevron se quedan por ser
   navegación, no contenido del evento. */
.appbar[data-colapsada="true"] #btn-editar-evento {
  display: none;
}

/* Detalles plegables: plazo, lugar/fechas/convocados, enlaces y "Editar
   evento". max-height (no display) para poder animar la transición. */
.appbar-detalles {
  display: grid;
  gap: 0.5rem;
  padding: 0 0.8rem 0.9rem;
  overflow: hidden;
  max-height: 320px;
  opacity: 1;
  transition: max-height 0.22s ease, opacity 0.18s ease, padding 0.22s ease;
}

.appbar[data-colapsada="true"] .appbar-detalles {
  max-height: 0;
  opacity: 0;
  padding-top: 0;
  padding-bottom: 0;
}

.pill-estado {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.3rem 0.75rem;
  border-radius: 999px;
  font-family: var(--font-title);
  font-size: 0.75rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  background: var(--bg-aprobada);
  color: var(--text-aprobada);
}

.pill-estado::before {
  content: "";
  width: 0.45rem;
  height: 0.45rem;
  border-radius: 50%;
  background: currentColor;
}

.pill-estado[data-tono="cerrado"] {
  background: var(--color-background);
  color: var(--color-gray);
}

/* Estado + plazo de decisión debajo de lugar/fechas/convocados (depuración de
   cabecera, 2026-08-08): antes iban arriba del todo, delante del nombre. */
.appbar-estado-fila {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.5rem 0.75rem;
}

.plazo {
  font-size: 0.82rem;
  color: var(--color-gray);
}

.plazo strong {
  color: var(--text-por-revisar);
  font-variant-numeric: tabular-nums;
}

.hero-meta {
  font-size: 0.92rem;
  color: var(--color-gray);
  margin: 0;
}

.hero-links {
  display: flex;
  gap: 0.4rem;
  flex-wrap: wrap;
}

.link-chip {
  /* text-transform/letter-spacing/font-family explícitos: el botón .ics
     (<button>) hereda si no los reinicios el "button { text-transform:
     uppercase; letter-spacing: 0.03em; font-family: var(--font-title) }"
     genérico -- los enlaces de WhatsApp/Tricount (<a>) nunca lo sufrían al
     no ser <button>, de ahí que solo el .ics saliera en mayúsculas pese a
     compartir la misma clase (depuración de cabecera, 2026-08-08). */
  font-family: inherit;
  /* Más compactos (2026-08-08): el tamaño anterior (0.82rem / 0.4rem 0.75rem)
     seguía sin encajar con el resto de chips pequeños del hero (.stat-chip,
     0.72rem) -- con los tres enlaces juntos (WhatsApp, Tricount, .ics)
     ocupaban dos líneas enteras de la tarjeta. */
  font-size: 0.72rem;
  font-weight: 600;
  text-transform: none;
  letter-spacing: normal;
  text-decoration: none;
  color: var(--color-primary);
  border: 1px solid var(--color-border);
  border-radius: 999px;
  padding: 0.28rem 0.6rem;
  background: none;
  cursor: pointer;
  transition: var(--transition-all);
}

.link-chip:hover {
  border-color: var(--color-primary);
  background: var(--bg-por-revisar);
}

/* Ajuste visual Fase 27: rótulo suelto de sección, en vez de una cabecera de
   panel con título + botón "← Resumen" -- el prototipo no repite cabecera por
   pestaña, la navegación es solo la barra inferior + hoja "Más" + los atajos
   de Resumen (mismo atributo data-target). */
.eyebrow {
  font-family: var(--font-title);
  font-size: 0.72rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--color-gray);
  margin: 1.1rem 0 0.5rem;
}

.eyebrow:first-child {
  margin-top: 0;
}

/* Aviso de acceso restringido en Moderación (sustituye al título de panel) */
.aviso-gestor {
  font-size: 0.85rem;
  color: var(--color-gray);
  background: var(--color-surface);
  border: 1px dashed var(--color-border);
  border-radius: var(--radius-md);
  padding: 0.6rem 0.7rem;
  margin-bottom: 0.8rem;
  line-height: 1.45;
}

/* ============================================================
   Fase 38 (propuesta de diseño "Convocados con la estética de la portada"):
   tarjeta con cabecera oscura para listas de personas/entidades del evento --
   generaliza `.tarjeta-convocatoria`, la maqueta estática de la portada
   (Fase 37), a las listas reales: Convocados, Coches, Partidos y Plan de
   comidas, que hasta la Fase 27 usaban `.fila` suelta sin envoltorio. Un
   único componente para toda la app -- la portada usa estas mismas clases.
   ============================================================ */
.tarjeta-lista {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-md);
  overflow: hidden;
  margin-bottom: 1.5rem;
}

/* Más separación antes de la siguiente sección de la portada (37.D.3) que la
   que necesita una tarjeta de lista real dentro de una pestaña. Los ítems de
   la portada son de una sola línea (solo un nombre) -- centrados en vertical,
   a diferencia de los de una lista real, que pueden crecer a varias líneas
   (meta, observación, botones) y necesitan alinear el avatar arriba. */
.tarjeta-lista--portada {
  margin-bottom: 2.75rem;
}

.tarjeta-lista--portada .tarjeta-lista-item {
  align-items: center;
}

.tarjeta-lista-cabecera {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  background: var(--tinta-fija);
  color: var(--crema-fija);
  padding: 0.8rem 1.1rem;
}

.tarjeta-lista-titulo {
  font-family: var(--font-title);
  font-size: 0.8rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

/* Insignia de la cabecera: plazo de decisión (Convocados), plazas libres
   (Coches)... el punto usa currentColor para heredar el color del texto sin
   duplicar el keyframe por variante -- solo la insignia por defecto (ámbar,
   un plazo real que corre) pulsa; el resto queda fijo. */
.tarjeta-lista-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  font-family: var(--font-title);
  font-size: 0.72rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--color-amber);
  flex-shrink: 0;
}

.tarjeta-lista-badge::before {
  content: "";
  width: 7px;
  height: 7px;
  flex-shrink: 0;
  border-radius: 50%;
  background: currentColor;
  animation: pulso-plazo 2s infinite;
}

.tarjeta-lista-badge--teal {
  color: var(--color-teal);
}

.tarjeta-lista-badge--teal::before {
  animation: none;
}

@keyframes pulso-plazo {
  0% { box-shadow: 0 0 0 0 rgba(242, 169, 0, 0.55); }
  70% { box-shadow: 0 0 0 7px rgba(242, 169, 0, 0); }
  100% { box-shadow: 0 0 0 0 rgba(242, 169, 0, 0); }
}

.tarjeta-lista-items {
  list-style: none;
  margin: 0;
  padding: 0.2rem 1.1rem 0.9rem;
  display: flex;
  flex-direction: column;
}

.tarjeta-lista-item {
  display: flex;
  align-items: flex-start;
  gap: 0.65rem;
  font-size: 0.92rem;
  padding: 0.65rem 0;
  border-bottom: 1px solid var(--color-border);
}

.tarjeta-lista-item:last-child {
  border-bottom: none;
}

.tarjeta-lista-avatar {
  flex-shrink: 0;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-title);
  font-weight: 600;
  font-size: 0.78rem;
  color: #fff;
  margin-top: 1px;
}

.tarjeta-lista-info {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.15rem;
}

.tarjeta-lista-nombre {
  font-weight: 600;
  font-size: 0.92rem;
  line-height: 1.25;
  color: var(--color-tinta);
}

.tarjeta-lista-nombre-boton {
  background: none;
  border: none;
  padding: 0;
  font-family: inherit;
  text-align: left;
  cursor: pointer;
}

.tarjeta-lista-nombre-boton:disabled {
  cursor: default;
}

.tarjeta-lista-nombre-boton:hover:not(:disabled) {
  color: var(--color-primary);
}

.tarjeta-lista-meta {
  font-size: 0.74rem;
  color: var(--color-gray);
}

.tarjeta-lista-obs {
  font-size: 0.76rem;
  color: var(--color-tinta);
  line-height: 1.4;
  margin: 0.1rem 0 0;
  padding-left: 0.5rem;
  border-left: 2px solid var(--color-border);
}

/* "Reactivar"/"Eliminar" (.btn-ghost) dentro de un ítem de convocado: mismo
   ajuste de proporción que ya hacía `.fila-texto .btn-ghost` -- .btn-ghost
   solo cambia color/fondo/borde, así que heredaba el font-size (1.1rem), el
   padding (0.65rem 1.25rem) y las mayúsculas del <button> genérico, fuera de
   proporción con el resto del ítem (nombre a 0.92rem, avatar de 32px). */
.tarjeta-lista-info .btn-ghost {
  font-size: 0.78rem;
  font-weight: 600;
  padding: 0.2rem 0.5rem;
  text-transform: none;
}

/* Estado en píldora a la derecha de un ítem (Convocados/Coches/Partidos/
   Plan de comidas) -- antes `.estado-punto`, chip rectangular; reutiliza los
   mismos tokens de color semánticos, solo cambia la forma. */
.tarjeta-lista-estado {
  flex-shrink: 0;
  font-family: var(--font-title);
  font-size: 0.68rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  padding: 0.22rem 0.65rem;
  border-radius: 999px;
  white-space: nowrap;
  margin-top: 1px;
}

.tarjeta-lista-estado--confirmado {
  color: var(--color-teal);
  background: var(--bg-confirmado);
}

.tarjeta-lista-estado--confirmado::before {
  content: "✓ ";
}

.tarjeta-lista-estado--pendiente {
  color: var(--text-por-revisar);
  background: var(--bg-por-revisar);
}

/* Gris neutro, no rojo de "rechazada": una Baja o un "Libre" no es un error,
   es solo la ausencia de algo -- Fase 38: unificada con `--text-archivado`/
   `--bg-archivado` (ya usados en Propuestas), antes esta píldora tenía su
   propio gris fijo (`rgba(107, 114, 128, 0.15)`) sin variante de modo oscuro. */
.tarjeta-lista-estado--baja {
  color: var(--text-archivado);
  background: var(--bg-archivado);
}

/* Resumen compacto por categoría en la pestaña Propuestas, encima del listado
   completo de fichas (que conserva su ficha-grid con formulario e interacciones) */
.propuestas-resumen {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  margin-bottom: 1.5rem;
}

.propuesta-row {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  padding: 0.6rem 0.8rem;
  background: var(--color-background);
  border-radius: 8px;
  border: 1px solid var(--color-border);
}

.propuesta-row-principal {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  flex-wrap: wrap;
}

.propuesta-categoria {
  font-size: 0.88rem;
  font-weight: 600;
}

.propuesta-badges {
  display: flex;
  gap: 0.4rem;
  flex-wrap: wrap;
}

/* Fase 25.C: cierre de decisión por categoría -- antes "Elegir y cerrar"
   vivía dentro de cada ficha; ahora es esta fila, en la cabecera del bloque
   de la categoría. */
.propuesta-decision {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  flex-wrap: wrap;
  border-top: 1px dashed var(--color-border);
  padding-top: 0.5rem;
}

.propuesta-decision-texto {
  font-size: 0.85rem;
  color: var(--color-gray);
}

/* Acción primaria, distinguible de "Votar"/"Comentarios (n)" (25.C.3): mismo
   tono que el antiguo .btn-cerrar por ficha, ahora a nivel de categoría. */
.btn-cerrar-categoria {
  background-color: var(--color-teal);
  color: var(--color-surface);
  border: 1px solid var(--color-teal);
  font-weight: 600;
  padding: 0.55rem 1rem;
  min-height: 44px;
  border-radius: 8px;
  cursor: pointer;
  white-space: nowrap;
  transition: var(--transition-all);
}

.btn-cerrar-categoria:hover {
  background-color: var(--color-primary);
  border-color: var(--color-primary);
}

.badge-mini {
  font-size: 0.7rem;
  font-weight: 700;
  padding: 0.15rem 0.5rem;
  border-radius: 999px;
  text-transform: uppercase;
}

/* Calendario de partidos (fila compacta, en vez de ficha-card) */
.partidos-list {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  margin-bottom: 1.5rem;
}

/* Logística de coches (fila compacta, en vez de ficha-card) */
.coche-list {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  margin-bottom: 1.5rem;
}

/* Tab bar inferior fija en móvil (9.B.6) */
@media (max-width: 640px) {
  /* Fase 27.B.4: antes solo la barra reservaba el hueco con env(), no el
     contenido -- en iPhone con barra de gestos el último elemento de cada
     panel quedaba tapado por la propia barra inferior. */
  #vista-fichas {
    padding-bottom: calc(4.5rem + env(safe-area-inset-bottom));
  }

  /* Barra de 5 destinos fijos (Fase 27.B.2): grid en vez de flex para que
     ninguno se comprima ni desborde, con icono arriba y etiqueta debajo. */
  .tabs-nav {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 1000;
    display: grid;
    grid-template-columns: repeat(5, 1fr);
    height: 58px;
    margin-bottom: 0;
    border-bottom: none;
    border-top: 2px solid var(--color-border);
    box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.08);
    padding-bottom: env(safe-area-inset-bottom, 0);
  }

  .tab-btn {
    flex-direction: column;
    justify-content: center;
    gap: 0.15rem;
    min-width: 0;
    text-align: center;
    padding: 0.4rem 0.2rem;
    font-size: 0.62rem;
    border-bottom: none;
  }

  .tab-btn .icono-tab {
    width: 21px;
    height: 21px;
  }
}

/* Hoja "Más" (Fase 27.B.3): bottom-sheet con los destinos que no caben en la
   barra inferior -- Coches, Partidos, Moderación, Sitios de interés y Editar
   el viaje. <dialog> nativo: Escape y el propio navegador ya gestionan el
   foco modal, solo hace falta posicionarlo abajo y estilar el velo. */
#hoja-mas {
  position: fixed;
  inset: auto 0 0 0;
  width: 100%;
  max-width: 480px;
  margin: 0 auto;
  border: none;
  border-radius: var(--radius-2xl) var(--radius-2xl) 0 0;
  padding: 0.6rem 0.8rem calc(1rem + env(safe-area-inset-bottom));
  background: var(--color-surface);
  color: var(--color-tinta);
  box-shadow: 0 -8px 30px rgba(0, 0, 0, 0.25);
}

#hoja-mas::backdrop {
  background: rgba(0, 0, 0, 0.45);
}

.hoja-mas-asa {
  width: 36px;
  height: 4px;
  border-radius: 999px;
  background: var(--color-border);
  margin: 0.3rem auto 0.8rem;
}

.hoja-mas-item {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  width: 100%;
  background: none;
  border: none;
  border-bottom: 1px solid var(--color-border);
  padding: 0.75rem 0.2rem;
  font-family: var(--font-body);
  font-size: 0.95rem;
  font-weight: 500;
  color: var(--color-tinta);
  cursor: pointer;
  text-align: left;
}

.hoja-mas-item:last-child {
  border-bottom: none;
}

.hoja-mas-item[hidden] {
  display: none;
}

.hoja-mas-item .icono-tab {
  color: var(--color-gray);
  flex-shrink: 0;
}

.hoja-mas-cuenta {
  margin-left: auto;
  font-size: 0.72rem;
  font-weight: 700;
  color: #fff;
  background: var(--color-primary);
  border-radius: 999px;
  padding: 0.1rem 0.4rem;
}

/* ============================================================
   Componente .card-ticket (rediseño visual, Paso 3): tarjeta con
   aspecto de "ticket" — bordes perforados simulados con notches
   circulares en los laterales, rellenos del color de fondo de la
   página para que parezcan un recorte. Se aplica a .rol-card en el
   Paso 4.
   ============================================================ */
.card-ticket {
  position: relative;
  border-radius: var(--radius-3xl);
  overflow: visible;
}

.card-ticket::before,
.card-ticket::after {
  content: "";
  position: absolute;
  top: 50%;
  width: 1.5rem;
  height: 1.5rem;
  background: var(--color-background);
  border-radius: 50%;
  transform: translateY(-50%);
  pointer-events: none;
}

.card-ticket::before {
  left: -0.75rem;
}

.card-ticket::after {
  right: -0.75rem;
}

/* ============================================================
   Vista de inicio (portada de captación, Fase 37: reencuadre del mensaje --
   docs/FASE_37_PORTADA_Y_MARCA.md)
   ============================================================ */

.landing-hero {
  text-align: center;
  margin-bottom: 2.75rem;
}

.landing-hero h2 {
  border-left: none;
  padding-left: 0;
  margin-bottom: 0.75rem;
}

/* 37.A.1 / D37.1: titular en dos frases -- "el club convoca al equipo" queda
   en tinta normal, "vosotros convocáis a las familias" en --color-primary,
   resolviendo el reparto de papeles en la propia primera lectura. */
.hero-titular-club,
.hero-titular-familias {
  display: block;
  font-size: clamp(1.55rem, 5.2vw, 2.3rem);
  line-height: 1.2;
  text-wrap: balance;
}

.hero-titular-familias {
  color: var(--color-primary);
}

.landing-hero p {
  font-size: 1.02rem;
  color: var(--color-gray);
  max-width: 46ch;
  margin: 0 auto;
}

/* Rótulo pequeño en versalitas sobre el titular de cada sección de la
   portada (kicker), igual que .eyebrow pero en --color-primary con una
   pequeña marca previa -- .eyebrow se queda en gris porque se reutiliza
   dentro del detalle del evento y no debe cambiar de color ahí. */
.landing-kicker {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-family: var(--font-title);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  font-size: 0.78rem;
  color: var(--color-primary);
  margin-bottom: 0.5rem;
}

.landing-kicker::before {
  content: "";
  width: 18px;
  height: 2px;
  background: var(--color-amber);
  flex-shrink: 0;
}

.comparativa .landing-kicker,
.flujo .landing-kicker,
.ventajas .landing-kicker,
.faq .landing-kicker {
  display: flex;
  justify-content: center;
}

/* Fase 29 (A-02): deja de ser un ancla discreta de contorno que hacía scroll
   a "Entra en tu cuenta" y pasa a ser LA acción de la página -- crear cuenta.
   De ahí el relleno naranja: es lo que debe mirarse primero al aterrizar. */
.landing-cta-row {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: 0.75rem;
}

.landing-cta {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  margin-top: 1.5rem;
  min-height: 48px;
  padding: 0.8rem 1.9rem;
  border-radius: 999px;
  border: none;
  background: var(--color-primary);
  color: #fff;
  font-family: var(--font-title);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  font-size: 1rem;
  text-decoration: none;
  cursor: pointer;
  box-shadow: var(--shadow-warm-md);
  transition: var(--transition-all);
}

.landing-cta:hover {
  background: var(--color-primary-hover);
  box-shadow: var(--shadow-warm-lg);
  transform: translateY(-1px);
}

.landing-cta:focus-visible {
  outline: 2px solid var(--color-teal);
  outline-offset: 2px;
}

/* Acción secundaria junto al CTA principal del hero: ancla a #como-funciona,
   mismo contorno que .btn-ghost pero con el tamaño de un CTA de hero. */
.landing-cta-ghost {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin-top: 1.5rem;
  min-height: 48px;
  padding: 0.8rem 1.6rem;
  border-radius: 999px;
  border: 1.5px solid var(--color-border);
  background: transparent;
  color: var(--color-tinta);
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 0.95rem;
  text-decoration: none;
  cursor: pointer;
  transition: var(--transition-all);
}

.landing-cta-ghost:hover {
  border-color: var(--color-primary);
  color: var(--color-primary);
}

/* 37.D.8: CTA de cierre, tras la FAQ. */
.landing-cta-final {
  text-align: center;
  margin: 2.75rem 0;
}

.landing-cta-final h3 {
  font-family: var(--font-title);
  font-weight: 700;
  text-transform: uppercase;
  font-size: clamp(1.5rem, 6vw, 2rem);
  line-height: 1.1;
  letter-spacing: -0.01em;
}

.landing-cta-final p {
  color: var(--color-gray);
  font-size: 0.98rem;
  margin: 0.85rem auto 0;
  max-width: 38ch;
}

/* ============================================================
   37.D.1 -- Tarjeta "Convocatoria del viaje": maqueta ilustrativa y estática,
   sin conexión a datos reales (criterio de aceptación 6). Desde la Fase 38
   reutiliza el mismo componente de tarjeta que las listas reales de la app
   (`.tarjeta-lista*`, más arriba en este fichero) en vez de una clase propia
   -- partido bloqueado (D37.9) arriba, estados de asistencia de cuatro
   familias de ejemplo abajo, con `.tarjeta-lista-items`/`-item`/`-avatar`/
   `-estado--*`.
   ============================================================ */
.partido-bloqueado {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  background: color-mix(in srgb, var(--color-primary) 6%, transparent);
  border-bottom: 1px dashed var(--color-border);
  padding: 0.9rem 1.1rem;
}

.partido-candado {
  flex-shrink: 0;
  color: var(--color-primary);
  /* Pulso sutil sobre el candado -- criterio de aceptación 9: queda anulado
     por la regla global @media (prefers-reduced-motion: reduce) de arriba
     del fichero, que ya neutraliza cualquier animation-duration. */
  animation: pulso-candado 2.4s ease-in-out infinite;
}

@keyframes pulso-candado {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.55; }
}

.partido-texto {
  flex: 1;
  min-width: 0;
  font-size: 0.88rem;
  color: var(--color-tinta);
}

.partido-etiqueta {
  flex-shrink: 0;
  font-family: var(--font-title);
  font-size: 0.66rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--color-primary);
  border: 1px solid var(--color-primary);
  border-radius: 999px;
  padding: 0.25rem 0.6rem;
  white-space: nowrap;
}

/* ============================================================
   37.D.3 / D37.7 -- Comparativa "Hoy, por WhatsApp" / "Con Call-Up"
   ============================================================ */
.comparativa {
  margin-bottom: 2.75rem;
  text-align: center;
}

/* Titular grande de sección (mismo tratamiento que el hero: Oswald 700,
   versales, condensado), bajo el kicker pequeño -- .comparativa h3,
   .flujo h3, .ventajas h3 y .faq h3 comparten esta jerarquía. */
.comparativa h3,
.flujo h3,
.roles h3,
.ventajas h3,
.faq h3 {
  font-family: var(--font-title);
  font-weight: 700;
  text-transform: uppercase;
  font-size: clamp(1.35rem, 5.5vw, 1.75rem);
  line-height: 1.12;
  letter-spacing: -0.01em;
  text-align: center;
  margin: 0 0 1.4rem;
}

.comparativa-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1rem;
  text-align: left;
}

@media (min-width: 680px) {
  .comparativa-grid {
    grid-template-columns: 1fr 1fr;
  }
}

.comparativa-col {
  border-radius: var(--radius-lg);
  padding: 1.4rem 1.4rem;
  border: 1px solid var(--color-border);
}

.comparativa-col h4 {
  font-family: var(--font-title);
  font-size: 1.05rem;
  font-weight: 700;
  text-transform: uppercase;
  margin-bottom: 0.85rem;
}

.comparativa-col ul {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  font-size: 0.9rem;
}

.comparativa-col li {
  display: flex;
  align-items: flex-start;
  gap: 0.6rem;
}

.comparativa-col li::before {
  flex-shrink: 0;
  font-weight: 700;
}

.comparativa-col--whatsapp {
  background: var(--color-surface);
  color: var(--color-gray);
}

.comparativa-col--whatsapp h4 {
  color: var(--color-tinta);
}

.comparativa-col--whatsapp li::before {
  content: "✕";
  color: var(--color-gray);
}

/* Polaridad invertida a propósito -- misma lectura que el prototipo de
   referencia: "hoy" en tarjeta clara y "con Call-Up" en tarjeta oscura,
   para que el contraste entre ambas columnas se note sin leer el texto. */
.comparativa-col--callup {
  background: var(--tinta-fija);
  border-color: var(--tinta-fija);
  color: var(--crema-fija);
}

.comparativa-col--callup h4 {
  color: var(--color-amber);
}

.comparativa-col--callup li::before {
  content: "→";
  color: var(--color-amber);
}

.flujo {
  margin-bottom: 2.75rem;
  text-align: center;
}

.flujo-intro {
  text-align: center;
  color: var(--color-gray);
  font-size: 0.92rem;
  max-width: 40ch;
  margin: 0 auto 1.8rem;
}

/* ============================================================
   Pasos "Así de sencillo": timeline vertical numerada, siempre en una sola
   columna -- deliberadamente distinta de .ventajas-grid (rejilla de
   tarjetas) para no confundir una secuencia ordenada con una lista de
   argumentos sueltos.
   ============================================================ */
.flujo-pasos {
  display: flex;
  flex-direction: column;
  max-width: 42ch;
  margin: 0 auto;
  text-align: left;
}

.paso-item {
  display: flex;
  gap: 1rem;
  padding-bottom: 1.7rem;
  position: relative;
}

.paso-item:not(:last-child)::after {
  content: "";
  position: absolute;
  left: 1.05rem;
  top: 2.6rem;
  bottom: 0;
  width: 2px;
  background: var(--color-border);
}

.paso-numero {
  flex-shrink: 0;
  width: 2.15rem;
  height: 2.15rem;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--color-primary);
  color: #fff;
  font-family: var(--font-title);
  font-weight: 600;
  font-size: 0.98rem;
  position: relative;
  z-index: 1;
}

/* El último paso (Animad) marca el punto de anclaje del viaje -- el partido
   -- con el mismo contraste de tinta que usa el resto de la marca para
   distinguir "lo fijo" de "lo que decide el grupo". */
.paso-item--final .paso-numero {
  background: var(--tinta-fija);
}

.paso-texto h4 {
  font-family: var(--font-title);
  font-size: 1.15rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: -0.005em;
  color: var(--color-tinta);
  margin-bottom: 0.3rem;
}

.paso-texto p {
  font-size: 0.9rem;
  color: var(--color-gray);
}

/* ============================================================
   37.D.5 -- Ventajas: rejilla de tarjetas con icono, siempre a 2 columnas
   (incluso en móvil, como el prototipo de referencia) porque cada tarjeta
   es breve y no son pasos ordenados, a diferencia de .flujo-pasos.
   ============================================================ */
.ventajas {
  margin-bottom: 2.75rem;
  text-align: center;
}

.ventaja-card {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  padding: 1.1rem 1rem;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  text-align: left;
  transition: var(--transition-all);
}

.ventaja-card:hover {
  transform: translateY(-3px);
  box-shadow: var(--shadow-md);
  border-color: var(--color-primary);
}

.ventaja-icono {
  width: 2.6rem;
  height: 2.6rem;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: linear-gradient(150deg, rgba(232, 86, 43, 0.16), rgba(242, 169, 0, 0.14));
  border: 1px solid rgba(232, 86, 43, 0.25);
}

.ventaja-icono svg {
  width: 1.3rem;
  height: 1.3rem;
  stroke: var(--color-primary);
  fill: none;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.ventaja-card h4 {
  font-family: var(--font-title);
  font-size: 1rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: -0.005em;
  color: var(--color-tinta);
}

.ventaja-card p {
  font-size: 0.85rem;
  color: var(--color-gray);
}

/* A 2 columnas desde el principio, como el prototipo de referencia -- cada
   tarjeta es breve y cabe de sobra en la mitad de un móvil normal; por
   debajo de ese ancho (relojes, plegables cerrados) cae a 1 columna. */
.ventajas-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.75rem;
}

@media (max-width: 360px) {
  .ventajas-grid {
    grid-template-columns: 1fr;
  }
}

/* ============================================================
   37.D.6 / D37.8 -- Preguntas frecuentes, sobre <details>/<summary> nativos:
   funcionan con teclado sin JS propio (criterio de aceptación 10).
   ============================================================ */
.faq {
  margin-bottom: 2.75rem;
  text-align: center;
}

.faq-lista {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  max-width: 60ch;
  margin: 0 auto;
}

.faq-item {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  padding: 0.2rem 1.1rem;
  text-align: left;
  transition: border-color 0.2s ease;
}

.faq-item[open] {
  border-color: var(--color-primary);
}

.faq-pregunta {
  cursor: pointer;
  list-style: none;
  min-height: 44px;
  display: flex;
  align-items: center;
  gap: 0.75rem;
  font-weight: 600;
  padding: 0.75rem 0;
}

.faq-pregunta::-webkit-details-marker {
  display: none;
}

/* Icono "+" en un círculo, que gira 45º al abrirse hasta leerse como una
   "×" -- mismo lenguaje que el resto de la marca (círculo + trazo). */
.faq-pregunta::after {
  content: "+";
  margin-left: auto;
  flex-shrink: 0;
  width: 1.4rem;
  height: 1.4rem;
  border-radius: 50%;
  border: 1.5px solid var(--color-border);
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-title);
  font-size: 1rem;
  line-height: 1;
  color: var(--color-primary);
  transition: var(--transition-all);
}

.faq-item[open] .faq-pregunta::after {
  transform: rotate(45deg);
}

.faq-pregunta:focus-visible {
  outline: 2px solid var(--color-primary);
  outline-offset: 2px;
}

.faq-respuesta {
  font-size: 0.92rem;
  color: var(--color-gray);
  padding-bottom: 0.9rem;
}

/* Fase 32 (docs/PLAN_MEJORA_PRODUCTO_COMERCIAL.md): pie de la portada, único
   sitio de la app fuera del alta donde privacidad/términos quedan visibles
   sin que haga falta empezar a crear una cuenta. Fase 37 (37.B.3): envuelve
   el lockup de marca a escala menor (arriba) y los enlaces legales (abajo). */
.pie-footer {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1.1rem;
  margin-top: 2.5rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--color-border);
}

.pie-legal {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.82rem;
  color: var(--color-gray);
}

.pie-legal a {
  color: var(--color-gray);
}

.roles-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1.1rem;
}

@media (min-width: 620px) {
  .roles-grid {
    grid-template-columns: 1fr 1fr;
  }
}

/* Fase 25 (25.A.2, AUD-07): el título es un <h4> fuera del <button> (un
   encabezado no puede vivir dentro de un control interactivo), así que
   ".rol-card-grupo" es quien ocupa la celda del grid y apila título + botón;
   el botón conserva el mismo aspecto visual de "ticket" que tenía antes. */
.rol-card-grupo {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

button.rol-card {
  display: flex;
  flex-direction: column;
  gap: 0.65rem;
  text-align: left;
  background: var(--color-surface);
  color: var(--color-tinta);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-md);
  padding: 1.6rem 1.4rem;
  cursor: pointer;
  transition: var(--transition-all);
  font-family: var(--font-body);
  font-size: 1rem;
  font-weight: 400;
  text-transform: none;
  letter-spacing: normal;
  width: 100%;
}

button.rol-card:hover {
  background: var(--color-surface);
  transform: translateY(-3px);
  box-shadow: var(--shadow-lg);
  border-color: var(--color-primary);
}

.rol-icono {
  width: 2.75rem;
  height: 2.75rem;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.3rem;
  background: var(--color-background);
}

.rol-titulo {
  font-family: var(--font-title);
  font-size: 1.2rem;
  font-weight: 600;
  text-transform: uppercase;
  color: var(--color-tinta);
  padding: 0 0.2rem;
}

.rol-card p {
  font-size: 0.9rem;
  color: var(--color-gray);
}

.rol-cta {
  font-family: var(--font-title);
  font-size: 0.82rem;
  font-weight: 600;
  text-transform: uppercase;
  color: var(--color-primary);
}

/* ============================================================
   Acceso (Fase 29, docs/AUDITORIA_UXUI_ACCESO_2026-08-04.md)
   ============================================================ */

.landing-secundaria {
  text-align: center;
  font-size: 0.88rem;
  color: var(--color-gray);
  margin: 1.4rem auto 0;
}

/* Conmutador Crear cuenta / Entrar. role="group" + aria-pressed, no
   role="tablist": los paneles no son tabpanels de verdad (cada modo tiene su
   propia URL y su propio <form>), y un tablist mal formado es peor que
   ninguno -- mismo criterio que la Fase 25.A aplicó al filtro de categorías. */
.acceso-tabs {
  display: flex;
  gap: 0.4rem;
  margin-bottom: 1.5rem;
}

.acceso-tab {
  flex: 1 1 0;
  min-height: 44px; /* objetivo táctil, mismo criterio que la Fase 25.B */
  border: 1px solid var(--color-border);
  border-radius: 999px;
  background: var(--color-surface);
  color: var(--color-gray);
  font-family: var(--font-title);
  font-size: 0.9rem;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  cursor: pointer;
  transition: var(--transition-all);
}

.acceso-tab[aria-pressed="true"] {
  background: var(--color-primary);
  border-color: var(--color-primary);
  color: #fff;
  box-shadow: var(--shadow-warm-md);
}

.acceso-tab:hover:not([aria-pressed="true"]) {
  border-color: var(--color-primary);
  color: var(--color-tinta);
}

.acceso-form {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  max-width: 26rem;
}

/* Bug de cascada [hidden] ya conocido en este archivo (.admin-form[hidden],
   .comentarios-panel[hidden] de la Fase 25.B): una regla de autor con
   `display` gana SIEMPRE al [hidden] de la hoja de user-agent, sea cual sea
   la especificidad. Sin esto los tres formularios se verían a la vez. */
.acceso-form[hidden] {
  display: none;
}

.campo-ayuda {
  font-size: 0.78rem;
  color: var(--color-gray);
  margin: 0.3rem 0 0;
}

.campo-consentimiento label {
  display: flex;
  align-items: flex-start;
  gap: 0.5rem;
  font-size: 0.85rem;
  font-weight: 400;
  color: var(--color-gray);
  line-height: 1.45;
}

.campo-consentimiento input {
  margin-top: 0.15rem;
  flex: 0 0 auto;
}

/* Sin esto los dos enlaces salían en el azul por defecto del navegador,
   el único color fuera de la paleta en toda la pantalla de acceso. */
.campo-consentimiento a {
  color: var(--color-teal);
  font-weight: 600;
}

.acceso-mensaje {
  font-size: 0.86rem;
  font-weight: 600;
  color: var(--text-aprobada);
  margin: 0;
}

/* Un fallo de acceso es un error, no un estado: color propio y role="alert"
   en el HTML. Antes el color se fijaba con element.style.color desde app.js,
   contra la convención de la Fase 16 (sin CSS inline). */
.acceso-mensaje.es-error {
  color: var(--text-rechazada);
}

.acceso-mensaje[hidden] {
  display: none;
}

/* ============================================================
   Listados por rol (Administración de eventos / Resumen de eventos)
   ============================================================ */

.cabecera-vista-eventos {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
}

.cabecera-vista-eventos h2 {
  margin: 0;
}

.subtitulo-vista {
  color: var(--color-gray);
  font-size: 0.92rem;
  margin-top: 0.35rem;
  margin-bottom: 1.5rem;
  padding-left: 1rem;
}

.badge-abierto {
  background-color: var(--bg-aprobada);
  color: var(--text-aprobada);
}

.badge-decidido {
  background-color: var(--bg-por-revisar);
  color: var(--text-por-revisar);
}

.badge-archivado {
  background-color: var(--bg-archivado);
  color: var(--text-archivado);
}

/* ─────────────────────────────────────────────────────────
   Fase 16 (docs/PLAN_IMPLEMENTACION.md): extracción de los style="..."
   inline que quedaban en index.html, agrupados por patrón. No cambia el
   aspecto visual -- cada regla reproduce exactamente el valor que tenía el
   atributo inline que sustituye.
   ───────────────────────────────────────────────────────── */

/* Grid de 2 columnas, reutilizado en varios formularios (fechas del evento,
   coche, partido). */
.grid-2-columnas {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1rem;
}

/* Encabezado de subsección tipo h4 dentro de una pestaña (coches,
   partidos) -- no se generaliza a un h4{} global porque otros <h4> de la
   landing (.paso-texto h4, .ventaja-card h4, .rol-card h4) ya tienen su
   propio estilo. */
.subseccion-titulo {
  font-family: var(--font-title);
  text-transform: uppercase;
  font-size: 1rem;
  margin-bottom: 0.75rem;
}

/* Ya existían en el HTML pero sin regla propia: el style="..." inline era
   hasta ahora la única fuente de su apariencia. */
.nota-explicativa {
  font-size: 0.85rem;
  color: var(--color-gray);
  margin-bottom: 1rem;
}

/* Fase 38: ya no es una tarjeta propia -- la lista de dentro (#lista-asistentes)
   es ahora su propia .tarjeta-lista, así que envolverla aquí también dejaba
   una tarjeta blanca dentro de otra tarjeta blanca. Queda solo como
   contenedor de espaciado entre la tarjeta y el formulario de alta. */
.seccion-asistentes {
  display: flex;
  flex-direction: column;
  gap: 1.1rem;
}

.seccion-partidos {
  margin-bottom: 2rem;
}

/* Campos de formulario más compactos que el input/select por defecto
   (padding/radio menores) -- ya eran así antes de esta fase, se conserva
   el mismo aspecto, solo se deja de fijar con style="...". */
.campo-compacto {
  padding: 0.5rem;
  border-radius: 6px;
  border: 1px solid var(--color-border);
}

#mapa-evento {
  height: 350px;
  border-radius: var(--radius-md);
  margin-bottom: 1rem;
  border: 1px solid var(--color-border);
  z-index: 1;
}

/* Tema oscuro (Fase 27.E.8): filtro CSS de inversión sobre las teselas de
   OpenStreetMap -- apaño reconocido (la alternativa limpia, un proveedor de
   teselas oscuras, exige alta y límites de uso fuera de las gratuitas sin
   registro). Se revisa si molesta. */
:root[data-tema="oscuro"] #mapa-evento .leaflet-tile {
  filter: invert(1) hue-rotate(180deg) brightness(0.92) contrast(0.9);
}

/* Mapa en miniatura de Resumen (ajuste visual Fase 27, revisa 27.E.2): un
   Leaflet real y pequeño -- no interactivo -- con un botón superpuesto hacia
   la vista completa, igual que hace el prototipo con sus dos instancias de
   la misma librería (no es una segunda dependencia). */
.mapa-caja {
  position: relative;
  border-radius: var(--radius-md);
  overflow: hidden;
  border: 1px solid var(--color-border);
  background: var(--color-background);
  box-shadow: var(--shadow-sm);
}

.mapa-caja-preview {
  height: 150px;
  margin-bottom: 0.5rem;
}

.mapa-caja-preview #mapa-resumen-preview {
  position: absolute;
  inset: 0;
  z-index: 0;
}

/* Estado vacío del mini-mapa (auditoría 2026-08-03, ver #mapa-evento-vacio):
   ocupa el mismo hueco que el mapa mientras no hay ningún pin real. */
.mapa-caja-preview #mapa-resumen-preview-vacio {
  position: absolute;
  inset: 0;
  z-index: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 0;
  padding: 0.5rem 3.5rem 0.5rem 0.5rem;
  font-size: 0.85rem;
}

/* Mismo bug de cascada que ya documentan .comentarios-panel[hidden] y otros
   6 casos en este archivo: el "display: flex" de arriba gana al [hidden] de
   user-agent por origen de cascada, sea cual sea la especificidad -- hace
   falta esta regla explícita para que el atributo hidden funcione. */
.mapa-caja-preview #mapa-resumen-preview-vacio[hidden] {
  display: none;
}

.mapa-abrir {
  position: absolute;
  right: 0.5rem;
  bottom: 0.5rem;
  z-index: 3;
  font-family: var(--font-body);
  font-size: 0.72rem;
  font-weight: 700;
  background: var(--color-surface);
  color: var(--color-tinta);
  border: 1px solid var(--color-border);
  border-radius: 999px;
  padding: 0.35rem 0.65rem;
  cursor: pointer;
  box-shadow: var(--shadow-sm);
}

.mapa-abrir:hover {
  border-color: var(--color-primary);
  color: var(--color-primary);
}

/* Leyenda de colores del mapa (Fase 27.E) */
.leyenda-mapa {
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem 0.75rem;
  margin: 0.6rem 0 0.9rem;
  font-size: 0.82rem;
  color: var(--color-gray);
}

.leyenda-item {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
}

.punto-color {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  flex-shrink: 0;
}

.punto-fijo { background: var(--color-tinta); }
.punto-elegido { background: var(--color-teal); }
.punto-votacion { background: var(--color-primary); }
.punto-revision { background: var(--color-amber); }

/* Pines del mapa (Fase 27.E): color por estado, no por categoría -- el icono
   dentro es el símbolo del sprite de la sección correspondiente (27.B). */
.pin-gota {
  width: 26px;
  height: 26px;
  border-radius: 50% 50% 50% 4px;
  transform: rotate(-45deg);
  display: flex;
  align-items: center;
  justify-content: center;
  border: 2px solid #fff;
  box-shadow: var(--shadow-sm);
}

.pin-gota .icono-tab {
  width: 13px;
  height: 13px;
  transform: rotate(45deg);
  color: #fff;
}

.pin-fijo .pin-gota { background: var(--color-tinta); }
.pin-elegido .pin-gota { background: var(--color-teal); }
.pin-votacion .pin-gota { background: var(--color-primary); }
.pin-revision .pin-gota { background: var(--color-amber); }

/* Ficha resumida bajo el mapa al tocar un pin (27.E.3/27.E.4): no un popup de
   Leaflet, que en móvil tapa el propio mapa. */
#mapa-ficha-resumida:empty {
  display: none;
}

.mapa-detalle {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  padding: 0.9rem 1rem;
  margin-bottom: 0.9rem;
  box-shadow: var(--shadow-sm);
}

.mapa-detalle-top {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-bottom: 0.4rem;
}

.mapa-detalle-nombre {
  font-family: var(--font-title);
  font-size: 1rem;
  font-weight: 600;
  margin: 0;
  flex: 1;
}

.mapa-detalle-dato {
  font-size: 0.85rem;
  color: var(--color-gray);
  margin: 0 0 0.6rem;
}

#lista-asistentes {
  display: flex;
  gap: 0.5rem;
  flex-wrap: wrap;
  margin-bottom: 1rem;
}

#formulario-convocado {
  display: flex;
  gap: 0.5rem;
  flex-wrap: wrap;
  align-items: flex-end;
}

/* Mismo bug de cascada [hidden] ya conocido en este CSS (.admin-form[hidden]
   y los otros 6 casos documentados): el "display: flex" de arriba gana por
   origen de cascada al [hidden] del user-agent, así que al elegir "Compartir
   enlace" en el alta de convocado (fijarModoAltaConvocado(), app.js) este
   formulario (nombre + email) se quedaba visible encima del panel de enlace
   en vez de ocultarse, generando dudas sobre cuál de los dos rellenar. */
#formulario-convocado[hidden] {
  display: none;
}

#formulario-convocado > div {
  flex: 1 1 200px;
  display: grid;
}

/* Fase 32: la casilla de declaración de terceros ocupa su propia línea --
   sin esto heredaba flex: 1 1 200px + align-items: flex-end del contenedor
   y aparecía flotando junto a Nombre/Email en vez de debajo. */
#formulario-convocado .campo-consentimiento {
  flex: 1 1 100%;
  align-self: stretch;
}

#formulario-convocado label {
  margin-bottom: 0.25rem;
}

#formulario-coche,
#formulario-partido,
.formulario-ficha {
  margin-bottom: 1.5rem;
}

#partido-instalacion {
  background: var(--color-surface);
}

#admin-estado-panel {
  background: var(--color-surface);
  padding: 1rem;
  border-radius: var(--radius-md);
  border: 1px solid var(--color-border);
  margin-bottom: 1.5rem;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
}

.admin-estado-grupo {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-wrap: wrap;
}

#admin-estado-panel label {
  font-weight: 600;
}

#evento-estado-select {
  font-weight: 500;
}

#modal-asistencia {
  padding: 2rem;
  border-radius: var(--radius-md);
  border: 1px solid var(--color-border);
  max-width: 400px;
  margin: auto;
  box-shadow: var(--shadow-lg);
}

#modal-asistente-nombre {
  margin-top: 0;
}

.modal-campo {
  margin-bottom: 1rem;
  display: grid;
}

.modal-campo label {
  margin-bottom: 0.25rem;
}

#modal-asistente-familiares-grupo {
  margin-bottom: 1.5rem;
  display: grid;
}

#modal-asistente-familiares-grupo > label {
  margin-bottom: 0.25rem;
}

#modal-asistente-familiares-lista {
  display: grid;
  gap: 0.5rem;
}

#btn-anadir-familiar {
  margin-top: 0.5rem;
  justify-self: start;
}

.modal-acciones {
  display: flex;
  gap: 1rem;
  justify-content: flex-end;
}
