/* ==========================================================================
   Casa Verdezza — sistema de diseño compartido
   Lo cargan las CUATRO interfaces (public, family, care, crm) ANTES de su
   propio styles.css, que solo debe contener composición.
   --------------------------------------------------------------------------
   MARCA: Casa Verdezza (manual de marca y kit de logotipos, sept-2026).
   Sustituye a la identidad "Green House" en todo el ecosistema. Los nombres
   de los tokens no cambiaron en la migración —`--sage` sigue siendo el color
   de marca— para que ninguna superficie tuviera que reescribirse; lo que
   cambió son los VALORES. Ver docs/01-arquitectura.md §1.7.

   DIRECCIÓN VISUAL: crema, bosque y oro.
   El lienzo es un crema cálido (--paper #F5F0E6), no un blanco ni un verde:
   es papel con luz, y es lo que separa a Casa Verdezza de cualquier producto
   de salud. Sobre él, verde bosque profundo (--sage #1E4638) para todo lo que
   manda, y oro (--accent) para lo que acompaña: la versalita que presenta una
   sección, la palabra en cursiva que remata un titular, la regla de 2px.
   Las formas son redondas —píldoras de 999px, tarjetas de 26px— porque una
   casa no tiene esquinas vivas. El tiempo —la bitácora, el ritmo del día— es
   un dispositivo estructural, no un adorno.

   REGLAS QUE NO SE NEGOCIAN AL AGREGAR PANTALLAS
   1. Contenido nunca baja de 16px. Solo micro-etiquetas en versalitas con
      tracking bajan a 13px, y se usan cuando codifican información real.
   2. Todo control interactivo mide >= --tap (44px).
   3. Marca: verde bosque + oro (--accent). El azul (--teal) informa, no
      decora. Nada de morado ni "azul SaaS".
   4. Iconos: SVG del sprite de cada página. Nunca emojis.
   5. El movimiento responde a una acción del usuario. La única excepción es
      UNA entrada orquestada por superficie. Con prefers-reduced-motion no se
      atenúa: se desactiva.
   ========================================================================== */

:root {
  /* --- Color ------------------------------------------------------------
     Superficies: crema de papel. El blanco puro no existe en esta marca; el
     panel es un blanco CÁLIDO, para que sobre el crema lea como luz y no
     como un recorte de otra paleta. */
  --paper: #f6f1e7;       /* lienzo de marca («Admin — Vistas», sept-2026) */
  --paper-sunk: #efe9dd;  /* un paso por debajo: encabezados, huecos */
  --pane: #fffcf5;        /* blanco cálido: tarjetas, paneles */
  --pane-soft: #f7f2e9;   /* bloque recogido dentro de un panel */

  /* Tinta verde-negra de marca. */
  --ink: #1c2b24;
  --ink-soft: #55645b;
  /* Medido contra las TRES superficies reales, no solo contra el panel:
     --pane 5.7:1 · --paper 5.2:1 · --paper-sunk 4.8:1.

     El diseño de septiembre traia aqui #6b7a70 y **no pasa AA en ninguna de
     las tres**: 4.41 sobre el panel, 4.02 sobre el papel y 3.74 sobre el
     hundido. Es el mismo fallo que ya se documento con otro candidato (#5b6b60,
     4.42 sobre --paper-sunk): el gris que se ve bien sobre el panel se cae
     sobre el crema hundido, que es donde viven los encabezados.

     Este valor es ese mismo tono al 85%: visualmente es el del diseño y pasa
     AA con margen en las tres. Es la unica correccion que se le hizo a la
     paleta entregada, y se hizo midiendo. */
  --ink-faint: #5b685f;

  /* Marca. Verde bosque del logotipo oficial.
     Crema (--paper) sobre --sage = 8.9:1 · --sage como texto sobre crema = 8.9:1. */
  --sage: #1f4a3a;
  --sage-deep: #163629;
  /* Verde vivo: SOLO decorativo (puntos, reglas, halos). Como texto da
     3.3:1 y no pasa AA en ninguna superficie. */
  --sage-bright: #3f8a5e;
  --sage-wash: #dce9df;
  /* Dos verdes claros mas del diseño, y no son el mismo: --sage-soft es el
     fondo de un distintivo sobre crema; --sage-line es la barra de progreso
     DENTRO de una tarjeta verde, donde un verde oscuro no se veria. */
  --sage-soft: #e4ede6;
  --sage-line: #9fd1ae;

  /* Oro: el acento de Casa Verdezza, donde antes iba el azul de confianza.
     Dos valores porque tienen trabajos distintos y solo uno es legible:
       --accent      texto (versalitas, enlaces en hover)  5.4:1 sobre --paper
       --accent-lit  decoración (reglas, filos, halos)     NO es para texto */
  /* El oro de texto del diseño de septiembre es mas oscuro que el anterior
     (#7a5c2a) y por eso CONTRASTA MEJOR: 6.4:1 sobre el papel contra 5.4:1. */
  --accent: #7a4e12;
  --accent-lit: #c4a26b;
  /* Tercer oro, y no es un capricho: el del manual (--accent-lit) da 4.39:1
     sobre el verde de marca y se queda justo por debajo de AA. Sobre fondo
     oscuro el oro que SE LEE es este; --accent-lit sigue valiendo ahí para
     filetes y puntos, que no son texto. */
  --accent-on-dark: #d4b88a;
  --accent-wash: #faebd2;
  /* El filete del aviso ambar. No es --accent-lit: ese es decorativo de marca
     y este delimita un bloque de atencion. */
  --accent-line: #edd3a6;

  /* Azul-verdoso de la submarca Salud y Rehabilitación: INFORMACIÓN y
     MEDICIÓN. Es el único color del ecosistema que no es ni verde, ni oro,
     ni tierra, y por eso sirve para lo que hay que distinguir de un vistazo
     sin leer: las etapas de trato activo del CRM, los signos vitales, los
     avisos informativos. 6.6:1 sobre --paper.

     No confundir con --accent: el oro ENFATIZA (es la voz de la marca), el
     azul INFORMA. Un distintivo de "signos vitales" en oro competía con el
     rótulo dorado de la sección que tiene justo encima. */
  --teal: #2a5b6e;
  --teal-wash: #deeaee;
  /* --trust (el azul de la identidad anterior) ya no existe. Durante la
     migración fue un alias del oro para no reescribir cinco superficies de
     golpe; ahora que --teal tiene el significado que --trust tenía, un
     token cuyo nombre dice una cosa y cuyo valor dice otra solo confunde.
     Lo informativo usa --teal; el énfasis de marca, --accent. */

  /* Atención (requiere acción) y error. Son DOS cosas y tienen que verse
     como dos cosas: "quedan 4 paquetes" y "este lote está vencido" no piden
     la misma reacción.

     Ámbar para atención, rojo de tierra para error. El terracota del manual
     (#a34f2c, el de la submarca Cuidado a Domicilio) se probó aquí y fue un
     error: a 16 puntos de distancia del rojo, los dos avisos del inventario
     se leían como el mismo. Ese color sigue siendo el de su submarca —en la
     rejilla del ecosistema del sitio— pero no es un color de estado. */
  --clay: #8a5a14;
  --clay-wash: #f7edd8;
  --alert: #9b3a26;
  --alert-wash: #fae7e1;

  /* Estructura: reglas finas sobre crema. */
  --rule: #e6ddcb;
  --rule-strong: #cfc5b1;

  /* Sombras: cuatro niveles con intención distinta, no una sola genérica.
     --lift solo aparece en respuesta a hover/foco. */
  /* Teñidas de verde marca, no de gris: sobre un lienzo crema una sombra
     neutra se ve sucia. */
  --shadow-pane: 0 1px 2px rgba(31, 74, 58, 0.05), 0 1px 1px rgba(31, 74, 58, 0.03);
  --shadow-lift: 0 12px 30px -14px rgba(31, 74, 58, 0.28);
  --shadow-float: 0 24px 54px -22px rgba(31, 74, 58, 0.34);
  --shadow-glow: 0 0 0 3px var(--sage-wash);

  /* --- Tipografía --------------------------------------------------------
     Fraunces con los ejes SOFT y WONK activos: la variante "wonky" de la
     fuente aporta el carácter humano que pide la marca sin cambiar de familia.
     Atkinson Hyperlegible (Braille Institute) para todo lo demás. */
  --font-display: "Fraunces", Georgia, "Times New Roman", serif;
  --font-body: "Atkinson Hyperlegible", -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;

  /* Escala modular ~1.25 sobre una base de 16px.
     --t-small es el papel "secundario" (ayudas, metadatos, fechas, botones
     compactos) y mide LO MISMO que el cuerpo a propósito: en Casa Verdezza la
     información secundaria se distingue por color (--ink-faint) y por peso,
     nunca encogiendo la letra. El piso de 16px del brief no admite excepciones
     para texto que alguien tiene que leer. */
  --t-micro: 0.8125rem;  /* 13px — ÚNICA excepción: versalitas con tracking que
                            etiquetan datos (encabezado de columna, tipo de
                            registro). La caja alta y el interletrado compensan. */
  --t-small: 1rem;       /* 16px — secundario */
  --t-body: 1rem;        /* 16px — cuerpo */
  --t-body-lg: 1.0625rem;/* 17px */
  --t-lead: 1.1875rem;   /* 19px — entradillas */
  --t-h3: 1.375rem;      /* 22px */
  --t-h2: 1.75rem;       /* 28px */
  --t-h1: 2.25rem;       /* 36px */

  /* --- Espacio (base 4) --- */
  --s-1: 4px;  --s-2: 8px;  --s-3: 12px; --s-4: 16px;
  --s-5: 20px; --s-6: 24px; --s-8: 32px; --s-10: 40px;
  --s-12: 48px; --s-16: 64px; --s-20: 80px; --s-24: 96px;

  /* --- Forma ---
     Radios distintos por jerarquía: un radio único en todo es un tic visual. */
  /* Casa Verdezza es redonda: una casa no tiene esquinas vivas. Los radios
     subieron respecto a la identidad anterior y los controles pasaron a ser
     píldoras completas, como en el diseño de marca. */
  --r-sm: 10px;
  --r-md: 16px;
  --r-lg: 26px;
  --r-xl: 34px;
  --r-pill: 999px;
  /* Radio del bloque de llamada a la acción: el elemento más grande y más
     redondo del sitio, y el único que lo usa. */
  --r-cta: 40px;

  /* --- Movimiento --- */
  --ease: cubic-bezier(0.22, 1, 0.36, 1);        /* salida suave, entrada decidida */
  /* El easing del manual de marca: arranca decidido y frena largo. Es el
     que usan el titular, la galería y las filas del modelo MAHRI. */
  --ease-marca: cubic-bezier(0.2, 0.8, 0.2, 1);
  --ease-soft: cubic-bezier(0.65, 0, 0.35, 1);
  --dur-fast: 140ms;
  --dur: 220ms;
  --dur-slow: 440ms;

  /* Objetivo táctil mínimo (WCAG 2.5.5). */
  --tap: 44px;
}

/* ==========================================================================
   Base
   ========================================================================== */

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: var(--t-body);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

[hidden] { display: none !important; }

h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-weight: 600;
  line-height: 1.15;
  letter-spacing: -0.012em;
  margin: 0;
  text-wrap: balance;
  /* SOFT suaviza los terminales; WONK activa las formas swash de Fraunces. */
  font-variation-settings: "SOFT" 40, "WONK" 1;
}

/* Los navegadores le dan a <figure> un `margin: 1em 40px` heredado de los
   noventa. Sin reiniciarlo, una figura dentro de una rejilla se sale 40px
   por cada lado y provoca scroll horizontal en móvil. Lo mismo con
   <blockquote>, <dl> y <dd>. */
p, figure, blockquote, dl, dd { margin: 0; }
/* Medida de lectura por debajo de 80 caracteres (Bringhurst). */
p, li { max-width: 68ch; }

/* Verde de marca, oro al pasar por encima: es el gesto de enlace de Casa
   Verdezza. El oro claro (--accent-lit) nunca se usa aquí — no es legible. */
a { color: var(--sage); text-underline-offset: 3px; text-decoration-thickness: 1.5px; }
a:hover { color: var(--accent); }

img, svg { max-width: 100%; }

:focus-visible {
  outline: 3px solid var(--sage);
  outline-offset: 2px;
  border-radius: 4px;
}
/* Sobre fondos de marca el anillo verde desaparece: se invierte a blanco. */
.on-brand :focus-visible, :focus-visible.on-brand { outline-color: #fff; }

::selection { background: var(--sage-wash); color: var(--sage-deep); }

.icon {
  width: 1em; height: 1em;
  stroke: currentColor; fill: none;
  stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round;
  flex: none;
}

/* Solo para lectores de pantalla. */
.sr-only {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* Primer tabulable de cada página. */
.skip-link {
  position: absolute; left: var(--s-3); top: -72px; z-index: 100;
  background: var(--sage-deep); color: #fff;
  padding: var(--s-3) var(--s-5);
  border-radius: var(--r-sm);
  font-weight: 700; text-decoration: none;
  transition: top var(--dur) var(--ease);
}
.skip-link:focus { top: var(--s-3); }

/* Versalitas con tracking. Se usan SOLO cuando la etiqueta codifica
   información (tipo de registro, encabezado de columna), nunca como adorno
   encima de un título. */
/* La versalita que presenta una sección va en oro y con MÁS interletrado
   que el resto del sistema: es el gesto editorial de la marca. Cuando la
   etiqueta rotula un dato (encabezado de columna) sigue yendo apagada, con
   .label-micro.is-quiet. */
.label-micro {
  font-size: var(--t-micro);
  font-weight: 700;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--accent);
}
.label-micro.is-quiet { letter-spacing: 0.07em; color: var(--ink-faint); }

/* Filete de 2px que acompaña a la versalita en el diseño de marca. */
.label-micro.has-rule { display: inline-flex; align-items: center; gap: var(--s-3); }
.label-micro.has-rule::before {
  content: ""; width: 40px; height: 2px; flex: none;
  background: var(--accent-lit);
}

/* ==========================================================================
   Movimiento
   La clase .js-motion la pone motion.js en <html>. Sin JS, nada se oculta:
   el contenido es visible siempre, la animación es progresiva.
   ========================================================================== */

.js-motion [data-reveal] {
  opacity: 0;
  transform: translateY(16px);
  will-change: opacity, transform;
}
.js-motion [data-reveal].is-revealed {
  opacity: 1;
  transform: none;
  transition:
    opacity var(--dur-slow) var(--ease) var(--reveal-delay, 0ms),
    transform var(--dur-slow) var(--ease) var(--reveal-delay, 0ms);
}
/* Variante para el panel del hero: entra desde la derecha, no desde abajo. */
.js-motion [data-reveal="side"] { transform: translateX(22px); }

/* Apagado total del movimiento. No se atenúa: se desactiva y todo queda
   en su estado final e inmediato. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    transition-delay: 0ms !important;
    scroll-behavior: auto !important;
  }
  html { scroll-behavior: auto !important; }
  .js-motion [data-reveal] { opacity: 1 !important; transform: none !important; }
}

/* ==========================================================================
   Botones — la jerarquía la marca el peso visual, no el tamaño
   ========================================================================== */

.btn {
  display: inline-flex; align-items: center; justify-content: center;
  gap: var(--s-2);
  min-height: var(--tap);
  padding: 11px var(--s-6);
  border: 1.5px solid transparent;
  /* Píldora: la forma de botón de la marca, en las cinco superficies. */
  border-radius: var(--r-pill);
  font-family: var(--font-body);
  font-size: var(--t-body);
  font-weight: 700;
  line-height: 1.3;
  text-decoration: none;
  cursor: pointer;
  touch-action: manipulation;
  position: relative;
  transition:
    background var(--dur-fast) var(--ease-soft),
    border-color var(--dur-fast) var(--ease-soft),
    color var(--dur-fast) var(--ease-soft),
    box-shadow var(--dur) var(--ease),
    transform var(--dur-fast) var(--ease);
}
.btn:disabled, .btn[aria-disabled="true"] {
  opacity: 0.5; cursor: not-allowed; transform: none !important; box-shadow: none !important;
}
/* Respuesta táctil: el botón cede bajo el dedo/cursor. */
.btn:active:not(:disabled) { transform: translateY(1px) scale(0.99); }

.btn-primary { background: var(--sage); color: #fff; box-shadow: var(--shadow-pane); }
.btn-primary:hover:not(:disabled) {
  background: var(--sage-deep); color: #fff;
  transform: translateY(-2px); box-shadow: var(--shadow-lift);
}

.btn-outline {
  background: transparent; color: var(--sage);
  border-color: var(--rule-strong);
}
.btn-outline:hover:not(:disabled) {
  background: var(--sage-wash); border-color: var(--sage); color: var(--sage-deep);
  transform: translateY(-2px);
}

.btn-quiet { background: transparent; color: var(--sage-deep); }
.btn-quiet:hover:not(:disabled) { background: var(--sage-wash); color: var(--sage-deep); }

.btn-danger { background: var(--alert-wash); color: var(--alert); border-color: var(--alert); }
.btn-danger:hover:not(:disabled) { background: var(--alert); color: #fff; }

.btn-block { width: 100%; }
.btn-sm { min-height: var(--tap); padding: 8px var(--s-5); font-size: var(--t-small); }

/* Indicador de proceso dentro del botón. */
.btn-spinner {
  width: 16px; height: 16px; flex: none;
  border: 2.5px solid currentColor; border-top-color: transparent;
  border-radius: 50%;
  animation: gh-spin 0.7s linear infinite;
}
@keyframes gh-spin { to { transform: rotate(360deg); } }

/* ==========================================================================
   Campos de formulario
   ========================================================================== */

.field { margin-top: var(--s-5); }
.field:first-child { margin-top: 0; }

.field > label, label.field-label {
  display: block;
  font-size: var(--t-body);
  font-weight: 700;
  color: var(--ink-soft);
  margin-bottom: var(--s-2);
}

.field-hint {
  display: block;
  font-size: var(--t-small);
  color: var(--ink-faint);
  margin: -2px 0 var(--s-2);
  max-width: 62ch;
}

input, select, textarea {
  width: 100%;
  min-height: var(--tap);
  padding: 11px 14px;
  border: 1.5px solid var(--rule-strong);
  border-radius: var(--r-sm);
  background: var(--pane);
  color: var(--ink);
  font-family: inherit;
  font-size: var(--t-body);
  transition: border-color var(--dur-fast) var(--ease-soft), box-shadow var(--dur-fast) var(--ease-soft);
}
input:hover, select:hover, textarea:hover { border-color: var(--sage-bright); }
input:focus, select:focus, textarea:focus {
  outline: none;
  border-color: var(--sage);
  box-shadow: var(--shadow-glow);
}
textarea { resize: vertical; min-height: 104px; line-height: 1.55; }

select {
  appearance: none;
  padding-right: 42px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%233f5242' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 13px center;
  background-size: 18px;
}

/* Error de campo: el mensaje dice qué pasó Y cómo resolverlo. */
input[aria-invalid="true"], select[aria-invalid="true"], textarea[aria-invalid="true"] {
  border-color: var(--alert);
  background: #fffbfa;
}
input[aria-invalid="true"]:focus, textarea[aria-invalid="true"]:focus, select[aria-invalid="true"]:focus {
  box-shadow: 0 0 0 3px var(--alert-wash);
}
.field-error {
  display: flex; align-items: flex-start; gap: var(--s-2);
  margin-top: var(--s-2);
  font-size: var(--t-small);
  font-weight: 700;
  color: var(--alert);
  animation: gh-field-in var(--dur) var(--ease);
}
.field-error .icon { width: 17px; height: 17px; margin-top: 2px; }
@keyframes gh-field-in { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: none; } }

/* Control segmentado (tipo de solicitud, filtros binarios). */
.segmented { display: flex; flex-wrap: wrap; gap: var(--s-2); }
.segment {
  min-height: var(--tap);
  padding: 9px var(--s-4);
  border: 1.5px solid var(--rule-strong);
  border-radius: var(--r-pill);
  background: var(--pane);
  color: var(--ink-soft);
  font-family: inherit; font-size: var(--t-small); font-weight: 700;
  cursor: pointer; touch-action: manipulation;
  transition: background var(--dur-fast) var(--ease-soft), border-color var(--dur-fast) var(--ease-soft),
              color var(--dur-fast) var(--ease-soft), transform var(--dur-fast) var(--ease);
}
.segment:hover { border-color: var(--sage); background: var(--sage-wash); }
.segment:active { transform: scale(0.97); }
.segment[aria-pressed="true"], .segment[aria-selected="true"] {
  background: var(--sage); border-color: var(--sage); color: #fff;
}

/* LA CUENTA dentro de la pildora: es lo que decide si merece la pena pulsarla.
   Vivia solo en la hoja del CRM; al necesitarla Family quedaron dos copias, asi
   que sube. «Negociacion 3» se lee de un golpe; «Negociacion (3)», no. */
.segment .count {
  margin-left: 2px;
  padding: 1px 8px;
  border-radius: var(--r-pill);
  background: var(--paper-sunk); color: var(--ink-soft);
  font-size: var(--t-micro); font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.segment[aria-pressed="true"] .count { background: rgba(255, 255, 255, 0.22); color: #fff; }

/* Una opcion VACIA se atenua en vez de desaparecer — pero solo donde el
   conjunto es fijo y hay que verlo entero: el CRM ensena el pipeline completo,
   porque «nadie en negociacion» es informacion y una etapa que desaparece hace
   creer que no existe. Donde el conjunto NO es fijo (los tipos de novedad de
   Family) la superficie no dibuja la opcion vacia: alli seria un clic perdido.
   La clase la pone quien decide; el componente solo sabe pintarla. */
.segment.is-zero:not([aria-pressed="true"]) { opacity: 0.5; }

/* ==========================================================================
   Superficies
   ========================================================================== */

/* Panel: la superficie base. Lee como vidrio iluminado sobre --paper. */
.pane {
  background: var(--pane);
  border: 1px solid var(--rule);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-pane);
}

/* Bloque recogido, sin elevación: para notas y avisos dentro de un panel. */
.inset {
  background: var(--pane-soft);
  border: 1px solid var(--rule);
  border-radius: var(--r-md);
  padding: var(--s-4);
}

/* ==========================================================================
   Distintivos de estado
   ========================================================================== */

.badge {
  display: inline-flex; align-items: center; gap: var(--s-2);
  padding: 5px 12px;
  border-radius: var(--r-pill);
  background: var(--sage-wash); color: var(--sage-deep);
  font-size: var(--t-small); font-weight: 700;
  white-space: nowrap;
}
.badge::before { content: ""; width: 7px; height: 7px; border-radius: 50%; background: currentColor; flex: none; }
.badge-info { background: var(--teal-wash); color: var(--teal); }
.badge-clay  { background: var(--clay-wash);  color: var(--clay); }
.badge-alert { background: var(--alert-wash); color: var(--alert); }
.badge-solid { background: var(--sage); color: #fff; }
.badge-flat::before { display: none; }

/* ==========================================================================
   Mensajes
   ========================================================================== */

.notice {
  display: flex; align-items: flex-start; gap: var(--s-3);
  padding: var(--s-3) var(--s-4);
  border-radius: var(--r-md);
  border: 1.5px solid transparent;
  font-size: var(--t-body);
  animation: gh-field-in var(--dur) var(--ease);
}
.notice .icon { width: 20px; height: 20px; margin-top: 2px; }
.notice-error { background: var(--alert-wash); color: var(--alert); border-color: color-mix(in srgb, var(--alert) 32%, transparent); }
.notice-ok    { background: var(--sage-wash);  color: var(--sage-deep); border-color: color-mix(in srgb, var(--sage) 28%, transparent); }
.notice-info  { background: var(--teal-wash); color: var(--teal); border-color: color-mix(in srgb, var(--teal) 26%, transparent); }
.notice-clay  { background: var(--clay-wash);  color: var(--clay); border-color: color-mix(in srgb, var(--clay) 30%, transparent); }

/* ==========================================================================
   Estados: carga, vacío, error
   ========================================================================== */

.skeleton-bar {
  height: 13px;
  border-radius: var(--r-pill);
  background: linear-gradient(90deg, var(--paper-sunk) 25%, #eef3ec 37%, var(--paper-sunk) 63%);
  background-size: 400% 100%;
  animation: gh-shimmer 1.4s ease-in-out infinite;
}
@keyframes gh-shimmer { from { background-position: 100% 0; } to { background-position: 0 0; } }
@media (prefers-reduced-motion: reduce) {
  .skeleton-bar { background: var(--paper-sunk); }
}

.state {
  padding: var(--s-16) var(--s-6);
  text-align: center;
  max-width: 46ch;
  margin-inline: auto;
}
.state-figure {
  width: 60px; height: 60px;
  margin: 0 auto var(--s-5);
  border-radius: var(--r-lg);
  display: grid; place-items: center;
  background: var(--sage-wash); color: var(--sage-deep);
}
.state-figure .icon { width: 28px; height: 28px; }
.state-figure.is-error { background: var(--alert-wash); color: var(--alert); }
.state h3 { font-size: var(--t-h3); margin-bottom: var(--s-3); }
.state p { color: var(--ink-soft); margin-inline: auto; margin-bottom: var(--s-2); }
.state-actions {
  margin-top: var(--s-6);
  display: flex; gap: var(--s-3); justify-content: center; flex-wrap: wrap;
}
.state-detail { margin-top: var(--s-5); font-size: var(--t-small); color: var(--ink-faint); word-break: break-word; }

/* ==========================================================================
   Toasts — confirman una acción sin robar el foco
   ========================================================================== */

.toast-region {
  position: fixed; left: 50%; bottom: var(--s-6);
  transform: translateX(-50%);
  z-index: 90;
  display: flex; flex-direction: column; gap: var(--s-3); align-items: center;
  width: min(460px, calc(100% - 32px));
  pointer-events: none;
}
.toast {
  display: flex; align-items: flex-start; gap: var(--s-3);
  width: 100%;
  padding: var(--s-4) var(--s-5);
  border-radius: var(--r-md);
  background: var(--ink); color: #fff;
  font-size: var(--t-body); font-weight: 700;
  box-shadow: var(--shadow-float);
  animation: gh-toast-in var(--dur) var(--ease);
}
.toast .icon { width: 20px; height: 20px; margin-top: 2px; }
.toast-ok .icon { color: var(--sage-bright); }
.toast-error { background: var(--alert); }
.toast.is-leaving { animation: gh-toast-out var(--dur) var(--ease-soft) forwards; }
@keyframes gh-toast-in  { from { opacity: 0; transform: translateY(16px) scale(0.97); } to { opacity: 1; transform: none; } }
@keyframes gh-toast-out { to { opacity: 0; transform: translateY(8px) scale(0.98); } }

/* ==========================================================================
   Diálogo lateral
   ========================================================================== */

.sheet-overlay {
  position: fixed; inset: 0; z-index: 80;
  background: rgba(18, 37, 27, 0.42);
  backdrop-filter: blur(3px);
  display: flex; justify-content: flex-end;
  animation: gh-fade-in var(--dur-fast) var(--ease-soft);
}
.sheet-overlay.is-leaving { animation: gh-fade-out var(--dur-fast) var(--ease-soft) forwards; }
@keyframes gh-fade-in  { from { opacity: 0; } to { opacity: 1; } }
@keyframes gh-fade-out { to { opacity: 0; } }

.sheet {
  width: min(520px, 100%);
  height: 100%;
  overflow-y: auto;
  overscroll-behavior: contain;
  background: var(--pane);
  box-shadow: -18px 0 52px rgba(18, 37, 27, 0.2);
  padding: var(--s-6) var(--s-6) var(--s-16);
  animation: gh-sheet-in var(--dur) var(--ease);
}
.sheet-overlay.is-leaving .sheet { animation: gh-sheet-out var(--dur-fast) var(--ease-soft) forwards; }
@keyframes gh-sheet-in  { from { transform: translateX(34px); opacity: 0.3; } to { transform: none; opacity: 1; } }
@keyframes gh-sheet-out { to { transform: translateX(22px); opacity: 0; } }

.sheet-close {
  width: var(--tap); height: var(--tap);
  flex: none; padding: 0;
  border: none; border-radius: 50%;
  background: var(--paper-sunk); color: var(--ink-soft);
  display: grid; place-items: center;
  cursor: pointer; touch-action: manipulation;
  transition: background var(--dur-fast) var(--ease-soft), color var(--dur-fast) var(--ease-soft), transform var(--dur-fast) var(--ease);
}
.sheet-close:hover { background: var(--sage-wash); color: var(--sage-deep); transform: rotate(90deg); }
.sheet-close .icon { width: 19px; height: 19px; }

/* La cabecera de la hoja: título a un lado, cerrar al otro. Vivía solo en el
   styles.css de Care, pero la usan cinco sitios —CRM, Admin, el sitio público y
   la hoja compartida de «Mis datos»—, y donde no estaba definida la «X» se caía
   debajo del título en cuanto este era largo. `min-width: 0` deja que el título
   se parta antes de empujar el botón fuera de la fila. El TAMAÑO del título es
   composición de cada superficie y se queda en su hoja. */
.sheet-head { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--s-4); margin-bottom: var(--s-5); }
.sheet-head > :first-child { min-width: 0; overflow-wrap: anywhere; }

/* Bloquea el scroll de fondo mientras hay un diálogo abierto. */
body.has-sheet { overflow: hidden; }

/* ==========================================================================
   Pantalla de arranque
   Se muestra mientras se comprueba si la cookie de sesión sigue viva. Es
   deliberadamente sobria: no es un momento para lucirse, es medio segundo
   entre abrir la app y ver lo que se vino a ver.
   ========================================================================== */

.view-boot {
  position: fixed; inset: 0; z-index: 70;
  display: grid; place-items: center;
  background: var(--paper);
}
.boot-card { display: grid; justify-items: center; gap: var(--s-5); }
.boot-card .brand-mark {
  width: 52px; height: 52px;
  border-radius: 15px;
  background: linear-gradient(152deg, var(--sage-bright), var(--sage-deep));
  color: #fff;
  display: grid; place-items: center;
  box-shadow: var(--shadow-lift);
  animation: boot-breathe 2s var(--ease-soft) infinite;
}
.boot-card .brand-mark .icon { width: 26px; height: 26px; }
.boot-text { color: var(--ink-faint); font-size: var(--t-small); }

/* Latido lento, no un spinner: comunica "espera un momento" sin urgencia. */
@keyframes boot-breathe {
  0%, 100% { transform: scale(1);    opacity: 1; }
  50%      { transform: scale(0.93); opacity: 0.72; }
}
@media (prefers-reduced-motion: reduce) {
  .boot-card .brand-mark { animation: none; }
}

/* ==========================================================================
   Utilidades mínimas
   ========================================================================== */

.stack > * + * { margin-top: var(--s-4); }
.row { display: flex; align-items: center; gap: var(--s-3); }
.row-between { display: flex; align-items: center; justify-content: space-between; gap: var(--s-4); }
.wrap-tight { max-width: 72ch; }
.text-soft { color: var(--ink-soft); }
.text-faint { color: var(--ink-faint); }
.nums { font-variant-numeric: tabular-nums; }

/* ==========================================================================
   ==========================================================================
   CAPA DE COMPOSICIÓN
   --------------------------------------------------------------------------
   Todo lo que sigue vivía repetido —con valores distintos— en dos, tres o
   cuatro superficies: el isotipo medía 44px en el CRM, 46px en Family y 52px
   en Care; la barra superior estaba escrita dos veces; la tabla solo existía
   en el CRM y la línea de tiempo solo en Family, aunque ambas son estructuras
   del ecosistema, no de una pantalla.

   La regla es la de siempre: aquí vive el LENGUAJE VISUAL; en el styles.css
   de cada superficie vive solo su COMPOSICIÓN y su vocabulario de dominio
   (qué es "grave", qué es "negociación"). Si un componente sirve a dos
   superficies, se escribe aquí una vez.
   ==========================================================================
   ========================================================================== */

/* ==========================================================================
   Marca — el bloque isotipo + nombre
   Un solo lockup para las cuatro superficies. Los tamaños son modificadores,
   no valores que cada app vuelve a inventar.
   ========================================================================== */

.brand { display: flex; align-items: center; gap: var(--s-3); min-width: 0; }

/* Cuando la marca es un ENLACE —lleva al sitio desde las apps internas— es un
   control, y le aplica la regla de 44px como a cualquier otro. El logotipo
   mide 38 de alto, así que sin esto el objetivo se queda corto. Estaba así en
   el CRM desde el principio y no se había visto: su auditoría solo llegaba a
   la pantalla de acceso, donde la marca no es un enlace. */
a.brand { min-height: var(--tap); }

/* La puerta de cada app: logotipo vertical centrado, el nombre de la app en
   versalita dorada y una línea que dice para quién es. Centrado y en
   columna, no en fila: una caja de acceso no tiene a dónde mirar más que a
   su propio centro. */
.login-brand {
  display: grid; justify-items: center; gap: var(--s-4);
  margin-bottom: var(--s-8);
  text-align: center;
}
.login-brand img { height: 96px; width: auto; }
.login-brand .label-micro { margin-bottom: calc(-1 * var(--s-2)); }

/* El isotipo NO se redibuja: es el archivo oficial del kit de marca
   (01_Logotipo/SVG/icono-app.svg). Antes era una hoja genérica dibujada a
   mano con un degradado; ahora, si el estudio actualiza el logotipo, basta
   reemplazar el archivo y cambia en las cinco superficies a la vez.
   El radio es el del propio icono (26/120 del lado) para que el recorte
   coincida exactamente con el arte. */
.brand-mark {
  width: 44px; height: 44px; flex: none;
  border-radius: 21.7%;
  background: url("/shared/marca/icono-app.svg") center / contain no-repeat;
  box-shadow: var(--shadow-pane);
}
.brand-mark.is-sm { width: 36px; height: 36px; }
.brand-mark.is-lg { width: 52px; height: 52px; }

/* En rem fijo a propósito: el lockup de marca no crece cuando Family sube su
   escala de contenido a 18px. La marca es constante; el contenido, no. */
.brand-name {
  font-family: var(--font-display); font-weight: 600;
  font-size: 1.1875rem; line-height: 1.2;
  font-variation-settings: "SOFT" 40, "WONK" 1;
}
.brand-sub { color: var(--ink-faint); font-size: var(--t-small); }

/* ==========================================================================
   Barra superior
   Un solo componente para Family, Care y el CRM. Incluye el respeto al
   notch (env safe-area-inset-top) que antes solo tenía Care: no estorba en
   escritorio, donde la variable resuelve a 0.
   ========================================================================== */

.topbar {
  position: sticky;
  /* Cede su sitio al aviso de conexión cuando lo hay (ver GH.watchConnection);
     sin él la variable vale 0 y la barra se pega arriba del todo. */
  top: var(--offline-h, 0px);
  z-index: 20;
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--s-3);
  padding: var(--s-3) var(--s-5);
  padding-top: max(var(--s-3), env(safe-area-inset-top));
  /* OPACA, por lo mismo que la barra de pestañas: es `sticky` y el contenido le
     pasa por debajo. El desenfoque disimula el cruce mientras el navegador lo
     aplica, pero no siempre lo aplica —sin GPU, con transparencias reducidas por
     accesibilidad, en una captura— y entonces se lee el texto de la página a
     través del nombre del hogar. Un efecto que a veces no está no es un efecto:
     es un fallo intermitente. El fondo es el mismo de la página, así que lo
     único que separa la barra es su filete inferior, que es lo que debe
     separarla. */
  background: var(--paper);
  border-bottom: 1px solid var(--rule);
}
.topbar .brand-mark { width: 36px; height: 36px; border-radius: 10px; }
.topbar .brand-mark .icon { width: 18px; height: 18px; }
.topbar .brand-name { font-size: 1.0625rem; }

/* Grupo elástico de la izquierda (título largo, migas): absorbe el ancho y
   deja el grupo de acciones pegado a la derecha. */
.topbar-main { display: flex; align-items: center; gap: var(--s-3); flex: 1; min-width: 0; }
/* Sin esto, el bloque de título+subtítulo no puede encoger por debajo de su
   contenido (regla de flexbox: `min-width` es `auto`) y el texto empuja fuera
   al grupo de la derecha en vez de recortarse. Se nota en cuanto la barra gana
   un control más, como el selector de hogar. */
.topbar-main > * { min-width: 0; }
.topbar-right { display: flex; align-items: center; gap: var(--s-3); }

/* Título de contexto dentro de la barra (el nombre del residente en Care). */
.topbar-title {
  font-family: var(--font-display); font-weight: 600;
  font-size: 1.3rem; line-height: 1.2;
  font-variation-settings: "SOFT" 50, "WONK" 1;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.topbar-sub {
  color: var(--ink-faint); font-size: var(--t-small);
  /* Una línea, igual que el título: el nombre de quien entró y su rol pueden
     sumar cuarenta caracteres, y envolverlos hace crecer la barra hasta
     empujar el logotipo fuera de su sitio. */
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* ==========================================================================
   Botón de solo icono
   Mide --tap por los dos lados, así que cumple el objetivo táctil de la
   superficie donde esté (44px en general, 52px en Care).
   ========================================================================== */

.icon-btn {
  width: var(--tap); height: var(--tap); flex: none;
  padding: 0; border: none; border-radius: var(--r-md);
  background: transparent; color: var(--ink-soft);
  display: grid; place-items: center;
  cursor: pointer; touch-action: manipulation;
  transition: background var(--dur-fast) var(--ease-soft),
              color var(--dur-fast) var(--ease-soft),
              transform var(--dur-fast) var(--ease);
}
.icon-btn:hover { background: var(--sage-wash); color: var(--sage-deep); }
.icon-btn:active { transform: scale(0.94); }
.icon-btn .icon { width: 23px; height: 23px; }

/* ==========================================================================
   Pantalla y tarjeta de acceso
   Las tres apps internas abren con la misma pantalla. Era la misma regla
   escrita tres veces con tres anchos distintos.
   ========================================================================== */

.auth-canvas {
  min-height: 100vh;
  display: flex; align-items: center; justify-content: center;
  padding: var(--s-6);
  /* Dos focos de luz muy tenues —verde de marca arriba a la izquierda, azul
     de confianza abajo a la derecha—, no un degradado de fondo completo. */
  background:
    radial-gradient(45% 41% at 17% 15%, color-mix(in srgb, var(--sage-bright) 21%, transparent), transparent 70%),
    radial-gradient(43% 43% at 86% 88%, color-mix(in srgb, var(--teal) 12%, transparent), transparent 70%),
    var(--paper);
}

.login-card {
  width: 100%; max-width: 440px;
  padding: var(--s-10) var(--s-8);
  box-shadow: var(--shadow-float);
  animation: gh-card-rise var(--dur-slow) var(--ease) both;
}
@keyframes gh-card-rise { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: none; } }

/* Frase de bienvenida: la única vez que Fraunces aparece dentro de un
   formulario. Es lo que convierte un login en una puerta de casa. */
.login-welcome {
  font-family: var(--font-display); font-weight: 600;
  font-size: 1.45rem; line-height: 1.25;
  margin-bottom: var(--s-6);
  font-variation-settings: "SOFT" 60, "WONK" 1;
}
.login-help {
  margin-top: var(--s-8);
  padding-top: var(--s-5);
  border-top: 1px solid var(--rule);
  font-size: var(--t-small);
  color: var(--ink-faint);
}

/* «Olvidé mi contraseña». Está en las CUATRO superficies —quien pierde su clave
   puede ser una enfermera, un familiar o dirección— así que vive aquí y no en
   cada `styles.css`.

   Lleva su propio objetivo táctil: un enlace de texto suelto mide la altura de
   su línea, unos 22px, y la regla del sistema son 44px (52 en Care, que redefine
   `--tap`). Se consigue con `min-height` y centrado, no agrandando la letra:
   lo que no cede nunca es el tamaño del texto. */
.login-forgot {
  margin: var(--s-4) 0 0;
  text-align: center;
  font-size: var(--t-small);
}
.login-forgot a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: var(--tap);
  padding: 0 var(--s-3);
  color: var(--ink-soft);
  text-decoration: underline;
  text-underline-offset: 3px;
}
.login-forgot a:hover { color: var(--sage); }

/* MIS DATOS. La hoja vive en `/shared/perfil.js` y la usan tres superficies
   —Family, Care y CRM— así que sus dos estilos propios viven aquí por la misma
   razón: lo que sirve a dos se escribe una vez y arriba.

   El resto de la hoja ya lo pinta este archivo: el diálogo, los campos, el aviso
   y el botón. Esto es solo el correo bajo el título y la etiqueta del botón de la
   barra, que se esconde en pantalla estrecha igual que «Cerrar sesión» — el
   objetivo táctil lo da el botón, no el texto. */
.perfil-correo {
  margin: 0 0 var(--s-5);
  color: var(--ink-faint);
}

/* En pantalla estrecha las etiquetas de la barra superior se esconden y queda el
   icono. Sube aquí porque la usan DOS superficies —Family y CRM— y por un motivo
   medido: la barra del CRM con el selector de hogar, «Mis datos» y «Cerrar
   sesión» pedía 412px en un viewport de 390 y desbordaba la página entera.
   El objetivo táctil lo da el botón, nunca la etiqueta. */
@media (max-width: 560px) {
  .perfil-text, .logout-text { display: none; }
}

/* ==========================================================================
   Encabezados de página y de sección
   Tres alturas distintas, y la diferencia es intencional:
   · .page-head    — título de la pantalla, en Fraunces. "¿Dónde estoy?"
   · .section-head — rótulo de un bloque, en Atkinson. Es mobiliario.
   · .block-head   — igual que el anterior, con acción a la derecha.
   ========================================================================== */

.page-head { margin-bottom: var(--s-6); }
.page-head h1 { font-size: clamp(1.75rem, 4vw, var(--t-h1)); margin-bottom: var(--s-2); }
.page-head p { color: var(--ink-soft); }

/* `flex-wrap`: con título, resumen y un botón, la cabecera no cabía en un
   teléfono y el botón se salía de la pantalla (lo encontró la auditoría al
   añadir «Ajustar días» al seguimiento del CRM). Partirse en dos líneas
   siempre es mejor que desbordar. */
.section-head, .block-head {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: var(--s-2) var(--s-4);
  margin-bottom: var(--s-4);
}
.block-head { margin-bottom: var(--s-5); }

/* Rótulo de bloque: deliberadamente NO usa Fraunces. Si cada caja llevara un
   título con serif de display, la pantalla se llenaría de voces compitiendo
   y el nombre de la persona dejaría de ser lo más fuerte de la vista. */
.section-head h2, .section-head h3,
.block-head h2, .block-head h3 {
  display: flex; align-items: center; gap: var(--s-3);
  font-family: var(--font-body); font-weight: 700;
  font-size: var(--t-body);
  letter-spacing: 0;
  font-variation-settings: normal;
  color: var(--ink-soft);
}
.section-head h2 .icon, .section-head h3 .icon,
.block-head h2 .icon, .block-head h3 .icon { width: 20px; height: 20px; color: var(--sage); }

/* ==========================================================================
   Avatar
   Iniciales, no una silueta genérica. Cuando haya fotografía autorizada, el
   <img> ocupa la misma caja sin cambiar nada más.
   ========================================================================== */

.avatar {
  width: 52px; height: 52px; flex: none;
  border-radius: 50%;
  background: var(--sage-wash); color: var(--sage-deep);
  border: 1.5px solid color-mix(in srgb, var(--sage) 35%, transparent);
  display: grid; place-items: center;
  overflow: hidden;
  font-family: var(--font-display); font-weight: 600; font-size: 1.1875rem;
  line-height: 1;
  font-variation-settings: "SOFT" 40, "WONK" 1;
}
.avatar img { width: 100%; height: 100%; object-fit: cover; }
.avatar.is-sm { width: 38px; height: 38px; font-size: 0.9375rem; }
.avatar.is-lg { width: 72px; height: 72px; font-size: 1.5625rem; }
/* Sobre una superficie de marca (la tarjeta de estado de Family). */
.avatar.on-brand {
  background: rgba(255, 255, 255, 0.17);
  border: 2px solid rgba(255, 255, 255, 0.4);
  color: #fff;
}

/* ==========================================================================
   Campo de búsqueda
   ========================================================================== */

.search-field { position: relative; }
.search-field .search-icon {
  position: absolute; left: 15px; top: 50%; transform: translateY(-50%);
  width: 20px; height: 20px; color: var(--ink-faint); pointer-events: none;
  transition: color var(--dur-fast) var(--ease-soft);
}
.search-field input { padding-left: 47px; min-height: var(--tap); }
.search-field:focus-within .search-icon { color: var(--sage); }

/* ==========================================================================
   Etiqueta
   Distinta del .badge: el badge califica un ESTADO (lleva punto, va en
   redonda); la etiqueta clasifica un REGISTRO (versalita con tracking, sin
   punto). Son dos trabajos distintos y por eso son dos componentes.
   ========================================================================== */

.tag {
  display: inline-flex; align-items: center;
  padding: 3px 11px;
  border-radius: var(--r-pill);
  background: var(--sage-wash); color: var(--sage-deep);
  font-size: var(--t-micro); font-weight: 700;
  letter-spacing: 0.04em; text-transform: uppercase;
  white-space: nowrap;
}
.tag-info { background: var(--teal-wash); color: var(--teal); }
.tag-ok   { background: var(--sage-wash);  color: var(--sage-deep); }
.tag-clay  { background: var(--clay-wash);  color: var(--clay); }
.tag-alert { background: var(--alert-wash); color: var(--alert); }
.tag-mute  { background: var(--paper-sunk); color: var(--ink-soft); }

/* ==========================================================================
   Métrica
   Un número solo no dice nada. El componente obliga a tres piezas: qué se
   mide, cuánto, y respecto a qué. Si no hay comparación ni contexto, la
   métrica probablemente no merece estar en la pantalla.
   ========================================================================== */

.metric-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: var(--s-4);
}

.metric {
  position: relative;
  display: flex; flex-direction: column; gap: var(--s-2);
  padding: var(--s-5) var(--s-5) var(--s-5) var(--s-6);
  background: var(--pane);
  border: 1px solid var(--rule);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-pane);
  text-align: left;
}
/* Filo de color a la izquierda: deja barrer la fila de métricas sin leer. */
.metric::before {
  content: ""; position: absolute; left: 0; top: var(--s-5); bottom: var(--s-5);
  width: 3px; border-radius: 0 3px 3px 0;
  background: var(--sage);
}
.metric.is-attention::before { background: var(--clay); }
.metric.is-alert::before     { background: var(--alert); }
.metric.is-info::before      { background: var(--teal); }
.metric.is-quiet::before     { background: var(--rule-strong); }

.metric-label {
  font-size: var(--t-micro); font-weight: 700;
  letter-spacing: 0.07em; text-transform: uppercase;
  color: var(--ink-faint);
}
.metric-value {
  font-family: var(--font-display); font-weight: 600;
  font-size: 2.125rem; line-height: 1;
  font-variation-settings: "SOFT" 40, "WONK" 1;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
}
.metric-value small { font-size: 1.0625rem; font-weight: 700; color: var(--ink-faint); margin-left: 4px; }
/* El contexto es obligatorio por diseño: responde "¿comparado con qué?". */
.metric-context { font-size: var(--t-small); color: var(--ink-soft); max-width: none; }
.metric-trend { display: inline-flex; align-items: center; gap: 5px; font-weight: 700; }
.metric-trend .icon { width: 16px; height: 16px; }
.metric-trend.is-up   { color: var(--sage); }
.metric-trend.is-down { color: var(--alert); }
.metric-trend.is-flat { color: var(--ink-faint); }


/* --- Métrica DESTACADA ----------------------------------------------------
   La primera de una rejilla, en verde de marca. No es decoración: en una
   pantalla de diecisiete cifras iguales, la vista no sabe por dónde empezar, y
   la que importa es siempre la misma — la ocupación en el panel de dirección,
   lo vencido en cartera.

   UNA por rejilla. Si se destacan tres, no hay destacada: vuelve a ser una
   rejilla plana con más ruido. */
.metric.is-featured {
  background: var(--sage);
  border-color: var(--sage);
  color: var(--paper);
}
/* El filo de color sobra dentro de una tarjeta que ya es del color del filo. */
.metric.is-featured::before { display: none; }
.metric.is-featured { padding-left: var(--s-5); }
.metric.is-featured .metric-label   { color: var(--sage-line); }
.metric.is-featured .metric-value   { color: var(--paper); }
.metric.is-featured .metric-value small,
.metric.is-featured .metric-context { color: var(--sage-line); }
/* El oro legible sobre verde es --accent-on-dark; --accent no se lee ahí. */
.metric.is-featured .chip { background: rgba(246, 241, 231, 0.18); color: var(--paper); border-color: rgba(246, 241, 231, 0.5); }

/* Barra de proporción dentro de una métrica. Solo donde el número ES una
   proporción: una barra bajo «34 incidentes» no mide nada contra nada. */
.metric-bar {
  height: 8px; border-radius: var(--r-pill);
  background: var(--paper-sunk); overflow: hidden;
  margin-top: var(--s-2);
}
.metric.is-featured .metric-bar { background: rgba(246, 241, 231, 0.22); }
.metric-bar > span {
  display: block; height: 100%; border-radius: inherit;
  background: var(--sage);
}
.metric.is-featured .metric-bar > span { background: var(--sage-line); }

/* ==========================================================================
   Chip
   Un dato de UNA palabra, redondo, que se lee sin entrar en nada: «17
   indicadores», «0 con meta», «sin meta».

   No es `.tag`. Un `.tag` clasifica —es el estado de la fila que lo lleva, va
   en versalitas y grita un poco—; un chip RESUME y se lee como una frase
   corta. Meterlos en el mismo componente obligaba a elegir entre versalitas
   donde no tocan o un tag que no se distingue del texto.
   ========================================================================== */

.chip-row { display: flex; flex-wrap: wrap; gap: var(--s-2); align-items: center; }

.chip {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 6px 14px;
  border-radius: var(--r-pill);
  border: 1px solid transparent;
  background: var(--paper-sunk);
  color: var(--ink-soft);
  /* 16px como todo lo que alguien tiene que leer. El diseño lo traía a 11,5px;
     el piso del proyecto no admite excepción para texto de contenido. */
  font-size: var(--t-small);
  line-height: 1.2;
  white-space: nowrap;
}
/* `.chip` NO se pulsa. Para un filtro esta `.segment`, que ya existia aqui con
   sus 44px y su estado pulsado — se llego a escribir aqui un `button.chip` que
   la duplicaba, y dos componentes para el mismo trabajo acaban divergiendo.

   La frontera: `.chip` RESUME un dato que se lee («17 indicadores», «sin
   meta»); `.segment` FILTRA lo que hay debajo. */

.chip-ok    { background: var(--sage-soft);  color: var(--sage-deep); }
.chip-info  { background: var(--teal-wash);  color: var(--teal); }
.chip-clay  { background: var(--clay-wash);  color: var(--clay); }
.chip-alert { background: var(--alert-wash); color: var(--alert); }

/* Chip de TRAZO DISCONTINUO: lo que falta por declarar, no lo que está mal.
   «Sin meta» no es un error —el sistema no inventa umbrales— y pintarlo como
   una alerta haría que dirección creyera que hay algo roto. El trazo abierto
   dice «esto está por rellenar» sin pedir auxilio. */
.chip-pending {
  background: transparent;
  border: 1px dashed var(--rule-strong);
  color: var(--ink-faint);
}

/* ==========================================================================
   Paso a paso (mes anterior · mes · mes siguiente)
   Sustituye al `<input type="month">` nativo, que en cada navegador se pinta
   distinto y en Windows abre un calendario de sistema que no se parece a nada
   del resto de la pantalla. Aquí el mes se cambia como se piensa: uno adelante
   o uno atrás.
   ========================================================================== */

.stepper {
  display: inline-flex; align-items: center; gap: var(--s-2);
  padding: 4px;
  background: var(--pane);
  border: 1px solid var(--rule);
  border-radius: var(--r-pill);
  box-shadow: var(--shadow-pane);
}
.stepper-label {
  display: inline-flex; align-items: center; gap: var(--s-2);
  padding: 0 var(--s-3);
  font-weight: 600; font-size: var(--t-body);
  color: var(--ink);
  white-space: nowrap;
}
.stepper-label .icon { width: 18px; height: 18px; color: var(--ink-faint); }
.stepper button {
  display: inline-flex; align-items: center; justify-content: center;
  width: var(--tap); height: var(--tap);
  min-width: var(--tap);
  border: 0; border-radius: var(--r-pill);
  background: transparent; color: var(--ink-soft);
  cursor: pointer; font-family: inherit;
  transition: background var(--dur-fast) var(--ease-soft);
}
.stepper button:hover:not(:disabled) { background: var(--paper-sunk); color: var(--ink); }
.stepper button:disabled { opacity: 0.4; cursor: default; }
.stepper button .icon { width: 20px; height: 20px; }

/* En un telefono estrecho el paso a paso ocupa TODO el ancho y el rotulo se
   queda con lo que sobra. Como `inline-flex` toma el ancho de su contenido,
   «Septiembre de 2026» mas dos objetivos tactiles de 44px no caben en 320px y
   la flecha derecha se salia del borde — un control que se sale es un control
   que no se puede pulsar. */
@media (max-width: 480px) {
  .stepper { display: flex; width: 100%; }
  .stepper-label { flex: 1; justify-content: center; min-width: 0; }
  .stepper-label > span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
}

/* ==========================================================================
   Navegación en la barra superior (escritorio)
   Las puertas de la superficie, dentro de la barra y no en una fila aparte:
   gana una fila entera de alto, que en una pantalla de trabajo se nota.

   La activa va en píldora de verde claro y NO en verde de marca: el verde
   fuerte de la barra ya lo lleva el logotipo, y dos manchas oscuras a diez
   píxeles compiten. Lo que manda aquí es cuál está abierta, no la marca.
   ========================================================================== */

.topnav { display: none; align-items: center; gap: 2px; }
.topnav button {
  display: inline-flex; align-items: center; gap: 8px;
  min-height: var(--tap);
  padding: 0 var(--s-4);
  border: 0; border-radius: var(--r-pill);
  background: transparent; color: var(--ink-soft);
  font-family: inherit; font-size: var(--t-body); font-weight: 600;
  cursor: pointer; white-space: nowrap;
  transition: background var(--dur-fast) var(--ease-soft), color var(--dur-fast) var(--ease-soft);
}
.topnav button .icon { width: 18px; height: 18px; }
.topnav button:hover { background: var(--paper-sunk); color: var(--ink); }
.topnav button[aria-current="page"],
.topnav button[aria-selected="true"] {
  background: var(--sage-soft);
  color: var(--sage-deep);
}

/* ==========================================================================
   Navegación inferior FLOTANTE (móvil)
   La barra no se pega al borde: flota sobre el contenido con aire alrededor.
   No es un capricho del diseño — en los teléfonos con gesto de inicio, una
   barra pegada al borde queda debajo de la franja del sistema y el último
   botón se vuelve difícil de acertar. `env(safe-area-inset-bottom)` la levanta
   por encima de esa franja.
   ========================================================================== */

.bottomnav {
  position: fixed; z-index: 40;
  left: var(--s-3); right: var(--s-3);
  bottom: calc(var(--s-3) + env(safe-area-inset-bottom, 0px));
  display: flex; align-items: stretch;
  padding: 6px;
  /* OPACA. Igual que `.topbar` y `.tabs`: un fondo traslúcido con desenfoque
     no siempre se aplica —sin GPU, con transparencias reducidas, en una
     captura— y entonces el contenido de la página se lee a través de las
     etiquetas. Un efecto que a veces no está es un fallo intermitente. */
  background: var(--pane);
  border: 1px solid var(--rule);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-float);
}
.bottomnav button {
  flex: 1 1 0; min-width: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 3px;
  min-height: var(--tap);
  padding: 6px 2px;
  border: 0; border-radius: var(--r-md);
  background: transparent; color: var(--ink-faint);
  font-family: inherit; font-size: var(--t-micro); font-weight: 600;
  cursor: pointer;
  /* Que la etiqueta pueda partirse: «Administración» no cabe entera en una
     quinta parte de 320px, y una palabra larga centrada en una columna
     flexible se desborda por los dos lados sin llegar a partirse nunca.
     Hacen falta las tres cosas. Misma lección que la barra de Care. */
  overflow-wrap: anywhere;
  text-align: center;
}
.bottomnav button .icon { width: 22px; height: 22px; flex: 0 0 auto; }
.bottomnav button[aria-current="page"],
.bottomnav button[aria-selected="true"] {
  background: var(--sage-soft);
  color: var(--sage-deep);
}
/* El contenido no puede terminar debajo de la barra flotante. */
.has-bottomnav { padding-bottom: calc(var(--tap) + var(--s-10) + env(safe-area-inset-bottom, 0px)); }

@media (min-width: 900px) {
  .topnav { display: flex; }
  .bottomnav { display: none; }
  .has-bottomnav { padding-bottom: 0; }
}

/* Métrica pulsable: filtra la vista de abajo. */
button.metric {
  width: 100%; font-family: inherit; cursor: pointer; touch-action: manipulation;
  transition: border-color var(--dur-fast) var(--ease-soft),
              transform var(--dur-fast) var(--ease),
              box-shadow var(--dur) var(--ease);
}
button.metric:hover { border-color: var(--sage); box-shadow: var(--shadow-lift); transform: translateY(-2px); }
button.metric:active { transform: translateY(0) scale(0.99); }
button.metric[aria-pressed="true"] { border-color: var(--sage); background: var(--pane-soft); }

/* ==========================================================================
   Tabla de datos
   Por debajo de 768px se convierte en lista de tarjetas CONSERVANDO el
   marcado <table>: la semántica y los lectores de pantalla no cambian, solo
   la presentación, y cada celda recupera su encabezado con data-label.
   ========================================================================== */

.data-table { width: 100%; border-collapse: collapse; font-size: var(--t-body); }

.data-table thead th {
  text-align: left;
  padding: var(--s-4) var(--s-5);
  border-bottom: 1.5px solid var(--rule);
  background: var(--pane-soft);
  white-space: nowrap;
  font-size: var(--t-micro); font-weight: 700;
  letter-spacing: 0.07em; text-transform: uppercase;
  color: var(--ink-soft);
}
.data-table tbody td { padding: var(--s-4) var(--s-5); border-bottom: 1px solid var(--rule); vertical-align: middle; }
.data-table tbody tr:last-child td { border-bottom: none; }
.data-table tbody tr { transition: background var(--dur-fast) var(--ease-soft); }
.data-table tbody tr:hover { background: var(--pane-soft); }
/* El foco real de teclado vive en el botón de la última celda; este realce
   indica en qué fila está. */
.data-table tbody tr:focus-within { background: var(--sage-wash); }

.data-table .num { font-variant-numeric: tabular-nums; white-space: nowrap; }
.data-table .cell-end { text-align: right; }

/* Acción de fila: compacta, pero sigue midiendo --tap de alto. */
.btn-row {
  min-height: var(--tap);
  padding: 8px var(--s-5);
  border: 1.5px solid var(--rule-strong);
  border-radius: var(--r-pill);
  background: transparent;
  color: var(--sage-deep);
  font-family: inherit; font-size: var(--t-small); font-weight: 700;
  white-space: nowrap; cursor: pointer; touch-action: manipulation;
  display: inline-flex; align-items: center; gap: var(--s-2);
  transition: background var(--dur-fast) var(--ease-soft), border-color var(--dur-fast) var(--ease-soft);
}
.btn-row:hover:not(:disabled) { background: var(--sage-wash); border-color: var(--sage); }
.btn-row:disabled { opacity: 0.55; cursor: not-allowed; }

@media (max-width: 768px) {
  .data-table, .data-table thead, .data-table tbody, .data-table tr, .data-table td { display: block; width: 100%; }
  .data-table thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }

  .data-table tbody tr { padding: var(--s-5); border-bottom: 1px solid var(--rule); }
  .data-table tbody tr:last-child { border-bottom: none; }

  .data-table tbody td {
    padding: 5px 0; border: none;
    display: flex; align-items: center; justify-content: space-between; gap: var(--s-4);
  }
  .data-table tbody td::before {
    content: attr(data-label);
    flex: none;
    font-size: var(--t-micro); font-weight: 700;
    letter-spacing: 0.06em; text-transform: uppercase;
    color: var(--ink-faint);
  }
  /* La celda marcada como título de la tarjeta va a ancho completo. */
  .data-table .cell-title { display: block !important; font-size: 1.2rem; font-weight: 700; padding-bottom: var(--s-3) !important; }
  .data-table .cell-title::before { content: none; }
  .data-table .cell-end { display: block !important; text-align: left; padding-top: var(--s-4) !important; }
  .data-table .cell-end::before { content: none; }
  .data-table .cell-end .btn-row { width: 100%; justify-content: center; }
}

/* ==========================================================================
   Línea de tiempo
   El tiempo es el dispositivo estructural del ecosistema: el ritmo del día en
   el sitio, las novedades en Family, la bitácora en el CRM. Una sola pieza.
   ========================================================================== */

.timeline { position: relative; list-style: none; margin: 0; padding: 0; }
.timeline::before {
  content: ""; position: absolute; left: 7px; top: 14px; bottom: 14px;
  width: 2px; border-radius: 2px;
  background: linear-gradient(180deg, var(--sage-bright), var(--rule));
}
.timeline li {
  position: relative;
  display: grid; grid-template-columns: 16px 1fr;
  gap: 0 var(--s-4);
  padding-block: var(--s-4);
  max-width: none;
}
.timeline li + li { border-top: 1px solid var(--rule); }

.timeline-dot {
  width: 16px; height: 16px; margin-top: 5px;
  border-radius: 50%;
  background: var(--pane);
  border: 3px solid var(--rule-strong);
}
/* El registro más reciente es el que la persona vino a leer. */
.timeline li:first-child .timeline-dot {
  border-color: var(--sage);
  box-shadow: 0 0 0 4px var(--sage-wash);
}
.timeline-top {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--s-3); flex-wrap: wrap;
  margin-bottom: var(--s-2);
}
.timeline-when { font-size: var(--t-small); color: var(--ink-faint); font-variant-numeric: tabular-nums; }
.timeline-body { font-size: var(--t-body); color: var(--ink); white-space: pre-wrap; max-width: none; }

/* ==========================================================================
   Barra de pestañas fija
   Nace en Care (se usa de pie, con el pulgar) y por eso vive abajo. En
   pantallas anchas sube: ahí no hay pulgar que alcanzar y una barra fija
   abajo solo roba espacio.
   ========================================================================== */

.tabs {
  /* FLOTANTE, no pegada al borde (diseño de septiembre). No es solo estetica:
     en los telefonos con gesto de inicio, una barra pegada al borde queda bajo
     la franja del sistema y el ultimo boton se vuelve dificil de acertar.
     `env(safe-area-inset-bottom)` la levanta por encima de esa franja. */
  position: fixed; z-index: 30;
  left: var(--s-3); right: var(--s-3);
  bottom: calc(var(--s-3) + env(safe-area-inset-bottom, 0px));
  display: grid; grid-auto-flow: column; grid-auto-columns: 1fr;
  padding: 6px;
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-float);
  /* Opaca, como la barra superior y por lo mismo: es `fixed` y el contenido le
     pasa por debajo. El 96% con desenfoque que tenía antes era casi opaco, pero
     "casi" depende de que el navegador aplique el desenfoque, y no siempre lo
     aplica. `--pane` y no `--paper`: una barra que flota sobre el contenido es
     una superficie elevada, y esa es la que el sistema usa para eso. */
  background: var(--pane);
  border: 1px solid var(--rule);
}
.tab {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px;
  /* Crece si la etiqueta se parte; 62px es el suelo, no el techo. */
  min-height: 62px;
  padding: var(--s-2) 4px;
  border: none; background: none;
  font-family: inherit;
  /* 16px, como cualquier otro contenido. La excepción de 13px del sistema es
     solo para versalitas con tracking, y esto es texto en caja baja: cuatro
     palabras que alguien tiene que leer de un vistazo, de pie, a veces de
     madrugada. Antes bajaba a 13px (y a 11px por debajo de 380px), lo que
     incumplía la regla del propio proyecto; nunca se detectó porque la
     auditoría de Care medía el listado, donde no hay pestañas.
     Lo que cede para que quepa es la altura: la etiqueta se parte en dos
     líneas y la barra crece. Una barra más alta se acepta; una etiqueta
     ilegible, no. */
  font-size: var(--t-small); font-weight: 700;
  line-height: 1.15;
  text-align: center;
  hyphens: auto;
  /* Sin esto, la etiqueta NO se parte: un elemento de rejilla no baja de lo que
     mide su palabra más larga (`min-width: auto`), así que "Medicamentos" fijaba
     un suelo y las seis pestañas de Care empujaban la barra fuera del viewport a
     320px. La regla de arriba —"lo que cede es la altura, no el tamaño de la
     letra"— solo se cumple si se le permite ceder. Se notó cuando a una pestaña
     le apareció su contador de pendientes y el ancho que ya iba justo dejó de
     serlo. */
  min-width: 0;
  color: var(--ink-faint);
  cursor: pointer; touch-action: manipulation;
  position: relative;
  transition: color var(--dur-fast) var(--ease-soft);
}
.tab .icon { width: 23px; height: 23px; }
/* La etiqueta se parte aunque sea UNA palabra larga. `hyphens: auto` sola no
   basta: la partición por guiones necesita el diccionario del idioma y el
   navegador no siempre lo trae, y entonces "Medicamentos" se queda de una pieza
   —117px— dentro de una pestaña de 53px y se sale por la izquierda. Con esto,
   cuando hay diccionario se parte con guion y cuando no lo hay se parte igual.
   Lo que nunca cede es el tamaño de la letra. */
.tab > span { min-width: 0; max-width: 100%; overflow-wrap: break-word; }
/* El `max-width` es la mitad que faltaba: la etiqueta es un elemento flexible
   dentro de una columna centrada, asi que toma el ancho de su CONTENIDO y se
   desborda por los dos lados sin llegar a partirse nunca. Partir solo funciona
   si antes se le pone un techo. */
.tab[aria-selected="true"] { color: var(--sage-deep); }
/* Barra superior que marca la pestaña activa. */
.tab::before {
  content: ""; position: absolute; top: 0; left: 22%; right: 22%;
  height: 3px; border-radius: 0 0 3px 3px;
  background: var(--sage);
  transform: scaleX(0); transform-origin: center;
  transition: transform var(--dur) var(--ease);
}
.tab[aria-selected="true"]::before { transform: scaleX(1); }
.tab:active { background: var(--sage-wash); }

/* Contador de pendientes sobre una pestaña. Un número sin nombre accesible
   no es información para quien no ve la pantalla: quien lo use debe poner
   aria-label en el elemento (ver pintarPendientes en care/app.js). */
.tab-count {
  position: absolute; top: 6px; left: 50%;
  transform: translateX(6px);
  min-width: 20px; height: 20px;
  padding: 0 6px;
  border-radius: var(--r-pill);
  background: var(--alert); color: #fff;
  font-size: var(--t-micro); font-weight: 700;
  line-height: 20px; text-align: center;
  font-variant-numeric: tabular-nums;
}
@media (min-width: 860px) {
  .tab-count { position: static; transform: none; margin-left: var(--s-1); }
}

/* Entrada del panel al cambiar de pestaña.
   Cuatro pestañas en fila son un eje: el panel entra desde el lado hacia el
   que te moviste, y eso dice dónde caíste sin tener que releer la cabecera.
   14px y 220ms — se lee la dirección, no se espera la animación. */
.entra-derecha  { animation: gh-panel-der var(--dur) var(--ease); }
.entra-izquierda { animation: gh-panel-izq var(--dur) var(--ease); }
@keyframes gh-panel-der { from { opacity: 0; transform: translateX(14px); } to { opacity: 1; transform: none; } }
@keyframes gh-panel-izq { from { opacity: 0; transform: translateX(-14px); } to { opacity: 1; transform: none; } }

/* Registro recién guardado.
   Confirma DÓNDE quedó lo que se acaba de escribir, no solo que se guardó.
   Se apaga solo: pasado el momento de la confirmación, un realce permanente
   deja de informar. */
.recien-guardado {
  animation: gh-guardado 4s var(--ease-soft) forwards;
}
@keyframes gh-guardado {
  0%   { border-color: var(--sage); box-shadow: 0 0 0 3px var(--sage-wash); }
  70%  { border-color: var(--sage); box-shadow: 0 0 0 3px var(--sage-wash); }
  100% { border-color: var(--rule); box-shadow: none; }
}
/* Sin movimiento, la confirmación sigue existiendo: se queda fija en verde
   el mismo tiempo, sin transición. */
@media (prefers-reduced-motion: reduce) {
  .recien-guardado { animation: none; border-color: var(--sage) !important; }
}

@media (min-width: 860px) {
  .tabs {
    position: sticky; top: 68px; bottom: auto;
    max-width: 780px; margin-inline: auto;
    grid-auto-columns: auto;
    justify-content: start; gap: var(--s-2);
    border-top: none; border-bottom: 1px solid var(--rule);
    /* OPACA, y esto no es estética: la barra es `sticky`, así que el contenido
       de la página se desliza POR DEBAJO de ella. Con fondo transparente las
       etiquetas se cruzaban con el texto que pasaba por detrás y no se leía ni
       una cosa ni la otra. La barra inferior del teléfono sí puede ser
       traslúcida porque lleva desenfoque; esta no lo llevaba: solo
       transparencia. Una barra pegajosa se pinta sobre el fondo de la página. */
    background: var(--paper); backdrop-filter: none;
    padding: 0 var(--s-4);
  }
  .tab { flex-direction: row; gap: var(--s-2); min-height: var(--tap); padding-inline: var(--s-4); font-size: var(--t-small); }
  .tab::before { top: auto; bottom: 0; left: 0; right: 0; border-radius: 3px 3px 0 0; }
}

/* ==========================================================================
   Elección
   Botones grandes en vez de un <select>, para cuando cada opción necesita una
   línea que la explique y la decisión tiene consecuencias: registrar una dosis
   en Care, declarar el régimen de IVA en /admin. Un <select> esconde las
   opciones hasta que se abre y no deja sitio para el porqué.

   El COLOR de cada opción no vive aquí: es vocabulario de dominio. Care
   pinta "administrado" en verde y "rechazado" en rojo desde su propia hoja.
   ========================================================================== */

.choice-group { display: grid; gap: var(--s-3); }
.choice {
  display: flex; align-items: center; gap: var(--s-4);
  width: 100%; min-height: 64px;
  padding: var(--s-4);
  border: 2px solid var(--rule-strong);
  border-radius: var(--r-md);
  background: var(--pane);
  font-family: inherit; font-size: var(--t-body); font-weight: 700;
  color: var(--ink); text-align: left;
  cursor: pointer; touch-action: manipulation;
  transition: border-color var(--dur-fast) var(--ease-soft), background var(--dur-fast) var(--ease-soft), transform var(--dur-fast) var(--ease);
}
.choice:active { transform: scale(0.985); }
/* Sin marca de color, la opción elegida se distingue por el borde. Es lo que
   usa /admin, que no tiene vocabulario de color para esto. */
.choice[aria-pressed="true"] { border-color: var(--sage); background: var(--sage-wash); }
.choice .choice-mark {
  width: 34px; height: 34px; flex: none;
  border-radius: 50%;
  display: grid; place-items: center;
}
.choice .choice-mark .icon { width: 19px; height: 19px; }
/* La ayuda de una opción es una FRASE que se lee para decidir («sin
   consecuencias, no requirió intervención»), no una versalita que etiqueta un
   dato: va al tamaño secundario, nunca a --t-micro. Estuvo a 13px en las
   veintiocho hojas que usan este componente —la gravedad de un incidente, el
   tipo de una nota— y ninguna auditoría lo vio, porque ninguna medía una hoja
   ABIERTA. Lo encontró la de mantenimiento (web/tools/casa.js). */
.choice small { display: block; font-weight: 400; font-size: var(--t-small); color: var(--ink-faint); margin-top: 2px; }

@media (prefers-reduced-motion: reduce) {
  .choice { transition: none; }
  .choice:active { transform: none; }
}

/* ==========================================================================
   Lista de pendientes
   Un aviso que no se queda en "hay tres cosas pendientes": cada línea es el
   pendiente concreto y se pulsa para ir a resolverlo. Nació en Care —a quién
   le toca una escala, qué cita no tiene acompañante— y la usa también /admin
   para los meses de cartera sin generar.

   Vive dentro de un `.notice`, así que no lleva color propio: lo pone el tono
   del aviso que la contiene. La altura mínima es `--tap`, que cada superficie
   define a su medida (52px en Care, 44px en el resto).
   ========================================================================== */

.pendientes-lista { list-style: none; display: grid; gap: var(--s-2); margin-top: var(--s-3); }

.pendiente-fila {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 2px;
  width: 100%;
  min-height: var(--tap);
  padding: var(--s-3);
  border: 1px solid var(--rule);
  border-radius: var(--r-sm);
  background: var(--pane);
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.pendiente-fila:hover { border-color: var(--sage); }
.pendiente-fila:active { transform: scale(0.99); }
.pendiente-quien { font-weight: 700; }
.pendiente-que { color: var(--ink-soft); font-size: var(--t-small); }

@media (prefers-reduced-motion: reduce) {
  .pendiente-fila:active { transform: none; }
}

/* ==========================================================================
   Diálogo centrado
   El .sheet lateral sirve para consultar un registro largo; este es para una
   decisión corta que hay que tomar ahora. No se usa para confirmar cosas
   reversibles: eso es un toast, no un muro.
   ========================================================================== */

.modal-overlay {
  position: fixed; inset: 0; z-index: 85;
  display: grid; place-items: center;
  padding: var(--s-5);
  background: rgba(18, 37, 27, 0.42);
  backdrop-filter: blur(3px);
  animation: gh-fade-in var(--dur-fast) var(--ease-soft);
}
.modal-overlay.is-leaving { animation: gh-fade-out var(--dur-fast) var(--ease-soft) forwards; }
.modal {
  width: min(520px, 100%);
  max-height: min(86vh, 720px);
  overflow-y: auto; overscroll-behavior: contain;
  background: var(--pane);
  border-radius: var(--r-xl);
  box-shadow: var(--shadow-float);
  padding: var(--s-8) var(--s-6);
  animation: gh-modal-in var(--dur) var(--ease);
}
.modal-overlay.is-leaving .modal { animation: gh-modal-out var(--dur-fast) var(--ease-soft) forwards; }
@keyframes gh-modal-in  { from { opacity: 0; transform: translateY(12px) scale(0.97); } to { opacity: 1; transform: none; } }
@keyframes gh-modal-out { to { opacity: 0; transform: scale(0.98); } }
.modal-head { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--s-4); margin-bottom: var(--s-5); }
.modal-head h2 { font-size: var(--t-h3); line-height: 1.22; }
.modal-head p { color: var(--ink-faint); font-size: var(--t-small); margin-top: var(--s-1); }
.modal-actions { display: flex; gap: var(--s-3); flex-wrap: wrap; margin-top: var(--s-8); }
.modal-actions .btn { flex: 1; min-width: 140px; }

/* ==========================================================================
   Fotografía
   Casa Verdezza todavía no tiene banco de imágenes propio, así que el sistema
   define el HUECO antes que la foto: relación de aspecto fija (la página no
   salta cuando carga), recorte por object-fit con punto focal configurable,
   y un estado "sin fotografía" que se ve intencional en vez de roto.
   Sustituir el <img> no obliga a tocar una línea de CSS.

   Las fotografías de residentes son datos personales: solo se publican con
   consentimiento documentado y bajo los permisos de docs/02-usuarios-roles.md.
   ========================================================================== */

.figure {
  position: relative;
  display: block;
  overflow: hidden;
  border-radius: var(--r-lg);
  background: var(--paper-sunk);
  aspect-ratio: var(--figure-ratio, 4 / 3);
}
.figure > img {
  width: 100%; height: 100%;
  object-fit: cover; object-position: var(--figure-focus, 50% 50%);
  display: block;
}
.figure.is-portrait { --figure-ratio: 3 / 4; }
.figure.is-square   { --figure-ratio: 1; }
.figure.is-wide     { --figure-ratio: 16 / 9; }
.figure.is-panorama { --figure-ratio: 21 / 9; }

/* Velo inferior: solo cuando hay texto encima de la imagen, y es exactamente
   el mínimo para que ese texto pase contraste. */
.figure.has-caption::after {
  content: ""; position: absolute; inset: 40% 0 0;
  background: linear-gradient(180deg, transparent, rgba(18, 37, 27, 0.72));
  pointer-events: none;
}
/* El pie lleva SU PROPIO fondo, no solo el velo: sobre una foto de paredes
   blancas el velo no basta (el blanco de la foto se cuela por la parte alta
   del degradado). Sobre blanco puro este fondo da 8:1 con el texto. */
.figure-caption {
  position: absolute; left: var(--s-4); right: auto; bottom: var(--s-4); z-index: 1;
  max-width: calc(100% - 2 * var(--s-4));
  margin: 0; padding: var(--s-2) var(--s-4);
  border-radius: var(--r-md);
  background: rgba(18, 37, 27, 0.8);
  color: #fff; font-size: var(--t-small); font-weight: 700; line-height: 1.35;
}

/* Sin fotografía todavía: hoja dibujada sobre el lienzo hundido. No es un
   error ni un rectángulo gris: es el mismo lenguaje de línea que las
   ilustraciones de las habitaciones. */
.figure-empty {
  position: absolute; inset: 0;
  display: grid; place-items: center;
  color: color-mix(in srgb, var(--sage) 34%, transparent);
}
.figure-empty .icon { width: 34%; max-width: 76px; height: auto; aspect-ratio: 1; stroke-width: 1.1; }

/* Mientras la imagen viaja. */
.figure.is-loading {
  animation: gh-shimmer 1.4s ease-in-out infinite;
  background: linear-gradient(90deg, var(--paper-sunk) 25%, #eef3ec 37%, var(--paper-sunk) 63%);
  background-size: 400% 100%;
}
@media (prefers-reduced-motion: reduce) { .figure.is-loading { animation: none; } }

/* ==========================================================================
   Estados dentro de un bloque
   .state ocupa una pantalla entera. Estos caben dentro de una caja que es
   una parte de la pantalla, y por eso no se centran ni respiran igual: al
   lado hay contenido que sí cargó.
   ========================================================================== */

.block-state { padding: var(--s-6) 0; text-align: left; }
.block-state h3 {
  font-family: var(--font-body); font-weight: 700;
  font-size: var(--t-body-lg);
  letter-spacing: 0; font-variation-settings: normal;
  margin-bottom: var(--s-2);
}
.block-state p { color: var(--ink-soft); font-size: var(--t-body); }
.block-state .btn { margin-top: var(--s-5); }

/* Sin permiso. Nunca se oculta el bloque: se explica qué falta. Un bloque que
   desaparece parece un fallo; uno que explica, informa. */
.locked {
  display: flex; gap: var(--s-4); align-items: flex-start;
  padding: var(--s-5);
  background: var(--pane-soft);
  border: 1px solid var(--rule);
  border-radius: var(--r-md);
}
.locked .icon { width: 22px; height: 22px; color: var(--ink-faint); margin-top: 2px; flex: none; }
.locked strong { display: block; margin-bottom: var(--s-1); }
.locked p { color: var(--ink-soft); font-size: var(--t-small); }

/* Esqueletos con la forma de lo que va a llegar, no rectángulos genéricos. */
.skeleton-line { display: grid; gap: var(--s-3); padding-block: var(--s-3); }
.skeleton-line .skeleton-bar:nth-child(1) { width: 34%; }
.skeleton-line .skeleton-bar:nth-child(2) { width: 100%; }
.skeleton-line .skeleton-bar:nth-child(3) { width: 72%; }

.skeleton-card {
  display: grid; gap: var(--s-3);
  padding: var(--s-5);
  background: var(--pane);
  border: 1px solid var(--rule);
  border-radius: var(--r-lg);
  margin-bottom: var(--s-3);
}
.skeleton-card .skeleton-bar:nth-child(1) { width: 42%; height: 16px; }
.skeleton-card .skeleton-bar:nth-child(2) { width: 100%; }
.skeleton-card .skeleton-bar:nth-child(3) { width: 64%; }

.skeleton-row {
  display: flex; align-items: center; gap: var(--s-5);
  padding: var(--s-4) var(--s-5);
  border-bottom: 1px solid var(--rule);
}
.skeleton-row:last-child { border-bottom: none; }

/* ==========================================================================
   Aviso de conexión
   Se ancla arriba y empuja al contenido en vez de taparlo: si no hay red,
   eso es lo primero que hay que saber, no un mensaje que se va solo.
   ========================================================================== */

.offline-bar {
  position: sticky; top: 0; z-index: 40;
  /* flex-start, no center: cuando el aviso ocupa dos líneas en un teléfono
     estrecho, con `center` el icono quedaba flotando a media altura en vez
     de junto a la primera palabra. */
  display: flex; align-items: flex-start; justify-content: center; gap: var(--s-3);
  padding: var(--s-3) var(--s-4);
  background: var(--clay-wash); color: var(--clay);
  border-bottom: 1px solid color-mix(in srgb, var(--clay) 30%, transparent);
  font-size: var(--t-small); font-weight: 700;
  text-align: center;
}
.offline-bar .icon { width: 19px; height: 19px; flex: none; margin-top: 3px; }
.offline-bar span { max-width: 44ch; }

/* ==========================================================================
   Responsive del armazón
   Lo que cede primero en un teléfono es el texto de la marca: el isotipo ya
   identifica la app y el nombre completo empujaba las acciones fuera de la
   barra. Esto valía igual en Family y en el CRM, así que se decide una vez.
   ========================================================================== */

@media (max-width: 560px) {
  .topbar { padding-inline: var(--s-4); }
  .topbar .brand-name, .topbar .brand-sub { display: none; }
  .login-card { padding: var(--s-8) var(--s-5); }
  .modal { padding: var(--s-6) var(--s-5); }
  .modal-actions .btn { flex: 1 1 100%; }
}

/* Dedo, no cursor: en pantallas táctiles el realce de hover se queda pegado
   después de tocar. Se reserva para punteros finos. */
@media (hover: none) {
  .btn-primary:hover:not(:disabled),
  .btn-outline:hover:not(:disabled) { transform: none; box-shadow: var(--shadow-pane); }
  button.metric:hover { transform: none; box-shadow: var(--shadow-pane); }
  .gallery-item:hover { transform: none; }
}

/* ==========================================================================
   Selector de hogar
   Aparece en la barra superior de las superficies internas cuando la cuenta
   trabaja en más de una casa. Va arriba y no en un menú porque "¿en qué casa
   estoy?" es una pregunta que hay que poder responder SIN abrir nada: en un
   sistema de varios hogares, creer que estás en el otro es cómo se registra
   sobre la persona equivocada.

   Con un solo hogar el botón se oculta (lo decide cada app): un control que
   siempre dice lo mismo deja de leerse a la semana.
   ========================================================================== */

.hogar-chip {
  display: inline-flex; align-items: center; gap: var(--s-2);
  /* --tap, no 40px: la regla de 44px de este sistema no tiene excepción para
     los controles de la barra superior. Lo descubrió la propia guía viva, que
     se audita como cualquier otra pantalla. En Care hereda los 52px. */
  min-height: var(--tap);
  padding: 0 var(--s-3);
  border: 1px solid var(--rule-strong);
  border-radius: var(--r-pill);
  background: var(--pane);
  color: var(--ink);
  font: inherit; font-size: var(--t-small); font-weight: 700;
  cursor: pointer;
  /* 34vw, no 44: con 44 el chip se comía el ancho y el título de la barra
     —que es lo que dice DÓNDE estás— quedaba en "Resid…". El nombre del hogar
     puede truncarse; el sitio en el que estás, no. */
  max-width: 34vw;
  transition: background var(--dur-fast) var(--ease-soft), border-color var(--dur-fast) var(--ease-soft);
}
.hogar-chip:hover { background: var(--sage-wash); border-color: var(--sage); }
.hogar-chip:active { transform: scale(0.97); }
.hogar-chip > span {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.hogar-chip .icon { width: 18px; height: 18px; flex: none; color: var(--sage); }
/* La flecha de cambio es más pequeña y más tenue: señala que se puede tocar,
   no compite con el nombre de la casa, que es el dato. */
.hogar-chip .hogar-swap { width: 15px; height: 15px; color: var(--ink-faint); }

@media (max-width: 420px) {
  /* En un teléfono, el nombre de la casa vale más que el icono de la casa. */
  .hogar-chip > .icon:first-child { display: none; }
  .hogar-chip { padding-inline: var(--s-2); gap: 6px; }
}

/* Variante de escritorio del mismo control: un desplegable del sistema en vez
   de una hoja. No es incoherencia — es la misma regla que hace que Care use
   objetivos de 52px y el CRM no. De pie y con guantes gana la hoja; sentado y
   veinte veces al día gana el <select>, que abre y cierra en un gesto. */
.hogar-select select {
  width: auto; min-width: 200px; max-width: 320px;
  min-height: var(--tap);
  font-size: var(--t-small); font-weight: 700;
}

@media (max-width: 640px) {
  .hogar-select select { min-width: 0; max-width: 42vw; }
}

/* ==========================================================================
   Fila de casilla
   Una casilla suelta con su etiqueta al lado tiene un objetivo táctil del
   tamaño del cuadrito (13px). Aquí el objetivo es toda la fila.
   ========================================================================== */

.check-row {
  display: flex; align-items: center; gap: var(--s-3);
  min-height: var(--tap);
  margin-top: var(--s-4);
  padding: 0 var(--s-3);
  border: 1px solid var(--rule);
  border-radius: var(--r-md);
  background: var(--pane-soft);
  cursor: pointer;
}
.check-row:hover { border-color: var(--rule-strong); }
.check-row input[type="checkbox"] {
  width: 22px; height: 22px;
  flex: none;
  accent-color: var(--sage);
  cursor: pointer;
}
.check-row span { font-weight: 700; }

/* ==========================================================================
   Conversación
   El hilo entre la familia de un residente y el equipo del hogar. Lo pintan
   DOS superficies —Family y Care— desde los dos lados del mismo hilo, así que
   vive aquí: es lenguaje visual, no composición de una pantalla.

   No es un chat. Se lee entera de una pasada, no hay indicador de
   "escribiendo…" y no hay burbujas de colores vivos, porque al otro lado no
   hay alguien esperando: hay un turno.
   ========================================================================== */

.msg-hilo { list-style: none; display: grid; gap: var(--s-3); }

.msg {
  padding: var(--s-4);
  border-radius: var(--r-md);
  background: var(--paper);
  /* Lo que dice el OTRO lado se apoya a la izquierda. */
  border-left: 3px solid var(--sage);
  max-width: 34rem;
}

/* Lo propio se apoya al otro lado. No es decoración: en una conversación de
   diez mensajes, saber de un vistazo quién dijo qué es la única forma de
   releerla sin esfuerzo. El color del filete lo decide cada superficie —lo que
   para la familia es "mío" para el equipo es "del hogar". */
.msg-mio {
  margin-left: auto;
  background: var(--sage-wash);
  border-left: 0;
  border-right: 3px solid var(--rule-strong);
}

.msg-autor {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--s-2);
  font-weight: 700;
  margin-bottom: var(--s-2);
}
.msg-cuando { color: var(--ink-faint); font-weight: 400; font-size: var(--t-small); }

/* `pre-wrap`: si alguien escribe tres párrafos contando lo que le preocupa, se
   leen como tres párrafos. */
.msg-cuerpo { white-space: pre-wrap; }

.msg-acuse {
  display: inline-flex; align-items: center; gap: 5px;
  margin-top: var(--s-3);
  color: var(--sage-deep);
  font-size: var(--t-small); font-weight: 700;
}
.msg-acuse .icon { width: 16px; height: 16px; }
/* "Enviado" / "sin leer" NO es un estado de error: a las seis de la mañana es
   lo normal. Va apagado, nunca en ámbar ni en rojo. */
.msg-acuse.is-pendiente { color: var(--ink-faint); font-weight: 400; }

.msg-form { margin-top: var(--s-6); padding-top: var(--s-5); border-top: 1px solid var(--rule); }
.msg-form textarea { resize: vertical; }
.msg-form .btn { margin-top: var(--s-3); }

/* La FOTO de un mensaje (`/shared/foto-mensaje.js`). Ocupa el ancho de la
   burbuja y no más alto que media pantalla de teléfono: una foto vertical de
   cámara mide 4000px, y a tamaño natural empujaría el hilo fuera de la vista. */
.msg-foto { margin: var(--s-2) 0 0; }
.msg-foto img,
.foto-previa img {
  display: block;
  max-width: 100%;
  max-height: min(360px, 55vh);
  border-radius: var(--r-sm);
  background: var(--paper-sunk);
}
.msg-foto-cargando {
  display: inline-flex; align-items: center; gap: var(--s-2);
  color: var(--ink-faint);
}
.foto-adjunto { margin-top: var(--s-3); }
.foto-previa { display: grid; justify-items: start; gap: var(--s-2); }
.foto-previa img { max-height: 200px; }
/* No es un error: es una regla de la casa sobre esta persona. Va en el tono
   tranquilo del texto, con el candado, nunca en rojo. */
.foto-no-permitida {
  display: flex; align-items: flex-start; gap: var(--s-2);
  margin-top: var(--s-3);
  color: var(--ink-soft);
}
.foto-no-permitida .icon { flex: none; margin-top: 3px; }

@media (max-width: 480px) {
  .msg { max-width: none; }
}

/* ==========================================================================
   MOVIMIENTO VIVO (oct. 2026, a pedido de dirección: «más visual, con
   animaciones, más como app» — diseño `Casa Verdezza Admin re.html`).

   Escrito UNA vez aquí y heredado por las cinco superficies. Cada pieza
   responde a una de tres cosas, y ninguna es adorno suelto:

     · ENTRAR   lo que se acaba de pintar sube en escalera (`data-escalonar`
                en el contenedor; lo hace `motion.js`). Dice «esto es nuevo»
                y el orden en que se lee.
     · CONTAR   una cifra sube hasta su valor (`data-contar`), una barra se
                llena hasta su proporción (`.barra-viva`). El número final es
                el mismo; el recorrido dice cuánto es.
     · LATIR    un punto que late (`.punto-vivo`) marca lo que pide atención
                AHORA. Solo eso: si todo late, nada pide atención.

   Con `prefers-reduced-motion` todo esto se APAGA (no se atenúa): las cifras
   aparecen en su valor, las barras llenas, los puntos quietos.
   ========================================================================== */

@keyframes gh-sube    { from { opacity: 0; transform: translateY(16px); } to { opacity: 1; transform: none; } }
@keyframes gh-vista   { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }
@keyframes gh-brillo  { from { transform: translateX(-120%); } to { transform: translateX(320%); } }
@keyframes gh-flota   { 0%, 100% { transform: translateY(0) rotate(-8deg); } 50% { transform: translateY(-14px) rotate(4deg); } }
@keyframes gh-marca   { from { opacity: 0; transform: translateY(-6px) scale(0.94); } to { opacity: 1; transform: none; } }
@keyframes gh-late-ok {
  0%   { box-shadow: 0 0 0 0 color-mix(in srgb, var(--sage-line) 70%, transparent); }
  100% { box-shadow: 0 0 0 10px transparent; }
}
@keyframes gh-late-alerta {
  0%   { box-shadow: 0 0 0 0 color-mix(in srgb, var(--clay) 55%, transparent); }
  100% { box-shadow: 0 0 0 10px transparent; }
}

/* ENTRAR — la escalera. El retraso lo pone motion.js (`--i`), con techo: la
   décima tarjeta no espera un segundo para aparecer. */
.gh-entra { animation: gh-sube var(--dur-slow) var(--ease) both; animation-delay: calc(var(--i, 0) * 55ms); }

/* Cambiar de vista: la pantalla nueva sube un poco. Responde a un toque. */
.gh-vista-entra { animation: gh-vista var(--dur) var(--ease) both; }

/* La marca entra una vez, al abrir la superficie. Es el archivo oficial
   (no se redibuja): se anima la imagen, no sus trazos. */
.topbar .brand img, .topbar .brand-mark { animation: gh-marca var(--dur-slow) var(--ease) both; }

/* LATIR */
.punto-vivo {
  display: inline-block; flex: none;
  width: 10px; height: 10px; border-radius: 50%;
  background: var(--sage-line);
  animation: gh-late-ok 1.8s var(--ease-soft) infinite;
}
.punto-vivo.es-alerta { background: var(--clay); animation-name: gh-late-alerta; }

/* CONTAR — la barra que se llena. `.barra-relleno` arranca en 0 y motion.js
   le pone el ancho de `data-ancho`; la transición hace el resto. Un brillo
   la recorre de vez en cuando: dice que es un dato vivo, del mes en curso.
   `.barra-meta` es la línea de la meta, cuando la hay. */
.barra-viva {
  position: relative; height: 10px; border-radius: var(--r-pill);
  background: var(--paper-sunk);
  margin-top: var(--s-3);
}
.barra-relleno {
  position: relative; overflow: hidden;
  display: block; height: 100%; width: 0; border-radius: inherit;
  background: var(--sage);
  transition: width 1.2s var(--ease);
}
.barra-relleno::after {
  content: ""; position: absolute; top: 0; bottom: 0; width: 30%;
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.45), transparent);
  animation: gh-brillo 2.6s 1.6s var(--ease-soft) infinite;
}
.barra-relleno.es-alerta { background: var(--clay); }
.barra-relleno.es-neutra { background: var(--accent-lit); }
.barra-meta {
  position: absolute; top: -4px; bottom: -4px; width: 2px;
  border-radius: 2px; background: var(--ink);
}

/* Tarjetas que se levantan bajo el puntero. Solo con ratón: en un teléfono un
   «hover» se queda pegado después del toque. */
@media (hover: hover) {
  .gh-levanta { transition: transform var(--dur) var(--ease), box-shadow var(--dur) var(--ease); }
  .gh-levanta:hover { transform: translateY(-4px); box-shadow: var(--shadow-float); }
}

/* La pestaña se hunde al pulsarla, como ya lo hacen botones y píldoras. */
.tab { transition: color var(--dur-fast) var(--ease-soft), transform var(--dur-fast) var(--ease); }
.tab:active { transform: scale(0.94); }

/* El INDICADOR que se desliza a la pestaña activa (GH.indicadorDeslizante).
   Una sola pieza que viaja en vez de una que se apaga aquí y se enciende
   allá: el ojo sigue el movimiento y sabe a dónde fue. */
.gh-con-indicador { isolation: isolate; } /* la posición la pone JS solo si la barra es estática: pisar un `fixed` la sacaría de su sitio */
.gh-indicador {
  position: absolute; z-index: -1; top: 0; left: 0;
  border-radius: var(--r-md);
  background: var(--sage-wash);
  pointer-events: none;
  transition: transform var(--dur-slow) cubic-bezier(0.5, 1.4, 0.4, 1),
              width var(--dur-slow) var(--ease), height var(--dur-slow) var(--ease),
              opacity var(--dur-fast) var(--ease-soft);
}
.gh-con-indicador .tab::before { display: none; }

@media (prefers-reduced-motion: reduce) {
  .gh-entra, .gh-vista-entra, .topbar .brand img, .topbar .brand-mark { animation: none; }
  .punto-vivo, .barra-relleno::after { animation: none; }
  .barra-relleno, .gh-indicador { transition: none; }
  .gh-levanta:hover, .tab:active { transform: none; }
}

/* Un titular con su punto vivo delante: lo que pide atención AHORA. */
.con-punto { display: inline-flex; align-items: center; gap: var(--s-2); }
/* Dentro de un aviso rojo, el punto es del color del aviso. */
.notice-error .punto-vivo.es-alerta { background: var(--alert); }

/* ==========================================================================
   INGRESO EN DOS PANELES (oct. 2026, `Casa Verdezza Login.html`)
   --------------------------------------------------------------------------
   Lo arma `/shared/ingreso.js` sobre el `#view-login` de cada aplicación: a la
   izquierda la marca, a la derecha el MISMO formulario de siempre. El verde
   del panel es el del manual (#1E4638) y no `--sage`: es el fondo que traen
   los archivos negativos del logotipo, y con otro verde se vería su cuadrado.
   ========================================================================== */
.auth-canvas.auth-split {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  align-items: stretch;
  padding: 0;
  background: var(--paper);
}
.auth-split .login-card {
  align-self: center; justify-self: center;
  width: 100%; max-width: 480px;
  margin: var(--s-10) var(--s-6);
  padding: 0;
  background: none; border: 0; box-shadow: none;
}

.ingreso-marca {
  --verde-manual: #1e4638;
  position: relative; overflow: hidden;
  display: flex; flex-direction: column; justify-content: space-between; gap: var(--s-10);
  min-height: 100vh;
  padding: clamp(32px, 5vw, 64px);
  background: var(--verde-manual);
  color: var(--paper);
}
.ingreso-casa {
  position: absolute; right: -180px; bottom: -200px;
  width: 560px; height: 560px; opacity: .07; pointer-events: none;
  background: url("/shared/marca/simbolo-negativo.svg") center / contain no-repeat;
  animation: gh-flota 10s ease-in-out infinite;
}
.ingreso-filete {
  position: absolute; left: -10%; top: 30%;
  width: 70%; height: 8px; border-radius: 8px;
  background: var(--accent-lit); opacity: .14; rotate: -38deg; pointer-events: none;
}
.ingreso-volver {
  position: relative; align-self: flex-start;
  display: inline-flex; align-items: center; gap: var(--s-2);
  min-height: var(--tap);
  color: var(--paper); font-weight: 700; text-decoration: none;
}
.ingreso-volver .icon { width: 20px; height: 20px; }
.ingreso-volver:hover { color: var(--accent-on-dark); }
.ingreso-centro { position: relative; display: grid; gap: var(--s-6); max-width: 520px; }
.ingreso-logo {
  width: min(100%, 420px); height: auto; display: block;
  margin-left: -4.5%;   /* el archivo trae 24/486 de aire a la izquierda */
  animation: gh-marca var(--dur-slow, .9s) var(--ease) both;
}
.ingreso-lema {
  margin: 0; font-size: 1.3rem; line-height: 1.55;
  color: color-mix(in srgb, var(--paper) 88%, var(--verde-manual));
  text-wrap: pretty;
}
.ingreso-casas { position: relative; display: grid; gap: var(--s-3); }
.ingreso-casas-titulo {
  margin: 0; font-size: .8125rem; font-weight: 700;
  letter-spacing: .22em; text-transform: uppercase; color: var(--accent-on-dark);
}
.ingreso-chips { display: flex; gap: var(--s-2); flex-wrap: wrap; }
.ingreso-chip {
  display: inline-flex; align-items: center; gap: var(--s-2);
  padding: 10px 16px; border-radius: var(--r-pill);
  background: color-mix(in srgb, var(--paper) 8%, transparent);
  border: 1px solid color-mix(in srgb, var(--paper) 16%, transparent);
  font-weight: 700;
}
.ingreso-punto { width: 9px; height: 9px; border-radius: 50%; background: #5fb07f; flex: none; }

/* El título de cada puerta: versalita, Fraunces grande y una línea. */
.auth-split .login-brand { justify-items: start; text-align: left; gap: var(--s-3); margin-bottom: var(--s-8); }
.auth-split .login-brand img { display: none; }   /* el logotipo ya está en el panel */
.auth-split .login-brand .label-micro { margin: 0; color: var(--accent); }
.login-titulo {
  margin: 0;
  font-family: var(--font-display); font-weight: 600;
  font-size: clamp(2.2rem, 4vw, 3.1rem); line-height: 1.04; letter-spacing: -.02em;
  color: var(--sage);
  font-variation-settings: "SOFT" 40, "WONK" 1;
}
.auth-split .brand-sub { font-size: var(--t-body-lg, 1.125rem); color: var(--ink-soft); }

/* Las tres puertas: enlaces, con un fondo que se sitúa en la actual. */
.ingreso-puertas {
  position: relative;
  display: grid; grid-template-columns: repeat(3, 1fr);
  padding: 6px; margin-bottom: var(--s-8);
  border-radius: 18px; background: var(--paper-sunk);
}
.ingreso-puertas-fondo {
  position: absolute; top: 6px; bottom: 6px; left: 6px;
  width: calc((100% - 12px) / 3);
  border-radius: 13px; background: var(--pane);
  box-shadow: 0 8px 18px -10px rgba(22, 36, 30, .4);
  transform: translateX(calc(var(--activa, 0) * 100%));
}
.ingreso-puertas a {
  position: relative;
  display: flex; align-items: center; justify-content: center;
  min-height: var(--tap); padding: var(--s-2);
  font-weight: 700; color: var(--ink-soft); text-decoration: none;
  border-radius: 13px;
}
.ingreso-puertas a[aria-current] { color: var(--sage); }
.ingreso-puertas a:not([aria-current]):hover { color: var(--sage); }

/* Mostrar la contraseña: dentro del campo, sin taparle el texto. */
.ingreso-clave { position: relative; display: block; }
.ingreso-clave input { width: 100%; padding-right: 104px; }
.ingreso-ver {
  position: absolute; right: 6px; top: 50%; transform: translateY(-50%);
  min-height: var(--tap); padding: 0 var(--s-4);
  border: 0; border-radius: 12px; background: none;
  font: inherit; font-weight: 700; color: var(--sage); cursor: pointer;
}
.ingreso-ver:hover { background: var(--paper-sunk); }
.ingreso-mayus { margin: var(--s-2) 0 0; font-weight: 700; color: var(--accent); }

.auth-split .login-help { border-top-color: var(--rule); }
.ingreso-soporte { margin: var(--s-4) 0 0; }
.ingreso-soporte a {
  display: inline-flex; align-items: center; gap: var(--s-2);
  min-height: var(--tap); font-weight: 700; color: var(--sage); text-decoration: none;
}
.ingreso-wa { width: 9px; height: 9px; border-radius: 50%; background: #25d366; }

/* En el teléfono el panel es una franja: lo que se viene a hacer es entrar,
   y una pantalla entera de marca antes del formulario es un desplazamiento
   que nadie pidió. Quedan el «volver» y el logotipo. */
@media (max-width: 859px) {
  .auth-canvas.auth-split { grid-template-columns: 1fr; align-content: start; }
  .ingreso-marca {
    min-height: 0; gap: var(--s-4);
    padding: var(--s-4) var(--s-5) var(--s-6);
    flex-direction: column; justify-content: flex-start;
  }
  .ingreso-lema, .ingreso-casas, .ingreso-filete { display: none; }
  .ingreso-logo { width: 220px; }
  .ingreso-casa { width: 260px; height: 260px; right: -70px; bottom: -110px; }
  .auth-split .login-card { margin: var(--s-8) auto var(--s-10); padding: 0 var(--s-5); }
}
@media (prefers-reduced-motion: reduce) {
  .ingreso-casa, .ingreso-logo { animation: none; }
}
/* El botón de entrar respira del último campo (Family lo tenía; las otras tres no). */
.auth-split #login-submit { margin-top: var(--s-6); min-height: 56px; }
