/* ─────────────────────────────────────────────────────────────────
   Capa de componentes del rediseño.

   Por qué vive en su propio archivo y no dentro de styles.css: aquel
   creció por pantalla —`.bundle-*`, `.tele-*`, `.week-*`, `.wallet-*`,
   `.vp-*`— y ya arrastra unas 450 clases donde nadie puede saber cuál
   sigue en uso. Esto es lo contrario: bloques por componente, cada uno
   usado por varias pantallas. A medida que una pantalla migra, sus
   clases viejas de styles.css quedan huérfanas y se borran.

   Se carga DESPUÉS de styles.css a propósito, así que durante la
   migración una pantalla puede usar las dos capas sin pelear.

   Los nombres siguen BEM como los bloques nuevos del proyecto
   (`.system-state__icon`, `.address-card__actions`) y ninguno colisiona
   con los que ya existen: se verificó contra la lista completa.

   Móvil primero. Los cortes son los del proyecto: 640, 768, 1024.
   ───────────────────────────────────────────────────────────────── */


/* ═══ Icono ══════════════════════════════════════════════════════
   Todos salen de `{% icono %}` sobre una caja de 24×24 (`core/icons.py`).

   El tamaño y el grosor del trazo se deciden JUNTOS y los pone el
   componente, no la plantilla: el mismo icono mide 13 px en una etiqueta y
   26 px en una burbuja, y a 13 px un trazo de 1,7 se aguada mientras a 26 px
   se empasta. Por eso el peso sube cuando el icono se achica. Cambiar uno sin
   el otro es exactamente lo que hacía que dos iconos vecinos parecieran de
   familias distintas.

   Las parejas salen de los mockups: chevrones de 12 px a 2,4; iconos de fila
   de 17 px a 1,7–1,9; burbujas de 26 px a 1,5.                                */

.ic {
    flex: none;
    inline-size: var(--ic-tam, 1.0625rem);
    block-size: var(--ic-tam, 1.0625rem);
    stroke-width: var(--ic-trazo, 1.8);
}

/* Un icono relleno pesa mucho más que el mismo icono en trazo. Se usa
   solo cuando el estado ya ocurrió —la reseña escrita, el pago hecho— y
   nunca al lado de otro del mismo tamaño en trazo. */
.ic--relleno { fill: currentColor; stroke: none; }


/* ═══ Barra de navegación ══════════════════════════════════════════
   La píldora blanca que flota sobre el lienzo. Reemplaza a `.topbar`.  */

.appbar {
    position: relative;
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: .5rem .5rem .5rem .875rem;
    border-radius: var(--r-pill);
    background: var(--bg);
    box-shadow: var(--shadow-sm);
}

.appbar__brand {
    display: inline-flex;
    align-items: center;
    gap: .625rem;
    flex: none;
    min-block-size: var(--control-min);
}

/* width junto a height: sin él el navegador no reserva el hueco y la
   barra salta al cargar. Mismo motivo que en la barra actual. */
.appbar__logo {
    block-size: 2rem;
    inline-size: auto;
    display: block;
}

.appbar__wordmark {
    font-family: var(--font-display);
    font-size: 1.125rem;
    font-weight: 700;
    letter-spacing: -.03em;
    color: var(--navy);
    white-space: nowrap;
}

.appbar__wordmark span { color: var(--green); }

/* La insignia de rol del veterinario. */
.appbar__role {
    display: none;
    align-items: center;
    min-block-size: 1.625rem;
    padding-inline: .75rem;
    border-radius: var(--r-pill);
    background: var(--action-neutral-surface);
    color: var(--navy);
    font-size: .75rem;
    font-weight: 700;
    letter-spacing: .04em;
}

/* La navegación se esconde bajo 1024px y la reemplaza el botón de menú:
   a ese ancho los cuatro enlaces más las acciones no caben sin que el
   logo se comprima, que es el defecto que ya tuvo la barra actual. */
.appbar__nav {
    display: none;
    gap: .25rem;
}

.appbar__link {
    display: inline-flex;
    align-items: center;
    gap: .375rem;
    min-block-size: var(--control-min);
    padding-inline: 1rem;
    border-radius: var(--r-pill);
    color: var(--muted);
    font-size: .90625rem;
    font-weight: 600;
    white-space: nowrap;
    transition: color .15s, background .15s;
}

.appbar__link:hover { color: var(--green-ink); }

/* El chevron de un enlace es puntuación, no icono: a 12 px necesita
   2,4 de trazo para pesar lo mismo que la palabra que acompaña. */
.appbar__link { --ic-tam: .75rem; --ic-trazo: 2.4; }

.appbar__link--activa {
    background: var(--tint-green);
    color: var(--navy);
}

.appbar__link--activa:hover { color: var(--navy); }

/* ── Menú desplegable bajo 1024px ──────────────────────────────────
   Bajo ese ancho los enlaces no caben en la píldora, así que el panel
   se despliega desde la barra. El JS es el que ya existe
   (site-navigation.js): abre por [data-nav-toggle] y marca
   `nav-open` en <html>. */

.appbar__toggle {
    flex: none;
    margin-inline-start: auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    inline-size: var(--control-min);
    block-size: var(--control-min);
    border: none;
    border-radius: var(--r-pill);
    background: transparent;
    color: var(--navy);
    cursor: pointer;
}

.appbar__toggle { --ic-tam: 1.375rem; --ic-trazo: 1.9; }
.appbar__toggle:hover { background: var(--bg-soft); }

.appbar__panel {
    display: none;
    position: absolute;
    inset-block-start: calc(100% + .5rem);
    inset-inline: 0;
    z-index: 60;
    padding: var(--space-3);
    border-radius: var(--r-xl);
    background: var(--bg);
    box-shadow: var(--shadow-pop);
}

.nav-open .appbar__panel { display: block; }

.appbar__panel .appbar__nav {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: .125rem;
}

.appbar__panel .appbar__link {
    justify-content: flex-start;
    border-radius: var(--r-md);
}

/* El velo cierra al tocar fuera. Va bajo el panel y sobre la página. */
.appbar__scrim {
    display: none;
    position: fixed;
    inset: 0;
    z-index: 55;
    border: none;
    background: rgba(20, 30, 80, .28);
    cursor: default;
}

.nav-open .appbar__scrim { display: block; }

.appbar__actions {
    display: flex;
    align-items: center;
    gap: .5rem;
}

.appbar__icon-btn {
    position: relative;
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    inline-size: var(--control-min);
    block-size: var(--control-min);
    border: none;
    border-radius: var(--r-pill);
    background: var(--bg-soft);
    color: var(--navy);
    cursor: pointer;
    transition: background .15s;
}

.appbar__icon-btn { --ic-tam: 1.1875rem; --ic-trazo: 1.7; }
.appbar__icon-btn:hover { background: var(--action-neutral-surface); }

/* El número es visual: el rótulo accesible lo dice para quien no lo ve. */
.appbar__badge {
    position: absolute;
    inset-block-start: .1875rem;
    inset-inline-end: .1875rem;
    min-inline-size: 1rem;
    block-size: 1rem;
    padding-inline: .25rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: var(--r-pill);
    background: var(--orange);
    color: #fff;
    font-size: .625rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

.appbar__user {
    display: inline-flex;
    align-items: center;
    gap: .5625rem;
    min-block-size: var(--control-min);
    padding-inline: .25rem .875rem;
    border: none;
    border-radius: var(--r-pill);
    background: var(--bg-soft);
    color: var(--navy);
    font-family: var(--font-body);
    font-size: .875rem;
    font-weight: 650;
    cursor: pointer;
}

.appbar__user { --ic-tam: .75rem; --ic-trazo: 2.4; }

.appbar__user-name { display: none; }

.appbar__avatar {
    flex: none;
    inline-size: 2.125rem;
    block-size: 2.125rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: var(--r-pill);
    background: var(--tint-navy);
    color: var(--navy);
    font-size: .8125rem;
    font-weight: 700;
    overflow: hidden;
}

.appbar__avatar img {
    inline-size: 100%;
    block-size: 100%;
    object-fit: cover;
}

@media (min-width: 640px) {
    .appbar__user-name { display: inline; }
    .appbar__wordmark { font-size: 1.1875rem; }
}

@media (min-width: 1024px) {
    .appbar {
        gap: var(--space-5);
        padding-inline-start: 1.625rem;
    }
    .appbar__nav { display: flex; }
    .appbar__role { display: inline-flex; }
    .appbar__toggle { display: none; }
    .appbar__actions { margin-inline-start: auto; }

    /* Ya no es un desplegable: los enlaces viven en la barra. */
    .appbar__panel {
        display: contents;
        position: static;
        padding: 0;
        border-radius: 0;
        box-shadow: none;
        background: none;
    }

    .appbar__panel .appbar__nav { flex-direction: row; align-items: center; }
    .appbar__panel .appbar__link { justify-content: center; border-radius: var(--r-pill); }
    .appbar__scrim { display: none; }
}


/* ═══ Encabezado de vista ══════════════════════════════════════════ */

.view-head {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: var(--space-4);
}

.view-head__main { min-inline-size: 0; }

.view-head__title {
    font-family: var(--font-display);
    font-size: clamp(1.75rem, 6vw, 2.125rem);
    font-weight: 700;
    letter-spacing: -.03em;
    line-height: 1.14;
    color: var(--navy);
    margin: 0;
}

.view-head__sub {
    margin: .375rem 0 0;
    color: var(--muted);
    font-size: 1rem;
}

.view-head__action { margin-inline-start: auto; }


/* ═══ Navegación de sección ════════════════════════════════════════
   La fila de píldoras que saca las pantallas de la cuenta del menú del
   avatar. En teléfono se desliza en horizontal en vez de envolverse:
   siete píldoras envueltas ocupan tres líneas y empujan el contenido
   fuera de la primera pantalla. */

.section-nav {
    display: flex;
    gap: var(--space-2);
    overflow-x: auto;
    scrollbar-width: none;
    overscroll-behavior-inline: contain;
    margin-inline: calc(var(--page-gutter) * -1);
    padding-inline: var(--page-gutter);
    padding-block-end: var(--space-1);
}

.section-nav::-webkit-scrollbar { display: none; }

.section-nav__item {
    display: inline-flex;
    align-items: center;
    gap: .4375rem;
    flex: none;
    min-block-size: 2.5rem;
    padding-inline: 1.125rem;
    border-radius: var(--r-pill);
    background: var(--bg);
    color: var(--muted);
    font-size: .875rem;
    font-weight: 600;
    white-space: nowrap;
    transition: background .15s, color .15s;
}

.section-nav__item:hover { color: var(--navy); }

.section-nav__item--activa {
    background: var(--surface-inverse);
    color: var(--surface-inverse-text);
    font-weight: 650;
}

.section-nav__item--activa:hover { color: var(--surface-inverse-text); }

/* Variante de filtro: mismo componente, pero el activo se marca con
   contorno en vez de relleno, porque conviven en la misma pantalla y
   dos rellenos oscuros competirían. */
.section-nav__item--marcada {
    border: 1.5px solid var(--navy);
    color: var(--navy);
    font-weight: 700;
}

.section-nav__count {
    min-inline-size: 1.25rem;
    block-size: 1.25rem;
    padding-inline: .375rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: var(--r-pill);
    background: var(--surface-inverse);
    color: #fff;
    font-size: .71875rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

.section-nav__item--activa .section-nav__count {
    background: rgba(255, 255, 255, .22);
}

@media (min-width: 768px) {
    .section-nav {
        flex-wrap: wrap;
        overflow-x: visible;
        margin-inline: 0;
        padding-inline: 0;
    }
}


/* ═══ Superficies ══════════════════════════════════════════════════ */

.panel {
    background: var(--bg);
    border-radius: var(--r-xl);
    padding: var(--space-5);
}

.panel--raised { box-shadow: var(--shadow-sm); }
.panel--floating { box-shadow: var(--shadow-md); }

/* El escalón de adentro: un bloque anidado que necesita separarse del
   blanco de su propia tarjeta. */
.panel--sunken {
    background: var(--surface-sunken);
    border-radius: var(--r-lg);
    padding: var(--space-4);
}

.panel--alerta {
    background: #FFF8F3;
    border: 1.5px solid #F2D2B8;
    color: var(--orange-ink);
}

/* Bloque de marca. Los halos van en pseudo-elementos para que el markup
   no cargue con dos divs decorativos por cada uso. */
.panel--navy {
    position: relative;
    overflow: hidden;
    background: var(--surface-inverse);
    color: var(--surface-inverse-text);
}

.panel--navy::before,
.panel--navy::after {
    content: '';
    position: absolute;
    border-radius: var(--r-pill);
    pointer-events: none;
}

.panel--navy::before {
    inset-block-start: -3.75rem;
    inset-inline-end: -3.125rem;
    inline-size: 11.25rem;
    block-size: 11.25rem;
    background: rgba(105, 174, 43, .2);
}

.panel--navy::after {
    inset-block-end: -5rem;
    inset-inline-start: -2.5rem;
    inline-size: 9.375rem;
    block-size: 9.375rem;
    background: rgba(59, 164, 219, .16);
}

.panel--navy > * { position: relative; }

.panel__title {
    font-family: var(--font-display);
    font-size: 1.0625rem;
    font-weight: 650;
    color: var(--navy);
    margin: 0;
}

.panel--navy .panel__title { color: var(--surface-inverse-text); }

.panel__eyebrow {
    margin: 0;
    font-size: .75rem;
    font-weight: 700;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--muted);
}

.panel--navy .panel__eyebrow { color: #9FB0DB; }


/* ═══ Botón píldora ════════════════════════════════════════════════ */

.pill {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: .5rem;
    min-block-size: var(--control-min);
    padding-inline: 1.125rem;
    border: none;
    border-radius: var(--r-pill);
    background: var(--bg-soft);
    color: var(--navy);
    font-family: var(--font-body);
    font-size: .90625rem;
    font-weight: 650;
    text-align: center;
    cursor: pointer;
    transition: background .15s, color .15s, filter .15s;
}

.pill:hover { background: var(--action-neutral-surface); color: var(--navy); }

.pill--primary { background: var(--green-ink); color: #fff; }
.pill--primary:hover { background: var(--green-ink-hover); color: #fff; }

.pill--navy { background: var(--surface-inverse); color: #fff; }
.pill--navy:hover { filter: brightness(1.15); color: #fff; }

.pill--urgente { background: var(--orange-ink); color: #fff; }
.pill--urgente:hover { filter: brightness(.94); color: #fff; }

.pill--contorno {
    background: var(--bg);
    border: 1.5px solid var(--border);
}
.pill--contorno:hover { background: var(--bg); border-color: var(--navy); }

.pill--peligro { background: transparent; color: var(--danger-ink); }
.pill--peligro:hover { background: var(--danger-surface); color: var(--danger-ink-strong); }

/* El botón que confirma algo destructivo tiene que verse botón: transparente
   se lee como enlace y queda más débil que el «no cancelar» de al lado. Se
   queda en el rojo suave, no en rojo pleno: es la salida correcta cuando
   alguien decide cancelar, no la que hay que empujar. */
.pill--peligro-solido {
    background: var(--danger-surface);
    color: var(--danger-ink-strong);
    border: 1.5px solid var(--danger-border-strong, transparent);
}
.pill--peligro-solido:hover { filter: brightness(.96); color: var(--danger-ink-strong); }

.pill--grande {
    min-block-size: 3.25rem;
    padding-inline: 1.75rem;
    font-size: 1rem;
    font-weight: 700;
}

.pill--bloque { display: flex; inline-size: 100%; }

.pill--icono { padding-inline: 0; inline-size: var(--control-min); }

.pill { --ic-tam: 1.0625rem; --ic-trazo: 1.9; }
.pill--grande { --ic-tam: 1.25rem; --ic-trazo: 1.75; }
.pill--icono  { --ic-tam: 1.125rem; }

.pill:focus-visible { outline-color: var(--navy); outline-offset: 3px; }


/* ═══ Insignia de estado ═══════════════════════════════════════════ */

.tag {
    display: inline-flex;
    align-items: center;
    gap: .3125rem;
    min-block-size: 1.5rem;
    padding-inline: .6875rem;
    border-radius: var(--r-pill);
    font-size: .75rem;
    font-weight: 700;
    white-space: nowrap;
}

.tag--ok      { background: var(--success-surface); color: var(--success-ink); }
.tag--aviso   { background: var(--tint-orange);     color: var(--orange-ink); }
.tag--info    { background: var(--tint-blue);       color: var(--blue-ink); }
.tag--neutral { background: var(--action-neutral-surface); color: var(--navy); }
.tag--apagada { background: var(--bg-soft);         color: var(--muted); }
.tag--peligro { background: var(--danger-surface);  color: var(--danger-ink); }

.tag { --ic-tam: .8125rem; --ic-trazo: 2.4; }


/* ═══ Burbuja de icono ═════════════════════════════════════════════ */

.bubble {
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    inline-size: 3.25rem;
    block-size: 3.25rem;
    border-radius: var(--r-pill);
    background: var(--tint-navy);
    color: var(--navy);
    font-size: .875rem;
    font-weight: 700;
    overflow: hidden;
}

.bubble--verde   { background: var(--tint-green);  color: var(--green-ink); }
.bubble--naranjo { background: var(--tint-orange); color: var(--orange-ink); }
.bubble--azul    { background: var(--tint-blue);   color: var(--blue-ink); }
.bubble--apagada { background: var(--bg-soft);     color: var(--muted); }

.bubble--sm { inline-size: 2.5rem; block-size: 2.5rem; font-size: .8125rem; }
.bubble--lg { inline-size: 4.25rem; block-size: 4.25rem; font-size: 1.625rem; }

.bubble    { --ic-tam: 1.625rem;  --ic-trazo: 1.25; }
.bubble--sm { --ic-tam: 1.1875rem; --ic-trazo: 1.95; }
.bubble--lg { --ic-tam: 2.125rem;  --ic-trazo: 1; }

.bubble img { inline-size: 100%; block-size: 100%; object-fit: cover; }


/* ═══ Fila de dato ═════════════════════════════════════════════════ */

.meta-list {
    display: flex;
    flex-direction: column;
    gap: .5rem;
    margin: 0;
}

.meta-row {
    display: flex;
    align-items: center;
    gap: .625rem;
    margin: 0;
    color: var(--text);
    font-size: .90625rem;
}

.meta-row {
    --ic-tam: 1.0625rem;
    --ic-trazo: 1.8;
}

/* El icono de una fila de dato es señal de qué dato es, no del dato: va más
   apagado que el texto para que la lectura empiece por la palabra. Pasa por
   una variable porque hay filas —una cancelación— donde el icono sí tiene que
   acompañar al texto en vez de apagarse. */
.meta-row > .ic { color: var(--ic-color, var(--icon-muted)); }

.meta-row--peligro {
    --ic-color: currentColor;
    color: var(--danger-ink);
}

.meta-row--apagada { color: var(--muted); }

/* Las filas se ponen en línea solo cuando hay ancho que lo justifique:
   apiladas se leen mejor en teléfono. */
@media (min-width: 768px) {
    .meta-list--inline {
        flex-direction: row;
        flex-wrap: wrap;
        gap: var(--space-3) var(--space-6);
    }
}


/* ═══ Cifra ════════════════════════════════════════════════════════ */

.metric__value {
    display: block;
    font-family: var(--font-display);
    font-size: 1.625rem;
    font-weight: 700;
    letter-spacing: -.03em;
    line-height: 1.15;
    color: var(--navy);
    font-variant-numeric: tabular-nums;
}

.metric__label {
    display: block;
    font-size: .8125rem;
    color: var(--muted);
}

.metric--grande .metric__value { font-size: clamp(1.875rem, 5vw, 2.25rem); }

.panel--navy .metric__value { color: var(--surface-inverse-text); }
.panel--navy .metric__label { color: var(--surface-inverse-muted); }


/* ═══ Barra de progreso ════════════════════════════════════════════ */

.progress {
    block-size: .375rem;
    border-radius: var(--r-pill);
    background: var(--action-neutral-surface-hover);
    overflow: hidden;
}

.progress__bar {
    block-size: 100%;
    border-radius: var(--r-pill);
    background: var(--blue);
}


/* ═══ Composición con columna lateral ══════════════════════════════
   La lateral solo existe a partir de 1024px. Entre 768 y 1023 se apila
   bajo el contenido: a ese ancho una columna de 21rem deja el contenido
   principal más angosto que apilado, que es el defecto que ya costó
   caro en «Mis direcciones». */

.with-aside {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-5);
    align-items: start;
}

.with-aside > * { min-inline-size: 0; }

@media (min-width: 1024px) {
    .with-aside { grid-template-columns: minmax(0, 1fr) 21rem; }

    /* El aside acompaña la lectura: en un formulario largo el botón de enviar
       (o el resumen del pago) quedaba fuera de pantalla a los dos pasos. */
    .with-aside > aside {
        position: sticky;
        top: calc(var(--header-height, 4.6875rem) + var(--space-4));
        max-block-size: calc(100dvh - var(--header-height, 4.6875rem) - var(--space-6));
        overflow-y: auto;
    }
}

.stack-cards {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
}


/* ═══ Tarjeta de visita ════════════════════════════════════════════
   Composición propia de «Mis citas» y de la agenda del veterinario.
   En teléfono se apila; desde 768px la burbuja, el cuerpo y la columna
   de acciones se reparten en tres columnas. */

.visit-card {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    gap: var(--space-3) var(--space-4);
    align-items: center;
}

.visit-card__body { min-inline-size: 0; }

.visit-card__heading {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .5rem;
}

.visit-card__title {
    font-family: var(--font-display);
    font-size: 1.125rem;
    font-weight: 650;
    letter-spacing: -.02em;
    color: var(--navy);
    margin: 0;
}

.visit-card__detail {
    grid-column: 1 / -1;
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    min-inline-size: 0;
}

.visit-card__actions {
    grid-column: 1 / -1;
    display: flex;
    flex-wrap: wrap;
    gap: .5rem;
}

.visit-card__actions > form { margin: 0; display: contents; }

/* Lo que se lleva el veterinario, pegado al botón de tomar el caso. Va ahí
   y no en la fila de datos porque es parte de la decisión de tomarlo, no de
   la descripción de la visita. */
.visit-card__payout {
    inline-size: 100%;
    margin: 0;
    font-size: .8125rem;
    color: var(--muted);
    font-variant-numeric: tabular-nums;
}

/* Centrado solo cuando comparte la columna angosta con el botón; apilado
   bajo un botón alineado a la izquierda se veía suelto. */
@media (min-width: 768px) {
    .visit-card__payout { text-align: center; }
}

.visit-card__payout strong { color: var(--navy); font-size: .9375rem; }

/* La especie entre paréntesis acompaña al nombre sin competir con él. */
.visit-card__aside { font-weight: 500; color: var(--muted); }


/* ═══ Fila de importe ══════════════════════════════════════════════
   Concepto a la izquierda, cifra a la derecha. Las cifras van en
   tabulares y alineadas al mismo borde: es lo que permite leer una
   resta sin sumar mentalmente.                                        */

.amount-row {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-4);
    margin: 0;
    font-size: .90625rem;
    color: var(--muted);
}

.amount-row > .cifra {
    flex: none;
    font-variant-numeric: tabular-nums;
    color: var(--text);
}

.amount-row--fuerte {
    font-weight: 650;
    color: var(--navy);
}

/* Un examen cuelga de su mascota: su precio ya está dentro del de la
   visita, así que va sangrado y sin monto propio. Repetirlo haría que el
   total pareciera mal sumado. */
.amount-row--anidada {
    padding-inline-start: var(--space-4);
    font-size: .84375rem;
}

.amount-row--fuerte > .cifra {
    font-family: var(--font-display);
    font-size: 1.0625rem;
    font-weight: 700;
    letter-spacing: -.02em;
    color: var(--navy);
}

/* El total se separa con un filete: sin él la última fila es una más. */
.amount-row--total {
    padding-block-start: var(--space-3);
    border-block-start: 1px solid var(--hairline);
}


/* Cifras que se comparan de un vistazo —horas, montos, fechas— en
   tabulares, para que no bailen entre filas. */
.tabular { font-variant-numeric: tabular-nums; }

.visit-card--cerrada .visit-card__title { color: #4A5372; }

@media (min-width: 768px) {
    .visit-card {
        grid-template-columns: auto minmax(0, 1fr) auto;
        align-items: start;
    }

    .visit-card__detail { grid-column: 2 / 3; }

    .visit-card__actions {
        grid-column: 3 / 4;
        grid-row: 1 / span 2;
        flex-direction: column;
        align-items: stretch;
        /* 10.5rem y no 9.25: a ese ancho «Voy en camino» partía en dos
           líneas y el botón quedaba del doble de alto que sus vecinos. */
        inline-size: 10.5rem;
    }

    .visit-card__title { font-size: 1.3125rem; }
}


/* ═══ Ficha de mascota ═══════════════════════════════════════════
   La banda de foto arriba y el retrato montado sobre ella. El montaje
   es lo que hace que la tarjeta se lea como una ficha de alguien y no
   como una fila más de una tabla.

   El tinte lo elige `Pet.tinte` por `pk`, no al azar: si cambiara entre
   recargas dejaría de servir para reconocer a la mascota de un vistazo,
   que es lo único que hace.

   Se llama `pet-profile` y no `pet-card` porque ese nombre ya es de la
   tarjeta vieja de styles.css, que trae `align-items: start` y le dejaba
   la banda de foto en cero de ancho. Aquella queda huérfana con esta
   migración; se borra cuando se limpie styles.css.                     */

.pet-profile {
    display: flex;
    flex-direction: column;
    overflow: hidden;
    padding: 0;
}

.pet-profile__cover {
    position: relative;
    flex: none;
    block-size: 7.25rem;
    background: #EDF2F9;
    overflow: hidden;
}

/* El halo va en un pseudo-elemento: la plantilla no tiene por qué cargar
   con un div que solo existe para pintar un círculo. */
.pet-profile__cover::after {
    content: '';
    position: absolute;
    inset-block-start: -2.5rem;
    inset-inline-end: -1.875rem;
    inline-size: 9.375rem;
    block-size: 9.375rem;
    border-radius: var(--r-pill);
    background: var(--pet-halo, rgba(105, 174, 43, .16));
}

.pet-profile__photo {
    position: relative;
    z-index: 1;
    inline-size: 100%;
    block-size: 100%;
    object-fit: cover;
    display: block;
}

/* La banda vacía no repite el nombre —ya está dos líneas más abajo—: ofrece
   lo que falta, que es la foto. */
.pet-profile__cover-empty {
    position: absolute;
    inset: 0;
    z-index: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: .5rem;
    padding-inline: var(--space-4);
    font-size: .84375rem;
    font-weight: 600;
    color: #7C89A3;
    text-align: center;
    --ic-tam: 1.0625rem;
    --ic-trazo: 1.8;
}

.pet-profile__cover-empty:hover { color: var(--green-ink); }

.pet-profile__body {
    padding: 0 var(--space-5) var(--space-5);
    margin-block-start: -2.125rem;
}

.pet-profile__avatar {
    position: relative;
    z-index: 2;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    inline-size: 4.25rem;
    block-size: 4.25rem;
    border-radius: var(--r-pill);
    border: 4px solid var(--bg);
    background: var(--tint-green);
    color: var(--green-ink);
    overflow: hidden;
    --ic-tam: 1.75rem;
    --ic-trazo: 1.3;
}

.pet-profile--azul .pet-profile__avatar    { background: var(--tint-blue);   color: var(--blue-ink); }
.pet-profile--naranjo .pet-profile__avatar { background: var(--tint-orange); color: var(--orange-ink); }

.pet-profile--azul    { --pet-halo: rgba(59, 164, 219, .14); }
.pet-profile--naranjo { --pet-halo: rgba(232, 116, 44, .14); }

.pet-profile__avatar img { inline-size: 100%; block-size: 100%; object-fit: cover; }

.pet-profile__heading {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: .625rem;
    margin-block-start: var(--space-3);
}

.pet-profile__name {
    font-family: var(--font-display);
    font-size: 1.4375rem;
    font-weight: 650;
    letter-spacing: -.02em;
    color: var(--navy);
    margin: 0;
}

.pet-profile__breed {
    margin: .125rem 0 0;
    font-size: .90625rem;
    color: var(--muted);
}

/* La presentación es la voz del dueño sobre su mascota, así que se marca
   como una cita y no como un párrafo más. */
.pet-profile__quote {
    margin: var(--space-3) 0 0;
    padding-inline-start: .875rem;
    border-inline-start: 2px solid #C9D2E4;
    font-size: .90625rem;
    font-style: italic;
    color: var(--text);
    text-wrap: pretty;
}

.pet-profile__actions {
    display: flex;
    flex-wrap: wrap;
    gap: .5rem;
    margin-block-start: var(--space-4);
}


/* ═══ Ranura para agregar ══════════════════════════════════════════
   El hueco al final de una grilla. Va punteado porque todavía no es una
   tarjeta: es el lugar donde puede haber una.                          */

.add-slot {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: .625rem;
    min-block-size: 15rem;
    padding: var(--space-6) var(--space-5);
    border: 2px dashed var(--border-dashed);
    border-radius: var(--r-xl);
    color: var(--navy);
    text-align: center;
    transition: border-color .15s, background .15s;
}

.add-slot:hover { border-color: var(--green-ink); background: var(--bg); color: var(--navy); }

.add-slot__mark {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    inline-size: 3.5rem;
    block-size: 3.5rem;
    border-radius: var(--r-pill);
    background: var(--tint-green);
    color: var(--green-ink);
    --ic-tam: 1.5rem;
    --ic-trazo: 1.7;
}

.add-slot__title { font-size: 1rem; font-weight: 650; }

.add-slot__text {
    max-inline-size: 26ch;
    font-size: .875rem;
    color: var(--muted);
}


/* ═══ Grilla de tarjetas ═══════════════════════════════════════════ */

.card-grid {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-4);
}

@media (min-width: 640px) {
    .card-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* ═══ Campo de formulario ══════════════════════════════════════════
   El rótulo va sobre el control, en peso alto y color de título: en un
   formulario largo el rótulo es la única forma de saber dónde estás
   parado, y en gris claro deja de cumplirla.

   Alto de 3rem, no el mínimo táctil de 44px: un control de escritura se
   toca con más precisión que un botón y el aire de más se agradece al
   escribir.                                                            */

.field {
    display: flex;
    flex-direction: column;
    gap: .4375rem;
    min-inline-size: 0;
}

.field__label {
    font-size: .84375rem;
    font-weight: 650;
    color: var(--navy);
}

.field__label .opcional {
    margin-inline-start: .375rem;
    font-weight: 500;
    color: var(--muted);
}

.field__control,
.field input:not([type="checkbox"]):not([type="radio"]):not([type="file"]),
.field select,
.field textarea {
    inline-size: 100%;
    min-block-size: 3rem;
    padding: .6875rem .9375rem;
    border: 1.5px solid var(--border);
    border-radius: var(--r-md);
    background: var(--bg);
    color: var(--text);
    font-family: var(--font-body);
    font-size: .9375rem;
    transition: border-color .15s, box-shadow .15s;
}

.field textarea { min-block-size: 5rem; resize: vertical; }

.field input::placeholder,
.field textarea::placeholder { color: #9AA3B5; }

.field :is(input, select, textarea):focus-visible {
    outline: none;
    border-color: var(--green-ink);
    box-shadow: 0 0 0 3px var(--tint-green);
}

/* El error se dice con palabras y con un color que no es el único
   portador: el borde cambia, pero debajo va el texto que explica qué
   pasó. */
.field--error :is(input, select, textarea) { border-color: var(--danger-ink); }

.field__help { font-size: .8125rem; color: var(--muted); }

.field__error {
    margin: 0;
    padding: 0;
    list-style: none;
    font-size: .8125rem;
    font-weight: 600;
    color: var(--danger-ink);
}

/* Dos campos por fila solo cuando hay ancho: apilados nunca estorban. */
.field-row {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-4);
}

@media (min-width: 480px) {
    .field-row { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* ═══ Encabezado de sección ════════════════════════════════════════
   Título, conteo y una línea que dice qué se hace acá. El conteo va
   pegado al título y no en una esquina: es parte de lo que el título
   afirma.                                                             */

.section-head { margin-block-end: var(--space-4); }

.section-head__row {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: .75rem;
}

.section-head__title {
    margin: 0;
    font-family: var(--font-display);
    font-size: 1.375rem;
    font-weight: 650;
    letter-spacing: -.02em;
    color: var(--navy);
}

.section-head__sub {
    margin: .25rem 0 0;
    font-size: .90625rem;
    color: var(--muted);
    text-wrap: pretty;
}


/* ═══ Fila de lista ════════════════════════════════════════════════
   Marca, cuerpo y acciones en una línea. Bajo 768px las acciones bajan
   a su propia fila en vez de comprimir el texto a tres palabras por
   línea, que es donde una lista deja de servir para buscar.            */

.list-row {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--space-3) var(--space-4);
    padding: 1.25rem 1.375rem;
}

.list-row__body {
    flex: 1 1 12rem;
    min-inline-size: 0;
}

.list-row__heading {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: .625rem;
}

.list-row__title {
    margin: 0;
    font-family: var(--font-display);
    font-size: 1.09375rem;
    font-weight: 650;
    color: var(--navy);
}

.list-row__text {
    margin: .125rem 0 0;
    font-size: .90625rem;
    color: var(--muted);
    text-wrap: pretty;
}

.list-row__actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .5rem;
}

.list-row__actions form { margin: 0; }

/* Una línea y elipsis: el último mensaje sirve para reconocer la
   conversación, no para leerla. Dos líneas ya harían de la lista un hilo. */
.list-row__text--corta {
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}

.list-row__aside {
    flex: none;
    font-size: .75rem;
    color: var(--icon-muted);
    font-variant-numeric: tabular-nums;
}

/* Una fila que además es enlace tiene que responder al puntero: si no,
   nada dice que se pueda abrir. */
a.list-row { color: inherit; transition: box-shadow .15s, transform .15s; }
a.list-row:hover { box-shadow: var(--shadow-md); }
a.list-row:hover .list-row__title { color: var(--green-ink); }

/* El borde marca la que está en uso. Va con la etiqueta al lado del
   nombre, nunca solo: el color no puede ser el único que lo diga. */
.list-row--destacada {
    border: 2px solid var(--green-ink);
    padding: calc(1.25rem - 2px) calc(1.375rem - 2px);
}

@media (max-width: 767px) {
    .list-row__actions { inline-size: 100%; }
}


/* ═══ Bloque destacado con lateral ═════════════════════════════════
   Un dato que manda —la dirección de siempre, la próxima visita— junto
   a su ilustración o su mapa. Bajo 1024px la lateral pasa abajo: a esa
   altura el mapa compite con el dato en vez de ubicarlo.               */

.spotlight {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-3);
    padding: .75rem;
}

.spotlight__body { padding: var(--space-5) var(--space-5) var(--space-4); }

.spotlight__aside {
    border-radius: var(--r-lg);
    overflow: hidden;
    min-block-size: 12rem;
    background: var(--surface-sunken);
}

.spotlight__title {
    margin: var(--space-4) 0 0;
    font-family: var(--font-display);
    font-size: clamp(1.5rem, 3vw, 1.875rem);
    font-weight: 700;
    letter-spacing: -.025em;
    color: var(--navy);
}

.spotlight__lead {
    margin: .5rem 0 0;
    font-size: 1.0625rem;
    color: var(--text);
}

.spotlight__note { margin-block-start: .875rem; }
.spotlight__action { margin: 1.375rem 0 0; }

.spotlight__map {
    display: block;
    inline-size: 100%;
    block-size: 100%;
    min-block-size: inherit;
    border: 0;
}

/* La segunda columna se abre solo si hay algo que poner en ella: sin mapa
   —sin coordenadas o sin llave de Google— el bloque quedaba con 26rem de
   nada a la derecha del dato. */
@media (min-width: 1024px) {
    .spotlight:has(.spotlight__aside) { grid-template-columns: minmax(0, 1fr) 26rem; }
    .spotlight__aside { min-block-size: 15rem; }
}


/* ═══ Cabecera de panel ════════════════════════════════════════════
   Marca, título y bajada. Es lo que abre un panel de formulario: dice
   qué se está por hacer antes del primer campo.                       */

.panel__head {
    display: flex;
    align-items: center;
    gap: var(--space-3);
}

.panel__head-text { min-inline-size: 0; }

.panel__sub {
    margin: .125rem 0 0;
    font-size: .84375rem;
    color: var(--muted);
    text-wrap: pretty;
}

/* ═══ Tarjeta con portada ══════════════════════════════════════════
   Banda de marca arriba y el retrato montado sobre ella. Es la misma
   idea que la ficha de mascota, pero en azul y para una persona: la
   banda le da a la identidad el sitio que en una lista no tiene.       */

.cover-card { padding: 0; overflow: hidden; }

.cover-card__band {
    position: relative;
    block-size: 8rem;
    background: var(--surface-inverse);
    overflow: hidden;
}

/* Los halos van en pseudo-elementos: el markup no carga con dos divs
   que solo existen para pintar dos círculos. */
.cover-card__band::before,
.cover-card__band::after {
    content: '';
    position: absolute;
    border-radius: var(--r-pill);
}

.cover-card__band::before {
    inset-block-start: -4.375rem;
    inset-inline-end: 5rem;
    inline-size: 15rem;
    block-size: 15rem;
    background: rgba(105, 174, 43, .2);
}

.cover-card__band::after {
    inset-block-end: -6.25rem;
    inset-inline-end: -2.5rem;
    inline-size: 13.75rem;
    block-size: 13.75rem;
    background: rgba(59, 164, 219, .18);
}

.cover-card__body {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: var(--space-4) var(--space-5);
    padding: 0 var(--space-5) var(--space-5);
}

/* El montaje lo hace SOLO el retrato. Cuando el margen negativo estaba en
   toda la fila, el nombre subía con ella y quedaba azul sobre la banda
   azul: invisible, y sin que nada en el markup lo delatara. */
.cover-card__avatar {
    flex: none;
    margin-block-start: -3rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    inline-size: 5.5rem;
    block-size: 5.5rem;
    border-radius: var(--r-pill);
    border: 5px solid var(--bg);
    background: var(--tint-navy);
    color: var(--navy);
    font-family: var(--font-display);
    font-size: 2rem;
    font-weight: 700;
    overflow: hidden;
}

.cover-card__avatar img { inline-size: 100%; block-size: 100%; object-fit: cover; }

.cover-card__id {
    flex: 1 1 14rem;
    min-inline-size: 0;
    padding-block-end: .375rem;
}

.cover-card__name {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: .625rem;
    margin: 0;
    font-family: var(--font-display);
    font-size: clamp(1.5rem, 4vw, 1.75rem);
    font-weight: 700;
    letter-spacing: -.025em;
    color: var(--navy);
}

.cover-card__role {
    margin: .25rem 0 0;
    font-size: .9375rem;
    color: var(--muted);
}

.cover-card__bio {
    margin: 0;
    padding: 0 var(--space-5) var(--space-5);
    max-inline-size: 68ch;
    color: var(--text);
    text-wrap: pretty;
}

@media (min-width: 640px) {
    .cover-card__avatar {
        inline-size: 6.75rem;
        block-size: 6.75rem;
        margin-block-start: -3.75rem;
        font-size: 2.5rem;
    }
}


/* ═══ Rejilla de campos ════════════════════════════════════════════
   Los campos responden al ancho de SU tarjeta y no al del viewport: en
   una columna lateral de 21rem, dos columnas fijas dan campos de 9rem
   que parten «Fecha de nacimiento» en tres líneas.                     */

.field-grid {
    container: field-grid / inline-size;
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-4);
}

@container field-grid (min-width: 30rem) {
    .field-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* El botón de un formulario largo va a la derecha, donde termina de
   leerse la última fila. En teléfono ocupa el ancho: ahí no hay «a la
   derecha» que signifique algo. */
.form-foot {
    display: flex;
    justify-content: flex-end;
}

@media (max-width: 639px) {
    .form-foot { justify-content: stretch; }
    .form-foot > .pill { inline-size: 100%; }
}


/* ═══ Tira de cifras ═══════════════════════════════════════════════
   Los números que resumen una cuenta, separados por un filete. No es
   un tablero: son tres datos que caben en una línea.                  */

/* Una pantalla de un solo paso —cancelar, reseñar, elegir cómo seguir—
   no necesita todo el ancho: leerla de un tirón importa más. */
.stack--angosta { inline-size: min(100%, var(--content-form)); }


/* Dos botones que son la misma decisión con salidas opuestas. Se llama
   `--dual` y no `form-buttons` porque ese nombre ya es de la capa vieja,
   que le mete un filete arriba. En teléfono se apilan con el que confirma
   abajo, donde cae el pulgar. */
.form-foot--dual {
    flex-wrap: wrap;
    align-items: center;
    gap: .75rem;
}

@media (max-width: 479px) {
    .form-foot--dual { flex-direction: column-reverse; align-items: stretch; }
    .form-foot--dual > * { inline-size: 100%; }
}


.stars-field legend { padding: 0; }


.stat-strip {
    display: flex;
    flex-wrap: wrap;
    align-items: stretch;
    gap: var(--space-3) var(--space-5);
    padding-block-end: .5rem;
}

.stat-strip > .metric { text-align: center; }

/* El filete separa cifras vecinas, así que se apaga cuando la tira envuelve:
   colgando al principio de una línea nueva no separa nada. */
@media (min-width: 480px) {
    .stat-strip > .metric + .metric {
        padding-inline-start: var(--space-5);
        border-inline-start: 1px solid var(--hairline);
    }
}


/* ═══ Fila de opción ═══════════════════════════════════════════════
   Nombre del ajuste, qué hace y el control que lo cambia. El texto
   explica la consecuencia, no repite el nombre: quien llega a una
   pantalla de ajustes no sabe qué apaga cada cosa.                    */

.option-row {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--space-3) var(--space-4);
    padding-block: var(--space-4);
}

.option-row + .option-row { border-block-start: 1px solid var(--hairline); }

.option-row__body { flex: 1 1 14rem; min-inline-size: 0; }

.option-row__label {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: .5rem;
    font-size: .9375rem;
    font-weight: 650;
    color: var(--navy);
}

.option-row__value {
    margin: .1875rem 0 0;
    font-size: .875rem;
    color: var(--muted);
    text-wrap: pretty;
}

.option-row__control { flex: none; }
.option-row__control form { margin: 0; }

/* La casilla se agranda y arrastra a su texto: un interruptor de 13px
   se falla al tocarlo y no se ve si está puesto. */
.switch-field {
    display: flex;
    align-items: flex-start;
    gap: .875rem;
    cursor: pointer;
}

.switch-field input[type="checkbox"] {
    flex: none;
    inline-size: 1.375rem;
    block-size: 1.375rem;
    margin-block-start: .125rem;
    accent-color: var(--green-ink);
    cursor: pointer;
}

.panel--peligro {
    border: 1.5px solid var(--danger-surface);
}

.panel--peligro .panel__title { color: var(--danger-ink-strong); }

/* ═══ Tarjeta de paquete ═══════════════════════════════════════════
   Lo que incluye arriba y el precio abajo, pegado al borde: en una
   grilla de paquetes de distinto largo, los precios alineados son lo
   único que permite compararlos sin leerlos enteros.                  */

.pack-card {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}

/* El descuento va en la esquina y no en la fila del precio: ahí es una
   razón para mirar la tarjeta, y abajo sería una cifra más. */
.pack-card__badge {
    position: absolute;
    inset-block-start: var(--space-4);
    inset-inline-end: var(--space-4);
    display: inline-flex;
    align-items: center;
    block-size: 1.625rem;
    padding-inline: .6875rem;
    border-radius: var(--r-pill);
    background: var(--orange-ink);
    color: #fff;
    font-size: .75rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

.pack-card__name {
    margin: 0;
    font-family: var(--font-display);
    font-size: 1.25rem;
    font-weight: 650;
    letter-spacing: -.02em;
    color: var(--navy);
}

.pack-card__for {
    margin: -.5rem 0 0;
    font-size: .875rem;
    color: var(--muted);
}

.pack-card__desc {
    margin: 0;
    font-size: .90625rem;
    color: var(--text);
    text-wrap: pretty;
}

.pack-card__list {
    display: flex;
    flex-direction: column;
    gap: .4375rem;
    margin: 0;
    padding: 0;
    list-style: none;
    --ic-tam: .9375rem;
    --ic-trazo: 2.4;
}

.pack-card__list li {
    display: flex;
    align-items: flex-start;
    gap: .5625rem;
    font-size: .90625rem;
}

.pack-card__list .ic { margin-block-start: .25rem; color: var(--green-ink); }

/* `auto` empuja el precio al fondo pase lo que pase arriba. */
.pack-card__foot {
    margin-block-start: auto;
    padding-block-start: var(--space-4);
    border-block-start: 1px solid var(--hairline);
}

.pack-card__prices {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: .625rem;
}

.pack-card__was {
    font-size: .9375rem;
    color: var(--muted);
    text-decoration: line-through;
    font-variant-numeric: tabular-nums;
}

.pack-card__now {
    font-family: var(--font-display);
    font-size: 1.5rem;
    font-weight: 700;
    letter-spacing: -.03em;
    color: var(--navy);
    font-variant-numeric: tabular-nums;
}

.pack-card__saving {
    margin: .1875rem 0 0;
    font-size: .8125rem;
    font-weight: 650;
    color: var(--green-ink);
}

.pack-card__fine {
    margin: .1875rem 0 0;
    font-size: .8125rem;
    color: var(--muted);
}

.pack-card__cta { margin-block-start: var(--space-4); }

.pack-group { margin: var(--space-5) 0 var(--space-3); }

@media (min-width: 1024px) {
    .card-grid--tres { grid-template-columns: repeat(3, minmax(0, 1fr)); }
    .card-grid--cuatro { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

/* ═══ Paso de un formulario largo ══════════════════════════════════
   El número no es adorno: en un formulario que decide un pago, la
   secuencia es parte de lo que hay que entender —qué falta y cuánto
   queda—. Cada paso pregunta algo en vez de rotular un campo.          */

.step__head {
    display: flex;
    align-items: center;
    gap: .75rem;
    margin-block-end: var(--space-4);
}

.step__num {
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    inline-size: 1.875rem;
    block-size: 1.875rem;
    border-radius: var(--r-pill);
    background: var(--tint-navy);
    color: var(--navy);
    font-family: var(--font-display);
    font-size: .9375rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

.step__title {
    margin: 0;
    font-family: var(--font-display);
    font-size: 1.1875rem;
    font-weight: 650;
    letter-spacing: -.015em;
    color: var(--navy);
}

.step__title .opcional {
    margin-inline-start: .375rem;
    font-family: var(--font-body);
    font-size: .875rem;
    font-weight: 500;
    color: var(--muted);
}


/* ═══ Nota al pie de un bloque ═════════════════════════════════════
   Lo que hay que saber antes de seguir, no una alerta: fondo hundido y
   sin borde de color, para que no compita con un error de verdad.      */

.note {
    display: flex;
    align-items: flex-start;
    gap: .625rem;
    padding: .8125rem .9375rem;
    border-radius: var(--r-md);
    background: var(--surface-sunken);
    font-size: .875rem;
    color: var(--muted);
    text-wrap: pretty;
    --ic-tam: 1.0625rem;
    --ic-trazo: 1.8;
}

.note > .ic { margin-block-start: .0625rem; color: var(--icon-muted); }

.note--aviso {
    background: var(--tint-orange);
    color: var(--orange-ink);
}

.note--aviso > .ic { color: currentColor; }

.note strong { color: var(--navy); }
.note--aviso strong { color: inherit; }


/* ═══ Volver ═══════════════════════════════════════════════════════ */

.back {
    display: inline-flex;
    align-items: center;
    gap: .4375rem;
    align-self: flex-start;
    min-block-size: var(--control-min);
    font-size: .90625rem;
    font-weight: 600;
    color: var(--muted);
    --ic-tam: 1rem;
    --ic-trazo: 2;
}

.back:hover { color: var(--green-ink); }


/* ═══ Lista de opciones marcables ══════════════════════════════════
   Los checkbox y radio de Django. Se apunta a `label:has(input)` y no a
   `li label` porque el markup del widget cambió entre versiones —de
   `<ul><li>` a `<div><div>`— y porque así el rótulo del campo, que es un
   `label` hermano sin control adentro, queda fuera.

   La caja entera es el blanco táctil: un cuadradito de 13px al lado del
   texto se falla constantemente en teléfono.                            */

.pick-list .field > div,
.pick-list .field > ul {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: .5rem;
    margin: 0;
    padding: 0;
    list-style: none;
}

.pick-list label:has(input) {
    display: flex;
    align-items: center;
    gap: .75rem;
    min-block-size: var(--control-min);
    padding: .625rem .875rem;
    border: 1.5px solid var(--border);
    border-radius: var(--r-md);
    background: var(--bg);
    font-size: .9375rem;
    font-weight: 500;
    color: var(--text);
    cursor: pointer;
    transition: border-color .15s, background .15s;
}

.pick-list label:has(input):hover { border-color: var(--green-ink); }

.pick-list input[type="checkbox"],
.pick-list input[type="radio"] {
    flex: none;
    inline-size: 1.25rem;
    block-size: 1.25rem;
    accent-color: var(--green-ink);
    cursor: pointer;
}

/* `:has()` mueve el borde a la caja cuando lo que cambió está adentro:
   sin esto, lo elegido solo se distingue por un punto de 20px. */
.pick-list label:has(input:checked) {
    border-color: var(--green-ink);
    background: var(--tint-green);
    color: var(--navy);
    font-weight: 650;
}

.pick-list label:has(input:focus-visible) {
    outline: 2px solid var(--green-ink);
    outline-offset: 2px;
}

@media (min-width: 640px) {
    .pick-list--dos .field > div,
    .pick-list--dos .field > ul { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}


/* ═══ Portada ══════════════════════════════════════════════════════
   La única pantalla del proyecto en modo persuadir. Todo lo demás es
   una herramienta; aquí hay que ganarse un clic, y por eso es la única
   que se permite una foto grande y una entrada animada.

   Los bloques `home-*` viven acá y no en un `<style>` de la plantilla,
   que es de donde salieron: 360 líneas de CSS incrustado que ninguna
   otra pantalla podía reusar ni el navegador cachear.                  */

.home-hero {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-6);
    align-items: center;
    padding-block: var(--space-6) var(--space-7);
}

.home-hero__eyebrow {
    display: inline-flex;
    align-items: center;
    gap: .5rem;
    block-size: 2rem;
    padding-inline: .875rem;
    border-radius: var(--r-pill);
    background: var(--tint-green);
    color: var(--green-ink);
    font-size: .8125rem;
    font-weight: 700;
    --ic-tam: .9375rem;
    --ic-trazo: 2;
}

.home-hero__title {
    margin: var(--space-4) 0 0;
    font-family: var(--font-display);
    font-size: var(--title-1);
    font-weight: 700;
    letter-spacing: -.04em;
    line-height: 1.05;
    color: var(--navy);
    text-wrap: balance;
}

.home-hero__title em { font-style: normal; color: var(--green-ink); }

.home-hero__lead {
    margin: var(--space-4) 0 0;
    max-inline-size: 46ch;
    font-size: var(--body-lg);
    color: var(--muted);
    text-wrap: pretty;
}

.home-hero__actions {
    display: flex;
    flex-wrap: wrap;
    gap: .75rem;
    margin-block-start: var(--space-5);
}

.home-hero__trust {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3) var(--space-5);
    margin-block-start: var(--space-5);
}

.home-hero__art {
    position: relative;
    border-radius: var(--r-3xl);
    overflow: hidden;
    background: var(--tint-navy);
}

.home-hero__art img {
    display: block;
    inline-size: 100%;
    block-size: 100%;
    object-fit: cover;
    aspect-ratio: 4 / 3;
}

@media (min-width: 1024px) {
    .home-hero { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: var(--space-7); }

    /* «Cómo funciona» explica sin panel a la derecha: el encabezado ocupa todo. */
    .home-hero--completo { grid-template-columns: minmax(0, 1fr); }
}


/* ═══ Sección de portada ═══════════════════════════════════════════ */

.home-section { padding-block: var(--space-7); }

.home-section__head {
    max-inline-size: 52ch;
    margin-block-end: var(--space-5);
}

.home-section__title {
    margin: 0;
    font-family: var(--font-display);
    font-size: var(--title-2);
    font-weight: 700;
    letter-spacing: -.03em;
    color: var(--navy);
    text-wrap: balance;
}

.home-section__sub {
    margin: .625rem 0 0;
    font-size: var(--body-lg);
    color: var(--muted);
    text-wrap: pretty;
}


/* ═══ Tarjeta de servicio ══════════════════════════════════════════
   Es un enlace entero, no una tarjeta con un enlace dentro: el blanco
   táctil de un servicio en teléfono tiene que ser la tarjeta.          */

.svc-card {
    display: flex;
    flex-direction: column;
    gap: .625rem;
    color: inherit;
    transition: box-shadow .18s cubic-bezier(.16, 1, .3, 1), transform .18s cubic-bezier(.16, 1, .3, 1);
}

.svc-card:hover {
    box-shadow: var(--shadow-md);
    transform: translateY(-2px);
    color: inherit;
}

.svc-card__title {
    margin: .375rem 0 0;
    font-family: var(--font-display);
    font-size: 1.1875rem;
    font-weight: 650;
    letter-spacing: -.02em;
    color: var(--navy);
}

.svc-card__desc {
    margin: 0;
    font-size: .90625rem;
    color: var(--muted);
    text-wrap: pretty;
}

.svc-card__cta {
    display: inline-flex;
    align-items: center;
    gap: .375rem;
    margin-block-start: auto;
    padding-block-start: var(--space-3);
    font-size: .875rem;
    font-weight: 650;
    color: var(--green-ink);
    --ic-tam: .9375rem;
    --ic-trazo: 2;
}

.svc-card__cta .ic { transition: transform .18s cubic-bezier(.16, 1, .3, 1); }
.svc-card:hover .svc-card__cta .ic { transform: translateX(3px); }


/* ═══ Paso de «cómo funciona» ══════════════════════════════════════ */

.how-step { text-align: center; }

.how-step__mark {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    inline-size: 4.5rem;
    block-size: 4.5rem;
    border-radius: var(--r-pill);
    background: var(--tint-green);
    color: var(--green-ink);
    --ic-tam: 1.875rem;
    --ic-trazo: 1.5;
}

.how-step__title {
    margin: var(--space-4) 0 0;
    font-family: var(--font-display);
    font-size: 1.1875rem;
    font-weight: 650;
    color: var(--navy);
}

.how-step__text {
    margin: .375rem auto 0;
    max-inline-size: 30ch;
    font-size: .90625rem;
    color: var(--muted);
    text-wrap: pretty;
}

/* El CTA de una sección pública se centra bajo la grilla: no es el pie
   de un formulario (eso es .form-foot, que va a la derecha). */
.home-section__cta {
    display: flex;
    justify-content: center;
    margin-block-start: var(--space-6);
}


/* ═══ Bloque «por qué» ═════════════════════════════════════════════ */

.home-why {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-5);
    align-items: center;
}

.home-why__list {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
    margin: var(--space-5) 0 0;
    padding: 0;
    list-style: none;
}

.home-why__list li {
    display: flex;
    align-items: flex-start;
    gap: .875rem;
    font-size: 1rem;
    text-wrap: pretty;
    --ic-tam: 1.375rem;
    --ic-trazo: 1.6;
}

.home-why__list .ic { flex: none; margin-block-start: .125rem; color: var(--green-ink); }

.home-why__art { border-radius: var(--r-3xl); overflow: hidden; }
.home-why__art img { display: block; inline-size: 100%; block-size: auto; }

@media (min-width: 1024px) {
    .home-why { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: var(--space-7); }
}


/* ═══ Reseña ═══════════════════════════════════════════════════════ */

.review-card { display: flex; flex-direction: column; gap: var(--space-3); }

.review-card__stars {
    font-size: 1rem;
    letter-spacing: .1em;
    color: #B07407;
}

.review-card__text {
    margin: 0;
    font-size: .96875rem;
    color: var(--text);
    text-wrap: pretty;
}

.review-card__who {
    display: flex;
    align-items: center;
    gap: .625rem;
    margin-block-start: auto;
    padding-block-start: var(--space-3);
    font-size: .875rem;
    font-weight: 650;
    color: var(--navy);
}


/* ═══ Preguntas frecuentes ═════════════════════════════════════════ */

.faq-list {
    display: flex;
    flex-direction: column;
    gap: .625rem;
    max-inline-size: 52rem;
}

.faq-list details {
    border-radius: var(--r-lg);
    background: var(--bg);
    box-shadow: var(--shadow-sm);
}

.faq-list summary {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-4);
    min-block-size: var(--control-min);
    padding: var(--space-4) var(--space-5);
    font-size: 1rem;
    font-weight: 650;
    color: var(--navy);
    cursor: pointer;
    list-style: none;
    --ic-tam: 1rem;
    --ic-trazo: 2.2;
}

.faq-list summary::-webkit-details-marker { display: none; }
.faq-list summary .ic { flex: none; transition: transform .2s cubic-bezier(.16, 1, .3, 1); }
.faq-list details[open] summary .ic { transform: rotate(180deg); }

.faq-list details > p {
    margin: 0;
    padding: 0 var(--space-5) var(--space-5);
    color: var(--muted);
    text-wrap: pretty;
}


/* ═══ Banda de cierre ══════════════════════════════════════════════ */

.closing {
    text-align: center;
    padding: var(--space-7) var(--space-5);
    border-radius: var(--r-3xl);
}

.closing__title {
    margin: 0;
    font-family: var(--font-display);
    font-size: var(--title-2);
    font-weight: 700;
    letter-spacing: -.03em;
    color: var(--surface-inverse-text);
    text-wrap: balance;
}

.closing__text {
    margin: var(--space-3) auto 0;
    max-inline-size: 46ch;
    color: var(--surface-inverse-muted);
    text-wrap: pretty;
}

.closing__action { margin-block-start: var(--space-5); }

.pill--claro { background: var(--bg); color: var(--navy); }
.pill--claro:hover { background: var(--bg); color: var(--green-ink); }


/* ═══ Entrada al hacer scroll ══════════════════════════════════════
   Un solo gesto y una sola vez. Se aplica solo si el JS marca la
   página: sin JS —o con `prefers-reduced-motion`— nada se oculta y la
   portada se ve entera igual.                                         */

@media (prefers-reduced-motion: no-preference) {
    .js-enter .enter {
        opacity: 0;
        transform: translateY(14px);
        transition: opacity .5s cubic-bezier(.16, 1, .3, 1), transform .5s cubic-bezier(.16, 1, .3, 1);
    }

    .js-enter .enter--visible { opacity: 1; transform: none; }
}

/* ═══ Riel de fecha ════════════════════════════════════════════════
   Día, número y hora en una columna a la izquierda de la tarjeta. Una
   agenda se recorre por fecha, no por servicio: puesto así, la columna
   de números se lee de corrido sin entrar a cada tarjeta.              */

.date-rail {
    flex: none;
    inline-size: 3.75rem;
    padding: .625rem .25rem;
    border-radius: var(--r-md);
    background: var(--surface-sunken);
    text-align: center;
    line-height: 1.15;
    font-variant-numeric: tabular-nums;
}

.date-rail__dow {
    display: block;
    font-size: .6875rem;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--muted);
}

.date-rail__num {
    display: block;
    margin-block: .125rem;
    font-family: var(--font-display);
    font-size: 1.5rem;
    font-weight: 700;
    letter-spacing: -.03em;
    color: var(--navy);
}

.date-rail__time {
    display: block;
    font-size: .75rem;
    font-weight: 650;
    color: var(--green-ink);
}

/* Pasada o cancelada, la fecha deja de ser una cita a la que llegar. */
.date-rail--apagada { background: var(--bg-soft); }
.date-rail--apagada .date-rail__num { color: #4A5372; }
.date-rail--apagada .date-rail__time { color: var(--muted); }


/* ═══ Lista de un día ══════════════════════════════════════════════
   Lo que hay marcado en la fecha elegida: bloques disponibles y
   visitas tomadas, en el mismo sitio. Verlos separados era lo que
   obligaba a cruzar dos pantallas para saber si un hueco estaba
   realmente libre.                                                     */

.day-list {
    display: flex;
    flex-direction: column;
    gap: 0;
    margin: 0;
    padding: 0;
    list-style: none;
}

.day-list li {
    display: flex;
    align-items: center;
    gap: .75rem;
    padding-block: .75rem;
    --ic-tam: 1.0625rem;
    --ic-trazo: 1.8;
}

.day-list li + li { border-block-start: 1px solid var(--hairline); }

.day-list li > .ic { flex: none; color: var(--icon-muted); }

.day-list__body { flex: 1 1 auto; min-inline-size: 0; }

.day-list__time {
    display: block;
    font-size: .90625rem;
    font-weight: 650;
    color: var(--navy);
    font-variant-numeric: tabular-nums;
}

.day-list__what {
    display: block;
    font-size: .8125rem;
    color: var(--muted);
}

.day-list li form { margin: 0; }

/* ═══ Cartera de la semana ═════════════════════════════════════════
   La cifra que se transfiere el lunes, en el tamaño que merece: es la
   única pregunta con la que se entra a esta pantalla.                  */

.wallet-amount {
    margin: var(--space-3) 0 0;
    font-family: var(--font-display);
    font-size: clamp(2.25rem, 7vw, 3.25rem);
    font-weight: 700;
    letter-spacing: -.04em;
    line-height: 1;
    color: var(--surface-inverse-text);
    font-variant-numeric: tabular-nums;
}

.wallet-meta {
    margin: .625rem 0 0;
    font-size: .90625rem;
    color: var(--surface-inverse-muted);
}

/* El desglose va sobre el mismo azul, así que el filete y las cifras
   se aclaran en vez de heredar los del panel blanco. */
.wallet-split {
    display: flex;
    flex-direction: column;
    gap: .625rem;
    justify-content: center;
    padding: var(--space-5);
    background: rgba(255, 255, 255, .08);
}

.wallet-split .amount-row { color: var(--surface-inverse-muted); }
.wallet-split .amount-row > .cifra { color: var(--surface-inverse-text); }

.wallet-split .amount-row--fuerte,
.wallet-split .amount-row--fuerte > .cifra { color: var(--surface-inverse-text); }

.wallet-split .amount-row--total { border-block-start-color: rgba(255, 255, 255, .18); }

.wallet-bank {
    display: flex;
    align-items: center;
    gap: .5rem;
    margin: .25rem 0 0;
    font-size: .8125rem;
    color: var(--surface-inverse-muted);
    --ic-tam: 1rem;
    --ic-trazo: 1.8;
}


/* ═══ Par de gráficos ══════════════════════════════════════════════
   Dos lienzos que se apilan bajo 768px. Chart.js dibuja a lo ancho del
   contenedor, así que la columna tiene que poder achicarse: sin
   `minmax(0, …)` el lienzo fija el ancho y desborda la tarjeta.        */

.chart-pair {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-5);
}

@media (min-width: 768px) {
    .chart-pair { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* La pestaña activa del período se marca como el resto de lo elegido. */
.ep-tab.active {
    background: var(--surface-inverse);
    color: #fff;
}

/* ═══ Rejilla de señales ═══════════════════════════════════════════
   Los datos clínicos de una urgencia. Rejilla y no filas de importe:
   se leen de un vistazo para decidir en minutos, y lo que interesa es
   el conjunto, no comparar un valor con otro.                          */

.signal-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
    gap: var(--space-3);
    margin: 0;
    padding: var(--space-4);
    border-radius: var(--r-lg);
    background: var(--surface-sunken);
}

.signal { min-inline-size: 0; }

.signal__label {
    font-size: .75rem;
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--muted);
}

.signal__value {
    margin: .1875rem 0 0;
    font-size: .9375rem;
    font-weight: 600;
    color: var(--navy);
    text-wrap: pretty;
}

/* Un valor que exige actuar no se dice solo con color: lleva su propio
   peso y el rótulo ya nombra de qué señal se trata. */
.signal--alerta .signal__value { color: var(--danger-ink); }

/* Un `fieldset` no hereda el display del bloque: sin esto la lista de
   opciones se queda con la caja del navegador. */
.field fieldset,
fieldset.field { min-inline-size: 0; border: 0; margin: 0; padding: 0; }

fieldset.field legend { padding: 0; }

/* ═══ Pantalla partida de acceso ═══════════════════════════════════
   Formulario a un lado, marca al otro. Bajo 1024px el panel de marca
   desaparece entero en vez de encogerse: en teléfono, quien viene a
   entrar no quiere leer una promesa, quiere el campo de correo.       */

.auth-split {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    min-block-size: 100dvh;
}

/* La pantalla partida es de borde a borde: main la estrechaba a 1120px y el
   panel de marca moría antes del borde derecho, con una franja blanca al lado. */
main:has(> .auth-split) {
    max-inline-size: none;
    padding-inline: 0;
}

.auth-split__form {
    display: flex;
    flex-direction: column;
    justify-content: center;
    inline-size: 100%;
    max-inline-size: 30rem;
    margin-inline: auto;
    padding: clamp(1.5rem, 6vw, 3.5rem);
}

.auth-split__brand { display: none; }

.auth-split__logo {
    display: inline-flex;
    align-items: center;
    gap: .625rem;
    align-self: flex-start;
    margin-block-end: var(--space-6);
}

.auth-split__logo img { block-size: 2.75rem; inline-size: auto; display: block; }

.auth-split__wordmark {
    font-family: var(--font-display);
    font-size: 1.25rem;
    font-weight: 700;
    letter-spacing: -.03em;
    color: var(--navy);
}

.auth-split__wordmark span { color: var(--green); }

.auth-split__title {
    margin: 0;
    font-family: var(--font-display);
    font-size: clamp(1.625rem, 5vw, 2rem);
    font-weight: 700;
    letter-spacing: -.03em;
    color: var(--navy);
    text-wrap: balance;
}

.auth-split__sub {
    margin: .5rem 0 var(--space-5);
    color: var(--muted);
    text-wrap: pretty;
}

/* «Olvidé mi contraseña» pegado al botón y no al final de la página:
   quien lo necesita lo busca justo cuando el botón no le funcionó. */
.auth-split__aside-link {
    display: flex;
    justify-content: flex-end;
    font-size: .875rem;
    font-weight: 600;
}

.auth-split__sep {
    display: flex;
    align-items: center;
    gap: var(--space-4);
    margin-block: var(--space-5);
    color: var(--muted);
    font-size: .8125rem;
}

.auth-split__sep::before,
.auth-split__sep::after {
    content: '';
    flex: 1;
    block-size: 1px;
    background: var(--border);
}

@media (min-width: 1024px) {
    .auth-split { grid-template-columns: 1fr 1fr; }

    .auth-split__brand {
        position: relative;
        display: flex;
        flex-direction: column;
        justify-content: center;
        gap: var(--space-4);
        overflow: hidden;
        padding: var(--space-7);
        border-radius: 0;
    }

    /* En formularios largos (registro de vet) la columna de marca queda pegada
       al viewport: centrada en el alto de la página entera se veía un panel
       azul vacío durante todo el primer pantallazo. */
    .auth-split--larga .auth-split__brand {
        position: sticky;
        top: 0;
        align-self: start;
        block-size: 100dvh;
    }
}

.auth-split__brand-title {
    margin: 0;
    font-family: var(--font-display);
    font-size: clamp(1.75rem, 3vw, 2.375rem);
    font-weight: 700;
    letter-spacing: -.03em;
    line-height: 1.18;
    max-inline-size: 24ch;
    color: var(--surface-inverse-text);
    text-wrap: balance;
}

.auth-split__brand-title em { font-style: normal; color: var(--green); }

.auth-split__brand-desc {
    margin: 0;
    max-inline-size: 42ch;
    color: var(--surface-inverse-muted);
    text-wrap: pretty;
}

.auth-split__brand .meta-row { color: var(--surface-inverse-muted); }
.auth-split__brand .meta-row > .ic { color: var(--green); }


/* ═══ Barra de filtros ═════════════════════════════════════════════
   Los controles de búsqueda en una fila que envuelve. Cada control
   lleva su icono adentro: en una fila de cinco cajas iguales, el icono
   es lo que permite reconocer cuál es cuál sin leerlas.                */

.filter-bar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .625rem;
}

.filter {
    position: relative;
    display: flex;
    align-items: center;
    flex: 1 1 12rem;
    min-inline-size: 0;
    --ic-tam: 1rem;
    --ic-trazo: 1.9;
}

.filter > .ic {
    position: absolute;
    inset-inline-start: .875rem;
    color: var(--icon-muted);
    pointer-events: none;
}

.filter :is(input, select) {
    inline-size: 100%;
    min-block-size: var(--control-min);
    padding: .625rem .875rem .625rem 2.4375rem;
    border: 1.5px solid var(--border);
    border-radius: var(--r-pill);
    background: var(--bg);
    color: var(--text);
    font-family: var(--font-body);
    font-size: .90625rem;
    appearance: none;
}

.filter :is(input, select):focus-visible {
    outline: none;
    border-color: var(--green-ink);
    box-shadow: 0 0 0 3px var(--tint-green);
}

.filter--auto { flex: 0 1 auto; }


/* ═══ Ficha, filtro aplicado ═══════════════════════════════════════
   Lo que está filtrando ahora mismo, con su aspa. Repetir el filtro
   fuera del control es lo que evita el «no aparece nadie» sin saber
   por qué.                                                            */

.chip {
    display: inline-flex;
    align-items: center;
    gap: .375rem;
    block-size: 1.75rem;
    padding-inline: .75rem;
    border-radius: var(--r-pill);
    background: var(--tint-navy);
    color: var(--navy);
    font-size: .8125rem;
    font-weight: 650;
    --ic-tam: .8125rem;
    --ic-trazo: 2.4;
}

.chip:hover { background: var(--action-neutral-surface); color: var(--navy); }


/* ═══ Ficha de profesional ═════════════════════════════════════════
   Retrato, nombre y por qué elegirlo. Se llama `pro-card` y no
   `vet-card` porque ese nombre ya es del directorio viejo.             */

.pro-card {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
}

.pro-card__head {
    display: flex;
    align-items: center;
    gap: var(--space-3);
}

.pro-card__photo {
    position: relative;
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    inline-size: 3.75rem;
    block-size: 3.75rem;
    border-radius: var(--r-pill);
    background: var(--tint-navy);
    color: var(--navy);
    font-family: var(--font-display);
    font-size: 1.125rem;
    font-weight: 700;
    overflow: hidden;
}

.pro-card__photo img { inline-size: 100%; block-size: 100%; object-fit: cover; }

/* El punto de estado se monta sobre el retrato, con borde del color de
   la tarjeta para que se lea como encima y no como parte de la foto. */
.pro-card__dot {
    position: absolute;
    inset-block-end: 0;
    inset-inline-end: 0;
    inline-size: 1rem;
    block-size: 1rem;
    border-radius: var(--r-pill);
    border: 2.5px solid var(--bg);
}

.pro-card__id { min-inline-size: 0; }

.pro-card__name {
    margin: 0;
    font-family: var(--font-display);
    font-size: 1.0625rem;
    font-weight: 650;
    color: var(--navy);
}

.pro-card__specialty {
    margin: .125rem 0 .375rem;
    font-size: .875rem;
    color: var(--muted);
}

.pro-card__facts {
    display: flex;
    flex-direction: column;
    gap: .25rem;
    padding-block: var(--space-3);
    border-block: 1px solid var(--hairline);
    font-size: .84375rem;
    color: var(--muted);
}

.pro-card__actions {
    display: flex;
    gap: .5rem;
    margin-block-start: auto;
}

.pro-card__actions > * { flex: 1 1 0; }


/* ═══ Canal de contacto ════════════════════════════════════════════ */

.channel {
    display: flex;
    align-items: center;
    gap: var(--space-3);
}

.channel__label {
    display: block;
    font-size: .75rem;
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--muted);
}

.vet-stats, .vet-new { --ic-tam: .875rem; --ic-trazo: 2; }


/* ═══ Maqueta de teleconsulta ══════════════════════════════════════
   Una figura, no una captura falsa: el mockup dibuja aquí una sesión
   con nombre de veterinaria y minutos restantes, que es una consulta
   inventada. Esto muestra la forma sin afirmar nada.                   */

.tele-mock {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}

.tele-mock__screen {
    display: flex;
    align-items: center;
    justify-content: center;
    aspect-ratio: 16 / 10;
    border-radius: var(--r-lg);
    background: rgba(255, 255, 255, .08);
    color: var(--surface-inverse-muted);
    --ic-tam: 3rem;
    --ic-trazo: 1.2;
}

.tele-mock__live {
    display: flex;
    align-items: center;
    gap: .5rem;
    margin: 0;
    font-size: .75rem;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--surface-inverse-text);
}

.tele-mock__dot {
    inline-size: .5rem;
    block-size: .5rem;
    border-radius: var(--r-pill);
    background: var(--green);
}

.tele-limite { margin-block-start: var(--space-5); }

/* Un correo largo no entra en una tarjeta de un tercio: se achica antes
   de partirse, porque «contacto@vet / sconnect.cl» no se puede copiar de
   un vistazo ni leer como una dirección. */
.channel__value {
    display: block;
    margin: .0625rem 0 0;
    font-size: .9375rem;
    font-weight: 650;
    color: var(--navy);
    overflow-wrap: break-word;
}

@media (min-width: 1200px) {
    .channel__value { font-size: 1rem; }
}

/* ═══ Dato de solo lectura ═════════════════════════════════════════
   Rótulo arriba, valor en una caja hundida. Se parece a un campo pero
   no lo es, y esa es la idea: en una boleta el valor está fijado, y una
   caja con borde de campo invita a escribir encima.                    */

.readout { min-inline-size: 0; }

.readout__label {
    display: block;
    font-size: .75rem;
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--muted);
}

.readout__value {
    display: flex;
    align-items: center;
    gap: .5rem;
    min-block-size: 3rem;
    margin: .375rem 0 0;
    padding: .625rem .9375rem;
    border-radius: var(--r-md);
    background: var(--surface-sunken);
    font-size: .9375rem;
    color: var(--navy);
    text-wrap: pretty;
    --ic-tam: 1.0625rem;
    --ic-trazo: 1.8;
}

/* El código de seguimiento se dicta por teléfono y se copia a mano: en
   monoespaciada y espaciado, para que no se confunda 0 con O. */
.readout__value--codigo {
    font-family: ui-monospace, "SFMono-Regular", "Cascadia Mono", Menlo, monospace;
    font-size: 1.125rem;
    font-weight: 700;
    letter-spacing: .12em;
}


/* ═══ Cuenta regresiva ═════════════════════════════════════════════
   El plazo del pago. Al último minuto cambia de tono: no es lo mismo
   «tienes 14 minutos» que «tienes 40 segundos», y el aviso tiene que
   notarlo antes que la persona.                                        */

.countdown strong {
    font-variant-numeric: tabular-nums;
    font-size: 1.0625rem;
}

.countdown--urgente {
    background: var(--danger-surface);
    color: var(--danger-ink-strong);
}

.countdown--urgente > .ic { color: currentColor; }
.countdown--urgente strong { color: inherit; }


/* ═══ Opción grande ════════════════════════════════════════════════
   Un botón que es una decisión, no una acción: título y la consecuencia
   debajo. Se usa donde elegir mal cuesta —qué hacer si el veterinario
   no llegó— y ahí la consecuencia tiene que estar en el botón, no en
   una nota aparte.                                                     */

.choice {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: .375rem;
    inline-size: 100%;
    padding: var(--space-4) var(--space-5);
    border: 1.5px solid var(--border);
    border-radius: var(--r-lg);
    background: var(--bg);
    font-family: var(--font-body);
    text-align: start;
    cursor: pointer;
    transition: border-color .15s, box-shadow .15s;
}

.choice:hover { border-color: var(--green-ink); box-shadow: var(--shadow-sm); }
.choice:focus-visible { outline: 2px solid var(--green-ink); outline-offset: 2px; }

.choice__title {
    display: flex;
    align-items: center;
    gap: .5rem;
    font-size: 1rem;
    font-weight: 650;
    color: var(--navy);
    --ic-tam: 1.125rem;
    --ic-trazo: 1.8;
}

.choice__desc {
    font-size: .875rem;
    color: var(--muted);
    text-wrap: pretty;
}

.choice--primaria {
    border-color: var(--green-ink);
    background: var(--tint-green);
}

.choice--primaria .choice__desc { color: var(--green-ink); }

/* La salida que devuelve el dinero no se destaca ni se esconde: está
   ahí, en el mismo tamaño, sin invitar ni disuadir. */
.choice--apagada { background: var(--bg-soft); border-color: transparent; }
.choice--apagada .choice__title { color: var(--muted); }


/* ═══ Estrellas ════════════════════════════════════════════════════
   Cinco radios de verdad, no cinco iconos con JavaScript encima: así se
   recorren con el tabulador, se eligen con las flechas y el lector de
   pantalla dice cuántas estrellas es cada una.                          */

.stars {
    display: flex;
    align-items: center;
    gap: .25rem;
    border: 0;
    margin: 0;
    padding: 0;
    min-inline-size: 0;
}

.stars input {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

.stars label {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    inline-size: var(--control-min);
    block-size: var(--control-min);
    border-radius: var(--r-md);
    color: var(--border-dashed);
    cursor: pointer;
    transition: color .12s, transform .12s;
    --ic-tam: 2rem;
    --ic-trazo: 1.5;
}

.stars label:hover { transform: scale(1.08); }

/* La estrella marcada y todas las anteriores. `:has()` sobre el grupo
   deja que la CSS lo resuelva sin que el JS toque clases. */
.stars label.stars__on { color: #E8A33C; }

.stars input:focus-visible + label {
    outline: 2px solid var(--green-ink);
    outline-offset: 2px;
}

.stars__word {
    margin-inline-start: .75rem;
    font-size: .9375rem;
    font-weight: 650;
    color: var(--navy);
}


/* ═══ Marcas de pago ═══════════════════════════════════════════════ */

.pay-brands {
    display: flex;
    align-items: center;
    gap: .5rem;
    margin: 0;
    font-size: .8125rem;
    color: var(--muted);
    --ic-tam: 1.125rem;
    --ic-trazo: 1.8;
}

/* ═══ Documento legal ══════════════════════════════════════════════
   Términos y privacidad se leen en dos contextos: la página completa y
   el modal del registro, que inyecta el mismo parcial por fetch. El
   bloque viaja con el parcial para verse igual en ambos. */

.legal-doc { max-inline-size: 68ch; }

.legal-doc h1 { margin-block-end: .375rem; }

.legal-doc__sub {
    margin: 0 0 var(--space-4);
    color: var(--muted);
}

.legal-doc h2 {
    margin: var(--space-5) 0 var(--space-2);
    font-family: var(--font-display);
    font-size: 1.0625rem;
    color: var(--navy);
}

.legal-doc p { margin: 0 0 var(--space-2); line-height: 1.65; }

.legal-doc ul {
    margin: 0 0 var(--space-2);
    padding-inline-start: 1.4rem;
    display: grid;
    gap: .4rem;
}

.legal-doc li { line-height: 1.6; }
.legal-doc li::marker { color: var(--muted); }

.legal-doc__note {
    margin: var(--space-6) 0 0;
    padding-block-start: var(--space-4);
    border-block-start: 1px solid var(--hairline);
    color: var(--muted);
    font-size: .8438rem;
}

/* ═══ Iconos en bloques que todavía viven en styles.css ═════════════
   El menú del avatar, el panel de servicios, el buzón de avisos y el
   estado vacío dimensionaban su icono con `font-size` sobre un `<i>`, que
   a un `<svg>` no le dice nada. Estas reglas repiten ahí la pareja
   tamaño/trazo y se borran cuando esos bloques migren a la capa nueva. */

.ud-item, .ud-logout button { --ic-tam: 1.125rem; --ic-trazo: 1.8; }
.ud-item > .ic { color: var(--muted); }

.nd-item { --ic-tam: 1.1875rem; --ic-trazo: 1.8; }
.nd-item > .ic { margin-block-start: .125rem; color: var(--green); }

.svc-foot { --ic-tam: 1rem; --ic-trazo: 2; }
.svc-foot > .ic { transition: transform .18s cubic-bezier(.16, 1, .3, 1); }
.svc-foot:hover > .ic { transform: translateX(3px); }

/* El icono del servicio es la tarjetita verde, no solo el trazo: el
   relleno cabe dentro del propio SVG con `box-sizing`, sin envoltorio. */
.svc-item > .ic {
    box-sizing: border-box;
    inline-size: 2.125rem;
    block-size: 2.125rem;
    padding: .4375rem;
    border-radius: var(--r-sm);
    background: rgba(105, 174, 43, .1);
    color: var(--green);
    stroke-width: 1.65;
}

.empty-state-ic { --ic-tam: 2rem; --ic-trazo: 1.5; }

/* La caja de estado de las páginas de error dimensionaba su icono con
   `font-size` sobre un `<i>`; a un svg hace falta la pareja. */
.system-state__icon { --ic-tam: 1.875rem; --ic-trazo: 1.5; }

.page-btn, .load-more-btn { --ic-tam: .875rem; --ic-trazo: 2.2; }
