/* ==========================================================================
   Nivel UP · Portal
   Un solo CSS para las tres zonas. Mobile-first: las familias entran desde el
   móvil, así que ese es el caso base y el escritorio solo ensancha.
   Usa los tokens de marca de tokens.css.
   ========================================================================== */
*, *::before, *::after { box-sizing: border-box; }

html, body {
  margin: 0;
  font-family: var(--font-body, "Plus Jakarta Sans", system-ui, sans-serif);
  font-size: 16px;                 /* 16px base: evita el zoom automático de iOS */
  color: var(--ink, #16243f);
  background: var(--cream-2, #eef3fb);
  -webkit-text-size-adjust: 100%;
  -webkit-tap-highlight-color: transparent;
}

a { color: var(--azul); }

/* Accesibilidad: foco siempre visible al navegar con teclado */
:focus-visible { outline: 3px solid var(--azul); outline-offset: 2px; }

.oculto { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

/* ==========================================================================
   1. Estructura de página (portal: familias / monitores)
   ========================================================================== */
.pt { min-height: 100vh; min-height: 100dvh; display: flex; flex-direction: column; }

.pt__bar {
  position: sticky; top: 0; z-index: 20;
  display: flex; align-items: center; gap: 12px;
  padding: calc(env(safe-area-inset-top) + 12px) 16px 12px;
  background: var(--white, #fff);
  border-bottom: 1px solid var(--line, #e3e9f3);
}
.pt__bar img { height: 26px; width: auto; }
.pt__bar .titulo { font-family: var(--font-display, "Outfit", sans-serif); font-weight: 700; font-size: 16px; line-height: 1.1; }
.pt__bar .titulo small { display: block; font-family: inherit; font-weight: 600; font-size: 12px; color: var(--azul-deep); }
.pt__bar .sep { margin-left: auto; }

/* Hoy solo es el «Cerrar sesión» de la cabecera: algo que casi nunca se
   pulsa, así que sin disco de fondo, solo el icono en gris. El área de toque
   sigue siendo de 44 px aunque no se vea (24/09/2026). */
.icon-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 44px; height: 44px; margin-right: -8px; border-radius: 999px;
  background: transparent; color: var(--muted);
  border: none; cursor: pointer; font-size: 20px; text-decoration: none;
}
.icon-btn:hover { color: var(--ink); background: var(--line-soft); }
.icon-btn:active { background: var(--line-soft); }

.pt__main {
  flex: 1; width: 100%; max-width: 680px; margin: 0 auto;
  padding: 18px 16px calc(env(safe-area-inset-bottom) + 96px);
}
@media (min-width: 720px) { .pt__main { padding-bottom: 40px; } }

/* Barra inferior tipo app */
.pt__nav {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 30;
  display: flex; justify-content: space-around;
  background: var(--white); border-top: 1px solid var(--line);
  padding: 8px 8px calc(env(safe-area-inset-bottom) + 8px);
}
.pt__nav a, .pt__nav button {
  flex: 1; min-height: 48px;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px;
  background: none; border: none; cursor: pointer; text-decoration: none;
  color: var(--muted, #8090a4); font-family: inherit; font-size: 11.5px; font-weight: 600;
  padding: 6px 2px; border-radius: 12px;
  white-space: nowrap;             /* que la etiqueta no se parta en dos líneas */
  line-height: 1.2;
}
.pt__nav i { font-size: 21px; line-height: 1; }
.pt__nav .activo { color: var(--azul-deep); }
.pt__nav .activo i { color: var(--azul); }

/* El botón de apuntar: cinco pestañas y la de en medio levantada, que es
   donde el pulgar llega solo. No lleva estado «activo» porque no es un sitio
   donde se esté, sino algo que se hace.
   Va ANTES del bloque de escritorio a propósito: con la misma especificidad
   gana la regla de más abajo, así que si estas estuvieran detrás del `@media`
   el escritorio no podría cambiarles ni el color ni el tamaño del icono. */
.pt__nav .pt__cta { color: var(--azul-deep); }
.pt__cta__disco {
  display: inline-flex; align-items: center; justify-content: center;
  width: 46px; height: 46px; margin-top: -22px; margin-bottom: 1px;
  border-radius: 999px; background: var(--azul); color: var(--white);
  box-shadow: 0 8px 18px -6px rgba(22, 36, 63, .45);
  border: 3px solid var(--white);
}
.pt__nav .pt__cta__disco i { font-size: 22px; }
.pt__cta:active .pt__cta__disco { transform: scale(.94); }

/* Pantallas muy estrechas: reduce un punto la etiqueta antes que romperla. */
@media (max-width: 360px) {
  .pt__nav a, .pt__nav button { font-size: 10.5px; }
  .pt__nav i { font-size: 20px; }
}

/* Seis pestañas: las de quien coordina un colegio y además va en el equipo
   de un viaje de fin de curso (11/10/2026). En el móvil cada una se queda en
   unos 60 px y «Mi colegio» no cabía en la suya: la letra baja un punto y el
   relleno de los lados se va. En pantalla ancha la barra flota y crece con
   lo que lleva, así que ahí no hace falta. */
@media (max-width: 719px) {
  .pt__nav--seis { padding-left: 4px; padding-right: 4px; }
  .pt__nav--seis a { font-size: 10px; padding-left: 0; padding-right: 0; }
  .pt__nav--seis i { font-size: 19px; }
}

/* Tablet y escritorio: barra flotante con icono y texto EN LÍNEA, que queda
   mucho más limpia que la disposición en columna del móvil. */
@media (min-width: 720px) {
  .pt__nav {
    position: sticky; bottom: 20px;
    width: max-content; max-width: 100%;
    margin: 24px auto; padding: 7px;
    gap: 4px; justify-content: center;
    border-radius: 999px; border: 1px solid var(--line);
    box-shadow: var(--sh-card, 0 22px 44px -24px rgba(22,36,63,.22));
  }
  .pt__nav a, .pt__nav button {
    flex: 0 0 auto;                /* cada opción ocupa lo que necesita */
    flex-direction: row; gap: 9px;
    min-height: 44px; padding: 10px 18px;
    font-size: 14.5px; border-radius: 999px;
  }
  .pt__nav i { font-size: 19px; }
  .pt__nav a:hover { background: var(--cream-2); color: var(--ink); }
  .pt__nav .activo { background: var(--c-academia-bg, #e7efff); color: var(--azul-deep); }
  /* En escritorio la barra ya flota por sí sola: el disco levantado no pinta
     nada ahí y encima se salía por arriba. El botón pasa a ser una píldora
     más de la barra, solo que en color. El disco se deshace del todo —margen,
     borde y sombra incluidos—, no basta con quitarle el fondo. */
  .pt__nav .pt__cta {
    flex-direction: row; gap: 9px; padding: 10px 20px; margin-top: 0;
    background: var(--azul); color: var(--white);
  }
  .pt__nav .pt__cta:hover { background: var(--azul-deep); color: var(--white); }
  .pt__nav .pt__cta__disco {
    width: auto; height: auto; margin: 0; padding: 0;
    border: none; border-radius: 0; background: none; box-shadow: none;
    color: inherit;
  }
  .pt__nav .pt__cta__disco i { font-size: 19px; }
}

/* ==========================================================================
   2. Cabeceras y textos
   ========================================================================== */
.saludo { margin: 4px 0 18px; }
.saludo h1 { font-family: var(--font-display); font-size: 24px; margin: 0 0 4px; line-height: 1.15; }
.saludo p { margin: 0; color: var(--muted); }
.subtitulo { font-family: var(--font-display); font-size: 13px; text-transform: uppercase; letter-spacing: .05em; color: var(--muted); margin: 24px 2px 10px; }
.meta { color: var(--muted); font-size: 14px; margin: 2px 0 0; }
/* La línea del buzón de incidencias (ver templates/_soporte.html). Va al pie
   y separada: tiene que estar cuando se la busca, sin competir con el botón. */
.soporte { margin-top: 18px; text-align: center; }
.soporte a { text-decoration: underline; }
/* Las tarjetas que se aceptan (`_tarjetas.html`): lo exige Getnet donde se
   paga y en las páginas legales. */
.tarjetas-aceptadas { display: inline-flex; align-items: center; gap: 6px; vertical-align: middle; }
.tarjetas-aceptadas__texto { font-size: 13px; color: var(--muted); margin-right: 2px; }
.tarjetas-aceptadas__logo { display: block; width: 40px; height: 25px; }
.tarjetas-pie { display: flex; justify-content: center; margin-top: 12px; }

/* ==========================================================================
   3. Tarjetas y listas
   ========================================================================== */
.tarjeta {
  background: var(--white); border: 1px solid var(--line);
  border-radius: var(--r, 18px); padding: 18px;
  box-shadow: var(--sh-soft, 0 14px 30px -16px rgba(22,36,63,.18));
  margin-bottom: 14px;
}
.tarjeta--plana { box-shadow: none; }

.fila {
  display: flex; align-items: center; gap: 14px;
  background: var(--white); border: 1px solid var(--line);
  border-radius: var(--r); padding: 16px; margin-bottom: 12px;
  min-height: 72px; text-decoration: none; color: inherit;
}
.fila:active { transform: scale(.995); }
.fila__ic {
  flex: 0 0 auto; width: 46px; height: 46px; border-radius: 14px;
  display: grid; place-items: center; font-size: 22px;
  background: var(--c-academia-bg, #e7efff); color: var(--azul-deep);
}
.fila__tx { min-width: 0; flex: 1; }
.fila__tx strong { display: block; font-size: 16px; }
.fila__tx span { color: var(--muted); font-size: 14px; }
.fila__chev { color: var(--muted); font-size: 20px; flex: 0 0 auto; }

/* ==========================================================================
   4. Botones
   ========================================================================== */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  min-height: 50px; padding: 12px 20px;
  font-family: inherit; font-weight: 700; font-size: 16px;
  border: none; border-radius: var(--r-btn, 12px); cursor: pointer; text-decoration: none;
  transition: background .15s, transform .1s;
}
.btn:active { transform: scale(.99); }
.btn--principal { background: var(--coral, #2fa84f); color: #fff; }
.btn--principal:hover { background: var(--coral-deep); }
.btn--secundario { background: var(--white); color: var(--body); border: 1.5px solid var(--line); }
.btn--secundario:hover { border-color: var(--azul); color: var(--azul); }
.btn--peligro { background: #fff; color: var(--rojo); border: 1.5px solid #f0c8c2; }
.btn--bloque { width: 100%; }
.btn--sm { min-height: 40px; padding: 8px 14px; font-size: 14px; border-radius: var(--r-btn-sm, 10px); }
.btn[disabled], .btn--off { opacity: .55; pointer-events: none; }

.acciones { display: flex; gap: 10px; flex-wrap: wrap; margin-top: 18px; }

/* ==========================================================================
   5. Formularios (targets grandes, 16px para no disparar el zoom en iOS)
   ========================================================================== */
.form { background: var(--white); border: 1px solid var(--line); border-radius: var(--r); padding: 18px 16px; box-shadow: var(--sh-soft); }
.campo { margin-bottom: 16px; }
.campo > label { display: block; font-weight: 700; font-size: 14px; margin-bottom: 6px; }
/* Ojo: se excluyen casillas y radios, porque `appearance: none` les quita el
   tick nativo y parecen no funcionar. */
.campo input:not([type="checkbox"]):not([type="radio"]),
.campo select, .campo textarea {
  width: 100%; min-height: 50px; padding: 12px 14px;
  border: 1.5px solid var(--line); border-radius: 12px;
  font-family: inherit; font-size: 16px; color: var(--ink);
  background: var(--white); appearance: none; -webkit-appearance: none;
}
/* La flecha del desplegable. Va en una regla suya y no dentro de `.campo`
   porque los filtros usan exactamente la misma: son el mismo control, y con
   dos flechas distintas —la nuestra en el formulario y la del sistema en los
   filtros— la pantalla parece hecha por dos personas.

   Solo se puede vestir el botón cerrado. La lista que se despliega al pulsar
   la dibuja el sistema operativo, no la página, y no hay CSS que la alcance:
   en el móvil es la ruleta nativa (que es justo lo que se quiere) y en el
   escritorio, la lista del navegador. */
.campo select,
.filtros select {
  appearance: none; -webkit-appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 24 24' fill='none' stroke='%238090a4' stroke-width='2'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 12px center; padding-right: 42px;
  cursor: pointer;
}
/* El del filtro es más bajo que el del formulario, así que la flecha se
   arrima un poco más al borde para que no baile respecto al texto. */
.filtros select { background-position: right 10px center; padding-right: 36px; }
.campo select:hover, .filtros select:hover { border-color: var(--azul); }
.campo textarea { min-height: 92px; resize: vertical; }
.campo input:focus, .campo select:focus, .campo textarea:focus {
  outline: none; border-color: var(--azul); box-shadow: 0 0 0 3px rgba(46,107,240,.15);
}
.campo .ayuda { display: block; color: var(--muted); font-size: 13px; margin-top: 5px; }
.campo .errores { color: var(--rojo); font-size: 13.5px; margin: 6px 0 0; padding: 0; list-style: none; }
/* Casilla: apariencia nativa (se ve el tick), grande y con el color de marca.
   Toda la fila es clicable, no solo el cuadradito. */
.campo--check { display: flex; align-items: flex-start; gap: 12px; padding: 10px 0; cursor: pointer; }
.campo--check input[type="checkbox"] {
  width: 24px; height: 24px; min-height: 0; flex: 0 0 auto; margin: 1px 0 0;
  appearance: auto; -webkit-appearance: checkbox;
  accent-color: var(--azul);
  cursor: pointer;
}
.campo--check label { font-weight: 600; margin: 0; cursor: pointer; line-height: 1.35; }
.grupo-campos { margin: 22px 0 12px; font-family: var(--font-display); font-size: 16px; font-weight: 700; }
@media (min-width: 620px) {
  .form-fila { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
}

/* ==========================================================================
   5 bis. Wizard de inscripción (para quién → qué actividad → confirmar)
   ========================================================================== */
.pasos { display: flex; align-items: center; gap: 8px; margin-bottom: 18px; }
.paso {
  display: flex; align-items: center; gap: 7px;
  font-size: 13px; font-weight: 600; color: var(--muted); white-space: nowrap;
}
.paso__n {
  width: 24px; height: 24px; border-radius: 50%; flex: 0 0 auto;
  display: grid; place-items: center; font-size: 12px; font-weight: 700;
  /* Tinta oscura sobre el gris: con el azul claro de --white el número era
     casi invisible (1.4:1). El activo va en blanco puro, no en --white,
     que en esta paleta tira a azul. */
  background: var(--line); color: var(--ink);
}
.paso--activo { color: var(--azul-deep); }
.paso--activo .paso__n { background: var(--azul); color: #fff; }
.paso--hecho .paso__n { background: var(--verde); color: #fff; }
.paso__linea { flex: 1; height: 2px; background: var(--line); border-radius: 2px; min-width: 10px; }
@media (max-width: 460px) {
  /* En móvil no caben los cuatro rótulos, pero dejar solo números obliga a
     adivinar qué es el 2. Se enseña el del paso actual, que es el que dice
     dónde estás; los demás siguen siendo su número. */
  .paso span.texto { display: none; }
  .paso--activo span.texto { display: inline; }
  .paso__linea { min-width: 10px; }
}

/* Tarjeta seleccionable (elegir hijo o actividad) */
.opcion {
  display: flex; align-items: center; gap: 14px; width: 100%;
  background: var(--white); border: 1.5px solid var(--line);
  border-radius: var(--r); padding: 16px; margin-bottom: 12px;
  min-height: 76px; text-decoration: none; color: inherit; text-align: left;
  font-family: inherit; font-size: 16px; cursor: pointer;
}
.opcion:hover { border-color: var(--azul); }
.opcion:active { transform: scale(.995); }
.opcion__av {
  flex: 0 0 auto; width: 46px; height: 46px; border-radius: 50%;
  display: grid; place-items: center; font-weight: 800; font-size: 17px;
  background: var(--c-academia-bg, #e7efff); color: var(--azul-deep);
}
/* Cuerpo de la opción: título, meta, datos sueltos y etiquetas. */
.opcion__cuerpo { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.opcion__cuerpo strong { font-size: 17px; line-height: 1.25; }
.opcion__datos { display: flex; flex-wrap: wrap; gap: 6px 16px; margin-top: 8px; }
.opcion__datos .dato {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 14px; color: var(--body); font-weight: 600;
}
.opcion__datos .dato i { color: var(--muted); }
.opcion__flecha { flex: 0 0 auto; color: var(--muted); font-size: 18px; }
/* Una opción que no se puede pulsar (ya está apuntado a ese horario). */
.opcion--inerte { opacity: .72; cursor: default; }
.opcion--inerte:hover { border-color: var(--line); }

/* Elección única entre dos o tres cosas cortas (¿en qué mes empieza?).
   Debajo hay radios de verdad: marcar una desmarca la otra sola, y el
   teclado y el lector de pantalla funcionan sin una línea de JavaScript. */
.opciones-radio {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
  gap: 10px;
}
.opcion-radio {
  position: relative; display: block; text-align: center; cursor: pointer;
  background: var(--white); border: 1.5px solid var(--line);
  border-radius: var(--r); padding: 12px 10px;
}
.opcion-radio input { position: absolute; inset: 0; opacity: 0; cursor: pointer; }
.opcion-radio strong { display: block; font-size: 16px; }
.opcion-radio .meta { margin: 2px 0 0; }
.opcion-radio:hover { border-color: var(--azul); }
.opcion-radio:has(input:checked) {
  border-color: var(--azul);
  box-shadow: inset 0 0 0 1px var(--azul);
  background: var(--c-academia-bg, #e7efff);
}
.opcion-radio:has(input:focus-visible) { outline: 2px solid var(--azul); outline-offset: 2px; }

/* Tres opciones en UNA fila también en el móvil (¿mes, semana o día?). El
   grid de arriba pide un mínimo de 130 px por opción, y en 390 px eso son dos
   columnas y la tercera debajo: justo lo que hace que la elegida no se vea
   como una de tres. Se aprieta un poco el texto para que quepan. */
.opciones-radio--tres { grid-template-columns: repeat(3, 1fr); gap: 8px; }
.opciones-radio--tres .opcion-radio { padding: 12px 6px; }
.opciones-radio--tres .opcion-radio strong { font-size: 15px; line-height: 1.2; }
.opciones-radio--tres .opcion-radio .meta { font-size: 12.5px; }

/* La misma pieza cuando las opciones son ENLACES a otra pantalla y no radios
   de un formulario. En «¿cuánto tiempo necesitáis?» dos de las tres se van al
   calendario, y la tercera —el mes completo— es la pantalla en la que ya
   estás. `--activa` pinta ese estado marcado sin necesitar un input debajo:
   antes se explicaba con un «sigue abajo, es esta pantalla» que había que leer
   para entenderlo, y esto se ve sin leer nada. */
a.opcion-radio { color: inherit; text-decoration: none; }
.opcion-radio--activa {
  border-color: var(--azul);
  box-shadow: inset 0 0 0 1px var(--azul);
  background: var(--c-academia-bg, #e7efff);
  cursor: default;
}
.opcion-radio--activa:hover { border-color: var(--azul); }

/* Filas del resumen de confirmación. */
.resumen__fila {
  display: flex; justify-content: space-between; gap: 14px;
  padding: 12px 0; border-bottom: 1px solid var(--line);
}
.resumen__fila:first-child { padding-top: 0; }
.resumen__fila--ultima { border-bottom: 0; padding-bottom: 0; }

/* ==========================================================================
   6. Avisos y estados
   ========================================================================== */
.avisos { display: flex; flex-direction: column; gap: 10px; margin-bottom: 16px; }
.aviso { padding: 13px 16px; border-radius: 12px; font-weight: 600; font-size: 14.5px; }
.aviso--ok { background: var(--c-deportes-bg, #e8f5de); color: #2b6416; }
.aviso--error { background: var(--rojo-suave); color: var(--rojo); }
.aviso--info { background: var(--c-academia-bg, #e7efff); color: var(--azul-deep); }
/* Para lo que hay que leer antes de confirmar algo irreversible (una baja). */
.aviso--warn { background: var(--ambar-suave); color: var(--ambar-ink); font-weight: 500; }
.aviso--warn strong { font-weight: 700; }
.aviso--warn li { margin-bottom: 5px; line-height: 1.45; }

.etiqueta { display: inline-flex; align-items: center; gap: 5px; padding: 4px 11px; border-radius: 999px; font-size: 12.5px; font-weight: 700; }
.et--confirmada { background: var(--c-deportes-bg); color: #2b6416; }
.et--reservada { background: var(--c-musica-bg, #f0f6dd); color: var(--ambar-ink); }
/* La solicitud aún no es plaza: ámbar, el color que el portal ya usa para
   «esto está pendiente de algo». Los mismos tokens que .aviso--warn. */
.et--preinscrita { background: var(--ambar-suave); color: var(--ambar-ink); }
/* Con plaza pero sin cobro: verde como la confirmada (la plaza es de verdad),
   sin el peso de la confirmada del todo. */
.et--admitida { background: var(--c-deportes-bg, #e8f5de); color: #2b6416; }
/* El mismo estado con los dos nombres que se usan por el código: el largo
   viene del valor del enum, el corto de escribirlo a mano en Grupos. Estaba
   solo el largo, así que la etiqueta de Grupos salía sin fondo ni color. */
.et--lista_espera,
.et--espera { background: var(--c-academia-bg); color: var(--azul-deep); }
.et--caducada, .et--baja { background: #f1eee9; color: var(--muted); }
/* Solicitud cancelada (no salió el grupo): gris como las bajas. Es un
   estado cerrado y no es culpa de la familia; el rojo hacía parecer que se
   le había dicho que no a este niño (21/09/2026). */
.et--rechazada { background: #f1eee9; color: var(--muted); }
.et--medico { background: var(--rojo-suave); color: var(--rojo); }
/* Un dato que no cuadra y que hay que mirar, no un estado del negocio:
   por eso es ámbar y no rojo. Se usa en Impagados para una cuota que no
   cuelga de ninguna inscripción, que no es una deuda que reclamar. */
.et--revisar { background: var(--ambar-suave); color: var(--ambar-ink); }
/* Modalidad de una solicitud (Preinscripciones): por mes es lo normal y va
   discreta; semana y días sueltos se cobran distinto al confirmar y por eso
   llaman la atención. */
.et--mes { background: #f1eee9; color: var(--muted); }
/* Plaza sin pagar en las listas de asistencia: se pasa lista igual, pero se
   ve, para que el monitor sepa a quién recordarle el pago. */
.et--sin-pagar { background: var(--rojo-suave); color: var(--rojo); }
/* Con las dos clases: la regla base de `.asistencia` va más abajo en este
   fichero y, a igual especificidad, se quedaba con el fondo azul. */
.asistencia.asistencia--sin-pagar { background: var(--rojo-suave); border-left: 4px solid var(--rojo); }
.et--semana { background: var(--c-academia-bg); color: var(--azul-deep); }
.et--dias, .et--mixto { background: var(--ambar-suave); color: var(--ambar-ink); }
/* «Se va solo»: la familia ha autorizado por escrito que no lo recoja nadie.
   Ámbar y con borde, como el aviso de su ficha: en la puerta es lo que hay
   que ver de un vistazo en la lista, sin entrar niño por niño (01/10/2026). */
.et--solo { background: var(--ambar-suave); color: var(--ambar-ink);
            border: 1.5px solid var(--ambar-borde); }
.solos { margin: 0 0 18px; }
.solos__nombres { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
/* Baja: discreta a propósito, pero con altura suficiente para el dedo. */
.enlace-baja {
  display: inline-flex; align-items: center; min-height: 44px;
  margin-top: 6px; font-size: 14px; font-weight: 600; color: var(--muted);
  text-decoration: underline; text-underline-offset: 3px;
}
.enlace-baja:hover, .enlace-baja:focus-visible { color: var(--rojo); }
/* Disponibilidad: a la familia se le dice si corre prisa, no cuántas quedan.
   El número exacto no le sirve y convierte la inscripción en una carrera. */
.et--plazas { background: var(--c-deportes-bg, #e8f5de); color: #2b6416; }
.et--pocas { background: var(--ambar-suave); color: var(--ambar-ink); }
.et--ultimas { background: #ffeee9; color: #a8401d; }
.et--completo { background: var(--rojo-suave); color: var(--rojo); }
/* El estado de una asistencia, en el detalle de una sesión: los mismos tres
   colores que ya usaba la rejilla de asistencia (.asi--p/a/j) para lo mismo,
   aquí en formato etiqueta porque la fila es de una tabla normal, no una
   casilla de rejilla. */
.et--presente { background: var(--c-deportes-bg, #e8f5de); color: #2b6416; }
.et--ausente { background: var(--rojo-suave); color: var(--rojo); }
.et--justificado { background: #fff7df; color: #7a5200; }

/* ==========================================================================
   7. Login y registro
   ========================================================================== */
.acceso {
  min-height: 100vh; min-height: 100dvh; display: grid; place-items: center;
  padding: 24px 16px calc(env(safe-area-inset-bottom) + 24px);
  background: linear-gradient(150deg, var(--azul-ink) 0%, var(--azul-deep) 100%);
}
.acceso__caja {
  background: var(--white); border-radius: 24px; padding: 30px 22px;
  width: 100%; max-width: 420px; box-shadow: 0 30px 60px -30px rgba(0,0,0,.5);
}
.acceso__caja img { height: 34px; margin-bottom: 14px; }
.acceso__caja h1 { font-family: var(--font-display); font-size: 22px; margin: 0 0 4px; }
.acceso__caja .sub { color: var(--muted); margin: 0 0 22px; font-size: 14.5px; }
/* Enlaces de acción bajo un formulario ("crear cuenta", "he olvidado la
   contraseña"). Van con altura táctil de 44px: son enlaces que se pulsan con
   prisa y con el móvil en una mano. */
.enlace-centro {
  display: flex; align-items: center; justify-content: center;
  min-height: 44px; padding: 4px 8px; margin-top: 10px;
  text-align: center; color: var(--azul-deep); font-weight: 600;
  text-decoration: none; line-height: 1.35;
}
.enlace-centro:hover, .enlace-centro:focus-visible { text-decoration: underline; }

/* ==========================================================================
   8. Panel de gestión (escritorio, pero usable en móvil)
   ========================================================================== */
.gs { display: grid; grid-template-columns: 240px 1fr; min-height: 100vh; }
.gs__side {
  background: var(--azul-ink); color: #dbe6ff; padding: 20px 14px;
  display: flex; flex-direction: column; gap: 18px;
  position: sticky; top: 0; height: 100vh; overflow-y: auto;
}
.gs__side img { height: 28px; }
.gs__nav { display: flex; flex-direction: column; gap: 3px; }
.gs__nav a {
  display: flex; align-items: center; gap: 11px; padding: 11px 12px;
  border-radius: 12px; color: #c9d8f5; font-weight: 600; font-size: 14.5px; text-decoration: none;
}
.gs__nav a:hover { background: rgba(255,255,255,.09); }
.gs__nav a.activo { background: var(--azul); color: #fff; }
.gs__nav .grupo { font-size: 11px; text-transform: uppercase; letter-spacing: .08em; color: #7e95c9; margin: 14px 12px 4px; }
.gs__pie { margin-top: auto; font-size: 13px; color: #9fb6e8; display: flex; flex-direction: column; gap: 8px; }
.gs__main { min-width: 0; display: flex; flex-direction: column; }
.gs__top {
  position: sticky; top: 0; z-index: 5;
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  padding: 15px 24px; background: var(--white); border-bottom: 1px solid var(--line);
}
.gs__top h1 { font-family: var(--font-display); font-size: 20px; margin: 0; }
.gs__top .ruta { font-size: 13px; color: var(--muted); }
/* `flex: 1` para que el contenido empuje el pie hasta abajo. Sin esto, en
   una pantalla corta la versión se quedaba flotando a media altura, justo
   debajo del último bloque, en vez de anclada al borde inferior. */
.gs__cont { padding: 24px; max-width: 1200px; width: 100%; flex: 1 1 auto; }

/* En pantallas pequeñas el menú lateral se convertía en un bloque de 12
   enlaces —medio móvil de navegación antes de ver nada— en cada página. Se
   pliega en un desplegable: sigue estando entero, pero cerrado por defecto. */
@media (max-width: 900px) {
  .gs { grid-template-columns: 1fr; }
  .gs__side {
    position: sticky; top: 0; z-index: 30; height: auto;
    max-height: 100vh; overflow-y: auto;
  }
  .gs__nav { flex-direction: row; flex-wrap: wrap; gap: 6px; }
  .gs__nav .grupo { flex-basis: 100%; margin: 6px 4px 0; }
  .gs__top, .gs__cont { padding: 14px 16px; }

  /* El menú vive dentro de un <details>: cerrado ocupa solo su cabecera. */
  .gs__menu > summary {
    display: flex; align-items: center; gap: 10px;
    min-height: 52px; padding: 10px 4px; cursor: pointer; list-style: none;
    color: #fff; font-weight: 700; font-size: 15px;
  }
  .gs__menu > summary::-webkit-details-marker { display: none; }
  .gs__menu > summary::after {
    content: "\25BE"; margin-left: auto; font-size: 13px; transition: transform .15s;
  }
  .gs__menu[open] > summary::after { transform: rotate(180deg); }
}
/* En escritorio el menú va siempre abierto y sin resumen que pulsar.
   Ojo: NO se puede lograr forzando `display` sobre un <details> cerrado.
   Chromium le aplica `content-visibility:hidden` a ::details-content, así que
   el menú se PINTA pero no recibe clics ni foco: se ve perfecto y no hace
   nada. El estado `open` lo pone un script mínimo según el ancho. */
@media (min-width: 901px) {
  .gs__menu > summary { display: none; }
}

/* Tablas: en móvil scrollean en horizontal en vez de recortarse */
.tabla-caja { background: var(--white); border: 1px solid var(--line); border-radius: var(--r); overflow-x: auto; -webkit-overflow-scrolling: touch; box-shadow: var(--sh-soft); }
table.datos { width: 100%; border-collapse: collapse; font-size: 14.5px; }
table.datos th, table.datos td { text-align: left; padding: 13px 16px; border-bottom: 1px solid var(--line); white-space: nowrap; }
table.datos th { background: var(--cream, #f7faff); font-size: 12.5px; text-transform: uppercase; letter-spacing: .04em; color: var(--body); }
table.datos tr:last-child td { border-bottom: none; }
table.datos .envuelve { white-space: normal; min-width: 180px; }
.tabla-vacia { padding: 40px 20px; text-align: center; color: var(--muted); }

/* Autorizados a recoger: en el móvil la fila NO cabe. Dos campos con sus
   márgenes y el aspa de quitar suman más de 375 px, así que la tabla se
   salía por la derecha y el aspa quedaba fuera de la pantalla — justo en la
   pantalla que existe para consultarse con prisa en la puerta del colegio.
   Debajo de 560 px cada persona se apila como un bloque, con el aspa arriba
   a la derecha. Es la MISMA tabla y el mismo formulario (los nombres de los
   campos no se tocan, que es lo que WTForms lee): solo cambia cómo se ve. */
@media (max-width: 560px) {
  .tabla-autorizados thead { display: none; }
  .tabla-autorizados,
  .tabla-autorizados tbody,
  .tabla-autorizados tr,
  .tabla-autorizados td { display: block; width: auto; }
  .tabla-autorizados tr.autorizado {
    position: relative;
    padding: 12px 46px 12px 12px;
    border-bottom: 1px solid var(--line);
  }
  .tabla-autorizados tr:last-child { border-bottom: none; }
  .tabla-autorizados tr.autorizado td {
    padding: 0; border: none; white-space: normal;
  }
  .tabla-autorizados tr.autorizado td + td { margin-top: 8px; }
  /* El aspa, fuera del flujo y pegada arriba a la derecha: en línea empujaba
     los campos y volvía a no caber. */
  .tabla-autorizados tr.autorizado td:last-child {
    position: absolute; top: 10px; right: 6px; margin: 0;
  }
}

/* Indicadores */
.kpis { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 14px; margin-bottom: 24px; }
.kpi { background: var(--white); border: 1px solid var(--line); border-radius: var(--r); padding: 16px 18px; box-shadow: var(--sh-soft); }
.kpi b { display: block; font-family: var(--font-display); font-size: 30px; color: var(--azul-deep); line-height: 1; }
.kpi span { display: block; color: var(--muted); font-weight: 600; font-size: 13px; margin-top: 7px; }

/* Barra de ocupación de un grupo */
.ocupacion { display: flex; align-items: center; gap: 10px; }
.ocupacion__barra { flex: 1; min-width: 70px; height: 8px; border-radius: 999px; background: var(--line); overflow: hidden; }
.ocupacion__relleno { height: 100%; background: var(--verde); border-radius: 999px; }
.ocupacion__relleno.lleno { background: var(--rojo); }


/* ==========================================================================
   9. Componentes añadidos después de la base

   Van al final a propósito: son modificadores (.tarjeta--atencion,
   .btn--grande, .tarjeta--activa) y si se colocan antes de .tarjeta o .btn
   la regla base los pisa por orden de cascada, con la misma especificidad.
   Lo aprendimos por las malas: la tarjeta de alergias del monitor se veía
   igual que una tarjeta normal.
   ========================================================================== */
/* Barra de filtros por fechas (jornadas). */
.filtros { display: flex; flex-wrap: wrap; gap: 12px; align-items: flex-end; margin-bottom: 18px; }
.filtros label { display: flex; flex-direction: column; gap: 4px; font-size: 13px; font-weight: 600; color: var(--body); }
/* Los campos de filtro miden todos lo mismo para que la fila quede a una
   altura. Las casillas y los redondeles quedan fuera: una casilla de 42px de
   alto y 13 de ancho es una raya, y estiraba a 68px cada fila del
   desplegable de colegios. */
.filtros input:not([type="checkbox"]):not([type="radio"]) {
  height: 42px; padding: 0 10px; font-size: 15px;
  border: 1px solid var(--line); border-radius: 10px; background: var(--white);
}

/* ==========================================================================
   Portal de monitores. Se usa de pie, en un patio, con una mano: todo grande.
   ========================================================================== */
.btn--grande { min-height: 58px; font-size: 17px; }
.tarjeta--activa { border-color: var(--verde); background: var(--c-deportes-bg, #e8f5de); }
/* Punto que avisa de jornada abierta en la barra inferior. */
.punto {
  display: inline-block; width: 8px; height: 8px; border-radius: 50%;
  background: var(--verde); margin-left: 4px; vertical-align: super;
}

/* Pasar lista: una fila por alumno con tres botones de estado. */
.asistencia {
  background: var(--white); border: 1px solid var(--line);
  border-radius: var(--r); padding: 14px; margin-bottom: 10px;
}
.asistencia__quien { display: flex; align-items: center; gap: 12px; margin-bottom: 12px; }
.asistencia__estados { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }
.estado { position: relative; display: block; }
.estado input { position: absolute; opacity: 0; width: 100%; height: 100%; margin: 0; cursor: pointer; }
.estado span {
  display: flex; align-items: center; justify-content: center; gap: 5px;
  min-height: 46px; padding: 6px 4px; border-radius: 12px;
  border: 1.5px solid var(--line); background: var(--white);
  font-weight: 700; font-size: 14px; color: var(--muted); text-align: center;
}
.estado input:checked + span { border-width: 2px; }
.estado--presente input:checked + span { background: var(--c-deportes-bg); border-color: var(--verde); color: var(--verde-deep); }
.estado--ausente input:checked + span { background: var(--rojo-suave); border-color: var(--rojo); color: var(--rojo); }
.estado--justificado input:checked + span { background: var(--ambar-suave); border-color: var(--ambar-borde); color: var(--ambar-ink); }
.estado input:focus-visible + span { outline: 3px solid var(--azul); outline-offset: 2px; }

/* Ficha del alumno que ve el monitor. */
.ficha-cabecera { display: flex; align-items: center; gap: 16px; margin-bottom: 18px; }
.ficha-foto {
  width: 82px; height: 82px; border-radius: 22px; object-fit: cover;
  flex-shrink: 0; border: 2px solid var(--line);
}
.ficha-foto--vacia {
  display: grid; place-items: center; background: var(--c-academia-bg, #e7efff);
  color: var(--azul-deep); font-weight: 800; font-size: 26px;
}
/* El nombre junto a la foto. La ficha de extraescolares lo lleva escrito a
   mano (`style=`); la del viaje (11/10/2026) usa esto. */
.ficha-cabecera__nombre {
  margin: 0; font-family: var(--font-display); font-size: 23px; line-height: 1.15;
}

/* Lista de pagos: una línea por cobro, separadas sin ruido visual. */
.pago {
  display: flex; justify-content: space-between; gap: 12px;
  padding: 12px 0; border-bottom: 1px solid var(--line);
}
.pago:last-child { border-bottom: 0; padding-bottom: 0; }
.tarjeta--atencion { border-color: #f0c8c2; background: #fff8f7; }

/* Bloque plegado: el resto del curso, los pagos antiguos. Nadie necesita ver
   nueve cuotas futuras de golpe, pero tienen que estar si se buscan. */
.plegable {
  background: var(--white); border: 1px solid var(--line);
  border-radius: var(--r); margin-bottom: 14px;
}
.plegable > summary {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  min-height: 52px; padding: 12px 16px; cursor: pointer;
  font-weight: 700; color: var(--azul-deep); list-style: none;
}
.plegable > summary::-webkit-details-marker { display: none; }
.plegable > summary::after {
  content: "\25BE"; font-size: 13px; color: var(--muted); transition: transform .15s;
}
.plegable[open] > summary::after { transform: rotate(180deg); }
.plegable > summary .meta { font-weight: 500; }
.plegable__cuerpo { padding: 0 16px 14px; }
/* Aclaración al principio de un bloque plegado, antes de su contenido. */
.plegable__nota { margin: 0 0 12px; }

/* Un cobro de «Mis pagos». Un cobro es una FECHA, no un apunte: el día 1 se
   pasa un cargo por cada cuota que venza ese día, así que arriba van el día y
   el TOTAL de todo lo que se cobra, y debajo las líneas que lo componen.
   Pintarlo como un apunte suelto le decía a una familia con tres actividades
   que le iban a cobrar 30 € el día que le iban a cobrar 90. */
.cobro__cab {
  display: flex; justify-content: space-between; align-items: baseline;
  gap: 12px; margin-top: 6px;
}
.cobro__dia { font-size: 17px; }
.cobro__total {
  font-size: 22px; font-family: var(--font-display); white-space: nowrap;
}
.cobro__lineas { margin-top: 8px; }
/* La línea que tranquiliza: «se cobra solo, no tienes que hacer nada». */
.cobro__nota { margin: 12px 0 0; }
/* Cada día dentro del bloque plegado de lo que viene. */
.cobro-dia + .cobro-dia { margin-top: 14px; }
/* Las dos mitades de una línea de pago: el concepto se encoge (sin min-width
   una palabra larga empuja el importe fuera de la tarjeta) y el importe no
   parte nunca en dos renglones. */
.pago__concepto { min-width: 0; }
.pago__importe { white-space: nowrap; }
/* Título que parte una pantalla en bloques. Es el canónico en las tres zonas.
   En gestión estaba escrito a mano en doce sitios (`style="font-family:
   var(--font-display);font-size:18px"`) teniendo la clase aquí sin usar: si
   hace falta un título de sección, se usa esto. */
.seccion-titulo { font-family: var(--font-display); font-size: 18px; margin: 26px 0 10px; color: var(--ink); }
/* El primero de una pantalla no necesita separarse de lo de arriba. */
.seccion-titulo:first-child { margin-top: 0; }

/* Medida de lectura. Un párrafo de explicación a lo ancho de 1200 px no se
   lee: el ojo pierde el renglón al volver. Estaba resuelto con
   `style="max-width:720px"` en once sitios. */
.medida { max-width: 720px; }

/* ==========================================================================
   Páginas legales (privacidad, aviso legal). Texto largo: se prioriza que se
   lea bien, con medida de línea corta y aire entre apartados.
   ========================================================================== */
.legal { max-width: 780px; margin: 0 auto; padding: 26px 18px 60px; }
.legal__marca { display: inline-block; margin-bottom: 22px; }
.legal__marca img { height: 34px; width: auto; }
.legal__texto { background: var(--white); border: 1px solid var(--line); border-radius: var(--r); padding: 26px 24px; }
.legal__texto h1 { font-family: var(--font-display); font-size: 27px; margin: 0 0 4px; color: var(--ink); }
.legal__texto h2 { font-family: var(--font-display); font-size: 19px; margin: 30px 0 8px; color: var(--azul-deep); }
.legal__texto p, .legal__texto li { line-height: 1.65; color: var(--body); }
.legal__texto ul { padding-left: 20px; }
.legal__texto li { margin-bottom: 7px; }
.legal__texto mark { background: #fff2c4; color: #6b4e00; padding: 1px 5px; border-radius: 5px; font-weight: 600; }
.legal__pie { text-align: center; margin-top: 22px; font-size: 14px; color: var(--muted); }
table.datos-legal { width: 100%; border-collapse: collapse; margin: 12px 0 6px; }
table.datos-legal th, table.datos-legal td { text-align: left; vertical-align: top; padding: 9px 12px; border-bottom: 1px solid var(--line); font-size: 15px; line-height: 1.5; }
table.datos-legal th { width: 40%; color: var(--ink); font-weight: 700; }
@media (max-width: 560px) {
  table.datos-legal th, table.datos-legal td { display: block; width: auto; border-bottom: 0; padding: 4px 0; }
  table.datos-legal td { padding-bottom: 12px; border-bottom: 1px solid var(--line); }
}

/* Foto del alumno: la miniatura junto al selector de archivo. */
.foto-campo { display: flex; gap: 14px; align-items: flex-start; margin-bottom: 18px; }
.foto-actual {
  width: 76px; height: 76px; border-radius: 18px; object-fit: cover;
  flex-shrink: 0; border: 2px solid var(--line); background: var(--white);
}
.foto-actual--vacia {
  display: inline-flex; align-items: center; justify-content: center;
  color: var(--muted); font-size: 30px; border-style: dashed;
}
.foto-input { width: 100%; font-size: 15px; }
.foto-input::file-selector-button {
  margin-right: 10px; padding: 10px 14px; min-height: 40px;
  border: 1.5px solid var(--line); border-radius: 10px;
  background: var(--white); color: var(--azul-deep);
  font-weight: 700; font-size: 14px; cursor: pointer;
}
/* Miniatura en las listas (mis hijos, listado del monitor). */
.avatar {
  width: 46px; height: 46px; border-radius: 14px; object-fit: cover;
  flex-shrink: 0; border: 1px solid var(--line);
}

/* Volver: es el enlace más pulsado del portal en móvil, así que 44px de alto
   y algo de margen a la izquierda para no tener que afinar con el pulgar. */
.volver {
  display: inline-flex; align-items: center; gap: 6px;
  min-height: 44px; padding: 0 10px 0 0; margin-bottom: 6px;
  color: var(--muted); font-weight: 600; font-size: 14px; text-decoration: none;
}
.volver:hover, .volver:focus-visible { color: var(--azul-deep); }

/* ==========================================================================
   10. Accesibilidad: correcciones de la auditoría
   ========================================================================== */

/* Casillas: el cuadro nativo mide 24px, por debajo del objetivo táctil. Se
   agranda y se da área a toda la fila, que es lo que la gente toca. */
.campo--check, label.campo--check { min-height: 48px; padding: 6px 0; }
.campo--check input[type="checkbox"],
.campo input[type="checkbox"], .campo input[type="radio"] {
  width: 26px; height: 26px; margin-right: 4px;
}

/* Enlaces sueltos dentro de texto o de tabla: se les da altura de dedo sin
   romper el flujo del párrafo. */
table.datos a, .legal__pie a, .ruta a {
  display: inline-flex; align-items: center; min-height: 44px;
}
.legal__texto a { padding: 2px 0; }

/* Botones pequeños del panel: 40px se queda corto para el pulgar. */
.btn--sm { min-height: 44px; }

/* Campos de formulario embebidos en tablas y filtros: 16px para que iOS no
   haga zoom al enfocarlos. Las casillas y los redondeles quedan fuera: el
   `min-height` gana siempre a la altura que se les ponga, y una casilla de
   44px de alto estiraba cada fila del desplegable de colegios. Su objetivo
   táctil lo da la fila entera, que sí mide 44. */
.filtros input:not([type="checkbox"]):not([type="radio"]),
.tabla-caja input[type="email"], .tabla-caja input[type="text"],
.tabla-caja input[type="time"], .tabla-caja input[type="date"],
.tabla-caja input[type="number"] {
  font-size: 16px; min-height: 44px;
}

/* Campo editable DENTRO de una celda: ocupa la celda entera y se apoya en el
   borde de la fila, sin la caja propia de `.campo`.
   Es lo que permite editar una lista sin convertir cada elemento en una
   tarjeta: con `.campo`, tres filas llenaban la pantalla. */
.campo-linea {
  width: 100%; box-sizing: border-box;
  padding: 8px 10px; font-family: inherit; font-size: 16px;
  color: var(--ink); background: var(--white);
  border: 1px solid var(--line); border-radius: 8px;
}
.campo-linea:focus {
  outline: none; border-color: var(--azul);
  box-shadow: 0 0 0 3px var(--c-academia-bg);
}
.campo-linea::placeholder { color: var(--muted); }

/* Enlaces del pie legal: el azul de marca sobre el lienzo se quedaba en
   2.6:1. El tono oscuro llega a 4.95:1. */
.legal__pie a { color: var(--azul-deep); }

/* Lista de casillas (asignar monitores a un grupo). Cada fila entera es
   clicable: marcar un cuadrado de 26px con el ratón es innecesariamente fino. */
.lista-check {
  display: grid; gap: 6px; margin-bottom: 18px;
  background: var(--white); border: 1px solid var(--line);
  border-radius: var(--r); padding: 10px 12px;
}
.lista-check ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 6px; }
.check-fila, .lista-check li {
  display: flex; align-items: center; gap: 10px;
  min-height: 44px; padding: 4px 6px; border-radius: 10px; cursor: pointer;
}
.check-fila:hover, .lista-check li:hover { background: var(--cream-2); }
.lista-check input[type="checkbox"] { width: 22px; height: 22px; flex: 0 0 auto; }
.lista-check label { display: flex; align-items: center; gap: 10px; min-height: 44px; cursor: pointer; }
/* Una fila con acciones detrás de la casilla (las flechas de subir y bajar
   del panel de columnas del listado imprimible): la etiqueta ocupa el hueco
   —casilla y nombre EN LÍNEA dentro de ella, sin partirse en dos renglones—
   y las acciones quedan al final. Este `<label>` vive dentro de un
   `<form class="filtros">` (la barra de la hoja), y `.filtros label` (más
   arriba) le pone `flex-direction: column` y tipografía de rótulo de
   filtro: misma especificidad que esta regla, así que lo que ESTA no
   declare lo sigue mandando esa —por eso `flex-direction` y la tipografía
   se repiten aquí en vez de dar por hecho que con `display:flex` basta—.
   Mismo tamaño, peso y color que ya usa `.desple-multi__panel .check-fila`
   para esta fila, no unos inventados. */
.check-fila > label {
  flex: 1 1 auto; display: flex; flex-direction: row; align-items: center; gap: 10px;
  min-width: 0; font-size: 14.5px; font-weight: 400; color: var(--ink);
}
.check-fila > label span { white-space: nowrap; }
/* Si algún día una `.lista-check` vive dentro de un formulario `.filtros`,
   sus etiquetas necesitan esto: `.filtros label` pone `flex-direction:
   column` y negrita pequeña (rótulo encima del campo), pensado para un
   campo de filtro suelto, no para una fila de casilla + nombre. */
.filtros .lista-check label {
  flex-direction: row; font-size: inherit; font-weight: 400; color: var(--ink);
}
/* Variante en línea: para listas cortas de cosas pequeñas (los meses del
   curso), donde una columna de diez filas a 44px sería un muro. */
.lista-check--linea { grid-template-columns: repeat(auto-fit, minmax(130px, 1fr)); }
.lista-check--linea .check-fila { min-height: 34px; }

/* ==========================================================================
   11. Contraste: segunda pasada de la auditoría
   ========================================================================== */

/* El azul de marca no llega a 4,5:1 como color de enlace: 3,57 sobre las
   tarjetas y 2,62 sobre el lienzo. El tono oscuro llega a 4,95 y 7,66. */
a { color: var(--azul-deep); }
/* `:not(.btn)` no es cosmético: un botón que es un enlace («Apuntar»,
   «Añadir hijo/a») ya trae su color, y esta regla —más específica que
   `.btn--principal`— se lo pisaba al pasar el ratón. El texto de un botón
   verde se volvía azul y casi no se leía. Cada variante de botón sigue
   decidiendo su propio hover. */
a:not(.btn):hover { color: var(--azul); }

/* Paso ya completado del asistente: el verde de marca con texto blanco se
   queda en 3,02:1. Con el tono oscuro sube a 5,4. */
.paso--hecho .paso__n { background: var(--verde-deep); color: #fff; }

/* Titulares de la pantalla de revisión: van sobre el lienzo azul, no sobre
   tarjeta, así que necesitan tonos más oscuros. */
.titulo-bloqueante { color: #96271b; }
.titulo-aviso { color: #6b4600; }

/* Pasar lista: «Vino» es el estado por defecto de todos los alumnos, y el
   aviso de alergias es información de seguridad. Ambos a 4,5:1. */
.estado--presente input:checked + span { color: #2b6416; }
.asistencia__quien .meta { color: #96271b; }

/* Errores de formulario y enlaces dentro de avisos. */
.campo .errores, .campo .errores li, .campo__error { color: #96271b; }
.aviso--warn a { color: #6b4600; text-decoration: underline; }
.aviso a { display: inline-flex; align-items: center; min-height: 44px; }

/* Menú de gestión en móvil: es la navegación principal, a 44px. */
@media (max-width: 900px) { .gs__nav a { min-height: 44px; } }

/* ============================================================
   12. Formularios: obligatorios y errores
   ------------------------------------------------------------
   Va al final del fichero por la misma razón que el bloque 9: son
   modificadores y tienen que ganarle a las reglas base del bloque de
   campos, que están más arriba.
   ============================================================ */

/* El asterisco de obligatorio. Rojo y en negrita, pero sin gritar. */
.obligatorio { color: var(--rojo); font-weight: 700; }

.leyenda-obligatorios { margin: 0 0 18px; }

/* Campo con error: el borde rojo es lo que hace que se encuentre de un
   vistazo en un formulario de veinte campos. El texto de debajo solo, se
   pasa por alto. */
.campo--error > label { color: var(--rojo-deep); }

.campo--error input:not([type="checkbox"]):not([type="radio"]),
.campo--error select,
.campo--error textarea {
  border-color: var(--rojo);
  background: var(--rojo-suave);
}

/* Al enfocarlo sigue en rojo: si al hacer clic se volviera azul, se
   perdería la referencia de qué había que corregir. */
.campo--error input:focus,
.campo--error select:focus,
.campo--error textarea:focus {
  border-color: var(--rojo);
  box-shadow: 0 0 0 3px rgba(214, 40, 57, .18);
}

/* Casillas: el input no tiene borde propio, así que se marca el conjunto. */
.campo--error.campo--check {
  border-left: 3px solid var(--rojo);
  padding-left: 10px;
}
.campo--error.campo--check label { color: var(--rojo-deep); }

/* ============================================================
   13. Versión y aviso de actualización (panel de gestión)
   ============================================================ */

.gs__version {
  text-align: right;
  padding: 4px 24px 16px;
  color: var(--muted);
  font-size: 12px;
  font-variant-numeric: tabular-nums;
  user-select: all;   /* para que se pueda copiar de un doble clic al reportar */
}

.aviso-version {
  position: fixed; right: 20px; bottom: 20px; z-index: 60;
  max-width: min(360px, calc(100vw - 40px));
  display: flex; flex-direction: column; gap: 12px;
  padding: 16px 18px;
  background: var(--white);
  border: 1.5px solid var(--azul);
  border-radius: 14px;
  box-shadow: 0 12px 32px rgba(16, 30, 60, .18);
}
.aviso-version[hidden] { display: none; }
.aviso-version strong { display: block; font-size: 15px; }
.aviso-version .meta { display: block; margin-top: 2px; font-size: 13px; }
.aviso-version__botones { display: flex; gap: 8px; flex-wrap: wrap; }
/* En el portal la barra de navegación vive pegada abajo: la banda se iza
   por encima para no taparla (y no quedar bajo el gesto de inicio del móvil). */
.pt .aviso-version { bottom: calc(76px + env(safe-area-inset-bottom, 0px)); }

@media (max-width: 640px) {
  .aviso-version { right: 12px; left: 12px; bottom: 12px; max-width: none; }
  .gs__version { text-align: center; padding: 4px 16px 14px; }
}

/* ============================================================
   14. Logo del colegio
   ------------------------------------------------------------
   `object-fit: contain` y no `cover`: un logo recortado pierde justo lo
   que lo identifica, el nombre del colegio.
   ============================================================ */

.logo-colegio {
  width: 40px; height: 40px;
  object-fit: contain;
  border-radius: 8px;
  background: #fff;      /* los logos con transparencia suelen ser oscuros */
  padding: 3px;
  flex: 0 0 auto;
}
.logo-colegio--grande { width: 120px; height: 120px; padding: 8px; border-radius: 12px; }

/* Sustituto cuando el colegio aún no ha mandado su logo: la inicial. */
.logo-colegio--vacio {
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--cream-2); color: var(--azul-ink);
  font-weight: 800; font-size: 17px;
}
.logo-colegio--grande.logo-colegio--vacio { font-size: 44px; }

.celda-con-logo { display: flex; align-items: center; gap: 10px; }

/* ============================================================
   15. Programación en tres columnas
   ------------------------------------------------------------
   Colegio → actividad → grupo. Cada columna se abre con lo elegido en
   la anterior, y en móvil se apilan (el orden del HTML ya es el bueno).
   ============================================================ */

.prog {
  display: grid;
  grid-template-columns: minmax(220px, 1fr) minmax(220px, 1fr) minmax(320px, 1.4fr);
  gap: 16px;
  align-items: start;
}

.prog__col {
  background: var(--white);
  border: 1.5px solid var(--line);
  border-radius: 16px;
  overflow: hidden;
  /* Que no crezcan sin fin: la tercera columna puede tener muchos grupos y
     obligaría a bajar hasta abajo para volver a la primera. */
  display: flex; flex-direction: column;
  max-height: calc(100vh - 220px);
}

/* Sin nada que elegir todavía: se atenúa, pero se sigue leyendo qué va a ir
   ahí. Ocultarla dejaría la pantalla sin explicar el recorrido. */
.prog__col--apagada { opacity: .62; }

.prog__cab {
  display: flex; align-items: center; gap: 10px;
  padding: 14px 16px;
  border-bottom: 1.5px solid var(--line);
  background: var(--cream);
  flex: 0 0 auto;
}
.prog__cab h2 { margin: 0; font-size: 15px; font-weight: 700; color: var(--ink); }

.prog__n {
  flex: 0 0 auto;
  width: 24px; height: 24px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--azul-deep); color: #fff;
  font-size: 13px; font-weight: 800;
}

.prog__cuerpo { padding: 10px; overflow-y: auto; }

.prog__item {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 12px;
  border-radius: 12px;
  text-decoration: none;
  color: var(--ink);
  min-height: 44px;          /* objetivo táctil */
}
.prog__item:hover { background: var(--cream); }
.prog__item--activo {
  background: var(--azul-deep);
  color: #fff;
}
.prog__item--activo .meta,
.prog__item--activo strong { color: #fff; }
.prog__item__tx { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.prog__item__tx strong { font-size: 14.5px; }
.prog__item__tx .meta { font-size: 12.5px; }

.punto {
  width: 10px; height: 10px; border-radius: 50%;
  flex: 0 0 auto; background: var(--azul);
}

.prog__vacio {
  margin: 6px; padding: 14px;
  color: var(--muted); font-size: 14px; line-height: 1.5;
}

.prog__anadir { margin: 10px 4px 4px; }
.prog__anadir > summary {
  /* `list-style: none` no basta en Safari: hace falta el pseudo de WebKit. */
  list-style: none; cursor: pointer; display: inline-flex; width: auto;
}
.prog__anadir > summary::-webkit-details-marker { display: none; }
.prog__anadir > form {
  margin-top: 12px; padding: 14px;
  background: var(--cream); border-radius: 12px;
}

.prog__grupo {
  border: 1.5px solid var(--line);
  border-radius: 12px;
  padding: 12px 14px;
  margin-bottom: 10px;
}
.prog__grupo__cab {
  display: flex; align-items: center; justify-content: space-between;
  gap: 10px; margin-bottom: 8px;
}

.prog__datos { display: grid; grid-template-columns: 1fr 1fr; gap: 10px 14px; margin: 0; }
.prog__datos dt {
  font-size: 11.5px; text-transform: uppercase; letter-spacing: .03em;
  color: var(--muted); font-weight: 700; margin-bottom: 2px;
}
.prog__datos dd { margin: 0; font-size: 14px; color: var(--ink); }

.txt-error { color: var(--rojo-deep); font-weight: 600; }

@media (max-width: 1100px) {
  .prog { grid-template-columns: 1fr; }
  .prog__col { max-height: none; }
  /* Apiladas, una columna atenuada y vacía solo estorba. */
  .prog__col--apagada { display: none; }
}

/* ------------------------------------------------------------
   Color por categoría. Las clases `cat--*` ya se usaban en el catálogo
   de familias pero no estaban definidas en ninguna hoja: el icono salía
   sin color. Se define aquí una vez para las dos zonas.
   ------------------------------------------------------------ */
.cat--deportes   { --cat: var(--c-deportes);   --cat-bg: var(--c-deportes-bg); }
.cat--academia   { --cat: var(--c-academia);   --cat-bg: var(--c-academia-bg); }
.cat--artisticas { --cat: var(--c-arte);       --cat-bg: var(--c-arte-bg); }
.cat--teatro     { --cat: var(--c-teatro);     --cat-bg: var(--c-teatro-bg); }
.cat--estrategia { --cat: var(--c-estrategia); --cat-bg: var(--c-estrategia-bg); }
.cat--servicios  { --cat: var(--c-servicios);  --cat-bg: var(--c-servicios-bg); }

.punto[class*="cat--"] { background: var(--cat, var(--azul)); }
.fila__ic[class*="cat--"] { background: var(--cat-bg); color: var(--cat); }
/* Sobre el fondo lavado el color de marca no siempre llega a 4.5:1, así que
   el texto va en tinta y el color queda en el fondo y el borde. */
.etiqueta[class*="cat--"] {
  background: var(--cat-bg); color: var(--ink);
  box-shadow: inset 0 0 0 1.5px var(--cat);
}

.prog__quitar { margin: 0 4px 12px; }
.prog__nota { margin: 0 4px 12px; line-height: 1.5; }

/* ============================================================
   16. Formularios compactos (fichas de maestros)
   ------------------------------------------------------------
   La ficha de un colegio son quince campos. Con el alto por defecto no
   cabía en pantalla y había que bajar para encontrar el botón de guardar,
   que es justo cuando la gente cree que el formulario está incompleto.

   Se aprieta el espacio, NO los objetivos táctiles: los campos siguen
   midiendo 44 px de alto y el texto 16 px (por debajo de eso, iOS hace
   zoom al enfocar y descoloca la página).
   ============================================================ */

.form--compacto .campo { margin-bottom: 12px; }
.form--compacto .campo > label { margin-bottom: 4px; font-size: 13.5px; }
.form--compacto .campo input:not([type="checkbox"]):not([type="radio"]),
.form--compacto .campo select,
.form--compacto .campo textarea {
  min-height: 44px;            /* el mínimo accesible, ni un píxel menos */
  padding: 10px 12px;
}
.form--compacto .campo select { padding-right: 38px; }
.form--compacto .campo .ayuda { margin-top: 3px; font-size: 12.5px; }
.form--compacto .form-fila { gap: 14px; }
.form--compacto .leyenda-obligatorios { margin-bottom: 14px; }

/* Rejillas de fila. La de 2-1 es para «nombre + localidad»: el nombre
   necesita el doble de sitio y con dos columnas iguales quedaba corto. */
@media (min-width: 720px) {
  .form-fila--3 { grid-template-columns: 1fr 1fr 1fr; }
  .form-fila--2-1 { grid-template-columns: 2fr 1fr; }
}

/* Bloque para una entidad distinta dentro de la misma ficha (el AMPA).
   El recuadro no es adorno: dice que esos datos son de otra organización,
   que es justo lo que se confundía. */
.bloque {
  border: 1.5px solid var(--line);
  border-radius: 14px;
  padding: 14px 16px 4px;
  margin: 4px 0 18px;
  background: var(--cream);
}
.bloque__titulo {
  padding: 0 8px;
  margin-left: -4px;
  font-family: var(--font-display);
  font-size: 15px; font-weight: 700; color: var(--ink);
}
.bloque__pie {
  margin: 0 0 12px;
  color: var(--muted); font-size: 13px; line-height: 1.45;
}

/* Logo y vista previa, uno al lado del otro.
   Dentro del formulario la vista previa va a 72 px, no a 120: sirve para
   comprobar de un vistazo que el logo se lee, y a 120 se comía todo el alto
   que se acababa de ganar apretando los campos. */
.campo-logo { display: flex; align-items: flex-start; gap: 16px; margin-bottom: 12px; }
.campo-logo .logo-colegio--grande { width: 72px; height: 72px; padding: 6px; }
.campo-logo .logo-colegio--grande.logo-colegio--vacio { font-size: 30px; }
.campo-logo__campos { flex: 1 1 auto; min-width: 0; }
.campo-logo__campos .campo:last-child { margin-bottom: 0; }

/* Casilla de confirmar algo que no se deshace. */
.campo--confirmar {
  border: 1.5px solid var(--ambar);
  border-radius: 12px;
  padding: 10px 14px;
  margin-bottom: 14px;
  background: var(--white);
}

@media (max-width: 719px) {
  .campo-logo { flex-direction: column; gap: 10px; }
}

/* ============================================================
   17. Modal (<dialog> nativo)
   ------------------------------------------------------------
   Se usa el elemento nativo y no un div: trae el cierre con Escape, el
   foco atrapado dentro y el fondo inerte, que a mano es donde se cuelan
   los fallos de accesibilidad.
   ============================================================ */

.modal {
  width: min(680px, calc(100vw - 32px));
  max-height: calc(100vh - 48px);
  padding: 0;
  border: none;
  border-radius: 18px;
  background: var(--white);
  color: var(--ink);
  box-shadow: 0 24px 64px rgba(16, 30, 60, .28);
  overflow: hidden;
}
.modal::backdrop { background: rgba(16, 30, 60, .45); }
.modal > form { display: flex; flex-direction: column; max-height: inherit;
                background: none; border: none; box-shadow: none; padding: 0; }

.modal__cab {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 16px 20px;
  border-bottom: 1.5px solid var(--line);
  background: var(--cream);
  flex: 0 0 auto;
}
.modal__cab h2 { margin: 0; font-size: 17px; }

.modal__cerrar {
  flex: 0 0 auto;
  width: 44px; height: 44px;          /* objetivo táctil completo */
  display: inline-flex; align-items: center; justify-content: center;
  border: none; border-radius: 50%;
  background: transparent; color: var(--body);
  font-size: 18px; cursor: pointer;
}
.modal__cerrar:hover { background: var(--cream-2); }

/* El cuerpo es lo único que hace scroll: la cabecera y los botones se
   quedan siempre a la vista, que es de lo que se quejaba la gente. */
.modal__cuerpo { padding: 18px 20px 4px; overflow-y: auto; flex: 1 1 auto; }

.modal__pie {
  display: flex; gap: 10px; flex-wrap: wrap;
  padding: 14px 20px;
  border-top: 1.5px solid var(--line);
  background: var(--cream);
  flex: 0 0 auto;
}

/* ============================================================
   18. Cursos pulsables y días
   ============================================================ */

.cursos {
  border: 1.5px solid var(--line);
  border-radius: 12px;
  padding: 10px 12px;
  background: var(--cream);
  margin-top: 6px;
}
.cursos__etapa { display: flex; align-items: center; gap: 10px; margin-bottom: 6px; }
.cursos__titulo {
  flex: 0 0 76px;
  font-size: 11.5px; font-weight: 700; text-transform: uppercase;
  letter-spacing: .03em; color: var(--muted);
}
.cursos__fila { display: flex; flex-wrap: wrap; gap: 6px; }

.curso {
  min-width: 44px; min-height: 36px; padding: 6px 10px;
  border: 1.5px solid var(--line); border-radius: 9px;
  background: var(--white); color: var(--ink);
  font-family: inherit; font-size: 14px; font-weight: 600;
  cursor: pointer;
}
.curso:hover { border-color: var(--azul); }
.curso:focus-visible { outline: 2px solid var(--azul); outline-offset: 2px; }
.curso--activo {
  background: var(--azul-deep); border-color: var(--azul-deep); color: #fff;
}

.cursos__resumen { margin: 8px 0 8px; font-size: 13px; color: var(--body); }

/* Los días, en una fila apretada: son siete casillas y en lista ocupaban
   media pantalla. */
.dias { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 4px; }
/* `inline-flex` y no el `inline` por defecto de <label>: con un contenedor
   inline, el input en position:absolute se estira a la caja de línea (26 px)
   en vez de al recuadro, y la zona pulsable de verdad se quedaba muy por
   debajo de los 44 px que se ven. */
.dia { position: relative; display: inline-flex; }
/* Se repite `input[type="checkbox"]` para ganarle a la regla de arriba que
   fija 26×26 px a todas las casillas dentro de un `.campo`: aquí la casilla
   está escondida y lo que se pulsa es el recuadro entero. Con `inset` en vez
   de width/height 100% no depende de cómo se resuelvan los porcentajes. */
.campo .dia input[type="checkbox"] {
  position: absolute; inset: 0; opacity: 0;
  width: auto; height: auto; margin: 0; cursor: pointer;
}
.dia span {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 52px; min-height: 44px; padding: 0 10px;
  border: 1.5px solid var(--line); border-radius: 10px;
  background: var(--white);
  font-size: 14px; font-weight: 600;
}
.dia input:checked + span {
  background: var(--azul-deep); border-color: var(--azul-deep); color: #fff;
}
.dia input:focus-visible + span { outline: 2px solid var(--azul); outline-offset: 2px; }

/* Cabecera de columna con enlace a la ficha. */
.prog__cab__enlace { margin-left: auto; font-size: 13px; font-weight: 600; }
.prog__pie { display: flex; flex-wrap: wrap; gap: 8px; margin: 10px 4px 4px; }
.prog__grupo__acciones { display: flex; align-items: center; gap: 8px; }

@media (max-width: 480px) {
  .cursos__etapa { flex-direction: column; align-items: flex-start; gap: 4px; }
  .cursos__titulo { flex: none; }
}

/* ============================================================
   19. Modal de alta de grupo: más apretado
   ------------------------------------------------------------
   Doce campos con su explicación debajo daban un modal de 900 px que
   había que recorrer entero. Las explicaciones que solo repetían la
   etiqueta se han quitado, y las que decían qué pasa al dejar el campo
   en blanco están ahora dentro del propio campo, en gris.
   ============================================================ */

.modal .form--compacto .campo { margin-bottom: 10px; }
.modal .form--compacto .campo > label { font-size: 13px; margin-bottom: 3px; }
.modal .modal__cuerpo { padding: 14px 18px 2px; }

/* El bloque de cursos, sin recuadro: con marco propio parecía una isla
   dentro del formulario y sumaba 20 px de aire por los cuatro lados. */
.modal .cursos {
  border: none; background: none; padding: 0; margin-top: 2px;
}
.modal .cursos__etapa { margin-bottom: 4px; }
.modal .cursos__resumen {
  display: flex; align-items: baseline; gap: 10px;
  margin: 6px 0 0; font-size: 12.5px; color: var(--muted);
}

/* La etapa es pulsable: marca sus cursos de una vez. Se ve que lo es sin
   parecer otro botón más, que ya hay trece al lado. */
.cursos__titulo {
  flex: 0 0 86px;
  padding: 4px 0; border: none; background: none; text-align: left;
  font-family: inherit; font-size: 11.5px; font-weight: 700;
  text-transform: uppercase; letter-spacing: .03em; color: var(--muted);
  cursor: pointer;
}
.cursos__titulo:hover { color: var(--azul-deep); text-decoration: underline; }
.cursos__titulo:focus-visible { outline: 2px solid var(--azul); outline-offset: 2px; }

.enlace-flojo {
  border: none; background: none; padding: 0;
  font-family: inherit; font-size: 12.5px; font-weight: 600;
  color: var(--azul-deep); text-decoration: underline; cursor: pointer;
}

/* Días y horas en la misma fila: es un solo dato («cuándo es»), y sueltos
   el bloque de los días quedaba colgando. */
.fila-horario { display: grid; grid-template-columns: 1fr; gap: 12px; }
@media (min-width: 620px) {
  .fila-horario { grid-template-columns: auto 1fr 1fr; align-items: start; }
}
.modal .dias { gap: 4px; }
.modal .dia span { min-width: 46px; padding: 0 6px; }

/* Últimos apretones del modal de grupo: la cabecera y el pie no necesitan
   el aire de una página, y los botones de curso son trece en tres filas,
   donde cada píxel de alto se multiplica. */
#modal-grupo { width: min(620px, calc(100vw - 32px)); }
#modal-grupo .modal__cab { padding: 12px 18px; }
#modal-grupo .modal__pie { padding: 12px 18px; }
#modal-grupo .modal__cab h2 { font-size: 16px; }
#modal-grupo .curso { min-height: 32px; padding: 4px 9px; font-size: 13.5px; }
#modal-grupo .cursos__etapa { margin-bottom: 2px; gap: 8px; }
/* La etapa es un botón de verdad, así que necesita altura para el dedo. No
   suma nada al modal: la fila ya mide lo que miden los botones de curso. */
#modal-grupo .cursos__titulo {
  flex-basis: 74px; font-size: 11px;
  display: inline-flex; align-items: center; min-height: 32px;
}
#modal-grupo .enlace-flojo { display: inline-flex; align-items: center; min-height: 30px; }
#modal-grupo .cursos__resumen { margin-top: 4px; }

/* ============================================================
   20. Filtros de listado
   ------------------------------------------------------------
   Van en GET a propósito: la búsqueda se puede guardar en marcadores y
   el botón de exportar arrastra los mismos parámetros.
   ============================================================ */

.filtros {
  display: flex; flex-wrap: wrap; gap: 8px; align-items: center;
  margin-bottom: 14px;
}
.filtros__buscar { flex: 1 1 260px; min-width: 0; }
.filtros input[type="search"], .filtros select {
  width: 100%; min-height: 44px; padding: 9px 12px;
  border: 1.5px solid var(--line); border-radius: 10px;
  font-family: inherit; font-size: 15px; color: var(--ink);
  background: var(--white);
}
.filtros select { width: auto; min-width: 170px; }
.filtros input:focus, .filtros select:focus {
  outline: none; border-color: var(--azul); box-shadow: 0 0 0 3px rgba(46,107,240,.15);
}
.resultado { margin: 0 0 10px; }

/* Solo para lectores de pantalla: la etiqueta existe, pero el hueco del
   filtro no da para enseñarla sin que la barra crezca al doble. */
.visually-hidden {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}

/* ============================================================
   21. Ficha (alumno, familia…)
   ============================================================ */

.ficha { display: flex; flex-direction: column; gap: 18px; }
.ficha__bloque h2 { margin: 0 0 10px; font-size: 17px; }
/* Un bloque al que se vuelve con un ancla (`#equipo`, `#pago` en la ficha de
   un colegio del viaje): sin aire arriba, la barra fija de Gestión (`.gs__top`,
   de 90 a 120 px según lo que lleve) tapaba su título y su entradilla, y se
   veía la tabla sin saber de qué era. */
.ficha__bloque[id] { scroll-margin-top: 130px; }
.ficha__resumen {
  background: var(--white); border: 1px solid var(--line);
  border-radius: var(--r); padding: 16px 18px; box-shadow: var(--sh-soft);
}
.datos-pares {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 12px 18px; margin: 0 0 4px;
}
.datos-pares dt {
  font-size: 11.5px; text-transform: uppercase; letter-spacing: .03em;
  color: var(--muted); font-weight: 700; margin-bottom: 2px;
}
.datos-pares dd { margin: 0; font-size: 14.5px; color: var(--ink); }
.lista-plana { margin: 8px 0 0; padding-left: 18px; }
.lista-plana li { margin-bottom: 3px; }

.bloque-plegable > summary { list-style: none; cursor: pointer; display: inline-flex; }
.bloque-plegable > summary::-webkit-details-marker { display: none; }
.bloque-plegable > form { margin-top: 14px; }

/* La celda de acciones NO puede ser `display: flex`.
   Un <td> con display distinto de `table-cell` sale del layout de la tabla:
   deja de compartir la altura de su fila y su borde inferior se pinta por su
   cuenta, con lo que la línea de separación aparecía partida y a distinta
   altura que la del resto de columnas.
   Los iconos ya son `inline-flex`, así que basta con no dejar que se partan
   de línea y separarlos entre sí. */
.acciones-celda { white-space: nowrap; }
.acciones-celda > * + * { margin-left: 6px; }

/* ============================================================
   22. Densidad del panel de gestión
   ------------------------------------------------------------
   El panel se veía suelto: filas de 46 px, cabeceras enormes y mucho
   aire entre bloques. Para una pantalla de trabajo, donde se miran
   cuarenta filas seguidas, eso significa hacer scroll para todo.

   Esto SOLO afecta al panel (`.gs`), nunca al portal de familias, que
   se usa desde el móvil y donde el aire ayuda. Y no se tocan los
   objetivos táctiles: los botones y los campos siguen midiendo 44 px.
   ============================================================ */

.gs table.datos { font-size: 14px; }
.gs table.datos th, .gs table.datos td { padding: 9px 14px; }
.gs table.datos th {
  font-size: 11.5px; letter-spacing: .05em;
  position: sticky; top: 0; z-index: 1;   /* la cabecera no se pierde al bajar */
}
/* Rayado suave: con quince columnas iguales, seguir una fila con la vista
   es lo primero que falla. */
.gs table.datos tbody tr:nth-child(even) { background: rgba(255, 255, 255, .45); }
.gs table.datos tbody tr:hover { background: var(--cream); }

/* Los botones de dentro de una tabla no necesitan el tamaño de un botón
   principal, pero sí seguir siendo pulsables: 36 px de alto y área ancha. */
.gs table.datos .btn--sm { min-height: 36px; padding: 6px 12px; font-size: 13px; }
.gs table.datos .etiqueta { padding: 3px 9px; font-size: 11.5px; }
.gs table.datos .meta { font-size: 12.5px; }

.gs .gs__cont { padding: 18px 22px; }
.gs .gs__top { padding: 11px 22px; }
.gs .gs__top h1 { font-size: 18px; }
.gs .tabla-caja { border-radius: 14px; }
.gs .kpis { gap: 12px; margin-bottom: 18px; }

/* El menú lateral: 14 enlaces entran sin scroll. */
.gs .gs__nav a { padding: 7px 11px; font-size: 14px; }
.gs .gs__nav .grupo { margin-top: 12px; }

/* Tarjeta de grupo en Programación: dos líneas de datos, sin rejilla.
   Con la rejilla de cuatro rótulos en mayúsculas cada grupo medía 170 px y
   no cabían tres en pantalla, que es lo normal en una actividad. */
.prog__grupo { padding: 10px 12px; margin-bottom: 8px; }
.prog__grupo__cab { margin-bottom: 4px; }
.prog__grupo__linea {
  margin: 0; font-size: 13px; color: var(--body); line-height: 1.5;
}
.prog__grupo__linea .sep { color: var(--line); margin: 0 6px; }
.prog__grupo .btn--sm { min-height: 32px; padding: 4px 10px; font-size: 12.5px; }

/* El «+» de la cabecera de cada columna de Programación. Sustituye a los
   botones del final de la lista: con veinte colegios había que recorrerla
   entera para llegar a añadir uno. */
.prog__mas {
  margin-left: auto;
  flex: 0 0 auto;
  width: 32px; height: 32px;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1.5px solid var(--azul-deep); border-radius: 9px;
  background: var(--azul-deep); color: #fff;
  font-size: 15px; cursor: pointer; text-decoration: none;
}
.prog__mas:hover { background: var(--azul); border-color: var(--azul); }
.prog__mas:focus-visible { outline: 2px solid var(--azul); outline-offset: 2px; }

/* La cabecera lleva ahora el «+» y, en la tercera, el interruptor. */
.prog__cab { flex-wrap: wrap; }
.prog__cab__enlace { margin-left: 0; }

/* Modal de una sola pregunta: no necesita el alto del de grupo. */
.modal--corto { width: min(460px, calc(100vw - 32px)); }

.prog__mas--peligro {
  background: var(--white); color: var(--rojo); border-color: var(--rojo);
}
.prog__mas--peligro:hover { background: var(--rojo); border-color: var(--rojo); color: #fff; }
/* Solo el primero se separa del título; los demás van pegados a él. */
.prog__cab .prog__mas + .prog__mas { margin-left: 6px; }

/* ============================================================
   23. Acciones de tabla como icono
   ------------------------------------------------------------
   Un botón entero por acción y por fila llena la tabla de cajas. Como
   icono se lee de un vistazo cuál es cuál, sin perder el objetivo
   táctil: el cuadro sigue midiendo 36 px y el `title` dice qué hace.
   ============================================================ */

/* El selector repite `table.datos a` para ganarle a la regla general que da
   44 px de alto a los enlaces dentro de una tabla. Sin eso, el icono de
   editar (un <a>) medía 44 y el de borrar (un <button>) 36, en la misma
   celda. Y el `padding: 0` quita el que trae el navegador en los botones. */
.icono-accion,
table.datos a.icono-accion,
table.datos button.icono-accion {
  width: 36px; height: 36px;
  min-width: 36px; min-height: 36px;
  padding: 0;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1.5px solid var(--line); border-radius: 9px;
  background: var(--white); color: var(--azul-deep);
  font-size: 15px; line-height: 1; cursor: pointer; text-decoration: none;
}
.icono-accion:hover { border-color: var(--azul); background: var(--cream); }
.icono-accion:focus-visible { outline: 2px solid var(--azul); outline-offset: 2px; }
.icono-accion--peligro { color: var(--rojo); }
.icono-accion--peligro:hover { background: var(--rojo); border-color: var(--rojo); color: #fff; }

/* Por qué no sale un monitor en la lista de un grupo. Plegado: interesa
   justo cuando alguien echa en falta a una persona concreta. */
.descartados { margin: 8px 0 16px; font-size: 14px; }
.descartados > summary { cursor: pointer; color: var(--azul-deep); font-weight: 600; }
.descartados .lista-plana { margin-top: 8px; color: var(--body); }

/* Columnas de números en los informes: alineadas a la derecha, para poder
   comparar importes de un vistazo, y con cifras de ancho fijo para que no
   bailen las columnas. */
table.datos th.num, table.datos td.num {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

/* Alias de `.seccion-titulo`. Nació aparte y acabó siendo lo mismo con un
   punto menos de tamaño; lo usan tres plantillas de familias. Se iguala aquí
   en vez de tocarlas: el canon es `.seccion-titulo`, este nombre se queda
   funcionando y no hay dos títulos de sección con pintas distintas. */
.titulo-bloque {
  font-family: var(--font-display); font-size: 18px;
  margin: 26px 0 10px; color: var(--ink);
}

/* ============================================================
   24. Monitores: retrato, presentación y reseñas
   ============================================================ */

.retrato {
  width: 72px; height: 72px; flex: 0 0 auto;
  border-radius: 50%; object-fit: cover;
  background: var(--cream-2);
}
.retrato--grande { width: 104px; height: 104px; }
.retrato--mini { width: 32px; height: 32px; }
.retrato--vacio {
  display: inline-flex; align-items: center; justify-content: center;
  color: var(--azul-ink); font-weight: 800; font-size: 26px;
}
.retrato--grande.retrato--vacio { font-size: 38px; }
.retrato--mini.retrato--vacio { font-size: 14px; }

.ficha__cabecera { display: flex; align-items: center; gap: 16px; margin-bottom: 16px; }
.bio { margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--line); }
.bio h3 { margin: 0 0 6px; font-size: 14px; }
.bio p { margin: 0 0 6px; line-height: 1.6; white-space: pre-line; }

/* Contador junto a un botón: «Documentación (3)» sin que parezca otro botón. */
.cuenta {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 20px; height: 20px; padding: 0 6px; margin-left: 4px;
  border-radius: 999px; background: var(--azul-deep); color: #fff;
  font-size: 12px; font-weight: 700;
}

/* --- Reseñas --- */
.resenas { display: flex; flex-direction: column; gap: 12px; }
.resena {
  background: var(--white); border: 1px solid var(--line);
  border-radius: 14px; padding: 14px 16px; box-shadow: var(--sh-soft);
}
.resena__cab {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: 10px; margin-bottom: 8px;
}
.resena__texto { margin: 0 0 8px; line-height: 1.6; white-space: pre-line; }
.resena__acciones { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.resena__rechazo { display: flex; gap: 6px; align-items: center; flex: 1 1 260px; }
.resena__rechazo input {
  flex: 1 1 auto; min-width: 0; min-height: 36px; padding: 6px 10px;
  border: 1.5px solid var(--line); border-radius: 9px;
  font-family: inherit; font-size: 13.5px;
}
.resena--publica { background: var(--cream); }

/* --- El monitor, en el portal de familias --- */
.perfil-monitor {
  background: var(--white); border: 1px solid var(--line);
  border-radius: var(--r); padding: 18px; box-shadow: var(--sh-soft);
}
.perfil-monitor__cab { display: flex; align-items: center; gap: 16px; }
.perfil-monitor__cab h1 { margin: 0 0 2px; font-size: 22px; }
/* Empuja la nota al extremo derecho de la cabecera y deja que el nombre
   ocupe lo que sobre. */
.perfil-monitor__quien { flex: 1 1 auto; min-width: 0; }
.perfil-monitor__bio {
  margin: 16px 0 0; padding-top: 14px; border-top: 1px solid var(--line);
  line-height: 1.65; white-space: pre-line;
}
.perfil-monitor__pie {
  margin: 14px 0 0; padding-top: 12px; border-top: 1px solid var(--line);
}
.perfil-monitor__pie a {
  display: inline-flex; align-items: center; gap: 8px;
  min-height: 44px; font-weight: 600;
}

/* La nota, arriba a la derecha del nombre. Es un enlace a la pantalla de
   reseñas: aquí solo cabe el resumen. */
.nota-chip {
  flex: 0 0 auto; align-self: flex-start;
  display: flex; flex-direction: column; align-items: flex-end; gap: 1px;
  padding: 6px 10px; min-height: 44px;
  border: 1.5px solid var(--line); border-radius: 12px;
  background: var(--white); text-decoration: none; color: inherit;
}
.nota-chip:hover { border-color: var(--azul); }
.nota-chip__cifra { font-size: 20px; font-weight: 800; color: var(--ink); line-height: 1.1; }
.nota-chip .meta { font-size: 11px; white-space: nowrap; }
/* Estrellas pequeñas: aquí son el adorno de la cifra, no el dato. Si van a
   tamaño normal el chip se come el ancho del nombre en un móvil. */
.nota-chip .estrellas { font-size: 11px; }

/* En el móvil no caben foto grande, nombre y nota en la misma línea: la foto
   cede, que es lo que menos información lleva. */
@media (max-width: 480px) {
  .perfil-monitor__cab { gap: 12px; }
  .perfil-monitor__cab .retrato--grande { width: 72px; height: 72px; }
  .perfil-monitor__cab .retrato--grande.retrato--vacio { font-size: 28px; }
  .perfil-monitor__cab h1 { font-size: 19px; }
}

/* La tarjeta de una inscripción en «Mi cuenta». Cabecera con el título a la
   izquierda y el estado a la derecha: el estado no se parte nunca en dos
   líneas (se partía «En lista de espera»), es el título el que cede. */
.insc__cab { display: flex; justify-content: space-between; align-items: flex-start; gap: 10px; }
.insc__tx { min-width: 0; }
.insc__titulo { display: block; font-size: 17px; line-height: 1.25; }
.insc__cab .etiqueta { flex: 0 0 auto; white-space: nowrap; }
.insc__dato {
  display: flex; align-items: center; gap: 7px;
  margin: 10px 0 0; font-size: 14px; color: var(--body);
}
.insc__dato i { color: var(--muted); font-size: 15px; }

/* Quién da la clase: un bloque separado por una raya fina, con el rótulo en
   minúscula normal (en mayúsculas gritaba más que el propio título) y una
   fila por monitor a todo el ancho, como una lista de ajustes. */
.insc__monitores { margin-top: 12px; padding-top: 10px; border-top: 1px solid var(--line-soft); }
.insc__rotulo { margin: 0 0 2px; font-size: 13px; font-weight: 600; color: var(--muted); }
.monitor-fila {
  display: flex; align-items: center; gap: 10px;
  min-height: 44px; padding: 4px 0;
  color: var(--ink); text-decoration: none; font-size: 15px; font-weight: 600;
}
.monitor-fila + .monitor-fila { border-top: 1px solid var(--line-soft); }
.monitor-fila__nombre { flex: 1; min-width: 0; }
.monitor-fila .ph-caret-right { font-size: 14px; color: var(--muted); }
.monitor-fila:hover .monitor-fila__nombre { color: var(--azul-deep); }

.volver { display: inline-flex; align-items: center; gap: 6px; min-height: 44px; }

/* Las normas de las reseñas, plegadas. El portal de familias se ve casi
   siempre en el móvil: el texto entero antes del formulario ocupaba una
   pantalla y había que pasarlo para llegar a escribir. Quien quiera leerlo
   lo abre; la casilla de aceptar está justo debajo, siempre a la vista. */
.normas-resena { margin: 0 0 8px; font-size: 14.5px; }
.normas-resena > summary {
  display: inline-flex; align-items: center; gap: 6px;
  min-height: 44px;                       /* objetivo táctil en el móvil */
  color: var(--azul-deep); font-weight: 600; cursor: pointer;
}
.normas-resena__cuerpo {
  padding: 12px 14px; margin-bottom: 4px;
  background: var(--cream); border-radius: 12px; line-height: 1.6;
}
.normas-resena__cuerpo p { margin: 0 0 8px; }
.normas-resena__cuerpo ul { margin: 0 0 8px; padding-left: 20px; }
.normas-resena__cuerpo li { margin-bottom: 2px; }
.normas-resena__cuerpo p:last-child { margin-bottom: 0; }

.criterios { margin-bottom: 14px; font-size: 14px; }
.criterios > summary { cursor: pointer; color: var(--azul-deep); font-weight: 600; }
.criterios p { margin: 8px 0 0; max-width: 70ch; line-height: 1.55; }

/* ============================================================
   25. Estrellas
   ============================================================ */

/* La estrella va dibujada en la propia plantilla (macro `estrella`). Se mide
   en `em` y se pinta con `currentColor` para que herede el tamaño y el color
   de quien la contenga, que es como se comportaba el icono al que sustituye:
   todo lo de abajo sigue valiendo sin cambiar una línea. */
.estrella { width: 1em; height: 1em; display: block; flex: none; }

.estrellas { display: inline-flex; gap: 1px; font-size: 15px; line-height: 1; }
.estrellas--grande { font-size: 21px; }
.estrellas__on { color: #e8a300; }
/* Un gris que se vea sobre el lienzo azul: con `--line` (#a6c1e7) la
   estrella apagada quedaba casi del color del fondo y no se veía. */
.estrellas__off { color: #93a9c9; }

.nota { display: inline-flex; align-items: baseline; gap: 8px; }
.nota__cifra { font-size: 26px; font-weight: 800; color: var(--ink); line-height: 1; }

/* Elegir estrellas: los radios siguen siendo radios (teclado, lectores de
   pantalla) y solo se esconden a la vista. Las opciones van de 5 a 1 en el
   HTML y se voltean con `row-reverse`, que es lo que permite encender las de
   la izquierda con `~` sin una línea de JavaScript. */
.estrellas-elegir { border: none; padding: 0; margin: 0 0 12px; }
.estrellas-elegir legend { font-weight: 700; font-size: 14px; margin-bottom: 6px; padding: 0; }
.estrellas-elegir__fila {
  display: inline-flex; flex-direction: row-reverse;
  justify-content: flex-end; gap: 4px;
}
.estrellas-elegir input { position: absolute; opacity: 0; width: 1px; height: 1px; }
.estrellas-elegir label {
  width: 44px; height: 44px;               /* objetivo táctil */
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 28px; color: #93a9c9; cursor: pointer;
}
.estrellas-elegir label:hover,
.estrellas-elegir label:hover ~ label,
.estrellas-elegir input:checked ~ label { color: #e8a300; }
.estrellas-elegir input:focus-visible + label {
  outline: 2px solid var(--azul); outline-offset: 2px; border-radius: 8px;
}
.estrellas-elegir.campo--error label { color: var(--rojo); }

/* La nota en el listado de monitores. En rojo por debajo de 3,5: es el
   aviso de «aquí hay que mirar», que es justo para lo que sirve tenerla
   en la lista y no solo dentro de cada ficha. */
.nota-mini { font-weight: 800; font-size: 15px; color: var(--ink); margin-right: 4px; }
.nota-mini--baja { color: var(--rojo-deep); }

/* ==========================================================================
   26. El catálogo abierto de familias
   ========================================================================== */
/* Filtros como pastillas pulsables. Mismo tamaño y mismo radio que las
   casillas de día del panel (`.dia span`): es el mismo gesto y tiene que
   verse igual en los dos sitios. */
/* Los dos filtros del catálogo, repartiéndose el ancho. Ocupan siempre lo
   mismo por muchas combinaciones de días que tenga el colegio: esa es la
   razón de que sean desplegables y no pastillas. */
.filtros--oferta { gap: 10px; margin-bottom: 16px; }
.filtros--oferta label { flex: 1 1 140px; min-width: 0; font-size: 12px; }
.filtros--oferta select {
  width: 100%; min-width: 0;
  /* Por debajo de 16px, iOS hace zoom al enfocar el campo y descoloca la
     pantalla entera. */
  font-size: 16px;
}

/* Las caras de quien da la actividad, dentro de la tarjeta del listado. */
.opcion__caras { display: flex; align-items: center; gap: 6px; margin-top: 8px; }
.opcion__caras .retrato--mini { flex: 0 0 auto; }
.opcion__caras .meta { margin: 0; font-size: 13px; }
.opcion__nota { display: flex; align-items: center; gap: 6px; margin-top: 4px; }
.opcion__nota .estrellas { font-size: 12px; }
.opcion__nota .meta { margin: 0; font-size: 13px; }

.tarjeta--horario { margin-bottom: 10px; }
.tarjeta--horario strong { font-size: 15px; }

/* La llamada a la acción al final de la ficha, separada del contenido y con
   sitio para que no la tape la barra de abajo. */
.acciones--pegadas { margin: 20px 0 8px; }
.btn--ancho { width: 100%; justify-content: center; }

/* Los tres atajos de «Mi cuenta», en una sola barra partida en tres y no
   en tres cajas sueltas: ocupa la mitad de alto y no se confunde con las
   tarjetas de inscripción de debajo. El contador va pegado al icono, como
   el globo de una app, en vez de en una línea propia (24/09/2026). */
.atajos-cuenta {
  display: flex; margin: 0 0 4px;
  background: var(--white); border: 1px solid var(--line);
  border-radius: var(--r-sm); overflow: hidden;
}
.atajo {
  flex: 1 1 0; min-height: 56px; position: relative;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 3px; padding: 8px 4px;
  text-decoration: none; color: var(--ink);
  font-size: 13.5px; font-weight: 600; text-align: center;
}
.atajo + .atajo { border-left: 1px solid var(--line); }
.atajo:hover { background: var(--line-soft); }
.atajo i { font-size: 20px; color: var(--azul); }
.atajo .cuenta {
  position: absolute; top: 5px; left: calc(50% + 6px); margin: 0;
  min-width: 18px; height: 18px; font-size: 11px;
}

/* La cara del monitor delante de su nombre, en el listado. `inline-flex` y no
   `flex`: una celda en `display:flex` deja de comportarse como celda y se
   pierden los separadores entre filas (ya pasó en Alumnos). */
.celda-monitor { display: inline-flex; align-items: center; gap: 10px; }
.celda-monitor .retrato--mini { flex: 0 0 auto; }
/* Mismas medidas que el retrato, pero sin nada dentro: solo está para que
   todos los nombres empiecen en la misma vertical. */
.retrato-hueco { flex: 0 0 auto; display: inline-block; width: 32px; height: 32px; }

/* La lista de «dónde falla» dentro de un aviso agrupado. */
.lista-simple { margin: 6px 0 0; padding-left: 18px; }
.lista-simple li { font-size: 14px; color: var(--muted); line-height: 1.7; }
.lista-simple a { margin-left: 6px; }

/* Las clases dentro de la ficha del grupo. */
.clases-cab { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; margin-top: 26px; }
.clase-ficha__cab { display: flex; align-items: center; gap: 8px; }
.clase-ficha__campos { display: flex; gap: 8px; margin-top: 8px; }
.clase-ficha__campos input {
  flex: 1 1 auto; min-height: 44px; padding: 0 10px; font-size: 16px;
  border: 1.5px solid var(--line); border-radius: 10px; background: var(--white);
}

/* Las casillas de monitor dentro de la tarjeta de una clase: la rejilla en
   línea de .lista-check, pegada al detalle y sin el margen de formulario. Y
   los descartados, plegados justo debajo. */
.clase-ficha__monitores { margin: 8px 0 0; padding: 4px 8px; }
.clase-ficha .descartados { margin: 6px 0 0; }

/* El bloque de acceso al portal, en la ficha del monitor. */
.acceso-monitor {
  margin-top: 18px; padding-top: 14px; border-top: 1px solid var(--line);
}
.acceso-monitor h3 { font-size: 15px; margin: 0 0 10px; }
.acceso-monitor__acciones { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }

/* Pedir por correo un documento que falta, en el expediente del monitor. */
.pedir-doc { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 14px; align-items: center; }
.pedir-doc select {
  min-height: 44px; padding: 0 10px; font-size: 16px;
  border: 1.5px solid var(--line); border-radius: 10px; background: var(--white);
}

/* ==========================================================================
   27. Rediseño del panel: workspace neutro
   --------------------------------------------------------------------------
   El CRM deja el lienzo azul para el portal de familias (allí es marca) y
   pasa a un gris neutro: con todo azul, contexto, contenido y tarjetas se
   fundían y la ficha parecía «lavada». Se hace sobrescribiendo los tokens
   DENTRO de .gs: un solo sitio, y todos los componentes del panel —tablas,
   kpis, tarjetas, formularios— se retiñen solos sin tocar sus reglas.
   La navegación lateral sigue azul oscuro: es la identidad.
   ========================================================================== */
.gs {
  --cream: #f4f7fb;        /* workspace */
  --cream-2: #ecf1f8;
  --white: #ffffff;        /* superficie de tarjetas */
  --paper: #ffffff;
  --line: #e5eaf1;
  --line-soft: rgba(18, 35, 63, 0.06);
  --ink: #12233f;
  --muted: #66758f;
  --body: #42536f;
  --r: 16px;
  --sh-soft: 0 8px 28px rgba(18, 35, 63, 0.07);
  --sh-card: 0 10px 32px rgba(18, 35, 63, 0.08);
  /* El fondo lo pintaba el <body>, que queda FUERA de .gs y no ve estos
     tokens: sin esta línea el workspace seguía azul aunque el token ya
     fuera gris. */
  background: var(--cream);
}
/* El cebreado de las tablas era blanco translúcido sobre fondo azul; sobre
   superficie blanca desaparecía. Un gris casi imperceptible hace el trabajo. */
.gs table.datos tbody tr:nth-child(even) { background: #f8fafc; }
.gs table.datos tbody tr:hover { background: #eef3fa; }
/* Más ancho útil: a 1200px quedaba una franja muerta enorme a la derecha. */
.gs .gs__cont { max-width: 1500px; }

/* ==========================================================================
   28. Ficha del monitor: perfil + acceso + módulos
   ========================================================================== */
.fm-grid {
  display: grid; grid-template-columns: minmax(0, 1.8fr) minmax(330px, 0.8fr);
  gap: 18px; margin-bottom: 18px;
  /* stretch, no start: las dos tarjetas de cada fila miden lo mismo de alto.
     Con cada una a su aire, la ficha parecía puesta sin escuadra. */
  align-items: stretch;
}
/* Las dos filas comparten EXACTAMENTE las mismas columnas: si cada una lleva
   su proporción, la costura vertical no coincide y el conjunto baila. */
.fm-grid--secciones { grid-template-columns: minmax(0, 1.8fr) minmax(330px, 0.8fr); }
@media (max-width: 1100px) {
  .fm-grid, .fm-grid--secciones { grid-template-columns: 1fr; }
}

/* --- Tarjeta de perfil --- */
.fm-identidad {
  display: flex; align-items: center; gap: 16px;
  padding-bottom: 18px; border-bottom: 1px solid var(--line);
}
.fm-identidad .retrato--grande { width: 70px; height: 70px; }
.fm-nombre { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.fm-nombre h2 { font-size: 20px; margin: 0; letter-spacing: -0.01em; }
.fm-contacto {
  display: flex; gap: 18px; flex-wrap: wrap; margin-top: 7px;
  color: var(--muted); font-size: 12.5px;
}
.fm-stats { display: grid; grid-template-columns: repeat(4, 1fr); margin-top: 18px; }
.fm-stat { padding: 2px 18px; border-right: 1px solid var(--line); min-width: 0; }
.fm-stat:first-child { padding-left: 0; }
.fm-stat:last-child { border-right: none; }
.fm-stat dt {
  font-size: 10px; letter-spacing: 0.07em; text-transform: uppercase;
  color: #8390a6; font-weight: 700; margin: 0 0 6px;
}
.fm-stat dd {
  margin: 0; font-size: 14.5px; font-weight: 700; color: var(--ink);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
@media (max-width: 640px) {
  .fm-stats { grid-template-columns: repeat(2, 1fr); row-gap: 14px; }
  .fm-stat:nth-child(2) { border-right: none; }
  .fm-stat:nth-child(3) { padding-left: 0; }
}
.fm-presentacion {
  margin-top: 18px; padding-top: 14px; border-top: 1px solid var(--line);
  display: flex; justify-content: space-between; align-items: baseline; gap: 14px;
  color: var(--muted); font-size: 12.5px; line-height: 1.5;
}
.fm-presentacion strong { color: var(--ink); }
.fm-presentacion a { font-weight: 700; white-space: nowrap; }

/* --- Tarjeta de acceso al portal --- */
.fm-portal { display: flex; flex-direction: column; }
.fm-portal__cab {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; margin-bottom: 14px;
}
.fm-portal__cab h3 { font-size: 15px; margin: 0; }
/* El estado va con punto Y texto: el color solo no puede ser el mensaje. */
.fm-estado { display: inline-flex; align-items: center; gap: 8px; font-size: 12px; font-weight: 700; }
.fm-estado::before {
  content: ""; width: 8px; height: 8px; border-radius: 50%; background: currentColor;
  box-shadow: 0 0 0 4px color-mix(in srgb, currentColor 14%, transparent);
}
.fm-estado--ok { color: #16803c; }
.fm-estado--off { color: var(--rojo-deep); }
.fm-estado--sin { color: #a35f00; }
.fm-kv { display: grid; gap: 12px; margin-bottom: 16px; }
.fm-kv > div {
  background: #f8fafc; border: 1px solid #edf0f5; border-radius: 10px;
  padding: 11px 12px;
}
.fm-kv dt {
  font-size: 10px; text-transform: uppercase; letter-spacing: 0.06em;
  color: #8a95a8; font-weight: 700; margin: 0 0 4px;
}
.fm-kv dd {
  margin: 0; font-size: 13px; font-weight: 650; color: var(--ink);
  overflow-wrap: anywhere;
}
.fm-kv dd.apagado { font-weight: 500; color: var(--muted); }
.fm-portal__acciones { display: flex; gap: 8px; flex-wrap: wrap; }
.fm-portal__ayuda { margin-top: 12px; color: #8a95a8; font-size: 11.5px; line-height: 1.5; }
/* Destructiva en outline: no puede competir con la acción normal. */
.btn--peligro-suave {
  background: var(--white); color: var(--rojo-deep); border: 1px solid #f0caca;
}
.btn--peligro-suave:hover { background: #fff5f5; }

/* --- Módulos (grupos, reseñas) --- */
.fm-seccion { padding: 0; overflow: hidden; display: flex; flex-direction: column; }
/* El estado vacío rellena lo que sobre: así las dos tarjetas de la fila
   terminan a la misma altura y el hueco queda centrado, no descolgado. */
.fm-seccion .estado-vacio { flex: 1 1 auto; }
.fm-seccion .tabla-caja { flex: 1 1 auto; }
.fm-seccion__cab {
  min-height: 58px; padding: 10px 18px;
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  border-bottom: 1px solid var(--line);
}
.fm-seccion__titulo { display: flex; align-items: center; gap: 10px; min-width: 0; }
.fm-seccion__titulo h3 { font-size: 15px; margin: 0; }
.icon-chip {
  width: 30px; height: 30px; border-radius: 9px; flex: 0 0 auto;
  background: #eef4ff; color: var(--azul); display: grid; place-items: center;
}
.fm-seccion .tabla-caja { border: none; border-radius: 0; box-shadow: none; margin: 0; }

/* Estado vacío compacto: explica qué aparecerá, no un rectángulo mudo. */
.estado-vacio { padding: 28px; display: grid; place-items: center; text-align: center; }
.estado-vacio > div { max-width: 360px; }
.estado-vacio .icono {
  width: 48px; height: 48px; border-radius: 14px; margin: 0 auto 12px;
  background: #f1f5fb; color: #6983ac; display: grid; place-items: center; font-size: 22px;
}
.estado-vacio h4 { margin: 0 0 6px; font-size: 14px; }
.estado-vacio p { margin: 0 auto 14px; color: var(--muted); font-size: 12.5px; line-height: 1.5; }
.estado-vacio p:last-child { margin-bottom: 0; }

/* Reseñas dentro del módulo */
.fm-resena { padding: 14px 18px; border-bottom: 1px solid var(--line); }
.fm-resena:last-child { border-bottom: none; }
.fm-resena .meta { font-size: 12px; }
.fm-resena p { margin: 6px 0; font-size: 13.5px; line-height: 1.5; }

/* ==========================================================================
   29. Desplegable de selección múltiple
   --------------------------------------------------------------------------
   Las mismas casillas de siempre, pero plegadas: diez colegios y veinte
   actividades como listas abiertas se comían la mitad del alto del
   formulario. Es un <details> nativo: funciona sin JavaScript (el script
   solo cierra al pinchar fuera y resume la selección en el botón).
   ========================================================================== */
.desple-multi { position: relative; }
.desple-multi > summary {
  list-style: none; cursor: pointer;
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  min-height: 44px; padding: 9px 12px;
  border: 1.5px solid var(--line); border-radius: 10px;
  background: var(--white); font-size: 15px; color: var(--ink);
}
.desple-multi > summary::-webkit-details-marker { display: none; }
.desple-multi > summary .caret { color: var(--muted); transition: transform .12s ease; }
.desple-multi[open] > summary { border-color: var(--azul); }
.desple-multi[open] > summary .caret { transform: rotate(180deg); }
.desple-multi > summary .resumen {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.desple-multi > summary .resumen.apagado { color: var(--muted); }
.desple-multi__panel {
  /* Anclado por la DERECHA, no por la izquierda: estos desplegables caen al
     final de la fila de filtros y, al ser el panel más ancho que el resumen,
     creciendo hacia la derecha se salía de la pantalla. */
  position: absolute; z-index: 8; top: calc(100% + 6px); right: 0; left: auto;
  /* El panel no puede medir lo que mida el resumen: «Todos los colegios»
     es más corto que «CEIP San Lucas y María» y el nombre se partía en dos
     líneas dentro de una caja estrechísima. */
  min-width: 260px; max-width: 88vw;
  max-height: 280px; overflow-y: auto;
  background: var(--white); border: 1px solid var(--line); border-radius: 12px;
  box-shadow: var(--sh-card); padding: 6px;
}
/* La casilla y el nombre, EN LÍNEA. Hay que decirlo aquí porque estos
   desplegables viven dentro de `.filtros`, y `.filtros label` pone
   `flex-direction: column` para los filtros normales (rótulo encima del
   campo). Sin esto, la casilla salía centrada sobre el texto y cada colegio
   ocupaba tres renglones. El peso y el color, por lo mismo: los hereda del
   rótulo de filtro, que va en negrita. */
.desple-multi__panel .check-fila {
  display: flex; flex-direction: row; align-items: center; gap: 10px;
  padding: 9px 10px; border-radius: 8px; cursor: pointer;
  font-size: 14.5px; font-weight: 400; color: var(--ink);
}
.desple-multi__panel .check-fila input { flex: 0 0 auto; width: 20px; height: 20px; }
.desple-multi__panel .check-fila:hover { background: var(--cream-2); }
/* Variante para el panel de columnas del listado imprimible: cada fila
   lleva además dos acciones de fila (subir/bajar, 36 px de `.icono-accion`)
   y hay ocho seguidas, donde los 44 px de siempre no cabían sin scroll. Solo
   aquí: los demás `.desple-multi__panel` (los filtros de Familias) siguen a
   44 px, que es su único uso hoy, sin flechas que encajar. */
.desple-multi__panel--filas .check-fila { min-height: 40px; padding: 2px 10px; }

/* Pestañas de filtro (correos por destinatario). */
.pestanas { display: flex; gap: 6px; margin-bottom: 14px; flex-wrap: wrap; }
.pestana {
  display: inline-flex; align-items: center; min-height: 40px; padding: 0 16px;
  border: 1px solid var(--line); border-radius: 999px; background: var(--white);
  font-size: 14px; font-weight: 600; color: var(--body); text-decoration: none;
}
.pestana:hover { border-color: var(--azul); }
.pestana.activa { background: var(--azul); border-color: var(--azul); color: #fff; }

/* Las variables de una plantilla de correo, como fichas pulsables. */
.vars-chips { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 6px; }
.chip-var {
  font-family: ui-monospace, "Cascadia Mono", Consolas, monospace;
  font-size: 13px; padding: 6px 10px; min-height: 36px;
  border: 1px solid var(--line); border-radius: 8px;
  background: var(--cream-2); color: var(--ink); cursor: pointer;
}
.chip-var:hover { border-color: var(--azul); background: #eef4ff; }

/* El expediente del monitor: un renglón por tipo de documento. */
.exp-fila {
  display: flex; align-items: center; gap: 12px;
  padding: 12px 18px; border-bottom: 1px solid var(--line);
}
.exp-fila:last-child { border-bottom: none; }
.exp-fila__que { flex: 1 1 auto; min-width: 0; }
.exp-fila__estado { flex: 0 0 auto; }
.exp-fila__acciones { flex: 0 0 auto; display: flex; gap: 4px; }
@media (max-width: 640px) {
  .exp-fila { flex-wrap: wrap; }
  .exp-fila__que { flex-basis: 100%; }
}

/* ============================================================
   30. Asistencia: la rejilla alumno × día
   ------------------------------------------------------------
   El nombre queda fijo a la izquierda porque la rejilla se desplaza en
   horizontal: sin eso, al llegar a diciembre ya no se sabe de quién es
   la fila. Colores de los avisos de siempre: verde ok, rojo error,
   ámbar aviso.
   ============================================================ */

.rejilla-asi td, .rejilla-asi th { white-space: nowrap; }
.rejilla-asi .asi-nombre {
  position: sticky; left: 0; background: var(--white);
  min-width: 180px; font-weight: 600;
}
.rejilla-asi .asi-nombre .meta { display: block; font-weight: 400; font-size: 12.5px; }
.rejilla-asi .asi-dia { font-variant-numeric: tabular-nums; font-size: 12.5px; }
.rejilla-asi td.asi { text-align: center; font-weight: 700; cursor: default; }
.rejilla-asi .asi-total { text-align: right; font-variant-numeric: tabular-nums; }

.asi--p { color: #2b6416; }
.asi--a { color: var(--rojo); background: var(--rojo-suave); }
.asi--j { color: #7a5200; background: #fff7df; }
.asi--nada { color: var(--muted); }
span.asi { padding: 1px 7px; border-radius: 6px; font-weight: 700; }
span.asi--p { background: var(--c-deportes-bg, #e8f5de); }

.asi--num { font-variant-numeric: tabular-nums; }
td.asi--rojo { color: var(--rojo); font-weight: 700; }

/* La barra de filtros de asistencia lleva más controles que las demás. */
.filtros--envuelve { flex-wrap: wrap; }
.filtros--envuelve input[type="search"] { min-width: 150px; }

/* ============================================================
   31. Jornadas: el semáforo de duración
   ------------------------------------------------------------
   La clase normal ronda la hora: verde 50min–1:10, ámbar 1:10–1:44,
   rojo fuera de eso. El rojo va en sólido y no en suave a propósito:
   casi siempre es un fichaje mal hecho y tiene que saltar a la vista.
   ============================================================ */

.jt {
  display: inline-block; padding: 3px 10px; border-radius: 8px;
  font-weight: 700; font-variant-numeric: tabular-nums; white-space: nowrap;
}
.jt--verde { background: var(--c-deportes-bg, #e8f5de); color: #2b6416; }
.jt--ambar { background: #fff7df; color: #7a5200; }
.jt--rojo  { background: var(--rojo); color: #fff; }

/* ============================================================
   32. Celdas que se recortan
   ------------------------------------------------------------
   Para tablas de una fila por registro: el dato largo (un email, el
   nombre de un colegio) se corta con «…» en vez de partir la fila en
   tres alturas. El valor entero se lee en el `title`.
   ============================================================ */

table.datos td.recorta { max-width: 260px; overflow: hidden; text-overflow: ellipsis; }
table.datos td.recorta .meta { font-size: 13px; }

/* ============================================================
   33. Resumen de preinscripciones: la matriz
   ------------------------------------------------------------
   Una fila por grupo y una columna por curso. Las columnas de curso
   nacen plegadas bajo el total de su etapa: la pregunta normal es
   «cuántos de primaria», y solo a veces «cuántos de 3º». El nombre
   queda fijo al desplazar en horizontal, como en la rejilla de
   asistencia.
   ============================================================ */

table.matriz td:first-child, table.matriz th:first-child {
  position: sticky; left: 0; background: var(--white); min-width: 220px;
}
table.matriz .fila-act td { background: var(--cream, #f7faff); font-size: 15px; }
table.matriz .fila-gru td:first-child { padding-left: 32px; }
table.matriz .oculta { display: none; }
table.matriz th.cur, table.matriz td.cur { background: #fbfdff; }

.etapa-abrir {
  background: none; border: 0; padding: 0; cursor: pointer;
  font: inherit; color: inherit; letter-spacing: inherit;
  text-transform: inherit; display: inline-flex; align-items: center; gap: 6px;
}
.etapa-abrir i { font-size: 11px; transition: transform .15s ease; }
.etapa-abrir[aria-expanded="true"] i { transform: rotate(90deg); }
.etapa-abrir:hover { color: var(--azul); }

/* El icono de vaciar los filtros: misma altura que los campos de al lado. */
.filtros .icono-accion { flex: 0 0 auto; }

/* ============================================================
   34. Pantalla de pago: el velo de «procesando»
   ------------------------------------------------------------
   El formulario de tarjeta es de SumUp y, mientras autentica con el
   banco, va cambiando de página dentro de su marco: la familia ve
   destellos de direcciones que no reconoce («eu-test.oppwa.com…») y
   se asusta justo cuando está pagando. Este velo lo tapa con una
   pantalla nuestra.

   Se levanta SOLO si el banco pide de verdad confirmación, porque esa
   pantalla hay que verla y tocarla. Lo invisible se queda invisible;
   lo que necesita a la persona, se enseña.
   ============================================================ */

.caja-pago { position: relative; }

.pago-velo {
  position: absolute; inset: 0; z-index: 5;
  background: var(--white, #fff);
  border-radius: inherit;
  display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 14px;
  text-align: center; padding: 28px 20px;
}
.pago-velo[hidden] { display: none; }
.pago-velo__rueda {
  width: 34px; height: 34px; border-radius: 50%;
  border: 3px solid var(--line, #dbe6f5);
  border-top-color: var(--azul, #1b4de4);
  animation: pago-girar .8s linear infinite;
}
.pago-velo strong { font-size: 17px; }
.pago-velo .meta { max-width: 30ch; }

@keyframes pago-girar { to { transform: rotate(360deg); } }

@media (prefers-reduced-motion: reduce) {
  .pago-velo__rueda { animation-duration: 2.4s; }
}


/* ============================================================
   35. Estimación mes a mes
   ------------------------------------------------------------
   Misma matriz que el resumen de preinscripciones. Las filas de
   total van en negrita con una línea encima; la de resultado, con
   fondo; y un número negativo se pinta en rojo, que es lo único
   que hay que ver de un vistazo en una cuenta de resultados.
   ============================================================ */
table.matriz tr.fila-total td { border-top: 1px solid var(--line); font-weight: 600; }
table.matriz tr.fila-resultado td { background: var(--cream, #f7faff); }
table.matriz td.negativo, table.matriz td.negativo strong { color: var(--rojo); }

/* ============================================================
   36. Pista al pasar el ratón
   ------------------------------------------------------------
   Para la explicación de una cifra o de un concepto que no cabe
   en la celda: un icono pequeño y el texto aparece encima al
   pasar el ratón o al enfocarlo con el teclado. Se usa en la
   estimación mes a mes, donde cada línea lleva su «cómo se
   calcula» y ponerlo debajo doblaba el alto de la tabla.

   El texto va en `data-pista`. Se repite en `title` para el
   móvil, que no tiene ratón: ahí el navegador lo enseña con una
   pulsación larga.
   ============================================================ */
.pista {
  position: relative; display: inline-flex; align-items: center;
  justify-content: center; width: 20px; height: 20px; margin-left: 4px;
  border-radius: 50%; color: var(--muted); cursor: help; vertical-align: middle;
  font-size: 14px;
}
.pista:hover, .pista:focus-visible { color: var(--azul); outline: none; }
.pista::after {
  content: attr(data-pista);
  position: absolute; left: 50%; bottom: calc(100% + 8px); transform: translateX(-50%);
  width: max-content; max-width: 320px; padding: 9px 12px;
  background: var(--ink, #142849); color: #fff; font-size: 13px; line-height: 1.45;
  font-weight: 400; text-align: left; border-radius: 10px; box-shadow: var(--sh-card);
  white-space: normal; pointer-events: none; opacity: 0; visibility: hidden;
  transition: opacity .12s ease; z-index: 30;
}
/* Con el foco a secas, no solo el de teclado: en el móvil no hay ratón y
   la pista se abre al tocar el icono. */
.pista:hover::after, .pista:focus::after { opacity: 1; visibility: visible; }
/* En la primera columna de una tabla ancha, la pista se pegaría al borde
   izquierdo: se ancla a la izquierda en vez de centrarse. */
td:first-child .pista::after { left: 0; transform: none; }
/* Debajo en vez de encima: para las primeras filas de una tabla con
   desplazamiento, donde encima no hay sitio y la caja la recortaría. */
.pista--abajo::after { bottom: auto; top: calc(100% + 8px); }
/* La primera columna de la matriz es fija y la cabecera también: al pasar
   el ratón, la celda sube por encima de la cabecera para que la pista no
   quede tapada. */
table.matriz td:first-child:hover, table.matriz td:first-child:focus-within { z-index: 2; }

/* ==========================================================================
   37. Tacto nativo (PWA)
   Lo que hace que el portal instalado se comporte como una app y no como una
   página dentro de un navegador. Decisión de producto (06/09/2026): SIN zoom
   de ningún tipo. Quien vea mal no podrá ampliar; si eso llega a soporte, se
   deshace quitando `touch-action` de aquí y `user-scalable=no` del viewport.
   ========================================================================== */

/* Pellizco y doble toque, fuera. El viewport con user-scalable=no lo obedece
   Android, pero Safari lo ignora desde iOS 10: en iPhone el zoom solo se
   corta bloqueando el GESTO. pan-x pan-y deja desplazar (también las tablas
   que scrollean en horizontal) y quita todo lo demás, incluido el doble toque
   —que además elimina los 300 ms que el navegador esperaba tras cada
   pulsación para ver si venía otra. Se nota al tocar botones. */
html, body { touch-action: pan-x pan-y; }

/* Sin rebote elástico ni «tirar para recargar» cuando va instalada: al llegar
   arriba, una app nativa se queda quieta; una web deja ver un hueco blanco
   por detrás. En el navegador se respeta, que ahí sí es lo que la gente
   espera. Recargar no hace falta para estar al día: el service worker no
   guarda HTML y el aviso de «versión nueva» ya avisa solo. */
@media (display-mode: standalone) {
  html, body { overscroll-behavior-y: none; }
}

/* Lo que es INTERFAZ no se selecciona ni saca el menú de «guardar imagen» al
   dejar el dedo: barra, pestañas, botones, filas y opciones. Solo la
   interfaz: los datos de la familia, sus hijos o un correo de contacto se
   tienen que poder seleccionar y copiar. El sello de versión conserva su
   user-select: all para poder copiarlo al reportar. */
.pt__bar, .pt__nav, .btn, .fila, .opcion-radio, .icon-btn, .acceso__caja > img {
  -webkit-user-select: none; user-select: none;
  -webkit-touch-callout: none;
}
.pt__bar img, .acceso__caja > img, .fila__ic img { -webkit-user-drag: none; }

/* Estados «pulsado» donde faltaban. El resalte gris del navegador ya está
   quitado (tap-highlight transparente, arriba del todo), y sin una respuesta
   propia el toque parece que no ha entrado: la gente vuelve a pulsar. Botones,
   filas e icono ya lo tenían; estos dos no. */
.opcion-radio:active { transform: scale(.98); }
.pt__nav a:active, .pt__nav button:active { opacity: .55; }

/* ==========================================================================
   38. Calendario escolar: la línea del curso y los días ya pasados
   ========================================================================== */

/* Los siete hitos del curso en una tira compacta: inicio, los tres
   trimestres y las dos vacaciones que se DEDUCEN de ellos, más el fin. Antes
   Navidad y Semana Santa eran una nota gris pegada al botón de guardar —la
   información más interesante de la pantalla, y la que menos se veía—; aquí
   son dos paradas más de la tira, solo que con otro fondo. */
.curso-linea {
  display: flex; flex-wrap: wrap; align-items: center; gap: 4px 2px;
  background: var(--white); border: 1px solid var(--line); border-radius: var(--r);
  padding: 12px 14px; margin-bottom: 22px; box-shadow: var(--sh-soft);
}
.curso-linea__paso {
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  padding: 5px 12px; border-radius: 10px; text-align: center;
}
.curso-linea__etq {
  font-size: 11px; font-weight: 700; text-transform: uppercase;
  letter-spacing: .03em; color: var(--muted); white-space: nowrap;
}
.curso-linea__fecha { font-size: 13.5px; font-weight: 600; color: var(--ink); white-space: nowrap; }
/* Deducida: el mismo lavado ámbar que `.aviso--warn` y `.et--preinscrita`,
   la pieza que el panel ya usa para «esto no lo ha tecleado nadie». */
.curso-linea__paso--deducido { background: var(--ambar-suave); }
.curso-linea__paso--deducido .curso-linea__etq { color: var(--ambar-ink); }
/* Un hito sin fecha no desaparece: dice que falta, para que se note en
   «Fechas del curso» qué hueco hay que rellenar todavía. */
.curso-linea__fecha--falta { color: var(--muted); font-weight: 500; font-style: italic; }
.curso-linea__flecha { color: var(--line); font-size: 13px; flex: 0 0 auto; }

/* Un día ya pasado no se descarta —puede hacer falta para justificar un
   cobro antiguo— pero no tiene que competir por la vista con los que
   vienen. Atenuado y no plegado: un <details> no puede envolver <tr> (no es
   contenido válido de una tabla), así que plegarlos de verdad pediría una
   segunda tabla o JavaScript para algo que se mira una vez al año. Mismo
   truco que `.opcion--inerte` y `.prog__col--apagada`. */
.fila-pasada { opacity: .55; }

/* ==========================================================================
   Fuera de lista (Gestión)
   ========================================================================== */

/* La cola de llamadas de Asistencia: una .tabla-caja con título. El título
   va DENTRO de la caja y no como .seccion-titulo encima, porque es una lista
   de tareas metida entre los filtros y las listas, y suelta parecía otra
   pantalla. Lavado ámbar: la pieza que el panel ya usa para «esto está
   pendiente de algo» (.aviso--warn, .et--revisar). */
.fuera-lista { margin-bottom: 18px; }
.fuera-lista__cab {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 12px;
  padding: 10px 16px; border-bottom: 1px solid var(--line);
  background: var(--ambar-suave);
}
.fuera-lista__cab strong {
  font-family: var(--font-display); font-size: 15px; color: var(--ambar-ink);
}
.fuera-lista__cab .meta { margin: 0; font-size: 13px; }

/* La etiqueta «Lista de llegada» en la tarjeta de la actividad, en
   Programación. A la derecha del nombre y sin crecer: la tarjeta es un
   enlace de dos líneas y la etiqueta no puede convertirla en tres. */
.prog__item__et {
  margin-left: auto; flex: 0 0 auto;
  font-size: 11.5px; padding: 3px 9px; white-space: nowrap;
}
   Lista de llegada
   La puerta del matinal: una lista para toda la actividad, dos monitoras, y
   se marca a quien entra. Cada fila es un botón grande (se toca de pie, con
   un niño de la mano) y el estado va a la derecha en texto y en color: el
   color solo no puede ser el mensaje. Al final va lo de `lista.html`, el
   guardado de cada toque, que nació con esto y vale para todas las listas.
   ========================================================================== */
.llegada__cab { text-align: center; padding: 14px 18px 12px; }
.llegada__contador { display: flex; align-items: baseline; justify-content: center; gap: 8px; }
.llegada__contador strong {
  font-family: var(--font-display); font-size: 42px; line-height: 1; color: var(--verde-deep);
}
.llegada__contador span { font-size: 15px; font-weight: 600; color: var(--muted); }
.llegada__cierre { margin: 8px 0 0; font-weight: 600; }
/* El rato de después de terminar: se avisa, pero sin alarma. Ámbar y no
   rojo, que no es un error: es que aún da tiempo a acabar de marcar. */
.llegada__margen { margin: 8px 0 0; font-weight: 600; color: var(--ambar-ink); }
#llegada-aviso { margin: 10px 0 0; text-align: left; }

/* Buscador y filtro, pegados bajo la barra del portal: con 33 niños y una
   mano ocupada, lo que se hace es teclear tres letras y tocar. El `top` lo
   ajusta el script al alto real de la barra (cambia con la muesca). */
.llegada__barra {
  position: sticky; top: 56px; z-index: 5;
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px 14px;
  padding: 8px 0 10px; margin-bottom: 6px; background: var(--cream);
}
.llegada__barra input[type="search"] {
  flex: 1 1 200px; min-height: 48px; padding: 9px 14px;
  border: 1.5px solid var(--line); border-radius: 12px; background: var(--white);
  font-family: inherit; font-size: 16px; color: var(--ink);
}
.llegada__barra input[type="search"]:focus {
  outline: none; border-color: var(--azul); box-shadow: 0 0 0 3px rgba(46, 107, 240, .15);
}
.llegada__solo {
  display: inline-flex; align-items: center; gap: 8px; min-height: 44px;
  font-weight: 600; font-size: 14.5px; cursor: pointer;
}
.llegada__solo input { width: 22px; height: 22px; margin: 0; accent-color: var(--verde); }

/* La fila. Un <button> de verdad y no un div con onclick: foco, teclado y
   lector de pantalla gratis. Misma altura y radio que `.opcion`. */
.llegada__fila {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  width: 100%; min-height: 64px; padding: 10px 14px; margin-bottom: 8px;
  background: var(--white); border: 1.5px solid var(--line); border-radius: var(--r);
  font-family: inherit; font-size: 16px; color: inherit; text-align: left; cursor: pointer;
  -webkit-user-select: none; user-select: none; -webkit-touch-callout: none;
}
.llegada__fila:active { transform: scale(.995); }
.llegada__fila:focus-visible { outline: 3px solid var(--azul); outline-offset: 2px; }
.llegada__fila[data-estado="presente"] { background: var(--c-deportes-bg, #e8f5de); border-color: var(--verde); }
/* Mientras viaja el toque: a medias, y no se vuelve a tocar. */
.llegada__fila[aria-busy="true"] { opacity: .55; }
.llegada__quien { min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.llegada__quien strong { font-size: 16px; line-height: 1.25; }
.llegada__quien .meta {
  display: flex; flex-wrap: wrap; align-items: center; gap: 4px 6px;
  margin: 0; font-size: 13.5px;
}
.llegada__marca {
  flex: 0 0 auto; display: inline-flex; align-items: center; gap: 5px;
  font-weight: 700; font-size: 14px; color: var(--muted); white-space: nowrap;
}
.llegada__fila[data-estado="presente"] .llegada__marca { color: #2b6416; }
/* «No se ha guardado, toca otra vez»: en rojo y a dos líneas si hace falta. */
.llegada__fila--error .llegada__marca { color: var(--rojo); white-space: normal; text-align: right; }
/* `hidden` tiene que ganarle al `display` de estas piezas: es como las
   esconden el buscador, el filtro y el refresco. */
.llegada__fila[hidden], .llegada__cierre[hidden], .llegada__margen[hidden],
#llegada-aviso[hidden], .llegada__bloque[hidden] { display: none; }

/* «Sin reserva para hoy», plegado: no es la lista, es por si aparecen. */
.llegada__bloque { margin: 18px 0; }
.llegada__bloque > summary {
  display: flex; align-items: center; flex-wrap: wrap; gap: 6px; min-height: 44px;
  font-weight: 700; font-size: 15px; cursor: pointer;
}
.llegada__bloque > summary .meta { font-weight: 500; margin: 0; }
.llegada__bloque > .meta { margin: 0 0 8px; }

/* Lo anotado hoy fuera de lista. */
.llegada__fuera { display: flex; flex-direction: column; gap: 2px; padding: 12px 14px; margin-bottom: 8px; }
.llegada__fuera .meta { margin: 0; }
.llegada__fuera a { color: var(--azul-deep); font-weight: 600; }

/* Lista normal: el guardado de cada toque, bajo el nombre. Con su propia
   clase porque `.asistencia__quien .meta` es rojo (es la línea de alergias). */
.asistencia__quien .asistencia__guardado { color: var(--muted); font-size: 13px; margin-top: 2px; }
.asistencia__quien .asistencia__guardado:empty { display: none; }
.asistencia__quien .asistencia__guardado--error { color: var(--rojo); font-weight: 600; }
.asistencia--enviando { opacity: .6; }

/* ==========================================================================
   Viaje de fin de curso (06/10/2026)
   ========================================================================== */
/* Un campo de varias opciones con su rótulo (`casillas()` y `opciones()` de
   _macros.html, que llevan `.campo--grupo`): el fieldset sin el marco del
   navegador, y la leyenda con el aire del rótulo de un campo. Acotado a
   `.campo--grupo` a propósito: `estrellas_elegir()` también es un
   `fieldset.campo` y tiene sus propias reglas (`.estrellas-elegir`). */
fieldset.campo--grupo { border: 0; padding: 0; margin: 0 0 16px; min-width: 0; }
fieldset.campo--grupo > legend { font-weight: 700; font-size: 14px; margin-bottom: 6px; padding: 0; }
.form--compacto fieldset.campo--grupo > legend { font-size: 13.5px; margin-bottom: 4px; }
/* Con error, la leyenda en rojo como el rótulo de `campo()`. */
fieldset.campo--grupo.campo--error > legend { color: var(--rojo-deep); }
/* La ayuda del grupo va entre la leyenda y las opciones: sin el margen de
   arriba de la de un campo (`.campo .ayuda`; con `.campo` en el selector para
   pesar más que la del formulario compacto, y detrás de `.campo--grupo` para
   no tocar a `estrellas_elegir()`) y con aire hasta las opciones. Y la lista
   de casillas, sin su margen de debajo: el del grupo ya lo trae. */
fieldset.campo--grupo.campo > .ayuda { margin: 0 0 8px; }
fieldset.campo--grupo > .lista-check { margin-bottom: 0; }

/* Un aviso sobre el campo de justo encima (en los campos de una plaza, el
   curso que no es del viaje): pegado a él y con su aire hasta lo siguiente,
   como la ayuda de un campo, no como un aviso suelto de la pantalla. */
.aviso--campo { margin: -4px 0 16px; }

/* La nota de un bloque de campos, justo debajo de su rótulo (`.grupo-campos`):
   para qué son esos datos y quién los ve (la salud, en los campos de una
   plaza). Va con `.meta`; esto solo le da su aire hasta el primer campo. */
.grupo-campos__nota { margin-bottom: 14px; }

/* Notas y pies del portal del viaje (07/10/2026): lo que sus pantallas llevaban
   escrito a mano (`style=`), con nombre y con su ejemplo en la guía.
   La entradilla bajo la cabecera de la pantalla (`.saludo`), pegada a ella. */
.meta--intro { margin: -6px 0 14px; }
/* La nota que cierra una tarjeta, separada de lo de arriba. */
.meta--aparte { margin-top: 10px; }
/* La nota centrada bajo una acción («¿Ya tienes cuenta?», la de padre y madre). */
.meta--centro { margin: 10px 0 0; text-align: center; }
/* La nota pegada debajo de una tabla, que habla de ella (en Cobros hechos,
   dónde se concilia el viaje, bajo la tabla de las pasarelas). No es
   `.meta--intro`, que es la entradilla bajo la cabecera de una pantalla. */
.meta--pie-tabla { margin: 8px 0 16px; }
/* El pie de una ficha: su acción secundaria (quitar la inscripción) o su nota. */
.pie-ficha { margin-top: 22px; text-align: center; }
/* Un texto largo de la oficina (la descripción del viaje), con sus saltos de línea. */
.tarjeta--texto { white-space: pre-line; }
/* El texto que se acepta, justo encima de su casilla. */
.tarjeta--autorizacion > p { margin: 0 0 8px; }
/* Los pagos del portal del viaje (10/10/2026). En «Pagos», cada niño es una
   tarjeta: su nombre arriba (esto), cómo va su pago en una línea `.meta` y sus
   plazos con las líneas de siempre (`.cobro__lineas` y `.pago`). La pantalla
   de pagar no necesita nada nuevo: lo de hoy es un cobro (`.cobro__cab`). */
.plazos__nombre { display: block; font-size: 17px; line-height: 1.25; }

/* ==========================================================================
   Piezas de la ficha del panel (Gestión → Viajes, 06/10/2026)
   --------------------------------------------------------------------------
   Nacieron en las pantallas del viaje y valen para cualquier ficha. Están en
   la guía de estilos (`/gestion/estilos`, «Tarjetas y bloques»): si una
   pantalla necesita lo mismo, se usan, no se escriben otra vez a mano.
   ========================================================================== */

/* Una línea de ficha: lo que se sabe, a la izquierda (una etiqueta y su
   frase), y su acción al final. Es la fila de una tabla con su icono para
   cuando es un solo dato y no merece tabla. Si no cabe, la acción baja en vez
   de apretar el texto. */
.ficha__linea { display: flex; align-items: center; flex-wrap: wrap; gap: 8px 12px; }
.ficha__linea > .meta { flex: 1 1 260px; min-width: 0; margin: 0; }

/* Un enlace que se copia: el texto, seleccionable de un clic, y su botón. En
   el enlace que se imprime en un cartel importa que se copie entero. */
.enlace-copiable { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; margin-top: 12px; }
.enlace-copiable code {
  padding: 8px 12px; border-radius: 10px; font-size: 14px;
  background: var(--white); border: 1.5px solid var(--line);
  overflow-wrap: anywhere; user-select: all;
}

/* Un campo y su botón en la misma línea (subir un fichero, cambiar una cosa).
   Alinea por abajo y sin el margen del campo: con él, el botón quedaba por
   debajo del campo, a la altura de su margen. */
.form-en-linea { display: flex; align-items: flex-end; flex-wrap: wrap; gap: 8px 12px; margin-top: 10px; }
.form-en-linea .campo { flex: 1 1 240px; max-width: 480px; margin-bottom: 0; }

/* Un indicador que no llega a lo que debería (los inscritos frente a su
   mínimo): la cifra en el ámbar de «ojo, mira esto», el mismo de las
   etiquetas `et--revisar`, no en rojo, que es de error. */
.kpi--aviso b { color: var(--ambar-ink); }

/* Un indicador que lleva a su lista (los «Con algo pendiente» de un colegio
   del viaje, a la lista de niños con ese filtro): todo él es el enlace, sin
   subrayado ni el azul de los enlaces, y con el borde azul al pasar por
   encima o con el foco, para que se vea que se pulsa. Con `.kpi--aviso`, en
   ámbar como siempre. */
.kpi--enlace { text-decoration: none; color: inherit; }
.kpi--enlace:hover, .kpi--enlace:focus-visible { border-color: var(--azul); }

/* Un correo tal cual le llegará a la familia, en texto plano (la vista previa
   del «Ya podéis pagar» en Gestión → Viajes): con la pinta de un correo, el
   ancho de lectura y sus saltos de línea. El mismo aspecto que la vista
   previa de Preinscripciones. */
.previa-correo {
  white-space: pre-wrap; background: var(--c-academia-bg, #eef3fb);
  border-radius: 12px; padding: 16px 18px; font-size: 15px; line-height: 1.55;
  max-width: 62ch;
}

/* Varias acciones en la cabecera de una pantalla. La cabecera reparte a los
   extremos lo que le cuelga (`justify-content: space-between`): sueltas, tres
   acciones se iban una a cada lado del título. Envueltas, van juntas a la
   derecha y pasan de línea si no caben. */
.acciones-cabecera { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 8px 10px; }

/* La cabecera de una ficha (`.ficha__cabecera`) sin estilos sueltos: el nombre
   y su línea gris pegados y, debajo, juntas, las etiquetas de estado. En cada
   ficha se escribían a mano (`margin:0 0 2px`, `margin-top:6px`). */
.ficha__cabecera h2 { margin: 0 0 2px; }
.ficha__cabecera .meta { margin: 0; }
.ficha__etiquetas { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 6px; }

/* Datos largos de una ficha (`.datos-pares`): un correo se parte en vez de
   salirse de su columna, y un dato de texto libre —observaciones, una cláusula
   del documento— ocupa la fila entera y respeta sus saltos de línea. */
.datos-pares dd { overflow-wrap: break-word; }
.datos-pares .dato--ancho { grid-column: 1 / -1; }
.datos-pares .dato--ancho dd { white-space: pre-line; }

/* La explicación de una casilla. `campo()` pinta la casilla pero no su
   `description` (la `ayuda` de `campo()` solo sale en los campos que no son
   casillas), así que va en su propio párrafo justo debajo: en gris, pegada a la
   casilla de arriba y alineada con su texto, no con el cuadrado (26 px de
   cuadrado, 4 de margen y 12 de hueco). A la casilla que la lleva se le quita
   el alto mínimo y el margen de debajo (que son su aire hasta el campo
   siguiente): sin eso la explicación quedaba a más de 30 px de lo que explica. */
.ayuda-casilla { margin: 0 0 12px 42px; color: var(--muted); font-size: 13px; }
.form--compacto .ayuda-casilla { font-size: 12.5px; }
.campo--check:has(+ .ayuda-casilla) { min-height: 0; margin-bottom: 0; padding-bottom: 2px; }
/* Con error, `campo()` pinta el aviso de la casilla (`ul.errores`) entre ella y
   su explicación, y FUERA de su `.campo`: sin los estilos de los avisos de los
   demás campos (salía con viñetas y en el color del texto). Aquí se le dan —solo
   al que precede a una explicación— y se sangran, él y la explicación, 13 px
   más: la casilla con error lleva una raya roja de 3 px y 10 de sangría
   (`.campo--error.campo--check`) que le empujan el texto. */
.errores:has(+ .ayuda-casilla) {
  margin: 0 0 2px 55px; padding: 0; list-style: none;
  color: var(--rojo-deep); font-size: 13.5px;
}
.errores + .ayuda-casilla { margin-left: 55px; }
.campo--check:has(+ .errores + .ayuda-casilla) { min-height: 0; margin-bottom: 0; padding-bottom: 2px; }

/* La explicación de una fila de campos (`.form-fila`), a todo su ancho y justo
   debajo de la rejilla. Como `ayuda` de uno de sus campos se estrechaba a su
   columna y, si era larga, alargaba solo esa columna y desequilibraba la fila
   (el mínimo de un colegio del viaje). Pegada a los campos de arriba (les
   quita la mitad de su margen) y con su aire hasta lo siguiente. */
.ayuda-fila { margin: -6px 0 14px; color: var(--muted); font-size: 13px; line-height: 1.45; }
.form--compacto .ayuda-fila { font-size: 12.5px; }

/* ==========================================================================
   Portal del monitor: el viaje de fin de curso (11/10/2026)
   --------------------------------------------------------------------------
   Lo que la ficha de una plaza del viaje llevaría escrito a mano (`style=`),
   con nombre y con su ejemplo en la guía. Los datos van en `.datos-pares` y
   no en `.pago`: en el portal del monitor no se enseña nada de pagos, y ni la
   clase tiene que sugerirlo.
   ========================================================================== */

/* El título de una tarjeta de ficha («En el viaje», «Teléfonos»), con su
   icono. Con `.txt-error`, en rojo («Atención médica»). Va detrás de
   `.txt-error` para que el peso sea el del título. */
.tarjeta__titulo {
  display: flex; align-items: center; gap: 6px;
  margin: 0 0 12px; font-family: inherit; font-size: 17px; font-weight: 700; line-height: 1.25;
}

/* Un dato que se dicta o se copia entero (el número de la tarjeta sanitaria,
   un DNI): con letra de ancho fijo, para compararlo carácter a carácter, y
   seleccionado entero de un toque. */
.copiable {
  font-family: ui-monospace, "Cascadia Mono", Consolas, monospace;
  font-size: 15px; letter-spacing: .5px; overflow-wrap: anywhere;
  -webkit-user-select: all; user-select: all;
}

/* ==========================================================================
   La hoja para imprimir (11/10/2026)
   --------------------------------------------------------------------------
   Una lista en papel, en página suelta (sin menú): la del viaje en el portal
   del monitor (`monitores/viaje_imprimir.html`). En pantalla es un folio
   blanco sobre el lienzo, con su botón de imprimir; en el papel, solo la
   tabla: sin botones, sin marco, sin fondos de color (salvo la fila de
   cabeceras, que se fuerza a imprimir), y cada fila entera en su hoja.
   Lo médico va en rojo y en negrita: en una impresora en blanco y negro,
   la negrita es lo que se ve. Con letra del sistema a propósito, como la hoja
   de un grupo en Gestión: la página no carga `fuentes.css`.
   ========================================================================== */
.hoja-impresa {
  max-width: 1000px; margin: 16px auto; padding: 24px;
  background: var(--surface); color: var(--ink);
  border: 1px solid var(--line); border-radius: var(--r-sm);
  font-size: 13px; line-height: 1.4;
}
/* Imprimir y Volver: solo en pantalla. */
.hoja-impresa__acciones { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin-bottom: 18px; }
.hoja-impresa__cab {
  display: flex; justify-content: space-between; align-items: flex-start; gap: 20px;
  border-bottom: 2px solid var(--ink); padding-bottom: 12px; margin-bottom: 18px;
}
.hoja-impresa__cab h1 { font-family: var(--font-display); font-size: 22px; margin: 0; }
.hoja-impresa__lado { text-align: right; font-size: 13px; }
.hoja-impresa__logo { display: block; height: 28px; width: auto; margin-left: auto; }
/* La tabla, en su contenedor: en el móvil (390 px) la tabla mide más que la
   hoja, y sin esto ensanchaba la página entera. Con `overflow-x: auto` se
   desplaza ella sola. En papel no cambia nada (ver `@media print`). */
.hoja-impresa__tabla { overflow-x: auto; }
.hoja-impresa table { width: 100%; border-collapse: collapse; font-size: 12.5px; }
.hoja-impresa th, .hoja-impresa td {
  border: 1px solid var(--line); padding: 6px 7px; text-align: left; vertical-align: top;
}
.hoja-impresa th {
  background: var(--c-academia-bg); font-size: 11px; text-transform: uppercase; letter-spacing: .03em;
}
.hoja-impresa__n { width: 28px; }
/* Texto escrito por una familia: respeta sus saltos de línea y no revienta la
   columna con un número largo. Con `break-word` y no `anywhere`: este último
   encoge el ancho mínimo de la columna y la tabla las aprieta hasta partir
   «celiaquía» en dos líneas. */
.hoja-impresa td > div { white-space: pre-line; overflow-wrap: break-word; }
/* Lo que se dicta o se marca de una vez y no se parte en dos líneas: un
   teléfono, el número de la tarjeta sanitaria. Con `td >` para ganar a la
   regla de arriba, que es la de los textos libres. */
.hoja-impresa td > .hoja-impresa__entero { white-space: nowrap; }
.hoja-impresa__medico { color: var(--rojo-deep); font-weight: 700; }
.hoja-impresa__pie { margin: 14px 0 0; font-size: 11.5px; color: var(--muted); }
@media print {
  /* El lienzo azul de detrás no se imprime aunque el navegador imprima fondos. */
  html:has(> body > .hoja-impresa), body:has(> .hoja-impresa) { background: none; }
  .hoja-impresa { max-width: none; margin: 0; padding: 0; border: 0; border-radius: 0; background: none; }
  .hoja-impresa__acciones { display: none; }
  .hoja-impresa__tabla { overflow: visible; }
  .hoja-impresa th { -webkit-print-color-adjust: exact; print-color-adjust: exact; }
  .hoja-impresa tr { page-break-inside: avoid; break-inside: avoid; }
}
