:root {
    /* Tipografía. Bricolage Grotesque lleva un eje óptico (opsz 12–96): el
       navegador lo ajusta solo con font-optical-sizing, así que los títulos
       grandes cierran formas y los chicos abren. Public Sans para lectura.
       Los stacks viven acá y no repartidos por el archivo. */
    --font-display: 'Bricolage Grotesque', 'Trebuchet MS', system-ui, sans-serif;
    --font-body: 'Public Sans', 'Segoe UI', system-ui, sans-serif;

    --navy: #232E73;
    --green: #69AE2B;
    --green-dark: #558E22;
    /* El verde de marca sobre blanco da 2.73:1 y no sirve para texto ni para
       llevar texto encima. --green-ink es el mismo verde, más profundo, para
       ese trabajo: 5.9:1 en ambos sentidos. --green y --green-dark siguen
       siendo los de íconos, tintes y acentos. */
    --green-ink: #41701A;
    --green-ink-hover: #345712;
    --orange: #E8742C;
    /* Mismo caso que el verde: el naranjo de marca con texto blanco encima da
       3.01:1. --orange-ink es para los rellenos que llevan texto. */
    --orange-ink: #B4520F;
    --blue: #3BA4DB;
    --text: #2A2F3A;
    --muted: #6B7280;
    --bg: #FFFFFF;
    --bg-soft: #F4F7FB;
    /* Un escalón más claro que --bg-soft, para celdas apagadas del calendario. */
    --bg-subtle: #FAFBFD;
    /* Superficie oscura estable para bloques con texto claro. No depende de
       --navy, porque ese token cambia a un tono claro en modo oscuro. */
    --surface-inverse: #232E73;
    --surface-inverse-text: #FFFFFF;
    --surface-inverse-muted: #E6ECFA;
    --surface-inverse-subtle: #C7D2EC;
    /* Anillo de foco para controles sobre --surface-inverse: el verde del
       anillo general da 2.13:1 contra ese navy y WCAG 2.2 SC 1.4.11 pide 3:1
       para indicadores no textuales. Este ámbar llega a 7.8:1. */
    --focus-ring-inverse: #F4C758;

    /* Estados. El proyecto ya usaba esta paleta repartida en literales —
       .btn-danger, .status-cancelled, .message-error, .badge-verified— y el
       bloque de direcciones la volvió a inventar con valores casi iguales
       pero distintos (#9D3430 contra #A32D2D, #E8F6EE contra #E1F5EE). Aquí
       gana la que ya estaba: nombrarla es lo que evita la tercera versión. */
    --danger-ink: #A32D2D;
    --danger-ink-strong: #791F1F;
    --danger-surface: #FCEBEB;
    --danger-border: #F7C1C1;
    --danger-border-strong: #E7B8B8;
    --success-ink: #0F6E56;
    --success-surface: #E1F5EE;
    --success-border: #9FE1CB;
    /* Acción disponible pero no urgente. Es el par que ya usaba el enlace a
       Maps de la libreta de direcciones; nombrarlo evita que la próxima
       pantalla invente el suyo. */
    --action-neutral-surface: #EEF3FA;
    --action-neutral-surface-hover: #E2E9F5;
    --border: #E7EAF0;
    --radius: 14px;
    --shadow: 0 1px 3px rgba(20,30,80,.06), 0 8px 28px rgba(20,30,80,.06);

    /* Escala de radios: los valores que el proyecto ya usaba, ahora con nombre.
       Antes convivían doce radios distintos y cada componente elegía el suyo. */
    --r-xs: 8px;
    --r-sm: 10px;
    --r-md: 12px;
    --r-lg: var(--radius);
    --r-xl: 20px;
    --r-2xl: 24px;
    --r-pill: 999px;

    /* Sombras: siempre desplazamiento + desenfoque, nunca un halo plano. */
    --shadow-sm: 0 1px 2px rgba(20,30,80,.05), 0 2px 6px rgba(20,30,80,.05);
    --shadow-md: 0 2px 6px rgba(20,30,80,.06), 0 10px 28px rgba(20,30,80,.09);
    --shadow-lg: 0 4px 12px rgba(20,30,80,.08), 0 20px 48px rgba(20,30,80,.14);
    /* Capas flotantes (menús, notificaciones, toasts): despegan más del plano. */
    --shadow-pop: 0 2px 6px rgba(20,30,80,.06), 0 10px 30px rgba(20,30,80,.14);
}

* { box-sizing: border-box; }

@media (prefers-reduced-motion: reduce) {
    *,
*::before,
*::after {
        animation-duration: .01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: .01ms !important;
    }

}

body {
    font-family: var(--font-body);
    margin: 0; color: var(--text); background: var(--bg); line-height: 1.65;
    -webkit-font-smoothing: antialiased;
}

/* Rampa de títulos. El peso y el tracking se mueven juntos con el tamaño: un
   h1 y un h3 con el mismo peso obligan a leer para saber cuál manda.
   Los tamaños no cambian, solo el peso y el espaciado óptico. */

h1,
h2,
h3 { font-family: var(--font-display); color: var(--navy);
             font-weight: 600; line-height: 1.2; text-wrap: balance;
             letter-spacing: -0.01em; font-optical-sizing: auto; }

h1 { font-weight: 700; letter-spacing: -0.03em; }

h2 { font-weight: 650; letter-spacing: -0.02em; }

h3 { font-weight: 600; letter-spacing: -0.01em; }

a { color: var(--navy); text-decoration: none; }

/* Accesibilidad: anillo de foco visible al navegar con teclado */

:focus-visible { outline: 2px solid var(--green-ink); outline-offset: 2px; border-radius: 4px; }

input:focus-visible,
select:focus-visible,
textarea:focus-visible { outline: none; }

/* Barra de navegación (responsive) */

/* Lo pegajoso es el bloque completo (barra + tabs móviles). Cuando cada uno se
   pegaba por su cuenta, las tabs tenían que declarar el alto de la barra en
   duro y ese número quedaba mal en cuanto el logo cambiaba de tamaño. */

.site-head { position: sticky; top: 0; z-index: 50; }

.topbar { background: rgba(255,255,255,.92); backdrop-filter: blur(8px);
    border-bottom: 1px solid var(--border); }

.topbar-inner { max-width: 1120px; margin: 0 auto; display: flex;
    align-items: center; gap: 1.5rem; padding: .75rem 1.5rem; flex-wrap: wrap; }

/* `flex: none`: en la barra del veterinario (selector de estado + campana +
   menú) el logo se comprimía hasta 19px de ancho a 320px de pantalla. */

.topbar .logo { display: inline-flex; align-items: center; flex: none; min-height: 44px; }

.topbar .logo img { height: 50px; display: block; }

.nav-toggle { display: none; background: none; border: none; cursor: pointer;
    font-size: 1.7rem; color: var(--navy); margin-left: auto; line-height: 1; }

.nav-collapse { display: flex; flex: 1; align-items: center; gap: 1.5rem; }

.nav-links { display: flex; gap: 1.4rem; }

/* Una etiqueta de navegación no se parte: «Mi agenda» en dos líneas duplica
   el alto de la barra entera. */

/* Los enlaces centran su texto en la misma caja de 44px que el botón de
   «Servicios»: sin esto el enlace estira su caja al alto de la fila y escribe
   arriba, mientras el botón centra, y las etiquetas quedan a distinta altura. */

/* Solo enlaces directos: con «.nav-links a» el nowrap y el tamaño de la barra
   se colaban dentro del panel de Servicios y las descripciones no saltaban de
   línea — el texto se salía del cuadro blanco. */

.nav-links > a { color: var(--muted); font-size: .95rem; font-weight: 500;
    white-space: nowrap; transition: color .15s;
    display: inline-flex; align-items: center; min-height: var(--control-min); }

.nav-links > a:hover { color: var(--green-ink); }

.auth { display: flex; align-items: center; gap: 1.1rem; margin-left: auto; }

.auth a.login { color: var(--navy); font-weight: 500; }

.auth a.login:hover { color: var(--green-ink); }

.auth .username { color: var(--navy); font-weight: 500; }

.auth form.logout { margin: 0; }

.auth form.logout button { background: none; border: 1.5px solid var(--border);
    color: var(--navy); font: inherit; font-weight: 500; padding: .45rem 1.1rem;
    border-radius: var(--r-pill); cursor: pointer; transition: .15s; }

.auth form.logout button:hover { border-color: var(--navy); }

/* ── Menú de servicios ────────────────────────────────────────
   No es una lista de enlaces: es la vitrina. Cada servicio se explica en una
   línea porque «Chequeo general» y «Telemedicina» no dicen lo mismo a quien
   nunca ha pedido una visita. Cada uno entra al formulario ya elegido. */

.svc-menu { position: relative; display: flex; align-items: center; }

.svc-trigger {
    display: inline-flex; align-items: center; gap: .35rem;
    background: none; border: none; padding: 0; cursor: pointer;
    font: inherit; font-size: .95rem; font-weight: 500; color: var(--muted);
    transition: color .15s;
}

.svc-trigger:hover,
.svc-menu.open .svc-trigger { color: var(--green-ink); }

.svc-panel {
    position: absolute; top: calc(100% + .9rem); left: -1.25rem;
    width: min(680px, calc(100vw - 3rem));
    background: var(--bg); border: 1px solid var(--border);
    border-radius: var(--r-xl); box-shadow: var(--shadow-lg);
    padding: 1.25rem; z-index: 120;
    /* Cerrado no ocupa espacio ni recibe foco, pero conserva su caja para que
       la entrada no tenga que recalcular el layout. */
    opacity: 0; visibility: hidden; transform: translateY(-6px);
    transition: opacity .18s ease-out, transform .22s cubic-bezier(.16,1,.3,1), visibility .18s;
}

.svc-menu.open .svc-panel { opacity: 1; visibility: visible; transform: translateY(0); }

/* El hueco entre el botón y el panel se cubre con un puente invisible: sin él
   el menú se cierra al cruzar los 14px que los separan. */

.svc-panel::before {
    content: ''; position: absolute; left: 0; right: 0; top: -.9rem; height: .9rem;
}

.svc-grid { display: grid; grid-template-columns: 1fr 1fr; gap: .25rem; }

.svc-item {
    display: flex; gap: .8rem; align-items: flex-start;
    padding: .8rem .85rem; border-radius: var(--r-md);
    color: inherit; text-decoration: none;
    transition: background .15s;
}

.svc-item:hover { background: var(--bg-soft); }

.svc-item-body { display: flex; flex-direction: column; gap: .1rem; min-width: 0; }

.svc-item-title { font-family: var(--font-display); font-weight: 600; color: var(--navy);
    font-size: .98rem; letter-spacing: -.01em; }

.svc-item-desc { color: var(--muted); font-size: .85rem; line-height: 1.45; text-wrap: pretty; }

.svc-foot {
    display: inline-flex; align-items: center; gap: .4rem;
    margin: .9rem .85rem 0; padding-top: .9rem;
    border-top: 1px solid var(--border); width: calc(100% - 1.7rem);
    color: var(--green-ink); font-size: .9rem; font-weight: 600;
}

/* Barra de tabs horizontal (mobile only) */

.mobile-tabs { display: none; }

/* La navegación cambia de forma antes que el resto del layout: entre 769 y
   1024 la nav horizontal ya no cabe junto al bloque de sesión —los cuatro
   enlaces se partían en dos líneas y la barra del veterinario crecía a 142px—
   pero la página sigue siendo de escritorio. Por eso este corte va en 1024 y
   el de densidad táctil sigue en 768. */

@media (max-width: 1024px) {
    .mobile-tabs {
        display: flex;
        background: #fff;
        border-bottom: 1px solid var(--border);
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
        scrollbar-width: none;
        padding: 0 .5rem;
    }

    .mobile-tabs::-webkit-scrollbar { display: none; }

    .mobile-tabs a {
        flex-shrink: 0;
        padding: .65rem .75rem;
        font-size: .82rem;
        font-weight: 500;
        color: var(--muted);
        white-space: nowrap;
        border-bottom: 2px solid transparent;
        transition: color .15s, border-color .15s;
    }

    .mobile-tabs a:hover,
.mobile-tabs a:focus-visible { color: var(--green-ink); border-bottom-color: var(--green); }

    /* Hamburger ya no necesario: nav-links están en mobile-tabs */

    .nav-toggle { display: none; }

    .topbar-inner { flex-wrap: nowrap; }

    /* `flex: none` y no `flex: 0`: este último trae `flex-basis: 0%`, así que
       el bloque se encogía hasta su min-content y «Iniciar sesión» se partía
       en dos líneas, llevándose la barra de 74 a 113px. */

    .nav-collapse { display: flex !important; flex: none; padding: 0; width: auto; gap: .75rem; margin-left: auto; }

    .nav-links { display: none; }

    .auth a.login,
.auth a.btn-vet,
.user-trigger .user-name { white-space: nowrap; }

}

@media (max-width: 768px) {
    .nav-collapse { gap: .5rem; }

    .auth { flex-direction: row; align-items: center; gap: .4rem; margin-left: 0; width: auto; }

    /* Ocultar nombre en el botón de perfil para ahorrar espacio */

    .user-trigger .user-name,
.user-trigger i { display: none; }

    .user-trigger { padding: .2rem; border: none; background: none; }

    /* Login y ¿Eres Vet? más compactos, pero tocables: son las dos puertas de
       entrada de quien todavía no tiene cuenta. */

    .auth a.login,
.auth a.btn-vet {
        min-height: 44px; display: inline-flex; align-items: center; justify-content: center;
    }

    .auth a.login { font-size: .85rem; }

    .auth a.btn-vet { font-size: .8rem; padding: .35rem .7rem; }

}

/* Botones */

/* inline-flex y no inline-block: components.css estira todo botón a 44px, y con
   display en flujo el sobrante se iba entero abajo. Se veía en los compactos,
   donde el relleno no llega solo al mínimo: el .btn-sm de la agenda del
   veterinario medía 6px arriba y 19 abajo. El gap repone la separación entre
   ícono y texto que flex colapsa. */

.btn,
.btn-outline,
.btn-vet { font-family: var(--font-body); font-weight: 600;
    border-radius: var(--r-md); cursor: pointer; transition: .18s;
    display: inline-flex; align-items: center; justify-content: center; gap: .4rem;
    text-align: center; }

.btn { background: var(--green-ink); color: #fff; padding: .8rem 1.6rem; border: none; }

.btn:hover { background: var(--green-ink-hover); transform: translateY(-1px); }

.btn:active { transform: scale(.98); }

.btn-outline { background: #fff; color: var(--navy); padding: .8rem 1.6rem;
               border: 1.5px solid var(--border); }

.btn-outline:hover { border-color: var(--navy); }

.btn-outline:active { transform: scale(.98); }

.btn-vet { background: var(--orange-ink); color: #fff; padding: .5rem 1.15rem;
           border-radius: var(--r-pill); font-size: .92rem; }

.btn-vet:hover { filter: brightness(.95); }

.btn:disabled,
.btn-outline:disabled { opacity: .6; cursor: not-allowed; transform: none; }

/* El anillo de foco global es verde: sobre un botón verde no se distingue.
   En los rellenos de color el anillo pasa a navy y se separa del borde. */

.btn:focus-visible,
.btn-vet:focus-visible,
.page-btn--active:focus-visible {
    outline-color: var(--navy); outline-offset: 3px;
}

/* Variante secundaria y tamaño compacto: las plantillas ya las pedían
   (`btn-secondary`, `btn-sm`) pero no existían, así que cada acción de apoyo
   —navegar el mes, descargar un resultado— se pintaba como acción principal. */

/* Acción destructiva. Antes había dos definiciones de .btn-danger y la segunda
   solo cambiaba el fondo: el texto quedaba rojo sobre rojo, ilegible en las
   tres confirmaciones que la usan (cancelar cita, eliminar mascota, desactivar
   cuenta). */

/* Números dinámicos (precios, totales): ancho fijo, sin saltos de layout */

.price,
[data-price] {
    font-variant-numeric: tabular-nums;
}

main { max-width: 1120px; margin: 0 auto; padding: 0 1.5rem; }

.card { background: var(--bg); border: 1px solid var(--border);
        border-radius: var(--radius); padding: 1.5rem; }

/* Footer */

.site-footer { background: var(--navy); margin-top: 4rem; }

.site-footer .footer-inner { max-width: 1120px; margin: 0 auto; padding: 2.5rem 1.5rem 1.5rem; }

.site-footer .footer-top { display: flex; flex-wrap: wrap; gap: 2rem; justify-content: space-between; }

.site-footer .brand-col { max-width: 280px; }

.site-footer .footer-logo { font-family: var(--font-display); font-size: 1.4rem; font-weight: 600; color: #fff; }

.site-footer .brand-col p { color: #cfd6f0; font-size: .92rem; margin: .6rem 0 0; }

.site-footer h4 { color: #fff; font-family: var(--font-display); font-size: 1rem; margin: 0 0 .8rem; }

.site-footer a { color: #cfd6f0; font-size: .92rem; display: block; padding: .3rem 0; margin-bottom: .1rem; }

.site-footer a:hover { color: #fff; }

/* El margen negativo alinea ópticamente la fila con el título: cada ícono lleva
   su propio relleno para llegar al área táctil de 44px. */

.site-footer .socials { display: flex; align-items: center; margin-left: -.7rem; }

.site-footer .socials a,
.site-footer .socials > i { width: 44px; height: 44px; display: inline-flex;
    align-items: center; justify-content: center; margin: 0; padding: 0; color: #cfd6f0; }

.site-footer .socials i { font-size: 1.3rem; }

.site-footer .socials a:hover { color: #fff; }

/* Sin cursor de mano en los íconos que todavía no llevan a ninguna parte. */

.site-footer .socials > i { cursor: default; }

.site-footer .footer-bottom { border-top: 1px solid rgba(255,255,255,.15); margin-top: 2rem;
    padding-top: 1.2rem; display: flex; justify-content: space-between; flex-wrap: wrap;
    gap: 1rem; font-size: .85rem; color: #9fa8cf; }

.site-footer .footer-bottom a { display: inline; margin-bottom: 0; }

/* Paginación */

.pagination-nav {
    display: flex; align-items: center; justify-content: center;
    gap: .4rem; margin-top: 1.5rem; flex-wrap: wrap;
}

.page-btn {
    display: inline-flex; align-items: center; justify-content: center;
    min-width: 44px; height: 44px; padding: 0 .7rem;
    border: 1.5px solid var(--border); border-radius: var(--r-xs);
    background: var(--bg); color: var(--navy);
    font-size: .88rem; font-weight: 500; text-decoration: none;
    transition: border-color .15s, background .15s, color .15s;
}

.page-btn:hover { border-color: var(--green-ink); color: var(--green-ink); background: #f4fbe8; }

.page-btn--active {
    background: var(--green-ink); border-color: var(--green-ink);
    color: #fff; pointer-events: none;
}

.page-btn--disabled {
    color: var(--muted); border-color: var(--border);
    background: var(--bg-soft); pointer-events: none; opacity: .5;
}

/* Páginas de autenticación (recuperar contraseña, etc.) */

/* Formularios — campos modernos */

.form-field { margin-bottom: 1.2rem; }

.form-field label { display: block; font-weight: 500; color: var(--navy);
    margin-bottom: .45rem; font-size: .92rem; }

/* Estiliza TODOS los inputs del formulario, no solo .form-control */

.register-form input:not([type="radio"]):not([type="checkbox"]),
.register-form select,
.form-control {
    width: 100%;
    padding: .8rem 1rem;
    border: 1.5px solid var(--border);
    /* Mismo radio que los botones: en un formulario van uno al lado del otro. */
    border-radius: var(--r-md);
    font: inherit;
    color: var(--text);
    background: #fff;
    transition: border-color .18s, box-shadow .18s, background .18s;
    box-shadow: 0 1px 2px rgba(20,30,80,.04);
}

/* Al pasar el mouse */

.register-form input:not([type="radio"]):hover,
.register-form select:hover,
.form-control:hover {
    border-color: #c7cedd;
}

/* Al hacer foco (campo activo): borde verde + halo suave */

.register-form input:focus,
.register-form select:focus,
.form-control:focus {
    outline: none;
    border-color: var(--green-ink);
    box-shadow: 0 0 0 4px rgba(105,174,43,.18), 0 4px 12px rgba(20,30,80,.08);
    background: #fff;
}

/* Al completar correctamente: borde verde suave. Va por :user-valid, que exige
   que la persona haya interactuado: `:not(:placeholder-shown):valid` daba por
   completado todo campo opcional vacío sin placeholder —"Raza", "Fecha de
   nacimiento", "Foto"— y los pintaba de verde antes de tocarlos. */

.register-form input:user-valid,
.register-form select:user-valid {
    border-color: var(--green);
    box-shadow: 0 2px 8px rgba(105,174,43,.12);
}

/* Input con prefijo fijo (teléfono) */

.phone-input-group {
    position: relative;
}

.phone-prefix {
    position: absolute;
    left: 1rem;
    top: 50%;
    transform: translateY(-50%);
    color: var(--muted);
    font-size: .95rem;
    opacity: .6;
    pointer-events: none;
    user-select: none;
    white-space: nowrap;
    z-index: 1;
    line-height: 1;
}

.form-field .helptext { font-size: .82rem; color: var(--muted); margin-top: .35rem; }

.form-field .errorlist { font-size: .82rem; color: #c0392b; list-style: none;
    padding: 0; margin: .35rem 0 0; }

/* Campos armados a mano (foto de mascota, selección de exámenes): usan
   form-group / form-label / form-error y hasta ahora salían sin estilo,
   con la etiqueta indistinguible del texto que la rodea. */

/* Bajada de página: acompaña al h1 y no compite con él. */

/* Los títulos de sección piden más aire arriba que abajo: pertenecen a lo que
   viene, no a lo que quedó atrás. */

/* Campo con error: borde y halo rojos */

.form-field:has(.errorlist) input,
.form-field:has(.errorlist) select,
.form-field:has(.errorlist) textarea,
.register-form input:user-invalid,
.register-form select:user-invalid,
.register-form textarea:user-invalid {
    border-color: #e07a7a;
}

/* Ajustes responsive generales */

img { max-width: 100%; height: auto; }

@media (max-width: 768px) {
    main { padding-left: 1rem; padding-right: 1rem; }

}

/* Registro por secciones */

.grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem 1.5rem; }

/* El fieldset de movilidad agrupa por accesibilidad, no por marco: el borde
   «groove» de fábrica no pertenece a ningún otro formulario del proyecto. */

/* El texto va dentro de un <span> para que sea UN solo flex item: si no, el gap
   se cuela entre los enlaces y la puntuación ("Privacidad ."). */

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

}

/* Campos de subida de archivo */

.register-form input[type="file"] {
    width: 100%; padding: .7rem 1rem; border: 1.5px dashed var(--border);
    border-radius: var(--r-md); background: var(--bg-soft); font: inherit;
    color: var(--muted); cursor: pointer; transition: border-color .18s, background .18s;
}

.register-form input[type="file"]:hover { border-color: var(--green); background: #fff; }

.register-form input[type="file"]::file-selector-button {
    background: var(--navy); color: #fff; border: none; padding: .5rem 1rem;
    border-radius: var(--r-xs); margin-right: 1rem; cursor: pointer; font: inherit;
}

/* Páginas legales / institucionales */

/* El contenedor mide 820px: a ese ancho la línea pasa de 100 caracteres y el
   ojo pierde el renglón al volver. El texto se limita, los títulos no. */

/* Modal de términos y privacidad (registro) */

.legal-dialog { width: min(640px, calc(100% - 2rem)); max-height: 85vh; padding: 0;
    border: none; border-radius: var(--radius); background: var(--bg); color: var(--text);
    box-shadow: 0 1px 3px rgba(20,30,80,.10), 0 24px 60px rgba(20,30,80,.22); overflow: hidden; }

.legal-dialog[open] { display: flex; flex-direction: column; }

.legal-dialog::backdrop { background: rgba(20,30,80,.45); backdrop-filter: blur(2px); }

.legal-dialog[open] { animation: legal-dialog-in .18s cubic-bezier(.23,1,.32,1); }

.legal-dialog[open]::backdrop { animation: legal-backdrop-in .18s ease-out; }

@keyframes legal-dialog-in { from { opacity: 0; transform: translateY(8px) scale(.98); } }

@keyframes legal-backdrop-in { from { opacity: 0; } }

.legal-dialog-head { display: flex; align-items: center; justify-content: space-between;
    gap: 1rem; padding: .6rem .75rem .6rem 1.25rem; border-bottom: 1px solid var(--border); }

.legal-dialog-external { color: var(--muted); font-size: .85rem; }

.legal-dialog-external:hover { color: var(--navy); text-decoration: underline; }

.legal-dialog-close { width: 40px; height: 40px; display: inline-flex; align-items: center;
    justify-content: center; border: none; border-radius: var(--r-sm); background: transparent;
    color: var(--muted); font-size: 1rem; cursor: pointer; transition: background .15s, color .15s; }

.legal-dialog-close:hover { background: var(--bg-soft); color: var(--text); }

.legal-dialog-close:active { transform: scale(.97); }

.legal-dialog-body { overflow-y: auto; padding: 0 1.5rem 1.5rem; }

.legal-dialog-body:focus { outline: none; }

.legal-dialog-body h1 { font-size: 1.35rem; margin: 1.5rem 0 .25rem; }

.legal-dialog-body h2 { font-size: 1.05rem; margin-top: 1.6rem; }

.legal-dialog-body p,
.legal-dialog-body li { font-size: .93rem; text-wrap: pretty; }

.legal-dialog-loading { color: var(--muted); padding: 2rem 0; }

.legal-dialog-foot { display: flex; justify-content: flex-end; gap: .75rem;
    padding: .9rem 1.25rem; border-top: 1px solid var(--border); background: var(--bg); }

.legal-dialog-foot .btn,
.legal-dialog-foot .btn-outline { width: auto; }

@media (max-width: 640px) {
    .legal-dialog { width: 100%; max-width: 100%; max-height: 92vh; margin: auto auto 0;
        border-radius: var(--radius) var(--radius) 0 0; }

    .legal-dialog-body { padding: 0 1.1rem 1.2rem; }

    .legal-dialog-foot .btn,
.legal-dialog-foot .btn-outline { flex: 1; text-align: center; }

}

/* Mis mascotas */

/* Suelta el tope de 820px de .page-narrow, que dejaba la columna del listado
   en 444px: una sola tarjeta por fila por mucho monitor que hubiera. El ancho
   efectivo lo sigue fijando .surface__inner, igual que en la libreta de
   direcciones —son dos pantallas del mismo flujo—, y queda en 1008px. */

/* Grid y no flex: el ícono se alineaba al centro de toda la tarjeta y quedaba
   flotando frente al nombre, y las acciones vivían dentro de la columna de
   texto, apiladas en la mitad del ancho disponible. */

/* Los campos responden al ancho de su tarjeta y no al del viewport: en el
   costado mide 303px y dos columnas fijas daban campos de 139px, que parten
   "Fecha de nacimiento (opcional)" en tres líneas y cortan el propio
   dd-mm-aaaa; apilada la tarjeta es mucho más ancha y una sola columna
   desperdiciaría el sitio. */

/* Con labels de distinta altura los campos arrancaban a distinta altura: el
   input se pega abajo para que la fila quede alineada por el control. */

.photo-upload-wrap { display: flex; align-items: center; gap: 1rem; flex-wrap: wrap; }

.photo-preview { width: 72px; height: 72px; border-radius: 50%; object-fit: cover;
    border: 2px solid var(--border); flex-shrink: 0; }

/* A ancho completo de la tarjeta y repartidas: en la columna de texto los tres
   botones caían uno bajo otro. `auto-fit` deja dos por fila en la tarjeta
   angosta y las tres en línea cuando hay sitio. */

.empty-note { color: var(--muted); }

/* Estado vacío con ícono + CTA */

.empty-state { text-align: center; padding: 3rem 1.5rem; }

.empty-state-ic {
    width: 72px; height: 72px; margin: 0 auto 1rem;
    display: flex; align-items: center; justify-content: center;
    border-radius: 50%; background: var(--bg-soft);
    color: var(--green); font-size: 2rem;
}

.empty-state h3 { margin: 0 0 .4rem; font-size: 1.15rem; }

.empty-state p { color: var(--muted); margin: 0 auto 1.4rem; max-width: 380px; }

/* ── Telemedicina landing ───────────────────────── */

/* ── Telemedicina sesión ───────────────────────── */

.tele-session-body { display: grid; grid-template-columns: 1fr 360px; gap: 1.2rem; align-items: start; }

.tele-video-panel { border-radius: var(--r-lg); overflow: hidden; background: #000;
    box-shadow: 0 4px 20px rgba(20,30,80,.15); }

.tele-iframe { width: 100%; height: 580px; border: none; display: block; }

.tele-side-panel { display: flex; flex-direction: column; gap: 1rem; }

.tele-chat { display: flex; flex-direction: column; border: 1.5px solid var(--border);
    border-radius: var(--r-lg); overflow: hidden; background: #fff;
    box-shadow: var(--shadow-sm); }

.tele-chat-messages { flex: 1; min-height: 340px; max-height: 380px; overflow-y: auto;
    padding: 1rem; display: flex; flex-direction: column; gap: .6rem; }

.tele-chat-empty { color: var(--muted); font-size: .88rem; text-align: center; margin: auto; }

.tele-msg { display: flex; flex-direction: column; max-width: 85%; }

.tele-msg-mine { align-self: flex-end; align-items: flex-end; }

.tele-msg-other { align-self: flex-start; align-items: flex-start; }

.tele-msg-sender { font-size: .72rem; color: var(--muted); font-weight: 600; margin-bottom: .15rem; }

.tele-msg-text { background: var(--bg-soft); border-radius: 12px 12px 12px 2px;
    padding: .5rem .75rem; font-size: .9rem; margin: 0; line-height: 1.45; word-break: break-word; }

.tele-msg-mine .tele-msg-text { background: var(--green-ink); color: #fff;
    border-radius: 12px 12px 2px 12px; }

.tele-msg-time { font-size: .7rem; color: var(--muted); margin-top: .1rem; }

.tele-chat-form { display: flex; border-top: 1px solid var(--border); padding: .6rem; gap: .5rem; }

.tele-chat-form input { flex: 1; border: 1.5px solid var(--border); border-radius: var(--r-sm);
    padding: .5rem .75rem; font: inherit; font-size: .9rem; }

.tele-chat-form input:focus { outline: none; border-color: var(--green); }

.tele-chat-form button { background: var(--green-ink); color: #fff; border: none;
    border-radius: var(--r-sm); padding: .5rem .85rem; cursor: pointer; font-size: 1rem;
    transition: background .15s; }

.tele-chat-form button:hover { background: var(--green-ink-hover); }

/* ── Responsive telemedicina ───────────────────── */

@media (max-width: 1024px) {
    .tele-session-body { grid-template-columns: 1fr; }

    .tele-iframe { height: 420px; }

}

@media (max-width: 900px) {
    .tele-iframe { height: 380px; }

    .tele-chat-messages { min-height: 220px; max-height: 280px; }

}

@media (max-width: 600px) {
    .tele-iframe { height: 280px; }

    .tele-chat-messages { min-height: 180px; max-height: 240px; }

}

@media (max-width: 420px) {
    .tele-iframe { height: 220px; }

    .tele-chat-messages { min-height: 150px; max-height: 200px; }

}

/* Paquetes de exámenes */

/* Citas / reservas */

/* Suelta el tope de 820px de .page-narrow, igual que las otras pantallas del
   flujo de dueño: el ancho efectivo lo fija .surface__inner. */

/* Sustituye el style inline que tenía el encabezado para deshacer .action-bar,
   que lo apilaba en una columna. */

/* Más chico y sin relieve de control: el estado se lee, no se toca. */

.booking-list { display: flex; flex-direction: column; gap: 1rem; margin-top: 0; }

/* Ahora es un <iframe> de Maps Embed: sin width e inline-block se queda en los
   300px por defecto del navegador y deja un descender bajo el borde. */

/* Acotado: a ancho completo el mapa era lo más grande de la tarjeta y le
   ganaba a la cita, con la rotulación comercial de Google compitiendo por la
   atención. Ubica, que es para lo que está. Lleva .surface--owner porque
   responsive.css topa todo iframe del flujo con `.surface--owner iframe`
   (0-1-1) y sin ese peso el max-inline-size de aquí no llega a aplicarse. */

.booking-map { display: block; inline-size: 100%; height: 140px; border-radius: var(--r-sm);
    border: 1px solid var(--border); overflow: hidden; margin-top: .9rem; z-index: 0; }

.surface--owner .booking-map { max-inline-size: 28rem; }

.status { font-size: .8rem; font-weight: 600; padding: .35rem .8rem; border-radius: var(--r-pill);
    white-space: nowrap; }

/* Sidebar de citas: columna derecha con todos los estados y acciones */

/* En filas que envuelven, no en columna: seis pastillas apiladas medían 294px
   y estiraban la tarjeta dejando un blanco de ~190px junto al texto. Es el
   mismo criterio que ya usa el móvil pequeño; el tope de ancho evita que la
   barra invada el texto de la izquierda. */

/* Estados */

/* Pagada */

/* Reseñada */

/* Acciones: tres papeles con significado estable, no un color por acción.
   Convivían cinco —ámbar Pagar, azul Mensaje, naranjo Reseñar, rojo Cancelar,
   violeta Reagendar— y el color no codificaba nada: hacía de índice. Ahora
   distingue qué desbloquea el flujo, qué está disponible y qué destruye. */

/* Primaria: la que el estado está pidiendo. Una por tarjeta. */

/* Disponible, sin urgencia. */

/* Destructiva: contenida en reposo, explícita al apuntarla. */

/* .rebook-banner se borró: declaraba un violeta que nunca llegó a verse.
   Vive antes que .directed-banner con la misma especificidad y el elemento
   lleva las dos clases, así que el banner de reagendar siempre se pintó con
   los colores de .directed-banner. */

/* En móvil y tablet la barra lateral se vuelve una fila de píldoras envuelta y
   varias son enlaces o botones reales (Pagar, Boleta, Cancelar). A 28px de alto
   se fallan con el pulgar: solo las interactivas crecen, las de estado no. */

/* ── Mis ganancias (incluye la cartera semanal) ───────────── */

/* La semana en curso es el foco de la página: gana por tamaño y por el aire
   que la rodea, no por color ni bordes. El resto de los períodos baja a una
   fila de datos sin tarjeta, para que no compita. */

.ep-tab {
    padding: .5rem 1rem; border: none; border-radius: var(--r-xs);
    background: transparent; font-size: .85rem; font-weight: 600;
    color: var(--muted); cursor: pointer; transition: all .2s;
}

.ep-tab.active {
    background: var(--bg); color: var(--green-ink);
    box-shadow: var(--shadow-sm);
}

.ep-tab:hover:not(.active) { color: var(--text); }

/* `minmax(0, 1fr)` y no `1fr`: el mínimo automático de una pista de grilla es
   el min-content de su contenido, y un <canvas> sin atributo width mide 300px.
   Con `1fr` la pista crecía a 346px dentro de un contenedor de 253 y la
   tarjeta se salía de la pantalla en teléfonos angostos. */

/* Liquidación cerrada: se abre para ver las visitas que la componen.
   <details> nativo, así el teclado y los lectores de pantalla ya funcionan. */

.payout { background: var(--bg); border: 1px solid var(--border);
    border-radius: var(--radius); }

/* Toast notifications */

.messages {
    position: fixed; top: 76px; right: 1.25rem; z-index: 1000;
    display: flex; flex-direction: column; gap: .5rem;
    width: 320px; pointer-events: none;
}

.message {
    display: flex; align-items: flex-start; gap: .75rem;
    padding: .85rem 1rem; border-radius: var(--r-md);
    font-size: .9rem; border: 1px solid transparent;
    box-shadow: var(--shadow-pop);
    pointer-events: all;
    opacity: 1; transform: translateX(0);
    transition: opacity .35s ease, transform .35s ease;
}

.message.toast-hiding { opacity: 0; transform: translateX(30px); }

.message-success { background: var(--success-surface); color: var(--success-ink); border-color: var(--success-border); }

.message-error { background: var(--danger-surface); color: var(--danger-ink); border-color: var(--danger-border); }

.message-info { background: #E6F1FB; color: #185FA5; border-color: #B5D4F4; }

.message-warning { background: #FEF6E7; color: #92510B; border-color: #FAD78B; }

.toast-text { flex: 1; }

.toast-close {
    background: none; border: none; cursor: pointer;
    color: inherit; opacity: .55; font-size: 1.1rem; line-height: 1;
    padding: 0; flex-shrink: 0;
}

.toast-close:hover { opacity: 1; }

/* En móvil la cabecera pegajosa mide barra + tabs y el aviso caía debajo de
   ella. Va abajo, donde además queda al alcance del pulgar. */

@media (max-width: 768px) {
    .messages { top: auto; bottom: 1rem; left: 1rem; right: 1rem; width: auto; }

    .message.toast-hiding { transform: translateY(24px); }

}

/* Cancelación */

/* Salidas tras una falta del veterinario. Son <button> de un mismo formulario,
   así que hay que devolverles tipografía, alineación y caja: sin esto salían
   como botones grises del navegador, con el título y la explicación pegados en
   una línea, justo en la pantalla donde alguien ya se llevó un mal rato. */

/* La salida recomendada gana por relleno y borde, no por tamaño: las tres
   siguen siendo la misma decisión y deben leerse a la par. */

/* Menú de usuario */

.user-menu { position: relative; }

.user-trigger { display: inline-flex; align-items: center; gap: .5rem; background: none;
    border: 1px solid var(--border); border-radius: var(--r-pill); padding: .35rem .8rem .35rem .4rem;
    cursor: pointer; font: inherit; color: var(--navy); transition: border-color .15s; }

.user-trigger:hover { border-color: #c7cedd; }

.user-trigger .avatar-sm { width: 30px; height: 30px; border-radius: 50%; background: #E9F3DD;
    color: var(--green-ink); display: flex; align-items: center; justify-content: center;
    font-weight: 500; font-size: .9rem; flex-shrink: 0; }

.user-trigger .user-name { font-weight: 500; font-size: .92rem; }

.user-trigger i { font-size: .75rem; color: var(--muted); transition: transform .2s; }

.user-menu.open .user-trigger i { transform: rotate(180deg); }

.user-dropdown { display: none; position: absolute; right: 0; top: calc(100% + 10px);
    width: 264px; background: #fff; border: 1px solid var(--border); border-radius: var(--r-lg);
    box-shadow: var(--shadow-pop); overflow: hidden; z-index: 100; }

.user-menu.open .user-dropdown { display: block; }

.ud-header { display: flex; align-items: center; gap: 12px; padding: 15px 16px; }

.ud-header .avatar { width: 42px; height: 42px; border-radius: 50%; background: #E9F3DD;
    color: var(--green-ink); display: flex; align-items: center; justify-content: center;
    font-weight: 500; flex-shrink: 0; }

.ud-name { font-weight: 500; color: var(--navy); font-size: .92rem; }

.ud-email { color: var(--muted); font-size: .8rem; white-space: nowrap; overflow: hidden;
    text-overflow: ellipsis; max-width: 180px; }

.ud-section { padding: 6px 0; border-top: 1px solid var(--border); }

.ud-item { display: flex; align-items: center; gap: 12px; padding: 10px 16px;
    color: var(--text); font-size: .9rem; text-decoration: none; }

.ud-item i { font-size: 1.05rem; color: var(--muted); width: 20px; text-align: center; }

a.ud-item:hover { background: var(--bg-soft); }

.ud-item.disabled { color: #9aa3b2; }

.ud-logout { margin: 0; }

.ud-logout button { display: flex; align-items: center; gap: 12px; padding: 10px 16px;
    width: 100%; text-align: left; background: none; border: none; cursor: pointer;
    font: inherit; font-size: .9rem; color: var(--danger-ink); }

.ud-logout button i { font-size: 1.05rem; }

.ud-logout button:hover { background: var(--danger-surface); }

@media (max-width: 768px) {
    .user-menu { width: auto; }

    .user-dropdown {
        position: absolute;
        right: 0;
        left: auto;
        width: 280px;
        box-shadow: var(--shadow-pop);
        border: 1px solid var(--border);
        border-radius: var(--r-lg);
        margin-top: .5rem;
    }

}

/* Perfil */

/* Direcciones */

/* El encabezado y el resumen son la misma unidad: --space-7 (hasta 5rem) los
   separaba tanto que el título parecía pertenecer a otra pantalla. */

.default-address-hero { display: grid; grid-template-columns: minmax(0, .9fr) minmax(20rem, 1.1fr); margin-block-end: var(--space-6); overflow: hidden; border-radius: var(--r-lg); background: var(--surface-inverse); box-shadow: 0 1.1rem 2.6rem rgba(20, 45, 101, .18); }

.default-address-hero h2 { margin: 0; color: var(--surface-inverse-text); font-size: clamp(1.5rem, 2.5vw, 2rem); }

/* Lleva .surface--owner porque responsive.css pinta el anillo con
   `.surface--owner a:focus-visible` (0-2-1) y sin ese peso esta regla (0-2-0)
   perdía en silencio: el ámbar estaba declarado pero nunca se veía. */

/* Sin mapa el cuerpo entero se acotaba a 44rem dentro de una caja de 74rem:
   casi un tercio de la banda quedaba en azul vacío. La medida la piden las
   líneas de texto, no el bloque. */

/* Con ancho de sobra la acción se va al costado y la tarjeta ocupa el alto de
   lo que dice, no el de la que sí trae mapa. Más abajo apila: el botón al lado
   dejaría la calle en un hilo de texto. */

/* Vertical generoso entre bloques, horizontal contenido: --space-7 en las dos
   direcciones abría una zanja de 5rem entre el listado y el formulario. */

/* .68rem eran 10,9px: por debajo del piso legible aunque el contraste diera. */

/* El desfase lo manda la barra superior, no la escala de espaciado: con
   --space-7 + 4rem el panel se pegaba 9rem abajo del borde visible. */

/* Configuración */

/* Interruptor (toggle) */

/* Ayuda y contacto */

/* Acordeón FAQ (global) */

.faq { margin-top: 1.2rem; }

.faq details { background: var(--bg); border: 1px solid var(--border); border-radius: var(--radius);
    padding: 1rem 1.3rem; margin-bottom: .8rem; }

.faq summary { cursor: pointer; font-weight: 500; color: var(--navy); list-style: none;
    display: flex; justify-content: space-between; align-items: center; gap: 1rem; }

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

.faq summary i { color: var(--muted); transition: transform .2s; }

.faq details[open] summary i { transform: rotate(180deg); }

.faq p { color: var(--muted); margin: .8rem 0 0; }

/* Avatares con foto */

.avatar-sm img,
.avatar img { width: 100%; height: 100%;
    object-fit: cover; border-radius: 50%; }

/* Perfil público del vet */

/* Listado de veterinarios — header y filtros */

/* Grid de veterinarios */

/* Salida hacia la app de mapas. Es un enlace, no un botón primario: la acción
   de la pantalla sigue siendo cerrar la visita, no irse del sitio. */

.maps-link { display: inline-flex; align-items: center; gap: .35rem;
    min-height: var(--control-min); color: var(--navy); font-size: .9rem; font-weight: 500; }

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

/* ── Trayectoria del veterinario ──────────────────────────────
   Visitas realizadas y urgencias, o la insignia de nuevo cuando todavía no
   llega al umbral. El dato es texto y no color: la tarjeta se lee igual en
   escala de grises y el lector de pantalla lo dice completo. */

.vet-stats { display: inline-flex; align-items: center; gap: .35rem;
    flex-wrap: wrap; color: var(--muted); font-size: .82rem; }

.vet-stats-sep { color: var(--border); }

.vet-new { display: inline-flex; align-items: center; gap: .3rem;
    color: var(--green-ink); font-size: .82rem; font-weight: 500; }

/* Status dot */

.status-dot {
    position: absolute; bottom: 2px; right: 2px;
    width: 13px; height: 13px; border-radius: 50%;
    border: 2px solid #fff; display: flex; align-items: center; justify-content: center;
}

/* El punto es el único portador del estado en la lista de vets, así que tiene
   que separarse del blanco (3:1 mínimo). Los cuatro tonos venían de otra
   paleta; ahora son los del proyecto, a la intensidad que sí se distingue.
   El gris de OFFLINE además lleva una ✕ blanca de 7px encima. */

.status-dot--ACTIVE { background: var(--green-ink); }

.status-dot--AWAY { background: var(--orange-ink); }

.status-dot--BUSY { background: var(--danger-ink); }

.status-dot--OFFLINE { background: var(--muted); font-size: 7px; color: #fff; font-weight: 700; line-height: 1; }

/* El punto que va dentro del selector de la barra, no sobre un avatar.
   `flex: none` porque es hijo de un flex y se aplastaba a 7px de ancho. */

.status-dot--inline { position: static; border: none; width: 10px; height: 10px; flex: none; }

/* Selector de estado (vet navbar) */

.vet-status-selector {
    display: flex; align-items: center; gap: .4rem;
    font-size: .82rem; background: var(--bg-soft);
    border: 1px solid var(--border); border-radius: var(--r-xs);
    padding: .3rem .6rem; cursor: pointer;
}

.vet-status-selector select {
    border: none; background: transparent; font-size: .82rem;
    font-family: inherit; cursor: pointer; outline: none; color: var(--text);
}

/* Estrellas reseña */

@keyframes pop {
    0% { transform: scale(.7); }
    60% { transform: scale(1.25); }
    100% { transform: scale(1); }
}

/* Pago */

.pay-brands { margin-top: 1rem; color: var(--muted); font-size: .85rem; }

/* Cuenta regresiva del plazo para pagar */

/* Comprobante de pago */

/* ===== Responsive global ===== */

/* Nada se desborda horizontalmente.
   `clip` y no `hidden`: `overflow-x: hidden` convierte al elemento en contenedor
   de scroll y eso anula el `position: sticky` de la cabecera —la barra superior
   se iba con el scroll en todas las páginas—. `clip` recorta igual sin crear el
   contenedor. */

html { overflow-x: hidden; }

body { overflow-x: clip; }

img,
video,
table { max-width: 100%; }

* { word-wrap: break-word; overflow-wrap: break-word; }

/* ── Tablet landscape (≤ 900px) ── */

/* ── Tablet (≤ 768px) ── */

@media (max-width: 768px) {
    main { padding-left: 1rem; padding-right: 1rem; }

    h1 { font-size: 1.6rem; }

    h2 { font-size: 1.3rem; }

    .card { padding: 1.3rem; }

    /* Perfil: cabecera apila */

    /* Perfil público vet */

    /* Footer: apilar columnas */

    .site-footer .footer-top { flex-direction: column; gap: 1.5rem; }

    .site-footer .brand-col { max-width: 100%; }

    /* Topbar: logo más chico */

    .topbar .logo img { height: 40px; }

    /* Notif dropdown alineado a la derecha */

    .notif-dropdown { right: 0; width: 290px; }

}

/* ── Móvil (≤ 640px) ── */

@media (max-width: 640px) {
    .grid-2,
.reviews { grid-template-columns: 1fr; }

    /* Register form: reduce padding */

    /* Perfil form: campos a 1 columna, ya cubierto por .grid-2 */

    /* Formulario acciones: apilar */

    /* Chat: mensajes más anchos */

    .msg { max-width: 88%; }

    .chat-box { max-height: 350px; min-height: 180px; }

}

/* ── Móvil pequeño (≤ 540px) ── */

@media (max-width: 540px) {
    /* Tarjetas de booking/dirección/mascota: apilar */

    /* Mapa en bookings: más bajo */

    .booking-map { height: 130px; }

}

/* ── Pantalla muy pequeña (≤ 420px) ── */

@media (max-width: 420px) {
    /* flex y no block: ocupa el ancho igual, pero sin volver a dejar el texto
       pegado arriba cuando el mínimo de 44px estira la caja. */

    .btn,
.btn-outline { display: flex; width: 100%; text-align: center; }

    /* Los compactos viven dentro de filas de lista: a ancho completo romperían
       la fila en la que están. */

    /* Topbar padding reducido */

    .topbar-inner { padding: .6rem .8rem; }

    .topbar .logo img { height: 36px; }

    /* Page narrow: márgenes mínimos */

    main { padding-left: .6rem; padding-right: .6rem; }

    /* Notif y user dropdown: alineados a derecha, ancho razonable */

    .notif-dropdown { width: calc(100vw - 2rem); right: 0; }

    .user-dropdown { width: calc(100vw - 2rem); right: 0; }

}

/* Notificaciones — campanita */

.notif-menu { position: relative; }

.notif-trigger { position: relative; background: none; border: 1px solid var(--border);
    width: 44px; height: 44px; border-radius: 50%; cursor: pointer; color: var(--navy);
    font-size: 1.1rem; display: flex; align-items: center; justify-content: center; transition: .15s; }

.notif-trigger:hover { border-color: #c7cedd; }

.notif-badge { position: absolute; top: -4px; right: -4px; background: var(--orange-ink); color: #fff;
    font-size: .72rem; font-weight: 600; min-width: 18px; height: 18px; padding: 0 4px;
    border-radius: var(--r-pill); display: flex; align-items: center; justify-content: center; }

.notif-dropdown { display: none; position: absolute; right: 0; top: calc(100% + 10px);
    width: 320px; background: #fff; border: 1px solid var(--border); border-radius: var(--r-lg);
    box-shadow: var(--shadow-pop); overflow: hidden; z-index: 100; }

.notif-menu.open .notif-dropdown { display: block; }

.nd-header { display: flex; justify-content: space-between; align-items: center;
    padding: 13px 16px; border-bottom: 1px solid var(--border); font-weight: 600; color: var(--navy); }

.nd-readall { background: none; border: none; color: var(--green-ink); font-size: .8rem;
    cursor: pointer; font-weight: 500; }

.nd-item { display: flex; gap: 11px; padding: 11px 16px; text-decoration: none; color: var(--text);
    border-bottom: 1px solid var(--border); }

.nd-item:hover { background: var(--bg-soft); }

.nd-item.unread { background: #F2F8EC; }

.nd-item i { color: var(--green); font-size: 1.1rem; margin-top: 2px; }

.nd-title { font-size: .88rem; font-weight: 500; color: var(--navy); }

.nd-time { font-size: .74rem; color: var(--muted); margin-top: 2px; }

.nd-empty { padding: 1.5rem; text-align: center; color: var(--muted); font-size: .9rem; }

.nd-all { display: block; text-align: center; padding: 11px; color: var(--green-ink);
    font-weight: 500; font-size: .88rem; }

/* Notificaciones — página */

/* No leída: mismo tinte que en el desplegable de la campanita. Antes era una
   barra verde de 3px al costado, así que el mismo estado se leía distinto
   según dónde lo mirabas —y además desalineaba la fila respecto a las leídas. */

/* Sobre el tinte verde el gris de --muted se queda en 4.47:1. El texto
   secundario se tiñe del mismo tono en vez de seguir gris. */

.nd-item.unread .nd-time { color: #4C5B41; }

@media (max-width: 480px) {
    .notif-dropdown { width: 280px; }

}

/* Mensajería */

/* La columna del medio se queda con el espacio sobrante y puede encogerse:
   sin min-width:0 un último mensaje largo empuja la hora fuera de la fila. */

.chat-box { display: flex; flex-direction: column; gap: .6rem; min-height: 300px;
    max-height: 460px; overflow-y: auto; padding: .5rem 0; }

.msg { max-width: 75%; padding: .65rem .95rem; border-radius: var(--r-lg); }

.msg p { margin: 0; font-size: .93rem; }

.msg-time { font-size: .68rem; opacity: .7; display: block; margin-top: .25rem; }

.msg.mine { align-self: flex-end; background: var(--green-ink); color: #fff; border-bottom-right-radius: 4px; }

.msg.theirs { align-self: flex-start; background: var(--bg-soft); color: var(--text); border-bottom-left-radius: 4px; }

.chat-form { display: flex; gap: .7rem; margin-top: 1rem; padding-top: 1rem; border-top: 1px solid var(--border); }

.chat-form input { flex: 1; padding: .75rem 1rem; border: 1.5px solid var(--border);
    border-radius: var(--r-pill); font: inherit; }

.chat-form input:focus { outline: none; border-color: var(--green); }

.chat-form .btn { border-radius: 50%; width: 46px; padding: 0; flex-shrink: 0; }

.receipt-map { display: block; width: 100%; height: 200px; border-radius: var(--r-md);
    border: 1px solid var(--border); overflow: hidden; z-index: 0; }

/* ── Exámenes a domicilio ─────────────────────── */

.exam-select-section { margin-top: 1rem; }

/* Aviso de ayuno en la lista de pedidos: mismo naranjo que el badge del
   catálogo, para que el dato se reconozca de un lado al otro del flujo.
   Va también con `.booking-main` porque ahí vive el aviso y `.booking-main p`
   lo pintaría gris como cualquier otra línea de la tarjeta. */

/* Naranjo de ayuno un punto más oscuro que el original (#E65100): a .78rem
   sobre el crema quedaba en 3.46:1 y no llegaba al mínimo de texto. Mismo tono,
   ahora legible. Igual criterio para el rojo del descuento (#E83E3E → #D32A2A).
   No toca la paleta de marca: son colores de estado. */

/* ══ Fase 4: modo oscuro (variables CSS) ══ */

[data-theme="dark"] {
    --navy: #A9B6FF;
    --green: #7DC24A;
    --green-dark: #69AE2B;
    --blue: #5FB7E8;
    --orange: #F08A4B;
    --text: #E6EAF3;
    --muted: #9AA3B8;
    --bg: #12151F;
    --bg-soft: #1A1F2E;
    --border: #2A3145;
    --shadow: 0 1px 3px rgba(0,0,0,.4), 0 8px 28px rgba(0,0,0,.35);
    color-scheme: dark;
}

[data-theme="dark"] body { background: var(--bg); }

[data-theme="dark"] .topbar,
[data-theme="dark"] .card,
[data-theme="dark"] .register-form,
[data-theme="dark"] .mobile-tabs { background: var(--bg-soft); }

[data-theme="dark"] .form-control {
    background: #101420; color: var(--text); border-color: var(--border);
}

[data-theme="dark"] img { filter: brightness(.94); }

/* ══ Fase 4: spinner anti doble envío ══ */

.btn-spinner {
    display: inline-block; width: 1em; height: 1em; vertical-align: -0.15em;
    border: 2px solid currentColor; border-right-color: transparent;
    border-radius: 50%; animation: btn-spin .7s linear infinite;
}

@keyframes btn-spin { to { transform: rotate(360deg); } }

/* ══ Fase 4: botones flotantes (tema + instalar PWA) ══ */

#theme-toggle-btn,
#pwa-install-btn {
    position: fixed; z-index: 1100; border: 1px solid var(--border);
    background: var(--bg-soft); color: var(--text); cursor: pointer;
    box-shadow: var(--shadow); font-family: inherit;
}

#theme-toggle-btn {
    right: 16px; bottom: 84px; width: 44px; height: 44px;
    border-radius: 50%; font-size: 1.15rem;
}

#pwa-install-btn {
    right: 16px; bottom: 140px; padding: .5rem .9rem;
    border-radius: var(--r-pill); font-size: .9rem;
}

/* ══ Fase 4: botón cargar más ══ */

.load-more-btn {
    display: block; margin: 1.5rem auto; padding: .6rem 1.6rem;
    border-radius: var(--r-pill); border: 1px solid var(--border);
    background: var(--bg-soft); color: var(--navy); cursor: pointer; font-weight: 600;
}

/* ── Calendario de disponibilidad del vet ─────────────────── */

/* Este bloque venía escrito contra tokens que el proyecto no tiene
   (--primary, --surface), así que caía en los fallbacks: un azul #2563eb y una
   familia de grises y verdes ajenos a la marca. Ahora usa la paleta del sitio,
   con el mismo reparto de significado que el resto: verde = disponible,
   azul = visita tomada, navy = hoy. */

.cal-card { background: var(--bg); border: 1px solid var(--border); border-radius: var(--r-lg); padding: 1rem; margin-bottom: 1.25rem; }

.cal-head { display: flex; justify-content: space-between; align-items: center; gap: .75rem; flex-wrap: wrap; margin-bottom: .75rem; }

.cal-nav { display: flex; gap: .4rem; flex-wrap: wrap; }

.cal-title { margin: 0; font-size: 1.15rem; }

.cal-grid { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 1px; background: var(--border); border: 1px solid var(--border); border-radius: var(--r-sm); overflow: hidden; }

.cal-dow { background: var(--bg-soft); padding: .5rem .25rem; text-align: center; font-size: .72rem; font-weight: 600; letter-spacing: .04em; color: var(--muted); }

.cal-cell { background: var(--bg); min-height: 84px; padding: .35rem; display: flex; flex-direction: column; gap: .2rem; position: relative; }

.cal-cell--fuera { background: var(--bg-subtle); }

.cal-cell--fuera .cal-num { color: var(--muted); font-weight: 500; }

.cal-cell--bloqueada { background: var(--bg-soft); }

.cal-cell--bloqueada .cal-num { color: var(--muted); }

.cal-cell--hoy { outline: 2px solid var(--navy); outline-offset: -2px; }

.cal-cell--activa { background: #EDF1FA; }

.cal-num { font-size: .82rem; font-weight: 600; text-decoration: none; color: inherit; font-variant-numeric: tabular-nums; }

a.cal-num:hover { color: var(--green-ink); text-decoration: underline; }

.cal-hoy { position: absolute; top: .3rem; right: .3rem; font-size: .72rem; font-weight: 600; letter-spacing: .04em; background: var(--navy); color: #fff; border-radius: var(--r-pill); padding: .1rem .4rem; }

.cal-chip { display: block; font-size: .74rem; border-radius: 6px; padding: .12rem .3rem; border: 1px solid transparent; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.cal-chip--libre { background: #F2F8EC; border-color: #CDE6B0; color: #3D6B18; }

.cal-chip--visita { background: #E6F1FB; border-color: #B5D4F4; color: #185FA5; }

.cal-chip__compact { display: none; }

/* ── Semana tipo del vet ──────────────────────────────────── */

.week-table-wrap { overflow-x: auto; }

.week-table { width: 100%; border-collapse: collapse; }

.week-table thead th { text-align: left; font-size: .78rem; letter-spacing: .03em; text-transform: uppercase; color: var(--muted); font-weight: 600; padding: 0 .5rem .5rem; border-bottom: 1px solid var(--border); }

.week-table td,
.week-table tbody th { padding: .3rem .5rem; vertical-align: middle; }

.week-table select { min-width: 6.5rem; }

/* La línea separa días, no tramos: el segundo tramo pertenece al de arriba. */

.week-row--inicio-dia > * { border-top: 1px solid var(--border); padding-top: .55rem; }

.week-table tbody tr:first-child > * { border-top: 0; }

.week-day { text-align: left; white-space: nowrap; }

.week-day-name { display: block; font-weight: 600; }

.week-day-date { display: block; font-size: .78rem; color: var(--muted); font-variant-numeric: tabular-nums; }

.week-tramo { color: var(--muted); white-space: nowrap; font-size: .88rem; }

.visually-hidden { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }

/* El error ocupa su propia fila: dentro de la celda desplazaba los selects. */

.week-error-row td { padding: 0 .5rem .4rem; }

.week-error-row .errorlist { margin: 0; }

/* El número del día era un enlace de 19×22: por debajo del área de destino
   mínima, y en tablet táctil tampoco crecía. Pasa a ocupar la celda entera,
   que es lo que la persona intenta tocar de todos modos. */

@media (max-width: 768px) {
    .cal-cell { min-height: 64px; padding: .25rem; }

    .cal-num { display: block; width: 100%; text-align: center;
               padding: .3rem 0 .15rem; min-height: 28px; }

}

@media (max-width: 640px) {
    /* Siete columnas en 320px de pantalla dejaban celdas de 30px con texto de
       9px. La tarjeta recupera el ancho que gastaba en relleno. */

    .cal-card { padding: .75rem .5rem; }

    .cal-chip { font-size: .72rem; text-align: center; }

    .cal-dow { font-size: .7rem; padding: .45rem .1rem; }

    .cal-chip__full { display: none; }

    .cal-chip__compact { display: inline; }

    /* La tabla se apila: cuatro columnas con dos selects no caben en 375px.
       Las reglas van con `.week-table tr...` y no con la clase sola porque
       `.week-table tr` le gana en especificidad y dejaría la fila en block. */

    .week-table thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }

    .week-table,
.week-table tbody { display: block; width: 100%; }

    /* Dos columnas fijas para los selects: si el rótulo compartiera fila, la
       columna `auto` mediría distinto en cada fila y los selects del mismo día
       quedarían desalineados entre sí. */

    .week-table tr.week-row { display: grid; grid-template-columns: 1fr 1fr; align-items: center; column-gap: .4rem; row-gap: .15rem; padding: .35rem 0; }

    .week-table tr.week-row > * { padding: 0; border-top: 0; }

    .week-day,
.week-tramo { grid-column: 1 / -1; }

    .week-cell--vacia { display: none; }

    .week-table tr.week-row--inicio-dia { border-top: 1px solid var(--border); padding-top: .6rem; margin-top: .35rem; }

    .week-table tbody tr:first-child { border-top: 0; margin-top: 0; }

    .week-table tr.week-error-row { display: block; }

    .week-table tr.week-error-row td { display: block; padding: 0 0 .4rem; }

    .week-day-name,
.week-day-date { display: inline; }

    .week-day-date { margin-left: .35rem; }

    .week-table select { min-width: 0; width: 100%; }

}

/* ══ Controles en pantallas de dedo ═══════════════════════════
   Va al final a propósito: sube el piso de los controles que el resto del
   archivo dejó por debajo del área tocable, sin reescribir cada componente.
   Solo altura y relleno — ni un color ni una tipografía cambian acá. */

@media (max-width: 768px) {
    /* Botones compactos y pestañas: nacen chicos para caber en filas densas,
       pero en teléfono la fila ya se apiló y el alto sobra. */

    .ep-tab,
.page-btn,
.load-more-btn,
.nd-readall {
        min-height: 44px;
        display: inline-flex; align-items: center; justify-content: center;
    }

    .nd-readall { justify-content: flex-start; }

    /* Selectores nativos dentro de una cápsula: el <select> solo recibe el
       toque en su propia caja, no en el relleno del envoltorio, así que el
       control crece y la cápsula deja de acolchar. */

    /* La barra del vet no cabe en 320px con el selector de estado escrito.
       El punto de color pasa a ser el control: 44px tocables, el <select>
       nativo encima transparente y las palabras en su lista desplegable. */

    .vet-status-selector {
        position: relative; width: 44px; height: 44px; padding: 0;
        border: none; background: none; justify-content: center; flex: none;
    }

    .vet-status-selector .status-dot--inline { width: 15px; height: 15px; font-size: 9px; }

    .vet-status-selector select {
        position: absolute; inset: 0; width: 100%; height: 100%;
        opacity: 0; cursor: pointer;
    }

    /* El gap de escritorio (1.5rem) se come 24px de una barra de 320. */

    .topbar-inner { gap: .6rem; }

    /* Acordeones: el resumen es el único control de la sección. */

    .faq summary { min-height: 44px; }

    .faq summary { align-items: center; }

    /* Casillas y radios: 13px de fábrica. El rótulo ya es tocable, la casilla
       en sí no lo era. 24px es el mínimo de área de destino de WCAG.
       El interruptor de configuración no se toca acá: `.switch-row input`
       tiene más especificidad y conserva su forma de 44×24. */

    input[type="checkbox"],
input[type="radio"] {
        width: 24px; height: 24px; accent-color: var(--green-ink); flex: none;
    }

    /* Enlaces de vuelta y pie: son navegación, no texto corrido. */

    .site-footer a { padding: .55rem 0; }

    /* Texto por debajo de 11px: en el contador de avisos y en el aviso de
       ayuno el dato ya no se leía. */

    .notif-badge { font-size: .72rem; min-width: 20px; height: 20px; }

}

/* Cuando el puntero es grueso hay que separar además de agrandar: dos
   píldoras pegadas se fallan aunque cada una mida 44px. */

@media (pointer: coarse) {
    .pagination-nav { gap: .5rem; }

}

/* Operación de urgencias: estado primero, formularios de apoyo después. */

.emergency-workspace { padding-top: 2rem; padding-bottom: 2rem; }

.emergency-workspace [hidden] { display: none !important; }

.emergency-workspace,
.emergency-form { min-width: 0; }

.emergency-workspace input,
.emergency-workspace select,
.emergency-workspace textarea { max-width: 100%; }

.emergency-form .grid-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }

.emergency-form .grid-2 > * { min-width: 0; }

.emergency-form .form-field { min-width: 0; }

.emergency-form h2 { margin-top: 0; }

.presence-countdown { align-items: center; background: var(--navy); border-radius: var(--r-md); color: #fff; display: flex; flex-direction: column; justify-content: center; min-width: 142px; padding: .9rem; }

.presence-countdown span { font-family: var(--font-display); font-size: 2rem; font-variant-numeric: tabular-nums; }

.presence-countdown small { color: #d5daf2; }

@media (max-width: 700px) {
    .emergency-form .grid-2 { grid-template-columns: 1fr; }

    .presence-countdown { align-self: stretch; }

}
