/* ═══════════════════════════════════════════════════════════
   CASIA — estilos globales
   assets/css/main.css

   Orden del archivo:
     1. Tokens de marca
     2. Bootstrap re-tematizado (variables, no clases reescritas)
     2b. Modales: techo de pantalla y columna flex del form
     3. Base y accesibilidad
     4. Marca (logotipo tipográfico)
     5. Armazón de la app: barra superior, menú lateral, lienzo
     6. Componentes propios (alertas, badges, botón de envío)
     7. Componentes compartidos entre módulos (vista previa, detalles)
     8. Utilidades del proyecto
     9. Movimiento reducido e impresión

   Regla de la casa: cero style="" en el HTML. Si algo necesita un
   valor dinámico desde PHP, entra por --variable.
   ═══════════════════════════════════════════════════════════ */

/* ═══ 1. Tokens de marca ═══════════════════════════════════
   Verde pino para lo estable (el dinero, la casa) y terracota
   —color de teja— para lo cálido. Ni azul de plantilla ni
   degradados de startup. Los contrastes están verificados
   contra blanco y contra --casia-lienzo. */

:root {
    /* Primario: #125C4B sobre blanco = 7.9:1 (AAA) */
    --casia-primario: #125c4b;
    --casia-primario-oscuro: #0b3a2f;
    --casia-primario-medio: #14514a;
    --casia-primario-sutil: #e4efeb;
    --casia-primario-borde: #bcd6ce;

    /* Acento terracota. Como texto solo la variante oscura
       (#9C4A24 sobre blanco = 6.1:1); la clara es decorativa. */
    --casia-acento: #c0623a;
    --casia-acento-oscuro: #9c4a24;
    --casia-acento-sutil: #fbede4;

    /* Tinta y superficies */
    --casia-tinta: #1c2523;          /* 14.9:1 sobre blanco  */
    --casia-tinta-fuerte: #101614;
    --casia-tinta-suave: #5a6764;    /*  5.9:1 sobre blanco  */
    --casia-linea: #e3dfd8;
    --casia-superficie: #ffffff;
    --casia-lienzo: #f6f4f0;         /* papel cálido */
    --casia-lienzo-hundido: #efebe4;

    /* Semánticos, coherentes con Bootstrap pero desaturados */
    --casia-exito: #2f7d5c;
    --casia-aviso: #d99206;
    --casia-peligro: #b3261e;
    --casia-info: #2e6c8e;

    /* Objetivo táctil mínimo. 44 px es la recomendación de Apple y es
       lo que hace usable el sistema con el pulgar, que es como lo va a
       usar el administrador parado en una finca. */
    --casia-tactil-min: 44px;

    /* Armazón */
    --casia-alto-nav: 3.75rem;
    --casia-ancho-menu: 16rem;

    --casia-sombra-1: 0 1px 2px rgba(28, 37, 35, .06), 0 1px 3px rgba(28, 37, 35, .05);
    --casia-sombra-2: 0 2px 4px rgba(28, 37, 35, .05), 0 10px 28px rgba(28, 37, 35, .07);
}

/* ═══ 2. Bootstrap re-tematizado ═══════════════════════════
   Se sobreescriben las variables que Bootstrap ya consume, para
   que .btn, .card, .alert, .badge y compañía hereden el tema sin
   que haya que reescribir ni una clase del framework. */

:root,
[data-bs-theme="light"] {
    /* Tipografía: pila del sistema. Sin petición de red, sin cambiar
       la CSP, y en iPhone/iPad es San Francisco. */
    --bs-body-font-family: system-ui, -apple-system, "Segoe UI", Roboto,
        "Helvetica Neue", "Noto Sans", Arial, sans-serif,
        "Apple Color Emoji", "Segoe UI Emoji";
    --bs-body-font-size: 1rem;
    --bs-body-line-height: 1.55;

    --bs-body-color: var(--casia-tinta);
    --bs-body-color-rgb: 28, 37, 35;
    --bs-body-bg: var(--casia-superficie);
    --bs-body-bg-rgb: 255, 255, 255;

    --bs-emphasis-color: var(--casia-tinta-fuerte);
    --bs-emphasis-color-rgb: 16, 22, 20;
    --bs-heading-color: var(--casia-tinta-fuerte);

    --bs-secondary-color: var(--casia-tinta-suave);
    --bs-secondary-color-rgb: 90, 103, 100;
    --bs-secondary-bg: var(--casia-lienzo-hundido);
    --bs-secondary-bg-rgb: 239, 235, 228;

    --bs-tertiary-color: var(--casia-tinta-suave);
    --bs-tertiary-bg: var(--casia-lienzo);
    --bs-tertiary-bg-rgb: 246, 244, 240;

    --bs-border-color: var(--casia-linea);
    --bs-border-color-translucent: rgba(28, 37, 35, .1);

    /* Paleta */
    --bs-primary: var(--casia-primario);
    --bs-primary-rgb: 18, 92, 75;
    --bs-primary-text-emphasis: var(--casia-primario-oscuro);
    --bs-primary-bg-subtle: var(--casia-primario-sutil);
    --bs-primary-border-subtle: var(--casia-primario-borde);

    --bs-secondary: #6c726e;
    --bs-secondary-rgb: 108, 114, 110;
    --bs-secondary-text-emphasis: #3d423f;
    --bs-secondary-bg-subtle: #eeeeec;
    --bs-secondary-border-subtle: #d5d7d5;

    --bs-success: var(--casia-exito);
    --bs-success-rgb: 47, 125, 92;
    --bs-success-text-emphasis: #1d4e39;
    --bs-success-bg-subtle: #e6f1ec;
    --bs-success-border-subtle: #c2ddd1;

    --bs-danger: var(--casia-peligro);
    --bs-danger-rgb: 179, 38, 30;
    --bs-danger-text-emphasis: #7a1a15;
    --bs-danger-bg-subtle: #fae7e5;
    --bs-danger-border-subtle: #f0c4c0;

    --bs-warning: var(--casia-aviso);
    --bs-warning-rgb: 217, 146, 6;
    --bs-warning-text-emphasis: #7a4e00;
    --bs-warning-bg-subtle: #fbf0dc;
    --bs-warning-border-subtle: #f0d9a8;

    --bs-info: var(--casia-info);
    --bs-info-rgb: 46, 108, 142;
    --bs-info-text-emphasis: #1c4459;
    --bs-info-bg-subtle: #e3eef4;
    --bs-info-border-subtle: #bbd5e3;

    /* Enlaces */
    --bs-link-color: var(--casia-primario);
    --bs-link-color-rgb: 18, 92, 75;
    --bs-link-hover-color: var(--casia-primario-oscuro);
    --bs-link-hover-color-rgb: 11, 58, 47;

    /* Esquinas: redondeo generoso pero no de burbuja */
    --bs-border-radius: .625rem;
    --bs-border-radius-sm: .375rem;
    --bs-border-radius-lg: .875rem;
    --bs-border-radius-xl: 1.125rem;
    --bs-border-radius-xxl: 1.75rem;

    --bs-focus-ring-color: rgba(18, 92, 75, .3);
}

/* Botones: Bootstrap resuelve el color de cada botón con sus propias
   --bs-btn-*, que no salen de --bs-primary. Hay que darlas a mano. */
.btn-primary {
    --bs-btn-bg: var(--casia-primario);
    --bs-btn-border-color: var(--casia-primario);
    --bs-btn-hover-bg: var(--casia-primario-oscuro);
    --bs-btn-hover-border-color: var(--casia-primario-oscuro);
    --bs-btn-active-bg: var(--casia-primario-oscuro);
    --bs-btn-active-border-color: var(--casia-primario-oscuro);
    --bs-btn-disabled-bg: var(--casia-primario);
    --bs-btn-disabled-border-color: var(--casia-primario);
    --bs-btn-focus-shadow-rgb: 18, 92, 75;
}

.btn-outline-primary {
    --bs-btn-color: var(--casia-primario-oscuro);
    --bs-btn-border-color: var(--casia-primario-borde);
    --bs-btn-hover-bg: var(--casia-primario);
    --bs-btn-hover-border-color: var(--casia-primario);
    --bs-btn-active-bg: var(--casia-primario-oscuro);
    --bs-btn-active-border-color: var(--casia-primario-oscuro);
    --bs-btn-disabled-color: var(--casia-primario);
    --bs-btn-disabled-border-color: var(--casia-primario-borde);
    --bs-btn-focus-shadow-rgb: 18, 92, 75;
}

.btn-outline-secondary {
    --bs-btn-color: var(--casia-tinta-suave);
    --bs-btn-border-color: var(--casia-linea);
    --bs-btn-hover-color: var(--casia-tinta);
    --bs-btn-hover-bg: var(--casia-lienzo-hundido);
    --bs-btn-hover-border-color: var(--casia-linea);
    --bs-btn-active-color: var(--casia-tinta);
    --bs-btn-active-bg: var(--casia-lienzo-hundido);
    --bs-btn-active-border-color: var(--casia-linea);
    --bs-btn-focus-shadow-rgb: 18, 92, 75;
}

.btn-danger {
    --bs-btn-bg: var(--casia-peligro);
    --bs-btn-border-color: var(--casia-peligro);
    --bs-btn-hover-bg: #8f1e17;
    --bs-btn-hover-border-color: #8f1e17;
    --bs-btn-active-bg: #7a1a15;
    --bs-btn-active-border-color: #7a1a15;
    --bs-btn-focus-shadow-rgb: 179, 38, 30;
}

.btn-success {
    --bs-btn-bg: var(--casia-exito);
    --bs-btn-border-color: var(--casia-exito);
    --bs-btn-hover-bg: #266548;
    --bs-btn-hover-border-color: #266548;
    --bs-btn-active-bg: #1d4e39;
    --bs-btn-active-border-color: #1d4e39;
    --bs-btn-focus-shadow-rgb: 47, 125, 92;
}

.btn {
    --bs-btn-font-weight: 500;
    --bs-btn-border-radius: var(--bs-border-radius);
}

/* Foco de formularios: Bootstrap trae el azul en duro, no por variable. */
.form-control:focus,
.form-select:focus {
    border-color: #6fa093;
    box-shadow: 0 0 0 .25rem rgba(18, 92, 75, .2);
}

.form-check-input:focus {
    border-color: #6fa093;
    box-shadow: 0 0 0 .25rem rgba(18, 92, 75, .2);
}

.form-check-input:checked {
    background-color: var(--casia-primario);
    border-color: var(--casia-primario);
}

.card {
    --bs-card-border-color: var(--casia-linea);
    --bs-card-border-radius: var(--bs-border-radius-lg);
    --bs-card-inner-border-radius: calc(var(--bs-border-radius-lg) - 1px);
}

/* `.card` es flex-column: su `.table-responsive` es un hijo flex y, por la
   misma razón de arriba, necesita min-width:0 para no crecer con la tabla.
   El scroll táctil con inercia es el que hace que arrastrar la tabla con el
   pulgar en iPhone se sienta nativo; iOS moderno lo añade solo, pero se
   declara para no depender de eso. */
.table-responsive {
    min-width: 0;
    -webkit-overflow-scrolling: touch;
    /* Solo queremos scroll horizontal aquí. Pero al fijar overflow-x en
       "auto" y dejar overflow-y en su default ("visible"), la spec de CSS
       obliga al navegador a computar el otro eje como "auto" también (no
       puede haber un eje "auto" y otro "visible" a la vez). Con tablas de
       una sola fila, un desfase de subpíxel entre clientHeight y
       scrollHeight (~1px, por redondeo) hace que ese overflow-y: auto
       dibuje una barra vertical innecesaria que corta la última columna.
       Fijarlo en hidden evita la barra sin recortar contenido real. */
    overflow-y: hidden;
}

.dropdown-menu {
    --bs-dropdown-border-color: var(--casia-linea);
    --bs-dropdown-border-radius: var(--bs-border-radius);
    --bs-dropdown-link-active-bg: var(--casia-primario);
    --bs-dropdown-link-hover-bg: var(--casia-primario-sutil);
    --bs-dropdown-item-padding-y: .5rem;
}

/* ═══ 2b. Modales: caben enteros en la pantalla ═══════════
   Bootstrap ya hace de .modal-content una columna flex con
   cabecera y pie inencogibles (flex-shrink: 0) y cuerpo elástico
   (flex: 1 1 auto). En CASIA faltaban dos piezas para que eso se
   cumpla de verdad:

   1. El <form> envuelve cabecera+cuerpo+pie dentro de
      .modal-content (patrón de todos los modales del proyecto).
      Un <form> bloque interpuesto rompe la columna: .modal-body
      deja de ser hijo flex y nunca desplaza. Medido en Chromium
      con el patrón real, un modal con .modal-dialog-scrollable
      recortaba el pie —los botones de acción— por debajo de la
      pantalla SIN scroll posible: el <form> no encoge y el
      contenido (overflow: hidden) lo recorta. Con display:contents
      el formulario deja de ser una caja y cabecera/cuerpo/pie
      vuelven a ser los hijos flex del contenido; el formulario
      sigue existiendo intacto para el envío.

   2. A partir de sm los modal-fullscreen-* están inactivos (solo
      rigen bajo su breakpoint) y el margen vertical es de
      1.75rem. Ahí el contenido se topa con la altura de la
      pantalla y el cuerpo desplaza dentro —lo que Bootstrap solo
      hace con la clase .modal-dialog-scrollable, aplicado a todo
      modal—. Sin este techo, un modal centrado más alto que la
      pantalla dependía del scroll del propio .modal: la cabecera
      huía y los botones quedaban al final de un desplazamiento a
      ciegas; por eso en una PC de poca altura había que reducir
      la letra para ver el modal completo. Debajo de sm el techo
      no hace falta: allí todos los modales son
      .modal-fullscreen-sm-down y, con el form fuera de la columna,
      la pantalla completa fija cabecera y pie de verdad con el
      cuerpo desplazable.

   overflow-y: auto en el cuerpo a cualquier altura es inocuo: sin
   contenido de sobra no pinta barra, el scroll nace solo cuando
   sobra; overscroll-behavior: contain evita que el dedo arrastre
   la página detrás del modal. La variante dvh se declara después
   con @supports, para los móviles con barra dinámica; quien no la
   soporta se queda con la de vh. */

.modal-content > form {
    display: contents;
}

.modal-body {
    overflow-y: auto;
    overscroll-behavior: contain;
}

@media (min-width: 576px) {
    .modal-content {
        max-height: calc(100vh - var(--bs-modal-margin) * 2);
    }
}

@supports (max-height: 100dvh) {
    @media (min-width: 576px) {
        .modal-content {
            max-height: calc(100dvh - var(--bs-modal-margin) * 2);
        }
    }
}


/* ═══ 3. Base y accesibilidad ══════════════════════════════ */

/* El body nunca desplaza en horizontal. Sin esto, una tabla ancha dentro de
   un .table-responsive sigue desplazando la PÁGINA en Chrome/Safari móvil:
   el eje X interno del .table-responsive no evita que su contenido siga
   contando para el "layout viewport" del navegador, así que cualquier
   elemento `position: fixed` (la barra superior, el offcanvas de ayuda) se
   estira para acompañarlo y se sale de la pantalla al desplazar (medido en
   Gastos, Presupuestos y Proveedores — /docs/LESSONS.md). El contenido ancho
   se desplaza dentro de SU PROPIO contenedor (`.table-responsive`, que ya
   trae `overflow-x: auto`); el documento, nunca. */
html,
body {
    overflow-x: hidden;
}

body {
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    text-wrap: pretty;
}

h1, h2, h3, h4, h5, h6,
.h1, .h2, .h3, .h4, .h5, .h6 {
    font-weight: 600;
    letter-spacing: -.01em;
    text-wrap: balance;
}

/* Tamaño táctil. 44 px en todo lo que se toca. */
.btn,
.form-control,
.form-select,
.nav-link,
.dropdown-item,
.page-link {
    min-height: var(--casia-tactil-min);
}

/* Con min-height, un enlace de bloque no centra su texto. */
.dropdown-item {
    display: flex;
    align-items: center;
}

/* Los botones de icono también deben ser cuadrados de 44. */
.btn-icono {
    min-width: var(--casia-tactil-min);
    display: inline-flex;
    align-items: center;
    justify-content: center;
}

/* Dentro de una tabla densa el mínimo estorba; ahí manda .btn-sm. */
.table .btn-sm {
    min-height: 2rem;
}

/* iOS hace zoom al enfocar un input de menos de 16 px. Esta regla pisa
   a propósito el .form-control-sm de Bootstrap (14 px), que provocaría
   ese salto de escala en el teléfono. */
.form-control,
.form-select {
    font-size: 1rem;
}

/* Pero el tamaño grande sí se respeta: va después para ganarle a la
   regla de arriba, que tiene la misma especificidad. */
.form-control-lg,
.form-select-lg {
    font-size: 1.125rem;
}

.form-label {
    font-weight: 500;
    margin-bottom: .375rem;
}

.skip-link {
    position: absolute;
    top: .5rem;
    left: .5rem;
    z-index: 1080;
    padding: .5rem 1rem;
    background-color: var(--casia-superficie);
    color: var(--casia-primario-oscuro);
    font-weight: 600;
    border: 1px solid var(--casia-primario-borde);
    border-radius: var(--bs-border-radius-sm);
    box-shadow: var(--casia-sombra-2);
}

:focus-visible {
    outline: 2px solid var(--casia-primario);
    outline-offset: 2px;
}

/* Sobre la barra verde el foco verde no se vería. */
.casia-topbar :focus-visible {
    outline-color: #ffffff;
}

/* ═══ 4. Marca ═════════════════════════════════════════════
   Logotipo tipográfico, sin imagen: cuadro con casa + palabra. */

.casia-marca {
    display: inline-flex;
    align-items: center;
    gap: .625rem;
    /* En la barra superior es un enlace: tiene que ser tocable. */
    min-height: var(--casia-tactil-min);
    text-decoration: none;
    color: inherit;
    line-height: 1;
}

.casia-marca:hover,
.casia-marca:focus {
    color: inherit;
    text-decoration: none;
}

.casia-marca__icono {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2rem;
    height: 2rem;
    flex: 0 0 auto;
    border-radius: .5rem;
    background-color: var(--casia-primario);
    color: #ffffff;
    font-size: 1.0625rem;
}

.casia-marca__texto {
    font-weight: 700;
    font-size: 1.1875rem;
    letter-spacing: .13em;
    color: var(--casia-primario-oscuro);
}

/* Sobre fondo oscuro (barra superior) */
.casia-marca--claro .casia-marca__icono {
    background-color: rgba(255, 255, 255, .16);
    color: #ffffff;
}

.casia-marca--claro .casia-marca__texto {
    color: #ffffff;
}

/* En las pantallas públicas, en grande y apilado */
.casia-marca--grande {
    flex-direction: column;
    gap: .75rem;
}

.casia-marca--grande .casia-marca__icono {
    width: 3.25rem;
    height: 3.25rem;
    border-radius: .875rem;
    font-size: 1.75rem;
}

.casia-marca--grande .casia-marca__texto {
    font-size: 1.75rem;
    letter-spacing: .18em;
}

/* ═══ 5. Armazón de la app ═════════════════════════════════ */

/* ─── Barra superior, siempre visible ─────────────────────
   Es lo único de la navegación que se ve en el teléfono, así
   que carga la marca. Verde pino: blanco sobre ella da 7.9:1. */

.casia-topbar {
    height: var(--casia-alto-nav);
    background-color: var(--casia-primario);
    box-shadow: inset 0 -1px 0 rgba(255, 255, 255, .12), 0 1px 3px rgba(28, 37, 35, .12);
    z-index: 1030;
}

.casia-topbar__interior {
    height: 100%;
    display: flex;
    align-items: center;
    gap: .75rem;
    padding-inline: .75rem;
}

@media (min-width: 992px) {
    .casia-topbar__interior {
        padding-inline: 1.25rem;
    }
}

.casia-hamburguesa,
.casia-btn-usuario {
    --bs-btn-color: #ffffff;
    --bs-btn-hover-color: #ffffff;
    --bs-btn-active-color: #ffffff;
    --bs-btn-bg: transparent;
    --bs-btn-border-color: transparent;
    --bs-btn-hover-bg: rgba(255, 255, 255, .14);
    --bs-btn-hover-border-color: transparent;
    --bs-btn-active-bg: rgba(255, 255, 255, .22);
    --bs-btn-active-border-color: transparent;
    --bs-btn-box-shadow: none;
}

.casia-hamburguesa {
    min-width: var(--casia-tactil-min);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 1.5rem;
    padding: 0;
}

.casia-btn-usuario {
    display: inline-flex;
    align-items: center;
    gap: .5rem;
    font-weight: 500;
    max-width: 16rem;
}

.casia-btn-usuario__nombre {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* ─── Menú: barra lateral en ≥lg, offcanvas por la derecha en <lg ───
   El propietario tiene doce entradas. En horizontal se desbordan en
   un portátil de 1280 px; en vertical caben, se leen de un vistazo y
   queda sitio para las que vengan. En el teléfono entra por la
   derecha, que es donde llega el pulgar. */

.casia-menu-envoltura {
    display: contents;
}

.casia-menu {
    --bs-offcanvas-width: 17.5rem;
    --bs-offcanvas-bg: var(--casia-superficie);
    --bs-offcanvas-padding-x: .75rem;
    --bs-offcanvas-padding-y: .75rem;
}

.casia-menu__cabecera {
    align-items: flex-start;
    border-bottom: 1px solid var(--casia-linea);
    padding: 1rem;
}

.casia-menu__cabecera .btn-close {
    min-width: var(--casia-tactil-min);
    min-height: var(--casia-tactil-min);
    margin: -.5rem -.5rem 0 auto;
}

.casia-menu__usuario {
    min-width: 0;
    font-weight: 600;
    overflow-wrap: anywhere;
}

/* Dos clases a propósito: de lg para arriba Bootstrap aplica
   `.offcanvas-lg .offcanvas-body { display:flex; padding:0 }`, que con
   una sola clase le ganaría por especificidad al padding de abajo. */
.casia-menu .casia-menu__cuerpo {
    display: flex;
    flex-direction: column;
}

.casia-menu__lista {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: .125rem;
}

/* Rótulo de cada bloque del menú («Día a día», «Planificar»,
   «Configurar»). Pequeño y en mayúsculas para que ordene sin competir
   con los enlaces. El primero no lleva margen superior: el menú ya
   empieza pegado a la cabecera. */
.casia-menu__grupo {
    margin: 1rem 0 .25rem;
    padding: 0 .75rem;
    font-size: .6875rem;
    font-weight: 700;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--casia-tinta-suave);
}

.casia-menu__grupo:first-child {
    margin-top: .25rem;
}

/* Bloque sin rótulo al final del menú (la guía de uso): separado del
   grupo anterior por un espacio, no por un encabezado. */
.casia-menu__lista--suelta {
    margin-top: 1rem;
}

.casia-menu__enlace {
    display: flex;
    align-items: center;
    gap: .75rem;
    min-height: var(--casia-tactil-min);
    padding: .625rem .75rem;
    border-radius: var(--bs-border-radius);
    color: var(--casia-tinta);
    text-decoration: none;
    font-weight: 500;
    border-left: 3px solid transparent;
    transition: background-color .15s ease-in-out, color .15s ease-in-out;
}

.casia-menu__enlace:hover,
.casia-menu__enlace:focus-visible {
    background-color: var(--casia-lienzo);
    color: var(--casia-primario-oscuro);
}

.casia-menu__enlace .casia-menu__icono {
    font-size: 1.125rem;
    line-height: 1;
    color: var(--casia-tinta-suave);
    flex: 0 0 1.25rem;
    text-align: center;
}

.casia-menu__enlace:hover .casia-menu__icono,
.casia-menu__enlace:focus-visible .casia-menu__icono {
    color: var(--casia-primario);
}

/* Activo: fondo tenue + barra a la izquierda. Contraste del texto
   sobre el fondo tenue = 10.7:1. */
.casia-menu__enlace.is-activo {
    background-color: var(--casia-primario-sutil);
    border-left-color: var(--casia-primario);
    color: var(--casia-primario-oscuro);
    font-weight: 600;
}

.casia-menu__enlace.is-activo .casia-menu__icono {
    color: var(--casia-primario);
}

.casia-menu__pie {
    margin-top: auto;
    padding-top: .75rem;
    border-top: 1px solid var(--casia-linea);
}

.casia-menu__accion {
    display: flex;
    align-items: center;
    gap: .75rem;
    width: 100%;
    min-height: var(--casia-tactil-min);
    padding: .625rem .75rem;
    border: 0;
    border-radius: var(--bs-border-radius);
    background: none;
    color: var(--casia-tinta);
    font-weight: 500;
    text-align: left;
    text-decoration: none;
}

.casia-menu__accion:hover,
.casia-menu__accion:focus-visible {
    background-color: var(--casia-lienzo);
    color: var(--casia-primario-oscuro);
}

.casia-menu__accion--salir:hover,
.casia-menu__accion--salir:focus-visible {
    background-color: var(--bs-danger-bg-subtle);
    color: var(--bs-danger-text-emphasis);
}

@media (min-width: 992px) {
    /* De lg para arriba el offcanvas deja de ser un panel y se
       convierte en la columna izquierda. Bootstrap le fuerza
       background transparent, por eso el color va en la envoltura. */
    .casia-menu-envoltura {
        display: block;
        position: fixed;
        top: var(--casia-alto-nav);
        left: 0;
        bottom: 0;
        width: var(--casia-ancho-menu);
        z-index: 1020;
        background-color: var(--casia-superficie);
        border-right: 1px solid var(--casia-linea);
        overflow-y: auto;
        overscroll-behavior: contain;
    }

    .casia-menu {
        height: 100%;
    }

    .casia-menu .casia-menu__cuerpo {
        height: 100%;
        padding: .875rem .75rem;
        overflow-y: visible;
    }
}

/* ─── Lienzo: lo que no es navegación ───────────────────── */

.casia-lienzo {
    display: flex;
    flex-direction: column;
    min-height: 100vh;
    min-height: 100dvh;
    padding-top: var(--casia-alto-nav);
}

.casia-lienzo > main {
    flex: 1 0 auto;
    /* Un hijo flex no encoge por debajo de su contenido salvo que se le
       diga (misma razón que .min-ancho-0, sección 8): sin esto, una tabla
       ancha empuja el ancho de <main> en vez de quedarse contenida en su
       propio .table-responsive. */
    min-width: 0;
}

@media (min-width: 992px) {
    .casia-lienzo {
        padding-left: var(--casia-ancho-menu);
    }
}

.casia-pie {
    padding: 1.5rem 1rem 2rem;
    text-align: center;
}

/* ═══ 6. Componentes propios ═══════════════════════════════ */

/* Alerta con ícono. El botón de cerrar lo posiciona Bootstrap. */
.casia-alerta {
    display: flex;
    align-items: flex-start;
    gap: .75rem;
    border-radius: var(--bs-border-radius);
}

.casia-alerta__icono {
    font-size: 1.125rem;
    line-height: 1.4;
    flex: 0 0 auto;
}

.casia-alerta__texto {
    min-width: 0;
    overflow-wrap: anywhere;
}

/* Distintivo de rol */
.casia-badge-rol {
    display: inline-block;
    padding: .375rem .875rem;
    border-radius: 50rem;
    background-color: var(--casia-primario-sutil);
    color: var(--casia-primario-oscuro);
    font-size: .9375rem;
    font-weight: 600;
    letter-spacing: .02em;
}

/* Botón que se bloquea al enviar. El spinner ya está en el HTML y
   solo se muestra; así no hace falta inyectar nodos desde JS. */
.casia-btn-envio {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: .5rem;
}

.casia-btn-envio__spinner {
    display: none;
}

.casia-btn-envio.is-enviando .casia-btn-envio__spinner {
    display: inline-block;
}

.casia-btn-envio.is-enviando .casia-btn-envio__icono {
    display: none;
}

/* Mostrar/ocultar contraseña. El botón nace hidden y lo revela
   main.js: sin JavaScript no queda un control muerto en pantalla. */
.casia-ver-clave {
    min-width: var(--casia-tactil-min);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 1.0625rem;
    /* Va junto a un .form-control-lg, que redondea con -lg. Sin esto,
       el grupo tendría una esquina de .875rem y la otra de .625rem. */
    --bs-btn-border-radius: var(--bs-border-radius-lg);
}

/* Sin JavaScript el botón queda [hidden], pero sigue siendo un hijo del
   .input-group, así que Bootstrap le cuadra la esquina derecha al campo
   como si el botón estuviera ahí. Se le devuelve el redondeo.
   El !important es deliberado: la regla de Bootstrap encadena seis
   :not() y suma (0,7,0); igualarla a base de selectores sería peor
   remedio que la enfermedad. */
.input-group > .form-control:has(+ [hidden]) {
    border-top-right-radius: var(--bs-border-radius-lg) !important;
    border-bottom-right-radius: var(--bs-border-radius-lg) !important;
}

/* Indicador de fortaleza. Solo orientativo: quien valida de verdad
   es validar_contrasena() en el servidor. */
.casia-fuerza {
    margin-top: .625rem;
}

.casia-fuerza__barra {
    height: .375rem;
    border-radius: 50rem;
    background-color: var(--casia-lienzo-hundido);
    overflow: hidden;
}

.casia-fuerza__nivel {
    display: block;
    height: 100%;
    width: 0;
    border-radius: 50rem;
    background-color: var(--casia-peligro);
    transition: width .2s ease-in-out, background-color .2s ease-in-out;
}

.casia-fuerza__nivel.is-nivel-1 { width: 33%; background-color: var(--casia-peligro); }
.casia-fuerza__nivel.is-nivel-2 { width: 66%; background-color: var(--casia-aviso); }
.casia-fuerza__nivel.is-nivel-3 { width: 100%; background-color: var(--casia-exito); }

.casia-fuerza__texto {
    margin-top: .25rem;
    color: var(--casia-tinta-suave);
    min-height: 1.25rem;
}

/* Tarjeta con cabecera de color tenue (listados, bloques del inicio) */
.casia-tarjeta {
    border-color: var(--casia-linea);
    box-shadow: var(--casia-sombra-1);
}

.casia-tarjeta__cabecera {
    display: flex;
    align-items: center;
    gap: .625rem;
    background-color: transparent;
    border-bottom: 1px solid var(--casia-linea);
    padding: 1rem 1.25rem;
}

/* Ícono en cuadro tenue, para tarjetas y estados vacíos */
.casia-ficha-icono {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.75rem;
    height: 2.75rem;
    flex: 0 0 auto;
    border-radius: .75rem;
    background-color: var(--casia-primario-sutil);
    color: var(--casia-primario);
    font-size: 1.25rem;
}

.casia-ficha-icono--acento {
    background-color: var(--casia-acento-sutil);
    color: var(--casia-acento-oscuro);
}

/* Estado vacío */
.casia-vacio {
    text-align: center;
    padding: 2.5rem 1.25rem;
}

.casia-vacio__icono {
    font-size: 2.5rem;
    color: var(--casia-tinta-suave);
    opacity: .55;
}

/* ═══ 7. Componentes compartidos entre módulos ═════════════
   Hoy los usan Gastos y Propiedades (create/edit de los dos). Aquí SOLO
   lo que es igual en los dos: el aspecto de "zona de carga" de la vista
   previa antes de subir, y el <details> plegable. La disposición (una
   caja grande vs. una rejilla de miniaturas) y el resto de variantes son
   decisión de cada módulo y siguen en su propia hoja
   (assets/css/modules/gastos.css y propiedades.css). */

/* Vista previa de lo que se va a subir (create y edit). Nace [hidden] en
   el PHP; el JS del módulo la revela al elegir un archivo. */
.casia-preview {
    background-color: var(--casia-lienzo-hundido);
    border: 1px dashed var(--casia-linea);
    border-radius: var(--bs-border-radius);
}

.casia-preview__img {
    display: block;
    width: 100%;
    object-fit: cover;
    object-position: center;
}

.casia-preview__peso {
    margin: 0;
}

/* Campos plegables (<details>). Se abre sin JavaScript porque es HTML
   nativo. El summary necesita verse tocable (44 px) y el marcador por
   defecto del navegador es demasiado discreto en un teléfono. */

.casia-detalles > summary {
    display: flex;
    align-items: center;
    min-height: var(--casia-tactil-min);
    padding: .5rem 0;
    cursor: pointer;
    color: var(--casia-primario-oscuro);
    list-style: none;
}

.casia-detalles > summary::-webkit-details-marker {
    display: none;
}

.casia-detalles > summary::before {
    content: "\f4fe"; /* bi-chevron-right, vía Bootstrap Icons ya cargado */
    font-family: "bootstrap-icons", sans-serif;
    margin-right: .5rem;
    font-size: .8em;
    transition: transform .15s ease-in-out;
}

.casia-detalles[open] > summary::before {
    transform: rotate(90deg);
}

/* Grupo de renglones activables por categoría (<fieldset class="casia-
   grupo-renglones"> + <legend>). Lo usan modules/propiedades/edit.php
   (renglones por propiedad) y la sección «Gastos generales» de
   modules/catalogo/index.php (renglones de gasto general): mismo marcado,
   mismo aspecto, así que vive aquí y no en el CSS de un solo módulo.
   Una columna en el teléfono, dos o tres en cuanto hay sitio, con
   auto-fill para que el propio navegador decida cuántas caben a partir
   de 13rem. */

.casia-grupo-renglones {
    border: 1px solid var(--casia-linea);
    border-radius: var(--bs-border-radius);
    padding: 1rem;
    margin: 0;
    height: 100%;
}

.casia-grupo-renglones legend {
    float: none;
    width: auto;
    padding: 0 0 .75rem;
    margin: 0;
    font-size: 1rem;
}

.casia-grupo-renglones .row,
.casia-grupo-renglones > div:not(legend) {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(13rem, 1fr));
    gap: .125rem .75rem;
}

.casia-grupo-renglones .form-check {
    display: flex;
    align-items: center;
    gap: .5rem;
    min-height: var(--casia-tactil-min);
    margin-bottom: 0;
    padding-left: 0;
}

.casia-grupo-renglones .form-check-input {
    float: none;
    flex: 0 0 auto;
    margin-top: 0;
    margin-left: 0;
    width: 1.125em;
    height: 1.125em;
}

.casia-grupo-renglones .form-check-label {
    flex: 1 1 auto;
    padding-block: .5rem;
    cursor: pointer;
    overflow-wrap: anywhere;
}

/* Botón "Marcar todos" / "Desmarcar todos". Nace [hidden] en el PHP y el
   JS del módulo lo revela; el objetivo táctil no puede caer por debajo
   del mínimo solo por ir en un legend.
   OJO: un selector de atributo no hace prefijo. [data-marcar-grupo] NO
   selecciona un elemento con data-marcar-grupo-general (ni ningún otro
   data-marcar-grupo-*): son atributos distintos para CSS. Cada variante
   que se añada tiene que sumarse aquí a mano, con su propio selector. */
.casia-grupo-renglones [data-marcar-grupo],
.casia-grupo-renglones [data-marcar-grupo-general] {
    min-height: 2rem;
    padding-inline: .25rem;
}

/* ═══ 8. Utilidades del proyecto ═══════════════════════════ */

/* Un hijo flex no encoge por debajo de su contenido salvo que se le
   diga. Sin esto, un nombre largo de propiedad desborda la tarjeta. */
.min-ancho-0 {
    min-width: 0;
}

.romper-palabra {
    overflow-wrap: anywhere;
}

/* Cifras de dinero: tabulares para que las columnas alineen. */
.monto {
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.monto-negativo {
    color: var(--casia-peligro);
}

/* Contenedor estándar de gráficos (ver .claude/rules/estilos.md). */
.chart-container {
    width: 100%;
    min-height: 300px;
}

.chart-sm { height: 250px; }
.chart-md { height: 400px; }
.chart-lg { height: 550px; }

/* ═══ 9. Movimiento reducido e impresión ═══════════════════ */

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

@media print {
    .casia-topbar,
    .casia-menu-envoltura,
    .casia-pie,
    .skip-link,
    .btn,
    .no-imprimir {
        display: none !important;
    }

    .casia-lienzo {
        padding: 0 !important;
        min-height: 0;
    }

    .card,
    .casia-tarjeta {
        border: 1px solid #ccc !important;
        box-shadow: none !important;
        break-inside: avoid;
    }

    body {
        background: #fff !important;
        color: #000;
        font-size: 12pt;
    }
}

/* ═══ 12. Modo demo ════════════════════════════════════════
   Botón DEMO en la barra superior y franja de aviso fija.
   Aditivo: sin esta sección el resto del sitio se ve igual. */

/* ─── Botón DEMO ──────────────────────────────────────────
   Ámbar sobre el verde de la barra: tiene que destacar del
   resto de los controles, porque es lo que se le ofrece a
   quien todavía no sabe usar el sistema. El <form> que lo
   envuelve no debe romper la fila de la barra. */

.casia-demo-form {
    display: flex;
    margin: 0;
}

.casia-btn-demo {
    --bs-btn-color: #1c2523;
    --bs-btn-hover-color: #1c2523;
    --bs-btn-active-color: #1c2523;
    --bs-btn-bg: var(--casia-aviso);
    --bs-btn-hover-bg: #e8a212;
    --bs-btn-active-bg: #c07f05;
    --bs-btn-border-color: transparent;
    --bs-btn-hover-border-color: transparent;
    --bs-btn-active-border-color: transparent;
    display: inline-flex;
    align-items: center;
    gap: .35rem;
    font-weight: 600;
    letter-spacing: .02em;
    white-space: nowrap;
}

/* En el teléfono la barra ya lleva marca, ayuda y hamburguesa:
   el botón se queda en el ícono para que quepa todo. */
.casia-btn-demo__texto {
    display: none;
}

@media (min-width: 576px) {
    .casia-btn-demo__texto {
        display: inline;
    }
}

/* ─── Franja de aviso ─────────────────────────────────────
   Fija bajo la barra superior y en todas las pantallas: quien
   practica tiene que poder comprobar de un vistazo, sin
   desplazarse, que no está tocando sus datos de verdad.

   Alto fijo y una sola línea a propósito. Si creciera con el
   texto, el padding que la compensa dejaría de cuadrar y la
   franja taparía el encabezado de cada pantalla. */

body.is-demo {
    --casia-alto-demo: 2.5rem;
}

.casia-demo-franja {
    position: fixed;
    top: var(--casia-alto-nav);
    left: 0;
    right: 0;
    height: var(--casia-alto-demo, 2.5rem);
    background-color: #fdf0d2;
    border-bottom: 1px solid var(--casia-aviso);
    color: #5c4405;
    z-index: 1035;
}

.casia-demo-franja__interior {
    height: 100%;
    display: flex;
    align-items: center;
    gap: .5rem;
    padding-inline: .75rem;
    overflow: hidden;
}

@media (min-width: 992px) {
    .casia-demo-franja__interior {
        padding-inline: 1.25rem;
    }
}

.casia-demo-franja__icono {
    flex: 0 0 auto;
    color: #a06c04;
}

.casia-demo-franja__texto {
    flex: 1 1 auto;
    margin: 0;
    min-width: 0;
    font-size: .875rem;
    line-height: 1.2;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.casia-demo-franja__form {
    flex: 0 0 auto;
    margin: 0;
}

.casia-btn-salir-demo {
    --bs-btn-color: #5c4405;
    --bs-btn-hover-color: #ffffff;
    --bs-btn-active-color: #ffffff;
    --bs-btn-bg: transparent;
    --bs-btn-hover-bg: #a06c04;
    --bs-btn-active-bg: #7d5503;
    --bs-btn-border-color: var(--casia-aviso);
    --bs-btn-hover-border-color: #a06c04;
    --bs-btn-active-border-color: #7d5503;
    display: inline-flex;
    align-items: center;
    gap: .35rem;
    white-space: nowrap;
}

/* La franja se superpone: hay que hacerle sitio al contenido y
   a la columna del menú, o taparía la primera línea de ambos. */

body.is-demo .casia-lienzo {
    padding-top: calc(var(--casia-alto-nav) + var(--casia-alto-demo));
}

@media (min-width: 992px) {
    body.is-demo .casia-menu-envoltura {
        top: calc(var(--casia-alto-nav) + var(--casia-alto-demo));
    }
}

/* Una franja de pantalla no dice nada en un papel. */
@media print {
    .casia-demo-franja {
        display: none !important;
    }

    body.is-demo .casia-lienzo {
        padding-top: 0 !important;
    }
}

/* ─── Aviso de demo dentro del panel de ayuda ─────────────
   Vive aquí y no en modules/ayuda.css porque depende del modo
   demo, no de la ayuda: quien lo busque lo va a buscar junto
   al resto de la demo. */

.casia-ayuda__demo {
    display: flex;
    align-items: flex-start;
    gap: .5rem;
    margin-bottom: 1rem;
    padding: .625rem .75rem;
    border-left: 3px solid var(--casia-aviso);
    border-radius: .375rem;
    background-color: #fdf0d2;
    color: #5c4405;
    font-size: .875rem;
    line-height: 1.4;
}
