/* ==========================================================================
   AL INMOBILIARIA — sistema de diseño v2 «Umbral», portado a CSS vanilla
   ==========================================================================

   Origen: /Página web (src/app/globals.css + atelier.css + motion.css) y
   docs/DIRECCION_ARTE.md. Allí el sistema vivía sobre Tailwind 4 con
   `@theme` y `@utility`; aquí no hay compilador, así que los valores se
   extraen y se reescriben como CSS a mano con custom properties.

   Cero dependencias (ADR-001). Cero `<style>` y cero `onclick` inline
   (ADR-004: la CSP no lleva `unsafe-inline` en `script-src`).

   VOCABULARIO — leído de la imagen de marca del cliente, no inventado:
     · panel rectangular con moldura dorada de esquinas a inglete
     · luz de cornisa (`cove`): la luz entra SIEMPRE por arriba
     · apliques (`sconces`): dos halos radiales simétricos
     · mármol gris CÁLIDO en las escenas claras
     · canto dorado a fuego (`--gilt`): el oro es gradiente, no color
     · el oro es el metal de la MARCA; el bronce, el del MOBILIARIO y la sombra
   Prohibido: arcos como forma rectora, viñetas grises sobre teal, #FFF puro
   en superficies grandes, fotos verticales recortadas contra su formato.

   CONTRASTE — calculado con la fórmula de luminancia relativa de WCAG 2.1
   (script en el informe de la tarea), nunca estimado a ojo. Los ratios que
   gobiernan el sistema están anotados junto a cada token semántico.
   ========================================================================== */

/* ==========================================================================
   0. TIPOGRAFÍA AUTOHOSPEDADA — cero CDN, cero Google Fonts
   Las tres familias ya viven en /public/fonts. Añadir Google Fonts metería
   una dependencia de red que la app hoy no tiene.
     · AL Display = TeX Gyre Pagella      (revival del Palatino de Zapf)
     · AL Text    = TeX Gyre Heros        (revival de Helvetica)
     · AL Mono    = Latin Modern Mono     (el Computer Modern de Knuth)
   Todas GUST Font License. Archivos originales sin modificar.
   ========================================================================== */
@font-face { font-family: "AL Display"; src: url("/fonts/texgyrepagella-regular.otf") format("opentype"); font-weight: 400; font-style: normal; font-display: swap; }
@font-face { font-family: "AL Display"; src: url("/fonts/texgyrepagella-bold.otf") format("opentype"); font-weight: 700; font-style: normal; font-display: swap; }
@font-face { font-family: "AL Display"; src: url("/fonts/texgyrepagella-italic.otf") format("opentype"); font-weight: 400; font-style: italic; font-display: swap; }
@font-face { font-family: "AL Display"; src: url("/fonts/texgyrepagella-bolditalic.otf") format("opentype"); font-weight: 700; font-style: italic; font-display: swap; }
@font-face { font-family: "AL Text"; src: url("/fonts/texgyreheros-regular.otf") format("opentype"); font-weight: 400; font-style: normal; font-display: swap; }
@font-face { font-family: "AL Text"; src: url("/fonts/texgyreheros-bold.otf") format("opentype"); font-weight: 700; font-style: normal; font-display: swap; }
@font-face { font-family: "AL Text"; src: url("/fonts/texgyreheros-italic.otf") format("opentype"); font-weight: 400; font-style: italic; font-display: swap; }
@font-face { font-family: "AL Mono"; src: url("/fonts/lmmono10-regular.otf") format("opentype"); font-weight: 400; font-style: normal; font-display: swap; }
@font-face { font-family: "AL Mono"; src: url("/fonts/lmmonolt10-regular.otf") format("opentype"); font-weight: 300; font-style: normal; font-display: swap; }

/* ==========================================================================
   1. TOKENS
   ========================================================================== */

:root {
  /* ---- Paleta v2 (muestreada de la imagen de marca del cliente) -------- */
  --void: #000000;              /* solo el vacío entre escenas */
  --ink: #04100f;               /* negro con subtono teal (recepción) */
  --ink-2: #071718;             /* tinta un grado más clara (no confundir con
                                   --ink-soft, que es un token SEMÁNTICO de
                                   tema y se redefine en .on-dark/.on-light) */

  --teal-900: #0a2726;
  --teal-800: #12403f;          /* PRIMARIO — tarjeta de presentación */
  --teal-700: #1b4b4c;          /* pared de recepción */
  --teal-600: #24605f;
  --teal-500: #2e7573;          /* solo acentos, nunca fondos grandes */

  /* El ORO es el metal de la MARCA: letras, filetes, cantos. */
  --gold-700: #6d582d;
  --gold-600: #a8873c;
  --gold-500: #cbab51;          /* núcleo */
  --gold-400: #e0c368;
  --gold-300: #fde261;          /* brillo especular */

  /* El BRONCE es el metal del MOBILIARIO y la SOMBRA: fondos, bordes en
     reposo, texto secundario sobre claro. Es MARRÓN, no oro amarillo.
     Confundirlos aplana todo — fue el error de la v1 de la web. */
  --bronze-900: #3a2c1c;
  --bronze-800: #4b3928;
  --bronze-600: #6e5642;
  --bronze-500: #8c6a3f;
  --bronze-400: #9b7c64;

  /* Luz de cornisa del techo artesonado. */
  --cove: #dac39f;
  --cove-dim: #bea98a;

  /* Mármol del piso de recepción. Gris CÁLIDO, nunca azulado. */
  --marble-900: #3a3a38;
  --marble-800: #605e58;
  --marble-700: #7e7a75;
  --marble-500: #9c9a95;
  --marble-300: #c2bfba;
  --marble-100: #eeefed;

  /* Papelería. Blanco CÁLIDO; el puro se reserva a especulares. */
  --paper: #f2f1ed;
  --pure: #ffffff;
  --cream: #f3f1e7;             /* par de lectura por defecto sobre oscuro */
  --cream-dim: #d8d8cc;

  /* ---- Estado ----------------------------------------------------------
     Dos juegos, porque un solo verde no puede leerse sobre teal Y sobre
     mármol. Ratios calculados (ver §2). */
  --ok-dark: #7fbf95;           /* 7,35 : 1 sobre teal-900 */
  --warn-dark: #e0c368;         /* 9,15 : 1 sobre teal-900 (= gold-400) */
  --err-dark: #f0a08c;          /* 7,60 : 1 sobre teal-900 */
  --ok-light: #1f5637;          /* 7,45 : 1 sobre marble-100 */
  --warn-light: #6d4a12;        /* 6,90 : 1 sobre marble-100 */
  --err-light: #8a2c1c;         /* 7,41 : 1 sobre marble-100 */

  /* ---- Metales como gradiente -----------------------------------------
     «El oro es un gradiente, no un color». Un oro plano traiciona la marca:
     el logo es metálico, sombra → núcleo → brillo especular. */
  --gilt: linear-gradient(105deg,
    #6d582d 0%, #a8873c 22%, #cbab51 42%, #fde261 52%,
    #cbab51 62%, #8c6a3f 82%, #4b3928 100%);
  --gold-leaf: linear-gradient(105deg,
    #6d582d 0%, #cbab51 38%, #fde261 52%, #a8873c 74%, #6d582d 100%);
  /* Moldura: dos filos, uno de luz y uno de sombra, para que lea como
     relieve y no como una línea pintada. */
  --molding: linear-gradient(160deg,
    rgba(218, 195, 159, 0.85) 0%,
    rgba(203, 171, 81, 0.70) 40%,
    rgba(75, 57, 40, 0.90) 100%);
  /* Moldura sobre escena clara: en claro el metal es BRONCE (el oro
     amarillo da 2,94 : 1 sobre mármol y no se lee ni como borde). */
  --molding-light: linear-gradient(160deg,
    rgba(140, 106, 63, 0.85) 0%,
    rgba(110, 86, 66, 0.75) 45%,
    rgba(58, 44, 28, 0.55) 100%);

  /* ---- Escala tipográfica fluida --------------------------------------
     clamp() con mínimos en rem. Nunca `font-size: 1vw` en :root — anula la
     preferencia de tamaño del usuario y rompe el zoom: antipatrón de a11y. */
  --fs-display: clamp(2.5rem, 8vw, 7rem);
  --fs-h1: clamp(1.875rem, 3.6vw, 3rem);      /* h1 de páginas de producto */
  --fs-h2: clamp(1.75rem, 4.2vw, 3.25rem);
  --fs-h3: clamp(1.25rem, 2.2vw, 1.75rem);
  --fs-lead: clamp(1.0625rem, 1.5vw, 1.3125rem);
  --fs-body: clamp(0.9375rem, 1.05vw, 1.0625rem);  /* nunca < 15 px */
  --fs-small: 0.875rem;
  --fs-label: 0.6875rem;

  --font-display: "AL Display", "Palatino Linotype", Palatino, Georgia, serif;
  --font-body: "AL Text", "Helvetica Neue", Helvetica, Arial, sans-serif;
  --font-mono: "AL Mono", "SF Mono", Consolas, "Courier New", monospace;

  /* ---- Retícula y ritmo ------------------------------------------------ */
  --gutter: clamp(1.25rem, 5vw, 6rem);
  --grid-gap: clamp(0.75rem, 1.4vw, 1.5rem);
  --chapter-space: clamp(4.5rem, 11vh, 9rem);
  --measure: 34em;                   /* ~68 caracteres */
  --shell-max: 88rem;

  /* ---- Movimiento ------------------------------------------------------
     Un solo easing para toda apertura. Duraciones: micro 180, media 420,
     umbral 900. Prohibidos rebotes, rotaciones decorativas y entradas
     laterales. */
  --ease-threshold: cubic-bezier(0.16, 1, 0.3, 1);
  --dur-micro: 180ms;
  --dur-mid: 420ms;
  --dur-threshold: 900ms;

  color-scheme: dark;
}

/* ==========================================================================
   2. TEMA POR ESCENA — OBLIGATORIO
   El ritmo luz/oscuridad rompe la suposición de que todo el sitio es oscuro
   y el texto puede heredar `cream` del body. Sobre mármol claro ese heredado
   da 1,02 : 1 — texto invisible. Ese bug ya ocurrió en este proyecto.
   NO HAY VALOR POR DEFECTO SEGURO: toda sección declara su tema.
   ========================================================================== */

/* Sobre escena oscura (ink, teal, void). Par de lectura por defecto:
   cream / teal-800 = 10,13 : 1 (AAA). */
.on-dark {
  color: var(--cream);
  --ink-strong: var(--cream);        /* 13,93 sobre teal-900  AAA */
  --ink-soft: var(--cream-dim);      /* 10,98 sobre teal-900  AAA */
  --ink-quiet: #b9b8ad;              /*  8,17 sobre teal-900  AAA */
  --metal: var(--gold-400);          /*  9,15 sobre teal-900  AAA */
  --metal-quiet: var(--gold-500);    /*  7,12 sobre teal-900  AAA */
  --light-accent: var(--cove);       /*  9,23 sobre teal-900  AAA */
  --hairline: rgba(243, 241, 231, 0.16);
  --hairline-strong: rgba(203, 171, 81, 0.42);
  --molding-current: var(--molding);
  --surface: rgba(58, 44, 28, 0.38);      /* bronce translúcido */
  --surface-solid: var(--teal-900);
  --well: rgba(4, 16, 15, 0.55);
  --focus-ring: var(--gold-400);
  --ok: var(--ok-dark);
  --warn: var(--warn-dark);
  --err: var(--err-dark);
}

/* ----------------------------------------------------------------------------
   EL VERDE DE «ESTO YA ESTÁ HECHO»
   ----------------------------------------------------------------------------
   El verde que usa cualquiera para decir «tarea completada», y aquí dice algo
   concreto: al propietario de esa fila ya se le pagó. Se mira de un vistazo
   sobre setenta filas, así que tiene que verse SIN leer — el primer intento
   fue un tinte al 5,5 % y no se veía a un palmo de la pantalla.

   Va como par de tokens y no como un color suelto porque la fila vive en las
   DOS escenas de la casa: clara en la agenda, oscura dentro de una ventana. El
   mismo mint sobre teal se vería sucio, y el mismo tinte sobre papel se vería
   gris. Cada escena declara el suyo.

   Se queda del lado claro del verde a propósito: la fila sigue siendo una fila
   de trabajo con texto encima, no una insignia. Un verde saturado obligaría a
   recalcular el contraste de todo lo que lleva dentro.
-------------------------------------------------------------------------- */
.on-dark {
  --hecho: rgba(74, 200, 130, 0.15);
  --hecho-filete: #4ac882;
  --hecho-tinta: #a9e9c4;
}

/* Sobre escena clara (mármol, papel).
   SOBRE CLARO EL METAL ES BRONCE. Ratios sobre marble-100 #EEEFED:
     ink        16,76  AAA        bronze-900  11,69  AAA
     bronze-600  5,92  AA         bronze-500   4,29  solo bordes
     gold-600    2,94  FALLA — ni bordes                        */
.on-light {
  color: var(--ink);
  --ink-strong: var(--ink);
  --ink-soft: var(--bronze-900);
  --ink-quiet: var(--bronze-600);
  --metal: var(--bronze-600);        /* 5,92 — legible como texto */
  --metal-quiet: var(--bronze-500);  /* 4,29 — solo bordes y filetes */
  --light-accent: var(--bronze-800);
  --hairline: rgba(58, 44, 28, 0.22);
  --hairline-strong: rgba(58, 44, 28, 0.45);
  --molding-current: var(--molding-light);
  /* Paspartú de escena clara: OPACO a propósito. Un blanco translúcido deja el
     contraste del texto a merced de lo que haya debajo (sobre marble-300 el
     bronce caía a 3,73 : 1). Con #EAE8E3 fijo:
       ink 15,79 · bronze-900 11,02 · bronze-600 5,58 (AA) · bronze-500 4,04 (solo bordes) */
  --surface: #eae8e3;
  /* Mint sobre papel: destaca sin gritar y deja legible la tinta de encima.
     Contraste del texto de la fila sobre #E2F5E9: ink 15,1 · bronze-600 5,3. */
  --hecho: #e2f5e9;
  --hecho-filete: #2f9e63;
  --hecho-tinta: #1f5637;
  --surface-solid: var(--paper);
  --well: rgba(58, 44, 28, 0.07);
  --focus-ring: var(--bronze-900);   /* 11,69 — el oro no llega a 3:1 aquí */
  --ok: var(--ok-light);
  --warn: var(--warn-light);
  --err: var(--err-light);
}

/* Fondos de escena. Cada uno se aplica junto a su tema.
   TODA escena con degradado declara ADEMÁS un `background-color` del mismo
   valor. Sin él, `getComputedStyle().backgroundColor` es transparente y la
   escena hereda el fondo del body: una sección `.on-light` sobre tinta da
   texto oscuro sobre oscuro (1,02 : 1) — exactamente el bug que el brief
   manda evitar. Lo detectó la medición de contraste en el navegador. */
.sc-void   { background-color: var(--void); }
.sc-ink    { background-color: var(--ink); }
.sc-teal   { background-color: var(--teal-900); }
.sc-teal-800 { background-color: var(--teal-800); }
.sc-deep   { background-color: var(--teal-900); background-image: linear-gradient(180deg, var(--ink) 0%, var(--teal-900) 55%, var(--ink) 100%); }
.sc-rise   { background-color: var(--ink); background-image: linear-gradient(180deg, var(--void) 0%, var(--ink) 34%, var(--teal-900) 100%); }
.sc-fall   { background-color: var(--ink); background-image: linear-gradient(180deg, var(--teal-900) 0%, var(--ink) 55%, var(--void) 100%); }
.sc-marble { background-color: var(--marble-100); }
.sc-paper  { background-color: var(--paper); }
.sc-marble-mid { background-color: var(--marble-300); background-image: linear-gradient(180deg, var(--marble-100) 0%, var(--marble-300) 100%); }

/* COSTURA DE UMBRAL — el cruce entre capítulos.
   Sin ella, cada cambio de valor es un corte en seco (prohibición nº 8 de la
   dirección de arte). La costura hace que el capítulo saliente se DISUELVA en
   el entrante: el cambio de luz sigue siendo un acontecimiento, pero se cruza
   en vez de suceder de golpe. Es decorativa: va con aria-hidden. */
.seam { height: clamp(3rem, 8vh, 7rem); position: relative; }
.seam-to-dark  { background-image: linear-gradient(180deg, var(--marble-100) 0%, #6f7166 46%, var(--ink) 100%); }
.seam-to-dark-mid { background-image: linear-gradient(180deg, var(--marble-300) 0%, #5c5b52 46%, var(--teal-900) 100%); }
.seam-to-void { background-image: linear-gradient(180deg, var(--marble-300) 0%, #4c4b45 46%, var(--void) 100%); }
.seam-to-void-light { background-image: linear-gradient(180deg, var(--marble-100) 0%, #55554f 46%, var(--void) 100%); }
.seam-to-light { background-image: linear-gradient(180deg, var(--teal-900) 0%, #6b7268 52%, var(--marble-100) 100%); }
.seam-to-light-ink { background-image: linear-gradient(180deg, var(--ink) 0%, #5f6459 52%, var(--marble-100) 100%); }
/* Un filete de luz de cornisa marca la línea del cruce, como el inserto dorado
   del filete del piso de recepción. */
.seam::after {
  content: "";
  position: absolute;
  inset: auto 0 0 0;
  height: 1px;
  background-image: linear-gradient(90deg, transparent 0%, rgba(218, 195, 159, 0.5) 50%, transparent 100%);
}
.seam-to-dark::after, .seam-to-dark-mid::after { inset: 0 0 auto 0; }

/* Utilidades semánticas de tinta. Funcionan igual en claro y en oscuro. */
.ink-strong { color: var(--ink-strong); }
.ink-soft   { color: var(--ink-soft); }
.ink-quiet  { color: var(--ink-quiet); }
.muted      { color: var(--ink-quiet); }
.metal      { color: var(--metal); }

/* ==========================================================================
   3. BASE
   ========================================================================== */

*, *::before, *::after { box-sizing: border-box; }

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

body {
  margin: 0;
  background-color: var(--ink);
  color: var(--cream);
  font-family: var(--font-body);
  font-size: var(--fs-body);
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  /* El overflow-x se ataja en la raíz: ninguna sección puede provocar scroll
     horizontal por un título sin tope de ancho. */
  overflow-x: clip;
}

img, video, canvas, svg, picture { display: block; max-width: 100%; }
picture { height: auto; }
button, input, textarea, select { font: inherit; color: inherit; }
button { cursor: pointer; background: none; border: 0; padding: 0; }
a { color: inherit; text-decoration: none; }
h1, h2, h3, h4, p, dl, dd, figure, ul, ol { margin: 0; padding: 0; }
ul, ol { list-style: none; }
p { max-width: var(--measure); }

/* Focus visible. Nunca `outline: none` sin sustituto.
   En oscuro el anillo es oro (gold-400 / teal-900 = 9,15). En claro el oro
   amarillo daría 2,94 y no alcanza el 3:1 que exige un indicador de foco,
   así que el anillo pasa a bronze-900 (11,69) y el oro queda como filo
   interior — se conserva la lectura de metal sin perder el contraste. */
:focus-visible {
  outline: 2px solid var(--focus-ring, var(--gold-400));
  outline-offset: 3px;
  border-radius: 2px;
}
.on-light :focus-visible,
.on-light:focus-visible {
  box-shadow: 0 0 0 1px var(--gold-500);
}

::selection { background: var(--gold-500); color: var(--ink); }

.skip-link {
  position: absolute;
  left: 50%;
  top: 0;
  translate: -50% -150%;
  z-index: 900;
  padding: 0.75rem 1.5rem;
  background: var(--teal-900);
  color: var(--cream);
  font-family: var(--font-mono);
  font-size: var(--fs-label);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  border: 1px solid var(--gold-600);
  transition: translate var(--dur-mid) var(--ease-threshold);
}
/* `:focus` además de `:focus-visible`: el foco programático (por ejemplo el que
   deja un lector de pantalla o un script) no siempre activa `:focus-visible`, y
   un enlace de salto que no se ve al recibir el foco no sirve para nada. */
.skip-link:focus,
.skip-link:focus-visible { translate: -50% 0.5rem; }

.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border-width: 0;
}

.hidden { display: none !important; }

/* ==========================================================================
   4. TIPOGRAFÍA
   ========================================================================== */

.t-display {
  font-family: var(--font-display);
  font-size: var(--fs-display);
  line-height: 0.94;
  letter-spacing: -0.03em;
  font-weight: 400;
  text-wrap: balance;
  max-width: 20ch;
}
h1, .t-h1 {
  font-family: var(--font-display);
  font-size: var(--fs-h1);
  line-height: 1.04;
  letter-spacing: -0.022em;
  font-weight: 400;
  text-wrap: balance;
  color: var(--ink-strong);
}
h2, .t-h2 {
  font-family: var(--font-display);
  font-size: var(--fs-h2);
  line-height: 1.0;
  letter-spacing: -0.024em;
  font-weight: 400;
  text-wrap: balance;
  max-width: 26ch;
  color: var(--ink-strong);
}
h3, .t-h3 {
  font-family: var(--font-display);
  font-size: var(--fs-h3);
  line-height: 1.14;
  letter-spacing: -0.016em;
  font-weight: 400;
  color: var(--ink-strong);
}
h4 { font-family: var(--font-body); font-size: 1rem; font-weight: 700; color: var(--ink-strong); }
em { font-style: italic; }
.t-display em, h1 em, h2 em { color: var(--metal); font-style: italic; }

.t-lead {
  font-size: var(--fs-lead);
  line-height: 1.55;
  max-width: var(--measure);
  color: var(--ink-soft);
}

/* Etiquetas y cifras: mono, versalitas espaciadas. La textura de precisión. */
.t-label, .eyebrow, .overline {
  display: inline-block;
  font-family: var(--font-body);
  font-size: var(--fs-label);
  line-height: 1.4;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  font-weight: 400;
  color: var(--metal);
  max-width: none;
}
.eyebrow {
  position: relative;
  padding-left: 2.75rem;
}
/* Filete de 1 px en pan de oro cerrando la etiqueta, como el inserto del
   piso de recepción. */
.eyebrow::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.58em;
  width: 2rem;
  height: 1px;
  background-image: var(--gilt);
}
.on-light .eyebrow::before { background-image: none; background-color: var(--bronze-500); }

.t-figure, .num {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.01em;
}

/* Texto en pan de oro. Solo display: en cuerpo el gradiente no se lee.
   No se usa nunca sobre escena clara. */
.gilt-text {
  background-image: var(--gilt);
  background-size: 260% 100%;
  background-position: 30% 0;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  -webkit-text-fill-color: transparent;
}
/* Salvaguarda: si el navegador no soporta background-clip:text el texto
   quedaría transparente. Se restituye el color plano. */
@supports not ((-webkit-background-clip: text) or (background-clip: text)) {
  .gilt-text { color: var(--gold-400); -webkit-text-fill-color: var(--gold-400); }
}

/* Filete dorado horizontal. */
.gilt-rule {
  height: 1px;
  border: 0;
  margin: 0;
  background-image: var(--gilt);
  background-size: 300% 100%;
}
.on-light .gilt-rule { background-image: none; background-color: var(--bronze-500); }

/* ==========================================================================
   5. RETÍCULA Y CAPÍTULOS
   ========================================================================== */

.shell {
  width: 100%;
  margin-inline: auto;
  padding-inline: var(--gutter);
  max-width: var(--shell-max);
}
.wrap { /* alias heredado de la app, mismo contrato */
  width: 100%;
  margin-inline: auto;
  padding-inline: var(--gutter);
  max-width: var(--shell-max);
}

.chapter {
  position: relative;
  padding-block: var(--chapter-space);
  isolation: isolate;
}
.section { position: relative; padding-block: var(--chapter-space); }

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

.section-head {
  display: flex;
  align-items: end;
  justify-content: space-between;
  gap: clamp(1.25rem, 3vw, 2.5rem);
  margin-bottom: clamp(2rem, 4vw, 3.5rem);
  flex-wrap: wrap;
}
.section-head > div:first-child { max-width: 56ch; }
.section-head h2 { margin-bottom: 0.75rem; }
.section-head p { color: var(--ink-quiet); max-width: 54ch; }

/* Numeración editorial de capítulo, en mono. */
body { counter-reset: sec; }
.chapter[data-numbered] .section-head h2::before,
.section[data-numbered] .section-head h2::before {
  counter-increment: sec;
  content: "( " counter(sec, decimal-leading-zero) " )";
  display: block;
  font-family: var(--font-mono);
  font-size: var(--fs-label);
  letter-spacing: 0.16em;
  color: var(--metal);
  margin-bottom: 1rem;
}

.flex { display: flex; gap: 0.875rem; align-items: center; flex-wrap: wrap; }
.grow { flex: 1; }
.center { text-align: center; }
.center p, .center h1, .center h2, .center .t-lead { margin-inline: auto; }
.mt-1 { margin-top: 0.625rem; } .mt-2 { margin-top: 1.125rem; }
.mt-3 { margin-top: 1.875rem; } .mt-4 { margin-top: 3rem; }

/* ==========================================================================
   6. PANEL — la forma rectora
   Rectángulo con moldura metálica y esquinas a inglete. NADA DE ARCOS: la
   marca no tiene ni uno. Las imágenes viven DENTRO de paneles, no en
   tarjetas con sombra.
   ========================================================================== */

.panel {
  position: relative;
  isolation: isolate;
}
/* La moldura es un borde real de 1 px en degradado metálico, hecho con
   máscara para que sea marco y no un fondo tapado. */
.panel::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 4;
  pointer-events: none;
  padding: 1px;
  background-image: var(--molding-current, var(--molding));
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask-composite: exclude;
}

/* Panel con paspartú, como las láminas enmarcadas del vestíbulo. */
.panel-matted {
  padding: clamp(0.5rem, 1.1vw, 1.25rem);
  background-color: var(--surface);
}

/* Esquinas a inglete: cuatro filos cortos en las esquinas, el remate de una
   moldura de verdad. Más sutil y más caro de leer que un borde entero.
   Se dibujan con ocho gradientes en UN SOLO pseudoelemento (::after) a
   propósito: `.panel` ya reclama ::before y un nodo solo tiene dos. La
   versión con ::before + ::after se comía la moldura al combinar
   `panel mitre` en el mismo elemento — colisión silenciosa. */
.mitre { position: relative; --mitre-len: clamp(1.25rem, 2.4vw, 2.5rem); }
.mitre::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 5;
  pointer-events: none;
  background-image:
    linear-gradient(var(--hairline-strong), var(--hairline-strong)),
    linear-gradient(var(--hairline-strong), var(--hairline-strong)),
    linear-gradient(var(--hairline-strong), var(--hairline-strong)),
    linear-gradient(var(--hairline-strong), var(--hairline-strong)),
    linear-gradient(var(--hairline-strong), var(--hairline-strong)),
    linear-gradient(var(--hairline-strong), var(--hairline-strong)),
    linear-gradient(var(--hairline-strong), var(--hairline-strong)),
    linear-gradient(var(--hairline-strong), var(--hairline-strong));
  background-size:
    var(--mitre-len) 1px, 1px var(--mitre-len),
    var(--mitre-len) 1px, 1px var(--mitre-len),
    var(--mitre-len) 1px, 1px var(--mitre-len),
    var(--mitre-len) 1px, 1px var(--mitre-len);
  background-position:
    left top, left top,
    right top, right top,
    left bottom, left bottom,
    right bottom, right bottom;
  background-repeat: no-repeat;
}

/* Lámina: el contenedor de imagen con gradación unificadora.
   El portafolio es heterogéneo (una casa moderna, un apartamento con luz
   amarillenta, locales bajo la lluvia). Sin gradación común el sitio parece
   seis sitios pegados. Se aplica en CSS, no quemada en los archivos. */
.plate {
  display: block;                  /* también se usa sobre <span> dentro de <a> */
  position: relative;
  overflow: clip;
  isolation: isolate;
  background-color: var(--teal-900);
}
/* `<picture>` necesita altura propia: sin ella el `height: 100%` del <img> se
   resuelve contra una caja de altura automática, el porcentaje se ignora y la
   foto estira el panel por su tamaño natural. Se veía como una lámina vertical
   que rompía la fila de la rejilla. */
.plate > picture { display: block; width: 100%; height: 100%; }
.plate > img, .plate > video, .plate > picture > img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
/* `min-height: 0` desarma el tamaño mínimo automático de `aspect-ratio`: sin
   él el contenido puede estirar la caja y la proporción declarada se pierde. */
.plate[style*="aspect-ratio"], .card-img, .rail-piece .plate { min-height: 0; }

/* Lámina CON PASPARTÚ: la foto entra completa y el fondo del panel hace de
   paspartú. Es la garantía mecánica de que ninguna foto vertical se recorta
   contra una caja horizontal para cuadrar una rejilla (prohibición nº 4 de la
   dirección de arte). Las horizontales, que son 4:3 nativas, llenan la caja
   exacta y no se ve paspartú alguno. */
.plate-mat > img, .plate-mat > picture > img { object-fit: contain; }

/* Lámina que RESPETA el formato: la altura la fija la foto, no el contenedor.
   Se usa en la galería, donde el compás recibe la proporción real de la foto. */
.plate-fit { height: auto; }
.plate-fit > picture { height: auto; }
.plate-fit > img, .plate-fit > picture > img {
  height: auto;
  object-fit: contain;
}
.plate-graded > img,
.plate-graded > video,
.plate-graded > picture > img { filter: saturate(0.93) contrast(1.04); }
/* Viñeta CÁLIDA y duotono comparten ::before, como dos capas de background:
   `grain` necesita ::after y un nodo solo tiene dos pseudoelementos. */
.plate-graded::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  background-image:
    radial-gradient(120% 90% at 50% 40%, transparent 42%, rgba(58, 44, 28, 0.42) 100%),
    linear-gradient(163deg, rgba(203, 171, 81, 0.13) 0%, transparent 45%, rgba(18, 64, 63, 0.16) 100%);
}

/* Grano de película. Convierte el artefacto de compresión en textura. */
.grain::after {
  content: "";
  position: absolute;
  inset: -50%;
  z-index: 4;
  pointer-events: none;
  opacity: 0.035;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.82' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
  animation: a-grain 6s steps(6) infinite;
}
@keyframes a-grain {
  0%   { transform: translate(0, 0); }
  16%  { transform: translate(-2%, 1%); }
  33%  { transform: translate(1%, -2%); }
  50%  { transform: translate(-1%, 2%); }
  66%  { transform: translate(2%, 1%); }
  83%  { transform: translate(-2%, -1%); }
  100% { transform: translate(0, 0); }
}

/* ==========================================================================
   7. LUZ COMO MATERIAL
   ========================================================================== */

/* Cornisa: la luz entra SIEMPRE por arriba, como en el techo artesonado. */
.cove-light { position: relative; }
.cove-light::before {
  content: "";
  position: absolute;
  inset: 0 0 auto 0;
  height: clamp(7rem, 20vh, 18rem);
  z-index: 1;
  pointer-events: none;
  background-image: linear-gradient(to bottom,
    rgba(218, 195, 159, 0.26) 0%,
    rgba(218, 195, 159, 0.08) 38%,
    transparent 100%);
  mix-blend-mode: screen;
}
/* Sobre escena clara la cornisa no puede ir en `screen` (se perdería):
   se dibuja como un velo cálido descendente. */
.on-light.cove-light::before {
  mix-blend-mode: normal;
  background-image: linear-gradient(to bottom,
    rgba(218, 195, 159, 0.55) 0%,
    rgba(218, 195, 159, 0.14) 44%,
    transparent 100%);
}

/* Apliques: dos charcos radiales simétricos, como los de la recepción.
   La simetría es del edificio, no un capricho. Su intensidad sube con el
   scroll: la sección SE ENCIENDE al entrar. */
.sconces { position: relative; --lit: 1; }
.sconces::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  opacity: var(--lit);
  background-image:
    radial-gradient(28vw 34vh at 16% 26%, rgba(218, 195, 159, 0.20) 0%, transparent 70%),
    radial-gradient(28vw 34vh at 84% 26%, rgba(218, 195, 159, 0.20) 0%, transparent 70%);
  mix-blend-mode: screen;
}
@property --lit { syntax: "<number>"; initial-value: 1; inherits: false; }
@keyframes a-lights-on { from { --lit: 0.15; } to { --lit: 1; } }

/* Penumbra CÁLIDA, nunca gris. Una viñeta gris sobre teal ensucia. */
.penumbra { position: relative; }
.penumbra::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  background-image: radial-gradient(130% 100% at 50% 34%,
    transparent 38%, rgba(58, 44, 28, 0.55) 100%);
}

/* Niebla que se levanta sobre el borde del paisaje. */
.mist { position: relative; }
.mist::after {
  content: "";
  position: absolute;
  inset: auto 0 0 0;
  height: 38%;
  z-index: 3;
  pointer-events: none;
  background-image: linear-gradient(to top,
    var(--teal-900) 0%,
    rgba(10, 39, 38, 0.82) 34%,
    rgba(218, 195, 159, 0.06) 72%,
    transparent 100%);
}



/* ==========================================================================
   8. NAVEGACIÓN
   ========================================================================== */

.nav {
  position: sticky;
  top: 0;
  z-index: 300;
  background-color: rgba(4, 16, 15, 0.86);
  backdrop-filter: blur(14px) saturate(1.1);
  border-bottom: 1px solid var(--hairline);
}
/* Filete dorado a fuego en el canto inferior de la barra. */
.nav::after {
  content: "";
  position: absolute;
  inset: auto 0 -1px 0;
  height: 1px;
  background-image: var(--gilt);
  background-size: 300% 100%;
  opacity: 0.7;
}
.nav-inner {
  display: flex;
  align-items: center;
  gap: clamp(1rem, 2vw, 2rem);
  min-height: 4.25rem;
}
.brand {
  display: flex;
  align-items: center;
  gap: 0.8rem;
  font-family: var(--font-display);
  font-size: 1.1875rem;
  letter-spacing: 0.02em;
  line-height: 1.1;
  color: var(--cream);
  flex: 0 0 auto;
}
.brand img { width: auto; height: 2.5rem; }
.brand b, .brand > span > span:first-child { font-weight: 400; }
.brand small {
  display: block;
  font-family: var(--font-body);
  font-size: 0.5625rem;
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: var(--gold-500);
  margin-top: 0.2rem;
}
.nav-links {
  display: flex;
  gap: 0.25rem;
  margin-left: auto;
  align-items: center;
  font-size: var(--fs-small);
  flex-wrap: wrap;
  justify-content: flex-end;
}
/* Los enlaces y los botones de la barra comparten estilo: «Salir» y
   «Seguridad» son <button> desde que se eliminaron los handlers inline, y no
   deben leerse como una tipografía distinta al resto de la navegación. */
/* `:not(.btn)` es imprescindible: sin él este bloque le gana en cascada a
   `.btn` (0,1,1 contra 0,1,0) y el CTA de la barra pierde la voz de sistema
   —mono, versalitas espaciadas— para quedarse en texto corrido. */
.nav-links a:not(.btn),
.nav-links .nav-btn {
  position: relative;
  font-family: var(--font-body);
  font-size: var(--fs-small);
  letter-spacing: normal;
  text-transform: none;
  color: var(--cream-dim);
  padding: 0.55rem 0.85rem;
  transition: color var(--dur-micro) var(--ease-threshold);
}
.nav-links a.btn { padding: 0.625rem 1.125rem; }
.nav-links .nav-btn::after {
  content: "";
  position: absolute;
  left: 0.85rem;
  right: 0.85rem;
  bottom: 0.3rem;
  height: 1px;
  background-image: var(--gold-leaf);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform var(--dur-mid) var(--ease-threshold);
}
.nav-links .nav-btn:hover, .nav-links .nav-btn:focus-visible { color: var(--cream); }
.nav-links .nav-btn:hover::after, .nav-links .nav-btn:focus-visible::after { transform: scaleX(1); }
/* Subrayado en pan de oro que se dibuja desde la izquierda. Hover y focus
   comparten coreografía: quien navega con teclado ve lo mismo. */
.nav-links a:not(.btn)::after {
  content: "";
  position: absolute;
  left: 0.85rem;
  right: 0.85rem;
  bottom: 0.3rem;
  height: 1px;
  background-image: var(--gold-leaf);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform var(--dur-mid) var(--ease-threshold);
}
.nav-links a:not(.btn):hover, .nav-links a:not(.btn):focus-visible { color: var(--cream); }
.nav-links a:not(.btn):hover::after,
.nav-links a:not(.btn):focus-visible::after,
.nav-links a.active:not(.btn)::after { transform: scaleX(1); }
.nav-links a.active:not(.btn) { color: var(--gold-400); }
/* `.nav-links a` es (0,1,1) y le ganaba en cascada a `.btn-gold`, que es (0,1,0):
   el CTA de la barra salía con texto cream sobre pan de oro — 1,54 : 1, ilegible.
   Se restituye el par correcto (ink sobre gold-500 = 8,73 : 1  AAA). */
.nav-links a.btn { color: var(--cream); }
.nav-links a.btn-gold,
.nav-links a.btn-gold:hover,
.nav-links a.btn-gold:focus-visible { color: var(--ink); }

/* ==========================================================================
   9. BOTONES
   El rótulo va en mono espaciado: es la voz de sistema.
   ========================================================================== */

.btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.625rem;
  padding: 0.9375rem 1.75rem;
  font-family: var(--font-body);
  font-size: 0.75rem;
  font-weight: 400;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  line-height: 1.3;
  text-align: center;
  color: var(--cream);
  background-color: var(--teal-800);
  border: 0;
  isolation: isolate;
  overflow: clip;
  transition: background-color var(--dur-mid) var(--ease-threshold),
              color var(--dur-mid) var(--ease-threshold);
}
/* Moldura del botón: el canto metálico, no un borde plano. */
.btn::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  padding: 1px;
  background-image: var(--gilt);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask-composite: exclude;
}
/* Barrido de luz sobre el metal. El pseudo se traslada (se compone en GPU),
   no se anima background-position. */
.btn::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  translate: -110% 0;
  background-image: linear-gradient(100deg, transparent 0%, rgba(253, 226, 97, 0.30) 50%, transparent 100%);
  transition: translate var(--dur-threshold) var(--ease-threshold);
}
.btn:hover::after, .btn:focus-visible::after { translate: 110% 0; }
.btn:hover { background-color: var(--teal-700); }
.btn:active { background-color: var(--teal-900); }

/* Primario: teal profundo, cream (10,13 : 1 sobre teal-800  AAA). */
.btn-primary { background-color: var(--teal-800); color: var(--cream); }
/* Oro: pan de oro sólido con tinta encima (ink / gold-500 = 8,73  AAA). */
.btn-gold {
  background-color: var(--gold-500);
  background-image: linear-gradient(105deg, #a8873c 0%, #cbab51 38%, #e0c368 52%, #a8873c 100%);
  color: var(--ink);
}
.btn-gold:hover { background-color: var(--gold-400); color: var(--ink); }
.btn-gold::after { background-image: linear-gradient(100deg, transparent 0%, rgba(255, 255, 255, 0.45) 50%, transparent 100%); }
/* Fantasma: solo moldura. */
.btn-ghost { background-color: transparent; color: var(--ink-strong); }
.btn-ghost::before { background-image: none; background-color: transparent; box-shadow: inset 0 0 0 1px var(--hairline-strong); }
.btn-ghost:hover { background-color: var(--well); color: var(--ink-strong); }
/* WhatsApp: NO el verde #25D366 de la marca WhatsApp — no combina con la
   paleta. Fondo teal-700, filete en pan de oro, ícono en gold-500.
   cream / teal-700 = 8,60 : 1  AAA. */
.btn-wa { background-color: var(--teal-700); color: var(--cream); }
.btn-wa:hover { background-color: var(--teal-600); }
/* El ícono hereda `currentColor` del SVG, así que basta darle el oro aquí.
   Nunca el verde #25D366 de la marca WhatsApp: no combina con la paleta. */
.btn-wa .ic { color: var(--gold-500); }
.ic { flex: 0 0 auto; }
.btn-sm { padding: 0.625rem 1.125rem; font-size: 0.6875rem; }
.btn-block { width: 100%; }
.btn[disabled], .btn[aria-disabled="true"] { opacity: 0.45; pointer-events: none; }
/* En escena clara los botones fantasma y los rótulos cambian de metal. */
.on-light .btn-ghost { color: var(--bronze-900); }

/* Botón flotante de WhatsApp. */
.wa-float {
  position: fixed;
  right: clamp(1rem, 3vw, 2.25rem);
  bottom: clamp(1rem, 3vw, 2.25rem);
  z-index: 320;
  width: 3.5rem;
  height: 3.5rem;
  display: grid;
  place-items: center;
  background-color: var(--teal-700);
  color: var(--gold-500);
  font-size: 1.5rem;
  isolation: isolate;
  box-shadow: 0 0.75rem 2rem rgba(4, 16, 15, 0.45);
  transition: background-color var(--dur-mid) var(--ease-threshold);
}
.wa-float::before {
  content: "";
  position: absolute;
  inset: 0;
  padding: 1px;
  background-image: var(--gilt);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask-composite: exclude;
}
.wa-float:hover { background-color: var(--teal-600); }

/* ==========================================================================
   10. UMBRAL (hero)
   Negro → teal: la luz se enciende. El video/lámina va a sangre, sin marco:
   «los videos en cajas con overflow: clip» están prohibidos.
   ========================================================================== */

.hero {
  position: relative;
  padding-block: clamp(3.5rem, 9vh, 7rem) clamp(3rem, 7vh, 5.5rem);
  overflow: clip;
}
.hero-inner { position: relative; z-index: 3; }
.hero .t-display { margin-block: 1.25rem 1.5rem; }
.hero .t-lead { margin-bottom: clamp(1.75rem, 4vw, 2.75rem); }

/* Escena del umbral: la lámina de fondo a sangre, con la cornisa por encima
   para que parezca iluminada por el espacio y no pegada. */
.hero-scene {
  position: absolute;
  inset: 0;
  z-index: 0;
  overflow: clip;
  background-color: var(--ink);
}
.hero-scene img, .hero-scene video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0.42;
  filter: saturate(0.85) contrast(1.05);
}
.hero-scene::after {
  content: "";
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(180deg, rgba(4, 16, 15, 0.72) 0%, rgba(4, 16, 15, 0.55) 45%, var(--ink) 100%),
    radial-gradient(120% 80% at 50% 0%, rgba(218, 195, 159, 0.22) 0%, transparent 62%);
}

/* Indicador de scroll: el sitio tiene que decir que hay más abajo. */
.cue {
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  gap: 0.5rem;
  margin-top: clamp(2rem, 5vh, 3.5rem);
  font-family: var(--font-body);
  font-size: var(--fs-label);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--cream-dim);
}
.cue span[aria-hidden] { animation: a-cue 2.4s var(--ease-threshold) infinite; }
@keyframes a-cue {
  0%, 100% { transform: translateY(0); opacity: 0.45; }
  50% { transform: translateY(0.5rem); opacity: 1; }
}

/* Buscador del umbral: una bandeja con moldura y pozos hundidos. */
.searchbar {
  position: relative;
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  align-items: stretch;
  padding: 0.75rem;
  background-color: rgba(10, 39, 38, 0.78);
  backdrop-filter: blur(8px);
  max-width: 58rem;
}
.searchbar select, .searchbar input {
  flex: 1 1 11rem;
  min-width: 0;
  border: 1px solid var(--hairline);
  background-color: var(--well);
  color: var(--cream);
  padding: 0.8125rem 1rem;
  font-size: var(--fs-body);
}
.searchbar select { appearance: auto; }
.searchbar option { color: var(--ink); }
.searchbar .btn { flex: 0 0 auto; }
.searchbar .sep { display: none; }

/* Banda de cifras. Sobre teal-900: cream-dim 10,98  AAA. */
.stats-band {
  border-top: 1px solid var(--hairline);
  border-bottom: 1px solid var(--hairline);
  padding-block: clamp(1.25rem, 3vw, 2rem);
}
.stats-band .wrap { display: flex; flex-wrap: wrap; gap: clamp(1rem, 3vw, 3rem); }
.stat-chip {
  flex: 1 1 16rem;
  display: block;
  font-size: var(--fs-small);
  color: var(--ink-soft);
  line-height: 1.6;
  padding-left: 1rem;
  border-left: 1px solid var(--hairline-strong);
  max-width: 30ch;
}
.stat-chip b {
  display: block;
  font-family: var(--font-body);
  font-variant-numeric: tabular-nums;
  font-size: clamp(1.375rem, 2.6vw, 2rem);
  font-weight: 400;
  color: var(--metal);
  letter-spacing: -0.02em;
  margin-bottom: 0.25rem;
}

/* ==========================================================================
   11. FILTROS Y FICHAS DE PORTAFOLIO
   ========================================================================== */

.filters { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-bottom: clamp(1.5rem, 3vw, 2.25rem); }
.chip {
  padding: 0.5625rem 1.125rem;
  font-family: var(--font-body);
  font-size: 0.6875rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-quiet);
  background-color: transparent;
  border: 1px solid var(--hairline);
  transition: color var(--dur-micro) var(--ease-threshold),
              border-color var(--dur-micro) var(--ease-threshold),
              background-color var(--dur-micro) var(--ease-threshold);
}
.chip:hover { color: var(--ink-strong); border-color: var(--hairline-strong); }
.chip.active {
  color: var(--ink-strong);
  background-color: var(--well);
  border-color: var(--metal-quiet);
}
select.chip { appearance: auto; text-transform: none; letter-spacing: 0.04em; }

/* Rejilla de láminas. Las fichas son PANELES, no tarjetas con sombra. */
.grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(22rem, 100%), 1fr));
  gap: clamp(1.25rem, 2.6vw, 2.25rem);
}

.card {
  position: relative;
  display: flex;
  flex-direction: column;
  isolation: isolate;
  background-color: var(--surface);
  padding: clamp(0.5rem, 0.9vw, 0.875rem);
  --plate-lift: 0;
  transition: background-color var(--dur-mid) var(--ease-threshold);
}
.card-img {
  position: relative;
  aspect-ratio: 4 / 3;
  overflow: clip;
  background-color: var(--teal-900);
}
.card-img img {
  width: 100%; height: 100%;
  object-fit: cover;
  transform: scale(1.02);
  filter: saturate(0.93) contrast(1.04);
  transition: transform var(--dur-threshold) var(--ease-threshold);
}
.card:hover, .card:focus-visible, .card:focus-within { --plate-lift: 1; background-color: var(--well); }
.card:hover .card-img img, .card:focus-visible .card-img img, .card:focus-within .card-img img { transform: scale(1.07); }
.card-rule {
  height: 1px;
  background-image: var(--gilt);
  transform: scaleX(var(--plate-lift));
  transform-origin: left center;
  transition: transform 700ms var(--ease-threshold);
}
/* La lámina es un <a> y sus partes son <span>: se fuerzan a bloque para que
   el marco, el recorte y la retícula interna funcionen igual. */
.card > span { display: block; }
.card-body { padding: 1.125rem 0.75rem 0.75rem; display: flex; flex-direction: column; gap: 0.5rem; flex: 1; }
.card-price {
  display: block;
  font-family: var(--font-display);
  font-variant-numeric: tabular-nums;
  font-variant-numeric: tabular-nums;
  font-size: 1.1875rem;
  letter-spacing: -0.015em;
  color: var(--metal);
}
.card-price small { font-size: 0.625rem; letter-spacing: 0.1em; color: var(--ink-quiet); }
.card-title { display: block; font-family: var(--font-display); font-size: 1.125rem; line-height: 1.3; color: var(--ink-strong); }
.card-loc {
  display: block;
  font-family: var(--font-body);
  font-size: 0.6875rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-quiet);
}
.card-specs {
  display: flex; flex-wrap: wrap; gap: 0.375rem 1rem;
  font-family: var(--font-body);
  font-size: 0.6875rem;
  letter-spacing: 0.04em;
  color: var(--ink-quiet);
  margin-top: auto;
  padding-top: 0.875rem;
  border-top: 1px solid var(--hairline);
}
/* El pie de la lámina sube al pasar por encima. NO se le baja la opacidad en
   reposo: bronce al 70 % sobre el paspartú cae a ~3,2 : 1 y el texto de 11 px
   deja de pasar AA. La coreografía es el desplazamiento, no la transparencia. */
.card-meta {
  transform: translateY(calc((1 - var(--plate-lift)) * 0.4rem));
  transition: transform 600ms var(--ease-threshold);
}

.badges { position: absolute; top: 0.625rem; left: 0.625rem; z-index: 3; display: flex; gap: 0.375rem; flex-wrap: wrap; max-width: calc(100% - 1.25rem); }
.badge {
  font-family: var(--font-body);
  font-size: 0.5625rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  padding: 0.375rem 0.6875rem;
  line-height: 1.4;
  /* Casi opaco a propósito: la insignia se lee sobre una pared blanca igual que
     sobre un jardín en contraluz. Con 0,82 de alfa el fondo variaba tanto que el
     contraste dejaba de ser predecible. Sobre este fondo, cream = 15,1 : 1. */
  background-color: rgba(4, 16, 15, 0.94);
  backdrop-filter: blur(6px);
  color: var(--cream);
  border: 1px solid rgba(203, 171, 81, 0.42);
}
.badge-deal { color: var(--cream); }
.badge-verif { color: var(--gold-400); }     /* 11,21 sobre ink  AAA */
.badge-dueno { color: var(--cove); }         /* 11,31 sobre ink  AAA */
.lock-pill {
  position: absolute;
  bottom: 0.625rem; right: 0.625rem;
  z-index: 3;
  display: inline-flex; align-items: center; gap: 0.375rem;
  background-color: rgba(4, 16, 15, 0.94);
  backdrop-filter: blur(6px);
  padding: 0.4375rem 0.75rem;
  font-family: var(--font-body);
  font-size: 0.5625rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--gold-400);
  border: 1px solid rgba(203, 171, 81, 0.42);
  line-height: 1.4;
}

/* ==========================================================================
   12. VITRINA HORIZONTAL
   Sección de vitrina recorrida de lado. Se implementa con scroll nativo
   (`overflow-x`) y NO con una pista trasladada por `scroll()`: el scroll
   nativo es navegable por teclado (Tab lleva el foco y el navegador
   desplaza), y no hay scroll-jacking — la rueda hace lo que el usuario
   espera. La decoración ligada al scroll sí es CSS: cada pieza gira
   levemente al pasar por la vitrina con `view(inline)`.
   ========================================================================== */

.vitrine { position: relative; }
.rail {
  display: grid;
  grid-auto-flow: column;
  /* El carril se dimensiona por la pieza VERTICAL, que es la estrecha; las
     horizontales ocupan dos carriles. Así caben cuatro o cinco piezas a la vez
     y la vitrina se lee como una serie, no como una foto gigante por pantalla. */
  grid-auto-columns: clamp(8.5rem, 14vw, 13rem);
  gap: clamp(1rem, 2vw, 2rem);
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x proximity;
  padding-block: 0.5rem clamp(1rem, 2vw, 1.75rem);
  padding-inline: var(--gutter);
  margin-inline: calc(var(--gutter) * -1);
  scrollbar-color: var(--metal-quiet) transparent;
  scrollbar-width: thin;
  /* Cada pieza mide lo que mide su foto: no se estiran para igualar la fila. */
  align-items: start;
}
.rail > * { scroll-snap-align: center; }
.rail-piece { position: relative; display: block; }
.rail-piece > span { display: block; }
/* Las piezas horizontales ocupan más carril que las verticales: es lo que hace
   que la vitrina tenga ritmo en vez de ser doce columnas iguales. */
.rail-piece.is-wide { grid-column: span 2; }
.rail-cap {
  display: block;
  margin-top: 0.75rem;
  font-family: var(--font-body);
  font-size: 0.6875rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-quiet);
}
.rail-nav { display: flex; gap: 0.5rem; justify-content: flex-end; margin-bottom: 0.75rem; }
.rail-btn {
  width: 2.75rem; height: 2.75rem;
  display: grid; place-items: center;
  border: 1px solid var(--hairline-strong);
  color: var(--ink-strong);
  font-size: 1rem;
  transition: background-color var(--dur-micro) var(--ease-threshold);
}
.rail-btn:hover { background-color: var(--well); }
.rail-hint {
  font-family: var(--font-body);
  font-size: var(--fs-label);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-quiet);
}

/* ==========================================================================
   13. RITMO EDITORIAL DE GALERÍA — compases
   La v1 tiraba todas las fotos en una rejilla uniforme, así que los
   verticales se recortaban a la fuerza. Aquí cada foto va al compás que le
   corresponde por su relación de aspecto REAL (que el JS lee de la imagen)
   y el contenedor adopta esa relación: NINGUNA foto se recorta contra su
   formato. Petición literal del cliente.
   ========================================================================== */

.score {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  gap: clamp(0.75rem, 1.8vw, 2.25rem);
  align-items: start;
}
.score figure { margin: 0; }
.score figcaption {
  margin-top: 0.625rem;
  font-family: var(--font-body);
  font-size: 0.6875rem;
  letter-spacing: 0.08em;
  color: var(--ink-quiet);
}
/* Compás A — horizontal grande, dos tercios */
.bar-a { grid-column: 1 / span 8; }
/* Compás B — vertical apareado, formato retrato respetado */
.bar-b { grid-column: 9 / span 4; }
/* Compás C — horizontal a sangre */
.bar-c { grid-column: 1 / -1; }
/* Compás D — vertical alto, desplazado */
.bar-d { grid-column: 3 / span 4; margin-block-start: clamp(1.5rem, 5vw, 5rem); }
/* Compás E — horizontal mediana, en par */
.bar-e { grid-column: span 6; }
@media (max-width: 767px) {
  .bar-a, .bar-b, .bar-c, .bar-d, .bar-e { grid-column: 1 / -1; margin-block-start: 0; }
}

/* ==========================================================================
   14. PASOS, BANDA Y BLOQUES EDITORIALES
   ========================================================================== */

.steps {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(15rem, 100%), 1fr));
  gap: clamp(1.25rem, 2.4vw, 2rem);
}
.step { position: relative; padding: clamp(1.5rem, 2.6vw, 2.25rem) clamp(1.25rem, 2vw, 1.75rem); }
.step-num {
  font-family: var(--font-body);
  font-size: 0.8125rem;
  letter-spacing: 0.12em;
  color: var(--metal);
  margin-bottom: 1.25rem;
  display: block;
}
.step h3 { margin-bottom: 0.75rem; }
.step p { font-size: var(--fs-small); color: var(--ink-quiet); }

.band {
  display: flex;
  flex-wrap: wrap;
  gap: clamp(1.5rem, 3vw, 2.5rem);
  align-items: center;
  justify-content: space-between;
  padding: clamp(2rem, 4vw, 3.5rem);
  background-color: var(--surface);
}
.band > div { flex: 1 1 26rem; }
.band h2 { max-width: 28ch; }
.band p { color: var(--ink-quiet); margin-top: 1rem; max-width: 58ch; }
.band .eyebrow { margin-bottom: 1rem; }

/* Marco de escena a sangre (video de marca sin caja, la cornisa por encima) */
.scene-full {
  position: relative;
  min-height: clamp(24rem, 62vh, 44rem);
  overflow: clip;
  display: grid;
  align-items: center;
}
.scene-full > .scene-media {
  position: absolute;
  inset: 0;
  z-index: 0;
}
.scene-full > .scene-media img,
.scene-full > .scene-media video {
  width: 100%; height: 100%;
  object-fit: cover;
  filter: saturate(0.9) contrast(1.05);
}
.scene-full > .scene-media::after {
  content: "";
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(180deg, rgba(4, 16, 15, 0.55) 0%, rgba(4, 16, 15, 0.35) 40%, rgba(4, 16, 15, 0.85) 100%),
    radial-gradient(120% 70% at 50% 0%, rgba(218, 195, 159, 0.24) 0%, transparent 60%);
}
.scene-full > .shell { position: relative; z-index: 2; }

/* ==========================================================================
   15. FICHA DE PROPIEDAD
   ========================================================================== */

.prop-scene {
  position: relative;
  min-height: clamp(18rem, 48vh, 34rem);
  overflow: clip;
  background-color: var(--teal-900);
}
.prop-scene img { width: 100%; height: 100%; object-fit: cover; position: absolute; inset: 0; filter: saturate(0.93) contrast(1.04); }
.prop-scene::after {
  content: "";
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(180deg, rgba(4, 16, 15, 0.45) 0%, transparent 40%, rgba(4, 16, 15, 0.75) 100%),
    radial-gradient(120% 70% at 50% 0%, rgba(218, 195, 159, 0.22) 0%, transparent 58%);
}

.prop-head { position: relative; z-index: 5; margin-top: clamp(-4rem, -6vw, -2rem); }
.prop-panel { padding: clamp(1.5rem, 3.4vw, 3rem); background-color: var(--surface-solid); }
.prop-title-row { display: flex; flex-wrap: wrap; gap: 1.25rem 2.5rem; justify-content: space-between; align-items: start; }
.prop-title-row > div:first-child { flex: 1 1 28rem; }
.prop-title-row h1 { margin-block: 0.875rem 0.625rem; max-width: 26ch; }
.prop-price {
  font-family: var(--font-display);
  font-variant-numeric: tabular-nums;
  font-size: clamp(1.375rem, 2.6vw, 2rem);
  letter-spacing: -0.02em;
  color: var(--metal);
  white-space: nowrap;
  padding-top: 1rem;
}
.prop-price small { display: block; font-size: 0.625rem; letter-spacing: 0.14em; color: var(--ink-quiet); text-align: right; margin-top: 0.25rem; }

.spec-row { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-top: 1.5rem; }
.spec {
  padding: 0.5rem 0.9375rem;
  font-family: var(--font-body);
  font-size: 0.6875rem;
  letter-spacing: 0.05em;
  color: var(--ink-soft);
  border: 1px solid var(--hairline);
  line-height: 1.5;
}
.prop-grid { display: grid; grid-template-columns: minmax(0, 1.55fr) minmax(0, 1fr); gap: clamp(1.5rem, 3vw, 2.75rem); margin-top: clamp(1.75rem, 3.5vw, 2.5rem); align-items: start; }
@media (max-width: 60rem) { .prop-grid { grid-template-columns: 1fr; } }
.prose { font-size: var(--fs-body); line-height: 1.8; max-width: var(--measure); color: var(--ink-soft); }
.feature-list { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-top: 1.5rem; }
.feature {
  padding: 0.4375rem 0.875rem;
  font-family: var(--font-body);
  font-size: 0.6875rem;
  letter-spacing: 0.05em;
  color: var(--ink-quiet);
  border: 1px solid var(--hairline);
  line-height: 1.5;
}

/* Candado CDV. Panel oscuro dentro de escena clara: el cambio de valor
   convierte el candado en un acontecimiento. cream / teal-900 = 13,93 AAA. */
.lockbox {
  position: sticky;
  top: 5.5rem;
  padding: clamp(1.5rem, 2.8vw, 2.25rem);
  background-color: var(--teal-900);
  color: var(--cream);
  --ink-strong: var(--cream);
  --ink-soft: var(--cream-dim);
  --ink-quiet: #b9b8ad;
  --metal: var(--gold-400);
  --metal-quiet: var(--gold-500);
  --hairline: rgba(243, 241, 231, 0.16);
  --hairline-strong: rgba(203, 171, 81, 0.42);
  --molding-current: var(--molding);
  --well: rgba(4, 16, 15, 0.55);
  --focus-ring: var(--gold-400);
  --ok: var(--ok-dark);
  --err: var(--err-dark);
}
.lock-icon {
  width: 3.25rem; height: 3.25rem;
  display: grid; place-items: center;
  margin: 0 auto 1.25rem;
  color: var(--gold-400);
  border: 1px solid var(--hairline-strong);
  max-width: none;
}
.lockbox h3 { text-align: center; margin-bottom: 0.75rem; }
.lockbox > p { font-size: var(--fs-small); color: var(--cream-dim); margin: 0 auto 1.25rem; text-align: center; max-width: 34ch; }
.lockbox input {
  width: 100%;
  padding: 0.8125rem 1rem;
  margin-bottom: 0.75rem;
  border: 1px solid var(--hairline);
  background-color: var(--well);
  color: var(--cream);
  letter-spacing: 0.05em;
}
.lockbox input::placeholder { color: #9d9c92; letter-spacing: normal; }
.lockbox .hint { font-size: 0.78125rem; color: var(--ink-quiet); margin-top: 1.125rem; }
.lockbox label.check { display: flex; gap: 0.625rem; font-size: 0.78125rem; color: var(--cream-dim); margin: 0.375rem 0 1.125rem; align-items: start; line-height: 1.6; }
.lockbox label.check input { width: auto; margin: 0.25rem 0 0; accent-color: var(--gold-500); }

.private-block {
  padding: clamp(1.25rem, 2.4vw, 1.75rem);
  margin-top: 1.75rem;
  background-color: var(--well);
}
.private-block h4 {
  font-family: var(--font-body);
  font-weight: 400;
  color: var(--metal);
  font-size: 0.6875rem;
  text-transform: uppercase;
  letter-spacing: 0.2em;
  margin-bottom: 1.125rem;
}
.kv { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 0.625rem 1.5rem; font-size: var(--fs-small); }
.kv dt { font-family: var(--font-body); font-size: 0.6875rem; letter-spacing: 0.06em; text-transform: uppercase; color: var(--ink-quiet); padding-top: 0.1875rem; }
.kv dd { color: var(--ink-strong); overflow-wrap: anywhere; }

#map, .map-box, .region-map { height: clamp(20rem, 46vh, 30rem); z-index: 1; overflow: hidden; background-color: var(--teal-900); }
.map-frame { position: relative; padding: clamp(0.4rem, 0.8vw, 0.75rem); background-color: var(--surface); }
.map-note { font-size: 0.78125rem; color: var(--ink-quiet); margin-top: 0.75rem; }
.zone-ring { cursor: pointer; }
.leaflet-tooltip { font-family: var(--font-body); font-size: 0.8rem; line-height: 1.5; }
.leaflet-tooltip strong { font-family: var(--font-display); font-weight: 400; }
.map-offline { height: 100%; max-width: none; display: grid; place-items: center; text-align: center; padding: 2rem; color: var(--cream-dim); }

/* Animación de desbloqueo: la ficha se abre, no aparece de golpe. */
@keyframes a-unlock { from { opacity: 0; clip-path: inset(12% 0 0 0); } to { opacity: 1; clip-path: inset(0 0 0 0); } }
.unlocked-flash { animation: a-unlock 700ms var(--ease-threshold) both; }

/* ==========================================================================
   16. FORMULARIOS, TABLAS, PESTAÑAS Y DIÁLOGOS
   ========================================================================== */

.form-card {
  padding: clamp(1.75rem, 3.2vw, 2.75rem);
  max-width: 34rem;
  margin-inline: auto;
  background-color: var(--surface);
}
.form-card.wide { max-width: 50rem; }
.field { margin-bottom: 1.25rem; }
.field label {
  display: block;
  font-family: var(--font-body);
  font-size: 0.6875rem;
  text-transform: uppercase;
  letter-spacing: 0.16em;
  color: var(--metal);
  margin-bottom: 0.5rem;
}
.field input, .field select, .field textarea {
  width: 100%;
  padding: 0.75rem 0.9375rem;
  border: 1px solid var(--hairline);
  background-color: var(--well);
  color: var(--ink-strong);
}
.field select { appearance: auto; }
.field textarea { min-height: 7.5rem; resize: vertical; line-height: 1.7; }
.field input::placeholder, .field textarea::placeholder { color: var(--ink-quiet); }
.form-row { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1.125rem; }
.form-row-3 { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 1.125rem; }
@media (max-width: 40rem) { .form-row, .form-row-3 { grid-template-columns: 1fr; } }

.msg {
  padding: 0.8125rem 1.0625rem;
  font-size: var(--fs-small);
  margin: 1rem 0;
  display: none;
  line-height: 1.6;
  border-left: 2px solid currentColor;
  background-color: var(--well);
}
.msg.err { display: block; color: var(--err); }
.msg.ok { display: block; color: var(--ok); }

.tabs {
  display: flex;
  gap: 0;
  flex-wrap: wrap;
  margin-bottom: clamp(1.5rem, 3vw, 2.25rem);
  border-bottom: 1px solid var(--hairline);
}
.tab {
  position: relative;
  padding: 0.8125rem 1.125rem;
  font-family: var(--font-body);
  font-size: 0.6875rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-quiet);
  transition: color var(--dur-micro) var(--ease-threshold);
}
.tab::after {
  content: "";
  position: absolute;
  inset: auto 0 -1px 0;
  height: 1px;
  background-image: var(--gilt);
  transform: scaleX(0);
  transform-origin: center;
  transition: transform var(--dur-mid) var(--ease-threshold);
}
.tab:hover, .tab:focus-visible { color: var(--ink-strong); }
.tab:hover::after, .tab:focus-visible::after { transform: scaleX(0.7); }
.tab.active { color: var(--metal); }
.tab.active::after { transform: scaleX(1); }

.panel-stat-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(11rem, 100%), 1fr)); gap: clamp(0.75rem, 1.6vw, 1.25rem); margin-bottom: clamp(1.75rem, 3vw, 2.5rem); }
.pstat { padding: clamp(1.125rem, 2vw, 1.5rem); background-color: var(--surface); }
.pstat .n {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: clamp(1.125rem, 2vw, 1.5rem);
  color: var(--metal);
  letter-spacing: -0.02em;
  overflow-wrap: anywhere;
  line-height: 1.25;
}
.pstat .l { font-family: var(--font-body); font-size: 0.625rem; letter-spacing: 0.1em; text-transform: uppercase; color: var(--ink-quiet); margin-top: 0.5rem; }

.table-wrap { overflow-x: auto; background-color: var(--surface); }
table.data { width: 100%; border-collapse: collapse; font-size: var(--fs-small); min-width: 40rem; }
table.data th {
  text-align: left;
  padding: 0.875rem 1rem;
  font-family: var(--font-mono);
  font-weight: 400;
  font-size: 0.625rem;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--ink-quiet);
  border-bottom: 1px solid var(--hairline-strong);
  white-space: nowrap;
}
table.data td { padding: 0.8125rem 1rem; border-bottom: 1px solid var(--hairline); line-height: 1.6; vertical-align: top; color: var(--ink-soft); }
table.data tr:last-child td { border-bottom: none; }
table.data a { color: var(--metal); }
table.data a:hover { text-decoration: underline; text-decoration-color: var(--metal-quiet); }
.mono { font-family: var(--font-mono); }
.break { overflow-wrap: anywhere; }

.pill {
  display: inline-block;
  padding: 0.3125rem 0.6875rem;
  font-family: var(--font-body);
  font-size: 0.625rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  line-height: 1.4;
  border: 1px solid currentColor;
  white-space: nowrap;
}
.pill-ok { color: var(--ok); }
.pill-warn { color: var(--warn); }
.pill-err { color: var(--err); }
.pill-info { color: var(--metal); }

.code-reveal {
  font-family: var(--font-body);
  font-size: 1.375rem;
  letter-spacing: 0.18em;
  color: var(--gold-400);
  background-color: var(--well);
  padding: 1.125rem 1.25rem;
  text-align: center;
  margin: 1.125rem 0;
  border: 1px solid var(--hairline-strong);
  overflow-wrap: anywhere;
}

/* Diálogos. Foco atrapado, Escape y aria-modal los aporta el JS. */
.modal-back {
  position: fixed;
  inset: 0;
  background-color: rgba(4, 16, 15, 0.82);
  backdrop-filter: blur(7px);
  z-index: 500;
  display: none;
  align-items: center;
  justify-content: center;
  padding: 1.5rem;
}
.modal-back.open { display: flex; }
.modal {
  /* La ventana es OSCURA aunque el panel que la abre sea claro, así que los
     tokens de escena que dependen del fondo se redeclaran aquí. Sin esto, una
     fila «hecha» dentro de una ventana heredaría el mint de papel y su tinta
     verde oscura sobre teal: legible por accidente, ilegible en cuanto alguien
     cambie un tono. */
  --hecho: rgba(74, 200, 130, 0.15);
  --hecho-filete: #4ac882;
  --hecho-tinta: #a9e9c4;
  position: relative;
  background-color: var(--teal-900);
  color: var(--cream);
  --ink-strong: var(--cream);
  --ink-soft: var(--cream-dim);
  --ink-quiet: #b9b8ad;
  --metal: var(--gold-400);
  --metal-quiet: var(--gold-500);
  --hairline: rgba(243, 241, 231, 0.16);
  --hairline-strong: rgba(203, 171, 81, 0.42);
  --molding-current: var(--molding);
  --well: rgba(4, 16, 15, 0.55);
  --surface: rgba(58, 44, 28, 0.38);
  --focus-ring: var(--gold-400);
  --ok: var(--ok-dark);
  --err: var(--err-dark);
  padding: clamp(1.5rem, 3vw, 2.25rem);
  max-width: 34rem;
  width: 100%;
  max-height: 88vh;
  overflow-y: auto;
  animation: a-unlock var(--dur-mid) var(--ease-threshold) both;
}
.modal-wide { max-width: 45rem; }
.modal h3 { margin-bottom: 1rem; }
.modal > p { margin-bottom: 1.25rem; color: var(--ink-quiet); }

/* ==========================================================================
   17. PIE
   ========================================================================== */

footer.site-foot { padding-block: clamp(3rem, 6vw, 4.5rem) 2.25rem; }
footer.site-foot .cols { display: grid; grid-template-columns: 2fr 1fr 1fr; gap: clamp(1.75rem, 3.5vw, 3rem); margin-bottom: 2.75rem; }
@media (max-width: 48rem) { footer.site-foot .cols { grid-template-columns: 1fr; gap: 2rem; } }
footer.site-foot h4 {
  font-family: var(--font-body);
  font-size: 0.625rem;
  font-weight: 400;
  text-transform: uppercase;
  letter-spacing: 0.22em;
  color: var(--metal);
  margin-bottom: 1.125rem;
}
footer.site-foot a.f-link { display: block; color: var(--ink-quiet); font-size: var(--fs-small); margin-bottom: 0.625rem; transition: color var(--dur-micro) var(--ease-threshold); }
footer.site-foot a.f-link:hover { color: var(--ink-strong); }
.f-social { display: flex; gap: 0.5rem; margin-top: 1rem; flex-wrap: wrap; }
.f-social a {
  width: 2.5rem; height: 2.5rem;
  display: grid; place-items: center;
  border: 1px solid var(--hairline-strong);
  color: var(--metal);
  font-size: 0.6875rem;
  font-family: var(--font-body);
  letter-spacing: 0.06em;
  transition: background-color var(--dur-micro) var(--ease-threshold);
}
.f-social a:hover { background-color: var(--well); }
.legal { border-top: 1px solid var(--hairline); padding-top: 1.5rem; font-size: 0.75rem; color: var(--ink-quiet); line-height: 1.8; max-width: none; }

/* ==========================================================================
   18. ESQUELETOS
   ========================================================================== */

.skeleton {
  height: 20rem;
  background-image: linear-gradient(100deg, rgba(58, 44, 28, 0.35) 25%, rgba(110, 86, 66, 0.45) 50%, rgba(58, 44, 28, 0.35) 75%);
  background-size: 300% 100%;
  animation: a-shimmer 1.6s linear infinite;
}
@keyframes a-shimmer { from { background-position: 150% 0; } to { background-position: -150% 0; } }

/* ==========================================================================
   19. MOVIMIENTO — CSS scroll-driven
   Corre en el hilo de composición del navegador y cuesta 0 KB de JS.

   REGLA QUE NO SE NEGOCIA: el ESTADO FINAL es el estado por DEFECTO, y solo
   se revierte dentro de `@supports (animation-timeline: view())`. En un
   navegador sin soporte no hay destello ni contenido invisible: hay una
   página estática correcta. Nunca se deja algo en `opacity: 0` esperando
   una feature — ese bug ya pasó en este proyecto (38 elementos invisibles y
   un <h1> que no aparecía).
   ========================================================================== */

@keyframes m-rise { from { opacity: 0; transform: translateY(2.25rem); } to { opacity: 1; transform: none; } }
@keyframes m-line { from { transform: translateY(105%); } to { transform: translateY(0); } }
@keyframes m-draw { from { transform: scaleX(0); } to { transform: scaleX(1); } }
@keyframes m-draw-y { from { transform: scaleY(0); } to { transform: scaleY(1); } }
@keyframes m-drift { from { transform: translateY(-5%) scale(1.12); } to { transform: translateY(5%) scale(1.12); } }
@keyframes m-recede {
  from { opacity: 1; transform: scale(1); letter-spacing: -0.03em; }
  to   { opacity: 0; transform: scale(0.9); letter-spacing: 0.05em; }
}
@keyframes m-threshold { from { clip-path: inset(100% 0 0 0); } to { clip-path: inset(0 0 0 0); } }
/* Ninguna lámina va torcida. Reducir la rotación de 2,2° a 1° no arregló el
   problema, solo lo hizo menos visible: una moldura fuera de plomo contradice
   el vocabulario de la marca, cuyos paneles de recepción están todos a plomo.
   Un catálogo inmobiliario con fichas torcidas parece un collage.

   Se conserva solo la profundidad: la pieza del centro a escala plena y las de
   los bordes un punto atrás. Eso sí lee como vitrina. */
@keyframes m-rail-piece {
  0%   { scale: 0.965; }
  50%  { scale: 1; }
  100% { scale: 0.965; }
}
@keyframes m-specular { from { background-position: -60% 0; } to { background-position: 160% 0; } }

/* Apertura de umbral AL CARGAR, no al hacer scroll.
   `view()` no sirve para el primer elemento a pantalla completa: su fase
   `entry` ya está agotada en el primer paint porque no hay distancia previa
   desde la que entrar. Y conceptualmente el umbral se abre cuando uno LLEGA. */
@keyframes m-threshold-load {
  from { clip-path: inset(100% 0 0 0); transform: scale(1.04); }
  to   { clip-path: inset(0 0 0 0); transform: scale(1); }
}
.m-threshold-load { animation: m-threshold-load 1400ms var(--ease-threshold) 120ms both; }

@supports (animation-timeline: view()) {
  .m-rise {
    animation: m-rise linear both;
    animation-timeline: view();
    animation-range: entry 8% cover 26%;
  }
  /* Escalonado: el retardo no funciona con timelines de scroll, así que se
     desplaza el RANGO de cada hijo según su índice `--i`. */
  .m-stagger > * {
    animation: m-rise linear both;
    animation-timeline: view();
    animation-range: entry calc(4% + var(--i, 0) * 4%) cover calc(22% + var(--i, 0) * 5%);
  }
  /* Líneas que emergen por una puerta: el clip va en el contenedor y la
     translación en la línea. Sin las dos cosas el texto se corta en seco. */
  .m-lines > span { display: block; overflow: clip; }
  .m-lines > span > span {
    display: block;
    animation: m-line linear both;
    animation-timeline: view();
    animation-range: entry calc(6% + var(--i, 0) * 5%) cover calc(26% + var(--i, 0) * 6%);
  }
  .m-draw {
    transform-origin: left center;
    animation: m-draw linear both;
    animation-timeline: view();
    animation-range: entry 12% cover 30%;
  }
  .m-draw-y {
    transform-origin: top center;
    animation: m-draw-y linear both;
    animation-timeline: view();
    animation-range: entry 10% cover 40%;
  }
  /* Parallax interno: la imagen deriva más despacio que su marco. Ya viene
     con scale(1.12) para no descubrir el borde. */
  .m-drift {
    animation: m-drift linear both;
    animation-timeline: view();
    animation-range: cover 0% cover 100%;
  }
  /* El rótulo del umbral cede el paso mientras la cámara avanza. */
  .m-recede {
    animation: m-recede linear both;
    animation-timeline: scroll(root block);
    animation-range: 0 90vh;
  }
  /* Barra de progreso de lectura. */
  .m-progress {
    transform-origin: left center;
    animation: m-draw linear both;
    animation-timeline: scroll(root block);
  }
  /* La sección SE ENCIENDE al entrar. */
  .m-lights-on {
    animation: a-lights-on linear both;
    animation-timeline: view();
    animation-range: entry 10% cover 40%;
  }
  /* Las piezas de la vitrina giran levemente al pasar, como en un expositor.
     Timeline en el eje inline: la mide el propio scroll horizontal. */
  .m-rail-piece {
    animation: m-rail-piece linear both;
    animation-timeline: view(inline);
    animation-range: cover 0% cover 100%;
  }
  /* Especular sobre el metal, ligado al scroll: lo que hace que el oro
     parezca metal y no color amarillo. */
  .m-specular {
    animation: m-specular linear both;
    animation-timeline: view();
    animation-range: cover 0% cover 100%;
  }
  .m-threshold {
    animation: m-threshold linear both;
    animation-timeline: view();
    animation-range: entry 0% cover 34%;
  }
}

/* Barra de progreso de lectura. Es el único elemento cuyo estado final NO es
   un estado por defecto aceptable (una barra llena miente sobre la posición),
   así que se retira por completo donde no hay timelines de scroll. */
.progress-rail { position: fixed; inset: 0 0 auto 0; height: 2px; z-index: 400; pointer-events: none; }
.progress-rail > span { display: block; height: 100%; background-image: var(--gilt); }
@supports not (animation-timeline: scroll()) {
  .progress-rail { display: none; }
}

/* ==========================================================================
   20. PREFERENCIAS DEL USUARIO
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 200ms !important;
  }
  /* Sin scrub, sin parallax, sin grano en movimiento, sin vitrina que gire.
     El sitio sigue COMPLETO y sigue siendo bello: solo deja de moverse. */
  .grain::after, .cue span[aria-hidden], .skeleton { animation: none !important; }
  .m-rise, .m-stagger > *, .m-lines > span > span, .m-draw, .m-draw-y,
  .m-drift, .m-recede, .m-progress, .m-lights-on, .m-rail-piece,
  .m-specular, .m-threshold, .m-threshold-load, .unlocked-flash, .modal {
    animation: none !important;
    opacity: 1 !important;
    transform: none !important;
    clip-path: none !important;
    rotate: none !important;
    scale: none !important;
    translate: none !important;
  }
  /* La barra de progreso sin scrub quedaría llena y mentiría: se retira. */
  .progress-rail { display: none; }
  .rail { scroll-snap-type: none; scroll-behavior: auto; }
  .card-rule { transform: scaleX(1) !important; }
  .card-meta { transform: none !important; opacity: 1 !important; }
  video { /* el autoplay lo apaga el JS al detectar la preferencia */ }
}

@media (prefers-contrast: more) {
  .on-dark { --ink-strong: var(--pure); --ink-soft: var(--pure); --ink-quiet: var(--cream); --hairline: rgba(255,255,255,0.4); }
  .on-light { --ink-soft: var(--ink); --ink-quiet: var(--bronze-900); --hairline: rgba(4,16,15,0.45); }
  .plate-graded::before, .sconces::after, .cove-light::before, .penumbra::after { opacity: 0.35; }
  .grain::after { display: none; }
}

/* ==========================================================================
   21. RESPONSIVE
   ========================================================================== */

@media (max-width: 60rem) {
  .lockbox { position: static; }
  .prop-head { margin-top: clamp(-2.5rem, -4vw, -1.5rem); }
}

@media (max-width: 45rem) {
  .nav-inner { min-height: 3.75rem; gap: 0.5rem; }
  .brand { font-size: 1rem; }
  .brand img { height: 2rem; }
  .nav-links { gap: 0; font-size: 0.8125rem; }
  .nav-links a, .nav-links button { padding: 0.5rem 0.5rem; }
  /* `.hide-sm` tiene que valer para <a> Y para <button>: «Salir» es un botón
     desde que se quitaron los handlers inline, y con el selector antiguo
     (`a.hide-sm`) la barra se partía en tres filas en móvil. */
  .nav-links .hide-sm { display: none; }
  .nav-links .pill { display: none; }
  .nav-links a:not(.btn)::after { left: 0.5rem; right: 0.5rem; }
  .searchbar { padding: 0.625rem; }
  .searchbar select, .searchbar input, .searchbar .btn { flex: 1 1 100%; }
  .stat-chip { flex: 1 1 100%; }
  .prop-panel { padding: 1.25rem 1.125rem; }
  .rail { grid-auto-columns: 78vw; }
}

/* ==========================================================================
   RECORRIDO EN VIDEO DEL INMUEBLE
   Verticales de 464x832 a 576x1024, grabados en teléfono, de 2 a 87 segundos.
   Enmarcados en 9:16 dentro de un panel con moldura: estirarlos a pantalla
   completa desde 576 px de ancho destruye el detalle y se ve barato.
   ========================================================================== */
.tour-frame {
  position: relative;
  isolation: isolate;
  width: min(100%, 26rem);
  margin-inline: auto;
  padding: clamp(0.5rem, 1.1vw, 1.25rem);
  background: color-mix(in oklab, var(--bronze-900) 42%, transparent);
}
.tour-frame::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 4;
  pointer-events: none;
  padding: 1px;
  background: var(--molding);
  mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  mask-composite: exclude;
}
.tour-media {
  display: block;
  width: 100%;
  aspect-ratio: 9 / 16;
  object-fit: cover;
  background: var(--teal-900);
}
/* Los controles nativos se dejan visibles a propósito: en un recorrido de 87
   segundos, poder saltar es más importante que un reproductor a medida. */
.tour-media::-webkit-media-controls-panel { background: color-mix(in oklab, var(--ink) 70%, transparent); }

/* ==========================================================================
   UMBRAL — el cruce entre capítulos
   La cámara ATRAVIESA de un espacio a otro (cocina→sala, piscina→sala). Es el
   gesto que da nombre al concepto y estaba sin usar: 3,1 MB de video muertos
   en disco. Va a sangre y sin marco; meterlo en una caja lo mataría.
   Alto contenido: es un respiro entre capítulos, no una sección con contenido.
   ========================================================================== */
.umbral { min-height: 62vh; display: grid; place-items: center; }
.umbral .shell { position: relative; z-index: 3; text-align: center; }
.umbral .eyebrow { font-size: clamp(0.75rem, 1.5vw, 1rem); letter-spacing: 0.22em; }
@media (max-width: 767px) { .umbral { min-height: 48vh; } }

/* ==========================================================================
   PAISAJE — gradación mínima
   `plate-graded` está calibrada para fotos de WhatsApp desiguales: desatura,
   mete teal en sombras y cierra con viñeta. Aplicada al atardecer aéreo del
   Eje Cafetero lo mataba: un cielo de oro y salmón sobre colinas verdes quedaba
   en sopa teal oscura, que es exactamente lo que el cliente señaló.

   Este material NO necesita unificarse con nada: ya es bueno. Se le deja el
   color, se sube un punto de saturación y solo se sostiene la base para que el
   texto encima siga legible.
   ========================================================================== */
.plate-landscape > video,
.plate-landscape > img,
.plate-landscape > picture > img {
  filter: saturate(1.06) contrast(1.03);
}
.plate-landscape::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  /* Solo el pie, y cálido: el degradado sujeta el borde inferior sin tocar el
     cielo. Nada de viñeta radial ni duotono encima del atardecer. */
  background-image: linear-gradient(
    to bottom,
    transparent 0%,
    transparent 58%,
    rgba(10, 39, 38, 0.55) 88%,
    var(--teal-900) 100%
  );
}

/* Recuento de resultados del buscador del umbral.
   Aparece bajo la barra tras pulsar BUSCAR: es la confirmación inmediata de que
   la búsqueda hizo algo, en el sitio donde el usuario estaba mirando. Sin esto,
   los resultados cambiaban tres pantallas más abajo y la acción parecía muerta. */
.search-count {
  margin: 0.75rem 0 0;
  font-family: var(--font-body);
  font-size: var(--fs-small, 0.8125rem);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--gold-300, #DAC39F);
}

/* ==========================================================================
   MAPA — chinchetas de precio y ventana de inmueble
   Sustituyen a los aros de 420 m, que a zoom de región eran puntitos y nada
   indicaba que se pudieran pulsar. El aro se conserva debajo, más tenue, porque
   comunica algo cierto: la posición publicada es una ZONA, no el punto exacto.
   ========================================================================== */
.mapa-precio { background: none; border: 0; }
.mapa-precio span {
  display: inline-block;
  transform: translate(-50%, -140%);
  white-space: nowrap;
  padding: 0.3rem 0.6rem;
  border-radius: 999px;
  background: #04100F;
  border: 1px solid #CBAB51;
  color: #F0E6D2;
  font-family: var(--font-body);
  font-size: 0.75rem;
  letter-spacing: 0.02em;
  box-shadow: 0 2px 10px rgb(0 0 0 / 0.45);
  cursor: pointer;
}
.mapa-precio span:hover,
.mapa-precio:focus-visible span { background: #CBAB51; color: #04100F; }

.mapa-popup .leaflet-popup-content-wrapper { border-radius: 4px; padding: 0; overflow: hidden; }
.mapa-popup .leaflet-popup-content { margin: 0; width: 240px !important; }
.mapa-tarjeta img { display: block; width: 100%; height: 150px; object-fit: cover; }
.mapa-tarjeta h4 { margin: 0.7rem 0.8rem 0.15rem; font-size: 0.95rem; line-height: 1.25; }
.mapa-zona { margin: 0 0.8rem; font-size: 0.75rem; color: #6b6b6b; }
.mapa-precio-txt { margin: 0.35rem 0.8rem 0.6rem; font-weight: 600; }
.mapa-tarjeta .btn { margin: 0 0.8rem 0.8rem; width: calc(100% - 1.6rem); }

/* ==========================================================================
   14. CRISTAL — y por qué solo en cuatro sitios
   ==========================================================================
   El glassmorphism sirve cuando hay ALGO DETRÁS que difuminar y el elemento
   flota por encima. Sobre un fondo plano no refracta nada: solo ensucia el
   color y cuesta una capa de composición. Por eso aquí va exactamente donde se
   gana algo y en ningún otro lugar:

     1. La barra de navegación — pasa por encima de vídeo, mármol y mapa.
     2. El buscador del héroe — flota sobre el vídeo.
     3. Las insignias sobre las fotos — texto blanco sobre imagen impredecible.
     4. El mapa: etiquetas de precio y ventana — sobre teselas ajenas.

   NO va en las tarjetas del catálogo: se apoyan en mármol plano y el cristal
   las volvería turbias sin ganar nada.

   Todo lleva respaldo: si el navegador no soporta `backdrop-filter`, el color
   sólido de reserva mantiene el contraste. El cristal es un lujo, no la única
   defensa de la legibilidad.
   ========================================================================== */

:root {
  --vidrio-borde: rgba(255, 255, 255, 0.14);
  --vidrio-luz: rgba(255, 255, 255, 0.10);
}

/* --- 1. Barra de navegación ------------------------------------------------
   Cristal más profundo y con un filo de luz superior, que es lo que separa el
   «cristal» del «panel translúcido»: un borde que capta la luz del entorno. */
.nav {
  background-color: rgba(4, 16, 15, 0.62);
  border-top: 1px solid var(--vidrio-luz);
}
@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
  .nav {
    background-color: rgba(4, 16, 15, 0.42);
    -webkit-backdrop-filter: blur(22px) saturate(1.6);
    backdrop-filter: blur(22px) saturate(1.6);
  }
}

/* --- 2. Buscador del héroe -------------------------------------------------
   Es el elemento con más trabajo que hacer de toda la portada y estaba plano.
   Cristal, filo de luz arriba y sombra proyectada para despegarlo del vídeo. */
.searchbar {
  background-color: rgba(10, 39, 38, 0.72);
  border: 1px solid var(--vidrio-borde);
  border-top-color: var(--vidrio-luz);
  box-shadow: 0 18px 48px rgb(0 0 0 / 0.42), inset 0 1px 0 rgb(255 255 255 / 0.07);
}
@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
  .searchbar {
    background-color: rgba(10, 39, 38, 0.44);
    -webkit-backdrop-filter: blur(20px) saturate(1.5);
    backdrop-filter: blur(20px) saturate(1.5);
  }
  /* Los campos, un grado MENOS de cristal que el panel: si los dos tuvieran el
     mismo, el conjunto se leería como una mancha sin jerarquía. */
  .searchbar select, .searchbar input {
    background-color: rgba(4, 16, 15, 0.42);
    -webkit-backdrop-filter: blur(6px);
    backdrop-filter: blur(6px);
  }
}

/* --- 3. Insignias sobre fotografía ----------------------------------------
   «Venta», «Verificada», «Ficha con código». Van sobre una foto que puede ser
   clara u oscura, así que el cristal les da un fondo propio sin taparla. */
.badge, .lock-pill {
  border: 1px solid var(--vidrio-borde);
}
@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
  .badge, .lock-pill {
    background-color: rgba(4, 16, 15, 0.46);
    -webkit-backdrop-filter: blur(12px) saturate(1.4);
    backdrop-filter: blur(12px) saturate(1.4);
  }
}

/* --- 4. Mapa: etiquetas y ventana -----------------------------------------
   Sobre teselas de OpenStreetMap, que son claras, saturadas y ajenas a la
   marca. El cristal las integra sin taparlas. */
@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
  .mapa-precio span {
    background-color: rgba(4, 16, 15, 0.68);
    -webkit-backdrop-filter: blur(10px) saturate(1.4);
    backdrop-filter: blur(10px) saturate(1.4);
  }
  .mapa-popup .leaflet-popup-content-wrapper {
    background-color: rgba(246, 245, 241, 0.82);
    -webkit-backdrop-filter: blur(16px) saturate(1.3);
    backdrop-filter: blur(16px) saturate(1.3);
  }
}

/* El botón flotante de WhatsApp: flota sobre TODO, así que es el caso más claro. */
@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
  .wa-float {
    background-color: rgba(18, 64, 63, 0.58);
    -webkit-backdrop-filter: blur(14px) saturate(1.5);
    backdrop-filter: blur(14px) saturate(1.5);
    border: 1px solid var(--vidrio-borde);
  }
}

/* ==========================================================================
   15. AJUSTES DE DIAGNÓSTICO — fotografía, ritmo y anclas
   ========================================================================== */

/* --- El menú fijo ya no se come los titulares ------------------------------
   «La colección» aparecía CORTADA POR LA MITAD detrás de la barra al llegar por
   un ancla, y desde que BUSCAR desplaza hasta ahí, ese corte era el estado
   normal después de cada búsqueda. `scroll-margin-top` reserva la altura de la
   barra al saltar; se aplica a los destinos de ancla, no a todo. */
:root { --alto-nav: 4.75rem; }
#explorar, #mapa, #contacto, [id^="h-"], .chapter[id] {
  scroll-margin-top: calc(var(--alto-nav) + 1.5rem);
}

/* --- La gradación deja de apagar las fotos ---------------------------------
   `plate-graded` apila viñeta marrón al 42 %, duotono oro-teal y una bajada de
   saturación. Se calibró para unificar fotos de WhatsApp desiguales, pero pagan
   justos por pecadores: aplasta también las buenas, que son las que venden.
   En las TARJETAS se alivia a la mitad; en las escenas grandes se conserva,
   porque ahí la viñeta sí construye la atmósfera. */
.card-img.plate-graded::before {
  background-image:
    radial-gradient(120% 90% at 50% 40%, transparent 58%, rgba(58, 44, 28, 0.20) 100%),
    linear-gradient(163deg, rgba(203, 171, 81, 0.05) 0%, transparent 55%, rgba(18, 64, 63, 0.07) 100%);
}
.card-img.plate-graded > picture > img,
.card-img.plate-graded > img {
  /* Sin bajar saturación: la foto de un inmueble es el producto. */
  filter: contrast(1.03);
}

/* --- El precio, legible de un vistazo -------------------------------------- */
.card-price {
  font-size: clamp(1.125rem, 1.5vw, 1.4375rem);
  letter-spacing: -0.01em;
  line-height: 1.15;
}
.card-price small {
  font-family: var(--font-body);
  font-size: 0.6875rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  opacity: 0.62;
}

/* --- Marca del menú: una sola vez -----------------------------------------
   Llevaba el logo completo (que ya dice AL INMOBILIARIA · PEREIRA ·
   DOSQUEBRADAS) Y al lado el mismo texto otra vez. Dicho dos veces, y el logo
   a esa altura convertía su detalle dorado en un borrón.
   Ahora va el MONOGRAMA —solo la A, la L y la casa, que a 2 rem sí se lee— y el
   texto hace de marca denominativa. Cada pieza dice algo distinto. */
.brand img { height: 2.125rem; width: auto; }
@media (max-width: 46rem) { .brand img { height: 1.75rem; } }

/* ==========================================================================
   16. VOLTAJE — el héroe enseña, la marca sabe de dónde es
   ==========================================================================
   El diagnóstico decía que el sitio «se siente genérico». Las tres causas que
   quedaban por atacar son estas, y ninguna se arregla con más decoración:
     · El héroe no enseña ningún inmueble.
     · Nada en el color dice Eje Cafetero.
     · La fotografía —el único activo real— pesaba menos que la tipografía.
   ========================================================================== */

/* --- 16.1  Ámbar del atardecer: identidad sin inventar una marca nueva ------
   No se añade una paleta ajena. Estos tonos están SACADOS del vídeo de las
   colinas que ya vive en la sección 02: el mismo atardecer que se ve al bajar.
   Así el color de acento y el material fotográfico dicen lo mismo, que es lo
   que hace que un sitio parezca de un sitio y no de una plantilla. */
:root {
  --atardecer: #e8a34e;         /* sol bajo sobre las colinas */
  --atardecer-hondo: #b8622a;   /* la tierra al contraluz */
  --cafetal: #24605f;           /* ya existía como teal-600: aquí se nombra */
  --brasa: linear-gradient(105deg,
    var(--atardecer-hondo) 0%, var(--atardecer) 38%,
    var(--gold-300) 52%, var(--atardecer) 66%, var(--atardecer-hondo) 100%);
}

/* --- 16.2  EL HÉROE ENSEÑA -------------------------------------------------
   El vídeo estaba al 42 % de opacidad Y con un velo oscuro encima: el resultado
   era un rectángulo negro. Un héroe de inmobiliaria que no enseña un inmueble
   está desperdiciando la primera pantalla.

   La solución no es quitar el velo —el texto dejaría de leerse— sino ORIENTARLO:
   oscuro donde vive el texto (izquierda y pie), transparente donde está la
   imagen (derecha y alto). Es el recurso editorial de toda la vida y funciona
   porque el ojo lee a la izquierda y mira a la derecha. */
.hero-scene img, .hero-scene video {
  opacity: 0.88;
  filter: saturate(1.02) contrast(1.06);
}
.hero-scene::after {
  background-image:
    /* velo direccional: protege el texto, libera la imagen */
    linear-gradient(100deg,
      rgba(4, 16, 15, 0.92) 0%,
      rgba(4, 16, 15, 0.78) 34%,
      rgba(4, 16, 15, 0.30) 62%,
      rgba(4, 16, 15, 0.08) 100%),
    /* cierre inferior para empalmar con la franja de datos */
    linear-gradient(180deg, transparent 55%, rgba(4, 16, 15, 0.72) 88%, var(--ink) 100%),
    /* calidez del atardecer entrando por el alto */
    radial-gradient(90% 70% at 78% 0%, rgba(232, 163, 78, 0.20) 0%, transparent 60%);
}
/* Menos aire para que el buscador entre en la primera pantalla: era lo único
   accionable del héroe y quedaba por debajo del pliegue en portátiles. */
.hero { padding-block: clamp(2.5rem, 6vh, 4.5rem) clamp(2.25rem, 5vh, 3.5rem); }
.hero .t-lead { max-width: 44ch; margin-bottom: clamp(1.25rem, 3vh, 1.75rem); }
.hero .t-display { margin-block: 0.75rem 1rem; }

/* --- 16.3  MÁS VOLTAJE TIPOGRÁFICO ----------------------------------------
   El titular era grande pero blando: interletrado suelto y peso ligero lo
   dejaban en «bonito». Se cierra el tracking y se marca el contraste entre la
   romana y la cursiva dorada, que es el gesto de la marca. */
.t-display {
  letter-spacing: -0.022em;
  line-height: 0.94;
}
.t-display em {
  font-style: italic;
  background-image: var(--brasa);
  background-size: 220% 100%;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
.chapter h2 { letter-spacing: -0.018em; }

/* --- 16.4  LA FOTOGRAFÍA MANDA --------------------------------------------
   La tarjeta repartía el peso a partes iguales entre foto y texto. En una
   inmobiliaria la foto decide el clic: se le da altura y se le sube el precio
   ENCIMA, sobre cristal. Aquí el cristal sí trabaja — hay una fotografía
   impredecible detrás y el precio tiene que leerse sobre cualquiera de ellas. */
.card-img { aspect-ratio: 3 / 2; }
.card-precio-flotante {
  position: absolute;
  left: 0.625rem; bottom: 0.625rem;
  z-index: 3;
  display: inline-flex;
  align-items: baseline;
  gap: 0.375rem;
  padding: 0.4375rem 0.75rem;
  border: 1px solid var(--vidrio-borde);
  background-color: rgba(4, 16, 15, 0.72);
  color: var(--cream);
  font-family: var(--font-display);
  font-variant-numeric: tabular-nums;
  font-size: 1.0625rem;
  letter-spacing: -0.01em;
  line-height: 1.1;
}
.card-precio-flotante small {
  font-family: var(--font-body);
  font-size: 0.5625rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  opacity: 0.7;
}
@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
  .card-precio-flotante {
    background-color: rgba(4, 16, 15, 0.42);
    -webkit-backdrop-filter: blur(16px) saturate(1.5);
    backdrop-filter: blur(16px) saturate(1.5);
  }
}
/* El precio sube a la foto, así que abajo manda el TÍTULO. */
.card-body { padding-top: 0.875rem; gap: 0.375rem; }
.card-title { font-size: 1.1875rem; letter-spacing: -0.01em; }

/* La píldora del código se mueve a la derecha ARRIBA: abajo ya está el precio. */
.lock-pill { bottom: auto; top: 0.625rem; right: 0.625rem; }

/* --- 16.5  EL HOVER SE SIENTE ---------------------------------------------
   Antes: un zoom del 7 % y poco más. Ahora la tarjeta se levanta, el filete
   dorado barre de izquierda a derecha y la brasa entra por el canto. */
.card {
  transition: background-color var(--dur-mid) var(--ease-threshold),
              transform var(--dur-mid) var(--ease-threshold),
              box-shadow var(--dur-mid) var(--ease-threshold);
}
.card:hover, .card:focus-visible, .card:focus-within {
  transform: translateY(-0.375rem);
  box-shadow: 0 22px 46px rgb(4 16 15 / 0.20);
}
.card-rule { background-image: var(--brasa); height: 2px; }
@media (prefers-reduced-motion: reduce) {
  .card:hover, .card:focus-visible, .card:focus-within { transform: none; }
}

/* --- 16.6  LAS COSTURAS, CON BRASA ---------------------------------------- */
.seam-to-light::after, .seam-to-dark::after { background-image: var(--brasa); }
.nav::after { background-image: var(--brasa); opacity: 0.85; }

/* --- 16.7  (retirado) ------------------------------------------------------
   Aquí vivió la tarjeta de inmueble destacado del héroe. Se retiró por
   decisión de la dueña del proyecto: el héroe limpio respira mejor y el
   buscador queda como único protagonista de la primera pantalla. El HTML
   y el JS que la alimentaban se retiraron con ella. */

/* ==========================================================================
   17. PREMIUM — el lujo es quitar
   ==========================================================================
   La pasada anterior subió contraste y color: voltaje eléctrico. Pero lo que
   distingue una marca inmobiliaria premium de una plantilla vistosa es lo
   contrario — AIRE, CONTENCIÓN y ESCALA. Un Sotheby's no grita; deja espacio.

   Este bloque aplica cuatro reglas y deshace dos excesos de la pasada anterior:

     1. El doble de aire entre secciones. El espacio en blanco ES el lujo.
     2. Tarjetas más grandes y menos por fila: pieza de galería, no catálogo.
     3. El cromo (nav, chips, indicadores) se encoge y se calla.
     4. El movimiento se vuelve lento y físico: nada «salta».

   Deshace: la brasa en las costuras (era ruido repetido seis veces) y el
   barrido dorado del hover (feria). La brasa queda SOLO en el titular del héroe
   y en el filete del menú — un acento usado una vez es un gesto; seis, un tema
   de PowerPoint.
   ========================================================================== */

/* --- 17.1  AIRE ------------------------------------------------------------ */
:root {
  --chapter-space: clamp(6.5rem, 16vh, 13rem);
}
.section-head { margin-bottom: clamp(2.5rem, 6vh, 4.5rem); }
.chapter h2 { margin-bottom: 0.75rem; }

/* --- 17.2  LA REJILLA RESPIRA ----------------------------------------------
   De «cuantas quepan de 22rem» a piezas de mínimo 26rem con separación 4rem.
   Con 6 inmuebles, tres filas holgadas de dos valen más que dos filas
   apretadas de tres: cada propiedad se mira, no se escanea. */
.grid {
  grid-template-columns: repeat(auto-fill, minmax(min(26rem, 100%), 1fr));
  gap: clamp(2rem, 4.5vw, 4rem);
}
.card { padding: 0; background-color: transparent; }
.card:hover, .card:focus-visible, .card:focus-within { background-color: transparent; }
.card-body { padding-inline: 0; }

/* --- 17.3  EL CROMO SE CALLA ----------------------------------------------- */
/* La tira de datos, en susurro: era tres frases compitiendo con el héroe. */
.stats-band { padding-block: clamp(1.5rem, 3vh, 2.25rem); }
.stat-chip { font-size: 0.75rem; line-height: 1.55; opacity: 0.82; }
.stat-chip b { font-size: 0.8125rem; }

/* El indicador de scroll no necesita gritar en mayúsculas con animación. */
.cue { letter-spacing: 0.1em; opacity: 0.55; }
.cue span[aria-hidden] { animation-duration: 3.6s; }

/* Insignias: más pequeñas y sin borde llamativo. La foto manda. */
.badge { font-size: 0.5rem; padding: 0.3125rem 0.5625rem; letter-spacing: 0.1em; }
.lock-pill { font-size: 0.5625rem; opacity: 0.85; }

/* --- 17.4  MOVIMIENTO FÍSICO, NO EFECTISTA --------------------------------- */
.card { transition-duration: 560ms; }
.card:hover, .card:focus-visible, .card:focus-within {
  transform: translateY(-0.25rem);
  box-shadow: 0 26px 60px rgb(4 16 15 / 0.16);
}
.card:hover .card-img img, .card:focus-visible .card-img img, .card:focus-within .card-img img {
  transform: scale(1.035);
  transition-duration: 900ms;
}

/* --- 17.5  DESHACER LOS EXCESOS DE LA PASADA ANTERIOR ---------------------- */
/* La brasa vuelve a oro sereno en costuras y filete de tarjeta. */
.seam-to-light::after, .seam-to-dark::after { background-image: var(--gilt); }
.card-rule { background-image: var(--gilt); height: 1px; }

/* --- 17.6  TIPOGRAFÍA CON MÁS CUERPO --------------------------------------- */
/* El titular del héroe, más grande aún: es el único elemento que debe dominar. */
:root { --fs-display: clamp(2.75rem, 9vw, 8rem); }
.hero .t-lead { font-size: clamp(0.9375rem, 1.15vw, 1.0625rem); opacity: 0.88; }

/* Títulos de sección en escala editorial: grandes, serenos, sin adornos. */
.chapter h2 { font-size: clamp(2rem, 5vw, 3.75rem); line-height: 1.02; }
.section-head p { max-width: 52ch; }

/* --- 17.7  LA FICHA COMO OBJETO -------------------------------------------
   El precio flotante pierde la caja de cristal en reposo: aparece SOLO al
   pasar el ratón o enfocar. En reposo la foto está limpia — como en los
   catálogos de subastas, donde el precio no mancha la lámina. En táctil
   (sin hover) se muestra siempre, porque ahí no hay «pasar el ratón». */
@media (hover: hover) {
  .card-precio-flotante {
    opacity: 0;
    transform: translateY(0.375rem);
    transition: opacity 420ms var(--ease-threshold), transform 420ms var(--ease-threshold);
  }
  .card:hover .card-precio-flotante,
  .card:focus-visible .card-precio-flotante,
  .card:focus-within .card-precio-flotante {
    opacity: 1;
    transform: none;
  }
  /* Y el precio vuelve TAMBIÉN al cuerpo en reposo, para que nunca falte. */
}
.card-title { font-size: clamp(1.1875rem, 1.6vw, 1.375rem); }
.card-precio-cuerpo {
  display: block;
  font-family: var(--font-display);
  font-variant-numeric: tabular-nums;
  font-size: 1.0625rem;
  letter-spacing: -0.01em;
  color: var(--metal);
}
.card-precio-cuerpo small {
  font-family: var(--font-body);
  font-size: 0.5625rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  opacity: 0.6;
}

/* ==========================================================================
   18. VOZ — Fraunces y la escala editorial
   ==========================================================================
   TeX Gyre Pagella es un clon de Palatino; Heros, de Helvetica. Palatino +
   Helvetica es la pareja por defecto de medio internet: ninguna decisión
   tipográfica = ninguna voz. Era el factor #1 de la sensación «genérica».

   Fraunces (OFL, variable, con eje óptico real) da a los titulares carácter de
   revista sin perder la serif clásica que pide una inmobiliaria. El texto se
   queda en Heros: el cuerpo debe desaparecer, no opinar. Se sirve por Google
   Fonts SOLO en exploración — la CSP ya lo permitía; si la voz se aprueba, se
   autoaloja como el resto.
   ========================================================================== */
:root {
  --font-display: "Fraunces", "AL Display", Georgia, serif;
}
.t-display {
  font-weight: 420;
  font-variation-settings: "opsz" 144;
  letter-spacing: -0.028em;
  line-height: 0.92;
}
.t-display em { font-weight: 380; }
.chapter h2, .section-head h2 {
  font-weight: 440;
  font-variation-settings: "opsz" 96;
  letter-spacing: -0.02em;
}

/* --- El numeral de capítulo, GIGANTE --------------------------------------
   El «( 01 )» tímido pasa a ser el gesto editorial de la página: un numeral de
   hasta 13rem al 5,5 % de opacidad DETRÁS del título. currentColor hace que
   funcione igual sobre mármol que sobre teal sin declarar dos colores. */
[data-numbered] .section-head { position: relative; }
[data-numbered] .section-head h2 { position: relative; z-index: 1; }
[data-numbered] .section-head h2::before {
  content: counter(sec, decimal-leading-zero);
  position: absolute;
  z-index: -1;
  top: -0.52em;
  left: -0.06em;
  font-family: var(--font-display);
  font-weight: 300;
  font-variation-settings: "opsz" 144;
  font-size: clamp(6.5rem, 15vw, 13rem);
  line-height: 1;
  letter-spacing: -0.03em;
  color: currentColor;
  opacity: 0.055;
  pointer-events: none;
}

/* --- Mayúsculas con tracking: SOLO antetítulos ------------------------------
   Botones a caja normal. «Buscar» dice lo mismo que «BUSCAR» y deja de sonar a
   plantilla de lujo; el énfasis lo pone el peso, no la caja. */
.btn {
  text-transform: none;
  letter-spacing: 0.01em;
  font-size: 0.9375rem;
  font-weight: 700;
}
.tab, .chip { text-transform: none; letter-spacing: 0.01em; }

/* ==========================================================================
   19. LÁMINAS — la colección como galería, no como catálogo
   ==========================================================================
   Con SEIS propiedades, la rejilla uniforme es el formato equivocado: trata el
   inventario corto como si fuera masivo. El formato correcto es el de revista:
   una lámina a sangre, luego un ritmo asimétrico 7/5 y 5/7, nunca tres iguales
   en fila.

   Todo por posición (:nth-child), sin tocar el JS: el ritmo funciona igual con
   6 resultados que con 2 tras un filtro — y con 1, esa única propiedad ocupa la
   lámina completa, que es exactamente lo que debe pasar.

   Período de 5:  [lámina completa] [7] [5] [5] [7]  y vuelve a empezar.
   ========================================================================== */
@media (min-width: 56rem) {
  /* SEGUNDA VERSIÓN, tras verla en pantalla. La primera alternaba anchos 7/5 y
     proporciones de foto distintas, y el resultado no leía «revista»: leía
     DESORDEN — seis fotos de tamaños dispares sin razón aparente. La jerarquía
     necesita exactamente UNA excepción para funcionar:

        [ lámina de apertura, a sangre, texto sobre la foto ]
        [ lámina ] [ lámina ]
        [ lámina ] [ lámina ]     ← todas iguales, 3:2, dos por fila
        [ lámina ] …

     Una excepción es jerarquía; cinco son ruido. */
  .grid {
    grid-template-columns: repeat(12, 1fr);
    align-items: start;
    row-gap: clamp(2.5rem, 6vh, 4rem);
    column-gap: clamp(1.5rem, 2.5vw, 2.5rem);
  }
  .grid > * { grid-column: span 6; }
  .grid > *:first-child { grid-column: 1 / -1; }

  /* --- La lámina de apertura: panorámica con el texto SOBRE la foto -------- */
  .grid > .card:first-child .card-img { aspect-ratio: 21 / 9; }
  .grid > .card:first-child .card-rule { display: none; }
  .grid > .card:first-child .card-body {
    position: absolute;
    inset: auto 0 0 0;
    z-index: 3;
    padding: clamp(1.25rem, 3vw, 2.5rem);
    background: linear-gradient(180deg,
      transparent 0%, rgba(4, 16, 15, 0.55) 52%, rgba(4, 16, 15, 0.86) 100%);
  }
  .grid > .card:first-child .card-title {
    color: var(--cream);
    font-size: clamp(1.5rem, 2.6vw, 2.375rem);
    line-height: 1.08;
    letter-spacing: -0.015em;
  }
  .grid > .card:first-child .card-loc { color: var(--cream-dim); }
  .grid > .card:first-child .card-specs,
  .grid > .card:first-child .card-specs span { color: var(--cream-dim); }
  .grid > .card:first-child .card-precio-cuerpo {
    color: var(--gold-400);
    font-size: clamp(1.375rem, 2.2vw, 1.875rem);
  }
  /* El precio flotante sobra aquí: el cuerpo entero ya vive sobre la foto. */
  .grid > .card:first-child .card-precio-flotante { display: none; }
}

/* ==========================================================================
   20. LUZ — la interacción firma, sistematizada
   ==========================================================================
   Tres gestos, los tres con el mismo lenguaje (la luz que llega), y nada más:

   1. EL FILETE SE DIBUJA. Al entrar cada capítulo, una línea dorada se traza de
      izquierda a derecha bajo el título — la luz recorre la sala. Scroll-driven
      nativo, cero JS, y en navegadores sin soporte la línea simplemente está.
   2. LA EXPOSICIÓN. Al posarse sobre una lámina, la foto gana +7 % de brillo
      cálido en 900 ms: revelado fotográfico, no zoom de stock. La duración
      lenta queda RESERVADA a la luz; todo lo demás va a 240/560 ms.
   3. EL FUNDIDO ENTRE PÁGINAS. View Transitions entre documentos: pasar del
      catálogo a la ficha funde en vez de parpadear en blanco. Una regla CSS,
      mejora progresiva pura, y desactivada si el usuario pide menos movimiento.
   ========================================================================== */

/* --- 20.1  El filete que se dibuja ---------------------------------------- */
[data-numbered] .section-head::after {
  content: "";
  display: block;
  grid-column: 1 / -1;
  height: 1px;
  margin-top: clamp(1rem, 2.5vh, 1.75rem);
  background-image: var(--gilt);
  transform-origin: left center;
}
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    [data-numbered] .section-head::after {
      animation: a-filete linear both;
      animation-timeline: view();
      animation-range: entry 12% entry 55%;
    }
  }
}
@keyframes a-filete {
  from { transform: scaleX(0); }
  to   { transform: scaleX(1); }
}

/* --- 20.2  La exposición ---------------------------------------------------
   El hover deja de ser solo zoom: la foto SE REVELA. brightness sobre el
   contraste base, transición de 900 ms — el tiempo de la luz. */
.card-img img,
.card-img picture img {
  transition: transform 900ms var(--ease-threshold), filter 900ms var(--ease-threshold);
}
.card:hover .card-img img,
.card:focus-visible .card-img img,
.card:focus-within .card-img img {
  filter: contrast(1.03) brightness(1.07) saturate(1.05);
}
.rail-piece img { transition: filter 900ms var(--ease-threshold); }
.rail-piece:hover img, .rail-piece:focus-visible img {
  filter: brightness(1.07) saturate(1.04);
}

/* --- 20.3  El fundido entre páginas ---------------------------------------
   Cross-document View Transitions (Chrome 126+, Safari 18.2+). Donde no hay
   soporte, navegación normal de toda la vida: la regla se ignora. */
@media (prefers-reduced-motion: no-preference) {
  @view-transition { navigation: auto; }
  ::view-transition-old(root) {
    animation-duration: 200ms;
    animation-timing-function: ease-out;
  }
  ::view-transition-new(root) {
    animation-duration: 380ms;
    animation-timing-function: ease-in-out;
  }
}

/* ==========================================================================
   21. CORRECCIONES DEL RECORRIDO — navegado en local, anotado y corregido
   ========================================================================== */

/* --- 21.1  El titular ya no parte «en» a fin de línea ----------------------
   «El portafolio del Eje Cafetero, en / un solo lugar.» dejaba el «en» naranja
   colgando al final del segundo renglón: la peor partición posible. La cursiva
   pasa a línea propia — el corte deja de depender del ancho de la pantalla. */
.t-display em { display: block; }

/* --- 21.2  El ámbar se retira del titular ----------------------------------
   Mirándolo en pantalla: el degradado brasa sobre el teal lee ÓXIDO, no
   atardecer. Contra la sala verdosa, el naranja quemado pelea; el oro champán
   de la casa, no. La brasa queda como recurso disponible, pero el titular y el
   filete del menú vuelven al oro de la marca. */
.t-display em { background-image: var(--gilt); }
.nav::after { background-image: var(--gilt); opacity: 0.7; }
.destacado-eyebrow { background-image: var(--gilt); }

/* --- 21.3  Las láminas ya no se disuelven en el mármol ---------------------
   Fotos de paredes blancas sobre fondo mármol: el borde desaparecía y la
   composición flotaba sin definición. Una línea de paspartú —el filo que separa
   la lámina de la pared en cualquier galería— y sombra base mínima. */
.card-img {
  outline: 1px solid rgb(4 16 15 / 0.12);
  outline-offset: -1px;
  box-shadow: 0 1px 2px rgb(4 16 15 / 0.06);
}

/* --- 21.4  Las insignias se leen sobre foto clara --------------------------
   VENTA / FICHA CON CÓDIGO desaparecían sobre paredes blancas: cristal al 46 %
   sobre blanco es niebla. Más cuerpo y un borde que las recorta. */
.badge, .lock-pill {
  background-color: rgba(4, 16, 15, 0.62);
  border-color: rgb(255 255 255 / 0.22);
}

/* --- 21.5  El numeral gigante, ahora sí ------------------------------------
   No aparecía: la regla original (.section[data-numbered]…) ganaba por
   especificidad y conservaba el «( 01 )» pequeño. Se iguala el selector — el
   nuestro queda después en la cascada, así que gana. Y la opacidad sube en
   salas oscuras, donde el 5,5 % era invisible. */
.section[data-numbered] .section-head h2::before,
.chapter[data-numbered] .section-head h2::before {
  content: counter(sec, decimal-leading-zero);
  position: absolute;
  z-index: -1;
  top: -0.5em;
  left: -0.05em;
  font-family: var(--font-display);
  font-weight: 300;
  font-variation-settings: "opsz" 144;
  font-size: clamp(6.5rem, 15vw, 13rem);
  line-height: 1;
  letter-spacing: -0.03em;
  color: currentColor;
  opacity: 0.06;
  pointer-events: none;
}
.on-dark[data-numbered] .section-head h2::before { opacity: 0.10; }

/* --- 21.6  Los controles del mapa se visten de la casa ---------------------
   Sobre el plano claro: botones en tinta sobre blanco roto, con el filo fino
   de la casa. Discretos, no invisibles. */
.leaflet-control-zoom a {
  background-color: rgba(255, 255, 255, 0.92) !important;
  color: var(--ink) !important;
  border-color: rgb(4 16 15 / 0.15) !important;
}
.leaflet-control-zoom a:hover { background-color: var(--pure) !important; color: var(--teal-700) !important; }
.leaflet-control-attribution {
  background: rgba(255, 255, 255, 0.75) !important;
  color: rgb(4 16 15 / 0.55) !important;
}
.leaflet-control-attribution a { color: rgb(4 16 15 / 0.7) !important; }

/* ==========================================================================
   22. GALERÍA EN TARJETA, ÚLTIMA FILA CENTRADA Y FOCO VISIBLE
   ========================================================================== */

/* --- El enlace extendido: toda la tarjeta navega, sin envolver botones ----- */
.card-enlace { position: absolute; inset: 0; z-index: 2; }

/* La galería envuelve lámina y flechas. Es posicionada para que las flechas
   se ubiquen contra la caja de la FOTO (no de la tarjeta entera) estando
   FUERA de la lámina aislada — así su z-index compite de verdad con el
   enlace extendido. No crea contexto propio: no aísla, no transforma. */
.card-galeria { display: block; position: relative; }

/* --- Flechas de galería ----------------------------------------------------
   VISIBLES SIEMPRE, en todo dispositivo (decisión del dueño tras verlas
   fallar ocultas): presencia serena en reposo, plena al posarse. Cristal
   oscuro: van sobre foto. */
.foto-nav {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  z-index: 4;
  width: 2.375rem; height: 2.375rem;
  display: grid; place-items: center;
  border: 1px solid rgb(255 255 255 / 0.22);
  border-radius: 999px;
  background-color: rgba(4, 16, 15, 0.55);
  color: var(--cream);
  font-size: 1.375rem;
  line-height: 1;
  cursor: pointer;
  opacity: 0.85;
  transition: opacity 240ms var(--ease-threshold), background-color 240ms var(--ease-threshold);
}
.foto-prev { left: 0.625rem; }
.foto-next { right: 0.625rem; }
.card:hover .foto-nav, .card:focus-within .foto-nav { opacity: 1; }
.foto-nav:hover { background-color: rgba(4, 16, 15, 0.8); }
@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
  .foto-nav { -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px); }
}
@media (hover: none) { .foto-nav { opacity: 1; } }

/* Contador «3 / 12»: dice que hay más fotos ANTES de que nadie pulse nada. */
.foto-contador {
  position: absolute;
  right: 0.625rem; bottom: 0.625rem;
  z-index: 4;
  padding: 0.25rem 0.5625rem;
  border-radius: 999px;
  background-color: rgba(4, 16, 15, 0.55);
  color: var(--cream-dim);
  font-family: var(--font-body);
  font-size: 0.625rem;
  letter-spacing: 0.08em;
  font-variant-numeric: tabular-nums;
}
/* En la lámina de apertura el pie ya está ocupado por el cuerpo: sube. */
@media (min-width: 56rem) {
  .grid > .card:first-child .foto-contador { bottom: auto; top: 3rem; }
}

/* El precio flotante se retira al hojear… no: convive. El contador va a la
   derecha y el precio a la izquierda; no compiten. */

/* --- Última fila centrada --------------------------------------------------
   Tras la lámina de apertura, las tarjetas van en pares. Cuando el total es
   par, la última queda sola y ARRINCONADA a la izquierda. Centrarla cierra la
   composición. (Los pares empiezan en posición par: sola = par y última.) */
@media (min-width: 56rem) {
  .grid > *:nth-child(even):last-child { grid-column: 4 / span 6; }
}

/* --- Foco visible de la casa ----------------------------------------------
   El anillo de foco por defecto del navegador (azul) rompe la paleta y en
   algunos casos ni se ve. Oro sobre cualquier fondo del sitio. */
:where(a, button, select, input, .card-enlace):focus-visible {
  outline: 2px solid var(--gold-400);
  outline-offset: 2px;
}

/* ==========================================================================
   23. RADIOS — la esquina redonda como sistema, no como parche
   ==========================================================================
   Pedido del dueño: tarjetas redondeadas. La forma barata sería un
   border-radius suelto en .card; la forma correcta es un LENGUAJE de esquinas:

   · Tres radios, no veinte: controles (10px), láminas (14–18px, fluido) y
     superficies grandes (18–26px). El radio CRECE con el tamaño de la pieza —
     la regla de concentricidad de cualquier sistema de diseño serio.
   · Anidado concéntrico: la foto dentro del marco usa el radio exterior menos
     el grosor del marco, para que las curvas corran paralelas.
   · La moldura metálica (panel::before y btn::before ya usan la técnica de
     máscara con padding) hereda el radio y sigue la curva sola.
   · El inglete se retira. Cuatro filos rectos en una esquina curva son dos
     lenguajes pegados con cinta; el remate de esquina ahora ES la curva.
     La clase .mitre queda en el HTML sin efecto — retirarla del markup de
     seis páginas no aporta nada y tocaría todo el árbol.
   ========================================================================== */
:root {
  --r-ctrl: 0.625rem;                          /* botones, campos, selects   */
  --r-lam:  clamp(0.875rem, 1.1vw, 1.125rem);  /* tarjetas, láminas, paneles */
  --r-sala: clamp(1.125rem, 1.8vw, 1.625rem);  /* buscador, mapa, apertura   */
}

.mitre::after { display: none; }

.panel { border-radius: var(--r-lam); }
.panel::before { border-radius: inherit; }

/* La tarjeta: marco redondeado; la foto, concéntrica y solo arriba (abajo la
   remata el filete y el cuerpo de texto). */
.card { border-radius: var(--r-lam); }
.card .card-img {
  border-radius: calc(var(--r-lam) - 1px) calc(var(--r-lam) - 1px) 0 0;
}
.badge, .lock-pill { border-radius: 999px; }
.skeleton { border-radius: var(--r-lam); }

/* La lámina de apertura es la pieza mayor: radio de sala, y el velo del cuerpo
   sobre la foto cierra con las mismas curvas abajo. */
@media (min-width: 56rem) {
  .grid > .card:first-child { border-radius: var(--r-sala); }
  .grid > .card:first-child .card-img { border-radius: calc(var(--r-sala) - 1px); }
  .grid > .card:first-child .card-body {
    border-radius: 0 0 calc(var(--r-sala) - 1px) calc(var(--r-sala) - 1px);
  }
}

/* Cromo y controles. */
.searchbar { border-radius: var(--r-sala); }
.searchbar select, .searchbar input { border-radius: var(--r-ctrl); }
.btn { border-radius: var(--r-ctrl); }
.btn::before { border-radius: inherit; }
.chip { border-radius: 999px; }
.rail-btn { border-radius: 999px; }
.field input, .field select, .field textarea { border-radius: var(--r-ctrl); }

/* El mapa y su tarjeta emergente entran al mismo lenguaje. */
.region-map { border-radius: var(--r-sala); overflow: clip; }
/* Un punto más de cuerpo sobre Voyager: el plano gana definición sin dejar de
   ser claro. Se aplica a la tesela, no al contenedor: los pines y la tarjeta
   emergente conservan sus colores exactos de marca. */
/* Las teselas venían de CARTO Voyager, que es de suyo apagada, y por eso este
   filtro SUBÍA el color. Desde el 29-08-2026 la fuente es OpenStreetMap, que
   trae el relieve en verde fuerte y las montañas en café: con el filtro viejo
   el mapa gritaba y los pines dorados dejaban de ser lo que más resalta.

   Ahora BAJA el color en vez de subirlo. Se probaron tres graduaciones sobre
   Pereira y se eligió la más suave a propósito: en su día se descartó un mapa
   más pálido porque «así de clarito no se ve bien», y ese aviso sigue valiendo.
   Apagar hasta el gris habría repetido el error con otra fuente. */
.region-map .leaflet-tile { filter: saturate(.72) brightness(1.06) contrast(.96); }

/* ============================================================================
   GASTOS Y LIQUIDACIÓN, DESDE LA PROPIA FILA  (31-08-2026)
   ============================================================================
   Eran dos pestañas: dos pantallas con las mismas 73 filas y otras columnas.
   Ahora son dos botones en la fila del inmueble, que es donde nace la
   pregunta. Estos estilos existen para que la fila NO se convierta en una
   hilera de botones iguales donde no se distingue nada.
   ========================================================================== */

/* La barra de la agenda: lo que no es de ninguna fila, y el panorama. */
.adm-agenda-acciones { display: flex; gap: .5rem; flex-wrap: wrap; margin: .75rem 0 .5rem; }

/* El botón de gastos lleva el número y el total en el rótulo, así que es más
   ancho que los demás y necesita cifras tabulares para no bailar al repintar. */
.adm-gastos-fila { font-variant-numeric: tabular-nums; white-space: nowrap; }
/* Con gastos cargados se marca en oro: de un vistazo se ve qué inmuebles ya
   tienen movimiento este mes y cuáles siguen en cero. */
.adm-gastos-fila.adm-tiene {
  border-color: var(--gold-400, #cbb89f);
  color: var(--ink-strong, #0b100e);
  font-weight: 600;
}
/* Un borrador es trabajo a medias: se señala, pero sin la fuerza del oro,
   que aquí significa «hecho». */
.adm-liquidar.adm-borrador { border-style: dashed; }
.adm-liq-emitida { border-color: var(--gold-400, #cbb89f); font-weight: 600; }

/* La ventana de gastos hereda la lista entera de la pestaña que sustituye, así
   que necesita más ancho que un formulario. `min(...)` y no un ancho fijo: en
   un teléfono manda la pantalla. */
.modal-ancha { width: min(46rem, 94vw); max-height: 88dvh; overflow-y: auto; }

@media (max-width: 40rem) {
  /* En el teléfono la fila ya va apretada: los botones bajan a su propia
     línea en vez de encogerse hasta ser intocables. */
  .adm-agenda-acciones { gap: .4rem; }
  .adm-gastos-fila, .adm-liquidar, .adm-liq-emitida { flex: 1 1 auto; text-align: center; }
}
.mapa-popup .leaflet-popup-content-wrapper { border-radius: 0.875rem; padding: 0; overflow: hidden; }
.leaflet-bar { border-radius: var(--r-ctrl) !important; overflow: clip; }

/* ==========================================================================
   24. MÓVIL — las optimizaciones estándar del mercado
   ==========================================================================
   Lo que cualquier auditoría móvil seria exige, aplicado sin excepción:
   sin zoom involuntario de iOS al enfocar campos, sin destello gris al tocar,
   sin doble-tap fantasma, sin desborde horizontal, y objetivos táctiles de
   44px donde el dedo de verdad aterriza. El mapa deja de secuestrar el
   desplazamiento: con UN dedo corre la página, con DOS se mueve el mapa
   (el estándar de los mapas embebidos).
   ========================================================================== */
html { -webkit-tap-highlight-color: transparent; }
body { overflow-x: clip; }
a, button, select, input, textarea, .chip { touch-action: manipulation; }

/* iOS hace zoom automático sobre cualquier campo con letra menor de 16px.
   En pantallas de teléfono, todo campo va a 16px reales: se acabó el salto. */
@media (max-width: 45rem) {
  input, select, textarea { font-size: max(1rem, 16px); }
}

/* Donde no hay puntero fino, los objetivos crecen al mínimo táctil. */
@media (hover: none) {
  .foto-nav { width: 2.75rem; height: 2.75rem; }
  .rail-btn { min-width: 2.75rem; min-height: 2.75rem; }
  .leaflet-control-zoom a {
    width: 2.75rem !important;
    height: 2.75rem !important;
    line-height: 2.75rem !important;
  }
  .chip { padding-block: 0.6875rem; }
}

/* ==========================================================================
   25. LA CORNISA SE GUARDA — escenas limpias al leer
   ==========================================================================
   Al bajar, el menú se retira tras el borde superior y la escena queda
   completa — el héroe, las láminas y el mapa sin cromo encima. Al subir,
   que es el gesto universal de «quiero ir a otra parte», reaparece al
   instante. El estado lo pone app.js con umbrales acumulados (un temblor
   de trackpad no debe hacerlo parpadear) y nunca se guarda en el primer
   alto de pantalla. Con el teclado dentro se queda quieto: esconder el
   elemento que tiene el foco es una crueldad de accesibilidad. */
.nav { transition: transform 380ms var(--ease-threshold); }
.nav.nav-guardada { transform: translateY(-102%); }
.nav.nav-guardada:focus-within { transform: none; }
@media (prefers-reduced-motion: reduce) {
  .nav { transition: none; }
}

/* ==========================================================================
   26. EL MENÚ MÓVIL — la barra nunca se apila
   ==========================================================================
   El fallo que se veía en el teléfono: .nav-links lleva flex-wrap y, cuando
   la fila no cabe junto a la marca, los enlaces se APILAN en vertical — una
   cornisa de un tercio de pantalla. La corrección no es encoger letras hasta
   que quepan: bajo 56rem la fila de escritorio se retira y entran tres
   piezas: marca compacta, el CTA del negocio SIEMPRE visible (enterrar
   «Publicar» dentro del menú es el error clásico de conversión) y el botón
   «Menú» — con palabra, no jeroglífico de tres rayas a secas. */
.menu-boton, .menu-cta { display: none; }

@media (max-width: 56rem) {
  .nav-links { display: none; }
  .nav-inner { gap: 0.625rem; min-height: 3.75rem; }
  .brand { font-size: 1rem; gap: 0.625rem; }
  .brand img { height: 2rem; }
  .brand small { display: none; }        /* una sola línea: marca compacta */

  .menu-cta { display: inline-flex; margin-left: auto; padding: 0.5625rem 0.9375rem; }
  .menu-cta[hidden] { display: none; }

  .menu-boton {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    min-width: 2.75rem;
    min-height: 2.75rem;
    padding: 0.5rem 0.375rem 0.5rem 0.625rem;
    font-family: var(--font-body);
    font-size: 0.8125rem;
    letter-spacing: 0.08em;
    color: var(--cream);
    background: none;
    border: 0;
    cursor: pointer;
  }
  /* Dos filos, no tres rayas: el gesto de la casa. */
  .menu-icono {
    width: 1.125rem;
    height: 0.5625rem;
    border-top: 1.5px solid currentColor;
    border-bottom: 1.5px solid currentColor;
  }
}

/* --- La hoja: <dialog> en capa superior nativa ----------------------------- */
.menu-velo {
  position: fixed;
  inset: 0 0 0 auto;
  width: min(21rem, 86vw);
  height: 100dvh;
  max-height: none;
  max-width: none;
  margin: 0;
  padding: 0;
  border: 0;
  background-color: rgba(6, 22, 21, 0.97);
  color: var(--cream);
  box-shadow: -28px 0 70px rgb(0 0 0 / 0.5);
  transform: translateX(100%);
  transition: transform 360ms var(--ease-threshold);
}
.menu-velo[open] { transform: none; }
@starting-style {
  .menu-velo[open] { transform: translateX(100%); }
}
@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
  .menu-velo {
    background-color: rgba(6, 22, 21, 0.82);
    -webkit-backdrop-filter: blur(22px) saturate(1.3);
    backdrop-filter: blur(22px) saturate(1.3);
  }
}
.menu-velo::backdrop {
  background: rgb(2 8 8 / 0.55);
  -webkit-backdrop-filter: blur(4px);
  backdrop-filter: blur(4px);
}
/* El fondo no se desplaza con el menú abierto: candado sin JS. */
html:has(.menu-velo[open]) { overflow: hidden; }
@media (prefers-reduced-motion: reduce) {
  .menu-velo { transition: none; }
}

.menu-hoja {
  display: flex;
  flex-direction: column;
  height: 100%;
  padding: max(0.625rem, env(safe-area-inset-top))
           max(1.375rem, env(safe-area-inset-right))
           max(1.375rem, env(safe-area-inset-bottom))
           1.375rem;
}
.menu-cabecera {
  display: flex;
  align-items: center;
  justify-content: space-between;
  min-height: 3.125rem;
  margin-bottom: 0.75rem;
  border-bottom: 1px solid var(--hairline);
}
.menu-titulo {
  font-family: var(--font-body);
  font-size: 0.6875rem;
  letter-spacing: 0.24em;
  color: var(--gold-500);
}
.menu-cerrar {
  width: 2.75rem;
  height: 2.75rem;
  display: grid;
  place-items: center;
  font-size: 1.125rem;
  color: var(--cream);
  background: none;
  border: 0;
  border-radius: 999px;
  cursor: pointer;
}

.menu-lista { display: flex; flex-direction: column; }
.menu-fila {
  display: flex;
  align-items: center;
  width: 100%;
  min-height: 3.375rem;
  padding: 0.625rem 0.125rem;
  border: 0;
  border-bottom: 1px solid var(--hairline);
  background: none;
  cursor: pointer;
  text-align: left;
  font-family: var(--font-display);
  font-size: 1.4375rem;
  font-weight: 420;
  letter-spacing: -0.01em;
  color: var(--cream);
}
.menu-fila.active { color: var(--gold-400); }
.menu-publicar { margin-top: 1.75rem; width: 100%; }
.menu-sesion {
  margin-top: 0.875rem;
  font-family: var(--font-body);
  font-size: 0.6875rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-quiet);
  color: var(--cream-dim);
  opacity: 0.7;
}
.menu-wa {
  margin-top: auto;
  padding-top: 1.75rem;
  font-family: var(--font-body);
  font-size: 0.8125rem;
  letter-spacing: 0.04em;
  color: var(--cream-dim);
}

/* --- 26-bis · El remate visto en producción --------------------------------
   En 390px, marca con nombre + «Publicar» + «Menú» no caben: el botón salía
   cortado por el borde. Bajo 30rem el nombre se retira y queda el monograma
   —el nombre completo vive en la cabecera de la hoja y en el pie— igual que
   hacen las marcas que resuelven bien el móvil. */
@media (max-width: 30rem) {
  .brand > span { display: none; }
  .nav-inner { gap: 0.5rem; }
  .menu-cta { padding-inline: 0.8125rem; }
}

/* --- El racimo del mapa ----------------------------------------------------
   Mismo idioma que la etiqueta de precio (píldora oro sobre tinta) con un
   grado más de presencia: fondo dorado e «N inmuebles» en tinta. Se distingue
   de un precio a un vistazo — un racimo INVITA a abrir, un precio informa. */
.mapa-racimo { background: none; border: 0; }
.mapa-racimo span {
  display: inline-block;
  transform: translate(-50%, -50%);
  white-space: nowrap;
  padding: 0.4rem 0.75rem;
  border-radius: 999px;
  background: #CBAB51;
  border: 1px solid #04100F;
  box-shadow: 0 0 0 2px rgb(203 171 81 / 0.35), 0 3px 12px rgb(0 0 0 / 0.45);
  color: #04100F;
  font-family: var(--font-body);
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.02em;
  cursor: pointer;
  transition: transform 160ms var(--ease-threshold);
}
.mapa-racimo span:hover { transform: translate(-50%, -50%) scale(1.06); }
/* Patas del abanico: se dibujan al abrirse. */
.leaflet-cluster-spider-leg { transition: stroke-dashoffset 300ms ease-out, stroke-opacity 300ms ease-out; }

/* ==========================================================================
   27. MODO ADMINISTRACIÓN — ADM1: la agenda como sala de la misma casa
   ========================================================================== */
.adm { padding-block: clamp(2rem, 5vh, 3.5rem); }
.adm-cabecera {
  display: flex; align-items: end; justify-content: space-between;
  gap: 1rem; flex-wrap: wrap; margin-bottom: clamp(1.5rem, 3vh, 2.25rem);
}
.adm-titulo { font-family: var(--font-display); font-weight: 440; font-size: clamp(1.75rem, 4vw, 2.75rem); line-height: 1.05; }
.adm-mes { display: flex; align-items: center; gap: 0.75rem; }
.adm-mes-nombre { font-family: var(--font-display); font-size: 1.125rem; min-width: 11ch; text-align: center; text-transform: capitalize; }
.adm-mes-btn {
  width: 2.75rem; height: 2.75rem; display: grid; place-items: center;
  border: 1px solid var(--hairline-strong); border-radius: 999px;
  background: none; color: var(--ink-strong); font-size: 1.25rem; cursor: pointer;
}
.adm-mes-btn:hover { background-color: var(--well); }

.adm-cifras {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(11rem, 100%), 1fr));
  gap: clamp(0.75rem, 1.6vw, 1.25rem); margin-bottom: clamp(1.75rem, 4vh, 2.75rem);
}
.adm-cifra { display: block; padding: 1rem 1.125rem; border-radius: var(--r-lam); background-color: var(--surface); }
.adm-cifra b { display: block; font-family: var(--font-display); font-size: clamp(1.375rem, 2.4vw, 1.875rem); color: var(--metal); font-variant-numeric: tabular-nums; }
.adm-cifra span { font-size: 0.6875rem; letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink-quiet); }
.adm-cifra-alerta b { color: var(--err); }
.adm-cifra-skel, .adm-fila-skel { height: 4.5rem; border-radius: var(--r-lam); }

.adm-filtros { display: flex; gap: 0.5rem; flex-wrap: wrap; margin-bottom: 1rem; }
/* `container-type` para que la fila se adapte AL SITIO DONDE ESTÁ y no al
   tamaño de la ventana. Ver el bloque de abajo. */
.adm-lista { display: flex; flex-direction: column; gap: 0.625rem; container-type: inline-size; }
.adm-fila {
  display: grid; grid-template-columns: minmax(0, 1fr) auto auto auto; align-items: center;
  gap: 0.75rem 1.25rem; padding: 0.875rem 1.125rem;
  border-radius: var(--r-lam); background-color: var(--surface);
}
/* --------------------------------------------------------------------------
   MINMAX(0, 1fr) Y NO 1fr — la mitad del solapamiento estaba aquí
   --------------------------------------------------------------------------
   Una columna `1fr` no baja de su ancho mínimo de contenido. Con un concepto
   largo —«Reparación puerta por terremoto»— la primera columna se plantaba en
   lo que midiera la palabra más larga, las otras tres seguían pidiendo su
   `auto`, y la suma se salía de la caja: aparecía una barra horizontal y el
   valor se montaba encima del título.

   `minmax(0, 1fr)` la deja encogerse, y el texto se parte donde toque en vez
   de empujar la fila entera.
-------------------------------------------------------------------------- */
.adm-fila-quien { min-width: 0; }
.adm-fila-quien b, .adm-fila-quien span { overflow-wrap: anywhere; }
.adm-fila-mora { outline: 1px solid rgb(162 69 46 / 0.5); outline-offset: -1px; }
.adm-fila-quien b { display: block; font-family: var(--font-display); font-size: 1.0625rem; color: var(--ink-strong); }
.adm-fila-quien span { font-size: 0.75rem; color: var(--ink-quiet); }
.adm-fila-datos { text-align: right; }
.adm-canon { display: block; font-variant-numeric: tabular-nums; color: var(--metal); }
.adm-dia { font-size: 0.6875rem; color: var(--ink-quiet); }
.adm-fila-estado { display: flex; align-items: center; gap: 0.5rem; }
.adm-fecha { font-size: 0.6875rem; color: var(--ink-quiet); font-variant-numeric: tabular-nums; }
.adm-nota { grid-column: 1 / -1; margin: 0; font-size: 0.8125rem; color: var(--ink-quiet); border-top: 1px solid var(--hairline); padding-top: 0.5rem; }

.adm-chip {
  padding: 0.3125rem 0.6875rem; border-radius: 999px;
  font-size: 0.6875rem; letter-spacing: 0.04em; border: 1px solid transparent;
}
.adm-chip-pago  { background-color: rgb(203 171 81 / 0.16); color: #6d5a1e; border-color: rgb(203 171 81 / 0.45); }
.adm-chip-vacio { background-color: rgb(4 16 15 / 0.05); color: var(--ink-quiet); border-color: var(--hairline); }
.adm-chip-coman { background-color: rgb(140 110 60 / 0.12); color: #7a5c2e; border-color: rgb(140 110 60 / 0.35); }
.adm-chip-mora  { background-color: rgb(162 69 46 / 0.10); color: var(--err); border-color: rgb(162 69 46 / 0.4); }
/* «Dueño pagado»: el mismo verde de la caja de lo hecho, para que la fila y su
   caja hablen el mismo idioma de color. */
.adm-chip-dueno {
  background-color: color-mix(in srgb, var(--hecho-filete) 18%, transparent);
  color: var(--hecho-tinta);
  border-color: color-mix(in srgb, var(--hecho-filete) 55%, transparent);
}

/* ----------------------------------------------------------------------------
   EL CUADRITO DE LA ADMINISTRACIÓN  (12-09-2026)
   ----------------------------------------------------------------------------
   Tres estados y un mismo sitio en la fila. El verde se va llenando conforme
   el trabajo se termina: hueco cuando falta descontarla, medio cuando está
   descontada, sólido cuando además está el comprobante.

   El estado NO se cifra solo en el color: cada uno lleva su propio signo
   —□ ◧ ■— y su título. Quien no distinga el ámbar del verde sigue viendo la
   diferencia, que es la misma regla que ya sigue el verde de «Dueño pagado».
-------------------------------------------------------------------------- */
.adm-cuadro {
  display: inline-grid; place-items: center;
  width: 1.375rem; height: 1.375rem;
  border-radius: 0.3125rem; border: 1px solid var(--hairline);
  font-size: 0.75rem; line-height: 1; cursor: help;
}
.adm-cuadro-falta {
  background-color: rgb(162 69 46 / 0.10);
  color: var(--err);
  border-color: rgb(162 69 46 / 0.45);
}
.adm-cuadro-descontada {
  background-color: color-mix(in srgb, var(--hecho-filete) 14%, transparent);
  color: var(--hecho-tinta);
  border-color: color-mix(in srgb, var(--hecho-filete) 45%, transparent);
}
/* Sobre el verde SÓLIDO, tinta blanca. Con `--hecho-tinta` encima se leía mal
   —verde claro sobre verde medio en el tema oscuro, contraste de 2:1— y este
   cuadrito existe justamente para leerse de un vistazo sobre setenta filas.
   Blanco sobre este verde da 4,6:1 en claro y 4,9:1 en oscuro. */
.adm-cuadro-completa {
  background-color: var(--hecho-filete);
  color: #fff;
  border-color: var(--hecho-filete);
  font-weight: 700;
}

/* ----------------------------------------------------------------------------
   LA FILA CON EL CICLO CERRADO
   ----------------------------------------------------------------------------
   Verde MUY claro, sobre el papel de la lámina: la pregunta que contesta —«¿a
   este dueño ya le pagué?»— se hace de un vistazo sobre setenta filas, y para
   eso el color tiene que verse sin leer y sin gritar.

   Va con un filete a la izquierda además del fondo. El fondo solo sería una
   diferencia de luminosidad de un 4 %: quien distinga mal el verde no vería
   nada. El filete, el chip «Dueño pagado» y el rótulo del botón dicen lo mismo
   por tres caminos distintos, que es la regla de la casa para no cifrar
   información únicamente en el color.
-------------------------------------------------------------------------- */
/* Al día con el dueño, pero sin el papel. El informe que le llega saldría sin
   su comprobante anexo, así que el botón lo dice con un borde punteado — la
   misma señal que ya usa el borrador. Verde por el estado, punteado por lo que
   falta: dos cosas distintas, dos señales distintas. */
/* El botón, con el verde de su fila: si la tarjeta dice hecho y el botón sigue
   pareciendo pendiente, uno de los dos miente. */
.adm-pago-dueno.adm-pagado {
  background-color: color-mix(in srgb, var(--hecho-filete) 14%, transparent);
  border-color: var(--hecho-filete);
  color: var(--hecho-tinta);
  font-weight: 600;
}
.adm-pago-dueno.adm-sin-comprobante { border-style: dashed; }

.adm-fila-dueno-pagado {
  background-color: var(--hecho);
  box-shadow: inset 4px 0 0 var(--hecho-filete);
}
/* El nombre del inmueble también se tiñe: es lo primero que se lee de la fila,
   y con el fondo verde detrás una tinta neutra pierde el hilo del estado. */
.adm-fila-dueno-pagado .adm-fila-quien b { color: var(--hecho-tinta); }
/* La mora manda por encima: un inmueble en mora al que ya se le pagó al dueño
   sigue siendo, sobre todo, una mora. El contorno rojo no se pierde y el verde
   baja a la mitad para no pelear con él. */
.adm-fila-dueno-pagado.adm-fila-mora {
  background-color: color-mix(in srgb, var(--hecho) 50%, transparent);
}
.adm-ver-soporte-dueno { filter: none; }
.adm-chip-pend  { background-color: transparent; color: var(--ink-quiet); border-color: var(--hairline-strong); }

.adm-estados { display: flex; gap: 0.5rem; flex-wrap: wrap; margin-block: 0.75rem 1rem; }
.adm-pago { border-top: 1px solid var(--hairline); padding-top: 0.875rem; margin-top: 0.5rem; }
.adm-check { display: flex; gap: 0.5rem; align-items: center; font-size: 0.875rem; margin-bottom: 0.75rem; }
.modal-acciones { display: flex; gap: 0.75rem; justify-content: flex-end; margin-top: 1.25rem; }

.adm-acciones { display: flex; align-items: center; gap: 0.375rem; }
.adm-lapiz {
  width: 2.25rem; height: 2.25rem; display: grid; place-items: center;
  border: 1px solid var(--hairline); border-radius: 999px;
  background: none; color: var(--ink-quiet); cursor: pointer; font-size: 0.9375rem;
}
.adm-lapiz:hover { color: var(--ink-strong); border-color: var(--hairline-strong); background-color: var(--well); }

/* ----------------------------------------------------------------------------
   EL ↺ DE VOLVER A LIQUIDAR — 15-09-2026
   ----------------------------------------------------------------------------
   Reemplaza un documento que ya salió con folio: no es un botón del día a día,
   es la salida de un error. Va en la misma familia que los demás discos de la
   fila —mismo tamaño, mismo sitio para el pulgar— pero con la tinta del aviso,
   para que no se pulse por inercia creyendo que es el lápiz de al lado.

   La señal no es solo el color: el símbolo ↺ no se parece a ningún otro de la
   fila, y el título dice qué va a pasar con el folio. Quien no distinga bien
   los colores sigue teniendo dos avisos.
-------------------------------------------------------------------------- */
.adm-reliquidar { color: var(--err); border-color: rgb(162 69 46 / 0.40); font-size: 1.0625rem; }
.adm-reliquidar:hover {
  color: var(--err);
  border-color: rgb(162 69 46 / 0.75);
  background-color: rgb(162 69 46 / 0.10);
}
.adm-reliquidar[disabled] { opacity: 0.45; cursor: progress; }

/* ----------------------------------------------------------------------------
   LOS DOS WHATSAPP DE UNA FILA
   ----------------------------------------------------------------------------
   Al inquilino se le cobra; al propietario se le rinde cuentas. Son dos
   conversaciones distintas y hasta hoy solo existía un botón. Puestos uno al
   lado del otro tienen que distinguirse SIN leer: dos discos idénticos y
   contiguos son una trampa para el pulgar en un teléfono.

   La marca es el borde y la «d» volada, no el color solo: quien no distinga
   bien los colores sigue viendo cuál es cuál. El `sup` se aparta del flujo para
   no descentrar el símbolo dentro del círculo.
-------------------------------------------------------------------------- */
.adm-wa-dueno { position: relative; border-color: var(--metal); color: var(--metal); }
.adm-wa-dueno:hover { border-color: var(--ink-strong); }
.adm-wa-dueno sup {
  position: absolute; top: 0.25rem; right: 0.375rem;
  font-size: 0.5rem; line-height: 1; letter-spacing: 0;
}

/* LA FILA QUE NO ESTÁ ENGANCHADA A NADA, y EL GASTO SIN SU PAPEL.
   Los dos avisan sin bloquear, así que los dos se quedan en el registro
   discreto: un borde y un chip. Nada parpadea ni pide un clic para cerrarse
   — un aviso que hay que despachar acaba despachándose sin leerlo. */
/* Pedir el celular que falta, sin sacar a nadie de la pantalla. En móvil se
   apila: el campo a lo ancho y el botón debajo, que es donde cae el pulgar. */
.adm-wa-pedir { flex-wrap: wrap; align-items: center; gap: 0.5rem; margin-top: 0.75rem; }
.adm-wa-pedir label { font-size: 0.8125rem; color: var(--ink-quiet); flex-basis: 100%; }
.adm-wa-pedir input { flex: 1 1 12rem; min-width: 0; }
@media (max-width: 30rem) { .adm-wa-pedir .btn { flex-basis: 100%; } }

/* El botón que lleva al informe único de la sociedad. Se distingue del de
   liquidar para que no se pulse por inercia: no hace lo mismo. */
.adm-liq-sociedad { border-color: var(--metal); color: var(--metal); }

.adm-sep { border: 0; border-top: 1px solid var(--hairline); margin-block: 2rem; }
.adm-subtitulo { font-family: var(--font-display); font-size: 1.25rem; margin-bottom: 0.25rem; }
/* La rejilla del formulario: dos columnas en escritorio, una en telefono.
   `adm-form-ancho` es para los campos de texto largo, que necesitan las dos. */
.adm-form-rejilla { display: grid; grid-template-columns: 1fr 1fr; gap: 0.75rem 1rem; margin-block: 1rem; }
.adm-form-rejilla label { display: flex; flex-direction: column; gap: 0.25rem; font-size: 0.8125rem; color: var(--ink-quiet); }
.adm-form-rejilla input, .adm-form-rejilla select, .adm-form-rejilla textarea {
  padding: 0.5rem 0.625rem; border: 1px solid var(--hairline); border-radius: var(--r-lam);
  background-color: var(--surface); color: var(--ink); font: inherit; font-size: 0.9375rem;
}
.adm-form-ancho { grid-column: 1 / -1; }
/* Un campo que el sistema rellena y no se debe teclear se VE distinto: si
   pareciera editable, alguien intentaria corregirlo y no podria. */
.adm-fijo { background-color: var(--well); color: var(--ink-quiet); }
@media (max-width: 40rem) { .adm-form-rejilla { grid-template-columns: 1fr; } }

.adm-chip-sinficha { border-style: dashed; }
.adm-fila-sinpapel { outline: 1px dashed rgb(162 69 46 / 0.45); outline-offset: -1px; }
.adm-aviso-soporte { margin-block: 0.5rem 0; }

/* ----------------------------------------------------------------------------
   LA FILA SE MIDE CONTRA SU CAJA, NO CONTRA LA VENTANA
   ----------------------------------------------------------------------------
   Esta regla existía solo como `@media`, y por eso el descuadre aparecía en una
   pantalla grande: la lista de gastos vive DENTRO de una ventana modal de unos
   30rem, así que el viewport medía 90rem —la regla no entraba— mientras la caja
   real medía un tercio de eso. El resultado era el de la captura: el título
   partido en una columna de tres palabras y la cifra encima.

   Con `@container` la fila se adapta al ancho de `.adm-lista`, que es donde de
   verdad está. Se conserva ADEMÁS el `@media` porque hay filas que se pintan
   fuera de una `.adm-lista` —el historial del inmueble, por ejemplo— y ésas no
   tienen contenedor que consultar: sin el media quedarían apretadas en el
   teléfono.
-------------------------------------------------------------------------- */
@container (max-width: 45rem) {
  .adm-fila { grid-template-columns: minmax(0, 1fr) auto; }
  .adm-fila-datos { text-align: left; grid-row: 2; }
  .adm-fila-estado { grid-row: 2; justify-self: end; flex-wrap: wrap; justify-content: flex-end; }
  .adm-acciones { grid-column: 2; grid-row: 1; flex-wrap: wrap; justify-content: flex-end; }
}
@media (max-width: 45rem) {
  .adm-fila { grid-template-columns: minmax(0, 1fr) auto; }
  .adm-fila-datos { text-align: left; grid-row: 2; }
  .adm-fila-estado { grid-row: 2; justify-self: end; flex-wrap: wrap; justify-content: flex-end; }
  .adm-acciones { grid-column: 2; grid-row: 1; flex-wrap: wrap; justify-content: flex-end; }
}
/* Y en una caja MUY estrecha, todo en columna: apilar es más legible que
   encoger hasta que las palabras se parten de a una. */
@container (max-width: 26rem) {
  .adm-fila { grid-template-columns: minmax(0, 1fr); }
  .adm-fila-datos, .adm-fila-estado, .adm-acciones {
    grid-column: 1; grid-row: auto; justify-self: start; justify-content: flex-start; text-align: left;
  }
}

/* --- 27.2 · Gastos (ADM2) -------------------------------------------------- */
.adm-salas { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-bottom: 1.25rem; }
.adm-sala {
  padding: 0.5625rem 1.125rem; border-radius: 999px; cursor: pointer;
  border: 1px solid var(--hairline-strong); background: none; color: var(--ink-quiet);
  font-family: var(--font-body); font-size: 0.8125rem; letter-spacing: 0.02em;
}
.adm-sala.active { background-color: var(--well); color: var(--ink-strong); border-color: var(--metal-quiet); }
.adm-gastos-barra { display: flex; gap: 0.75rem; align-items: center; margin-bottom: 0.5rem; flex-wrap: wrap; }
.adm-buscar {
  flex: 1 1 16rem; padding: 0.625rem 0.875rem;
  border: 1px solid var(--hairline-strong); border-radius: var(--r-ctrl);
  background-color: var(--surface); color: var(--ink-strong);
}
.adm-gastos-total { margin: 0 0 0.875rem; font-variant-numeric: tabular-nums; }
.adm-gasto-quien { font-size: 0.6875rem; color: var(--ink-quiet); }
.adm-sin-pagar { color: var(--err); }
.adm-soporte { display: flex; align-items: center; gap: 0.75rem; margin-top: 0.5rem; flex-wrap: wrap; }
.adm-soporte-estado { font-size: 0.75rem; color: var(--ink-quiet); }
.adm-check-campo { gap: 0.375rem; }
.adm-ver-soporte { font-size: 0.75rem; text-decoration: underline; cursor: pointer; background: none; border: 0; color: var(--ink-quiet); padding: 0; }
.adm-ver-soporte:hover { color: var(--ink-strong); }

/* --- 27.3 · Liquidaciones (ADM3) ------------------------------------------- */
.adm-candidatos { margin-block: 0.75rem; display: flex; flex-direction: column; gap: 0.375rem; }
/* Un gasto que YA se descontó en otro registro del mismo edificio: se ofrece,
   desmarcado, y se dice dónde está. Atenuado porque marcarlo aquí sería
   cobrarle la misma administración a dos propietarios. */
.adm-check-ojo { color: var(--ink-quiet); }
/* El resto del mes, plegado: existe para poder adjuntar a mano un gasto que
   está escrito con otro nombre, no para invitar a repartir gastos ajenos. */
.adm-otros-gastos { margin-top: 0.75rem; border-top: 1px solid var(--hairline); padding-top: 0.5rem; }
.adm-otros-gastos > summary { cursor: pointer; font-size: 0.8125rem; color: var(--ink-quiet); }
.adm-otros-gastos > summary:hover { color: var(--ink-strong); }
.adm-otros-gastos i { color: var(--ink-quiet); font-style: normal; opacity: 0.85; }
.adm-check-ojo b { color: var(--err); font-weight: 600; }
.adm-candidatos-titulo { font-size: 0.8125rem; color: var(--ink-quiet); margin: 0 0 0.25rem; }
.adm-neto { font-family: var(--font-display); font-size: 1.125rem; margin-block: 0.75rem 0; }
.adm-neto b { color: var(--metal); font-variant-numeric: tabular-nums; }

/* --- 27.4 · EL INFORME — documento papel, la misma casa a la luz ----------- */
body.papel { background: #f4f1ea; color: #1c1a15; }
.informe {
  max-width: 46rem; margin: clamp(1rem, 4vh, 3rem) auto; padding: clamp(1.5rem, 4vw, 3rem);
  background: #fdfcf9; color: #1c1a15;
  border-radius: var(--r-lam); box-shadow: 0 10px 40px rgb(28 26 21 / 0.12);
  font-family: var(--font-body);
}
.informe-borrador { background: #8c6e3c22; border: 1px dashed #8c6e3c; padding: 0.5rem 0.75rem; border-radius: var(--r-ctrl); font-size: 0.8125rem; }
.informe-cabecera { display: flex; justify-content: space-between; align-items: start; gap: 1rem; border-bottom: 2px solid #CBAB51; padding-bottom: 1rem; }
.informe-marca { display: flex; gap: 0.75rem; align-items: center; }
.informe-marca b { display: block; font-family: var(--font-display); letter-spacing: 0.02em; }
.informe-marca span { font-size: 0.625rem; letter-spacing: 0.22em; color: #8a7f68; text-transform: uppercase; }
.informe-folio { text-align: right; }
.informe-folio span { display: block; font-size: 0.625rem; letter-spacing: 0.14em; text-transform: uppercase; color: #8a7f68; }
.informe-folio b { font-family: var(--font-display); font-variant-numeric: tabular-nums; letter-spacing: 0.04em; }
.informe-titulo { font-family: var(--font-display); font-weight: 440; font-size: clamp(1.375rem, 3vw, 1.875rem); margin: 1.25rem 0 0.25rem; }
.informe-sub { color: #6d6350; margin: 0 0 0.25rem; }
.informe-para { font-size: 0.9375rem; margin: 0.25rem 0 1rem; }
.informe-tabla { width: 100%; border-collapse: collapse; margin-block: 1rem; }
.informe-tabla td { padding: 0.625rem 0.25rem; border-bottom: 1px solid #e2dccd; font-size: 0.9375rem; }
.informe-tabla .num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.informe-neto td { border-bottom: 0; border-top: 2px solid #CBAB51; font-family: var(--font-display); font-size: 1.125rem; padding-top: 0.875rem; }
.informe-notas { font-size: 0.875rem; color: #524b3c; border-left: 3px solid #CBAB51; padding-left: 0.75rem; }
.informe-pie { margin-top: 2rem; font-size: 0.6875rem; color: #8a7f68; line-height: 1.6; }
.informe-acciones { position: sticky; bottom: 0; display: flex; flex-wrap: wrap; align-items: center; gap: 0.75rem; justify-content: center; padding: 1rem; background: linear-gradient(transparent, #f4f1ea 40%); }
/* El renglon que explica por que un boton no esta, o que acaba de pasar. Ocupa
   toda la fila para no empujar los botones a un tercer renglon en movil. */
/* El renglon que dice cuantos mensajes esperan turno. Solo tokens: ningun
   color propio, como manda la casa. */
.ia-cola {
  margin: 0 0 0.5rem;
  padding: 0.4rem 0.75rem;
  font-size: var(--fs-label);
  color: var(--ink-quiet);
  background-color: var(--surface);
  border-radius: var(--r-ctrl);
  border: 1px solid var(--hairline);
}
.informe-aviso { flex: 1 0 100%; margin: 0; text-align: center; font-size: var(--fs-small); color: var(--ink-quiet); }
.informe-aviso.ok  { color: var(--ok); }
.informe-aviso.err { color: var(--err); }
body.papel .btn { background-color: #1c1a15; }
@media print {
  .no-print { display: none !important; }
  body.papel { background: #fff; }
  .informe { box-shadow: none; margin: 0; max-width: none; border-radius: 0; }
  @page { margin: 14mm; }
}

.informe-consignacion { margin-block: 1.25rem; }
.informe-consignacion h2 { font-family: var(--font-display); font-size: 1rem; font-weight: 600; margin-bottom: 0.375rem; }
.informe-consignacion p { font-size: 0.875rem; margin: 0.2rem 0; color: #524b3c; }
.informe-firmas { display: flex; gap: 2.5rem; margin-top: 3rem; flex-wrap: wrap; }
.informe-firmas div { flex: 1 1 13rem; font-size: 0.6875rem; color: #8a7f68; }
/* La raya de la firma es el PRIMER span de cada casilla y solo ese: los demás
   llevan el nombre y la cédula, y con la regla anterior —que rayaba todos los
   span— cada dato salía con una línea encima, como tres firmas seguidas. */
.informe-firmas div > span:first-child {
  display: block; border-top: 1px solid #b9ae95;
  margin-bottom: 0.375rem; padding-top: 0.25rem;
}
.informe-firma-rotulo { display: block; font-weight: 400; }
.informe-firma-nombre {
  display: block; margin-top: 0.15rem;
  font-size: 0.75rem; font-weight: 700; color: var(--ink, #1c1a15);
}
.informe-firma-cc { display: block; margin-top: 0.1rem; font-variant-numeric: tabular-nums; }

/* --- 27.5 · Personas (ADM4) ------------------------------------------------ */
.adm-tel { display: block; font-variant-numeric: tabular-nums; color: var(--metal); text-decoration: none; }
.adm-tel:hover { text-decoration: underline; }

/* --- 27.6 · Galatea (ADM5) ------------------------------------------------- */
.adm-galatea-form { padding: 1.25rem; border-radius: var(--r-lam); background-color: var(--surface); }
.adm-galatea-gastos { margin-block: 0.5rem 1rem; }
.adm-galatea-gastos summary { cursor: pointer; font-size: 0.8125rem; color: var(--ink-quiet); }

/* --- 27.7 · Campana (ADM6) ------------------------------------------------- */
.adm-campana {
  position: relative; width: 2.75rem; height: 2.75rem;
  display: grid; place-items: center;
  border: 1px solid var(--hairline-strong); border-radius: 999px;
  background: none; color: var(--ink-strong); cursor: pointer;
}
.adm-campana:hover { background-color: var(--well); }
.adm-campana-badge {
  position: absolute; top: -0.25rem; right: -0.25rem;
  min-width: 1.25rem; height: 1.25rem; padding-inline: 0.25rem;
  display: grid; place-items: center;
  border-radius: 999px; background-color: #a2452e; color: #fff;
  font-size: 0.6875rem; font-variant-numeric: tabular-nums;
}
/* ----------------------------------------------------------------------------
   LOS AVISOS: TRES SOLAPAMIENTOS QUE ERAN TRES CAUSAS DISTINTAS
   ----------------------------------------------------------------------------
   1 · EL BOTÓN ✓ SE MONTABA SOBRE EL TEXTO. Un hijo de flex no baja de su
       ancho de contenido mínimo salvo que se le diga, así que un recordatorio
       largo —«CORRECCIÓN INFORME GALATEA AGOSTO 2026: Hoja 5 incluye gastos de
       administración de otras propiedades…»— empujaba y el botón acababa
       encima de la última línea. `min-width: 0` en el texto y `flex-shrink: 0`
       en las acciones: encoge el párrafo, nunca el botón.

   2 · LA BARRA DE DESPLAZAMIENTO PISABA LAS TARJETAS. La lista scrollea y su
       barra se dibuja sobre el borde derecho. `scrollbar-gutter: stable` le
       reserva el sitio antes de que aparezca, así que el contenido no salta
       cuando la lista crece ni queda pegado a la barra.

   3 · LOS BOTONES DE ABAJO QUEDABAN CORTADOS. Dos listas de 40vh, más el
       formulario, más la cabecera, pasaban del alto de la ventana: «Cerrar» y
       «Crear recordatorio» caían fuera y había que hacer scroll a ciegas para
       encontrarlos. Las listas bajan a 30vh y las acciones se quedan pegadas
       al fondo con `position: sticky`, que es donde se las busca.

   La alineación pasa a `flex-start`: con dos líneas de texto, un ✓ centrado
   verticalmente queda flotando en mitad del párrafo.
-------------------------------------------------------------------------- */
.adm-avisos {
  display: flex; flex-direction: column; gap: 0.375rem;
  max-height: 30vh; overflow-y: auto; scrollbar-gutter: stable;
  padding-right: 0.25rem;
  /* Al llegar al final de la lista, la rueda no sigue moviendo la ventana de
     detrás: dos scrolls encadenados hacen perder el sitio. */
  overscroll-behavior: contain;
}
.adm-aviso {
  display: flex; align-items: flex-start; justify-content: space-between; gap: 0.75rem;
  padding: 0.5rem 0.625rem; border: 1px solid var(--hairline); border-radius: var(--r-ctrl);
}
.adm-aviso-texto { font-size: 0.8125rem; min-width: 0; overflow-wrap: anywhere; line-height: 1.45; }
.adm-aviso-texto small { display: block; color: var(--ink-quiet); font-size: 0.6875rem; }
.adm-aviso-acciones { display: flex; gap: 0.375rem; align-items: center; flex: 0 0 auto; }

/* ----------------------------------------------------------------------------
   LAS ACCIONES DE LA VENTANA, SIEMPRE A LA VISTA
   ----------------------------------------------------------------------------
   `sticky` y no un pie flotante: en una ventana corta no hace absolutamente
   nada —no hay desbordamiento contra el que pegarse— y en una larga se queda
   abajo sin sacar los botones del flujo. Un pie con `position: fixed` habría
   que colocarlo a mano en cada ventana y se despegaría en cuanto una cambiara
   de alto.

   El fondo es OPACO, el de la ventana: si fuera transparente, el texto que
   pasa por debajo se leería a través de los botones. Y `flex-wrap` porque en
   un teléfono dos botones anchos no caben en una línea.
-------------------------------------------------------------------------- */
.modal .modal-acciones {
  position: sticky; bottom: 0; z-index: 1;
  background-color: var(--teal-900);
  padding-block: 0.75rem;
  flex-wrap: wrap;
}
.adm-recordatorios-titulo { margin: 1rem 0 0.5rem; font-size: 0.8125rem; letter-spacing: 0.06em; text-transform: uppercase; color: var(--ink-quiet); }
.adm-recordatorio-nuevo { margin-top: 0.75rem; }

/* El botón de estado por fila es un símbolo: que pese como botón. */
.adm-chulear { min-width: 2.6rem; font-size: 1rem; line-height: 1; }

/* == 26.v · Integración total: cuentas, historial, destinos =============== */
.adm-cifra-btn { text-align: left; cursor: pointer; font: inherit; border: 1px solid var(--hairline-strong); }
.adm-cifra-btn:hover { border-color: var(--metal); }
.adm-cuentas-titulo { font-size: 1rem; margin: 0 0 .75rem; }
#cuentasZona { margin-bottom: 1.5rem; }
.adm-nombre { cursor: pointer; }
.adm-nombre:hover { color: var(--metal); text-decoration: underline; text-underline-offset: 3px; }
.adm-descuenta { color: var(--ok); font-size: .72rem; }
.adm-destino-aviso { font-size: .8rem; margin: .25rem 0 0; }
.adm-ver-soporte-g { font-size: .75rem; text-decoration: underline; cursor: pointer; background: none; border: 0; color: var(--ink-quiet); padding: 0; }
.hist-meses { display: flex; flex-wrap: wrap; gap: .35rem; margin: .75rem 0 1rem; }
.hist-mes { font-size: .7rem; padding: .25rem .45rem; border-radius: 7px; border: 1px solid var(--hairline-strong); font-variant-numeric: tabular-nums; }
.hist-p { background: rgba(31, 86, 55, .12); color: var(--ok); border-color: var(--ok); }
.hist-d { opacity: .55; }
.hist-x { background: rgba(162, 69, 46, .08); }
#agendaBuscar, #liqBuscar { margin-bottom: .75rem; width: 100%; }

/* == 26.w · A2: sala de fotos del panel ================================== */
.fotos-nota { margin-top: 0; font-size: .875rem; }
.fotos-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
  gap: .75rem; margin: 1rem 0; max-height: 46vh; overflow-y: auto;
}
.foto-mini { position: relative; margin: 0; border: 1px solid var(--hairline-strong); border-radius: 10px; overflow: hidden; }
.foto-mini img { display: block; width: 100%; aspect-ratio: 4/3; object-fit: cover; }
.foto-portada { outline: 2px solid var(--metal); outline-offset: 1px; }
.foto-etiqueta {
  position: absolute; top: .3rem; left: .3rem; z-index: 1;
  font-size: .55rem; letter-spacing: .12em; padding: .15rem .4rem;
  background: var(--ink); color: var(--cream); border-radius: 6px;
}
.foto-acciones {
  position: absolute; inset-inline: 0; bottom: 0; display: flex; justify-content: center; gap: .25rem;
  padding: .25rem; background: linear-gradient(transparent, rgba(4,16,15,.55));
}
.foto-acciones button {
  border: 0; border-radius: 6px; width: 1.7rem; height: 1.7rem; cursor: pointer;
  background: var(--cream); color: var(--ink); font-size: .9rem; line-height: 1;
}
.foto-acciones button:disabled { opacity: .35; cursor: default; }
.foto-quitar { background: #f0d9d3 !important; }

/* == 26.x · Seguridad de la cuenta (TOTP) ================================= */
.seg-tarjeta { max-width: 640px; padding: 1.5rem; }
.seg-titulo { margin: 0 0 .4rem; font-size: 1.25rem; }
.seg-texto { font-size: .9rem; line-height: 1.5; }
.seg-estado { margin: 1rem 0; font-size: .95rem; }
.seg-chip-ok { background: rgba(31, 86, 55, .12); color: var(--ok); border-color: var(--ok); }
.seg-secreto {
  font-family: ui-monospace, Consolas, monospace; font-size: 1.05rem;
  letter-spacing: .12em; overflow-wrap: anywhere;
  padding: .6rem .8rem; background: var(--well); border-radius: 8px;
}
#segCodigo { font-size: 1.3rem; letter-spacing: .35em; text-align: center; }

/* == 26.y · Panel en claro: tinta firme =================================
   En el modo administración el texto secundario es DATO (cánones, fechas,
   rótulos de cifras), no decoración editorial: sobre mármol, el bronce-600
   del tema claro general (5,92:1) se ve lavado. Aquí sube a bronce-800/900.
   SOLO el panel: el sitio público conserva su paleta. */
.adm.on-light {
  --ink-quiet: var(--bronze-800);   /* rótulos y secundarios ≈ 9:1 */
  --ink-soft: var(--ink);           /* texto de apoyo a tinta plena */
  --metal: var(--bronze-900);       /* cifras de dinero 11,69:1 */
}

/* == 26.z · [hidden] es ley ==============================================
   Dos veces el mismo bug: una clase con display propio (.ia-panel, .msg)
   le ganaba al atributo hidden del UA. Regla global: lo oculto, oculto. */
[hidden] { display: none !important; }

/* == 27.8b · Cajas que delimitan la información (Galatea y afines) ======== */
.adm-caja {
  border: 1px solid var(--hairline-strong);
  border-radius: 12px;
  padding: 0.9rem 1rem 1rem;
  margin: 0 0 1rem;
  min-width: 0;
}
.adm-caja legend {
  padding: 0 0.45rem;
  font-size: var(--fs-label);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-quiet);
}
.adm-caja-texto { margin-top: 0; }
.adm-caja-reparto { background: var(--well); }

/* == 27.9 · ADM7: asistente IA ============================================ */
.ia-burbuja-btn {
  position: fixed; right: max(1rem, env(safe-area-inset-right)); bottom: max(1rem, env(safe-area-inset-bottom)); z-index: 59;
  width: 54px; height: 54px; border-radius: 50%;
  border: 1px solid var(--oro, #B8935A);
  background: var(--tinta, #04100F); color: var(--oro, #B8935A);
  display: grid; place-items: center; cursor: pointer;
  box-shadow: 0 10px 28px rgba(4, 16, 15, .35);
  transition: transform .15s ease;
}
.ia-burbuja-btn:hover { transform: scale(1.06); }
.ia-burbuja-btn[hidden] { display: none; }
.ia-panel {
  position: fixed; right: 1rem; bottom: 1rem; z-index: 60;
  width: min(400px, calc(100vw - 2rem));
  height: min(620px, calc(100dvh - 6rem));
  display: flex; flex-direction: column;
  background: var(--papel, #FDFCF9);
  border: 1px solid var(--linea, #E4DFD5);
  border-radius: 18px; overflow: hidden;
  box-shadow: 0 24px 64px rgba(28, 25, 20, .22);
}
.ia-panel[hidden] { display: none; }
.ia-cabecera { position: relative; padding: 1.1rem 1.25rem .8rem; border-bottom: 1px solid var(--linea, #E4DFD5); }
.ia-cabecera h3 { margin: 0; font-size: 1.05rem; }
.ia-sub { margin: .3rem 0 0; font-size: .8rem; line-height: 1.35; }
.ia-cerrar {
  position: absolute; top: .7rem; right: .8rem;
  border: 0; background: none; font-size: 1.5rem; line-height: 1;
  cursor: pointer; color: var(--tinta-suave, #6B6558); padding: .2rem .45rem;
}
.ia-hilo { flex: 1; overflow-y: auto; padding: 1rem 1.1rem; display: flex; flex-direction: column; gap: .55rem; }
.ia-burbuja {
  max-width: 88%; padding: .55rem .8rem; border-radius: 14px;
  font-size: .875rem; line-height: 1.45; white-space: pre-wrap; overflow-wrap: anywhere;
}
.ia-asistente { align-self: flex-start; background: #F3F0E8; border: 1px solid var(--linea, #E4DFD5); border-bottom-left-radius: 4px; }
.ia-usuario { align-self: flex-end; background: var(--tinta, #1C1914); color: var(--papel, #FDFCF9); border-bottom-right-radius: 4px; }
.ia-sistema { align-self: center; background: none; color: var(--tinta-suave, #6B6558); font-size: .8rem; text-align: center; }
.ia-error { align-self: center; background: #FBEFEC; border: 1px solid #E4C4BA; color: #7A3B2A; font-size: .8rem; }
.ia-pensando { animation: iaPulso 1.2s ease-in-out infinite; }
@keyframes iaPulso { 0%, 100% { opacity: .45; } 50% { opacity: 1; } }
.ia-confirma {
  margin: 0 1.1rem .6rem; padding: .8rem .9rem;
  border: 1px solid var(--oro, #B8935A); border-radius: 12px;
  background: rgba(184, 147, 90, .08);
}
.ia-confirma-titulo { margin: 0 0 .25rem; font-weight: 600; font-size: .85rem; color: var(--oro-oscuro, #8A6B3D); }
.ia-confirma-detalle { margin: 0 0 .6rem; font-size: .875rem; line-height: 1.4; }
.ia-confirma-botones { display: flex; gap: .5rem; justify-content: flex-end; }
.ia-entrada {
  display: flex; gap: .5rem; padding: .8rem 1.1rem;
  border-top: 1px solid var(--linea, #E4DFD5); background: var(--papel, #FDFCF9);
  padding-bottom: max(.8rem, env(safe-area-inset-bottom));
}
.ia-clip {
  border: 1px solid var(--linea, #E4DFD5); background: #fff; color: #6B6558;
  border-radius: 999px; width: 38px; height: 38px; flex: none;
  display: grid; place-items: center; cursor: pointer;
}
.ia-clip:hover { color: var(--oro, #B8935A); border-color: var(--oro, #B8935A); }
.ia-adjunto {
  margin: 0 1.1rem .4rem; font-size: .8rem; color: #524b3c;
  display: flex; align-items: center; gap: .4rem;
}
.ia-adjunto button { border: 0; background: none; cursor: pointer; color: #a2452e; font-size: .9rem; }
.ia-entrada input {
  flex: 1; min-width: 0; border: 1px solid var(--linea, #E4DFD5); border-radius: 999px;
  padding: .55rem .95rem; font: inherit; font-size: .9rem; background: #fff;
}
.ia-entrada input:focus { outline: 2px solid var(--oro, #B8935A); outline-offset: 1px; }
@media (max-width: 560px) {
  .ia-panel { right: .5rem; left: .5rem; bottom: .5rem; width: auto; height: min(78dvh, 620px); }
  .adm-cabecera { align-items: center; }
  .adm-mes { width: 100%; justify-content: space-between; }
}


/* ==========================================================================
   28.b — FRANJA NEBO MALABAR (proyecto destacado, lote 18-ago)
   Render de fondo con velo para legibilidad AAA sobre oscuro; tres datos en
   tarjetas de vidrio; descargo legal visible. La sección nace [hidden] y la
   revela page-index.js cuando la ficha existe.
   ========================================================================== */
.franja-nebo { position: relative; overflow: hidden; }
.franja-nebo .nebo-fondo { position: absolute; inset: 0; }
.franja-nebo .nebo-fondo img { width: 100%; height: 100%; object-fit: cover; opacity: 0.32; }
.franja-nebo .nebo-fondo::after { content: ''; position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(4,16,15,0.88), rgba(4,16,15,0.55) 45%, rgba(4,16,15,0.92)); }
.franja-nebo .nebo-inner { position: relative; z-index: 1; }
.nebo-sub { max-width: 62ch; margin-top: 0.75rem; opacity: 0.92; }
.nebo-datos { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1rem; margin: 1.75rem 0 1.5rem; }
.nebo-dato { border: 1px solid rgba(255,255,255,0.16); background: rgba(255,255,255,0.05);
  padding: 1rem 1.1rem; border-radius: 10px; display: grid; gap: 0.3rem; }
.nebo-dato b { font-size: 0.82rem; letter-spacing: 0.08em; text-transform: uppercase; opacity: 0.85; }
.nebo-dato span { font-size: 0.92rem; opacity: 0.85; }
.nebo-dato strong { font-size: 1.35rem; }
.nebo-legal { font-size: 0.78rem; opacity: 0.72; margin-top: 1rem; max-width: 70ch; }
@media (max-width: 760px) { .nebo-datos { grid-template-columns: 1fr; } }


/* ==========================================================================
   28.c — LETRERO DE NEGOCIO (orden de la dueña, 18-ago): «un letrero que diga
   en renta o en venta». La insignia de negocio deja de ser discreta: fondo
   sólido POR NEGOCIO (dorado = venta, crema = arriendo, cove = renta corta),
   tinta firme y cuerpo mayor. En la ficha acompaña al precio.
   ========================================================================== */
.badge-deal { font-weight: 700; font-size: 0.72rem; letter-spacing: 0.14em; }
.badge-deal.badge-venta { background-color: var(--gold-400); color: var(--ink); border-color: transparent; }
.badge-deal.badge-arriendo { background-color: var(--cream); color: var(--ink); border-color: transparent; }
.badge-deal.badge-renta_corta { background-color: var(--cove); color: var(--ink); border-color: transparent; }
.prop-price-lado { display: flex; flex-direction: column; align-items: flex-end; gap: 0.45rem; }
.letrero-ficha { position: static; display: inline-block; font-size: 0.8rem; padding: 0.45rem 0.9rem; }


/* ==========================================================================
   28.d — PORTAFOLIO INTERNACIONAL: franja de portada y vitrina propia.
   ========================================================================== */
.franja-intl .nebo-sub { margin-bottom: 1.5rem; }


/* 28.e — DOBLE NEGOCIO: segundo letrero y precio alterno bajo el principal. */
.prop-price-alterno { font-size: 1.05rem; opacity: 0.85; margin-top: 0.2rem; text-align: right; }
.prop-price-alterno small { font-size: 0.7em; margin-left: 0.2rem; }


/* 28.f — SIN RESULTADOS: invitación a asesoría en vez de callejón sin salida. */
.sin-resultados { grid-column: 1 / -1; text-align: center; padding: 2.75rem 1.5rem;
  display: grid; gap: 0.8rem; justify-items: center; }
.sin-resultados h3 { margin: 0; }
.sin-resultados p { max-width: 52ch; margin: 0; }

/* ── Sala Inmuebles + Sala Personal (colecciones de la casa) ─────────────── */
.adm-barra { display: flex; gap: 0.75rem; align-items: center; margin-bottom: 0.75rem; flex-wrap: wrap; }
.adm-col-detalle-barra b { font-size: 1.05rem; }
.adm-grupo-titulo { margin: 1.1rem 0 0.5rem; font-size: 0.8rem; letter-spacing: 0.14em; text-transform: uppercase; color: var(--ink-soft, #5b6663); }
.adm-col-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 0.75rem; }
/* La tarjeta de un tipo de documento lleva su descripción debajo, y ésa sí es
   una frase: sin esto sale en una sola línea y se corta a la mitad. */
.adm-col-card .muted { white-space: normal; line-height: 1.35; }

/* ══ UN DOCUMENTO ANULADO SE VE ANULADO ═══════════════════════════════════
   El folio no desaparece —un consecutivo que se esfuma deja un hueco que hay
   que explicar— así que la fila se queda en la lista. Pero tiene que leerse
   distinta a simple vista: apagada y con el folio tachado. Si se viera igual,
   alguien acabaría mandando un documento anulado creyendo que vale. */
.adm-anulada { opacity: 0.62; }
.adm-anulada b { text-decoration: line-through; text-decoration-thickness: 1px; }

/* La tabla de líneas dentro del formulario de emisión: los ítems de una
   cotización, el inventario de un acta. Las celdas son campos de verdad, así
   que se les da ancho completo y el número se alinea a la derecha, como en el
   papel que van a producir. */
.adm-tabla input { width: 100%; min-width: 4.5rem; box-sizing: border-box; }
.adm-tabla input[type="number"] { text-align: right; font-variant-numeric: tabular-nums; }

/* ══ LA FICHA DEL INMUEBLE ════════════════════════════════════════════════
   Para CONSULTAR, no para llenar: por eso son parejas rótulo/valor y no una
   rejilla de casillas. El rótulo pequeño arriba y el dato grande debajo, que es
   como se lee un número de matrícula por teléfono sin perder el renglón. */
.adm-ficha-seccion { margin-bottom: 1.25rem; }
.adm-ficha-seccion h3 {
  margin: 0 0 0.6rem; font-size: 0.75rem; letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--ink-soft, #5b6663);
  border-bottom: 1px solid var(--hairline, #d8ddd9); padding-bottom: 0.35rem;
}
.adm-ficha-datos { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 0.7rem 1rem; }
.adm-ficha-dato { display: flex; flex-direction: column; gap: 0.1rem; min-width: 0; }
.adm-ficha-dato span { font-size: 0.7rem; letter-spacing: 0.06em; text-transform: uppercase; color: var(--ink-quiet); }
/* `break-word` y no `nowrap`: una cuenta bancaria o una ficha catastral son
   cadenas largas sin espacios, y cortarlas con puntos suspensivos dejaría un
   dato inservible justo en el sitio donde se va a copiar. */
.adm-ficha-dato b { font-size: 0.9375rem; overflow-wrap: anywhere; }
/* UN HUECO SE VE. Un campo vacío que desaparece es un campo que nadie llena. */
.adm-ficha-falta b { color: var(--ink-quiet); font-weight: 400; font-style: italic; opacity: 0.75; }

.adm-ficha-personas { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 0.75rem; }
.adm-ficha-persona {
  border: 1px solid var(--hairline, #d8ddd9); border-radius: var(--r-lam, 12px);
  padding: 0.75rem 0.9rem; display: grid; gap: 0.5rem; background-color: var(--surface, #fff);
}
.adm-ficha-persona-quien { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; }
.adm-ficha-avisos { margin: 0; padding-left: 1.1rem; display: grid; gap: 0.35rem; font-size: 0.875rem; }
.adm-col-card { display: flex; flex-direction: column; align-items: flex-start; gap: 0.25rem; padding: 0.9rem 1rem; text-align: left; cursor: pointer; border: 1px solid var(--hairline, #d8ddd9); border-radius: 12px; background: var(--panel-bg, #fff); }
.adm-col-card:hover { border-color: var(--hairline-strong, #9aa5a0); }
.adm-col-icono { font-size: 1.4rem; line-height: 1; }
/* El estado de la cuenta en la tarjeta: lo que falta, que es la pregunta que se
   hace de un vistazo sobre la rejilla. En tinta fuerte porque es el dato, no un
   pie de foto; en verde cuando ya no falta nada. */
.adm-col-estado {
  margin-top: 0.35rem; font-size: 0.8125rem; font-weight: 600;
  color: var(--ink-strong, #26312e); overflow-wrap: anywhere; text-align: left;
}
.adm-col-estado-ok { color: var(--ok-light, #1f5637); font-weight: 500; }

/* ══ LA LISTA ABIERTA, CON LA MISMA COMPOSICIÓN QUE EL INFORME ═══════════
   Un bloque por evento, su suma debajo y el estado al final. Si la pantalla y
   el papel se ven distinto, revisar antes de mandar es comparar de memoria. */
.adm-col-grupo { display: flex; flex-direction: column; gap: 0.625rem; margin-bottom: 1.5rem; }
.adm-col-grupo-titulo {
  margin: 0; font-size: 0.75rem; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--ink-soft, #5b6663); border-bottom: 1px solid var(--hairline, #d8ddd9);
  padding-bottom: 0.35rem;
}
.adm-col-suma {
  margin: 0; padding: 0.5rem 1.125rem 0; display: flex; flex-wrap: wrap; gap: 0.35rem 1rem;
  justify-content: flex-end; font-size: 0.875rem; color: var(--ink-quiet);
  border-top: 1px solid var(--hairline, #d8ddd9);
}
.adm-col-suma span { margin-right: auto; text-transform: uppercase; letter-spacing: 0.08em; font-size: 0.7rem; }
.adm-col-suma b { font-variant-numeric: tabular-nums; color: var(--ink); }
/* La fila del TRATO no es un movimiento: se marca con el filete dorado, el
   mismo recurso que usa el papel para distinguirla. */
.adm-fila-trato { border-left: 3px solid var(--metal, #cbab51); }

.adm-col-estado-caja {
  border: 1px solid var(--hairline-strong, #9aa5a0); border-radius: var(--r-lam, 12px);
  padding: 0.9rem 1.125rem; margin-bottom: 1rem; display: grid; gap: 0.4rem;
  background-color: var(--surface, #fff);
}
.adm-col-estado-fila {
  display: flex; gap: 1rem; justify-content: space-between; align-items: baseline;
  font-size: 0.9375rem; color: var(--ink-quiet);
}
.adm-col-estado-fila b { font-variant-numeric: tabular-nums; min-width: 7rem; text-align: right; color: var(--ink); }
.adm-col-estado-falta {
  border-top: 1px solid var(--metal-quiet, #b99f66); padding-top: 0.45rem; margin-top: 0.2rem;
  font-weight: 600; color: var(--ink-strong, #26312e); text-transform: uppercase;
  letter-spacing: 0.06em; font-size: 0.8125rem;
}
.adm-col-estado-falta b { font-size: 1.0625rem; text-transform: none; letter-spacing: 0; }

/* ══ LOS AVISOS QUE YA NO SE PINTAN ══════════════════════════════════════
   Aquí vivían `.adm-doble-aviso` y `.adm-dup-grupo`: las cajas que avisaban del
   total escrito a mano y de lo anotado dos veces. Se retiran con su motivo, no
   en silencio.

   Duraron un día. El 04-09-2026 salieron cuatro avisos en la misma pantalla y
   los cuatro eran falsos: dos casas del mismo conjunto compradas el mismo día
   al mismo precio, tres apartamentos iguales, un abono que por casualidad valía
   la mitad de la suma, y el techo de una cuenta comparado con el pago que lo
   alcanzaba. Cuatro avisos falsos seguidos y el quinto —el que importa— ya no
   lo lee nadie.

   Los detectores siguen corriendo; ahora anotan en la libreta de revisiones.
   Lo único que sigue interrumpiendo es la puerta del informe cuando el valor
   del negocio está anotado dos veces, y eso no es un aviso: es una cifra
   multiplicada saliendo hacia un comprador.
   (`.adm-dup-lista` y `.adm-dup-item`, del panel de duplicados de contabilidad,
   son otra cosa y siguen donde estaban.)
   ══════════════════════════════════════════════════════════════════════ */

/* ══ LA TABLA DEL INFORME, ESCRITA ENCIMA ════════════════════════════════
   Misma composición que el papel —una sección por persona, su cabecera con lo
   que falta, su tabla en orden de fecha— y cada casilla es la de verdad. La
   casilla no se disfraza de casilla: se ve el renglón, y el borde aparece al
   pasar por encima. Así la pantalla se LEE como un informe y se ESCRIBE como
   una hoja de cálculo, que era justo lo que hacía falta para corregir. */
.adm-col-informe { gap: 0.75rem; }
.adm-col-informe-cab {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.5rem 1rem;
  border-bottom: 1px solid var(--hairline, #d8ddd9); padding-bottom: 0.4rem;
}
.adm-col-informe-cab .adm-col-grupo-titulo { border: 0; padding: 0; margin-right: auto; font-size: 0.9375rem; letter-spacing: 0.1em; }
.adm-col-informe-acc { display: flex; align-items: center; gap: 0.75rem; flex-wrap: wrap; }
.adm-col-trazas { font-size: 0.75rem; color: var(--ink-quiet); font-variant-numeric: tabular-nums; }
.adm-col-estado-cab { margin-bottom: 0.25rem; }

.adm-tabla-envoltura { overflow-x: auto; }
.adm-tabla-informe { width: 100%; border-collapse: collapse; font-size: 0.875rem; }
.adm-tabla-informe th {
  text-align: left; font-weight: 500; font-size: 0.6875rem; letter-spacing: 0.1em;
  text-transform: uppercase; color: var(--ink-quiet); padding: 0 0.4rem 0.35rem;
  border-bottom: 1px solid var(--metal-quiet, #b99f66); white-space: nowrap;
}
.adm-tabla-informe th.adm-td-num { text-align: right; }
.adm-tabla-informe td { padding: 0; border-bottom: 1px solid var(--hairline, #d8ddd9); }
.adm-tabla-informe input[type="text"],
.adm-tabla-informe input[type="date"] {
  width: 100%; min-width: 5.5rem; border: 1px solid transparent; border-radius: 4px;
  background: transparent; padding: 0.4rem; font: inherit; color: inherit;
}
.adm-tabla-informe input:hover { border-color: var(--hairline, #d8ddd9); }
.adm-tabla-informe input:focus {
  border-color: var(--metal, #cbab51); background-color: var(--surface, #fff); outline: none;
}
.adm-td-num input { text-align: right; font-variant-numeric: tabular-nums; }
.adm-td-fecha input { min-width: 8.5rem; }
.adm-td-sino { text-align: center; }
.adm-td-acc { white-space: nowrap; text-align: right; padding-left: 0.35rem; }
.adm-td-acc .adm-lapiz { padding: 0.2rem 0.3rem; }
.adm-tabla-informe tr.adm-fila-trato td { background-color: color-mix(in srgb, var(--metal, #cbab51) 9%, transparent); }
.adm-tabla-informe tr.adm-fila-trato input { font-weight: 600; }
.adm-tabla-informe tr.adm-fila-guardando td { opacity: 0.55; }
.adm-tabla-informe tr.adm-fila-error td { background-color: #f9e9e7; }
/* Retirada: sigue ahí, tachada y apagada, con su botón para devolverla. Que se
   vea es lo que hace que retirar sea reversible de verdad y no de palabra. */
.adm-tabla-informe tr.adm-fila-retirada input { text-decoration: line-through; opacity: 0.5; }

@media (max-width: 640px) {
  .adm-tabla-informe { font-size: 0.8125rem; }
  .adm-tabla-informe input[type="text"], .adm-tabla-informe input[type="date"] { padding: 0.3rem; }
}

.adm-modal-ancho { max-width: 720px; width: min(720px, 94vw); max-height: 88vh; overflow-y: auto; }
.adm-form-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 0.6rem 0.9rem; margin: 0.75rem 0; }
.adm-form-grid .field input, .adm-form-grid .field select { width: 100%; }
.adm-field-corto { max-width: 140px; }
.adm-field-check { flex-direction: row; align-items: center; gap: 0.5rem; }
.adm-field-check input[type="checkbox"] { width: 1.15rem; height: 1.15rem; }
.adm-campo-def { align-items: end; border-bottom: 1px dashed var(--hairline, #d8ddd9); padding-bottom: 0.5rem; margin-bottom: 0.5rem; }
.adm-peligro { color: #8c2f2f; border-color: #c9a0a0; }
.adm-peligro:hover { background: #f7ecec; }

/* Foto de colección: vista previa de la CONVERTIDA (lo único que se sube). */
.adm-foto-zona { display: grid; gap: 0.5rem; margin: 0.5rem 0 0.75rem; }
.adm-foto-previa { display: grid; gap: 0.35rem; justify-items: start; }
.adm-foto-previa img { max-width: 240px; max-height: 180px; border-radius: 10px;
  border: 1px solid var(--hairline, #d8ddd9); object-fit: cover; }

/* ══ CAJAS «lo que falta» / «lo que ya se hizo» (orden del dueño, 20-08) ══
   Una sola columna: primero lo pendiente, después lo hecho. El borde dice el
   estado sin leer una palabra — gris de la paleta para lo pendiente, verde
   CLARO de la misma familia para lo evacuado. Nada de rojo: la mora ya tiene
   su propio chip; aquí se trata de saber qué falta, no de alarmar. */
.adm-caja-estado { border: 1.5px solid; border-radius: var(--r-lam, 12px); padding: 0.9rem 1rem 1rem;
  margin-bottom: 1rem; background-color: var(--surface, #fff); }
.adm-caja-pendiente { border-color: var(--hairline-strong, rgba(58,44,28,0.45)); }
.adm-caja-hecho { border-color: color-mix(in srgb, var(--ok-light, #1f5637) 62%, transparent); }
/* MEDIDO en pantalla (20-08): al 42 % el verde se confundía con el gris del
   pendiente a un metro de distancia — y una caja que no se distingue no sirve
   para «saber qué falta». Al 62 % se lee VERDE al instante y sigue siendo el
   claro de la familia, no el verde fuerte de los chips. */
.adm-caja-cabecera { display: flex; align-items: baseline; gap: 0.6rem; flex-wrap: wrap;
  margin: 0 0 0.75rem; }
.adm-caja-cabecera h3 { margin: 0; font-size: 0.95rem; letter-spacing: 0.02em; }
.adm-caja-pendiente .adm-caja-cabecera h3 { color: var(--ink-soft, #3a2c1c); }
.adm-caja-hecho .adm-caja-cabecera h3 { color: var(--ok-light, #1f5637); }
.adm-caja-cuenta { font-size: 0.75rem; color: var(--ink-quiet); font-variant-numeric: tabular-nums; }
.adm-caja-vacia { margin: 0; font-size: 0.85rem; color: var(--ink-quiet); font-style: italic; }
/* Dentro de las cajas la lista respira igual, pero en UNA columna siempre. */
.adm-caja-estado .adm-lista { gap: 0.5rem; }

/* ══ PANEL CONTABLE: libros en línea, tabla de trabajo ═══════════════════ */
.adm-conta-barra { display: grid; gap: 0.5rem; margin-bottom: 0.75rem; }
.adm-conta-filtros { display: flex; gap: 0.75rem; align-items: flex-end; flex-wrap: wrap;
  padding: 0.85rem 1rem; margin-bottom: 0.85rem; }
.adm-conta-filtros .field { margin: 0; }
.adm-conta-cifras { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: 0.6rem; margin-bottom: 0.85rem; }
.adm-conta-cifras .adm-cifra { padding: 0.7rem 0.9rem; }
.adm-conta-cifras .adm-cifra b { font-size: 1.25rem; }
/* La tabla es la herramienta: ancha, con desplazamiento propio y cabecera
   pegada arriba — leer 200 movimientos sin perder de vista los títulos. */
.adm-tabla-marco { overflow: auto; max-height: 62vh; border: 1px solid var(--hairline, #d8ddd9);
  border-radius: var(--r-lam, 12px); background: var(--surface, #fff); }
.adm-tabla { width: 100%; border-collapse: collapse; font-size: 0.8125rem; }
/* Cabecera fija. El fondo DEBE ser opaco: `--well` de la escena clara es
   rgba(58,44,28,0.07) —translúcido— y con él las filas se leían A TRAVÉS de
   los títulos al desplazarse (solapamiento medido en pantalla el 20-08). Se
   compone un gris de la misma familia pero sólido, con el color de fondo del
   marco como base; el fallback es igual de opaco. */
.adm-tabla th { position: sticky; top: 0; z-index: 3; text-align: left; white-space: nowrap;
  background-color: #e4e1da;
  background-color: color-mix(in srgb, var(--ink, #1a2422) 7%, var(--surface, #eae8e3));
  color: var(--ink-strong); font-weight: 600;
  padding: 0.55rem 0.7rem; border-bottom: 1px solid var(--hairline-strong, #9aa5a0);
  box-shadow: 0 1px 0 var(--hairline-strong, #9aa5a0); }
/* El cuerpo jamás compite con la cabecera por la capa. */
.adm-tabla tbody td { position: relative; z-index: 0; }
.adm-tabla td { padding: 0.42rem 0.7rem; border-bottom: 1px solid var(--hairline, #d8ddd9);
  vertical-align: middle;
  /* DENSIDAD (medido en pantalla el 20-08): con el texto envuelto, cada fila
     ocupaba 3–4 líneas y en un monitor cabían seis movimientos. Una tabla
     contable se lee por filas: UNA fila, UNA línea. Lo que no cabe se corta
     con puntos suspensivos y el texto completo vive en el `title`. */
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 26ch;
  /* Cada celda se puede pulsar para verla entera: el recorte es solo la vista
     en reposo, no una pérdida. Antes el texto completo vivía únicamente en el
     `title`, que en un móvil no existe —no hay ratón que pase por encima— y
     obligaba a adivinar. */
  cursor: pointer; }
.adm-tabla td.adm-td-largo { max-width: 40ch; }
.adm-tabla td.adm-td-num { max-width: none; }

/* Celda abierta: se despliega en su sitio, sin sacar a nadie de la tabla ni
   perder la fila que se estaba mirando. */
.adm-tabla td.abierta {
  white-space: normal; overflow: visible; max-width: 60ch;
  background: color-mix(in srgb, var(--gold-500, #cbab51) 12%, var(--surface));
  box-shadow: inset 3px 0 0 var(--gold-500, #cbab51);
}
/* Modo «ver todo»: la tabla deja de recortar por completo. Para cuando hay que
   leer de verdad y no solo repasar cifras. */
.adm-tabla.sin-recorte td { white-space: normal; overflow: visible; max-width: 46ch; }
.adm-tabla-barra { display: flex; gap: .5rem; align-items: center; margin-bottom: .5rem; }
.adm-tabla tbody tr:hover td { background: color-mix(in srgb, var(--gold-500, #cbab51) 8%, transparent); }
.adm-td-num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.adm-td-centro { text-align: center; }
.adm-td-vacio { color: var(--ink-quiet); }
.adm-td-largo { max-width: 34ch; }
.adm-th-orden { cursor: pointer; user-select: none; }
.adm-th-orden:hover { color: var(--metal); }
.adm-tabla-vacia { padding: 1.5rem; text-align: center; }
.adm-conta-paginas { display: flex; gap: 0.75rem; align-items: center; justify-content: center;
  margin-top: 0.75rem; }

/* Cinta de «se actualizó solo»: avisa sin interrumpir ni tapar el trabajo. */
.adm-cinta { position: fixed; left: 50%; bottom: 1.25rem; transform: translate(-50%, 1rem);
  background: var(--teal-800, #12403f); color: var(--cream, #f3f1e7);
  padding: 0.55rem 1.1rem; border-radius: 999px; font-size: 0.8125rem;
  box-shadow: 0 6px 20px rgb(0 0 0 / 0.18); opacity: 0; pointer-events: none;
  transition: opacity 0.25s ease, transform 0.25s ease; z-index: 60; }
.adm-cinta.visible { opacity: 1; transform: translate(-50%, 0); }
@media (prefers-reduced-motion: reduce) { .adm-cinta { transition: none; } }

/* Anotaciones enfrentadas al revisar una posible duplicación. Una debajo de
   otra y no en columnas: se comparan leyendo, y leer es de arriba abajo. */
.adm-dup-lista { display: grid; gap: .5rem; margin: .75rem 0 1rem; }
.adm-dup-item {
  display: flex; gap: .6rem; align-items: flex-start; cursor: pointer;
  padding: .6rem .7rem; border-radius: .5rem;
  border: 1px solid color-mix(in srgb, var(--ink) 14%, transparent);
  background: color-mix(in srgb, var(--ink) 3%, var(--surface));
}
.adm-dup-item:hover { border-color: color-mix(in srgb, var(--gold) 55%, transparent); }
.adm-dup-item input { margin-top: .25rem; flex: 0 0 auto; }
.adm-dup-item span { display: grid; gap: .15rem; min-width: 0; }
.adm-dup-item strong { font-size: .92rem; }
.adm-dup-item small { font-size: .8rem; color: color-mix(in srgb, var(--ink) 62%, transparent); }

/* Historial de un inmueble: lo que entra y lo que sale, uno al lado del otro.
   Antes solo se veían los pagos, y con esa mitad no se puede responder a la
   pregunta que de verdad hace un propietario: por qué recibió menos. */
.hist-resumen { display: flex; flex-wrap: wrap; gap: 1.25rem; margin: .75rem 0 1rem; font-size: .8125rem; }
.hist-cifra { color: var(--ink-quiet, #6b6355); }
.hist-cifra b { display: block; font-size: 1.05rem; color: var(--ink); font-variant-numeric: tabular-nums; }
.hist-cifra-fuerte b { color: var(--metal, #6b5f3f); }
.hist-cifra-ojo { color: #a8422f; }
.hist-titulo-lista {
  margin: 1.25rem 0 .5rem; font-size: .75rem; letter-spacing: .08em;
  text-transform: uppercase; color: var(--ink-quiet, #6b6355);
}

/* Lector del archivo. `pre` con envoltura: los documentos vienen en Markdown
   de Notion, con sus tablas y sangrías alineadas a base de espacios — si se
   reflowan como párrafo normal, una tabla de consignaciones se vuelve ilegible. */
.doc-cuerpo {
  max-height: 60vh; overflow: auto; margin: .75rem 0 0;
  padding: 1rem; border-radius: var(--r-lam, .5rem);
  background: color-mix(in srgb, var(--ink) 3%, var(--surface));
  border: 1px solid color-mix(in srgb, var(--ink) 12%, transparent);
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: .8125rem; line-height: 1.55;
  white-space: pre-wrap; word-break: break-word;
}
.hist-doc { font-size: .75rem; }

/* ==========================================================================
   28 · SOCIOS, RUTA DEL DINERO, PANORAMA DE GASTOS Y CUADRE  (22-08-2026)
   ==========================================================================
   Todo lo de aquí se escribe pensando primero en el teléfono de Angie y en
   Safari: nada de `gap` en flex sin respaldo, nada de `:has()` para lo
   estructural, ningún alto en `vh` que el navegador de iOS mueva al aparecer
   la barra de direcciones, y áreas de toque de 44px como mínimo, que es lo
   que pide la guía de Apple.
   ========================================================================== */

/* --- Las pestañas, cuando ya no caben ------------------------------------ */
@media (max-width: 46rem) {
  .adm-salas {
    flex-wrap: nowrap; overflow-x: auto; margin-inline: calc(var(--pad, 1rem) * -1);
    padding-inline: var(--pad, 1rem); padding-bottom: 0.35rem;
    -webkit-overflow-scrolling: touch;              /* inercia en iOS antiguo */
    scroll-snap-type: x proximity;
    scrollbar-width: none;
  }
  .adm-salas::-webkit-scrollbar { display: none; }
  .adm-sala { flex: 0 0 auto; scroll-snap-align: start; min-height: 2.75rem; }
}

/* --- Cifras compactas ---------------------------------------------------- */
.adm-cifras-compacta { margin-bottom: clamp(0.9rem, 2vh, 1.4rem); }
.adm-cifras-compacta .adm-cifra { padding: 0.7rem 0.9rem; }
.adm-cifras-compacta .adm-cifra b { font-size: clamp(1.1rem, 2vw, 1.4rem); }
.adm-cifra-aviso b { color: var(--bronze-500, #8c6a3f); }

/* --- Socios -------------------------------------------------------------- */
.adm-socios-intro { flex: 1 1 20rem; margin: 0; font-size: 0.8125rem; line-height: 1.5; }
.adm-socios-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(min(19rem, 100%), 1fr));
  gap: 0.75rem; margin-bottom: 1.5rem;
}
.adm-socio {
  position: relative; padding: 1rem 1.1rem; border-radius: var(--r-lam);
  background-color: var(--surface); border-left: 3px solid var(--socio-color, var(--metal));
}
.adm-socio-off { opacity: 0.55; }
.adm-socio-cab { display: flex; align-items: baseline; justify-content: space-between; margin-bottom: 0.5rem; }
.adm-socio-cab b { font-family: var(--font-display); font-size: 1.0625rem; line-height: 1.2; }
.adm-socio-datos { display: flex; flex-direction: column; margin: 0 0 0.5rem; font-size: 0.8125rem; line-height: 1.55; color: var(--ink-quiet); }
.adm-socio-cifras { margin: 0; font-size: 0.8125rem; color: var(--ink-quiet); font-variant-numeric: tabular-nums; }
.adm-socio-cifras b { color: var(--ink-strong); }
.adm-socio-notas { margin-top: 0.5rem; font-size: 0.75rem; line-height: 1.5; }
.adm-socio .adm-acciones { position: absolute; top: 0.6rem; right: 0.6rem; }
.adm-chip-socio { background-color: var(--well); color: var(--metal); }
.adm-chip-aliado { background-color: var(--well); color: var(--bronze-500, #8c6a3f); }
.adm-chip-destino { background-color: var(--well); color: var(--teal-600, #24605f); }

/* --- La ruta de un inmueble ---------------------------------------------- */
.adm-ruta-barra { display: flex; gap: 0.6rem; flex-wrap: wrap; align-items: center; }
.adm-ruta { padding: 1rem 1.1rem; border-radius: var(--r-lam); background-color: var(--surface); }
.adm-ruta h4 { margin: 0 0 0.5rem; font-family: var(--font-display); font-size: 1.0625rem; }
.adm-ruta-linea { display: flex; flex-wrap: wrap; gap: 0.35rem 1rem; margin: 0 0 0.6rem; font-size: 0.8125rem; color: var(--ink-quiet); }
.adm-ruta-linea b { color: var(--ink-strong); font-variant-numeric: tabular-nums; }
.adm-ruta-texto { margin: 0 0 0.6rem; font-size: 0.875rem; line-height: 1.6; }
.adm-ruta-alertas { margin: 0 0 0.6rem; padding-left: 1.1rem; }
.adm-ruta-alerta { font-size: 0.8125rem; line-height: 1.5; color: var(--err); }
.adm-ruta-acciones { display: flex; flex-direction: column; gap: 0.5rem; }
.adm-ruta-accion { padding: 0.6rem 0.75rem; border-radius: var(--r-ctrl); background-color: var(--well); }
.adm-ruta-accion b { display: block; font-size: 0.875rem; margin-bottom: 0.15rem; }
.adm-ruta-accion span { font-size: 0.8125rem; line-height: 1.5; color: var(--ink-quiet); }

/* --- Panorama de gastos --------------------------------------------------- */
.adm-gastos-panorama { margin-bottom: 1.25rem; }
.adm-gastos-cortes { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(15rem, 100%), 1fr)); gap: 0.6rem; }
.adm-corte { border: 1px solid var(--hairline-strong); border-radius: var(--r-lam); background-color: var(--surface); }
.adm-corte > summary {
  padding: 0.7rem 0.9rem; cursor: pointer; font-size: 0.8125rem; letter-spacing: 0.02em;
  min-height: 2.75rem; display: flex; align-items: center; justify-content: space-between;
  list-style: none; -webkit-tap-highlight-color: transparent;
}
/* Safari sigue dibujando su propio triángulo si no se apaga el pseudo-elemento
   con prefijo: sin esta línea aparecen dos marcadores, uno encima del otro. */
.adm-corte > summary::-webkit-details-marker { display: none; }
.adm-corte > summary::after { content: '›'; transform: rotate(90deg); color: var(--ink-quiet); font-size: 1.1rem; line-height: 1; }
.adm-corte[open] > summary::after { transform: rotate(-90deg); }
.adm-corte-pista { color: var(--ink-quiet); font-variant-numeric: tabular-nums; margin-left: auto; margin-right: 0.6rem; }
.adm-corte-cuerpo { padding: 0 0.9rem 0.8rem; }
.adm-barra-fila { display: grid; grid-template-columns: minmax(0, 1fr) 4.5rem auto; gap: 0.5rem; align-items: center; padding: 0.28rem 0; }
.adm-barra-nom { font-size: 0.8125rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.adm-barra-pista { display: block; height: 0.3rem; border-radius: 999px; background-color: var(--well); overflow: hidden; }
.adm-barra-pista i { display: block; height: 100%; background-color: var(--metal); }
.adm-barra-val { font-size: 0.8125rem; text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.adm-barra-val small { display: block; font-size: 0.6875rem; color: var(--ink-quiet); }
.adm-gastos-avisos { margin-top: 0.6rem; }
.adm-aviso-linea { margin: 0.2rem 0; font-size: 0.8125rem; line-height: 1.5; color: var(--bronze-500, #8c6a3f); }

/* --- El cuadre de la sociedad -------------------------------------------- */
.adm-cuadre { margin-top: 0.75rem; }
.adm-cuadre-frase { margin: 0 0 0.7rem; font-size: 0.875rem; line-height: 1.6; }
.adm-cuadre-socios { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(15rem, 100%), 1fr)); gap: 0.6rem; margin-bottom: 0.6rem; }
.adm-cuadre-socio { display: flex; flex-direction: column; padding: 0.75rem 0.9rem; border-radius: var(--r-ctrl); background-color: var(--well); }
.adm-cuadre-socio b { font-size: 0.9375rem; margin-bottom: 0.2rem; }
.adm-cuadre-socio span { font-size: 0.8125rem; line-height: 1.5; color: var(--ink-quiet); font-variant-numeric: tabular-nums; }
.adm-cuadre-falta { color: var(--ink-strong) !important; font-weight: 600; }
.adm-cuadre-ya { color: var(--bronze-500, #8c6a3f) !important; }
.adm-cuadre-cuenta { font-size: 0.6875rem !important; margin-top: 0.25rem; }
.adm-cuadre-alerta { outline: 1px solid var(--err); }
.adm-cuadre-alerta .adm-cuadre-falta { color: var(--err) !important; }

/* --- Cambio de inquilino -------------------------------------------------- */
.adm-modal-nota { margin: -0.35rem 0 0.9rem; font-size: 0.8125rem; line-height: 1.55; }
/* Las otras cajas estrechas que pintan filas: el historial del inmueble y los
   candidatos de la liquidación. Con esto también consultan su propio ancho. */
#histGastos, #lGastos, .adm-lista-corta { container-type: inline-size; }
.adm-lista-corta { max-height: 14rem; overflow-y: auto; -webkit-overflow-scrolling: touch; }
.adm-candidato {
  display: flex; flex-direction: column; align-items: flex-start; width: 100%;
  padding: 0.6rem 0.75rem; border: 1px solid var(--hairline-strong); border-radius: var(--r-ctrl);
  background: none; cursor: pointer; font: inherit; text-align: left; min-height: 2.75rem;
}
.adm-candidato.active { border-color: var(--metal); background-color: var(--well); }
.adm-candidato b { font-size: 0.875rem; }
.adm-candidato span { font-size: 0.75rem; color: var(--ink-quiet); }

/* --- La tarjeta de confirmación del asistente ---------------------------- */
.ia-confirma-campos {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(11rem, 100%), 1fr));
  gap: .35rem .8rem; margin: 0 0 .6rem;
  padding: .55rem .65rem; border-radius: 8px; background: rgba(0, 0, 0, .04);
}
.ia-campo { min-width: 0; }
.ia-confirma-campos dt { font-size: .6875rem; letter-spacing: .06em; text-transform: uppercase; color: var(--tinta-suave, #6B6558); }
.ia-confirma-campos dd { margin: 0; font-size: .8125rem; line-height: 1.4; word-break: break-word; overflow-wrap: anywhere; }
.ia-confirma-porque { margin: 0 0 .5rem; font-size: .8125rem; line-height: 1.5; color: var(--tinta-suave, #6B6558); }
.ia-confirma-cuidado { margin: 0 0 .5rem; padding-left: 1.1rem; }
.ia-confirma-cuidado li { font-size: .8125rem; line-height: 1.5; margin-bottom: .2rem; }
.ia-confirma-reversible { margin: 0 0 .6rem; font-size: .75rem; }
.ia-confirma-botones .btn { min-height: 2.75rem; }

/* Con el teclado abierto en iOS la tarjeta puede quedar más alta que la
   pantalla; que tenga su propio desplazamiento evita que los botones queden
   fuera de alcance sin manera de llegar a ellos. */
@media (max-height: 40rem) {
  .ia-confirma { max-height: 60vh; overflow-y: auto; -webkit-overflow-scrolling: touch; }
}

/* Quien haya pedido menos movimiento, que no lo tenga. */
@media (prefers-reduced-motion: reduce) {
  .adm-corte > summary::after { transition: none; }
  .ia-pensando { animation: none; opacity: .7; }
}

/* La frase del cuadre, dentro del bloque de avisos. Se pintaba con esta clase
   y no tenía ninguna regla: se veía, pero por accidente. */
.adm-cuadre-explica { display: block; margin-bottom: 0.4rem; }

/* --- Lo que no se puede deshacer, se ve distinto (24-08-2026) -------------
   El asistente ya puede emitir liquidaciones y cerrar el mes de Galatea. Los
   dos ponen folio y congelan. La tarjeta cambia de color, de título y de
   texto en el botón: quien confirme uno de estos tiene que haberse dado
   cuenta de que lo estaba haciendo. */
.ia-confirma-grave {
  border-color: var(--err, #A03A28);
  background: rgba(160, 58, 40, .07);
}
.ia-confirma-grave .ia-confirma-titulo { color: var(--err, #A03A28); }
.ia-confirma-grave .ia-confirma-reversible {
  color: var(--err, #A03A28); font-weight: 600;
}
.ia-confirma-grave .ia-confirma-cuidado li { color: var(--err, #A03A28); }

/* ==========================================================================
   EL VISOR DE FOTOGRAFÍAS (APPLE1, 28-08-2026)
   ==========================================================================
   La lámina deja de ser un `<span>` y pasa a ser un `<button>`: así se puede
   pulsar con el dedo, con el ratón, con el teclado y con un lector de
   pantalla, sin escribir una sola línea de accesibilidad a mano. Un `div` con
   `onclick` habría necesitado rol, tabindex y manejo de Enter y Espacio —tres
   sitios donde equivocarse— para acabar siendo un botón peor.

   Se hereda el aspecto de `.plate` tal cual; solo hay que apagar lo que el
   navegador le pone de fábrica a los botones.
   ========================================================================== */
.lam-abrir {
  display: block;
  width: 100%;
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  color: inherit;
  cursor: zoom-in;
  /* iOS pinta un destello gris al tocar cualquier cosa pulsable. En una
     fotografía a pantalla casi completa eso se ve como un parpadeo sucio. */
  -webkit-tap-highlight-color: transparent;
}
.lam-abrir:focus-visible {
  outline: 2px solid var(--focus-ring, #CBAB51);
  outline-offset: 3px;
}

.visor-back { padding: 0; background-color: rgba(4, 16, 15, 0.94); z-index: 900; }
.visor {
  position: relative;
  width: 100%;
  /* `dvh` y no `vh`: en iOS la barra de direcciones entra y sale, y con `vh`
     el visor queda cortado por abajo justo donde va el contador. Es el mismo
     criterio que ya sigue el resto de la hoja. */
  height: 100dvh;
  display: flex;
  align-items: center;
  justify-content: center;
}
.visor-img {
  max-width: 94vw;
  max-height: 82dvh;
  width: auto;
  height: auto;
  object-fit: contain;
  border-radius: 2px;
  /* Sin esto, arrastrar la foto en un escritorio la «despega» como si fuera
     un archivo, y el gesto de pasar a la siguiente se pierde. */
  -webkit-user-drag: none;
  user-select: none;
  -webkit-user-select: none;
}
.visor-x, .visor-nav {
  position: absolute;
  background-color: rgba(4, 16, 15, 0.62);
  color: var(--cream, #F3F1E7);
  border: 1px solid rgba(203, 171, 81, 0.42);
  cursor: pointer;
  line-height: 1;
  display: grid;
  place-items: center;
  -webkit-tap-highlight-color: transparent;
}
/* 44 px es el mínimo que Apple pide para un objetivo táctil, y es la razón
   por la que estos botones son más grandes de lo que su icono sugiere. */
.visor-x {
  top: max(0.75rem, env(safe-area-inset-top));
  right: max(0.75rem, env(safe-area-inset-right));
  width: 44px; height: 44px;
  font-size: 1.75rem;
  border-radius: 50%;
}
.visor-nav {
  top: 50%;
  transform: translateY(-50%);
  width: 48px; height: 64px;
  font-size: 2rem;
}
.visor-prev { left: max(0.5rem, env(safe-area-inset-left)); }
.visor-next { right: max(0.5rem, env(safe-area-inset-right)); }
.visor-x:hover, .visor-nav:hover { background-color: rgba(203, 171, 81, 0.28); }
.visor-x:focus-visible, .visor-nav:focus-visible {
  outline: 2px solid var(--gold-400, #CBAB51);
  outline-offset: 2px;
}
.visor-cuenta {
  position: absolute;
  /* `env(safe-area-inset-bottom)` mantiene el contador por encima de la barra
     de gestos del iPhone, que si no lo tapa a medias. */
  bottom: calc(0.9rem + env(safe-area-inset-bottom));
  left: 0; right: 0;
  margin: 0;
  text-align: center;
  color: var(--cream-dim, #d8d5c7);
  font-size: 0.85rem;
  letter-spacing: 0.08em;
}
@media (max-width: 30rem) {
  /* En un teléfono las flechas estorban más que ayudan: se desliza. Se dejan
     visibles pero pequeñas y abajo, para quien no descubra el gesto.

     Medido en un viewport de 375×812: con `2.6rem` las flechas terminaban a
     5 px del contador. Cabía, pero cinco píxeles no son un margen, son una
     casualidad — y en una pantalla un poco más baja se tocan. Con `3rem` el
     hueco sube a 11 px y deja de depender de la suerte. */
  .visor-nav { width: 40px; height: 48px; font-size: 1.5rem; top: auto; bottom: calc(3rem + env(safe-area-inset-bottom)); transform: none; }
}

/* Enlaces dentro de la conversación del asistente (WA7). El de WhatsApp se
   ve como lo que es —un botón que abre el chat— y no como una dirección que
   hay que copiar. Hereda el oro de la casa: el verde de WhatsApp no entra. */
.ia-enlace { color: var(--metal, #CBAB51); text-underline-offset: 3px; }
.ia-enlace-wa {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  margin: 0.35rem 0;
  padding: 0.45rem 0.8rem;
  border: 1px solid var(--hairline-strong, rgba(203, 171, 81, 0.42));
  border-radius: 2px;
  text-decoration: none;
  font-weight: 600;
  /* 44 px de alto real: es un objetivo táctil, no un enlace de texto. */
  min-height: 44px;
  box-sizing: border-box;
  -webkit-tap-highlight-color: transparent;
}
/* Aquí iba un icono pintado con `mask` y una variable `--wa-mask` que nunca
   llegué a definir: sin máscara, `background-color: currentColor` habría
   dibujado un cuadrado dorado sólido al lado de cada enlace. Se quita en vez
   de inventarle un valor — la etiqueta ya dice «Abrir el chat de WhatsApp»,
   que es más claro que cualquier icono. */
.ia-enlace-wa:hover { background-color: rgba(203, 171, 81, 0.14); }
.ia-enlace-wa:focus-visible { outline: 2px solid var(--focus-ring, #CBAB51); outline-offset: 2px; }

/* ----------------------------------------------------------------------------
   LA VISTA PREVIA DEL INFORME, DENTRO DEL FORMULARIO DE LIQUIDAR — 19-09-2026
   ----------------------------------------------------------------------------
   Se ve como el papel y no como el formulario: fondo de hoja, filete de oro
   sobre el neto y la misma tipografía de cifras. La diferencia visual es el
   mensaje —«esto no es un campo más, esto es lo que va a salir»— y es lo que
   hace que se lea antes de pulsar Emitir en vez de después, cuando el folio ya
   está sellado y el documento solo se puede reemplazar.
-------------------------------------------------------------------------- */
.adm-previa {
  margin: 0.75rem 0 0; padding: 0.875rem 1rem;
  border: 1px solid var(--hairline); border-radius: 0.5rem;
  background-color: var(--well);
}
.adm-previa-titulo {
  margin: 0 0 0.5rem; font-size: 0.75rem; letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--ink-quiet);
}
.adm-previa-tabla { width: 100%; border-collapse: collapse; }
.adm-previa-tabla td { padding: 0.4rem 0; border-bottom: 1px solid var(--hairline); vertical-align: top; }
.adm-previa-tabla .num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.adm-previa-tabla small { display: inline-block; margin-top: 0.15rem; font-size: 0.75rem; line-height: 1.35; }
.adm-previa-neto td {
  border-bottom: none; border-top: 2px solid var(--metal);
  padding-top: 0.55rem; font-weight: 700;
}
