/* =========================================================================
   Reserva pública — /@usuario/reservar y /r/<token>
   =========================================================================

   REGLA DE ESTE ARCHIVO: no inventa ni un token, ni un color, ni una sombra.
   Todo sale de linkr.css. Lo que hay aquí es composición: cómo se colocan las
   primitivas que ya existen para que el flujo se pueda completar de un tirón
   desde un móvil.

   Móvil primero, y de verdad: el flujo se diseñó a 320px y se ensancha. Los
   objetivos táctiles no bajan de 44px en ninguna pantalla.
   ========================================================================= */

/* Reserva es una superficie pública larga: la barra vertical aparece cuando
   hace falta y no debe reservar una franja lateral permanente. `linkr.css`
   usa `scrollbar-gutter: stable` para la aplicación autenticada; aquí esa
   reserva se traduce en dos píxeles extra del layout viewport móvil y hace que
   la raíz mida más que el lienzo. Se desactiva la reserva, no se oculta ningún
   desbordamiento: cualquier contenido que saliera del viewport seguirá siendo
   visible para la sonda y fallará la matriz. */
html {
    scrollbar-gutter: auto;
}

.rv {
    /* LA TIPOGRAFÍA SE DECLARA AQUÍ, y no sobra.

       linkr.css define el token `--font` pero NO lo aplica al <body>: eso lo
       hace la hoja de cada página (inicio.css, ajustes.css, editor.css…). Es la
       convención del proyecto y se respeta en lugar de tocar la hoja
       compartida, que afectaría a las cinco pantallas de siempre.

       Sin esta línea la página caía a la serif del navegador con las @font-face
       ya cargadas y todo: se declaraba Be Vietnam Pro y no la usaba nadie. No
       se detectó en ninguna de las 169 comprobaciones automáticas —el HTML era
       correcto, el CSS era correcto y la fuente se servía— y se vio en el
       primer segundo de mirar la pantalla. */
    font-family: var(--font);
    color: var(--ink);
    background: var(--page-bg);
    min-height: 100vh;
    display: flex;
    flex-direction: column;
}

/* -------------------------------------------------------------------------
   Cabecera: quién es el negocio. No es la isla del producto —quien reserva no
   tiene sesión ni secciones— pero comparte su altura y su tinta para que la
   página siga siendo Linkr.
   ---------------------------------------------------------------------- */
.rv-cab {
    display: flex;
    align-items: center;
    gap: var(--s-2);
    padding: var(--s-3) max(var(--s-3), env(safe-area-inset-left));
    border-bottom: 1px solid var(--line);
    background: var(--surface);
}

.rv-cab__volver {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 40px; height: 40px;
    flex: 0 0 auto;
    border-radius: 50%;
    color: var(--ink-2);
    text-decoration: none;
}
.rv-cab__volver:hover { background: var(--surface-2); }

/* 44px con el dedo. Es el criterio del producto y este botón es el único
   camino de vuelta que tiene la página. */
@media (pointer: coarse) {
    .rv-cab__volver { width: 44px; height: 44px; }
}

.rv-cab__quien {
    display: flex;
    align-items: center;
    gap: var(--s-2);
    min-width: 0;
    font-weight: 600;
    color: var(--ink);
}
.rv-cab__quien img {
    width: 32px; height: 32px;
    border-radius: 50%;
    object-fit: cover;
    flex: 0 0 auto;
}
.rv-cab__quien span {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* -------------------------------------------------------------------------
   El cuerpo
   ---------------------------------------------------------------------- */
.rv-main {
    flex: 1;
    width: 100%;
    max-width: 520px;
    margin: 0 auto;
    padding: var(--s-4) max(var(--s-3), env(safe-area-inset-left)) var(--s-6);
    box-sizing: border-box;
}
.rv-main--gestion { max-width: 440px; text-align: center; }

/* SIN CABECERA DEL NEGOCIO, EL TITULAR SE QUEDABA PEGADO AL BORDE DE ARRIBA.
   -------------------------------------------------------------------------
   `/r/<token>` pinta la cabecera con el nombre y la foto del negocio, y esa
   cabecera es la que separa el contenido del borde de la pantalla. Pero cuando
   el token NO existe no hay cita, así que no hay negocio del que sacar la
   cabecera — y entonces `main` es el primer hijo del `body` y arranca en y=0
   con sus 16px de relleno y nada más.

   Medido en un iPhone de 375: «No encontramos esa cita» empezaba a 16px del
   borde superior, a tamaño de titular y de lado a lado. No parecía una página
   de Linkr; parecía una página rota, que es justo lo que no puede parecer un
   error de una superficie pública.

   `:first-child` es exacto y no necesita tocar el PHP: cuando la cabecera
   existe, es ella la primera y esta regla no aplica sola. */
.rv-main:first-child { padding-top: var(--s-8); }

/* El título de cada paso.
   -------------------------------------------------------------------------
   Sube de 1.5rem a una escala fluida de 26 a 30px. No es capricho: cada
   pantalla de este flujo hace UNA pregunta, y la pregunta era del mismo
   tamaño que el nombre de un servicio de la lista de al lado. Con una sola
   cosa que leer, el titular puede —y debe— llevar el peso.

   `clamp` en vez de una media query para que crezca con la pantalla en lugar
   de dar un salto: a 320 son 26px, a 640 en adelante son 30. */
.rv-h1 {
    font-size: clamp(1.625rem, 1.35rem + 1.4vw, 1.875rem);
    font-weight: 700;
    letter-spacing: -.025em;
    line-height: 1.2;
    margin: 0 0 var(--s-2);
    color: var(--ink);
}
/* LA FECHA ERA CASI UN SEGUNDO TITULAR, y no lo es.
   ------------------------------------------------------------------------
   A 17px sobre `--ink-2`, debajo de un `<h1>` de 26, «Miércoles 19 de agosto»
   pesaba casi lo mismo que «¿A qué hora?». Tres bloques de texto seguidos con
   pesos parecidos no forman jerarquía: forman una lista.

   La pregunta manda —es lo que hay que hacer—, la fecha la acompaña y lo que
   se está reservando es el recordatorio. Se separan de verdad. */
.rv-sub { margin: 0 0 var(--s-1); color: var(--ink-3); font-size: var(--fs-md); }

/* Qué se está reservando. Subordinada al título y a la fecha: es un recordatorio,
   no una decisión. Se parte en varias líneas antes que salirse a 320px. */
.rv-elegido {
    margin: 0 0 var(--s-5);
    color: var(--ink-3);
    font-size: var(--fs-base);
    line-height: 1.5;
    overflow-wrap: break-word;
}
.rv-sub + .rv-elegido { margin-top: var(--s-2); }

/* El nombre del servicio, con peso. Era una cadena corrida —«Mechas · 2 h 30
   min · 85 € · con quien esté libre»— toda del mismo gris, así que la única
   parte que identifica lo que estás reservando se leía igual que su duración.
   Ahora el ojo tiene dónde agarrarse sin que la línea deje de ser secundaria. */
.rv-elegido strong { color: var(--ink-2); font-weight: 600; }

/* El estado vacío dentro del flujo respira igual que el resto del contenido. */
.rv-main .lk-vacio { margin-top: var(--s-2); }

/* -------------------------------------------------------------------------
   El progreso. Es una secuencia de estados, no cinco pestañas. El círculo
   explica posición/completado y la línea explica continuidad sin convertirlo
   en un componente alto en móvil.
   ---------------------------------------------------------------------- */
.rv-pasos {
    display: flex;
    gap: 0;
    list-style: none;
    margin: 0 0 var(--s-4);
    padding: 0;
    font-size: var(--fs-xs);
    color: var(--ink-3);
    counter-reset: rv-paso;
}
.rv-pasos li {
    counter-increment: rv-paso;
    position: relative;
    z-index: 0;
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.rv-pasos li::before {
    content: counter(rv-paso);
    position: relative;
    z-index: 2;
    display: grid;
    place-items: center;
    width: 26px;
    height: 26px;
    box-sizing: border-box;
    border: 2px solid var(--line-2);
    border-radius: 50%;
    background: var(--page-bg);
    color: var(--ink-3);
    font-size: var(--fs-2xs);
    font-weight: 700;
    line-height: 1;
}
.rv-pasos li:not(:last-child)::after {
    content: '';
    position: absolute;
    z-index: 1;
    top: 12px;
    left: calc(50% + 13px);
    width: calc(100% - 26px);
    height: 2px;
    background: var(--line);
}
.rv-pasos .esta-hecho { color: var(--ink-2); }
.rv-pasos .esta-hecho::before {
    content: '✓';
    border-color: var(--brand-200);
    background: var(--brand-100);
    color: var(--brand-text);
}
.rv-pasos .esta-hecho::after { background: var(--brand-200); }
.rv-pasos .es-actual { color: var(--brand-text); font-weight: 700; }
.rv-pasos .es-actual::before {
    border-color: var(--brand);
    background: var(--brand);
    color: #fff;
    box-shadow: 0 0 0 4px var(--brand-050);
}

@media (max-width: 380px) {
    .rv-pasos li { font-size: 0; }
    .rv-pasos .es-actual { font-size: var(--fs-xs); flex: 1.45; }
    .rv-pasos li::before { font-size: var(--fs-2xs); }
}

/* -------------------------------------------------------------------------
   Listas de servicio y de profesional.

   Es el patrón de `.est-fila` de estadísticas —icono, texto, cifra— adaptado a
   una fila pulsable. No se inventa un componente nuevo: se hereda el ritmo.
   ---------------------------------------------------------------------- */
.rv-lista { list-style: none; margin: 0; padding: 0; }
.rv-lista li + li { margin-top: var(--s-2); }

.rv-fila {
    display: flex;
    align-items: center;
    gap: var(--s-3);
    width: 100%;
    min-height: 56px;
    padding: var(--s-3);
    box-sizing: border-box;
    border: 1px solid var(--line);
    border-radius: var(--r-lg);
    background: var(--surface);
    text-decoration: none;
    color: inherit;
    transition: border-color .18s, box-shadow .18s, transform .18s;
}
.rv-fila:hover {
    border-color: var(--brand-200);
    box-shadow: var(--shadow-sm);
}
.rv-fila:active { transform: scale(.995); }

/* «Cualquiera» va primero porque es el camino más corto y el que más
   convierte. Llevaba el borde discontinuo, y eso lo hundía en vez de
   destacarlo: en este proyecto lo discontinuo significa «Otro / genérico»
   (`.ng-fam--otro`), o sea la opción de descarte. Aquí es justo la contraria.

   Ahora es una fila normal con el fondo de marca al 4 %: se lee como la
   recomendada sin gritar y sin estrenar ningún color. */
.rv-fila--cualquiera {
    border-color: var(--brand-200);
    background: color-mix(in srgb, var(--brand) 4%, var(--surface));
}
@supports not (background: color-mix(in srgb, red 4%, white)) {
    .rv-fila--cualquiera { background: var(--brand-050); }
}

.rv-fila__texto { flex: 1; min-width: 0; display: block; }
.rv-fila__nombre {
    display: flex;
    align-items: center;
    gap: var(--s-2);
    font-weight: 600;
    color: var(--ink);
}
/* DOS LÍNEAS, no una con puntos suspensivos.

   Estaba en `white-space: nowrap` y se veía al mirar la pantalla de «¿Con
   quién?»: «Cortes y color. Lleva el estudio desde …». Lo que se cortaba era
   justo la mitad que sirve para elegir a una persona. Con dos líneas caben las
   descripciones reales del sembrador enteras, y las larguísimas siguen
   teniendo tope.

   `.lk-clamp-2` es la primitiva que ya hace esto en el producto; aquí solo se
   heredan sus propiedades para no obligar a la plantilla a llevar dos clases
   en cada fila. */
.rv-fila__desc {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    margin-top: 2px;
    font-size: var(--fs-sm);
    line-height: 1.45;
    color: var(--ink-3);
    overflow: hidden;
    overflow-wrap: break-word;
}
.rv-fila__meta {
    display: block;
    margin-top: 4px;
    font-size: var(--fs-sm);
    font-weight: 500;
    color: var(--ink-2);
}
.rv-fila__flecha { flex: 0 0 auto; color: var(--ink-4); }

/* -------------------------------------------------------------------------
   Calendario. Sin librería: son 42 celdas y una <table>.
   ---------------------------------------------------------------------- */
.rv-cal {
    border: 1px solid var(--line);
    border-radius: var(--r-lg);
    background: var(--surface);
    padding: var(--s-3);
}
.rv-cal__cab {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--s-2);
    margin-bottom: var(--s-3);
}
/* El mes va centrado de verdad: `flex: 1` + `text-align: center`, y no
   confiando en que el hueco de la izquierda mida lo mismo que el botón de la
   derecha. Con `space-between` a secas el rótulo salía corrido hacia la
   derecha en cuanto los dos extremos no median exactamente igual — que es lo
   que pasa el primer mes, cuando no hay flecha de "anterior". */
.rv-cal__cab strong { flex: 1; text-align: center; font-size: var(--fs-md); }

/* Mismo ancho que `.lk-icon-btn`, para que el rótulo quede centrado también
   cuando falta una de las dos flechas. */
.rv-cal__hueco { width: 40px; flex: 0 0 auto; }

.rv-cal__rejilla { width: 100%; border-collapse: collapse; table-layout: fixed; }
.rv-cal__rejilla th {
    padding-bottom: var(--s-2);
    font-size: var(--fs-2xs);
    font-weight: 600;
    /* Las iniciales de los días del calendario: sin ellas no se sabe qué
       columna es cuál. Ver linkr.css § 1. */
    color: var(--ink-3);
    text-transform: uppercase;
    letter-spacing: .04em;
}
.rv-cal__rejilla th abbr { text-decoration: none; border: 0; }
.rv-cal__rejilla td { padding: 2px; text-align: center; }

.rv-dia {
    display: flex;
    align-items: center;
    justify-content: center;
    /* 40px de alto mínimo: es el objetivo táctil del resto del producto. */
    min-height: 40px;
    border-radius: var(--r-md);
    font-size: var(--fs-base);
    font-weight: 600;
    text-decoration: none;
    color: var(--brand-text);
    background: var(--brand-050);
    transition: background-color .15s;
}
.rv-dia:hover { background: var(--brand-100); }
.rv-dia.es-hoy { outline: 2px solid var(--brand); outline-offset: -2px; }

/* Un día sin huecos NO es un enlace: es un <span>. No se puede tabular ni
   pulsar, así que no promete nada que no vaya a cumplir. */
.rv-dia--no {
    /* NO SE PUEDE PULSAR, PERO HAY QUE PODER LEERLO.
       La atenuación es la señal —y la leyenda de debajo la explica con
       palabras, que es lo que hace que funcione— pero el NÚMERO del día sigue
       siendo el dato que orienta en la rejilla: sin él no se sabe si el que
       está libre es el 12 o el 19. El contraste con el hueco libre lo dan el
       fondo y el peso, no la ilegibilidad. */
    color: var(--ink-3);
    background: transparent;
    font-weight: 400;
    cursor: default;
}

/* Y un día que YA PASÓ, más apagado todavía.
   -------------------------------------------------------------------------
   Con un solo estado para «no se puede», el 3 de agosto y un sábado completo
   se dibujaban igual, y abriendo la reserva un día 24 eso son tres semanas de
   la rejilla diciendo lo mismo que un día lleno.

   La diferencia se hace con la tinta y no con otra forma: son la misma clase
   de casilla —texto plano, sin fondo, sin pulsar— y lo único que cambia es
   cuánta atención piden. Se queda legible a propósito: el número del día es lo
   que orienta en la rejilla, y esa razón, que está escrita justo aquí arriba,
   vale igual para el pasado. `--ink-4` es lo correcto aquí y no una excepción a
   su regla: esto no es texto informativo, es la retícula del calendario. */
.rv-dia--pasado { color: var(--ink-4); }

.rv-leyenda { margin-top: var(--s-3); text-align: center; max-width: none; }

/* -------------------------------------------------------------------------
   Horas
   ---------------------------------------------------------------------- */
.rv-horas { border: 0; margin: 0 0 var(--s-4); padding: 0; }
.rv-horas legend {
    padding: 0;
    margin-bottom: var(--s-2);
    font-size: var(--fs-sm);
    font-weight: 600;
    color: var(--ink-3);
}
.rv-horas__rejilla {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(78px, 1fr));
    gap: var(--s-2);
}
.rv-hora { min-height: 44px; justify-content: center; }
.rv-turnos { display: grid; gap: var(--s-1); }

/* -------------------------------------------------------------------------
   Resumen
   ---------------------------------------------------------------------- */
.rv-resumen {
    margin: 0 0 var(--s-4);
    padding: var(--s-3);
    border: 1px solid var(--line);
    border-radius: var(--r-lg);
    background: var(--surface);
}
.rv-resumen div {
    display: flex;
    justify-content: space-between;
    gap: var(--s-3);
    padding: 6px 0;
}
.rv-resumen div + div { border-top: 1px solid var(--line-soft); }
.rv-resumen dt { color: var(--ink-3); font-size: var(--fs-base); }
.rv-resumen dd { margin: 0; font-weight: 600; text-align: right; }
.rv-resumen--final { text-align: left; }

/* -------------------------------------------------------------------------
   Formulario
   ---------------------------------------------------------------------- */
.rv-form .lk-field { margin-bottom: var(--s-3); }
.rv-form.esta-enviando { opacity: .82; }
.rv-hora-form { margin: 0; min-width: 0; }
.rv-hora-form .rv-hora { width: 100%; }
.rv-horas-ayuda { margin-top: 20px; max-width: 48ch; }
.rv-retencion {
    display: flex; align-items: center; gap: 10px;
    padding: 12px 14px; margin: 0 0 22px; border-radius: 14px;
    background: #edf8f3; border: 1px solid #d4ebdf; color: #225f49;
}
.rv-retencion p { flex: 1; min-width: 0; margin: 0; font-size: 12px; line-height: 1.5; }
.rv-retencion strong, .rv-retencion p span { display: block; }
.rv-retencion strong { font-size: 13px; }
.rv-retencion__punto { width: 7px; height: 7px; flex: none; border-radius: 50%; background: currentColor; }
.rv-retencion__tiempo { font-size: 17px; font-weight: 700; font-variant-numeric: tabular-nums; white-space: nowrap; }
.rv-retencion--caducada { background: #fff6e8; color: #805312; border-color: #f0dfc1; }

/* Un último paso breve, sin registro ni formularios que desplacen la página. */
.rv-main--paso-6 { max-width: 540px; }
.rv-verificar { padding: clamp(20px, 5vw, 32px); border: 1px solid var(--line); border-radius: 24px; background: var(--surface); box-shadow: var(--shadow-sm); }
.rv-verificar__icono { display: grid; place-items: center; width: 52px; height: 52px; margin-bottom: 20px; border-radius: 16px; background: var(--brand-050); color: var(--brand-text); }
.rv-verificar .rv-h1 { margin-bottom: 10px; }
.rv-verificar__intro { margin: 0 0 24px; color: var(--ink-3); line-height: 1.65; overflow-wrap: anywhere; }
.rv-verificar__intro strong { color: var(--ink); font-weight: 600; }
.rv-verificar__cita { display: flex; flex-direction: column; gap: 6px; padding: 16px; margin-bottom: 24px; border-radius: 14px; background: var(--surface-2); font-size: var(--fs-sm); }
.rv-verificar__cita span { color: var(--ink-3); line-height: 1.5; }
.rv-verificar .rv-codigo { width: 100%; min-width: 0; box-sizing: border-box; height: 60px; margin-top: 8px; text-align: center; font-size: 26px; letter-spacing: .25em; font-variant-numeric: tabular-nums; }
.rv-verificar .rv-codigo::placeholder { color: var(--ink-4); }
.rv-verificar .lk-help { margin: 10px 0 20px; }
.rv-verificar__ayuda { margin-top: 24px; padding-top: 20px; border-top: 1px solid var(--line); }
.rv-verificar__ayuda p, .rv-verificar__privado { font-size: var(--fs-xs); color: var(--ink-3); line-height: 1.6; }
.rv-verificar__ayuda p { margin: 0 0 12px; }
.rv-verificar__otra { display: block; padding: 12px 0; text-align: center; font-size: var(--fs-sm); color: var(--brand-text); }
.rv-verificar__privado { margin: 16px 0 0; }
@media (max-width: 420px) {
    .rv-main--paso-6 .rv-pasos li { font-size: 0; }
    .rv-main--paso-6 .rv-pasos .es-actual { font-size: var(--fs-xs); flex: 1.5; }
    .rv-verificar { padding: 20px; border-radius: 20px; }
}
/* Igual que `.ng-opcional`: «(opcional)» cambia el significado del campo de
   al lado y no puede ser lo menos legible de la etiqueta. */
.rv-opcional { font-weight: 400; color: var(--ink-3); }

/* El honeypot. Fuera de la pantalla pero NO con display:none: algunos bots
   ignoran los campos ocultos con display:none precisamente porque saben que
   suelen ser trampas. */
.rv-hp {
    position: absolute;
    left: -9999px;
    width: 1px; height: 1px;
    overflow: hidden;
}

/* -------------------------------------------------------------------------
   Confirmación
   ---------------------------------------------------------------------- */
.rv-ok { text-align: center; }
.rv-ok__icono {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 56px; height: 56px;
    margin-bottom: var(--s-3);
    border-radius: 50%;
    background: var(--ok-soft);
    color: var(--ok);
}
.rv-ok h1 { font-size: 1.5rem; margin: 0 0 var(--s-1); letter-spacing: -.02em; }
.rv-ok__cuando { margin: 0 0 var(--s-4); color: var(--ink-2); font-size: var(--fs-lg); }
.rv-ok__acciones { display: flex; flex-direction: column; gap: var(--s-2); margin-bottom: var(--s-3); }
.rv-ok__nota { text-align: left; }

.rv-estado {
    display: inline-block;
    margin: 0 0 var(--s-3);
    padding: 6px 14px;
    border-radius: var(--r-pill);
    background: var(--surface-3);
    color: var(--ink-2);
    font-size: var(--fs-sm);
    font-weight: 600;
}
.rv-estado--cancelada { background: var(--danger-soft); color: var(--danger); }

/* «Elegir otro día» / «Elegir otra hora».

   Es una ACCIÓN de navegación, no un enlace dentro de una frase, así que la
   excepción de los enlaces en línea no le vale: medía 18px de alto y había que
   apuntarle. Ahora es una pastilla de 44 con su propio relleno, discreta en
   color pero cómoda de tocar. */
.rv-atras { margin-top: var(--s-4); text-align: center; font-size: var(--fs-base); }
.rv-atras a {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: 44px;
    padding: 0 var(--s-4);
    border-radius: var(--r-pill);
    color: var(--ink-3);
    text-decoration: none;
}
.rv-atras a:hover { background: var(--surface-2); color: var(--ink-2); }
.rv-atras a:focus-visible { text-decoration: underline; }

/* -------------------------------------------------------------------------
   Los legales dentro de un formulario: un escalón por debajo del texto de
   ayuda normal. Se leen si se buscan y no compiten con el botón.
   ---------------------------------------------------------------------- */
/* Texto legal: es justo lo que no puede quedar por debajo del mínimo. */
.lk-help--legal { color: var(--ink-3); font-size: var(--fs-xs); margin-top: var(--s-2); }
.lk-help--legal a { color: var(--ink-3); text-decoration: underline; }

/* -------------------------------------------------------------------------
   A partir de 640 hay sitio para respirar, no para cambiar de diseño: la
   columna sigue siendo una y estrecha. Un flujo de reserva a 1200px de ancho
   se lee peor, no mejor.
   ---------------------------------------------------------------------- */
@media (min-width: 640px) {
    .rv-main { padding-top: var(--s-6); }
    .rv-cab { padding-left: var(--s-4); padding-right: var(--s-4); }
}

/* Desktop no es un móvil aislado en medio del monitor. Las decisiones que se
   comparan usan dos columnas; calendario y datos conservan un ancho de lectura
   deliberado. El encabezado se alinea con el lienzo de 960 px. */
@media (min-width: 900px) {
    .rv-cab {
        padding-left: max(var(--s-4), calc((100vw - 960px) / 2));
        padding-right: max(var(--s-4), calc((100vw - 960px) / 2));
    }
    /* AQUÍ YA NO SE DECLARA EL RELLENO SUPERIOR, Y ES A PROPÓSITO.
       -------------------------------------------------------------------
       Esta regla llevaba `padding-top: var(--s-7)`, y `--s-7` no existe: la
       escala salta de `--s-6` (24) a `--s-8` (32). Un `var()` sin respaldo
       cuyo token no está declarado invalida la declaración entera, así que el
       relleno valía 0 desde 900px sin que nadie lo viera.
       Se corrigió a `--s-6` y entonces se vio lo de verdad: `.rv-main` YA
       lleva `padding-top: var(--s-6)` desde 640px, así que la declaración era
       redundante — una regla que existía para no cambiar nada. Se retira y el
       valor sigue siendo 24px, heredado del tramo anterior.
       Medido después de quitarla: 24px a 900 y a 1280.
       Lo que sí es propio de este tramo —el ancho— se queda. */
    .rv-main:not(.rv-main--gestion) { max-width: 960px; }
    .rv-main--paso-1 .rv-lista,
    .rv-main--paso-2 .rv-lista {
        display: grid;
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: var(--s-3);
    }
    .rv-main--paso-1 .rv-lista li + li,
    .rv-main--paso-2 .rv-lista li + li { margin-top: 0; }
    .rv-main--paso-1 .rv-fila,
    .rv-main--paso-2 .rv-fila { min-height: 82px; }
    .rv-main--paso-3 { max-width: 680px !important; }
    .rv-main--paso-4 { max-width: 820px !important; }
    .rv-main--paso-4 .rv-turnos {
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: var(--s-6);
    }
    .rv-main--paso-4 .rv-horas { margin-bottom: 0; }
    .rv-main--paso-5 { max-width: 900px !important; }
    .rv-datos-layout {
        display: grid;
        grid-template-columns: minmax(250px, .8fr) minmax(360px, 1.2fr);
        align-items: start;
        gap: clamp(36px, 5vw, 72px);
    }
    .rv-datos-layout .rv-resumen { position: sticky; top: var(--s-5); }
    .rv-main--paso-7 { max-width: 620px !important; }
    .rv-main.rv-main--paso-6 { max-width: 540px; }
}

/* =========================================================================
   EL AVANCE, CONTADO CON MOVIMIENTO

   Ver la nota larga de reservar.php: los cuatro pasos son recargas de página y
   la barra de progreso afirmaba un avance que la pantalla no respaldaba.

   TRES DECISIONES, Y LAS TRES SON DE CONTENCIÓN:

   1. LA BARRA DE PROGRESO NO SE MUEVE. `:not(.rv-pasos)` la deja fija a
      propósito: es la referencia contra la que se percibe el movimiento. Si se
      moviera todo a la vez no habría avance, habría un cambio de pantalla.

   2. 14 PÍXELES Y 340 ms. Lo justo para que el ojo registre una dirección. Un
      desplazamiento grande convierte una recarga en una transición de app y
      hace que el producto PAREZCA más lento de lo que es, que es exactamente lo
      contrario de lo que se busca.

   3. `both` y no `forwards`: el primer fotograma se aplica antes de empezar, y
      así no hay un destello del contenido en su sitio final antes de arrancar.

   Y las dos las apaga el bloque global de `prefers-reduced-motion` de
   linkr.css § 2 sin necesidad de guarda propia — comprobado: esta hoja carga
   linkr.css.
   ========================================================================= */
.rv-main--adelante > *:not(.rv-pasos) {
    animation: rv-entra-der var(--dur-slow) var(--ease) both;
}

.rv-main--atras > *:not(.rv-pasos) {
    animation: rv-entra-izq var(--dur-slow) var(--ease) both;
}

@keyframes rv-entra-der {
    from { opacity: 0; transform: translateX(14px); }
    to   { opacity: 1; transform: none; }
}

@keyframes rv-entra-izq {
    from { opacity: 0; transform: translateX(-14px); }
    to   { opacity: 1; transform: none; }
}

/* Reprogramación dentro del enlace de gestión. */
.rv-cambio {
    margin: var(--s-6) 0;
    padding: var(--s-5);
    border: 1px solid var(--line);
    border-radius: var(--r-lg);
    background: var(--surface);
    box-shadow: var(--shadow-xs);
}
.rv-cambio h2 { margin: 0; font-size: var(--fs-lg); color: var(--ink); }
.rv-cambio > p { margin: var(--s-2) 0 var(--s-5); color: var(--ink-3); line-height: 1.5; }
.rv-cambio__filtros { display: grid; gap: var(--s-3); }
.rv-cambio__filtros label { display: grid; gap: 6px; font-size: var(--fs-sm); font-weight: 600; color: var(--ink-2); }
.rv-cambio__filtros input,
.rv-cambio__filtros select {
    width: 100%; min-height: 46px; padding: 10px 12px;
    border: 1px solid var(--line-2); border-radius: var(--r-md);
    background: var(--surface); color: var(--ink); font: inherit;
}
/* `--focus` no se declara en ninguna hoja; ver inicio.css. */
.rv-cambio__filtros input:focus-visible,
.rv-cambio__filtros select:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
.rv-cambio__confirmar { margin-top: var(--s-5); }
.rv-cambio .lk-btn { min-height: 46px; }
.rv-cambio__confirmar > .lk-btn--primary { min-height: 48px; }
.rv-cambio__confirmar fieldset { margin: 0 0 var(--s-4); padding: 0; border: 0; }
.rv-cambio__confirmar legend { margin-bottom: var(--s-3); font-size: var(--fs-sm); font-weight: 700; color: var(--ink-2); }
.rv-cambio .rv-horas { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }
.rv-cambio .rv-hora { position: relative; cursor: pointer; }
.rv-cambio .rv-hora input { position: absolute; opacity: 0; pointer-events: none; }
.rv-cambio .rv-hora span {
    display: grid; min-height: 46px; place-items: center;
    border: 1px solid var(--line-2); border-radius: var(--r-md);
    background: var(--surface); color: var(--ink-2);
    font-size: var(--fs-md); font-weight: 700; font-variant-numeric: tabular-nums;
    transition: background-color var(--dur) var(--ease), border-color var(--dur) var(--ease), color var(--dur) var(--ease);
}
.rv-cambio .rv-hora input:checked + span { border-color: var(--brand); background: var(--brand); color: #fff; }
/* El más importante de los cuatro: el `input` está a `opacity: 0`, así que
   esta regla era su ÚNICA señal posible de foco. Con `--focus` sin declarar,
   elegir hora con el teclado en la reprogramación pública no se veía. */
.rv-cambio .rv-hora input:focus-visible + span { outline: 2px solid var(--brand); outline-offset: 2px; }
.rv-cambio__confirmar + .lk-btn { margin-top: var(--s-3); }
@media (max-width: 380px) { .rv-cambio .rv-horas { grid-template-columns: repeat(2, 1fr); } }
@media (prefers-reduced-motion: reduce) { .rv-cambio .rv-hora span { transition: none; } }
