/* Sistema tipográfico oficial "Clara y cálida". Las fuentes viven dentro de la aplicación:
   recepción no pierde legibilidad si se corta Internet y ninguna pantalla depende de un CDN.

   En WOFF2 y no en TTF, que es como estaban hasta el 03-08. El mismo archivo pesa entre un 60 %
   y un 74 % menos —2,1 MB de tipografías quedaron en 744 KB— porque WOFF2 trae la compresión
   Brotli adentro, y los ejes variables sobreviven intactos. El formato es de 2018 y no hay
   navegador en uso que no lo entienda, así que no queda un TTF de respaldo: sería peso muerto
   en el repositorio y una segunda copia que mantener sincronizada.

   Por venir ya comprimidos, estos archivos quedan fuera de `server.compression`: volver a
   comprimirlos gasta CPU del servidor para no ahorrar un byte. */
@font-face {
    font-family: "Nunito Sans";
    src: url("/fonts/nunito-sans-variable-abc455272596a9f52975ebdc73338d1c.woff2") format("woff2");
    font-style: normal;
    font-weight: 200 1000;
    font-stretch: 75% 125%;
    font-display: swap;
}

@font-face {
    font-family: "Nunito Sans";
    src: url("/fonts/nunito-sans-italic-variable-034231bc8baa7bdae0bf1aa829d88693.woff2") format("woff2");
    font-style: italic;
    font-weight: 200 1000;
    font-stretch: 75% 125%;
    font-display: swap;
}

@font-face {
    font-family: "Source Sans 3";
    src: url("/fonts/source-sans-3-variable-61db60cc19bc3d38ccc670fda4139fa4.woff2") format("woff2");
    font-style: normal;
    font-weight: 200 900;
    font-display: swap;
}

@font-face {
    font-family: "Source Sans 3";
    src: url("/fonts/source-sans-3-italic-variable-4419d63052fc56006f68d8aa299aa52d.woff2") format("woff2");
    font-style: italic;
    font-weight: 200 900;
    font-display: swap;
}

:root {
    /* Paleta oficial "Menta amable". Ver docs/identidad-visual.md. */
    color-scheme: light;
    --turquesa: #2aae91;
    --turquesa-profundo: #16745f;
    --sobre-turquesa: #102f2b;
    --rojo: #d95663;
    --rojo-profundo: #9d2f3e;
    --texto: #244643;
    --texto-tenue: #58716d;
    --fondo: #f7fbf5;
    --superficie: #ffffff;
    --barra: #ffffff;
    --campo: #ffffff;
    --menta-suave: #e1f2e8;
    --rojo-suave: #fceced;
    --borde: #caddd8;
    --blanco: #ffffff;

    --fuente-marca: "Nunito Sans", system-ui, sans-serif;
    --fuente-interfaz: "Source Sans 3", system-ui, sans-serif;

    /* Tintas del símbolo. Van aparte de los tokens de interfaz a propósito: el logo no
       sigue al color de un botón, sigue a la marca. Ver "Uso en la aplicación" en
       docs/identidad-visual.md. */
    --marca-turquesa: #2aae91;
    --marca-tinta: #244643;
    --marca-rojo: #d95663;

    --sombra: 0 1px 2px rgba(36, 70, 67, 0.06);
}

/* "Grafito clínico": modo oscuro oficial. Puede forzarse con data-tema="oscuro". */
:root[data-tema="oscuro"] {
    color-scheme: dark;
    --turquesa: #55cbb2;
    --turquesa-profundo: #70dbc3;
    --sobre-turquesa: #102e29;
    --rojo: #f2737d;
    --rojo-profundo: #ff9ba4;
    --texto: #f1f6f4;
    --texto-tenue: #b4c3bf;
    --fondo: #171c1c;
    --superficie: #222b2a;
    --barra: #1b2322;
    --campo: #1b2423;
    --menta-suave: #293b37;
    --rojo-suave: #3a2529;
    --borde: #3a4947;

    --marca-turquesa: #55cbb2;
    --marca-tinta: #f1f6f4;
    --marca-rojo: #f2737d;

    --sombra: none;
}

@media (prefers-color-scheme: dark) {
    :root:not([data-tema="claro"]) {
        color-scheme: dark;
        --turquesa: #55cbb2;
        --turquesa-profundo: #70dbc3;
        --sobre-turquesa: #102e29;
        --rojo: #f2737d;
        --rojo-profundo: #ff9ba4;
        --texto: #f1f6f4;
        --texto-tenue: #b4c3bf;
        --fondo: #171c1c;
        --superficie: #222b2a;
        --barra: #1b2322;
        --campo: #1b2423;
        --menta-suave: #293b37;
        --rojo-suave: #3a2529;
        --borde: #3a4947;

        --marca-turquesa: #55cbb2;
        --marca-tinta: #f1f6f4;
        --marca-rojo: #f2737d;

        --sombra: none;
    }
}

* { box-sizing: border-box; }

body {
    margin: 0;
    font-family: var(--fuente-interfaz);
    font-optical-sizing: auto;
    color: var(--texto);
    background: var(--fondo);
    line-height: 1.5;
}

main {
    max-width: 48rem;
    margin: 0 auto;
    padding: 2rem 1.25rem;
}

h1,
h2,
h3 {
    font-family: var(--fuente-marca);
}

h1 {
    color: var(--turquesa-profundo);
    margin-bottom: 0.25rem;
}

section {
    margin-top: 2rem;
    padding: 1.25rem;
    background: var(--superficie);
    border-radius: 0.5rem;
    border: 1px solid var(--borde);
    box-shadow: var(--sombra);
}

/* El margen propio del h2 se suma al padding de la sección y deja más aire arriba que a los
   lados. Se nota sobre todo cuando hay varias secciones seguidas, que es casi siempre. */
section > :first-child {
    margin-top: 0;
}

section > :last-child {
    margin-bottom: 0;
}

main.angosto {
    max-width: 24rem;
}

/* Los enlaces del contenido: sin esto quedan en el azul del navegador, que no es de la
   paleta y sobre Grafito clínico casi no se lee. */
a {
    color: var(--turquesa-profundo);
}

/* Un foco visible es lo que permite operar la pantalla con el teclado, y recepción cobra
   con las dos manos ocupadas. El anillo se dibuja separado del borde del campo para que
   se note también sobre los inputs. */
:focus-visible {
    outline: 2px solid var(--turquesa);
    outline-offset: 2px;
    border-radius: 0.2rem;
}

/* Nace fuera de la pantalla y baja al recibir el foco: quien navega con teclado lo
   encuentra en el primer tabulador, y quien usa el mouse no lo ve nunca. */
.saltar {
    position: absolute;
    top: -3rem;
    left: 0.75rem;
    z-index: 20;
    padding: 0.5rem 0.9rem;
    border-radius: 0 0 0.3rem 0.3rem;
    background: var(--turquesa);
    color: var(--sobre-turquesa);
    text-decoration: none;
    transition: top 0.12s ease;
}

.saltar:focus {
    top: 0;
}

/* El <main> recibe el foco al saltar, pero es un contenedor: dibujarle el anillo alrededor
   de toda la pantalla no señala nada. */
main:focus-visible {
    outline: none;
}

.barra {
    position: sticky;
    top: 0;
    z-index: 10;
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 1rem;
    padding: 0.6rem 1.25rem;
    background: var(--barra);
    border-bottom: 1px solid var(--borde);
    font-size: 0.9rem;
}

/* El símbolo y el nombre son un solo enlace al inicio. Nunito Sans compone el nombre como
   logotipo tipográfico mientras se definen las composiciones horizontal y vertical. */
.marca {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    font-family: var(--fuente-marca);
    font-weight: 700;
    letter-spacing: 0.01em;
}

.marca svg {
    width: 1.75rem;
    height: 1.75rem;
    flex: none;
}

.barra .grupo {
    display: flex;
    align-items: center;
    gap: 1rem;
}

/* En una pantalla angosta el nombre largo se parte en tres líneas y estira la barra sobre
   el contenido. Lo que se va es el rol: se deduce de lo que la pantalla deja hacer, mientras
   que el nombre es lo único que distingue una sesión de otra en un computador compartido. */
@media (max-width: 40rem) {
    .barra {
        flex-wrap: wrap;
        row-gap: 0.4rem;
    }

    .barra .sesion {
        white-space: nowrap;
    }

    .barra .rol {
        display: none;
    }
}

label {
    display: block;
    margin-top: 0.9rem;
    font-size: 0.9rem;
}

input[type="email"],
input[type="password"] {
    width: 100%;
    padding: 0.5rem;
    margin-top: 0.25rem;
    border: 1px solid var(--borde);
    color: var(--texto);
    background: var(--campo);
    border-radius: 0.3rem;
    font: inherit;
}

button {
    margin-top: 1.25rem;
    padding: 0.55rem 1.1rem;
    border: 0;
    border-radius: 0.3rem;
    background: var(--turquesa);
    color: var(--sobre-turquesa);
    font: inherit;
    cursor: pointer;
    transition: filter 0.12s ease, background-color 0.12s ease;
}

button:hover {
    filter: brightness(1.06);
}

button:active {
    filter: brightness(0.94);
}

/* Un botón apagado que se ve igual que uno vivo se clickea igual, y el usuario concluye que
   la pantalla no responde. Los hay: los formularios dentro de un fieldset deshabilitado. */
button:disabled,
button:disabled:hover {
    filter: none;
    opacity: 0.5;
    cursor: not-allowed;
}

button.enlace {
    margin: 0;
    padding: 0;
    background: none;
    color: var(--turquesa-profundo);
    text-decoration: underline;
}

/* brightness() sobre una superficie casi blanca o sobre nada no cambia nada: el botón
   secundario y el de texto necesitan su propio hover o quedan sin respuesta al pasar. */
button.secundario:hover {
    filter: none;
    background: var(--menta-suave);
}

button.enlace:hover {
    filter: none;
    color: var(--texto);
}

/* Anular es irreversible. Va en rojo desde antes de tocarlo, no después en un mensaje. */
button.enlace.riesgo {
    color: var(--rojo-profundo);
}

/* "Salir" es un botón porque cerrar sesión es un POST, pero en la barra es un enlace más:
   sin esto queda turquesa y subrayado entre cuatro enlaces que no lo están. */
.barra button.enlace {
    color: var(--texto);
    text-decoration: none;
}

.barra button.enlace:hover {
    color: var(--turquesa-profundo);
    text-decoration: underline;
}

/* ---------------------------------------------------------------------------
   Mensajes del sistema
   --------------------------------------------------------------------------- */

/* "Guardado." como línea suelta de texto se pierde: después de un POST la pantalla se
   vuelve a dibujar entera y el ojo va al formulario, no a un párrafo del mismo tamaño y
   peso que todo lo demás. El mensaje va en un cuadro con icono para que se lea primero.

   El icono se dibuja con una máscara y no con un <img> ni un <svg> en la plantilla: así
   toma el color del mensaje —turquesa o rojo, claro u oscuro— sin repetir el mismo bloque
   de marcado en las veintitantas pantallas que muestran uno.

   El relleno izquierdo lo hace `padding` y no `flex`, a propósito: varios mensajes traen
   un <strong> adentro, y en un contenedor flex ese <strong> se convertiría en columna
   aparte en vez de seguir el párrafo. */
.aviso,
.error {
    position: relative;
    margin: 1rem 0;
    padding: 0.7rem 0.9rem 0.7rem 2.5rem;
    border: 1px solid;
    border-radius: 0.5rem;
    animation: mensaje-aparece 0.2s ease-out;
}

.aviso::before,
.error::before {
    content: "";
    position: absolute;
    top: 0.78rem;
    left: 0.85rem;
    width: 1.15rem;
    height: 1.15rem;
    background-color: currentColor;
    -webkit-mask: var(--icono) center / contain no-repeat;
    mask: var(--icono) center / contain no-repeat;
}

.aviso {
    color: var(--turquesa-profundo);
    background: var(--menta-suave);
    border-color: var(--turquesa);
    --icono: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.9' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='9.2'/%3E%3Cpath d='m7.7 12.3 3 3 5.6-6.3'/%3E%3C/svg%3E");
}

.error {
    color: var(--rojo-profundo);
    background: var(--rojo-suave);
    border-color: var(--rojo);
    --icono: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.9' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='9.2'/%3E%3Cpath d='M12 7.3v5.3'/%3E%3Ccircle cx='12' cy='16.4' r='1.05' fill='black' stroke='none'/%3E%3C/svg%3E");
}

/* Mismo tono que el aviso, otro icono. La paleta oficial tiene dos colores de señal —menta
   y rojo— y un tercero inventado para "ojo con esto" diría menos de lo que ensuciaría; el
   visto y la i separan "quedó hecho" de "hay algo que saber" sin agregar color. */
.aviso.info {
    --icono: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.9' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='9.2'/%3E%3Cpath d='M12 11.3v5.3'/%3E%3Ccircle cx='12' cy='7.6' r='1.05' fill='black' stroke='none'/%3E%3C/svg%3E");
}

/* El mensaje llega con la página ya cargada, no aparece mientras se mira: sin el
   desplazamiento corto no hay nada que delate que algo cambió en la pantalla. */
@keyframes mensaje-aparece {
    from {
        opacity: 0;
        transform: translateY(-0.3rem);
    }
}

.tenue {
    color: var(--texto-tenue);
}

/* Microchips, RUT, folios y códigos: se leen dígito a dígito y se comparan con lo que trae
   el tutor en un papel. Antes iban en la monoespaciada del sistema, que es una cuarta
   familia fuera del sistema tipográfico oficial; Source Sans 3 con cifras tabulares alinea
   igual las columnas y el espaciado extra basta para no perder el dígito. */
.mono {
    font-variant-numeric: tabular-nums;
    letter-spacing: 0.04em;
}

.barra nav {
    display: inline-flex;
    align-items: center;
    gap: 1rem;
}

.barra a {
    color: var(--texto);
    text-decoration: none;
}

.barra a:hover {
    color: var(--turquesa-profundo);
}

form.en-linea,
.barra form {
    display: inline;
}

input[type="text"],
input[type="search"],
input[type="tel"],
input[type="date"],
input[type="number"],
select,
textarea {
    width: 100%;
    padding: 0.5rem;
    margin-top: 0.25rem;
    border: 1px solid var(--borde);
    color: var(--texto);
    background: var(--campo);
    border-radius: 0.3rem;
    font: inherit;
}

textarea {
    resize: vertical;
}

/* El campo tiene que decir dónde está el cursor y cuál está bajo el puntero. Sin esto, un
   formulario largo —la ficha nueva son catorce campos— es una grilla de rectángulos
   iguales, y el anillo de foco es la única pista. */
input:hover:not(:disabled),
select:hover:not(:disabled),
textarea:hover:not(:disabled) {
    border-color: var(--texto-tenue);
}

input:focus,
select:focus,
textarea:focus {
    border-color: var(--turquesa);
}

/* El gris por defecto del navegador no está en la paleta y en varios se lee casi tanto como
   el valor escrito, que es justo lo que un ejemplo no debe hacer. */
::placeholder {
    color: var(--texto-tenue);
    opacity: 1;
}

fieldset {
    border: 0;
    padding: 0;
    margin: 0;
    min-width: 0;
}

fieldset:disabled {
    opacity: 0.75;
}

.campos {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
    gap: 0 1rem;
}

.campos .ancho {
    grid-column: 1 / -1;
}

.acciones {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 1rem;
    margin-top: 1.5rem;
}

/* Los botones traen su propio margen superior para cuando cierran un formulario. Dentro de
   una fila de acciones ese margen los baja respecto de los enlaces que tienen al lado, y la
   fila queda escalonada. */
.acciones > button,
.acciones > a.boton {
    margin-top: 0;
}

.titulo-con-accion {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 1rem;
}

/* Una fila de acciones que acompaña a un título no arrastra el margen que lleva cuando cierra
   un formulario: acá va a la altura del h2 y no debajo. */
.titulo-con-accion .acciones,
.titulo-con-accion .acciones button {
    margin-top: 0;
}

button.secundario {
    background: var(--superficie);
    color: var(--turquesa-profundo);
    border: 1px solid var(--turquesa);
}

a.boton {
    display: inline-block;
    margin-top: 0.75rem;
    padding: 0.55rem 1.1rem;
    border-radius: 0.3rem;
    background: var(--turquesa);
    color: var(--sobre-turquesa);
    text-decoration: none;
    transition: filter 0.12s ease;
}

/* Se ve como un botón: tiene que responder como un botón. */
a.boton:hover {
    filter: brightness(1.06);
}

a.boton:active {
    filter: brightness(0.94);
}

table {
    width: 100%;
    border-collapse: collapse;
    margin-top: 0.75rem;
}

th, td {
    text-align: left;
    padding: 0.5rem 0.6rem;
    border-bottom: 1px solid var(--borde);
    vertical-align: top;
}

th {
    font-size: 0.8rem;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: var(--texto-tenue);
}

/* ---------------------------------------------------------------------------
   La cola de cobro

   Seis columnas y la última es un control, así que el ancho está justo. Repartirlo a mano por
   porcentaje deja "Emitido" en dos líneas incluso cuando cabía de sobra: la fila se ve alta y
   desordenada todo el tiempo para cubrir el caso raro. Acá reparte la tabla y solo se sujeta
   lo que de verdad se desborda.
   --------------------------------------------------------------------------- */

/* Con seis columnas el relleno lateral se lleva por sí solo casi una palabra de cada nombre.
   Algo más apretada que el resto de las tablas es lo que deja la fila entera en una línea. */
.tabla-cola-cobros th,
.tabla-cola-cobros td {
    padding-left: 0.45rem;
    padding-right: 0.45rem;
}

/* Paciente, tutor y responsable los escribe la clínica y no tienen largo controlado. En el
   escritorio la tabla no tiene a dónde desbordarse, así que un nombre de una sola palabra
   larguísima se parte antes que empujar el saldo fuera de la sección.

   Solo en el escritorio: bajo 40rem la tabla ya se desplaza dentro de su sección, y ahí
   `anywhere` deja de proteger nada y pasa a hacer daño —le dice al navegador que la columna
   puede medir una letra, y "María González" baja partida en "María Gonz / ález". */
@media (min-width: 40rem) {
    .tabla-cola-cobros td:nth-child(2),
    .tabla-cola-cobros td:nth-child(3),
    .tabla-cola-cobros td:nth-child(4) {
        overflow-wrap: anywhere;
    }
}

/* Un saldo de la cola no pasa de seis cifras. Fijarle el ancho es lo que impide que la línea
   del abono, que es larga, se lleve un tercio de la tabla y deje a los nombres sin dónde caber. */
.tabla-cola-cobros .columna-saldo {
    width: 6.5rem;
}

/* El abono explica el saldo, no es otra cifra que se compare hacia abajo: si no cabe se apila
   en dos líneas cortas en vez de ensanchar la columna. Cada mitad se mantiene entera, porque
   partir "$200.000" entre el signo y el número es justo lo que `.numero` evita. */
.tabla-cola-cobros .abono-en-cola {
    white-space: normal;
}

.tabla-cola-cobros .abono-en-cola span {
    white-space: nowrap;
}

/* `width: 1%` con `nowrap` es cómo se le pide a una tabla automática que una columna se quede
   con lo justo de su contenido: el ancho que sobra va a las tres de texto, que es donde varía.
   El alto lo pone el botón, así que la celda aporta menos relleno propio para que la fila no
   crezca respecto de las demás pantallas. */
.tabla-cola-cobros .columna-accion {
    width: 1%;
    padding: 0.25rem 0.35rem;
    white-space: nowrap;
    vertical-align: middle;
}

dl {
    display: grid;
    grid-template-columns: max-content 1fr;
    gap: 0.35rem 1rem;
    margin: 0;
}

dt {
    color: var(--texto-tenue);
    font-size: 0.9rem;
}

dd {
    margin: 0;
}

.folio {
    font-size: 0.9rem;
    font-weight: normal;
    color: var(--texto-tenue);
}

/* Los datos que identifican el presupuesto son una sola fila de lectura. Cada pieza comparte
   el mismo eje vertical y, si falta ancho, salta completa en vez de cortar un nombre o una fecha. */
ul.metadatos-presupuesto {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.25rem 0.45rem;
    margin: 0.75rem 0 0;
    padding: 0;
    list-style: none;
}

/* El `gap` no es aire de más: un contenedor flex descarta el espacio en blanco entre sus
   hijos, así que "ficha <span>10</span>" se leía "ficha10". Es el único dato de la fila que
   lleva palabra y valor en piezas separadas, y era el único que salía pegado. */
.metadatos-presupuesto > li {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    min-height: 1.5rem;
    white-space: nowrap;
}

/* Descontado el `gap` que ahora separa a los hijos, para que la separación tras el punto
   quede donde estaba. */
.metadatos-presupuesto > li + li::before {
    content: "·";
    margin-right: 0.2rem;
    color: var(--texto-tenue);
}

/* La etiqueta es una sola pieza en todo el sistema —el estado de un presupuesto, la línea
   exenta, el paciente extraviado, el tutor principal— y por eso el alto lo pone ella y no su
   contenido: dos etiquetas seguidas miden igual aunque una diga "exenta" y la otra "nota de
   crédito pendiente". Lo que se ganó al subir esto desde la del presupuesto, que era la única
   que lo tenía, es que dejaran de sentarse medio renglón más abajo que el texto que acompañan. */
.etiqueta {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: 1.5rem;
    padding: 0.15rem 0.55rem;
    border-radius: 0.8rem;
    background: var(--menta-suave);
    color: var(--turquesa-profundo);
    font-size: 0.75rem;
    line-height: 1;
    vertical-align: middle;
}

/* Casilla y su texto en la misma línea, sin el display:block de los demás label. */
label.opcion {
    display: flex;
    align-items: center;
    gap: 0.4rem;
}

label.opcion input {
    width: auto;
    margin: 0;
}

/* El dinero se lee comparando columnas, y para eso tiene que estar alineado a la derecha
   y con cifras de ancho fijo: si no, $9.000 y $130.000 no se pueden comparar de un vistazo.

   `nowrap` es por los negativos: en una columna angosta el navegador parte "−$25.000" entre
   el signo y el peso, y el menos queda huérfano al final de una línea. Justo lo que enPesos
   existe para evitar. */
.numero {
    text-align: right;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/* La acción que se repite en cada fila: abrir el presupuesto, editar al tutor, agregar el
   servicio del catálogo. Es un botón y no un enlace suelto porque en una columna de "abrir"
   idénticos la palabra sola no dice dónde termina un objetivo y empieza el siguiente, y en el
   mesón se apunta con el dedo sobre una pantalla táctil: 2.25rem es lo que hace que se acierte
   sin mirar.

   Ancho completo de su celda para que todas midan igual. Contorno y no relleno turquesa: hay
   una por fila, y una columna de botones sólidos pesa más que los datos que acompaña.

   Vale para `button` y para `a` —abrir es un GET y agregar del catálogo un POST— y por eso la
   caja se declara entera acá en vez de heredarla: un `a` no toma nada de la regla de `button`.
   El centrado va con flex porque `min-height` sobre un `a` estira la caja y deja el texto
   pegado arriba, mientras el `button` lo centraba solo; sin esto los dos no coincidían. */
button.boton-tabla,
a.boton-tabla {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    min-height: 2.25rem;
    margin: 0;
    padding: 0.35rem 0.7rem;
    border: 1px solid var(--turquesa);
    border-radius: 0.3rem;
    background: var(--superficie);
    color: var(--turquesa-profundo);
    font: inherit;
    font-weight: 400;
    text-align: center;
    text-decoration: none;
    cursor: pointer;
}

button.boton-tabla:hover,
a.boton-tabla:hover {
    filter: none;
    background: var(--menta-suave);
}

button.boton-tabla:active,
a.boton-tabla:active {
    filter: none;
    background: var(--borde);
}

/* Las dos columnas que no son datos sino señales: el estado y la acción. Se encogen a su
   contenido —`width: 1%` en una tabla al 100% deja que el sobrante lo repartan las columnas de
   datos— y no parten su contenido en dos líneas.

   El `nowrap` no es cosmético en ninguna de las dos: sin él el botón se estiraba hasta donde
   llegara la celda y cada tabla tenía un "abrir" de otro ancho, y la etiqueta "en curso" se
   rompía por el espacio y quedaba de dos renglones dentro de una píldora pensada para uno. */
.columna-accion,
.columna-estado {
    width: 1%;
    white-space: nowrap;
}

/* ---------------------------------------------------------------------------
   El catálogo del presupuesto

   Servicio, precio y acción forman una retícula estable. La confirmación ocupa el mismo lugar
   que el botón: el resultado del clic se ve donde se actuó, pero no ensancha la columna ni mueve
   el siguiente objetivo bajo el puntero.
   --------------------------------------------------------------------------- */
.catalogo-servicios {
    table-layout: fixed;
}

.catalogo-servicios th,
.catalogo-servicios td {
    padding-top: 0.35rem;
    padding-bottom: 0.35rem;
    vertical-align: middle;
}

.catalogo-servicios .servicio-catalogo {
    width: auto;
    color: var(--texto);
    font-size: 1rem;
    font-weight: 400;
    letter-spacing: normal;
    text-transform: none;
}

.catalogo-servicios .precio-catalogo {
    width: 7rem;
    color: var(--texto);
    font-weight: 400;
}

.catalogo-servicios .agregar-catalogo {
    width: 7.75rem;
    text-align: right;
}

.catalogo-servicios tbody tr:last-child > * {
    border-bottom: 0;
}

.catalogo-servicios tbody tr:hover > * {
    background: var(--menta-suave);
}

.control-catalogo {
    position: relative;
    display: inline-block;
    width: 6.5rem;
}

.control-catalogo form {
    display: block;
}

.confirmacion {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.3rem;
    border: 1px solid var(--turquesa);
    border-radius: 0.3rem;
    background: var(--menta-suave);
    color: var(--turquesa-profundo);
    font-size: 0.85rem;
    font-weight: 600;
    opacity: 0;
    pointer-events: none;
}

.confirmacion::before {
    content: "✓";
    font-weight: 700;
}

.confirmacion.visible {
    animation: confirmar 1.6s ease-out;
}

@keyframes confirmar {
    0%   { opacity: 0; }
    15%  { opacity: 1; }
    70%  { opacity: 1; }
    100% { opacity: 0; }
}

/* Quien pidió no ver animaciones igual necesita la señal: se queda quieta y se va sin
   transición. */
@media (prefers-reduced-motion: reduce) {
    .confirmacion.visible {
        animation: confirmar 1.6s step-end;
    }
}

h2.categoria {
    margin: 1.75rem 0 0;
    font-size: 0.8rem;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: var(--texto-tenue);
}

h2.categoria + table {
    margin-top: 0.25rem;
}

@media (max-width: 32rem) {
    .catalogo-servicios,
    .catalogo-servicios tbody {
        display: block;
        overflow: visible;
    }

    .catalogo-servicios tr {
        display: grid;
        grid-template-columns: minmax(0, 1fr) auto;
        grid-template-areas:
            "servicio precio"
            "servicio accion";
        gap: 0.35rem 1rem;
        padding: 0.7rem 0.4rem;
        border-bottom: 1px solid var(--borde);
    }

    .catalogo-servicios th,
    .catalogo-servicios td {
        width: auto;
        padding: 0;
        border-bottom: 0;
    }

    .catalogo-servicios .servicio-catalogo {
        grid-area: servicio;
        align-self: center;
    }

    .catalogo-servicios .precio-catalogo {
        grid-area: precio;
    }

    .catalogo-servicios .agregar-catalogo {
        grid-area: accion;
    }

    .catalogo-servicios tbody tr:last-child {
        border-bottom: 0;
    }
}

tr.inactiva td {
    color: var(--texto-tenue);
}

/* La cantidad de una línea se edita dentro de la tabla del presupuesto, así que el input no
   puede llevar el ancho completo ni el margen que tiene en un formulario. */
.cantidad input {
    width: 4.5rem;
    margin: 0;
    text-align: right;
    font-variant-numeric: tabular-nums;
}

/* El detalle repite la misma lógica visual del catálogo: la descripción absorbe el ancho
   disponible y las cifras y la acción conservan una columna estable para poder compararlas. */
.detalle-presupuesto {
    table-layout: fixed;
}

.detalle-presupuesto th,
.detalle-presupuesto td {
    vertical-align: middle;
}

.detalle-presupuesto .cantidad-detalle {
    width: 6rem;
}

/* Quién ejecutó la línea. El select va al ancho de la columna —con `table-layout: fixed` un
   nombre largo la desbordaría— y sin el margen que tiene en un formulario, igual que el input
   de cantidad. */
.detalle-presupuesto .ejecutor-detalle {
    width: 11rem;
}

.detalle-presupuesto .ejecutor-detalle select {
    width: 100%;
    margin: 0;
}

.detalle-presupuesto .precio-detalle,
.detalle-presupuesto .monto-detalle {
    width: 7rem;
}

.detalle-presupuesto .accion-detalle {
    width: 7.75rem;
    text-align: right;
}

.detalle-presupuesto .accion-detalle form {
    display: inline-block;
    width: 6.5rem;
}

/* El total cierra la tabla: sin la línea de abajo, que ya no separa nada, y sin el gris de
   encabezado que lo dejaría más apagado que las líneas que suma. */
tfoot th,
tfoot td {
    border-bottom: 0;
    color: var(--texto);
    font-size: 1rem;
    font-weight: 600;
    text-transform: none;
    letter-spacing: normal;
}

/* ---------------------------------------------------------------------------
   El buscador de fichas

   Mismo criterio que el catálogo del presupuesto, y por el mismo motivo: el listado se vuelve a
   dibujar con cada tecla, así que con anchos automáticos las columnas se recalculan a mitad de
   la búsqueda y lo que se estaba leyendo se corre de sitio. Folio, especie y microchip miden lo
   que miden sus datos —el microchip son quince dígitos y no crece—, y paciente y tutor se
   reparten lo que sobra.

   Van dentro de una consulta de ancho porque solo aplican donde hay ancho que repartir: bajo
   40rem la tabla ya se desplaza sola dentro de su sección, y ahí imponerle veinte rem de mínimo
   entre tres columnas es garantizarle el desplazamiento lateral en vez de dejarla apretarse.
   --------------------------------------------------------------------------- */
@media (min-width: 40rem) {
    .tabla-fichas {
        table-layout: fixed;
    }

    .tabla-fichas .folio-ficha {
        width: 4rem;
    }

    .tabla-fichas .especie-ficha {
        width: 5rem;
    }

    .tabla-fichas .microchip-ficha {
        width: 9.5rem;
    }
}

/* La que manda el alto de la fila es la del tutor, que lleva dos líneas. Las demás se centran
   contra ella en vez de colgar del borde de arriba: así ficha, paciente, marca, especie y
   microchip se leen sobre un mismo eje y no escalonados. */
.tabla-fichas td {
    vertical-align: middle;
}

/* Nombre y marca, en ese orden y sin posibilidad de que la marca baje: es una fila flex que no
   envuelve, así que un nombre que no quepa se parte él y la marca se queda a su derecha. Corrido
   como texto suelto, era el largo del nombre el que decidía dónde caía la marca. */
.con-marca {
    display: flex;
    align-items: center;
    gap: 0.4rem;
}

.con-marca > .etiqueta {
    flex: none;
}

/* El tutor sí va en dos líneas: el RUT se compara dígito a dígito contra el papel que trae el
   tutor, y detrás del nombre el navegador lo partía por la mitad. Debajo empieza siempre en el
   mismo punto y se puede recorrer la columna con la vista. */
.apilado {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 0.25rem;
}

/* ---------------------------------------------------------------------------
   Cambio de tema
   --------------------------------------------------------------------------- */

/* Nace oculto y lo muestra tema.js: sin JavaScript el botón no haría nada, y un control
   muerto en la barra es peor que no tenerlo. */
.tema[hidden] {
    display: none;
}

.tema {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    margin: 0;
    padding: 0.35rem;
    border-radius: 0.3rem;
    background: none;
    color: var(--texto-tenue);
    cursor: pointer;
}

.tema:hover {
    filter: none;
    background: var(--menta-suave);
    color: var(--turquesa-profundo);
}

.tema svg {
    width: 1.15rem;
    height: 1.15rem;
    display: none;
}

/* Solo se dibuja el icono del estado actual: automático, claro u oscuro. */
.tema[data-estado="sistema"] .icono-sistema,
.tema[data-estado="claro"] .icono-claro,
.tema[data-estado="oscuro"] .icono-oscuro {
    display: block;
}

/* Para lectores de pantalla: el estado del tema se anuncia, pero en la barra lo dice el
   icono. */
.visualmente-oculto {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

/* El caption de una tabla es la única excepción: se oculta igual, pero sin salirse del flujo.
   Con `table-layout: fixed` y sin `<colgroup>`, los anchos de columna salen de las celdas de la
   primera fila, y un caption absoluto se los hace perder: el navegador reparte la tabla en
   partes iguales y los `width` declarados no se aplican nunca. Eso dejaba el catálogo del
   presupuesto con tres columnas de 229px —"Esterilización canina hasta 15 kg" partido en dos
   líneas con 220px libres al lado— en vez de las de 450, 112 y 124 que pide el bloque del
   catálogo. Las tablas que sí declaran `<colgroup>` —usuarios y servicios— nunca dependieron de
   la primera fila y miden igual con o sin esto. Recortado a 1px ocupa lo mismo quieto que
   absoluto, y el lector de pantalla lo sigue anunciando. */
caption.visualmente-oculto {
    position: static;
}

/* La sección de la barra donde está parado el usuario. */
.barra a.actual {
    color: var(--turquesa-profundo);
    font-weight: 600;
}

tbody tr:hover td {
    background: var(--menta-suave);
}

/* La última línea de la tabla no separa nada de lo que viene abajo: es el borde de la
   sección el que cierra. */
table:not(:has(tfoot)) tbody tr:last-child td {
    border-bottom: 0;
}

/* En pantalla angosta las cuatro columnas de una tabla de montos no caben, y la página
   entera termina desplazándose de lado. Primero se recupera ancho apretando los rellenos;
   la tabla que aun así no quepa se desplaza sola dentro de su sección, que es lo que evita
   que el encabezado y el resto del contenido se vayan con ella. */
@media (max-width: 40rem) {
    main {
        padding: 1.5rem 0.9rem;
    }

    section {
        padding: 1rem;
    }

    th,
    td {
        padding: 0.5rem 0.4rem;
    }

    section table,
    form table {
        /* `relative` no coloca nada: encierra. Los títulos que solo oye un lector de pantalla
           —el `caption` de una tabla agrupada, el "Acción" de la columna del botón— van en
           `position: absolute`, y sin un ancestro posicionado se sitúan respecto de la página.
           Quedan a la derecha de la tabla desplazada, fuera del ancho del teléfono, y arrastran
           de lado justo lo que este bloque existe para no mover. */
        position: relative;
        display: block;
        overflow-x: auto;
    }
}

/* La portada del login: el símbolo hace de encabezado y el nombre va debajo. */
.portada {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.35rem;
    margin-bottom: 1.5rem;
    text-align: center;
}

.portada svg {
    width: 4rem;
    height: 4rem;
}

.portada h1 {
    margin: 0;
    font-size: 1.6rem;
    letter-spacing: 0.01em;
}

.portada p {
    margin: 0;
    font-size: 0.9rem;
}

/* En el login no hay barra donde colgar el cambio de tema, y sigue haciendo falta: el
   computador de recepción se configura una vez, desde la pantalla de entrada. */
.tema-esquina {
    position: absolute;
    top: 0.6rem;
    right: 0.75rem;
}

/* El desglose tributario: pocas cifras, alineadas a la derecha y sin competir con el total
   de la tabla, que es el número que se cobra. */
dl.desglose {
    grid-template-columns: max-content 7rem;
    justify-content: end;
    margin-top: 0.75rem;
    font-size: 0.9rem;
}

dl.desglose dd {
    text-align: right;
    font-variant-numeric: tabular-nums;
}

/* En el mesón los cuatro importes se comparan antes de cobrar. Cantidad conserva su ancho y
   precio, monto y desgloses comparten una guía de siete rem, sin inmovilizar toda la tabla. */
.tabla-cobro .cantidad-cobro {
    width: 6rem;
}

.tabla-cobro .precio-cobro,
.tabla-cobro .monto-cobro {
    width: 7rem;
}

/* Un cobro mixto se lee como una lista corta de comprobantes, no como una sola grilla que
   accidentalmente ganó más columnas. El borde conserva juntas las tres piezas de cada pago
   cuando hay varios y sigue usando las mismas superficies en tema claro y oscuro. */
.lista-medios-cobro {
    display: grid;
    gap: 1rem;
}

.medio-cobro {
    padding: 1rem;
    border: 1px solid var(--borde);
    border-radius: 0.55rem;
    background: var(--superficie);
}

.medio-cobro legend {
    padding: 0 0.4rem;
    color: var(--texto);
    font-family: var(--fuente-marca);
    font-weight: 700;
}

.acciones-del-medio {
    justify-content: flex-end;
    margin-top: 0.35rem;
}

.nota-codigo-cobro {
    margin-bottom: 0;
}

/* El comprobante lleva el texto más largo y necesita más aire que el monto. En ancho estrecho
   vuelve a mandar la grilla adaptable de `.campos`, que apila sin comprimir los controles. */
@media (min-width: 40rem) {
    .campos-del-medio {
        grid-template-columns: minmax(8rem, 0.85fr) minmax(10rem, 1fr) minmax(14rem, 1.3fr);
    }
}

/* Agregar un medio y comprobar el saldo son el mismo cierre del reparto del pago. La línea los
   reúne sin convertirlos en otra tarjeta dentro de la sección. */
.pie-medios-cobro {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: end;
    gap: 1rem 2rem;
    margin-top: 0.85rem;
    padding-top: 0.85rem;
    border-top: 1px solid var(--borde);
}

.acciones-medios-cobro {
    margin-top: 0;
}

dl.resumen-del-cobro {
    margin-top: 0;
}

@media (max-width: 40rem) {
    .pie-medios-cobro {
        grid-template-columns: 1fr;
        align-items: start;
    }

    dl.resumen-del-cobro {
        width: 100%;
    }
}

.error-en-linea {
    color: var(--rojo-profundo);
    font-weight: 700;
}

/* El estado del presupuesto se busca de un vistazo desde recepción, y para eso el color
   tiene que decir algo antes que la palabra. */
.etiqueta.estado-emitido {
    background: var(--turquesa);
    color: var(--sobre-turquesa);
}

/* `apagada` es el estado del paciente que cerró su historial. Comparte el gris con el
   presupuesto anulado porque dice lo mismo —esto ya no está en curso— y tiene nombre propio
   porque no es lo mismo: una ficha no se anula. */
.etiqueta.estado-anulado,
.etiqueta.apagada {
    background: var(--borde);
    color: var(--texto-tenue);
}

/* El refuerzo atrasado y el frasco vencido son las dos cosas del carnet que hay que ver sin
   leer. Van en el rojo de la paleta —que es color de señal oficial, no uno inventado para la
   ocasión— y no en menta, porque menta acá diría "todo en orden".

   `alerta` es el mismo rojo para el paciente extraviado, y por el mismo motivo: es la única
   marca de la ficha que pide hacer algo ahora —llamar al tutor del perro que acaban de traer—.
   Van juntas para que nadie tenga que acordarse de cambiar dos rojos. */
.etiqueta.atrasada,
.etiqueta.alerta {
    background: var(--rojo-suave);
    color: var(--rojo-profundo);
}

/* El reverso de un pago no es un estado muerto como "anulado": es un movimiento que ocurrió
   y que mueve plata. Va con contorno y no con relleno para que se distinga de un vistazo de
   la fila anulada que tiene justo encima, que era el problema: dos etiquetas grises con
   nombres casi iguales se leían como la misma cosa repetida. */
.etiqueta.reverso {
    background: none;
    border: 1px solid var(--texto-tenue);
    color: var(--texto-tenue);
}

/* ---------------------------------------------------------------------------
   Usuarios
   --------------------------------------------------------------------------- */

.panel-usuarios {
    margin-top: 1.5rem;
}

.controles-usuarios {
    padding-bottom: 1rem;
    border-bottom: 1px solid var(--borde);
}

.controles-usuarios > label:first-child {
    margin-top: 0;
}

label.filtro-inactivos {
    margin-top: 0.75rem;
}

.resultados-usuarios {
    margin-top: 0.75rem;
}

.tabla-usuarios {
    table-layout: fixed;
    margin-top: 0;
}

.tabla-usuarios .columna-persona {
    width: 31%;
}

.tabla-usuarios .columna-correo {
    width: 43%;
}

.tabla-usuarios .columna-estado {
    width: 26%;
}

.tabla-usuarios th,
.tabla-usuarios td {
    vertical-align: middle;
}

.tabla-usuarios .persona-usuario[scope="row"] {
    color: var(--texto);
    font-size: 1rem;
    font-weight: 400;
    letter-spacing: normal;
    text-transform: none;
}

.tabla-usuarios .correo-usuario {
    overflow-wrap: anywhere;
}

.tabla-usuarios .estado-usuario {
    text-align: right;
}

.estado-usuario-contenido {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    flex-wrap: wrap;
    gap: 0.35rem;
}

.estado-usuario-contenido .etiqueta {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: 1.5rem;
    line-height: 1;
}

.etiqueta.inicial {
    border: 1px solid var(--borde);
    background: transparent;
    color: var(--texto-tenue);
}

.tabla-usuarios .fila-rol th {
    padding: 1.25rem 0.6rem 0.35rem;
    border-bottom: 0;
    color: var(--texto-tenue);
    font-size: 0.8rem;
    letter-spacing: 0.03em;
    text-transform: uppercase;
}

.tabla-usuarios tbody:first-of-type .fila-rol th {
    padding-top: 0.75rem;
}

.cantidad-rol {
    margin-left: 0.45rem;
    font-size: 0.75rem;
    font-weight: 400;
    letter-spacing: normal;
    text-transform: none;
}

.tabla-usuarios tbody tr:last-child > * {
    border-bottom: 0;
}

.tabla-usuarios tr:not(.fila-rol):hover > * {
    background: var(--menta-suave);
}

.tabla-usuarios tr.inactiva .persona-usuario a {
    color: var(--texto-tenue);
}

.resumen-usuarios {
    margin: 1rem 0 0;
    text-align: right;
    font-variant-numeric: tabular-nums;
}

.vacio-usuarios {
    margin: 0;
    padding: 1.5rem 0;
    text-align: center;
}

@media (max-width: 40rem) {
    .tabla-usuarios,
    .tabla-usuarios tbody {
        display: block;
        overflow: visible;
    }

    .tabla-usuarios colgroup,
    .tabla-usuarios thead {
        display: none;
    }

    .tabla-usuarios .fila-rol {
        display: block;
    }

    .tabla-usuarios .fila-rol th {
        display: block;
        width: auto;
        padding-right: 0.4rem;
        padding-left: 0.4rem;
    }

    .tabla-usuarios tr:not(.fila-rol) {
        display: grid;
        grid-template-columns: minmax(0, 1fr) auto;
        grid-template-areas:
            "persona estado"
            "correo estado";
        gap: 0.15rem 1rem;
        padding: 0.7rem 0.4rem;
        border-bottom: 1px solid var(--borde);
    }

    .tabla-usuarios tr:not(.fila-rol) > * {
        width: auto;
        padding: 0;
        border-bottom: 0;
    }

    .tabla-usuarios tr:not(.fila-rol) .persona-usuario {
        grid-area: persona;
    }

    .tabla-usuarios tr:not(.fila-rol) .correo-usuario {
        grid-area: correo;
    }

    .tabla-usuarios tr:not(.fila-rol) .estado-usuario {
        grid-area: estado;
        align-self: center;
    }
}

/* ---------------------------------------------------------------------------
   Servicios
   --------------------------------------------------------------------------- */

.panel-servicios {
    margin-top: 1.5rem;
}

.controles-servicios {
    padding-bottom: 1rem;
    border-bottom: 1px solid var(--borde);
}

.controles-servicios > label:first-child {
    margin-top: 0;
}

label.filtro-inactivos-servicios {
    margin-top: 0.75rem;
}

.resultados-servicios {
    margin-top: 0.75rem;
}

.tabla-servicios {
    table-layout: fixed;
    margin-top: 0;
}

.tabla-servicios .columna-servicio {
    width: 46%;
}

.tabla-servicios .columna-codigo {
    width: 18%;
}

.tabla-servicios .columna-precio {
    width: 17%;
}

.tabla-servicios .columna-estado-servicio {
    width: 19%;
}

.tabla-servicios th,
.tabla-servicios td {
    vertical-align: middle;
}

.tabla-servicios .nombre-servicio[scope="row"] {
    color: var(--texto);
    font-size: 1rem;
    font-weight: 400;
    letter-spacing: normal;
    text-transform: none;
}

.descripcion-servicio {
    display: block;
    margin-top: 0.1rem;
    font-size: 0.85rem;
    font-weight: 400;
}

.tabla-servicios .codigo-servicio {
    overflow-wrap: anywhere;
}

.tabla-servicios .estado-servicio {
    text-align: right;
}

.estado-servicio-contenido {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    flex-wrap: wrap;
    gap: 0.35rem;
}

.estado-servicio-contenido .etiqueta {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: 1.5rem;
    line-height: 1;
}

.etiqueta.exenta {
    border: 1px solid var(--borde);
    background: transparent;
    color: var(--texto-tenue);
}

.tabla-servicios .fila-categoria-servicio th {
    padding: 1.25rem 0.6rem 0.35rem;
    border-bottom: 0;
    color: var(--texto-tenue);
    font-size: 0.8rem;
    letter-spacing: 0.03em;
    text-transform: uppercase;
}

.tabla-servicios tbody:first-of-type .fila-categoria-servicio th {
    padding-top: 0.75rem;
}

.cantidad-categoria {
    margin-left: 0.45rem;
    font-size: 0.75rem;
    font-weight: 400;
    letter-spacing: normal;
    text-transform: none;
}

.tabla-servicios tbody tr:last-child > * {
    border-bottom: 0;
}

.tabla-servicios tr:not(.fila-categoria-servicio):hover > * {
    background: var(--menta-suave);
}

.tabla-servicios tr.inactiva .nombre-servicio,
.tabla-servicios tr.inactiva .nombre-servicio a {
    color: var(--texto-tenue);
}

.resumen-servicios {
    margin: 1rem 0 0;
    text-align: right;
    font-variant-numeric: tabular-nums;
}

.vacio-servicios {
    margin: 0;
    padding: 1.5rem 0;
    text-align: center;
}

.vacio-catalogo > :first-child {
    margin-top: 0;
}

@media (max-width: 40rem) {
    .tabla-servicios,
    .tabla-servicios tbody {
        display: block;
        overflow: visible;
    }

    .tabla-servicios colgroup,
    .tabla-servicios thead {
        display: none;
    }

    .tabla-servicios .fila-categoria-servicio {
        display: block;
    }

    .tabla-servicios .fila-categoria-servicio th {
        display: block;
        width: auto;
        padding-right: 0.4rem;
        padding-left: 0.4rem;
    }

    .tabla-servicios tr:not(.fila-categoria-servicio) {
        display: grid;
        grid-template-columns: minmax(0, 1fr) auto;
        grid-template-areas:
            "servicio precio"
            "codigo estado";
        gap: 0.3rem 1rem;
        padding: 0.7rem 0.4rem;
        border-bottom: 1px solid var(--borde);
    }

    .tabla-servicios tr:not(.fila-categoria-servicio) > * {
        width: auto;
        padding: 0;
        border-bottom: 0;
    }

    .tabla-servicios tr:not(.fila-categoria-servicio) .nombre-servicio {
        grid-area: servicio;
    }

    .tabla-servicios tr:not(.fila-categoria-servicio) .codigo-servicio {
        grid-area: codigo;
    }

    .tabla-servicios tr:not(.fila-categoria-servicio) .precio-servicio {
        grid-area: precio;
    }

    .tabla-servicios tr:not(.fila-categoria-servicio) .estado-servicio {
        grid-area: estado;
    }
}

/* ---------------------------------------------------------------------------
   Auditoría
   --------------------------------------------------------------------------- */

/* Cambios y accesos son dos pantallas de la misma sección. La barra de arriba marca la
   sección; esto marca en cuál de las dos se está parado. */
nav.sub {
    display: flex;
    gap: 1.25rem;
    margin: 0.5rem 0 1rem;
    border-bottom: 1px solid var(--borde);
}

nav.sub a {
    padding: 0.35rem 0;
    margin-bottom: -1px;
    border-bottom: 2px solid transparent;
    text-decoration: none;
}

nav.sub a.actual {
    color: var(--turquesa-profundo);
    font-weight: 600;
    border-bottom-color: var(--turquesa);
}

/* El diff vive dentro de una celda: sin viñetas ni sangría, porque compite con el resto de
   la fila y lo que tiene que leerse primero es el valor nuevo. */
ul.diff {
    margin: 0;
    padding: 0;
    list-style: none;
    font-size: 0.9rem;
}

ul.diff li + li {
    margin-top: 0.15rem;
}

/* De dónde venía el valor: presente para poder comparar, apagado para no disputarle la
   atención a en qué quedó. */
.antes {
    color: var(--texto-tenue);
}

/* Una celda de auditoría puede traer ocho campos; sin esto, una nota larga estira la
   columna y desplaza la tabla entera de lado. */
ul.diff li {
    overflow-wrap: anywhere;
}

@media (prefers-reduced-motion: reduce) {
    * {
        transition: none !important;
    }
}

/* ---------------------------------------------------------------------------
   La hoja: la epicrisis, que es lo único que se imprime

   En pantalla se ve como el resto del sistema —hereda `main`— pero está pensada para el
   papel. Todo lo que acá se ajusta responde a algo que se rompe al imprimir: los fondos de
   sección que se comen el tóner, la consulta que queda partida entre dos páginas, y el
   encabezado de la clínica, que en pantalla no existe en ninguna otra pantalla.
   --------------------------------------------------------------------------- */
.hoja .membrete {
    padding-bottom: 0.75rem;
    border-bottom: 2px solid var(--turquesa);
}

.hoja .membrete .tenue {
    display: block;
    font-size: 0.85rem;
}

/* Una atención se lee como bloque: dos columnas de etiqueta y contenido, con el texto largo
   —anamnesis, tratamiento— respetando los saltos de línea que escribió el veterinario. */
.hoja .consulta dd {
    white-space: pre-wrap;
}

.hoja .pie {
    margin-top: 2.5rem;
}

.hoja .firma {
    margin-top: 3rem;
    max-width: 18rem;
}

/* La línea sobre la que se firma. Va con borde y no con guiones bajos para que no se corte
   entre dos líneas cuando el pie cae justo al final de la página. */
.hoja .firma span {
    display: block;
    border-top: 1px solid var(--texto);
}

.hoja .firma p {
    margin: 0.25rem 0 0;
}

@media print {
    /* Los botones y el enlace de volver no son parte del documento. */
    .sin-imprimir {
        display: none !important;
    }

    /* Sobre papel manda el papel: aunque la pantalla esté en Grafito clínico, lo que sale de
       la impresora es tinta sobre blanco. Sin esto, el tema oscuro imprime un rectángulo
       gris de tinta por cada sección. */
    body {
        background: white;
        color: black;
    }

    .hoja {
        max-width: none;
        padding: 0;
    }

    .hoja section {
        background: none;
        border: none;
        box-shadow: none;
        padding: 0;
        margin-top: 1.25rem;
        /* Que una consulta no quede partida entre dos hojas: leerla a caballo entre dos
           páginas es exactamente lo que hace que un resumen clínico se malinterprete. */
        break-inside: avoid;
    }

    .hoja h1,
    .hoja h2 {
        color: black;
    }

    .hoja .etiqueta {
        border: 1px solid black;
        background: none;
        color: black;
    }
}

/* ---------------------------------------------------------------------------
   Documentos impresos: presupuesto, DTE y receta

   Comparten la gramática de la epicrisis —membrete, hoja blanca y controles que desaparecen—
   pero no su estructura clínica. La jerarquía acá es emisor → documento → detalle → firma o
   advertencia, que es la lectura natural de una hoja que se entrega en el mesón.
   --------------------------------------------------------------------------- */
.hoja-documento {
    max-width: 58rem;
}

.cabecera-documento {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 2rem;
    margin-top: 2rem;
}

.cabecera-documento h1 {
    margin-bottom: 0.15rem;
}

.folio-documento {
    margin: 0;
    color: var(--texto-tenue);
    font-variant-numeric: tabular-nums;
}

/* Se lee como un sello de documento, no como un estado interactivo de la aplicación. */
.sello-no-boleta,
.estado-documento {
    display: inline-block;
    flex: 0 0 auto;
    padding: 0.55rem 0.75rem;
    border: 2px solid var(--rojo);
    color: var(--rojo-profundo);
    font-size: 0.85rem;
    line-height: 1.2;
    text-align: center;
}

.estado-documento {
    border-width: 1px;
    border-color: var(--borde);
    color: var(--texto-tenue);
}

.advertencia-impresa {
    margin-top: 1.25rem;
    padding: 0.85rem 1rem;
    border: 1px solid var(--rojo);
    background: var(--rojo-suave);
    color: var(--rojo-profundo);
}

.advertencia-impresa strong {
    display: block;
    margin-bottom: 0.15rem;
}

.hoja-documento .datos-documento dl {
    grid-template-columns: minmax(5rem, max-content) 1fr;
}

.tabla-documento tbody tr,
.tabla-documento tfoot tr {
    break-inside: avoid;
}

.desglose-impreso {
    break-inside: avoid;
}

.texto-documento {
    max-width: 75ch;
    white-space: pre-wrap;
}

.bloque-receta .texto-documento {
    min-height: 4rem;
    font-size: 1.05rem;
    line-height: 1.65;
}

.pie-documento {
    padding-top: 1rem;
    border-top: 1px solid var(--borde);
}

.firma-profesional {
    width: min(20rem, 100%);
    margin-top: 5rem;
    text-align: center;
}

.firma-profesional > span {
    display: block;
    border-top: 1px solid var(--texto);
}

.firma-profesional p {
    margin: 0.25rem 0 0;
}

@media (max-width: 640px) {
    .cabecera-documento {
        flex-direction: column;
        gap: 1rem;
    }
}

@media print {
    .hoja-documento {
        font-size: 10.5pt;
    }

    /* Una tabla larga puede continuar en la hoja siguiente; cada fila se mantiene unida. */
    .hoja-documento section {
        break-inside: auto;
    }

    .hoja-receta .bloque-receta,
    .hoja-documento .datos-documento,
    .hoja-documento .pie-documento {
        break-inside: avoid;
    }

    .sello-no-boleta,
    .estado-documento,
    .advertencia-impresa {
        border-color: black;
        background: none;
        color: black;
    }

    .hoja-documento .membrete {
        border-bottom-color: black;
    }

    .pie-documento,
    .firma-profesional > span {
        border-color: black;
    }
}
