/* =========================================================================
   HABITHEA · Hoja de estilos principal
   -------------------------------------------------------------------------
   Índice:
     01. Tokens de diseño (CSS Variables) y temas claro / oscuro
     02. Reset y base tipográfica
     03. Utilidades y layout
     04. Componentes: botones, chips, badges, alertas
     05. Formularios
     06. Tarjetas, métricas, tablas, listas
     07. Barras de progreso, timeline, feed, chat
     08. Pantalla de autenticación
     09. Shell de aplicación (sidebar + topbar + vista)
     10. Modal y toasts
     11. Responsivo (mobile-first: los breakpoints amplían)
   ========================================================================= */

/* =========================================================================
   01. TOKENS DE DISEÑO
   ========================================================================= */
:root {
  /* --- Marca ----------------------------------------------------------
     La escala sale del verde azulado del logotipo de Habithea (#2F9296) y
     del verde hoja (#9CC069).

     Un detalle que no es capricho: `--brand-500` NO es el color exacto del
     logo, sino uno un punto más oscuro. La razón es de contraste. En esta
     hoja, el 500 se usa para dos cosas a la vez —texto de enlaces sobre
     blanco y relleno de botones con texto blanco encima— y el verde azulado
     del logo sólo alcanza 3.7:1 sobre blanco, por debajo del 4.5:1 que pide
     la norma para texto. El tono elegido da 4.98:1 en los dos sentidos.

     El color exacto del logo vive en `--brand-400`, que es donde se usa sin
     texto encima: degradados, bordes, aros de foco y la propia marca. Así
     la identidad se ve donde se tiene que ver, sin dejar ilegible a quien
     no distingue bien los tonos.                                        */
  --brand-50:  #eef7f7;
  --brand-100: #d3ecec;
  --brand-200: #a9dcdd;
  --brand-300: #74c3c6;
  --brand-400: #2f9296;   /* el verde azulado del logotipo */
  --brand-500: #237b80;
  --brand-600: #1c6268;
  --brand-700: #175055;
  --brand-800: #14434a;
  --brand-900: #113940;

  /* Verde hoja del logotipo. Decorativo: nunca lleva texto encima. */
  --brand-hoja: #9cc069;

  /* --- Semánticos ---------------------------------------------------- */
  --success: #10a37f;
  --success-soft: #e5f6f1;
  --warning: #d98314;
  --warning-soft: #fdf3e3;
  --danger:  #d64545;
  --danger-soft: #fdeceb;
  --info:    #237b80;
  --info-soft: #eaf5f5;

  /* --- Superficies (tema claro) -------------------------------------- */
  --bg:            #f4f8f8;
  --bg-elevated:   #ffffff;
  --surface:       #ffffff;
  --surface-2:     #f7fbfb;
  --surface-3:     #eaf2f2;
  --sidebar-bg:    #ffffff;
  --overlay:       rgba(15, 23, 42, .45);

  /* --- Texto --------------------------------------------------------- */
  --text:        #0f172a;
  --text-muted:  #64748b;
  --text-subtle: #94a3b8;
  --text-invert: #ffffff;

  /* --- Bordes y sombras ---------------------------------------------- */
  --border:        #dfeaea;
  --border-strong: #c3d7d7;
  --ring: 0 0 0 3px rgba(47, 146, 150, .28);

  --shadow-xs: 0 1px 2px rgba(15, 23, 42, .06);
  --shadow-sm: 0 1px 3px rgba(15, 23, 42, .08), 0 1px 2px rgba(15, 23, 42, .04);
  --shadow-md: 0 6px 16px rgba(15, 23, 42, .08);
  --shadow-lg: 0 18px 40px rgba(15, 23, 42, .14);

  /* --- Tipografía ---------------------------------------------------- */
  --font: 'Plus Jakarta Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  --fs-xs:  .75rem;    /* 12 */
  --fs-sm:  .8125rem;  /* 13 */
  --fs-md:  .875rem;   /* 14 */
  --fs-base: .9375rem; /* 15 */
  --fs-lg:  1.0625rem; /* 17 */
  --fs-xl:  1.375rem;  /* 22 */
  --fs-2xl: 1.75rem;   /* 28 */
  --fs-3xl: 2.25rem;   /* 36 */

  /* --- Espaciado y formas -------------------------------------------- */
  --sp-1: .25rem;  --sp-2: .5rem;   --sp-3: .75rem;  --sp-4: 1rem;
  --sp-5: 1.25rem; --sp-6: 1.5rem;  --sp-8: 2rem;    --sp-10: 2.5rem;
  --sp-12: 3rem;

  --r-sm: 8px;
  --r-md: 12px;
  --r-lg: 16px;
  --r-xl: 22px;
  --r-full: 999px;

  --sidebar-w: 268px;
  --topbar-h: 68px;
  --content-max: 1320px;

  --t-fast: 120ms ease;
  --t-base: 200ms cubic-bezier(.4, 0, .2, 1);

  color-scheme: light;
}

/* --- Tema oscuro ----------------------------------------------------- */
[data-theme='dark'] {
  /* En oscuro la escala se invierte: los tonos bajos son fondos y los
     altos, texto. El verde azulado del logo (#2F9296) queda aquí como
     `--brand-300`, porque sobre una superficie oscura ya contrasta de
     sobra y los tonos que llevan texto tienen que ser más claros. */
  --brand-50:  #0d2426;
  --brand-100: #123336;
  --brand-200: #17474b;
  --brand-300: #2f9296;   /* el verde azulado del logotipo */
  --brand-400: #3ea7ab;
  --brand-500: #5cc0c3;
  --brand-600: #82d2d4;
  --brand-700: #a8e0e1;

  --brand-hoja: #9cc069;

  --success: #34d3aa;
  --success-soft: #10312a;
  --warning: #f0ad4e;
  --warning-soft: #362713;
  --danger:  #f87171;
  --danger-soft: #3b1a1a;
  --info:    #5cc0c3;
  --info-soft: #123336;

  --bg:          #0a1416;
  --bg-elevated: #101b1d;
  --surface:     #101b1d;
  --surface-2:   #152325;
  --surface-3:   #1b2b2e;
  --sidebar-bg:  #0d1719;
  --overlay:     rgba(2, 14, 16, .68);

  --text:        #e6efee;
  --text-muted:  #98aeac;
  --text-subtle: #6d8280;
  --text-invert: #0a1416;

  --border:        #223336;
  --border-strong: #324548;
  --ring: 0 0 0 3px rgba(92, 192, 195, .32);

  --shadow-xs: 0 1px 2px rgba(0, 0, 0, .4);
  --shadow-sm: 0 1px 3px rgba(0, 0, 0, .5);
  --shadow-md: 0 8px 20px rgba(0, 0, 0, .5);
  --shadow-lg: 0 20px 44px rgba(0, 0, 0, .6);

  color-scheme: dark;
}

/* =========================================================================
   02. RESET Y BASE
   ========================================================================= */
*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  /* `100vh` en un teléfono cuenta la barra del navegador como si nunca
     estuviera, así que la página mide más que la pantalla y da el salto
     clásico al aparecer y desaparecer esa barra. `dvh` es el alto que hay
     de verdad en cada momento; `vh` queda como respaldo para navegadores
     viejos, que lo leen primero y luego lo pisan. */
  min-height: 100vh;
  min-height: 100dvh;
  font-family: var(--font);
  font-size: var(--fs-base);
  font-weight: 400;
  line-height: 1.55;
  color: var(--text);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
  transition: background-color var(--t-base), color var(--t-base);
}

h1, h2, h3, h4 { margin: 0; font-weight: 700; letter-spacing: -.02em; line-height: 1.25; }
h1 { font-size: var(--fs-xl); }
h2 { font-size: var(--fs-lg); }
h3 { font-size: var(--fs-base); }
p  { margin: 0; }
ul, ol { margin: 0; padding: 0; list-style: none; }
a { color: var(--brand-500); text-decoration: none; }
a:hover { text-decoration: underline; }

button, input, select, textarea { font: inherit; color: inherit; }
button { cursor: pointer; background: none; border: none; }

code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: .9em;
  background: var(--surface-3);
  padding: .1em .4em;
  border-radius: var(--r-sm);
}

:focus-visible { outline: none; box-shadow: var(--ring); border-radius: var(--r-sm); }

[hidden] { display: none !important; }

::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-thumb { background: var(--border-strong); border-radius: var(--r-full); border: 3px solid transparent; background-clip: content-box; }
::-webkit-scrollbar-track { background: transparent; }

/* =========================================================================
   03. UTILIDADES
   ========================================================================= */
.muted   { color: var(--text-muted); }
.subtle  { color: var(--text-subtle); }
.small   { font-size: var(--fs-sm); }
.xsmall  { font-size: var(--fs-xs); }
.strong  { font-weight: 600; }
.center  { text-align: center; }
.right   { text-align: right; }
.truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mono { font-variant-numeric: tabular-nums; }

.row { display: flex; gap: var(--sp-3); align-items: center; }
.row--between { justify-content: space-between; }
.row--end { justify-content: flex-end; }
.row--wrap { flex-wrap: wrap; }
.stack { display: flex; flex-direction: column; gap: var(--sp-4); }
.stack--sm { gap: var(--sp-2); }

.grid { display: grid; gap: var(--sp-4); }
.grid--metrics { grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); }
.grid--cards   { grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); }
.grid--2       { grid-template-columns: 1fr; }
.grid--form    { grid-template-columns: 1fr; }

.spinner {
  width: 20px; height: 20px; display: inline-block;
  border: 2.5px solid var(--border-strong);
  border-top-color: var(--brand-500);
  border-radius: 50%;
  animation: spin .7s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

.boot-screen {
  position: fixed; inset: 0; z-index: 200;
  display: grid; place-items: center;
  background: var(--bg);
}
.boot-screen__box { display: flex; flex-direction: column; align-items: center; gap: var(--sp-3); color: var(--text-muted); }

/* --- Logo ------------------------------------------------------------ */
.logo { display: inline-flex; align-items: center; gap: var(--sp-2); font-weight: 800; letter-spacing: -.03em; }
/* La marca de Habithea —la casa con la hoja— es una imagen, no una letra
   dentro de un cuadro de color. Va siempre sobre BLANCO, y a propósito: el
   verde azulado del logotipo encima de un degradado del mismo verde azulado
   se pierde. El cuadro blanco se lee igual en el tema claro, en el oscuro y
   sobre el panel de bienvenida, que es oscuro en los dos temas. */
.logo__mark {
  display: block;
  width: 34px; height: 34px;
  border-radius: 10px;
  background: #fff;
  padding: 2px;
  object-fit: contain;
  box-shadow: var(--shadow-sm);
}
.logo--lg .logo__mark { width: 46px; height: 46px; border-radius: 14px; padding: 3px; }
.logo--lg .logo__text { font-size: var(--fs-xl); }
.logo--sm .logo__text { font-size: var(--fs-base); }

/* --- Entrada con Google / Microsoft ----------------------------------
   Los botones de proveedor van en blanco con borde, no en el color de la
   marca. Es la convención que Google y Microsoft piden en sus guías, y
   además tiene sentido aquí: el botón primario de la pantalla es "Entrar",
   y dos botones más del mismo color competirían con él sin que se entienda
   cuál es cuál. El logotipo a la izquierda es lo que se reconoce.        */
.proveedores { display: flex; flex-direction: column; gap: var(--sp-3); }
.proveedores__nota { text-align: center; margin-top: calc(var(--sp-1) * -1); }

.btn--proveedor {
  width: 100%;
  justify-content: center;
  gap: var(--sp-3);
  padding: .65rem .9rem;
  background: var(--surface);
  border-color: var(--border-strong);
  color: var(--text);
  font-weight: 600;
}
.btn--proveedor:hover:not(:disabled) { background: var(--surface-2); }
.btn__marca { width: 18px; height: 18px; flex: none; }

/* En tema oscuro los logotipos de color piden fondo claro para leerse
   igual que en las guías de marca de cada proveedor. */
[data-theme='dark'] .btn--proveedor { background: #ffffff; color: #1f2328; border-color: #d0d7de; }
[data-theme='dark'] .btn--proveedor:hover:not(:disabled) { background: #f3f5f7; }

/* Separador con el texto centrado sobre la línea. */
.separador {
  display: flex; align-items: center; gap: var(--sp-3);
  color: var(--text-subtle); font-size: var(--fs-sm);
}
.separador::before, .separador::after {
  content: ''; flex: 1; height: 1px; background: var(--border);
}

/* =========================================================================
   04. BOTONES, CHIPS, BADGES, ALERTAS
   ========================================================================= */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--sp-2);
  padding: .5rem .9rem;
  font-size: var(--fs-md); font-weight: 600;
  border: 1px solid transparent;
  border-radius: var(--r-md);
  transition: background-color var(--t-fast), border-color var(--t-fast), color var(--t-fast), transform var(--t-fast), opacity var(--t-fast);
  white-space: nowrap;
}
.btn:active { transform: translateY(1px); }
.btn:disabled { opacity: .55; cursor: not-allowed; transform: none; }

.btn--primary { background: var(--brand-500); color: #fff; box-shadow: var(--shadow-xs); }
.btn--primary:hover:not(:disabled) { background: var(--brand-600); }
[data-theme='dark'] .btn--primary { color: #08101f; }

.btn--secondary { background: var(--surface); color: var(--text); border-color: var(--border); }
.btn--secondary:hover:not(:disabled) { background: var(--surface-2); border-color: var(--border-strong); }

.btn--ghost { background: transparent; color: var(--text-muted); }
.btn--ghost:hover:not(:disabled) { background: var(--surface-3); color: var(--text); }

.btn--danger { background: var(--danger-soft); color: var(--danger); border-color: transparent; }
.btn--danger:hover:not(:disabled) { background: var(--danger); color: #fff; }

.btn--success { background: var(--success); color: #fff; }
[data-theme='dark'] .btn--success { color: #08101f; }

.btn--sm { padding: .3rem .6rem; font-size: var(--fs-sm); border-radius: var(--r-sm); }
.btn--lg { padding: .7rem 1.2rem; font-size: var(--fs-base); }
.btn--block { width: 100%; }
.btn--icon {
  width: 38px; height: 38px; padding: 0;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: var(--r-md);
  color: var(--text-muted);
  background: transparent;
}
.btn--icon:hover { background: var(--surface-3); color: var(--text); }

.chip {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  padding: .35rem .7rem;
  font-size: var(--fs-sm); font-weight: 600;
  color: var(--text-muted);
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--r-full);
  transition: all var(--t-fast);
}
.chip:hover { border-color: var(--brand-400); color: var(--brand-500); }

.badge {
  display: inline-flex; align-items: center; gap: .35rem;
  padding: .2rem .55rem;
  font-size: var(--fs-xs); font-weight: 700;
  letter-spacing: .01em;
  border-radius: var(--r-full);
  background: var(--surface-3); color: var(--text-muted);
  white-space: nowrap;
}
.badge--success { background: var(--success-soft); color: var(--success); }
.badge--warning { background: var(--warning-soft); color: var(--warning); }
.badge--danger  { background: var(--danger-soft);  color: var(--danger); }
.badge--info    { background: var(--info-soft);    color: var(--info); }
.badge--soft    { background: var(--brand-50); color: var(--brand-500); }

.alert {
  padding: var(--sp-3) var(--sp-4);
  border-radius: var(--r-md);
  font-size: var(--fs-md);
  border: 1px solid transparent;
}
.alert--danger  { background: var(--danger-soft);  color: var(--danger);  border-color: color-mix(in srgb, var(--danger) 25%, transparent); }
.alert--success { background: var(--success-soft); color: var(--success); }
.alert--info    { background: var(--info-soft);    color: var(--info); }
.alert--warning { background: var(--warning-soft); color: var(--warning); }

/* =========================================================================
   05. FORMULARIOS
   ========================================================================= */
.form { display: flex; flex-direction: column; gap: var(--sp-4); }

.field { display: flex; flex-direction: column; gap: var(--sp-2); }
.field__label { font-size: var(--fs-sm); font-weight: 600; color: var(--text-muted); }
.field__hint { font-size: var(--fs-xs); color: var(--text-subtle); }

.field__input, .field__select, .field__textarea {
  width: 100%;
  padding: .62rem .8rem;
  font-size: var(--fs-md);
  color: var(--text);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  transition: border-color var(--t-fast), box-shadow var(--t-fast), background-color var(--t-fast);
}
.field__input::placeholder, .field__textarea::placeholder { color: var(--text-subtle); }
.field__input:hover, .field__select:hover, .field__textarea:hover { border-color: var(--border-strong); }
.field__input:focus, .field__select:focus, .field__textarea:focus {
  outline: none; border-color: var(--brand-400); box-shadow: var(--ring);
}
.field__textarea { min-height: 92px; resize: vertical; }
.field__select { appearance: none; cursor: pointer;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath fill='%2394a3b8' d='M1 1l5 5 5-5'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right .8rem center; padding-right: 2rem;
}
.field__group { display: flex; }
.field__group .field__input { border-top-right-radius: 0; border-bottom-right-radius: 0; }
.field__addon {
  padding: 0 .8rem;
  font-size: var(--fs-sm); font-weight: 600; color: var(--text-muted);
  background: var(--surface-2);
  border: 1px solid var(--border); border-left: none;
  border-radius: 0 var(--r-md) var(--r-md) 0;
}
.field__addon:hover { color: var(--brand-500); }


/* =========================================================================
   06. TARJETAS, MÉTRICAS, TABLAS
   ========================================================================= */
.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-xs);
  overflow: hidden;
}
.card__head {
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3);
  padding: var(--sp-4) var(--sp-5);
  border-bottom: 1px solid var(--border);
  flex-wrap: wrap;
}
.card__title { font-size: var(--fs-base); font-weight: 700; }
.card__subtitle { font-size: var(--fs-sm); color: var(--text-muted); font-weight: 400; }
.card__body { padding: var(--sp-5); }
.card__body--flush { padding: 0; }
.card__foot { padding: var(--sp-3) var(--sp-5); border-top: 1px solid var(--border); background: var(--surface-2); }

.metric {
  position: relative;
  padding: var(--sp-5);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-xs);
  overflow: hidden;
  transition: transform var(--t-fast), box-shadow var(--t-fast);
}
.metric:hover { transform: translateY(-2px); box-shadow: var(--shadow-md); }
.metric::after {
  content: ''; position: absolute; inset: 0 auto 0 0; width: 4px;
  background: var(--brand-500);
}
.metric--success::after { background: var(--success); }
.metric--warning::after { background: var(--warning); }
.metric--danger::after  { background: var(--danger); }
.metric__label { font-size: var(--fs-sm); font-weight: 600; color: var(--text-muted); }
.metric__value { font-size: var(--fs-2xl); font-weight: 800; letter-spacing: -.03em; margin-top: var(--sp-1); font-variant-numeric: tabular-nums; }
.metric__foot { font-size: var(--fs-xs); color: var(--text-subtle); margin-top: var(--sp-1); }

.table-wrap { width: 100%; overflow-x: auto; }
.table { width: 100%; border-collapse: collapse; font-size: var(--fs-md); }
.table th, .table td { padding: .75rem var(--sp-5); text-align: left; white-space: nowrap; }
.table thead th {
  font-size: var(--fs-xs); font-weight: 700; text-transform: uppercase; letter-spacing: .05em;
  color: var(--text-subtle);
  background: var(--surface-2);
  border-bottom: 1px solid var(--border);
  position: sticky; top: 0; z-index: 1;
}
.table tbody tr { border-bottom: 1px solid var(--border); transition: background-color var(--t-fast); }
.table tbody tr:last-child { border-bottom: none; }
.table tbody tr:hover { background: var(--surface-2); }
.table td.wrap { white-space: normal; min-width: 220px; }
.table .actions { display: flex; gap: var(--sp-2); justify-content: flex-end; }

.cell-main { font-weight: 600; }
.cell-sub  { font-size: var(--fs-xs); color: var(--text-muted); }

.avatar {
  display: grid; place-items: center; flex: none;
  width: 36px; height: 36px;
  border-radius: 50%;
  background: var(--brand-50); color: var(--brand-500);
  font-size: var(--fs-sm); font-weight: 700;
}
.avatar--lg { width: 44px; height: 44px; font-size: var(--fs-base); }

.empty { padding: var(--sp-10) var(--sp-5); text-align: center; color: var(--text-muted); }
.empty__icon { font-size: 2rem; opacity: .5; }
.empty__title { font-weight: 700; color: var(--text); margin-top: var(--sp-2); }

.toolbar {
  display: flex; flex-wrap: wrap; gap: var(--sp-3);
  align-items: center; justify-content: space-between;
  margin-bottom: var(--sp-4);
}
.toolbar__filters { display: flex; flex-wrap: wrap; gap: var(--sp-2); align-items: center; }
.search { position: relative; flex: 1 1 200px; min-width: 180px; }
.search .field__input { padding-left: 2.1rem; }
.search::before { content: '⌕'; position: absolute; left: .75rem; top: 50%; transform: translateY(-50%); color: var(--text-subtle); font-size: 1.1rem; }

/* =========================================================================
   07. PROGRESO, FEED, CHAT
   ========================================================================= */
.progress { height: 8px; background: var(--surface-3); border-radius: var(--r-full); overflow: hidden; }
.progress__bar { height: 100%; border-radius: var(--r-full); background: linear-gradient(90deg, var(--brand-400), var(--brand-600)); transition: width .5s var(--t-base); }
.progress--success .progress__bar { background: linear-gradient(90deg, var(--success), var(--success)); }
.progress--warning .progress__bar { background: linear-gradient(90deg, var(--warning), var(--warning)); }

.project-card { display: flex; flex-direction: column; gap: var(--sp-3); padding: var(--sp-5); }
.project-card__pct { font-size: var(--fs-xl); font-weight: 800; letter-spacing: -.03em; font-variant-numeric: tabular-nums; }

.notice { display: flex; gap: var(--sp-4); padding: var(--sp-5); border-bottom: 1px solid var(--border); }
.notice:last-child { border-bottom: none; }
.notice__bar { width: 4px; border-radius: var(--r-full); background: var(--info); flex: none; }
.notice__bar--warning { background: var(--warning); }
.notice__bar--danger  { background: var(--danger); }
.notice__body { flex: 1; min-width: 0; }
.notice__title { font-weight: 700; }
.notice__text { color: var(--text-muted); font-size: var(--fs-md); margin-top: var(--sp-1); white-space: pre-wrap; }
.notice__meta { display: flex; flex-wrap: wrap; gap: var(--sp-3); font-size: var(--fs-xs); color: var(--text-subtle); margin-top: var(--sp-2); }

.thread { display: flex; flex-direction: column; gap: var(--sp-3); max-height: 46vh; overflow-y: auto; padding: var(--sp-5); }
.bubble { max-width: 78%; padding: .6rem .85rem; border-radius: var(--r-lg); font-size: var(--fs-md); }
.bubble__meta { font-size: var(--fs-xs); opacity: .75; margin-top: .2rem; }
.bubble--out { align-self: flex-end; background: var(--brand-500); color: #fff; border-bottom-right-radius: var(--r-sm); }
[data-theme='dark'] .bubble--out { color: #08101f; }

.contact-list { display: flex; flex-direction: column; }
.contact {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-5);
  border-bottom: 1px solid var(--border);
  cursor: pointer; text-align: left; width: 100%;
  transition: background-color var(--t-fast);
}
.contact:hover { background: var(--surface-2); }
.contact--active { background: var(--brand-50); }
[data-theme='dark'] .contact--active { background: var(--surface-3); }

.kv { display: grid; grid-template-columns: minmax(120px, 40%) 1fr; gap: var(--sp-2) var(--sp-4); font-size: var(--fs-md); }
.kv dt { color: var(--text-muted); }
.kv dd { margin: 0; font-weight: 600; }

/* =========================================================================
   08. AUTENTICACIÓN
   ========================================================================= */
.auth { display: grid; grid-template-columns: 1fr; min-height: 100vh; min-height: 100dvh; }

.auth__brand {
  display: none;
  padding: var(--sp-12);
  color: #fff;
  /* Colores fijos: el panel de marca conserva su identidad en ambos temas. */
  background:
    radial-gradient(1000px 500px at 10% 10%, rgba(255,255,255,.16), transparent 60%),
    linear-gradient(150deg, #2f9296, #175055 55%, #0d2a2e);
  position: relative; overflow: hidden;
}
.auth__brand::after {
  content: ''; position: absolute; right: -120px; bottom: -140px;
  width: 420px; height: 420px; border-radius: 50%;
  background: rgba(255,255,255,.06);
}
.auth__brand-inner { position: relative; z-index: 1; max-width: 460px; margin: auto 0; display: flex; flex-direction: column; gap: var(--sp-5); }
.auth__brand .logo__mark { background: #fff; }
.auth__brand-title { font-size: var(--fs-3xl); font-weight: 800; line-height: 1.15; }
.auth__brand-copy { color: rgba(255,255,255,.8); font-size: var(--fs-lg); }
.auth__brand-list { display: flex; flex-direction: column; gap: var(--sp-2); color: rgba(255,255,255,.85); font-size: var(--fs-md); }
.auth__brand-list li { display: flex; gap: var(--sp-2); align-items: center; }
.auth__brand-list li::before { content: '✓'; display: grid; place-items: center; width: 20px; height: 20px; border-radius: 50%; background: rgba(255,255,255,.16); font-size: var(--fs-xs); flex: none; }

.auth__panel { display: grid; place-items: center; padding: var(--sp-6); background: var(--bg); }
.auth__panel-inner { width: 100%; max-width: 400px; display: flex; flex-direction: column; gap: var(--sp-6); }
.auth__logo-mobile { align-self: flex-start; margin-bottom: var(--sp-4); }
.auth__header { display: flex; flex-direction: column; gap: var(--sp-1); }
.auth__title { font-size: var(--fs-2xl); }
.auth__subtitle { color: var(--text-muted); font-size: var(--fs-md); }

.auth__demo {
  padding: var(--sp-4);
  background: var(--surface);
  border: 1px dashed var(--border-strong);
  border-radius: var(--r-lg);
  display: flex; flex-direction: column; gap: var(--sp-3);
}
.auth__demo-title { font-size: var(--fs-sm); font-weight: 700; color: var(--text-muted); }
.auth__demo-grid { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.auth__demo-hint { font-size: var(--fs-xs); color: var(--text-subtle); }
.auth__footer { display: flex; align-items: center; justify-content: space-between; }

/* =========================================================================
   09. SHELL DE APLICACIÓN
   ========================================================================= */
.shell { display: flex; min-height: 100vh; min-height: 100dvh; }

.sidebar {
  position: fixed; inset: 0 auto 0 0; z-index: 60;
  width: var(--sidebar-w);
  display: flex; flex-direction: column;
  background: var(--sidebar-bg);
  border-right: 1px solid var(--border);
  transform: translateX(-100%);
  transition: transform var(--t-base);
}
.sidebar--open { transform: translateX(0); box-shadow: var(--shadow-lg); }
.sidebar__head { display: flex; align-items: center; justify-content: space-between; height: var(--topbar-h); padding: 0 var(--sp-5); border-bottom: 1px solid var(--border); flex: none; }
.sidebar__context { padding: var(--sp-4) var(--sp-4) 0; }
.sidebar__foot { margin-top: auto; padding: var(--sp-4); border-top: 1px solid var(--border); display: flex; flex-direction: column; gap: var(--sp-3); }
.sidebar__backdrop { position: fixed; inset: 0; z-index: 55; background: var(--overlay); }

.user-card { display: flex; align-items: center; gap: var(--sp-3); min-width: 0; }
.user-card__name { font-weight: 700; font-size: var(--fs-md); }
.user-card__mail { font-size: var(--fs-xs); color: var(--text-muted); }

.nav { flex: 1; overflow-y: auto; padding: var(--sp-4); display: flex; flex-direction: column; gap: var(--sp-1); }
.nav__section { padding: var(--sp-4) var(--sp-3) var(--sp-2); font-size: var(--fs-xs); font-weight: 700; text-transform: uppercase; letter-spacing: .07em; color: var(--text-subtle); }
.nav__item {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: .58rem var(--sp-3);
  border-radius: var(--r-md);
  font-size: var(--fs-md); font-weight: 600; color: var(--text-muted);
  text-align: left; width: 100%;
  transition: background-color var(--t-fast), color var(--t-fast);
}
.nav__item:hover { background: var(--surface-3); color: var(--text); }
.nav__item--active { background: var(--brand-50); color: var(--brand-500); }
[data-theme='dark'] .nav__item--active { background: var(--surface-3); color: var(--brand-500); }
.nav__icon {
  width: 20px; height: 20px; flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  text-align: center; font-size: 1rem;
  color: var(--text-subtle);
}
.nav a.is-active .nav__icon, .nav button.is-active .nav__icon { color: currentColor; }
.nav__count { margin-left: auto; font-size: var(--fs-xs); font-weight: 700; padding: .05rem .4rem; border-radius: var(--r-full); background: var(--danger-soft); color: var(--danger); }

.content { flex: 1; min-width: 0; display: flex; flex-direction: column; }

.topbar {
  position: sticky; top: 0; z-index: 40;
  display: flex; align-items: center; gap: var(--sp-3);
  /* El notch y la isla dinámica se comen la franja de arriba. Se aparta con
     relleno en lugar de con margen para que el fondo difuminado siga
     llegando hasta el borde de la pantalla: si no, queda una banda de otro
     color bajo el reloj. `env()` vale 0 en cualquier pantalla sin recorte,
     así que en escritorio y en Android no cambia nada. */
  height: calc(var(--topbar-h) + env(safe-area-inset-top));
  padding: env(safe-area-inset-top) calc(var(--sp-4) + env(safe-area-inset-right)) 0 calc(var(--sp-4) + env(safe-area-inset-left));
  background: color-mix(in srgb, var(--bg) 85%, transparent);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--border);
}
.topbar__titles { min-width: 0; flex: 1; overflow: hidden; }
.topbar__title { font-size: var(--fs-base); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.topbar__subtitle { display: none; font-size: var(--fs-xs); color: var(--text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.topbar__actions { display: flex; align-items: center; gap: var(--sp-2); }

.view {
  flex: 1; width: 100%; max-width: var(--content-max); margin: 0 auto;
  /* Abajo, el indicador de inicio del iPhone tapa lo último de la lista. */
  padding: var(--sp-5)
           calc(var(--sp-4) + env(safe-area-inset-right))
           calc(var(--sp-10) + env(safe-area-inset-bottom))
           calc(var(--sp-4) + env(safe-area-inset-left));
  display: flex; flex-direction: column; gap: var(--sp-5);
}
.view:focus { outline: none; }
.view__section { display: flex; flex-direction: column; gap: var(--sp-4); }
.view__section-head { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3); flex-wrap: wrap; }

.content__footer { display: flex; justify-content: space-between; gap: var(--sp-3); padding: var(--sp-4); border-top: 1px solid var(--border); flex-wrap: wrap; }

/* Banner de contexto (condominio activo) */
.context-pill {
  display: flex; align-items: center; gap: var(--sp-2);
  width: 100%; padding: var(--sp-2) var(--sp-3);
  background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--r-md);
  font-size: var(--fs-sm); font-weight: 600; color: var(--text-muted);
}

/* =========================================================================
   10. MODAL Y TOASTS
   ========================================================================= */
.modal { position: fixed; inset: 0; z-index: 100; display: grid; place-items: center; padding: var(--sp-4); }
.modal__backdrop { position: absolute; inset: 0; background: var(--overlay); animation: fade .18s ease; }
.modal__dialog {
  position: relative; z-index: 1;
  width: min(640px, 100%); max-height: 88vh;
  display: flex; flex-direction: column;
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: var(--r-xl);
  box-shadow: var(--shadow-lg);
  animation: pop .2s var(--t-base);
}
.modal__head { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3); padding: var(--sp-5); border-bottom: 1px solid var(--border); }
.modal__title { font-size: var(--fs-lg); }
.modal__body { padding: var(--sp-5); overflow-y: auto; }
.modal__foot { display: flex; justify-content: flex-end; gap: var(--sp-3); padding: var(--sp-4) var(--sp-5); border-top: 1px solid var(--border); background: var(--surface-2); border-radius: 0 0 var(--r-xl) var(--r-xl); }
.modal--wide .modal__dialog { width: min(860px, 100%); }

@keyframes fade { from { opacity: 0; } }
@keyframes pop { from { opacity: 0; transform: translateY(12px) scale(.98); } }

.toasts { position: fixed; z-index: 150; right: var(--sp-4); bottom: var(--sp-4); display: flex; flex-direction: column; gap: var(--sp-2); max-width: min(360px, calc(100vw - 2rem)); }
.toast {
  display: flex; gap: var(--sp-3); align-items: flex-start;
  padding: var(--sp-3) var(--sp-4);
  background: var(--bg-elevated); border: 1px solid var(--border); border-left: 4px solid var(--brand-500);
  border-radius: var(--r-md); box-shadow: var(--shadow-md);
  font-size: var(--fs-md);
  animation: slide-in .22s var(--t-base);
}
.toast--success { border-left-color: var(--success); }
.toast--error   { border-left-color: var(--danger); }
.toast--warning { border-left-color: var(--warning); }
.toast--out { animation: slide-out .2s ease forwards; }
@keyframes slide-in { from { opacity: 0; transform: translateX(24px); } }
@keyframes slide-out { to { opacity: 0; transform: translateX(24px); } }

/* Pasarela de pago simulada */
.pay-summary { padding: var(--sp-4); background: var(--surface-2); border-radius: var(--r-md); display: flex; justify-content: space-between; align-items: center; }
.pay-total { font-size: var(--fs-xl); font-weight: 800; letter-spacing: -.03em; }
.pay-methods { display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: var(--sp-2); }
.pay-method {
  padding: var(--sp-3); text-align: center;
  border: 1px solid var(--border); border-radius: var(--r-md);
  background: var(--surface); font-size: var(--fs-sm); font-weight: 600; color: var(--text-muted);
  transition: all var(--t-fast);
}
.pay-method:hover { border-color: var(--brand-400); }
.pay-method--active { border-color: var(--brand-500); background: var(--brand-50); color: var(--brand-500); }
[data-theme='dark'] .pay-method--active { background: var(--surface-3); }

/* =========================================================================
   11. RESPONSIVO (mobile-first)
   =========================================================================

   11.a · TABLAS EN EL TELÉFONO
   -------------------------------------------------------------------------
   Una tabla de seis columnas no cabe en 390 px. Se resolvía con scroll
   horizontal, y eso no es un problema de estilo sino de información: nadie
   adivina que a la derecha hay un monto y un botón para pagar. Una columna
   escondida detrás de un gesto invisible es una columna que no existe.

   Debajo de 720 px la tabla deja de comportarse como tabla: cada fila se
   apila como ficha, con el nombre del campo delante de su valor. No queda
   nada oculto y no hay nada que deslizar. Los marcadores (`data-label`,
   `data-principal`, `data-control`) los pone `UI.table` en ui.js.
   ========================================================================= */
@media (max-width: 719px) {
  /* Sin scroll: ya no hay nada fuera de la pantalla. */
  .table-wrap { overflow-x: visible; }

  .table, .table tbody, .table tr, .table td { display: block; width: auto; }
  .table thead { display: none; }

  .table tbody tr {
    display: flex;
    flex-direction: column;
    gap: var(--sp-2);
    padding: var(--sp-4) var(--sp-5);
    border-bottom: 1px solid var(--border);
  }
  .table tbody tr:last-child { border-bottom: 0; }

  .table td {
    display: flex;
    align-items: baseline;
    gap: var(--sp-3);
    padding: 0;
    /* El `nowrap` de escritorio es lo que cortaba «07 sep 20…». */
    white-space: normal;
    text-align: left;
  }

  /* El nombre del campo, delante del valor. */
  .table td::before {
    content: attr(data-label);
    flex: 0 0 7rem;
    font-size: var(--fs-xs);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .05em;
    color: var(--text-subtle);
  }

  /* La primera columna con nombre encabeza la ficha: sin etiqueta y con el
     peso de un título, para que se lea como el nombre de la cosa. */
  .table td[data-principal] { display: block; font-weight: 700; font-size: var(--fs-base); }
  .table td[data-principal]::before { content: none; }

  /* Casillas y botones: al final, que es donde se espera una acción, y a lo
     ancho, que es lo que se puede tocar con el pulgar. */
  .table td[data-control] { order: 2; }
  .table td[data-control] .btn { width: 100%; justify-content: center; }
  /* Una casilla suelta necesita saber qué selecciona; un botón se explica
     solo. Por eso la etiqueta se oculta por vacía, no por ser un control. */
  .table td[data-label='']::before { content: none; }
  .table td[data-label=''] { display: block; }
  /* La casilla, más grande que la de escritorio: se toca con el dedo. */
  .table td[data-control] input[type='checkbox'] { width: 1.25rem; height: 1.25rem; }

  /* `right` alinea columnas de dinero en la tabla; en una ficha de dos
     columnas empujaría el valor lejos de su etiqueta. */
  .table td.right { text-align: left; }

  .table .cell-main { font-weight: 600; }
  .table .cell-sub { font-size: var(--fs-xs); color: var(--text-subtle); }
}

/* -------------------------------------------------------------------------
   11.b · Y SI AUN ASÍ ALGO SE DESPLAZA, QUE SE VEA
   -------------------------------------------------------------------------
   De 720 px en adelante una tabla ancha todavía puede desbordar, y ahí sigue
   valiendo la misma regla: si hay contenido fuera de la vista, tiene que
   notarse. La sombra del borde lo dice.

   Se pinta con fondos, no con un pseudo-elemento, y la razón es que el
   pseudo-elemento se desplazaría junto a la tabla en vez de quedarse pegado
   al borde: `.table-wrap` es el propio contenedor con scroll. En cambio, un
   par de degradados con `background-attachment: scroll` quedan clavados al
   marco, y otro par con `attachment: local` viaja con el contenido y los
   tapa justo al llegar a cada extremo. Resultado: la sombra aparece sólo
   del lado donde de verdad queda algo por ver, sin una línea de JavaScript.
   ------------------------------------------------------------------------- */
@media (min-width: 720px) {
  .table-wrap {
    background:
      /* tapas que viajan con el contenido */
      linear-gradient(to right, var(--surface) 40%, transparent) 0 0 / 2.5rem 100% no-repeat local,
      linear-gradient(to left,  var(--surface) 40%, transparent) 100% 0 / 2.5rem 100% no-repeat local,
      /* sombras ancladas al marco */
      radial-gradient(farthest-side at 0 50%, rgba(15, 23, 42, .16), transparent) 0 0 / 1.25rem 100% no-repeat scroll,
      radial-gradient(farthest-side at 100% 50%, rgba(15, 23, 42, .16), transparent) 100% 0 / 1.25rem 100% no-repeat scroll;
  }
  [data-theme='dark'] .table-wrap {
    background:
      linear-gradient(to right, var(--surface) 40%, transparent) 0 0 / 2.5rem 100% no-repeat local,
      linear-gradient(to left,  var(--surface) 40%, transparent) 100% 0 / 2.5rem 100% no-repeat local,
      radial-gradient(farthest-side at 0 50%, rgba(0, 0, 0, .5), transparent) 0 0 / 1.25rem 100% no-repeat scroll,
      radial-gradient(farthest-side at 100% 50%, rgba(0, 0, 0, .5), transparent) 100% 0 / 1.25rem 100% no-repeat scroll;
  }
}

/* -------------------------------------------------------------------------
   11.b-bis · ZONAS TÁCTILES
   -------------------------------------------------------------------------
   Se consulta `pointer: coarse` y no el ancho: lo que decide el tamaño
   mínimo de un botón no es una pantalla estrecha sino un dedo. Una tableta
   grande también se toca, y una ventana de escritorio angosta no.

   44 px es la medida que pide Apple y que Google redondea a 48; por debajo
   de eso el índice tapa el objetivo y se falla el toque. Sale de la anchura
   real del pulpejo de un dedo, no de una convención de diseño.
   ------------------------------------------------------------------------- */
@media (pointer: coarse) {
  .btn--icon { width: 44px; height: 44px; }
  .nav__item { min-height: 44px; }
  .field__input, .field__select { min-height: 44px; }
  /* Los navegadores de iOS hacen zoom al enfocar un campo de menos de 16 px.
     No es un capricho de estilo: al ampliar, la página se descoloca y hay
     que volver a encuadrar a mano después de cada campo. */
  .field__input, .field__select, .field__textarea, textarea { font-size: 16px; }
}

/* -------------------------------------------------------------------------
   11.c · MÉTRICAS QUE NO SE COMAN LA PANTALLA
   -------------------------------------------------------------------------
   `minmax(210px, 1fr)` da una sola columna en un teléfono, y con el relleno
   y el cuerpo de escritorio cada tarjeta medía 250 px: tres seguidas eran
   750 px, más que la pantalla entera, antes de que apareciera un solo aviso
   o una sola cuota. Las métricas son contexto, no el contenido; en dos
   columnas compactas caben las tres en el primer golpe de vista y dejan
   sitio a lo que el residente vino a ver.
   ------------------------------------------------------------------------- */
@media (max-width: 639px) {
  /* El título corto en lugar del largo: cabe entero y por eso se entiende.
     Se cambia con `content` y no con JavaScript para que ambos convivan en
     el mismo elemento y el cambio ocurra al girar el teléfono, sin
     re-renderizar la vista. */
  .topbar__title { font-size: 0; }
  .topbar__title::before {
    content: attr(data-corto);
    font-size: var(--fs-base);
    font-weight: 700;
    letter-spacing: -.02em;
  }

  .grid--metrics { grid-template-columns: 1fr 1fr; gap: var(--sp-3); }
  .metric { padding: var(--sp-4); }
  .metric__value { font-size: var(--fs-xl); }
  .metric__label { font-size: var(--fs-xs); line-height: 1.3; }
  .metric__foot { font-size: 11px; }

  /* Una métrica sola no se parte por la mitad: ocupa el ancho. */
  .grid--metrics > .metric:only-child { grid-column: 1 / -1; }
  /* Con tres, la última cierra la fila a lo ancho en vez de dejar un hueco. */
  .grid--metrics > .metric:nth-child(3):nth-last-child(1) { grid-column: 1 / -1; }

  .view { padding: var(--sp-4) var(--sp-4) var(--sp-10); gap: var(--sp-4); }
  .card__head { padding: var(--sp-4) var(--sp-5); }
  .card__body { padding: var(--sp-5); }
}

@media (min-width: 640px) {
  .grid--form { grid-template-columns: 1fr 1fr; }
  .grid--form .span-2 { grid-column: 1 / -1; }
  .view { padding: var(--sp-6) var(--sp-6) var(--sp-12); }
  .topbar { padding: 0 var(--sp-6); }
  .topbar__title { font-size: var(--fs-lg); }
  .topbar__subtitle { display: block; }
  .content__footer { padding: var(--sp-4) var(--sp-6); }
}

@media (min-width: 900px) {
  .auth { grid-template-columns: 1.05fr 1fr; }
  .auth__brand { display: flex; }
  .auth__logo-mobile { display: none; }
  .grid--2 { grid-template-columns: 1fr 1fr; }
}

@media (min-width: 1024px) {
  .sidebar { transform: none; box-shadow: none; }
  .sidebar__close, .topbar__burger { display: none; }
  .sidebar__backdrop { display: none !important; }
  .content { margin-left: var(--sidebar-w); }
  :root { --topbar-h: 72px; }
}

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

/* =========================================================================
   EL REPORTE MENSUAL EN PANTALLA
   ========================================================================= */
.reporte__head { padding-bottom: .75rem; border-bottom: 1px solid var(--border); }
.reporte__eyebrow {
  margin: 0 0 .15rem; font-size: .78rem; letter-spacing: .09em;
  text-transform: uppercase; color: var(--muted);
}
.reporte__titulo { margin: 0 0 .3rem; font-size: 1.35rem; line-height: 1.2; }
.reporte__pie { margin-top: .5rem; }

/* =========================================================================
   IMPRESIÓN · «Guardar como PDF» del navegador
   -------------------------------------------------------------------------
   El reporte del mes se entrega en PDF, y el PDF lo hace el propio
   navegador desde su diálogo de impresión. Traer una librería para generarlo
   habría costado unos 300 KB en cada carga de la aplicación —para todos los
   vecinos, todos los días, por una pantalla que se abre una vez al mes— y
   habría obligado a abrir la política de seguridad a otro dominio.

   Lo que hace falta a cambio son estas reglas. `.imprimiendo` la pone el
   JavaScript en el `body` justo antes de abrir el diálogo, y `.para-imprimir`
   marca el único bloque que debe salir en el papel.
   ========================================================================= */
@media print {
  .sidebar, .topbar, .toasts, .content__footer,
  .toolbar, .modal, .boot-screen { display: none !important; }
  .content { margin-left: 0; }

  /* Papel blanco y tinta negra pase lo que pase: el tema oscuro imprimiría
     páginas enteras en negro, que además de ilegible se lleva el tóner. */
  html, body {
    background: #fff !important;
    color: #111 !important;
  }

  /* Con `.imprimiendo`, todo se esconde salvo el bloque marcado y sus
     ancestros. Es la forma de imprimir UNA tarjeta de la pantalla sin
     arrastrar el resto de la vista.

     ESTO DECÍA `.view > *:not(.para-imprimir)`, y por eso el PDF salía EN
     BLANCO. La regla daba por hecho que el bloque a imprimir era hijo
     DIRECTO de `.view`, y no lo es: las vistas envuelven su contenido en un
     `.stack`. Ese envoltorio era el único hijo directo, no llevaba la
     marca, se escondía — y se llevaba dentro justo el bloque que se quería
     imprimir. El navegador hacía exactamente lo que se le pedía.

     Ahora el JavaScript marca con `.imprimir-ancestro` toda la cadena desde
     el bloque hasta `.view`, y aquí se esconden, en CADA nivel, sólo los
     HERMANOS de ese camino. Deja de importar a qué profundidad cuelgue el
     contenido, que era la suposición frágil de la versión anterior. */
  body.imprimiendo .imprimir-ancestro > *:not(.imprimir-ancestro):not(.para-imprimir) {
    display: none !important;
  }

  .card, .reporte {
    box-shadow: none !important;
    border-color: #ccc !important;
    background: #fff !important;
    page-break-inside: auto;
  }
  .card__head { border-bottom: 1px solid #ccc; }

  /* Una fila partida entre dos hojas es la forma más fácil de que alguien
     lea mal una cifra. */
  table { page-break-inside: auto; }
  tr, .metric { page-break-inside: avoid; }
  thead { display: table-header-group; }   /* encabezado en cada página */

  .badge {
    border: 1px solid #999 !important;
    background: transparent !important;
    color: #111 !important;
  }
  .grid--metrics { display: grid !important; grid-template-columns: repeat(4, 1fr) !important; }
  .metric { border: 1px solid #ddd !important; background: #fff !important; }

  a[href]::after { content: ''; }          /* sin URLs pegadas al texto */

  /* «Ver comprobante ↗» en una hoja de papel no lleva a ningún sitio: es
     tinta gastada en algo que no se puede pulsar. En pantalla sí sirve. */
  .no-imprimir { display: none !important; }

  @page { margin: 14mm 12mm; }
}

/* =========================================================================
   MODAL OBLIGATORIO
   -------------------------------------------------------------------------
   Cuando el condominio declara una pregunta como obligatoria, el cuadro no
   se cierra sin contestar. `Modal.close()` ya lo impide —es el único camino
   de las tres formas de cerrar—, pero dejar la equis a la vista sería
   ofrecer una salida que no funciona: el vecino la pulsa, no pasa nada, y
   concluye que la aplicación está rota. Si no hay salida, que no se vea.
   ========================================================================= */
.modal--obligatorio [data-modal-close] { display: none !important; }
.modal--obligatorio .modal__backdrop { cursor: default; }

/* =========================================================================
   CALENDARIO · la cuadrícula del mes
   -------------------------------------------------------------------------
   Las celdas enseñan QUÉ pasa, no un punto de color. La primera versión
   sólo pintaba puntos: decían que algo ocurría ese día y no decían qué, con
   lo que había que bajar a la lista para enterarse — y entonces la rejilla
   no servía para nada.

   En pantallas estrechas no cabe el texto, así que ahí se esconden los
   títulos y vuelven los puntos. No es una degradación: en un teléfono la
   vista útil es la agenda, y el mes se consulta para ubicarse.
   ========================================================================= */
.cal__cabecera,
.cal__rejilla {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 4px;
}
.cal__dia {
  text-align: center;
  font-size: var(--fs-xs);
  color: var(--text-subtle);
  padding-bottom: .35rem;
}
.cal__celda {
  min-height: 84px;
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 4px;
  display: flex;
  flex-direction: column;
  gap: 3px;
  min-width: 0;
  overflow: hidden;
}
.cal__celda--vacia { border-color: transparent; }
.cal__celda--con { cursor: pointer; }
.cal__celda--con:hover { border-color: var(--brand-400); }
.cal__celda--hoy {
  border-color: var(--brand-500);
  box-shadow: inset 0 0 0 1px var(--brand-500);
}
/* El día abierto se marca con relleno, no sólo con borde: con el borde
   solo no se distingue del de hoy, y son dos cosas distintas. */
.cal__celda--sel { background: var(--brand-50); border-color: var(--brand-500); }

.cal__num { font-size: var(--fs-xs); color: var(--text-subtle); }
.cal__celda--hoy .cal__num { color: var(--brand-500); font-weight: 600; }

.cal__evs { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.cal__ev {
  display: flex;
  align-items: center;
  gap: 3px;
  font-size: 11px;
  line-height: 1.25;
  padding: 1px 4px;
  border-radius: 4px;
  background: var(--brand-50);
  color: var(--text);
  min-width: 0;
}
.cal__ev-icono { flex: none; font-size: 10px; }
/* El título se corta con puntos suspensivos en vez de desbordar: una celda
   que crece rompe la cuadrícula entera y descoloca el mes. */
.cal__ev-txt { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cal__ev--info    { background: var(--info-soft); }
.cal__ev--success { background: var(--success-soft); }
.cal__ev--warning { background: var(--warning-soft); }
.cal__ev--danger  { background: var(--danger-soft); }
.cal__mas { font-size: 10px; color: var(--text-subtle); padding-left: 4px; }

/* Los puntos son el respaldo de pantalla estrecha: ocultos cuando hay sitio
   para los títulos. */
.cal__puntos { display: none; flex-wrap: wrap; gap: 2px; margin-top: auto; }
.cal__punto { width: 6px; height: 6px; border-radius: 50%; background: var(--text-subtle); }
.cal__punto--info    { background: var(--info); }
.cal__punto--success { background: var(--success); }
.cal__punto--warning { background: var(--warning); }
.cal__punto--danger  { background: var(--danger); }
.cal__punto--soft    { background: var(--brand-500); }

@media (max-width: 720px) {
  .cal__celda { min-height: 44px; }
  .cal__evs { display: none; }
  .cal__puntos { display: flex; }
}
