/* ==========================================================================
   Analizador — sistema de componentes
   ==========================================================================
   Los tokens (color, tipografía, espacio, radios, curvas) viven en styles.css.
   Aquí vive cómo se ven y cómo se comportan las piezas.

   Tres reglas que gobiernan el archivo:

   1. COMPARTIMENTOS. Cada cosa dentro de un contenedor con su rótulo. Lo que
      separa un bloque de otro es un borde de 1px y espacio, no una sombra.
   2. UN SOLO ACENTO. El turquesa es para la acción principal, el foco y lo
      activo. Si además pintara títulos e iconos, dejaría de señalar nada.
   3. UN ESTADO SE VE. Hover, pulsado, foco, deshabilitado, cargando y vacío
      existen para todos los controles, no solo para los botones.

   El movimiento se apaga entero si el sistema lo pide (último bloque).
   ========================================================================== */

/* ==========================================================================
   1 · Tipografía
   ========================================================================== */

body { font-size: var(--texto-base); }

/* Título de la pantalla: uno por vista, arriba y sin competencia. */
.topbar__head h1 {
  font-size: var(--t-pagina);
  font-weight: var(--peso-fuerte);
  letter-spacing: -.015em;
  line-height: 1.2;
}
.topbar__head p { font-size: var(--t-secundario); color: var(--text-muted); }

/* Título de tarjeta. */
.card__head h2,
.card > h2 {
  font-size: var(--t-tarjeta);
  font-weight: var(--peso-fuerte);
  letter-spacing: -.005em;
}
.card__head p { font-size: var(--t-meta); color: var(--text-muted); line-height: 1.45; }
.card h3 { font-size: var(--t-cuerpo); font-weight: var(--peso-medio); }
.secondary, .muted { font-size: var(--t-secundario); color: var(--text-secondary); }
.muted { color: var(--text-muted); }

/* ==========================================================================
   2 · Sección: el compartimento
   ==========================================================================
   Un grupo de tarjetas que responden a la misma pregunta, con su rótulo encima.
   Es la pieza que evita que una vista parezca un único bloque continuo. */

.seccion { display: grid; gap: var(--sp-3); }
.seccion + .seccion { margin-top: var(--sp-2); }

.seccion__head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--sp-3); flex-wrap: wrap;
  padding-bottom: 2px;
}
.seccion__titulo {
  font-size: var(--t-seccion);
  font-weight: var(--peso-fuerte);
  letter-spacing: -.005em;
  color: var(--text-primary);
  margin: 0;
}
.seccion__pista {
  font-size: var(--t-meta); color: var(--text-muted);
  margin: 2px 0 0;
}
.seccion__acciones { display: flex; gap: var(--sp-2); align-items: center; }

/* Rótulo pequeño en versales para agrupaciones dentro de una tarjeta. */
.rotulo {
  font-size: var(--t-meta); font-weight: var(--peso-fuerte);
  text-transform: uppercase; letter-spacing: .06em;
  color: var(--text-muted);
}

/* ==========================================================================
   3 · Tarjetas
   ========================================================================== */

.card {
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow);
  padding: var(--card-pad);
  transition: border-color var(--normal) var(--curva), box-shadow var(--normal) var(--curva);
}
.card__head {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: var(--sp-3); flex-wrap: wrap;
  margin-bottom: var(--sp-4);
}
.card__head:last-child { margin-bottom: 0; }
.card__tools { display: flex; gap: var(--sp-2); align-items: flex-end; flex-wrap: wrap; }

/* Tarjeta pulsable: solo si de verdad lleva a algún sitio. */
.card--accion { cursor: pointer; text-align: left; width: 100%; font-family: inherit; color: inherit; }
.card--accion:hover { border-color: var(--border-strong); }
.card--accion:active { transform: scale(.995); }

/* ==========================================================================
   4 · KPI
   ==========================================================================
   Rótulo arriba, cifra grande, variación debajo. Siempre en ese orden: se leen
   en fila y el ojo compara las cifras porque están a la misma altura. */

.kpi { display: grid; gap: var(--sp-2); align-content: start; }
.kpi__label {
  font-size: var(--t-etiqueta); font-weight: var(--peso-medio);
  color: var(--text-secondary);
}
.kpi__valor {
  font-size: var(--t-cifra); font-weight: var(--peso-fuerte);
  letter-spacing: -.02em; line-height: 1.1;
  font-variant-numeric: tabular-nums;
  color: var(--text-primary);
}
.kpi__pie { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; }
.kpi__pie span { font-size: var(--t-meta); color: var(--text-muted); }

/* La variación: signo, color y nada más. */
.var {
  display: inline-flex; align-items: center; gap: 3px;
  font-size: var(--t-meta); font-weight: var(--peso-medio);
  font-variant-numeric: tabular-nums;
  padding: 2px 6px; border-radius: var(--radius-xs);
}
.var--sube { color: var(--success-text); background: color-mix(in srgb, var(--good) 10%, var(--surface-1)); }
.var--baja { color: var(--critical); background: color-mix(in srgb, var(--critical) 10%, var(--surface-1)); }
.var--igual { color: var(--text-muted); background: var(--surface-2); }

/* Rejilla de KPI: nunca menos de 200px, así no se parten los números. */
.kpis {
  display: grid; gap: var(--sp-3);
  grid-template-columns: repeat(auto-fit, minmax(min(210px, 100%), 1fr));
}

/* ==========================================================================
   5 · Botones
   ==========================================================================
   Cuatro pesos y no más: principal (uno por pantalla), normal, fantasma y
   peligro. El tamaño lo da --control-alto, que respeta el dedo. */

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  min-height: var(--control-alto);
  padding: 0 var(--sp-4);
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background: var(--surface-1);
  color: var(--text-primary);
  font-family: inherit;
  font-size: var(--t-cuerpo);
  font-weight: var(--peso-medio);
  cursor: pointer;
  transition:
    background var(--rapido) var(--curva),
    border-color var(--rapido) var(--curva),
    color var(--rapido) var(--curva),
    transform var(--rapido) var(--curva);
}
.btn:hover { background: var(--surface-2); border-color: var(--border-strong); }
.btn:active { transform: scale(.98); }
.btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.btn--primary {
  background: var(--accent); border-color: transparent; color: var(--accent-ink);
}
.btn--primary:hover { background: var(--accent-hover); border-color: transparent; }
.btn--primary:active { background: var(--accent-activo); }

.btn--ghost { background: transparent; border-color: transparent; color: var(--text-secondary); }
.btn--ghost:hover { background: var(--surface-2); border-color: transparent; color: var(--text-primary); }

.btn--danger { color: var(--critical); border-color: var(--border); background: var(--surface-1); }
.btn--danger:hover { background: color-mix(in srgb, var(--critical) 8%, var(--surface-1)); border-color: color-mix(in srgb, var(--critical) 35%, var(--border)); }

.btn--sm { min-height: 32px; padding: 0 var(--sp-3); font-size: var(--t-secundario); }
.btn--gigante { min-height: 52px; padding: 0 var(--sp-5); font-size: 15.5px; }

/* Deshabilitado: gris, sin puntero y sin animación. Se ve que está ahí. */
.btn:disabled, .btn[aria-disabled="true"] {
  background: var(--disabled-bg); border-color: var(--disabled-borde);
  color: var(--disabled-ink); cursor: not-allowed; opacity: 1; transform: none;
}
.btn:disabled:hover { background: var(--disabled-bg); border-color: var(--disabled-borde); }

/* ==========================================================================
   6 · Campos
   ========================================================================== */

.field { display: grid; gap: var(--sp-1); }
.field > span {
  font-size: var(--t-etiqueta); font-weight: var(--peso-medio);
  color: var(--text-secondary); padding-left: 1px;
}
.field__hint { font-size: var(--t-meta); color: var(--text-muted); line-height: 1.45; }

input:not([type="checkbox"]):not([type="radio"]), select, textarea {
  min-height: var(--control-alto);
  padding: 0 var(--sp-3);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface-1);
  color: var(--text-primary);
  font-family: inherit;
  font-size: var(--t-cuerpo);
  transition: border-color var(--rapido) var(--curva), box-shadow var(--rapido) var(--curva);
}
textarea { padding: var(--sp-2) var(--sp-3); line-height: 1.5; }
input:hover, select:hover, textarea:hover { border-color: var(--border-strong); }
input:focus-visible, select:focus-visible, textarea:focus-visible {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
input:disabled, select:disabled, textarea:disabled {
  background: var(--disabled-bg); color: var(--disabled-ink); cursor: not-allowed;
}
input[aria-invalid="true"], .campo-mal {
  border-color: var(--critical);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--critical) 12%, transparent);
}
select {
  appearance: none;
  padding-right: var(--sp-6);
  background-image: linear-gradient(45deg, transparent 50%, var(--text-muted) 50%),
                    linear-gradient(135deg, var(--text-muted) 50%, transparent 50%);
  background-position: calc(100% - 17px) center, calc(100% - 12px) center;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
}

/* ==========================================================================
   7 · Tablas
   ========================================================================== */

table.data { width: 100%; border-collapse: collapse; font-size: var(--t-secundario); }
table.data thead th {
  font-size: var(--t-meta); font-weight: var(--peso-fuerte);
  text-transform: uppercase; letter-spacing: .05em;
  color: var(--text-muted);
  background: var(--surface-2);
  padding: var(--sp-2) var(--sp-3);
  border-bottom: 1px solid var(--border);
  position: sticky; top: 0; z-index: 1;
}
table.data thead th:first-child { border-top-left-radius: var(--radius-sm); }
table.data thead th:last-child { border-top-right-radius: var(--radius-sm); }
table.data td { padding: var(--celda-y) var(--sp-3); border-bottom: 1px solid var(--grid); }
table.data tbody tr { transition: background var(--rapido) var(--curva); }
table.data tbody tr:hover { background: var(--surface-2); }
table.data tbody tr:last-child td { border-bottom: 0; }

/* ==========================================================================
   8 · Etiquetas, avisos y pastillas
   ========================================================================== */

.badge {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 2px 8px; border-radius: var(--radius-xs);
  font-size: var(--t-meta); font-weight: var(--peso-medio);
  background: var(--surface-2); color: var(--text-secondary);
  border: 1px solid var(--border);
}
.badge--acento { background: var(--accent-soft); color: var(--accent); border-color: var(--accent-border); }
.badge--bueno { background: color-mix(in srgb, var(--good) 10%, var(--surface-1)); color: var(--success-text); border-color: color-mix(in srgb, var(--good) 28%, var(--border)); }
.badge--malo { background: color-mix(in srgb, var(--critical) 10%, var(--surface-1)); color: var(--critical); border-color: color-mix(in srgb, var(--critical) 28%, var(--border)); }

.pill {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 3px 9px; border-radius: var(--radius-pill);
  font-size: var(--t-meta); font-weight: var(--peso-medio);
}

/* Aviso dentro de una vista: una franja de color a la izquierda, nada más. */
.alerta {
  display: grid; grid-template-columns: auto 1fr; gap: var(--sp-3);
  align-items: start;
  padding: var(--sp-3) var(--sp-4);
  border: 1px solid var(--border);
  border-left: 3px solid var(--text-muted);
  border-radius: var(--radius-sm);
  background: var(--surface-1);
}
.alerta__icono { font-size: 15px; line-height: 1.4; color: var(--text-muted); }
.alerta strong { display: block; font-size: var(--t-cuerpo); font-weight: var(--peso-fuerte); }
.alerta span { font-size: var(--t-secundario); color: var(--text-secondary); }
.alerta--info { border-left-color: var(--accent); background: var(--accent-soft); }
.alerta--info .alerta__icono { color: var(--accent); }
.alerta--ojo { border-left-color: var(--warning); }
.alerta--mal { border-left-color: var(--critical); }
.alerta--mal .alerta__icono { color: var(--critical); }
.alerta--bien { border-left-color: var(--good); }
.alerta--bien .alerta__icono { color: var(--success-text); }

/* ==========================================================================
   9 · Pestañas
   ========================================================================== */

.tabs {
  display: flex; gap: var(--sp-1); flex-wrap: wrap;
  border-bottom: 1px solid var(--border);
  margin-bottom: var(--sp-4);
}
.tabs__item {
  min-height: 40px; padding: 0 var(--sp-3);
  background: none; border: 0;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  color: var(--text-secondary);
  font-family: inherit; font-size: var(--t-cuerpo); font-weight: var(--peso-medio);
  cursor: pointer;
  transition: color var(--rapido) var(--curva), border-color var(--rapido) var(--curva);
}
.tabs__item:hover { color: var(--text-primary); }
.tabs__item[aria-selected="true"] { color: var(--accent); border-bottom-color: var(--accent); }

/* ==========================================================================
   10 · Paginación
   ========================================================================== */

.paginacion {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--sp-3); flex-wrap: wrap;
  padding-top: var(--sp-3); margin-top: var(--sp-3);
  border-top: 1px solid var(--border);
}
.paginacion__info { font-size: var(--t-meta); color: var(--text-muted); }
.paginacion__botones { display: flex; gap: var(--sp-1); }

/* ==========================================================================
   11 · Vacío, cargando y error
   ==========================================================================
   Los tres se parecen a propósito: mismo hueco, misma jerarquía. Lo único que
   cambia es qué se puede hacer a continuación. */

.estado {
  display: grid; gap: var(--sp-3); justify-items: center; text-align: center;
  padding: var(--sp-6) var(--sp-4);
}
.estado__icono {
  width: 44px; height: 44px; border-radius: var(--radius-pill);
  display: grid; place-items: center;
  background: var(--surface-2); color: var(--text-muted);
  font-size: 19px;
}
.estado strong { font-size: var(--t-cuerpo); font-weight: var(--peso-fuerte); }
.estado span { font-size: var(--t-secundario); color: var(--text-secondary); max-width: 44ch; line-height: 1.55; }
.estado--error .estado__icono { background: color-mix(in srgb, var(--critical) 10%, var(--surface-1)); color: var(--critical); }

.empty { padding: var(--sp-6) var(--sp-4); }
.empty strong { font-size: var(--t-cuerpo); color: var(--text-primary); font-weight: var(--peso-fuerte); }

/* Esqueletos: la forma de lo que viene, sin números inventados. */
@keyframes brilloEsqueleto {
  from { background-position: -160% 0; }
  to   { background-position: 260% 0; }
}
.hueso {
  border-radius: var(--radius-xs);
  background: linear-gradient(100deg,
    var(--surface-2) 28%, var(--n-100) 46%, var(--surface-2) 62%);
  background-size: 260% 100%;
  animation: brilloEsqueleto 1.5s linear infinite;
}
.hueso--linea { height: 12px; }
.hueso--titulo { height: 20px; width: 45%; }
.hueso--cifra { height: 32px; width: 60%; }
.hueso--fila { height: 44px; }
.esqueleto { display: grid; gap: var(--sp-3); }

/* ==========================================================================
   12 · Modales
   ========================================================================== */

.modal {
  border-radius: var(--radius);
  border: 1px solid var(--border);
  box-shadow: var(--shadow-alta);
  animation: entraModal var(--normal) var(--curva);
}
@keyframes entraModal {
  from { opacity: 0; transform: translateY(10px) scale(.985); }
  to   { opacity: 1; transform: none; }
}
.modal__head { padding-bottom: var(--sp-3); border-bottom: 1px solid var(--border); }
.modal__head h2 { font-size: 16px; font-weight: var(--peso-fuerte); }
.modal__foot {
  display: flex; justify-content: flex-end; gap: var(--sp-2);
  padding-top: var(--sp-4); margin-top: var(--sp-4);
  border-top: 1px solid var(--border);
}

/* ==========================================================================
   13 · Navegación lateral
   ==========================================================================
   Agrupada por para-qué-sirve, no por orden histórico. El grupo lleva su rótulo
   y lo activo se marca con fondo y con una barra: color solo no basta para
   quien no distingue el turquesa. */

.sidebar__panel { padding: var(--sp-4); gap: var(--sp-4); }

.brand { gap: var(--sp-3); padding-bottom: var(--sp-2); }
.brand strong { font-size: 14.5px; font-weight: var(--peso-fuerte); letter-spacing: -.01em; }
.brand span { font-size: var(--t-meta); color: var(--text-muted); }

.nav { display: grid; gap: var(--sp-4); }
.nav__grupo { display: grid; gap: 2px; }
.nav__grupo-rotulo {
  font-size: var(--t-meta); font-weight: var(--peso-fuerte);
  text-transform: uppercase; letter-spacing: .07em;
  color: var(--text-muted);
  padding: 0 var(--sp-2) var(--sp-1);
}

.nav__item {
  position: relative;
  display: flex; align-items: center; gap: var(--sp-3);
  width: 100%; min-height: 40px;
  padding: 0 var(--sp-3);
  background: none; border: 0; border-radius: var(--radius-sm);
  color: var(--text-secondary);
  font-family: inherit; font-size: var(--t-cuerpo); font-weight: var(--peso-normal);
  text-align: left; cursor: pointer;
  transition: background var(--rapido) var(--curva), color var(--rapido) var(--curva);
}
.nav__item:hover { background: var(--surface-2); color: var(--text-primary); }
.nav__item:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.nav__icon {
  width: 18px; text-align: center; font-size: 14px;
  color: var(--text-muted); flex: none;
  transition: color var(--rapido) var(--curva);
}
.nav__item:hover .nav__icon { color: var(--text-secondary); }

.nav__item[aria-current="page"] {
  background: var(--accent-soft);
  color: var(--accent);
  font-weight: var(--peso-medio);
}
.nav__item[aria-current="page"] .nav__icon { color: var(--accent); }
/* Nada de barras ni cajas: el fondo teñido y el texto en acento bastan, y el
   fondo es una señal que funciona también sin distinguir el color. */

.nav__badge {
  margin-left: auto;
  min-width: 20px; padding: 1px 6px;
  border-radius: var(--radius-pill);
  background: var(--surface-sunken); color: var(--text-secondary);
  font-size: var(--t-meta); font-weight: var(--peso-medio);
  text-align: center; font-variant-numeric: tabular-nums;
}
.nav__item[aria-current="page"] .nav__badge { background: var(--surface-1); color: var(--accent); }

/* ==========================================================================
   14 · Cabecera de la pantalla
   ==========================================================================
   Dónde estoy (miga), qué estoy viendo (título) y qué puedo hacer (acción). */

.topbar {
  gap: var(--sp-3);
  padding: var(--sp-4) var(--sp-5);
  border-bottom: 1px solid var(--border);
  background: var(--surface-1);
}
.miga {
  display: flex; align-items: center; gap: 6px;
  font-size: var(--t-meta); color: var(--text-muted);
  margin-bottom: 2px;
}
.miga button {
  background: none; border: 0; padding: 0;
  color: var(--text-muted); font-family: inherit; font-size: inherit;
  cursor: pointer; border-radius: 3px;
}
.miga button:hover { color: var(--accent); text-decoration: underline; }
.miga span[aria-hidden] { opacity: .6; }

.view { padding: var(--sp-5); gap: var(--sp-5); background: transparent; }

/* ==========================================================================
   15 · Rejillas de contenido
   ========================================================================== */

.grid { display: grid; gap: var(--sp-3); }
.grid--2 { grid-template-columns: repeat(auto-fit, minmax(min(340px, 100%), 1fr)); }
.grid--tiles { grid-template-columns: repeat(auto-fit, minmax(min(210px, 100%), 1fr)); }

/* ==========================================================================
   16 · Movimiento
   ========================================================================== */

@keyframes entraArriba {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: none; }
}
@keyframes aparece { from { opacity: 0; } to { opacity: 1; } }
@keyframes pulsoAcento {
  0%   { box-shadow: 0 0 0 0 color-mix(in srgb, var(--accent) 40%, transparent); }
  70%  { box-shadow: 0 0 0 14px color-mix(in srgb, var(--accent) 0%, transparent); }
  100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--accent) 0%, transparent); }
}
@keyframes trazaCheck { from { stroke-dashoffset: 34; } to { stroke-dashoffset: 0; } }

.entra {
  animation: entraArriba var(--normal) var(--curva) backwards;
  animation-delay: calc(var(--i, 0) * 45ms);
}
.aparece {
  animation: aparece var(--normal) var(--curva) backwards;
  animation-delay: calc(var(--i, 0) * 45ms);
}
.pulsa { animation: pulsoAcento 900ms var(--curva); }

.marca-ok {
  width: 52px; height: 52px; border-radius: var(--radius-pill);
  display: grid; place-items: center; margin: 0 auto;
  background: var(--accent-soft);
  animation: pulsoAcento 900ms var(--curva) 2;
}
.marca-ok svg { width: 28px; height: 28px; }
.marca-ok path {
  fill: none; stroke: var(--accent); stroke-width: 3.2;
  stroke-linecap: round; stroke-linejoin: round;
  stroke-dasharray: 34;
  animation: trazaCheck 400ms var(--curva) 100ms backwards;
}

/* ==========================================================================
   17 · Inicio
   ==========================================================================
   La pantalla de entrada: resumen arriba, acciones, y el detalle debajo. */

.inicio { display: grid; gap: var(--sp-5); align-content: start; }

/* La cifra protagonista. Vive en una tarjeta normal, no en un bloque de color:
   lo que la destaca es el tamaño y que es el único número en turquesa. */
.resumen-hero {
  display: grid; gap: var(--sp-5);
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
}
.resumen-hero__cifra { display: grid; gap: var(--sp-2); }
.resumen-hero__valor {
  font-size: var(--t-cifra-alta); font-weight: var(--peso-fuerte);
  letter-spacing: -.025em; line-height: 1;
  font-variant-numeric: tabular-nums;
  color: var(--accent);
}
.resumen-hero__pie { font-size: var(--t-secundario); color: var(--text-secondary); max-width: 46ch; line-height: 1.5; }

.aro { display: block; width: 112px; height: 112px; flex: none; }
.aro__pista { fill: none; stroke: var(--surface-sunken); stroke-width: 8; }
.aro__valor {
  fill: none; stroke: var(--accent); stroke-width: 8; stroke-linecap: round;
  transform: rotate(-90deg); transform-origin: 50% 50%;
  transition: stroke-dashoffset var(--lento) var(--curva);
}
.aro__texto {
  font-size: 19px; font-weight: var(--peso-fuerte);
  fill: var(--text-primary);
  font-variant-numeric: tabular-nums;
}
.aro__sub { font-size: 8.5px; fill: var(--text-muted); text-transform: uppercase; letter-spacing: .08em; }

@media (max-width: 620px) {
  .resumen-hero { grid-template-columns: 1fr; justify-items: start; gap: var(--sp-4); }
  .aro { width: 96px; height: 96px; }
}

/* Acciones: la principal con acento, las demás neutras. Tres como máximo. */
.acciones {
  display: grid; gap: var(--sp-3);
  grid-template-columns: repeat(auto-fit, minmax(min(230px, 100%), 1fr));
}
.accion {
  display: grid; grid-template-columns: 38px 1fr auto; align-items: center;
  gap: var(--sp-3);
  min-height: 68px;
  padding: var(--sp-3) var(--sp-4);
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  text-align: left; cursor: pointer;
  color: var(--text-primary); font-family: inherit;
  transition:
    border-color var(--rapido) var(--curva),
    background var(--rapido) var(--curva),
    transform var(--rapido) var(--curva);
}
.accion:hover { border-color: var(--border-strong); background: var(--surface-2); }
.accion:active { transform: scale(.99); }
.accion:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.accion__icono {
  display: grid; place-items: center;
  width: 38px; height: 38px; border-radius: var(--radius-sm);
  background: var(--surface-2); color: var(--text-secondary);
  font-size: 17px; line-height: 1;
}
.accion__texto { display: grid; gap: 2px; min-width: 0; }
.accion__texto strong { font-size: var(--t-cuerpo); font-weight: var(--peso-fuerte); }
.accion__texto span { font-size: var(--t-meta); color: var(--text-muted); }
.accion__flecha { color: var(--text-muted); font-size: 16px; transition: transform var(--rapido) var(--curva); }
.accion:hover .accion__flecha { transform: translateX(3px); }

.accion--principal { border-color: var(--accent-border); background: var(--accent-soft); }
.accion--principal:hover { background: var(--accent-suave); border-color: var(--accent); }
.accion--principal .accion__icono { background: var(--accent); color: var(--accent-ink); }
.accion--principal .accion__flecha { color: var(--accent); }

/* Lista de movimientos: filas altas, importe a la derecha, nada más. */
.lista { display: grid; }
.lista__fila {
  display: grid; grid-template-columns: 34px 1fr auto; align-items: center;
  gap: var(--sp-3);
  width: 100%; min-height: 52px;
  padding: var(--sp-2) var(--sp-1);
  background: none; border: 0; border-bottom: 1px solid var(--grid);
  text-align: left; cursor: pointer; color: inherit; font-family: inherit;
  transition: background var(--rapido) var(--curva);
}
.lista__fila:last-child { border-bottom: 0; }
.lista__fila:hover { background: var(--surface-2); }
.lista__punto {
  width: 32px; height: 32px; border-radius: var(--radius-pill);
  display: grid; place-items: center; font-size: 13px;
  background: var(--surface-2); color: var(--text-secondary);
}
.lista__texto { display: grid; gap: 1px; min-width: 0; }
.lista__texto strong {
  font-size: var(--t-cuerpo); font-weight: var(--peso-medio);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.lista__texto span { font-size: var(--t-meta); color: var(--text-muted); }
.lista__monto { font-size: var(--t-cuerpo); font-weight: var(--peso-fuerte); font-variant-numeric: tabular-nums; }
.lista__monto[data-signo="mas"] { color: var(--success-text); }

/* ==========================================================================
   18 · Bienvenida
   ==========================================================================
   Primera vez: ni una gráfica vacía ni un cero. Un texto y una acción. */

.bienvenida {
  display: grid; gap: var(--sp-5); justify-items: center; text-align: center;
  max-width: 520px; margin: clamp(8px, 5vh, 56px) auto;
  padding: 0 var(--sp-4) var(--sp-6);
}
/* Sin fondo de acento: el logotipo ya es turquesa y quedaría turquesa sobre
   turquesa. Solo se le da sitio. */
.bienvenida__marca { display: grid; place-items: center; }
.bienvenida__marca img { width: auto; height: 44px; }
.bienvenida h1 {
  font-size: clamp(23px, 5.5vw, 28px); font-weight: var(--peso-fuerte);
  letter-spacing: -.02em; line-height: 1.25; margin: 0;
}
.bienvenida__texto {
  color: var(--text-secondary); font-size: 15px; line-height: 1.6;
  max-width: 42ch; margin: 0;
}
.bienvenida .btn--gigante { width: 100%; max-width: 340px; }
.bienvenida__otra {
  background: none; border: 0; color: var(--text-secondary);
  font-family: inherit; font-size: var(--t-secundario); cursor: pointer;
  min-height: 36px; padding: 0 var(--sp-2); border-radius: var(--radius-xs);
  transition: color var(--rapido) var(--curva);
}
.bienvenida__otra:hover { color: var(--accent); text-decoration: underline; }

/* Las tres promesas: un compartimento con tres filas, no tres tarjetas. */
.promesas {
  display: grid; gap: var(--sp-4); width: 100%; text-align: left;
  padding: var(--sp-4);
  border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--surface-1);
}
.promesa { display: grid; grid-template-columns: 28px 1fr; align-items: start; gap: var(--sp-3); }
.promesa__icono {
  width: 28px; height: 28px; border-radius: var(--radius-xs);
  display: grid; place-items: center;
  background: var(--accent-soft); color: var(--accent); font-size: 13px;
}
.promesa strong { display: block; font-size: var(--t-cuerpo); font-weight: var(--peso-fuerte); }
.promesa span { font-size: var(--t-secundario); color: var(--text-secondary); line-height: 1.5; }

/* ==========================================================================
   19 · Menos movimiento
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 1ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 1ms !important;
  }
  .hueso { animation: none; background: var(--surface-2); }
  .entra, .aparece { animation: none; opacity: 1; transform: none; }
}

/* ==========================================================================
   20 · Compatibilidad
   ==========================================================================
   .tile es ahora un alias de .kpi (misma pieza, dos nombres por historia).
   Las clases internas antiguas se mapean para que nada quede sin estilo. */

.tile { display: grid; gap: var(--sp-2); align-content: start; }
.tile__label { font-size: var(--t-etiqueta); font-weight: var(--peso-medio); color: var(--text-secondary); }
.tile__value {
  font-size: var(--t-cifra); font-weight: var(--peso-fuerte);
  letter-spacing: -.02em; line-height: 1.1; font-variant-numeric: tabular-nums;
}
.tile__foot, .kpi__pie { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; }
.tile__foot span, .kpi__pie span { font-size: var(--t-meta); color: var(--text-muted); }
.tile--nota { background: var(--surface-2); border-color: transparent; }

/* La variación antigua (.delta) comparte aspecto con la nueva (.var). */
.delta {
  display: inline-flex; align-items: center; gap: 3px;
  font-size: var(--t-meta); font-weight: var(--peso-medio);
  font-variant-numeric: tabular-nums;
  padding: 2px 6px; border-radius: var(--radius-xs);
}
.delta--good { color: var(--success-text); background: color-mix(in srgb, var(--good) 10%, var(--surface-1)); }
.delta--bad { color: var(--critical); background: color-mix(in srgb, var(--critical) 10%, var(--surface-1)); }
.delta--flat { color: var(--text-muted); background: var(--surface-2); }

/* ==========================================================================
   21 · Responsive
   ==========================================================================
   No se encoge: se recompone. Lo que cambia en cada corte es la ESTRUCTURA
   (cuántas columnas, qué se apila, qué se convierte en scroll), no el tamaño
   de la letra. */

/* Portátil: el lateral se estrecha y el contenido gana el hueco. */
@media (max-width: 1200px) {
  .app { grid-template-columns: 216px 1fr; }
  .view { padding: var(--sp-4); gap: var(--sp-4); }
}

/* Tableta: fuera el lateral fijo (pasa a off-canvas, ya existía) y los pares de
   tarjetas se ponen en una sola columna, que a 700px no caben dos gráficos. */
@media (max-width: 1023px) {
  .topbar { padding: var(--sp-3) var(--sp-4); }
  .grid--2 { grid-template-columns: 1fr; }
  .seccion__head { align-items: flex-start; }
}

/* Móvil: los KPI en dos columnas, no en cuatro filas. Una columna de cifras
   sueltas obliga a recordar la de arriba para comparar; en 2×2 se ven juntas. */
@media (max-width: 640px) {
  .view { padding: var(--sp-3); gap: var(--sp-4); }
  .kpis { grid-template-columns: 1fr 1fr; gap: var(--sp-2); }
  .kpi__valor, .tile__value { font-size: 20px; }
  .card { padding: var(--sp-4); }
  .card__head { margin-bottom: var(--sp-3); }
  /* La acción principal, la primera y a todo lo ancho. */
  .acciones { grid-template-columns: 1fr; }
  .accion { min-height: 60px; }
  /* Las pestañas se desplazan en vez de partirse en dos filas. */
  .tabs { flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; }
  .tabs::-webkit-scrollbar { display: none; }
  /* Los botones de una cabecera pasan a ocupar la fila entera. */
  .card__tools, .seccion__acciones { width: 100%; }
  .modal__foot { flex-direction: column-reverse; }
  .modal__foot .btn { width: 100%; }
}

/* Teléfono pequeño: ahí sí, una columna. */
@media (max-width: 380px) {
  .kpis { grid-template-columns: 1fr; }
}

/* ==========================================================================
   22 · Carcasa
   ==========================================================================
   Lienzo gris, hojas blancas. El lateral y la cabecera son blancos y se
   separan del lienzo con un borde de pelo, nunca con una sombra. */

body { background: var(--page); color: var(--text-primary); }
/* .app y .view NO llevan fondo: body ya pinta --page y .app mide 100vh, así
   que era pintar dos veces lo mismo. Importa desde que hay una capa de fondo
   fija detrás (el papel y las luces de la puerta): un fondo opaco aquí la
   tapaba entera, y la regla parecía no funcionar cuando sí lo hacía. */
.app { background: transparent; }

.sidebar { background: var(--surface-1); border-right: 1px solid var(--border); }

/* ---------- Tarjetas plegables (solo en el teléfono) ----------

   Lo pone js/plegar.js, y solo por debajo de 640 px. La cabecera se queda
   siempre visible: así la pantalla se lee como un índice de lo que hay dentro,
   no como una fila de cajas cerradas. */
.bloque--plegable > .card__head,
.bloque--plegable > .seccion__head {
  display: flex; align-items: center; gap: var(--sp-3);
  cursor: default;
}
.card__tirador {
  margin-left: auto; flex: 0 0 auto;
  width: 40px; height: 40px;
  display: inline-flex; align-items: center; justify-content: center;
  background: transparent; border: 0; border-radius: var(--radius-sm);
  color: var(--text-secondary); cursor: pointer;
}
.card__tirador:hover { background: var(--surface-2); color: var(--text-primary); }
/* La flecha se dibuja con un borde girado en vez de un carácter: un ▾ cambia de
   tamaño y de línea base según la fuente del sistema, y aquí tiene que quedar
   centrado siempre. */
.card__tirador::before {
  content: ''; width: 9px; height: 9px;
  border-right: 2px solid currentColor; border-bottom: 2px solid currentColor;
  transform: translateY(-2px) rotate(45deg);
  transition: transform var(--rapido) var(--curva);
}
.bloque--abierto > .card__head .card__tirador::before,
.bloque--abierto > .seccion__head .card__tirador::before {
  transform: translateY(2px) rotate(225deg);
}
/* Una tarjeta plegada no necesita el relleno de abajo: sería un hueco vacío
   debajo del título. */
.bloque--plegable.card:not(.bloque--abierto) { padding-bottom: var(--sp-2); }
.card__cuerpo { display: grid; gap: var(--sp-4); }

@media (prefers-reduced-motion: reduce) {
  .card__tirador::before { transition: none; }
}

/* ---------- La barra del pulgar (solo en el teléfono) ----------

   Lo pone js/barra-movil.js, y solo por debajo de 640 px. En una pantalla ancha
   la barra lateral ya enseña las catorce secciones: dos navegaciones a la vez
   diciendo cosas distintas confunden más de lo que ayudan.  */

.pulgar {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 40;
  display: grid; grid-template-columns: repeat(5, 1fr);
  /* El fondo es casi opaco y con desenfoque: se intuye que hay contenido debajo
     —así se sabe que la pantalla sigue— sin que ese contenido moleste. */
  background: color-mix(in srgb, var(--surface-1) 92%, transparent);
  backdrop-filter: blur(12px);
  border-top: 1px solid var(--border);
  /* El hueco del indicador de inicio en los teléfonos sin botón. Sin esto, el
     último milímetro de los botones cae debajo de la raya del sistema y no se
     puede pulsar. */
  padding-bottom: env(safe-area-inset-bottom, 0px);
}

.pulgar__btn {
  display: grid; justify-items: center; gap: 3px;
  padding: 8px 2px 6px;
  /* 56 px de alto: por encima del mínimo cómodo para un dedo, y lo bastante
     bajo para no comerse la pantalla en un teléfono corto. */
  min-height: 56px;
  background: none; border: 0; cursor: pointer;
  color: var(--text-muted);
  font-size: 10.5px; font-weight: var(--peso-fuerte);
  -webkit-tap-highlight-color: transparent;
  transition: color var(--rapido) var(--curva);
}
.pulgar__ico { width: 22px; height: 22px; }
.pulgar__txt { line-height: 1; letter-spacing: .01em; }

/* El activo, con el acento y un punto encima. El punto existe porque solo con
   el color no se entera quien no distingue turquesa de gris — una de cada doce
   personas. */
.pulgar__btn--aqui { color: var(--accent); }
.pulgar__btn--aqui::before {
  /* Anclado al borde de arriba del botón. Sin `top`/`left` el pseudoelemento se
     queda en su posición estática —que en una rejilla es la primera celda— y el
     punto acababa pintado ENCIMA del icono en vez de sobre él. */
  content: ''; position: absolute; top: 0; left: 50%;
  transform: translateX(-50%);
  width: 16px; height: 3px; border-radius: var(--radius-pill);
  background: var(--accent);
  animation: pulgarMarca var(--normal) var(--curva);
}
@keyframes pulgarMarca {
  from { transform: translateX(-50%) scaleX(0); opacity: 0; }
  to   { transform: translateX(-50%) scaleX(1); opacity: 1; }
}
.pulgar__btn { position: relative; }

/* La respuesta al dedo. En un teléfono no hay hover: si no se hunde al tocar,
   la pantalla parece que no ha registrado el toque y se pulsa otra vez. */
.pulgar__btn:active { transform: scale(.92); color: var(--accent); }

/* El del centro es la acción, no un destino: sube los gastos, que es lo que hay
   que hacer la primera vez y repetir cada mes. Se distingue con el acento. */
.pulgar__btn--centro .pulgar__ico {
  width: 42px; height: 42px; padding: 10px;
  border-radius: var(--radius-sm);
  background: var(--accent); color: var(--accent-ink);
  margin-top: -14px;
  /* Sin sombra teñida de acento: la casa no las usa (pruebas/sistema-visual.mjs),
     porque compiten con el botón principal. Aquí además sobraría — el relleno
     turquesa sobre una barra apagada ya lo separa de los otros cuatro. */
  transition: transform var(--rapido) var(--curva);
}
.pulgar__btn--centro:active .pulgar__ico { transform: scale(.9); }
.pulgar__btn--centro.pulgar__btn--aqui::before { display: none; }

/* Y el contenido deja sitio para la barra, o sus últimas filas quedan debajo y
   no se pueden ni leer ni tocar. */
body.con-pulgar .view { padding-bottom: calc(76px + env(safe-area-inset-bottom, 0px)); }
body.con-pulgar .pie { padding-bottom: calc(76px + env(safe-area-inset-bottom, 0px)); }
/* Los avisos flotantes suben por encima de la barra. */
body.con-pulgar .toasts { bottom: calc(72px + env(safe-area-inset-bottom, 0px)); }

@media (prefers-reduced-motion: reduce) {
  .pulgar__btn, .pulgar__btn--centro .pulgar__ico { transition: none; }
  .pulgar__btn:active { transform: none; }
  .pulgar__btn--aqui::before { animation: none; }
}

/* ---------- Conexiones bancarias ---------- */

/* ── El widget de Bridge, enmarcado ──

   Lo de dentro del iframe es de Bridge y no se toca: es otro origen, y además
   tiene que verse que es suyo (ahí se teclea la contraseña del banco). Lo que
   se hace aquí es el marco: nuestro fondo detrás y su tarjeta como un panel
   que flota sobre la aplicación, en vez de una pantalla que la tapa entera. */
.bridge-fondo {
  position: fixed; inset: 0; z-index: 9998;
  background: color-mix(in srgb, var(--page) 74%, transparent);
  backdrop-filter: blur(6px);
  animation: bridgeEntra var(--normal) var(--curva);
}

/* Con !important, que aquí no es pereza: Bridge escribe la geometría del iframe
   como estilo EN LÍNEA (top/left/width/height), y un estilo en línea gana a
   cualquier clase. Sin esto el panel se va a la esquina y sale medio fuera de la
   pantalla — se vio en una captura, no leyendo el archivo. */
.bridge-panel {
  position: fixed !important; z-index: 9999; border: 0;
  top: 50% !important; left: 50% !important;
  transform: translate(-50%, -50%) !important;
  /* Alto generoso: los pasos no miden lo mismo —elegir banco es una lista larga
     y meter las credenciales son dos campos— y el iframe no puede medirse solo
     desde fuera. Se toma la medida del paso más largo y los cortos respiran. */
  width: min(460px, 94vw) !important;
  height: min(700px, 88vh) !important;
  border-radius: var(--radius-lg);
  overflow: hidden;
  box-shadow: 0 24px 64px -24px rgba(0, 0, 0, .8);
  animation: bridgeSube var(--normal) var(--curva);
}

/* En un teléfono no se enmarca nada: 460 px de panel sobre una pantalla de 390
   sería un marco más ancho que el hueco. Ocupa lo que hay, con las esquinas
   redondeadas abajo para que no parezca una página nueva. */
@media (max-width: 560px) {
  .bridge-panel {
    width: 100vw !important; height: 100dvh !important;
    border-radius: 0;
  }
}

@keyframes bridgeEntra { from { opacity: 0; } }
@keyframes bridgeSube {
  from { opacity: 0; transform: translate(-50%, -46%) scale(.98); }
}

/* Quien pidió que nada se mueva ve el panel ya puesto. */
@media (prefers-reduced-motion: reduce) {
  .bridge-fondo, .bridge-panel { animation: none; }
}


/* Un bloque que explica algo antes de que la persona decida. No es una
   alerta: no ha pasado nada malo. Es el sitio donde se dice que hay un
   tercero de por medio, y eso tiene que leerse antes de pulsar, no después. */
.nota {
  display: grid; gap: var(--sp-2);
  padding: var(--sp-4); border-radius: var(--radius-sm);
  background: var(--surface-2); border: 1px solid var(--border);
  font-size: var(--t-menor); color: var(--text-secondary);
}

/* Una casilla que no es una línea: lleva dentro un nombre, un balance y un
   desplegable. Se alinea arriba para que el cuadrito quede junto al nombre
   y no flotando a media altura del bloque. */
.casilla--bloque {
  align-items: start; gap: var(--sp-3);
  padding: var(--sp-3); border: 1px solid var(--border);
  border-radius: var(--radius-sm); cursor: pointer;
}
.casilla--bloque:hover { border-color: var(--border-strong); }
.casilla--bloque > .stack { gap: 4px; }
.stack--fino { display: grid; gap: 4px; }

/* El aviso de «esto se parece a algo que ya tienes». Va en el color de
   atención, no en el de error: no es un fallo, es una decisión que tomar. */
.aviso-linea { color: var(--warning); font-size: var(--t-meta); }

/* El estado de una conexión, de un vistazo. El punto lleva el color y el
   texto dice qué pasa: solo con el color no se entera quien no distingue
   verde de rojo, que es una de cada doce personas. */
.estado-banco { display: inline-flex; align-items: center; gap: 6px; font-size: var(--t-meta); }
.estado-banco::before {
  content: ''; width: 8px; height: 8px; background: var(--text-muted);
  border-radius: var(--radius-pill);
}
.estado-banco--conectada::before { background: var(--good); }
.estado-banco--sincronizando::before { background: var(--accent); }
.estado-banco--reautenticar::before { background: var(--warning); }
.estado-banco--error::before { background: var(--critical); }

.banco-fila {
  display: flex; flex-wrap: wrap; gap: var(--sp-3); align-items: center;
  justify-content: space-between;
  padding: var(--sp-3) 0; border-bottom: 1px solid var(--border);
}
.banco-fila:last-child { border-bottom: 0; }

/* ---------- Hojas sobre la tinta (solo en oscuro) ----------

   Detrás de todo esto hay una capa fija con el papel rayado y dos luces —el
   mismo fondo que la puerta de entrada—. Con las superficies opacas solo
   asomaba por las rendijas, y una textura a trozos parece un fallo de pintado,
   no profundidad. Dejando pasar un 6% se vuelve continua.

   El 6% sobre una textura que ya está al 3% no mueve el contraste bajo el
   texto de forma medible: no cuesta la legibilidad de ninguna cifra.

   Sin backdrop-filter a propósito: hay pantallas con veinte tarjetas, y veinte
   desenfoques a pantalla completa se notan en un portátil modesto. */
@media (prefers-color-scheme: dark) {
  :root:where(:not([data-theme="light"])) .card,
  :root:where(:not([data-theme="light"])) .sidebar {
    background: color-mix(in srgb, var(--surface-1) 94%, transparent);
  }
}
:root[data-theme="dark"] .card,
:root[data-theme="dark"] .sidebar {
  background: color-mix(in srgb, var(--surface-1) 94%, transparent);
}
.sidebar__panel { padding: var(--sp-4) var(--sp-3); }

/* La marca, en su caja con borde, como la referencia. */
.brand { padding: var(--sp-1) var(--sp-2) var(--sp-3); }
/* La caja con borde se fue con el logotipo dibujado: el archivo real ya
   trae su propio marco. */

/* Los iconos del menú son SVG que heredan el color del texto. */
.nav__item .ico, .nav__icon .ico { flex: none; }
.nav__icon { display: inline-flex; align-items: center; justify-content: center; }

/* ---------- Cabecera ---------- */

.topbar {
  align-items: center;
  background: var(--surface-1);
  border-bottom: 1px solid var(--border);
}
.topbar__head { flex: 1 1 auto; min-width: 0; }
.topbar__derecha {
  display: flex; align-items: center; gap: var(--sp-2);
  flex: none;
}

/* Buscador: un campo tranquilo con su atajo escrito dentro. */
.buscador {
  display: flex; align-items: center; gap: var(--sp-2);
  min-width: 260px; height: 38px;
  padding: 0 var(--sp-2) 0 var(--sp-3);
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--surface-1);
  transition: border-color var(--rapido) var(--curva), box-shadow var(--rapido) var(--curva);
}
.buscador:focus-within { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
.buscador__ico { display: inline-flex; color: var(--text-muted); flex: none; }
.buscador input {
  flex: 1 1 auto; min-width: 0; min-height: 0; height: 100%;
  border: 0; padding: 0; background: none;
  font-size: var(--t-secundario);
}
.buscador input:hover, .buscador input:focus-visible { border: 0; box-shadow: none; }
.buscador input::placeholder { color: var(--text-muted); }
.buscador__atajo {
  flex: none;
  padding: 2px 6px; border-radius: var(--radius-xs);
  border: 1px solid var(--border); background: var(--surface-2);
  color: var(--text-muted); font-family: inherit; font-size: 11px;
}

/* Botón de solo icono: la campana y compañía. */
.icono-btn {
  position: relative;
  display: grid; place-items: center;
  width: 38px; height: 38px;
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--surface-1); color: var(--text-secondary);
  cursor: pointer;
  transition: background var(--rapido) var(--curva), color var(--rapido) var(--curva),
    border-color var(--rapido) var(--curva);
}
.icono-btn:hover { background: var(--surface-2); color: var(--text-primary); border-color: var(--border-strong); }
.icono-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.avisos-btn[data-hay="1"] { border-color: var(--accent-border); color: var(--accent); }
.avisos-btn__cuenta {
  position: absolute; top: -5px; right: -5px;
  min-width: 17px; height: 17px; padding: 0 4px;
  border-radius: var(--radius-pill);
  background: var(--critical); color: #fff;
  font-size: 10.5px; font-weight: var(--peso-fuerte);
  display: grid; place-items: center;
}

/* Chip de usuario. */
.usuario {
  display: flex; align-items: center; gap: var(--sp-2);
  height: 38px; padding: 0 var(--sp-2);
  border: 1px solid transparent; border-radius: var(--radius-sm);
  background: none; cursor: pointer; font-family: inherit;
  transition: background var(--rapido) var(--curva), border-color var(--rapido) var(--curva);
}
.usuario:hover { background: var(--surface-2); border-color: var(--border); }
.usuario:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.usuario__avatar {
  width: 28px; height: 28px; border-radius: var(--radius-pill);
  display: grid; place-items: center; flex: none;
  background: var(--accent); color: var(--accent-ink);
  font-size: 12.5px; font-weight: var(--peso-fuerte);
}
.usuario__texto { display: grid; text-align: left; line-height: 1.25; }
.usuario__texto strong { font-size: var(--t-secundario); font-weight: var(--peso-fuerte); color: var(--text-primary); }
.usuario__texto span { font-size: 11px; color: var(--text-muted); }
.usuario__flecha { color: var(--text-muted); font-size: 13px; }

@media (max-width: 1100px) {
  .buscador { min-width: 0; width: 38px; padding: 0; justify-content: center; }
  .buscador input, .buscador__atajo { display: none; }
  .usuario__texto, .usuario__flecha { display: none; }
}

/* ---------- Píldora del periodo ---------- */

/* Los filtros globales dejan de ser una fila de campos sueltos: se convierten en
   una píldora alineada a la derecha del contenido, como el rango de fechas de la
   referencia. */
/* Barra de contexto: qué periodo y qué cuenta se está mirando, más la acción
   principal. Sin fondo propio —vive sobre el lienzo, como el resto— y con las
   etiquetas a la vista: un desplegable que dice «Este mes» sin decir «Periodo»
   obliga a adivinar. */
.filters {
  display: flex; align-items: flex-end; gap: var(--sp-3);
  flex-wrap: wrap;
  padding: var(--sp-4) var(--sp-5) 0;
  background: none;
  min-width: 0;
}
.filters .field { flex: 0 1 auto; min-width: 0; }
.filters .field > span {
  font-size: var(--t-meta); font-weight: var(--peso-medio);
  color: var(--text-muted);
}
.filters select, .filters input[type="date"] {
  height: 38px; min-height: 38px;
  font-size: var(--t-secundario);
  background: var(--surface-1);
}
/* La acción principal se va al extremo, separada de los filtros: son cosas
   distintas y no deben leerse como una fila de controles iguales. */
.filters #btnQuickAdd { margin-left: auto; flex: none; }
.periodo-nav {
  display: inline-flex; align-items: center; gap: var(--sp-1);
  padding: 2px; border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--surface-1);
}
.periodo-nav span { font-size: var(--t-secundario); padding: 0 var(--sp-2); color: var(--text-secondary); }

/* ---------- Pie ---------- */

.pie {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--sp-3); flex-wrap: wrap;
  padding: var(--sp-4) var(--sp-5);
  border-top: 1px solid var(--border);
  background: var(--surface-1);
  font-size: var(--t-meta); color: var(--text-muted);
}
.pie__enlaces { display: flex; gap: var(--sp-4); }
.pie__enlaces button {
  background: none; border: 0; padding: 0;
  color: var(--text-muted); font-family: inherit; font-size: inherit;
  cursor: pointer; border-radius: 3px;
  transition: color var(--rapido) var(--curva);
}
.pie__enlaces button:hover { color: var(--accent); }

/* ==========================================================================
   23 · KPI con icono
   ==========================================================================
   Icono en cápsula a la izquierda, cifra a la derecha. La cápsula es gris y el
   icono gris oscuro: si las cuatro fueran turquesa, la fila entera gritaría. */

.kpi--ico {
  grid-template-columns: 44px 1fr;
  gap: var(--sp-3);
  align-items: center;
}
.kpi__capsula {
  width: 44px; height: 44px; border-radius: var(--radius-sm);
  display: grid; place-items: center; flex: none;
  background: var(--surface-2); color: var(--text-secondary);
}
.kpi--ico .kpi__cuerpo { display: grid; gap: 2px; min-width: 0; }
.kpi--ico .kpi__valor { font-size: 24px; }
.kpi--ico .kpi__label { font-size: var(--t-meta); }

/* La cápsula del KPI protagonista sí lleva acento: es uno, no cuatro. */
.kpi--destacado .kpi__capsula { background: var(--accent-soft); color: var(--accent); }

/* ==========================================================================
   24 · Actividad reciente
   ==========================================================================
   Icono circular, dos líneas de texto y el importe a la derecha. */

.actividad { display: grid; }
.actividad__fila {
  display: grid; grid-template-columns: 36px 1fr auto; align-items: center;
  gap: var(--sp-3);
  width: 100%; min-height: 56px;
  padding: var(--sp-2) 0;
  background: none; border: 0;
  text-align: left; cursor: pointer; color: inherit; font-family: inherit;
  border-radius: var(--radius-sm);
  transition: background var(--rapido) var(--curva);
}
.actividad__fila:hover { background: var(--surface-2); }
.actividad__ico {
  width: 36px; height: 36px; border-radius: var(--radius-pill);
  display: grid; place-items: center; flex: none;
  background: var(--surface-2); color: var(--text-secondary);
}
.actividad__texto { display: grid; gap: 1px; min-width: 0; }
.actividad__texto strong {
  font-size: var(--t-cuerpo); font-weight: var(--peso-medio);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.actividad__texto span { font-size: var(--t-meta); color: var(--text-muted); }
.actividad__monto { font-size: var(--t-cuerpo); font-weight: var(--peso-fuerte); font-variant-numeric: tabular-nums; }
.actividad__monto[data-signo="mas"] { color: var(--success-text); }

/* Enlace «Ver todo» de la cabecera de una tarjeta. */
.vertodo {
  background: none; border: 0; padding: 0;
  color: var(--accent); font-family: inherit; font-size: var(--t-secundario);
  font-weight: var(--peso-medio); cursor: pointer; border-radius: 3px;
  transition: opacity var(--rapido) var(--curva);
}
.vertodo:hover { opacity: .75; text-decoration: underline; }

/* ==========================================================================
   25 · Rejilla del tablero
   ==========================================================================
   Dos tercios para el gráfico y un tercio para la lista, como la referencia.
   En pantalla estrecha se apilan, con el gráfico primero. */

.tablero-2-1 {
  display: grid; gap: var(--sp-3);
  grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
  align-items: start;
}
.tablero-3 {
  display: grid; gap: var(--sp-3);
  grid-template-columns: repeat(3, minmax(0, 1fr));
  align-items: start;
}
@media (max-width: 1100px) {
  .tablero-2-1, .tablero-3 { grid-template-columns: 1fr; }
}

/* ==========================================================================
   25b · La respuesta: «¿puedo gastar?»
   ==========================================================================
   La tarjeta de arriba de Inicio, y la única cosa que se ve entera en un móvil
   sin desplazar. Tiene una cifra, un comparador de dos barras y una frase.

   La frase es lo importante. La cifra dice cuánto queda; la frase dice si eso es
   una buena noticia, que es lo que en realidad se venía a saber.

   El tono (bien / ojo / mal / neutro) lo pone la vista en data-tono y de ahí
   sale el color del borde superior, de la barra y de la señal. Un solo atributo
   gobierna los tres: si el color viviera en tres sitios, tarde o temprano
   dirían cosas distintas. */

.respuesta { display: grid; gap: var(--sp-4); position: relative; overflow: hidden; }
/* Una línea de color arriba, no un fondo teñido: el fondo de color hace que el
   texto encima pierda contraste y obliga a elegir entre la letra y el aviso. */
.respuesta::before {
  content: ""; position: absolute; inset: 0 0 auto; height: 3px;
  background: var(--tono, var(--accent));
}
.respuesta[data-tono="bien"]   { --tono: var(--good); }
.respuesta[data-tono="ojo"]    { --tono: var(--warning); }
.respuesta[data-tono="mal"]    { --tono: var(--critical); }
.respuesta[data-tono="neutro"] { --tono: var(--border-strong); }

.respuesta__cabeza {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: var(--sp-3); flex-wrap: wrap;
}
.respuesta__rotulo {
  margin: 0 0 2px; font-size: var(--t-etiqueta); font-weight: var(--peso-fuerte);
  text-transform: uppercase; letter-spacing: .07em; color: var(--text-muted);
}
.respuesta__cifra {
  font-size: var(--t-cifra-alta); font-weight: var(--peso-fuerte);
  letter-spacing: -.03em; line-height: 1.05;
  font-variant-numeric: tabular-nums; color: var(--text-primary);
}
.respuesta__pie { margin: 6px 0 0; font-size: var(--t-secundario); color: var(--text-secondary); }
.respuesta__nota { margin: 0; font-size: var(--t-meta); color: var(--text-muted); }
.respuesta__mas { flex: 0 0 auto; }

/* La frase. Lleva la señal delante para que se distinga de un pie de foto. */
.respuesta__dictamen {
  margin: 0; display: grid; grid-template-columns: auto 1fr; gap: var(--sp-2);
  align-items: start;
  font-size: var(--t-cuerpo); line-height: 1.45; color: var(--text-primary);
}
.respuesta__senal {
  width: 20px; height: 20px; border-radius: var(--radius-pill);
  display: grid; place-items: center;
  font-size: var(--t-meta); font-weight: var(--peso-fuerte);
  background: color-mix(in srgb, var(--senal, var(--text-muted)) 16%, transparent);
  color: var(--senal, var(--text-muted));
}
.respuesta__dictamen[data-tono="bien"]   { --senal: var(--good); }
.respuesta__dictamen[data-tono="ojo"]    { --senal: var(--warning); }
.respuesta__dictamen[data-tono="mal"]    { --senal: var(--critical); }
.respuesta__dictamen[data-tono="neutro"] { --senal: var(--text-muted); }

/* ---------- El comparador de ritmo ---------- */

/* Dos barras, una encima de otra y a la misma escala. La comparación se hace con
   el ojo: si la de arriba es más larga, vas gastando más rápido que el
   calendario. Eso no hay frase que lo diga tan rápido. */
.ritmo {
  display: grid; gap: var(--sp-3);
  padding: var(--sp-3) 0; border-top: 1px solid var(--border);
}
.ritmo__fila {
  display: grid; grid-template-columns: 1fr auto; gap: 4px var(--sp-3);
  align-items: baseline;
}
.ritmo__rotulo { font-size: var(--t-secundario); color: var(--text-secondary); }
.ritmo__cifra {
  font-size: var(--t-secundario); font-weight: var(--peso-fuerte);
  font-variant-numeric: tabular-nums; color: var(--text-primary);
}
.ritmo__carril {
  grid-column: 1 / -1; height: 8px; border-radius: var(--radius-pill);
  background: var(--surface-sunken); overflow: hidden;
}
.ritmo__relleno {
  display: block; height: 100%; border-radius: var(--radius-pill);
  background: var(--tono, var(--accent));
  transform: scaleX(var(--parte, 0)); transform-origin: left;
  animation: barraCrece var(--lento) var(--curva) backwards;
}
.ritmo__pie {
  grid-column: 1 / -1; font-size: var(--t-meta); color: var(--text-muted);
}
.ritmo__fila[data-tono="bien"]   { --tono: var(--good); }
.ritmo__fila[data-tono="ojo"]    { --tono: var(--warning); }
.ritmo__fila[data-tono="mal"]    { --tono: var(--critical); }
.ritmo__fila[data-tono="neutro"] { --tono: var(--accent); }
/* La barra del tiempo es gris a propósito: es la referencia contra la que se
   compara, no una de las dos cosas comparadas. Si tuviera color, las dos barras
   parecerían dos medidas del mismo tipo. */
.ritmo__fila[data-tono="tiempo"] { --tono: var(--border-strong); }

/* ==========================================================================
   25c · El reparto: «¿en qué se me va?»
   ==========================================================================
   Barras en DOM y no el SVG de charts.hbars, a propósito: hbars mete el rótulo
   y el importe DENTRO del dibujo con anchos calculados, y a 360 px de ancho el
   nombre de la categoría sale cortado. Aquí el texto se ajusta solo. */

.reparto { display: grid; }
.reparto__fila {
  display: grid; grid-template-columns: 1fr auto; gap: 4px var(--sp-3);
  align-items: baseline; text-align: left;
  width: 100%; padding: var(--sp-3) var(--sp-2);
  background: none; border: 0; border-radius: var(--radius-sm);
  font: inherit; color: inherit; cursor: pointer;
  transition: background var(--rapido) var(--curva);
}
.reparto__fila + .reparto__fila { border-top: 1px solid var(--border); border-radius: 0; }
/* Una fila que no lleva a ningún sitio no finge que se puede pulsar. */
.reparto__fila--quieta { cursor: default; }
.reparto__fila--quieta:hover { background: none; }
.reparto__fila:not(.reparto__fila--quieta):hover { background: var(--surface-sunken); }
.reparto__fila:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.reparto__nombre {
  font-size: var(--t-cuerpo); font-weight: var(--peso-medio); color: var(--text-primary);
}
.reparto__monto {
  font-size: var(--t-cuerpo); font-weight: var(--peso-fuerte);
  font-variant-numeric: tabular-nums; color: var(--text-primary);
}
.reparto__carril {
  grid-column: 1 / -1; height: 6px; border-radius: var(--radius-pill);
  background: var(--surface-sunken); overflow: hidden; margin-top: 2px;
}
.reparto__relleno {
  display: block; height: 100%; border-radius: var(--radius-pill);
  background: var(--color, var(--accent));
  transform: scaleX(var(--parte, 0)); transform-origin: left;
  animation: barraCrece var(--lento) var(--curva) backwards;
  animation-delay: var(--retraso, 0ms);
}
.reparto__parte {
  grid-column: 1 / -1; font-size: var(--t-meta); color: var(--text-muted);
}

@keyframes barraCrece { from { transform: scaleX(0); } }

/* ---------- Barra de controles de una vista ---------- */

/* Los desplegables que deciden QUÉ se está mirando. No es una tarjeta de
   contenido y no lleva título: ponerle uno obligaba a inventar un rótulo, y en
   Mis límites salía «Presupuestos» dentro de una pantalla ya titulada «Mis
   límites» — la misma palabra dos veces para nombrar dos selectores. */
.barra-vista { display: grid; gap: var(--sp-3); }
.barra-vista__controles {
  display: flex; gap: var(--sp-3); align-items: flex-end; flex-wrap: wrap;
}
.barra-vista__controles > * { flex: 1 1 min(200px, 100%); }
.barra-vista__nota {
  margin: 0; font-size: var(--t-secundario); color: var(--text-muted); line-height: 1.5;
}

/* ---------- Panel de compartir ---------- */

/* Se abre desde la tarjeta de un espacio. Dentro van bloques, no tarjetas: ya
   está dentro de una, y una tarjeta dentro de otra da una caja dentro de otra
   caja que no separa nada — solo mete un borde más. */
.compartir { display: grid; gap: var(--sp-5); }
.compartir__bloque { display: grid; gap: var(--sp-3); }
.compartir__bloque + .compartir__bloque {
  padding-top: var(--sp-5); border-top: 1px solid var(--border);
}
.compartir__bloque .card__head { margin-bottom: 0; }
.compartir__bloque h3 {
  font-size: var(--t-tarjeta); font-weight: var(--peso-fuerte); letter-spacing: -.005em;
}
.compartir__bloque .card__head p {
  font-size: var(--t-meta); color: var(--text-muted); line-height: 1.45;
}
.compartir__pie {
  font-size: var(--t-secundario); line-height: 1.5; margin: 0;
  padding-top: var(--sp-4); border-top: 1px solid var(--border);
}

/* ---------- Cambios que no se pudieron guardar ---------- */

/* Se ve desde cualquier pantalla y no se va sola: es la única forma de recuperar
   un cambio que no llegó al servidor. Va pegada arriba porque quien la necesita
   está en mitad de otra cosa y tiene que verla sin desplazarse. */
.sin-guardar {
  position: sticky; top: var(--sp-2); z-index: 30;
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: var(--sp-3);
  margin: 0 0 var(--sp-3);
  padding: var(--sp-3) var(--sp-4);
  background: color-mix(in srgb, var(--critical) 10%, var(--surface-1));
  border: 1px solid color-mix(in srgb, var(--critical) 35%, transparent);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}
.sin-guardar__texto { display: grid; gap: 2px; min-width: 0; }
.sin-guardar__texto strong { font-size: var(--t-cuerpo); color: var(--text-primary); }
.sin-guardar__texto span { font-size: var(--t-secundario); color: var(--text-secondary); }
.sin-guardar__acciones { display: flex; gap: var(--sp-2); flex: none; }

/* ---------- Casilla con su texto ---------- */

/* El patrón «casilla + etiqueta» aparecía en cinco vistas, cada una con su
   propio gap escrito a mano y un paddingTop de 14px para alinearla con los
   desplegables de al lado. Aquí una vez, con el objetivo táctil que hace falta
   para pulsarla con el pulgar: el hueco que se toca es la etiqueta entera, no
   solo el cuadradito de 18 px. */
.casilla {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  min-height: var(--control-alto); cursor: pointer;
  font-size: var(--t-secundario); color: var(--text-secondary);
}
.casilla input[type="checkbox"] { flex: none; }
.casilla:hover { color: var(--text-primary); }

/* ---------- Tareas colgadas de la respuesta ---------- */

/* Cuando la vista, además de responder, ofrece algo que HACER (registrar los
   pagos fijos pendientes). Se separa con un borde y no con una raya suelta,
   porque no es más contenido de la respuesta: es otra cosa. */
.respuesta__tareas {
  display: grid; gap: var(--sp-3);
  padding-top: var(--sp-3); border-top: 1px solid var(--border);
}
.respuesta__ajustes { display: flex; flex-wrap: wrap; gap: var(--sp-2) var(--sp-4); }
.respuesta__pendientes {
  display: flex; flex-wrap: wrap; gap: var(--sp-2); align-items: center;
}

/* ---------- Casilla de cifra, versión suave ---------- */

/* Cinco vistas tenían su propia función `tile()` con las mismas tres líneas:
   fondo hundido, sin borde y la cifra un poco más chica que en un KPI de
   verdad. Escritas a mano cinco veces, y con la cifra en 18px en una vista y
   20px en las otras — el mismo elemento con dos tamaños distintos.

   `aviso` tiñe el fondo cuando el dato pide atención. */
.tile--suave { background: var(--surface-2); border-color: transparent; }
.tile--suave .tile__value,
.tile--suave .kpi__valor { font-size: var(--t-cifra-media); }
.tile--suave[data-aviso="si"] {
  background: color-mix(in srgb, var(--warning) 12%, var(--surface-2));
}

/* Sitio de un gráfico. Reserva el alto antes de que se dibuje para que nada de
   alrededor dé un salto al aparecer. */
.grafico { min-height: 200px; }

/* ==========================================================================
   26 · Nada se desborda, nada se corta
   ==========================================================================
   Dos fallos que se veían en pantalla y que aquí se cierran de raíz:

   · La página era más ancha que la ventana (barra de desplazamiento horizontal).
     Una rejilla con una columna de 240px y otra "1fr" se ensancha si el
     contenido de la segunda tiene un mínimo mayor: hay que decirle que puede
     encogerse.
   · El pie del lateral (el conmutador de tema) quedaba cortado, porque el
     panel medía 100vh sin poder desplazarse. */

html, body { max-width: 100%; overflow-x: clip; }

.app {
  grid-template-columns: 240px minmax(0, 1fr);   /* minmax(0,..) = puede encoger */
  max-width: 100%;
}
.main { min-width: 0; max-width: 100%; }
.view, .topbar, .filters, .pie { min-width: 0; max-width: 100%; }

/* El lateral se desplaza por dentro si no cabe, y el pie queda siempre visible. */
.sidebar { background: var(--surface-1); }
.sidebar__panel {
  height: 100%;
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-width: thin;
  padding-bottom: calc(var(--sp-3) + env(safe-area-inset-bottom, 0px));
}
.sidebar__foot { margin-top: auto; padding-top: var(--sp-3); }

/* Cualquier cosa ancha (tablas, gráficos) se desplaza DENTRO de su tarjeta,
   nunca arrastrando la página entera. */
.table-scroll { overflow-x: auto; max-width: 100%; }
.card > * { min-width: 0; }

/* ==========================================================================
   26b · La tabla en un teléfono
   ==========================================================================
   Siete columnas no caben en 360 px y no hay forma de que quepan. Lo que había
   era esconder columnas: eso no resuelve el problema, lo cambia por otro — en el
   teléfono ves MENOS datos, y quien mira sus gastos desde el móvil se queda sin
   la mitad.

   Por debajo de 640 px cada fila deja de ser una fila y pasa a ser un bloque:
   el rótulo de la columna a la izquierda, el valor a la derecha, uno debajo de
   otro. Se ve todo, en vertical, sin desplazar de lado. El rótulo sale de
   `data-col`, que dataTable pone en cada celda.

   Esto vale para las ocho vistas con tabla a la vez, porque todas salen de la
   misma función. */

/* El «Ordenar por» del móvil vive en el <caption> y en escritorio no existe:
   ahí se ordena pulsando la cabecera, que es donde todo el mundo lo busca. */
.data__orden { display: none; }

/* Desplegable dentro de una fila de tabla: cabe en la celda sin ensancharla.
   El ancho máximo solo aplica mientras la tabla es una tabla; apilada, el
   desplegable ocupa la línea entera y encogerlo lo dejaría suelto en medio. */
.compact-select {
  padding: 3px 6px; font-size: var(--t-meta);
  max-width: 170px; min-width: 0;
}

@media (max-width: 640px) {
  table.data,
  table.data tbody,
  table.data tr,
  table.data td { display: block; width: auto; }

  /* La cabecera se va: su trabajo —decir qué es cada valor— lo hace ahora el
     rótulo de cada celda. */
  table.data thead { display: none; }

  table.data tr {
    border: 1px solid var(--border); border-radius: var(--radius-sm);
    padding: var(--sp-2) var(--sp-3);
    margin-bottom: var(--sp-2);
    background: var(--surface-1);
  }
  table.data tr:last-child { margin-bottom: 0; }

  table.data td {
    display: flex; align-items: center; justify-content: space-between;
    gap: var(--sp-3);
    padding: 6px 0; border: 0;
    min-height: 0; text-align: left;
    /* Un importe largo no puede empujar el rótulo fuera de la pantalla. */
    overflow-wrap: anywhere;
  }
  table.data td + td { border-top: 1px solid var(--border); }
  table.data td::before {
    content: attr(data-col);
    flex: 0 0 auto;
    font-size: var(--t-meta); font-weight: var(--peso-medio);
    color: var(--text-muted);
    /* Sin esto, una celda vacía deja el rótulo suelto sin nada al lado. */
    white-space: nowrap;
  }
  /* Una celda sin rótulo —los botones de acción de la fila— ocupa el ancho y no
     finge que es un dato con nombre. */
  table.data td:not([data-col]) { justify-content: flex-end; }
  table.data td.num { justify-content: space-between; }
  /* Los controles de la fila (categoría, ✎) se estiran: en el móvil se pulsan
     con el pulgar, no se apunta. */
  table.data td select,
  table.data td input { flex: 1 1 auto; min-width: 0; }
  table.data td .compact-select { max-width: none; font-size: 16px; }
  /* El punto de color junto a la descripción existía para adivinar la categoría
     cuando su columna se escondía. Ya no se esconde: ahora tiene su propia línea
     con su nombre escrito, así que el punto sobra y confunde. */
  table.data td i.only-movil { display: none; }

  .data__orden {
    display: flex; align-items: center; gap: var(--sp-2);
    caption-side: top; text-align: left;
    padding-bottom: var(--sp-3);
    font-size: var(--t-secundario); color: var(--text-secondary);
  }
  .data__orden select { flex: 1 1 auto; min-width: 0; }

  /* Ya no hay nada que desplazar de lado. */
  .table-scroll { overflow-x: visible; }
}

/* ==========================================================================
   27 · Selector de espacio
   ==========================================================================
   Es el contexto de todo lo que se ve debajo, así que se lee como un bloque
   propio: sin caja gris de relleno, con el nombre entero y el detalle en una
   segunda línea que puede cortarse sin dejar la fila torcida. */

.espacio-sel {
  gap: var(--sp-3);
  margin: 0 0 var(--sp-2);
  padding: var(--sp-2);
  background: none;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  min-height: 52px;
}
.espacio-sel:hover { background: var(--surface-2); border-color: var(--border-strong); }
.espacio-sel__icono {
  width: 34px; height: 34px; border-radius: var(--radius-sm);
  box-shadow: none; font-size: 16px;
}
.espacio-sel__texto strong {
  font-size: var(--t-cuerpo); font-weight: var(--peso-fuerte);
  color: var(--text-primary);
}
.espacio-sel__texto span { font-size: var(--t-meta); }
.espacio-sel__flecha { color: var(--text-muted); }

.espacio-menu {
  margin: 0 0 var(--sp-2);
  border-radius: var(--radius-sm);
  border-color: var(--border);
  box-shadow: var(--shadow-alta);
}
.espacio-menu__item { min-height: 44px; }

/* ==========================================================================
   28 · Responsive, revisado a mano en cada corte
   ========================================================================== */

/* Portátil estrecho: el lateral adelgaza antes de desaparecer. */
@media (max-width: 1280px) {
  .app { grid-template-columns: 224px minmax(0, 1fr); }
  .buscador { min-width: 200px; }
}

/* Tableta: el lateral pasa a menú y la cabecera se reordena en dos filas, para
   que el título nunca comparta línea con el buscador. */
@media (max-width: 1023px) {
  .app { grid-template-columns: minmax(0, 1fr); }
  .topbar { flex-wrap: wrap; row-gap: var(--sp-3); }
  .topbar__head { order: 1; flex: 1 1 60%; }
  .topbar__derecha { order: 2; margin-left: auto; }
  .filters { padding: var(--sp-3) var(--sp-4) 0; }
  /* El lateral vuelve a ser un panel que cae: aquí sí lleva su propio fondo. */
  .sidebar { background: none; border-right: 0; }
}

/* Móvil: la barra de contexto se convierte en un panel plegable (lo abre
   #btnFiltros) y la acción principal ocupa la fila entera. */
@media (max-width: 640px) {
  .topbar { padding: var(--sp-3); }
  .topbar__head h1 { font-size: 19px; }
  .filters {
    padding: var(--sp-3) var(--sp-3) 0;
    gap: var(--sp-2);
  }
  .filters .field { flex: 1 1 45%; }
  .filters .field select { width: 100%; }
  .filters #btnQuickAdd { margin-left: 0; width: 100%; }
  .pie { padding: var(--sp-4) var(--sp-3); }
  .pie__enlaces { gap: var(--sp-3); flex-wrap: wrap; }
  /* El chip de usuario se queda en el avatar: el nombre ya está en el menú. */
  .usuario { padding: 0; }
}

/* ==========================================================================
   29 · Barra de filtros de una vista
   ==========================================================================
   Distinta de «.filters», que es la barra de contexto de la aplicación entera
   (periodo y cuenta). Esta vive DENTRO de una tarjeta y filtra su contenido.
   Se separan por nombre a propósito: son dos cosas y confundirlas fue la causa
   de que la de arriba se viera con relleno de más. */

.filtros-vista {
  display: flex; align-items: flex-end; gap: var(--sp-3);
  flex-wrap: wrap; min-width: 0;
}
.filtros-vista__buscar { flex: 1 1 240px; min-width: 0; }
.filtros-vista__buscar input { width: 100%; }
.filtros-vista__cuenta {
  display: grid; gap: 1px; text-align: right; margin-left: auto;
}
.filtros-vista__cuenta strong { font-size: var(--t-cuerpo); font-weight: var(--peso-fuerte); }
.filtros-vista__cuenta span { font-size: var(--t-meta); color: var(--text-muted); }

.filtros-vista__mas {
  display: grid; gap: var(--sp-3);
  grid-template-columns: repeat(auto-fit, minmax(min(180px, 100%), 1fr));
  margin-top: var(--sp-4); padding-top: var(--sp-4);
  border-top: 1px solid var(--border);
  animation: entraArriba var(--rapido) var(--curva);
}
.filtros-vista__mas[hidden] { display: none; }

/* Etiquetas de los filtros puestos: cada una se quita sola. */
.chips-filtro {
  display: flex; align-items: center; gap: var(--sp-2);
  flex-wrap: wrap;
  margin-top: var(--sp-3); padding-top: var(--sp-3);
  border-top: 1px solid var(--border);
}
.chip-filtro {
  display: inline-flex; align-items: center; gap: 6px;
  min-height: 30px; padding: 0 var(--sp-2) 0 var(--sp-3);
  border: 1px solid var(--accent-border); border-radius: var(--radius-pill);
  background: var(--accent-soft); color: var(--accent);
  font-family: inherit; font-size: var(--t-meta); font-weight: var(--peso-medio);
  cursor: pointer;
  transition: background var(--rapido) var(--curva), border-color var(--rapido) var(--curva);
}
.chip-filtro:hover { background: var(--accent-suave); border-color: var(--accent); }
.chip-filtro:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.chip-filtro__x { font-size: 11px; opacity: .7; }
.chip-filtro:hover .chip-filtro__x { opacity: 1; }

/* ==========================================================================
   30 · Barra de selección
   ==========================================================================
   Aparece solo cuando hay filas marcadas y se queda pegada al fondo de la
   tarjeta: la selección se hace bajando por la tabla, así que las acciones
   tienen que seguir estando a mano cuando llegas abajo. */

.seleccion {
  position: sticky; bottom: 0; z-index: 2;
  display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap;
  margin: var(--sp-4) calc(var(--card-pad) * -1) calc(var(--card-pad) * -1);
  padding: var(--sp-3) var(--card-pad);
  border-top: 1px solid var(--border);
  border-radius: 0 0 var(--radius-lg) var(--radius-lg);
  background: var(--surface-1);
  animation: entraAbajo var(--rapido) var(--curva);
}
.seleccion strong { font-size: var(--t-secundario); margin-right: var(--sp-1); }
@keyframes entraAbajo {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: none; }
}

@media (max-width: 640px) {
  .filtros-vista__cuenta { margin-left: 0; text-align: left; }
  .seleccion { gap: var(--sp-1); }
  .seleccion .btn { flex: 1 1 auto; }
}

/* ==========================================================================
   31 · Desplegable de espacios
   ==========================================================================
   Flota sobre el contenido en vez de empujarlo: dentro de una columna flex con
   desplazamiento, un panel en el flujo se comprime hasta quedar en una rendija
   con barra de scroll (que es justo lo que pasaba). */

.espacio-zona { position: relative; }

.espacio-menu {
  position: absolute; z-index: 60;
  top: calc(100% + 4px); left: 0; right: 0;
  margin: 0;
  padding: var(--sp-1);
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-alta);
  display: grid; gap: 2px;
  max-height: min(60vh, 420px);
  overflow-y: auto;
  animation: entraArriba var(--rapido) var(--curva);
}
.espacio-menu[hidden] { display: none; }
.espacio-menu__titulo { padding: var(--sp-2) var(--sp-2) var(--sp-1); }
.espacio-menu__item {
  min-height: 48px; padding: var(--sp-2);
  border-radius: var(--radius-sm);
  transition: background var(--rapido) var(--curva);
}
.espacio-menu__item:hover { background: var(--surface-2); }

/* El selector no se estira ni se encoge dentro de la columna. */
.espacio-sel { flex: 0 0 auto; }

/* ==========================================================================
   32 · Pasos, miembros e invitación
   ==========================================================================
   Los pasos se ven en orden y el que ya está hecho se marca. Un paso pendiente
   dice POR QUÉ lo está: es la diferencia entre una pantalla que guía y una que
   solo enumera. */

.pasos { display: grid; gap: var(--sp-4); }
.paso { display: grid; grid-template-columns: 32px 1fr; gap: var(--sp-3); align-items: start; }
.paso__num {
  width: 32px; height: 32px; border-radius: var(--radius-pill);
  display: grid; place-items: center;
  background: var(--surface-2); color: var(--text-secondary);
  font-size: var(--t-secundario); font-weight: var(--peso-fuerte);
}
.paso--hecho .paso__num { background: var(--accent-soft); color: var(--accent); }
.paso__cuerpo { display: grid; gap: 2px; min-width: 0; }
.paso__cuerpo strong { font-size: var(--t-cuerpo); font-weight: var(--peso-fuerte); }
.paso--hecho .paso__cuerpo strong { color: var(--text-secondary); }
.paso__cuerpo span { font-size: var(--t-secundario); color: var(--text-muted); line-height: 1.5; }

.miembro {
  display: grid; grid-template-columns: 36px 1fr auto auto; gap: var(--sp-3);
  align-items: center;
  padding: var(--sp-2) 0;
  border-bottom: 1px solid var(--grid);
}
.miembro:last-child { border-bottom: 0; }
.miembro__avatar {
  width: 36px; height: 36px; border-radius: var(--radius-pill);
  display: grid; place-items: center;
  background: var(--surface-2); color: var(--text-secondary);
  font-size: var(--t-secundario); font-weight: var(--peso-fuerte);
}
.miembro__texto { display: grid; gap: 1px; min-width: 0; }
.miembro__texto strong { font-size: var(--t-cuerpo); font-weight: var(--peso-medio); }
.miembro__texto span {
  font-size: var(--t-meta); color: var(--text-muted);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.miembro select { min-height: 34px; font-size: var(--t-secundario); }

.invitacion { margin-top: var(--sp-4); padding-top: var(--sp-4); border-top: 1px solid var(--border); }
.invitacion input { flex: 1 1 240px; font-family: ui-monospace, monospace; font-size: var(--t-secundario); }

@media (max-width: 640px) {
  .miembro { grid-template-columns: 36px 1fr; }
  .miembro select, .miembro .btn, .miembro .badge { grid-column: 2; justify-self: start; }
}

/* ==========================================================================
   33 · El logotipo
   ==========================================================================
   El archivo ya trae su propio marco redondeado, así que aquí NO se le pone
   borde ni fondo: serían dos marcos, uno dentro de otro. */

.brand__logo { display: inline-flex; align-items: center; }
.logo-obi { display: block; height: auto; max-width: 100%; }

/* El tope es de ALTURA, no de anchura.

   Solo con `max-width: 100%` el logotipo mide lo que mida su hueco, y eso en
   el escritorio son los 240 px de la barra —bien— pero en el cajón del móvil,
   que ocupa todo el ancho, se iba a 350x202: un cuarto de la pantalla para la
   marca, antes de que se viera un solo enlace del menú.

   Con la altura acotada y `width: auto` conserva su proporción y se comporta
   igual en los dos sitios. */
.brand__logo .logo-obi { width: auto; max-height: 34px; }

/* En oscuro el turquesa sobre el fondo casi negro se apaga un poco. Un realce
   mínimo lo devuelve sin desteñir el color de la marca. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .logo-obi { filter: brightness(1.12); }
}
:root[data-theme="dark"] .logo-obi { filter: brightness(1.12); }

/* Un dato que pide atención dentro de una tabla: una fecha ya pasada, un plazo
   vencido. No es una alerta —no lleva fondo ni icono— pero tampoco es texto
   normal, y hay que poder distinguirlo de un vistazo al recorrer la columna. */
.texto-ojo { color: var(--warning); font-weight: var(--peso-medio); }

/* ==========================================================================
   La cabecera del teléfono
   ==========================================================================

   Medido antes de tocar nada, en 390×844: la cabecera ocupaba 161 px y la barra
   de periodo y cuenta otros 123. Son 284 px —un tercio de la pantalla— gastados
   en decir dónde estás antes de enseñar un solo número.

   Y dentro de esos 284 px había dos cosas rotas:

   · `#btnFiltros` no hacía nada. La regla que plegaba la barra era
     `.topbar[data-filtros="1"] .filters`, pero `.filters` es HERMANO de
     `.topbar`, no descendiente: el selector no podía casar nunca. Y el
     `display: none` que la escondía vivía en styles.css, que carga ANTES que
     esta hoja, donde `.filters { display: flex }` lo pisa por orden. Así que la
     barra estaba siempre abierta y el botón solo giraba la flecha.

   · El ☰ y el título repetían lo que ya dice la barra de abajo.

   La salida no es arreglar el panel plegable: es no tenerlo. El periodo y la
   cuenta son CONTEXTO —lo que estás mirando— y esconder el contexto detrás de
   un botón obliga a abrirlo para saber si la cifra que ves es de este mes o del
   año entero. Se quedan a la vista, como dos fichas en una sola línea.

   Quedan 88 px.  */

@media (max-width: 640px) {

  /* El ☰ se va: «Más», en la barra de abajo, abre el mismo cajón y está donde
     llega el pulgar. Dos maneras de abrir lo mismo, una de ellas en la esquina
     más lejana de la pantalla, no es una opción: es un estorbo. */
  body.con-pulgar #btnMenu { display: none; }

  /* La miga y el subtítulo tampoco: la barra de abajo ya dice en qué sección
     estás, resaltada y con su nombre debajo. */
  body.con-pulgar .miga,
  body.con-pulgar #viewSubtitle { display: none; }

  body.con-pulgar .topbar {
    flex-wrap: nowrap; gap: var(--sp-2);
    padding: 10px var(--sp-3);
    /* Se queda arriba al desplazar. El título es la única pista de en qué
       subpantalla estás cuando ya llevas mil filas de movimientos. */
    position: sticky; top: 0; z-index: 30;
    background: color-mix(in srgb, var(--surface-1) 92%, transparent);
    backdrop-filter: blur(12px);
  }
  body.con-pulgar .topbar__head h1 {
    font-size: 17px; line-height: 1.25;
    /* Una línea. «Reglas de traspaso entre cuentas» partido en dos empuja todo
       lo de abajo y hace que la cabecera salte al cambiar de sección. */
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  /* El orden lo fija la regla de tableta (`.topbar__head { order: 1 }`), pensada
     para cuando el ☰ abría el menú desde la izquierda. Al retirar el ☰, lo que
     quedaba con orden 0 era el «+», y aparecía pegado al borde izquierdo: el
     sitio donde en un teléfono se espera «atrás». Se pulsaría por error.
     El título manda, y las acciones se van al final. */
  body.con-pulgar .topbar__head { order: 0; }
  body.con-pulgar .topbar__derecha { order: 1; gap: 4px; margin-left: auto; }
  body.con-pulgar .topbar__acciones { order: 2; }

  /* El buscador se encoge a su icono. Ocupaba una fila entera para un campo que
     se usa de vez en cuando; al enfocarlo se abre sobre la cabecera. */
  body.con-pulgar .buscador {
    min-width: 0; width: 38px; padding: 0;
    transition: width var(--normal) var(--curva);
  }
  body.con-pulgar .buscador__ico { margin: 0 auto; }
  body.con-pulgar .buscador input,
  body.con-pulgar .buscador__atajo { display: none; }
  body.con-pulgar .buscador:focus-within {
    position: absolute; left: var(--sp-3); right: var(--sp-3); z-index: 2;
    width: auto; padding: 0 var(--sp-3);
    background: var(--surface-2);
  }
  body.con-pulgar .buscador:focus-within input { display: block; flex: 1; }

  /* Y el botón que no hacía nada se retira, en vez de dejarlo ahí girando la
     flecha sobre una barra que ya no se pliega. */
  body.con-pulgar #btnFiltros { display: none; }

  /* Periodo y cuenta: dos fichas en una línea.
     Los rótulos se quedan. El primer intento los escondió —«Este mes» y «Todas
     las cuentas» ya se explican solos— y eso rompe una regla de la casa que
     existe por un motivo escrito: un desplegable que dice «Este mes» sin decir
     de qué obliga a adivinar. Ahorraba 16 px de 844. No compensa.  */
  body.con-pulgar .filters {
    display: flex; flex-wrap: nowrap; align-items: center;
    gap: 6px; padding: 0 var(--sp-3) 10px;
    /* Si el nombre de la cuenta es largo, se arrastra en horizontal en vez de
       partirse en dos filas. */
    overflow-x: auto; scrollbar-width: none;
  }
  body.con-pulgar .filters::-webkit-scrollbar { display: none; }
  body.con-pulgar .filters { align-items: end; }
  body.con-pulgar .filters .field {
    flex: 1 1 0; min-width: 0;
    display: grid; gap: 2px;
  }
  body.con-pulgar .filters .field > span {
    font-size: var(--t-meta); line-height: 1.1;
    padding-left: 12px;   /* alineado con el texto de dentro de la ficha */
  }
  body.con-pulgar .filters select {
    width: 100%; min-height: 34px; padding: 4px 26px 4px 12px;
    border-radius: var(--radius-pill);
    font-size: 13px; font-weight: var(--peso-fuerte);
  }
  body.con-pulgar .filters .periodo-nav { flex: none; }
  /* «+ Anotar un gasto» a lo ancho ya está en el «+» de la cabecera y en la
     propia pantalla de Inicio. Tres veces el mismo botón es una vez de más. */
  body.con-pulgar .filters #btnQuickAdd { display: none; }
  body.con-pulgar .filters #fFromWrap,
  body.con-pulgar .filters #fToWrap { flex: 1 1 0; }
  body.con-pulgar .filters #fFromWrap > span,
  body.con-pulgar .filters #fToWrap > span { display: block; }

  body.con-pulgar .view { padding-top: 12px; }
}

/* ==========================================================================
   Que se note que es una aplicación
   ==========================================================================

   Una web cambia de página: la anterior desaparece y la siguiente ya está ahí.
   Una aplicación cambia de PANTALLA, y ese matiz se nota en dos sitios.

   El primero es la entrada. Al tocar una pestaña, el contenido nuevo sube unos
   píxeles y aparece, y las tarjetas lo hacen escalonadas. No es adorno: el
   escalón dice en qué orden leer, y el movimiento confirma que el toque hizo
   algo — sin él, tocar una pestaña y ver otra pantalla idéntica de estructura
   deja la duda de si cambió.

   El segundo es el dedo. En un teléfono no existe el «hover»: si lo que tocas
   no se hunde, la pantalla parece muerta y se vuelve a pulsar. Por eso todo lo
   que se puede tocar responde al tocarlo, y no solo al soltar.

   El escalón se corta a la sexta tarjeta: con doce, la última entraría casi
   medio segundo tarde y eso ya no se lee como fluido, se lee como lento.  */

@media (max-width: 640px) {

  body.con-pulgar #view > * { animation: entraPantalla var(--normal) var(--curva) both; }

  @keyframes entraPantalla {
    from { opacity: 0; transform: translateY(10px); }
    to   { opacity: 1; transform: none; }
  }

  body.con-pulgar #view > * > .card,
  body.con-pulgar #view > * > .seccion {
    animation: entraFicha 320ms var(--curva) both;
  }
  body.con-pulgar #view > * > :nth-child(2) { animation-delay: 40ms; }
  body.con-pulgar #view > * > :nth-child(3) { animation-delay: 80ms; }
  body.con-pulgar #view > * > :nth-child(4) { animation-delay: 120ms; }
  body.con-pulgar #view > * > :nth-child(5) { animation-delay: 160ms; }
  body.con-pulgar #view > * > :nth-child(n+6) { animation-delay: 200ms; }

  @keyframes entraFicha {
    from { opacity: 0; transform: translateY(14px); }
    to   { opacity: 1; transform: none; }
  }

  /* La respuesta al dedo. `transform` y `opacity` y nada más: son las dos cosas
     que el navegador puede animar sin volver a calcular la página, y en un
     teléfono de gama media eso es la diferencia entre fluido y a tirones. */
  body.con-pulgar .card__head[aria-expanded],
  body.con-pulgar .seccion__head[aria-expanded],
  body.con-pulgar .btn,
  body.con-pulgar .icono-btn,
  body.con-pulgar .nav__item {
    transition: transform var(--rapido) var(--curva);
    -webkit-tap-highlight-color: transparent;
  }
  body.con-pulgar .card__head[aria-expanded]:active,
  body.con-pulgar .seccion__head[aria-expanded]:active,
  body.con-pulgar .btn:active,
  body.con-pulgar .icono-btn:active,
  body.con-pulgar .nav__item:active { transform: scale(.97); }

  /* Y el desplazamiento se frena como en una aplicación, no como en un
     documento: al llegar al final no arrastra la página entera detrás. */
  body.con-pulgar { overscroll-behavior-y: contain; }

  /* La muesca y las esquinas redondeadas de los teléfonos de ahora. Sin esto el
     «+» de la cabecera queda debajo del reloj en un iPhone. */
  body.con-pulgar .topbar {
    padding-top: calc(10px + env(safe-area-inset-top, 0px));
    padding-left: calc(var(--sp-3) + env(safe-area-inset-left, 0px));
    padding-right: calc(var(--sp-3) + env(safe-area-inset-right, 0px));
  }
}

/* Quien pide menos movimiento lo pide para todo. Se queda la escala del toque
   —que es respuesta, no decoración— y desaparece el resto. */
@media (prefers-reduced-motion: reduce) {
  body.con-pulgar #view > *,
  body.con-pulgar #view > * > .card,
  body.con-pulgar #view > * > .seccion { animation: none; }
}

/* ---------- Lista para elegir varias cosas ---------- */

/* Elegir de una lista larga sin que la lista se coma el formulario: alto
   acotado y desplazamiento propio. Sin el tope, sesenta gastos empujan los
   botones de guardar fuera de la pantalla y hay que rodar hasta el final para
   encontrar el que hay que pulsar. */
.lista-elegir {
  max-height: 240px; overflow-y: auto;
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--surface-2);
}
.lista-elegir__fila {
  display: flex; width: 100%; gap: var(--sp-2); align-items: center;
  padding: var(--sp-2) var(--sp-3);
  border-bottom: 1px solid var(--border);
}
.lista-elegir__fila:last-child { border-bottom: 0; }
.lista-elegir__que { display: flex; flex-direction: column; gap: 1px; min-width: 0; flex: 1; }
/* Que un concepto largo no empuje el importe fuera de la fila. */
.lista-elegir__que strong { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lista-elegir__cuanto {
  flex: none; font-variant-numeric: tabular-nums; color: var(--text-secondary);
}
.lista-elegir > p { padding: var(--sp-3); margin: 0; }
