:root {
  color-scheme: light;
  --bg: #f5f7f8;
  --surface: #ffffff;
  --surface-soft: #eef4f2;
  --text: #172026;
  --muted: #65727b;
  --line: #d8e0e4;
  --nav: #22304a;
  --teal: #0f766e;
  --teal-hover: #0b5f59;
  --green: #18794e;
  --red: #c92a2a;
  --mod-blue: #2563eb;
  --mod-blue-bg: rgba(37, 99, 235, 0.12);
  --mod-green: #16a34a;
  --mod-green-bg: rgba(22, 163, 74, 0.13);
  --mod-amber: #d97706;
  --mod-amber-bg: rgba(217, 119, 6, 0.14);
  --mod-violet: #7c3aed;
  --mod-violet-bg: rgba(124, 58, 237, 0.13);
  --mod-orange: #ea580c;
  --mod-orange-bg: rgba(234, 88, 12, 0.13);
  --mod-rose: #db2777;
  --mod-rose-bg: rgba(219, 39, 119, 0.13);
  --shadow: 0 16px 48px rgba(23, 32, 38, 0.07);
  font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  font-size: 75%;
}

/* Tema lavanda: fondo lavanda muy suave, acentos primarios en rosa
   pastel y nav en rosa más oscuro. Los iconos de los módulos
   (azul, violeta, verde, naranja, rosa) y los semánticos verde/rojo
   de saldos se mantienen sin cambios para no perder señalética. */
[data-theme="lavanda"] {
  --bg: #fdf3f6;
  --teal: #d97a98;
  --teal-hover: #c45e80;
  --nav: #7a4a5f;
}

/* Selector de tema en Configuración → Tema. Dos cards lado a lado
   con un swatch visual del tema, etiqueta y pequeña descripción. */
.theme-toggle {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
  margin-top: 14px;
}

.theme-option {
  display: grid;
  gap: 6px;
  padding: 14px 16px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 10px;
  cursor: pointer;
  text-align: left;
  transition: border-color 120ms ease, background 120ms ease;
}

.theme-option:hover {
  border-color: var(--teal);
}

.theme-option.is-active {
  border-color: var(--teal);
  background: var(--surface-soft);
  box-shadow: 0 0 0 2px var(--teal) inset;
}

.theme-option > span:not(.theme-swatch) {
  font-weight: 700;
  font-size: 0.95rem;
}

.theme-option small {
  color: var(--muted);
  font-size: 0.8rem;
  line-height: 1.35;
}

.theme-swatch {
  display: block;
  width: 100%;
  height: 36px;
  border-radius: 6px;
  border: 1px solid var(--line);
}

/* Swatches: una banda con el fondo y un círculo con el botón
   primario, para que se vea de un vistazo el resultado. */
.theme-swatch--classic {
  background: linear-gradient(90deg, #f5f7f8 0%, #f5f7f8 70%, #0f766e 70%, #0f766e 100%);
}

.theme-swatch--lavanda {
  background: linear-gradient(90deg, #fdf3f6 0%, #fdf3f6 70%, #d97a98 70%, #d97a98 100%);
}

@media (max-width: 480px) {
  .theme-toggle {
    grid-template-columns: 1fr;
  }
}

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  min-height: 100vh;
  background: var(--bg);
  color: var(--text);
}

button,
input,
select,
textarea {
  font: inherit;
}

button {
  cursor: pointer;
}

.shell {
  min-height: 100vh;
}

.sidebar {
  position: fixed;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 10;
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 6px;
  padding: 8px;
  background: rgba(255, 255, 255, 0.94);
  border-top: 1px solid var(--line);
  backdrop-filter: blur(16px);
}

.brand {
  display: none;
}

.nav {
  display: contents;
}

.nav-separator {
  display: none;
}

.nav-button {
  position: relative;
  display: grid;
  min-height: 44px;
  place-items: center;
  color: var(--muted);
  background: transparent;
  border: 0;
  border-radius: 6px;
}

.nav-button.is-active {
  color: #ffffff;
  background: var(--nav);
}

.nav-button::after {
  position: absolute;
  bottom: calc(100% + 8px);
  left: 50%;
  z-index: 20;
  padding: 6px 8px;
  color: #ffffff;
  background: var(--nav);
  border-radius: 6px;
  content: attr(aria-label);
  font-size: 0.78rem;
  font-weight: 800;
  opacity: 0;
  pointer-events: none;
  transform: translateX(-50%) translateY(3px);
  transition: opacity 120ms ease, transform 120ms ease;
  white-space: nowrap;
}

.nav-button:hover::after,
.nav-button:focus-visible::after {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}

/* Dispositivos sin hover real (móvil táctil): el tooltip salía con
   el tap y resultaba ruido — el nombre del módulo ya se lee en el
   título de la vista que se abre. Se mantiene aria-label accesible
   para lectores de pantalla; solo desactivamos el ::after visual. */
@media (hover: none) {
  .nav-button::after {
    display: none;
  }
}

.nav-icon {
  display: block;
  width: 20px;
  height: 20px;
  fill: none;
  stroke: currentColor;
  stroke-linecap: round;
  stroke-linejoin: round;
  stroke-width: 2;
}

.app {
  width: min(100%, 1180px);
  margin: 0 auto;
  padding: 18px 28px 92px;
}

.view {
  display: none;
}

.view.is-active {
  display: block;
}

/* Home: el panel de tiles se centra verticalmente en el espacio
   disponible del navegador en lugar de pegarse al borde superior.
   La topbar (eyebrow + título "Home") sigue arriba; el panel se
   reparte el aire restante con margin-auto encima/debajo. Aplica
   tanto en móvil como en escritorio — solo cambia el min-height
   según el padding del .app contenedor. */
#home-view.is-active {
  display: flex;
  flex-direction: column;
}

#home-view.is-active > .panel {
  margin-top: auto;
  margin-bottom: auto;
}

@media (min-width: 720px) {
  #home-view.is-active {
    /* 100vh menos los paddings top/bottom de .app (18px + 92px). */
    min-height: calc(100vh - 110px);
  }
}

@media (max-width: 719px) {
  #home-view.is-active {
    /* 100vh menos los paddings top/bottom de .app móvil (12px + 140px
       para librar la sidebar fija del fondo). */
    min-height: calc(100vh - 152px);
  }
}

/* El panel del Home pierde el cuadro contenedor en móvil y en
   escritorio: sin fondo, sin borde, sin sombra ni padding propio.
   Las cards "flotan" directamente sobre el fondo del .app. El padding
   lateral viene del .app (14px en desktop, 10px en móvil). */
#home-view .panel {
  background: transparent;
  border: 0;
  box-shadow: none;
  padding: 0;
}

.topbar {
  display: flex;
  gap: 16px;
  align-items: flex-end;
  justify-content: space-between;
  margin-bottom: 18px;
}

.period {
  margin: 0;
  color: var(--nav);
  font-size: 0.78rem;
  font-weight: 800;
  text-transform: uppercase;
}

h1,
h2,
h3,
p {
  margin-top: 0;
}

h1 {
  margin-bottom: 0;
  font-size: 2rem;
  line-height: 1;
}

h2 {
  margin-bottom: 0;
  font-size: 1rem;
}

.summary {
  display: grid;
  grid-template-columns: 1fr;
  gap: 10px;
  margin-bottom: 14px;
}

.metric,
.panel,
.module-card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 8px;
  box-shadow: var(--shadow);
}

/* Borders más redondeados para las tarjetas del Home (CTA, módulos
   y meta-links). El estilo base de .module-card es 8px; aquí
   subimos a 14px solo en el contexto del home-view. */
#home-view .module-card {
  border-radius: 14px;
}

#home-view .home-add-cta {
  /* El CTA ya es pill (999px); sin cambios. */
}

.metric {
  display: flex;
  min-height: 76px;
  align-items: center;
  justify-content: space-between;
  padding: 16px;
}

.metric span {
  color: var(--muted);
  font-size: 0.86rem;
  font-weight: 700;
}

.metric strong {
  font-size: 1.24rem;
}

.metric-balance {
  background: var(--surface-soft);
}

.module-grid {
  display: grid;
  gap: 10px;
  /* Móvil por defecto: 1 columna (5 tiles apilados verticalmente).
     En desktop pasa a 5 cols con cada tile en aspect-ratio 3:4 — ver
     el @media (min-width: 720px) más abajo. */
  grid-template-columns: 1fr;
}

.module-groups {
  display: grid;
  gap: 12px;
}

/* CTA principal del Home: pill verde teal con icono "+" y
   "Añadir/movimiento" en dos líneas. Atajo al modal de Nuevo
   movimiento — el flujo más usado pasa de tres clics a uno. El
   botón se ajusta a su contenido (no banner full ancho) y se
   centra horizontalmente con margin auto. */
.home-add-cta {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  width: auto;
  margin: 0 auto 22px;
  padding: 14px 26px;
  /* Mismo verde teal de var(--teal) que usan "Nuevo movimiento" y
     "Añadir contacto" en sus paneles. Coherencia con el resto de
     CTAs primarios de la app. */
  background: var(--teal);
  color: #ffffff;
  border: none;
  border-radius: 999px;
  font-weight: 700;
  letter-spacing: 0.01em;
  cursor: pointer;
  box-shadow: 0 8px 22px rgba(15, 118, 110, 0.28);
  transition: transform 120ms ease, box-shadow 120ms ease, background 120ms ease;
}

/* El padre es un .panel (display: block); para centrar un inline-flex
   forzamos display: block en el botón con margin auto. Mantenemos los
   children como flex via la propia regla del button. */
.home-add-cta {
  display: flex;
  width: fit-content;
}

.home-add-cta:hover {
  background: var(--teal-hover);
  transform: translateY(-1px);
  box-shadow: 0 12px 28px rgba(15, 118, 110, 0.34);
}

.home-add-cta:active {
  transform: translateY(0);
  box-shadow: 0 6px 16px rgba(15, 118, 110, 0.3);
}

.home-add-cta svg {
  width: 26px;
  height: 26px;
  flex: 0 0 auto;
}

/* Hijos del CTA sin pointer-events propios: en móvil, a veces el SVG
   o el span captura el tap y el click no se sintetiza correctamente
   al <button> padre. Con esto, el tap siempre cuenta como click del
   button y el listener dispara fiable. */
.home-add-cta > * {
  pointer-events: none;
}

/* Label en dos líneas: "Añadir" arriba y "movimiento" debajo.
   Dos spans block dentro de un wrapper flex column. */
.home-add-cta-label {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  line-height: 1.1;
  font-size: 1.05rem;
  text-align: left;
}

.module-group {
  display: grid;
  gap: 8px;
}

.module-card {
  display: grid;
  grid-template-columns: 28px 1fr;
  gap: 4px 12px;
  align-items: center;
  /* Móvil: ~20% más alto que el padding 14px previo. La card pasa
     de ~80px a ~96px de alto sin tocar el contenido interno. */
  padding: 22px 14px;
  color: var(--text);
  text-align: left;
}

.module-card:hover {
  border-color: #b8c5cb;
  background: #fbfcfd;
}

.module-card .nav-icon {
  grid-row: span 2;
  color: var(--nav);
}

.module-card strong {
  font-size: 1rem;
}

.module-card small {
  color: var(--muted);
  font-size: 0.86rem;
  line-height: 1.35;
}

.module-card--accent {
  grid-template-columns: 36px 1fr;
  gap: 4px 14px;
}

/* Desktop: las cards se vuelven verticales tipo "carta" 3:4, los 5
   tiles en una sola fila (5 cols). Icono grande arriba centrado,
   etiqueta principal en medio, descripción debajo. */
@media (min-width: 720px) {
  .module-card {
    grid-template-columns: 1fr;
    grid-auto-rows: auto;
    gap: 12px;
    aspect-ratio: 3 / 4;
    text-align: center;
    justify-items: center;
    align-content: center;
    padding: 18px 12px;
  }

  .module-card--accent {
    grid-template-columns: 1fr;
    gap: 12px;
  }

  .module-card .nav-icon,
  .module-card .module-icon {
    grid-row: auto;
  }

  .module-card .module-icon {
    width: 52px;
    height: 52px;
  }

  .module-card .module-icon .nav-icon {
    width: 26px;
    height: 26px;
  }

  .module-card strong {
    font-size: 1.04rem;
  }

  .module-card small {
    font-size: 0.82rem;
  }
}

.module-icon {
  grid-row: span 2;
  display: inline-flex;
  width: 36px;
  height: 36px;
  align-items: center;
  justify-content: center;
  border-radius: 8px;
  background: var(--module-tile-bg, var(--surface-soft));
  color: var(--module-tile-fg, var(--nav));
}

.module-icon .nav-icon {
  width: 20px;
  height: 20px;
  color: inherit;
}

.module-card[data-color="blue"] {
  --module-tile-bg: var(--mod-blue-bg);
  --module-tile-fg: var(--mod-blue);
}

.module-card[data-color="green"] {
  --module-tile-bg: var(--mod-green-bg);
  --module-tile-fg: var(--mod-green);
}

.module-card[data-color="amber"] {
  --module-tile-bg: var(--mod-amber-bg);
  --module-tile-fg: var(--mod-amber);
}

.module-card[data-color="violet"] {
  --module-tile-bg: var(--mod-violet-bg);
  --module-tile-fg: var(--mod-violet);
}

.module-card[data-color="orange"] {
  --module-tile-bg: var(--mod-orange-bg);
  --module-tile-fg: var(--mod-orange);
}

.module-card[data-color="rose"] {
  --module-tile-bg: var(--mod-rose-bg);
  --module-tile-fg: var(--mod-rose);
}

/* ==== Home modules layout: jerarquía Movimientos > resto ====
   Movimientos pasa a ser la card destacada (columna izquierda en PC,
   fila grande arriba en móvil). Las otras 4 viven en un grid 2x2 en
   PC, apiladas en columna en móvil. Mismos colores de tile que ya
   existían (data-color con su par de variables). */

.home-modules-layout {
  display: grid;
  gap: 14px;
  grid-template-columns: 1fr;
}

.home-modules-secondary {
  display: grid;
  gap: 14px;
  grid-template-columns: 1fr;
}

/* (El reset del .panel del Home — sin background, border ni padding —
   está más arriba junto al centrado vertical, y aplica en ambos
   viewports.) */

/* Movil: primary lleva el mismo layout horizontal que las secundarias
   pero con padding más generoso y tipografía algo mayor para destacar
   sin romper el ritmo visual. */
.module-card.home-module-primary {
  padding: 26px 16px;
}

.module-card.home-module-primary .module-icon {
  width: 44px;
  height: 44px;
}

.module-card.home-module-primary .module-icon .nav-icon {
  width: 24px;
  height: 24px;
}

.module-card.home-module-primary strong {
  font-size: 1.15rem;
}

@media (min-width: 720px) {
  /* PC: 2 cols 45/55. La card de Movimientos ocupa todo el alto del
     row gracias a align-items: stretch (default) + override de
     aspect-ratio. */
  .home-modules-layout {
    grid-template-columns: 45fr 55fr;
    gap: 18px;
  }

  .home-modules-secondary {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 18px;
  }

  /* PC primary (Movimientos): icono grande arriba centrado + título
     grande + descripción debajo. Sin aspect-ratio 3/4 para que llene
     el alto del row. */
  .module-card.home-module-primary {
    aspect-ratio: auto;
    grid-template-columns: 1fr;
    grid-template-rows: auto auto auto;
    gap: 14px;
    text-align: center;
    justify-items: center;
    align-content: center;
    padding: 36px 20px;
  }

  .module-card.home-module-primary .module-icon {
    width: 72px;
    height: 72px;
    border-radius: 14px;
  }

  .module-card.home-module-primary .module-icon .nav-icon {
    width: 36px;
    height: 36px;
  }

  .module-card.home-module-primary strong {
    font-size: 1.7rem;
  }

  .module-card.home-module-primary small {
    font-size: 0.95rem;
  }

  /* PC secondary: layout horizontal (icono izquierda + texto derecha),
     sin aspect-ratio. Mismo reparto que en mobile pero ajustado. */
  .module-card.home-module-secondary {
    aspect-ratio: auto;
    grid-template-columns: 48px 1fr;
    grid-template-rows: auto auto;
    gap: 2px 14px;
    text-align: left;
    justify-items: stretch;
    align-content: center;
    padding: 18px 18px;
  }

  .module-card.home-module-secondary .module-icon {
    grid-row: 1 / span 2;
    align-self: center;
    width: 48px;
    height: 48px;
  }

  .module-card.home-module-secondary .module-icon .nav-icon {
    width: 24px;
    height: 24px;
  }

  .module-card.home-module-secondary strong {
    font-size: 1.02rem;
    text-align: left;
  }

  .module-card.home-module-secondary small {
    font-size: 0.84rem;
    text-align: left;
    line-height: 1.35;
  }
}

/* ==== Novedades destacadas (panel debajo del grid del Home) ====
   Cards informativas que resaltan las grandes features recientes.
   Tonos sage neutros para no competir con los tiles de navegación
   de arriba — la atención principal son los botones, esto es
   contexto secundario.

   PC: 2 columnas, cards con icono + título + descripción.
   Móvil: 2 columnas también, MUY compactas (icono pequeño + título
   solo, sin descripción) para que entren en una sola fila baja sin
   forzar scroll. */
.home-highlights {
  margin-top: 14px;
}

.highlight-grid {
  display: grid;
  gap: 8px;
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

@media (min-width: 720px) {
  .highlight-grid {
    gap: 12px;
  }
}

.highlight-card {
  display: grid;
  align-items: center;
  text-align: left;
  background: #f1f4f2;
  border: 1px solid #dde2dd;
  border-left: 3px solid #8a9b8e;
  border-radius: 10px;
  cursor: pointer;
  color: var(--text);
  transition: transform 0.12s ease, box-shadow 0.12s ease, background 0.12s ease;
}

.highlight-card:hover {
  background: #ecf0ed;
}

@media (min-width: 720px) {
  .highlight-card:hover {
    transform: translateY(-2px);
    box-shadow: 0 4px 12px rgba(74, 85, 80, 0.10);
  }
}

/* Móvil: layout horizontal compacto. Icono a la izquierda spannning
   las 2 filas, título arriba y descripción abajo en la columna
   derecha. Fuente más pequeña que en PC para no forzar scroll. */
.highlight-card {
  grid-template-columns: 32px 1fr;
  gap: 2px 10px;
  padding: 10px 12px;
}

.highlight-icon {
  display: grid;
  place-items: center;
  width: 32px;
  height: 32px;
  border-radius: 6px;
  background: #ffffff;
  color: #5d6c64;
  border: 1px solid #dde2dd;
  grid-row: span 2;
}

.highlight-icon svg {
  width: 18px;
  height: 18px;
}

.highlight-card strong {
  font-size: 0.85rem;
  font-weight: 700;
  color: #3f4a44;
  line-height: 1.2;
}

.highlight-card p {
  margin: 0;
  font-size: 0.74rem;
  color: #5a6660;
  line-height: 1.3;
}

/* PC: cards más generosas con icono grande, padding amplio y
   tipografías mayores. */
@media (min-width: 720px) {
  .highlight-card {
    grid-template-columns: 52px 1fr;
    gap: 4px 14px;
    padding: 16px;
    border-left-width: 4px;
    border-radius: 12px;
  }

  .highlight-icon {
    width: 52px;
    height: 52px;
    border-radius: 12px;
  }

  .highlight-icon svg {
    width: 26px;
    height: 26px;
  }

  .highlight-card strong {
    font-size: 1.02rem;
  }

  .highlight-card p {
    font-size: 0.86rem;
    line-height: 1.4;
  }
}

/* Fila de accesos secundarios (Configuración, Novedades, Roadmap) bajo
   el grid principal del Home: 3 círculos icono-only centrados. La
   etiqueta de texto queda en sr-only para lectores de pantalla;
   tooltip nativo (atributo title) muestra el texto al pasar el ratón. */
.meta-row {
  display: flex;
  justify-content: center;
  gap: 18px;
  padding-top: 18px;
  margin-top: 8px;
  border-top: 1px solid var(--line);
}

.meta-link {
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  padding: 0;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 50%;
  color: var(--muted);
  cursor: pointer;
  transition: background 0.12s ease, color 0.12s ease, border-color 0.12s ease;
}

.meta-link:hover {
  color: var(--text);
  background: rgba(23, 32, 38, 0.04);
  border-color: #b8c5cb;
}

.meta-link .nav-icon {
  width: 18px;
  height: 18px;
  color: currentColor;
}

/* Etiqueta del botón siempre oculta visualmente; sigue accesible para
   screen readers. El icono + el title attribute en el HTML cubren la
   identificación visual y la pista de tooltip al pasar el ratón. */
.meta-link span {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.changelog-list {
  display: grid;
  gap: 0;
}

/* Cada bloque de fecha es el "containing block" del sticky de su
   propio header. Mismo patrón que .month-section en Movimientos: al
   pasar al día siguiente el header se desadhiere de forma natural.
   Margen-bottom amplio para que cada grupo de un mismo día quede
   claramente separado del siguiente día. */
.changelog-date-section {
  display: grid;
  gap: 6px;
  margin-bottom: 26px;
}

.changelog-date-section:last-child {
  margin-bottom: 0;
}

.changelog-date-header {
  position: sticky;
  top: 0;
  z-index: 3;
  padding: 10px 6px 6px;
  margin: 0 0 4px;
  background: var(--surface);
  color: var(--text);
  font-size: 0.85rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  border-bottom: 2px solid var(--line);
}

.changelog-date-header time {
  font: inherit;
  color: inherit;
}

.changelog-item {
  background: #fbfcfd;
  border: 1px solid var(--line);
  border-radius: 8px;
  overflow: hidden;
}

.changelog-item > summary {
  list-style: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 10px 14px;
  -webkit-tap-highlight-color: rgba(15, 118, 110, 0.08);
}

.changelog-item > summary::-webkit-details-marker {
  display: none;
}

.changelog-item > summary::after {
  content: "";
  flex: 0 0 auto;
  width: 10px;
  height: 10px;
  border-right: 2px solid var(--muted);
  border-bottom: 2px solid var(--muted);
  transform: rotate(45deg);
  transition: transform 160ms ease;
}

.changelog-item[open] > summary::after {
  transform: rotate(-135deg);
}

.changelog-title {
  margin: 0;
  flex: 1 1 auto;
  font-size: 0.95rem;
  font-weight: 700;
  line-height: 1.35;
}

.changelog-commit {
  flex: 0 0 auto;
  padding: 2px 5px;
  background: #eef2f4;
  border-radius: 4px;
  color: var(--muted);
  font-family: ui-monospace, SFMono-Regular, Consolas, "Liberation Mono", monospace;
  font-size: 0.72rem;
  font-weight: 700;
}

.changelog-changes {
  display: grid;
  gap: 5px;
  padding: 0 14px 12px 32px;
  margin: 0;
  color: var(--muted);
  font-size: 0.9rem;
  line-height: 1.45;
}

.panel {
  padding: 16px;
  margin-top: 14px;
}

.modal {
  position: fixed;
  inset: 0;
  z-index: 40;
  display: grid;
  place-items: center;
  padding: 16px;
  background: rgba(23, 32, 38, 0.28);
}

.modal[hidden] {
  display: none;
}

.modal-dialog {
  position: relative;
  width: min(100%, 940px);
  max-height: calc(100vh - 32px);
  /* Solo scroll vertical: cualquier overflow horizontal (tooltips
     posicionados, contenido pegado al borde, etc.) se corta en lugar
     de sumar una barra horizontal innecesaria. */
  overflow-x: hidden;
  overflow-y: auto;
  /* Reservamos espacio para el scrollbar siempre — sin esto, cuando
     aparece la barra come 14-16px del padding-right y tapa el borde
     derecho de inputs y la X de cerrar. Padding-right algo mayor que
     el resto: 22px deja una franja confortable entre el contenido /
     la X y el scrollbar (que ronda 14-16px). */
  scrollbar-gutter: stable;
  padding: 14px 22px 14px 14px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 8px;
  box-shadow: var(--shadow);
}

/* X de cerrar del modal de movimiento: vuelve a la esquina superior
   derecha (absolute) tras quitar el feedback del header. El `right`
   está a 22px (no 10) para que el botón quede a la izquierda del
   scrollbar cuando el modal hace scroll. El padding-right del
   modal-dialog deja una franja del mismo ancho para que tampoco el
   contenido toque el scrollbar. */
#close-movement-modal {
  position: absolute;
  top: 10px;
  right: 22px;
  z-index: 1;
}

.modal-dialog .section-heading {
  padding-right: 40px;
}

.section-heading {
  display: flex;
  min-height: 28px;
  gap: 12px;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 14px;
}

.section-heading p,
.section-heading span {
  margin: 0;
  color: var(--muted);
  font-size: 0.86rem;
}

.movement-form,
.filters,
.settings-form,
.config-toolbar {
  display: grid;
  gap: 12px;
}

label {
  display: grid;
  gap: 6px;
}

/* `display: grid` arriba pisaba al atributo nativo [hidden] (que pone
   display: none). Sin esta regla, cualquier <label hidden> seguía
   ocupando una celda del grid del form. Mantener la semántica nativa
   del atributo hidden es importante para los campos que ocultamos
   condicionalmente (día/mes en plantilla, etc.). */
label[hidden] {
  display: none;
}

label span {
  color: var(--muted);
  font-size: 0.78rem;
  font-weight: 800;
  text-transform: uppercase;
}

.toggle-field {
  display: flex;
  gap: 8px;
  align-items: center;
}

.toggle-field input {
  width: auto;
  min-height: auto;
}

.shared-fields {
  display: grid;
  grid-column: 1 / -1;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 8px;
}

.shared-fields[hidden] {
  display: none;
}

input,
select,
textarea {
  width: 100%;
  min-height: 46px;
  padding: 10px 12px;
  color: var(--text);
  background: #fbfcfd;
  border: 1px solid var(--line);
  border-radius: 6px;
}

textarea {
  min-height: 74px;
  resize: vertical;
}

input:focus,
select:focus,
textarea:focus,
button:focus-visible {
  outline: 3px solid rgba(15, 118, 110, 0.22);
  outline-offset: 2px;
}

.primary-action {
  min-height: 48px;
  padding: 0 18px;
  color: #ffffff;
  background: var(--teal);
  border: 0;
  border-radius: 6px;
  font-weight: 800;
}

.primary-action:hover {
  background: var(--teal-hover);
}

.date-trigger {
  width: 100%;
  min-height: 46px;
  padding: 10px 12px;
  color: var(--text);
  background: #fbfcfd;
  border: 1px solid var(--line);
  border-radius: 6px;
  text-align: left;
}

.date-picker {
  position: fixed;
  z-index: 50;
  width: min(300px, calc(100vw - 28px));
  padding: 10px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 8px;
  box-shadow: var(--shadow);
}

.date-picker[hidden] {
  display: none;
}

.date-picker-header {
  display: grid;
  grid-template-columns: 34px 1fr 34px;
  gap: 8px;
  align-items: center;
  margin-bottom: 8px;
}

.date-picker-header strong {
  font-size: 0.92rem;
  text-align: center;
  text-transform: capitalize;
}

.icon-button {
  display: grid;
  width: 34px;
  height: 34px;
  place-items: center;
  color: var(--text);
  background: #fbfcfd;
  border: 1px solid var(--line);
  border-radius: 6px;
  font-size: 1.2rem;
  font-weight: 900;
  line-height: 1;
}

.date-weekdays,
.date-grid {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 4px;
}

.date-weekdays {
  margin-bottom: 4px;
}

.date-weekdays span {
  display: grid;
  height: 24px;
  place-items: center;
  color: var(--muted);
  font-size: 0.72rem;
  font-weight: 900;
}

.date-spacer,
.date-day {
  width: 100%;
  aspect-ratio: 1;
}

.date-day {
  color: var(--text);
  background: #fbfcfd;
  border: 1px solid transparent;
  border-radius: 6px;
  font-size: 0.86rem;
  font-weight: 700;
}

.date-day:hover {
  border-color: var(--line);
}

.date-day.is-today {
  border-color: var(--teal);
}

.date-day.is-selected {
  color: #ffffff;
  background: var(--nav);
}

.movement-list,
.config-list {
  display: grid;
  margin-top: 14px;
}

.movement-list {
  gap: 8px;
}

.date-group {
  display: none;
}

.config-list {
  overflow: hidden;
  gap: 0;
  border: 1px solid var(--line);
  border-radius: 8px;
}

.movement-card,
.config-item {
  background: #fbfcfd;
  border: 1px solid var(--line);
  border-radius: 8px;
}

.movement-card {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto 34px;
  gap: 10px;
  align-items: start;
  padding: 12px;
}

.movement-card.is-compact {
  grid-template-columns: minmax(0, 1fr) auto;
}

.movement-card h3 {
  margin-bottom: 5px;
  font-size: 1rem;
}

.movement-note {
  margin-bottom: 0;
  color: var(--muted);
  font-size: 0.9rem;
  line-height: 1.45;
}

.tag {
  display: inline-flex;
  min-height: 24px;
  align-items: center;
  width: fit-content;
  padding: 0 9px;
  border-radius: 999px;
  font-size: 0.76rem;
  font-weight: 800;
}

.movement-main .tag {
  margin-bottom: 8px;
}

.movement-side {
  display: grid;
  gap: 4px;
  align-content: start;
  justify-items: end;
}

.amount {
  font-size: 1rem;
}

.amount.expense {
  color: var(--red);
}

.amount.income {
  color: var(--green);
}

.date {
  color: var(--muted);
  font-size: 0.82rem;
}

.movement-meta {
  display: grid;
  grid-column: 1 / -1;
  grid-template-columns: 1fr;
  gap: 8px;
  margin: 0;
}

.movement-meta div {
  display: flex;
  gap: 8px;
  justify-content: space-between;
  padding-top: 8px;
  border-top: 1px solid var(--line);
}

dt,
dd {
  margin: 0;
  font-size: 0.82rem;
}

dt {
  color: var(--muted);
  font-weight: 800;
}

.delete-action {
  display: grid;
  width: 34px;
  min-width: 34px;
  height: 34px;
  min-height: 34px;
  place-items: center;
  color: var(--red);
  background: transparent;
  border: 1px solid #f0b7b7;
  border-radius: 6px;
  font-size: 1rem;
  font-weight: 800;
  line-height: 1;
}

.empty-state {
  padding: 24px;
  color: var(--muted);
  text-align: center;
  border: 1px dashed var(--line);
  border-radius: 8px;
}

/* Empty-state variant for hints que solo necesitan una línea horizontal,
   no un panel cuadrado que se coma altura. Mismas dashed-borders pero
   con padding y tipografía calibrados para leerse como un aviso, no
   como un placeholder de tarjeta. */
.empty-state--inline {
  padding: 12px 14px;
  font-size: 0.88rem;
  text-align: left;
  margin: 0;
}

.callout-panel {
  border-left: 3px solid var(--teal);
  background: linear-gradient(180deg, rgba(15, 118, 110, 0.045), var(--surface) 60%);
}

details.callout-panel {
  padding: 0;
  overflow: hidden;
}

details.callout-panel > summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 14px 16px;
  font-size: 1.05rem;
  font-weight: 700;
  color: var(--text);
  cursor: pointer;
  list-style: none;
  user-select: none;
}

details.callout-panel > summary::-webkit-details-marker {
  display: none;
}

details.callout-panel > summary:hover {
  background: rgba(15, 118, 110, 0.04);
}

details.callout-panel .callout-chevron {
  width: 18px;
  height: 18px;
  flex-shrink: 0;
  color: var(--muted);
  transition: transform 0.18s ease;
}

details.callout-panel[open] .callout-chevron {
  transform: rotate(180deg);
}

details.callout-panel .callout-body {
  padding: 0 16px 16px;
}

.callout-panel h2 {
  margin: 0 0 12px;
  font-size: 1.05rem;
  color: var(--text);
}

.callout-panel p {
  margin: 0 0 10px;
  font-size: 0.95rem;
  line-height: 1.55;
  color: var(--muted);
}

.callout-panel p:last-child {
  margin-bottom: 0;
}

.callout-panel strong {
  color: var(--text);
}

.callout-panel .callout-example {
  padding: 10px 12px;
  background: rgba(15, 118, 110, 0.07);
  border-radius: 6px;
  font-size: 0.93rem;
  color: var(--text);
}

.callout-panel .callout-example strong {
  color: var(--teal);
}

.callout-panel .callout-hint {
  font-size: 0.88rem;
  font-style: italic;
}

.info-button {
  position: relative;
  display: inline-grid;
  place-items: center;
  width: 20px;
  height: 20px;
  margin-left: 8px;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: 50%;
  background: var(--surface);
  color: var(--muted);
  font-family: Georgia, "Times New Roman", serif;
  font-size: 0.78rem;
  font-weight: 700;
  font-style: italic;
  vertical-align: middle;
  cursor: help;
}

.info-button:hover,
.info-button:focus-visible {
  color: var(--teal);
  border-color: var(--teal);
}

.info-tooltip {
  position: absolute;
  z-index: 30;
  top: calc(100% + 8px);
  left: 50%;
  width: min(280px, 78vw);
  padding: 10px 12px;
  background: #1a242b;
  color: #ffffff;
  border-radius: 6px;
  font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  font-size: 0.82rem;
  font-weight: 400;
  font-style: normal;
  line-height: 1.5;
  text-align: left;
  white-space: normal;
  pointer-events: none;
  opacity: 0;
  transform: translate(-50%, -4px);
  transition: opacity 0.15s ease, transform 0.15s ease;
  box-shadow: var(--shadow);
}

.info-button:hover .info-tooltip,
.info-button:focus-visible .info-tooltip,
.info-button[aria-expanded="true"] .info-tooltip {
  opacity: 1;
  transform: translate(-50%, 0);
  pointer-events: auto;
}

.feedback-status {
  margin: 4px 0 0;
  font-size: 0.88rem;
  color: var(--muted);
}

.feedback-status[data-state="success"] {
  color: var(--green);
}

.feedback-status[data-state="error"] {
  color: var(--red);
}

.feedback-status[data-state="loading"] {
  color: var(--teal);
}

.roadmap-list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: grid;
  gap: 12px;
}

.roadmap-list li {
  display: grid;
  gap: 4px;
  padding: 14px 16px;
  background: var(--surface-soft);
  border: 1px solid var(--line);
  border-radius: 8px;
}

.roadmap-list li strong {
  font-size: 0.98rem;
  color: var(--text);
}

.roadmap-list li span {
  font-size: 0.9rem;
  line-height: 1.5;
  color: var(--muted);
}

a.primary-action {
  display: inline-grid;
  place-items: center;
  text-decoration: none;
}

.config-item {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(110px, 0.8fr) 42px 34px;
  gap: 8px;
  align-items: center;
  min-height: 42px;
  padding: 7px 10px;
  border: 0;
  border-bottom: 1px solid var(--line);
  border-radius: 0;
}

.config-item:last-child {
  border-bottom: 0;
}

.config-item strong {
  overflow: hidden;
  font-size: 0.92rem;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.config-item input,
.config-item select {
  min-height: 32px;
  padding: 5px 8px;
  background: #ffffff;
  font-size: 0.9rem;
}

.config-item .tag {
  justify-self: start;
  margin: 0;
}

.category-list .config-item {
  grid-template-columns: minmax(0, 1fr) 34px 42px;
}

#contacts-list .config-item {
  grid-template-columns: minmax(0, 1.1fr) minmax(0, 1.3fr) auto 42px 34px;
}

.contact-invite-button {
  min-height: 32px;
  padding: 0 12px;
  font-size: 0.84rem;
  white-space: nowrap;
}

.contact-invite-button.is-linked {
  color: var(--green);
  border-color: rgba(24, 121, 78, 0.3);
  background: rgba(24, 121, 78, 0.06);
}

.contact-invite-button.is-linked:hover {
  /* No hover change when already linked — read-only state. */
  color: var(--green);
  border-color: rgba(24, 121, 78, 0.3);
  background: rgba(24, 121, 78, 0.06);
}

/* ==== Invitation modal (recibe el invitado al primer login) ==== */
.invitation-list {
  list-style: none;
  margin: 8px 0 0;
  padding: 0;
  display: grid;
  gap: 8px;
}

.invitation-item {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 12px;
  background: var(--surface-soft);
  border: 1px solid var(--line);
  border-radius: 8px;
}

.invitation-item-text {
  display: grid;
  gap: 2px;
  flex: 1 1 auto;
  min-width: 0;
}

.invitation-item-text strong {
  font-size: 0.95rem;
}

.invitation-item-text small {
  color: var(--muted);
  font-size: 0.8rem;
}

.invitation-item .primary-action {
  flex: 0 0 auto;
  min-height: 36px;
  padding: 0 14px;
}

.invitation-feedback {
  margin: 12px 0 0;
  font-size: 0.88rem;
  color: var(--muted);
  min-height: 18px;
}

.invitation-feedback[data-state="error"] {
  color: var(--red);
}

.invitation-feedback[data-state="success"] {
  color: var(--green);
}

/* ==== History modal (registro de cambios por gasto compartido) ==== */
.history-list {
  display: grid;
  gap: 8px;
  margin-top: 12px;
}

.history-item {
  padding: 10px 12px;
  background: var(--surface-soft);
  border: 1px solid var(--line);
  border-radius: 8px;
}

.history-meta {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 4px;
  flex-wrap: wrap;
}

.history-meta strong {
  font-size: 0.92rem;
}

.history-meta small {
  color: var(--muted);
  font-size: 0.8rem;
  white-space: nowrap;
}

.history-summary {
  margin: 0;
  color: var(--text);
  font-size: 0.9rem;
  line-height: 1.4;
}

.history-comment {
  margin: 6px 0 0;
  padding: 6px 10px;
  border-left: 2px solid var(--teal);
  color: var(--muted);
  font-size: 0.88rem;
  font-style: italic;
  line-height: 1.4;
}

/* Per-row history button (small clock icon) */
.shared-entry-history {
  display: grid;
  place-items: center;
  width: 26px;
  min-width: 26px;
  height: 26px;
  min-height: 26px;
  padding: 0;
  background: transparent;
  border: 1px solid var(--line);
  border-radius: 6px;
  color: var(--muted);
  cursor: pointer;
}

.shared-entry-history:hover {
  color: var(--text);
  border-color: #b8c5cb;
}

/* Comment input shown only while editing a shared entry */
.edit-comment-field[hidden] {
  display: none;
}

.edit-comment-field input {
  font-size: 0.92rem;
}

.label-hint {
  color: var(--muted);
  font-weight: 700;
  text-transform: none;
  letter-spacing: 0;
}

.swatch {
  justify-self: end;
  width: 24px;
  height: 24px;
  border: 1px solid var(--line);
  border-radius: 999px;
}

.config-toolbar {
  grid-template-columns: 1fr 1fr;
  margin-top: 12px;
}

.settings-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  max-width: 860px;
  margin: 0 auto 8px;
}

.period-toolbar {
  display: grid;
  grid-template-columns: 34px 1fr 34px;
  gap: 8px;
  align-items: center;
  max-width: 360px;
  margin: 0 auto 10px;
}

.period-toolbar strong {
  text-align: center;
  text-transform: capitalize;
}

.compact-summary {
  margin-bottom: 10px;
}

.analysis-grid {
  display: grid;
  gap: 10px;
}

.breakdown-list {
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: 8px;
}

.breakdown-header,
.breakdown-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 56px 60px 110px;
  gap: 8px;
  align-items: center;
  padding: 5px 10px;
}

.breakdown-header {
  min-height: 28px;
  background: #eef2f4;
  border-bottom: 1px solid var(--line);
  color: var(--muted);
  font-size: 0.76rem;
  font-weight: 900;
  text-transform: uppercase;
}

.breakdown-header-cell {
  margin: 0;
  padding: 0;
  background: transparent;
  border: 0;
  color: inherit;
  font: inherit;
  text-align: left;
  text-transform: inherit;
  cursor: pointer;
  user-select: none;
  white-space: nowrap;
}

.breakdown-header-cell:not(:first-child) {
  justify-self: end;
  text-align: right;
}

.breakdown-header-cell:hover {
  color: var(--text);
}

.breakdown-header-cell.is-active {
  color: var(--nav);
}

.breakdown-row {
  min-height: 32px;
  background: #fbfcfd;
  border-bottom: 1px solid var(--line);
}

.breakdown-row:last-child {
  border-bottom: 0;
}

.breakdown-row strong {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.breakdown-row span {
  justify-self: end;
}

.balance-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  gap: 10px;
}

.balance-card {
  display: grid;
  gap: 8px;
  padding: 12px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-left: 4px solid var(--line);
  border-radius: 8px;
  text-align: left;
}

.balance-header {
  display: flex;
  gap: 10px;
  align-items: baseline;
  justify-content: space-between;
  min-width: 0;
}

.balance-header .balance-amount {
  flex: 0 0 auto;
  white-space: nowrap;
}

.balance-header strong {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.balance-actions {
  display: grid;
  gap: 6px;
  margin-top: 4px;
}

.balance-action {
  display: grid;
  gap: 2px;
  padding: 8px 10px;
  background: #fbfcfd;
  border: 1px solid var(--line);
  border-radius: 6px;
  text-align: left;
}

.balance-action strong {
  font-size: 0.85rem;
  font-weight: 800;
}

.balance-action small {
  color: var(--muted);
  font-size: 0.72rem;
  line-height: 1.25;
}

.balance-action.ghost {
  color: var(--muted);
  text-align: center;
  font-size: 0.78rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.balance-action.settle {
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: 6px;
  color: #ffffff;
  background: var(--nav);
  border-color: var(--nav);
}

.balance-action.settle small {
  color: rgba(255, 255, 255, 0.78);
}

.balance-action[disabled] {
  opacity: 0.45;
  cursor: not-allowed;
}

.balance-card.is-positive {
  border-left-color: var(--green);
}

.balance-card.is-negative {
  border-left-color: var(--red);
}

.balance-card.is-zero {
  opacity: 0.7;
}

.balance-card strong {
  font-size: 0.95rem;
}

.balance-hint {
  color: var(--muted);
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.balance-amount {
  font-size: 1.2rem;
  font-weight: 800;
}

/* Resumen tappable de saldos en móvil cuando el filtro está en "Todos".
   Cada fila muestra nombre + dirección (te debe / le debes / saldado) +
   importe. Al tocar, el card detallado de ese contacto reemplaza el
   resumen y los movimientos compartidos abajo se filtran a su entrada. */
.balance-summary {
  display: grid;
  gap: 8px;
}

.balance-summary-title {
  margin: 0 0 4px;
  color: var(--muted);
  font-size: 0.82rem;
}

.balance-summary-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 6px;
}

.balance-summary-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto;
  gap: 10px;
  align-items: center;
  padding: 10px 12px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-left: 3px solid var(--line);
  border-radius: 8px;
  cursor: pointer;
  -webkit-tap-highlight-color: rgba(15, 118, 110, 0.08);
}

.balance-summary-row:hover {
  border-color: #b8c5cb;
}

.balance-summary-row.is-positive {
  border-left-color: var(--green);
}

.balance-summary-row.is-negative {
  border-left-color: var(--red);
}

.balance-summary-row.is-zero {
  opacity: 0.7;
}

.balance-summary-name {
  font-size: 0.95rem;
  font-weight: 700;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
}

.balance-summary-direction {
  color: var(--muted);
  font-size: 0.74rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  white-space: nowrap;
}

.balance-summary-amount {
  font-size: 0.98rem;
  font-weight: 800;
  white-space: nowrap;
}

.balance-summary-row.is-positive .balance-summary-amount {
  color: var(--green);
}

.balance-summary-row.is-negative .balance-summary-amount {
  color: var(--red);
}

.balance-card.is-positive .balance-amount {
  color: var(--green);
}

.balance-card.is-negative .balance-amount {
  color: var(--red);
}

/* Mobile-only contact picker en la cabecera del panel Saldos — no se ve
   en desktop. Su valor está sincronizado con el dropdown de la sección
   "Movimientos compartidos" para que ambos viewports compartan estado. */
.shared-mobile-picker-row {
  display: none;
}

.shared-mobile-picker {
  display: none;
}

@media (max-width: 719px) {
  .shared-mobile-picker-row {
    display: flex;
    align-items: stretch;
    gap: 8px;
    margin-bottom: 14px;
  }

  .shared-mobile-picker {
    display: grid;
    gap: 4px;
    flex: 1 1 auto;
    min-width: 0;
    margin-bottom: 0;
  }

  /* Override del atributo hidden — sin estos, los display:flex/grid
     y display:inline-flex de arriba pisaban a [hidden]. */
  .shared-mobile-picker-row[hidden],
  .shared-mobile-picker[hidden],
  .shared-mobile-back[hidden] {
    display: none !important;
  }

  /* Atajo "Volver a Todos": aparece a la izquierda del dropdown solo
     cuando hay un filtro activo. Botón cuadrado con chevron y texto
     corto para que se entienda de un vistazo. */
  .shared-mobile-back {
    flex: 0 0 auto;
    align-self: end;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    height: 46px;
    padding: 0 12px;
    background: #fbfcfd;
    border: 1px solid var(--line);
    border-radius: 6px;
    color: var(--nav);
    font-size: 0.82rem;
    font-weight: 700;
    cursor: pointer;
    -webkit-tap-highlight-color: rgba(15, 118, 110, 0.08);
  }

  .shared-mobile-back svg {
    width: 14px;
    height: 14px;
    flex: 0 0 auto;
  }

  /* Resumen de saldos en móvil: dos columnas con una fila por card
     (nombre + cantidad lado a lado). El "TE DEBE / LE DEBES" se
     omite — el color del borde izquierdo (verde/rojo) ya da la
     dirección. La leyenda arriba del listado explica el código. */
  .balance-summary-list {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 8px;
  }

  .balance-summary-row {
    grid-template-columns: minmax(0, 1fr) auto;
    gap: 8px;
    padding: 10px 12px;
  }

  .balance-summary-direction {
    /* Texto redundante con el color: lo escondemos visualmente pero
       lo mantenemos en el DOM para lectores de pantalla. */
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
  }

  /* En pantallas muy estrechas (<360px) volvemos a 1 columna para
     que el nombre + cantidad respiren. */
  @media (max-width: 359px) {
    .balance-summary-list {
      grid-template-columns: 1fr;
    }
  }
}

/* Cabecera del resumen de saldos (móvil): título a la izquierda +
   leyenda en chip a la derecha. Si no caben, wrap a 2 líneas. */
.balance-summary-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 6px 10px;
  margin-bottom: 8px;
}

.balance-summary-header .balance-summary-title {
  margin: 0;
  flex: 1 1 auto;
  min-width: 0;
}

/* Leyenda como chip: caja sutil con fondo grisáceo, dos items
   (verde "te debe" + rojo "le debes") con punto de color al lado. */
.balance-summary-legend {
  display: inline-flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 4px 10px;
  margin: 0;
  padding: 4px 10px;
  background: #fbfcfd;
  border: 1px solid var(--line);
  border-radius: 999px;
  color: var(--muted);
  font-size: 0.74rem;
  line-height: 1.4;
  white-space: nowrap;
}

.balance-summary-legend-item {
  display: inline-flex;
  align-items: center;
  gap: 4px;
}

.balance-summary-legend-dot {
  display: inline-block;
  width: 9px;
  height: 9px;
  border-radius: 50%;
}

.balance-summary-legend-dot.is-positive {
  background: var(--green);
}

.balance-summary-legend-dot.is-negative {
  background: var(--red);
}

/* Variante desktop de la leyenda: vive como hijo del .balance-grid
   y ocupa toda la fila (las cards están en auto-fill repeat). */
.balance-summary-legend--desktop {
  grid-column: 1 / -1;
  justify-self: start;
  margin: 0 0 4px;
}

.shared-toolbar {
  display: flex;
  gap: 12px;
  align-items: flex-end;
  flex-wrap: wrap;
  margin: 6px 0 10px;
}

.shared-toolbar label {
  flex: 0 0 220px;
}

.shared-entries {
  display: grid;
  gap: 6px;
}

.shared-entry {
  display: grid;
  /* date | main | amount | (settle) | (history) | (edit) | (delete) —
     up to 7 cols. Trailing "auto" tracks collapse to 0 when the button
     isn't rendered. */
  grid-template-columns: 82px minmax(0, 1fr) repeat(5, auto);
  gap: 10px;
  align-items: center;
  padding: 8px 10px;
  background: #fbfcfd;
  border: 1px solid var(--line);
  border-radius: 8px;
}

.shared-entry[data-type="payment"] {
  background: #eef5fb;
  border-color: #cfdfeb;
}

.shared-entry-date {
  color: var(--muted);
  font-size: 0.82rem;
}

.shared-entry-main {
  display: grid;
  gap: 2px;
  min-width: 0;
}

.shared-entry-main strong {
  font-size: 0.92rem;
  white-space: normal;
}

.shared-entry-note,
.shared-entry-breakdown {
  color: var(--muted);
  font-size: 0.78rem;
}

.shared-entry-amount {
  font-size: 0.95rem;
  font-weight: 800;
  white-space: nowrap;
}

.shared-entry-amount.income {
  color: var(--green);
}

.shared-entry-amount.expense {
  color: var(--red);
}

/* Settled rows: dim the whole row + strike the amount, so the user
   sees them in the list as historical / closed but the entry itself
   stays accessible (concept, breakdown, etc. remain readable). */
.shared-entry.is-settled {
  opacity: 0.55;
}

.shared-entry.is-settled .shared-entry-amount {
  text-decoration: line-through;
  text-decoration-thickness: 1.5px;
}

.shared-entry-settled-tag {
  display: inline-flex;
  align-items: center;
  margin-top: 2px;
  padding: 1px 7px;
  background: rgba(24, 121, 78, 0.12);
  color: var(--green);
  border-radius: 999px;
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.02em;
  text-transform: uppercase;
}

.shared-entry-settled-tag::before {
  content: "✓";
  margin-right: 3px;
  font-weight: 900;
}

.shared-entry-settle {
  min-height: 30px;
  padding: 0 10px;
  font-size: 0.82rem;
  white-space: nowrap;
}

.shared-entry.is-partner {
  /* A subtle accent on the left edge tells the user this row originated
     in their partner's account (read-only edits in v1). */
  border-left: 3px solid rgba(124, 58, 237, 0.4);
}

.month-group {
  margin-top: 12px;
  padding: 6px 4px 4px;
  color: var(--muted);
  font-size: 0.78rem;
  font-weight: 800;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  border-bottom: 1px solid var(--line);
}

.month-group:first-child {
  margin-top: 0;
}

.shared-contact-control {
  display: flex;
  gap: 6px;
  align-items: stretch;
}

.shared-contact-control select {
  flex: 1 1 auto;
}

.shared-contact-control .icon-button {
  width: 36px;
  min-width: 36px;
  height: auto;
  align-self: stretch;
}

.shared-contact-field,
.shared-mode-field {
  grid-column: 1 / -1;
}

.shared-uneven {
  display: grid;
  grid-column: 1 / -1;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 8px;
}

.shared-uneven[hidden] {
  display: none;
}

.shared-uneven-feedback {
  grid-column: 1 / -1;
  margin: 0;
  padding: 6px 8px;
  background: #fbfcfd;
  border: 1px solid var(--line);
  border-radius: 6px;
  color: var(--muted);
  font-size: 0.82rem;
}

.shared-uneven-feedback[data-state="ok"] {
  color: var(--green);
  border-color: var(--green);
  background: #ebf5ec;
}

.shared-uneven-feedback[data-state="warn"] {
  color: var(--red);
  border-color: var(--red);
  background: #fbecec;
}

.settings-tab {
  min-height: 30px;
  padding: 0 10px;
  color: var(--muted);
  background: #fbfcfd;
  border: 1px solid var(--line);
  border-radius: 6px;
  font-size: 0.82rem;
  font-weight: 800;
}

.settings-tab.is-active {
  color: #ffffff;
  background: var(--nav);
  border-color: var(--nav);
}

.settings-panel {
  display: none;
}

.settings-panel.is-active {
  display: block;
}

.import-preview {
  white-space: pre-line;
  text-align: left;
}

.save-action {
  display: grid;
  width: 42px;
  min-width: 42px;
  height: 32px;
  min-height: 32px;
  place-items: center;
  color: #ffffff;
  background: var(--teal);
  border: 0;
  border-radius: 6px;
  font-size: 0.72rem;
  font-weight: 900;
  line-height: 1;
}

.config-group {
  margin: 0;
  padding: 8px 10px;
  color: var(--muted);
  background: #eef2f4;
  border-bottom: 1px solid var(--line);
  font-size: 0.78rem;
  font-weight: 900;
  text-transform: uppercase;
}

@media (min-width: 720px) {
  .summary {
    grid-template-columns: repeat(3, 1fr);
  }

  .module-grid {
    /* Desktop: 5 tiles en una sola fila. Cada tile usa aspect-ratio
       3/4 (definido en .module-card del bloque anterior), así que la
       altura sigue al ancho automáticamente. */
    grid-template-columns: repeat(5, minmax(0, 1fr));
  }

  .analysis-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .movement-form {
    grid-template-columns: repeat(4, 1fr);
  }

  .field-wide {
    grid-column: span 3;
  }

  /* Modal de "Nuevo movimiento" en escritorio: el resto de forms con
     clase .movement-form (recurring, payment) mantiene la rejilla de
     4 columnas; aquí pasamos #movement-form a 2 columnas con jerarquía
     vertical (Concepto+Fecha → Importe+Recurrencia → Emisor → Nota).
     Los botones Gasto/Ingreso se hacen visibles también en PC para
     que el toggle sea más obvio que el select hidden. */

  /* Modal-dialog del movimiento: ~30% más estrecho que el default de
     940px para que no se vea desplomado en escritorios anchos.
     Otros modales (plantilla periódica, pago, grupo) mantienen su
     ancho. */
  #movement-modal .modal-dialog {
    max-width: 660px;
  }

  #movement-form {
    grid-template-columns: repeat(2, 1fr);
  }

  #movement-form > * {
    grid-column: 1 / -1;
  }

  #movement-form .type-toggle {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 8px;
    order: 1;
  }

  /* Botones G/I en PC: presentes pero discretos (más bajos, menos
     padding, borde fino). En móvil siguen con su tamaño grande. */
  #movement-form .type-toggle-button {
    min-height: 40px;
    padding: 6px 10px;
    font-size: 0.92rem;
    border-width: 1px;
    border-radius: 8px;
  }

  /* Ocultar el select Tipo legacy en PC también — el toggle visual lo
     reemplaza igual que en móvil. */
  #movement-form > .type-select-field { display: none; }

  #movement-form > label:nth-of-type(4) { order: 2; grid-column: span 1; } /* Concepto */
  #movement-form > label:nth-of-type(2) { order: 3; grid-column: span 1; } /* Fecha */
  #movement-form > label:nth-of-type(3) { order: 4; grid-column: span 1; } /* Importe */
  #movement-form > label:nth-of-type(6) { order: 5; grid-column: span 1; } /* Recurrencia */
  #movement-form > label:nth-of-type(5) { order: 6; grid-column: 1 / -1; } /* Emisor */
  #movement-form > label.field-wide     { order: 7; grid-column: 1 / -1; } /* Nota */
  #movement-form > label.toggle-field   { order: 8; grid-column: 1 / -1; }
  #movement-form > #shared-fields       { order: 9; grid-column: 1 / -1; }
  #movement-form > #edit-comment-field  { order: 10; grid-column: 1 / -1; }
  #movement-form > #convert-to-recurring{ order: 11; grid-column: 1 / -1; }
  #movement-form > button[type="submit"]{ order: 12; grid-column: 1 / -1; }

  /* Nota: más alta verticalmente. El ancho lo dicta el grid (full
     ancho del modal) para que se alinee con los pares de arriba. */
  #movement-form #note {
    min-height: 110px;
  }

  /* Bloque rosa de "Compartido con grupo": Pagador y Reparto pasan a
     2 columnas en PC; el grid de partes y el feedback se quedan en
     fila propia full ancho debajo. */
  #movement-form .shared-group-fields {
    grid-template-columns: 1fr 1fr;
  }
  #movement-form .shared-group-fields > #shared-group-shares,
  #movement-form .shared-group-fields > .shared-uneven-feedback {
    grid-column: 1 / -1;
  }

  .primary-action {
    align-self: end;
  }

  .filters {
    grid-template-columns: 2fr 1fr 1fr;
  }

  .settings-form {
    grid-template-columns: 1.2fr 1fr auto;
    align-items: end;
  }

  /* Form de feedback: el textarea de Mensaje es alto y el input
     de Asunto es de una sola línea — con align-items: end heredado,
     Asunto se hundía al fondo dejando aire encima. Lo subimos a
     start para los inputs y dejamos solo el botón submit alineado
     al fondo (queda al lado de la base del textarea). */
  #feedback-form {
    align-items: start;
  }
  #feedback-form > button[type="submit"] {
    align-self: end;
  }

  .config-toolbar {
    grid-template-columns: 180px 180px;
  }

  .movement-card {
    grid-template-columns: minmax(230px, 1.25fr) minmax(110px, 0.55fr) minmax(230px, 1fr) 34px;
    align-items: center;
  }

  .movement-card.is-compact {
    grid-template-columns: minmax(230px, 1.25fr) minmax(110px, 0.55fr) minmax(230px, 1fr);
  }

  .movement-meta {
    grid-column: auto;
  }

  .movement-meta div {
    padding-top: 0;
    border-top: 0;
  }

  .delete-action {
    grid-column: auto;
  }

  .config-item {
    grid-template-columns: minmax(0, 1fr) 170px 42px 34px;
  }

  .category-list .config-item {
    grid-template-columns: minmax(0, 1fr) 34px 42px;
  }
}

@media (min-width: 980px) {
  .shell {
    display: grid;
    grid-template-columns: 76px 1fr;
  }

  .sidebar {
    position: sticky;
    top: 0;
    right: auto;
    bottom: auto;
    left: auto;
    display: flex;
    flex-direction: column;
    height: 100vh;
    padding: 18px 12px;
    background: var(--surface);
    border-top: 0;
    border-right: 1px solid var(--line);
  }

  .brand {
    display: grid;
    place-items: center;
    margin-bottom: 22px;
  }

  .brand-mark {
    display: grid;
    width: 42px;
    height: 42px;
    place-items: center;
    color: #ffffff;
    background: var(--nav);
    border-radius: 8px;
    font-weight: 900;
  }

  .brand div {
    display: none;
  }

  .nav {
    display: grid;
    gap: 10px;
    justify-items: center;
  }

  .nav-separator {
    display: block;
    width: 24px;
    height: 1px;
    background: var(--line);
    margin: 2px 0;
  }

  .nav-button {
    width: 44px;
    padding: 0;
  }

  .nav-button::after {
    top: 50%;
    bottom: auto;
    left: calc(100% + 10px);
    transform: translateY(-50%) translateX(-3px);
  }

  .nav-button:hover::after,
  .nav-button:focus-visible::after {
    transform: translateY(-50%) translateX(0);
  }

  .app {
    margin: 0;
    padding: 28px 28px 48px;
  }

  h1 {
    font-size: 2.6rem;
  }
}

/* Dense mode: FlowGrid prioritizes visible data over spacious cards. */
.sidebar {
  padding: 6px;
}

.nav-button {
  min-height: 34px;
}

.nav-icon {
  width: 16px;
  height: 16px;
}

.app {
  /* Bottom space large enough to clear the fixed mobile sidebar (nav row +
     session-footer row with the email/logout) so the last list item can
     be scrolled fully into view. Desktop overrides this further down. */
  padding: 12px 20px 140px;
}

.topbar {
  margin-bottom: 10px;
}

h1 {
  font-size: 1.65rem;
}

.summary {
  gap: 6px;
  margin-bottom: 8px;
}

.metric {
  min-height: 52px;
  padding: 10px;
}

.panel {
  padding: 10px;
  margin-top: 8px;
}

.section-heading {
  min-height: 22px;
  margin-bottom: 8px;
}

.movement-form,
.filters,
.settings-form,
.config-toolbar {
  gap: 8px;
}

label {
  gap: 4px;
}

input,
select,
textarea,
.date-trigger {
  min-height: 34px;
  padding: 6px 8px;
}

textarea {
  min-height: 52px;
}

.primary-action {
  min-height: 36px;
  padding: 0 12px;
}

.module-card {
  padding: 10px;
}

.movement-list {
  gap: 0;
  overflow-x: auto;
  border: 1px solid var(--line);
  border-radius: 8px;
}

.movement-header,
.movement-card {
  display: grid;
  grid-template-columns: 78px minmax(100px, 1fr) 84px minmax(120px, 1.3fr) minmax(100px, 0.9fr) minmax(80px, 96px) 76px minmax(70px, 0.6fr) 28px 28px 28px;
  gap: 6px;
  align-items: center;
}

.movement-actions {
  display: contents;
}

.movement-header {
  min-height: 28px;
  padding: 5px 8px;
  color: var(--muted);
  background: #eef2f4;
  border-bottom: 1px solid var(--line);
  font-size: 0.76rem;
  font-weight: 900;
  text-transform: uppercase;
}

.movement-header-cell {
  margin: 0;
  padding: 0;
  color: inherit;
  background: transparent;
  border: 0;
  font: inherit;
  text-align: left;
  text-transform: inherit;
  cursor: pointer;
  user-select: none;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.movement-header-cell:hover {
  color: var(--text);
}

.movement-header-cell.is-active {
  color: var(--nav);
}

.movement-header-cell-static {
  cursor: default;
}

.movement-card {
  min-height: 34px;
  padding: 5px 8px;
  border: 0;
  border-bottom: 1px solid var(--line);
  border-radius: 0;
  box-shadow: none;
}

.movement-card:last-child {
  border-bottom: 0;
}

.movement-card.is-compact {
  grid-template-columns: 82px minmax(120px, 1fr) 92px minmax(160px, 1.4fr) minmax(130px, 1fr) 112px 88px;
}

.movement-main,
.movement-side,
.movement-meta,
.movement-meta div {
  display: contents;
}

.movement-card h3 {
  order: 2;
  margin: 0;
  overflow: hidden;
  font-size: 0.95rem;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.movement-note {
  order: 4;
  margin: 0;
  overflow: hidden;
  font-size: 0.84rem;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.movement-main .tag {
  order: 6;
  margin: 0;
}

.tag {
  min-height: 18px;
  padding: 0 6px;
}

.amount {
  order: 3;
  justify-self: end;
  font-size: 0.95rem;
}

.date,
dd {
  overflow: hidden;
  font-size: 0.82rem;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.date {
  order: 1;
}

.party {
  order: 5;
}

.recurrence {
  order: 7;
}

.shared-cell {
  order: 8;
  overflow: hidden;
  color: var(--muted);
  text-overflow: ellipsis;
  white-space: nowrap;
}

.edit-action,
.duplicate-action {
  display: grid;
  place-items: center;
  width: 26px;
  min-width: 26px;
  height: 26px;
  min-height: 26px;
  padding: 0;
  color: var(--nav);
  background: transparent;
  border: 1px solid var(--line);
  border-radius: 6px;
  line-height: 1;
}

.action-icon {
  display: block;
  width: 14px;
  height: 14px;
  fill: none;
  stroke: currentColor;
  stroke-linecap: round;
  stroke-linejoin: round;
  stroke-width: 2;
}

.edit-action {
  order: 9;
}

.duplicate-action {
  order: 10;
}

dt {
  display: none;
}

.movement-card .delete-action {
  order: 11;
  width: 26px;
  min-width: 26px;
  height: 26px;
  min-height: 26px;
}

.config-item {
  min-height: 32px;
  padding: 4px 8px;
}

.config-item input,
.config-item select {
  min-height: 26px;
  padding: 3px 6px;
}

.save-action {
  width: 34px;
  min-width: 34px;
  height: 26px;
  min-height: 26px;
}

.delete-action {
  width: 26px;
  min-width: 26px;
  height: 26px;
  min-height: 26px;
}

@media (min-width: 720px) {
  .movement-card,
  .movement-card.is-compact {
    align-items: center;
  }
}

@media (min-width: 980px) {
  .shell {
    grid-template-columns: 58px 1fr;
  }

  .sidebar {
    padding: 12px 8px;
  }

  .brand-mark {
    width: 32px;
    height: 32px;
  }

  .nav-button {
    width: 34px;
  }

  .app {
    margin: 0 auto;
    padding: 18px 18px 34px;
  }

  h1 {
    font-size: 2rem;
  }

  .topbar,
  .summary,
  .panel {
    max-width: 1040px;
    margin-right: auto;
    margin-left: auto;
  }

  #home-view .panel,
  #settings-view .panel,
  #news-view .panel {
    max-width: 860px;
  }

  #movements-view .panel[aria-labelledby="form-title"] {
    max-width: 940px;
  }

  #movements-view .panel[aria-labelledby="ledger-title"] {
    max-width: 100%;
  }
}

@media (max-width: 719px) {
  .modal {
    align-items: stretch;
    padding: 0;
  }

  .modal-dialog {
    width: 100%;
    max-height: 100vh;
    border-radius: 0;
  }

  /* Mobile-only redesign of the new-movement form: 2-column grid so
     Concepto + Recurrencia can sit side-by-side, plus reordering and
     enlarged inputs. The type-toggle CSS itself lives inline in <head>
     to survive a stale styles.css cache. */
  .movement-form {
    grid-template-columns: repeat(2, 1fr);
  }

  /* By default every direct child spans the full row; only Concepto and
     Recurrencia (which we want side-by-side) override this below. */
  .movement-form > * {
    grid-column: 1 / -1;
  }

  /* Reorden móvil del modal de movimiento: Concepto + Fecha juntos
     arriba (más jerarquía), luego Importe, y la Recurrencia baja al
     5º lugar con tipografía menor para restarle peso visual. La
     rejilla pasa a 60/40 (Concepto se lleva la columna ancha) — los
     conceptos suelen ser más largos que la fecha (DD/MM/AAAA), que
     cabe holgada en menos ancho. Solo afecta a Concepto/Fecha; los
     demás campos siguen full ancho. */
  #movement-form {
    grid-template-columns: 3fr 2fr;
  }
  #movement-form .type-toggle           { order: 1; }
  #movement-form > label:nth-of-type(4) { order: 2; grid-column: span 1; } /* Concepto */
  #movement-form > label:nth-of-type(2) { order: 3; grid-column: span 1; } /* Fecha */
  #movement-form > label:nth-of-type(3) { order: 4; } /* Importe */
  #movement-form > label:nth-of-type(6) { order: 5; } /* Recurrencia */
  #movement-form > label:nth-of-type(5) { order: 6; } /* Emisor / receptor */
  #movement-form > label.field-wide     { order: 7; } /* Nota */
  #movement-form > label.toggle-field   { order: 8; } /* Gasto compartido */
  #movement-form > #shared-fields       { order: 9; }
  #movement-form > button[type="submit"]{ order: 10; }

  #date-trigger {
    min-height: 48px;
    padding: 6px 12px;
    font-size: 1.7rem;
    font-weight: 700;
  }

  /* Importe: keep the 3.2rem typography but tighten the box so it
     doesn't look like a billboard. Right padding is wider so the €
     suffix has its own room. */
  #movement-form #amount {
    min-height: 72px;
    padding: 6px 56px 6px 14px;
    font-size: 3.2rem;
    font-weight: 800;
    text-align: center;
  }

  #movement-form .amount-suffix {
    font-size: 2.4rem;
    right: 16px;
  }

  /* Concepto: misma jerarquía que Fecha (a su lado) e Importe (debajo).
     Mantenemos la tipografía grande para que sea el "qué" del gasto. */
  #movement-form #concept {
    min-height: 48px;
    padding: 4px 10px;
    font-size: 1.7rem;
    font-weight: 700;
  }

  /* Recurrencia: secundaria. Tipografía menor (1.05rem) y caja más
     baja para que pese menos visualmente que Concepto/Fecha/Importe.
     El usuario que solo registra gastos puntuales no necesita verla
     destacada. */
  #movement-form #recurrence {
    min-height: 40px;
    padding: 4px 10px;
    font-size: 1.05rem;
    font-weight: 600;
  }

  /* Gasto compartido toggle: turn into a proper tappable strip with
     extra breathing room above the Anadir button so it can't be
     missed-tapped. */
  .movement-form .toggle-field {
    min-height: 56px;
    padding: 12px 14px;
    margin-top: 8px;
    background: #fbfcfd;
    border: 1px solid var(--line);
    border-radius: 8px;
  }

  .movement-form .toggle-field input[type="checkbox"] {
    width: 22px;
    height: 22px;
  }

  .movement-form .toggle-field span {
    font-size: 1rem;
    font-weight: 700;
    text-transform: none;
    letter-spacing: 0;
    color: var(--text);
  }

  /* Floating square submit pinned to the bottom-center of the viewport.
     Removed from grid flow via position:fixed; the form gets bottom
     padding so the last in-flow field can't hide behind it. */
  #movement-form {
    padding-bottom: 120px;
  }

  #movement-form > button[type="submit"].movement-submit {
    position: fixed;
    bottom: 24px;
    left: 50%;
    transform: translateX(-50%);
    width: 76px;
    height: 76px;
    min-height: 76px;
    margin: 0;
    padding: 0;
    border-radius: 18px;
    box-shadow: 0 12px 28px rgba(15, 118, 110, 0.32);
    z-index: 50;
  }

  .movement-submit .movement-submit-label {
    display: none;
  }

  .movement-submit .movement-submit-icon {
    display: block;
  }

  /* Title removed on mobile (the modal is unambiguous), and the heading
     row collapses to whatever the feedback line says. */
  #movement-modal #form-title {
    display: none;
  }

  #movement-modal .section-heading {
    min-height: 0;
    margin-bottom: 4px;
    padding-right: 0;
  }

  /* Close button: also fixed at the bottom, smaller than the submit,
     placed to the right of the submit with the same gap. */
  #movement-modal #close-movement-modal {
    position: fixed;
    bottom: 34px;
    left: calc(50% + 56px);
    top: auto;
    right: auto;
    width: 56px;
    height: 56px;
    min-width: 56px;
    min-height: 56px;
    padding: 0;
    border-radius: 14px;
    font-size: 1.6rem;
    font-weight: 700;
    background: rgba(255, 255, 255, 0.95);
    box-shadow: 0 8px 22px rgba(23, 32, 38, 0.14);
    z-index: 50;
  }

  .shared-fields {
    grid-template-columns: 1fr;
  }

  .shared-uneven {
    grid-template-columns: 1fr;
  }

  .shared-toolbar {
    /* Mobile: el dropdown del panel Movimientos compartidos queda oculto
       — la selección del contacto la lleva el picker que sale al inicio
       del panel Saldos (.shared-mobile-picker). Ambos están sincronizados
       vía estado, así que basta con uno visible. */
    display: none;
  }

  /* Móvil: la tarjeta de saldo del contacto se aplana a 2 filas para
     aprovechar el ancho del panel y reducir la altura. Antes era una
     pila vertical (cabecera, importe, dos botones apilados); ahora la
     cabecera + importe van en la primera fila y los dos botones
     comparten la segunda. La rejilla del panel pasa a 1 columna para
     que la card use todo el ancho disponible. */
  .balance-grid {
    grid-template-columns: 1fr;
  }

  .balance-card {
    grid-template-columns: 1fr;
    grid-template-rows: auto auto;
    grid-template-areas:
      "header"
      "actions";
    gap: 8px;
    padding: 10px 12px;
  }

  .balance-card .balance-header {
    grid-area: header;
    flex-direction: row;
    align-items: baseline;
    justify-content: space-between;
    gap: 10px;
    min-width: 0;
  }

  .balance-card .balance-header strong {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    max-width: 100%;
  }

  .balance-card .balance-header .balance-amount {
    font-size: 1.2rem;
    font-weight: 800;
    white-space: nowrap;
    flex: 0 0 auto;
  }

  .balance-card .balance-actions {
    grid-area: actions;
    /* Solo una columna porque "Ver entradas" se oculta en móvil — el
       dropdown del Saldos ya filtra los movimientos abajo, así que el
       botón sería redundante (scrollear ≠ acción). Dejamos solo
       Liquidar saldo a ancho completo. */
    grid-template-columns: 1fr;
    gap: 8px;
    margin-top: 0;
  }

  .balance-card .balance-action {
    padding: 8px 10px;
    text-align: center;
  }

  .balance-card .balance-action.ghost {
    display: none;
  }

  /* En móvil mostramos también la coletilla "(te paga)" / "(le pagas)"
     porque ahora cabe en la misma línea que "Liquidar saldo" gracias
     a haber quitado el nombre redundante. */

  .balance-card .balance-action strong {
    font-size: 0.82rem;
  }

  .shared-entry {
    /* Mobile: 5 explicit columns. Amount on row 1 spans the three
       rightmost cells so col 5's width is only what the delete X
       button needs (26px) — otherwise the amount text would widen
       col 5 to ~70px and push the delete button visually away from
       the right edge of the card. With this span, the four action
       buttons in row 3 pack flush against the right edge, with the
       1fr col 1 absorbing all slack. */
    grid-template-columns: minmax(0, 1fr) auto auto auto auto;
    grid-template-areas:
      "date    .        amount   amount   amount"
      "main    main     main     main     main"
      ".       settle   history  edit     delete";
    align-items: center;
    gap: 6px;
  }

  .shared-entry-date { grid-area: date; }

  .shared-entry-amount {
    grid-area: amount;
    justify-self: end;
  }

  .shared-entry-main { grid-area: main; }

  .shared-entry .shared-entry-settle { grid-area: settle; }
  .shared-entry .shared-entry-history { grid-area: history; }
  .shared-entry .edit-action { grid-area: edit; }
  .shared-entry .delete-action { grid-area: delete; }

  .movement-list {
    gap: 8px;
    overflow-x: visible;
    background: transparent;
    border: 0;
  }

  .movement-header {
    display: none;
  }

  .date-group {
    display: block;
    margin: 6px 2px 0;
    color: var(--muted);
    font-size: 0.78rem;
    font-weight: 800;
    letter-spacing: 0.02em;
    text-transform: uppercase;
  }

  .date-group:first-child {
    margin-top: 0;
  }

  /* Simplified mobile card. Row 1: concepto (truncado) + importe.
     Row 2: badges inline (recurrencia si !puntual + compartido si aplica).
     La row 2 colapsa cuando no hay nada que mostrar. La card entera es
     tappable y abre el modal de detalle (gestionado en JS por viewport). */
  .movement-card {
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-rows: auto auto;
    grid-template-areas:
      "concept amount"
      "meta    meta";
    /* Column-gap only — row spacing is delivered via margin-top on the
       meta row and the expanded section so a collapsed expansion doesn't
       leave a 4px ghost gap. */
    column-gap: 12px;
    row-gap: 0;
    align-items: center;
    min-width: 0;
    min-height: 0;
    padding: 10px 12px;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: 10px;
    box-shadow: var(--shadow);
    cursor: pointer;
    -webkit-tap-highlight-color: rgba(15, 118, 110, 0.08);
  }

  .movement-card:active {
    background: #fbfcfd;
  }

  /* Caso común (puntual + no compartido): segunda fila desaparece. */
  .movement-card[data-recurrence="puntual"][data-shared="false"] {
    grid-template-rows: auto;
    grid-template-areas: "concept amount";
  }

  .movement-card[data-recurrence="puntual"][data-shared="false"] .movement-meta {
    display: none;
  }

  .movement-card .movement-main {
    display: contents;
  }

  .movement-card .movement-side {
    grid-area: amount;
    display: flex;
    flex-direction: row;
    align-items: center;
    justify-content: flex-end;
  }

  .movement-card .movement-meta {
    grid-area: meta;
    display: flex;
    flex-wrap: wrap;
    gap: 6px 8px;
    align-items: center;
    margin: 4px 0 0;
    min-width: 0;
  }

  .movement-card .movement-meta div {
    display: contents;
  }

  /* Datos que solo viven en el modal de detalle en mobile. */
  .movement-card .movement-note,
  .movement-card .party,
  .movement-card .movement-actions,
  .movement-card .tag,
  .movement-card .date,
  .movement-card dt {
    display: none;
  }

  .movement-card h3 {
    grid-area: concept;
    margin: 0;
    font-size: 0.98rem;
    font-weight: 700;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    min-width: 0;
  }

  .movement-card .amount {
    margin: 0;
    font-size: 1.05rem;
    font-weight: 700;
    white-space: nowrap;
  }

  .movement-card .recurrence {
    display: inline-flex;
    align-items: center;
    padding: 1px 8px;
    color: var(--muted);
    background: rgba(101, 114, 123, 0.1);
    border-radius: 999px;
    font-size: 0.7rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    white-space: nowrap;
  }

  .movement-card[data-recurrence="puntual"] .recurrence {
    display: none;
  }

  .movement-card .shared-cell {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    padding: 1px 9px 1px 7px;
    color: #5b21b6;
    background: rgba(124, 58, 237, 0.1);
    border-radius: 999px;
    font-size: 0.78rem;
    font-weight: 600;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 18ch;
  }

  .movement-card .shared-cell::before {
    content: "👥";
    font-size: 0.85em;
    margin-right: 1px;
    filter: grayscale(0.2);
  }

  .movement-card[data-shared="false"] .shared-cell {
    display: none;
  }

  /* Inline expansion: the section sits as a third row spanning both
     columns. Collapse uses grid-template-rows 0fr→1fr so the height
     transitions smoothly without measuring it. */
  .movement-card .movement-expanded {
    grid-column: 1 / -1;
    display: grid;
    grid-template-rows: 0fr;
    transition: grid-template-rows 0.28s ease-out;
  }

  .movement-card .movement-expanded-inner {
    overflow: hidden;
    min-height: 0;
    opacity: 0;
    transition: opacity 0.18s ease-out;
  }

  .movement-card.is-expanded .movement-expanded {
    grid-template-rows: 1fr;
  }

  .movement-card.is-expanded .movement-expanded-inner {
    opacity: 1;
    transition: opacity 0.22s ease-in 0.06s;
  }

  /* When expanded, the card behaves like a panel: drop the tap-pointer
     hint, slightly emphasise the border, and give the content room. */
  .movement-card.is-expanded {
    border-color: #b8c5cb;
  }

  .movement-card.is-expanded .movement-expanded-inner {
    padding-top: 12px;
    margin-top: 8px;
    border-top: 1px solid var(--line);
  }

  .movement-expanded-list {
    margin: 0;
    display: grid;
    gap: 0;
  }

  .movement-expanded-list > div {
    display: grid;
    grid-template-columns: 110px 1fr;
    gap: 8px;
    padding: 7px 0;
    border-bottom: 1px solid rgba(216, 224, 228, 0.6);
  }

  .movement-expanded-list > div:last-child {
    border-bottom: 0;
  }

  .movement-expanded-list > div[hidden] {
    display: none;
  }

  .movement-expanded-list dt {
    display: block;
    margin: 0;
    color: var(--muted);
    font-size: 0.82rem;
    font-weight: 600;
  }

  .movement-expanded-list dd {
    margin: 0;
    font-size: 0.92rem;
    word-break: break-word;
  }

  .movement-expanded-shared {
    margin: 12px 0 0;
    padding: 10px 12px;
    background: rgba(124, 58, 237, 0.06);
    border: 1px solid rgba(124, 58, 237, 0.18);
    border-radius: 8px;
  }

  .movement-expanded-shared[hidden] {
    display: none;
  }

  .movement-expanded-shared h4 {
    margin: 0 0 4px;
    font-size: 0.78rem;
    font-weight: 800;
    color: #5b21b6;
    letter-spacing: 0.04em;
    text-transform: uppercase;
  }

  .movement-expanded-shared .movement-expanded-list > div {
    border-bottom: 1px solid rgba(124, 58, 237, 0.14);
  }

  .movement-expanded-shared .movement-expanded-list > div:last-child {
    border-bottom: 0;
  }

  .movement-expanded-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-top: 14px;
  }

  .movement-expanded-actions .primary-action,
  .movement-expanded-actions .ghost-action {
    flex: 1 1 88px;
    min-height: 38px;
    padding: 0 12px;
    white-space: nowrap;
  }

  .movement-expanded-actions .exp-delete-action {
    color: var(--red);
  }

  .movement-expanded-actions .exp-delete-action:hover {
    color: #ffffff;
    background: var(--red);
    border-color: var(--red);
  }

  /* Hint that replaces the action row inside the expanded section for
     virtual movements (rows derived from a partner-owned shared_entry). */
  .movement-expanded-virtual-hint {
    margin: 0;
    padding: 10px 12px;
    color: var(--muted);
    font-size: 0.86rem;
    font-style: italic;
    background: var(--surface-soft);
    border: 1px solid var(--line);
    border-radius: 6px;
    line-height: 1.4;
  }
}

/* Virtual movements derived from a partner-owned shared_entry: the
   action buttons (edit/duplicate/delete) don't apply because the row
   doesn't live in this user's movements table — it's rendered from
   the linked shared_entry. Hide them in both viewports. visibility
   keeps the desktop grid columns intact so the row layout doesn't
   shift. */
.movement-card[data-virtual="true"] .edit-action,
.movement-card[data-virtual="true"] .duplicate-action,
.movement-card[data-virtual="true"] .delete-action {
  visibility: hidden;
}

/* ==== Importe with € suffix ==== */
.amount-input {
  position: relative;
}

.amount-suffix {
  position: absolute;
  top: 50%;
  right: 14px;
  transform: translateY(-50%);
  color: var(--muted);
  font-weight: 700;
  font-size: 1rem;
  pointer-events: none;
}

/* ==== Disabled toggle-field (e.g. Gasto compartido on income) ==== */
.toggle-field:has(input:disabled) {
  opacity: 0.2;
  pointer-events: none;
}

/* ==== Submit icon (visible only on mobile, when the button is square) ==== */
.movement-submit {
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.movement-submit-icon {
  display: none;
  width: 36px;
  height: 36px;
}

/* ==== Type toggle (movement form, mobile only) ==== */
.type-toggle {
  display: none;
}

.type-toggle-button {
  display: grid;
  place-items: center;
  min-height: 76px;
  padding: 12px;
  color: var(--muted);
  background: #fbfcfd;
  border: 2px solid var(--line);
  border-radius: 12px;
  font-size: 1.1rem;
  font-weight: 800;
}

.type-toggle-button[data-type-target="expense"].is-active {
  color: var(--red);
  background: rgba(201, 42, 42, 0.08);
  border-color: var(--red);
}

.type-toggle-button[data-type-target="income"].is-active {
  color: var(--green);
  background: rgba(24, 121, 78, 0.08);
  border-color: var(--green);
}

/* ==== Ledger header (panel de movimientos) ====
   Móvil: el header completo (top + filter-bar) queda sticky, así "N
   movimientos", el botón Filtrar y "Nuevo movimiento" siguen accesibles
   al hacer scroll por la lista. Desktop: header normal en flujo, con
   filter-bar permanente debajo (sin toggle). */
.ledger-header {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-bottom: 14px;
}

.ledger-header-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  min-height: 28px;
}

.ledger-header-top h2 {
  margin: 0;
}

.ledger-actions {
  display: flex;
  gap: 8px;
}

/* ==== Filter bar inline ==== */
.filter-bar {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
}

/* The global `input, select { width: 100% }` rule would force each control
   onto its own row in this flex layout. Override so each shrinks to its
   natural width and the text input grows to fill the rest. */
.filter-bar > select,
.filter-bar > input {
  width: auto;
  flex: 0 0 auto;
}

.filter-bar .filter-text {
  flex: 1 1 200px;
  min-width: 0;
}

.filter-bar select {
  min-height: 36px;
}

/* Sticky header en ambos viewports: titulo + botones + filter-bar siguen
   al usuario al hacer scroll. Las medidas concretas se afinan dentro de
   los media queries (margenes negativos para que el bar se extienda
   flush con los bordes del panel, cuyo padding cambia). */
#movements-view .ledger-header {
  position: sticky;
  top: 0;
  z-index: 5;
  margin: -16px -16px 14px;
  padding: 16px 16px 12px;
  background: var(--surface);
  box-shadow: 0 6px 12px -10px rgba(23, 32, 38, 0.18);
}

/* Mobile: bar collapses by default; "Filtrar" toggles it. The desktop-only
   controls (concepto/categoría/tipo dropdowns) are hidden, and the bar's
   own X button moves up to the ledger actions row (left of Filtrar) so the
   bar stays at exactly one line when expanded. */
@media (max-width: 719px) {
  .filter-bar.is-collapsed-mobile {
    display: none;
  }

  .filter-bar .filter-concept-desktop,
  .filter-bar .filter-category-desktop,
  .filter-bar .filter-type-desktop {
    display: none;
  }

  .filter-bar .filter-field-mobile {
    flex: 0 0 auto;
    max-width: 42%;
  }

  /* The bar X is hidden on mobile; the top X (in .ledger-actions) takes
     over so toggling the filter never grows the panel by an extra row.
     Specificity is bumped via the parent class so this beats the global
     `.filter-clear-button { display: grid }` rule that sits later in the
     stylesheet. */
  .filter-bar .filter-clear-button--bar {
    display: none;
  }

  .ledger-actions .filter-clear-button--top {
    width: 32px;
    height: 32px;
    min-height: 32px;
    font-size: 0.92rem;
  }

  /* Tighten the gap on the actions row so X + Filtrar + Nuevo movimiento
     fit comfortably on phones at 360px. */
  .ledger-actions {
    gap: 6px;
  }

  /* En móvil el panel tiene padding 10px (override en línea 1648),
     así que ajustamos los márgenes negativos para que el sticky
     siga sentado flush con los bordes del panel. */
  #movements-view .ledger-header {
    margin: -10px -10px 10px;
    padding: 10px 10px 8px;
  }
}

/* Desktop: bar permanente (ignora cualquier toggle), Filtrar oculto, todos
   los dropdowns visibles + el text input multi-campo. La X del top no tiene
   sentido aquí (la X del bar es lo que usa) así que la ocultamos. */
@media (min-width: 720px) {
  .filter-bar.is-collapsed-mobile,
  .filter-bar {
    display: flex;
  }

  .filter-bar .filter-field-mobile {
    display: none;
  }

  .filter-bar select {
    flex: 0 0 auto;
  }

  .ledger-filter-toggle {
    display: none;
  }

  .ledger-actions .filter-clear-button--top {
    display: none;
  }

  /* Cabeceras de la lista congeladas en desktop:
     - .ledger-header (panel header) ya está sticky en top: 0, ~108px de alto.
     - .movement-header (titulos de columnas) sticky justo debajo.
     - .month-group sticky justo debajo del column-header, scopeado a su
       propia .month-section para que al pasar al siguiente mes el nuevo
       empuje al anterior fuera de la vista de forma natural.
     Para que sticky funcione hay que descartar el overflow-x: auto del list
     (creaba un scroll-container que rompía el sticky). En narrow desktops
     (~720-980px) la tabla puede causar scroll horizontal de la página; en
     anchos normales (≥980, donde el panel max-width: 1040 entra) cabe sin
     problema. */
  .movement-list {
    overflow-x: visible;
  }

  .movement-header {
    position: sticky;
    top: 108px;
    z-index: 4;
    /* Altura exacta = 148px (top de .month-group) - 108px (top propio).
       Sin esto el min-height: 28px deja un hueco transparente entre la
       cabecera de columnas y el separador de mes por el que se ven las
       filas scrolleando por detrás. */
    min-height: 40px;
  }

  /* Cada .month-section es el "containing block" del sticky de su propia
     .month-group: cuando la sección termina (siguiente mes empieza), el
     header se desadhiere de forma natural en lugar de quedar pegado
     indefinidamente y solapar con el siguiente. */
  .month-group {
    position: sticky;
    top: 148px;
    z-index: 3;
    margin-top: 0;
    background: var(--surface);
  }
}

.ghost-action {
  min-height: 36px;
  padding: 0 14px;
  color: var(--muted);
  background: transparent;
  border: 1px solid var(--line);
  border-radius: 6px;
  font-weight: 700;
}

.ghost-action:hover {
  color: var(--text);
  border-color: #b8c5cb;
}

.filter-clear-button {
  display: grid;
  place-items: center;
  width: 36px;
  height: 36px;
  min-height: 36px;
  padding: 0;
  color: #ffffff;
  background: var(--red);
  border: 0;
  border-radius: 6px;
  font-size: 1rem;
  font-weight: 800;
  line-height: 1;
}

/* The HTML `hidden` attribute is the API used to toggle this button;
   without this rule the `display: grid` above wins and the button stays
   visible even when no filters are active. */
.filter-clear-button[hidden] {
  display: none;
}

.filter-clear-button:hover {
  background: #a82222;
}

/* ==== Danger zone (settings) ==== */
.danger-panel {
  border-color: #f0b7b7;
}

.danger-blurb {
  margin: 0 0 12px;
  color: var(--muted);
  font-size: 0.86rem;
  line-height: 1.45;
}

.danger-blurb strong {
  color: var(--red);
}

.danger-action {
  min-height: 36px;
  padding: 0 14px;
  color: var(--red);
  background: transparent;
  border: 1px solid #f0b7b7;
  border-radius: 6px;
  font-weight: 800;
}

.danger-action:hover {
  color: #ffffff;
  background: var(--red);
  border-color: var(--red);
}

/* ==== Build version label (fixed, top-right) ==== */
.app-version {
  position: fixed;
  top: 4px;
  right: 6px;
  z-index: 60;
  padding: 1px 5px;
  color: var(--muted);
  background: rgba(255, 255, 255, 0.7);
  border-radius: 3px;
  font-family: ui-monospace, SFMono-Regular, Consolas, "Liberation Mono", monospace;
  font-size: 0.66rem;
  opacity: 0.5;
  pointer-events: none;
  user-select: none;
}

/* ==== Auth gate ==== */
body.is-locked .shell {
  display: none;
}

.auth-gate {
  position: fixed;
  inset: 0;
  display: grid;
  place-items: center;
  background: var(--background, #f5f5f5);
  z-index: 100;
  padding: 24px;
}

/* The `hidden` attribute is the JS API we use to toggle the gate; without
   this rule the `display: grid` above wins and the gate stays visible. */
.auth-gate[hidden] {
  display: none;
}

.auth-card {
  width: 100%;
  max-width: 420px;
  background: var(--card, #fff);
  border: 1px solid var(--border, #e0e0e0);
  border-radius: 12px;
  padding: 32px 28px;
  display: grid;
  gap: 16px;
}

.auth-brand {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 18px;
}

.auth-card h1 {
  margin: 0;
  font-size: 22px;
}

.auth-blurb {
  margin: 0;
  color: var(--muted, #666);
  font-size: 14px;
  line-height: 1.5;
}

.auth-form {
  display: grid;
  gap: 12px;
}

.auth-form label {
  display: grid;
  gap: 4px;
  font-size: 13px;
  color: var(--muted, #666);
}

.auth-form input {
  font-size: 15px;
  padding: 10px 12px;
  border: 1px solid var(--border, #e0e0e0);
  border-radius: 8px;
}

#auth-feedback {
  margin: 0;
  font-size: 13px;
  color: var(--muted, #666);
  min-height: 18px;
}

/* ==== Session indicators in sidebar ====
   Email = chivato (no clickable). Logout = button.
   En el HTML van en este orden: <logout> <email>. Eso permite que en
   móvil (sidebar = grid 5 cols) el logout ocupe la celda 5 de la
   fila 2 (justo después de los 4 nav buttons "secundarios") y el
   email vaya a una tercera fila completa (grid-column: 1 / -1).
   En desktop (sidebar = flex column) el margin-top:auto va sobre el
   logout para empujar logout+email juntos al fondo de la columna. */
.session-email {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 34px;
  padding: 2px 4px;
  font-size: 10px;
  line-height: 1.15;
  color: var(--muted);
  text-align: center;
  overflow: hidden;
  text-overflow: ellipsis;
  word-break: break-all;
  /* En móvil (display: grid) ocupa toda la fila. En desktop el grid-
     -column se ignora porque la sidebar es flex column. */
  grid-column: 1 / -1;
}

.session-email:empty {
  visibility: hidden;
}

.session-logout {
  display: grid;
  place-items: center;
  min-height: 34px;
  padding: 6px;
  background: transparent;
  border: 0;
  border-radius: 6px;
  color: var(--muted);
  cursor: pointer;
}

.session-logout:hover {
  color: var(--text);
  background: rgba(23, 32, 38, 0.05);
}

@media (min-width: 980px) {
  .session-logout {
    width: 34px;
    align-self: center;
    margin-top: auto;
  }

  .session-email {
    width: 100%;
    padding: 6px 4px 2px;
  }
}

/* ==== Movement card inline expansion (móvil; se abre al tocar la card) ====
   Hidden globally so desktop never paints it; the @media (max-width: 719px)
   block below enables the smooth expand/collapse animation via the
   grid-template-rows 0fr→1fr trick. */
.movement-expanded {
  display: none;
}

/* ==== Periódicos (recurring templates) ====
   Layout responsive con UN solo HTML:
   - Desktop ≥720px: rejilla tipo tabla con cabecera de columnas y filas
     compactas. Las acciones van inline a la derecha.
   - Mobile <720px: cards mini con expansión al tocar. Colapsada muestra
     solo concepto + importe + próxima generación + (compartido). Al
     expandir aparece nota, periodicidad, emisor/receptor y botones. */

/* Texto de feedback que aparece bajo el header de un modal (antes
   estaba dentro del section-heading peleándose con la X — ahora vive
   en una fila propia para que la X quede limpia a la derecha). */
.modal-feedback {
  margin: 0 0 10px;
  color: var(--muted);
  font-size: 0.85rem;
  line-height: 1.4;
}

.modal-feedback:empty {
  display: none;
}

/* Reglas específicas del formulario de plantilla periódica para que
   los bloques que actúan como "fila propia" no compartan grid con
   inputs sueltos. Sin esto, el grid de 4 columnas distribuye toggle,
   bloque rosa y botón submit en celdas raras (al lado de un input). */
#recurring-form > .recurring-customize-toggle,
#recurring-form > #recurring-shared-group-info,
#recurring-form > button[type="submit"] {
  grid-column: 1 / -1;
}

.recurring-customize-toggle {
  justify-self: start;
  background: transparent;
  border: none;
  padding: 4px 0;
  margin: -4px 0 0;
  font-size: 0.78rem;
  color: var(--mod-violet, #7c3aed);
  cursor: pointer;
  text-decoration: underline;
  text-decoration-style: dotted;
  text-underline-offset: 3px;
}

.recurring-customize-toggle:hover {
  text-decoration-style: solid;
}

#recurring-form > button[type="submit"] {
  justify-self: stretch;
  margin-top: 4px;
}

.recurring-blurb {
  margin: 6px 0 18px;
  color: var(--muted);
  font-size: 0.92rem;
  line-height: 1.4;
}

.recurring-list {
  display: block;
}

.recurring-row {
  /* Compartida entre cabecera + filas para que las columnas alineen */
  display: grid;
  align-items: center;
}

/* ---- Cabecera de columnas (solo desktop) ---- */
.recurring-row--header {
  font-size: 0.74rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--muted);
  /* Mismo padding horizontal que las filas (12px 14px) para que las
     columnas del grid empiecen exactamente al mismo x — si no, los
     títulos quedan 2px desplazados respecto a los valores. Vertical
     más corto porque la cabecera no necesita tanto aire. */
  padding: 8px 14px;
  border-bottom: 1px solid var(--line);
}

.ri-col {
  white-space: nowrap;
}

/* ---- Comunes a las filas de plantilla ---- */
.ri-title {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.ri-concept {
  font-weight: 700;
  font-size: 1rem;
  line-height: 1.2;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.ri-note,
.ri-party {
  font-size: 0.82rem;
  color: var(--muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.ri-amount {
  font-variant-numeric: tabular-nums;
  font-weight: 700;
  white-space: nowrap;
}

.ri-amount.expense { color: #c92a2a; }
.ri-amount.income { color: #18794e; }

.ri-period,
.ri-next,
.ri-shared {
  font-size: 0.88rem;
  color: var(--muted);
}

.ri-shared {
  color: var(--mod-violet);
}

.ri-shared:empty {
  /* Cells without shared data still occupy the grid slot on desktop
     (alignment), pero en móvil escondemos la línea entera */
}

.ri-next--paused {
  color: var(--mod-orange);
  font-weight: 600;
}

.ri-next--ended {
  font-style: italic;
}

/* ---- Acciones (Editar / Pausar / Eliminar) ---- */
.ri-actions {
  display: flex;
  gap: 6px;
  flex-wrap: nowrap;
}

.ri-action {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 5px 10px;
  font-size: 0.82rem;
  font-weight: 600;
  border: 1px solid var(--line);
  background: transparent;
  color: var(--text);
  border-radius: 6px;
  cursor: pointer;
  white-space: nowrap;
}

.ri-action:hover {
  background: rgba(23, 32, 38, 0.04);
}

.ri-action--delete {
  color: #c92a2a;
  border-color: rgba(201, 42, 42, 0.35);
}

.ri-action--delete:hover {
  background: rgba(201, 42, 42, 0.08);
}

.ri-action-icon {
  width: 16px;
  height: 16px;
  flex: 0 0 auto;
}

/* ---- Desktop: layout tipo tabla ---- */
@media (min-width: 720px) {
  .recurring-row {
    /* Columna 6 (Acciones) FIJA en 120px — antes era `auto`, lo que la
       hacía dimensionarse a su contenido: ~70px en la cabecera (texto
       "ACCIONES"), ~108px en las filas (3 iconos). Como las columnas
       `fr` reparten lo que sobra, esa diferencia hacía que cada columna
       midiera ligeramente distinto en cabecera vs filas y los títulos
       nunca acababan de cuadrar con los valores. Con valor fijo, todas
       las columnas resuelven idénticamente en cabecera y filas. */
    grid-template-columns: minmax(180px, 2fr) minmax(110px, 1fr) minmax(150px, 1.6fr) minmax(90px, 1fr) minmax(180px, 2.4fr) 120px;
    gap: 16px;
    padding: 12px 14px;
  }

  .recurring-row--item {
    border-bottom: 1px solid var(--line);
    border-left: 3px solid var(--mod-orange);
    transition: background 0.12s ease;
  }

  .recurring-row--item:hover {
    background: rgba(234, 88, 12, 0.04);
  }

  .recurring-row--item.is-paused {
    border-left-color: var(--line);
    opacity: 0.6;
  }

  /* Cabecera "ACCIONES" centrada sobre el grupo de botones (en vez de
     pegada a la derecha). Como el grupo es más ancho que el texto del
     título, anclarlos por la derecha hacía que ACCIONES apareciera
     visualmente sobre el último icono y no sobre el conjunto. */
  .ri-col--actions {
    justify-self: center;
  }

  .ri-actions {
    justify-self: end;
  }

  /* Botones de acción en desktop: cuadrados con solo icono. La etiqueta
     queda accesible para lectores de pantalla pero invisible para que
     la columna se mantenga compacta. El title nativo (tooltip) sirve
     de aclaración al pasar el ratón. */
  .ri-action {
    width: 32px;
    height: 32px;
    padding: 0;
    gap: 0;
  }

  .ri-action-label {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
  }
}

/* ---- Mobile: mini-cards con expand/collapse ---- */
@media (max-width: 719px) {
  .recurring-row--header {
    display: none;
  }

  .recurring-row--item {
    grid-template-columns: 1fr auto;
    grid-template-areas:
      "title amount"
      "next  next"
      "shared shared"
      "period period"
      "actions actions";
    gap: 4px 12px;
    padding: 12px 14px;
    margin-bottom: 8px;
    background: #fff;
    border: 1px solid var(--line);
    border-left: 4px solid var(--mod-orange);
    border-radius: 10px;
    cursor: pointer;
  }

  .recurring-row--item.is-paused {
    border-left-color: var(--line);
    opacity: 0.7;
  }

  .ri-title { grid-area: title; min-width: 0; }
  .ri-amount { grid-area: amount; align-self: start; }
  .ri-next { grid-area: next; }
  .ri-shared { grid-area: shared; }
  .ri-period { grid-area: period; }
  .ri-actions { grid-area: actions; }

  /* Próxima generación: prefijar "Próxima: " en móvil para que el
     número solo no quede sin contexto. */
  .ri-next::before {
    content: "Próxima: ";
    color: var(--muted);
  }

  .ri-next--paused::before { content: ""; }
  .ri-next--ended::before { content: ""; }

  /* Colapsada: ocultar todo lo "extra" hasta que se toque la card */
  .recurring-row--item:not(.is-expanded) .ri-note,
  .recurring-row--item:not(.is-expanded) .ri-party,
  .recurring-row--item:not(.is-expanded) .ri-period,
  .recurring-row--item:not(.is-expanded) .ri-actions {
    display: none;
  }

  /* En móvil colapsada, las celdas vacías (.ri-shared sin contenido)
     no deben dejar hueco vertical. */
  .recurring-row--item:not(.is-expanded) .ri-shared:empty {
    display: none;
  }

  .recurring-row--item.is-expanded {
    cursor: default;
  }

  .recurring-row--item.is-expanded .ri-actions {
    display: flex;
    gap: 8px;
    margin-top: 8px;
    padding-top: 10px;
    border-top: 1px dashed var(--line);
  }

  .recurring-row--item.is-expanded .ri-action {
    flex: 1 1 auto;
    justify-content: center;
    text-align: center;
    padding: 8px 10px;
  }

  /* En móvil mostramos texto, ocultamos el icono — la lista de acciones
     se ve más clara cuando es texto ancho. */
  .ri-action-icon {
    display: none;
  }
}

/* ==== Grupos en Configuración ==== */
.group-blurb {
  margin: 6px 0 14px;
  color: var(--muted);
  font-size: 0.92rem;
  line-height: 1.45;
}

.groups-list {
  display: grid;
  gap: 8px;
  margin-top: 12px;
}

/* Card de grupo: una sola fila — nombre+miembros a la izquierda
   ocupando el espacio sobrante, tag opcional de rol al centro-derecha,
   botón "Gestionar" pegado a la derecha. Mismo layout en móvil y
   desktop; basta con flex-wrap si por algún caso extremo el texto
   del nombre fuera muy largo y comprimiera el botón. */
.group-card {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 14px;
  background: var(--surface, #fff);
  border: 1px solid var(--line);
  border-radius: 10px;
  border-left: 4px solid var(--mod-violet);
}

.group-card-info {
  flex: 1 1 auto;
  display: flex;
  align-items: baseline;
  gap: 10px;
  min-width: 0;
  flex-wrap: wrap;
}

.group-card-name {
  font-size: 1rem;
  font-weight: 700;
}

.group-card-meta {
  font-size: 0.85rem;
  color: var(--muted);
}

.group-card-role {
  flex: 0 0 auto;
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-weight: 700;
  padding: 3px 9px;
  border-radius: 999px;
  background: var(--mod-violet-bg);
  color: var(--mod-violet);
}

.group-card-edit {
  flex: 0 0 auto;
  padding: 6px 12px;
  font-size: 0.85rem;
  font-weight: 600;
  border-radius: 8px;
  border: 1px solid var(--line);
  background: transparent;
  color: var(--text);
  cursor: pointer;
}

.group-card-edit:hover {
  background: rgba(23, 32, 38, 0.04);
}

/* Modal de gestión de grupo */
.group-dialog {
  max-width: 540px;
}

.group-rename {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: end;
  gap: 10px;
  margin-bottom: 18px;
}

.group-admin-badge {
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--muted);
  padding: 3px 10px;
  border-radius: 999px;
  background: rgba(23, 32, 38, 0.06);
}

.group-admin-badge.is-admin {
  background: var(--mod-violet-bg);
  color: var(--mod-violet);
}

.group-role-meta {
  display: flex;
  align-items: center;
  gap: 6px;
}

.group-hint {
  margin: 4px 0 14px;
  font-size: 0.85rem;
  color: var(--muted);
  line-height: 1.4;
}

.group-members-section {
  margin-top: 8px;
  padding-top: 14px;
  border-top: 1px solid var(--line);
}

.group-members-list {
  display: grid;
  gap: 6px;
  margin: 8px 0 14px;
}

.group-member-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 10px;
  padding: 8px 12px;
  background: rgba(23, 32, 38, 0.03);
  border-radius: 8px;
}

.group-member-info {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px 10px;
  min-width: 0;
}

.group-member-info strong.is-me {
  color: var(--mod-violet);
}

.group-member-info small {
  color: var(--muted);
  font-size: 0.82rem;
}

.group-member-tag {
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  padding: 2px 8px;
  border-radius: 999px;
  background: var(--mod-violet-bg);
  color: var(--mod-violet);
  font-weight: 600;
}

.group-member-tag.is-offline {
  background: rgba(23, 32, 38, 0.06);
  color: var(--muted);
}

.group-member-actions {
  display: flex;
  gap: 6px;
}

.group-member-actions .ghost-action {
  padding: 4px 10px;
  font-size: 0.78rem;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: transparent;
  color: var(--text);
  cursor: pointer;
}

.group-member-actions .ghost-action:hover {
  background: rgba(23, 32, 38, 0.05);
}

.group-add-member {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: end;
  gap: 10px;
  margin-top: 12px;
}

.group-danger-zone {
  display: flex;
  justify-content: space-between;
  gap: 10px;
  margin-top: 18px;
  padding-top: 14px;
  border-top: 1px solid var(--line);
}

.group-danger-zone .ghost-action,
.group-danger-zone .danger-action {
  padding: 8px 14px;
  font-size: 0.88rem;
  border-radius: 8px;
  cursor: pointer;
  border: 1px solid var(--line);
  background: transparent;
}

.group-danger-zone .danger-action {
  color: #c92a2a;
  border-color: rgba(201, 42, 42, 0.4);
}

.group-danger-zone .danger-action:hover {
  background: rgba(201, 42, 42, 0.08);
}

/* Footer del modal de gestión de grupo: dado que cada subform aplica
   sus cambios al pulsar su propio botón, el footer NO es un "guardar"
   global — es solo un cierre claro tras terminar de configurar. La
   nota recuerda al usuario que no hay nada pendiente de aplicar. */
.group-modal-footer {
  display: flex;
  align-items: center;
  gap: 14px;
  margin-top: 18px;
  padding-top: 14px;
  border-top: 1px solid var(--line);
}

.group-modal-footer-hint {
  margin: 0;
  flex: 1 1 auto;
  color: var(--muted);
  font-size: 0.78rem;
  line-height: 1.35;
}

.group-modal-footer .primary-action {
  flex: 0 0 auto;
  min-width: 120px;
}

@media (max-width: 480px) {
  .group-modal-footer {
    flex-direction: column;
    align-items: stretch;
    gap: 8px;
  }
  .group-modal-footer .primary-action {
    width: 100%;
  }
}

/* Collapsible "Crear contacto nuevo" dentro del modal de grupo: cierra
   por defecto para no comer scroll si solo quieres añadir contactos
   existentes. El summary cumple la doble función de etiqueta + toggle. */
.group-new-contact-collapsible {
  margin-top: 10px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: #fbfcfd;
}

.group-new-contact-collapsible > summary {
  list-style: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 10px 12px;
  font-size: 0.88rem;
  font-weight: 700;
  color: var(--text);
}

.group-new-contact-collapsible > summary::-webkit-details-marker {
  display: none;
}

.group-new-contact-collapsible[open] > summary {
  border-bottom: 1px solid var(--line);
}

.group-new-contact-collapsible[open] > summary .callout-chevron {
  transform: rotate(180deg);
}

.group-new-contact-collapsible > summary .callout-chevron {
  width: 16px;
  height: 16px;
  transition: transform 160ms ease;
}

.group-new-contact-collapsible > .group-new-contact {
  padding: 12px;
  margin: 0;
}

/* Modal de confirmación robusta. Reutilizado en cualquier flujo que
   pida más que un confirm() nativo (borrar movimiento recurrente,
   borrar plantilla, etc.). El layout pone título en la sección-heading
   y los botones en una columna pegada abajo para que el usuario no se
   precipite a aceptar. */
.confirm-dialog {
  max-width: 460px;
}

.confirm-message {
  margin: 6px 0 0;
  line-height: 1.45;
  color: var(--text);
}

.confirm-extra {
  margin: 10px 0 0;
  font-size: 0.92rem;
  color: var(--muted);
}

.confirm-actions {
  display: grid;
  gap: 8px;
  margin-top: 18px;
}

.confirm-action {
  width: 100%;
  padding: 10px 14px;
  font-size: 0.95rem;
  font-weight: 600;
  border-radius: 8px;
  cursor: pointer;
  border: 1px solid var(--line);
  background: transparent;
  color: var(--text);
}

.confirm-action.primary-action {
  background: var(--mod-blue-bg);
  color: var(--mod-blue);
  border-color: rgba(37, 99, 235, 0.35);
}

.confirm-action.primary-action:hover {
  background: rgba(37, 99, 235, 0.18);
}

.confirm-action.ghost-action:hover {
  background: rgba(23, 32, 38, 0.05);
}

.confirm-action.danger-action {
  background: rgba(201, 42, 42, 0.06);
  color: #c92a2a;
  border-color: rgba(201, 42, 42, 0.4);
}

.confirm-action.danger-action:hover {
  background: rgba(201, 42, 42, 0.14);
}

/* Estado armado: el primer click de un botón con doble-confirmación
   lo cambia a "¿Seguro? Pulsa otra vez" y le aplicamos un fondo más
   intenso para que sea evidente que el siguiente click ejecuta. */
.confirm-action.is-armed {
  background: #c92a2a;
  color: #fff;
  border-color: #c92a2a;
  animation: confirm-pulse 0.4s ease-out;
}

@keyframes confirm-pulse {
  0% { transform: scale(1); }
  50% { transform: scale(1.03); }
  100% { transform: scale(1); }
}

/* Preview en vivo bajo el campo Nota del modal de plantilla periódica:
   muestra cómo se renderizaría la nota si la plantilla generara hoy una
   ocurrencia, con [mes]/[año]/etc. ya sustituidos. Solo aparece cuando
   la nota contiene placeholders. */
.placeholder-preview {
  display: block;
  margin-top: 6px;
  padding: 4px 8px;
  font-size: 0.82rem;
  font-style: italic;
  color: var(--mod-orange);
  background: var(--mod-orange-bg);
  border-radius: 4px;
}

/* Mismo problema que con label[hidden]: el display: block de arriba
   ganaba al atributo hidden y dejaba un bloque rosa visible aunque el
   preview estuviera vacío. */
.placeholder-preview[hidden] {
  display: none;
}

/* Bloque "Compartido con un grupo" del modal de gasto. Aparece
   debajo del selector cuando se elige un value con prefijo group:.
   Layout: pagador + modo en una fila si caben, partes desiguales en
   un grid vertical de inputs por miembro. */
.shared-group-fields {
  display: grid;
  gap: 10px;
  padding: 12px;
  background: rgba(219, 39, 119, 0.05);
  border: 1px solid rgba(219, 39, 119, 0.18);
  border-radius: 10px;
}

/* Override del comportamiento por defecto de [hidden] que el CSS del
   form rompe (el grid `.movement-form > *` set explícitamente display).
   Estas reglas devuelven la semántica esperada: cuando un bloque tiene
   el atributo hidden, no se ve. */
.shared-mode-field[hidden],
.shared-group-fields[hidden],
.shared-group-shares[hidden] {
  display: none !important;
}

/* El <p> de feedback se mantiene en el DOM aunque esté vacío (lo
   reusamos al cambiar el modo). Cuando no tiene texto, ocultarlo
   para que no deje una franja blanca dentro del bloque rosa. */
.shared-group-fields .shared-uneven-feedback:empty {
  display: none;
}

.shared-group-shares {
  display: grid;
  gap: 6px;
  padding-top: 4px;
  border-top: 1px dashed var(--line);
}

.shared-group-share {
  display: grid;
  grid-template-columns: 1fr 110px;
  align-items: center;
  gap: 10px;
}

.shared-group-share span {
  font-size: 0.88rem;
  color: var(--text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.shared-group-share input {
  text-align: right;
}

/* Pareja botón disparador del calendario + "Quitar" para fechas
   opcionales (la fecha de fin de una plantilla periódica). El botón
   Quitar solo aparece cuando hay fecha cargada. */
.date-trigger-row {
  display: flex;
  align-items: stretch;
  gap: 8px;
}

.date-trigger-row .date-trigger {
  flex: 1 1 auto;
}

.date-clear-button {
  flex: 0 0 auto;
  align-self: stretch;
  padding: 0 14px;
  font-size: 0.88rem;
  color: var(--muted);
  background: transparent;
  border: 1px dashed var(--line);
  border-radius: 6px;
  cursor: pointer;
}

.date-clear-button:hover {
  color: var(--text);
  border-style: solid;
}

/* Botón "Convertir en plantilla periódica" en el modal de movimiento.
   Ghost de ancho completo con icono SVG a la izquierda, en naranja para
   atar visualmente con la sección Periódicos del Home. */
.convert-to-recurring {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  width: 100%;
  padding: 10px 14px;
  font-size: 0.95rem;
  font-weight: 600;
  color: var(--mod-orange);
  background: var(--mod-orange-bg);
  border: 1px solid rgba(234, 88, 12, 0.35);
  border-radius: 8px;
  cursor: pointer;
  /* En el grid de 4 columnas del .movement-form (desktop), atravesar
     todas las columnas. En móvil ya es una sola columna por defecto. */
  grid-column: 1 / -1;
}

.convert-to-recurring:hover {
  background: rgba(234, 88, 12, 0.18);
}

.convert-to-recurring svg {
  width: 18px;
  height: 18px;
}

/* Override del [hidden] por defecto: el .movement-form > * { display: ... }
   sobrescribe la regla por defecto de [hidden]. Sin este !important el
   botón se ve incluso cuando estamos creando un movimiento nuevo (donde
   no hay editingMovementId que convertir), y al hacer click el handler
   loguea "[convert] no editingMovementId set" y no hace nada. */
.convert-to-recurring[hidden] {
  display: none !important;
}

/* Toggle Mensual/Anual al inicio de Análisis y Contactos/Grupos en
   Configuración. Mismo patrón visual que .type-toggle-button (Gasto/
   Ingreso) — pastilla con dos botones, el activo coloreado. */
.analysis-mode-toggle,
.subpane-toggle {
  display: inline-flex;
  gap: 6px;
  padding: 4px;
  background: rgba(23, 32, 38, 0.04);
  border-radius: 10px;
}

.analysis-mode-toggle .type-toggle-button,
.subpane-toggle .type-toggle-button {
  min-height: 0;
  padding: 8px 16px;
  font-size: 0.95rem;
  font-weight: 700;
  background: transparent;
  border: 0;
  color: var(--muted);
  cursor: pointer;
  border-radius: 8px;
  transition: background 0.15s ease, color 0.15s ease, box-shadow 0.15s ease;
}

/* Patrón "pill toggle" tipo iOS/macOS: el botón activo se eleva con
   fondo blanco + sombra suave sobre el fondo gris del contenedor. Es
   mucho más obvio visualmente que un teñido con la marca de la sección,
   que se confundía con el botón inactivo cuando los dos colores eran
   parecidos. El color de la TEXTO sí va con el acento (verde para
   Análisis, violeta para Contactos/Grupos). */
.analysis-mode-toggle .type-toggle-button.is-active,
.subpane-toggle .type-toggle-button.is-active {
  background: #fff;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08), 0 1px 1px rgba(0, 0, 0, 0.04);
}

.analysis-mode-toggle .type-toggle-button.is-active {
  color: var(--mod-green);
}

.contacts-mode-toggle .type-toggle-button.is-active {
  color: var(--mod-violet);
}

@media (max-width: 719px) {
  .analysis-mode-toggle,
  .contacts-mode-toggle {
    margin-top: 6px;
    align-self: flex-start;
  }
}

/* Divisor "o" entre los dos forms de añadir miembro al grupo: el de
   contacto existente arriba y el de crear-y-añadir abajo. La línea
   horizontal con la palabra centrada es el separador típico para
   ofrecer dos alternativas equivalentes al usuario sin esconder
   ninguna. */
.group-add-member-divider {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 16px 0 12px;
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--muted);
}

.group-add-member-divider::before,
.group-add-member-divider::after {
  content: "";
  flex: 1 1 auto;
  height: 1px;
  background: var(--line);
}

.group-new-contact {
  display: grid;
  gap: 10px;
}

.group-new-contact label {
  display: grid;
  gap: 4px;
}
