/*
 * rf-componentes.css — el catálogo del capítulo 4 del documento 03 (P2.5 las piezas mínimas de los tres layouts,
 * P7.1 el catálogo entero; revisión 4.5, P7.10: cada pieza con el aspecto del patrón visual de §15). La guía viva
 * de TODO lo de aquí, en todos sus estados, está en /admin/dev/estilo, y la referencia visual es
 * design/patron-visual/ (patron.css y prototipo.html).
 *
 * El patrón, en cinco reglas que se leen en cada bloque de abajo (§1.3 regla 8, §2.5, §15.2):
 *   · Papel, no pantalla: las superficies blancas solo en lo que se rellena o se pulsa; lo demás se separa con filetes.
 *   · Un color de marca (violeta, primario-700) para la acción principal, los enlaces y lo activo; lo ELEGIDO se rellena
 *     de tinta (chip, día, turno, marcador).
 *   · Esquinas discretas: 6 en controles, 10 en fotos y bloques, 14 en hojas; la píldora solo en el corazón, el avatar
 *     y las agrupaciones del mapa.
 *   · Nada flota en reposo: sin sombra salvo lo que flota de verdad (menús, hojas, modales, marcadores, avisos
 *     emergentes).
 *   · Cero degradados (salvo el brillo del esqueleto), cero círculos decorativos, cero mayúsculas espaciadas.
 *
 * Ningún color, sombra ni familia escritos a mano: solo las variables de rf-tokens.css (lo vigila
 * convenciones/PatronVisualTest, con su lista cerrada de excepciones). Un velo o un color translúcido se escribe con
 * `color-mix()` sobre un token, nunca con `rgba()`.
 */

/* ============================================================================================
   §4.1 Acciones — botones. Radio md (6 px), sin sombra ni degradado, texto en la familia de texto y
   nunca en mayúsculas. Un solo botón principal por vista.
   ============================================================================================ */
.rf-boton {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--rf-espacio-2);
  min-height: 48px;
  padding: 0 var(--rf-espacio-5);
  border-radius: var(--rf-radio-md);
  font-family: var(--rf-fuente-texto-pila);
  font-size: var(--rf-tipo-cuerpo-movil-tamano);
  font-weight: 600;
  line-height: 1.2;
  text-decoration: none;
  border: 1px solid transparent;
  cursor: pointer;
  transition: background-color var(--rf-duracion-rapida) var(--rf-curva-entrada),
              border-color var(--rf-duracion-rapida) var(--rf-curva-entrada);
}
.rf-boton:hover { text-decoration: none; }
/* Principal: violeta con texto blanco (7,10:1); al pasar, 800; pulsado, 900. */
.rf-boton-principal { background: var(--rf-color-primario-700); color: var(--rf-color-neutro-0); }
.rf-boton-principal:hover { background: var(--rf-color-primario-800); color: var(--rf-color-neutro-0); }
.rf-boton-principal:active { background: var(--rf-color-primario-900); }
/* Secundario: sin fondo, borde de 1 px de tinta y texto tinta; al pasar, papel 100. Es la acción de cada fila del
   panel del proveedor («Ver y responder», «Ha llegado»). */
.rf-boton-secundario { background: transparent; color: var(--rf-texto); border-color: var(--rf-color-neutro-900); }
.rf-boton-secundario:hover { background: var(--rf-color-neutro-100); color: var(--rf-texto); }
/* Texto: violeta subrayado a 3 px de la base, sin borde; para lo terciario («Cambiar el día»). */
.rf-boton-texto {
  background: transparent;
  color: var(--rf-color-primario-700);
  padding-inline: var(--rf-espacio-2);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
}
.rf-boton-texto:hover { color: var(--rf-color-primario-800); text-decoration: underline; text-decoration-thickness: 2px; }
/* Acento: oro con texto TINTA (9,30:1; nunca blanco sobre acento-400, §2.3). Solo la llamada a proveedores y
   las promociones. */
.rf-boton-acento { background: var(--rf-color-acento-400); color: var(--rf-color-neutro-900); }
.rf-boton-acento:hover { background: var(--rf-color-acento-100); border-color: var(--rf-color-acento-600); color: var(--rf-color-neutro-900); }
/* Destructivo: texto y borde de error; pasa a relleno solo dentro del diálogo de confirmación (.rf-modal-destructivo). */
.rf-boton-destructivo { background: transparent; color: var(--rf-color-semantico-error-texto); border-color: var(--rf-color-semantico-error-texto); }
.rf-boton-destructivo:hover { background: var(--rf-color-semantico-error-fondo); color: var(--rf-color-semantico-error-texto); }
.rf-boton-bloque { width: 100%; }
/* Densidad compacta (backoffice, filas de tabla): 40 px. */
.rf-boton-compacto { min-height: 40px; padding-inline: var(--rf-espacio-4); font-size: var(--rf-tipo-pequeno-movil-tamano); }

.rf-boton:disabled,
.rf-boton[aria-disabled="true"] { opacity: .4; cursor: not-allowed; pointer-events: none; }
/* Cargando: el texto se esconde y queda un indicador que gira; no se puede pulsar dos veces. */
.rf-boton[aria-busy="true"] {
  position: relative;
  color: transparent !important;
  pointer-events: none;
}
.rf-boton[aria-busy="true"]::after {
  content: "";
  position: absolute;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  border: 2px solid color-mix(in srgb, var(--rf-color-neutro-0) 50%, transparent);
  border-top-color: var(--rf-color-neutro-0);
  animation: rf-girar .7s linear infinite;
}
.rf-boton-secundario[aria-busy="true"]::after,
.rf-boton-texto[aria-busy="true"]::after,
.rf-boton-acento[aria-busy="true"]::after,
.rf-boton-destructivo[aria-busy="true"]::after {
  border-color: color-mix(in srgb, var(--rf-color-neutro-900) 25%, transparent);
  border-top-color: var(--rf-color-neutro-900);
}
@keyframes rf-girar { to { transform: rotate(360deg); } }

/* Botón de icono: 44 × 44, radio md, borde papel 400; sobre una foto, sin borde y con fondo blanco al 90 %. Nombre
   accesible obligatorio (lo lleva el aria-label de la plantilla). */
.rf-boton-icono {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  min-height: 44px;
  padding: 0;
  border-radius: var(--rf-radio-md);
  border: 1px solid var(--rf-color-neutro-400);
  background: var(--rf-superficie);
  color: var(--rf-texto);
  cursor: pointer;
  text-decoration: none;
}
.rf-boton-icono:hover { background: var(--rf-color-neutro-100); color: var(--rf-texto); }

/* Corazón de favorito (§4.1): sobre la foto, blanco al 90 % —es una de las tres píldoras permitidas—; activo, relleno
   de error con una pequeña escala de 120 ms. */
.rf-favorito {
  position: absolute;
  top: var(--rf-espacio-2);
  right: var(--rf-espacio-2);
  width: 36px;
  height: 36px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--rf-radio-pildora);
  border: none;
  background: color-mix(in srgb, var(--rf-color-neutro-0) 90%, transparent);
  color: var(--rf-color-neutro-900);
  cursor: pointer;
  z-index: 1;
}
.rf-favorito .rf-icono { width: 18px; height: 18px; transition: transform var(--rf-duracion-rapida) var(--rf-curva-entrada); }
.rf-favorito[aria-pressed="true"] { color: var(--rf-color-semantico-error-texto); }
.rf-favorito[aria-pressed="true"] .rf-icono { fill: currentColor; transform: scale(1.15); }
/* El corazón que guarda (P10.3) va dentro de un formulario: el formulario no ocupa sitio, el botón sigue sobre la foto. */
.rf-favorito-formulario { display: contents; margin: 0; }

/* ============================================================================================
   Iconos (§3.1, revisión 4.5; cierra D-73): una familia, Lucide, del sprite /img/iconos/lucide.svg
   (fragments/icono). Trazo 1,75, extremos redondos, sin relleno; el color es el del texto. Nunca
   dentro de un círculo o un cuadrado pastel: el icono va desnudo junto al texto.
   ============================================================================================ */
.rf-icono {
  width: 20px;
  height: 20px;
  flex-shrink: 0;
  stroke: currentColor;
  fill: none;
  stroke-width: 1.75;
  stroke-linecap: round;
  stroke-linejoin: round;
  vertical-align: -0.2em;
}
.rf-icono-pequeno { width: 16px; height: 16px; }
.rf-icono-24 { width: 24px; height: 24px; }
.rf-icono-grande { width: 32px; height: 32px; }

/* Ilustraciones de línea (§3.2): el mismo trazo, en tinta con un toque de acento (o de violeta); solo en el estado vacío,
   la confirmación, las páginas de error y el correo. El toque de color llega al símbolo por la variable. */
.rf-ilustracion {
  width: 96px;
  height: 96px;
  flex-shrink: 0;
  color: var(--rf-texto);
  --rf-ilustracion-acento: var(--rf-color-acento-600);
}
.rf-ilustracion-marca { --rf-ilustracion-acento: var(--rf-color-primario-700); }

/* ============================================================================================
   §4.5 Aviso (emergente y banda) y respuesta del sistema: el fondo semántico con el texto de su par,
   un filete de 3 px del mismo color a la izquierda y siempre icono y texto además del color (§11).
   ============================================================================================ */
.rf-aviso {
  display: flex;
  align-items: flex-start;
  gap: var(--rf-espacio-3);
  padding: var(--rf-espacio-3) var(--rf-espacio-4);
  border-radius: var(--rf-radio-md);
  border-left: 3px solid currentColor;
  font-size: var(--rf-tipo-pequeno-movil-tamano);
  line-height: var(--rf-tipo-pequeno-movil-interlinea);
}
.rf-aviso-icono { flex-shrink: 0; font-weight: 700; }
.rf-aviso .rf-aviso-icono.rf-icono { margin-top: 0; }
.rf-aviso-exito { background: var(--rf-color-semantico-exito-fondo); color: var(--rf-color-semantico-exito-texto); }
.rf-aviso-aviso { background: var(--rf-color-semantico-aviso-fondo); color: var(--rf-color-semantico-aviso-texto); }
.rf-aviso-error { background: var(--rf-color-semantico-error-fondo); color: var(--rf-color-semantico-error-texto); }
.rf-aviso-info  { background: var(--rf-color-semantico-info-fondo);  color: var(--rf-color-semantico-info-texto); }
.rf-aviso a { color: inherit; font-weight: 600; }
.rf-aviso .rf-boton-icono { margin-left: auto; width: 32px; height: 32px; min-height: 32px; border: 0; background: transparent; color: inherit; }

/* ============================================================================================
   Migas de pan (documento 03 §6, admin.html "migas de pan").
   ============================================================================================ */
.rf-migas {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--rf-espacio-1);
  margin: 0 0 var(--rf-espacio-4);
  padding: 0;
  list-style: none;
  font-size: var(--rf-tipo-pequeno-movil-tamano);
  color: var(--rf-texto-secundario);
}
.rf-migas li { display: flex; align-items: center; gap: var(--rf-espacio-1); }
.rf-migas li:not(:last-child)::after { content: "/"; color: var(--rf-color-neutro-400); margin-left: var(--rf-espacio-1); }
.rf-migas a { color: var(--rf-texto-secundario); text-decoration: none; }
.rf-migas a:hover { color: var(--rf-primario); text-decoration: underline; }
.rf-migas [aria-current="page"] { color: var(--rf-texto); font-weight: 600; }

/* ============================================================================================
   Paginación (documento 03 §4.5 "Tabla", que remite a esta pieza para recorrer páginas largas):
   la página actual se rellena de tinta, como todo lo elegido.
   ============================================================================================ */
.rf-paginacion {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--rf-espacio-1);
  margin: var(--rf-espacio-6) 0 0;
  padding: 0;
  list-style: none;
}
.rf-paginacion a,
.rf-paginacion span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 44px;
  min-height: 44px;
  padding: 0 var(--rf-espacio-2);
  border-radius: var(--rf-radio-md);
  text-decoration: none;
  color: var(--rf-texto);
}
.rf-paginacion a:hover { background: var(--rf-color-neutro-100); color: var(--rf-texto); }
.rf-paginacion [aria-current="page"] { background: var(--rf-color-neutro-900); color: var(--rf-color-neutro-0); font-weight: 600; }
.rf-paginacion .rf-paginacion-inactivo { color: var(--rf-color-neutro-400); }

/* ============================================================================================
   §4.2 Formularios. Etiqueta siempre visible encima; campo de 48 px, radio md, blanco sobre el papel,
   borde papel 400 (3,47:1: el de los controles; nunca papel 300, §2.3); foco con borde violeta y
   anillo; error con borde y mensaje en rojo MÁS un icono (nunca solo color, §11).
   ============================================================================================ */
.rf-campo { display: flex; flex-direction: column; gap: 6px; margin-bottom: var(--rf-espacio-4); }
.rf-campo-etiqueta { font-size: var(--rf-tipo-pequeno-movil-tamano); font-weight: 600; color: var(--rf-texto); }
.rf-campo-control {
  /* Un campo nunca es más ancho que su columna (WCAG 1.4.10): el de fichero mide por su texto («Seleccionar archivo…»). */
  min-width: 0;
  max-width: 100%;
  min-height: 48px;
  padding: 0 var(--rf-espacio-3);
  border: 1px solid var(--rf-color-neutro-400);
  border-radius: var(--rf-radio-md);
  font-family: var(--rf-fuente-texto-pila);
  font-size: var(--rf-tipo-cuerpo-movil-tamano);
  background: var(--rf-superficie);
  color: var(--rf-texto);
}
textarea.rf-campo-control { padding-block: var(--rf-espacio-3); }
/* El campo de fichero mide lo que su texto («Seleccionar archivo · No se ha seleccionado ningún archivo» en Chrome en
   castellano, 414 px) y ensanchaba la columna a 320 y 360 px (WCAG 1.4.10): con el ancho en porcentaje, cede. */
input[type="file"].rf-campo-control { width: 100%; padding-block: var(--rf-espacio-2); }
.rf-campo-control::placeholder { color: var(--rf-color-neutro-500); }
.rf-campo-control:focus {
  border-color: var(--rf-color-primario-700);
  outline: 3px solid var(--rf-color-primario-500);
  outline-offset: 1px;
}
.rf-campo-ayuda { font-size: var(--rf-tipo-pequeno-movil-tamano); color: var(--rf-texto-secundario); }
/* «Mostrar la contraseña» (mejoras v5, M-163): a su tamaño, bajo el campo; oculto hasta que rf-form.js lo destapa (el
   `display` de .rf-boton ganaría al `hidden` del navegador). */
.rf-campo-mostrar { align-self: flex-start; }
.rf-campo-mostrar[hidden] { display: none; }
.rf-campo-error-control { border-color: var(--rf-color-semantico-error-texto); }
.rf-campo-error-mensaje {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: var(--rf-tipo-pequeno-movil-tamano);
  color: var(--rf-color-semantico-error-texto);
}
.rf-campo-etiqueta-requerido { color: var(--rf-color-semantico-error-texto); }

/* La tira de campos (§4.2): los campos que van juntos («dónde · cuándo · cuántos») se dibujan como UNA tira con un
   borde de tinta y filetes verticales entre ellos, no como campos sueltos dentro de una tarjeta. En el móvil, los
   filetes son horizontales. El botón de la tira va pegado al final, en violeta. */
.rf-tira {
  display: grid;
  grid-template-columns: 1fr;
  border: 1px solid var(--rf-color-neutro-900);
  border-radius: var(--rf-radio-lg);
  background: var(--rf-superficie);
  overflow: hidden;
}
.rf-tira-campo {
  display: grid;
  gap: 2px;
  padding: var(--rf-espacio-3) var(--rf-espacio-4);
  border-bottom: 1px solid var(--rf-filete);
  margin: 0;
}
.rf-tira-etiqueta { font-size: var(--rf-tipo-etiqueta-movil-tamano); font-weight: 600; color: var(--rf-texto-secundario); }
.rf-tira-control {
  border: 0;
  padding: 0;
  min-height: 28px;
  background: transparent;
  color: var(--rf-texto);
  font-family: var(--rf-fuente-texto-pila);
  font-size: var(--rf-tipo-cuerpo-movil-tamano);
  width: 100%;
}
.rf-tira-control::placeholder { color: var(--rf-color-neutro-500); }
.rf-tira-control:focus { outline: none; }
.rf-tira-campo:focus-within { outline: 3px solid var(--rf-color-primario-500); outline-offset: -3px; }
.rf-tira-boton {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--rf-espacio-2);
  min-height: 52px;
  padding: 0 var(--rf-espacio-6);
  border: 0;
  background: var(--rf-color-primario-700);
  color: var(--rf-color-neutro-0);
  font: inherit;
  font-weight: 600;
  cursor: pointer;
}
.rf-tira-boton:hover { background: var(--rf-color-primario-800); }
@media (min-width: 768px) {
  .rf-tira { grid-template-columns: repeat(var(--rf-tira-campos, 3), minmax(0, 1fr)) auto; }
  .rf-tira-campo { border-bottom: 0; border-right: 1px solid var(--rf-filete); }
  .rf-tira-campo:last-of-type { border-right: 0; }
}

.rf-area-texto {
  min-height: 110px;
  padding: var(--rf-espacio-3);
  border: 1px solid var(--rf-color-neutro-400);
  border-radius: var(--rf-radio-md);
  font-family: var(--rf-fuente-texto-pila);
  font-size: var(--rf-tipo-cuerpo-movil-tamano);
  color: var(--rf-texto);
  background: var(--rf-superficie);
  resize: vertical;
}
.rf-area-texto:focus { border-color: var(--rf-color-primario-700); outline: 3px solid var(--rf-color-primario-500); outline-offset: 1px; }
.rf-area-texto-contador { display: flex; justify-content: flex-end; font-size: var(--rf-tipo-pequeno-movil-tamano); color: var(--rf-texto-secundario); }
.rf-area-texto-contador[data-rf-limite-superado] { color: var(--rf-color-semantico-error-texto); }

/* `rf-campo-input` y `rf-campo-texto` (la ficha, la denuncia, el contacto) son el mismo campo con otro nombre: hasta P7.11
   se quedaban sin estilo y se pintaban como el control del navegador, de 24 px. */
.rf-campo-select,
.rf-campo-fecha,
.rf-campo-hora,
.rf-campo-buscable,
.rf-campo-input,
.rf-campo-texto {
  min-height: 48px;
  width: 100%;
  padding: 0 var(--rf-espacio-3);
  border: 1px solid var(--rf-color-neutro-400);
  border-radius: var(--rf-radio-md);
  font-size: var(--rf-tipo-cuerpo-movil-tamano);
  font-family: var(--rf-fuente-texto-pila);
  background: var(--rf-superficie);
  color: var(--rf-texto);
}
.rf-campo-select:focus,
.rf-campo-fecha:focus,
.rf-campo-hora:focus,
.rf-campo-buscable:focus,
.rf-campo-input:focus,
.rf-campo-texto:focus { border-color: var(--rf-color-primario-700); outline: 3px solid var(--rf-color-primario-500); outline-offset: 1px; }
/* Fecha y hora: con el teclado, el foco lo recibe cada parte (día, mes, año) dentro del campo y el propio campo no
   casa con :focus en Chromium; sin esto el anillo no se veía (medido en P7.8, WCAG 2.4.7). */
.rf-campo-fecha:focus-within,
.rf-campo-hora:focus-within { border-color: var(--rf-color-primario-700); outline: 3px solid var(--rf-color-primario-500); outline-offset: 1px; }

.rf-casilla,
.rf-opcion-radio {
  display: flex;
  align-items: flex-start;
  gap: var(--rf-espacio-2);
  min-height: 44px;
  padding-block: var(--rf-espacio-1);
}
.rf-casilla input,
.rf-opcion-radio input {
  width: 20px;
  height: 20px;
  margin-top: 2px;
  accent-color: var(--rf-color-primario-700);
  flex-shrink: 0;
}
.rf-casilla label,
.rf-opcion-radio label { cursor: pointer; }

/* Interruptor: casilla nativa con role="switch" (documento 03 §4.2). Sigue siendo un <input type="checkbox"> de verdad:
   teclado, lector de pantalla y estado gratis. Revisión 4.5: rectángulo de esquinas discretas, no píldora; encendido,
   violeta. */
.rf-interruptor { display: inline-flex; align-items: center; gap: var(--rf-espacio-2); min-height: 44px; }
.rf-interruptor input[type="checkbox"] {
  appearance: none;
  -webkit-appearance: none;
  width: 44px;
  height: 24px;
  border-radius: var(--rf-radio-md);
  border: 1px solid var(--rf-color-neutro-400);
  background: var(--rf-color-neutro-200);
  position: relative;
  cursor: pointer;
  flex-shrink: 0;
  transition: background-color var(--rf-duracion-rapida) var(--rf-curva-entrada);
}
.rf-interruptor input[type="checkbox"]::after {
  content: "";
  position: absolute;
  top: 2px;
  left: 2px;
  width: 18px;
  height: 18px;
  border-radius: var(--rf-radio-sm);
  background: var(--rf-color-neutro-0);
  border: 1px solid var(--rf-color-neutro-400);
  transition: transform var(--rf-duracion-rapida) var(--rf-curva-entrada);
}
.rf-interruptor input[type="checkbox"]:checked { background: var(--rf-color-primario-700); border-color: var(--rf-color-primario-700); }
.rf-interruptor input[type="checkbox"]:checked::after { transform: translateX(20px); border-color: var(--rf-color-primario-700); }
.rf-interruptor input[type="checkbox"]:focus-visible { outline: 3px solid var(--rf-color-primario-500); outline-offset: 2px; }

/* Contador de asistentes, control de hora extra, cantidad de un extra: mismo patrón (− valor +), botones cuadrados de
   esquinas discretas. */
.rf-contador { display: inline-flex; align-items: center; gap: var(--rf-espacio-3); }
.rf-contador-boton {
  width: 40px;
  height: 40px;
  min-width: 40px;
  border-radius: var(--rf-radio-md);
  border: 1px solid var(--rf-color-neutro-400);
  background: var(--rf-superficie);
  color: var(--rf-texto);
  font-size: 18px;
  line-height: 1;
  cursor: pointer;
}
.rf-contador-boton:hover:not(:disabled) { background: var(--rf-color-neutro-100); border-color: var(--rf-color-neutro-900); }
.rf-contador-boton:disabled { opacity: .4; cursor: not-allowed; }
.rf-contador-valor { min-width: 2.5em; text-align: center; font-weight: 600; font-variant-numeric: tabular-nums; }
.rf-contador-motivo { font-size: var(--rf-tipo-pequeno-movil-tamano); color: var(--rf-texto-secundario); }

/* Rango de precios: dos campos de importe dentro de un fieldset (evita un slider doble a medida,
   caro de hacer accesible por teclado bien; dos números nativos lo son de serie). */
.rf-rango-precios { display: flex; align-items: flex-end; gap: var(--rf-espacio-3); border: 0; padding: 0; margin: 0; }
.rf-rango-precios legend { font-size: var(--rf-tipo-pequeno-movil-tamano); font-weight: 600; margin-bottom: var(--rf-espacio-1); padding: 0; }
.rf-rango-precios .rf-campo { flex: 1 1 0; margin-bottom: 0; }
/* Un <fieldset> mide como mínimo su contenido (min-inline-size: min-content): con dos campos numéricos se salía
   de la pantalla a 640, 360 y 320 px (P14.4, WCAG 1.4.10). Sin mínimo y con los campos que se reparten el ancho. */
.rf-rango-precios { min-inline-size: 0; flex-wrap: wrap; }
.rf-rango-precios .rf-campo { min-width: 0; flex-basis: 8rem; }
.rf-rango-precios .rf-campo-control { width: 100%; min-width: 0; }

/* Campo de importe: euros arriba (lo que ve la persona), céntimos por debajo en un campo oculto que
   sincroniza rf-form.js (§4 de rf-form.js) — nunca se envían euros con coma al servidor. */
.rf-campo-importe { position: relative; }
.rf-campo-importe input { padding-right: calc(var(--rf-espacio-3) + 1.4em); }
.rf-campo-importe-simbolo {
  position: absolute;
  right: var(--rf-espacio-3);
  top: 50%;
  transform: translateY(-50%);
  color: var(--rf-texto-secundario);
  pointer-events: none;
}

/* Campo de teléfono con prefijo: dos controles, un solo rf-campo alrededor. */
.rf-campo-telefono { display: flex; gap: var(--rf-espacio-2); }
.rf-campo-telefono-prefijo {
  width: 84px;
  flex-shrink: 0;
  min-height: 48px;
  padding: 0 var(--rf-espacio-2);
  border: 1px solid var(--rf-color-neutro-400);
  border-radius: var(--rf-radio-md);
  background: var(--rf-superficie);
  color: var(--rf-texto);
}
.rf-campo-telefono input[type="tel"] { flex: 1 1 auto; }

/* Cargador de imágenes: arrastrar, progreso por fichero, reordenar, texto alternativo. Sin
   arrastrar-para-reordenar real (dependería de una librería): botones "Subir" / "Bajar", que
   funcionan igual de bien con teclado y no dependen de un gesto de arrastre (documento 03 §11
   "ninguna acción depende solo de arrastrar"). */
.rf-cargador {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--rf-espacio-2);
  min-height: 140px;
  padding: var(--rf-espacio-6);
  border: 1px dashed var(--rf-color-neutro-400);
  border-radius: var(--rf-radio-lg);
  color: var(--rf-texto-secundario);
  text-align: center;
  background: var(--rf-superficie);
}
.rf-cargador.rf-cargador-sobre { border-color: var(--rf-color-primario-700); background: var(--rf-color-primario-50); color: var(--rf-primario); }
.rf-cargador input[type="file"] { position: absolute; opacity: 0; width: 1px; height: 1px; overflow: hidden; }
.rf-cargador-icono { width: 32px; height: 32px; color: var(--rf-texto-secundario); }
.rf-cargador-lista { display: grid; gap: var(--rf-espacio-2); margin-top: var(--rf-espacio-3); width: 100%; }
.rf-cargador-fila {
  display: flex;
  align-items: center;
  gap: var(--rf-espacio-3);
  padding: var(--rf-espacio-2);
  border: 1px solid var(--rf-filete);
  border-radius: var(--rf-radio-md);
  background: var(--rf-superficie);
  text-align: left;
}
.rf-cargador-miniatura { width: 48px; height: 36px; border-radius: var(--rf-radio-sm); object-fit: cover; flex-shrink: 0; background: var(--rf-color-neutro-100); }
.rf-cargador-info { flex: 1 1 auto; min-width: 0; }
.rf-cargador-nombre { font-size: var(--rf-tipo-pequeno-movil-tamano); font-weight: 600; color: var(--rf-texto); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rf-cargador-progreso { height: 4px; border-radius: var(--rf-radio-xs); background: var(--rf-color-neutro-200); margin-top: var(--rf-espacio-1); overflow: hidden; }
.rf-cargador-progreso-relleno { height: 100%; background: var(--rf-color-primario-700); transition: width var(--rf-duracion-media) linear; }
.rf-cargador-acciones { display: flex; gap: var(--rf-espacio-1); flex-shrink: 0; }
.rf-cargador-alt { margin-top: var(--rf-espacio-1); }
.rf-cargador-alt input { width: 100%; min-height: 36px; padding: 0 var(--rf-espacio-2); border: 1px solid var(--rf-color-neutro-400); border-radius: var(--rf-radio-sm); font-size: var(--rf-tipo-pequeno-movil-tamano); }

/* ============================================================================================
   Chips, etiquetas, insignias y estado (§4.3, §4.5). El chip es un rectángulo de radio md con borde
   papel 400, 36 px de alto; ACTIVO: relleno tinta con texto blanco en 600 (lo activo es tinta, §15.2
   regla 10). El contador va en el mismo color al 75 %.
   ============================================================================================ */
.rf-chips { display: flex; flex-wrap: wrap; gap: var(--rf-espacio-2); }
.rf-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 36px;
  padding: 0 var(--rf-espacio-3);
  border-radius: var(--rf-radio-md);
  border: 1px solid var(--rf-color-neutro-400);
  background: transparent;
  color: var(--rf-texto);
  font-family: var(--rf-fuente-texto-pila);
  font-size: var(--rf-tipo-pequeno-movil-tamano);
  text-decoration: none;
  cursor: pointer;
}
.rf-chip:hover { background: var(--rf-color-neutro-100); color: var(--rf-texto); }
.rf-chip[aria-pressed="true"],
.rf-chip[aria-current="true"],
.rf-chip-activo {
  background: var(--rf-color-neutro-900);
  border-color: var(--rf-color-neutro-900);
  color: var(--rf-color-neutro-0);
  font-weight: 600;
}
.rf-chip-contador { font-size: var(--rf-tipo-etiqueta-movil-tamano); color: var(--rf-texto-secundario); }
/* En el chip activo, el contador en el blanco del texto al 80 % (sin `opacity`, que en otro fondo bajaría del 4,5:1). */
.rf-chip[aria-pressed="true"] .rf-chip-contador,
.rf-chip[aria-current="true"] .rf-chip-contador,
.rf-chip-activo .rf-chip-contador,
.rf-busqueda-opcion:has(input:checked) .rf-chip-contador { color: color-mix(in srgb, var(--rf-color-neutro-0) 80%, transparent); }
/* Chip de interpretación (§4.5): lo que el buscador entendió del texto libre, con borde discontinuo violeta y texto en
   violeta, y su aspa para devolverlo al texto. */
.rf-chip-interpretado { border-style: dashed; border-color: var(--rf-color-primario-500); color: var(--rf-primario); background: transparent; }
.rf-chip-interpretado button,
.rf-chip-interpretado a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: none;
  background: none;
  color: inherit;
  cursor: pointer;
  padding: 0;
  margin-left: 2px;
  min-width: 24px;
  min-height: 24px;
  text-decoration: none;
}

/* Etiqueta de categoría (§2.2 y §4.3): el par fondo/texto llega POR DATOS (`category.tint_bg`/`tint_fg`, D-74, D-1715),
   nunca como clase CSS por categoría. Rectangular de radio sm, 13/600, sin mayúsculas. */
.rf-etiqueta-categoria {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 2px var(--rf-espacio-2);
  border-radius: var(--rf-radio-sm);
  font-size: var(--rf-tipo-etiqueta-movil-tamano);
  line-height: var(--rf-tipo-etiqueta-movil-interlinea);
  font-weight: var(--rf-tipo-etiqueta-peso);
}

/* Etiqueta de estado (§4.5): punto de 8 px y texto en 600 del mismo color, SIN píldora ni fondo; siempre con texto. */
.rf-etiqueta-estado,
.rf-estado {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: var(--rf-tipo-pequeno-movil-tamano);
  font-weight: 600;
}
.rf-etiqueta-estado::before,
.rf-estado::before { content: ""; width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; background: currentColor; }
.rf-etiqueta-estado-exito, .rf-estado-exito { color: var(--rf-color-semantico-exito-texto); }
.rf-etiqueta-estado-aviso, .rf-estado-aviso { color: var(--rf-color-semantico-aviso-texto); }
.rf-etiqueta-estado-neutro, .rf-estado-neutro { color: var(--rf-color-neutro-600); }
.rf-etiqueta-estado-neutro::before, .rf-estado-neutro::before { background: var(--rf-color-neutro-500); }
.rf-etiqueta-estado-error, .rf-estado-error { color: var(--rf-color-semantico-error-texto); }
.rf-etiqueta-estado-info, .rf-estado-info { color: var(--rf-color-semantico-info-texto); }

/* ============================================================================================
   §4.3 Tarjeta de oferta — la pieza más repetida. Revisión 4.5: NO es una caja. Es una fotografía
   4:3 de radio lg con el texto debajo, sin fondo, sin borde y sin sombra; en una rejilla las separan
   32 px de aire, en una lista un filete. Tres variantes: vertical, horizontal (foto de 128 px a la
   izquierda) y mini (foto de 64 px).
   ============================================================================================ */
/* "Toda la tarjeta es un único enlace; el corazón es un botón aparte" (documento 03 §4.3): el
   corazón no puede vivir DENTRO del enlace (un <button> dentro de un <a> es HTML inválido y rompe
   el foco de teclado). El contenedor (`.rf-tarjeta`, no interactivo) queda con `position: relative`
   y el enlace de verdad solo envuelve el nombre (`.rf-tarjeta-enlace`); su `::after` se estira a
   toda la tarjeta (patrón "stretched link"), así que pulsar la foto o el precio navega igual.
   El corazón, con su propio `position: relative` y por delante en la pila, sigue siendo pulsable.

   `.rf-tarjeta` a secas sigue siendo, además, el bloque de contenido genérico de las pantallas de la cuenta, la
   contratación y los paneles (160 usos): ese sí es una superficie blanca con filete y radio lg, sin sombra (las listas
   y tarjetas de panel del §8). Las pantallas lo irán cambiando por listas con filetes en P7.11 y P7.12. */
.rf-tarjeta {
  position: relative;
  display: block;
  border-radius: var(--rf-radio-lg);
  border: 1px solid var(--rf-filete);
  background: var(--rf-superficie);
  box-shadow: var(--rf-sombra-1);
}
.rf-tarjeta:is(.rf-tarjeta-vertical, .rf-tarjeta-horizontal, .rf-tarjeta-mini) {
  display: flex;
  flex-direction: column;
  gap: var(--rf-espacio-3);
  border: 0;
  border-radius: 0;
  background: transparent;
}
.rf-tarjeta-enlace { color: inherit; text-decoration: none; }
.rf-tarjeta-enlace:hover { color: inherit; text-decoration: underline; text-decoration-thickness: 1px; }
.rf-tarjeta-enlace::after { content: ""; position: absolute; inset: 0; }
.rf-tarjeta-media {
  position: relative;
  aspect-ratio: 4 / 3;
  border-radius: var(--rf-radio-lg);
  overflow: hidden;
  background: var(--rf-color-neutro-100);
}
.rf-tarjeta-media picture { display: contents; }
.rf-tarjeta-media img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* Sin foto (M-51): no hay bloque gris vacío, sino un marcador de posición con un icono en tinta suave sobre papel 100 y
   la proporción reservada. */
.rf-tarjeta-sin-foto { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; color: var(--rf-color-neutro-500); }
.rf-tarjeta-sin-foto .rf-icono { width: 32px; height: 32px; }
/* Insignia (§4.3): como mucho una, arriba a la izquierda, rectangular de radio sm; «Promocionado» sobre acento-100 en
   acento-700 gana a las demás y no se oculta nunca, tampoco en la mini (RN-16). */
.rf-tarjeta-insignia {
  position: absolute;
  top: var(--rf-espacio-2);
  left: var(--rf-espacio-2);
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 3px var(--rf-espacio-2);
  border-radius: var(--rf-radio-sm);
  font-size: var(--rf-tipo-etiqueta-movil-tamano);
  line-height: var(--rf-tipo-etiqueta-movil-interlinea);
  font-weight: var(--rf-tipo-etiqueta-peso);
  background: var(--rf-superficie);
  color: var(--rf-texto);
  border: 1px solid var(--rf-filete);
}
.rf-tarjeta-insignia-promocionado { background: var(--rf-color-acento-100); color: var(--rf-color-acento-700); border-color: transparent; }
.rf-tarjeta-cuerpo { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.rf-tarjeta-categoria,
.rf-tarjeta-cuerpo > .rf-etiqueta-categoria { margin-bottom: var(--rf-espacio-1); align-self: flex-start; }
/* Nombre y valoración en la MISMA línea (§4.3 punto 2): el nombre a la izquierda en la familia de títulos, la
   valoración a la derecha. */
.rf-tarjeta-fila { display: flex; justify-content: space-between; align-items: baseline; gap: var(--rf-espacio-3); }
.rf-tarjeta-nombre {
  margin: 0;
  min-width: 0;
  font-family: var(--rf-fuente-titulos-pila);
  font-size: 18px;
  line-height: 1.3;
  font-weight: 600;
  letter-spacing: -.005em;
  font-variation-settings: "opsz" 24;
  color: var(--rf-texto);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.rf-tarjeta-lugar { margin: 0; font-size: var(--rf-tipo-pequeno-movil-tamano); color: var(--rf-texto-secundario); }
.rf-tarjeta-valoracion { display: inline-flex; align-items: center; gap: 4px; font-size: var(--rf-tipo-pequeno-movil-tamano); white-space: nowrap; flex-shrink: 0; }
/* Atributos (§4.3 punto 4): dos o tres en una línea de texto separados por «·», sin iconos; lo incluido, el primero. */
.rf-tarjeta-atributos { font-size: var(--rf-tipo-pequeno-movil-tamano); color: var(--rf-texto-secundario); }
.rf-tarjeta-atributo:not(:last-child)::after { content: " · "; color: var(--rf-texto-secundario); font-weight: 400; }
.rf-tarjeta-atributo-incluye { color: var(--rf-color-apoyo-700); font-weight: 600; }
.rf-tarjeta-horario { margin: 0; font-size: var(--rf-tipo-pequeno-movil-tamano); color: var(--rf-texto); font-weight: 600; }
.rf-tarjeta-horario-extra { color: var(--rf-texto-secundario); font-weight: 400; }
.rf-tarjeta-horario-sin-hueco { color: var(--rf-color-neutro-600); font-weight: 400; }
/* Precio (§4.3 punto 6): «desde» en secundario, el importe en la familia de títulos, en euros enteros, y la unidad. */
.rf-tarjeta-precio { margin: var(--rf-espacio-1) 0 0; display: flex; align-items: baseline; gap: 6px; }
.rf-tarjeta-precio-desde { font-size: var(--rf-tipo-pequeno-movil-tamano); color: var(--rf-texto-secundario); }
.rf-tarjeta-precio-unidad { margin: 0; font-size: var(--rf-tipo-pequeno-movil-tamano); color: var(--rf-texto-secundario); }
.rf-tarjeta-encaje { margin: 0; font-size: var(--rf-tipo-pequeno-movil-tamano); }
.rf-tarjeta-encaje-dentro { color: var(--rf-color-apoyo-700); font-weight: 600; }
.rf-tarjeta-encaje-fuera { color: var(--rf-color-semantico-aviso-texto); font-weight: 600; }
.rf-tarjeta-encaje-motivos { color: var(--rf-color-neutro-600); }

/* Sin hueco para lo pedido: se apaga la FOTO al 60 %, no el texto (P14.4, WCAG 1.4.3; §4.5 «separador de grupo»). */
.rf-tarjeta-sin-hueco .rf-tarjeta-imagen, .rf-tarjeta-sin-hueco picture, .rf-tarjeta-sin-hueco img { opacity: .6; }

/* Variante horizontal: la lista junto al mapa, la web móvil y la venta cruzada (foto de 128 px a la izquierda). */
.rf-tarjeta.rf-tarjeta-horizontal { flex-direction: row; gap: var(--rf-espacio-4); align-items: flex-start; }
.rf-tarjeta-horizontal .rf-tarjeta-media { width: 128px; flex-shrink: 0; }
.rf-tarjeta-horizontal .rf-tarjeta-cuerpo { flex: 1 1 auto; }
.rf-tarjeta-horizontal .rf-tarjeta-nombre { font-size: var(--rf-tipo-cuerpo-lg-movil-tamano); -webkit-line-clamp: 2; }
/* En la foto de 128 px la insignia de arriba chocaba con el corazón (P7.11): en la horizontal va abajo a la izquierda. */
.rf-tarjeta-horizontal .rf-tarjeta-media .rf-tarjeta-insignia { top: auto; bottom: var(--rf-espacio-2); max-width: calc(100% - var(--rf-espacio-4)); }

/* Variante mini: favoritos, mensajes (foto de 64 px). */
.rf-tarjeta.rf-tarjeta-mini { flex-direction: row; align-items: center; gap: var(--rf-espacio-3); }
.rf-tarjeta-mini .rf-tarjeta-media { width: 64px; height: 64px; aspect-ratio: 1 / 1; border-radius: var(--rf-radio-md); flex-shrink: 0; }
.rf-tarjeta-mini .rf-tarjeta-nombre { font-size: var(--rf-tipo-cuerpo-movil-tamano); -webkit-line-clamp: 1; }
/* En la mini la foto es de 64 px: la insignia no cabe encima sin tapar el corazón, así que «Promocionado» (que no se
   oculta nunca, RN-16) va en el texto, en su propia línea (.rf-tarjeta-insignia-linea), y la de la foto no se pinta. */
.rf-tarjeta-mini .rf-tarjeta-media .rf-tarjeta-insignia { display: none; }
.rf-tarjeta-insignia.rf-tarjeta-insignia-linea { position: static; align-self: flex-start; padding: 1px 6px; }
.rf-tarjeta-mini .rf-favorito { width: 28px; height: 28px; top: 2px; right: 2px; }
.rf-tarjeta-mini .rf-favorito .rf-icono { width: 14px; height: 14px; }

/* Rejilla (tres en escritorio, dos en tableta, una en el móvil; 32 px de aire vertical) y lista con filetes. */
.rf-tarjetas-rejilla { display: grid; grid-template-columns: 1fr; gap: var(--rf-espacio-8) var(--rf-espacio-6); list-style: none; margin: 0; padding: 0; }
@media (min-width: 576px) { .rf-tarjetas-rejilla { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 992px) { .rf-tarjetas-rejilla { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
.rf-lista-tarjetas > * + * { border-top: 1px solid var(--rf-filete); padding-top: var(--rf-espacio-4); margin-top: var(--rf-espacio-4); }

/* ============================================================================================
   Valoración — estrella acento-600 y nota; barras de distribución en la ficha (documento 03 §4.5).
   ============================================================================================ */
.rf-valoracion-estrella { color: var(--rf-color-acento-600); fill: currentColor; }
.rf-valoracion-nota { font-weight: 600; color: var(--rf-texto); }
.rf-valoracion-numero { color: var(--rf-texto-secundario); }
.rf-valoracion-nueva { color: var(--rf-texto-secundario); }

.rf-distribucion { display: grid; gap: var(--rf-espacio-1); max-width: 320px; }
.rf-distribucion-fila { display: grid; grid-template-columns: 3em 1fr 2.5em; align-items: center; gap: var(--rf-espacio-2); font-size: var(--rf-tipo-pequeno-movil-tamano); }
.rf-distribucion-barra { height: 6px; border-radius: var(--rf-radio-xs); background: var(--rf-color-neutro-200); overflow: hidden; }
.rf-distribucion-barra-relleno { display: block; height: 100%; background: var(--rf-color-acento-600); }

/* ============================================================================================
   Sello de verificación (documento 03 §4.4): icono de escudo y texto, en verde.
   ============================================================================================ */
.rf-sello {
  display: inline-flex;
  align-items: center;
  gap: var(--rf-espacio-1);
  border: none;
  background: none;
  padding: 0;
  color: var(--rf-color-apoyo-700);
  font-size: var(--rf-tipo-pequeno-movil-tamano);
  font-weight: 600;
  cursor: pointer;
  min-height: 44px;
}
.rf-sello .rf-icono { color: var(--rf-color-apoyo-700); }
.rf-sello-detalle { font-size: var(--rf-tipo-pequeno-movil-tamano); color: var(--rf-texto-secundario); margin-top: var(--rf-espacio-1); }

/* ============================================================================================
   Galería en mosaico con visor (documento 03 §4; la composición 2+3 de la ficha la cierra P7.11).
   ============================================================================================ */
.rf-galeria { display: grid; grid-template-columns: repeat(4, 1fr); grid-template-rows: repeat(2, 1fr); gap: var(--rf-espacio-2); border-radius: var(--rf-radio-lg); overflow: hidden; aspect-ratio: 16 / 9; }
.rf-galeria-celda { position: relative; overflow: hidden; border: none; padding: 0; cursor: pointer; background: var(--rf-color-neutro-100); }
.rf-galeria-celda img { width: 100%; height: 100%; object-fit: cover; display: block; transition: transform var(--rf-duracion-media) var(--rf-curva-entrada); }
.rf-galeria-celda:hover img,
.rf-galeria-celda:focus-visible img { transform: scale(1.03); }
.rf-galeria-celda-principal { grid-column: 1 / 3; grid-row: 1 / 3; }
.rf-galeria-celda-mas { position: relative; }
.rf-galeria-celda-mas::after {
  content: attr(data-rf-mas);
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  background: color-mix(in srgb, var(--rf-color-neutro-900) 55%, transparent);
  color: var(--rf-color-neutro-0);
  font-weight: 600;
}
@media (max-width: 575.98px) {
  .rf-galeria { grid-template-columns: repeat(2, 1fr); aspect-ratio: 4 / 3; }
  .rf-galeria-celda-principal { grid-column: 1 / 3; grid-row: 1 / 2; }
}
.rf-visor .modal-content { background: color-mix(in srgb, var(--rf-color-neutro-900) 96%, transparent); border-radius: 0; }
.rf-visor-imagen { width: 100%; max-height: 70vh; object-fit: contain; background: var(--rf-color-neutro-900); }
.rf-visor-controles { display: flex; align-items: center; justify-content: space-between; padding: var(--rf-espacio-3) var(--rf-espacio-4); color: var(--rf-color-neutro-0); }
.rf-visor-contador { font-size: var(--rf-tipo-pequeno-movil-tamano); }
.rf-visor .rf-boton-icono {
  background: color-mix(in srgb, var(--rf-color-neutro-0) 12%, transparent);
  border-color: color-mix(in srgb, var(--rf-color-neutro-0) 30%, transparent);
  color: var(--rf-color-neutro-0);
}
.rf-visor .rf-boton-icono:hover { background: color-mix(in srgb, var(--rf-color-neutro-0) 22%, transparent); }

/* ============================================================================================
   §4.4 Disponibilidad y contratación.
   ============================================================================================ */

/* Calendario mensual (§4.4): semana que empieza en lunes, días del mes contiguo ocultos, cada día un CUADRADO de radio md
   (no un círculo). Libre: texto tinta y punto verde; pocas plazas: punto oro; completo: papel 500 tachado;
   cerrado y pasado: papel 500; hoy: aro fino papel 400; ELEGIDO: relleno tinta con texto blanco. */
.rf-calendario { max-width: 360px; }
.rf-calendario-cabecera { display: flex; align-items: center; justify-content: space-between; margin-bottom: var(--rf-espacio-3); }
.rf-calendario-cabecera .rf-boton-icono { border-color: transparent; background: transparent; }
.rf-calendario-cabecera .rf-boton-icono:hover { background: var(--rf-color-neutro-100); }
.rf-calendario-mes { font-family: var(--rf-fuente-titulos-pila); font-weight: 600; text-transform: capitalize; font-variation-settings: "opsz" 24; }
.rf-calendario-rejilla { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; text-align: center; }
.rf-calendario-dia-semana { font-size: var(--rf-tipo-etiqueta-movil-tamano); color: var(--rf-texto-secundario); padding-block: var(--rf-espacio-1); }
.rf-calendario-dia {
  position: relative;
  aspect-ratio: 1 / 1;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--rf-radio-md);
  border: 1px solid transparent;
  background: none;
  font-family: var(--rf-fuente-texto-pila);
  font-size: var(--rf-tipo-pequeno-movil-tamano);
  color: var(--rf-texto);
  text-decoration: none;
  cursor: pointer;
}
a.rf-calendario-dia:hover, button.rf-calendario-dia:hover:not(:disabled) { background: var(--rf-color-neutro-100); color: var(--rf-texto); }
.rf-calendario-dia::after { content: ""; position: absolute; bottom: 5px; width: 5px; height: 5px; border-radius: 50%; }
.rf-calendario-dia-libre::after { background: var(--rf-color-apoyo-700); }
.rf-calendario-dia-pocas::after { background: var(--rf-color-acento-600); }
.rf-calendario-dia-completo { color: var(--rf-color-neutro-500); text-decoration: line-through; }
.rf-calendario-dia-cerrado { color: var(--rf-color-neutro-500); }
/* Pasado: no se elige, pero se lee (P7.8: papel 500, 5,24:1 sobre el papel de la página, WCAG 1.4.3).
   Lo que lo distingue de un día libre es que no lleva punto ni enlace, y el lector de pantalla dice «ya ha pasado». */
.rf-calendario-dia-pasado { color: var(--rf-color-neutro-500); cursor: not-allowed; }
.rf-calendario-dia-hoy { border-color: var(--rf-color-neutro-400); }
.rf-calendario-dia-seleccionado,
.rf-calendario-dia-seleccionado:hover,
a.rf-calendario-dia-seleccionado:hover { background: var(--rf-color-neutro-900); color: var(--rf-color-neutro-0); border-color: var(--rf-color-neutro-900); }
.rf-calendario-dia-seleccionado::after { background: var(--rf-color-neutro-0); }
.rf-calendario-dia-oculto { visibility: hidden; }
.rf-calendario-leyenda { display: flex; flex-wrap: wrap; gap: var(--rf-espacio-4); margin-top: var(--rf-espacio-3); font-size: var(--rf-tipo-pequeno-movil-tamano); color: var(--rf-texto-secundario); }
.rf-calendario-leyenda span { display: inline-flex; align-items: center; gap: 4px; }
.rf-calendario-leyenda i { width: 8px; height: 8px; border-radius: 50%; display: inline-block; }
.rf-calendario-leyenda-punto-libre { background: var(--rf-color-apoyo-700); }
.rf-calendario-leyenda-punto-pocas { background: var(--rf-color-acento-600); }
/* Completo y cerrado no tienen punto: se enseñan como en el calendario (tachado y en gris) para que la leyenda los
   explique (pruebas funcionales del 2026-09-27). El hueco de una flecha que no se puede pulsar no pinta su borde. */
.rf-calendario-leyenda-muestra { font-weight: 600; min-width: 1ch; }
.rf-calendario-hueco { visibility: hidden; }

/* Selector de turnos (§4.4): una fila rectangular por turno (radio md, borde papel 400) con el nombre en 600, las horas
   y el estado en secundario a la izquierda y el precio en la familia de títulos a la derecha; ELEGIDO: relleno tinta con
   texto blanco; agotado: borde discontinuo, tachado y deshabilitado. */
.rf-turnos { display: grid; gap: var(--rf-espacio-2); }
.rf-turno {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 2px var(--rf-espacio-3);
  align-items: center;
  width: 100%;
  text-align: left;
  border: 1px solid var(--rf-color-neutro-400);
  border-radius: var(--rf-radio-md);
  background: var(--rf-superficie);
  color: var(--rf-texto);
  padding: 10px 14px;
  cursor: pointer;
  min-height: 44px;
  font-family: var(--rf-fuente-texto-pila);
  font-size: var(--rf-tipo-cuerpo-movil-tamano);
}
.rf-turno:hover:not(:disabled) { border-color: var(--rf-color-neutro-900); }
.rf-turno-nombre { grid-column: 1; font-weight: 600; }
.rf-turno-horas { grid-column: 1; font-size: var(--rf-tipo-pequeno-movil-tamano); color: var(--rf-texto-secundario); }
.rf-turno-precio { grid-column: 2; grid-row: 1 / span 2; font-family: var(--rf-fuente-titulos-pila); font-weight: 600; font-variation-settings: "opsz" 24; }
.rf-turno-estado { grid-column: 1; display: inline-flex; align-items: center; gap: 4px; font-size: var(--rf-tipo-pequeno-movil-tamano); color: var(--rf-texto-secundario); }
/* El punto del estado (un «●» decorativo en el marcado) va del tamaño de los puntos del calendario, no del de la letra. */
.rf-turno-estado > [aria-hidden="true"] { font-size: 8px; line-height: 1; }
.rf-turno-estado-libre { color: var(--rf-color-apoyo-700); }
.rf-turno-estado-pocas { color: var(--rf-color-acento-700); }
.rf-turno[aria-pressed="true"],
.rf-turno-elegido { background: var(--rf-color-neutro-900); border-color: var(--rf-color-neutro-900); color: var(--rf-color-neutro-0); }
.rf-turno[aria-pressed="true"] .rf-turno-horas,
.rf-turno[aria-pressed="true"] .rf-turno-estado,
.rf-turno-elegido .rf-turno-horas,
.rf-turno-elegido .rf-turno-estado { color: color-mix(in srgb, var(--rf-color-neutro-0) 80%, transparent); }
.rf-turno[disabled],
.rf-turno-agotado { color: var(--rf-color-neutro-500); text-decoration: line-through; border-style: dashed; cursor: not-allowed; background: transparent; }
.rf-turno-continuo { display: flex; flex-wrap: wrap; gap: var(--rf-espacio-3); align-items: flex-end; }
.rf-turno-continuo .rf-campo { margin-bottom: 0; min-width: 160px; }
.rf-turno-intervalo { margin-top: var(--rf-espacio-2); font-size: var(--rf-tipo-pequeno-movil-tamano); color: var(--rf-texto-secundario); }

/* Lista «Qué incluye» (§4.4): filas separadas por filetes con el icono, el nombre y la cantidad y, si se puede añadir
   más, el precio de la unidad adicional a la derecha. */
.rf-incluye { list-style: none; margin: 0; padding: 0; display: grid; }
.rf-incluye-fila { display: flex; align-items: center; gap: var(--rf-espacio-3); padding-block: var(--rf-espacio-3); border-top: 1px solid var(--rf-filete); }
.rf-incluye-fila:first-child { border-top: 0; }
.rf-incluye-icono { color: var(--rf-color-apoyo-700); flex-shrink: 0; }
.rf-incluye-texto { flex: 1 1 auto; }
.rf-incluye-nombre { font-weight: 600; }
.rf-incluye-cantidad { color: var(--rf-texto-secundario); font-size: var(--rf-tipo-pequeno-movil-tamano); }
.rf-incluye-extra { font-size: var(--rf-tipo-pequeno-movil-tamano); color: var(--rf-texto-secundario); }

/* Bloque de contratación (§4.4): en escritorio, lateral fijo al desplazarse, BLANCO, con borde de 1 px de tinta y radio
   lg, SIN sombra; en el móvil, barra inferior fija sobre blanco con filete superior. */
.rf-contratacion-lateral {
  display: grid;
  gap: var(--rf-espacio-4);
  border: 1px solid var(--rf-color-neutro-900);
  border-radius: var(--rf-radio-lg);
  box-shadow: var(--rf-sombra-1);
  padding: var(--rf-espacio-5);
  background: var(--rf-superficie);
}
/* Pegado a la vista en escritorio, pero nunca más alto que ella: con el turno, la hora extra, los extras y el desglose
   el bloque pasaba de la ventana y «Reservar» quedaba debajo, inalcanzable mientras la página no llegara al final
   (recorrido del 2026-09-28, F-11). Si no cabe, se desplaza por dentro. */
@media (min-width: 992px) {
  .rf-contratacion-lateral {
    position: sticky;
    top: calc(var(--rf-espacio-6) + 64px);
    max-height: calc(100vh - var(--rf-espacio-6) - 64px - var(--rf-espacio-4));
    overflow-y: auto;
    overscroll-behavior: contain;
  }
}
.rf-contratacion-precio { display: flex; align-items: baseline; flex-wrap: wrap; gap: 6px; margin: 0; }
.rf-contratacion-precio .rf-precio { font-size: 26px; line-height: 1.2; }
.rf-contratacion-precio-unidad { font-size: var(--rf-tipo-pequeno-movil-tamano); color: var(--rf-texto-secundario); font-weight: 400; }
.rf-contratacion-precio-nota { flex-basis: 100%; } /* «Total, gastos incluidos», en su línea (M-113) */
.rf-contratacion-campos { display: grid; gap: var(--rf-espacio-3); }
.rf-contratacion-campos .rf-campo { margin-bottom: 0; }

.rf-contratacion-barra-movil {
  position: fixed;
  /* Por encima del aviso de cookies mientras esté abierto (M-50: rf-cookies.js publica su alto). */
  left: 0; right: 0; bottom: var(--rf-aviso-alto, 0px);
  z-index: var(--rf-capa-barra-fija);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--rf-espacio-3);
  padding: var(--rf-espacio-3) var(--rf-espacio-4);
  padding-bottom: calc(var(--rf-espacio-3) + env(safe-area-inset-bottom, 0px));
  background: var(--rf-superficie);
  border-top: 1px solid var(--rf-filete);
}
.rf-contratacion-barra-movil-precio { font-family: var(--rf-fuente-titulos-pila); font-weight: 700; font-variation-settings: "opsz" 24; }
.rf-contratacion-barra-movil-unidad { font-size: var(--rf-tipo-pequeno-movil-tamano); color: var(--rf-texto-secundario); font-weight: 400; display: block; }
@media (min-width: 992px) { .rf-contratacion-barra-movil { display: none; } }
/* La barra fija de la ficha tapaba lo que el tabulador alcanza al final de la página (el calendario, el pie; P14.4,
   WCAG 2.4.11): el navegador deja el foco por encima de su alto. */
@media (max-width: 991.98px) { html:has(.rf-contratacion-barra-movil) { scroll-padding-bottom: 112px; } }

/* Desglose de precio (§4.4): concepto a la izquierda e importe a la derecha en cifras tabulares; descuentos en verde;
   filete de TINTA sobre el total, que va en la familia de títulos. */
.rf-desglose { display: grid; gap: 6px; }
.rf-desglose-linea { display: flex; justify-content: space-between; gap: var(--rf-espacio-3); font-size: var(--rf-tipo-pequeno-movil-tamano); }
.rf-desglose-linea-descuento { color: var(--rf-color-apoyo-700); }
.rf-desglose-importe { font-variant-numeric: tabular-nums; white-space: nowrap; }
.rf-desglose-info { color: var(--rf-texto-secundario); cursor: help; margin-left: 4px; }
.rf-desglose-separador { border: none; border-top: 1px solid var(--rf-color-neutro-900); margin: var(--rf-espacio-1) 0 0; opacity: 1; }
.rf-desglose-total { display: flex; justify-content: space-between; align-items: baseline; font-weight: 700; }
.rf-desglose-total .rf-desglose-importe { font-size: var(--rf-tipo-precio-movil-tamano); font-weight: var(--rf-tipo-precio-peso); }
.rf-desglose-senal { font-size: var(--rf-tipo-pequeno-movil-tamano); color: var(--rf-texto-secundario); margin: var(--rf-espacio-1) 0 0; }

/* Política de cancelación (§4.4): tres columnas con fechas concretas, cada una con su filete de 3 px arriba (verde:
   devolución total; oro: parcial; papel 400: sin devolución). El texto va en tinta: el color lo dice el filete
   y la frase, nunca solo el color. */
.rf-politica { display: grid; grid-template-columns: 1fr; gap: var(--rf-espacio-3); margin-block: var(--rf-espacio-2); list-style: none; padding: 0; }
@media (min-width: 576px) { .rf-politica { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--rf-espacio-2); } }
.rf-politica-tramo { padding-top: var(--rf-espacio-2); font-size: var(--rf-tipo-pequeno-movil-tamano); color: var(--rf-texto-secundario); border-top: 3px solid var(--rf-color-neutro-400); }
.rf-politica-tramo-total { border-top-color: var(--rf-color-apoyo-700); }
.rf-politica-tramo-parcial { border-top-color: var(--rf-color-acento-600); }
.rf-politica-tramo-sin { border-top-color: var(--rf-color-neutro-400); }
.rf-politica-tramo strong { display: block; color: var(--rf-texto); font-size: var(--rf-tipo-pequeno-movil-tamano); }

/* Cuenta atrás de la retención (§4.4): banda de información; a los 2 minutos, de aviso. */
.rf-retencion { display: flex; align-items: center; gap: var(--rf-espacio-2); padding: var(--rf-espacio-3) var(--rf-espacio-4); border-radius: var(--rf-radio-md); border-left: 3px solid currentColor; background: var(--rf-color-semantico-info-fondo); color: var(--rf-color-semantico-info-texto); font-size: var(--rf-tipo-pequeno-movil-tamano); }
.rf-retencion-tiempo { font-family: var(--rf-fuente-titulos-pila); font-weight: 700; font-variant-numeric: tabular-nums; }
.rf-retencion-aviso { background: var(--rf-color-semantico-aviso-fondo); color: var(--rf-color-semantico-aviso-texto); }
/* Al caducar, rf-form.js la esconde con `hidden` (M-107): el `display: flex` de arriba lo taparía. */
.rf-retencion[hidden] { display: none; }

/* Paso a paso (§4.4): tres pasos con un filete de 2 px encima —violeta el actual, tinta lo hecho, papel lo que falta—, el
   número y el nombre. Sin círculos numerados (§15.1). */
.rf-paso-a-paso { list-style: none; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--rf-espacio-3); margin: 0 0 var(--rf-espacio-4); padding: 0; }
.rf-paso-a-paso li { padding-top: var(--rf-espacio-2); border-top: 2px solid var(--rf-color-neutro-300); font-size: var(--rf-tipo-pequeno-movil-tamano); color: var(--rf-texto-secundario); }
.rf-paso-a-paso li::before { content: attr(data-rf-paso) " · "; font-family: var(--rf-fuente-titulos-pila); font-weight: 600; }
.rf-paso-a-paso li[aria-current="step"] { border-top-color: var(--rf-color-primario-700); color: var(--rf-texto); font-weight: 600; }
.rf-paso-a-paso li[aria-current="step"]::before { color: var(--rf-color-primario-700); }
.rf-paso-a-paso li[data-rf-hecho] { border-top-color: var(--rf-color-neutro-900); color: var(--rf-texto); }

/* ============================================================================================
   §4.5 Navegación, contenedores y respuesta del sistema.
   ============================================================================================ */

/* Pestañas: subrayado de 2 px violeta bajo la activa, texto en 600; desplazables en el móvil. */
.rf-pestanas { display: flex; gap: var(--rf-espacio-5); overflow-x: auto; border-bottom: 1px solid var(--rf-filete); list-style: none; margin: 0; padding: 0; }
.rf-pestanas a { display: inline-flex; align-items: center; padding: var(--rf-espacio-3) 0; color: var(--rf-texto-secundario); text-decoration: none; white-space: nowrap; border-bottom: 2px solid transparent; min-height: 44px; }
.rf-pestanas a:hover { color: var(--rf-texto); }
.rf-pestanas a[aria-current="page"] { color: var(--rf-texto); font-weight: 600; border-bottom-color: var(--rf-color-primario-700); }

/* Modal de confirmación y hoja inferior (§4.5): radio xl, sombra 3 (lo único que flota de verdad). El atrapado de foco
   y el cierre con Escape/clic fuera son de Bootstrap (`data-bs-toggle="modal"`), no se reescriben aquí. */
.rf-modal .modal-content {
  border-radius: var(--rf-radio-xl);
  border: none;
  box-shadow: var(--rf-sombra-3);
  background: var(--rf-superficie);
}
.rf-modal .modal-header,
.rf-modal .modal-body,
.rf-modal .modal-footer { padding: var(--rf-espacio-5); }
.rf-modal .modal-header { border-bottom-color: var(--rf-filete); }
.rf-modal .modal-footer { border-top-color: var(--rf-filete); gap: var(--rf-espacio-2); }
.rf-modal .modal-title { font-family: var(--rf-fuente-titulos-pila); font-weight: 600; }
.rf-modal.offcanvas-bottom { border-radius: var(--rf-radio-xl) var(--rf-radio-xl) 0 0; box-shadow: var(--rf-sombra-3); border: 0; }
.rf-modal-destructivo { background: var(--rf-color-semantico-error-texto); border-color: var(--rf-color-semantico-error-texto); color: var(--rf-color-neutro-0); }
.rf-modal-destructivo:hover { color: var(--rf-color-neutro-0); }

/* Aviso emergente flotante (toast) — variante de fragments/avisos con temporización de JS; flota, con sombra 2. */
.rf-toasts {
  position: fixed;
  top: var(--rf-espacio-4);
  right: var(--rf-espacio-4);
  z-index: var(--rf-capa-aviso-emergente);
  display: grid;
  gap: var(--rf-espacio-2);
  max-width: min(360px, calc(100vw - 2 * var(--rf-espacio-4)));
}
@media (max-width: 767.98px) {
  .rf-toasts { top: auto; bottom: calc(var(--rf-espacio-4) + env(safe-area-inset-bottom, 0px)); left: var(--rf-espacio-4); right: var(--rf-espacio-4); max-width: none; }
}
.rf-toast { box-shadow: var(--rf-sombra-2); border-radius: var(--rf-radio-md); }

/* Banda de aviso: ancho completo bajo la cabecera (mantenimiento, correo sin verificar, pago pendiente). */
.rf-banda-aviso { border-radius: 0; border-left: 0; justify-content: center; text-align: center; }
.rf-banda-aviso .rf-banda-enlace { color: inherit; font-weight: 600; text-decoration: underline; margin-inline-start: var(--rf-espacio-2); }

/* Estado vacío (§4.5): la ilustración de línea pequeña, una frase que explica y una acción. Sin círculo de fondo. */
.rf-estado-vacio {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: var(--rf-espacio-3);
  padding: var(--rf-espacio-10) var(--rf-espacio-4);
  color: var(--rf-texto-secundario);
}
.rf-estado-vacio p { margin: 0; max-width: 40ch; }

/* Esqueleto de carga (§4.5 y §5.2): bloques papel 100 con brillo suave, la forma del contenido; nunca una rueda a
   pantalla completa. El brillo es el ÚNICO degradado del patrón (con el rayado de un bloqueo en la agenda, §2.5) y se
   apaga con "reducir movimiento" (regla global de rf-base.css). */
.rf-esqueleto-tarjeta {
  display: flex;
  flex-direction: column;
  gap: var(--rf-espacio-1);
}
.rf-esqueleto {
  display: block;
  border-radius: var(--rf-radio-sm);
  background: linear-gradient(90deg,
      var(--rf-color-neutro-100) 25%, var(--rf-color-neutro-200) 37%, var(--rf-color-neutro-100) 63%);
  background-size: 400% 100%;
  animation: rf-esqueleto-brillo 1.4s ease-in-out infinite;
}
.rf-esqueleto-texto { height: 1em; width: 100%; margin-bottom: var(--rf-espacio-2); }
.rf-esqueleto-corta { width: 70%; }
.rf-esqueleto-titulo { height: 1.5em; width: 60%; margin-bottom: var(--rf-espacio-3); }
.rf-esqueleto-imagen { aspect-ratio: 4 / 3; width: 100%; border-radius: var(--rf-radio-lg); margin-bottom: var(--rf-espacio-2); }
.rf-esqueleto-imagen-16-9 { aspect-ratio: 16 / 9; width: 100%; border-radius: var(--rf-radio-lg); }
.rf-esqueleto-imagen-1-1 { aspect-ratio: 1 / 1; width: 100%; border-radius: var(--rf-radio-lg); }
.rf-esqueleto-avatar { border-radius: 50%; width: 44px; height: 44px; }
.rf-esqueleto-fila { height: 40px; width: 100%; border-radius: var(--rf-radio-sm); margin-bottom: var(--rf-espacio-2); }
@keyframes rf-esqueleto-brillo {
  0% { background-position: 100% 50%; }
  100% { background-position: 0 50%; }
}

/* Página de error (§4.5): ilustración de línea, qué ha pasado en una frase, qué hacer y el traceId copiable. */
.rf-pagina-error { display: flex; flex-direction: column; align-items: center; text-align: center; gap: var(--rf-espacio-3); padding: var(--rf-espacio-10) var(--rf-espacio-4); }
.rf-pagina-error h2 { margin: 0; }
.rf-pagina-error p { margin: 0; max-width: 48ch; color: var(--rf-texto-secundario); }
.rf-pagina-error-traza {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: var(--rf-tipo-pequeno-movil-tamano);
  background: var(--rf-color-neutro-100);
  color: var(--rf-texto);
  border-radius: var(--rf-radio-sm);
  padding: var(--rf-espacio-1) var(--rf-espacio-2);
  border: none;
  cursor: pointer;
}

/* Avatar (§4.5): círculo —píldora permitida— con las iniciales en tinta sobre papel 100 si no hay foto. */
.rf-avatar { display: inline-flex; align-items: center; justify-content: center; border-radius: 50%; background: var(--rf-color-neutro-100); color: var(--rf-texto); font-weight: 600; overflow: hidden; flex-shrink: 0; }
.rf-avatar img { width: 100%; height: 100%; object-fit: cover; }
.rf-avatar-sm { width: 32px; height: 32px; font-size: 13px; }
.rf-avatar-md { width: 44px; height: 44px; font-size: 16px; }
.rf-avatar-lg { width: 64px; height: 64px; font-size: 22px; }

/* Marcador de mapa (§4.5): rectángulo blanco de radio sm con borde de tinta y el precio en la familia de títulos, sombra
   2 (flota sobre el mapa); ELEGIDO: relleno tinta con texto blanco; destacado: borde oro y una estrella delante,
   nunca más grande; agrupaciones: círculo (la tercera píldora permitida) con el número. */
.rf-marcador {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 4px 9px;
  border-radius: var(--rf-radio-sm);
  background: var(--rf-superficie);
  color: var(--rf-texto);
  border: 1px solid var(--rf-color-neutro-900);
  font-family: var(--rf-fuente-titulos-pila);
  font-weight: 600;
  font-size: var(--rf-tipo-pequeno-movil-tamano);
  font-variation-settings: "opsz" 24;
  box-shadow: var(--rf-sombra-2);
  cursor: pointer;
}
.rf-marcador[aria-pressed="true"],
.rf-marcador-activo { background: var(--rf-color-neutro-900); color: var(--rf-color-neutro-0); }
.rf-marcador-destacado { border-color: var(--rf-color-acento-600); }
.rf-marcador-destacado .rf-icono { color: var(--rf-color-acento-600); fill: currentColor; }
.rf-marcador-grupo { display: inline-flex; align-items: center; justify-content: center; width: 32px; height: 32px; border-radius: 50%; background: var(--rf-color-neutro-900); color: var(--rf-color-neutro-0); font-family: var(--rf-fuente-titulos-pila); font-weight: 600; font-size: var(--rf-tipo-pequeno-movil-tamano); box-shadow: var(--rf-sombra-2); border: none; }

/* El logotipo de Google Maps (condiciones de Map Tiles API): entre 16 y 19 px de alto, la proporción del original y su
   espacio libre de 10 px a los lados y arriba y 5 abajo. MapLibre pone a los controles su propio margen, y su hoja llega después
   (rf-carga-del-mapa.js): la regla lleva sus dos clases para ganarle. */
.maplibregl-ctrl-bottom-left .maplibregl-ctrl.rf-mapa-logo {
  display: block;
  height: 18px;
  width: auto;
  margin: 10px 10px 5px;
  pointer-events: none;
}

/* El asa del radio (§7.2 «círculo con asa»; D-2401): una etiqueta como el marcador, en el borde este del círculo, con el
   borde en el violeta del círculo y la flecha doble del cursor; se arrastra o se mueve con las flechas (role="slider"). */
.rf-mapa-asa {
  display: inline-flex;
  align-items: center;
  padding: 3px 8px;
  border-radius: var(--rf-radio-sm);
  background: var(--rf-superficie);
  color: var(--rf-texto);
  border: 2px solid var(--rf-color-primario-700);
  font-family: var(--rf-fuente-titulos-pila);
  font-weight: 600;
  font-size: var(--rf-tipo-pequeno-movil-tamano);
  font-variation-settings: "opsz" 24;
  box-shadow: var(--rf-sombra-2);
  cursor: ew-resize;
  white-space: nowrap;
  touch-action: none;
  user-select: none;
}
.rf-mapa-asa:focus-visible { outline: 3px solid var(--rf-color-primario-500); outline-offset: 2px; }
/* El punto que se arrastra en el asistente de una oferta (D-2400): el marcador de MapLibre, con el foco visible. */
.rf-mapa-punto-movil { cursor: grab; }
.rf-mapa-punto-movil:focus-visible { outline: 3px solid var(--rf-color-primario-500); outline-offset: 2px; }

/* Control de presupuesto (§4.5): el importe con «en total / por asistente» y una barra con la zona de margen en aviso. */
.rf-presupuesto { max-width: 360px; }
.rf-presupuesto-modo { display: flex; gap: var(--rf-espacio-2); margin-bottom: var(--rf-espacio-2); }
.rf-presupuesto-barra { position: relative; height: 6px; border-radius: var(--rf-radio-xs); background: var(--rf-color-neutro-200); margin-top: var(--rf-espacio-3); overflow: hidden; }
.rf-presupuesto-margen { position: absolute; top: 0; bottom: 0; right: 0; width: 15%; background: var(--rf-color-semantico-aviso-fondo); }
.rf-presupuesto-relleno { position: absolute; top: 0; bottom: 0; left: 0; background: var(--rf-color-primario-700); }
.rf-presupuesto-relleno-demo { width: 78%; }
.rf-presupuesto-nota { font-size: var(--rf-tipo-pequeno-movil-tamano); color: var(--rf-texto-secundario); margin-top: var(--rf-espacio-1); }

/* Separador de grupo (§4.5): un filete a cada lado de un texto en papel 600. */
.rf-separador-grupo { display: flex; align-items: center; gap: var(--rf-espacio-3); margin-block: var(--rf-espacio-5); color: var(--rf-color-neutro-600); font-size: var(--rf-tipo-pequeno-movil-tamano); }
.rf-separador-grupo::before,
.rf-separador-grupo::after { content: ""; flex: 1 1 auto; border-top: 1px solid var(--rf-filete); }
.rf-separador-grupo-aviso { color: var(--rf-color-semantico-aviso-texto); }

/* «Por qué aparece» (§4.5): hasta tres motivos en una línea separados por «·»; en el móvil, los dos primeros. */
.rf-porque-aparece { display: flex; flex-wrap: wrap; gap: 0 var(--rf-espacio-1); margin: 0; color: var(--rf-color-neutro-600); font-size: var(--rf-tipo-pequeno-movil-tamano); }
.rf-porque-aparece span:not(:last-child)::after { content: "·"; margin-left: var(--rf-espacio-1); }
.rf-porque-aparece-oculto-movil { display: none; }
@media (min-width: 576px) { .rf-porque-aparece-oculto-movil { display: inline; } }

/* Lista «qué te falta» (§4.5): filas separadas por filetes con el icono desnudo, el nombre y el estado a la derecha. */
.rf-que-falta { list-style: none; margin: 0; padding: 0; display: grid; border-top: 1px solid var(--rf-filete); }
.rf-que-falta-fila { border-bottom: 1px solid var(--rf-filete); }
.rf-que-falta-resumen { display: flex; align-items: center; gap: var(--rf-espacio-3); padding: var(--rf-espacio-3) 0; cursor: pointer; list-style: none; min-height: 48px; }
.rf-que-falta-resumen::-webkit-details-marker { display: none; }
.rf-que-falta-icono { display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0; min-width: 20px; font-size: 10px; color: var(--rf-texto-secundario); }
.rf-que-falta-nombre { flex: 1 1 auto; font-weight: 600; }
.rf-que-falta-estado { font-size: var(--rf-tipo-pequeno-movil-tamano); }
.rf-que-falta-estado-contratado { color: var(--rf-color-semantico-exito-texto); font-weight: 600; }
.rf-que-falta-estado-solicitado { color: var(--rf-color-semantico-aviso-texto); font-weight: 600; }
.rf-que-falta-estado-descartado { color: var(--rf-color-neutro-600); text-decoration: line-through; }
.rf-que-falta-contenido { padding: 0 0 var(--rf-espacio-4); }

/* Barra de presupuesto (§4.5): total, comprometido y restante; violeta lo comprometido, papel 200 lo restante, aviso si se
   rebasa. */
.rf-barra-presupuesto-cifras { display: flex; justify-content: space-between; font-size: var(--rf-tipo-pequeno-movil-tamano); margin-bottom: var(--rf-espacio-1); }
.rf-barra-presupuesto-total { font-family: var(--rf-fuente-titulos-pila); font-weight: 700; color: var(--rf-texto); }
.rf-barra-presupuesto { display: flex; height: 10px; border-radius: var(--rf-radio-xs); overflow: hidden; background: var(--rf-color-neutro-200); }
.rf-barra-presupuesto-comprometido { background: var(--rf-color-primario-700); }
.rf-barra-presupuesto-rebasado { background: var(--rf-color-semantico-aviso-texto); }
.rf-barra-presupuesto-edicion { min-height: 36px; width: 10ch; text-align: right; border: 1px solid var(--rf-color-neutro-400); border-radius: var(--rf-radio-sm); }

/* Anillo de calidad (§4.5): de 0 a 100 con el número en el centro y siempre con texto; < 40 error, 40–69 aviso,
   ≥ 70 éxito. Es un dato, no un adorno: el círculo lo dibuja el SVG del fragmento. */
.rf-anillo-calidad { display: inline-flex; align-items: center; gap: var(--rf-espacio-2); }
.rf-anillo-calidad svg { width: 64px; height: 64px; transform: rotate(-90deg); }
.rf-anillo-calidad-pista { fill: none; stroke: var(--rf-color-neutro-200); stroke-width: 3; }
.rf-anillo-calidad-relleno { fill: none; stroke-width: 3; stroke-linecap: round; transition: stroke-dashoffset var(--rf-duracion-lenta) var(--rf-curva-entrada); }
.rf-anillo-calidad-error .rf-anillo-calidad-relleno { stroke: var(--rf-color-semantico-error-texto); }
.rf-anillo-calidad-aviso .rf-anillo-calidad-relleno { stroke: var(--rf-color-semantico-aviso-texto); }
.rf-anillo-calidad-exito .rf-anillo-calidad-relleno { stroke: var(--rf-color-semantico-exito-texto); }
.rf-anillo-calidad-numero { position: relative; }
.rf-anillo-calidad-cifra { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; font-family: var(--rf-fuente-titulos-pila); font-weight: 700; font-size: var(--rf-tipo-pequeno-movil-tamano); }
.rf-anillo-calidad-24 svg { width: 24px; height: 24px; }
.rf-anillo-calidad-24 .rf-anillo-calidad-pista,
.rf-anillo-calidad-24 .rf-anillo-calidad-relleno { stroke-width: 4; }

/* Tabla de paneles (§4.5): sobre blanco con filete y radio lg; cabecera en secundario 13/600 SIN mayúsculas con un
   filete de TINTA debajo; filas de 48 px (40 en el backoffice) separadas por filetes; se convierte en lista de tarjetas
   en el móvil ("no en desplazamiento horizontal"). Una sola tabla en el marcado; la conversión es solo CSS, con
   `data-rf-etiqueta` como seudocabecera de cada celda. */
.rf-tabla-contenedor { overflow-x: auto; }
/* Con overflow-x: auto el eje vertical también se desplaza: en el móvil, el margen de la última tarjeta dejaba un
   desplazamiento vertical de unos píxeles, una región desplazable sin forma de llegar con el teclado (axe
   scrollable-region-focusable, /admin/salud; P14.4). El contenedor no tiene alto propio: nada queda oculto. */
.rf-tabla-contenedor { overflow-y: hidden; }
/* El contenedor es el bloque de referencia de lo que va en posición absoluta dentro de la tabla (el texto oculto
   `visually-hidden` de una cabecera): sin él, ese texto escapaba del desplazamiento y alargaba la página entera a 768
   y 1280 px (/admin/pagos/webhooks; revisión en navegador del 2026-09-30). */
.rf-tabla-contenedor { position: relative; }
.rf-tabla { width: 100%; border-collapse: separate; border-spacing: 0; font-size: var(--rf-tipo-pequeno-movil-tamano); background: var(--rf-superficie); border: 1px solid var(--rf-filete); border-radius: var(--rf-radio-lg); }
.rf-tabla th { text-align: left; font-size: var(--rf-tipo-etiqueta-movil-tamano); font-weight: 600; color: var(--rf-texto-secundario); padding: var(--rf-espacio-2) var(--rf-espacio-3); border-bottom: 1px solid var(--rf-color-neutro-900); }
.rf-tabla td { padding: var(--rf-espacio-2) var(--rf-espacio-3); border-top: 1px solid var(--rf-filete); height: 48px; }
.rf-tabla tbody tr:first-child td { border-top: 0; }
/* La cabecera de una fila (la reserva de «Ingresos», el nombre de un parámetro) es una celda más en negrita, no otra
   cabecera de columna: sin el filete de tinta y con el tamaño y el color del texto (P7.12 lo corrigió solo en los
   paneles; desde los restos de la revisión 4.5, en todas las tablas). */
.rf-tabla tbody th { font-size: inherit; font-weight: 600; color: var(--rf-texto); border-bottom: 0; border-top: 1px solid var(--rf-filete); }
.rf-tabla tbody tr:first-child th { border-top: 0; }
/* Solo con la tabla de verdad (desde 768 px): con más especificidad que el `height: auto` de las tarjetas del móvil, a
   360 px fijaba cada celda a 40 px y un formulario que baja de línea se montaba sobre la fila siguiente y la última
   quedaba cortada por el contenedor (/admin/parametros; revisión en navegador del 2026-09-30). */
@media (min-width: 768px) { body.rf-admin .rf-tabla td { height: 40px; } }
/* El paso del ratón por una fila, en papel: el color es estado, no un lila de «activo» (§4.5, §8.3). */
.rf-tabla tbody tr:hover { background: var(--rf-color-neutro-50); }
/* Una columna de cifras: a la derecha y con números tabulares, para que se comparen de un vistazo. */
.rf-tabla .rf-numero { text-align: right; font-variant-numeric: tabular-nums; }
/* Una celda de acciones sigue siendo una celda (P14.4): `.rf-acciones` la volvía flex centrada, fuera del modelo de
   la tabla, y a 1280 px sus botones se montaban unos sobre otros («Editar» tapado por «Quitar» en «Tarifas», axe
   target-size y foco tapado). Los botones van en fila y bajan si no caben. */
@media (min-width: 768px) {
  .rf-tabla td.rf-acciones { display: table-cell; }
  .rf-tabla td.rf-acciones > * { display: inline-flex; vertical-align: middle; margin: 2px var(--rf-espacio-2) 2px 0; }
}
@media (max-width: 767.98px) {
  .rf-tabla { border: 0; background: transparent; }
  .rf-tabla thead { display: none; }
  /* El pie de la tabla, a lo ancho: como leyenda de una tabla que ya no es tabla se quedaba en una columna de una
     palabra (la tabla de tarifas de «Destacados»; restos de la revisión 4.5). */
  .rf-tabla caption { display: block; width: 100%; }
  .rf-tabla, .rf-tabla tbody, .rf-tabla tr, .rf-tabla td { display: block; width: 100%; }
  .rf-tabla tr { border: 1px solid var(--rf-filete); border-radius: var(--rf-radio-lg); background: var(--rf-superficie); margin-bottom: var(--rf-espacio-3); padding: var(--rf-espacio-2); }
  .rf-tabla td { display: flex; justify-content: space-between; gap: var(--rf-espacio-3); border-top: 0; border-bottom: 1px solid var(--rf-color-neutro-100); height: auto; padding: var(--rf-espacio-2) var(--rf-espacio-1); text-align: right; }
  .rf-tabla td:last-child { border-bottom: none; }
  .rf-tabla td::before { content: attr(data-rf-etiqueta); font-weight: 600; color: var(--rf-texto-secundario); text-align: left; }
  /* Lo que no cabe junto al rótulo baja a la línea siguiente (P14.4, WCAG 1.4.10 y 2.4.11): sin partir, un
     formulario de la celda (el de /admin/parametros) se montaba sobre el texto de al lado a 640 px y la página
     se salía por la derecha a 360. */
  .rf-tabla td { flex-wrap: wrap; }
  .rf-tabla td > * { min-width: 0; max-width: 100%; }
}

/* ============================================================================================
   Cabecera pública completa (documento 03 §4.5; el armazón, en rf-base.css): el buscador compacto
   rectangular, los enlaces, «Acceder» con borde de tinta, y el menú del móvil.
   ============================================================================================ */
.rf-publico-cabecera { transition: transform var(--rf-duracion-media) var(--rf-curva-entrada); }
.rf-publico-cabecera-oculta { transform: translateY(-100%); }
.rf-publico-cabecera-interior { flex-wrap: nowrap; }
.rf-publico-buscador { display: none; position: relative; flex: 1 1 auto; min-width: 0; max-width: 420px; }
/* La lupa dentro del campo (P7.11, como el prototipo): el texto deja su hueco a la izquierda. */
.rf-publico-buscador-icono { position: absolute; left: var(--rf-espacio-3); top: 50%; transform: translateY(-50%); width: 16px; height: 16px; color: var(--rf-texto-secundario); pointer-events: none; }
.rf-publico-buscador input {
  width: 100%;
  min-height: 40px;
  padding: 0 var(--rf-espacio-3) 0 calc(var(--rf-espacio-3) + 24px);
  border: 1px solid var(--rf-color-neutro-400);
  border-radius: var(--rf-radio-md);
  background: var(--rf-superficie);
  color: var(--rf-texto);
  font-family: var(--rf-fuente-texto-pila);
  font-size: var(--rf-tipo-pequeno-movil-tamano);
}
.rf-publico-buscador input::placeholder { color: var(--rf-color-neutro-500); }
@media (min-width: 768px) { .rf-publico-buscador { display: block; } }
.rf-publico-cabecera-acciones { display: flex; align-items: center; gap: var(--rf-espacio-1); flex-shrink: 0; }
@media (min-width: 768px) { .rf-publico-cabecera-acciones { gap: var(--rf-espacio-4); } }
/* En el móvil el idioma se reconoce por su bandera (el selector tiene su nombre accesible): el código se oculta para
   que la cabecera quepa a 320 px. */
@media (max-width: 399.98px) { .rf-publico-cabecera .rf-idioma-codigo { display: none; } }

/* Escritorio (≥768 px, documento 03 §4.5): «Cómo funciona» (desde 992), «Soy proveedor» y «Acceder» en línea, sin menú
   de hamburguesa. Móvil: solo la marca, un icono de búsqueda que lleva a /buscar, y el botón de menú que despliega los
   enlaces — es literalmente lo que dice el documento ("En móvil: marca, buscar y menú"). */
.rf-publico-soy-proveedor,
.rf-publico-acceder { display: none; font-size: var(--rf-tipo-pequeno-movil-tamano); font-weight: 500; color: var(--rf-texto); text-decoration: none; min-height: 44px; align-items: center; }
.rf-publico-soy-proveedor:hover,
.rf-publico-acceder:hover { color: var(--rf-texto); text-decoration: underline; }
@media (min-width: 768px) { .rf-publico-soy-proveedor, .rf-publico-acceder { display: inline-flex; } }
.rf-publico-como-funciona { display: none; }
@media (min-width: 992px) { .rf-publico-como-funciona { display: inline-flex; } }
/* «Acceder» (§4.5): con borde de tinta, radio md. */
.rf-publico-entrar { min-height: 40px; padding: 0 14px; border: 1px solid var(--rf-color-neutro-900); border-radius: var(--rf-radio-md); }
.rf-publico-entrar:hover { background: var(--rf-color-neutro-100); text-decoration: none; }

.rf-publico-buscar-movil { display: inline-flex; align-items: center; justify-content: center; width: 44px; height: 44px; color: var(--rf-texto); }
@media (min-width: 768px) { .rf-publico-buscar-movil { display: none; } }

.rf-publico-menu-boton { display: inline-flex; border-color: transparent; background: transparent; }
@media (min-width: 768px) { .rf-publico-menu-boton { display: none; } }

.rf-publico-menu-panel {
  display: grid;
  gap: 2px;
  padding: var(--rf-espacio-2) var(--rf-espacio-4) var(--rf-espacio-4);
  border-top: 1px solid var(--rf-filete);
  background: var(--rf-fondo);
}
.rf-publico-menu-panel a {
  display: flex;
  align-items: center;
  min-height: 44px;
  padding: 0 var(--rf-espacio-2);
  border-radius: var(--rf-radio-md);
  color: var(--rf-texto);
  text-decoration: none;
  font-weight: 600;
}
.rf-publico-menu-panel a:hover { background: var(--rf-color-neutro-100); color: var(--rf-texto); }
@media (min-width: 768px) { .rf-publico-menu-panel { display: none !important; } }
/* Con sesión (pruebas funcionales del 2026-09-27): «Cerrar sesión» es un POST con su testigo CSRF, así que es un botón
   dentro de un formulario; se pinta igual que los enlaces vecinos. */
.rf-publico-salir { display: contents; }
.rf-publico-boton-salir { background: none; border: 0; padding: 0; cursor: pointer; font: inherit; }
.rf-publico-menu-salir {
  display: flex; align-items: center; width: 100%; min-height: 44px; padding: 0 var(--rf-espacio-2);
  border: 0; border-radius: var(--rf-radio-md); background: none; color: var(--rf-texto);
  font: inherit; font-weight: 600; text-align: left; cursor: pointer;
}
.rf-publico-menu-salir:hover { background: var(--rf-color-neutro-100); }
/* «Configurar cookies» del pie es un botón que se lee como los enlaces de su lista. */
.rf-pie-cookies { background: none; border: 0; padding: 0; font: inherit; color: var(--rf-texto-secundario); cursor: pointer; text-align: left; }
.rf-pie-cookies:hover { color: var(--rf-primario); text-decoration: underline; }

/* ============================================================================================
   Selector de idioma con banderas (fragments/idioma; pruebas funcionales del 2026-09-27): un <details> que despliega
   un menú pequeño. Funciona sin JavaScript; rf-form.js lo cierra al pulsar fuera o con Escape. El menú flota (sombra 2).
   ============================================================================================ */
.rf-idioma { position: relative; flex-shrink: 0; }
.rf-idioma-actual {
  display: inline-flex; align-items: center; gap: var(--rf-espacio-1);
  min-height: 44px; padding: 0 var(--rf-espacio-2);
  border-radius: var(--rf-radio-md); cursor: pointer; list-style: none;
  font-size: var(--rf-tipo-pequeno-movil-tamano); font-weight: 600; color: var(--rf-texto);
}
.rf-idioma-actual::-webkit-details-marker { display: none; }
.rf-idioma-actual::after { content: ""; border: 4px solid transparent; border-top-color: currentColor; margin-top: 4px; }
.rf-idioma-actual:hover, .rf-idioma[open] .rf-idioma-actual { background: var(--rf-color-neutro-100); }
.rf-idioma-actual:focus-visible { outline: 3px solid var(--rf-color-primario-500); outline-offset: 2px; }
.rf-idioma-bandera { width: 24px; height: 16px; object-fit: cover; border-radius: var(--rf-radio-xs); outline: 1px solid var(--rf-filete); outline-offset: -1px; }
.rf-idioma-lista {
  position: absolute; right: 0; top: calc(100% + 4px); z-index: var(--rf-capa-desplegable);
  display: grid; min-width: 11rem; padding: var(--rf-espacio-1);
  background: var(--rf-superficie); border: 1px solid var(--rf-filete); border-radius: var(--rf-radio-md);
  box-shadow: var(--rf-sombra-2);
}
.rf-idioma-opcion {
  display: flex; align-items: center; gap: var(--rf-espacio-2); width: 100%; min-height: 44px;
  padding: 0 var(--rf-espacio-3); border: 0; border-radius: var(--rf-radio-md); background: none;
  font: inherit; color: var(--rf-texto); text-align: left; cursor: pointer;
}
.rf-idioma-opcion:hover, .rf-idioma-opcion:focus-visible { background: var(--rf-color-neutro-100); color: var(--rf-texto); }
.rf-idioma-opcion-actual { font-weight: 700; }
.rf-idioma-opcion-actual::after { content: "✓"; margin-left: auto; color: var(--rf-primario); }
