/* ============================================================
   Finanzas — estilos locales del módulo. Prefijo .fin-
   Cero overrides de .r-, cero valores crudos: todo sale de tokens.
   ============================================================ */

/* ---------- LÁPIDA: la plomada ----------
   `#finRoot` llevaba
     margin-inline: max(0px, (100% - var(--page-max)) / 2) auto;
   para caer en la misma vertical que la métrica de los demás módulos cuando
   la vista era una página de 1240 centrada. Dentro del panel flotante no hay
   página que centrar —el cuerpo del panel ya da la caja— y la expresión
   resuelve a 0 a cualquier ancho que el panel pueda tener (medido en el
   cómodo: 478 de caja contra 1240 de `--page-max`, o sea `max(0px, -381px)`).
   Se borra en vez de dejarse: una regla que solo puede dar cero se sigue
   copiando como si hiciera algo. La plomada hoy la pone `.r-flyout__body`.

   ---------- El ancho que manda es el del PANEL ----------
   Mismo cambio que en Workspace y por la misma razón: los cortes de este
   archivo eran `@media (max-width: 720px)` y dentro del panel no disparan
   nunca —la ventana mide 1280 y la caja 478—, así que la vista se acomodaba
   como si tuviera una página entera. `#finRoot` se declara contenedor y los
   cortes se miden contra él. */
/* ---------- La sección de Cuentas se recorre por dentro ----------
   La lista de cuentas no tiene techo —Robbie va a tener seis o veinte— y una
   lista sin techo dentro de una sección que tiene que caber es la promesa que
   se rompe el segundo mes. Así que la sección es cabeza + tasa (que caben
   siempre) y la lista es su contenido, con su propia pista: el mismo reparto
   exacto de `.lv-list` en Lever y de `.wk-col__l` en Workspace.

   Eso pide la cadena completa de altos, y por eso `#viewFin` y `#finRoot`
   estrenan `height: 100%`. Es el mismo eslabón —con el mismo comentario— que
   `#viewLever` y `#viewWork`: el cuerpo del panel declara `flex-shrink: 0` en
   sus hijos cuando hay alta (`ron.css` § 33d) y con `flex-basis: auto` el
   tamaño hipotético sale de la propiedad `height`. Finanzas SÍ declara alta,
   así que aquí la regla aplica de verdad.

   Y las otras secciones no cambian: `:where()` deja a todo hijo en `flex:
   0 0 auto` —nada cede, quien crece lo pide por su nombre, igual que en
   `.lv-root`— y solo Proyección reclama el alto sobrante. El libro de
   Balance crece más que el panel y hace scrollear el cuerpo: `#finRoot` no
   recorta (`container-type: inline-size` contiene layout, no pintura).
   Cuentas dejó de ser sección: sus azulejos viven dentro de Balance. */
#viewFin {
  display: flex;
  flex-direction: column;
  min-height: 0;
  height: 100%;
}

#finRoot {
  container-type: inline-size;
  container-name: fin;
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
}
:where(#finRoot) > * { flex: 0 0 auto; }

/* Proyección reclama el alto: su tabla de eventos es una lista sin techo
   dentro de una sección que tiene que caber, así que la cabeza (numeral,
   veredicto, gráfica, fila de captura) se queda quieta y la tabla es la
   que se recorre. `:where(#finRoot) > *` deja a todo hijo en `flex: 0 0
   auto` y **quien crece lo pide por su nombre**. */
[data-fin-sec="proy"]:not([hidden]) {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
}

/* Los dos bloques de arriba —la cifra y los seis meses— caben lado a lado a
   partir de 610 px: el numeral de puntos del balance mide 285 con su unidad al
   lado (~325), la gráfica pide sus 260, y entre los dos va --s-6.

   Debajo de eso se APILAN, y no es cosmético. `.r-lcd` es un `<svg>` con
   `width` y `viewBox` explícitos, así que en una retícula angosta no se
   reajusta: se ESCALA. Medido en el panel cómodo antes de este cambio, la
   columna de la cifra se quedaba con 194 px de los 478 y el balance se
   dibujaba al 68.1% de su tamaño — la métrica principal del módulo, en el
   numeral de matriz de puntos que `CLAUDE.md` reserva para "la cifra que
   manda", salía más chica que la gráfica de contexto de al lado. Apiladas,
   la cifra recupera su tamaño y la gráfica gana ancho, que es lo que una
   serie de seis meses sabe aprovechar. */
.fin-top {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--s-5);
  margin-bottom: var(--s-6);
}

@container fin (min-width: 610px) {
  .fin-top {
    grid-template-columns: minmax(0, 1fr) minmax(0, 260px);
    gap: var(--s-6);
    align-items: end;
    margin-bottom: var(--s-8);
  }
}
/* La métrica es un .r-lcdrow (flex), no un <p>: sin margen de párrafo que
   corregir. El de abajo se queda —separa la cifra de su fila de contexto—; el
   de arriba baja a --s-1 porque el rótulo "Balance" ya no tiene que despegarse
   de una caja de texto, sino de la primera fila de puntos. */
.fin-balance { margin: var(--s-1) 0 var(--s-3); }
.fin-sub { flex-wrap: wrap; --gap: var(--s-3); }

/* Rótulo y punto de estado en el mismo renglón, arriba de la cifra. `baseline`
   no: son dos alturas distintas y alinearlas por la base pega el texto al canto
   de abajo.

   Aquí vivía el SELECTOR DE MONEDA (`.r-seg.fin-cur`) y por eso este renglón
   existía: el segmentado gobernaba todo el resumen. Se fue con la
   consolidación —el resumen es uno, en `fxBase`— y el renglón se quedó porque
   ahora carga el punto que dice si la conversión es de fiar. Los 36 px del
   segmentado ya no están, así que con una sola moneda esto es el rótulo solo,
   que era el caso de todos los días de antes también. */
.fin-head {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  flex-wrap: wrap;
}

/* ============================================================
   Cuentas
   ============================================================ */

/* Patrimonio compacto: el protagonista de la vista es el Balance de arriba.
   --sm en el numeral, sin acento. */
.fin-pat { margin: 0 0 var(--s-4); }
.fin-pat__n { margin: var(--s-1) 0 0; }

/* ---------- Azulejos de cuenta ----------
   Sustituyen la pestaña Cuentas. El color de clase es señal (info/crit/ok/warn),
   no acento: el ácido se queda en el Balance. Picar filtra el libro y la
   cifra; el lápiz se revela. La tira se recorre a lo ancho. */
.fin-az { margin: 0 0 var(--s-4); }
.fin-tiles {
  display: flex;
  gap: var(--s-2);
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scrollbar-width: thin;
  padding: var(--s-1) 0 var(--s-2);
}
.fin-tile {
  position: relative;
  flex: 0 0 auto;
  width: 8rem;
  min-height: 4.5rem;
  border: var(--stroke) solid var(--hairline);
  border-radius: var(--r-md);
  background: var(--surface-sunk);
}
.fin-tile--info { background: var(--info-bg); }
.fin-tile--crit { background: var(--crit-bg); }
.fin-tile--ok { background: var(--ok-bg); }
.fin-tile--warn { background: var(--warn-bg); }
.fin-tile--on { border-color: var(--ink-3); }
.fin-tile--edit { border-color: var(--ink-2); }
.fin-tile__b {
  display: grid;
  align-content: start;
  gap: 0;
  width: 100%;
  height: 100%;
  padding: var(--s-2);
  border: 0;
  background: transparent;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.fin-tile__b:focus-visible { outline: var(--stroke) solid var(--ink-4); outline-offset: calc(var(--stroke) * -1); }
.fin-tile__n {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: var(--t-body-sm);
  color: var(--ink);
}
.fin-tile__c { color: var(--ink-3); }
.fin-tile__v {
  display: inline-flex;
  align-items: baseline;
  gap: var(--s-1);
  margin-top: var(--s-1);
  font-size: var(--t-body);
  color: var(--ink);
}
.fin-tile__cur { color: var(--ink-3); }
.fin-tile--pasivo .fin-tile__v { color: var(--crit); }
.fin-tile--pasivo .fin-tile__cur { color: var(--crit); opacity: .7; }
.fin-tile__e {
  position: absolute;
  top: var(--s-1);
  right: var(--s-1);
  opacity: 0;
  transition: opacity var(--d-fast) var(--ease);
}
.fin-tile:hover .fin-tile__e,
.fin-tile:focus-within .fin-tile__e,
.fin-tile--edit .fin-tile__e { opacity: 1; }
.fin-tile--add {
  display: grid;
  place-items: center;
  background: transparent;
  min-height: 4.5rem;
}
.fin-tile-add { display: inline-flex; }

/* El punto de estado de la conversión, junto al rótulo. No lleva texto a la
   vista: la palabra vive en el `title` y en `.r-sr`, que es el reparto que el
   sistema pide para un estado que se lee de un vistazo. El renglón de abajo
   —`.fin-fx`— es el que sí lo dice con palabras. */
.fin-fxdot { --gap: 0; }

/* ---------- El renglón de la tasa ----------
   Envuelve, porque con tres monedas y sus edades no cabe en uno solo a 478 px.
   Cada tasa es un grupo indivisible (`.fin-fx__i` no envuelve por dentro): una
   tasa partida entre dos renglones deja el número separado de su moneda, que es
   la única cosa que este renglón existe para no dejar ambigua. */
.fin-fx {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-1) var(--s-2);
  margin: var(--s-2) 0 0;
}
.fin-fx__i {
  display: inline-flex;
  align-items: center;
  gap: var(--s-1);
  white-space: nowrap;
}
/* El disparador de captura de la tasa se revela al hover y al foco, como toda
   acción secundaria. Pero NO cuando está armado: un campo abierto que se apaga
   porque el puntero se movió es un campo que se pierde a media escritura —el
   mismo arreglo, y la misma razón, que `.fin-mov__x[data-armed]`. */
.fin-fx__e {
  opacity: 0;
  transition: opacity var(--d-fast) var(--ease);
}
.fin-fx:hover .fin-fx__e,
.fin-fx:focus-within .fin-fx__e,
.fin-fx__e:has(.r-capture__t[aria-expanded="true"]) { opacity: 1; }
/* Una tasa que FALTA no se esconde nunca: es la única forma de arreglarla, y
   esconder el arreglo del dato que se está diciendo que falta es una broma. */
.fin-fx__i--falta .fin-fx__e { opacity: 1; }

.fin-fuera { margin: var(--s-2) 0 0; }

/* ---------- La pista: la lista de cuentas ----------
   Mismas propiedades que `.lv-list`, y por la misma razón. `overscroll-behavior`
   para que llegar al final no arrastre el cuerpo del panel. */
.fin-accs {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior-y: contain;
  scrollbar-width: thin;
  border-top: var(--stroke) solid var(--hairline);
  /* El relleno del cuerpo del panel queda fuera de este scroller, así que
     el último renglón se metería debajo del `.r-fab` y el clic se lo
     comería el alta. Ver `ron.css § 33d bis`. */
  padding-bottom: var(--fab-reserve);
}

.fin-acc {
  border-bottom: var(--stroke) solid var(--hairline);
  animation: os-slide-in var(--d-base) var(--ease-out) both;
  animation-delay: calc(var(--i, 0) * var(--stagger));
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  grid-template-areas: "row x" "ficha ficha";
  align-items: center;
  column-gap: var(--s-2);
}

/* El renglón es un botón entero: pica donde sea y la ficha se despliega. Un
   área de clic del ancho del renglón es lo que hace que no haya que buscar un
   chevron de 20 px.

   Cinco celdas en UNA fila, y el `1fr` es el de la metadata: el nombre pide lo
   que mide (`auto`) y lo que sobra es el hueco donde la metadata aparece al
   hover. Así el alto del renglón no depende de si se ve, y revelarla no
   reacomoda la lista. */
.fin-acc__r {
  grid-area: row;
  display: grid;
  grid-template-columns: auto auto minmax(0, 1fr) auto auto;
  align-items: center;
  gap: var(--s-2) var(--s-3);
  width: 100%;
  padding: var(--s-3) var(--s-2);
  border: 0;
  background: transparent;
  color: var(--ink-2);
  font-family: inherit;
  font-size: var(--t-body-sm);
  text-align: left;
  transition: background var(--d-fast) var(--ease);
}
.fin-acc__r:hover, .fin-acc__r:focus-visible { background: var(--surface-2); }
.fin-acc__r:focus-visible { outline: var(--stroke) solid var(--ink-4); outline-offset: calc(var(--stroke) * -1); }
/* El nombre pide lo que mide, con un techo: un nombre larguísimo no puede
   empujar el saldo fuera del renglón, así que cede a partir de 22 caracteres y
   se recorta. El completo queda en el `title` del renglón. */
.fin-acc__n {
  color: var(--ink);
  max-width: 22ch;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.fin-acc__v {
  font-size: var(--t-body);
  color: var(--ink);
  display: inline-flex;
  align-items: baseline;
  gap: var(--s-1);
}
.fin-acc__cur { color: var(--ink-3); }

/* Un PASIVO se ve. El menos ya está en el número (lo pone `renglon()`), y la
   tinta crítica es la que impide leer una deuda como si fuera dinero — que es el
   error en la dirección peligrosa. No es el acento de la vista: `--crit` es
   señal, y el acento sigue siendo el patrimonio. */
.fin-acc--pasivo .fin-acc__v { color: var(--crit); }
.fin-acc--pasivo .fin-acc__cur { color: var(--crit); opacity: .7; }

.fin-acc__meta {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.fin-acc__x { grid-area: x; }
.fin-acc__meta, .fin-acc__x {
  opacity: 0;
  transition: opacity var(--d-fast) var(--ease);
}
.fin-acc:hover .fin-acc__meta, .fin-acc:focus-within .fin-acc__meta,
.fin-acc:hover .fin-acc__x, .fin-acc:focus-within .fin-acc__x { opacity: 1; }
.fin-acc__x[data-armed] { opacity: 1; }
/* Con la ficha abierta la metadata se queda puesta: la fecha de valuación es
   justo el dato que se está por corregir. */
.fin-acc--open .fin-acc__meta, .fin-acc--open .fin-acc__x { opacity: 1; }
.fin-acc--open { background: var(--surface-sunk); }

/* ---------- La ficha, desplegada en su lugar ----------
   Una rejilla que envuelve: en el cómodo caben dos controles por renglón, en el
   techo de 760 caben cuatro. No hay corte por ancho porque no hace falta uno —
   `auto-fit` con un mínimo lo reparte solo. */
.fin-acc__f {
  grid-area: ficha;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: var(--s-2);
  padding: 0 var(--s-2) var(--s-4);
}
.fin-acc__f .r-input { height: 34px; }
.fin-acc__f .r-pick { min-width: 0; }
/* La nota se queda con el renglón completo: es texto libre y 140 px de mínimo
   la vuelven un campo donde no cabe una frase. */
.fin-acc__wide { grid-column: 1 / -1; }

/* ---------- Los movimientos sin cuenta ----------
   Una puerta, no una cuenta: por eso no vive dentro de `.fin-accs` ni tiene
   saldo. Va debajo de la lista, con su punto en warn, y desaparece sola cuando
   ya no queda ninguno. */
.fin-orfe {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  width: 100%;
  margin-top: var(--s-3);
  padding: var(--s-3) var(--s-2);
  border: 0;
  border-radius: var(--r-sm);
  background: transparent;
  color: var(--ink-2);
  font-family: inherit;
  font-size: var(--t-body-sm);
  text-align: left;
  transition: background var(--d-fast) var(--ease), color var(--d-fast) var(--ease);
}
.fin-orfe:hover, .fin-orfe:focus-visible { background: var(--surface-2); color: var(--ink); }
.fin-orfe__t { flex: 1 1 auto; min-width: 0; }
.fin-orfe .r-ico { --ico: 16px; color: var(--ink-3); }

/* ---------- La tira de filtros del libro ----------
   Solo existe con filtro puesto. Un libro filtrado sin nada que lo diga se lee
   como un libro con menos movimientos de los que hay. */
.fin-filtro {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2);
  margin-bottom: var(--s-3);
}
.fin-filtro__c { display: inline-flex; align-items: center; gap: var(--s-1); }
.fin-filtro__c .r-ico { --ico: 14px; }

/* La cuenta de un movimiento, dentro de su renglón de metadata. Es un botón
   pero se ve como el texto de al lado hasta que se apunta: la acción de fila se
   revela, y el renglón entero ya está revelándose al hover. */
.fin-mov__acc {
  border: 0;
  padding: 0;
  background: transparent;
  color: inherit;
  font: inherit;
  border-bottom: var(--stroke) dashed var(--hairline-strong);
  cursor: pointer;
}
.fin-mov__acc:hover, .fin-mov__acc:focus-visible { color: var(--ink); }
/* El comprimido que reemplaza al botón mide lo de un control, no lo del texto:
   sin esto empuja la fecha y la nota del renglón. */
.fin-mov__pick { max-width: 160px; vertical-align: middle; }
/* Y el renglón de metadata se queda PUESTO mientras el comprimido esté ahí. Sin
   esto el control nace dentro de una caja en `opacity: 0` y se apaga en cuanto
   el puntero se mueve — un selector abierto que desaparece por moverse. Es el
   mismo arreglo que `.fin-mov__x[data-armed]`, por la misma razón. */
.fin-mov__meta:has(.fin-mov__pick) { opacity: 1; }

/* Historia: seis meses. El eje va en micro y el mes en rojo se marca con la
   tinta crítica, porque las barras del sistema no dibujan negativos. */
.fin-hist { display: grid; gap: var(--s-2); }
.fin-hist .r-bars { height: 52px; }
.fin-hist__x { display: flex; justify-content: space-between; }

/* Captura: nace a la IZQUIERDA del +. No es persistente, no es
   hoja, no es un renglón a todo el ancho debajo de las cuentas.
   `fixed` lo ancla al FAB (finance.js · colocaAdd). Origen a la
   derecha: entra y se recoge con el resorte del sistema.

   `width: max-content` es lo que impide el renglón aplastado: la
   nota ya no crece hasta el techo. El techo (`max-width` +
   `--fin-add-room`) lo escribe `colocaAdd` contra el PANEL, no
   contra la ventana. Si el renglón no cabe, `data-fin-add-stack`
   apila dos filas a propósito —nunca a medias, nunca hoja. */
.fin-add {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  flex-wrap: nowrap;
  width: max-content;
  max-width: min(var(--fin-add-room, 28rem), calc(100% - var(--s-4)));
  padding: var(--s-1) var(--s-2);
  background: var(--surface-sunk);
  border: var(--stroke) solid var(--hairline-strong);
  border-radius: var(--r-pill);
  position: fixed;
  z-index: 4;
  transform-origin: right center;
}
.fin-add__row {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  min-width: 0;
  flex: 0 0 auto;
}
.fin-add__row .r-seg,
.fin-add__row .r-icon-btn,
.fin-add__amt,
.fin-add__cur { flex-shrink: 0; }
.fin-add[data-fin-add-stack] {
  flex-wrap: wrap;
  align-items: stretch;
  border-radius: var(--r-lg);
}
.fin-add[data-fin-add-stack] .fin-add__row {
  flex: 1 1 auto;
  flex-wrap: wrap;
}
.fin-add--in {
  animation: fin-add-in var(--d-base) var(--ease-spring);
}
.fin-add--out {
  animation: fin-add-out var(--d-base) var(--ease-spring) forwards;
  pointer-events: none;
}
@keyframes fin-add-in {
  from { opacity: 0; transform: translateX(1.25rem) scaleX(0.84); }
  to   { opacity: 1; transform: none; }
}
@keyframes fin-add-out {
  from { opacity: 1; transform: none; }
  to   { opacity: 0; transform: translateX(1.25rem) scaleX(0.84); }
}
@media (prefers-reduced-motion: reduce) {
  .fin-add--in,
  .fin-add--out { animation: none; }
}
.fin-add .r-input { height: 28px; min-height: 28px; }
.fin-add__amt { max-width: 88px; min-width: 4.5rem; text-align: right; }
/* Categoría: elegir y capturar en el mismo hueco de la fila. El ancho lo pone
   el envoltorio —no el selector— y el nombre largo se recorta dentro, que es lo
   que `.r-pick__v` ya sabe hacer con su elipsis. El `min-width: 0` no es un
   restilado del componente sino la condición para que encoja: un elemento de
   flex arranca en `min-width: auto` y con un nombre largo se niega a ceder,
   así que empujaría la nota y el botón de alta fuera del renglón. Misma
   naturaleza que el `height` que la fila ya le pone a sus inputs. */
.fin-add__cat {
  display: inline-flex;
  align-items: center;
  gap: var(--s-1);
  min-width: 0;
  max-width: 190px;
}
.fin-add__cat .r-pick { min-width: 0; }
/* La nota Cede, no crece: un `flex-grow` la convertía en la pista
   que aplastaba la barra a todo el hueco hasta el canto de la
   ventana. 8rem es sitio para una palabra; el resto vive al picar. */
.fin-add__note { flex: 0 1 8rem; min-width: 4rem; }
.fin-add[data-fin-add-stack] .fin-add__note { flex: 1 1 6rem; }

/* Categorías: la barra es la comparación, el número el detalle. */
.fin-cats { display: grid; gap: var(--s-1); margin-bottom: var(--s-6); }
.fin-cat {
  display: grid;
  grid-template-columns: minmax(0, 9ch) minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--s-3);
  width: 100%;
  padding: var(--s-2);
  border: 0;
  border-radius: var(--r-sm);
  background: transparent;
  color: var(--ink-2);
  font-family: inherit;
  font-size: var(--t-body-sm);
  text-align: left;
  transition: background var(--d-fast) var(--ease), color var(--d-fast) var(--ease);
}
.fin-cat:hover, .fin-cat:focus-visible { background: var(--surface-2); color: var(--ink); }
.fin-cat--on { background: var(--surface-sunk); color: var(--ink); }
.fin-cat__n { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fin-cat__bar {
  height: 6px;
  border-radius: var(--r-pill);
  background: var(--surface-sunk);
  position: relative;
  overflow: hidden;
}
.fin-cat__bar::after {
  content: "";
  position: absolute;
  inset: 0 auto 0 0;
  width: var(--at, 0%);
  background: var(--ink-4);
  border-radius: inherit;
  transition: width var(--d-slow) var(--ease-out);
}
.fin-cat--on .fin-cat__bar::after, .fin-cat:hover .fin-cat__bar::after { background: var(--ink-3); }
.fin-cat__v { color: var(--ink); }

/* El libro. La fecha, la nota y el botón de quitar se revelan al hover y al
   foco: con opacidad, para que el renglón mida siempre lo mismo. */
.fin-libro { border-top: var(--stroke) solid var(--hairline); margin-bottom: var(--s-8); }
.fin-mov {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto;
  grid-template-areas: "cat monto x" "meta meta x";
  align-items: center;
  gap: var(--s-1) var(--s-3);
  padding: var(--s-3) var(--s-2);
  border-bottom: var(--stroke) solid var(--hairline);
  animation: os-slide-in var(--d-base) var(--ease-out) both;
  animation-delay: calc(var(--i, 0) * var(--stagger));
}
.fin-mov__cat { grid-area: cat; font-size: var(--t-body-sm); color: var(--ink); }
.fin-mov__n {
  grid-area: monto;
  font-size: var(--t-body);
  color: var(--ink);
  display: inline-flex;
  align-items: baseline;
  gap: var(--s-1);
}
.fin-mov--in .fin-mov__n { color: var(--ok); }
.fin-mov__cur { color: var(--ink-3); }
.fin-mov__meta { grid-area: meta; }
.fin-mov__x { grid-area: x; }

.fin-mov__meta, .fin-mov__x {
  opacity: 0;
  transition: opacity var(--d-fast) var(--ease);
}
.fin-mov:hover .fin-mov__meta, .fin-mov:focus-within .fin-mov__meta,
.fin-mov:hover .fin-mov__x, .fin-mov:focus-within .fin-mov__x { opacity: 1; }

/* Armado, el bote deja de ser secundario.

   `.fin-mov__x` era el botón, y esconderlo hasta el hover era correcto: una
   acción de fila se revela. Ahora es el HOST del `.r-confirm`, así que la
   misma regla escondía también el panel con la pregunta — medido: con el bote
   armado el host seguía en `opacity: 0` y la confirmación era invisible.

   Una pregunta que confirma un borrado no puede depender de que el puntero
   siga encima de la fila para verse. El selector va sobre la clase del módulo
   y solo lee el estado del componente (`data-armed`): no reestiliza nada de
   `.r-`. */
.fin-mov__x[data-armed] { opacity: 1; }

/* ---------- El renglón al que llegó otro módulo ----------
   LEVER cita movimientos y su cita se pica: se aterriza en el libro, en el
   renglón exacto (ver `open()` en finance.js).

   La marca es un PUNTERO, no una selección —el libro no tiene filas
   seleccionadas y no se le inventa una— así que se apaga sola: entra con el
   fondo hundido y el canto marcado, y se desvanece en su lugar. Nada se
   mueve: ni padding, ni alto, ni el orden de la lista.

   NO es ácido, a propósito: el acento de esta vista es el balance, y es uno
   por vista. El canto va con `--ink`, que es lo más fuerte que puede señalar
   sin robarle la marca a la cifra.

   El canto es `box-shadow: inset` y no un `border-inline-start`, y eso no es
   sombra: un borde de verdad metería tres píxeles de caja y correría la
   categoría, el monto y la fecha del renglón marcado contra todos los demás
   del libro. La sombra interior dibuja la misma línea sin tocar el flujo.

   El `--i` de la cascada se conserva porque la lista entra igual —el renglón
   marcado no se salta su turno— y el desvanecido arranca cuando la fila ya
   está puesta, de ahí el segundo retardo. */
@keyframes fin-mark {
  from {
    background: var(--surface-sunk);
    box-shadow: inset calc(var(--stroke) * 3) 0 0 var(--ink);
  }
  to {
    background: transparent;
    box-shadow: inset calc(var(--stroke) * 3) 0 0 transparent;
  }
}
.fin-mov--mark {
  animation: os-slide-in var(--d-base) var(--ease-out) both,
             fin-mark calc(var(--d-slower) * 4) var(--ease-out) both;
  animation-delay: calc(var(--i, 0) * var(--stagger)), var(--d-base);
}
/* El foco llega por `focus()`, así que puede no encender `:focus-visible`; la
   fila igual dice que la tiene, con la misma tinta del canto. */
.fin-mov--mark:focus { outline: none; }
.fin-mov--mark:focus-visible { outline: var(--stroke) solid var(--ink); outline-offset: 0; }

.fin-vacio { padding: var(--s-6) 0; }

/* ---------- El libro en blanco ----------
   Mismas medidas que `.gw-blank`, que es el vacío del que este copia: aire de
   --s-8, todo centrado y techo en la medida de lectura. La diferencia es que
   aquí NO lleva `flex: 1 1 auto`: `#finRoot` no es una columna flex —solo
   contenedor de consultas— así que no hay alto sobrante que reclamar y pedirlo
   no haría nada. Queda pegado debajo del balance, que es de lo que habla. */
/* ---------- DOS vacíos, dos clases, un bloque de medidas ----------
   `.fin-blank` es el libro sin movimientos y `.fin-noacc` es el hueco sin
   cuentas. Comparten exactamente esto —el aire, el centrado, el techo de
   lectura— y nada más: son dos preguntas distintas, en la misma sección,
   con dos primeras acciones distintas.

   Y llevan dos nombres porque llevar el mismo costó una prueba roja:
   `test_vacios.py` cuenta `.fin-blank` para afirmar que la invitación del libro
   se pintó, y con las dos piezas compartiendo clase contaba dos. Una clase que
   dos piezas comparten es una clase con la que ya no se puede señalar ninguna. */
.fin-blank, .fin-noacc {
  padding: var(--s-8) var(--s-4);
  text-align: center;
  display: grid;
  gap: var(--s-3);
  justify-items: center;
  align-content: center;
  max-width: var(--measure);
  margin-inline: auto;
}
.fin-blank__s, .fin-noacc__s {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2);
  justify-content: center;
}
/* El vacío de cuentas ya no reclama alto: vive dentro de Balance, no en
   una columna flex propia. */

@media (prefers-reduced-motion: reduce) {
  .fin-mov, .fin-acc { animation: none; }
  .fin-cat__bar::after, .fin-mov__meta, .fin-mov__x, .fin-cat,
  .fin-acc__meta, .fin-acc__x, .fin-acc__r, .fin-fx__e, .fin-orfe { transition: none; }

  /* Sin animación la marca no se desvanece: se QUEDA puesta hasta el
     siguiente pintado del libro. Una marca que no puede animarse tiene que
     poder verse quieta — si aquí se apagara junto con la animación, quien
     tiene la preferencia puesta no vería nada al aterrizar. */
  .fin-mov--mark {
    animation: none;
    background: var(--surface-sunk);
    box-shadow: inset calc(var(--stroke) * 3) 0 0 var(--ink);
  }
}

/* Sin hover no hay revelación: en táctil lo secundario se queda visible. */
@media (hover: none) {
  .fin-mov__meta, .fin-mov__x,
  .fin-acc__meta, .fin-acc__x, .fin-fx__e,
  .fin-tile__e { opacity: 1; }
}

/* ============================================================
   Anchos — contra la caja del PANEL, no contra la ventana
   ============================================================ */

/* La barra flota junto al +: no hereda el ancho del panel. El
   apilado lo decide `colocaAdd` (`data-fin-add-stack`) contra el
   hueco real a la izquierda del +, no un corte de contenedor —
   `.fin-add` es `position: fixed` y un `@container fin` midiendo
   el panel no sabe cuánto aire hay frente al FAB. */

@container fin (max-width: 430px) {
  /* El aviso de tasa faltante puede ser más largo que el teléfono. El texto
     envuelve y el lápiz mantiene su propia columna, siempre dentro del panel. */
  .fin-fx__i--falta {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    min-width: 0;
    max-width: 100%;
    white-space: normal;
  }
  .fin-fx__i--falta > span:not(.fin-fx__e) { grid-column: 1; }
  .fin-fx__i--falta .fin-fx__e { grid-column: 2; grid-row: 1 / span 2; }

  .fin-cat { grid-template-columns: minmax(0, 8ch) minmax(0, 1fr) auto; }

  /* El numeral de puntos mide lo que mide su cadena: no es tipo que se
     reajuste, y tampoco encoge —un SVG con ancho explícito conserva su ancho
     intrínseco como mínimo—. El balance más largo que se puede dar aquí
     (signo + siete caracteres: "−200,583", 330px a --lg) deja 13px para la
     unidad y "MXN" se salía 11px de la caja.

     Se deja envolver, y la unidad baja al siguiente renglón en vez de
     empujar el panel a scroll horizontal. No es un override del componente:
     `flex-wrap` no lo declara `.r-lcdrow`, y la alternativa —bajarle el
     tamaño a la matriz— haría que la métrica que manda dejara de mandar en
     el ancho donde menos cosas hay para competirle. */
  .fin-balance { flex-wrap: wrap; }
}

/* ============================================================
   PROYECCIÓN — la sección que contesta «¿me va a hacer falta?»
   ============================================================
   Métrica → gráfica → tabla, y aquí la tabla es la PRUEBA de la cifra: se
   sigue la cuenta con el dedo, renglón por renglón, hasta el número grande.
   Por eso su renglón tiene una columna que las otras listas del módulo no
   tienen —el saldo que deja— y por eso esa columna nunca se esconde al hover:
   es el dato, no la metadata.

   Cabe sin scroll en el cómodo: cabeza 20 + numeral 60 + líquido 16 +
   veredicto 34 + salvedades 16 + gráfica 132 + fila 62 + tabla ~9 renglones a
   34 = ~660 px, con la tabla creciendo hasta ~30 renglones en el peor caso
   razonable. Es la única lista de la sección, así que es la que se recorre
   —igual que el libro en Movimientos— y la cabeza queda siempre a la vista. */

.fin-proy { display: flex; flex-direction: column; min-height: 0; flex: 1 1 auto; }

/* NADIE CEDE SALVO LA TABLA, y esto no es defensivo: sin la regla, un hijo de
   flex arranca en `flex-shrink: 1`, así que la gráfica de 132 px y la fila de
   captura se COMPRIMÍAN cuando la tabla crecía — medido en el panel angosto: la
   gráfica quedó encimada con la fila y sus etiquetas de eje salieron por debajo
   del segmentado. Es el mismo reparto de `:where(#finRoot) > *`: todo queda
   quieto y quien crece lo pide por su nombre. */
:where(.fin-proy) > * { flex: 0 0 auto; }

/* El saldo de hoy, pegado debajo del numeral: es de dónde ARRANCA la cuenta y
   sin él la cifra grande no se puede reconstruir. */
.fin-proy__ini { margin: 0 0 var(--s-2); }

/* El veredicto. Palabras completas —la excepción de claridad— así que se le
   deja respirar y no se recorta: si hay que envolver, envuelve. */
.fin-proy__v { margin: 0 0 var(--s-2); }

.fin-proy__s {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-1);
  margin: 0 0 var(--s-3);
}

/* El atajo a lo que falta capturar. Aparece solo cuando hay algo que arreglar,
   así que no se esconde al hover: sería esconder la salida. */
.fin-proy__fix, .fin-acc__cuadrar { margin-inline-start: var(--s-2); }

/* ---------- La gráfica ----------
   El alto se pide con `--chart-h`, que es la perilla del propio componente, y NO
   con un `height` sobre `.r-chart`. La diferencia es medida, no de estilo: el
   `<svg>` toma su alto de `--chart-h` (200px por omisión) y `.r-chart` reserva
   `--s-10` de padding arriba para el valor del endpoint, así que un `height:
   132px` en el contenedor no encoge el svg — **lo desborda**. Medido en el panel
   angosto: contenedor de 132, svg de 200 arrancando 40 px más abajo, o sea 108
   px de gráfica encimados sobre la fila de captura y sus etiquetas de eje
   metidas debajo del segmentado.

   132 y no los 200 de omisión porque aquí la gráfica es contexto, no la cifra:
   con 200 la sección no cabe sin scroll en el cómodo (~900 px de alto útil).
   El alto total del bloque queda en 40 + 132.

   Y esos 40 de arriba se dejan en paz. Son el aire que `.r-chart` reserva para
   el valor del endpoint, y aquí no lo hay: NO se pasa `data-unit`, porque el
   componente pinta ese valor como un `.r-metric` —o sea una segunda métrica en
   una vista cuyo dato que manda es el numeral de puntos— y además lo escribe sin
   separadores de millar, así que «17000» contradiría al «17,000» de tres
   renglones arriba. Comerse el hueco con un margen negativo sería restilar el
   componente por fuera; como espacio de sección se lee bien y el margen de abajo
   es lo único que este archivo pone. */
.fin-proy__g {
  --chart-h: 132px;
  margin-bottom: var(--s-4);
}

/* ---------- La fila de lo planeado ----------
   Mismas medidas que `.fin-add`: son la misma clase de gesto —capturar en un
   renglón— y dos formas distintas de la misma fila se leen como dos piezas.
   Comparten el bloque de arriba en espíritu y no en selector porque los anchos
   de sus campos son distintos (aquí hay un «cada cuánto» y un día). */
.fin-plan {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  flex-wrap: wrap;
  padding: var(--s-3);
  background: var(--surface-sunk);
  border-radius: var(--r-pill);
  margin-bottom: var(--s-4);
}
.fin-plan .r-input { height: 34px; }
.fin-plan__amt { max-width: 110px; text-align: right; }
.fin-plan__day { max-width: 68px; text-align: right; }
.fin-plan__date { max-width: 150px; }
/* El comprimido de la especie y el de la periodicidad ceden antes que la
   etiqueta: `min-width: 0` es la condición para que un hijo de flex encoja
   —arranca en `auto` y con un nombre largo se niega— no un restilado. */
.fin-plan__kind, .fin-plan__cur, .fin-plan__every { min-width: 0; }
.fin-plan__every { max-width: 140px; }
.fin-plan__lbl { flex: 1 1 120px; min-width: 0; }

@container fin (max-width: 560px) {
  .fin-plan { border-radius: var(--r-lg); }
  .fin-plan__lbl { flex-basis: 100%; }
}

/* ---------- La tabla de eventos ----------
   Cinco columnas y ninguna es opcional: cuándo, qué, cuánto, con qué se queda,
   y de dónde salió. La última es la que vuelve auditable el número —«esto es la
   nómina, esto es la tarjeta»— y va en micro y atenuada porque es la etiqueta,
   no el dato.

   Se recorre por dentro, con la misma pista que `.fin-accs`: la sección tiene
   que caber y la lista no tiene techo. */
.fin-tl {
  border-top: var(--stroke) solid var(--hairline);
  overflow-y: auto;
  min-height: 0;
  flex: 1 1 auto;
  margin-bottom: var(--s-6);
  /* El relleno del cuerpo del panel queda fuera de este scroller, así que
     el último renglón se metería debajo del `.r-fab` y el clic se lo
     comería el alta. Ver `ron.css § 33d bis`. */
  padding-bottom: var(--fab-reserve);
}
.fin-tl__r {
  display: grid;
  grid-template-columns: 5.5ch minmax(0, 1fr) auto auto;
  grid-template-areas: "d n a s" "d o o x";
  align-items: center;
  gap: 0 var(--s-3);
  padding: var(--s-2);
  border-bottom: var(--stroke) solid var(--hairline);
  animation: os-slide-in var(--d-base) var(--ease-out) both;
  animation-delay: calc(var(--i, 0) * var(--stagger));
}
.fin-tl__d { grid-area: d; color: var(--ink-3); }
.fin-tl__n {
  grid-area: n;
  font-size: var(--t-body-sm);
  color: var(--ink);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.fin-tl__a {
  grid-area: a;
  color: var(--ink);
  display: inline-flex;
  align-items: baseline;
  gap: var(--s-1);
}
.fin-tl__a--in { color: var(--ok); }
.fin-tl__cur { color: var(--ink-3); }

/* El saldo que deja. Es la columna que hace de esto una auditoría, así que
   NUNCA se esconde: se ve en reposo, sin hover. */
.fin-tl__s { grid-area: s; color: var(--ink-2); }

/* El origen, el bote y la paloma sí son secundarios: se revelan. Con opacidad
   y no con `display`, para que el renglón mida siempre lo mismo y revelarlos no
   reacomode la lista — el mismo arreglo que `.fin-acc__meta`. */
.fin-tl__o { grid-area: o; }
.fin-tl__x { grid-area: x; }
.fin-tl__ok { grid-area: x; }
.fin-tl__r:has(.fin-tl__ok) { grid-template-areas: "d n a s" "d o x ok"; }
.fin-tl__r:has(.fin-tl__ok) .fin-tl__ok { grid-area: ok; }
.fin-tl__o, .fin-tl__x, .fin-tl__ok {
  opacity: 0;
  transition: opacity var(--d-fast) var(--ease);
}
.fin-tl__r:hover .fin-tl__o, .fin-tl__r:focus-within .fin-tl__o,
.fin-tl__r:hover .fin-tl__x, .fin-tl__r:focus-within .fin-tl__x,
.fin-tl__r:hover .fin-tl__ok, .fin-tl__r:focus-within .fin-tl__ok { opacity: 1; }
/* Armado, el bote deja de ser secundario: una pregunta que confirma un borrado
   no puede depender de que el puntero siga encima. Mismo caso, mismo arreglo y
   misma frontera que `.fin-mov__x[data-armed]` — solo se lee el estado del
   componente, no se reestiliza nada de `.r-`. */
.fin-tl__x[data-armed] { opacity: 1; }

/* El día en que el saldo se va abajo de cero. Hundido y con su canto, la misma
   lengua que `.fin-mov--mark`, pero SIN desvanecerse: aquello es un puntero que
   se apaga solo y esto es un estado del dato. */
.fin-tl__r--neg {
  background: var(--crit-bg);
  box-shadow: inset 2px 0 0 0 var(--crit);
}

/* La tinta ámbar. `--warn` es un token del sistema; lo que no existe es una
   utilidad `.r-t-warn` que lo ponga en texto —`ron.css` declara `.r-t-ok` y
   `.r-t-crit` y se salta el de en medio—. Vive aquí con prefijo propio en vez
   de como override, y está pedida para el sistema: son tres piezas de este
   módulo las que la necesitan. */
.fin-t-warn { color: var(--warn); }

/* ---------- El vacío de Proyección ----------
   Tercer vacío del módulo, y va con su clase propia por la razón que ya
   documentó el par `.fin-blank` / `.fin-noacc`: una prueba que cuenta nodos
   necesita poder señalar UNA cosa. Comparte las MEDIDAS con los otros dos, que
   es lo que de verdad tienen en común. */
.fin-noproy { flex: 1 1 auto; min-height: 0; }

/* ---------- Lo que dice el libro, en la ficha de una cuenta ----------
   Ocupa el ancho completo de la ficha: es una oración, no un campo. */
.fin-acc__cuadre {
  grid-column: 1 / -1;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-1);
  margin: 0;
}

/* ---------- La lente del patrimonio ----------
   El segmentado va en la cabeza, junto al rótulo, y empuja el punto de estado
   al final del renglón. No crece: dos palabras cortas. */
.fin-pat__lente { flex: 0 0 auto; margin-inline-end: auto; }

/* ---------- La siguiente página del libro ----------
   Dice cuántos se ven de cuántos hay. Es la misma pieza que `.fin-orfe` —una
   puerta con su chevron— y comparte su naturaleza: aparece solo cuando hay algo
   que decir. */
.fin-mas {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--s-1);
  width: 100%;
  padding: var(--s-3);
  margin-top: calc(var(--s-8) * -1 + var(--s-2));
  margin-bottom: var(--s-8);
  background: none;
  border: 0;
  border-radius: var(--r-md);
  font: inherit;
  font-size: var(--t-body-sm);
  color: var(--ink-2);
  cursor: pointer;
  transition: background var(--d-fast) var(--ease), color var(--d-fast) var(--ease);
}
.fin-mas:hover, .fin-mas:focus-visible { background: var(--surface-2); color: var(--ink); }
.fin-mas .r-ico { --ico: 16px; color: var(--ink-3); }

@media (prefers-reduced-motion: reduce) {
  .fin-tl__r { animation: none; }
}

/* ---------- EL ALTA DE LA ESQUINA TAPA EL ÚLTIMO RENGLÓN DE UNA PISTA ----------
   El design system reserva el hueco del `.r-fab` con
   `.r-flyout[data-flyout-fab] .r-flyout__body { padding-bottom: --fab-reserve }`
   (ron.css § 33d), y es correcto para una vista que scrollea con el cuerpo del
   panel. Pero cuando la lista tiene **pista propia** —`.fin-accs` y `.fin-tl`,
   que se recorren por dentro— ese relleno queda FUERA del scroller: el último
   renglón de la lista siempre aterriza en la esquina inferior derecha, o sea
   exactamente debajo del botón.

   Y no es cosmético: ahí es donde viven las acciones de fila. Lo cazó una prueba
   de interfaz al intentar palomear un esperado — Playwright reintentó el clic
   durante treinta segundos con el diagnóstico literal «`<div class="r-fab">`
   intercepts pointer events». Con el puntero de una persona pasa lo mismo, solo
   que sin diagnóstico: el clic cae en el alta y aparece un campo que nadie pidió.

   El relleno se le pone A LA PISTA, que es la que scrollea, y solo cuando de
   verdad hay botón que esquivar. No se restila nada de `.r-`: el selector lee el
   estado del panel y aplica sobre clases de este módulo, igual que el `:has` de
   `workspace.css`. */
.r-flyout[data-flyout-fab] .fin-accs,
.r-flyout[data-flyout-fab] .fin-tl { padding-bottom: var(--fab-reserve); }
