/* ==========================================================================
   OBI · AURORA — el sistema visual
   ==========================================================================

   Esta hoja MANDA. Se carga la última a propósito: reescribe las fichas de
   styles.css y vuelve a vestir cada componente de sistema.css.

   Por qué una hoja aparte y no un parche dentro de las otras dos:

     Las otras dos suman 365 KB y describen el sistema ANTERIOR (Modernist:
     radio 0, cero sombras, dos azules, nada de color). Reescribirlas a mano
     habría dejado durante días una app medio vestida de cada cosa. Aurora
     entra de una pieza: mientras exista este archivo la app es Aurora, y si
     se quita vuelve entera a lo de antes. Un solo interruptor.

     Lo que queda de las hojas viejas es ANDAMIO — la maquetación, las
     rejillas, los @media. Eso no se toca porque funciona.

   Las tres decisiones que explican el resto:

     1. PROFUNDIDAD, NO REGLAS. Antes, dos bloques se separaban con una raya de
        2px. Ahora se separan porque uno está más cerca: capa, borde de vidrio,
        sombra. Es como se lee una app de banco en un teléfono a pleno sol.

     2. EL COLOR SIGNIFICA. Verde entra, coral se pasó, ámbar corre, violeta
        aún no pasó. El sistema viejo lo prohibía —«el dinero no es un
        semáforo»— y tenía razón para un informe impreso. En una pantalla que
        se mira diez segundos, obligar a leer el signo menos antes de saber si
        la noticia es buena cuesta esos diez segundos.

     3. EL DEGRADADO ES CARO. Solo lo llevan la cifra héroe, el logotipo, el
        botón principal, los anillos y las tarjetas de cuenta. Si lo llevara
        todo no destacaría nada, que es lo que le pasaba al azul de antes.

   ========================================================================== */


/* ==========================================================================
   1 · FICHAS — modo claro
   ==========================================================================
   Van en :root sin más. El oscuro llega después por tres caminos (§2), y el
   orden importa: gana el último que case. */

:root {
  color-scheme: light;

  /* ---------- Los tres colores de marca ----------
     No cambian entre modos: son la marca. Lo que cambia alrededor es el
     fondo, y por eso hacen falta las variantes -txt de más abajo. */
  --au-cyan:   #00E5FF;
  --au-blue:   #3D7BFF;
  --au-violet: #8B5CF6;

  /* ---------- Terreno y capas ----------
     En claro una tarjeta ES blanca y se levanta con sombra. En oscuro (§2) es
     un vidrio translúcido y se levanta con borde. Misma jerarquía, dos
     idiomas: el componente escribe var(--capa-1) y no se entera. */
  --bg:           #F5F8FD;
  --bg-2:         #E9EFF9;   /* hundido: pistas de barra, celdas vacías */
  --capa-1:       #FFFFFF;
  --capa-2:       #FFFFFF;
  --capa-3:       #FFFFFF;
  --capa-hover:   #F2F6FD;
  /* El fondo de un menú flotante es OPACO, no de vidrio. Por qué, en §6. */
  --menu-fondo:   #FFFFFF;
  /* Los iconos que dibuja el navegador —el calendario de un campo de fecha—
     vienen en negro y no se pueden recolorear: solo invertir. En claro, tal
     cual. */
  --invertir-icono: none;
  --linea:        rgba(11,18,32,.09);
  --linea-fuerte: rgba(11,18,32,.16);

  /* Los tres grises van más oscuros de lo que pide el ojo.
   *
   * El primer intento tenía --txt-3 en #8290A8, que sobre papel claro da 3.03:1
   * — se lee precioso en un monitor bueno y desaparece en un teléfono a pleno
   * sol, que es donde se mira esta app. DESIGN.md §9 no da rebaja por ser texto
   * pequeño, y precisamente lo pequeño es lo que más la necesita.
   *
   * Lo cazó pruebas/aurora.mjs midiendo, no mirando. */
  --txt:   #0B1220;
  --txt-2: #4C5A70;
  --txt-3: #5F6C82;

  /* ---------- Semántica del dinero ----------
     Dos fichas por estado a propósito:
       --ok       el color pleno: rellenos, barras, puntos, iconos.
       --ok-txt   el mismo tono BAJADO hasta pasar 4.5:1 sobre --bg.
     Sin la segunda, «entró 28,800» en verde menta sobre papel claro da 1.9:1 y
     no se lee. Con una sola ficha, o el relleno queda apagado o el texto queda
     ilegible; no hay un verde que valga para las dos cosas. */
  --ok:        #00A870;  --ok-txt:      #04724F;  --ok-suave:      rgba(0,168,112,.12);
  --alerta:    #E08A00;  --alerta-txt:  #8A5300;  --alerta-suave:  rgba(224,138,0,.13);
  --peligro:   #E0304F;  --peligro-txt: #B41E3A;  --peligro-suave: rgba(224,48,79,.11);
  --futuro:    #7038D8;  --futuro-txt:  #5B21B6;  --futuro-suave:  rgba(112,56,216,.11);
  --marca:     #2A63E8;  --marca-txt:   #1E4BC0;  --marca-suave:   rgba(42,99,232,.10);

  /* ---------- Degradados ----------
     El de la cifra se define en dos versiones porque en claro tiene que ir de
     tinta a azul (sobre papel) y en oscuro de blanco a celeste (sobre tinta).
     Es el único degradado que cambia entre modos. */
  --grad-marca:  linear-gradient(135deg, #00B8D4 0%, #2A63E8 48%, #7038D8 100%);
  --grad-cifra:  linear-gradient(115deg, #0B1220 0%, #17408F 46%, #2A63E8 100%);
  --grad-accion: linear-gradient(135deg, #2A63E8 0%, #5B3FE0 100%);
  --grad-ok:     linear-gradient(90deg, #00A870 0%, #00C98A 100%);
  --grad-alerta: linear-gradient(90deg, #E08A00 0%, #F5B23D 100%);
  --grad-peligro:linear-gradient(90deg, #E0304F 0%, #FF6B84 100%);
  --grad-futuro: linear-gradient(90deg, #7038D8 0%, #A78BFA 100%);
  --grad-vidrio: linear-gradient(160deg, rgba(255,255,255,.9), rgba(255,255,255,.55));

  /* La malla de luz del fondo. Dos manchas enormes y quietas. Sin esto el
     terreno se lee como un folio, y la app parece un formulario. */
  --malla-1: radial-gradient(1200px 780px at 8% -12%,  rgba(0,181,212,.16), transparent 62%);
  --malla-2: radial-gradient(1000px 700px at 104% 8%,  rgba(112,56,216,.13), transparent 60%);
  --malla-3: radial-gradient(900px  900px at 50% 118%, rgba(42,99,232,.10),  transparent 62%);

  /* ---------- Sombras ----------
     En claro hacen todo el trabajo de elevación. En oscuro (§2) se rebajan y
     entra el borde de vidrio. */
  --sombra-1: 0 1px 2px rgba(11,18,32,.05),  0 2px 8px rgba(11,18,32,.05);
  --sombra-2: 0 2px 6px rgba(11,18,32,.06),  0 12px 28px rgba(11,18,32,.08);
  --sombra-3: 0 8px 24px rgba(11,18,32,.10), 0 32px 64px rgba(11,18,32,.12);
  --brillo-accion:  0 6px 20px rgba(42,99,232,.28);
  --brillo-ok:      0 6px 20px rgba(0,168,112,.24);
  --brillo-peligro: 0 6px 20px rgba(224,48,79,.24);
  /* El filo de luz de arriba de cada tarjeta. En claro casi no existe; en
     oscuro es lo que hace que una tarjeta parezca una tarjeta. */
  --filo: inset 0 1px 0 rgba(255,255,255,.6);

  /* ---------- Forma ----------
     Radio 0 se acabó. Estas seis fichas son las únicas: si un componente pide
     un radio que no está aquí, es que el componente está mal medido. */
  --r-xs:   8px;
  --r-sm:  12px;
  --r-md:  16px;
  --r-lg:  22px;
  --r-xl:  28px;
  --r-full: 999px;

  /* ---------- Espacio ---------- */
  --e-1: 4px;  --e-2: 8px;  --e-3: 12px; --e-4: 16px; --e-5: 20px;
  --e-6: 24px; --e-7: 32px; --e-8: 40px; --e-9: 56px; --e-10: 72px;

  --ancho-max: 1240px;
  --canal: 24px;
  --alto-topbar: 64px;
  --alto-tabbar: 64px;

  /* ---------- La paleta de datos ----------
   *
   * OCHO tonos, y no son los de la marca. Es deliberado: la marca significa
   * «acción» y el semáforo significa «esto va bien o mal». Si las barras de
   * categoría usaran esos mismos colores, una barra verde diría «vas bien» en
   * vez de «esto es Supermercado».
   *
   * Dos condiciones, y las dos las mide pruebas/aurora.mjs:
   *
   *   · Al menos 25° de separación de TONO entre cualquier par. Es lo que hace
   *     falta para distinguirlos con deuteranopía y protanopía. Se mide el
   *     tono y no la luz porque dos colores con la misma luz y tonos opuestos
   *     se distinguen bien, y dos con tonos vecinos no se distinguen aunque uno
   *     sea más claro.
   *   · 3:1 contra el terreno (WCAG 1.4.11, elemento gráfico con significado).
   *
   * El primer intento tenía verde azulado (#0D9488) y cian (#0891B2) a 17°: dos
   * nombres distintos y la misma barra a la vista. El d-2 se movió a verde
   * franco para abrirle sitio al cian.
   *
   * Van aquí, con la paleta, y NO en la capa del puente de abajo: son fichas
   * con valor propio, no traducciones. */
  --d-1: #2563EB;  /* azul   · 221° */
  --d-2: #15803D;  /* verde  · 142° */
  --d-3: #B45309;  /* ámbar  ·  26° */
  --d-4: #DC2626;  /* rojo   ·   0° */
  --d-5: #7C3AED;  /* violeta· 262° */
  --d-6: #DB2777;  /* rosa   · 333° */
  --d-7: #0891B2;  /* cian   · 192° */
  --d-8: #4D7C0F;  /* lima   ·  86° */

  /* ---------- Movimiento ---------- */
  --curva:     cubic-bezier(.22,.61,.36,1);
  --curva-out: cubic-bezier(.16,1,.3,1);
  --muelle:    cubic-bezier(.34,1.56,.64,1);
}


/* ==========================================================================
   2 · FICHAS — modo oscuro
   ==========================================================================
   El modo de origen: OBI se diseñó a oscuras y el claro es la traducción.

   Se escribe TRES veces, y no es duplicación por descuido:
     .dark                        — la clase del sistema de diseño
     :root[data-theme="oscuro"]   — cómo lo marca esta app en el <html>
     @media + :root:not([data-theme]) — nadie ha elegido: manda el sistema

   La tercera lleva :not([data-theme]) para que en cuanto alguien elija, su
   elección gane. Sin esa condición, quien tenga el sistema en oscuro no
   podría ponerse en claro nunca: el media query se lo devolvería en cada
   pintado. */

.dark,
:root[data-theme="oscuro"] {
  color-scheme: dark;

  --bg:           #070B16;
  --bg-2:         #0C1322;
  --capa-1:       rgba(255,255,255,.045);
  --capa-2:       rgba(255,255,255,.075);
  --capa-3:       rgba(20,28,46,.92);
  --capa-hover:   rgba(255,255,255,.085);
  /* El mismo 20,28,46 de --capa-3, pero entero. Por qué, en §6. */
  --menu-fondo:   #141C2E;
  /* En oscuro el calendario del navegador viene negro sobre fondo oscuro y no
     se ve dónde pulsar. Invertirlo es lo único que se puede hacer con él. */
  --invertir-icono: invert(1) brightness(1.6);
  --linea:        rgba(255,255,255,.09);
  --linea-fuerte: rgba(255,255,255,.17);

  --txt:   #EEF3FA;
  --txt-2: #9BA9BF;
  /* Sube de #6B7A93: sobre el HUNDIDO (--bg-2, que es más claro que el terreno)
     daba 4.27:1 y hacía falta 4.5. El terreno lo pasaba; el hundido no, y el
     hundido es justo donde van las cabeceras de tabla. */
  --txt-3: #75849D;

  /* A oscuras el relleno y el texto pueden ser el MISMO tono: sobre tinta un
     menta claro da 9:1. Es en claro donde hacían falta dos. */
  --ok:        #00E5A0;  --ok-txt:      #34EBB2;  --ok-suave:      rgba(0,229,160,.14);
  --alerta:    #FFB020;  --alerta-txt:  #FFC152;  --alerta-suave:  rgba(255,176,32,.14);
  --peligro:   #FF5C7C;  --peligro-txt: #FF849B;  --peligro-suave: rgba(255,92,124,.14);
  --futuro:    #A78BFA;  --futuro-txt:  #C4B5FD;  --futuro-suave:  rgba(167,139,250,.15);
  --marca:     #4F8CFF;  --marca-txt:   #7CACFF;  --marca-suave:   rgba(79,140,255,.14);

  --grad-marca:  linear-gradient(135deg, #00E5FF 0%, #3D7BFF 48%, #8B5CF6 100%);
  --grad-cifra:  linear-gradient(115deg, #FFFFFF 0%, #CFE6FF 42%, #7CC5FF 100%);
  --grad-accion: linear-gradient(135deg, #3D7BFF 0%, #6D5CFF 100%);
  --grad-ok:     linear-gradient(90deg, #00E5A0 0%, #5EEAD4 100%);
  --grad-alerta: linear-gradient(90deg, #FFB020 0%, #FFD37A 100%);
  --grad-peligro:linear-gradient(90deg, #FF5C7C 0%, #FF9BAE 100%);
  --grad-futuro: linear-gradient(90deg, #8B5CF6 0%, #C4B5FD 100%);
  --grad-vidrio: linear-gradient(160deg, rgba(255,255,255,.07), rgba(255,255,255,.02));

  --malla-1: radial-gradient(1200px 780px at 8% -12%,  rgba(0,229,255,.13), transparent 62%);
  --malla-2: radial-gradient(1000px 700px at 104% 8%,  rgba(139,92,246,.15), transparent 60%);
  --malla-3: radial-gradient(900px  900px at 50% 118%, rgba(61,123,255,.11), transparent 62%);

  --sombra-1: 0 1px 2px rgba(0,0,0,.34),  0 2px 8px rgba(0,0,0,.24);
  --sombra-2: 0 4px 12px rgba(0,0,0,.40), 0 12px 32px rgba(0,0,0,.30);
  --sombra-3: 0 12px 28px rgba(0,0,0,.50),0 32px 72px rgba(0,0,0,.42);
  --brillo-accion:  0 6px 22px rgba(61,123,255,.42);
  --brillo-ok:      0 6px 22px rgba(0,229,160,.30);
  --brillo-peligro: 0 6px 22px rgba(255,92,124,.34);
  --filo: inset 0 1px 0 rgba(255,255,255,.07);

  /* Los mismos ocho tonos, subidos de luz para leerse sobre la tinta. El TONO
     no cambia entre modos —d-2 es verde en los dos, d-7 cian en los dos— o una
     categoría cambiaría de color al cambiar de modo y dejaría de reconocerse. */
  --d-1: #60A5FA; --d-2: #4ADE80; --d-3: #FBBF24; --d-4: #F87171;
  --d-5: #A78BFA; --d-6: #F472B6; --d-7: #22D3EE; --d-8: #A3E635;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme]) {
    color-scheme: dark;
    --bg:#070B16; --bg-2:#0C1322;
    --capa-1:rgba(255,255,255,.045); --capa-2:rgba(255,255,255,.075);
    --capa-3:rgba(20,28,46,.92); --capa-hover:rgba(255,255,255,.085);
    --menu-fondo:#141C2E; --invertir-icono:invert(1) brightness(1.6);
    --linea:rgba(255,255,255,.09); --linea-fuerte:rgba(255,255,255,.17);
    --txt:#EEF3FA; --txt-2:#9BA9BF; --txt-3:#6B7A93;
    --ok:#00E5A0; --ok-txt:#34EBB2; --ok-suave:rgba(0,229,160,.14);
    --alerta:#FFB020; --alerta-txt:#FFC152; --alerta-suave:rgba(255,176,32,.14);
    --peligro:#FF5C7C; --peligro-txt:#FF849B; --peligro-suave:rgba(255,92,124,.14);
    --futuro:#A78BFA; --futuro-txt:#C4B5FD; --futuro-suave:rgba(167,139,250,.15);
    --marca:#4F8CFF; --marca-txt:#7CACFF; --marca-suave:rgba(79,140,255,.14);
    --grad-marca:linear-gradient(135deg,#00E5FF 0%,#3D7BFF 48%,#8B5CF6 100%);
    --grad-cifra:linear-gradient(115deg,#FFFFFF 0%,#CFE6FF 42%,#7CC5FF 100%);
    --grad-accion:linear-gradient(135deg,#3D7BFF 0%,#6D5CFF 100%);
    --grad-ok:linear-gradient(90deg,#00E5A0 0%,#5EEAD4 100%);
    --grad-alerta:linear-gradient(90deg,#FFB020 0%,#FFD37A 100%);
    --grad-peligro:linear-gradient(90deg,#FF5C7C 0%,#FF9BAE 100%);
    --grad-futuro:linear-gradient(90deg,#8B5CF6 0%,#C4B5FD 100%);
    --grad-vidrio:linear-gradient(160deg,rgba(255,255,255,.07),rgba(255,255,255,.02));
    --malla-1:radial-gradient(1200px 780px at 8% -12%,rgba(0,229,255,.13),transparent 62%);
    --malla-2:radial-gradient(1000px 700px at 104% 8%,rgba(139,92,246,.15),transparent 60%);
    --malla-3:radial-gradient(900px 900px at 50% 118%,rgba(61,123,255,.11),transparent 62%);
    --sombra-1:0 1px 2px rgba(0,0,0,.34),0 2px 8px rgba(0,0,0,.24);
    --sombra-2:0 4px 12px rgba(0,0,0,.40),0 12px 32px rgba(0,0,0,.30);
    --sombra-3:0 12px 28px rgba(0,0,0,.50),0 32px 72px rgba(0,0,0,.42);
    --brillo-accion:0 6px 22px rgba(61,123,255,.42);
    --brillo-ok:0 6px 22px rgba(0,229,160,.30);
    --brillo-peligro:0 6px 22px rgba(255,92,124,.34);
    --filo:inset 0 1px 0 rgba(255,255,255,.07);
    --d-1:#60A5FA; --d-2:#4ADE80; --d-3:#FBBF24; --d-4:#F87171;
    --d-5:#A78BFA; --d-6:#F472B6; --d-7:#22D3EE; --d-8:#A3E635;
  }
}


/* ==========================================================================
   3 · EL PUENTE — las fichas viejas, colgadas de Aurora
   ==========================================================================
   Hay ~2 MB de JavaScript y 365 KB de CSS nombrando --page, --surface-1,
   --accent, --radius, --n-500. Renombrarlos sería tocar miles de sitios a
   cambio de nada.

   Ninguna ficha de aquí lleva un valor: todas APUNTAN. Es la capa que hace
   que las 70 vistas que no he reescrito ya se vean Aurora. */

:root {
  /* Superficies */
  --page:           var(--bg);
  --surface-1:      var(--capa-1);
  --surface-2:      var(--capa-2);
  --apagado:        var(--bg-2);
  --surface-sunken: var(--bg-2);

  --text-primary:   var(--txt);
  --text-secondary: var(--txt-2);
  --text-muted:     var(--txt-3);

  --border:        var(--linea);
  --border-strong: var(--linea-fuerte);
  --grid:          var(--linea);
  --axis:          var(--txt-3);

  /* La acción. --accent-ink es blanco SIEMPRE porque el relleno del botón
     principal es el degradado --grad-accion en los dos modos: el azul no se
     aclara a oscuras como hacía el del sistema viejo, así que la tinta encima
     tampoco tiene que invertirse. Era el fallo que aquel sistema arrastraba. */
  --accent:         var(--marca);
  --accent-hover:   var(--marca);
  --accent-activo:  var(--marca-txt);
  --accent-ink:     #FFFFFF;
  --accent-relleno: var(--marca);
  --accent-soft:    var(--marca-suave);
  --accent-suave:   var(--marca-suave);
  --accent-border:  var(--linea-fuerte);

  --color-bg:        var(--bg);
  --color-surface:   var(--bg-2);
  --color-text:      var(--txt);
  --color-divider:   var(--linea-fuerte);
  --color-hair-1:    var(--linea);
  --color-hair-2:    var(--linea-fuerte);
  --color-fill:      var(--marca);
  --color-on-fill:   #FFFFFF;
  --color-accent:    var(--marca);
  --color-on-accent: #FFFFFF;
  --color-accent-100: var(--marca-suave);
  --color-accent-400: var(--marca);
  --color-accent-700: var(--marca-txt);
  --color-neutral-300: var(--linea);
  --color-neutral-500: var(--txt-3);
  --color-neutral-800: var(--txt-2);

  --disabled-bg:    var(--bg-2);
  --disabled-ink:   var(--txt-3);
  --disabled-borde: var(--linea);

  --n-0: var(--capa-1); --n-25: var(--capa-1); --n-50: var(--bg);
  --n-100: var(--bg-2); --n-200: var(--bg-2);  --n-300: var(--linea);
  --n-400: var(--txt-3); --n-500: var(--txt-3); --n-600: var(--txt-2);
  --n-700: var(--txt-2); --n-800: var(--txt);   --n-900: var(--txt);

  --tinta-fondo: var(--bg);      --tinta-alza: var(--capa-1);
  --tinta-alza-2: var(--capa-2); --tinta-hondo: var(--bg-2);
  --tinta-ink: var(--txt);       --tinta-ink-2: var(--txt-2);
  --tinta-ink-3: var(--txt-3);   --tinta-linea: var(--linea);
  --tinta-linea-2: var(--linea-fuerte);
  --tinta-marca: var(--marca);   --tinta-marca-ink: #FFFFFF;
  --tinta-mal: var(--peligro-txt);

  /* Estado. Aurora SÍ es un semáforo, al revés que el sistema viejo. */
  --good:         var(--ok-txt);
  --warning:      var(--alerta-txt);
  --serious:      var(--alerta-txt);
  --critical:     var(--peligro-txt);
  --success-text: var(--ok-txt);

  /* Los nombres viejos de la serie apuntan a la paleta de datos de arriba. */
  --series-1: var(--d-1); --series-2: var(--d-2); --series-3: var(--d-3);
  --series-4: var(--d-4); --series-5: var(--d-5); --series-6: var(--d-6);
  --series-7: var(--d-7); --series-8: var(--d-8);

  --seq-250: color-mix(in oklab, var(--marca) 26%, transparent);
  --seq-350: color-mix(in oklab, var(--marca) 48%, transparent);
  --seq-450: color-mix(in oklab, var(--marca) 72%, transparent);
  --seq-600: var(--marca);
  --div-pos:    var(--ok);
  --div-neg:    var(--peligro);
  --div-neutro: var(--linea);

  /* Forma: aquí es donde muere el radio 0. Hay 176 reglas escribiendo
     border-radius: var(--radius*) y solo tres con un cero literal. */
  --radius:      var(--r-md);
  --radius-lg:   var(--r-lg);
  --radius-sm:   var(--r-sm);
  --radius-xs:   var(--r-xs);
  --radius-pill: var(--r-full);

  --shadow:       var(--sombra-1);
  --shadow-alta:  var(--sombra-2);
  --shadow-modal: var(--sombra-3);

  --sp-1: var(--e-1); --sp-2: var(--e-2); --sp-3: var(--e-3);
  --sp-4: var(--e-4); --sp-5: var(--e-6); --sp-6: var(--e-7); --sp-7: var(--e-9);
  --card-pad: var(--e-5);
  --celda-y: 12px;
  --control-alto: 46px;
  --tactil: 48px;

  --rapido: 160ms; --normal: 280ms; --lento: 520ms;
  --curva-salida: var(--curva);

  /* Tipografía. Archivo sigue: está empaquetada, y nada llega por la red. */
  --sans: "Archivo", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --font-body: var(--sans);
  --font-heading: var(--sans);
  --texto-base: 0.9375rem;

  --t-pagina:      clamp(1.55rem, 1.15rem + 1.6vw, 2.05rem);
  --t-seccion:     1.0rem;
  --t-tarjeta:     1.0625rem;
  --t-cifra:       clamp(1.65rem, 1.35rem + 1.1vw, 2.05rem);
  --t-cifra-media: 1.3rem;
  --t-cifra-alta:  clamp(2.6rem, 1.4rem + 7vw, 5.2rem);
  --t-cuerpo:      0.9375rem;
  --t-secundario:  0.875rem;
  --t-etiqueta:    0.8125rem;
  --t-meta:        0.8125rem;
  --t-rotulo:      0.6875rem;

  /* La escala menuda, y por qué está en rem y no en px.
   *
   * Un `font-size: var(--t-mini)` no crece cuando alguien sube el tamaño de letra en los
   * ajustes de su teléfono: se queda en once píxeles para siempre. Quien
   * necesita letra grande no la necesita solo en los párrafos — la necesita
   * también en el rótulo del chip y en el texto de la barra de abajo, que son
   * justo los que se escriben pequeños.
   *
   * En rem todo sigue a la letra del sistema. pruebas/escala-texto.mjs falla si
   * aparece un píxel suelto en un font-size, y hace bien. */
  --t-micro:  0.625rem;    /* 10px  · SOLO rótulos en caja alta */
  --t-mini:   0.6875rem;   /* 11px */
  --t-chip:   0.72rem;     /* 11.5px · chips y píldoras */
  --t-nano:   0.75rem;     /* 12px */
  /* Los tres de abajo no son texto: son el glifo dentro de un avatar, de un
     icono redondo o de un estado vacío. Van en rem por lo mismo — si el resto
     de la pieza crece con la letra y el glifo no, se descentra. */
  --t-glifo-sm: 0.8125rem; /* 13px */
  --t-glifo-md: 1.0625rem; /* 17px */
  --t-glifo-lg: 1.5rem;    /* 24px */

  --track-cifra:   -.04em;
  --track-titulo:  -.03em;
  --track-cifra-2: -.028em;
  --track-bloque:  -.018em;
  /* Con minúsculas, el tracking de caja alta sobra: .10em separaba las letras
     para que «TUS CUENTAS» respirara, y en «Tus cuentas» solo la desarma. */
  --track-rotulo:   .01em;

  /* ── La CAJA de los rótulos, en un solo sitio ──
   *
   * Los rótulos iban en CAJA ALTA: «TUS CUENTAS», «PUEDES GASTAR HOY», «LO QUE
   * NOTAMOS», «PERIODO», «CUENTA», «TIENES». En una sola pantalla de Inicio
   * había siete, y siete mayúsculas seguidas no se leen: se oyen. La pantalla
   * gritaba antes de decir nada.
   *
   * La caja alta es una herencia de los paneles de control, donde sirve para
   * separar el cromo del dato. Aquí no hace falta: los rótulos ya se distinguen
   * por tamaño, peso y color (--txt-3), y en minúsculas se leen de un vistazo en
   * vez de deletrearse.
   *
   * Va como ficha y no escrito en cada regla —eran veinticinco— para que la
   * decisión viva en un sitio: quien quiera volver a las versalitas cambia esta
   * línea y vuelven todas a la vez, sin buscar ninguna. */
  --caja-rotulo: none;

  --peso-normal: 400; --peso-medio: 600; --peso-fuerte: 800;
}

@media (pointer: coarse) { :root { --control-alto: 50px; } }
@media (max-width: 720px) { :root { --canal: 16px; } }


/* ==========================================================================
   4 · BASE
   ========================================================================== */

/* El <html> lleva el mismo terreno que el body, y no es repetirse: lo que se ve
   por debajo del contenido —el rebote del desplazamiento en un iPhone, y la
   franja bajo la barra del pulgar— lo pinta el <html>, no el body. Sin esto
   salía una banda BLANCA al final de cada pantalla en el teléfono. */
html { background: var(--bg); }

body {
  background: var(--bg);
  color: var(--txt);
  font-family: var(--sans);
  font-variant-numeric: tabular-nums;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* La malla de luz. Va en un pseudoelemento fijo y no en `background` del body
   porque tiene que quedarse quieta cuando la página se desplaza: si se moviera
   con el contenido, un scroll largo la sacaría de pantalla y la mitad de abajo
   de la app se vería de otro color.

   Son gradientes QUIETOS: no hay nada que apagar con prefers-reduced-motion, y
   no cuesta un solo cuadro por segundo después del primer pintado. */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -2;
  background:
    var(--malla-1),
    var(--malla-2),
    var(--malla-3),
    var(--bg);
  pointer-events: none;
}

/* El papel rayado del libro de cuentas: dos rejillas de 1px muy tenues. Se ve
   apenas, y es lo que impide que las zonas vacías se lean como un hueco. */
body::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  opacity: .5;
  background-image:
    linear-gradient(to right, var(--linea) 1px, transparent 1px),
    linear-gradient(to bottom, var(--linea) 1px, transparent 1px);
  background-size: 72px 72px;
  /* Se desvanece hacia abajo: arriba da textura, abajo estorbaría a las
     tablas largas. */
  -webkit-mask-image: linear-gradient(to bottom, rgba(0,0,0,.55), transparent 620px);
          mask-image: linear-gradient(to bottom, rgba(0,0,0,.55), transparent 620px);
}

::selection { background: var(--marca); color: #fff; }

/* Barras de desplazamiento a juego. Sin esto, en oscuro sale una barra gris
   del sistema pegada a una app azul casi negra. */
* { scrollbar-width: thin; scrollbar-color: var(--linea-fuerte) transparent; }
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  background: var(--linea-fuerte);
  border-radius: var(--r-full);
  border: 3px solid transparent;
  background-clip: content-box;
}
::-webkit-scrollbar-thumb:hover { background: var(--txt-3); background-clip: content-box; }

:focus-visible {
  outline: 2px solid var(--au-blue);
  outline-offset: 3px;
  border-radius: var(--r-sm);
}


/* ==========================================================================
   5 · TIPOGRAFÍA
   ========================================================================== */

h1, h2, h3, h4 { letter-spacing: var(--track-bloque); }

.topbar__head h1,
.titulo-pagina {
  font-size: var(--t-pagina);
  font-weight: 800;
  letter-spacing: var(--track-titulo);
  line-height: 1.08;
}

/* El rótulo que encabeza una SECCIÓN de la pantalla —«Tus cuentas», «Lo que
   notamos»— es un título, no una etiqueta.
 *
 * Iba a 11px en caja alta y gris apagado, o sea con el mismo aspecto que los
 * rotulitos que van dentro de una tarjeta. El resultado es que las secciones no
 * se veían: la pantalla era una lista de tarjetas sin nada que las agrupara, y
 * había que leerlas para saber de qué iba cada zona.
 *
 * Ahora tiene el tamaño y el color de lo que es. Los rotulitos de dentro de una
 * tarjeta siguen como estaban —esa distinción es la que hace que se entienda la
 * jerarquía de un vistazo—. */
.rotulo, .seccion__rotulo {
  font-size: var(--t-seccion);
  font-weight: 800;
  letter-spacing: var(--track-bloque);
  text-transform: var(--caja-rotulo);
  color: var(--txt);
}

/* La cifra con degradado. Se usa en la héroe y en los totales de tarjeta.

   El `color` de reserva NO es decorativo: si el navegador no aplica
   background-clip:text —o si alguien fuerza los colores del sistema— el texto
   se queda con `transparent` y desaparece la única cifra de la pantalla. Con
   la reserva se queda en tinta, que es fea pero legible. */
.cifra-grad {
  color: var(--txt);
  background: var(--grad-cifra);
  -webkit-background-clip: text;
          background-clip: text;
}
@supports ((-webkit-background-clip: text) or (background-clip: text)) {
  .cifra-grad { -webkit-text-fill-color: transparent; }
}
/* Con los colores forzados (alto contraste de Windows) el degradado se pierde
   y quedaría un hueco. Se devuelve la tinta. */
@media (forced-colors: active) {
  .cifra-grad { -webkit-text-fill-color: currentColor; background: none; }
}

.tnum, .num, .monto { font-variant-numeric: tabular-nums; }


/* ==========================================================================
   6 · LA CARCASA
   ==========================================================================
   Barra superior de vidrio · carril lateral en escritorio · barra inferior en
   móvil · contenido centrado a 1240. */

.app {
  /* vh primero como reserva: un WebView viejo que no entienda dvh se queda con
     el 100vh de arriba en vez de sin alto ninguno. */
  min-height: 100vh;
  min-height: 100dvh;
  background: transparent;
}

/* ---------- Barra superior ----------
   Pegajosa y de vidrio: al desplazar, el contenido pasa POR DEBAJO y se ve
   borroso. Es el gesto que más dice «app moderna» y cuesta una regla. */
.topbar {
  position: sticky;
  top: 0;
  z-index: 40;
  min-height: var(--alto-topbar);
  padding: var(--e-3) var(--canal);
  padding-top: calc(var(--e-3) + env(safe-area-inset-top, 0px));
  background: color-mix(in srgb, var(--bg) 78%, transparent);
  backdrop-filter: blur(22px) saturate(1.5);
  -webkit-backdrop-filter: blur(22px) saturate(1.5);
  border-bottom: 1px solid var(--linea);
  border-radius: 0;
  box-shadow: none;
  transition: box-shadow var(--normal) var(--curva),
              background var(--normal) var(--curva);
}
/* Al despegarse del tope aparece la sombra. Lo marca el JS con una clase
   (js/ds.js → vigilarScroll) porque no hay forma de detectar «sticky pegado»
   solo con CSS sin un sentinel, y el sentinel obliga a tocar el HTML de todas
   las vistas. */
.topbar[data-pegada="si"] {
  box-shadow: var(--sombra-2);
  background: color-mix(in srgb, var(--bg) 88%, transparent);
}

.topbar__head h1 { margin: 0; }
.topbar__head p { color: var(--txt-2); font-size: var(--t-secundario); }

/* ---------- Carril lateral ----------
   Ya no es un panel de color distinto: es el mismo terreno con una regla y,
   dentro, píldoras que se encienden. Un bloque sólido de otro tono a la
   izquierda de la pantalla pesaba tanto como el contenido. */
.sidebar__panel {
  background: transparent;
  border-right: 1px solid var(--linea);
  padding: var(--e-5) var(--e-4);
}

.nav__grupo-rotulo {
  font-size: var(--t-rotulo);
  font-weight: 700;
  letter-spacing: var(--track-rotulo);
  text-transform: var(--caja-rotulo);
  color: var(--txt-3);
  padding: 0 var(--e-3);
  margin-bottom: var(--e-2);
}

.nav__item {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--e-3);
  width: 100%;
  min-height: 44px;
  padding: 10px var(--e-3);
  border: 0;
  border-radius: var(--r-sm);
  background: transparent;
  color: var(--txt-2);
  font-size: var(--t-cuerpo);
  font-weight: 600;
  text-align: left;
  cursor: pointer;
  transition: background var(--rapido) var(--curva),
              color var(--rapido) var(--curva),
              transform var(--rapido) var(--muelle);
}
.nav__item:hover { background: var(--capa-2); color: var(--txt); }
.nav__item:active { transform: scale(.98); }

/* La activa: relleno tintado, texto de marca y una barrita luminosa a la
   izquierda. Tres señales, y ninguna es solo el color (§9). */
.nav__item[aria-current="page"] {
  background: var(--marca-suave);
  color: var(--marca-txt);
  font-weight: 700;
}
.nav__item[aria-current="page"]::before {
  content: "";
  position: absolute;
  left: 0; top: 50%;
  width: 3px; height: 20px;
  transform: translateY(-50%);
  border-radius: var(--r-full);
  background: var(--grad-marca);
  box-shadow: var(--brillo-accion);
}

.nav__badge {
  margin-left: auto;
  min-width: 22px;
  height: 20px;
  padding: 0 7px;
  display: inline-grid;
  place-items: center;
  border-radius: var(--r-full);
  background: var(--capa-2);
  border: 1px solid var(--linea);
  color: var(--txt-2);
  font-size: var(--t-mini);
  font-weight: 800;
}
.nav__item[aria-current="page"] .nav__badge {
  background: var(--marca);
  border-color: transparent;
  color: #fff;
}

/* ---------- Selector de espacio ---------- */
.espacio-sel {
  width: 100%;
  display: flex; align-items: center; gap: var(--e-3);
  padding: 10px var(--e-3);
  border: 1px solid var(--linea);
  border-radius: var(--r-md);
  background: var(--capa-1);
  box-shadow: var(--filo);
  cursor: pointer;
  transition: border-color var(--rapido) var(--curva), background var(--rapido) var(--curva);
}
.espacio-sel:hover { border-color: var(--linea-fuerte); background: var(--capa-2); }
.espacio-sel__icono {
  width: 34px; height: 34px;
  display: grid; place-items: center;
  border-radius: var(--r-sm);
  background: var(--marca-suave);
  font-size: var(--t-glifo-md);
}
.espacio-sel__texto { display: grid; text-align: left; min-width: 0; }
.espacio-sel__texto strong { font-size: var(--t-cuerpo); font-weight: 700; }
.espacio-sel__texto span { font-size: var(--t-nano); color: var(--txt-3); }
.espacio-sel__flecha { margin-left: auto; color: var(--txt-3); }

/* ---------- Menús flotantes ---------- */
/* Un menú flotante lleva fondo OPACO, y eso no es una excepción al vidrio:
 * es lo único que funciona donde está.
 *
 * Los tres cuelgan de .topbar, que sí es de vidrio. Y ahí está el detalle que
 * cuesta dos horas encontrar: un ancestro con `backdrop-filter` se convierte en
 * la RAÍZ del fondo de todo lo que lleva dentro. El desenfoque de este menú deja
 * de ver la página —que es lo que tenía que difuminar— y solo ve el trozo de
 * barra sobre el que se apoya. El filtro se aplica, no da error, y no hace
 * nada.
 *
 * Lo que queda entonces es el 8% de transparencia de --capa-3 sin difuminar
 * nada debajo. Con una tarjeta de cuenta detrás —un degradado a todo color— se
 * leían las palabras del fondo entre las del menú. Medido: «Anotar un gasto»
 * se distinguía a través del panel del avatar.
 *
 * Así que el fondo va entero. El desenfoque se queda por si algún día el menú
 * deja de colgar de la barra, pero ya no se depende de él para poder leer. */
.espacio-menu, .usuario-menu, .avisos-panel {
  background: var(--menu-fondo);
  border: 1px solid var(--linea-fuerte);
  border-radius: var(--r-lg);
  box-shadow: var(--sombra-3);
  backdrop-filter: blur(24px) saturate(1.6);
  -webkit-backdrop-filter: blur(24px) saturate(1.6);
  padding: var(--e-2);
  overflow: hidden;
}
.usuario-menu__item, .espacio-menu__item, .avisos-panel button {
  border-radius: var(--r-sm);
  transition: background var(--rapido) var(--curva);
}
.usuario-menu__item:hover, .espacio-menu__item:hover { background: var(--capa-2); }

/* ---------- Avatar y botón de usuario ---------- */
.usuario {
  display: flex; align-items: center; gap: var(--e-2);
  padding: 6px 10px 6px 6px;
  border: 1px solid var(--linea);
  border-radius: var(--r-full);
  background: var(--capa-1);
  cursor: pointer;
  transition: border-color var(--rapido) var(--curva), background var(--rapido) var(--curva);
}
.usuario:hover { border-color: var(--linea-fuerte); background: var(--capa-2); }
.usuario__avatar {
  width: 32px; height: 32px;
  display: grid; place-items: center;
  border-radius: var(--r-full);
  background: var(--grad-marca);
  color: #fff;
  font-weight: 800; font-size: var(--t-glifo-sm);
  box-shadow: var(--brillo-accion);
}
.usuario__texto strong { font-size: var(--t-glifo-sm); font-weight: 700; }
.usuario__texto span { font-size: var(--t-mini); color: var(--txt-3); }

.icono-btn, .avisos-btn {
  width: 40px; height: 40px;
  display: grid; place-items: center;
  border: 1px solid var(--linea);
  border-radius: var(--r-full);
  background: var(--capa-1);
  color: var(--txt-2);
  cursor: pointer;
  transition: background var(--rapido) var(--curva),
              color var(--rapido) var(--curva),
              transform var(--rapido) var(--muelle);
}
.icono-btn:hover, .avisos-btn:hover { background: var(--capa-2); color: var(--txt); }
.icono-btn:active, .avisos-btn:active { transform: scale(.94); }
.avisos-btn__cuenta {
  position: absolute; top: -2px; right: -2px;
  min-width: 18px; height: 18px; padding: 0 5px;
  display: grid; place-items: center;
  border-radius: var(--r-full);
  background: var(--peligro);
  color: #fff; font-size: var(--t-micro); font-weight: 800;
  border: 2px solid var(--bg);
}

/* ---------- Buscador ---------- */
.buscador {
  display: flex; align-items: center; gap: var(--e-2);
  height: 40px;
  padding: 0 var(--e-3);
  border: 1px solid var(--linea);
  border-radius: var(--r-full);
  background: var(--capa-1);
  transition: border-color var(--rapido) var(--curva),
              box-shadow var(--rapido) var(--curva),
              background var(--rapido) var(--curva);
}
.buscador:focus-within {
  border-color: var(--marca);
  background: var(--capa-2);
  box-shadow: 0 0 0 4px var(--marca-suave);
}
.buscador input { border: 0; background: transparent; outline: none; min-width: 0; }
.buscador__atajo {
  font-size: var(--t-micro); font-weight: 700;
  padding: 3px 6px;
  border: 1px solid var(--linea);
  border-radius: var(--r-xs);
  color: var(--txt-3);
  background: var(--bg-2);
}

/* ---------- Barra inferior (móvil) ----------
   Vidrio, cinco destinos, y el activo con una gota de luz encima. El centro es
   el botón de acción y sobresale. */
.pulgar {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: 45;
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 1fr;
  align-items: end;
  gap: 2px;
  padding: 6px var(--e-2);
  padding-bottom: calc(6px + env(safe-area-inset-bottom, 0px));
  background: color-mix(in srgb, var(--bg) 82%, transparent);
  backdrop-filter: blur(24px) saturate(1.6);
  -webkit-backdrop-filter: blur(24px) saturate(1.6);
  border-top: 1px solid var(--linea);
  border-radius: 0;
}
.pulgar__btn {
  position: relative;
  display: grid;
  justify-items: center;
  gap: 3px;
  min-height: 52px;
  padding: 7px 2px 5px;
  border: 0;
  border-radius: var(--r-sm);
  background: transparent;
  color: var(--txt-3);
  cursor: pointer;
  transition: color var(--rapido) var(--curva), transform var(--rapido) var(--muelle);
}
.pulgar__btn:active { transform: scale(.93); }
.pulgar__txt { font-size: var(--t-micro); font-weight: 700; letter-spacing: .01em; }
.pulgar__btn--aqui { color: var(--marca-txt); }
/* La gota de luz sobre la pestaña activa. */
.pulgar__btn--aqui::before {
  content: "";
  position: absolute; top: 0; left: 50%;
  width: 26px; height: 3px;
  transform: translateX(-50%);
  border-radius: var(--r-full);
  background: var(--grad-marca);
  box-shadow: var(--brillo-accion);
}
/* El centro: sobresale y lleva el degradado. Es el botón de subir/anotar. */
.pulgar__btn--centro {
  color: #fff;
  margin-top: -18px;
}
.pulgar__btn--centro::after {
  content: "";
  position: absolute;
  top: 2px; left: 50%;
  width: 46px; height: 46px;
  transform: translateX(-50%);
  border-radius: var(--r-full);
  background: var(--grad-accion);
  box-shadow: var(--brillo-accion);
  z-index: -1;
}
.pulgar__btn--centro .pulgar__txt { color: var(--txt-2); margin-top: 24px; }
.pulgar__btn--centro::before { display: none; }

/* De lado, lo que falta es ALTO. El teléfono sigue siendo teléfono girado (la
   barra existe por `esTelefono()`, no por un ancho), pero entre la cabecera, los
   filtros y 64px de barra quedaban unos 160px de 390 para el contenido. Aquí la
   barra baja a 48: sin rótulo a la vista —sigue ahí para el lector de pantalla—
   y el centro sin sobresalir. La app instalada no gira; esto es el navegador. */
@media (max-height: 500px) {
  body.con-pulgar { --alto-tabbar: 48px; }
  .pulgar {
    padding-top: 2px;
    padding-bottom: calc(2px + env(safe-area-inset-bottom, 0px));
    padding-left: calc(var(--e-2) + env(safe-area-inset-left, 0px));
    padding-right: calc(var(--e-2) + env(safe-area-inset-right, 0px));
  }
  .pulgar__btn { min-height: 44px; padding: 4px 2px; align-content: center; }
  .pulgar__txt {
    position: absolute; width: 1px; height: 1px;
    overflow: hidden; clip-path: inset(50%); white-space: nowrap;
  }
  .pulgar__btn--centro { margin-top: 0; }
  .pulgar__btn--centro::after { top: 50%; width: 40px; height: 40px; transform: translate(-50%, -50%); }
}

body.con-pulgar .main { padding-bottom: calc(var(--alto-tabbar) + env(safe-area-inset-bottom, 0px) + var(--e-6)); }

/* ---------- Botón flotante (escritorio) ---------- */
.fab {
  position: fixed;
  right: var(--e-6);
  bottom: var(--e-6);
  z-index: 44;
  width: 58px; height: 58px;
  display: grid; place-items: center;
  border: 0;
  border-radius: var(--r-full);
  background: var(--grad-accion);
  color: #fff;
  box-shadow: var(--brillo-accion), var(--sombra-2);
  cursor: pointer;
  transition: transform var(--normal) var(--muelle), box-shadow var(--normal) var(--curva);
}
.fab:hover { transform: translateY(-3px) scale(1.04); }
.fab:active { transform: scale(.94); }
@media (max-width: 900px) { .fab { display: none; } }

/* ---------- Filtros ---------- */
.filters {
  display: flex; flex-wrap: wrap; align-items: end; gap: var(--e-3);
  padding: var(--e-4) var(--canal);
  border-bottom: 1px solid var(--linea);
  background: transparent;
}

/* ---------- Pie ---------- */
.pie {
  padding: var(--e-7) var(--canal);
  border-top: 1px solid var(--linea);
  color: var(--txt-3);
  font-size: var(--t-meta);
}
.pie__enlaces button {
  border: 0; background: transparent; color: var(--txt-2);
  padding: 6px 10px; border-radius: var(--r-sm); cursor: pointer;
  transition: background var(--rapido) var(--curva), color var(--rapido) var(--curva);
}
.pie__enlaces button:hover { background: var(--capa-2); color: var(--txt); }

/* ---------- La zona de contenido ---------- */
.view {
  max-width: var(--ancho-max);
  margin: 0 auto;
  padding: var(--e-6) var(--canal) var(--e-9);
}


/* ==========================================================================
   7 · TARJETAS
   ==========================================================================
   La pieza que más cambia respecto al sistema viejo. Allí una tarjeta era del
   color de la página con una regla de 2px alrededor. Aquí es una CAPA: fondo
   propio, borde fino y sombra. */

.card, .seccion > .card, section.card {
  position: relative;
  background: var(--capa-1);
  border: 1px solid var(--linea);
  border-radius: var(--r-lg);
  box-shadow: var(--sombra-1), var(--filo);
  padding: var(--card-pad);
  overflow: hidden;
  transition: border-color var(--normal) var(--curva),
              box-shadow var(--normal) var(--curva),
              transform var(--normal) var(--curva);
}

/* Tarjeta pulsable: se levanta. Solo la que de verdad hace algo — un hover que
   promete y no cumple es peor que ninguno. */
.card--accion { cursor: pointer; }
.card--accion:hover {
  transform: translateY(-2px);
  border-color: var(--linea-fuerte);
  box-shadow: var(--sombra-2), var(--filo);
}

.card__head {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: var(--e-3);
  margin-bottom: var(--e-4);
}
.card__head h2, .card > h2 {
  font-size: var(--t-tarjeta);
  font-weight: 700;
  letter-spacing: var(--track-bloque);
}
.card__head p { font-size: var(--t-meta); color: var(--txt-3); line-height: 1.45; }

.seccion__titulo {
  font-size: var(--t-seccion);
  font-weight: 800;
  letter-spacing: var(--track-rotulo);
  text-transform: var(--caja-rotulo);
  color: var(--txt-3);
}
.seccion__pista { font-size: var(--t-meta); color: var(--txt-3); }

.grid { display: grid; gap: var(--e-4); }


/* ==========================================================================
   8 · BOTONES
   ========================================================================== */

.btn {
  display: inline-flex; align-items: center; justify-content: center;
  gap: var(--e-2);
  min-height: var(--control-alto);
  padding: 0 var(--e-5);
  border: 1px solid var(--linea-fuerte);
  border-radius: var(--r-sm);
  background: var(--capa-1);
  color: var(--txt);
  font-size: var(--t-cuerpo);
  font-weight: 700;
  letter-spacing: -.005em;
  cursor: pointer;
  white-space: nowrap;
  transition: background var(--rapido) var(--curva),
              border-color var(--rapido) var(--curva),
              transform 120ms var(--muelle),
              box-shadow var(--rapido) var(--curva);
}
.btn:hover { background: var(--capa-2); border-color: var(--txt-3); }
.btn:active { transform: scale(.97); }
.btn[disabled], .btn:disabled {
  opacity: .45; cursor: not-allowed; transform: none;
}

/* El principal. Degradado + brillo: es lo que hace que se vea el botón antes
   que el texto de al lado. Uno por pantalla. */
.btn--primary, .btn-primary {
  background: var(--grad-accion);
  border-color: transparent;
  color: #fff;
  box-shadow: var(--brillo-accion);
}
.btn--primary:hover, .btn-primary:hover {
  background: var(--grad-accion);
  border-color: transparent;
  filter: brightness(1.08);
  box-shadow: var(--brillo-accion), var(--sombra-2);
}

.btn--ghost, .btn-ghost {
  background: transparent;
  border-color: transparent;
  color: var(--txt-2);
}
.btn--ghost:hover, .btn-ghost:hover { background: var(--capa-2); color: var(--txt); }

.btn--danger {
  background: var(--peligro);
  border-color: transparent;
  color: #fff;
  box-shadow: var(--brillo-peligro);
}
.btn--danger:hover { filter: brightness(1.08); }

.btn--sm { min-height: 34px; padding: 0 var(--e-3); font-size: var(--t-meta); border-radius: var(--r-xs); }
.btn--block, .btn-block { width: 100%; }


/* ==========================================================================
   9 · CAMPOS
   ========================================================================== */

/* `align-content: start` no es cosmético.
 *
 * Un campo es una rejilla de dos o tres filas —rótulo, control y a veces una
 * pista debajo— y en una fila de cuatro campos todos se estiran a la altura del
 * más alto. Con las filas en `auto`, `align-content` vale `normal`, que en una
 * rejilla se comporta como `stretch`: el hueco sobrante se REPARTE entre las
 * filas, así que el campo sin pista baja su control medio dedo y el que tiene
 * cuatro líneas de pista lo sube. Los cuatro selectores de una fila salían a
 * cuatro alturas distintas.
 *
 * No se veía como un fallo de CSS: se veía como si los márgenes se hubieran
 * puesto a ojo. Se cazó en Configuración → Avisos, que es la fila más larga. */
.field { display: grid; gap: 6px; align-content: start; }
.field > span {
  font-size: var(--t-rotulo);
  font-weight: 700;
  letter-spacing: var(--track-rotulo);
  text-transform: var(--caja-rotulo);
  color: var(--txt-3);
}

.input, input[type=text], input[type=search], input[type=number],
input[type=date], input[type=email], input[type=password], select, textarea {
  min-height: var(--control-alto);
  padding: 0 var(--e-3);
  border: 1px solid var(--linea-fuerte);
  border-radius: var(--r-sm);
  background: var(--capa-1);
  color: var(--txt);
  font-size: var(--t-cuerpo);
  transition: border-color var(--rapido) var(--curva),
              box-shadow var(--rapido) var(--curva),
              background var(--rapido) var(--curva);
}
textarea { padding: var(--e-3); min-height: 92px; line-height: 1.5; }

/* LAS OPCIONES DEL DESPLEGABLE, PINTADAS A MANO
   ------------------------------------------------------------------
   Esto no es un detalle: sin estas dos líneas, el desplegable de un mes es
   ILEGIBLE en modo oscuro, y no en un navegador raro — en Chrome sobre Windows,
   que es donde más se usa esta aplicación.

   La lista que se despliega NO la dibuja la página: la dibuja el sistema
   operativo. Y Chrome hace una cosa a medias: le pasa el «color» del <select>
   —que aquí es casi blanco— pero pinta el fondo con el del sistema, que es
   blanco. Texto blanco sobre blanco. «color-scheme: dark» está puesto en el
   :root y no basta, porque un <select> con «background» propio deja de
   consultarlo para el popup.

   La única forma de arreglarlo es decirle a cada <option> de qué color va, y
   con un color SÓLIDO: --capa-3 es translúcida y una ventana del sistema no
   sabe componer transparencias. Por eso se usa --menu-fondo, que es la misma
   ficha que usan los menús flotantes por el mismo motivo. */
select option,
select optgroup {
  background-color: var(--menu-fondo);
  color: var(--txt);
}

/* El calendario y el reloj de los campos de fecha, por lo mismo. Sin esto, en
   oscuro el iconito sale negro sobre fondo oscuro y no se ve dónde pulsar. */
input[type=date]::-webkit-calendar-picker-indicator,
input[type=month]::-webkit-calendar-picker-indicator,
input[type=time]::-webkit-calendar-picker-indicator {
  filter: var(--invertir-icono, none);
  cursor: pointer;
  opacity: .85;
}
input[type=date]:hover::-webkit-calendar-picker-indicator { opacity: 1; }
.input:hover, select:hover, textarea:hover { border-color: var(--txt-3); }
.input:focus, input:focus, select:focus, textarea:focus {
  outline: none;
  border-color: var(--marca);
  background: var(--capa-2);
  box-shadow: 0 0 0 4px var(--marca-suave);
}
::placeholder { color: var(--txt-3); opacity: 1; }


/* ==========================================================================
   10 · PÍLDORAS Y CHIPS
   ========================================================================== */

.pill, .tag {
  display: inline-flex; align-items: center; gap: 5px;
  height: 24px; padding: 0 10px;
  border-radius: var(--r-full);
  background: var(--capa-2);
  border: 1px solid var(--linea);
  color: var(--txt-2);
  font-size: var(--t-chip); font-weight: 700;
  letter-spacing: .01em;
}
.pill--good    { background: var(--ok-suave);      border-color: transparent; color: var(--ok-txt); }
.pill--warning { background: var(--alerta-suave);  border-color: transparent; color: var(--alerta-txt); }
.pill--serious { background: var(--alerta-suave);  border-color: transparent; color: var(--alerta-txt); }
.pill--critical{ background: var(--peligro-suave); border-color: transparent; color: var(--peligro-txt); }
.pill--info    { background: var(--marca-suave);   border-color: transparent; color: var(--marca-txt); }
.pill--futuro  { background: var(--futuro-suave);  border-color: transparent; color: var(--futuro-txt); }

.chip-cat {
  display: inline-flex; align-items: center;
  height: 26px; padding: 0 10px;
  border-radius: var(--r-full);
  border: 1px solid var(--linea-fuerte);
  background: var(--capa-1);
  color: var(--txt-2);
  font-size: var(--t-chip); font-weight: 700;
  cursor: default;
  transition: background var(--rapido) var(--curva),
              border-color var(--rapido) var(--curva),
              transform var(--rapido) var(--muelle);
}
button.chip-cat { cursor: pointer; }
button.chip-cat:hover { background: var(--capa-2); border-color: var(--txt-3); }
button.chip-cat:active { transform: scale(.95); }
.chip-cat[data-variante="traspaso"]    { background: var(--capa-2); color: var(--txt-3); border-color: var(--linea); }
.chip-cat[data-variante="sin-asignar"] { border-style: dashed; color: var(--txt-3); }
.chip-cat[data-variante="accion"]      { background: var(--marca-suave); border-color: transparent; color: var(--marca-txt); }

/* En móvil el chip crece a zona táctil (§9: 48px). */
@media (pointer: coarse) {
  button.chip-cat { min-height: 40px; padding: 0 14px; }
}


/* ==========================================================================
   11 · LA RESPUESTA (cifra héroe)
   ==========================================================================
   Ya existía en el sistema viejo y se conserva la marca —la usan 15 vistas—
   pero se viste entera de nuevo: degradado por detrás, cifra con degradado
   dentro, y el tono pinta el halo. */

.respuesta {
  position: relative;
  padding: var(--e-7) var(--e-6);
  border-radius: var(--r-xl);
  overflow: hidden;
}
/* El halo de color detrás de la cifra. Cambia con data-tono, así que el
   componente no tiene que saber de colores: pone el tono y ya. */
.respuesta::before {
  content: "";
  position: absolute;
  top: -40%; left: -10%;
  width: 70%; height: 180%;
  background: radial-gradient(closest-side, var(--halo, var(--marca-suave)), transparent 72%);
  opacity: .9;
  pointer-events: none;
}
.respuesta[data-tono="bien"] { --halo: var(--ok-suave); }
.respuesta[data-tono="ojo"]  { --halo: var(--alerta-suave); }
.respuesta[data-tono="mal"]  { --halo: var(--peligro-suave); }

.respuesta__cabeza { position: relative; display: flex; justify-content: space-between; gap: var(--e-4); }
.respuesta__rotulo {
  font-size: var(--t-rotulo); font-weight: 700;
  letter-spacing: var(--track-rotulo); text-transform: var(--caja-rotulo);
  color: var(--txt-3);
  margin-bottom: var(--e-2);
}
.respuesta__cifra {
  font-size: var(--t-cifra-alta);
  font-weight: 800;
  letter-spacing: var(--track-cifra);
  line-height: .95;
  color: var(--txt);
  background: var(--grad-cifra);
  -webkit-background-clip: text;
          background-clip: text;
}
@supports ((-webkit-background-clip: text) or (background-clip: text)) {
  .respuesta__cifra { -webkit-text-fill-color: transparent; }
}
@media (forced-colors: active) {
  .respuesta__cifra { -webkit-text-fill-color: currentColor; background: none; }
}
.respuesta--secundaria { padding: var(--card-pad); border-radius: var(--r-lg); }
.respuesta--secundaria .respuesta__cifra { font-size: var(--t-cifra); }
.respuesta--secundaria::before { display: none; }

.respuesta__pie { position: relative; color: var(--txt-2); margin-top: var(--e-3); max-width: 62ch; }

.respuesta__dictamen {
  position: relative;
  display: flex; align-items: center; gap: var(--e-2);
  margin-top: var(--e-5);
  padding: 10px var(--e-4);
  border-radius: var(--r-md);
  background: var(--capa-2);
  border: 1px solid var(--linea);
  font-size: var(--t-secundario);
  font-weight: 600;
}
/* El tono viaja en una ficha propia (--senal) además de en `color`.
 *
 * El primer intento pintaba el disco con `background: currentColor` y el glifo
 * con `color: var(--bg)` en la MISMA regla. No funciona, y el motivo es sutil:
 * `currentColor` dentro de una declaración resuelve al `color` COMPUTADO DE ESE
 * elemento, no al que hereda del padre — y ese color acababa de ponerse al del
 * terreno. Resultado: disco oscuro con un glifo oscuro encima, o sea un punto
 * negro sin nada dentro. Se ve en una captura y no leyendo el código. */
.respuesta__dictamen { --senal: var(--txt-2); }
.respuesta__dictamen[data-tono="bien"] { background: var(--ok-suave);      border-color: transparent; color: var(--ok-txt);      --senal: var(--ok); }
.respuesta__dictamen[data-tono="ojo"]  { background: var(--alerta-suave);  border-color: transparent; color: var(--alerta-txt);  --senal: var(--alerta); }
.respuesta__dictamen[data-tono="mal"]  { background: var(--peligro-suave); border-color: transparent; color: var(--peligro-txt); --senal: var(--peligro); }
.respuesta__senal {
  width: 20px; height: 20px;
  display: grid; place-items: center;
  border-radius: var(--r-full);
  background: var(--senal);
  /* El glifo, del color del TERRENO: es lo que más contraste da contra
     cualquiera de los cuatro tonos, en los dos modos. */
  color: var(--bg);
  font-size: var(--t-mini); font-weight: 800;
  flex: none;
}
.respuesta__nota { position: relative; margin-top: var(--e-3); font-size: var(--t-meta); color: var(--txt-3); }


/* ==========================================================================
   12 · BARRAS: límite, reparto, medidor
   ========================================================================== */

.limite__carril, .meter__track, .reparto__carril {
  position: relative;
  display: block;
  height: 10px;
  border-radius: var(--r-full);
  background: var(--bg-2);
  overflow: hidden;
}
.limite__relleno, .meter__fill, .reparto__relleno {
  display: block;
  height: 100%;
  border-radius: var(--r-full);
  background: var(--grad-marca);
  transform-origin: left center;
  width: calc(min(var(--parte, 0), 1) * 100%);
  transition: width var(--lento) var(--curva-out);
}
.reparto__relleno { background: var(--color, var(--marca)); }

/* El estado tiñe la barra. Va por atributo en el contenedor para que el
   relleno no tenga que saberlo. */
.limite[data-pasado="si"] .limite__relleno { background: var(--grad-peligro); }
.limite[data-ritmo="rapido"] .limite__relleno { background: var(--grad-alerta); }
.limite[data-tono="bien"] .limite__relleno { background: var(--grad-ok); }

/* La marca del punto del mes: una rayita vertical. Sin ella la barra dice
   cuánto llevas pero no si vas rápido, que es la pregunta real. */
.limite__marca {
  position: absolute; top: -3px; bottom: -3px;
  left: calc(var(--marca, 0) * 100%);
  width: 2px;
  border-radius: var(--r-full);
  background: var(--txt);
  opacity: .5;
}
.limite__cabeza { display: flex; justify-content: space-between; gap: var(--e-3); margin-bottom: 7px; }
.limite__rotulo { font-size: var(--t-secundario); font-weight: 600; }
.limite__cifra  { font-size: var(--t-secundario); font-weight: 800; }
.limite__pie    { margin-top: 7px; font-size: var(--t-meta); color: var(--txt-3); }

.meter__track { height: 8px; }
.meter-row { display: grid; gap: 7px; }
.meter-row__top { display: flex; justify-content: space-between; gap: var(--e-3); }
.meter-row__name { display: flex; align-items: center; gap: 7px; font-weight: 600; font-size: var(--t-secundario); }
.meter-row__val  { font-weight: 800; font-size: var(--t-secundario); }
.dot-cat { width: 9px; height: 9px; border-radius: var(--r-full); background: var(--marca); flex: none; }

/* ---------- Reparto (en qué se te va) ---------- */
.reparto { display: grid; gap: 2px; }
.reparto__fila {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 3px var(--e-3);
  width: 100%;
  padding: 11px var(--e-3);
  border: 0;
  border-radius: var(--r-sm);
  background: transparent;
  color: inherit;
  text-align: left;
  cursor: pointer;
  transition: background var(--rapido) var(--curva);
}
.reparto__fila--quieta { cursor: default; }
button.reparto__fila:hover { background: var(--capa-2); }
.reparto__nombre { display: flex; align-items: baseline; gap: var(--e-2); font-weight: 600; font-size: var(--t-secundario); min-width: 0; }
.reparto__parte  { font-size: var(--t-meta); color: var(--txt-3); font-weight: 500; }
.reparto__monto  { font-weight: 800; font-size: var(--t-secundario); }
.reparto__carril { grid-column: 1 / -1; height: 7px; }


/* ==========================================================================
   13 · FILA DE MOVIMIENTO
   ==========================================================================
   El patrón de toda app de banco: avatar redondo, qué y dónde, monto a la
   derecha. El avatar lo pinta js/ds.js con las iniciales del comercio sobre un
   color derivado del nombre — determinista, así que el mismo comercio sale
   siempre igual y se reconoce de un vistazo sin leerlo. */

.mov-fila {
  display: grid;
  grid-template-columns: 1fr auto auto;
  align-items: center;
  gap: var(--e-3);
  padding: 11px var(--e-3);
  border-radius: var(--r-md);
  transition: background var(--rapido) var(--curva);
}
.mov-fila:hover { background: var(--capa-2); }
.mov-fila + .mov-fila { border-top: 1px solid var(--linea); }
.mov-fila[data-apagado="si"] { opacity: .58; }

.mov-fila__que {
  display: flex; flex-direction: column; gap: 2px;
  border: 0; background: transparent; color: inherit;
  text-align: left; min-width: 0; padding: 0;
}
.mov-fila__que--abre { cursor: pointer; }
.mov-fila__comercio { font-weight: 600; font-size: var(--t-cuerpo); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mov-fila__cuenta   { font-size: var(--t-meta); color: var(--txt-3); }
.mov-fila__monto    { font-weight: 700; font-size: var(--t-cuerpo); white-space: nowrap; }
.mov-fila__monto[data-signo="mas"] { color: var(--ok-txt); }

/* Con avatar (Movimientos): una columna más delante, del ancho del avatar. Con
   atributo en el selector para ganarle también a la regla del móvil, que pisa
   `.mov-fila` a secas. */
.mov-fila[data-con-avatar="si"] { grid-template-columns: auto minmax(0, 1fr) auto auto; }

/* Lo que queda por ordenar: una tarjeta más, con el borde tintado de ámbar
   —«corre»— para que se distinga de la lista sin gritar. El título dice qué
   pasa, así que el tono no va solo. */
.mov-pendientes { border-color: color-mix(in srgb, var(--alerta) 40%, var(--linea)); }
.mov-fila__av { display: grid; }
/* En el teléfono el chip sube a la columna del monto, debajo de él.
 *
 * Con «av que monto / av cat monto» cada fila eran TRES renglones —comercio,
 * cuenta y chip— y unos 130px por movimiento: a 390px el primero quedaba por
 * debajo del borde en cuanto había una tarjeta arriba. Así son dos renglones a
 * cada lado, como en cualquier app de banco: qué y dónde a la izquierda, cuánto
 * y de qué a la derecha. El chip se corta con puntos antes que empujar al
 * nombre, que es lo que se lee primero. */
@media (max-width: 640px) {
  .mov-fila[data-con-avatar="si"] {
    grid-template-columns: auto minmax(0, 1fr) auto;
    grid-template-areas:
      "av que monto"
      "av que cat";
    row-gap: 4px;
  }
  .mov-fila[data-con-avatar="si"] .mov-fila__av { grid-area: av; align-self: center; }
  .mov-fila[data-con-avatar="si"] .mov-fila__que { align-self: center; }
  .mov-fila[data-con-avatar="si"] .mov-fila__cat { justify-self: end; min-width: 0; max-width: 42vw; }
  .mov-fila[data-con-avatar="si"] .chip-cat {
    max-width: 100%;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }

  /* Y la cifra del periodo de Movimientos, más baja: es contexto de la lista,
     no la pantalla. Con su tamaño de tarjeta se comía media altura del teléfono
     antes del primer movimiento. */
  .mov-cifra { padding: var(--e-4); }
  .mov-cifra .respuesta__cifra { font-size: var(--t-cifra-media); }
  .mov-cifra .respuesta__pie { margin-top: 4px; }
  .mov-cifra .respuesta__dictamen { margin-top: var(--e-3); padding: 8px var(--e-3); }
}

.dia-cabeza {
  display: flex; justify-content: space-between; align-items: center;
  gap: var(--e-3);
  padding: 9px var(--e-3);
  margin-top: var(--e-4);
  border-radius: var(--r-sm);
  background: var(--bg-2);
  font-size: var(--t-meta);
}
.dia-cabeza__dia   { font-weight: 700; color: var(--txt-2); }
.dia-cabeza__total { font-weight: 800; color: var(--txt-2); }


/* ==========================================================================
   14 · FRANJA DE ATENDER
   ==========================================================================
   Una por pantalla, al pie.

   ══════════════════ Ya no es un bloque pintado ══════════════════

   Llevaba `--grad-accion` de fondo, y eso se saltaba §3 de este mismo sistema:
   «el degradado es caro, solo lo llevan la cifra héroe, el logotipo, el botón
   principal, los anillos y las tarjetas de cuenta». La franja no está en esa
   lista y se lo ponía igual.

   El resultado en pantalla era el que se ve en cualquier captura de Inicio: una
   mancha violeta a lo ancho, al final, que pesaba más que la cifra de arriba
   —que es lo que de verdad hay que mirar— y competía con las tarjetas de cuenta
   por ser lo más llamativo. Dos manchas fuertes en una pantalla es una de más.

   Ahora es una tarjeta como las demás, con el acento donde significa algo: una
   raya a la izquierda que la distingue de un vistazo, y el BOTÓN con el
   degradado, que sí lo tiene permitido por ser la acción principal. Se sigue
   viendo a la primera, pero ya no grita. */

.franja {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--e-5);
  flex-wrap: wrap;
  padding: var(--e-5) var(--e-6);
  border: 1px solid var(--linea);
  border-left: 3px solid var(--marca);
  border-radius: var(--r-lg);
  background: var(--capa-2);
  color: var(--txt);
  box-shadow: var(--sombra-1);
}
/* El color va EXPLÍCITO, y no heredado de `.franja`.
 *
 * sistema.css le pone `color: var(--color-on-accent)` —la tinta pensada para ir
 * ENCIMA del degradado— y esta hoja no lo nombraba: solo cambiaba el color del
 * contenedor. Lo que aurora.css no reescribe lo gana la hoja de debajo, así que
 * al quitar el fondo violeta el título se quedó con su tinta de antes: gris
 * oscuro sobre fondo oscuro, ilegible. El detalle sí se leía, porque ese sí
 * tenía color propio aquí — y esa diferencia es la que delata el problema. */
.franja__titulo {
  font-size: var(--t-tarjeta);
  font-weight: 800;
  letter-spacing: var(--track-bloque);
  color: var(--txt);
}
.franja__detalle { font-size: var(--t-secundario); color: var(--txt-2); margin-top: 3px; }
.franja__accion {
  min-height: var(--control-alto);
  padding: 0 var(--e-5);
  border: 0;
  border-radius: var(--r-sm);
  /* El degradado, aquí sí: es el botón principal de la franja. */
  background: var(--grad-accion);
  color: #fff;
  font-size: var(--t-cuerpo); font-weight: 700;
  cursor: pointer;
  transition: transform 120ms var(--muelle), box-shadow var(--rapido) var(--curva);
}
.franja__accion:hover { box-shadow: var(--sombra-2); }
.franja__accion:active { transform: scale(.96); }


/* ==========================================================================
   15 · KPI / TESELA
   ========================================================================== */

.kpi { display: grid; gap: 5px; align-content: start; }
.kpi__label {
  font-size: var(--t-rotulo); font-weight: 700;
  letter-spacing: var(--track-rotulo); text-transform: var(--caja-rotulo);
  color: var(--txt-3);
}
.kpi__valor {
  font-size: var(--t-cifra);
  font-weight: 800;
  letter-spacing: var(--track-cifra-2);
  line-height: 1.05;
}
.kpi__pie { display: flex; flex-wrap: wrap; align-items: center; gap: var(--e-2); font-size: var(--t-meta); color: var(--txt-3); }

.var {
  display: inline-flex; align-items: center; gap: 3px;
  height: 22px; padding: 0 8px;
  border-radius: var(--r-full);
  font-size: var(--t-chip); font-weight: 800;
}
.var--sube { background: var(--peligro-suave); color: var(--peligro-txt); }
.var--baja { background: var(--ok-suave);      color: var(--ok-txt); }
.var--igual{ background: var(--capa-2);        color: var(--txt-3); }


/* ==========================================================================
   16 · TABLAS
   ========================================================================== */

.table-scroll {
  border: 1px solid var(--linea);
  border-radius: var(--r-md);
  overflow: auto;
  background: var(--capa-1);
}
.data { width: 100%; border-collapse: collapse; font-size: var(--t-secundario); }
.data thead th {
  position: sticky; top: 0; z-index: 1;
  padding: 11px var(--e-3);
  background: var(--bg-2);
  border-bottom: 1px solid var(--linea);
  font-size: var(--t-rotulo); font-weight: 700;
  letter-spacing: var(--track-rotulo); text-transform: var(--caja-rotulo);
  color: var(--txt-3);
  text-align: left;
  white-space: nowrap;
}
.data tbody td { padding: 11px var(--e-3); border-bottom: 1px solid var(--linea); }
.data tbody tr:last-child td { border-bottom: 0; }
.data tbody tr { transition: background var(--rapido) var(--curva); }
.data tbody tr:hover { background: var(--capa-2); }
.data .num, .data td.num, .data th.num { text-align: right; font-variant-numeric: tabular-nums; }
.fila-pulsable { cursor: pointer; }
.data .sortable { cursor: pointer; user-select: none; }
.data .sortable:hover { color: var(--txt); }


/* ==========================================================================
   17 · AVISOS, ESTADOS Y VACÍOS
   ========================================================================== */

.alerta {
  display: flex; gap: var(--e-3);
  padding: var(--e-4);
  border: 1px solid var(--linea);
  border-left: 3px solid var(--marca);
  border-radius: var(--r-md);
  background: var(--marca-suave);
}
.alerta--ojo  { border-left-color: var(--alerta);  background: var(--alerta-suave); }
.alerta--mal  { border-left-color: var(--peligro); background: var(--peligro-suave); }
.alerta--bien { border-left-color: var(--ok);      background: var(--ok-suave); }
.alerta__icono {
  width: 22px; height: 22px; flex: none;
  display: grid; place-items: center;
  border-radius: var(--r-full);
  background: var(--marca); color: #fff;
  font-size: var(--t-nano); font-weight: 800;
}
.alerta--ojo  .alerta__icono { background: var(--alerta); }
.alerta--mal  .alerta__icono { background: var(--peligro); }
.alerta--bien .alerta__icono { background: var(--ok); }

.estado, .empty {
  display: grid; justify-items: center; gap: var(--e-3);
  padding: var(--e-9) var(--e-5);
  text-align: center;
  color: var(--txt-2);
}
.estado__icono {
  width: 60px; height: 60px;
  display: grid; place-items: center;
  border-radius: var(--r-full);
  background: var(--capa-2);
  border: 1px solid var(--linea);
  font-size: var(--t-glifo-lg);
  color: var(--txt-3);
}
.estado strong, .empty strong { font-size: var(--t-tarjeta); font-weight: 700; color: var(--txt); }

.toast {
  display: flex; align-items: center; gap: var(--e-3);
  padding: var(--e-3) var(--e-4);
  border: 1px solid var(--linea-fuerte);
  border-radius: var(--r-md);
  background: var(--capa-3);
  box-shadow: var(--sombra-3);
  backdrop-filter: blur(20px) saturate(1.5);
  -webkit-backdrop-filter: blur(20px) saturate(1.5);
  color: var(--txt);
  font-size: var(--t-secundario);
  font-weight: 600;
}
.toast__icon {
  width: 22px; height: 22px; flex: none;
  display: grid; place-items: center;
  border-radius: var(--r-full);
  background: var(--marca); color: #fff;
  font-size: var(--t-nano); font-weight: 800;
}
.toast--good .toast__icon { background: var(--ok); }
.toast--bad  .toast__icon { background: var(--peligro); }
.toast--warn .toast__icon { background: var(--alerta); }
.toast__accion {
  margin-left: auto;
  border: 0; background: var(--capa-2); color: var(--marca-txt);
  padding: 7px 12px; border-radius: var(--r-xs);
  font-weight: 700; cursor: pointer;
}


/* ==========================================================================
   18 · MODAL Y HOJA
   ==========================================================================
   En escritorio, modal centrado. En móvil (≤620px) la MISMA marca se convierte
   en hoja que sube desde abajo, porque en un teléfono un cuadro flotando en el
   centro deja el botón de aceptar donde el pulgar no llega. */

.modal-host {
  background: color-mix(in srgb, var(--bg) 55%, transparent);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  /* «place-items: center» con algo más alto que el hueco corta por ARRIBA y el
     scroll no llega hasta ahí: es el fallo clásico de centrar dentro de un
     contenedor con overflow. Con «safe center» el navegador se cae a «start»
     justo cuando no cabe, y donde no se entienda lo hace el max-height del
     propio modal. */
  place-items: safe center;
}
/* EL MODAL NUNCA ES MÁS ALTO QUE LA PANTALLA
   ------------------------------------------------------------------
   Y esto no era así. El modal no tenía max-height en escritorio y su cuerpo no
   rodaba en ningún sitio salvo con el teléfono de lado, así que una hoja con
   muchos campos —compartir un espacio, la liquidación— crecía por debajo del
   borde y SE LLEVABA EL PIE CON ELLA: los botones de Guardar y Cancelar
   quedaban fuera de la pantalla, sin forma de llegar a ellos.

   No pasaba en un monitor grande, que es donde se prueba. Pasaba en un portátil
   de 768px de alto, que es donde se trabaja.

   La forma correcta es la de siempre: columna flexible con la cabecera y el pie
   fijos y el cuerpo rodando en medio. Así el botón principal está SIEMPRE a la
   vista, mida lo que mida el contenido.

   «dvh» y «vh» en pares: el primero es lo que hay que usar en un teléfono —la
   barra del navegador entra y sale— y el segundo es el respaldo para quien no
   lo entienda. */
.modal {
  border: 1px solid var(--linea-fuerte);
  border-radius: var(--r-xl);
  background: var(--capa-3);
  box-shadow: var(--sombra-3);
  backdrop-filter: blur(28px) saturate(1.6);
  -webkit-backdrop-filter: blur(28px) saturate(1.6);
  overflow: hidden;

  display: flex;
  flex-direction: column;
  max-height: calc(100vh - 2 * var(--e-6));
  max-height: calc(100dvh - 2 * var(--e-6));
}
/* La cabecera y el pie no encogen: son lo que tiene que seguir viéndose. */
.modal__head, .modal__foot { flex: 0 0 auto; }
.modal__body {
  flex: 1 1 auto;
  overflow-y: auto;
  /* Que el gesto no arrastre la página de detrás al llegar al final. */
  overscroll-behavior: contain;
}
.modal__head {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--e-3);
  padding: var(--e-5) var(--e-6);
  border-bottom: 1px solid var(--linea);
}
.modal__head h2 { font-size: var(--t-tarjeta); font-weight: 800; letter-spacing: var(--track-bloque); }
.modal__body { padding: var(--e-6); }
.modal__foot {
  display: flex; justify-content: flex-end; gap: var(--e-3);
  padding: var(--e-4) var(--e-6);
  border-top: 1px solid var(--linea);
  background: var(--bg-2);
}

@media (max-width: 620px) {
  .modal-host { align-items: flex-end; }
  .modal {
    width: 100%;
    max-height: 92vh;
    max-height: 92dvh;
    border-radius: var(--r-xl) var(--r-xl) 0 0;
    animation: hoja-sube 320ms var(--muelle) both;
  }
  /* El suyo manda sobre el general: en una hoja que sube desde abajo, el 8%
     que queda arriba es lo que deja ver que hay algo detrás. */
  .modal { max-height: 92vh; max-height: 92dvh; }
  .modal__foot { padding-bottom: calc(var(--e-4) + env(safe-area-inset-bottom, 0px)); }
  /* El asidero. No hace nada —el arrastre no está implementado— pero dice
     «esto sube y baja», que es la mitad del trabajo de un asidero. */
  .modal__head::before {
    content: "";
    position: absolute; top: 8px; left: 50%;
    width: 38px; height: 4px;
    transform: translateX(-50%);
    border-radius: var(--r-full);
    background: var(--linea-fuerte);
  }
  .modal__head { position: relative; padding-top: var(--e-6); }
}
@keyframes hoja-sube { from { transform: translateY(100%); } to { transform: none; } }


/* ==========================================================================
   19 · PIEZAS NUEVAS DE AURORA
   ==========================================================================
   Lo que no existía en el sistema viejo. Las dibuja js/ds.js. */

/* ---------- Tarjeta de cuenta ----------
   Proporción de tarjeta física (1.586:1). Degradado propio por banco, brillo
   diagonal encima y los cuatro dígitos en tabular espaciado. Es la pieza que
   hace que la pantalla se lea como «mi banco» y no como «una hoja de cálculo». */
.cuentas-carrusel {
  display: grid;
  grid-auto-flow: column;
  /* Con tope arriba, y no `1fr`: con dos cuentas en un monitor ancho la columna
     se llevaba media pantalla y la tarjeta salía del tamaño de un cartel. */
  grid-auto-columns: minmax(276px, 420px);
  gap: var(--e-4);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  padding-bottom: var(--e-2);
  scrollbar-width: none;
}
.cuentas-carrusel::-webkit-scrollbar { display: none; }
.cuentas-carrusel > * { scroll-snap-align: start; }

/* En el TELÉFONO el carril se queda, y la tarjeta se estrecha.
 *
 * Se llegó a apilarlas —dos, y el resto en un botón— por miedo a que un carril
 * escondiera lo de detrás sin avisar. Pero arrastrar de lado para ver la
 * siguiente cuenta es EL gesto de una app de banco: se conoce, se hace sin
 * pensarlo, y quien tiene cuatro cuentas las ve todas sin salir de Inicio.
 *
 * Lo que sí hacía falta era que se notara que hay más. Con `minmax(276px, 1fr)`
 * una tarjeta ocupaba el ancho entero en 390px y no asomaba nada por el borde.
 * Con un ancho en porcentaje siempre queda un trozo de la siguiente a la vista,
 * y ese trozo cortado es lo que invita a arrastrar. */
@media (max-width: 640px) {
  .cuentas-carrusel {
    grid-auto-columns: 86%;
    gap: var(--e-3);
  }
}

/* `width: 100%` y no el estirado de la rejilla, que aquí NO ocurre.
 *
 * Con `aspect-ratio` y `min-height` juntos, el navegador saca el ANCHO del alto
 * —168 × 1.586 = 267px— en vez de estirar la tarjeta hasta su columna. La
 * columna medía 308 y la tarjeta 267: 41px de columna vacía que, sumados al
 * hueco entre columnas, se leían como una separación enorme entre tarjetas. Y
 * no se veía como lo que era, porque el hueco declarado son 12px.
 *
 * Con el ancho puesto a mano, el alto sale de la proporción y `min-height`
 * queda de suelo para las columnas estrechas, que es para lo que estaba. */
.tarjeta-cuenta {
  position: relative;
  width: 100%;
  aspect-ratio: 1.586 / 1;
  min-height: 168px;
  display: flex; flex-direction: column; justify-content: space-between;
  padding: var(--e-5);
  border: 0;
  border-radius: var(--r-lg);
  background: var(--tarjeta-grad, var(--grad-marca));
  color: #fff;
  text-align: left;
  overflow: hidden;
  cursor: pointer;
  box-shadow: var(--sombra-2);
  transition: transform var(--normal) var(--curva), box-shadow var(--normal) var(--curva);
}
.tarjeta-cuenta:hover { transform: translateY(-3px); box-shadow: var(--sombra-3); }
.tarjeta-cuenta:active { transform: scale(.985); }
/* El brillo diagonal: es lo que hace que parezca plástico y no un rectángulo
   de color. */
.tarjeta-cuenta::after {
  content: "";
  position: absolute; inset: 0;
  background:
    linear-gradient(115deg, rgba(255,255,255,.22) 0%, rgba(255,255,255,0) 42%),
    radial-gradient(120% 90% at 100% 0%, rgba(255,255,255,.16), transparent 60%);
  pointer-events: none;
}
.tarjeta-cuenta__banco { display: flex; align-items: center; justify-content: space-between; gap: var(--e-3); }
.tarjeta-cuenta__nombre { font-size: var(--t-secundario); font-weight: 700; opacity: .95; }
.tarjeta-cuenta__tipo {
  font-size: var(--t-micro); font-weight: 800;
  letter-spacing: var(--track-rotulo); text-transform: var(--caja-rotulo);
  padding: 4px 9px;
  border-radius: var(--r-full);
  background: rgba(255,255,255,.2);
}
.tarjeta-cuenta__saldo {
  font-size: 1.7rem; font-weight: 800;
  letter-spacing: var(--track-cifra-2);
  line-height: 1;
}
.tarjeta-cuenta__rotulo { font-size: var(--t-micro); font-weight: 800; letter-spacing: var(--track-rotulo); text-transform: var(--caja-rotulo); opacity: .8; margin-bottom: 4px; }
.tarjeta-cuenta__pie { display: flex; align-items: flex-end; justify-content: space-between; gap: var(--e-3); }
.tarjeta-cuenta__digitos { font-size: var(--t-secundario); font-weight: 700; letter-spacing: .18em; opacity: .9; }
.tarjeta-cuenta__mov { font-size: var(--t-mini); opacity: .8; }
/* Lo que toca hacer con ella —«Pagar antes del 6 sep»— en el sitio del número de
   movimientos, y más fuerte que él: a opacidad plena y en negrita. Sin fondo
   propio, que sobre el degradado le quitaría contraste a la tinta blanca. */
.tarjeta-cuenta__aviso { font-size: var(--t-mini); font-weight: 700; }

/* ---------- Anillo de progreso ----------
   Un SVG de dos trazos. Se usa para salud, metas y límites de una sola
   categoría. Nunca para repartir un total entre categorías: eso es un pastel
   con otro nombre y sigue prohibido (DESIGN.md §7). */
.anillo { position: relative; display: inline-grid; place-items: center; }
.anillo svg { transform: rotate(-90deg); display: block; }
.anillo__pista { fill: none; stroke: var(--bg-2); }
.anillo__valor {
  fill: none;
  stroke: var(--anillo-color, var(--marca));
  stroke-linecap: round;
  transition: stroke-dashoffset var(--lento) var(--curva-out);
}
.anillo__dentro {
  position: absolute;
  display: grid; place-items: center; gap: 1px;
  text-align: center;
}
.anillo__cifra { font-size: 1.5rem; font-weight: 800; letter-spacing: var(--track-cifra-2); line-height: 1; }
.anillo__nota  { font-size: var(--t-micro); font-weight: 700; letter-spacing: var(--track-rotulo); text-transform: var(--caja-rotulo); color: var(--txt-3); }

/* ---------- Descubrimiento ---------- */
/* Apilados, también en el teléfono.
 *
 * Aquí se convertían en un carril que se desplaza a lo ancho, con las tarjetas
 * al 82 % del ancho para que asomara la siguiente. La idea era buena —la media
 * tarjeta cortada invita a arrastrar— pero en la práctica esconde: lo que hay a
 * partir del segundo no existe para quien no se fije en ese borde, y el número
 * de al lado del título tampoco se lee como «hay más, arrastra».
 *
 * Apilados se ven los que hay, y los que no caben se dicen con un botón que los
 * cuenta (js/views/inicio.js). Cambia «esconder sin avisar» por «enseñar menos y
 * decirlo», que es lo que hace toda la pantalla desde que se limpió. */
.insights { display: grid; gap: var(--e-3); }

.insight {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--e-3);
  align-items: start;
  padding: var(--e-4);
  border: 1px solid var(--linea);
  border-radius: var(--r-md);
  background: var(--capa-1);
  box-shadow: var(--filo);
  transition: border-color var(--rapido) var(--curva), transform var(--rapido) var(--curva);
}
.insight:hover { border-color: var(--linea-fuerte); }
.insight__icono {
  width: 38px; height: 38px;
  display: grid; place-items: center;
  border-radius: var(--r-sm);
  background: var(--insight-suave, var(--marca-suave));
  color: var(--insight-color, var(--marca-txt));
  font-size: var(--t-glifo-md);
  flex: none;
}
.insight__texto { display: grid; gap: 3px; min-width: 0; }
.insight__titulo { font-weight: 700; font-size: var(--t-cuerpo); line-height: 1.35; }
.insight__detalle { font-size: var(--t-meta); color: var(--txt-3); line-height: 1.45; }
.insight__accion {
  justify-self: start;
  margin-top: 5px;
  border: 0; background: transparent;
  color: var(--marca-txt);
  font-size: var(--t-meta); font-weight: 700;
  padding: 5px 0;
  cursor: pointer;
}
.insight__accion:hover { text-decoration: underline; }
.insight[data-tono="ok"]      { --insight-suave: var(--ok-suave);      --insight-color: var(--ok-txt); }
.insight[data-tono="alerta"]  { --insight-suave: var(--alerta-suave);  --insight-color: var(--alerta-txt); }
.insight[data-tono="peligro"] { --insight-suave: var(--peligro-suave); --insight-color: var(--peligro-txt); }
.insight[data-tono="futuro"]  { --insight-suave: var(--futuro-suave);  --insight-color: var(--futuro-txt); }

/* ---------- Avatar de comercio ---------- */
.avatar-com {
  width: 40px; height: 40px; flex: none;
  display: grid; place-items: center;
  border-radius: var(--r-full);
  background: var(--av-bg, var(--capa-2));
  color: var(--av-txt, var(--txt-2));
  font-size: var(--t-glifo-sm); font-weight: 800;
  letter-spacing: -.02em;
}

/* ---------- Esqueleto de carga ----------
   Un bloque con un brillo que barre. Nunca la pantalla en blanco: en un
   teléfono lento eso se lee como que la app se rompió. */
.esqueleto {
  border-radius: var(--r-sm);
  background: var(--bg-2);
  position: relative;
  overflow: hidden;
}
.esqueleto::after {
  content: "";
  position: absolute; inset: 0;
  background: linear-gradient(90deg, transparent, var(--capa-2), transparent);
  transform: translateX(-100%);
  animation: barrido 1.4s linear infinite;
}
@keyframes barrido { to { transform: translateX(100%); } }

/* ---------- Segmentos (conmutador) ---------- */
.segmentos {
  display: inline-flex;
  gap: 2px;
  padding: 3px;
  border-radius: var(--r-full);
  background: var(--bg-2);
  border: 1px solid var(--linea);
}
.segmentos button {
  min-height: 34px;
  padding: 0 var(--e-4);
  border: 0;
  border-radius: var(--r-full);
  background: transparent;
  color: var(--txt-2);
  font-size: var(--t-meta); font-weight: 700;
  cursor: pointer;
  transition: background var(--rapido) var(--curva), color var(--rapido) var(--curva);
}
.segmentos button[aria-pressed="true"] {
  background: var(--capa-1);
  color: var(--txt);
  box-shadow: var(--sombra-1);
}

/* ---------- Mapa de calor del mes ---------- */
.calor { display: grid; grid-template-columns: repeat(7, 1fr); gap: 4px; }
.calor__dia {
  aspect-ratio: 1;
  border-radius: var(--r-xs);
  background: var(--bg-2);
  border: 0;
  cursor: pointer;
  transition: transform var(--rapido) var(--muelle);
}
.calor__dia:hover { transform: scale(1.14); }
.calor__dia[data-nivel="1"] { background: color-mix(in oklab, var(--marca) 22%, var(--bg-2)); }
.calor__dia[data-nivel="2"] { background: color-mix(in oklab, var(--marca) 44%, var(--bg-2)); }
.calor__dia[data-nivel="3"] { background: color-mix(in oklab, var(--marca) 68%, var(--bg-2)); }
.calor__dia[data-nivel="4"] { background: var(--marca); }

/* ---------- Zona de subida ---------- */
.dropzone, .zona-subida {
  display: grid; place-items: center; gap: var(--e-3);
  padding: var(--e-9) var(--e-5);
  border: 2px dashed var(--linea-fuerte);
  border-radius: var(--r-lg);
  background: var(--capa-1);
  text-align: center;
  transition: border-color var(--normal) var(--curva),
              background var(--normal) var(--curva),
              transform var(--normal) var(--curva);
}
.dropzone:hover, .zona-subida:hover { border-color: var(--marca); background: var(--marca-suave); }
.dropzone[data-encima="si"], .zona-subida[data-encima="si"] {
  border-color: var(--marca);
  background: var(--marca-suave);
  transform: scale(1.01);
}


/* ==========================================================================
   20 · LAS DOS PANTALLAS REHECHAS
   ==========================================================================
   Inicio y Metas. Lo que sigue solo lo usan ellas: cuando se rehagan las
   demás, cada una traerá lo suyo aquí abajo. */

/* ---------- Rejilla común ----------
   Dos columnas en escritorio, una apilada en móvil. `minmax(0,1fr)` y no `1fr`
   a secas: sin el mínimo en cero, una tabla ancha dentro de una celda de grid
   la ensancha y saca la página entera de cuadro. Es el fallo de maquetación
   más caro de encontrar porque solo aparece con datos reales. */
.inicio, .metas { display: grid; gap: var(--e-5); }
.inicio-dos { display: grid; gap: var(--e-5); grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
@media (max-width: 920px) { .inicio-dos { grid-template-columns: minmax(0, 1fr); } }

/* ── El `min-width: 0` que hace falta en TODO hijo de rejilla ──
 *
 * Sin esto, un hijo que se desplaza por dentro —el carrusel de cuentas, el
 * carrusel de descubrimientos en móvil, una tabla ancha— no se desplaza: ENSANCHA
 * su celda. El mínimo de una pista de grid es `auto`, o sea el ancho del
 * contenido, así que `overflow-x: auto` no llega a aplicarse nunca.
 *
 * Y no ensancha solo la celda: empuja la rejilla, que empuja la página. El
 * síntoma es que en un teléfono se desplaza TODA la pantalla a lo ancho y el
 * título de la cabecera sale cortado — que no se parece en nada a la causa, y
 * por eso cuesta encontrarlo. Se veía en la captura de 430px.
 *
 * `minmax(0, 1fr)` arregla las columnas declaradas; esto arregla las que se
 * crean solas (`display: grid` sin `grid-template-columns`). */
.inicio > *, .metas > *, .inicio-dos > *, .grid > *, .view > * { min-width: 0; }

/* Inicio en el ESCRITORIO: dos columnas desde 1280 (js/views/inicio.js). Por
   debajo las columnas no existen para la maquetación —`display: contents`— y
   sus tarjetas caen en la rejilla de `.inicio` como siempre. En la columna, el
   ritmo y el reparto van uno sobre otro: lado a lado no caben en media pantalla. */
.inicio-columnas, .inicio-col { display: contents; }
.inicio-col > * { min-width: 0; }
.inicio-cuentas__flechas { display: inline-flex; gap: var(--e-1); margin-left: auto; }
.inicio-cuentas__flechas[hidden] { display: none; }
@media (min-width: 1280px) {
  .inicio-columnas {
    display: grid;
    grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr);
    gap: var(--e-5);
    align-items: start;
  }
  .inicio-col { display: grid; gap: var(--e-5); min-width: 0; }
  .inicio-col .inicio-dos { grid-template-columns: minmax(0, 1fr); }
}
.cuentas-carrusel, .insights, .table-scroll, .barras-par, .sus-lista { min-width: 0; }

.inicio-cuentas__cabeza {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--e-3);
  margin-bottom: var(--e-4);
}

.heroe-acciones { display: flex; flex-wrap: wrap; gap: var(--e-2); align-items: flex-start; }
@media (max-width: 620px) {
  .respuesta__cabeza { flex-direction: column; }
  .heroe-acciones { width: 100%; }
  .heroe-acciones .btn { flex: 1 1 auto; }
}

/* ---------- Salud financiera ---------- */
.salud__cuerpo {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: var(--e-6);
  align-items: center;
}
@media (max-width: 520px) {
  .salud__cuerpo { grid-template-columns: minmax(0, 1fr); justify-items: center; }
}
.salud-factores { display: grid; gap: 10px; list-style: none; margin: 0; padding: 0; width: 100%; }
.salud-factor {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 82px auto;
  align-items: center;
  gap: var(--e-3);
  font-size: var(--t-meta);
}
.salud-factor__nombre { color: var(--txt-2); font-weight: 600; }
.salud-factor__barra {
  height: 6px; border-radius: var(--r-full);
  background: var(--bg-2); overflow: hidden;
}
.salud-factor__relleno {
  display: block; height: 100%;
  width: calc(var(--parte, 0) * 100%);
  border-radius: var(--r-full);
  background: var(--grad-marca);
  transition: width var(--lento) var(--curva-out);
}
.salud-factor__puntos { font-weight: 800; color: var(--txt-2); font-variant-numeric: tabular-nums; }
/* El factor que no se puede juzgar se apaga en vez de mentir con un cero. */
.salud-factor[data-sin="si"] { opacity: .5; }
.salud__nota { margin-top: var(--e-4); font-size: var(--t-meta); color: var(--txt-3); }

/* ---------- Ritmo ---------- */
.ritmo__grafico { margin: var(--e-2) 0 var(--e-3); }
.ritmo__pie { display: flex; gap: var(--e-4); flex-wrap: wrap; }
.ritmo__leyenda { display: inline-flex; align-items: center; gap: 6px; font-size: var(--t-meta); color: var(--txt-3); }
.ritmo__punto { width: 10px; height: 3px; border-radius: var(--r-full); background: var(--marca); }
.ritmo__punto--rayado {
  background: repeating-linear-gradient(90deg, var(--txt-3) 0 3px, transparent 3px 6px);
}
.ritmo__frase { margin-top: var(--e-3); font-size: var(--t-secundario); font-weight: 600; }

/* ---------- Lo que se viene ---------- */
.por-venir { display: grid; gap: 2px; }
.por-venir__fila {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--e-3);
  padding: 9px var(--e-2);
  border-radius: var(--r-sm);
}
.por-venir__fila:hover { background: var(--capa-2); }
.por-venir__que { display: grid; gap: 1px; min-width: 0; }
.por-venir__nombre { font-weight: 600; font-size: var(--t-secundario); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.por-venir__cuando { font-size: var(--t-meta); color: var(--txt-3); }
.por-venir__monto { font-weight: 800; font-size: var(--t-secundario); }

/* ---------- Fila de comercio (ds.filaComercio) ---------- */
.fila-com {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--e-3);
  width: 100%;
  padding: 9px var(--e-2);
  border: 0; background: transparent; color: inherit;
  text-align: left;
  border-radius: var(--r-sm);
  transition: background var(--rapido) var(--curva);
}
.fila-com--abre { cursor: pointer; }
.fila-com--abre:hover { background: var(--capa-2); }
.fila-com__que { display: grid; gap: 1px; min-width: 0; }
.fila-com__nombre { font-weight: 600; font-size: var(--t-secundario); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fila-com__meta { font-size: var(--t-meta); color: var(--txt-3); }
.fila-com__monto { font-weight: 800; font-size: var(--t-secundario); }

/* ---------- Barras pareadas (ds.barrasPareadas) ---------- */
.barras-par { display: flex; align-items: flex-end; gap: var(--e-3); overflow-x: auto; }
.barras-par__mes { display: grid; justify-items: center; gap: 6px; flex: 1 0 auto; }
.barras-par__pila { display: flex; align-items: flex-end; gap: 3px; height: var(--alto, 128px); }
.barras-par__barra { width: 11px; border-radius: 4px 4px 0 0; }
.barras-par__barra--entra { background: var(--grad-ok); }
.barras-par__barra--sale  { background: var(--grad-marca); }
/* El mes en que salió más de lo que entró. Es el único que pide atención, y por
   eso es el único que cambia de color (DESIGN.md §7). */
.barras-par__barra--sale[data-exceso="si"] { background: var(--grad-peligro); }
.barras-par__rotulo { font-size: var(--t-micro); font-weight: 700; color: var(--txt-3); }

/* ---------- Bienvenida ---------- */
.bienvenida {
  display: grid; justify-items: start; gap: var(--e-5);
  max-width: 640px;
  padding: var(--e-9) 0;
}
.bienvenida__marca { display: block; }
.bienvenida__titulo { font-size: var(--t-pagina); font-weight: 800; letter-spacing: var(--track-titulo); }
.bienvenida__texto { color: var(--txt-2); font-size: 1.0625rem; line-height: 1.55; }
.promesas { display: grid; gap: var(--e-3); list-style: none; margin: 0; padding: 0; }
.promesa { display: flex; gap: var(--e-3); align-items: flex-start; font-size: var(--t-secundario); color: var(--txt-2); }
.promesa__icono {
  width: 24px; height: 24px; flex: none;
  display: grid; place-items: center;
  border-radius: var(--r-full);
  background: var(--marca-suave);
  color: var(--marca-txt);
  font-size: var(--t-mini);
}
.bienvenida__acciones { display: flex; flex-wrap: wrap; gap: var(--e-3); }

/* ---------- ¿Me alcanza? ---------- */
.alcanza__titular {
  font-size: var(--t-cifra-media);
  font-weight: 800;
  letter-spacing: var(--track-cifra-2);
  margin-bottom: var(--e-4);
}
.alcanza[data-tono="bien"] .alcanza__titular { color: var(--ok-txt); }
.alcanza[data-tono="ojo"]  .alcanza__titular { color: var(--alerta-txt); }
.alcanza[data-tono="mal"]  .alcanza__titular { color: var(--peligro-txt); }

.alcanza__barra {
  display: flex;
  height: 18px;
  border-radius: var(--r-full);
  overflow: hidden;
  background: var(--bg-2);
}
.alcanza__trozo { height: 100%; transition: width var(--lento) var(--curva-out); }
.alcanza__trozo--gastado  { background: var(--marca); }
.alcanza__trozo--fijo     { background: var(--futuro); }
.alcanza__trozo--variable { background: var(--alerta); opacity: .75; }
.alcanza__trozo--libre    { background: var(--ok); }

.alcanza__tramos {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
  gap: var(--e-2) var(--e-4);
  margin-top: var(--e-4);
}
.alcanza__tramo { display: flex; align-items: center; gap: var(--e-2); font-size: var(--t-meta); }
.alcanza__punto { width: 9px; height: 9px; border-radius: var(--r-full); flex: none; }
.alcanza__rotulo { color: var(--txt-3); }
.alcanza__monto { margin-left: auto; font-weight: 800; }
.alcanza__consejo {
  margin-top: var(--e-4);
  padding: 10px var(--e-4);
  border-radius: var(--r-md);
  background: var(--marca-suave);
  color: var(--marca-txt);
  font-size: var(--t-secundario);
  font-weight: 600;
}

/* ---------- Límites y metas ---------- */
.limites-lista { display: grid; gap: var(--e-4); }
.limites-lista > .limite { animation: aurora-sube 380ms var(--curva-out) both; animation-delay: var(--retraso, 0ms); }

/* 320 y no 280: con 280 la tarjeta queda en 250 útiles y ahí no caben un anillo
   de 96 y «RD$ 180,000 de RD$ 180,000» en la misma línea. La cifra partía en dos
   renglones y se leía «RD$180,000. / 00 de …», que es peor que una columna
   menos. */
.metas-rejilla {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
  gap: var(--e-4);
}
.meta-tarjeta {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: var(--e-4);
  align-items: center;
  padding: var(--e-4);
  border: 1px solid var(--linea);
  border-radius: var(--r-md);
  background: var(--capa-1);
}
.meta-tarjeta__texto { display: grid; gap: 4px; justify-items: start; min-width: 0; }
.meta-tarjeta__nombre { font-weight: 700; font-size: var(--t-secundario); }
.meta-tarjeta__cifra {
  font-weight: 800;
  font-size: var(--t-cifra-media);
  letter-spacing: var(--track-cifra-2);
  line-height: 1.15;
  /* La cifra entera o nada: partida por la mitad deja «RD$ 180,» arriba y «000»
     abajo, que no se lee como un número. Si no cabe, que baje el «de …». */
  white-space: nowrap;
}
.meta-tarjeta__cifra .muted {
  font-size: var(--t-meta);
  font-weight: 600;
  white-space: normal;
}
.meta-tarjeta__pie { font-size: var(--t-meta); color: var(--txt-3); line-height: 1.4; }

/* Por debajo de 380 la tarjeta se apila: el anillo arriba y el texto debajo, a
   todo el ancho. En un teléfono de 360 no hay forma de meter las dos cosas al
   lado sin que una de las dos quede sin sitio. */
@media (max-width: 380px) {
  .meta-tarjeta { grid-template-columns: minmax(0, 1fr); justify-items: start; }
}

/* ---------- Suscripciones ---------- */
.sus-aviso {
  display: flex; gap: var(--e-3);
  padding: var(--e-3) var(--e-4);
  border-radius: var(--r-md);
  margin-bottom: var(--e-4);
}
.sus-aviso--sube   { background: var(--alerta-suave); color: var(--alerta-txt); --senal: var(--alerta); }
.sus-aviso--duerme { background: var(--futuro-suave); color: var(--futuro-txt); --senal: var(--futuro); }
.sus-aviso__ico {
  width: 26px; height: 26px; flex: none;
  display: grid; place-items: center;
  border-radius: var(--r-full);
  /* Con ficha y no con currentColor: ver la nota de .respuesta__senal. */
  background: var(--senal, var(--txt-2));
  color: var(--bg);
  font-weight: 800; font-size: var(--t-glifo-sm);
}
.sus-aviso__titulo { font-weight: 700; font-size: var(--t-secundario); }
.sus-aviso__detalle { font-size: var(--t-meta); opacity: .85; }

.sus-lista { display: grid; gap: 2px; margin-top: var(--e-3); }
.sus {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto auto;
  align-items: center;
  gap: var(--e-3);
  padding: 10px var(--e-2);
  border-radius: var(--r-sm);
  transition: background var(--rapido) var(--curva);
}
.sus:hover { background: var(--capa-2); }
/* La dormida se apaga: sigue en la lista porque puede ser dinero recuperable,
   pero no compite con las que cobran ahora mismo. */
.sus[data-viva="no"] { opacity: .55; }
.sus__que { display: grid; gap: 1px; min-width: 0; }
.sus__nombre { font-weight: 600; font-size: var(--t-secundario); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sus__meta { font-size: var(--t-meta); color: var(--txt-3); }
.sus__cifras { display: grid; gap: 1px; justify-items: end; }
.sus__monto { font-weight: 800; font-size: var(--t-secundario); }
.sus__anual { font-size: var(--t-meta); color: var(--txt-3); }
.sus__estado { display: flex; gap: 6px; align-items: center; }
.sus__nota { margin-top: var(--e-4); font-size: var(--t-meta); color: var(--txt-3); line-height: 1.5; }

@media (max-width: 620px) {
  .sus { grid-template-columns: auto minmax(0, 1fr) auto; }
  /* En móvil el estado baja a su propia línea, alineado con el nombre: cuatro
     columnas en 360px dejan el nombre en tres letras y un puntito. */
  .sus__estado { grid-column: 2 / -1; }
}


/* ==========================================================================
   21 · LOS CUATRO GRÁFICOS
   ==========================================================================
   `.obi-cuatro` venía del sistema anterior: una rejilla SIN hueco, con reglas
   de 2px en las celdas haciendo de separación. Ese truco funciona cuando las
   tarjetas no tienen fondo propio —eran del color de la página— y se rompe con
   Aurora, donde cada gráfico es una capa con su borde y su radio: cuatro
   tarjetas redondeadas pegadas unas a otras, con una quinta línea alrededor.

   Aquí vuelve a ser lo que es: cuatro tarjetas con aire entre ellas. */

.obi-cuatro {
  border: 0;
  gap: var(--e-5);
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
}
/* Las reglas de la rejilla vieja, apagadas. Se apagan con los mismos selectores
   —no con `> *`— para que no haya que subir la especificidad ni usar
   !important: esta hoja se lee después y con eso basta. */
.obi-cuatro > :nth-child(2n) { border-left: 0; }
.obi-cuatro > :nth-child(n + 3) { border-top: 0; }

.obi-grafico {
  min-width: 0;
  padding: var(--e-5);
  background: var(--capa-1);
  border: 1px solid var(--linea);
  border-radius: var(--r-lg);
  box-shadow: var(--sombra-1), var(--filo);
}
.obi-grafico__pregunta { font-size: var(--t-tarjeta); font-weight: 700; letter-spacing: var(--track-bloque); }
.obi-grafico__pista { font-size: var(--t-meta); color: var(--txt-3); white-space: nowrap; }
.obi-grafico__respuesta { font-size: var(--t-secundario); color: var(--txt-2); line-height: 1.5; }

/* A una columna antes de que las dos se estrechen tanto que el gráfico deje de
   leerse. 720 y no 640: en un iPad vertical (768) las dos columnas dan 350px
   cada una, que para una línea de treinta días es de sobra. */
@media (max-width: 720px) {
  .obi-cuatro { grid-template-columns: minmax(0, 1fr); }
  .obi-cuatro > :nth-child(n + 2) { border-top: 0; }
}
/* Y en el teléfono la cabeza del gráfico se parte: «El ritmo del mes» y
   «Acumulado día a día» en la misma línea a 360px dejan la pista en dos letras. */
@media (max-width: 480px) {
  .obi-grafico__cabeza { flex-direction: column; align-items: flex-start; gap: 2px; }
  .obi-grafico__pista { white-space: normal; }
}


/* ==========================================================================
   22 · EL BOTÓN FLOTANTE Y SU HUECO
   ==========================================================================
   El botón flota SOBRE el contenido, así que sin un hueco abajo la última
   tarjeta de la página queda debajo de él. Se veía en «Cómo voy»: el botón
   tapaba el texto de «Fijo o negociable».

   La clase la pone js/app.js (`ajustarFab`), que también lo esconde en las
   pantallas de configuración. Va por clase y no con :has() porque hay WebViews
   de Android en circulación que todavía no lo entienden, y ahí el hueco
   desaparecería sin ningún aviso. */
body.con-fab .view { padding-bottom: calc(var(--e-9) + 72px); }
/* Por debajo de 900 el botón no existe (lo esconde el CSS de §6) y el hueco
   sobra: lo que hay abajo es la barra del pulgar, que tiene el suyo. */
@media (max-width: 900px) { body.con-fab .view { padding-bottom: var(--e-9); } }


/* ==========================================================================
   25 · MOVIMIENTO
   ==========================================================================
   Lo enciende js/animacion.js, que ya respeta prefers-reduced-motion de una
   vez para toda la app. Aquí solo viven los fotogramas. */

@keyframes aurora-sube {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: none; }
}
.aurora-entra {
  animation: aurora-sube 420ms var(--curva-out) both;
  animation-delay: var(--retraso, 0ms);
}

/* ── La entrada escalonada de las tarjetas ──
 *
 * `.entra` la pone js/animacion.js → entradaEscalonada(), que además escribe en
 * cada hijo la ficha `--i` con su posición.
 *
 * Y ahí estaba el fallo: de las dos reglas `.entra` que hay en sistema.css
 * ganaba la última, y esa lee `--retraso` —una ficha que entradaEscalonada() no
 * escribe nunca—. O sea que el retraso salía 0 para todas y las tarjetas
 * entraban a la vez. El escalonado de DESIGN.md §8 no ha funcionado nunca; solo
 * que nadie lo echó de menos, porque una entrada simultánea tampoco se ve mal.
 *
 * Aquí se lee la ficha que de verdad se escribe. El `min()` topa la cascada a
 * ocho pasos: en una pantalla de veinte tarjetas, la última esperaría más de un
 * segundo a opacidad cero, y eso ya no es una entrada — es una pantalla que
 * tarda en cargar. */
.entra {
  animation: aurora-sube 420ms var(--curva-out) both;
  animation-delay: calc(min(var(--i, 0), 8) * 60ms);
}

/* La cascada del reparto. El CSS la hace solo con --retraso, que pone ui.js:
   así una lista de 30 filas no cuesta 30 llamadas a JavaScript. */
.reparto__fila { animation: aurora-sube 380ms var(--curva-out) both; animation-delay: var(--retraso, 0ms); }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
  .esqueleto::after { display: none; }
}

/* Quien pide menos transparencia no quiere vidrio: se le da fondo sólido. Sin
   esto, en un aparato lento el blur de la barra superior cuesta cuadros en
   cada scroll y encima va contra una preferencia declarada. */
@media (prefers-reduced-transparency: reduce) {
  .topbar, .pulgar, .modal, .toast, .espacio-menu, .usuario-menu, .avisos-panel, .modal-host {
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
    background: var(--bg);
  }
  .modal, .toast { background: var(--capa-1); }
}


/* ==========================================================================
   26 · EL PERFIL Y LA CONFIGURACIÓN
   ==========================================================================
   Antes esto eran tres pantallas sueltas —«Mi cuenta», «Mis espacios» y unos
   «Ajustes» de diez tarjetas sin relación— colgando de un menú que era una
   lista plana de ocho enlaces. No había ni una sola pantalla que contestara
   «¿quién soy aquí y qué puedo hacer?».

   La regla que ordena todo lo de abajo: esto lo tiene que poder usar alguien de
   sesenta años que no ha configurado una app en su vida, y también quien lleva
   la contabilidad de una empresa. Las dos personas piden lo mismo —que se vea
   de un golpe qué hay y dónde se toca— y ninguna pide un menú.
   ========================================================================== */

/* ---------- La cabecera de identidad ----------
   Quién eres, en grande y sin buscarlo. Abre la pantalla de perfil y abre el
   panel del avatar. */
.identidad {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--e-5);
  padding: var(--e-6);
  border-radius: var(--r-xl);
  background: var(--capa-1);
  border: 1px solid var(--linea);
  box-shadow: var(--sombra-1), var(--filo);
  position: relative;
  overflow: hidden;
}
/* El halo de marca por detrás. Es la única pantalla de configuración que lo
   lleva: es la que habla de ti, no de una preferencia. */
.identidad::before {
  content: "";
  position: absolute;
  inset: -60% 40% -60% -20%;
  background: radial-gradient(closest-side, var(--marca-suave), transparent 72%);
  pointer-events: none;
}
.identidad > * { position: relative; }

.identidad__avatar {
  width: 76px; height: 76px;
  display: grid; place-items: center;
  border-radius: var(--r-full);
  background: var(--grad-marca);
  color: #fff;
  font-size: 1.75rem; font-weight: 800;
  letter-spacing: -.03em;
  box-shadow: var(--brillo-accion);
  flex: none;
}
.identidad__quien { display: grid; gap: 4px; min-width: 0; }
.identidad__nombre {
  font-size: var(--t-cifra-media);
  font-weight: 800;
  letter-spacing: var(--track-cifra-2);
  line-height: 1.1;
}
.identidad__correo {
  display: flex; align-items: center; gap: var(--e-2);
  flex-wrap: wrap;
  font-size: var(--t-secundario); color: var(--txt-2);
  min-width: 0;
}
.identidad__desde { font-size: var(--t-meta); color: var(--txt-3); }
.identidad__acciones { display: flex; gap: var(--e-2); flex-wrap: wrap; }

@media (max-width: 720px) {
  .identidad {
    grid-template-columns: auto minmax(0, 1fr);
    gap: var(--e-4);
    padding: var(--e-5);
  }
  .identidad__avatar { width: 56px; height: 56px; font-size: 1.3rem; }
  /* Las acciones bajan a su propia línea y a lo ancho: en 360px un botón
     apretado contra el borde derecho es un botón que se falla. */
  .identidad__acciones { grid-column: 1 / -1; }
  .identidad__acciones .btn { flex: 1 1 auto; }
}

/* ---------- La insignia del plan ---------- */
.insignia {
  display: inline-flex; align-items: center; gap: 6px;
  height: 24px; padding: 0 10px;
  border-radius: var(--r-full);
  font-size: var(--t-chip); font-weight: 800;
  background: var(--marca-suave); color: var(--marca-txt);
  flex: none;
}
.insignia--pago { background: var(--grad-accion); color: #fff; box-shadow: var(--brillo-accion); }
.insignia--ok { background: var(--ok-suave); color: var(--ok-txt); }
.insignia--ojo { background: var(--alerta-suave); color: var(--alerta-txt); }
.insignia--mal { background: var(--peligro-suave); color: var(--peligro-txt); }

/* ---------- El uso contra el tope del plan ----------
   Una barra por límite. Dice lo que QUEDA, no el porcentaje (DESIGN.md §12). */
.uso { display: grid; gap: var(--e-4); }
.uso__fila { display: grid; gap: 6px; }
.uso__cabeza { display: flex; justify-content: space-between; gap: var(--e-3); align-items: baseline; }
.uso__que { font-size: var(--t-secundario); font-weight: 600; }
.uso__cifra { font-size: var(--t-secundario); font-weight: 800; font-variant-numeric: tabular-nums; }
.uso__carril { height: 8px; border-radius: var(--r-full); background: var(--bg-2); overflow: hidden; }
.uso__relleno {
  display: block; height: 100%;
  width: calc(min(var(--parte, 0), 1) * 100%);
  border-radius: var(--r-full);
  background: var(--grad-marca);
  transition: width var(--lento) var(--curva-out);
}
.uso__fila[data-tono="ojo"] .uso__relleno { background: var(--grad-alerta); }
.uso__fila[data-tono="mal"] .uso__relleno { background: var(--grad-peligro); }
.uso__pie { font-size: var(--t-meta); color: var(--txt-3); }

/* ---------- El índice: tarjetas grandes, no una lista de enlaces ----------
   Un menú de texto de doce líneas obliga a leerlas todas para encontrar una.
   Doce tarjetas con icono, nombre y una frase de qué hay dentro se escanean de
   un vistazo, y son un objetivo enorme para el dedo — que es lo que hace falta
   cuando quien toca no ve de cerca. */
.indice {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(268px, 1fr));
  gap: var(--e-3);
}
.indice__tarjeta {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--e-4);
  width: 100%;
  min-height: 76px;
  padding: var(--e-4);
  border: 1px solid var(--linea);
  border-radius: var(--r-md);
  background: var(--capa-1);
  color: inherit;
  text-align: left;
  cursor: pointer;
  transition: border-color var(--rapido) var(--curva),
              background var(--rapido) var(--curva),
              transform var(--rapido) var(--curva);
}
.indice__tarjeta:hover {
  border-color: var(--linea-fuerte);
  background: var(--capa-2);
  transform: translateY(-1px);
}
.indice__tarjeta:active { transform: scale(.99); }
.indice__icono {
  width: 42px; height: 42px; flex: none;
  display: grid; place-items: center;
  border-radius: var(--r-sm);
  background: var(--indice-suave, var(--marca-suave));
  color: var(--indice-color, var(--marca-txt));
  font-size: var(--t-glifo-md);
}
.indice__texto { display: grid; gap: 2px; min-width: 0; }
.indice__nombre { font-weight: 700; font-size: var(--t-cuerpo); }
.indice__pista { font-size: var(--t-meta); color: var(--txt-3); line-height: 1.4; }
.indice__flecha { color: var(--txt-3); font-size: var(--t-glifo-md); flex: none; }
/* El tono tiñe el ICONO, no la tarjeta: doce tarjetas de colores serían doce
   avisos, y esto es un índice. */
.indice__tarjeta[data-tono="ok"]      { --indice-suave: var(--ok-suave);      --indice-color: var(--ok-txt); }
.indice__tarjeta[data-tono="alerta"]  { --indice-suave: var(--alerta-suave);  --indice-color: var(--alerta-txt); }
.indice__tarjeta[data-tono="peligro"] { --indice-suave: var(--peligro-suave); --indice-color: var(--peligro-txt); }
.indice__tarjeta[data-tono="futuro"]  { --indice-suave: var(--futuro-suave);  --indice-color: var(--futuro-txt); }
/* Lo pendiente se dice con una píldora, no solo con el tono (§9). */
.indice__aviso {
  min-width: 22px; height: 22px; padding: 0 7px;
  display: grid; place-items: center;
  border-radius: var(--r-full);
  background: var(--peligro); color: #fff;
  font-size: var(--t-mini); font-weight: 800;
  flex: none;
}

/* ---------- Personas de un espacio ---------- */
.personas { display: grid; gap: 2px; }
.persona {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--e-3);
  padding: 10px var(--e-2);
  border-radius: var(--r-sm);
}
.persona:hover { background: var(--capa-2); }
.persona__quien { display: grid; gap: 1px; min-width: 0; }
.persona__nombre { font-weight: 600; font-size: var(--t-secundario); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.persona__correo { font-size: var(--t-meta); color: var(--txt-3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ---------- El panel del avatar ----------
   Era una lista plana de ocho enlaces con tres rótulos. Ahora es un panel:
   arriba quién eres y con qué plan, en medio el espacio en el que estás, y
   abajo lo poco que de verdad se abre desde aquí. Todo lo demás vive en las dos
   pantallas a las que lleva, que es donde se puede explicar. */
.panel-usuario { width: min(340px, calc(100vw - var(--e-6))); padding: 0; }
.panel-usuario__cabeza {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: center;
  gap: var(--e-3);
  padding: var(--e-4);
  border-bottom: 1px solid var(--linea);
}
.panel-usuario__avatar {
  width: 44px; height: 44px;
  display: grid; place-items: center;
  border-radius: var(--r-full);
  background: var(--grad-marca);
  color: #fff; font-weight: 800; font-size: var(--t-cuerpo);
}
.panel-usuario__quien { display: grid; gap: 2px; min-width: 0; }
.panel-usuario__nombre { font-weight: 800; font-size: var(--t-cuerpo); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.panel-usuario__correo { font-size: var(--t-meta); color: var(--txt-3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.panel-usuario__plan { margin-top: 4px; }

/* El espacio activo, con su cambiador. Es lo que más se toca de este panel en
   una empresa: quien lleva tres negocios entra aquí a saltar entre ellos. */
.panel-usuario__espacio {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--e-3);
  width: 100%;
  padding: var(--e-3) var(--e-4);
  border: 0; border-bottom: 1px solid var(--linea);
  background: transparent; color: inherit;
  text-align: left; cursor: pointer;
}
.panel-usuario__espacio:hover { background: var(--capa-2); }
.panel-usuario__icono {
  width: 34px; height: 34px;
  display: grid; place-items: center;
  border-radius: var(--r-sm);
  background: var(--marca-suave);
  font-size: var(--t-glifo-md);
}
.panel-usuario__rotulo {
  font-size: var(--t-micro); font-weight: 700;
  letter-spacing: var(--track-rotulo); text-transform: var(--caja-rotulo);
  color: var(--txt-3);
}
.panel-usuario__lista { padding: var(--e-2); display: grid; gap: 2px; }
.panel-usuario__pie {
  display: flex; gap: var(--e-2);
  padding: var(--e-2) var(--e-3) var(--e-3);
  border-top: 1px solid var(--linea);
}
.panel-usuario__pie .btn { flex: 1 1 auto; }

@media (max-width: 640px) {
  .panel-usuario { width: auto; }
}

/* ---------- «Más» en el teléfono (js/mas.js) ----------
   Una hoja propia, no el lateral del escritorio hecho cajón. Se viste con las
   piezas del panel del avatar —quién eres, en qué espacio estás, la lista con
   sus rótulos— para que las dos cosas que enseñan lo mismo se vean igual. Aquí
   ocupa el ancho de la hoja, y cada fila mide lo que pide el dedo. */
.panel-usuario.mas { width: auto; }
.mas__quien {
  width: 100%;
  border: 0; border-bottom: 1px solid var(--linea);
  background: transparent; color: inherit;
  text-align: left; cursor: pointer;
}
.mas__item {
  display: flex; align-items: center; justify-content: space-between; gap: var(--e-2);
  min-height: var(--tactil);
  text-align: left;
}
.mas .nav__badge { margin-left: auto; }
/* Dentro de un botón la columna estira a sus hijos: la insignia del plan salía
   de lado a lado, como una barra de progreso. */
.mas__quien .panel-usuario__plan { justify-self: start; }

/* ---------- El índice pegajoso de la configuración ----------
   No son pestañas: no esconden nada. Son atajos que llevan a su sección de la
   misma página. Con pestañas, lo que no está en la pestaña abierta no existe
   para quien no sabe que hay pestañas — y esta app la usa gente que no lo sabe. */
.saltos {
  position: sticky;
  top: calc(var(--alto-topbar) + var(--e-2));
  z-index: 10;
  display: flex;
  gap: var(--e-2);
  overflow-x: auto;
  padding: var(--e-2);
  margin-bottom: var(--e-2);
  border-radius: var(--r-full);
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  backdrop-filter: blur(18px) saturate(1.4);
  -webkit-backdrop-filter: blur(18px) saturate(1.4);
  border: 1px solid var(--linea);
  scrollbar-width: none;
  min-width: 0;
}
.saltos::-webkit-scrollbar { display: none; }
.saltos__ir {
  flex: none;
  min-height: 38px;
  padding: 0 var(--e-4);
  border: 0;
  border-radius: var(--r-full);
  background: transparent;
  color: var(--txt-2);
  font-size: var(--t-meta); font-weight: 700;
  cursor: pointer;
  white-space: nowrap;
  transition: background var(--rapido) var(--curva), color var(--rapido) var(--curva);
}
.saltos__ir:hover { background: var(--capa-2); color: var(--txt); }
.saltos__ir[aria-current="true"] { background: var(--marca-suave); color: var(--marca-txt); }

/* El título de un grupo de ajustes. El ancla del salto va en él. */
.grupo-ajustes { display: grid; gap: var(--e-4); }
.grupo-ajustes__titulo {
  font-size: var(--t-seccion);
  font-weight: 800;
  letter-spacing: var(--track-rotulo);
  text-transform: var(--caja-rotulo);
  color: var(--txt-3);
  padding-top: var(--e-4);
  /* Para que el título no quede debajo de la barra pegajosa al saltar. */
  scroll-margin-top: calc(var(--alto-topbar) + 72px);
}

/* ---------- Lo que incluye un plan, y lo que no ----------
   Con marca y con COLOR, pero sobre todo con marca: el ✓ y el ✕ los ve
   cualquiera, el verde y el gris no (DESIGN.md §9, el color nunca solo). */
.lista-plan { display: grid; gap: 6px; list-style: none; margin: 0; padding: 0; }
.lista-plan li {
  display: grid;
  grid-template-columns: 20px minmax(0, 1fr);
  gap: var(--e-2);
  align-items: baseline;
  font-size: var(--t-secundario);
}
.lista-plan li::before { font-weight: 800; }
.lista-plan__si::before { content: "✓"; color: var(--ok-txt); }
.lista-plan__no::before { content: "✕"; color: var(--txt-3); }
.lista-plan__no { color: var(--txt-3); }

/* La rejilla de la pantalla de perfil: una columna, con aire entre bloques. */
.perfil { display: grid; gap: var(--e-5); }
.perfil > * { min-width: 0; }

/* Los campos sueltos del perfil no se estiran a todo el ancho de la tarjeta.
   Un desplegable de «15 minutos» ocupando 1.100px se lee como un error de
   maquetación, y además obliga a cruzar la pantalla entera para tocarlo. */
.perfil .field { max-width: 340px; }
.perfil .field select,
.perfil .field input { width: 100%; }
@media (max-width: 640px) { .perfil .field { max-width: none; } }


/* ==========================================================================
   27 · NÓMINA
   ==========================================================================
   Una planilla es una lista de pares «concepto → cifra», y se lee de derecha a
   izquierda: primero la cifra, y solo si sorprende se busca de qué era. Por eso
   las cifras van alineadas en una columna y no pegadas al texto.

   El volante de pago repite la misma pieza dentro del modal, a propósito: el
   papel que se entrega y la pantalla desde la que se mira tienen que parecerse
   o nadie los reconoce como lo mismo. */

.nomina__fila {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--e-3);
  padding: var(--e-2) 0;
  border-bottom: 1px solid var(--linea);
}
.nomina__fila:last-child { border-bottom: 0; }
/* La cifra no se parte nunca. «RD$ 1,234.56» cortado en dos líneas dentro de
   una planilla deja de leerse como una cantidad. */
.nomina__fila > :last-child {
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

.nomina__pista {
  display: block;
  font-size: var(--t-meta);
  color: var(--txt-3);
}
/* En la misma línea cuando acompaña a un rótulo, y debajo cuando es la segunda
   línea de una celda. Lo decide el sitio, no una clase más. */
.nomina__fila .nomina__pista { display: inline; }

.nomina__nota {
  font-size: var(--t-meta);
  color: var(--txt-2);
  margin: var(--e-3) 0 0;
}

.nomina__raya {
  height: 1px;
  background: var(--linea-fuerte);
  margin: var(--e-2) 0;
}

/* El nombre de la planilla abre el volante, así que tiene que parecer tocable
   sin ser un botón con caja: en una tabla de veinte filas, veinte botones con
   fondo son veinte manchas. */
.nomina__quien {
  border: 0;
  background: none;
  padding: 0;
  text-align: left;
  color: inherit;
  cursor: pointer;
  /* 44px de alto aunque el texto sea una línea: es un objetivo táctil, y en la
     tabla de un teléfono se falla si mide menos. */
  min-height: 44px;
  display: grid;
  align-content: center;
  gap: 2px;
}
.nomina__quien:hover strong { color: var(--marca); }
.nomina__quien:focus-visible {
  outline: 2px solid var(--marca);
  outline-offset: 2px;
  border-radius: var(--r-xs);
}

/* La fila de totales cierra la tabla y se lee como un subrayado doble: la línea
   de arriba la separa, el fondo la fija. */
.nomina__total > td {
  border-top: 2px solid var(--linea-fuerte);
  background: var(--capa-1);
}

.nomina__acciones {
  display: flex;
  gap: var(--e-2);
  justify-content: flex-end;
  flex-wrap: wrap;
}

.nomina__volante { display: grid; gap: 2px; }
.nomina__volante h4,
.nomina__rotulo {
  margin: var(--e-4) 0 var(--e-1);
  font-size: var(--t-rotulo);
  font-weight: 700;
  letter-spacing: var(--track-rotulo);
  text-transform: var(--caja-rotulo);
  color: var(--txt-3);
}
.nomina__volante h4:first-of-type { margin-top: var(--e-2); }

/* La liquidación. Las partidas que NO corresponden se quedan a la vista y
   apagadas: son la mitad de la explicación, y quitarlas deja la pregunta
   «¿dónde está mi cesantía?» sin contestar. */
.nomina__liq { display: grid; gap: 2px; margin-top: var(--e-4); }
.nomina__liq-fila {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--e-3);
  padding: var(--e-3) 0;
  border-bottom: 1px solid var(--linea);
}
.nomina__liq-fila:last-child { border-bottom: 0; }
.nomina__liq-monto {
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
  font-weight: 700;
}
/* Apagada, no tachada: un importe tachado se lee como un descuento, y aquí lo
   que hay es una partida que no corresponde. */
.nomina__liq-fila[data-incluida="0"] { opacity: .62; }
.nomina__liq-fila[data-incluida="0"] .nomina__liq-monto {
  font-weight: 400;
  color: var(--txt-3);
}

/* Las normas: plegadas, porque no se miran cada día, pero con el mismo aire
   que una tarjeta cuando se abren. */
.nomina__normas { padding: var(--e-4); }
/* Dentro de una tarjeta va sin relleno propio: la tarjeta ya lo pone, y con
   los dos el bloque queda hundido y desalineado con el resto del contenido.
   Se separa con una línea, que es lo que hace falta para que se lea como un
   apartado y no como otra tarjeta. */
/* El texto de un aviso que es una PEGA y no una confirmación: un proveedor
   suspendido en la DGII, una cédula cuyo dígito verificador no cuadra, una
   cuenta que lleva demasiadas horas caída.

   Estaba escrita en cuatro sitios del código (js/rnc.js, js/admin-cuentas.js,
   js/views/proveedores.js y la ficha de nómina) y no existía en NINGUNA hoja,
   así que los cuatro avisos se veían igual que un mensaje normal — que es
   exactamente no avisar. Lo caza pruebas/cedula.mjs.

   Peso además del color, que §9 pide que el color nunca vaya solo. */
.avisoMal {
  color: var(--peligro-txt);
  font-weight: 600;
}

.nomina__normas--dentro {
  padding: 0;
  margin-top: var(--e-4);
  padding-top: var(--e-2);
  border-top: 1px solid var(--linea);
}
.nomina__normas > summary {
  cursor: pointer;
  font-weight: 700;
  /* Un objetivo táctil de verdad: un resumen de una línea mide 20px y se falla
     con el pulgar. */
  min-height: 44px;
  display: flex;
  align-items: center;
}
.nomina__norma {
  display: grid;
  gap: 2px;
  padding: var(--e-3) 0;
  border-bottom: 1px solid var(--linea);
}
.nomina__norma:last-child { border-bottom: 0; }
.nomina__norma > span {
  font-size: var(--t-meta);
  color: var(--txt-3);
}


/* ==========================================================================
   28 · LA CARTERA
   ==========================================================================
   Casi todo se apoya en las piezas de nómina, que resuelven lo mismo: pares de
   «concepto → cifra» con la cifra alineada a la derecha. Lo propio de aquí son
   dos cosas: el estado de cada factura y las barras de la antigüedad.

   El ESTADO nunca es solo un color (DESIGN.md §9). El tono viaja en un
   data-atributo y el texto va dentro; quitar el texto dejaría «rojo» y «ámbar»
   diciéndole a alguien a quién llamar hoy, que es justo lo que no puede pasar
   con un daltonismo o con el sol de frente. */

.cartera__fila {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--e-3);
  padding: var(--e-2) 0;
  border-bottom: 1px solid var(--linea);
}
.cartera__fila:last-child { border-bottom: 0; }
.cartera__fila > :last-child {
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

.cartera__pista {
  display: block;
  font-size: var(--t-meta);
  color: var(--txt-3);
}
.cartera__fila .cartera__pista { display: inline; }

.cartera__nota {
  font-size: var(--t-meta);
  color: var(--txt-2);
  margin: var(--e-3) 0 0;
}

.cartera__raya {
  height: 1px;
  background: var(--linea-fuerte);
  margin: var(--e-2) 0;
}

.cartera__acciones {
  display: flex;
  gap: var(--e-2);
  flex-wrap: wrap;
}

/* El estado. Píldora pequeña, con su palabra siempre dentro. */
.cartera__estado {
  display: inline-block;
  font-size: var(--t-meta);
  font-weight: 700;
  color: var(--txt-2);
  white-space: nowrap;
}
/* Cuando el estado es un DIV va en su propia línea. En la tabla de facturas
   vive debajo de la fecha, y con el inline-block de arriba salía pegado a
   ella: «20 jun 2026Vencida hace 80 días». */
div.cartera__estado { display: block; margin-top: 2px; }
.cartera__estado[data-tono="mal"] { color: var(--peligro-txt); }
.cartera__estado[data-tono="ojo"] { color: var(--alerta-txt); }
.cartera__estado[data-tono="bien"] { color: var(--ok-txt); }

/* El nombre abre la factura. Como en la planilla: tocable sin ser una caja, y
   con 44px de alto aunque el texto sea una línea. */
.cartera__quien {
  border: 0;
  background: none;
  padding: 0;
  text-align: left;
  color: inherit;
  cursor: pointer;
  min-height: 44px;
  display: grid;
  align-content: center;
  gap: 2px;
}
.cartera__quien:hover strong { color: var(--marca); }
.cartera__quien:focus-visible {
  outline: 2px solid var(--marca);
  outline-offset: 2px;
  border-radius: var(--r-xs);
}

/* La antigüedad. Una barra por tramo, todas contra el mismo total, para que se
   comparen de un vistazo sin leer los números. */
.cartera__tramo { padding: var(--e-2) 0; }
.cartera__tramo-cabeza {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--e-3);
  margin-bottom: 6px;
}
.cartera__tramo-cabeza > :last-child { font-variant-numeric: tabular-nums; }
/* Y en la cabecera del tramo la pista SÍ va debajo, no en línea. */
.cartera__tramo-cabeza .cartera__pista { display: block; }

.cartera__carril {
  display: block;
  height: 8px;
  border-radius: var(--r-full);
  background: var(--bg-2);
  overflow: hidden;
}
.cartera__relleno {
  display: block;
  height: 100%;
  width: calc(var(--parte, 0) * 100%);
  border-radius: var(--r-full);
  background: var(--marca);
  transition: width var(--medio) var(--curva);
}
/* Cuanto más viejo, más caliente. Es una escala, no un semáforo de tres
   colores: lo de 90 días no es «malo» de otra forma que lo de 60, es más. */
.cartera__relleno[data-tramo="porVencer"] { background: var(--marca); }
.cartera__relleno[data-tramo="d30"] { background: var(--alerta); }
.cartera__relleno[data-tramo="d60"] { background: var(--alerta); opacity: .85; }
.cartera__relleno[data-tramo="d90"] { background: var(--peligro); opacity: .8; }
.cartera__relleno[data-tramo="mas90"] { background: var(--peligro); }

/* El selector de lado no es una tarjeta con cabecera: es solo el conmutador. */
.cartera__lado { padding: var(--e-3) var(--card-pad); }

.cartera__detalle { display: grid; gap: 2px; }
.cartera__detalle h4 {
  margin: var(--e-4) 0 var(--e-1);
  font-size: var(--t-rotulo);
  font-weight: 700;
  letter-spacing: var(--track-rotulo);
  text-transform: var(--caja-rotulo);
  color: var(--txt-3);
}


/* ==========================================================================
   29 · LAS PRÓXIMAS SEMANAS (Inicio, solo empresa)
   ==========================================================================
   Ocho columnas y una línea de cero. No es un gráfico de los de §7 —no tiene
   ejes ni escala escrita— porque no se viene a leer una cifra exacta: se viene
   a ver DÓNDE se hunde. La cifra exacta está en el título de cada columna y en
   la etiqueta que lee un lector de pantalla. */

.semanas__titular {
  font-size: var(--t-tarjeta);
  font-weight: 800;
  margin: var(--e-3) 0 4px;
}
.semanas[data-tono="mal"] .semanas__titular { color: var(--peligro-txt); }
.semanas[data-tono="ojo"] .semanas__titular { color: var(--alerta-txt); }
.semanas[data-tono="bien"] .semanas__titular { color: var(--ok-txt); }

.semanas__detalle { color: var(--txt-2); margin: 0 0 var(--e-4); }

.semanas__grafico {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 1fr;
  gap: var(--e-2);
  align-items: end;
}
.semanas__col { display: grid; gap: 6px; min-width: 0; }

/* El hueco tiene altura fija y las barras se colocan dentro CONTRA EL CERO,
   que puede caer en cualquier punto: arriba del todo si las ocho semanas están
   en negativo, abajo si ninguna lo está. --cero es su posición medida desde
   abajo, y la calcula la vista una vez para las ocho columnas. */
.semanas__hueco {
  position: relative;
  height: 84px;
  border-radius: var(--r-xs);
  background: var(--capa-1);
  overflow: hidden;
}
/* La línea del cero, dibujada. Sin ella, ocho barras colgando no dicen desde
   dónde cuelgan. */
.semanas__cero {
  position: absolute;
  left: 0; right: 0;
  bottom: calc(var(--cero, 0) * 100%);
  height: 1px;
  background: var(--linea-fuerte);
}
.semanas__barra {
  position: absolute;
  left: 0; right: 0;
  height: calc(var(--alto, 0) * 100%);
  border-radius: var(--r-xs);
  background: var(--grad-marca);
  transition: height var(--medio) var(--curva);
}
/* Encima del cero crece hacia arriba; debajo, cuelga. El color solo no basta
   (DESIGN.md §9): aquí la forma lo dice sin leer nada. */
.semanas__barra[data-signo="mas"] { bottom: calc(var(--cero, 0) * 100%); }
.semanas__barra[data-signo="menos"] {
  top: calc((1 - var(--cero, 0)) * 100%);
  background: var(--peligro);
}

.semanas__pie {
  font-size: var(--t-micro);
  color: var(--txt-3);
  text-align: center;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.semanas__aviso {
  font-size: var(--t-meta);
  color: var(--txt-3);
  margin: var(--e-3) 0 0;
}


/* ==========================================================================
   30 · LOS COMPROBANTES
   ==========================================================================
   Una barra por rango, con el mismo lenguaje que las de la antigüedad de la
   cartera: llena es malo. Aquí «llena» quiere decir «no quedan», que es la
   única forma de quedarse sin poder facturar un viernes. */

.ncf__carril {
  display: block;
  height: 6px;
  margin-top: 6px;
  border-radius: var(--r-full);
  background: var(--bg-2);
  overflow: hidden;
}
.ncf__relleno {
  display: block;
  height: 100%;
  width: calc(var(--parte, 0) * 100%);
  border-radius: var(--r-full);
  background: var(--marca);
  transition: width var(--medio) var(--curva);
}
.ncf__relleno[data-tono="ojo"] { background: var(--alerta); }
.ncf__relleno[data-tono="mal"] { background: var(--peligro); }

/* El próximo número va en monoespaciada: se copia y se pega en una factura, y
   una cifra de once dígitos con la fuente del texto se lee mal por definición. */
.ncf__proximo {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: var(--t-meta);
  white-space: nowrap;
}

.ncf__vence[data-tono="ojo"] { color: var(--alerta-txt); font-weight: 700; }
.ncf__vence[data-tono="mal"] { color: var(--peligro-txt); font-weight: 700; }

.ncf__acciones { display: flex; gap: var(--e-2); justify-content: flex-end; }


/* ==========================================================================
   31 · EL ALMACÉN
   ==========================================================================
   Las mismas piezas que la planilla y la cartera: el nombre abre el detalle sin
   ser una caja, y la cifra que decide algo lleva su tono con su texto al lado.

   Los 44px del nombre NO son un capricho de diseño: es un objetivo táctil, y la
   primera versión de esta pantalla salió a 27px. La auditoría lo cazó en los
   anchos de móvil, que es donde se falla un botón con el pulgar. */

.alm__que {
  border: 0;
  background: none;
  padding: 0;
  text-align: left;
  color: inherit;
  cursor: pointer;
  min-height: 44px;
  display: grid;
  align-content: center;
  gap: 2px;
}
.alm__que:hover strong { color: var(--marca); }
.alm__que:focus-visible {
  outline: 2px solid var(--marca);
  outline-offset: 2px;
  border-radius: var(--r-xs);
}

.alm__pista {
  display: block;
  font-size: var(--t-meta);
  color: var(--txt-3);
}

.alm__nota {
  font-size: var(--t-meta);
  color: var(--txt-2);
  margin: var(--e-3) 0 0;
}

/* La existencia es la cifra que decide si hay que pedir. El tono nunca va solo:
   la fila lleva además el nombre y la unidad, y los avisos de arriba lo dicen
   con palabras. */
.alm__existencia {
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
  font-weight: 700;
}
.alm__existencia[data-tono="ojo"] { color: var(--alerta-txt); }
.alm__existencia[data-tono="mal"] { color: var(--peligro-txt); }

.alm__acciones {
  display: flex;
  gap: var(--e-2);
  justify-content: flex-end;
  flex-wrap: wrap;
}


/* ==========================================================================
   LO RESPONSIVE VA AL FINAL, Y ESO ES PARTE DE LA REGLA
   ==========================================================================
   Estos dos bloques —el táctil y el de la carcasa— estaban en medio del
   archivo, y ahí no sirven: una regla base escrita DESPUÉS con la misma
   especificidad los gana por orden de lectura.

   Pasó en cuanto se añadió la barra de saltos de la configuración. Su
   `.saltos__ir { min-height: 38px }` se escribió más abajo que el bloque
   táctil, así que en un teléfono seguía midiendo 38px por mucho que el bloque
   dijera 48. La auditoría lo cazó; leyendo el CSS no se ve.

   Poniéndolos los últimos, cualquier componente nuevo queda cubierto sin que
   quien lo escriba tenga que acordarse de nada. Si añades una pieza más abajo
   que esto, la trampa vuelve.
   ========================================================================== */


/* ==========================================================================
   23 · RESPONSIVE: LO QUE SE TOCA CON EL DEDO
   ==========================================================================
   DESIGN.md §9: zonas táctiles ≥ 48px. La ficha --tactil existía y no la
   respetaba casi nadie: `.btn--sm` medía 34px, los chips 26 y el enlace de un
   descubrimiento 30. En un teléfono eso no es un botón pequeño — es un botón
   que se falla, y se falla justo cuando se va rápido.

   ── Por qué DOS condiciones ──

   `(pointer: coarse)` es la correcta: describe el dedo, que es el problema.
   `(max-width: 640px)` va con ella porque es el ancho en el que esta app YA se
   comporta como móvil —aparece la barra del pulgar, las tablas se apilan— y
   porque un navegador puede mentir sobre el puntero: un portátil con pantalla
   táctil dice `fine`, y un móvil con un ratón bluetooth conectado, también.

   La coma es un O lógico: basta con que se cumpla una.

   ── Y por qué no se sube el tamaño y ya ──

   Porque en escritorio con ratón un botón de 44px de alto en una barra de
   herramientas es una barra que ocupa el doble sin ganar nada. Las medidas
   pequeñas están bien donde se apunta con un ratón; el fallo era no cambiarlas
   donde se apunta con un dedo. */

@media (pointer: coarse), (max-width: 640px) {
  /* Los botones pequeños dejan de serlo. El ancho sí se queda: lo que falla al
     tocar es el alto, porque el dedo se desplaza en vertical al bajar. */
  .btn--sm, .btn-sm { min-height: var(--tactil); padding: 0 var(--e-4); }

  /* Los chips: son el control que más se toca de la app —la pantalla de ordenar
     lo suelto es toda chips— y el que más pequeño estaba.
     Hay DOS familias con historia distinta y las dos se tocan igual: `.chip-cat`
     es la del sistema de diseño y `.chip` la de los filtros de Buscar.

     44 y no --tactil (48): un chip va DENTRO de una fila de movimiento, y con
     48 cada fila de la lista se iba a 90px de alto. Cincuenta movimientos a 90px
     son cinco pantallas más de desplazamiento para el mismo contenido. 44 es el
     mínimo con el que un dedo acierta, y aquí la diferencia se nota. */
  button.chip-cat,
  .chip, button.chip { min-height: 44px; padding: 0 var(--e-4); }
  /* La ✕ de un chip de filtro es su propio botón, y medía lo que su glifo. */
  .chip__x { min-width: 32px; min-height: 32px; display: inline-grid; place-items: center; }
  .chips-filtro .chip-filtro, .theme-switch button { min-height: var(--tactil); }

  /* El enlace de un descubrimiento y los demás botones-texto: sin relleno
     propio se quedaban en la altura de su línea. */
  .insight__accion,
  .pie__enlaces button,
  .vertodo,
  .saltos__ir,
  .card__tools .btn { min-height: var(--tactil); }

  /* Campos. `.input` ya seguía a --control-alto, pero los que viven dentro de
     una tabla traían su propia altura de 32px — y son justo los de «Mis
     límites», donde se teclea un número por categoría.

     El selector copia el de styles.css (`table.data select`, no `td select`):
     con menos especificidad no gana, aunque esta hoja se lea después. */
  input, select, textarea, .input,
  .meter-row input, .limite input,
  table.data select,
  table.data input:not([type="checkbox"]) { min-height: var(--control-alto); }
  /* Los de una barra de filtros traen `height: 38px` fijo, no un mínimo: hay que
     devolverles el `auto` antes de que el mínimo pueda hacer algo. Son los del
     periodo y la cuenta de arriba, y los propios de «Mis límites». */
  .filters select,
  .filters input[type="date"] { height: auto; min-height: var(--control-alto); font-size: 1rem; }
  /* Y a 16px. Se quedaban en los 14 de la barra de escritorio, y un iPad en
     Safari —dedo, pero experiencia de escritorio— hace zoom al enfocar un
     campo de menos de 16. El teléfono ya los tenía así (body.con-pulgar). */
  /* La casilla de una tabla sí crece: 18px es imposible de dar con el dedo. */
  table.data input[type="checkbox"],
  .mov-fila input[type="checkbox"] { width: 22px; height: 22px; }

  .segmentos button { min-height: 42px; }
  .nav__item { min-height: var(--tactil); }
  .usuario, .icono-btn, .avisos-btn { min-height: var(--tactil); min-width: var(--tactil); }

  /* Filas pulsables: una fila de 34px es una fila que se falla al bajar rápido. */
  .reparto__fila { min-height: 52px; }
  .mov-fila { min-height: 56px; }
  .mov-fila__que--abre { min-height: var(--tactil); justify-content: center; }
  .fila-com, .por-venir__fila, .sus { min-height: 56px; }
  .data tbody td { padding-top: 13px; padding-bottom: 13px; }
  .calor__dia { min-height: 34px; }
}


/* ==========================================================================
   24 · RESPONSIVE: LA CARCASA Y LAS BARRAS
   ==========================================================================
   Lo que se estrecha antes que nada es la cabecera: título, buscador, campana,
   avatar y dos filtros en 360px no caben de ninguna manera. */

/* ---------- Cabecera ---------- */
@media (max-width: 900px) {
  .topbar { padding: var(--e-3) var(--canal); }
  /* El cajón es una capa a pantalla completa, así que empieza donde empieza la
     pantalla: sin esto, el logotipo y el selector de espacio quedaban DEBAJO de
     la isla dinámica del iPhone (y de la cámara de cualquier Android).

     El hueco de la isla ya no lo pone el panel: lo pone su cabecera, que va
     pegada arriba (§15b). Con el hueco aquí, el contenido SE METÍA debajo de la
     isla en cuanto se bajaba la lista — el padding rueda con todo lo demás, así
     que protege el primer pintado y nada más. */
  .sidebar__panel { padding-top: 0; }
  /* El buscador se pliega a su lupa. El campo sigue existiendo —enfocarlo lo
     abre— pero deja de gastar 200px de una cabecera que no los tiene. */
  .buscador { padding: 0; width: 40px; justify-content: center; }
  /* Plegado, el campo se encoge a CERO y no se esconde con `display: none`: a un
     elemento oculto no se le puede dar el foco, y por eso pulsar la lupa no
     hacía nada. En el teléfono la lupa ya lleva a la pantalla Buscar (js/app.js);
     esto es para el tramo de tableta, donde el campo sigue estando. */
  .buscador input {
    width: 0; min-width: 0; padding: 0; border: 0; opacity: 0;
  }
  .buscador__atajo { display: none; }
  .buscador:focus-within { width: min(62vw, 300px); padding: 0 var(--e-3); justify-content: flex-start; }
  .buscador:focus-within input { width: auto; flex: 1 1 auto; opacity: 1; }
  /* Del chip de usuario solo queda el avatar: el nombre y el plan están dentro
     del menú que abre, así que repetirlos fuera cuesta sitio y no dice nada
     nuevo. */
  .usuario__texto, .usuario__flecha { display: none; }
  .usuario { padding: 4px; border-radius: var(--r-full); }
}

/* La lupa plegada, del tamaño de sus vecinas. Con dedo, o en una ventana
   estrecha, la campana y el avatar miden --tactil y la lupa se quedaba en 40
   —38 de blanco, quitando el borde—, y abierta volvía a 38. El teléfono ya lo
   tenía (body.con-pulgar); esto es el resto: una tableta, un iPad en Safari. */
@media (max-width: 900px) and (pointer: coarse), (max-width: 640px) {
  .buscador { width: var(--tactil); height: var(--tactil); }
  .buscador:focus-within .buscador__ico { width: 40px; height: 40px; }
}

@media (max-width: 640px) {
  /* La cabecera, en UNA fila.
   *
   * Era flexible y se partía en dos: arriba «☰ + Inicio» y debajo, alineados a
   * la derecha, la lupa, la campana y el avatar. Ciento treinta píxeles de cromo
   * antes de la primera cifra en una pantalla de 360, que es justo lo que esta
   * app dice no querer.
   *
   * En rejilla no se parte: el título ocupa lo que sobre —con `minmax(0,1fr)`,
   * que es lo que le permite encogerse en vez de empujar— y los iconos van
   * pegados a la derecha. La cuarta columna es el «+», que casi siempre está
   * escondido; una columna `auto` sin contenido no ocupa nada. */
  .topbar {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto auto;
    align-items: center;
    gap: var(--e-2);
  }
  .topbar__head { min-width: 0; }
  .topbar__head h1 {
    font-size: clamp(1.25rem, 1.05rem + 2vw, 1.6rem);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  /* En una fila, nunca partidos: la hoja vieja les deja `flex-wrap: wrap`, y con
     un título largo («Traspasos entre mis cuentas») la columna se encogía al
     ancho de UN icono y la campana, el avatar y el «+» salían en torre. Lo que
     cede es el título, que ya se recorta con «…». */
  .topbar__derecha { gap: 4px; flex-wrap: nowrap; flex: none; }
  /* Con la barra del pulgar no hay ☰, y la rejilla de cuatro columnas de arriba
     contaba con él: el título caía en la columna `auto` del ☰ —la que no se
     encoge nunca— y los iconos en la `1fr`. Con un título corto no se notaba;
     con «Traspasos entre mis cuentas» la campana quedaba debajo del «+» y el
     avatar fuera de la pantalla. Aquí, tres columnas y el título primero. */
  body.con-pulgar .topbar { grid-template-columns: minmax(0, 1fr) auto auto; }
  /* La miga y el subtítulo sobran en el teléfono: la barra de abajo ya dice
     dónde estás, y dos líneas más de cromo antes de la primera cifra son dos
     líneas de más. */
  .miga { display: none; }
  .topbar__head p { display: none; }

  /* Y el vidrio, más espeso.
   *
   * En un escritorio la cabecera flota sobre una página que se desplaza despacio
   * y el 78% de tinta deja ver una sombra de lo que pasa por debajo, que es el
   * efecto que se busca. En un teléfono el desplazamiento es rápido y lo que
   * cruza son cifras grandes y tarjetas de color: el título de la pantalla se
   * leía sobre un fondo que cambiaba de color a cada momento, y la franja de la
   * barra de estado —donde vive la isla dinámica del iPhone— era la peor, porque
   * ahí encima está además el reloj del sistema.
   *
   * Con el vidrio más espeso sigue viéndose que hay algo debajo y el título deja
   * de competir con ello. */
  .topbar { background: color-mix(in srgb, var(--bg) 92%, transparent); }
  .topbar[data-pegada="si"] { background: color-mix(in srgb, var(--bg) 97%, transparent); }
}

/* ---------- Barra de filtros ---------- */
@media (max-width: 640px) {
  .filters {
    /* Más aire por arriba que por abajo: pegada a la cabecera parecía parte de
       ella, y «PERIODO» se leía como un subtítulo del título de la pantalla. */
    padding: var(--e-4) var(--canal) var(--e-3);
    gap: var(--e-2);
  }
  /* Los dos selectores comparten fila y el botón se lleva la suya entera: a
     360px, tres cosas en una línea dejan «Esta quincena» en «Esta qu…». */
  .filters .field { flex: 1 1 calc(50% - var(--e-2)); min-width: 0; }
  .filters .btn--primary { flex: 1 1 100%; }
  .periodo-nav { flex: 1 1 100%; justify-content: space-between; }
}

/* ---------- Contenido ---------- */
@media (max-width: 640px) {
  .view { padding: var(--e-4) var(--canal) var(--e-8); }
  .card { padding: var(--e-4); border-radius: var(--r-md); }
  .respuesta { padding: var(--e-6) var(--e-4); border-radius: var(--r-lg); }
  /* La cabeza de una tarjeta con herramientas: el título arriba y los botones
     debajo, a lo ancho. En línea, el título se queda en una palabra. */
  .card__head { flex-wrap: wrap; }
  .card__tools { display: flex; flex-wrap: wrap; gap: var(--e-2); width: 100%; }
  .card__tools .btn { flex: 1 1 auto; }
  .seccion__head { flex-direction: column; align-items: flex-start; gap: var(--e-2); }
  .seccion__acciones { width: 100%; flex-wrap: wrap; }
}

/* ---------- La lista de movimientos ----------
   Tres columnas —qué · categoría · monto— caben en un portátil y no en un
   teléfono: el chip se iba a una fila entera para él solo, con el monto
   flotando a media altura al lado. Noventa píxeles por movimiento y una lista
   que no se lee.

   En dos columnas con áreas queda como en cualquier app de banco: el comercio y
   su chip a la izquierda, uno encima del otro, y el monto a la derecha
   ocupando el alto de los dos. */
@media (max-width: 640px) {
  .mov-fila {
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-areas:
      "que   monto"
      "cat   monto";
    row-gap: 6px;
    column-gap: var(--e-3);
    align-items: center;
  }
  .mov-fila__que   { grid-area: que; }
  .mov-fila__cat   { grid-area: cat; justify-self: start; }
  /* El monto se alinea con el NOMBRE del comercio, no con el centro de las dos
     filas: centrado quedaba flotando en el hueco entre la cuenta y el chip, sin
     pareja visual con nada. Arriba forma línea con el comercio, que es con lo
     que se lee («Licorería La Cava … −2,677.97»). */
  .mov-fila__monto { grid-area: monto; align-self: start; }
}

/* ---------- Pie ---------- */
@media (max-width: 640px) {
  .pie { padding: var(--e-6) var(--canal); display: grid; gap: var(--e-3); }
  .pie__enlaces { display: flex; flex-wrap: wrap; gap: var(--e-2); }
}

/* ---------- Modales y hojas ----------
   Ya suben desde abajo (§18). Aquí solo el relleno, que a 360px se comía media
   línea de texto por lado. */
@media (max-width: 480px) {
  .modal__head, .modal__body, .modal__foot { padding-left: var(--e-4); padding-right: var(--e-4); }
  .modal__foot { flex-wrap: wrap; }
  .modal__foot .btn { flex: 1 1 auto; }
}

/* ---------- Pantallas BAJAS: el teléfono de lado ----------
 *
 * Un iPhone en horizontal son 844×390. El ancho ya no es el problema —a 844 la
 * app se comporta como tableta— pero el ALTO sí: cabecera pegajosa (64px),
 * barra de filtros (72px) y barra del pulgar abajo dejaban 190px de contenido
 * de 390. Casi la mitad de la pantalla en cromo.
 *
 * Se mide por alto y no por orientación a secas: una ventana de escritorio
 * aplastada tiene el mismo problema y merece la misma solución. */
@media (max-height: 520px) {
  /* La cabecera deja de seguir al desplazamiento. Es lo que más ocupa y lo que
     menos falta hace mientras se lee una lista. */
  .topbar { position: static; min-height: 0; padding: var(--e-2) var(--canal); }
  .topbar__head h1 { font-size: 1.15rem; }
  .topbar__head p, .miga { display: none; }
  .filters { padding: var(--e-2) var(--canal); }
  .view { padding-top: var(--e-3); }
  /* Y la cifra héroe baja: a 390px de alto, 88px de número dejan la frase que
     lo explica fuera de la pantalla. */
  .respuesta { padding: var(--e-4); }
  .respuesta__cifra { font-size: clamp(2rem, 7vh, 3rem); }
  /* La hoja, en §36.2: aquí no hacía nada, porque aquella regla va después y
     pesa lo mismo. */
}

/* ---------- Pantallas muy anchas ----------
   Por encima de 1600 el contenido se queda en su columna de 1240 y el resto es
   margen. Se sube un punto: en un monitor de 27 pulgadas, 1240px de contenido
   centrado se lee como una app de móvil estirada. */
@media (min-width: 1600px) {
  :root { --ancho-max: 1440px; --canal: 40px; }
}
@media (min-width: 2000px) {
  :root { --ancho-max: 1600px; }
}


/* ==========================================================================
   32 · PREGUNTAR (la hoja de IA)
   ==========================================================================
   Una conversación dentro de un modal, y eso trae un problema que no tiene
   ningún otro formulario de la aplicación: el contenido CRECE mientras se usa.
   Si el hilo empujara la caja de texto hacia abajo, en un teléfono el botón de
   preguntar acabaría por debajo del borde justo cuando hace falta.

   Por eso el cuerpo es una columna con el hilo desplazándose por dentro
   (min-height: 0, que es lo que hace falta para que un hijo de flex pueda
   encogerse) y la caja anclada abajo. Medido en 640 de alto, que es donde
   aparece el fallo — no en un monitor grande.
   ========================================================================== */

.ia {
  display: flex;
  flex-direction: column;
  gap: var(--e-4);
  /* Alto FIJO, y contando con el MARCO.
   *
   * Dos cosas juntas. La primera: con `max-height` la hoja medía lo que midiera
   * su contenido —se abría pequeña, daba un salto al llegar la respuesta y
   * dejaba un hueco muerto abajo—, y una superficie de conversación tiene que
   * ser la misma antes y después de hablar.
   *
   * La segunda es la que se coló: decía `68vh` del CONTENIDO, y encima de ese
   * contenido hay una cabecera, el relleno del cuerpo y el margen del velo.
   * 0,68·alto + 162px se pasa de `alto` en cualquier portátil, así que el modal
   * salía por debajo del borde y aparecía una SEGUNDA barra de desplazamiento —
   * la del modal— además de la del hilo. Dos barras y la caja de texto medio
   * cortada.
   *
   * Restando el marco, la cuenta cierra sola: 162 + (alto − 208) = alto − 46.
   * Sobra siempre, mida lo que mida la pantalla. Los 560 son el tope de arriba,
   * para que en un monitor grande no se vuelva una columna de un metro, y el
   * `min-height` es el suelo: por debajo de eso ya no cabe una conversación y
   * quien manda es el modal, que rueda.
   *
   * `dvh` y no `vh` en la segunda línea: en un móvil la barra del navegador se
   * esconde al desplazar y `vh` cuenta la pantalla como si no estuviera. */
  height: min(560px, calc(100vh - 13rem));
  height: min(560px, calc(100dvh - 13rem));
  /* El suelo, bajo a propósito: 8rem.
     En un teléfono APAISADO la pantalla mide 360 y la cuenta da 152px para toda
     la hoja. Es poco, y aun así es lo correcto: con un suelo alto la hoja
     seguiría midiendo más que la pantalla y, como el cuerpo del modal ya no
     rueda, la caja de texto quedaría fuera y sin forma de llegar a ella.
     Apretado y alcanzable gana a cómodo e inalcanzable. */
  min-height: 8rem;
}

.ia__hilo {
  display: flex;
  flex-direction: column;
  gap: var(--e-4);
  overflow-y: auto;
  overscroll-behavior: contain;
  /* La pieza clave: un hijo de flex no se encoge por debajo de su contenido si
     no se le dice. Sin esto el hilo empuja la caja fuera del modal. */
  min-height: 0;
  flex: 1 1 auto;
  /* Sitio para la barra de desplazamiento, para que no se monte encima del
     texto cuando aparece. */
  padding-right: var(--e-2);
  scrollbar-width: thin;
}

/* La portada. Lo primero que se ve, y lo único que se ve mientras no se haya
   preguntado nada: centrada, porque una pantalla vacía con el texto pegado
   arriba parece una que se quedó a medio cargar. */
.ia__inicio {
  margin: auto 0;
  display: grid;
  gap: var(--e-3);
  justify-items: center;
  text-align: center;
  padding: var(--e-4) 0;
}
.ia__inicio-titulo {
  margin: 0;
  font-size: var(--t-tarjeta);
  font-weight: 800;
  letter-spacing: var(--track-bloque);
}
.ia__inicio-texto {
  margin: 0;
  max-width: 46ch;
  color: var(--txt-2);
}

/* Lo que se preguntó y lo que se contestó, distinguidos por posición y fondo —
   no solo por color: §9 dice que el color nunca va solo. */
.ia__mia {
  align-self: flex-end;
  max-width: 85%;
  padding: var(--e-2) var(--e-3);
  border-radius: var(--r-sm);
  background: var(--capa-2);
  border: 1px solid var(--linea);
}
.ia__mia p { margin: 0; }

.ia__suya {
  align-self: stretch;
  display: grid;
  gap: var(--e-3);
  padding: var(--e-4);
  border-radius: var(--r-md);
  background: var(--capa-1);
  border: 1px solid var(--linea);
}
.ia__suya--esperando { opacity: .7; }
/* El renglón, y su largo.
   La hoja es ancha a propósito —las cifras necesitan sitio— pero un párrafo de
   140 caracteres por línea se lee mal: al saltar de renglón se pierde el hilo y
   hay que volver a buscar dónde iba. Se topa el TEXTO, no la tarjeta: las
   fichas de cifras siguen usando todo el ancho. */
.ia__suya p { margin: 0; line-height: 1.55; max-width: 72ch; }

/* El resumen ES la respuesta; lo demás la sostiene. Va más grande que el resto
   del bloque para que se lea primero aunque debajo haya cifras. */
.ia__resumen {
  font-weight: 700;
  font-size: var(--t-tarjeta);
  line-height: 1.35;
}

.ia__bloque { display: grid; gap: 2px; }
.ia__bloque h4 {
  margin: var(--e-2) 0 0;
  font-size: var(--t-rotulo);
  font-weight: 700;
  letter-spacing: var(--track-rotulo);
  text-transform: var(--caja-rotulo);
  color: var(--txt-3);
}

/* Las cifras, en fichas. Sueltas en una fila se leían como parte del párrafo de
   al lado, y son lo que se viene a mirar. */
.ia__cifras {
  display: flex;
  flex-wrap: wrap;
  gap: var(--e-3);
  margin-top: var(--e-1);
}
.ia__cifra {
  display: grid;
  gap: 2px;
  padding: var(--e-2) var(--e-3);
  border-radius: var(--r-xs);
  background: var(--capa-2);
  min-width: 0;
}
.ia__cifra-rotulo {
  font-size: var(--t-rotulo);
  font-weight: 700;
  letter-spacing: var(--track-rotulo);
  text-transform: var(--caja-rotulo);
  color: var(--txt-3);
}
.ia__cifra strong {
  font-variant-numeric: tabular-nums;
  font-size: var(--t-cifra-media);
  letter-spacing: var(--track-bloque);
}

/* Una limitación no es un error: es parte de la respuesta, y cambia cómo se lee
   la cifra de al lado. Por eso va a la vista y no plegada. */
.ia__limitacion {
  font-size: var(--t-meta);
  color: var(--txt-3);
  padding-left: var(--e-3);
  border-left: 2px solid var(--linea);
}

.ia__fuentes > summary {
  cursor: pointer;
  /* Un objetivo táctil de verdad: un resumen de una línea mide 20px y se falla
     con el pulgar. */
  min-height: 44px;
  display: flex;
  align-items: center;
  font-size: var(--t-meta);
  color: var(--txt-3);
}
.ia__fuente {
  display: flex;
  justify-content: space-between;
  gap: var(--e-2);
  padding: var(--e-1) 0;
  font-size: var(--t-meta);
}
.ia__fuente-periodo { color: var(--txt-3); }

/* Las acciones, después de una línea: lo que se lee y lo que se hace son dos
   cosas, y sin la separación el botón parecía parte de la explicación. */
.ia__acciones {
  display: flex;
  flex-wrap: wrap;
  gap: var(--e-2);
  padding-top: var(--e-3);
  border-top: 1px solid var(--linea);
}

.ia__aviso {
  font-size: var(--t-micro);
  color: var(--txt-3);
  margin-top: var(--e-1) !important;
}

/* El texto del consentimiento, dentro del hilo. Se enseña ENTERO —qué sale y
   qué no— y no un resumen con un enlace: quien decide si sus cifras van a un
   tercero necesita leer qué va, y un enlace es una forma educada de que nadie
   lo lea. */
.ia__permiso {
  display: grid;
  gap: var(--e-2);
  padding: var(--e-3);
  border-radius: var(--r-sm);
  background: var(--capa-1);
  border: 1px solid var(--linea);
}
.ia__permiso h4 { margin: 0; font-size: var(--t-cuerpo); }
.ia__permiso p { margin: 0; }
.ia__permiso ul { margin: 0; padding-left: var(--e-4); }
.ia__permiso li { font-size: var(--t-meta); color: var(--txt-2); }
.ia__permiso-rotulo {
  font-size: var(--t-rotulo);
  font-weight: 700;
  letter-spacing: var(--track-rotulo);
  text-transform: var(--caja-rotulo);
  color: var(--txt-3);
}

/* Las sugerencias, en sus dos sitios. Es el mismo nodo movido —ver
   `colocarSugerencias()` en js/ia-hoja.js— y lo que cambia es el tamaño: en la
   portada EXPLICAN qué se puede preguntar, y encima de la caja solo ahorran
   escribir. */
.ia__sugerencias {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--e-2);
}
.ia__sugerencias-rotulo { font-size: var(--t-meta); color: var(--txt-3); }

/* En la portada: en columna y a lo ancho. Una fila de tres botones largos se
   parte en un teléfono y queda un escalón; en columna se leen como lo que son,
   una lista de lo que se puede preguntar. */
.ia__sugerencias[data-compacto="no"] {
  flex-direction: column;
  align-items: stretch;
  width: min(100%, 30rem);
  gap: var(--e-2);
}
.ia__sugerencias[data-compacto="no"] .ia__sugerencia {
  justify-content: flex-start;
  text-align: left;
  padding: var(--e-3);
  border-color: var(--linea);
  background: var(--capa-1);
}
.ia__sugerencias[data-compacto="no"] .ia__sugerencia:hover { background: var(--capa-2); }

/* Y en compacto, encima de la caja: fila que se desplaza si no cabe, nunca un
   bloque que empuje la caja hacia abajo. */
.ia__sugerencias[data-compacto="si"] {
  flex-wrap: nowrap;
  overflow-x: auto;
  scrollbar-width: none;
  /* Sin esto, un hijo de flex con hijos anchos no se encoge y desborda la hoja
     a lo ancho: el fallo más caro de esta aplicación. */
  min-width: 0;
}
.ia__sugerencias[data-compacto="si"]::-webkit-scrollbar { display: none; }
.ia__sugerencias[data-compacto="si"] .ia__sugerencia { flex: 0 0 auto; }
/* Y sin el «Por ejemplo:» ahí abajo: en la portada presenta la lista, pero
   encima de la caja ya no presenta nada —se ve que son preguntas— y en un
   teléfono se partía en dos renglones y se comía el ancho de la fila. */
.ia__sugerencias[data-compacto="si"] .ia__sugerencias-rotulo { display: none; }

/* UNA barra de desplazamiento, no dos.
   El cuerpo del modal rueda por omisión —y hace bien, para un formulario largo—
   pero aquí dentro ya hay algo que rueda: el hilo. Con los dos activos salían
   dos barras pegadas y el gesto de rueda movía una u otra según dónde estuviera
   el puntero. Se apaga por clase y no con `:has()`: hay WebViews antiguos donde
   `:has()` no existe y esto no puede depender de eso. */
.modal--conversacion .modal__body { overflow: hidden; }

/* Lo de abajo, que no se desplaza nunca. */
.ia__abajo {
  flex: 0 0 auto;
  display: grid;
  gap: var(--e-3);
  min-width: 0;
}

/* La caja y su botón, en UN recuadro.
   Eran dos cosas sueltas —un campo y un botón azul grande al lado— y entre las
   dos y el pie del modal quedaba un hueco muerto. Ahora es una sola pieza: se
   escribe arriba, y abajo van la cuota (a la izquierda, que es cuando se lee) y
   el botón. */
.ia__entrada {
  display: grid;
  gap: var(--e-2);
  padding: var(--e-3);
  border-radius: var(--r-md);
  border: 1px solid var(--linea);
  background: var(--capa-1);
  min-width: 0;
}
.ia__entrada:focus-within { border-color: var(--marca); }
.ia__caja {
  /* Sin esto, un hijo de rejilla con contenido largo no se encoge y desborda la
     hoja a lo ancho: el fallo más caro de esta aplicación. */
  min-width: 0;
  resize: none;
  font: inherit;
  /* Dos renglones, no los 92px del `textarea` de siempre.
     Una caja de cuatro renglones vacíos se come el sitio del hilo, que es lo que
     se vino a leer; y crece hasta seis cuando de verdad se escribe largo. */
  min-height: 2.8rem;
  max-height: 9rem;
  overflow-y: auto;
  /* Sin marco propio: el marco es el del recuadro que la contiene. */
  border: 0;
  background: transparent;
  color: var(--txt);
  padding: 0;
}
/* Al enfocar, el marco lo pone el RECUADRO, no la caja.
   `textarea:focus` (0,1,1) gana a `.ia__caja` (0,1,0), así que sin apagar aquí
   sus tres declaraciones salía un segundo recuadro dentro del primero: dos
   bordes y dos fondos para un solo campo. */
.ia__caja:hover,
.ia__caja:focus {
  outline: none;
  border-color: transparent;
  background: transparent;
  box-shadow: none;
}
.ia__entrada-pie {
  display: flex;
  align-items: center;
  justify-content: flex-end; /* el botón, solo, se queda a la derecha */
  gap: var(--e-3);
  min-width: 0;
}
.ia__pie { min-width: 0; }
.ia__cuota { font-size: var(--t-meta); color: var(--txt-3); }

/* Las barras de la espera. Del ancho de un renglón, no de una tarjeta: lo que
   se está esperando es texto. */
.ia__esqueleto { height: .7rem; border-radius: var(--r-xs); }
.ia__esqueleto--corto { width: 60%; }

/* «Lo que merece atención»: las recomendaciones, dentro de Inicio.
   No es un panel aparte y no lo va a ser: una pantalla de recomendaciones es una
   pantalla que hay que acordarse de visitar. */
.ia-atencion__fila {
  display: grid;
  gap: var(--e-2);
  padding: var(--e-3) 0;
  border-bottom: 1px solid var(--linea);
}
.ia-atencion__fila:last-of-type { border-bottom: 0; }
.ia-atencion__texto { display: grid; gap: var(--e-1); min-width: 0; }

/* El nivel, con PALABRA. §9: el color nunca va solo, y «alta» en un borde rojo
   es exactamente el color solo. El tono viene en data- para que la regla de
   color viva aquí y no en el JavaScript. */
.ia-atencion__nivel {
  justify-self: start;
  font-size: var(--t-micro);
  font-weight: 700;
  letter-spacing: var(--track-rotulo);
  text-transform: var(--caja-rotulo);
  padding: 2px var(--e-2);
  border-radius: var(--r-xs);
}
.ia-atencion__nivel[data-tono="mal"]  { color: var(--peligro-txt); background: var(--peligro-suave); }
.ia-atencion__nivel[data-tono="ojo"]  { color: var(--alerta-txt);     background: var(--alerta-suave); }
.ia-atencion__nivel[data-tono="info"] { color: var(--txt-3);       background: var(--capa-2); }

.ia-atencion__detalle { margin: 0; color: var(--txt-2); }
.ia-atencion__cifras {
  display: flex;
  flex-wrap: wrap;
  gap: var(--e-3);
  font-variant-numeric: tabular-nums;
}
.ia-atencion__cifra-rotulo { color: var(--txt-3); font-size: var(--t-meta); }

.ia-atencion__limite {
  margin: 0;
  font-size: var(--t-meta);
  color: var(--txt-3);
  padding-left: var(--e-3);
  border-left: 2px solid var(--linea);
}

.ia-atencion__acciones { display: flex; flex-wrap: wrap; gap: var(--e-2); }

.ia-atencion__fuentes > summary {
  cursor: pointer;
  /* Un objetivo táctil de verdad: un resumen de una línea mide 20px. */
  min-height: 44px;
  display: flex;
  align-items: center;
  font-size: var(--t-meta);
  color: var(--txt-3);
}
.ia-atencion__fuente {
  display: flex;
  justify-content: space-between;
  gap: var(--e-2);
  padding: 2px 0;
  font-size: var(--t-meta);
}

/* De cuándo son los datos. Una recomendación sin fecha se lee como si fuera de
   ahora mismo, y puede ser de hace tres días. */
.ia-atencion__pie {
  margin: var(--e-2) 0 0;
  font-size: var(--t-micro);
  color: var(--txt-3);
}

/* Un aviso que notó la IA, dentro de la MISMA campana que los que calcula la
   aplicación. Se distinguen porque no se atienden igual: los locales se
   recalculan solos en cuanto se arregla lo que los provocó, y estos hay que
   marcarlos uno a uno.

   Una raya al costado, y además la frase «OBI lo notó revisando tus cuentas»
   debajo del título: §9 dice que el color nunca va solo, y aquí la raya sola
   sería justo eso. */
.aviso-fila--ia {
  border-left: 2px solid var(--marca);
  padding-left: var(--e-2);
}

/* La línea que ofrece preguntar, dentro de una pantalla. Una línea y no una
   tarjeta: preguntar se hace MIRANDO otra cosa, y un bloque grande empujaría
   hacia abajo lo que se vino a ver. */
.ia-linea {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--e-3);
  flex-wrap: wrap;
  padding: var(--e-2) var(--e-3);
  border-radius: var(--r-sm);
  background: var(--capa-1);
  border: 1px solid var(--linea);
}
.ia-linea__texto { color: var(--txt-2); min-width: 0; }

/* ── Lo que OBI ha aprendido, en Configuración ──
 *
 * Una lista, no una tabla: son frases de largo desigual y una tabla las cortaría
 * en la primera columna estrecha. Cada fila lleva su texto y sus dos botones, y
 * en móvil los botones bajan — que es lo que tiene que pasar cuando el texto es
 * lo importante y la acción es lo secundario. */
.memoria { display: grid; gap: var(--e-3); }
.memoria__fila {
  display: flex;
  flex-wrap: wrap;
  align-items: start;
  justify-content: space-between;
  gap: var(--e-3);
  padding-bottom: var(--e-3);
  border-bottom: 1px solid var(--linea);
}
.memoria__fila:last-of-type { border-bottom: 0; padding-bottom: 0; }
/* `min-width: 0` porque este es hijo de un flex y su frase puede ser larga: sin
   esto se niega a encogerse y empuja la tarjeta fuera de la pantalla, que es el
   desbordamiento horizontal de siempre. */
.memoria__texto { display: grid; gap: var(--e-1); min-width: 0; flex: 1 1 16rem; }
.memoria__tipo {
  justify-self: start;
  padding: 2px var(--e-2);
  border-radius: 999px;
  background: var(--capa-2);
  color: var(--txt-3);
  font-size: var(--t-micro);
  text-transform: var(--caja-rotulo);
  letter-spacing: .04em;
}
.memoria__frase { margin: 0; color: var(--txt); overflow-wrap: anywhere; }
.memoria__pista { margin: 0; color: var(--txt-3); font-size: var(--t-meta); }
/* En pausa lleva color Y palabras (§9): la diferencia entre pausada y borrada es
   justo la que se confunde, y un tono apagado no la explica. */
.memoria__pausa { margin: 0; color: var(--alerta-txt); font-size: var(--t-meta); }
.memoria__acciones { display: flex; flex-wrap: wrap; gap: var(--e-2); }
.memoria__pie { display: flex; justify-content: flex-start; }

/* ── Apuntar hablando ──
 *
 * La misma familia que la hoja de preguntar, pero esta NO es una conversación:
 * es un formulario de una sola frase. Así que no tiene hilo, no tiene alto fijo
 * y crece con lo que haya que enseñar — que como mucho son cinco líneas.
 */
.captura { display: grid; gap: var(--e-4); min-width: 0; }
.captura__intro { margin: 0; color: var(--txt-2); max-width: 60ch; }

.captura__entrada {
  display: flex;
  gap: var(--e-2);
  align-items: flex-end;
  min-width: 0;
}
.captura__caja {
  flex: 1 1 auto;
  /* Sin esto, un hijo de flex con contenido largo no se encoge y desborda la
     hoja a lo ancho: el fallo más caro de esta aplicación. */
  min-width: 0;
  resize: none;
  font: inherit;
  min-height: 2.8rem;
}
.captura__ejemplos {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--e-2);
}
.captura__ejemplos-rotulo { font-size: var(--t-meta); color: var(--txt-3); }

.captura__estado { display: grid; gap: var(--e-3); min-width: 0; }

/* Cuando de una frase salen varios: uno por fila, y cada uno con su botón. No
   hay «guardar todos» a propósito — apuntar rápido es bueno; apuntar mal y
   rápido, no. */
.captura__fila {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--e-3);
  padding: var(--e-3);
  border-radius: var(--r-sm);
  background: var(--capa-1);
  border: 1px solid var(--linea);
}
.captura__texto { display: grid; gap: 2px; min-width: 0; flex: 1 1 14rem; }
.captura__pista { margin: 0; color: var(--txt-3); font-size: var(--t-meta); }

/* Una fila a la que le falta el importe. Ámbar y CON PALABRAS —«Falta el
   importe» está escrito en la propia fila—: §9, el color nunca va solo. */
.captura__fila[data-falta="monto"] {
  border-color: var(--alerta);
  background: var(--alerta-suave);
}

/* ══════════════════════ La página principal: piezas nuevas ══════════════════════ */

/* ── Las tarjetas de plan ── */
.inicio__plan-quien {
  margin: var(--e-2) 0 0;
  color: var(--txt-2);
  font-size: var(--t-meta);
}
.inicio__plan-falta {
  margin: var(--e-3) 0 0;
  padding-top: var(--e-3);
  border-top: 1px solid var(--linea);
  font-size: var(--t-meta);
  color: var(--txt-3);
}

/* ── La tabla de comparación ──
 *
 * La caja rueda a lo ancho y la tabla NO se encoge: cinco columnas en 360px o se
 * desplazan o se leen a cuatro caracteres por línea. Lo que no puede pasar —y es
 * el fallo de maquetación más caro de esta aplicación— es que la tabla empuje la
 * página entera: por eso el desplazamiento vive aquí dentro. */
.inicio__tabla-caja {
  overflow-x: auto;
  overscroll-behavior-x: contain;
  border-radius: var(--r-lg);
  border: 1px solid var(--linea);
  background: var(--capa-1);
  /* Sin esto, un hijo de rejilla con una tabla ancha dentro no se encoge. */
  min-width: 0;
  max-width: 100%;
}
.inicio__tabla {
  width: 100%;
  min-width: 44rem;
  border-collapse: collapse;
  font-size: var(--t-secundario);
}
.inicio__tabla th,
.inicio__tabla td {
  padding: var(--e-3) var(--e-4);
  text-align: left;
  border-bottom: 1px solid var(--linea);
  vertical-align: top;
}
.inicio__tabla tbody tr:last-child th,
.inicio__tabla tbody tr:last-child td { border-bottom: 0; }
.inicio__tabla thead th {
  position: sticky;
  top: 0;
  background: var(--capa-2);
  border-bottom: 1px solid var(--linea-fuerte);
}
.inicio__tabla tbody th {
  font-weight: 600;
  color: var(--txt);
  display: grid;
  gap: 2px;
}
.inicio__tabla-pie { font-size: var(--t-meta); color: var(--txt-3); font-weight: 400; }
.inicio__tabla-plan { display: block; font-weight: 800; }
.inicio__tabla-precio { display: block; font-size: var(--t-meta); color: var(--txt-3); font-weight: 400; }
.inicio__tabla td { color: var(--txt-2); font-variant-numeric: tabular-nums; }
/* El sí y el no llevan PALABRA además de color (§9). */
.inicio__si { color: var(--ok-txt); }
.inicio__no { color: var(--txt-3); }
.inicio__tabla-nota {
  margin: var(--e-4) 0 0;
  font-size: var(--t-meta);
  color: var(--txt-3);
  max-width: 70ch;
}

/* ── Cuánta IA llevas gastada ──
 *
 * Un anillo y tres barras. El anillo dice cómo se va de un vistazo; las barras
 * dicen de qué —y van siempre, porque el porcentaje junta tres topes que no
 * cuestan lo mismo y sin el desglose sería una media verdad. */
.ia-uso__cuerpo { display: grid; gap: var(--e-4); min-width: 0; }
.ia-uso__resumen {
  display: flex;
  align-items: center;
  gap: var(--e-4);
  min-width: 0;
}
/* 7rem y no 15: con 15 el bloque se partía en un teléfono y el aro se quedaba
   solo, con medio ancho vacío al lado. Dos líneas de texto caben en 7. */
.ia-uso__lado { flex: 1 1 7rem; min-width: 0; display: grid; gap: var(--e-1); }
.ia-uso__frase { margin: 0; font-weight: 700; font-size: var(--t-tarjeta); }
.ia-uso__total { margin: 0; color: var(--txt-3); font-size: var(--t-meta); }

.ia-uso__barras { display: grid; gap: var(--e-3); }
.ia-uso__linea { display: grid; gap: 4px; min-width: 0; }
.ia-uso__linea-alto {
  display: flex;
  justify-content: space-between;
  gap: var(--e-3);
  font-size: var(--t-meta);
  min-width: 0;
}
.ia-uso__linea-nombre { color: var(--txt-2); min-width: 0; }
.ia-uso__linea-cifra { color: var(--txt-3); font-variant-numeric: tabular-nums; white-space: nowrap; }
.ia-uso__barra {
  height: 6px;
  border-radius: var(--r-full);
  background: var(--capa-2);
  overflow: hidden;
}
.ia-uso__parte {
  display: block;
  height: 100%;
  border-radius: var(--r-full);
  background: var(--ok);
  /* `transform` y no `width`: la anchura repinta la caja y esto se anima en cada
     pintado de la tarjeta. Ojo con la ficha —ver aplicarEstilo en js/ui.js—: una
     personalizada solo entra con setProperty. */
  transform-origin: left center;
  transform: scaleX(var(--parte, 0));
  transition: transform var(--medio, .3s) var(--curva, ease);
}
.ia-uso__barra[data-tono="ojo"] .ia-uso__parte { background: var(--alerta); }
.ia-uso__barra[data-tono="mal"] .ia-uso__parte { background: var(--peligro); }
.ia-uso__barra[data-tono="info"] .ia-uso__parte { background: var(--txt-3); }

/* Y el pie de la hoja de preguntar: el porcentaje se pliega y enseña la tarjeta. */
.ia__uso > summary { cursor: pointer; list-style: none; }
.ia__uso > summary::-webkit-details-marker { display: none; }
.ia__uso[open] > summary { margin-bottom: var(--e-4); }
.ia__uso-detalle .card { margin: 0; }

/* ══════════════════════ El panel: equipo y planes ══════════════════════
 *
 * Dos pantallas que reparten poder —quién puede qué, y qué incluye lo que la
 * gente paga— y las dos tienen el mismo problema de fondo: son listas largas de
 * cosas parecidas donde una equivocación cuesta cara. Todo lo de aquí existe
 * para que no se lea como una lista.
 */

/* ── Los roles ──
 *
 * Tarjetas y no filas de una tabla: cada rol se lee entero de un vistazo —qué
 * es, qué deja hacer, cuánta gente lo tiene— y eso en una fila no cabe. */
.staff-roles {
  display: grid;
  gap: var(--e-4);
  grid-template-columns: repeat(auto-fit, minmax(min(17rem, 100%), 1fr));
}
.staff-rol {
  display: grid;
  gap: var(--e-2);
  align-content: start;
  padding: var(--e-4);
  border: 1px solid var(--linea);
  border-radius: var(--r-lg);
  background: var(--capa-1);
  min-width: 0;
}
.staff-rol__alto { display: flex; justify-content: space-between; gap: var(--e-3); align-items: start; }
.staff-rol h3 { margin: 0; font-size: var(--t-tarjeta); }
.staff-rol code { font-size: var(--t-meta); }
.staff-rol p { margin: 0; color: var(--txt-2); font-size: var(--t-secundario); }
.staff-rol__cuenta { color: var(--txt-3) !important; font-size: var(--t-meta) !important; }
.staff-rol__lista {
  margin: 0;
  padding-left: var(--e-4);
  display: grid;
  gap: 2px;
  color: var(--txt-2);
  font-size: var(--t-meta);
}

/* ── Las casillas de permiso ──
 *
 * Agrupadas por sección, que es como se reparte de verdad: «esta persona lleva
 * el soporte» y no «puede hacer estas nueve cosas». */
.staff-sec {
  margin: 0;
  padding: var(--e-3) var(--e-4) var(--e-4);
  border: 1px solid var(--linea);
  border-radius: var(--r-md);
  background: var(--capa-1);
}
.staff-sec legend {
  padding: 0 var(--e-2);
  color: var(--txt-3);
  font-size: var(--t-meta);
  font-weight: 700;
  text-transform: var(--caja-rotulo);
  letter-spacing: .1em;
}
.staff-permiso {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: var(--e-3);
  align-items: start;
  padding: var(--e-2) 0;
  cursor: pointer;
}
.staff-permiso > span { display: grid; gap: 1px; min-width: 0; }
.staff-permiso strong { font-size: var(--t-secundario); }
.staff-permiso .muted { font-size: var(--t-meta); }
/* Lo que no se puede dar. Apagado Y DICHO (§9: el color nunca va solo): una
   casilla gris sin explicación se lee como un fallo de la pantalla. */
.staff-permiso--no { cursor: not-allowed; opacity: .55; }
.staff-permiso__veto {
  color: var(--alerta);
  font-size: var(--t-meta);
  font-weight: 600;
}

/* ── Los planes ── */
.plan-ed__cols {
  display: grid;
  gap: var(--e-4);
  grid-template-columns: repeat(auto-fit, minmax(min(15rem, 100%), 1fr));
}
.plan-ed__sub {
  margin: 0 0 var(--e-2);
  color: var(--txt-3);
  font-size: var(--t-meta);
  text-transform: var(--caja-rotulo);
  letter-spacing: .1em;
}
.plan-ed__lista { margin: 0; padding: 0; list-style: none; display: grid; }
.plan-ed__lista li {
  display: flex;
  justify-content: space-between;
  gap: var(--e-3);
  padding: 5px 0;
  border-bottom: 1px solid var(--linea);
  font-size: var(--t-secundario);
  min-width: 0;
}
.plan-ed__lista li:last-child { border-bottom: 0; }
.plan-ed__lista strong { white-space: nowrap; font-variant-numeric: tabular-nums; }
/* Lo que el plan no trae, apagado. Con la palabra al lado —«— No»— y no solo
   con el tono: es la misma regla que en la tabla de la portada. */
.plan-ed__no { color: var(--txt-3); }
/* Un plan apagado se ve apagado, y además lo dice su etiqueta. */
.plan-ed--apagado { opacity: .7; }

/* Los campos del formulario de plan. El nombre grande, la clave pequeña y la
   explicación debajo: sin la explicación, nadie cambia un número cuyo efecto
   tiene que adivinar. */
.plan-campo {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 8rem;
  gap: var(--e-3);
  align-items: center;
  padding: var(--e-2) 0;
  border-bottom: 1px solid var(--linea);
}
.plan-campo:last-child { border-bottom: 0; }
.plan-campo > span { display: grid; gap: 1px; min-width: 0; }
.plan-campo strong { font-size: var(--t-secundario); }
.plan-campo code { font-size: var(--t-meta); }
.plan-campo .muted { font-size: var(--t-meta); }
/* Una función que ningún código mira. En ámbar y CON PALABRAS: marcarla
   creyendo que se vendió algo es el error caro de esta pantalla. */
.plan-campo__huerfana { color: var(--alerta); font-size: var(--t-meta); font-weight: 600; }
/* La de casilla va al revés: la casilla primero. */
.plan-campo--si { grid-template-columns: auto minmax(0, 1fr); }
.plan-check { display: flex; align-items: center; gap: var(--e-2); font-size: var(--t-secundario); }

.plan-grupo {
  margin: 0;
  padding: var(--e-3) var(--e-4) var(--e-4);
  border: 1px solid var(--linea);
  border-radius: var(--r-md);
  background: var(--capa-1);
}
.plan-grupo legend {
  padding: 0 var(--e-2);
  color: var(--txt-3);
  font-size: var(--t-meta);
  font-weight: 700;
  text-transform: var(--caja-rotulo);
  letter-spacing: .1em;
}

/* ── El diccionario ── */
.plan-dic { margin: 0; padding: 0; list-style: none; display: grid; }
.plan-dic__fila {
  display: flex;
  justify-content: space-between;
  align-items: start;
  gap: var(--e-4);
  padding: var(--e-3) 0;
  border-bottom: 1px solid var(--linea);
  min-width: 0;
  flex-wrap: wrap;
}
.plan-dic__fila:last-child { border-bottom: 0; }
.plan-dic__fila > div:first-child { min-width: 0; flex: 1 1 16rem; }
.plan-dic__fila code { margin-left: var(--e-2); font-size: var(--t-meta); }
.plan-dic__fila p { margin: 2px 0 0; color: var(--txt-3); font-size: var(--t-meta); }

/* Dos líneas apretadas dentro de una celda: el nombre y el correo, el rol y
   quién lo puso. Un `gap` de tarjeta ahí dentro parte la fila en dos. */
.stack-xs { display: grid; gap: 1px; min-width: 0; }

/* Dos columnas donde quepan. En un teléfono, una: dos campos de plan a 180px
   dejan el número más estrecho que el rótulo. */
.grid-2 { display: grid; gap: var(--e-3); grid-template-columns: minmax(0, 1fr); }
@media (min-width: 560px) {
  .grid-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* Los dos botones de una fila del equipo, en línea. Apilados parecían dos
   acciones de distinta importancia, y son la misma fila. */
.staff-acciones { display: flex; gap: 6px; flex-wrap: nowrap; }
.staff-acciones .btn { white-space: nowrap; }

/* ══════════════ El panel: cabecera, listas, formularios y conversación ══════════════ */

/* Trece secciones no caben en una fila de teléfono. Se envuelven en varias
   líneas: una fila que se desplaza a lo ancho esconde justo las secciones del
   final, que son las que menos se visitan y más cuesta encontrar. */
.adm-cabeza { display: grid; gap: var(--e-3); min-width: 0; }
.adm-pestanas { display: flex; flex-wrap: wrap; gap: var(--e-1); min-width: 0; }
.adm-pestanas .btn { white-space: nowrap; }

/* La ventana de administración: cuánto queda y las dos salidas. Es una nota y
   no un aviso, así que va en tinta secundaria; el último minuto pasa a ámbar
   —«corre»— y el texto lo dice con palabras, que el color nunca va solo. */
.adm-ventana {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--e-2);
  color: var(--txt-2);
  font-size: var(--t-meta);
  min-width: 0;
}
.adm-ventana__punto {
  width: 8px;
  height: 8px;
  flex: none;
  border-radius: var(--r-full);
  background: var(--ok);
}
.adm-ventana__texto { flex: 1 1 14rem; min-width: 0; }
.adm-ventana__acciones { display: flex; flex-wrap: wrap; gap: var(--e-1); }
.adm-ventana--acaba { color: var(--alerta-txt); }
/* El aviso de que falta el segundo factor ocupa su propia línea dentro de la
   cabecera: al lado del texto no cabe en un teléfono. */
.adm-ventana__aviso { flex: 1 1 100%; min-width: 0; }
.adm-ventana--acaba .adm-ventana__punto { background: var(--alerta); }

/* Buscador y filtros de una lista, en una fila que se envuelve. El buscador
   crece; los desplegables se quedan a su ancho y nunca más anchos que la
   pantalla. */
.adm-herramientas {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--e-2);
  margin-bottom: var(--e-4);
  min-width: 0;
}
.adm-herramientas input[type="search"] { flex: 1 1 14rem; min-width: 0; }
.adm-herramientas select { flex: 0 1 auto; min-width: 0; max-width: 100%; }

/* Una línea de etiquetas y botones pequeños que se envuelve. */
.adm-atajos { display: flex; flex-wrap: wrap; align-items: center; gap: var(--e-2); min-width: 0; }

/* El pie de una lista: cuántas se ven y el botón para ver más. */
.adm-pie-lista {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--e-3);
  margin-top: var(--e-3);
}

/* Lo que pide atención: una fila por cosa, con su número delante y su salto
   detrás. Hundida sobre la tarjeta y no separada por rayas: profundidad, no
   reglas. */
.adm-atencion { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--e-2); }
.adm-atencion li {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--e-3);
  padding: var(--e-2) var(--e-3);
  border-radius: var(--r-sm);
  background: var(--bg-2);
  min-width: 0;
}

.adm-error:empty { display: none; }
.adm-nota { display: block; margin-top: var(--e-3); }
.adm-tachado { text-decoration: line-through; }

/* El antes y el después del registro: JSON legible, que se desplaza DENTRO de
   su caja. Suelto, una línea larga empujaba el modal entero a lo ancho. */
.adm-json {
  margin: 0;
  padding: var(--e-3);
  border-radius: var(--r-sm);
  background: var(--bg-2);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: var(--t-meta);
  white-space: pre;
  overflow: auto;
  max-height: 40vh;
  min-width: 0;
}

/* Responder un ticket. Con «nota interna» marcada cambia la caja además del
   botón: una nota que parece una respuesta acaba enviándose como tal. */
.adm-responder__pie {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--e-2);
}
.adm-check {
  display: inline-flex;
  align-items: center;
  gap: var(--e-2);
  min-height: var(--tactil);
  font-size: var(--t-meta);
}
.adm-responder--nota textarea { border-style: dashed; border-color: var(--linea-fuerte); }

/* El alta del segundo factor: tres pasos numerados, la clave para teclear y los
   códigos de recuperación en una rejilla que se lee de un vistazo y se copia a
   un papel sin saltarse ninguno. */
.adm-pasos { margin: 0; padding-left: 1.2rem; display: grid; gap: var(--e-3); }
.adm-pasos li { display: grid; gap: var(--e-2); min-width: 0; }
.adm-clave { display: flex; flex-wrap: wrap; align-items: center; gap: var(--e-2); min-width: 0; }
.adm-clave code,
.adm-codigos code {
  padding: var(--e-2) var(--e-3);
  border-radius: var(--r-sm);
  background: var(--bg-2);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: var(--t-cuerpo);
  letter-spacing: .06em;
  overflow-wrap: anywhere;
  min-width: 0;
}
.adm-codigo { max-width: 12rem; font-variant-numeric: tabular-nums; letter-spacing: .12em; }
.adm-codigos {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: var(--e-2);
  grid-template-columns: repeat(auto-fill, minmax(min(9rem, 100%), 1fr));
}
.adm-codigos code { display: block; text-align: center; }

/* Y ninguna etiqueta se parte: «Suspendid / a» no se lee como un estado, se lee
   como un fallo de dibujo. */
.staff-rol .pill,
.plan-ed .pill,
.staff-acciones + * .pill,
.table-scroll .pill { white-space: nowrap; }

/* ══════════════════════ El panel: analíticas y precios ══════════════════════ */

/* Las cifras grandes. Cuatro, y las dos del medio son las que se confunden
   —caja y devengado— así que van juntas y con su pie explicándolas. */
.an-cifras {
  display: grid;
  gap: var(--e-3);
  grid-template-columns: repeat(auto-fit, minmax(min(11rem, 100%), 1fr));
}
.an-cifra {
  display: grid;
  gap: 2px;
  align-content: start;
  padding: var(--e-4);
  border: 1px solid var(--linea);
  border-radius: var(--r-md);
  background: var(--capa-1);
  min-width: 0;
}
/* La del MRR lleva el acento: es la única de las cuatro que contesta «¿cómo va
   el negocio?», y las otras tres se leen en función de ella. */
.an-cifra--marca {
  border-color: color-mix(in srgb, var(--marca) 35%, transparent);
  background: color-mix(in srgb, var(--marca) 10%, var(--capa-1));
}
.an-cifra__rotulo {
  color: var(--txt-3);
  font-size: var(--t-meta);
  text-transform: var(--caja-rotulo);
  letter-spacing: .08em;
}
.an-cifra__n { font-size: var(--t-cifra-media); font-variant-numeric: tabular-nums; }
.an-cifra__pie { color: var(--txt-3); font-size: var(--t-meta); line-height: 1.35; }

/* Un número que se puede abrir. Se pinta como un enlace y no como un botón:
   lleva a otra lista, no hace nada. */
.an-enlace {
  background: none;
  border: 0;
  /* Con el alto de un dedo. Sin esto son 20px: la auditoría lo cazó, y un
     objetivo de 20px en un teléfono se falla una de cada tres veces — y aquí
     fallar significa no abrir la lista que se venía a ver. El relleno va a los
     lados y arriba para no ensanchar la fila de la tabla. */
  min-height: var(--tactil);
  padding: 0 var(--e-2);
  color: var(--marca);
  font: inherit;
  font-variant-numeric: tabular-nums;
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 3px;
}
.an-enlace:focus-visible { outline: 2px solid var(--marca); outline-offset: 2px; }

/* Mes a mes. Dos barras por mes —lo que entró y lo que se ganó— porque son las
   dos cifras que hay que poder comparar de un vistazo, y en dos gráficos
   separados el ojo no las cruza. */
.an-grafico {
  display: flex;
  align-items: flex-end;
  gap: var(--e-2);
  overflow-x: auto;
  overscroll-behavior-x: contain;
  padding: var(--e-3) 0;
  min-width: 0;
}
.an-mes { display: grid; gap: 4px; justify-items: center; flex: 1 0 2.5rem; min-width: 0; }
.an-mes__barras { display: flex; align-items: flex-end; gap: 2px; height: 120px; }
.an-mes__barra {
  display: block;
  width: 10px;
  height: var(--alto, 0%);
  min-height: 2px;
  border-radius: var(--r-xs) var(--r-xs) 0 0;
  transition: height var(--medio, .3s) var(--curva, ease);
}
/* Llena = caja. Hueca = devengado. La diferencia se ve sin leyenda, y la
   leyenda está igual: el color nunca va solo. */
.an-mes__barra--caja { background: var(--marca); }
.an-mes__barra--dev {
  background: color-mix(in srgb, var(--marca) 22%, transparent);
  border: 1px solid color-mix(in srgb, var(--marca) 55%, transparent);
}
.an-mes__rotulo { color: var(--txt-3); font-size: var(--t-nano); white-space: nowrap; }
.an-mes__pie { color: var(--txt-3); font-size: var(--t-nano); white-space: nowrap; }

/* ── Los precios ── */
.precio-linea {
  display: flex;
  align-items: center;
  gap: var(--e-3);
  flex-wrap: wrap;
  padding: var(--e-3) 0;
  border-bottom: 1px solid var(--linea);
  min-width: 0;
}
.precio-linea:last-of-type { border-bottom: 0; }
.precio-linea > div:first-child { flex: 1 1 14rem; min-width: 0; display: grid; gap: 1px; }
.precio-linea__ciclo {
  color: var(--txt-3);
  font-size: var(--t-meta);
  text-transform: var(--caja-rotulo);
  letter-spacing: .08em;
}
.precio-linea__n { font-size: var(--t-cifra-media); font-variant-numeric: tabular-nums; }
/* Sin precio no se puede contratar, y eso se dice en ámbar: un hueco vacío se
   lee como «gratis». */
.precio-linea__vacio { color: var(--alerta); font-weight: 700; }
.precio-linea .muted { font-size: var(--t-meta); }
.precio-linea__futuro { display: flex; align-items: center; gap: var(--e-2); flex-wrap: wrap; }

.precio-hist { margin-top: var(--e-3); }
.precio-hist > summary {
  cursor: pointer;
  color: var(--txt-3);
  font-size: var(--t-meta);
  padding: var(--e-2) 0;
}
.precio-aviso:empty { display: none; }

/* Un aviso de la plataforma —«tu plan sube el 1 de diciembre»—.
 *
 * Se ve distinto de los demás a propósito: los otros salen de mirar TUS
 * cuentas y este viene de fuera. Y su texto es más largo que el de una
 * recomendación, porque tiene que decir el precio de antes, el de después y
 * desde cuándo: recortarlo obligaría a escribir para preguntar la cifra. */
.aviso-fila--plataforma {
  border-left: 3px solid var(--marca);
  background: color-mix(in srgb, var(--marca) 8%, transparent);
}
.aviso-fila--plataforma .aviso-fila__ir { align-items: flex-start; }
.aviso-fila--plataforma .muted {
  /* Sin recortar a una línea: aquí el detalle ES el aviso. */
  white-space: normal;
  line-height: 1.45;
}

/* El código de un descuento. En monoespaciada y con caja: se dicta por
   teléfono y se teclea, así que la O y el 0 tienen que distinguirse. */
.promo-codigo {
  display: inline-block;
  padding: 1px var(--e-2);
  border-radius: var(--r-xs);
  background: var(--capa-2);
  font-size: var(--t-meta);
  letter-spacing: .04em;
}
.promo-planes { display: flex; flex-wrap: wrap; gap: var(--e-3); }
.promo-plan {
  display: flex;
  align-items: center;
  gap: var(--e-2);
  font-size: var(--t-secundario);
  cursor: pointer;
}

/* De dónde sale el tope cuando se compró cupo aparte. Pequeño y apagado: es
   una aclaración, no un dato que haya que mirar cada vez. */
.ia-uso__linea-fuente {
  color: var(--txt-3);
  font-size: var(--t-nano);
}

/* La proyección. Tres líneas, cada una con su barra: comparadas de un vistazo
   es lo único que las hace útiles — una sola cifra a doce meses se lee como una
   promesa. */
.proy-linea {
  display: grid;
  gap: 4px;
  padding: var(--e-3) 0;
  border-bottom: 1px solid var(--linea);
  min-width: 0;
}
.proy-linea:last-of-type { border-bottom: 0; }
.proy-linea__alto {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--e-3);
  flex-wrap: wrap;
  min-width: 0;
}
.proy-linea__alto > div:first-child { display: grid; gap: 1px; min-width: 0; }
.proy-linea__alto .muted { font-size: var(--t-meta); }
.proy-linea__cifras {
  display: flex;
  align-items: baseline;
  gap: var(--e-2);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.proy-linea__cifras .muted { font-size: var(--t-meta); }
.proy-barra {
  height: 6px;
  border-radius: var(--r-full);
  background: var(--capa-2);
  overflow: hidden;
}
.proy-barra__parte {
  display: block;
  height: 100%;
  border-radius: var(--r-full);
  background: var(--marca);
  transform-origin: left center;
  transform: scaleX(var(--parte, 0));
  transition: transform var(--medio, .3s) var(--curva, ease);
}

/* Lo que escribió la IA. Marcado como suyo: quien lo lea tiene que saber que
   esas frases no las calculó la aplicación. */
.proy-texto {
  margin-top: var(--e-3);
  padding: var(--e-3);
  border-left: 3px solid var(--marca);
  border-radius: 0 var(--r-md) var(--r-md) 0;
  background: color-mix(in srgb, var(--marca) 8%, transparent);
}
.proy-texto p { margin: 4px 0 0; color: var(--txt-2); font-size: var(--t-secundario); }

/* Lo que la proyección NO sabe. Va con ella y no en una nota al pie. */
.proy-limites {
  margin: var(--e-3) 0 0;
  padding-left: var(--e-4);
  display: grid;
  gap: 2px;
  color: var(--txt-3);
  font-size: var(--t-meta);
}

/* La ficha de una cuenta en Cobros: lo cobrado y el historial de planes. */
.cob-sub {
  margin: var(--e-4) 0 var(--e-2);
  color: var(--txt-3);
  font-size: var(--t-meta);
  text-transform: var(--caja-rotulo);
  letter-spacing: .1em;
}
.cob-hist { margin-top: var(--e-3); }
.cob-hist > summary {
  cursor: pointer;
  color: var(--txt-3);
  font-size: var(--t-meta);
  padding: var(--e-2) 0;
}
/* Lo que va a costar un cambio de plan, dentro del formulario. Vacío no ocupa:
   sin cambiar nada no hay nada que decir, y un hueco reservado se lee como que
   falta algo por cargar. */
.cob-cuenta:empty { display: none; }

/* ══════════════════════ Tu suscripción ══════════════════════
 *
 * La cifra y la fecha arriba, grandes: es lo que se viene a mirar. Todo lo
 * demás —el descuento, la subida que viene, los recibos— son respuestas a
 * preguntas que se hacen después. */
.mi-sus__alto {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--e-4);
  flex-wrap: wrap;
  padding: var(--e-2) 0 var(--e-3);
  min-width: 0;
}
.mi-sus__cifra { font-size: var(--t-cifra-media); font-variant-numeric: tabular-nums; }
.mi-sus__cuando {
  display: flex;
  align-items: baseline;
  gap: 6px;
  flex-wrap: wrap;
  font-size: var(--t-secundario);
  min-width: 0;
}
.mi-sus__cuando .muted { font-size: var(--t-secundario); }

/* Las notas: el descuento, la subida, los complementos. Una línea cada una y
   con lo importante en negrita — se leen de reojo. */
.mi-sus__nota {
  margin: 0 0 var(--e-2);
  font-size: var(--t-secundario);
  color: var(--txt-2);
  line-height: 1.45;
}
/* La subida que viene lleva borde: es la única de las tres que pide una
   decisión, y sin marca se lee como una más. */
.mi-sus__nota--ojo {
  padding: var(--e-3);
  border-left: 3px solid var(--alerta);
  border-radius: 0 var(--r-md) var(--r-md) 0;
  background: color-mix(in srgb, var(--alerta) 8%, transparent);
}

.mi-sus__recibos { margin-top: var(--e-3); }
.mi-sus__recibos > summary {
  cursor: pointer;
  color: var(--txt-3);
  font-size: var(--t-meta);
  padding: var(--e-2) 0;
}
.mi-sus__lista { display: grid; }
.mi-sus__recibo {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--e-3);
  padding: var(--e-2) 0;
  border-bottom: 1px solid var(--linea);
  flex-wrap: wrap;
  min-width: 0;
}
.mi-sus__recibo:last-child { border-bottom: 0; }
.mi-sus__recibo > div:first-child { display: grid; gap: 1px; min-width: 0; }
.mi-sus__recibo .muted { font-size: var(--t-meta); }
.mi-sus__importe {
  display: flex;
  align-items: baseline;
  gap: var(--e-2);
  flex-wrap: wrap;
  font-variant-numeric: tabular-nums;
}
/* Una devolución, tachada Y con su etiqueta: un importe distinto sin
   explicación se lee como un error de la aplicación. */
.mi-sus__devuelto { text-decoration: line-through; color: var(--txt-3); }

/* Cancelar no se esconde, pero tampoco compite con nada: botón fantasma,
   abajo. Esconderlo es una fricción que solo retiene a quien ya decidió irse
   —y eso vuelve como una reclamación al banco—. */
.mi-sus__pie {
  display: flex;
  justify-content: flex-end;
  padding-top: var(--e-3);
}
/* Con los dos botones —cambiar y cancelar— se separan a los extremos, y en
   un teléfono se apilan: dos botones a la mitad del ancho parten sus textos
   en tres líneas cada uno. */
.mi-sus__pie--dos {
  justify-content: space-between;
  gap: var(--e-2);
  flex-wrap: wrap;
}
@media (max-width: 420px) {
  .mi-sus__pie--dos { flex-direction: column-reverse; align-items: stretch; }
}

/* El cambio ya pedido. Verde y no ámbar: no hay nada que arreglar, es una
   confirmación — y el ámbar de al lado (la subida de precio) dejaría de
   distinguirse si esto también lo llevara. Ver DESIGN.md §9: lleva texto
   además del tono. */
.mi-sus__nota--hecho {
  padding: var(--e-3);
  border-left: 3px solid var(--ok);
  border-radius: 0 var(--r-md) var(--r-md) 0;
  background: color-mix(in srgb, var(--ok) 8%, transparent);
}
/* En su propia línea: dentro del párrafo, el alto mínimo táctil del botón
   estiraba el renglón que lo contenía y dejaba un hueco en medio de la frase
   —se veía como si faltara algo—. */
.mi-sus__nota--hecho .btn { display: block; width: fit-content; margin: var(--e-2) 0 0; }

/* ── La lista de planes del modal ──
 *
 * Cada ficha dice el precio Y qué le pasa a quien la pulse, porque son dos
 * cosas distintas: el mismo plan es «entra hoy y se te cobran 266» para quien
 * sube y «entra el 1 de octubre» para quien baja. */
.mi-sus__planes { display: grid; gap: var(--e-3); min-width: 0; }
.mi-sus__planes-regla {
  margin: 0;
  font-size: var(--t-secundario);
  color: var(--txt-2);
  line-height: 1.45;
}
.mi-sus__plan {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--e-3);
  flex-wrap: wrap;
  padding: var(--e-3);
  border: 1px solid var(--linea);
  border-radius: var(--r-md);
  background: var(--capa-2);
  min-width: 0;
}
.mi-sus__plan-que { display: grid; gap: 2px; min-width: 0; flex: 1 1 14rem; }
.mi-sus__plan-que .muted { font-size: var(--t-meta); }
.mi-sus__plan-precio {
  display: flex;
  align-items: baseline;
  gap: 4px;
  flex-wrap: wrap;
  font-variant-numeric: tabular-nums;
}
.mi-sus__plan-pasa {
  font-size: var(--t-secundario);
  color: var(--txt-2);
  line-height: 1.4;
}
.mi-sus__plan .btn { flex: 0 0 auto; min-height: var(--tactil); }


/* ══════════════════ La franja de «guardando…» ══════════════════
 *
 * La misma franja dice dos cosas muy distintas y no se pueden pintar igual.
 *
 * ATASCO: la cola lo está intentando y va a entrar. No ha pasado nada malo, así
 * que no lleva el rojo del error — llevaba el mismo borde crítico que un fallo
 * de verdad, y ver eso a mitad de apuntar un gasto por haber pasado un túnel es
 * lo que hace que alguien deje de fiarse de una aplicación de dinero.
 *
 * Va en violeta —--futuro, que en este sistema es «aún no pasó» (DESIGN.md §9)— y con su
 * texto además del tono: la franja dice con palabras que se guarda solo.
 *
 * FALLO: ese sí se queda como estaba. */
.sin-guardar[data-tono="espera"] {
  background: color-mix(in srgb, var(--futuro) 10%, var(--capa-2));
  border-color: color-mix(in srgb, var(--futuro) 35%, transparent);
}
.sin-guardar[data-tono="espera"] .sin-guardar__texto strong {
  /* Sin negrita de alarma: es una nota, no un aviso. */
  font-weight: 600;
}


/* Qué no se guardó, uno por uno.
 *
 * Una franja que dice «2 cambios no se guardaron» y nada más obliga a adivinar
 * cuáles, y quien tiene que adivinar sobre su propio dinero no vuelve a confiar
 * en la pantalla. Caben tres; de ahí en adelante se cuentan. */
.sin-guardar__lista {
  margin: var(--e-2) 0 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: 2px;
  font-size: var(--t-meta);
  min-width: 0;
}
.sin-guardar__lista li { min-width: 0; overflow-wrap: anywhere; }
.sin-guardar__lista strong { color: var(--txt); }
.sin-guardar__lista span { color: var(--txt-3); }


/* ==========================================================================
   34 · ANÁLISIS
   ==========================================================================
   Lo que la pantalla del «¿por qué?» (js/views/panel.js) pide encima de las
   piezas comunes. Sustituye los estilos en línea que llevaba —`padding: 7px 0`,
   bordes con `--grid`, que en Aurora no existe— y los colores del sistema
   anterior en los dos gráficos hechos en DOM, que aquí salían los dos trozos
   de la barra partida del MISMO azul: `--color-fill` y `--color-accent` son
   `--marca` en el puente.

   Va antes de la 33 y no al final: la 33 es la pasada de móvil y tiene que
   poder pisar lo de aquí. */

.ana-pestanas { min-width: 0; }
.ana-pestanas .segmentos { max-width: 100%; }

/* La leyenda en palabras, debajo del dibujo (§9: el color nunca solo). */
.ana-leyenda {
  display: flex; flex-wrap: wrap; gap: var(--e-2) var(--e-4);
  margin-top: var(--e-3);
  font-size: var(--t-meta); color: var(--txt-2);
}
.ana-leyenda__clave { display: inline-flex; align-items: center; gap: 6px; }
.ana-leyenda__clave i {
  flex: none; width: 10px; height: 10px; border-radius: 3px;
  background: var(--clave, var(--txt-3));
}
.ana-leyenda__clave[data-tono="marca"]   { --clave: var(--marca); }
.ana-leyenda__clave[data-tono="gris"]    { --clave: var(--txt-3); }
.ana-leyenda__clave[data-tono="futuro"]  { --clave: var(--futuro); }
.ana-leyenda__clave[data-tono="ok"]      { --clave: var(--ok); }
.ana-leyenda__clave[data-tono="peligro"] { --clave: var(--peligro); }

/* «Qué cambió». Subir en ámbar —§2, «vas rápido»— y bajar en verde, «vas
   bien». No en coral: gastar más en una categoría que el mes pasado no es
   haberse pasado de nada. El cero sigue siendo la regla de marca de sistema.css. */
.obi-grafico .cambio__barra { border-radius: 4px; }
.obi-grafico .cambio__barra[data-sube="si"] { background: var(--alerta); }
.obi-grafico .cambio__barra[data-sube="no"] { background: var(--ok); }
.obi-grafico .cambio__pie { color: var(--txt-3); }
/* La línea contra el mismo mes del año pasado: una frase al pie, no otra gráfica. */
.obi-grafico .cambio__anual { margin: var(--e-3) 0 0; color: var(--txt-2); font-size: var(--t-secundario); }

/* «Fijo o negociable». Lo fijo hundido y neutro —no se mueve—, lo negociable
   tintado de acción —es donde se puede hacer algo—. Las dos parejas de tinta y
   fondo son las que ya se miden en otros componentes (el hundido y la píldora
   informativa), no dos nuevas sin medir. */
.partida__barra { height: 44px; gap: 2px; border-radius: var(--r-sm); overflow: hidden; }
.partida__fijo { background: var(--bg-2); color: var(--txt); }
.partida__variable { background: var(--marca-suave); color: var(--marca-txt); }

/* Las listas cortas de «qué · cuánto». */
.ana-lineas { display: grid; }
.ana-linea {
  display: flex; align-items: baseline; gap: var(--e-3);
  padding: var(--e-2) 0;
  border-bottom: 1px solid var(--linea);
  font-size: var(--t-secundario);
}
.ana-linea:last-child { border-bottom: 0; }
.ana-linea__que {
  flex: 1 1 auto; min-width: 0;
  color: var(--txt-2);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ana-linea__extra { flex: none; font-size: var(--t-meta); color: var(--txt-3); }
.ana-linea__monto { flex: none; font-weight: 700; font-variant-numeric: tabular-nums; color: var(--txt); }

.ana-nota {
  margin: 0;
  padding: var(--e-3) var(--e-4);
  border-radius: var(--r-sm);
  background: var(--marca-suave);
  color: var(--marca-txt);
  font-size: var(--t-secundario);
  line-height: 1.5;
}
.ana-nota--ancha { grid-column: 1 / -1; }
.ana-pie { margin: var(--e-3) 0 0; font-size: var(--t-meta); color: var(--txt-3); }
.ana-estado {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: var(--e-2) var(--e-3);
  margin-top: var(--e-4);
}
.ana-estado .ana-pie { margin: 0; }
.ana-recientes { display: grid; min-width: 0; }
.ana-primer-uso { justify-content: center; margin-top: var(--e-3); }

/* En el teléfono lo que se aparta es el «3 conceptos»: el nombre y la cifra
   son la fila, y con los tres en 360px el nombre se quedaba en «Ingresos f…». */
@media (max-width: 480px) {
  .ana-linea { flex-wrap: wrap; row-gap: 0; }
  .ana-linea__extra { order: 3; flex-basis: 100%; }
}

/* Un botón al final de una fila «qué · cuánto» («Ver», «Dejar 1»): centrado con
   la fila y sin estirarla. */
.ana-linea > .btn { flex: none; align-self: center; }

/* «A fondo»: el punto de color y el nombre de la categoría en las tablas, y la
   fila de totales. Sustituyen a `style: { gap: '7px' }` y a un `<strong>` metido
   como HTML en cada celda. */
.ana-cat { display: inline-flex; align-items: center; gap: var(--e-2); min-width: 0; }
.fila-total td { font-weight: 700; background: var(--bg-2); }
.ana-celda-total { font-weight: 700; }

/* «Revisar»: hasta dónde llegan los datos de cada cuenta. */
.rev-cuentas { display: grid; }
.rev-cuenta {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--e-3);
  padding: var(--e-3) 0;
  border-bottom: 1px solid var(--linea);
}
.rev-cuenta:last-child { border-bottom: 0; }
.rev-cuenta__que { display: grid; gap: 2px; min-width: 0; }
.rev-cuenta__meta { font-size: var(--t-meta); color: var(--txt-3); }
.rev-cuenta .pill { flex: none; }
@media (max-width: 480px) {
  .rev-cuenta { flex-direction: column; align-items: flex-start; }
}

/* La cifra que pide que se mire —datos de ejemplo, fijos que pueden repetir—
   con el borde de ámbar. El pie de la cifra ya dice qué pasa: el tono no va solo. */
.rev-tiles .tile[data-aviso="si"] { border-color: color-mix(in srgb, var(--alerta) 45%, var(--linea)); }

.rev-buscar { display: flex; gap: var(--e-2); margin-bottom: var(--e-4); }
.rev-buscar__campo { flex: 1 1 auto; min-width: 0; }
.rev-resultados { display: grid; min-width: 0; }
.rev-mas { margin-top: var(--e-3); width: 100%; }
.insight__texto > .btn { margin-top: var(--e-2); }


/* ==========================================================================
   35 · IMPORTAR
   ==========================================================================
   Lo que la pantalla de subir (js/views/importar.js) llevaba en estilos en
   línea —veintidós, dos de ellos con `font-size: 12px` escrito como texto— y
   las piezas que solo vestía styles.css con fichas del sistema anterior: los
   pasos, la tabla de corregir, el registro de líneas y la barra de progreso. */

.imp-progreso { margin-top: var(--e-3); }
.imp-fila { gap: var(--e-2); }
.imp-texto { font-family: ui-monospace, "Cascadia Code", Consolas, monospace; font-size: var(--t-secundario); }
.imp-resumen { margin: var(--e-1, 4px) 0 var(--e-4); }
.imp-globales { margin-top: var(--e-4); padding-top: var(--e-3); border-top: 1px solid var(--linea); }
.imp-cuenta { max-width: 12rem; }
.imp-numero { width: 6rem; }
.imp-archivo { display: grid; gap: 0; min-width: 0; }

/* El lote y el historial: una ficha por archivo en vez de una tabla ancha. El
   `min-width: 0` del nombre es lo que impide que un nombre largo empuje la ficha
   y con ella la pantalla entera. */
.imp-lotes { display: grid; gap: var(--e-2); margin-top: var(--e-3); }
.imp-lote, .imp-hist {
  display: flex; flex-wrap: wrap; gap: var(--e-2) var(--e-3); align-items: center;
  justify-content: space-between;
  padding: var(--e-3); border: 1px solid var(--linea); border-radius: var(--r-sm);
  background: var(--capa-1);
}
.imp-lote > .imp-archivo, .imp-hist > .imp-archivo { flex: 1 1 12rem; }
.imp-lote__cuenta { display: flex; gap: var(--e-2); align-items: center; flex-wrap: wrap; }
.imp-lote--activo { border-color: var(--marca); background: var(--capa-2); }
/* El saldo que trae el archivo: una fila entera de la ficha, con el texto que se
   parte si hace falta (la casilla no se encoge: `.casilla` la deja en `flex: none`). */
.imp-lote__saldo { flex: 1 1 100%; min-width: 0; }
.imp-lote__saldo span { min-width: 0; }
.imp-aviso { margin-bottom: var(--e-4); gap: var(--e-2); }
.imp-confirmar__que { display: grid; gap: 2px; min-width: 0; }
.imp-ayuda { margin: var(--e-2) 0 0; text-align: center; }

.imp-detalles { margin-top: var(--e-3); }
.imp-detalles > summary { cursor: pointer; font-size: var(--t-secundario); color: var(--txt-2); }
.imp-detalles--fuerte > summary { font-weight: 600; color: var(--txt); }
.imp-detalles > .map-grid, .imp-detalles > .log { margin-top: var(--e-3); }

/* Los campos de la tabla de corregir: compactos en escritorio, y a 16px con el
   dedo, o el iPhone hace zoom al tocar cada uno. */
.imp-campo { padding: 3px 6px; font-size: var(--t-secundario); }
.imp-campo--fecha { width: 9rem; }
.imp-campo--texto { width: 100%; }
.imp-campo--monto { width: 7rem; text-align: right; }
.imp-campo--categoria { max-width: 10rem; }
@media (pointer: coarse) {
  .imp-campo { font-size: 1rem; padding: 6px 8px; }
}

/* Los pasos: número en un círculo, el actual con el azul de acción y los
   hechos en verde (§2: verde es «ya está»), cada uno con su palabra. */
.steps { gap: var(--e-3); }
.step { color: var(--txt-3); }
.step__n { background: var(--capa-2); color: var(--txt-2); }
.step[data-active="1"] { color: var(--txt); }
.step[data-active="1"] .step__n { background: var(--marca); color: #fff; }
.step[data-done="1"] .step__n { background: var(--ok-suave); color: var(--ok-txt); }

.preview-scroll { border-color: var(--linea); border-radius: var(--r-sm); }
/* Un repetido, en ámbar y no en el azul del sistema anterior: es «falta decidir». */
tr.dupe td { background: var(--alerta-suave); }
.log { background: var(--bg-2); color: var(--txt-2); border-radius: var(--r-sm); }
.bar-progress { background: var(--capa-2); }
.bar-progress > i { background: var(--marca); }

/* Mis límites (js/views/presupuestos.js): lo que llevaba en línea. */
.lim-pista { margin: 0; }
.lim-dgii-nota { margin: var(--e-2) 0; }
.lim-celda-limite { display: inline-flex; align-items: center; gap: var(--e-2); flex-wrap: wrap; }
.lim-regla-form {
  display: flex; flex-wrap: wrap; align-items: flex-end;
  gap: var(--e-3);
  margin-bottom: var(--e-4);
}
.lim-regla-form .field { flex: 1 1 min(12rem, 100%); min-width: 0; }
.lim-regla-form > .btn { flex: none; }

/* Pagos fijos (js/views/fijos.js): lo que llevaba en línea. */
.fij-concepto { display: grid; gap: 0; min-width: 0; }
tr.fij-inactivo { opacity: .55; }
.fij-nota { margin-top: calc(-1 * var(--e-2)); }
.imp-detalles > .table-scroll { margin-top: var(--e-2); }

/* El planificador (js/views/planificador.js): lo que llevaba en línea. */
.plan-cabecera { display: flex; justify-content: space-between; align-items: center; gap: var(--e-3); flex-wrap: wrap; }
.plan-nota { margin: 0; }
.plan-aportes-vacio { margin: var(--e-3) 0 0; }
.plan-total-pista { margin: 2px 0 var(--e-2); }
.plan-nombre-fila { display: flex; gap: var(--e-3); align-items: flex-end; }
.plan-nombre-campo { flex: 1; min-width: 0; }
/* Un emoji grande en un campo pequeño: se centra y se ve de qué es. */
.plan-icono-campo { width: 4.5rem; text-align: center; font-size: var(--t-cifra-media); }
.plan-en-blanco { margin-top: var(--e-4); }
.plan-opcion { width: 100%; }

/* Me deben (js/views/cobros.js). `celda-dos` es la celda de tabla con dos
   líneas —qué y de quién; cuánto y su barra—, que iba con `gap` en línea. */
.celda-dos { display: grid; gap: 3px; min-width: 0; }
.cob-recibidos { gap: var(--e-2); }

/* Buscar (js/views/buscar.js). */
.bus-buscador { display: flex; flex-wrap: wrap; align-items: center; gap: var(--e-3); }
.bus-buscador__campo { flex: 1 1 15rem; min-width: 0; }
.bus-grupo { margin: var(--e-4) 0 var(--e-2); font-size: var(--t-secundario); color: var(--txt-2); }
.bus-herramientas { flex-wrap: wrap; gap: var(--e-2); }

/* DGII (js/views/dgii.js). */
.dgii-remite { display: flex; justify-content: space-between; align-items: center; gap: var(--e-3); flex-wrap: wrap; }
.dgii-selector { display: flex; gap: var(--e-4); flex-wrap: wrap; align-items: flex-end; }
.dgii-formatos { display: flex; gap: var(--e-2); flex-wrap: wrap; }
.dgii-cifra__rotulo { font-size: var(--t-nano); color: var(--txt-3); }
.dgii-cifra__valor { margin: 0; font-weight: 600; }
.dgii-lista { padding-left: 18px; font-size: var(--t-secundario); }
.dgii-enlace { padding: 0; }
.dgii-sin-ncf { margin-top: var(--e-2); }
.dgii-previa { font-size: var(--t-nano); line-height: 1.6; }
.dgii-detalle { margin-top: var(--e-3); font-size: var(--t-secundario); }

/* Configuración (js/views/ajustes.js). */
.aj-acciones { margin-top: var(--e-3); }
.aj-fila {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: var(--e-3);
}
.aj-fila__que { min-width: 15rem; }
.aj-fila__titulo { margin: 0; }
.aj-fila__pie { margin: 2px 0 0; }
.aj-nota { display: block; margin-top: 6px; }
.aj-linea { gap: var(--e-2); align-items: flex-end; flex-wrap: wrap; }
.aj-sep { margin: var(--e-3) 0; }
.aj-tipos { gap: 6px; }
.aj-subtitulo { font-size: var(--t-secundario); margin: 0 0 var(--e-2); }
.aj-lista { gap: var(--e-2); }
.aj-boton-izq { align-self: flex-start; }
.aj-salida, .aj-stack { margin-top: var(--e-3); }

/* Mi perfil (js/views/perfil.js). */
.perfil-rotulo { margin-top: var(--e-5); }
.perfil-rotulo--corto { margin-top: var(--e-4); }
.perfil-pie { margin-top: var(--e-4); }
.perfil-nota { margin-top: var(--e-3); }
.perfil-acciones { margin-top: var(--e-4); }
.perfil-avatar { width: 34px; height: 34px; font-size: var(--t-mini); }

/* ---------- Mantenimiento ----------
   Tapa TODO: no es un aviso dentro de la aplicación, es que la aplicación no
   está. Y se queda esperando a que vuelva, porque pedir que alguien recargue a
   mano es justo lo que no queremos. */
.mantenimiento {
  position: fixed; inset: 0;
  z-index: 95;
  display: grid; place-items: center;
  padding: var(--e-5);
  overflow-y: auto;
  background: var(--bg);
}
body.con-mantenimiento { overflow: hidden; }
.mantenimiento__caja {
  width: min(520px, 100%);
  display: grid; gap: var(--e-3);
  justify-items: center;
  text-align: center;
  padding: var(--e-6);
  border: 1px solid var(--linea);
  border-radius: var(--r-xl);
  background: var(--capa-1);
  box-shadow: var(--sombra-3);
}
.mantenimiento__icono { font-size: 2.5rem; }
.mantenimiento__titulo { margin: 0; font-size: 1.5rem; font-weight: 800; }
.mantenimiento__texto { margin: 0; color: var(--txt-2); }
.mantenimiento__cuando { margin: 0; font-weight: 700; }
.mantenimiento__espera, .mantenimiento__nota {
  margin: 0; font-size: var(--t-meta); color: var(--txt-3);
}
.mantenimiento__espera { display: flex; align-items: center; gap: var(--e-2); }
.mantenimiento__punto {
  width: 8px; height: 8px; flex: none;
  border-radius: var(--r-full);
  background: var(--marca);
}
.mantenimiento__acciones { margin-top: var(--e-2); }

/* ---------- La foto de perfil ----------
   Ocupa el mismo círculo que las iniciales, en la cabecera, en el panel del
   avatar y en Mi perfil. */
.usuario__avatar, .panel-usuario__avatar, .identidad__avatar { overflow: hidden; }
.usuario__avatar > img, .panel-usuario__avatar > img, .identidad__avatar > img {
  width: 100%; height: 100%;
  display: block;
  object-fit: cover;
  border-radius: inherit;
}
.con-foto { background: var(--capa-2); }
.identidad__acciones { display: flex; flex-wrap: wrap; gap: var(--e-2); }

/* El encuadre: la imagen se arrastra dentro de un cuadrado, y lo que queda fuera
   del círculo se oscurece, que es justo lo que no se va a ver. */
.foto-recorte {
  position: relative;
  width: min(280px, 100%);
  aspect-ratio: 1;
  max-width: 100%;
  margin-inline: auto;
  border-radius: var(--r-lg);
  overflow: hidden;
  background: var(--capa-2);
  touch-action: none;
}
.foto-recorte canvas { width: 100%; height: 100%; display: block; cursor: grab; }
.foto-recorte canvas:active { cursor: grabbing; }
.foto-recorte::after {
  content: '';
  position: absolute; inset: 0;
  border-radius: var(--r-full);
  box-shadow: 0 0 0 100vmax color-mix(in srgb, var(--bg) 62%, transparent);
  pointer-events: none;
}
.foto-recorte__zoom { display: grid; gap: var(--e-2); color: var(--txt-3); }
.foto-recorte__zoom input { width: 100%; min-height: 44px; }

/* Mis espacios (js/views/espacios.js). */
.esp-texto { font-size: var(--t-secundario); }
.esp-pista { font-size: var(--t-nano); }
.esp-fiscal { margin-top: var(--e-2); }

/* Traspasos (js/views/traspasos.js). La frase y su cuerpo van pegados: son una
   sola pieza que se abre, y un hueco entre los dos los parte en dos tarjetas. */
.tras-frase { gap: 0; }
.tras-pregunta { margin: 0 0 var(--e-3); }
.tras-acciones { gap: var(--e-2); margin-top: var(--e-3); }
.tras-regla { justify-content: space-between; gap: var(--e-3); align-items: center; }
.tras-regla__flujo { font-size: var(--t-secundario); margin-top: 4px; }
.tras-pill { margin-left: var(--e-2); }

/* Proveedores (js/views/proveedores.js). El nombre es un botón dentro de una
   celda: sin quitarle el relleno del botón la fila crece el doble. */
.prov-nombre { padding: 0; text-align: left; }
.prov-rnc { font-size: var(--t-nano); }

/* Soporte (js/views/soporte.js). El cuerpo del mensaje respeta los saltos de
   línea que escribió la persona: se pintan con `text`, nunca con HTML. */
.sop-linea { justify-content: space-between; gap: var(--e-2); flex-wrap: wrap; }
.sop-marcas { gap: 4px; }
.sop-cuerpo { margin: 4px 0 0; white-space: pre-wrap; }

/* Nómina (js/views/nomina.js). */
.nom-respuestas { margin-top: var(--e-4); }


/* ==========================================================================
   33 · RESPONSIVE: LA PASADA DE MÓVIL
   ==========================================================================
   Salió de medir la aplicación CON DEDO. Hasta ahora herramientas/responsive.mjs
   medía el teléfono con ratón —Chrome sin ventana dice `pointer: fine`—, así que
   a 360px medía una pantalla sin barra del pulgar, con la hamburguesa y con los
   tamaños de escritorio: una que no existe en ningún bolsillo. Con dedo
   emulado salieron 212 fallos en las 62 pantallas y hojas, y los 212 venían de
   CINCO causas: los bloques 1 a 3. En tableta y escritorio, ninguno.

   Los bloques 4 a 7 no los mide ninguna herramienta: salieron de mirar las
   capturas con dedo, pantalla por pantalla.

   Va todo junto y al final, en vez de repartido por la sección de cada
   componente, para que se lea como lo que es: lo que le pasaba a un teléfono. */

/* ---------- 1 · La letra de un campo nunca baja de 16px donde hay dedo ----------
   Safari en el iPhone AMPLÍA la página al enfocar un campo con letra de menos
   de 16px, y no la devuelve al salir. --t-cuerpo mide 15px, así que lo hacían
   TODOS los formularios: se toca el importe, la pantalla salta, sale cortada
   por la derecha y hay que pellizcar para volver. Ni Chrome ni Android lo
   hacen, y por eso no lo había visto nadie probando desde un portátil.

   No se arregla con `maximum-scale=1` en el viewport: eso le quita el zoom a
   quien lo necesita para leer. Se arregla con un píxel de letra.

   Los selectores repiten los de la regla base de campos y los de los
   componentes que traían su propio tamaño: con menos peso no ganarían.

   Y hay que repetir los `:not()`. La regla base de sistema.css es
   `input:not([type="checkbox"]):not([type="radio"])`, y cada `:not()` suma lo
   que pesa su atributo: (0,2,1) contra el (0,1,1) de `input[type=password]`.
   Sin ellos esta regla aplicaba y PERDÍA en todos los formularios —la primera
   versión solo arregló los campos con regla propia—, igual que ya perdía el
   `max(16px, …)` que styles.css tenía puesto a ≤640 para lo mismo. Se vio
   preguntándole al navegador qué reglas casaban con el campo
   (herramientas/responsive.mjs, «regla:»); leyendo el CSS no aparecía. */
@media (pointer: coarse), (max-width: 640px) {
  .input, input[type=text], input[type=search], input[type=number],
  input[type=date], input[type=email], input[type=password], input[type=tel],
  input[type=url], input:not([type]), select, textarea,
  input:not([type="checkbox"]):not([type="radio"]),
  table.data input:not([type="checkbox"]),
  .ia__caja, .captura__caja, .adm-codigo,
  table.data select, .compact-select {
    font-size: 1rem;
  }
}

/* ---------- 2 · La lupa de la cabecera, a 44px ----------
   Plegada, la lupa ocupa la caja entera del buscador (`inset: 0`, en
   sistema.css), así que su blanco ES la caja, y la caja medía 38px. Es el único
   botón que está en la cabecera de todas las pantallas, y el único de la fila
   por debajo del mínimo. Abierto, manda la regla de `:focus-within`, que pesa
   más que estas. */
@media (pointer: coarse) and (max-width: 1279px), (max-width: 640px) {
  .buscador,
  body.con-pulgar .buscador { width: 44px; min-width: 44px; height: 44px; }
}

/* ---------- 3 · La barra de periodo y cuenta en el teléfono ----------
   · Las dos fichas medían 34px y llevaban letra de 14px: el control que más se
     toca de la cabecera era el más pequeño de la pantalla, y además hacía
     saltar el zoom del bloque 1.
   · La barra tenía 12px de canal y el contenido de debajo 16: los bordes de la
     cabecera y los de las tarjetas no caían en la misma vertical.
   · «Todas las cuentas» salía «Todas las cuent» cortado a mitad de letra, sin
     puntos suspensivos, que se lee como un fallo de dibujo y no como un texto
     largo. */
/* Sin @media de ancho: va contra body.con-pulgar, que solo existe en un
   teléfono —también de lado—. */
  /* Con aire por arriba, y no pegada.
   *
   * Esto llevaba `padding-top: 0` y el resultado era el de la foto: «PERIODO» y
   * «CUENTA» empezando en la misma línea donde acaba la cabecera, sin nada en
   * medio. Dos rótulos en versalitas a cuatro píxeles del título de la pantalla
   * se leen como un subtítulo suyo, no como los mandos de otra cosa.
   *
   * Y la cabecera es de vidrio: lo que pase por debajo se ve borroso a través.
   * Sin este hueco, lo primero que cruzaba era el rótulo. */
  body.con-pulgar .filters { padding: var(--e-4) var(--canal) var(--e-3); gap: var(--e-2); }
  body.con-pulgar .filters select {
    min-height: 44px;
    padding: 0 30px 0 var(--e-3);
    font-size: 1rem;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  /* El micrófono, del alto de las fichas y alineado con ellas por abajo. */
  body.con-pulgar .filters #btnDictar {
    flex: none; width: 44px; min-height: 44px; padding: 0;
    align-self: flex-end;
  }
/* fin de las fichas de la barra de filtros con pulgar (sin @media de ancho) */

/* ---------- 4 · El hueco muerto encima de la barra del pulgar ----------
   Había TRES reservas para la misma barra: la de `.main` (§5) y las de `.view`
   y `.pie` (sistema.css). Sumaban unos 230px vacíos al final de cada pantalla,
   con el pie flotando en medio de la nada, y en una pantalla corta como
   «Subir» eran casi un tercio del alto. Con la de `.main` basta: es la que
   envuelve a las otras dos. */
body.con-pulgar .view { padding-bottom: var(--e-6); }
body.con-pulgar .pie { padding-bottom: var(--e-6); }

/* ---------- 5 · Las cabeceras plegables no se parten ----------
   El tirador de una tarjeta plegable se añade AL FINAL de su cabecera
   (js/plegar.js), y en el teléfono esa cabecera hace `flex-wrap` con las
   herramientas a lo ancho (§24). La flecha caía en una tercera fila ella sola
   —«Qué toca pagar», con un hueco y la flecha debajo— y en «Mis límites» el
   botón «Ajustar» quedaba flotando entre el título y la flecha.

   En rejilla la flecha se queda arriba a la derecha, junto al título, que es
   donde se busca, y lo demás baja a lo ancho. */
@media (max-width: 640px) {
  .bloque--plegable > .card__head,
  .bloque--plegable > .seccion__head {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: center;
    column-gap: var(--e-2);
    row-gap: var(--e-3);
  }
  .bloque--plegable > .card__head > .card__tirador,
  .bloque--plegable > .seccion__head > .card__tirador {
    grid-column: 2; grid-row: 1; margin-left: 0;
  }
  .bloque--plegable > .card__head > :not(:first-child):not(.card__tirador),
  .bloque--plegable > .seccion__head > :not(:first-child):not(.card__tirador) {
    grid-column: 1 / -1;
  }
}

/* ---------- 6 · Lo que solo se veía al pasar el ratón ----------
   `.row-actions` va a media opacidad y sube a entera con `tr:hover`. Sin ratón
   no hay hover: en «Me deben» y al compartir un espacio los botones de cada
   fila se quedaban siempre a medio tono, que es exactamente como se pinta un
   botón DESACTIVADO. */
@media (hover: none) {
  .row-actions { opacity: 1; }
}

/* ---------- 7 · La franja de «no se guardó» ----------
   Pegajosa arriba tiene sentido en un escritorio, donde mide una línea. En un
   teléfono mide 300px: pegajosa, tapaba media pantalla mientras se bajaba, y
   además por DETRÁS de la cabecera, que también es pegajosa y está a la misma
   altura. Ahí se queda en su sitio: se ve al entrar, que es cuando hay que
   verla, y no persigue.

   Y con los márgenes del contenido. Iba de borde a borde mientras las tarjetas
   de debajo guardan su canal y su ancho máximo: en un monitor ancho medía el
   doble que todo lo demás, y en el teléfono tocaba los bordes de la pantalla. */
.sin-guardar {
  margin: var(--e-4) max(var(--canal), calc((100% - var(--ancho-max)) / 2 + var(--canal))) 0;
}
@media (max-width: 640px) {
  .sin-guardar { position: static; margin-top: var(--e-3); }
}

/* ---------- 8 · El asidero de la hoja se deja arrastrar ----------
   js/hoja-arrastre.js cierra la hoja al arrastrar su cabecera hacia abajo. Sin
   `touch-action: none` el navegador se queda el gesto para desplazar la página
   y el arrastre no llega nunca: cancela el puntero al primer píxel. Solo en la
   cabecera: el cuerpo tiene que seguir rodando con el dedo. */
@media (max-width: 620px) {
  .modal__head { touch-action: none; }
}

/* ---------- 9 · Los campos de «Ajustar límites» ----------
   El importe y el periodo de cada categoría llevaban la letra EN LÍNEA desde
   js/views/presupuestos.js (`fontSize: var(--t-etiqueta)`, 13px), y un estilo
   en línea le gana a cualquier regla: eran los únicos campos de la aplicación
   que seguían haciendo saltar el zoom después del bloque 1. Ahora son una
   clase: compactos en la tabla del escritorio, como estaban, y a 16px y alto
   de dedo en el teléfono.

   Con `table.data` delante y el `:not()` repetido: la regla de campos de
   tabla de styles.css pesa (0,2,2), y con menos peso la tabla del escritorio
   se quedaría con su letra y no con la de aquí. */
table.data input.celda-limite:not([type="checkbox"]) {
  width: 110px; padding: 4px 6px; font-size: var(--t-etiqueta);
}
table.data select.celda-limite { padding: 4px 6px; font-size: var(--t-etiqueta); }
@media (pointer: coarse), (max-width: 640px) {
  table.data input.celda-limite:not([type="checkbox"]),
  table.data select.celda-limite {
    font-size: 1rem;
    min-height: 44px;
    padding: 0 var(--e-3);
  }
}

/* ---------- 10 · La ☰ no se pinta con el lateral puesto ----------
   `.only-movil { display: none }` vive en sistema.css, y `.btn { display:
   inline-flex }` aquí, en §8: mismo peso, y esta hoja va después. Así que todo
   botón con `.only-movil` se veía en TODOS los anchos. El que se notaba era la
   ☰ junto al título de un monitor de 1440, con el lateral ya abierto a la
   izquierda: un botón para abrir lo que ya está abierto.

   La regla de fondo es la de sistema.css —se ve por debajo de 1024, donde el
   lateral es cajón— y aquí solo se le devuelve el peso que perdió. */
.btn.only-movil { display: none; }
@media (max-width: 1023px) {
  .btn.only-movil { display: inline-flex; }
}

/* ---------- 11 · La cabecera de un límite no se parte a trozos ----------
   Nombre a la izquierda y cifra a la derecha, repartiendo el ancho a partes:
   a 390px «Comida & Bebida» y «quedan RD$4,067.85» se partían los DOS en dos
   renglones, cuatro palabras sueltas en dos columnas. La cifra ahora no se
   parte nunca: si no cabe al lado, baja entera y se alinea a la derecha. */
.limite__cabeza { flex-wrap: wrap; align-items: baseline; row-gap: 2px; }
.limite__rotulo { flex: 1 1 8rem; min-width: 0; }
.limite__cifra  { flex: 0 0 auto; margin-left: auto; white-space: nowrap; text-align: right; }

/* ---------- 12 · Una tabla apilada dentro de una tarjeta no son cajas ----------
   En el teléfono las tablas se apilan (sistema.css): cada fila pasa a ser una
   caja con borde, fondo y radio. Suelta en la página está bien. Dentro de una
   tarjeta —Pagos fijos, Me deben, Proveedores— era una caja dentro de otra:
   dos bordes, dos fondos y 24px de sangría perdidos en cada lado de una
   pantalla de 390. Dentro de una tarjeta las filas se separan con una raya,
   que es lo que ya son sus celdas por dentro. */
@media (max-width: 640px) {
  .card table.data tr {
    border: 0;
    border-radius: 0;
    background: transparent;
    padding: var(--e-3) 0;
    margin-bottom: 0;
  }
  .card table.data tr + tr { border-top: 1px solid var(--linea-fuerte); }
  /* Y la caja de fuera. Quitar el borde de cada fila no bastó: la tabla va
     dentro de `.table-scroll`, que §16 viste con borde, radio y fondo, y
     seguía siendo un panel dentro de la tarjeta. Apilada no se desplaza en
     horizontal (sistema.css ya le quita el overflow), así que esa caja no
     guarda nada. Con ella se va la sangría de las celdas, que dejaba el rótulo
     a 12px del texto de la tarjeta. */
  .card .table-scroll { border: 0; border-radius: 0; background: transparent; }
  .card table.data td { padding-left: 0; padding-right: 0; }
}

/* ---------- 13 · Las filas de «Mis límites», sin doble sangría ----------
   Cada límite es un botón con 24px de relleno a los lados (sistema.css,
   `.lim-fila`) dentro de una tarjeta que ya trae 16. A 390px la barra empezaba
   a 56px del borde y el nombre y la cifra se peleaban por lo que quedaba —de
   ahí que se partieran—. En el teléfono el relleno lateral lo pone la
   tarjeta, y la fila solo separa arriba y abajo. */
@media (max-width: 640px) {
  .lim-fila { padding: var(--e-4) 0; border-left: 0; }
}

/* ---------- 14 · Con el teclado abierto, la barra del pulgar se aparta ----------
   Con la página encogida por el teclado (index.html, interactive-widget), una
   barra fija abajo sube con él y se queda justo encima: tapa el campo que se
   está escribiendo, y en un teléfono con el teclado fuera deja dos o tres
   renglones útiles. Mientras hay un campo enfocado nadie cambia de sección, así
   que la barra se aparta y vuelve sola al salir del campo.

   Los desplegables no cuentan: en el teléfono abren una lista del sistema, no
   el teclado, y la barra no estorba. */

  .pulgar { transition: transform var(--rapido) var(--curva); }
  body.con-pulgar:has(:is(input:not([type="checkbox"]):not([type="radio"]), textarea):focus) .pulgar {
    transform: translateY(110%);
  }
/* fin: la barra solo existe en un teléfono, de pie o de lado */
@media (prefers-reduced-motion: reduce) {
  .pulgar { transition: none; }
}

/* ---------- 15 · El cajón de «Más» tiene fondo ----------
   Por debajo de 1024 el lateral deja de ser una barra y pasa a ser un cajón que
   cae sobre la pantalla. Y salía TRANSPARENTE: §6 de esta hoja pone
   `.sidebar__panel { background: transparent }` —en escritorio el carril es el
   mismo terreno que la página, y está bien— y como esta hoja va la última, pisa
   el fondo que styles.css le daba al cajón. Encima, sistema.css le quita al
   `.sidebar` el velo de detrás. Resultado en un teléfono: el logotipo, el
   espacio y las once secciones pintados letra sobre letra encima de las cifras
   de Inicio, sin poder leerse ni una cosa ni la otra.

   El panel lleva el mismo fondo entero que los otros menús que caen (§6,
   `--menu-fondo`), y el velo el mismo que el de los modales (§18). No se vio
   hasta ahora porque la auditoría no abría el cajón nunca. */
@media (max-width: 1023px) {
  .sidebar[data-abierto="1"] {
    background: color-mix(in srgb, var(--bg) 55%, transparent);
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
  }
  .sidebar__panel {
    background: var(--menu-fondo);
    border-right: 0;
    border-bottom: 1px solid var(--linea-fuerte);
    box-shadow: var(--sombra-3);
    /* Once secciones, doce con Empresa: en un teléfono de lado no caben, y lo
       que queda debajo del borde tiene que poder alcanzarse. */
    max-height: 100dvh;
    overflow-y: auto;
    overscroll-behavior: contain;
  }
}
@media (max-width: 1023px) and (prefers-reduced-transparency: reduce) {
  .sidebar[data-abierto="1"] {
    backdrop-filter: none; -webkit-backdrop-filter: none;
    background: color-mix(in srgb, var(--bg) 85%, transparent);
  }
}

/* ---------- 15b · La cabecera del cajón se queda arriba ----------

   El cajón cae desde el borde de la pantalla y RUEDA entero: catorce entradas
   más lo de la cuenta no caben de una vez. Y lo que rueda pasa por debajo de la
   barra de estado, que en un iPhone es donde vive la isla dinámica —y en casi
   cualquier Android, la cámara—. Con el hueco puesto como relleno del panel
   (§24), el primer pintado salía bien y bastaba bajar un dedo para ver el
   logotipo, la ✕ y el nombre del espacio cortados por el reloj.

   Así que el hueco de la isla lo lleva la CABECERA, que además se queda pegada:
   el resto de la lista pasa por debajo de ella, con el fondo del menú entre
   medias, y la ✕ está siempre donde se dejó — que en un cajón de pantalla
   completa es la salida que se busca con el pulgar.

   `--menu-fondo` es opaco a propósito (§6): con un fondo translúcido se leerían
   las entradas por debajo del logotipo. */
@media (max-width: 1023px) {
  .sidebar__panel .brand {
    position: sticky;
    top: 0;
    z-index: 3;
    margin-bottom: 0;
    padding-top: calc(var(--e-4) + env(safe-area-inset-top, 0px));
    padding-bottom: var(--e-3);
    background: var(--menu-fondo);
  }
  /* El selector de espacio va justo debajo y comparte el borde: sin esto se ve
     un hilo de la lista entre los dos al rodar. */
  .sidebar__panel .brand::after {
    content: "";
    position: absolute;
    left: 0; right: 0; bottom: -1px;
    height: 1px;
    background: var(--linea);
  }
}

/* ---------- 16 · Las notificaciones caben en el teléfono ----------
   El panel cuelga de la campana con 360px de ancho, anclado a su derecha. En
   un teléfono la campana no está en la esquina —a su derecha van el avatar y
   el «+»—, así que no hay 360px a su izquierda y el panel se salía por el borde
   izquierdo: los títulos de los avisos cortados a mitad de palabra. Es lo mismo
   que ya le pasó al menú del avatar (sistema.css), y se arregla igual: en el
   teléfono se pega a los dos bordes de la pantalla en vez de a su botón.

   Y en todos los anchos, que se pueda desplazar. §6 le pone `overflow: hidden`
   para recortar las esquinas redondeadas, y eso pisaba el `overflow: auto` de
   styles.css: con muchos avisos, los de abajo quedaban cortados por su
   `max-height` sin ninguna forma de llegar a ellos. */
.avisos-panel {
  overflow-y: auto;
  overscroll-behavior: contain;
  max-height: min(70vh, calc(100dvh - 140px));
}
@media (max-width: 640px) {
  .avisos-zona { position: static; }
  .avisos-panel {
    left: var(--canal);
    right: var(--canal);
    width: auto;
  }
}

/* ---------- 16b · El panel del avatar y el de espacios, también ----------
   Lo mismo que las notificaciones, y por lo mismo. `abrirMenuUsuario` le pone
   al panel del avatar el alto que queda de ventana y sistema.css le da
   `overflow-y: auto`, pero §6 le pone `overflow: hidden` para recortar las
   esquinas y, como aurora.css va la última, gana. La caja cabía y lo de abajo se
   cortaba sin barra: en un portátil, «Ayuda», «Cerrar sesión» y el pie no se
   podían alcanzar. El alto no se toca aquí: lo mide el código al abrir. */
.usuario-menu, .espacio-menu {
  overflow-y: auto;
  overscroll-behavior: contain;
}

/* ---------- 17 · El botón de modo, dentro del cajón ----------
   «Oscuro/Claro», junto al logotipo del cajón, medía 28px de alto: lo único de
   todo el cajón que no llegaba al mínimo del dedo. Tampoco se había medido
   nunca, por lo mismo que el cajón. */
@media (pointer: coarse), (max-width: 640px) {
  .modo { min-height: 44px; height: auto; }
}

/* ---------- 18 · El pie del cajón, por encima de la barra del pulgar ----------
   El cajón ocupa la pantalla entera, y la barra del pulgar va fija encima de
   todo: lo último de la lista —el nombre de la cuenta, y con él la entrada al
   panel de administración— quedaba DETRÁS de la barra, medio tapado y sin poder
   tocarse. Y el pie se separaba del resto con `margin-top: auto`, que en un
   panel alto lo manda al fondo, lejos de la última sección.

   Aquí el pie va pegado a lo que tiene encima, y el cajón reserva abajo el alto
   de la barra, igual que lo reserva el contenido de cualquier pantalla (§33.4). */

body.con-pulgar .sidebar__panel {
  padding-bottom: calc(var(--alto-tabbar) + env(safe-area-inset-bottom, 0px) + var(--e-4));
}
/* Y por encima de 1024 no hay lateral. El iPad dentro de la app es la
   experiencia de teléfono (esTelefono) y ahí el lateral dejaba de ser cajón:
   se veían las dos navegaciones a la vez, la columna y la barra. «Más» abre su
   propia hoja (js/mas.js). */
@media (min-width: 1024px) {
  body.con-pulgar .app { grid-template-columns: minmax(0, 1fr); }
  body.con-pulgar .sidebar { display: none; }
  /* Y el «+» de la cabecera, que es `.only-movil` y se escondía desde 1024:
     sin él, una tableta de 7" de lado no tenía en Movimientos forma de anotar
     a mano (el centro de la barra es Hablar). */
  body.con-pulgar .topbar__acciones.only-movil { display: flex; }
}
@media (max-width: 640px) {
  .sidebar__foot { margin-top: var(--e-3); }
}

/* ---------- 19 · Apuntar hablando ocupa la pantalla ----------
   En el teléfono es la acción principal de la barra de abajo, y lo que abre no
   es un formulario corto: es lo que se dicta, lo que se entendió, los avisos y
   los movimientos propuestos con sus importes. Como hoja al 92% se leía por una
   rendija y había que desplazar dentro de una caja dentro de otra.

   A pantalla completa, y sin esquinas redondeadas arriba: lo que ocupa todo no
   es una hoja que asoma, es una pantalla. */
@media (max-width: 640px) {
  .modal-host:has(.captura) { place-items: stretch; }
  .modal:has(.captura) {
    max-height: 100dvh;
    height: 100dvh;
    width: 100%;
    border-radius: 0;
    border: 0;
  }
  .modal:has(.captura) .modal__head::before { display: none; }
}

/* Y el contenido, arriba. `.captura` es una rejilla, y en una hoja que ahora
   mide toda la pantalla sus filas se estiraban a repartir el alto: la frase
   arriba del todo, la caja de texto flotando en mitad de la pantalla y los
   ejemplos sueltos a media altura, con huecos de doscientos píxeles entre
   ellos. Vale en los dos tamaños: una rejilla de contenido no se estira. */
.captura { align-content: start; }

/* ==========================================================================
   36 · LAS CAPAS EMPIEZAN POR SU TÍTULO
   ==========================================================================
   Lo que se abre por encima de la aplicación —una hoja, un modal, el cajón de
   «Más», el panel del avatar, las notificaciones— tiene que enseñar su
   encabezado y su primer control sin que nadie tenga que desplazarse. Lo
   gobierna js/overlay.js; aquí van las dos mitades que son de CSS.

   ---------- 36.1 · El fondo se queda quieto Y donde estaba ----------

   Antes esto era `body.menu-abierto { overflow: hidden }`, y hacía justo lo
   contrario de lo que prometía. Quien rueda en esta aplicación es el <html>;
   el <body> le PROPAGA su overflow al viewport, así que ponerlo en «hidden»
   manda la página al principio y pierde dónde estaba. Se abría «Más» desde el
   final de Movimientos y, al cerrarlo, se estaba en el encabezado: medido,
   2.437px antes de abrir y 0 después.

   Con el body fijo y subido lo que estaba desplazado, la página se queda
   EXACTAMENTE donde estaba —quieta, sin poder rodar por detrás— y al soltar
   vuelve sola. La posición la escribe js/overlay.js en `--capa-y`, que es un
   dato y no maquetación: no se puede saber desde una hoja de estilos.

   ── Y por qué NO se fija el body ──

   Fijar el body con un desplazamiento negativo es el truco clásico y aquí sale
   caro: con el body fuera del flujo, el <html> deja de tener nada que rodar y
   `position: sticky` se apaga. Medido: la cabecera pegajosa, que estaba clavada
   arriba, saltaba a su sitio natural —2.354px por encima de la pantalla— en
   cuanto se abría una hoja. O sea que arreglaba el fondo y rompía la cabecera.

   Lo que se hace es quitarle el desplazamiento AL PROPIO contenedor que rueda.
   El <html> sigue siendo el que rueda y conserva su posición, así que la
   cabecera sigue pegada y nada se mueve; lo único que se pierde es poder
   moverlo, que es justo lo que se quería. El guardado y la vuelta los hace
   js/overlay.js de todas formas, por si algún navegador lo lleva a cero.

   `touch-action: none` va sobre la aplicación y no sobre el body: en un iPhone
   `overflow: hidden` no siempre frena el dedo, y ponerlo en el body se llevaría
   por delante el desplazamiento DENTRO de la hoja, que cuelga del body igual
   que la aplicación. */
html.con-capa { overflow: hidden; overscroll-behavior: none; }
/* Y el dedo, solo sobre lo que hay DETRÁS.
 *
 * Esto decía `.app`, y dentro de `.app` viven también el cajón y el panel de
 * notificaciones: `touch-action` se hereda como una intersección —un hijo no
 * puede devolverse lo que un antepasado le quitó— así que bloqueaba el
 * desplazamiento DENTRO de las capas. En un iPhone, abrir «Más» o la campana
 * dejaba la lista sin poder moverse hasta cerrarla.
 *
 * La pantalla de detrás es #view y el pie; las capas cuelgan de la cabecera o
 * del lateral y se quedan fuera. */
html.con-capa #view,
html.con-capa .pie { touch-action: none; }
/* Y el hueco de la barra de desplazamiento se reserva SIEMPRE, no solo mientras
   hay una capa abierta.

   Lo que arreglaba antes sigue arreglado: al abrir una hoja, `overflow: hidden`
   se lleva la barra por delante y, sin hueco reservado, la página entera salta
   15px a la derecha y vuelve al cerrarla.

   Lo que arregla ahora es la otra mitad del mismo problema, que no se veía
   porque hay que abrir la hoja DESDE ABAJO para notarla: si el hueco aparece y
   desaparece con la capa, el ancho útil del contenido cambia en ese mismo
   instante. Y cuando el ancho cambia, el texto vuelve a repartirse en líneas: un
   párrafo pasa de dos a tres, el documento crece o mengua, y la página —que
   estaba al final— se recoloca. El fondo se movía entre 9 y 70 píxeles al abrir
   ocho hojas distintas, y ninguna tenía nada que ver con las otras.

   Reservado siempre, el ancho es el mismo antes, durante y después: no hay nada
   que reflowear. De regalo se va un salto que tampoco se buscaba — el de navegar
   de una pantalla que rueda a una que no.

   Sigue bajo `pointer: fine` porque `scrollbar-gutter` es para las barras que
   OCUPAN sitio; donde son superpuestas —un teléfono— no reserva nada. */
@media (pointer: fine) {
  html { scrollbar-gutter: stable; }
}

/* ---------- 36.2 · Una hoja nunca es más alta que su hueco ----------

   Esta es la avería que no se veía desde un ordenador, y la que explica el
   síntoma raro: la hoja abierta por la MITAD, con el título por encima del
   borde y sin forma de subir hasta él.

   `.modal-host` es `position: fixed; inset: 0`, o sea que mide el viewport
   PEQUEÑO: el que queda con la barra del navegador puesta. La hoja de dentro
   se recortaba con `92dvh`, y `dvh` es el viewport DINÁMICO, que con la barra
   retraída es mayor. En un teléfono de verdad, con la barra a la vista, la hoja
   salía más alta que su hueco — y como en móvil el hueco alinea abajo, lo que
   se sale es la cabecera, POR ARRIBA, donde ningún scroll llega (es el fallo
   clásico de centrar dentro de un contenedor con overflow).

   En un Chrome sin ventana no hay barra que se esconda, así que las dos
   unidades coincidían y la auditoría salía verde midiendo el caso bueno.

   La cuenta correcta es en PORCENTAJE del hueco, que ya es exactamente el
   viewport: 100% no puede salirse de 100%, mida lo que mida. */
.modal { max-height: calc(100% - 2 * var(--e-6)); }
/* De lado, el cromo de la hoja se comía la hoja. Con 360px de alto quedaban
   272 para el modal, y la cabecera (89), el pie (83), el relleno y los huecos
   que aún vienen de styles.css pedían 300 antes de enseñar una sola línea: el
   pie salía cortado y el cuerpo, que es lo que se viene a rellenar, en cero.
   Aquí el cromo se aprieta y el cuerpo se queda con lo que sobra. Por alto y
   no por orientación: una ventana aplastada tiene el mismo problema. */
@media (max-height: 520px) {
  .modal { gap: var(--e-2); }
  .modal__head { padding-top: var(--e-3); padding-bottom: var(--e-3); }
  .modal__body { padding-top: var(--e-4); padding-bottom: var(--e-4); }
  .modal__foot { padding-top: var(--e-2); }
}
/* Y lo de abajo y alrededor, solo donde la hoja es un cuadro centrado. Por
   debajo de 620 sube desde abajo, y el relleno inferior de la hoja y de su pie
   lleva el de la barra de inicio del iPhone (la regla de la hoja inferior,
   más arriba): pisarlo metería los botones debajo. */
@media (max-height: 520px) and (min-width: 621px) {
  .modal-host { padding: var(--e-2); }
  .modal { max-height: calc(100% - 2 * var(--e-2)); }
  .modal__foot { padding-bottom: var(--e-2); }
}
@media (max-width: 620px) {
  .modal { max-height: 92%; }
  /* Y la de apuntar hablando, que ocupa la pantalla entera. */
  .modal:has(.captura) { max-height: 100%; height: 100%; }
}

/* ---------- 36.3 · Un solo sitio por donde rodar ----------

   El hueco tenía `overflow: auto` y la hoja de dentro también rueda por su
   cuerpo. Dos barras pegadas es el «doble scroll» que hace que el dedo mueva la
   que no era. Con el recorte de arriba la hoja ya no puede desbordar el hueco,
   así que el hueco no necesita rodar: lo hace el cuerpo, que es el que tiene la
   cabecera y el pie quietos a los lados. */
.modal-host { overflow: hidden; }

/* ---------- 36.4 · El título, al enfocarlo, no se disfraza de campo ----------
   js/overlay.js le pone `tabindex="-1"` para poder anunciarlo. Sin esto,
   enfocarlo pinta el anillo de foco de un control, que ahí no significa nada:
   no hay nada que escribir. El anillo sigue saliendo para quien navega con
   teclado de verdad (`:focus-visible`). */
[data-titulo-capa]:focus { outline: none; }

/* ---------- 36.5 · El cajón y los paneles también ----------
   El cajón lateral tenía su propio bloqueo (`body.menu-abierto`) y era el que
   perdía la posición. Ahora comparte el de arriba, así que lo único que queda
   suyo es que su panel ruede por dentro y empiece por su cabecera. */
.sidebar__panel, .usuario-menu, .espacio-menu, .avisos-panel { overscroll-behavior: contain; }

/* ==========================================================================
   37 · HABLAR CON OBI (teléfono) Y CENTRO DE CAPTURA (escritorio)
   ==========================================================================
   Dos experiencias sobre el mismo núcleo (js/conversacion.js), y a propósito
   no se parecen:

   · En el TELÉFONO es una conversación a pantalla completa. El micrófono es lo
     principal, abajo y en el centro, donde está el pulgar; el estado se dice
     con palabras arriba; lo que se apunta aparece en fichas dentro del hilo.
   · En el ESCRITORIO es un panel ancho a la derecha con tres columnas: lo que
     tienes delante, la conversación y una tabla editable de lo detectado.

   Estados con color Y palabra (§9): verde guardado, ámbar falta algo, violeta
   aún no pasó (pendiente de revisar), coral fallo. El color va en un punto al
   lado del texto y no en el texto: así la letra tiene siempre el contraste de
   la tinta. */

/* ---------- 37.1 · La hoja del teléfono ocupa la pantalla ---------- */
.modal.modal--hablar .modal__body {
  display: flex;
  flex-direction: column;
  min-height: 0;
  overflow: hidden;
}
/* Sin @media de ancho: «Hablar» solo se abre en un TELÉFONO (esTelefono), y de
   lado —ancho de 844— tiene que seguir siendo la hoja del teléfono. */
  .modal-host:has(.modal--hablar) { place-items: end stretch; }
  .modal.modal--hablar {
    width: 100%;
    height: 100%;
    max-height: 100%;
    border: 0;
    border-radius: 0;
  }
  .modal--hablar .modal__head::before { display: none; }
  .modal--hablar .modal__head { padding-top: calc(var(--e-4) + env(safe-area-inset-top, 0px)); }

  /* COMPACTA al abrir: una hoja que asoma, con el estado, los ejemplos y el
     micrófono. Deja ver que detrás sigue la pantalla de donde se vino y que esto
     se va con un gesto. En cuanto se escucha, se escribe o hay conversación, pasa
     a ocupar la pantalla (js/hablar.js), y también arrastrando el asidero hacia
     arriba (js/hoja-arrastre.js). Se mide en % del hueco, no en dvh (§36.2). */
  .modal.modal--hablar[data-altura="compacta"] {
    height: min(36rem, 78%);
    border-top: 1px solid var(--linea-fuerte);
    border-radius: var(--r-xl) var(--r-xl) 0 0;
  }
  .modal--hablar[data-altura="compacta"] .modal__head::before { display: block; }
  .modal--hablar[data-altura="compacta"] .modal__head { padding-top: var(--e-6); }
  @media (prefers-reduced-motion: no-preference) {
    .modal.modal--hablar { transition: height 240ms var(--curva-out), border-radius 240ms var(--curva-out); }
  }

  /* Todo lo que se toca aquí mide 48px (DESIGN.md §9, `--tactil`), también los
     botones pequeños de las fichas y los campos de corregir: esta pantalla se usa
     de pie y con una mano, que es cuando más se falla un toque. */
  .modal--hablar .btn,
  .modal--hablar .input,
  .modal--hablar select,
  .modal--hablar textarea { min-height: var(--tactil); }
/* fin de la hoja del teléfono (sin @media de ancho) */
/* Con el teléfono de lado no hay alto para asomar: directamente entera. */
@media (max-width: 640px) and (max-height: 520px), (max-height: 520px) and (pointer: coarse) {
  .modal.modal--hablar[data-altura="compacta"] { height: 100%; border-radius: 0; }
}

/* (Aquí iba la altura de «Hablar» por encima de 641px: ya no se abre fuera
   de un teléfono —esTelefono()—, así que no hay otra altura que darle.) */


.hablar {
  display: flex;
  flex-direction: column;
  gap: var(--e-3);
  flex: 1 1 auto;
  min-height: 0;
  min-width: 0;
}

.hablar__estado {
  display: flex;
  align-items: center;
  gap: var(--e-3);
  padding: var(--e-3) var(--e-4);
  border-radius: var(--r-lg);
  background: var(--capa-2);
  box-shadow: var(--sombra-1);
  min-width: 0;
}
.hablar__estado-texto { display: grid; gap: 2px; min-width: 0; }
.hablar__rotulo { font-size: var(--t-cuerpo); font-weight: 700; color: var(--txt); }
.hablar__detalle { font-size: var(--t-meta); color: var(--txt-2); overflow-wrap: anywhere; }

/* La luz del micrófono. ACOMPAÑA al texto de al lado, nunca lo sustituye. */
.hablar__luz {
  flex: none;
  width: 0.875rem;
  height: 0.875rem;
  border-radius: var(--r-full);
  background: var(--txt-3);
}
.hablar__luz[data-estado="escuchando"] {
  background: var(--ok);
  box-shadow: 0 0 0 0.25rem color-mix(in srgb, var(--ok) 28%, transparent);
}
.hablar__luz[data-estado="pausado"],
.hablar__luz[data-estado="pidiendo-permiso"] { background: var(--futuro); }
.hablar__luz[data-estado="procesando"],
.hablar__luz[data-estado="reconectando"] { background: var(--alerta); }
.hablar__luz[data-estado="permiso-rechazado"],
.hablar__luz[data-estado="no-disponible"],
.hablar__luz[data-estado="error"] { background: var(--peligro); }
@media (prefers-reduced-motion: no-preference) {
  .hablar__luz[data-estado="escuchando"] { animation: hablar-late 1.4s var(--curva) infinite; }
  .hablar__luz[data-estado="procesando"] { animation: hablar-late 0.9s var(--curva) infinite; }
}
@keyframes hablar-late {
  50% { box-shadow: 0 0 0 0.5rem color-mix(in srgb, var(--ok) 8%, transparent); }
}

/* Lo que se va entendiendo: más suave que lo ya dicho, para que se lea como
   provisional. */
.hablar__parcial {
  margin: 0;
  padding: 0 var(--e-2);
  color: var(--txt-2);
  font-style: italic;
  overflow-wrap: anywhere;
}

/* El hilo es lo ÚNICO que rueda. La cabecera, el estado y los mandos se quedan
   quietos: son lo que hay que tener siempre a mano. */
.hablar__hilo {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  display: flex;
  flex-direction: column;
  gap: var(--e-3);
  padding: var(--e-1) var(--e-1) var(--e-3);
}
.hablar__intro { display: grid; gap: var(--e-2); color: var(--txt-2); }
.hablar__intro p { margin: 0; }
.hablar__intro-texto { color: var(--txt); }
.hablar__pista { font-size: var(--t-meta); color: var(--txt-3); }
.hablar__ejemplos { margin: 0; padding-left: var(--e-4); display: grid; gap: var(--e-1); }
.hablar__privacidad { font-size: var(--t-meta); color: var(--txt-3); }
.hablar__yo { align-self: flex-end; max-width: 85%; }
.hablar__nota { min-width: 0; }
.hablar__resumen { margin: 0; font-size: var(--t-meta); color: var(--txt-2); }

.hablar__escribir { display: flex; align-items: flex-end; gap: var(--e-2); min-width: 0; }
.hablar__caja {
  flex: 1 1 auto;
  min-width: 0;
  /* 1rem y no menos: por debajo, Safari amplía la página al enfocar. */
  font-size: 1rem;
  resize: none;
}

/* ---------- 37.1b · Escribir, en el teléfono ----------

   En una fila, la caja y «Enviar» se reparten 328 píxeles: la caja se queda en
   185 y el marcador de posición —«Escribe lo que quieras apuntar o
   preguntar»— sale en dos líneas partidas por la mitad. Escribir una frase de
   verdad ahí es escribir por una ranura, y esto es la pantalla que SUSTITUYE al
   dictado cuando no hay micrófono: es donde más se escribe de toda la app.

   Así que la caja se lleva la fila entera y el botón baja debajo, pegado a la
   derecha, que es donde cae el pulgar. Cuesta 48 píxeles de alto y los paga con
   creces. En el escritorio no cambia nada: ahí la fila mide 500 y sobra. */
@media (max-width: 640px) {
  .hablar__escribir { flex-wrap: wrap; }
  .hablar__caja { flex: 1 1 100%; }
  .hablar__enviar { margin-left: auto; }
}

/* Los mandos, en la zona del pulgar: lo secundario a los lados y el micrófono
   en el centro. En rejilla y no en fila flexible: el modal pone su pie en
   columna en los teléfonos, y aquí el orden es parte del diseño. */
.modal--hablar .modal__foot {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: var(--e-3);
}
.hablar__pie-lado { display: flex; flex-wrap: wrap; gap: var(--e-2); min-width: 0; }
.hablar__pie-lado--fin { justify-content: flex-end; }
.modal--hablar .modal__foot .hablar__boton { flex: 0 1 auto; width: auto; min-height: 3rem; }

.hablar__mic {
  width: 4.5rem;
  height: 4.5rem;
  border: 0;
  border-radius: var(--r-full);
  display: grid;
  place-items: center;
  align-content: center;
  gap: 2px;
  background: var(--grad-accion);
  color: #fff;
  box-shadow: var(--sombra-2);
  cursor: pointer;
}
.hablar__mic-ico { width: 1.75rem; height: 1.75rem; }
.hablar__mic-txt { font-size: var(--t-micro); font-weight: 700; }
.hablar__mic[aria-pressed="true"] {
  box-shadow: 0 0 0 0.3rem color-mix(in srgb, var(--ok) 35%, transparent), var(--sombra-2);
}
.hablar__mic:disabled {
  background: var(--capa-3);
  color: var(--txt-2);
  box-shadow: none;
  cursor: default;
}

/* ---------- 37.2 · Las fichas de movimiento ---------- */
.ficha {
  display: grid;
  gap: var(--e-1);
  margin-top: var(--e-2);
  padding: var(--e-3) var(--e-4);
  border-radius: var(--r-lg);
  background: var(--capa-2);
  box-shadow: var(--sombra-1);
  min-width: 0;
}
.ficha__cabeza { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--e-1) var(--e-3); min-width: 0; }
.ficha__n { font-size: var(--t-meta); color: var(--txt-3); font-variant-numeric: tabular-nums; }
.ficha__tipo { font-size: var(--t-meta); color: var(--txt-2); }
.ficha__monto { font-size: var(--t-tarjeta); font-weight: 800; font-variant-numeric: tabular-nums; }
.ficha__que { margin: 0; font-weight: 600; overflow-wrap: anywhere; }
.ficha__meta { margin: 0; font-size: var(--t-meta); color: var(--txt-2); overflow-wrap: anywhere; }
.ficha__acciones { display: flex; flex-wrap: wrap; gap: var(--e-2); margin-top: var(--e-2); }
.ficha__editor { display: flex; gap: var(--e-2); flex: 1 1 100%; min-width: 0; }
.ficha__editor .input { flex: 1 1 auto; min-width: 0; font-size: 1rem; }
.ficha__form { display: grid; gap: var(--e-3); }
.ficha__form .input, .ficha__form select { font-size: 1rem; }
.ficha[data-estado="eliminado"], .ficha[data-estado="deshecho"] { opacity: .65; }
.ficha[data-estado="eliminado"] .ficha__que,
.ficha[data-estado="deshecho"] .ficha__que { text-decoration: line-through; }

/* El estado: la palabra en tinta, y el punto de color al lado. */
.ficha__estado {
  display: inline-flex;
  align-items: center;
  gap: var(--e-1);
  margin-left: auto;
  padding: 2px var(--e-2);
  border-radius: var(--r-full);
  background: var(--capa-3);
  color: var(--txt);
  font-size: var(--t-meta);
  font-weight: 600;
  white-space: nowrap;
}
.ficha__estado::before {
  content: "";
  width: 0.5rem;
  height: 0.5rem;
  border-radius: var(--r-full);
  background: var(--txt-3);
}
.ficha__estado[data-estado="guardado"]::before { background: var(--ok); }
.ficha__estado[data-estado="incompleto"]::before { background: var(--alerta); }
.ficha__estado[data-estado="revision"]::before,
.ficha__estado[data-estado="pendiente"]::before { background: var(--futuro); }

/* ---------- 37.3 · El Centro de captura: un panel a la derecha ---------- */
@media (min-width: 641px) {
  /* Velo más ligero y sin desenfoque: la pantalla de detrás sigue siendo la que
     se trabaja, y taparla del todo la convertiría en una hoja cualquiera. */
  .modal-host:has(.modal--centro) {
    place-items: stretch end;
    padding: 0;
    background: color-mix(in srgb, var(--bg) 35%, transparent);
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
  }
  .modal.modal--centro {
    width: min(78rem, 96vw);
    height: 100%;
    max-height: 100%;
    border-radius: var(--r-xl) 0 0 var(--r-xl);
    border-right: 0;
  }
}
.modal--centro .modal__body {
  display: flex;
  flex-direction: column;
  min-height: 0;
  overflow: hidden;
  padding: var(--e-5);
}

.centro {
  flex: 1 1 auto;
  min-height: 0;
  display: grid;
  grid-template-columns: minmax(12rem, 15rem) minmax(18rem, 1fr) minmax(26rem, 1.45fr);
  gap: var(--e-5);
}
.centro > * { min-width: 0; min-height: 0; }
.centro[data-soltar="si"] { outline: 2px dashed var(--marca); outline-offset: calc(-1 * var(--e-2)); }

.centro__contexto {
  overflow-y: auto;
  overscroll-behavior: contain;
  display: grid;
  align-content: start;
  gap: var(--e-3);
}
.centro__bloque {
  display: grid;
  gap: var(--e-2);
  padding: var(--e-3);
  border-radius: var(--r-lg);
  background: var(--capa-2);
}
.centro__bloque-titulo { margin: 0; font-size: var(--t-meta); font-weight: 700; color: var(--txt-2); }
.centro__periodo { margin: 0; font-weight: 600; }
.centro__lista { margin: 0; padding: 0; list-style: none; display: grid; gap: var(--e-2); }
.centro__dato {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 0 var(--e-2);
  font-size: var(--t-secundario);
}
.centro__dato-nombre { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.centro__dato-cifra { font-variant-numeric: tabular-nums; font-weight: 600; }
.centro__dato-pie { grid-column: 1 / -1; font-size: var(--t-meta); color: var(--txt-3); }
.centro__vacio { margin: 0; font-size: var(--t-secundario); color: var(--txt-2); }

.centro__charla { display: flex; flex-direction: column; gap: var(--e-3); }
.centro__hilo {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  display: flex;
  flex-direction: column;
  gap: var(--e-3);
}
.centro__intro { display: grid; gap: var(--e-2); color: var(--txt-2); }
.centro__intro p { margin: 0; }
.centro__estado { margin: 0; min-height: 1.4em; font-size: var(--t-meta); color: var(--txt-2); }
.centro__entrada {
  display: grid;
  gap: var(--e-2);
  padding: var(--e-3);
  border-radius: var(--r-lg);
  background: var(--capa-2);
  box-shadow: var(--sombra-1);
}
.centro__caja { width: 100%; resize: vertical; min-height: 4.5rem; }
.centro__entrada-pie { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--e-2); }
.centro__pista { margin: 0; font-size: var(--t-meta); color: var(--txt-3); }
.centro__botones { display: flex; gap: var(--e-2); }

.centro__lote { display: flex; flex-direction: column; gap: var(--e-3); }
.centro__lote-cabeza { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--e-2) var(--e-3); }
.centro__lote-cabeza h3 { margin: 0; font-size: var(--t-tarjeta); font-weight: 800; }
.centro__cuenta { font-size: var(--t-meta); color: var(--txt-2); }
.centro__lote-barra { display: flex; flex-wrap: wrap; align-items: center; gap: var(--e-2); }
.centro__lote-barra select { width: auto; max-width: 12rem; }
.centro__lote-barra .btn--primary { margin-left: auto; }
.centro__tabla-caja {
  flex: 1 1 auto;
  min-height: 0;
  overflow: auto;
  overscroll-behavior: contain;
  border-radius: var(--r-lg);
  background: var(--capa-1);
}
.centro__tabla { width: 100%; border-collapse: separate; border-spacing: 0; font-size: var(--t-secundario); }
.centro__tabla th {
  position: sticky;
  top: 0;
  z-index: 1;
  padding: var(--e-2);
  background: var(--capa-3);
  color: var(--txt-2);
  font-size: var(--t-meta);
  font-weight: 700;
  text-align: left;
  white-space: nowrap;
}
.centro__tabla td { padding: var(--e-1) var(--e-2); border-top: 1px solid var(--linea); vertical-align: middle; }
.centro__tabla td .input, .centro__tabla td select { width: 100%; min-width: 6.5rem; }
.centro__tabla .centro__monto { min-width: 6rem; text-align: right; font-variant-numeric: tabular-nums; }
.centro__tabla tr:focus-within td { background: var(--capa-hover); }
.centro__tabla tr[data-estado="eliminado"] td,
.centro__tabla tr[data-estado="deshecho"] td { opacity: .6; }

/* Escritorio más estrecho: el contexto sube a una franja arriba y la
   conversación y la tabla se quedan lado a lado. */
@media (max-width: 1180px) {
  .centro { grid-template-columns: minmax(16rem, 1fr) minmax(24rem, 1.4fr); grid-template-rows: auto minmax(0, 1fr); }
  .centro__contexto {
    grid-column: 1 / -1;
    grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
    max-height: 12rem;
  }
}
/* Y en una ventana estrecha, una sola columna que rueda entera: con tres
   bloques apilados, que cada uno rodara por dentro serían tres barras. */
@media (max-width: 900px) {
  .modal--centro .modal__body { overflow-y: auto; }
  .centro { grid-template-columns: minmax(0, 1fr); grid-template-rows: none; }
  .centro__contexto, .centro__tabla-caja { max-height: none; overflow: visible; }
  .centro__hilo { max-height: 24rem; }
}

/* ══════════════════ Entrar con Google o con Apple ══════════════════
 *
 * Dos botones debajo del formulario de siempre, separados por un «o». Van
 * DESPUÉS de la contraseña y no antes a propósito: quien ya tiene cuenta aquí
 * entra con su correo, y poner los proveedores arriba empuja a crear una segunda
 * cuenta con el mismo correo — que es justo lo que el camino de vinculación
 * existe para arreglar después.
 *
 * Del mismo alto y del mismo ancho que el botón principal, para que ninguno
 * parezca el camino bueno. Lo que los distingue es la marca, no el tamaño. */
.entrada__otras { display: grid; gap: var(--e-2); }

.con-proveedor__o {
  display: grid; grid-template-columns: 1fr auto 1fr; align-items: center;
  gap: var(--e-3);
  margin: var(--e-2) 0;
  color: var(--txt-3);
  font-size: var(--t-mini);
}
/* Las dos rayas del «o» se pintan con pseudoelementos y no con tres nodos: es
   decoración y no tiene por qué existir en el árbol que lee un lector de
   pantalla. */
.con-proveedor__o::before, .con-proveedor__o::after {
  content: ''; height: 1px; background: var(--linea);
}

.con-proveedor {
  display: flex; align-items: center; justify-content: center; gap: var(--e-2);
  width: 100%; min-height: var(--control-alto);
  padding: 0 var(--e-5);
  border: 1px solid var(--linea-fuerte);
  border-radius: var(--r-sm);
  background: var(--capa-1);
  color: var(--txt);
  font: inherit; font-weight: 600;
  cursor: pointer;
  transition: background var(--rapido) var(--curva), border-color var(--rapido) var(--curva);
}
.con-proveedor:hover { background: var(--capa-2); border-color: var(--txt-3); }
.con-proveedor:active { transform: scale(.985); }
.con-proveedor:disabled { opacity: .55; cursor: progress; }
.con-proveedor:focus-visible { outline: 2px solid var(--marca); outline-offset: 2px; }
.con-proveedor svg { flex: 0 0 auto; }
.como-entras { display: grid; gap: var(--e-1); margin-bottom: var(--e-4); }
.como-entras__titulo { margin: 0; font-size: var(--t-mini); }
.como-entras__fila {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--e-2); min-height: 2rem;
}
.como-entras__que { min-width: 0; }
.como-entras__nota { margin: var(--e-1) 0 0; font-size: var(--t-mini); }
/* Cuando la vuelta de Google o Apple no acabó en sesión. Coral y con `role=alert`:
   quien llega aquí no sabe por qué sigue fuera. */
.con-proveedor__fallo {
  margin: 0 0 var(--e-2);
  color: var(--peligro-txt);
  font-size: var(--t-mini);
  text-align: center;
}

/* ==========================================================================
   38 · LA OFERTA DE AVISOS, AL ENTRAR EN EL TELÉFONO
   ==========================================================================
   La pasarela de la puerta vive en styles.css, con el resto de la puerta: usa
   la paleta de tinta que declara `.portada`, no las fichas de la aplicación. */
.avisos-oferta { display: grid; gap: var(--e-3); }
.avisos-oferta p { margin: 0; }
.avisos-oferta__lista {
  margin: 0;
  padding-left: var(--e-5);
  display: grid;
  gap: var(--e-1);
  color: var(--txt-2);
}

/* ==========================================================================
   39 · EL CERROJO: OBI BLOQUEADA
   ==========================================================================
   Tapa la aplicación entera mientras se pide la cara o la huella. Opaca del
   todo y sin transparencias: media tarjeta de saldo asomando por detrás sería
   enseñar justo lo que el cerrojo existe para tapar.

   El z-index (120) va por encima del hueco de los modales (80), de la pantalla
   de arranque (90) y de los avisos flotantes (95): al arrancar puede quedar
   algo abierto de la sesión anterior. */
.bloqueo {
  position: fixed;
  inset: 0;
  z-index: 120;
  display: grid;
  place-items: center;
  padding: max(var(--e-5), env(safe-area-inset-top)) var(--e-4)
           max(var(--e-5), env(safe-area-inset-bottom));
  background: var(--bg);
}
.bloqueo__caja {
  display: grid;
  gap: var(--e-3);
  justify-items: center;
  text-align: center;
  width: min(22rem, 100%);
}
.bloqueo__marca { margin-bottom: var(--e-2); }
.bloqueo__titulo { margin: 0; font-size: var(--t-pagina); }
.bloqueo__texto { margin: 0; color: var(--txt-2); }
/* Los dos botones, a lo ancho y con el tamaño del dedo: esta pantalla se usa de
   pie y con una mano. */
.bloqueo__btn { width: 100%; min-height: var(--tactil); justify-content: center; }
/* De quién es la sesión que se va a abrir. Solo sale cuando se pide la
   contraseña: con la cara o el dedo lo confirma el propio teléfono. */
.bloqueo__quien {
  margin: 0;
  color: var(--txt-3);
  font-size: var(--t-mini);
}
/* El campo, del ancho de los botones y del tamaño del dedo. 1rem para que Safari
   no amplíe la página al enfocarlo (§33.1) — y aquí se notaría el doble, porque
   es lo primero que se ve al volver a la aplicación. */
.bloqueo__clave {
  width: 100%;
  min-height: var(--tactil);
  font-size: 1rem;
  text-align: center;
}
.bloqueo__error:empty { display: none; }
.bloqueo__error {
  margin: 0;
  color: var(--peligro-txt);
  font-size: var(--t-mini);
}
/* Nada de detrás rueda mientras está puesto. */
html.con-bloqueo, html.con-bloqueo body { overflow: hidden; }


/* ==========================================================================
   40 · EN TÁCTIL NO HAY «ENCIMA»
   ==========================================================================
   El fallo se ve así: se abre «Más», se baja la lista con el dedo, y las
   entradas por las que pasa el dedo SE QUEDAN encendidas. Parecen elegidas, y
   al soltar sigue habiendo dos o tres iluminadas que no llevan a ninguna parte.
   Con varias encendidas a la vez, la lista deja de decir dónde estás.

   No es un fallo nuestro: es cómo funciona `:hover` sin ratón. El navegador del
   teléfono le da el estado «encima» al elemento que hay bajo el dedo y NO se lo
   quita hasta que se toca otra cosa. Cada regla de esta hoja pensada para el
   ratón se convierte, en un teléfono, en un rastro de lo que se acaba de rozar.

   Así que donde no hay ratón —`hover: none`— el «encima» no existe. Lo que sí
   se queda es `:active`, que es respuesta al toque y dura lo que dura el dedo;
   y `[aria-current]`, que es dónde estás de verdad.

   ══════════════════ Al añadir una pieza que se toque ══════════════════
   Si lleva `:hover` y vive dentro de algo que RUEDA —una lista, un menú, una
   tabla, un carrusel— se añade aquí. La prueba es esa: ¿puede pasar un dedo por
   encima sin querer pulsarla? Entonces no puede quedarse encendida. */
@media (hover: none) {
  /* La carcasa: el cajón, los dos menús que cuelgan de la cabecera y el pie. */
  .nav__item:hover,
  .usuario-menu__item:hover,
  .espacio-menu__item:hover,
  .panel-usuario__espacio:hover,
  .pie__enlaces button:hover,
  .saltos__ir:hover { background: transparent; color: var(--txt-2); }

  .espacio-sel:hover,
  .usuario:hover { background: transparent; border-color: var(--linea); }
  .icono-btn:hover,
  .avisos-btn:hover { background: transparent; color: var(--txt-2); }

  /* Las filas de las listas largas, que es por donde más se rueda. */
  .mov-fila:hover,
  .data tbody tr:hover,
  button.reparto__fila:hover,
  .por-venir__fila:hover,
  .fila-com--abre:hover,
  .sus:hover,
  .persona:hover,
  .con-proveedor:hover,
  .ia__sugerencias[data-compacto="no"] .ia__sugerencia:hover { background: transparent; }
  .con-proveedor:hover { border-color: var(--linea); }

  /* Y lo que se levantaba o crecía al pasar por encima: en un teléfono eso es
     una tarjeta que se mueve sola mientras se baja la pantalla. */
  .tarjeta-cuenta:hover,
  .calor__dia:hover,
  .fab:hover { transform: none; box-shadow: var(--sombra-2); }
  .tarjeta-cuenta:hover { box-shadow: var(--sombra-2); }
  .calor__dia:hover { box-shadow: none; }
  .insight:hover,
  .card--accion:hover,
  .indice__tarjeta:hover { border-color: var(--linea); transform: none; }

  /* Los botones y los campos. Un botón que se queda con el fondo del ratón
     después de rozarlo parece pulsado y no lo está. */
  /* Sin el principal ni el de peligro: esta regla va DESPUÉS de la suya y con la
     misma fuerza, así que les ganaba y un botón principal tocado se quedaba sin
     su degradado —transparente y con el texto del fondo, como uno cualquiera—. */
  .btn:not(.btn--primary):not(.btn-primary):not(.btn--danger):hover,
  .btn--ghost:hover,
  button.chip-cat:hover { background: transparent; border-color: var(--linea); color: inherit; }
  .btn--primary:hover, .btn-primary:hover { filter: none; }
  .btn--danger:hover { filter: none; }
  .input:hover, select:hover, textarea:hover { border-color: var(--linea); }

  /* Los que faltaban: lo que cambiaba de color o de sombra al rozarlo y se
     quedaba así. Cada uno vuelve a su valor de reposo. */
  .dropzone:hover, .zona-subida:hover { border-color: var(--linea-fuerte); background: var(--capa-1); }
  .franja__accion:hover { box-shadow: none; }
  .insight__accion:hover { text-decoration: none; }
  .nomina__quien:hover strong,
  .cartera__quien:hover strong,
  .alm__que:hover strong { color: inherit; }
  .data .sortable:hover { color: inherit; }

  /* Y ningún destello gris del sistema encima de todo esto: Android lo pinta
     sobre cualquier elemento pulsable, incluida una fila entera. */
  .nav__item, .usuario-menu__item, .espacio-menu__item, .pie__enlaces button,
  .mov-fila, .sus, .persona, .por-venir__fila, .fila-com, .con-proveedor,
  .espacio-sel, .usuario, .icono-btn, .avisos-btn, .btn, .chip-cat,
  .pulgar__btn, .card__head[aria-expanded], .seccion__head[aria-expanded] {
    -webkit-tap-highlight-color: transparent;
  }

  /* Y el rótulo de una entrada de menú no se selecciona.
   *
   * El otro «se me quedan marcadas»: bajar la lista con el dedo un poco despacio
   * es, para el navegador, empezar a seleccionar texto — sale el resaltado azul
   * del sistema sobre «Pagos fijos» y con él las dos manijas de selección, que
   * hay que quitar tocando en otro sitio. Es lo mismo que evitan todas las
   * aplicaciones en sus menús: el nombre de una sección no es texto que nadie
   * vaya a copiar, es una etiqueta.
   *
   * Solo en la NAVEGACIÓN. En una lista de movimientos el texto sí se copia —el
   * nombre de un comercio, una referencia— y quitarlo ahí sería quitar algo que
   * se usa. */
  .nav__item, .nav__grupo-rotulo, .usuario-menu__item, .espacio-menu__item,
  .pulgar__btn, .saltos__ir, .pie__enlaces button, .espacio-sel, .usuario {
    -webkit-user-select: none;
    user-select: none;
    -webkit-touch-callout: none;
  }
}


/* ==========================================================================
   41 · EL VELO DE LAS CAPAS DE LA CABECERA
   ==========================================================================
   La campana, el panel del avatar y el selector de espacio bloquean el fondo
   —lo hace la puerta de capas, igual que con cualquier hoja— y hasta ahora no
   enseñaban NADA que lo explicara. En un teléfono se veía así: se abren los
   avisos, se intenta seguir leyendo la pantalla de detrás, no se mueve, se
   insiste, sigue sin moverse. Parece que la aplicación se ha colgado.

   Y el «toca fuera para cerrar» que ya había no salvaba el caso, porque lo que
   se hace con el dedo para mover una pantalla no es un clic: es un arrastre, y
   un arrastre no dispara `click`. O sea que el único gesto que la persona
   intentaba era justo el que no cerraba nada.

   Con velo, las dos cosas se arreglan a la vez: se ve que hay algo delante, y
   tocarlo o arrastrarlo lo cierra (js/app.js, `capa()`).

   ══════════════════ Por qué queda por DEBAJO de la cabecera ══════════════════
   Estas tres capas cuelgan de sus botones, que viven en la cabecera. Si el velo
   tapara también la cabecera, taparía el botón que acaba de abrirla —y volver a
   pulsar la campana es la forma más natural de cerrarla—. Así que el velo se
   queda entre la página y la cabecera: 46, y la cabecera sube a 48 mientras dura.

   ══════════════════ Y los dos DENTRO de `.app` ══════════════════
   `.app` lleva `position: relative; z-index: 1`, o sea que es un contexto de
   apilamiento: sus hijos se ordenan entre ellos, pero frente al documento la
   aplicación entera vale 1. Con el velo colgando del <body> —como nació— tapaba
   la aplicación ENTERA, cabecera incluida, y el panel se abría por debajo: se
   veía el desenfoque y nada más. Subirle el z-index a la cabecera no arreglaba
   nada, porque el tope lo pone `.app`. Ver el comentario de index.html. */
.velo-capa {
  position: fixed;
  inset: 0;
  z-index: 46;
  background: color-mix(in srgb, var(--bg) 55%, transparent);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
}
.velo-capa[hidden] { display: none; }
/* Mientras hay velo, la cabecera y su capa van por encima de él. */
body.con-capa-cabecera .topbar { z-index: 48; }
/* Y el LATERAL, porque el selector de espacio no vive en la cabecera sino ahí.
 *
 * Sube el lateral entero y no la zona del selector, y la razón es la regla de
 * CSS que hace que estos fallos sean tan difíciles de ver: `position: sticky`
 * crea un contexto de apilamiento SIEMPRE, también sin z-index. `.sidebar` es
 * sticky, así que todo lo que tiene dentro queda encerrado en su nivel —da igual
 * que al desplegable se le pongan 48 o 600: frente al velo, el lateral entero
 * vale lo que valga el lateral—.
 *
 * Es también por lo que la cabecera sí funcionaba: es sticky igual, pero a ella
 * se le da un z-index explícito.
 *
 * Solo en escritorio: por debajo de 1024 el lateral es un cajón con su propio
 * z-index 50 y su propio velo, y ahí no hay nada que arreglar. */
@media (min-width: 1024px) {
  body.con-capa-cabecera .sidebar { z-index: 48; }
}
@media (prefers-reduced-transparency: reduce) {
  .velo-capa {
    backdrop-filter: none; -webkit-backdrop-filter: none;
    background: color-mix(in srgb, var(--bg) 85%, transparent);
  }
}
@media (prefers-reduced-motion: no-preference) {
  .velo-capa { animation: velo-entra 140ms var(--curva-out); }
  @keyframes velo-entra { from { opacity: 0; } }
}


/* ==========================================================================
   42 · EN EL TELÉFONO NO ES UNA PÁGINA WEB
   ==========================================================================
   Lo que pasó: anotar un movimiento y que la pantalla se fuera de zoom sola. No
   lo hizo ningún campo —los campos ya llevan letra de 16px por §33.1, que es lo
   que evita el zoom de Safari al enfocarlos— sino el DOBLE TOQUE.

   Un navegador, al recibir dos toques seguidos, hace zoom. Es una herencia de
   cuando las páginas venían pensadas para un monitor y había que acercarse a
   leerlas. En una aplicación no significa nada: dos toques seguidos sobre
   «Guardar» son dos intentos de guardar, no una petición de acercar la vista.

   `touch-action: manipulation` dice exactamente eso: de los gestos de esta
   pieza, atiende el desplazamiento y el pellizco, y OLVIDA el doble toque. De
   regalo quita el retardo de 300 ms que el navegador se tomaba para ver si venía
   un segundo toque, así que los botones responden al instante.

   ══════════════════ El pellizco: en la pestaña sí, en la aplicación no ══════════════════

   En la PESTAÑA del navegador el pellizco sigue funcionando, a propósito: es la
   forma de leer de quien necesita la letra más grande. En la APLICACIÓN del
   teléfono (instalada o añadida a inicio) no: «la aplicación de móvil no puede
   tener nada relacionado con funciones de web» (22-09), y ninguna aplicación
   del teléfono se deja acercar con dos dedos. Lo quita Capacitor
   (`zoomEnabled: false`) y, en la añadida a inicio, `maximum-scale=1`, que
   pone js/plataforma.js solo ahí. La letra sigue creciendo con el tamaño de
   texto del sistema (todo va en rem).

   Y en la aplicación tampoco se selecciona texto con una pulsación larga ni sale
   el menú del sistema, salvo en los campos: ver `html[data-app]` debajo.

   Va sobre lo PULSABLE y no sobre el body: `touch-action` se hereda como una
   intersección —un hijo no puede recuperar lo que un antepasado le quitó— y en
   el body se llevaría por delante los gestos de dentro de las hojas. */
/* La aplicación del teléfono no se comporta como una página: sin seleccionar
   texto con una pulsación larga, sin el menú de «copiar / buscar» del sistema y
   sin rebote al llegar al final. Los CAMPOS sí, que ahí se escribe y se corrige. */
html[data-app="1"] body {
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
  overscroll-behavior: none;
}
html[data-app="1"] :is(input, textarea, [contenteditable="true"], .seleccionable) {
  -webkit-user-select: text;
  user-select: text;
  -webkit-touch-callout: default;
}

/* ---------- 43 · «Ver las otras N» ----------
   Lo que no cabe se cuenta. Un carrusel escondía el resto sin decir que existía;
   esto dice cuántos son y lleva a verlos. Discreto a propósito: es una salida,
   no una acción — si pesara como un botón competiría con el de la tarjeta de
   arriba, que sí hay que pulsar. */
.inicio-cuentas__resto {
  width: 100%;
  min-height: var(--tactil);
  margin-top: var(--e-2);
  border: 1px dashed var(--linea-fuerte);
  border-radius: var(--r-md);
  background: transparent;
  color: var(--txt-2);
  font-size: var(--t-secundario);
  font-weight: 600;
  cursor: pointer;
}
.inicio-cuentas__resto:active { transform: scale(.99); }

/* ---------- 42a · La salida de Inicio hacia Análisis (solo teléfono) ----------
   Dice QUÉ hay al otro lado y no «Ver más»: un toque a ciegas no lo da nadie dos
   veces. Misma forma que las filas del índice de Mi perfil, para que se reconozca
   como «esto lleva a otro sitio» y no como una tarjeta más. */
.inicio-mas {
  display: flex;
  align-items: center;
  gap: var(--e-3);
  width: 100%;
  padding: var(--e-4);
  border: 1px solid var(--linea);
  border-radius: var(--r-lg);
  background: var(--capa-1);
  color: var(--txt);
  text-align: left;
  cursor: pointer;
}
.inicio-mas__que { display: grid; gap: 2px; flex: 1 1 auto; min-width: 0; }
.inicio-mas__que span { color: var(--txt-2); font-size: var(--t-meta); }
.inicio-mas:active { transform: scale(.99); }

/* ---------- 42b · El detalle del consentimiento, plegado ----------
   El texto es legal y viene del servidor: no se puede resumir por nuestra cuenta
   (js/views/ajustes.js). Lo que sí se puede es no ponerlo delante de la casilla,
   que es lo único que hay que decidir ahí. Mismo patrón que los otros
   desplegables de la aplicación (§27 normas de nómina, §32 fuentes de la IA). */
.consent__detalle {
  margin-top: var(--e-3);
  border-top: 1px solid var(--linea);
  padding-top: var(--e-2);
}
.consent__detalle > summary {
  cursor: pointer;
  font-weight: 700;
  font-size: var(--t-meta);
  color: var(--txt-2);
  /* 44px: un resumen de una línea mide veinte y se falla con el pulgar. */
  min-height: 44px;
  display: flex;
  align-items: center;
}
.consent__detalle[open] > summary { margin-bottom: var(--e-3); }

@media (pointer: coarse) {
  button, a, label, summary, select, input, textarea,
  [role="button"], [role="menuitem"], [role="tab"],
  .nav__item, .pulgar__btn, .mov-fila, .fila-com, .sus, .persona,
  .card__head[aria-expanded], .seccion__head[aria-expanded] {
    touch-action: manipulation;
  }

  /* Y el menú del sistema al dejar el dedo encima —«Copiar», «Compartir»,
     «Buscar»— sobre los BOTONES. En una página web tiene sentido; encima de
     «Anotar un gasto» es el menú de otra aplicación asomando dentro de la tuya.
     Solo en botones: sobre el texto de un comercio o una referencia sí se copia,
     y eso se usa. */
  button, [role="button"], .nav__item, .pulgar__btn {
    -webkit-touch-callout: none;
  }
}

/* ==========================================================================
   43 · IMPRIMIR
   ==========================================================================
   Imprimir —o «Guardar como PDF», que es lo que de verdad se hace para mandarle
   Análisis al contador o el estado de cuenta a un cliente— salía casi en
   blanco: Aurora nace oscura, el navegador quita los fondos al imprimir y deja
   el texto CLARO, así que todo se leía gris pálido sobre papel blanco. La única
   hoja de impresión que había era del sistema anterior (styles.css) y escondía
   piezas que ya no existen.

   El modo lo pone `js/modo-arranque.js`: pasa a claro en `beforeprint` y
   devuelve el que había en `afterprint`, así que las fichas de siempre dan tinta
   oscura sobre blanco sin escribir una paleta más. Aquí solo va lo que el papel
   no necesita y lo que en papel sobra:

   · Fuera la carcasa: lateral, cabecera, filtros, barra del pulgar, botón
     flotante, avisos, velos y la franja de «no se guardó». En papel se lee la
     pantalla, no cómo se navega.
   · Fuera la profundidad: sombra, vidrio y desenfoque no se imprimen y el
     desenfoque, además, vuelve borroso lo que tiene detrás en algunos
     navegadores. Cada bloque se separa con un borde fino.
   · Un bloque no se parte entre dos hojas: una tarjeta cortada por la mitad
     deja la cifra en una página y su explicación en la otra.
   · Todo lo plegado, abierto: lo que no se ve en pantalla no está en el papel,
     y quien imprime quiere el informe entero. */
@media print {
  .sidebar, .topbar, .filters, .pulgar, .fab, .toasts, .velo-capa, #veloCapa,
  .sin-guardar, .pie, .viz-tooltip, #avisoGlobal, .skip-link { display: none !important; }

  html, body { background: var(--bg) !important; }
  .app { display: block !important; }
  .main, .view { padding: 0 !important; margin: 0 !important; max-width: none !important; }

  *, *::before, *::after {
    box-shadow: none !important;
    text-shadow: none !important;
    backdrop-filter: none !important;
    -webkit-backdrop-filter: none !important;
    animation: none !important;
    transition: none !important;
  }
  .card, section.card { border: 1px solid var(--linea-fuerte) !important; break-inside: avoid; }
  .card__head { break-after: avoid; }

  /* La cifra con degradado es texto TRANSPARENTE sobre un fondo recortado a su
     forma: sin fondos —que es como imprime el navegador— desaparece entera, y
     la cifra que manda la pantalla sale como un hueco en el papel. */
  .cifra-grad, .respuesta__cifra {
    -webkit-text-fill-color: currentColor !important;
    background: none !important;
    color: var(--txt) !important;
  }
  .bloque--plegable > .card__cuerpo[hidden] { display: block !important; }
  .card__tirador { display: none !important; }

  /* Un botón de acción en papel no se pulsa. Solo los .btn: hay filas de datos
     que SON botones (un límite entero es su propio blanco) y esas se imprimen. */
  .btn, .icono-btn { display: none !important; }
  /* Ni cómo se elige lo que se ve (las pestañas de Análisis) ni la caja de
     preguntar: en papel no se elige ni se pregunta. */
  .ana-pestanas, .ia-linea, .franja__accion { display: none !important; }

  /* Las tarjetas de cuenta son tinta blanca SOBRE su degradado: sin el fondo
     —que el navegador quita al imprimir— el saldo salía blanco sobre blanco.
     Son de lo poco que tiene que llevar su color al papel. */
  .tarjeta-cuenta {
    -webkit-print-color-adjust: exact;
            print-color-adjust: exact;
  }
}

/* ==========================================================================
   44 · EL ESCRITORIO: SOLTAR EN CUALQUIER SITIO, Y LOS ATAJOS
   ==========================================================================
   Soltar un archivo en cualquier pantalla lo lleva a Importar (app.js). Mientras
   se arrastra, la pantalla entera lo dice: sin eso, soltar encima de Inicio es
   un acto de fe. `pointer-events: none` para que el aviso no se quede él con
   el archivo. */
body.soltando::after {
  content: 'Suéltalo aquí: lo leemos en Importar';
  position: fixed;
  inset: var(--e-4);
  z-index: 90;
  display: grid;
  place-items: center;
  border: 2px dashed var(--marca);
  border-radius: var(--r-xl);
  background: color-mix(in srgb, var(--bg) 82%, transparent);
  color: var(--txt);
  font-size: var(--t-tarjeta);
  font-weight: 700;
  pointer-events: none;
}

/* La hoja de «?»: cada grupo, sus teclas a la izquierda y lo que hacen a la
   derecha. `kbd` con el aire de una tecla, no de un chip: es lo que se pulsa. */
.atajos { display: grid; gap: var(--e-5); }
.atajos__titulo { margin: 0 0 var(--e-2); font-size: var(--t-etiqueta); color: var(--txt-2); font-weight: 600; }
.atajos__lista { display: grid; grid-template-columns: minmax(0, max-content) minmax(0, 1fr); gap: var(--e-2) var(--e-4); margin: 0; }
.atajos__teclas { display: flex; gap: var(--e-1); align-items: center; margin: 0; }
.atajos__que { margin: 0; align-self: center; color: var(--txt); min-width: 0; }
.atajos__tecla {
  min-width: 1.75rem;
  padding: 0.125rem var(--e-2);
  border: 1px solid var(--linea-fuerte);
  border-bottom-width: 2px;
  border-radius: var(--r-sm);
  background: var(--capa-2);
  color: var(--txt);
  font: inherit;
  font-size: var(--t-mini);
  font-weight: 600;
  text-align: center;
}

/* ==========================================================================
   45 · MOVIMIENTOS: ENTRE QUÉ MONTOS
   ==========================================================================
   Los dos campos van juntos en UNA celda de los filtros —«desde» y «hasta» son
   una sola pregunta— y los dos con `min-width: 0`: sin eso, a 360px el campo
   numérico mantiene su ancho propio y empuja la pantalla entera a lo ancho. */
.filtros-vista__monto {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: var(--e-2);
  min-width: 0;
}
.filtros-vista__monto input { width: 100%; min-width: 0; }

/* ==========================================================================
   46 · INICIO: EL SALDO DE VERDAD
   ==========================================================================
   Bajo las tarjetas de cuenta, cuando alguna enseña la suma de lo apuntado y
   no su saldo: la frase y el botón en una fila que se parte en dos en un
   teléfono estrecho. Sin tarjeta propia: es una nota al pie de las de arriba. */
.inicio-cuentas__saldo {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--e-2) var(--e-4);
  margin-top: var(--e-3);
  min-width: 0;
}
.inicio-cuentas__saldo p { margin: 0; flex: 1 1 16rem; min-width: 0; }

/* ==========================================================================
   47 · MI PERFIL Y MIS ESPACIOS: DOS EXPERIENCIAS
   ==========================================================================
   Desde el 2026-10-01 son dos archivos por pantalla —perfil-web.js y
   perfil-movil.js, espacios-web.js y espacios-movil.js— y cada uno viste sus
   propias clases: `perfil-web` / `esp-web` el escritorio, `pm` / `esp-movil`
   el teléfono. Así una regla de uno no puede colarse en el otro, que es lo
   que pasa cuando dos experiencias comparten clases y se distinguen por un
   ancho.

   Los cortes de ancho que quedan aquí son MAQUETACIÓN: dónde deja de caber la
   segunda columna. Qué se ofrece lo decidió ya esTelefono() al elegir archivo. */

/* ---------- Lo que incluye el plan y lo que no: lado a lado donde cabe ---------- */
.perfil-plan__listas { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(16rem, 100%), 1fr)); gap: 0 var(--e-6); }
.perfil-plan__listas > * { min-width: 0; }

/* ---------- Los aparatos con sesión, como filas ---------- */
.aparatos { display: grid; gap: 2px; list-style: none; margin: 0; padding: 0; }
.aparatos__fila {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--e-3);
  padding: var(--e-3) 0;
  border-bottom: 1px solid var(--linea);
}
.aparatos__fila:last-child { border-bottom: 0; }
.aparatos__quien { display: grid; gap: 2px; min-width: 0; }
.aparatos__nombre { font-weight: 600; font-size: var(--t-secundario); overflow-wrap: anywhere; }
.aparatos__cuando { font-size: var(--t-meta); color: var(--txt-3); }

/* ---------- Teléfono · Mi perfil ---------- */
.pm { display: grid; gap: var(--e-5); min-width: 0; }
.pm > * { min-width: 0; }

.pm-cabeza {
  position: relative;
  display: grid;
  justify-items: center;
  gap: var(--e-1);
  padding: var(--e-5) var(--e-4) var(--e-2);
  text-align: center;
}
/* El halo de marca, como en la identidad del escritorio: es la pantalla que
   habla de ti. */
.pm-cabeza::before {
  content: "";
  position: absolute;
  inset: -20% 0 30% 0;
  background: radial-gradient(closest-side, var(--marca-suave), transparent 75%);
  pointer-events: none;
}
.pm-cabeza > * { position: relative; }
.pm-cabeza__foto {
  position: relative;
  padding: 0;
  border: 0;
  border-radius: var(--r-full);
  background: transparent;
  cursor: pointer;
  margin-bottom: var(--e-2);
}
.pm-cabeza__avatar { width: 92px; height: 92px; font-size: 2rem; }
.pm-cabeza__lapiz {
  position: absolute;
  right: 0; bottom: 0;
  width: 30px; height: 30px;
  display: grid; place-items: center;
  border-radius: var(--r-full);
  background: var(--capa-3);
  border: 1px solid var(--linea-fuerte);
  color: var(--txt);
  font-size: var(--t-nano);
  box-shadow: var(--sombra-1);
}
.pm-cabeza__nombre {
  margin: 0;
  font-size: var(--t-cifra-media);
  font-weight: 800;
  letter-spacing: var(--track-cifra-2);
  line-height: 1.15;
  overflow-wrap: anywhere;
}
.pm-cabeza__correo {
  margin: 0 0 var(--e-2);
  font-size: var(--t-secundario);
  color: var(--txt-2);
  overflow-wrap: anywhere;
}
.pm-cabeza--sub { padding-top: var(--e-2); }
.pm-cabeza__botones { display: flex; flex-wrap: wrap; justify-content: center; gap: var(--e-2); }

/* Los cuatro accesos redondos. */
/* En columnas que se reparten, no en cuatro fijas: quien no es dueño del
   espacio no tiene «Invitar», y tres en una rejilla de cuatro dejaban un hueco. */
.pm-rapidos {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(0, 1fr);
  gap: var(--e-2);
}
.pm-rapido {
  display: grid;
  justify-items: center;
  align-content: start;
  gap: var(--e-2);
  min-height: 48px;
  min-width: 0;
  padding: var(--e-1) 0;
  border: 0;
  background: transparent;
  color: var(--txt);
  font: inherit;
  cursor: pointer;
}
.pm-rapido__icono {
  width: 56px; height: 56px;
  display: grid; place-items: center;
  border-radius: var(--r-full);
  background: var(--capa-1);
  border: 1px solid var(--linea);
  box-shadow: var(--sombra-1), var(--filo);
  color: var(--marca-txt);
  font-size: var(--t-glifo-lg);
  transition: transform 120ms var(--muelle);
}
.pm-rapido:active .pm-rapido__icono { transform: scale(.94); }
.pm-rapido[data-tono="ok"] .pm-rapido__icono { background: var(--ok-suave); color: var(--ok-txt); border-color: transparent; }
.pm-rapido__texto {
  font-size: var(--t-nano);
  font-weight: 600;
  color: var(--txt-2);
  line-height: 1.2;
  text-align: center;
}

/* Los grupos de filas: profundidad, no rayas. Una capa por grupo y una línea
   finísima entre filas, que es lo que separa sin pesar. */
.pm-grupo { display: grid; gap: var(--e-2); min-width: 0; }
.pm-grupo__titulo {
  margin: 0 var(--e-2);
  font-size: var(--t-etiqueta);
  font-weight: 700;
  color: var(--txt-3);
}
.pm-lista {
  display: grid;
  min-width: 0;
  background: var(--capa-1);
  border: 1px solid var(--linea);
  border-radius: var(--r-lg);
  box-shadow: var(--sombra-1), var(--filo);
  overflow: hidden;
}
.pm-lista > * + * { border-top: 1px solid var(--linea); }
.pm-fila {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto auto;
  align-items: center;
  gap: var(--e-3);
  width: 100%;
  min-width: 0;
  min-height: 56px;
  padding: var(--e-2) var(--e-4);
  border: 0;
  background: transparent;
  color: var(--txt);
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.pm-fila:active { background: var(--capa-2); }
.pm-fila__icono {
  width: 36px; height: 36px;
  display: grid; place-items: center;
  border-radius: var(--r-sm);
  background: var(--marca-suave);
  color: var(--marca-txt);
  font-size: var(--t-glifo-md);
  flex: none;
}
.pm-fila[data-tono="ok"] .pm-fila__icono { background: var(--ok-suave); color: var(--ok-txt); }
.pm-fila[data-tono="alerta"] .pm-fila__icono { background: var(--alerta-suave); color: var(--alerta-txt); }
.pm-fila[data-tono="peligro"] .pm-fila__icono,
.pm-fila--peligro .pm-fila__icono { background: var(--peligro-suave); color: var(--peligro-txt); }
.pm-fila--peligro .pm-fila__nombre { color: var(--peligro-txt); }
.pm-fila[data-tono="futuro"] .pm-fila__icono { background: var(--futuro-suave); color: var(--futuro-txt); }
.pm-fila__nombre {
  font-size: var(--t-cuerpo);
  font-weight: 600;
  min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.pm-fila__valor {
  max-width: 10rem;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-size: var(--t-secundario);
  color: var(--txt-3);
}
.pm-fila__flecha { color: var(--txt-3); font-size: var(--t-glifo-md); }
/* La fila de dos líneas (los espacios): nombre y, debajo, de qué es. */
.pm-fila__dos { display: grid; gap: 1px; min-width: 0; }
.pm-fila__meta {
  font-size: var(--t-meta);
  color: var(--txt-3);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* El interruptor del cerrojo, dentro de la lista. Si el aparato no puede, su
   hueco se quita y la fila vacía no se ve. */
.pm-fila--casilla { display: block; min-height: 0; padding: var(--e-3) var(--e-4); cursor: default; }
.pm-fila--casilla:empty { display: none; }
.pm-fila--casilla .casilla { margin: 0; }

.pm-pie { display: grid; padding-top: var(--e-2); }
.pm-pie__salir { width: 100%; min-height: 52px; }
.pm-nota { margin: 0 var(--e-2); }

/* La subpantalla: «‹ Mi perfil» y su título, arriba del contenido. */
.pm-sub__cabeza { display: grid; justify-items: start; gap: var(--e-1); }
.pm-sub__volver {
  min-height: 44px;
  padding: 0 var(--e-2);
  margin-left: calc(var(--e-2) * -1);
  color: var(--marca-txt);
}
.pm-sub__titulo {
  margin: 0;
  font-size: var(--t-pagina);
  font-weight: 800;
  letter-spacing: var(--track-cifra-2);
}

/* ---------- Escritorio · Mis espacios ---------- */
.esp-web {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--e-5);
  align-items: start;
}
.esp-web > *, .esp-web__principal > *, .esp-web__lado > * { min-width: 0; }
.esp-web__principal, .esp-web__lado { display: grid; gap: var(--e-4); min-width: 0; }
@media (min-width: 1280px) {
  .esp-web { grid-template-columns: minmax(0, 1fr) minmax(0, 360px); }
}

.esp-activo__icono, .esp-fila__icono {
  display: grid; place-items: center;
  flex: none;
  border-radius: var(--r-sm);
  color: #fff;
}
.esp-activo {
  display: grid;
  gap: var(--e-4);
  margin-top: var(--e-2);
  padding: var(--e-5);
  border: 1px solid var(--linea-fuerte);
  border-radius: var(--r-lg);
  background: linear-gradient(160deg, var(--marca-suave), transparent 70%), var(--capa-2);
  min-width: 0;
}
.esp-activo__cabeza {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--e-4);
}
.esp-activo__icono { width: 52px; height: 52px; font-size: var(--t-glifo-lg); border-radius: var(--r-md); }
.esp-activo__titulo { display: grid; gap: 2px; min-width: 0; }
.esp-activo__titulo strong {
  font-size: var(--t-cifra-media);
  font-weight: 800;
  overflow-wrap: anywhere;
}
.esp-activo__titulo .muted { font-size: var(--t-meta); }
/* Dos por fila, siempre: con cuatro en la fila la cifra de lo gastado se partía
   por la mitad, y con tres quedaba una huérfana debajo. */
.esp-activo__cifras {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--e-3);
  margin: 0;
}
.esp-activo__cifras > div {
  padding: var(--e-3);
  border-radius: var(--r-sm);
  background: var(--capa-1);
  border: 1px solid var(--linea);
  min-width: 0;
}
.esp-activo__cifras dt { margin: 0; font-size: var(--t-meta); }
.esp-activo__cifras dd {
  margin: 2px 0 0;
  font-size: var(--t-tarjeta);
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.esp-activo__acciones { display: flex; flex-wrap: wrap; gap: var(--e-2); }
@media (max-width: 640px) {
  .esp-activo__cabeza { grid-template-columns: auto minmax(0, 1fr); }
  .esp-activo__cabeza .pill { grid-column: 1 / -1; justify-self: start; }
}

.esp-web__otros { display: grid; gap: var(--e-3); margin-top: var(--e-5); min-width: 0; }
.esp-web__otros-cabeza {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--e-2) var(--e-4);
}
.esp-web__otros-cabeza .rotulo { margin: 0; }
.esp-web__otros-cabeza .input { flex: 0 1 18rem; min-width: 0; }
.esp-web__solo { margin-top: var(--e-4); }

.esp-lista { display: grid; list-style: none; margin: 0; padding: 0; min-width: 0; }
.esp-fila {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--e-4);
  padding: var(--e-3) var(--e-2);
  border-top: 1px solid var(--linea);
  border-radius: var(--r-sm);
}
.esp-fila:first-child { border-top: 0; }
.esp-fila[hidden] { display: none; }
.esp-fila:hover { background: var(--capa-2); }
.esp-fila__icono { width: 40px; height: 40px; font-size: var(--t-glifo-md); }
.esp-fila__quien { display: grid; gap: 2px; min-width: 0; }
.esp-fila__nombre { font-size: var(--t-cuerpo); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.esp-fila__meta { font-size: var(--t-meta); color: var(--txt-3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.esp-fila__acciones { display: flex; gap: var(--e-1); flex-wrap: wrap; justify-content: flex-end; }
@media (max-width: 640px) {
  .esp-fila { grid-template-columns: auto minmax(0, 1fr); }
  .esp-fila__acciones { grid-column: 1 / -1; justify-content: flex-start; }
}
.esp-lista__vacio { margin: var(--e-3) 0 0; }

/* ---------- Teléfono · Mis espacios ---------- */
.esp-movil { display: grid; gap: var(--e-5); min-width: 0; }
.esp-movil > * { min-width: 0; }
.esp-activo--movil { margin-top: 0; }
.esp-activo--movil .esp-activo__cabeza { grid-template-columns: auto minmax(0, 1fr); }
.esp-activo--movil .esp-activo__titulo .pill { justify-self: start; margin-bottom: var(--e-1); }
.esp-activo--movil .esp-activo__cifras { grid-template-columns: repeat(2, minmax(0, 1fr)); }
/* En el teléfono lo gastado va sin céntimos (espacios-movil.js) y no se parte:
   la regla de las celdas estrechas del teléfono deja cortar las cifras largas. */
.esp-activo--movil .esp-activo__cifras dd { font-size: var(--t-cuerpo); white-space: nowrap; overflow-wrap: normal; word-break: normal; }
.esp-activo--movil .esp-activo__acciones { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); }
.esp-activo--movil .esp-activo__acciones .btn--primary { grid-column: 1 / -1; }
.esp-activo--movil .esp-activo__acciones .btn { min-height: 48px; min-width: 0; padding: 0 var(--e-2); }
.esp-movil__fila { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; min-width: 0; }
.esp-movil__fila[hidden] { display: none; }
.esp-movil__fila .pm-fila { grid-template-columns: auto minmax(0, 1fr) auto; }
.esp-movil__mas { min-width: 48px; min-height: 48px; margin-right: var(--e-2); font-size: var(--t-glifo-md); }
.esp-movil__buscar .input { width: 100%; }
.esp-movil__crear { width: 100%; min-height: 52px; }
.esp-movil__opcion { width: 100%; min-height: 52px; }

/* ==========================================================================
   49 · MI CUENTA: UNA SOLA, EN NUEVE CATEGORÍAS
   ==========================================================================
   Mi perfil y Configuración son una sola pantalla desde el 2026-10-01
   (js/cuenta-secciones.js). En el escritorio (`cuenta-web`), una columna fija
   con quién eres, el buscador y el índice, y las categorías una debajo de
   otra; en el teléfono (`cm`, sobre las piezas `pm-` de §47), la lista de
   categorías y una subpantalla por categoría. */

/* ---------- Escritorio ---------- */
.cuenta-web {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--e-5);
  align-items: start;
}
.cuenta-web > * { min-width: 0; }
.cuenta-web__lado { display: grid; gap: var(--e-4); min-width: 0; }
@media (min-width: 1280px) {
  .cuenta-web { grid-template-columns: minmax(0, 300px) minmax(0, 1fr); gap: var(--e-7); }
  .cuenta-web__lado {
    position: sticky;
    top: calc(var(--alto-topbar) + var(--e-4));
    max-height: calc(100vh - var(--alto-topbar) - var(--e-6));
    overflow-y: auto;
    overscroll-behavior: contain;
    scrollbar-width: thin;
  }
}

.cuenta-web__quien {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: center;
  gap: var(--e-3);
  padding: var(--e-4);
  border-radius: var(--r-lg);
  background: linear-gradient(160deg, var(--marca-suave), transparent 75%), var(--capa-1);
  border: 1px solid var(--linea);
  box-shadow: var(--sombra-1), var(--filo);
}
.cuenta-web__avatar {
  width: 48px; height: 48px;
  display: grid; place-items: center;
  border-radius: var(--r-full);
  background: var(--grad-marca);
  color: #fff;
  font-weight: 800;
  overflow: hidden;
}
.cuenta-web__avatar > img { width: 100%; height: 100%; object-fit: cover; }
.cuenta-web__nombre { display: grid; gap: var(--e-1); justify-items: start; min-width: 0; }
.cuenta-web__nombre strong { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* El índice: icono, nombre y una línea de qué hay dentro. Por debajo de 1280
   se vuelve una rejilla de fichas encima del contenido. */
.cuenta-web__indice {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(14rem, 100%), 1fr));
  gap: var(--e-2);
}
@media (min-width: 1280px) { .cuenta-web__indice { grid-template-columns: minmax(0, 1fr); gap: 2px; } }
.cuenta-web__ir {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: center;
  gap: var(--e-3);
  min-height: 48px;
  padding: var(--e-2) var(--e-3);
  border: 1px solid var(--linea);
  border-radius: var(--r-sm);
  background: var(--capa-1);
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
  transition: background var(--rapido) var(--curva), border-color var(--rapido) var(--curva);
}
@media (min-width: 1280px) { .cuenta-web__ir { border-color: transparent; background: transparent; } }
.cuenta-web__ir:hover { background: var(--capa-2); }
.cuenta-web__ir[aria-current="true"] { background: var(--marca-suave); border-color: transparent; }
.cuenta-web__icono {
  width: 32px; height: 32px;
  display: grid; place-items: center;
  border-radius: var(--r-xs);
  background: var(--marca-suave);
  color: var(--marca-txt);
  font-size: var(--t-glifo-sm);
}
.cuenta-web__que { display: grid; gap: 1px; min-width: 0; }
.cuenta-web__titulo { font-size: var(--t-secundario); font-weight: 700; }
.cuenta-web__pista {
  font-size: var(--t-meta);
  color: var(--txt-3);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.cuenta-web__salir { width: 100%; }

.cuenta-web__cuerpo { display: grid; gap: var(--e-8); min-width: 0; }
.cuenta-seccion { display: grid; gap: var(--e-4); min-width: 0; scroll-margin-top: calc(var(--alto-topbar) + var(--e-4)); }
.cuenta-seccion__cabeza { display: flex; align-items: center; gap: var(--e-3); }
.cuenta-seccion__icono {
  width: 40px; height: 40px; flex: none;
  display: grid; place-items: center;
  border-radius: var(--r-sm);
  background: var(--grad-marca);
  color: #fff;
  font-size: var(--t-glifo-md);
  box-shadow: var(--brillo-accion);
}
.cuenta-seccion__titulo { margin: 0; font-size: var(--t-cifra-media); font-weight: 800; letter-spacing: var(--track-cifra-2); }
.cuenta-seccion__pista { margin: 0; font-size: var(--t-meta); color: var(--txt-3); }
.cuenta-seccion__tarjetas { display: grid; gap: var(--e-4); min-width: 0; }
.cuenta-seccion__tarjetas > * { min-width: 0; }
.cuenta-rotulo { margin-top: var(--e-4); }

/* La tarjeta a la que se llegó buscando, encendida un momento. Con el borde y
   no solo con un brillo: se tiene que ver también sin color (§9). */
.cuenta-destacada { outline: 2px solid var(--marca); outline-offset: 2px; }

/* ---------- El buscador de ajustes (las dos superficies) ---------- */
.cuenta-buscar { position: relative; display: grid; min-width: 0; }
.cuenta-buscar__campo { width: 100%; min-height: 48px; }
.cuenta-buscar__lista {
  display: grid;
  margin-top: var(--e-2);
  padding: var(--e-1);
  border: 1px solid var(--linea);
  border-radius: var(--r-md);
  background: var(--menu-fondo, var(--capa-3));
  box-shadow: var(--sombra-2);
}
.cuenta-buscar__lista[hidden] { display: none; }
.cuenta-buscar__item {
  display: grid;
  gap: 1px;
  min-height: 48px;
  padding: var(--e-2) var(--e-3);
  border: 0;
  border-radius: var(--r-sm);
  background: transparent;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.cuenta-buscar__item:hover, .cuenta-buscar__item:focus-visible { background: var(--capa-2); }
.cuenta-buscar__que { font-weight: 600; font-size: var(--t-secundario); }
.cuenta-buscar__donde { font-size: var(--t-meta); color: var(--txt-3); }
.cuenta-buscar__nada { margin: 0; padding: var(--e-3); }

/* ---------- Conectar el banco, en grande ---------- */
.cuenta-banco {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--e-3) var(--e-5);
  background: linear-gradient(135deg, var(--ok-suave), transparent 70%), var(--capa-1);
}
.cuenta-banco__texto { display: flex; align-items: center; gap: var(--e-3); min-width: 0; flex: 1 1 16rem; }
.cuenta-banco__texto > span:last-child { display: grid; gap: 2px; min-width: 0; }
.cuenta-banco__icono {
  width: 44px; height: 44px; flex: none;
  display: grid; place-items: center;
  border-radius: var(--r-full);
  background: var(--ok-suave);
  font-size: var(--t-glifo-md);
}

/* ---------- Los enlaces de Ayuda ---------- */
.cuenta-enlaces { display: grid; }
.cuenta-enlaces > * + * { border-top: 1px solid var(--linea); }
.cuenta-enlace {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--e-3);
  min-height: 56px;
  padding: var(--e-2) 0;
  border: 0;
  background: transparent;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.cuenta-enlace__texto { display: grid; gap: 2px; min-width: 0; }

/* ---------- Teléfono ---------- */
.cm-sub > .card, .cm-sub > section { min-width: 0; }

/* ==========================================================================
   48.3 · TELÉFONO: METAS, LÍMITES, FIJOS Y PLANIFICADOR
   ==========================================================================
   Las cuatro pantallas de «a dónde va el dinero» tienen su archivo de teléfono
   desde el 2026-10-01 (metas-movil.js, presupuestos-movil.js, fijos-movil.js,
   planificador-movil.js) y visten estas clases, `gm-`. Reutilizan las filas
   de Mi perfil (`pm-grupo`, `pm-lista`, `pm-fila`, §47): una lista de filas a
   lo ancho es la forma del teléfono, y dos versiones de la misma fila
   acabarían separándose.

   Todo lo que se pulsa mide 48px como mínimo; nada de tablas. */

.gm { display: grid; gap: var(--e-5); min-width: 0; }
.gm > *, .gm-bloques > * { min-width: 0; }
.gm-bloques { display: grid; gap: var(--e-4); }
.gm-ancho { width: 100%; min-height: 52px; }
.gm-opcion { width: 100%; min-height: 52px; }

.gm-grupo__cabeza {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--e-3);
  min-width: 0;
}
.gm-grupo__pista {
  margin-right: var(--e-2);
  font-size: var(--t-meta);
  font-weight: 600;
  color: var(--txt-2);
  white-space: nowrap;
}
.gm-grupo__nota { margin: 0 var(--e-2); font-size: var(--t-secundario); color: var(--txt-2); }

/* ---------- La respuesta de arriba, sin tarjeta ---------- */
.gm-heroe { display: grid; gap: var(--e-2); padding: var(--e-2) var(--e-1) 0; min-width: 0; }
.gm-heroe > * { min-width: 0; }
.gm-heroe__pregunta {
  margin: 0;
  font-size: var(--t-etiqueta);
  font-weight: 700;
  color: var(--txt-3);
}
.gm-heroe__titular {
  margin: 0;
  font-size: var(--t-cifra-media);
  font-weight: 800;
  line-height: 1.15;
  letter-spacing: var(--track-cifra-2);
  overflow-wrap: anywhere;
}
.gm-heroe__titular--medio { font-size: var(--t-tarjeta); }
.gm-heroe__cifra {
  margin: 0;
  font-size: var(--t-cifra);
  font-weight: 800;
  line-height: 1.05;
  letter-spacing: var(--track-cifra-2);
  overflow-wrap: anywhere;
}
.gm-heroe__apoyo, .gm-heroe__consejo { margin: 0; font-size: var(--t-secundario); color: var(--txt-2); }
.gm-heroe__frase {
  margin: 0;
  padding: var(--e-3) var(--e-4);
  border-radius: var(--r-md);
  background: var(--capa-1);
  border: 1px solid var(--linea);
  font-size: var(--t-secundario);
}
.gm-heroe[data-tono="ojo"] .gm-heroe__frase { background: var(--alerta-suave); color: var(--alerta-txt); border-color: transparent; }
.gm-heroe[data-tono="mal"] .gm-heroe__frase { background: var(--peligro-suave); color: var(--peligro-txt); border-color: transparent; }
.gm-heroe__barra { margin: var(--e-2) 0; }
.gm-heroe__botones { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--e-2); margin-top: var(--e-2); }
.gm-heroe__botones .btn { min-height: 52px; min-width: 0; padding: 0 var(--e-2); }

/* Las cuatro cifras de «¿me alcanza?», como filas de una lista. */
.gm-dato {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--e-3);
  min-height: 48px;
  padding: var(--e-2) var(--e-4);
}
.gm-dato__punto { width: 10px; height: 10px; border-radius: var(--r-full); background: var(--txt-3); }
.gm-dato__punto--gastado { background: var(--marca); }
.gm-dato__punto--fijo { background: var(--futuro); }
.gm-dato__punto--variable { background: var(--alerta); }
.gm-dato__punto--libre { background: var(--ok); }
.gm-dato__punto--falta { background: var(--peligro); }
.gm-dato__rotulo { font-size: var(--t-secundario); color: var(--txt-2); min-width: 0; }
.gm-dato__cifra { font-size: var(--t-cuerpo); font-weight: 700; white-space: nowrap; }

/* ---------- Una barra de límite que se pulsa entera ---------- */
.gm-limite {
  display: block;
  width: 100%;
  min-width: 0;
  min-height: 56px;
  padding: var(--e-3) var(--e-4);
  border: 0;
  background: transparent;
  color: var(--txt);
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.gm-limite:active { background: var(--capa-2); }
.gm-limite .limite__cabeza { min-width: 0; }
.gm-limite .limite__rotulo { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.gm-limite .limite__cifra { flex: none; }

.gm-vacio { padding: var(--e-2) var(--e-3); }
.gm-vacio .estado { padding: var(--e-4) var(--e-2); }

/* El punto de color de una categoría, en el hueco del icono de la fila. */
.gm-punto { background: var(--capa-2); }
.gm-punto .dot-cat { width: 12px; height: 12px; }
.gm-sugerencia { margin: 0 var(--e-2); }

/* ---------- Metas ---------- */
.gm-meta {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--e-3);
  padding: var(--e-3) var(--e-4);
  min-width: 0;
}
.gm-meta .anillo { flex: none; }
.gm-meta__texto { display: grid; gap: 2px; min-width: 0; }
.gm-meta__texto p { margin: 0; }
.gm-meta__nombre { font-weight: 700; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.gm-meta__cifra { font-size: var(--t-secundario); font-weight: 700; }
.gm-meta__pie { font-size: var(--t-meta); color: var(--txt-2); }
.gm-meta[data-estado="tarde"] .gm-meta__pie { color: var(--alerta-txt); }
.gm-meta[data-estado="lista"] .gm-meta__pie { color: var(--ok-txt); }
.gm-meta__apartar { min-height: 48px; padding: 0 var(--e-3); }

/* ---------- Suscripciones ---------- */
.gm-sus-total { margin: 0 var(--e-2); font-size: var(--t-secundario); color: var(--txt-2); }
.gm-metas .segmentos { justify-self: start; max-width: 100%; }
.gm .segmentos button { min-height: 44px; }
.gm-sus {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--e-3);
  min-height: 56px;
  padding: var(--e-2) var(--e-4);
  min-width: 0;
}
.gm-sus[data-viva="no"] { opacity: .7; }
.gm-sus__cifras { display: grid; justify-items: end; gap: 1px; }
.gm-sus__monto { font-weight: 700; white-space: nowrap; }
.gm-sus__estado, .gm-estado {
  font-size: var(--t-chip);
  font-weight: 700;
  color: var(--txt-3);
  white-space: nowrap;
}
.gm-sus__estado[data-tono="futuro"], .gm-estado[data-tono="info"] { color: var(--futuro-txt); }
.gm-sus__estado[data-tono="alerta"] { color: var(--alerta-txt); }
.gm-estado[data-tono="mal"] { color: var(--peligro-txt); }
.gm-estado[data-tono="good"] { color: var(--ok-txt); }

/* ---------- Mis límites: el mes con flechas ---------- */
.gm-periodo { display: grid; gap: var(--e-3); justify-items: stretch; }
.gm-periodo .segmentos { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); }
.gm-periodo .segmentos button { padding: 0 var(--e-1); min-width: 0; }
.gm-mes {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--e-2);
  padding: var(--e-1);
  border-radius: var(--r-full);
  background: var(--capa-1);
  border: 1px solid var(--linea);
}
.gm-mes__flecha {
  min-width: 48px;
  min-height: 48px;
  border-radius: var(--r-full);
  font-size: var(--t-glifo-md);
}
.gm-mes__nombre { text-align: center; font-weight: 700; text-transform: capitalize; min-width: 0; }

/* ---------- Filas con un botón al lado ---------- */
.gm-tarea {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--e-3);
  min-height: 56px;
  padding: var(--e-2) var(--e-2) var(--e-2) var(--e-4);
  min-width: 0;
}
.gm-tarea__texto { font-weight: 600; min-width: 0; }
.gm-tarea__boton { min-height: 48px; padding: 0 var(--e-3); }
.gm-tarea__quitar { min-width: 48px; min-height: 48px; font-size: var(--t-glifo-sm); }

/* Un pago: la fila abre sus opciones y «Pagado» va al lado, aparte. */
.gm-pago { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; min-width: 0; }
.gm-pago .pm-fila { grid-template-columns: minmax(0, 1fr); }
/* Dos líneas que se parten en vez de cortarse: «Préstamo del vehíc…» no se lee. */
.gm-pago .pm-fila__nombre, .gm-pago .pm-fila__meta { white-space: normal; overflow-wrap: anywhere; }
.gm-pago__pagar { min-height: 48px; margin-right: var(--e-2); padding: 0 var(--e-3); }
.gm-pago[data-estado="pagada"] .pm-fila__nombre,
.gm-pago[data-estado="omitida"] .pm-fila__nombre { color: var(--txt-2); }
.pm-fila[data-tono="apagado"] .pm-fila__icono { background: var(--capa-2); color: var(--txt-3); }
.pm-fila[data-tono="apagado"] .pm-fila__nombre { color: var(--txt-2); }
.gm-fijos .pm-fila--casilla { padding: var(--e-1) var(--e-4); }
.gm-fijos .pm-fila--casilla .casilla { display: flex; min-height: 48px; align-items: center; }

/* ---------- El planificador ---------- */
.gm-planfila {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--e-3);
  width: 100%;
  min-width: 0;
  min-height: 64px;
  padding: var(--e-3) var(--e-4);
  border: 0;
  background: transparent;
  color: var(--txt);
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.gm-planfila:active { background: var(--capa-2); }
.gm-planfila--cerrado { opacity: .75; }
.gm-planfila__icono, .gm-dentro__icono {
  width: 44px; height: 44px;
  display: grid; place-items: center;
  border-radius: var(--r-md);
  background: var(--capa-2);
  font-size: var(--t-glifo-lg);
}
.gm-planfila__medio { display: grid; gap: var(--e-1); min-width: 0; }

.gm-barra {
  display: block;
  height: 8px;
  border-radius: var(--r-full);
  background: var(--bg-2);
  overflow: hidden;
}
.gm-barra .plan-barra__relleno {
  display: block;
  height: 100%;
  width: calc(var(--parte, 0) * 100%);
  transform: none;
  border-radius: inherit;
  background: var(--marca);
}
.gm-barra.plan-barra--mal .plan-barra__relleno { background: var(--peligro); }
.gm-heroe[data-tono="mal"] .gm-heroe__apoyo { color: var(--peligro-txt); }

.gm-plantillas { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--e-2); }
.gm-plantilla {
  display: grid;
  justify-items: center;
  align-content: center;
  gap: var(--e-1);
  min-height: 96px;
  min-width: 0;
  padding: var(--e-3) var(--e-2);
  border: 1px solid var(--linea);
  border-radius: var(--r-lg);
  background: var(--capa-1);
  box-shadow: var(--sombra-1), var(--filo);
  color: var(--txt);
  font: inherit;
  cursor: pointer;
}
.gm-plantilla:active { transform: scale(.97); }
.gm-plantilla__icono { font-size: var(--t-glifo-lg); }
.gm-plantilla__nombre { font-size: var(--t-secundario); font-weight: 700; text-align: center; }
.gm-arranque { display: grid; gap: var(--e-3); justify-items: center; text-align: center; padding-top: var(--e-4); }
.gm-arranque > * { min-width: 0; width: 100%; }
.gm-arranque__icono { font-size: var(--t-cifra); }

.gm-dentro__cabeza { display: grid; grid-template-columns: auto minmax(0, 1fr); align-items: center; gap: var(--e-3); }
.gm-dentro__quien { display: grid; gap: 2px; min-width: 0; }
.gm-dentro__quien .pm-sub__titulo { overflow-wrap: anywhere; }
.gm-partida { display: grid; gap: var(--e-2); padding: var(--e-3) var(--e-4); min-width: 0; }
.gm-partida__cabeza { display: flex; justify-content: space-between; gap: var(--e-3); min-width: 0; }
.gm-partida__cifra { font-size: var(--t-secundario); font-weight: 700; white-space: nowrap; }


/* ==========================================================================
   48.1 · TELÉFONO: INICIO, MOVIMIENTOS Y BUSCAR
   ==========================================================================
   Desde el 2026-10-01 cada una tiene su archivo de teléfono —inicio-movil.js,
   movimientos-movil.js, buscar-movil.js— y viste sus propias clases: `im-`,
   `mm-` y `bm-`. Las filas agrupadas y los accesos redondos son los de Mi
   perfil (§47: `pm-lista`, `pm-fila`, `pm-rapidos`), para que todo el teléfono
   se lea con la misma mano.

   Sin cortes de ancho: estas clases solo existen en el teléfono, porque solo
   ahí se pinta el archivo que las pone. Todo lo que se toca mide 48px. */

/* ---------- Inicio ---------- */
.im { display: grid; gap: var(--e-6); min-width: 0; }
.im > * { min-width: 0; }

/* La cifra, sin tarjeta: centrada sobre el fondo con un halo del tono. */
.im-heroe {
  --halo: var(--marca-suave);
  position: relative;
  display: grid;
  justify-items: center;
  gap: var(--e-2);
  padding: var(--e-5) var(--e-2) var(--e-2);
  text-align: center;
}
.im-heroe[data-tono="bien"] { --halo: var(--ok-suave); }
.im-heroe[data-tono="ojo"]  { --halo: var(--alerta-suave); }
.im-heroe[data-tono="mal"]  { --halo: var(--peligro-suave); }
.im-heroe::before {
  content: "";
  position: absolute;
  inset: -10% 0 10% 0;
  background: radial-gradient(closest-side, var(--halo), transparent 80%);
  pointer-events: none;
}
.im-heroe > * { position: relative; margin: 0; }
.im-heroe__rotulo { font-size: var(--t-secundario); font-weight: 600; color: var(--txt-2); }
.im-heroe__cifra {
  font-size: var(--t-cifra-alta);
  font-weight: 800;
  letter-spacing: var(--track-cifra);
  line-height: 1;
  font-variant-numeric: tabular-nums;
  max-width: 100%;
  overflow-wrap: anywhere;
}
.im-heroe__frase, .mm-resumen__frase {
  display: inline-flex;
  align-items: center;
  gap: var(--e-2);
  max-width: 100%;
  padding: var(--e-1) var(--e-3);
  border-radius: var(--r-full);
  background: var(--capa-1);
  border: 1px solid var(--linea);
  font-size: var(--t-secundario);
  font-weight: 600;
  color: var(--txt);
  text-align: left;
}
.im-heroe__senal, .mm-resumen__senal {
  flex: none;
  width: 22px; height: 22px;
  display: grid; place-items: center;
  border-radius: var(--r-full);
  background: var(--marca-suave);
  color: var(--marca-txt);
  font-size: var(--t-nano);
  font-weight: 800;
}
:is(.im-heroe__frase, .mm-resumen__frase)[data-tono="bien"] > :first-child { background: var(--ok-suave); color: var(--ok-txt); }
:is(.im-heroe__frase, .mm-resumen__frase)[data-tono="ojo"] > :first-child { background: var(--alerta-suave); color: var(--alerta-txt); }
:is(.im-heroe__frase, .mm-resumen__frase)[data-tono="mal"] > :first-child { background: var(--peligro-suave); color: var(--peligro-txt); }
.im-heroe__pie { font-size: var(--t-meta); color: var(--txt-3); }
.im-heroe__nota {
  max-width: 30ch;
  font-size: var(--t-meta);
  color: var(--alerta-txt);
}

.im-rapidos { padding: 0 var(--e-1); }

.im-bloque { display: grid; gap: var(--e-3); min-width: 0; }
.im-bloque > * { min-width: 0; }
.im-bloque__cabeza, .mm-bloque__cabeza, .bm-grupo__cabeza {
  display: flex;
  align-items: center;
  gap: var(--e-2);
  min-width: 0;
  padding: 0 var(--e-2);
}
.im-bloque__titulo, .mm-bloque__titulo {
  flex: 1 1 auto;
  min-width: 0;
  margin: 0;
  font-size: var(--t-tarjeta);
  font-weight: 800;
}
.im-bloque__accion { min-height: 48px; margin-right: calc(var(--e-2) * -1); }
.im-bloque__vacio {
  margin: 0;
  padding: var(--e-4);
  border-radius: var(--r-lg);
  background: var(--capa-1);
  border: 1px solid var(--linea);
  font-size: var(--t-secundario);
  color: var(--ok-txt);
}
/* Los descubrimientos, apilados: en un carril lo del tercero no se ve. */
.im-notamos .insights { display: grid; grid-auto-flow: row; overflow: visible; }
.im-notamos .insight { width: auto; min-width: 0; }
.im-notamos__mas { width: 100%; min-height: 48px; }

/* Lo que se viene: una fila por pago. */
.im-pago {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--e-3);
  min-height: 60px;
  padding: var(--e-2) var(--e-4);
}
.im-pago__que { display: grid; gap: 1px; min-width: 0; }
.im-pago__nombre {
  font-weight: 600;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.im-pago__cuando { font-size: var(--t-meta); color: var(--txt-3); }
.im-pago__monto { font-weight: 800; font-variant-numeric: tabular-nums; white-space: nowrap; }

.im-preguntar { min-width: 0; }
/* La línea de preguntar, en UNA fila también a 360: la frase se encoge y el
   botón no. Partida en dos era una tarjeta alta para una pregunta. */
.im .ia-linea, .mm .ia-linea { flex-wrap: nowrap; }
.im .ia-linea__texto, .mm .ia-linea__texto { flex: 1 1 auto; font-size: var(--t-secundario); }
.im .ia-linea .btn, .mm .ia-linea .btn { flex: none; min-height: 48px; }

/* La bienvenida, centrada y corta. */
.im-bienvenida { justify-items: center; text-align: center; padding-top: var(--e-6); gap: var(--e-4); }
.im-bienvenida__marca { font-size: var(--t-cifra); }
.im-bienvenida__titulo { margin: 0; font-size: var(--t-pagina); font-weight: 800; }
.im-bienvenida__texto { margin: 0; max-width: 30ch; color: var(--txt-2); }
.im-bienvenida__promesa { margin: 0; max-width: 32ch; font-size: var(--t-meta); color: var(--txt-3); }
.im-bienvenida__acciones { display: grid; gap: var(--e-2); width: 100%; }
.im-bienvenida__acciones .btn { width: 100%; min-height: 52px; }

/* ---------- Movimientos ---------- */
.mm { display: grid; gap: var(--e-5); min-width: 0; }
.mm > * { min-width: 0; }

.mm-resumen, .bm-resumen {
  display: grid;
  justify-items: start;
  gap: var(--e-1);
  padding: var(--e-5) var(--e-4);
  border-radius: var(--r-lg);
  background: linear-gradient(160deg, var(--marca-suave), transparent 70%), var(--capa-1);
  border: 1px solid var(--linea);
  box-shadow: var(--sombra-1), var(--filo);
  min-width: 0;
}
.mm-resumen > *, .bm-resumen > * { margin: 0; max-width: 100%; }
.mm-resumen__rotulo, .bm-resumen__rotulo { font-size: var(--t-secundario); font-weight: 600; color: var(--txt-2); }
.mm-resumen__cifra, .bm-resumen__cifra {
  font-size: var(--t-cifra);
  font-weight: 800;
  letter-spacing: var(--track-cifra-2);
  line-height: 1.1;
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}
.mm-resumen__pie, .bm-resumen__pie { font-size: var(--t-meta); color: var(--txt-3); }
.mm-resumen__frase { margin-top: var(--e-2); }

/* El buscador a lo ancho y «Filtros» al lado. */
.mm-buscar {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: var(--e-2);
  min-width: 0;
}
/* Con el elemento en el selector: la regla base de los campos (sistema.css)
   pesa (0,2,1) y con dos clases solas se quedaba con el borde y el relleno. */
.mm-buscar input.mm-buscar__campo, .bm-campo input.bm-campo__texto {
  width: 100%;
  min-width: 0;
  min-height: 48px;
  padding: 0 var(--e-4);
  border-radius: var(--r-full);
  border: 1px solid var(--linea-fuerte);
  background: var(--capa-1);
  color: var(--txt);
  font: inherit;
  /* 1rem y no menos: con 15px el iPhone hace zoom al enfocar el campo. */
  font-size: 1rem;
}
.mm-buscar__filtros { min-height: 48px; border-radius: var(--r-full); padding: 0 var(--e-4); }

.mm-hoja { display: grid; gap: var(--e-4); min-width: 0; }
.mm-hoja > * { min-width: 0; }
.mm-hoja .segmentos { display: flex; width: 100%; }
.mm-hoja .segmentos button { flex: 1 1 0; min-width: 0; min-height: 44px; padding: 0 var(--e-1); }
.mm-hoja__montos { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--e-3); }
.mm-hoja__montos > * { min-width: 0; }
.mm-hoja select, .mm-hoja input { width: 100%; min-height: 48px; }

/* Los filtros puestos, cada uno con su ✕. */
.mm-etiquetas { display: flex; flex-wrap: wrap; gap: var(--e-2); min-width: 0; }
.mm-etiqueta {
  display: inline-flex;
  align-items: center;
  gap: var(--e-2);
  max-width: 100%;
  min-height: 40px;
  padding: 0 var(--e-3);
  border-radius: var(--r-full);
  border: 1px solid var(--linea-fuerte);
  background: var(--marca-suave);
  color: var(--marca-txt);
  font: inherit;
  font-size: var(--t-secundario);
  font-weight: 600;
  cursor: pointer;
}
.mm-etiqueta__que { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Los atajos de categoría, en un carril que se pasa con el dedo. */
.mm-atajos, .bm-atajos {
  display: flex;
  gap: var(--e-2);
  min-width: 0;
  overflow-x: auto;
  scrollbar-width: none;
  padding-bottom: 2px;
}
.bm-atajos { flex-wrap: wrap; overflow: visible; }
.mm-atajos::-webkit-scrollbar { display: none; }
.mm-atajo {
  flex: none;
  min-height: 40px;
  padding: 0 var(--e-4);
  border-radius: var(--r-full);
  border: 1px solid var(--linea);
  background: var(--capa-1);
  color: var(--txt-2);
  font: inherit;
  font-size: var(--t-secundario);
  font-weight: 600;
  white-space: nowrap;
  cursor: pointer;
}
.mm-atajo[aria-pressed="true"] { background: var(--capa-3); color: var(--txt); border-color: var(--linea-fuerte); box-shadow: var(--sombra-1); }
.mm-atajo--falta { border-style: dashed; color: var(--alerta-txt); }

.mm-bloque { display: grid; gap: var(--e-3); min-width: 0; }
.mm-bloque > * { min-width: 0; }
.mm-bloque__cuantos {
  padding: 2px var(--e-2);
  border-radius: var(--r-full);
  background: var(--capa-2);
  font-size: var(--t-chip);
  font-weight: 700;
  color: var(--txt-2);
}
/* El «⋯» mide lo que mide: la regla general de §13 estira las herramientas a lo
   ancho, y aquí partía el título en dos líneas. */
.mm-bloque__cabeza .card__tools { flex: none; width: auto; margin-left: auto; }
.mm-bloque__cabeza .card__tools .btn { flex: none; }
.mm-tres, .bm-tres { min-width: 48px; min-height: 48px; font-size: var(--t-glifo-md); }
.mm-bloque__cabeza .btn { min-height: 48px; }

.mm-lista { display: grid; gap: var(--e-4); min-width: 0; }
.mm-dia { display: grid; gap: var(--e-2); min-width: 0; }
.mm-dia .dia-cabeza { padding: 0 var(--e-2); background: transparent; border: 0; }

/* Una fila es un botón a todo lo ancho. */
.mm-fila {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--e-3);
  width: 100%;
  min-width: 0;
  min-height: 64px;
  padding: var(--e-2) var(--e-4);
  border: 0;
  background: transparent;
  color: var(--txt);
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.mm-fila:active { background: var(--capa-2); }
.mm-fila__que { display: grid; gap: 2px; min-width: 0; }
.mm-fila__nombre {
  font-weight: 600;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.mm-fila__meta {
  font-size: var(--t-meta);
  color: var(--txt-3);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.mm-fila[data-falta="si"] .mm-fila__cat { color: var(--alerta-txt); font-weight: 600; }
.mm-fila__monto {
  font-size: var(--t-secundario);
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.mm-fila__monto[data-signo="mas"] { color: var(--ok-txt); }
.mm-fila[data-apagado="si"] .mm-fila__nombre,
.mm-fila[data-apagado="si"] .mm-fila__monto { color: var(--txt-3); }
/* Seleccionando, la casilla ocupa el sitio del avatar y mide lo mismo. */
.mm-fila__casilla {
  width: 40px; height: 40px;
  display: grid; place-items: center;
  border-radius: var(--r-full);
  border: 2px solid var(--linea-fuerte);
  color: #fff;
  font-weight: 800;
}
.mm-fila[aria-pressed="true"] .mm-fila__casilla { background: var(--grad-accion); border-color: transparent; }
.mm-fila[aria-pressed="true"] { background: var(--marca-suave); }

.mm-mas { width: 100%; min-height: 48px; }
.mm-pie { margin: 0; padding: 0 var(--e-2); font-size: var(--t-meta); color: var(--txt-3); }

/* La barra de lo seleccionado, pegada abajo encima de la barra del pulgar. */
.mm-seleccion {
  position: sticky;
  bottom: calc(var(--alto-tabbar) + env(safe-area-inset-bottom, 0px) + var(--e-2));
  z-index: 5;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto auto;
  align-items: center;
  gap: var(--e-2);
  padding: var(--e-2) var(--e-2) var(--e-2) var(--e-4);
  border-radius: var(--r-lg);
  background: var(--capa-3);
  border: 1px solid var(--linea-fuerte);
  box-shadow: var(--sombra-2);
}
.mm-seleccion__cuantos { font-weight: 700; font-size: var(--t-secundario); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mm-seleccion .btn { min-height: 48px; padding: 0 var(--e-3); }

/* ---------- Buscar ---------- */
.bm { display: grid; gap: var(--e-5); min-width: 0; }
.bm > * { min-width: 0; }
.bm-campo { display: grid; gap: var(--e-3); min-width: 0; }
/* El campo es la PÍLDORA entera, con la lupa y la ✕ dentro como columnas: con
   la lupa encima del campo y un relleno a la izquierda, las reglas de los campos
   del teléfono le quitaban el relleno y la lupa tapaba la primera letra. */
.bm-campo__fila {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  min-width: 0;
  min-height: 52px;
  margin: 0;
  padding-left: var(--e-4);
  border-radius: var(--r-full);
  border: 1px solid var(--linea-fuerte);
  background: var(--capa-1);
}
.bm-campo__fila:focus-within { border-color: var(--marca); }
.bm-campo__fila input.bm-campo__texto {
  min-height: 48px;
  padding: 0 var(--e-2);
  border: 0;
  border-radius: 0;
  background: transparent;
  box-shadow: none;
}
.bm-campo__lupa { color: var(--txt-3); font-size: var(--t-glifo-md); pointer-events: none; }
.bm-campo__vaciar {
  width: 48px; height: 48px;
  border: 0;
  border-radius: var(--r-full);
  background: transparent;
  color: var(--txt-2);
  font: inherit;
  cursor: pointer;
}
.bm-campo .segmentos { display: flex; width: 100%; }
.bm-campo .segmentos button { flex: 1 1 0; min-width: 0; min-height: 44px; padding: 0 var(--e-1); }
.bm-pista { margin: 0; padding: 0 var(--e-2); font-size: var(--t-meta); color: var(--txt-3); }
.bm-punto { width: 14px; height: 14px; margin: 0 11px; border-radius: var(--r-full); }
.bm-grupo__cabeza { padding: 0; }
.bm-grupo__cabeza .pm-grupo__titulo { flex: 1 1 auto; }

.bm-resumen { position: relative; }
.bm-resumen__cabeza {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--e-2);
  width: 100%;
}
.bm-resumen__rotulo { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.bm-datos {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--e-2);
  width: 100%;
  margin: var(--e-3) 0 0;
}
.bm-dato {
  min-width: 0;
  padding: var(--e-2) var(--e-3);
  border-radius: var(--r-sm);
  background: var(--capa-2);
  border: 1px solid var(--linea);
}
.bm-dato dt { margin: 0; font-size: var(--t-meta); color: var(--txt-3); }
.bm-dato dd {
  margin: 2px 0 0;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.bm-tarjeta { padding: var(--e-4); min-width: 0; }

/* ==========================================================================
   48.2 · TELÉFONO: ANÁLISIS
   ==========================================================================
   Las pantallas de teléfono de Análisis —panel-movil.js, reportes-movil.js y
   diagnostico-movil.js— con sus piezas de js/analisis-piezas-movil.js. Prefijo
   `am-`: ninguna regla de aquí toca el escritorio, que sigue con las suyas
   (§34), y ninguna de las suyas llega aquí salvo las piezas que se reutilizan
   a propósito (`.cambio`, `.partida`, `.ana-leyenda`, `.limite`).

   Lo que se toca mide 48px (el pulgar), y lo que se lee va en FILAS: nombre a
   la izquierda, cifra a la derecha, nada que leer de lado. */

.am, .am-zona { display: grid; gap: var(--e-4); min-width: 0; }
.am > *, .am-zona > *, .am-preguntas > * { min-width: 0; }
.am-preguntas { display: grid; gap: var(--e-3); min-width: 0; }

/* ---------- Las tres pestañas: del ancho de la pantalla ---------- */
.am-pestanas .segmentos { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); width: 100%; }
.am-pestanas .segmentos button { min-height: 48px; padding: 0 var(--e-2); font-size: var(--t-secundario); }

/* ---------- La tarjeta-pregunta ----------
   La respuesta va en la cabecera, debajo de la pregunta, y se lee aunque la
   tarjeta esté plegada: un poco más grande y con la tinta de leer, no la gris
   de una pista. */
.am-pregunta { display: grid; gap: var(--e-3); }
.am-pregunta > .card__head { margin-bottom: 0; }
.am-pregunta > .card__head h2 { font-size: var(--t-tarjeta); }
.am-pregunta > .card__head p {
  margin-top: var(--e-1);
  font-size: var(--t-secundario);
  color: var(--txt-2);
  line-height: 1.4;
}

/* ---------- Las filas ---------- */
.am-filas { display: grid; min-width: 0; }
.am-filas > * + * { border-top: 1px solid var(--linea); }
.am-fila {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  column-gap: var(--e-3);
  row-gap: 6px;
  min-width: 0;
  min-height: 48px;
  padding: var(--e-2) 0;
}
.am-fila:has(> .am-fila__punto) { grid-template-columns: auto minmax(0, 1fr) auto; }
.am-fila__punto { width: 10px; height: 10px; border-radius: var(--r-full); flex: none; }
.am-fila__que { display: grid; gap: 2px; min-width: 0; }
.am-fila__nombre {
  font-weight: 600;
  font-size: var(--t-cuerpo);
  color: var(--txt);
  overflow-wrap: anywhere;
}
.am-fila__sub { font-size: var(--t-meta); color: var(--txt-3); overflow-wrap: anywhere; }
.am-fila__cuanto {
  font-weight: 700;
  font-size: var(--t-cuerpo);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  text-align: right;
}
.am-fila[data-tono="ok"] .am-fila__cuanto { color: var(--ok-txt); }
.am-fila[data-tono="peligro"] .am-fila__cuanto { color: var(--peligro-txt); }
.am-fila[data-tono="alerta"] .am-fila__cuanto { color: var(--alerta-txt); }
.am-fila[data-tono="marca"] .am-fila__cuanto { color: var(--marca-txt); }

/* La barra, a lo ancho y debajo: en 360px no hay sitio para tres columnas. */
.am-fila__carril {
  grid-column: 1 / -1;
  height: 6px;
  border-radius: var(--r-full);
  background: var(--bg-2);
  overflow: hidden;
}
.am-fila__barra {
  display: block;
  height: 100%;
  width: calc(var(--parte, 0) * 100%);
  border-radius: inherit;
  background: var(--marca);
}
.am-fila[data-tono="ok"] .am-fila__barra { background: var(--ok); }
.am-fila[data-tono="peligro"] .am-fila__barra { background: var(--peligro); }

/* Con su chispa: la forma de la categoría, a lo ancho y debajo. */
.am-fila--chispa .am-fila__chispa { grid-column: 1 / -1; display: block; min-width: 0; }
.am-fila--chispa .chispa { width: 100%; height: 28px; display: block; }

/* La fila que se toca: entera, con su flecha. */
.am-fila--boton {
  grid-template-columns: minmax(0, 1fr) auto auto;
  width: 100%;
  min-height: 56px;
  border: 0;
  border-radius: 0;
  background: transparent;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.am-fila--boton:active { background: var(--capa-2); }
.am-fila__flecha { color: var(--txt-3); font-size: var(--t-glifo-md); }

/* La cuenta y cómo va, en palabras y con su tono. */
.am-fila__estado { font-size: var(--t-meta); font-weight: 700; text-align: right; color: var(--txt-2); }
.am-fila--cuenta[data-tono="ok"] .am-fila__estado { color: var(--ok-txt); }
.am-fila--cuenta[data-tono="alerta"] .am-fila__estado { color: var(--alerta-txt); }
.am-fila--cuenta[data-tono="peligro"] .am-fila__estado { color: var(--peligro-txt); }

.am-nota { margin: 0; font-size: var(--t-meta); color: var(--txt-3); }

/* ---------- Los botones: anchos y de un pulgar ---------- */
.am-ir, .am-boton { min-height: 48px; width: 100%; justify-content: center; }
.am-ir--peligro, .am-boton--peligro { color: var(--peligro-txt); }
.am .ia-linea .btn { min-height: 48px; }
.am .insight__accion { min-height: 48px; padding: 0; display: inline-flex; align-items: center; }
.am-sospechas__abrir { color: var(--txt-2); }

/* ---------- La cifra de arriba ---------- */
.am-cifra .limite { margin-top: var(--e-2); }

/* ---------- Los dibujos ---------- */
.am-area { min-width: 0; }
.am-area .area { display: block; width: 100%; }
.am .cambio__barra { border-radius: 4px; }
.am .cambio__barra[data-sube="si"] { background: var(--alerta); }
.am .cambio__barra[data-sube="no"] { background: var(--ok); }
.am .cambio__pie { color: var(--txt-3); font-size: var(--t-meta); }
.am .cambio__anual { margin: var(--e-3) 0 0; color: var(--txt-2); font-size: var(--t-secundario); }
.am .barras-par { justify-content: space-between; gap: var(--e-2); }
.am-salud { display: grid; place-items: center; padding: var(--e-1) 0; }

/* ---------- Las listas que ya existían ---------- */
.am-comercios { display: grid; min-width: 0; }
.am-comercios .fila-com { min-height: 56px; padding-left: 0; padding-right: 0; }
.am-comercios > * + * { border-top: 1px solid var(--linea); }
.am-recientes .mov-fila { min-height: 56px; padding-left: 0; padding-right: 0; }
.am-recientes .mov-fila__que--abre { min-height: 48px; justify-content: center; }
.am-limites { display: grid; gap: var(--e-4); min-width: 0; }

/* ---------- Revisar: el mes, los repetidos y el buscador ---------- */
.am-mes { display: grid; gap: var(--e-1); min-width: 0; }
.am-mes__rotulo { font-size: var(--t-etiqueta); font-weight: 700; color: var(--txt-3); }
/* 1rem, no menos: con menos el iPhone acerca la pantalla al tocar el campo. */
.am-mes__campo { min-height: 48px; width: 100%; font-size: 1rem; }
.am-repetidos { display: grid; gap: var(--e-3); min-width: 0; }
.am-repetidos > * + * { border-top: 1px solid var(--linea); padding-top: var(--e-3); }
.am-repetido { display: grid; gap: var(--e-2); min-width: 0; }
.am-repetido__botones { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: var(--e-2); }
.am-buscar__forma { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: var(--e-2); min-width: 0; }
.am-buscar__campo { min-height: 48px; min-width: 0; font-size: 1rem; }
.am-buscar__forma .am-boton { width: auto; padding: 0 var(--e-4); }

/* ---------- Sin datos ---------- */
.am-vacio__acciones { display: grid; gap: var(--e-2); width: 100%; }
.am-vacio__acciones .btn { min-height: 48px; }

/* ==========================================================================
   48.4 · TELÉFONO: SUBIR, TRASPASOS, ME DEBEN Y AYUDA
   ==========================================================================
   Las cuatro tienen su archivo de teléfono desde el 2026-10-01
   (importar-movil.js, traspasos-movil.js, cobros-movil.js, soporte-movil.js) y
   visten estas clases, `um-`. Las filas y los grupos son los de Mi perfil
   (§47: `pm-grupo`, `pm-lista`, `pm-fila`) y la cifra de arriba la de Metas
   (§48.3: `gm-heroe`), para que todo el teléfono se lea con la misma mano.

   Sin cortes de ancho: estas clases solo existen en el teléfono. Todo lo que
   se pulsa mide 48px; nada de tablas. */

.um { display: grid; gap: var(--e-5); min-width: 0; }
.um > * { min-width: 0; }
.um-opcion { width: 100%; min-height: 52px; }
.um-vacio { padding: var(--e-2) var(--e-3); }
.um-vacio .estado { padding: var(--e-4) var(--e-2); }
.um-casilla { display: flex; align-items: center; min-height: 48px; }

/* ---------- La cabeza de Subir: sin tarjeta ---------- */
.um-heroe { display: grid; gap: var(--e-2); padding: var(--e-2) var(--e-1) 0; min-width: 0; }
.um-heroe > * { margin: 0; min-width: 0; }
.um-heroe__rotulo { font-size: var(--t-etiqueta); font-weight: 700; color: var(--txt-3); }
.um-heroe__titulo {
  font-size: var(--t-cifra-media);
  font-weight: 800;
  line-height: 1.15;
  letter-spacing: var(--track-cifra-2);
  overflow-wrap: anywhere;
}
.um-heroe__cifra {
  font-size: var(--t-cifra);
  font-weight: 800;
  line-height: 1.05;
  letter-spacing: var(--track-cifra-2);
  overflow-wrap: anywhere;
}
.um-heroe__apoyo { font-size: var(--t-secundario); color: var(--txt-2); }
.um-heroe__aviso {
  justify-self: start;
  padding: var(--e-1) var(--e-3);
  border-radius: var(--r-full);
  background: var(--alerta-suave);
  color: var(--alerta-txt);
  font-size: var(--t-meta);
  font-weight: 700;
}

/* Los tres botones de subir: el de acento a lo ancho, los otros dos debajo. */
.um-zona { display: grid; gap: var(--e-2); min-width: 0; border-radius: var(--r-lg); }
.um-dos { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--e-2); }
.um-grande { width: 100%; min-width: 0; min-height: 56px; padding: 0 var(--e-2); gap: var(--e-2); }
.um-zona > .um-grande { min-height: 64px; font-size: var(--t-tarjeta); }

/* ---------- Una ficha del lote ---------- */
.um .imp-lotes { margin-top: 0; }
.um-lote {
  display: grid;
  gap: var(--e-3);
  padding: var(--e-3) var(--e-4) var(--e-4);
  border-radius: var(--r-lg);
  box-shadow: var(--sombra-1), var(--filo);
  min-width: 0;
}
.um-lote > * { min-width: 0; }
.um-lote__cabeza {
  display: grid;
  gap: 2px;
  min-height: 48px;
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--txt);
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.um-lote__nombre { font-weight: 700; overflow-wrap: anywhere; }
.um-lote__meta { font-size: var(--t-meta); color: var(--txt-3); }
.um-cuenta { width: 100%; min-height: 48px; }
.um-lote__botones { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--e-2); }
.um-lote__botones .btn { min-height: 48px; min-width: 0; }
.um-lote .imp-lote__saldo { display: flex; align-items: flex-start; min-height: 48px; padding-top: var(--e-1); }
.um-numero { margin: 0; font-size: var(--t-meta); font-weight: 700; color: var(--txt-2); }
.um-numero[data-tono="ok"] { color: var(--ok-txt); }
.um-numero[data-tono="ojo"] { color: var(--alerta-txt); }
.um-numero[data-tono="mal"] { color: var(--peligro-txt); }
.um-numero-arreglo { display: grid; gap: var(--e-2); }

/* ---------- Lo leído: la fila de Movimientos, en dos líneas ---------- */
.um-lista {
  background: var(--capa-1);
  border: 1px solid var(--linea);
  border-radius: var(--r-lg);
  box-shadow: var(--sombra-1), var(--filo);
  overflow: hidden;
}
.um-lista .mov-fila {
  grid-template-columns: minmax(0, 1fr) auto;
  gap: var(--e-1) var(--e-3);
  padding: var(--e-2) var(--e-4);
  border-radius: 0;
}
.um-lista .mov-fila__que { grid-column: 1; grid-row: 1; min-height: 48px; justify-content: center; }
.um-lista .mov-fila__monto { grid-column: 2; grid-row: 1; }
.um-lista .mov-fila__cat { grid-column: 1 / -1; grid-row: 2; justify-self: start; min-width: 0; }
.um-lista .mov-fila__cat .chip-cat { min-height: 40px; }
.um-mas { width: 100%; min-height: 48px; }
.um-ignorada { display: grid; gap: 2px; padding: var(--e-2) var(--e-4); min-width: 0; }
.um-ignorada .pm-fila__meta { white-space: normal; overflow-wrap: anywhere; }

/* El pie de confirmar, pegado sobre la barra del pulgar. */
.um-pie {
  position: sticky;
  bottom: calc(var(--alto-tabbar) + env(safe-area-inset-bottom, 0px) + var(--e-2));
  z-index: 5;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: var(--e-2);
  padding: var(--e-2);
  border-radius: var(--r-lg);
  background: var(--capa-3);
  border: 1px solid var(--linea-fuerte);
  box-shadow: var(--sombra-2);
}
.um-pie .btn { min-height: 52px; min-width: 0; padding: 0 var(--e-3); }

/* ---------- Traspasos ---------- */
.um-idea {
  display: grid;
  justify-items: center;
  gap: var(--e-3);
  padding: var(--e-4);
  border-radius: var(--r-lg);
  background: linear-gradient(160deg, var(--marca-suave), transparent 75%), var(--capa-1);
  border: 1px solid var(--linea);
  text-align: center;
}
.um-idea__dibujo { display: flex; align-items: center; gap: var(--e-3); }
.um-idea__caja {
  width: 56px; height: 56px;
  display: grid; place-items: center;
  border-radius: var(--r-md);
  background: var(--capa-2);
  font-size: var(--t-glifo-lg);
}
.um-idea__flecha { font-size: var(--t-glifo-lg); color: var(--marca-txt); }
.um-idea__texto { margin: 0; font-size: var(--t-secundario); color: var(--txt-2); }
.um-idea__texto strong { color: var(--txt); }
.um-frase .pm-fila__dos { gap: var(--e-1); }
.um-frase__texto {
  font-size: var(--t-meta);
  white-space: normal;
  overflow-wrap: anywhere;
  color: var(--txt);
}

/* ---------- Me deben ---------- */
.um-heroe-cobros[data-tono="ojo"] .gm-heroe__frase { background: var(--alerta-suave); color: var(--alerta-txt); border-color: transparent; }
.um-cobro .pm-fila__nombre { white-space: normal; overflow-wrap: anywhere; }
.um-cobro .pm-fila__dos { gap: var(--e-1); }
.um-cuando[data-tono="ojo"] { color: var(--alerta-txt); font-weight: 700; }
.um-avance { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: var(--e-2); }
.um-avance__carril { display: block; height: 6px; border-radius: var(--r-full); background: var(--bg-2); overflow: hidden; }
.um-avance__relleno {
  display: block;
  height: 100%;
  width: calc(var(--parte, 0) * 100%);
  border-radius: inherit;
  background: var(--ok);
}
.um-avance__texto { font-size: var(--t-meta); font-weight: 700; color: var(--txt-2); white-space: nowrap; }
.um-cobro[data-estado="cerrado"] .pm-fila__nombre { color: var(--txt-2); }

/* ---------- Ayuda ---------- */
.um-ayuda__lista { display: grid; min-width: 0; }
.um-ticket .pm-fila__nombre { white-space: normal; overflow-wrap: anywhere; }
.um-nueva {
  padding: 2px var(--e-2);
  border-radius: var(--r-full);
  background: var(--ok-suave);
  color: var(--ok-txt);
  font-size: var(--t-chip);
  font-weight: 700;
}
.um-hilo { gap: var(--e-3); }
.um-hilo .pm-sub__titulo { overflow-wrap: anywhere; }
.um-hilo__mensajes { min-height: 40vh; }
.um-hilo__mensajes .hilo-soporte { max-height: none; overflow: visible; }
/* El campo, abajo y pegado sobre la barra del pulgar: donde llega el dedo. Con
   el teclado abierto la barra se esconde, y el campo baja con ella. */
.um-hilo__campo {
  position: sticky;
  bottom: calc(var(--alto-tabbar) + env(safe-area-inset-bottom, 0px) + var(--e-2));
  z-index: 5;
  padding: var(--e-3);
  border-radius: var(--r-lg);
  background: var(--capa-3);
  border: 1px solid var(--linea-fuerte);
  box-shadow: var(--sombra-2);
}
body.con-pulgar:has(.um-hilo__campo textarea:focus) .um-hilo__campo { bottom: var(--e-2); }
.um-hilo__campo textarea { width: 100%; min-height: 48px; resize: none; }
.um-hilo__campo .sop-linea { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--e-2); }
.um-hilo__campo .btn { min-height: 48px; min-width: 0; }

/* ==========================================================================
   48.5 · TELÉFONO: EMPRESA
   ==========================================================================
   Nómina, Cobrar y pagar, Almacén, Proveedores y DGII tienen su archivo de
   teléfono desde el 2026-10-06 (nomina-movil.js, cartera-movil.js,
   inventario-movil.js, proveedores-movil.js, dgii-movil.js) y visten estas
   clases, `em-`. Las filas y los grupos son los de Mi perfil (§47:
   `pm-grupo`, `pm-lista`, `pm-fila`), la cifra de arriba la de Metas (§48.3:
   `gm-heroe`) y la fila con su acción al lado la de Pagos fijos (`gm-pago`):
   todo el teléfono se lee con la misma mano. Las piezas comunes las pinta
   js/empresa-movil.js.

   Sin cortes de ancho: estas clases solo existen en el teléfono. Todo lo que
   se pulsa mide 48px; nada de tablas. */

.em { display: grid; gap: var(--e-5); min-width: 0; }
.em > *, .em-sub > * { min-width: 0; }
.em-vacio { padding: var(--e-2) var(--e-3); }
.em-vacio .estado { padding: var(--e-4) var(--e-2); }
.em-botones { display: grid; gap: var(--e-2); width: 100%; }
.em-botones .btn { min-height: 52px; }

/* Los dos lados, el formato, la quincena: del ancho de la pantalla. */
.em > .segmentos, .em-eleccion .segmentos, .em .gm-periodo .segmentos {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(0, 1fr);
}
.em .segmentos button { min-height: 44px; padding: 0 var(--e-2); min-width: 0; }
.em-eleccion { display: grid; gap: var(--e-3); }
.em-select { width: 100%; min-height: 48px; }

/* ---------- La cifra de arriba ---------- */
.em-heroe .gm-ancho { margin-top: var(--e-2); }
.em-heroe[data-tono="bien"] .gm-heroe__titular { color: var(--ok-txt); }

/* ---------- Las filas ---------- */
/* Una fila que solo se lee: sin dedo encima, ni flecha. */
.em-fila--quieta { cursor: default; }
.em-fila--quieta:active { background: transparent; }
/* Los avisos se leen enteros: cortar «Se acabaron 2 artículos: Azú…» quita
   justo el nombre que importa. */
.em-aviso .pm-fila__nombre, .em-aviso .pm-fila__meta { white-space: normal; overflow-wrap: anywhere; }
.em-accionable .pm-fila__dos { gap: var(--e-1); }
.em-rango .pm-fila__icono { font-size: var(--t-nano); font-weight: 800; letter-spacing: 0; }
.em-rango .pm-fila__valor { color: var(--txt); font-weight: 700; }
.em-fila .pm-fila__valor { color: var(--txt); font-weight: 700; }

/* Un estado en palabras, con su tono: el color nunca va solo. */
.em-estado { font-weight: 700; color: var(--txt-2); }
.em-estado[data-tono="ok"] { color: var(--ok-txt); }
.em-estado[data-tono="ojo"] { color: var(--alerta-txt); }
.em-estado[data-tono="mal"] { color: var(--peligro-txt); }

/* ---------- Una cifra en una lista ---------- */
.em-dato {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--e-3);
  min-height: 52px;
  padding: var(--e-2) var(--e-4);
  min-width: 0;
}
.em-dato__rotulo { display: grid; gap: 1px; min-width: 0; font-size: var(--t-secundario); color: var(--txt-2); overflow-wrap: anywhere; }
.em-dato__pie { font-size: var(--t-meta); color: var(--txt-3); }
.em-dato__cifra { font-weight: 700; white-space: nowrap; text-align: right; }
.em-dato--fuerte { background: var(--capa-2); }
.em-dato--fuerte .em-dato__rotulo { color: var(--txt); font-weight: 700; }
.em-dato--fuerte .em-dato__cifra { font-size: var(--t-cuerpo); }

/* ---------- La antigüedad: cinco filas con su barra ---------- */
.em-tramo {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: var(--e-1) var(--e-3);
  padding: var(--e-3) var(--e-4);
  min-width: 0;
}
.em-tramo__rotulo { display: grid; gap: 1px; font-weight: 600; min-width: 0; }
.em-tramo__pista { font-size: var(--t-meta); font-weight: 400; color: var(--txt-3); }
.em-tramo__cifra { font-weight: 700; white-space: nowrap; align-self: center; }
.em-tramo__carril {
  grid-column: 1 / -1;
  display: block;
  height: 6px;
  border-radius: var(--r-full);
  background: var(--bg-2);
  overflow: hidden;
}
.em-tramo__relleno {
  display: block;
  height: 100%;
  width: calc(var(--parte, 0) * 100%);
  border-radius: inherit;
  background: var(--marca);
}
/* Cuanto más viejo, más caliente: una escala, y el rótulo dice cuál es. */
.em-tramo[data-tramo="d30"] .em-tramo__relleno,
.em-tramo[data-tramo="d60"] .em-tramo__relleno { background: var(--alerta); }
.em-tramo[data-tramo="d90"] .em-tramo__relleno,
.em-tramo[data-tramo="mas90"] .em-tramo__relleno { background: var(--peligro); }

/* ---------- El buscador: 1rem, o el iPhone acerca la pantalla al tocarlo ---------- */
.em-buscar {
  width: 100%;
  min-height: 48px;
  padding: 0 var(--e-4);
  border-radius: var(--r-full);
  font-size: 1rem;
}

/* ---------- Lo que falta antes de generar ---------- */
.em-problema {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: start;
  gap: var(--e-3);
  padding: var(--e-3) var(--e-4);
  min-width: 0;
}
.em-problema__punto {
  width: 24px; height: 24px;
  display: grid; place-items: center;
  border-radius: var(--r-full);
  background: var(--alerta-suave);
  color: var(--alerta-txt);
  font-size: var(--t-nano);
  font-weight: 800;
}
.em-problema__texto { font-size: var(--t-secundario); overflow-wrap: anywhere; }

/* ---------- Las hojas ---------- */
.em-kardex .pm-lista { max-height: none; }
.em-linea .pm-fila__nombre, .em-linea .pm-fila__meta { white-space: normal; overflow-wrap: anywhere; }
.em-kardex__aviso {
  margin: 0;
  padding: var(--e-3) var(--e-4);
  border-radius: var(--r-md);
  background: var(--peligro-suave);
  color: var(--peligro-txt);
  font-size: var(--t-secundario);
}
.em-norma { display: grid; gap: 2px; font-size: var(--t-secundario); color: var(--txt-2); }
.em-norma strong { color: var(--txt); }

/* ---------- Las subpantallas de la nómina ---------- */
.em-sub { gap: var(--e-4); }
.em-campo select { width: 100%; min-height: 48px; }
.em .gm-mes__nombre.em-mes { text-transform: none; }
/* El apoyo de empresa es el otro dato («y debes…»), no la alarma: el tono lo
   lleva la frase de debajo, que lo dice en palabras. */
.em-heroe[data-tono="mal"] .gm-heroe__apoyo { color: var(--txt-2); }
/* Los datos de una fila se parten en vez de cortarse: «Quedan …» no dice cuánto. */
.em .pm-fila__meta { white-space: normal; overflow-wrap: anywhere; }
.em .pm-fila__nombre { white-space: normal; overflow-wrap: anywhere; }

/* ==========================================================================
   48.6 · TELÉFONO: ADMINISTRACIÓN
   ==========================================================================
   El panel tiene su archivo de teléfono desde el 2026-10-01 (admin-movil.js) y
   viste estas clases, `xm-`. Las filas y los grupos son los de Mi perfil (§47:
   `pm-grupo`, `pm-lista`, `pm-fila`, `pm-sub`), para que el panel se lea con la
   misma mano que el resto del teléfono.

   Dos cosas propias: el estado de cada cosa dicho en palabras con su tono
   (`xm-chip`: el color nunca solo), y lo que hace falta para que las secciones
   que se pintan con la pieza del ESCRITORIO —Planes, Precios, Cobros, Equipo…—
   se puedan tocar con el dedo dentro de la subpantalla (`.xm-seccion`).

   Sin cortes de ancho: estas clases solo existen en el teléfono. */

/* El ancho entero, a propósito. `.view` es un hijo de `.main` (una columna
   flex) centrado con `margin: 0 auto`, y así se encoge a lo que lleva dentro:
   con una subpantalla de filas cortas —las cifras— salía centrada y estrecha,
   con 16px de más a cada lado. Las pantallas con algo ancho no lo notan. */
.view:has(> .xm) { width: 100%; }
.xm { display: grid; gap: var(--e-5); width: 100%; min-width: 0; }
.xm > *, .xm-bloque > *, .xm-seccion > * { min-width: 0; }
.xm-bloque { display: grid; gap: var(--e-4); min-width: 0; }
.xm-seccion { display: grid; gap: var(--e-4); min-width: 0; }

/* ---------- La cabeza: la respuesta en una línea ---------- */
.xm-cabeza { display: grid; gap: var(--e-1); padding: var(--e-2) var(--e-1) 0; min-width: 0; }
.xm-cabeza > * { margin: 0; min-width: 0; }
.xm-cabeza__rotulo { font-size: var(--t-etiqueta); font-weight: 700; color: var(--txt-3); }
.xm-cabeza__titulo {
  font-size: var(--t-cifra-media);
  font-weight: 800;
  line-height: 1.15;
  letter-spacing: var(--track-cifra-2);
  overflow-wrap: anywhere;
}
.xm-cabeza[data-tono="ojo"] .xm-cabeza__titulo { color: var(--alerta-txt); }
.xm-cabeza[data-tono="bien"] .xm-cabeza__titulo { color: var(--ok-txt); }
.xm-cabeza__apoyo { font-size: var(--t-secundario); color: var(--txt-2); overflow-wrap: anywhere; }

/* ---------- La fila del panel: dos líneas y su estado ---------- */
.xm-fila .pm-fila__nombre {
  white-space: normal;
  overflow-wrap: anywhere;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}
.xm-fila__hueco { width: 0; }

.xm-chip {
  justify-self: end;
  max-width: 9rem;
  padding: 2px var(--e-2);
  border-radius: var(--r-full);
  background: var(--marca-suave);
  color: var(--marca-txt);
  font-size: var(--t-chip);
  font-weight: 700;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.xm-chip[data-tono="bien"], .xm-chip[data-tono="good"] { background: var(--ok-suave); color: var(--ok-txt); }
.xm-chip[data-tono="ojo"], .xm-chip[data-tono="warn"], .xm-chip[data-tono="warning"] {
  background: var(--alerta-suave); color: var(--alerta-txt);
}
.xm-chip[data-tono="mal"], .xm-chip[data-tono="bad"], .xm-chip[data-tono="critical"] {
  background: var(--peligro-suave); color: var(--peligro-txt);
}

/* Una fila que solo dice algo: rótulo y valor, sin flecha. */
.xm-dato {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--e-3);
  min-height: 48px;
  padding: var(--e-2) var(--e-4);
  min-width: 0;
}
.xm-dato__rotulo { min-width: 0; color: var(--txt-2); overflow-wrap: anywhere; }
.xm-dato__valor { font-weight: 700; text-align: right; overflow-wrap: anywhere; max-width: 12rem; }

/* Una línea del registro de una cuenta: qué, y debajo cuándo y quién. */
.xm-linea { display: grid; gap: 2px; padding: var(--e-3) var(--e-4); min-width: 0; }
.xm-linea__que { font-weight: 600; overflow-wrap: anywhere; }
.xm-linea__meta { font-size: var(--t-meta); color: var(--txt-3); overflow-wrap: anywhere; }

.xm-vacio { padding: var(--e-2) var(--e-3); }
.xm-vacio .estado { padding: var(--e-4) var(--e-2); }
.xm-ficha { display: grid; gap: var(--e-4); min-width: 0; }

/* ---------- Buscar y filtrar con el pulgar ---------- */
.xm-buscador, .xm-selector { width: 100%; min-height: 48px; min-width: 0; }
.xm-busca { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: var(--e-2); min-width: 0; }
.xm-busca__ir { min-height: 48px; }
.xm-herramientas { display: grid; gap: var(--e-2); min-width: 0; }
/* Una sola fila de partes iguales: envolviéndose, tres opciones quedaban dos
   arriba y una sola abajo, y la de abajo parecía otra cosa. */
.xm-filtro { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); gap: var(--e-2); min-width: 0; }
.xm-filtro__opcion {
  min-height: 48px;
  min-width: 0;
  padding-left: var(--e-2);
  padding-right: var(--e-2);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* El elegido, con el tono suave de la marca y no con el acento: el acento es de
   la acción de la pantalla. */
.xm-filtro__opcion[aria-pressed="true"] {
  background: var(--marca-suave);
  color: var(--marca-txt);
  border-color: var(--marca);
}
.xm-acciones { display: grid; gap: var(--e-2); min-width: 0; }
.xm-ancho, .xm-mas { width: 100%; min-height: 52px; }

/* ---------- La ventana, al final: sus tres botones como filas ---------- */
.xm-ventana .adm-ventana { padding: var(--e-3) var(--e-4); align-items: flex-start; }
.xm-ventana .adm-ventana__punto { margin-top: 6px; }
.xm-ventana .adm-ventana__texto { flex: 1 1 0; font-size: var(--t-secundario); }
.xm-ventana .adm-ventana__acciones { flex: 1 1 100%; display: grid; gap: var(--e-2); }
.xm-ventana .adm-ventana__acciones .btn { width: 100%; min-height: 48px; justify-content: center; }

/* ---------- Las secciones que se pintan con la pieza del escritorio ----------
   Sus botones son `btn--sm` y sus filtros, campos de 36px: se pensaron para un
   ratón. Dentro de la subpantalla todo lo que se toca mide 48, y las filas de
   herramientas se apilan en vez de apretarse. */
.xm-seccion .btn, .xm-seccion input:not([type="checkbox"]):not([type="radio"]),
.xm-seccion select { min-height: 48px; }
.xm-seccion .adm-herramientas { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--e-2); }
.xm-seccion .adm-herramientas > * { width: 100%; min-width: 0; }
.xm-seccion .adm-pie-lista { display: grid; gap: var(--e-2); }
.xm-seccion .card { min-width: 0; }
