/* coko-web — identidad Coko (claro, verde bosque, serif para cifras).
   Portado del mockup aprobado 2026-07-24/25. */

:root {
  --serif: Georgia, 'Iowan Old Style', 'Times New Roman', serif;
  --sans: system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
  --bg: #f2f2f2; --card: #ffffff; --accent: #1a6b3c; --accent-soft: #e6f0ea;
  --text: #1c1f1d; --muted: #6a736e; --border: #e7e7e5;
  --ok: #1a6b3c; --warn: #c98a1a; --crit: #c0392b; --income: #1a6b3c;
}

* { box-sizing: border-box; }
html, body { height: 100%; }
body {
  margin: 0; background: var(--bg); font-family: var(--sans); color: var(--text);
  overscroll-behavior-y: contain; overflow-x: hidden;
}
/* Sensación nativa: sin selección accidental ni destello azul al tocar */
button, .tab, .fab, .chip-q, .grow, .opt, .set-row, .card-label, .crumb,
.day-label, .month-pill, .tg-cta { user-select: none; -webkit-user-select: none; }
button, a { -webkit-tap-highlight-color: transparent; }

/* Shell: móvil a pantalla completa; en escritorio, columna centrada */
#appShell { max-width: 480px; margin: 0 auto; min-height: 100dvh;
  display: flex; flex-direction: column; background: var(--bg); position: relative; }
@media (min-width: 520px) {
  #appShell { border-left: 1px solid var(--border); border-right: 1px solid var(--border); }
}
/* `hidden` debe ganar a los display de abajo (si no, la portada no se oculta tras el login) */
#loginView[hidden], #appView[hidden], #altaView[hidden] { display: none !important; }

/* ── Arranque ── */
/* Visible desde el primer pintado (no lleva [hidden] en el HTML): mientras se
   piden la sesión y los datos, se ve Coko en vez de una pantalla en blanco. */
#cargando { flex: 1; display: flex; flex-direction: column; align-items: center;
  justify-content: center; gap: 6px; padding: 32px 24px; text-align: center; }
#cargando[hidden] { display: none; }
#cargando img { width: 64px; height: 64px; border-radius: 18px; margin-bottom: 8px; }
@media (prefers-reduced-motion: no-preference) {
  #cargando img { animation: latido 1.6s ease-in-out infinite; }
}
@keyframes latido { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.07); } }
#cargando .carg-t { font-family: var(--serif); font-size: 19px; font-weight: 600; margin: 0; }
#cargando .carg-s { font-size: 14px; color: var(--muted); margin: 0; }

/* ── Login ── */
#loginView { flex: 1; display: flex; flex-direction: column; align-items: center;
  justify-content: center; gap: 14px; padding: 32px 24px; text-align: center; }
#loginView img { width: 84px; height: 84px; border-radius: 22px; }
#loginView h1 { font-family: var(--serif); font-weight: 600; font-size: 26px; margin: 0; }
#loginView h1 small { display: block; font-family: var(--sans); font-weight: 400;
  font-size: 15px; color: var(--muted); margin-top: 8px; line-height: 1.5; }
#tgWidget { min-height: 48px; display: grid; place-items: center; }
#loginEstado { font-size: 13.5px; color: var(--muted); line-height: 1.5; max-width: 300px; margin: 0; }
#loginEstado[hidden] { display: none; }
#loginEstado.err { color: var(--crit, #c0392b); }
.dev-btn { border: 1px dashed var(--border); background: var(--card); color: var(--muted);
  font-family: var(--sans); font-size: 14px; padding: 9px 16px; border-radius: 10px; cursor: pointer; }
.login-note { font-size: 13.5px; color: var(--muted); line-height: 1.55; max-width: 300px; }
.login-note a { color: var(--accent); }

/* ── Error de carga (mes/histórico que no llegó) ── */
.mes-err { flex: 1; display: flex; flex-direction: column; align-items: center;
  justify-content: center; gap: 6px; padding: 48px 24px; text-align: center; }
.mes-err .err-t { font-family: var(--serif); font-size: 19px; font-weight: 600; margin: 0; }
.mes-err .err-s { font-size: 14px; color: var(--muted); margin: 0 0 6px; }

/* ── Cabecera ── */
/* Altura FIJA: el cuerpo reserva 60px para la cabecera, así que si esta crece
   (p. ej. el pill partido en dos líneas) tapa el principio del contenido. */
.app-head { position: fixed; top: 0; left: 50%; transform: translateX(-50%); width: 100%; max-width: 480px;
  padding: calc(10px + env(safe-area-inset-top)) 18px 12px; display: flex;
  align-items: center; justify-content: space-between; border-bottom: 1px solid var(--border);
  background: var(--card); z-index: 12; gap: 10px;
  height: calc(60px + env(safe-area-inset-top)); box-sizing: border-box; }
/* La marca NO se encoge: quien cede sitio si falta espacio es el pill del mes
   (abajo), que ya recorta con puntos en vez de partir «CokoApp». */
.app-head .brand { flex: none; }
.app-head .brand .name { white-space: nowrap; }
.head-right { flex: 1 1 auto; justify-content: flex-end; min-width: 0; }
/* Es un <button> (lleva al inicio), así que se le quitan los adornos de botón. */
.brand { display: flex; align-items: center; gap: 9px; border: 0; background: none;
  padding: 0; margin: 0; color: inherit; font-family: inherit; cursor: pointer; }
.brand img { width: 28px; height: 28px; border-radius: 8px; display: block; }
.brand .name { font-family: var(--serif); font-weight: 600; font-size: 19px;
  display: inline-flex; align-items: center; }
/* Flechas de mes: un toque para el anterior o el siguiente, sin desplegar nada. */
.mes-nav { border: 1px solid var(--border); background: #f4f5f3; width: 24px; height: 28px;
  border-radius: 8px; display: grid; place-items: center; cursor: pointer; flex: none;
  color: var(--accent); font-family: var(--sans); font-size: 17px; line-height: 1; padding: 0; }
.mes-nav:disabled { color: #c9cfcb; cursor: default; }
.mes-nav[hidden] { display: none; }
.head-right { display: flex; align-items: center; gap: 5px; }
/* NUNCA en dos líneas: un mes largo («Septiembre 2026») partía el pill, engordaba
   la cabecera fija y esta tapaba el principio del contenido. Si no cabe, se
   recorta con puntos suspensivos, pero la cabecera mantiene su altura.
   En un móvil estrecho («Agosto '26» + flechas + ojo + ajustes) el pill se
   quedaba corto por 1 carácter y se comía el último dígito del año SIN
   ellipsis (2026-08-19, vídeo real). El padding de aquí y el tamaño de
   `.mes-nav`/`.icon-btn` de arriba/abajo se recortaron un par de px cada uno
   —repartido, no de un sitio— para dejarle ese hueco sin tocar el diseño. */
.month-pill { font-size: 14px; font-weight: 500; background: #f4f5f3; color: var(--text);
  border: 1px solid var(--border); padding: 5px 9px; border-radius: 999px;
  display: flex; align-items: center; gap: 5px; cursor: pointer; font-family: var(--sans);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 38vw;
  flex: 0 1 auto; min-width: 0; }
.icon-btn { border: 1px solid var(--border); background: #f4f5f3; width: 30px; height: 30px;
  border-radius: 9px; display: grid; place-items: center; cursor: pointer; }
.icon-btn svg { width: 17px; height: 17px; stroke: var(--muted); fill: none; stroke-width: 1.9; }
.month-menu { position: absolute; top: calc(48px + env(safe-area-inset-top)); right: 18px;
  background: var(--card); border: 1px solid var(--border); border-radius: 12px;
  box-shadow: 0 10px 28px rgba(0,0,0,.16); overflow: hidden; z-index: 20; min-width: 160px; }
.month-menu[hidden] { display: none; }
.month-menu button { display: flex; width: 100%; justify-content: space-between;
  align-items: center; gap: 10px; border: 0; background: transparent; padding: 10px 14px;
  font-family: var(--sans); font-size: 15px; color: var(--text); cursor: pointer; text-align: left; }
.month-menu button:hover { background: var(--accent-soft); }
.month-menu button.sel { color: var(--accent); font-weight: 600; }

/* ── Cuerpo ── */
.app-body { flex: 1; padding: calc(60px + env(safe-area-inset-top)) 16px calc(96px + env(safe-area-inset-bottom)); }
.screen { display: flex; flex-direction: column; gap: 14px; }
@media (prefers-reduced-motion: no-preference) { .screen { animation: fadeUp .32s ease both; } }
@keyframes fadeUp { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }

.card { background: var(--card); border: 1px solid var(--border); border-radius: 16px; padding: 16px; }
.card-label { font-size: 12px; letter-spacing: .1em; text-transform: uppercase;
  color: var(--muted); font-weight: 600; margin: 0 0 10px; }

/* Modo incógnito: difumina SOLO cifras */
.big, .bal-strip .r b, .lv, .g-amt, .bg-top .amt, .num, .acc .av, .acc .mv,
.total-card .big, .donut, .sankey, .sk-lab .sk-v, .pig-big { transition: filter .28s ease; }
.money-blur .big, .money-blur .bal-strip .r b, .money-blur .lv, .money-blur .g-amt,
.money-blur .bg-top .amt, .money-blur .num, .money-blur .acc .av, .money-blur .acc .mv,
.money-blur .total-card .big, .money-blur .pig-big { filter: blur(7px); }
/* el donut entero (número central incluido): filtrar el <text> del SVG no es fiable en Safari */
.money-blur .donut { filter: blur(6px); }
/* el dibujo del sankey entero: los anchos de las cintas SON las proporciones
   del mes, así que tapar solo las cifras no taparía nada */
.money-blur .sankey { filter: blur(6px); }
/* sus etiquetas van en HTML aparte: se difumina la cifra, no el nombre */
.money-blur .sk-lab .sk-v { filter: blur(6px); }
/* el cerdito: el relleno de saldo (SVG + barra) también cuenta como cifra */
.money-blur .pig-fill, .money-blur .pig-bar-fill { filter: blur(4px); }

/* Resumen */
.bal-strip { display: flex; align-items: center; justify-content: space-between; }
.bal-strip .l .sub { font-size: 12px; color: var(--muted); letter-spacing: .07em;
  text-transform: uppercase; font-weight: 600; }
.bal-strip .l .big { font-family: var(--serif); font-size: 32px; font-weight: 600;
  color: var(--accent); font-variant-numeric: tabular-nums; line-height: 1.1; }
.bal-strip .l .big.neg { color: var(--crit); }
.bal-strip .l .delta { font-size: 13px; color: var(--muted); }
.bal-strip .r { text-align: right; display: flex; flex-direction: column; gap: 6px; }
.bal-strip .r div { font-size: 13px; color: var(--muted); }
.bal-strip .r b { font-family: var(--serif); font-variant-numeric: tabular-nums;
  font-weight: 600; font-size: 16px; }
.bal-strip .r b.in { color: var(--income); }

/* Donut */
.donut-wrap { display: flex; align-items: center; gap: 16px; }
.donut { width: 132px; height: 132px; flex: none; }
.dslice { transition: stroke-dasharray .9s cubic-bezier(.35,0,.25,1); }
@media (prefers-reduced-motion: reduce) { .dslice { transition: none; } }
.donut .d-c { font-family: var(--serif); font-size: 6.2px; font-weight: 600;
  fill: var(--text); text-anchor: middle; }
.donut .d-s { font-family: var(--sans); font-size: 2.6px; fill: var(--muted);
  text-anchor: middle; letter-spacing: .04em; text-transform: uppercase; }
/* Sankey (flujo del mes) */
.sankey-wrap { width: 100%; position: relative; }
.sankey { width: 100%; height: auto; display: block; }
/* Las cintas crecen desde su propio canto hacia el centro (`fill-box` ancla el
   origen a la caja del path, no al lienzo entero). Las barras salen antes,
   estirándose desde su eje: primero aparece de dónde sale el dinero y luego
   por dónde se va. */
.sankey-flow, .sankey-bar {
  transform-box: fill-box;
  transition: transform .8s cubic-bezier(.35,0,.25,1), opacity .5s ease;
}
.sankey-flow { transform-origin: left center; transform: scaleX(0); opacity: 0; }
.sankey-bar { transform-origin: center; transform: scaleY(.4); opacity: 0; }
.sankey-flow.ya, .sankey-bar.ya { transform: none; opacity: 1; }
.sankey-flow.ya:hover { opacity: .82; }

/* Las etiquetas son HTML por encima del dibujo, no <text> del SVG: dentro del
   SVG escalarían con el lienzo y medirían distinto en cada pantalla. Así
   heredan tamaño y colores de la app: 12px (el de `.card-label`) y el mismo
   reparto de color que la leyenda del donut — nombre en `--text`, cifra en
   `--muted`. Van sobre las cintas, de ahí el halo con el color de la tarjeta. */
.sk-lab { position: absolute; transform: translateY(-50%); max-width: 44%;
  font-size: 12px; line-height: 1.15; white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis; pointer-events: none;
  text-shadow: 0 0 3px var(--card), 0 0 3px var(--card), 0 0 6px var(--card);
  opacity: 0; transition: opacity .45s ease; }
.sk-lab.ya { opacity: 1; }
.sk-lab.sk-izq { left: var(--sk-izq); }
.sk-lab.sk-der { right: var(--sk-der); text-align: right; }
.sk-lab .sk-n { color: var(--text); }
.sk-lab .sk-v { color: var(--muted); font-variant-numeric: tabular-nums; }
@media (prefers-reduced-motion: reduce) { .sk-lab { transition: none; } }
@media (prefers-reduced-motion: reduce) {
  .sankey-flow, .sankey-bar { transition: none; }
}

.legend { flex: 1; display: flex; flex-direction: column; gap: 8px; min-width: 0; }
.lg { display: grid; grid-template-columns: 11px 1fr auto; align-items: center; gap: 8px; }
.lg .dot { width: 11px; height: 11px; border-radius: 3px; }
.lg .ln { font-size: 13.5px; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.lg .lv { font-size: 13.5px; color: var(--muted); font-variant-numeric: tabular-nums; }

/* Chat Coko (encabeza el Resumen) */
.chat-card { order: -1; padding: 12px 14px 10px; border-color: #cfe2d6;
  box-shadow: 0 4px 16px rgba(26,107,60,.06); }
.chat-head { display: flex; align-items: center; gap: 9px; margin-bottom: 10px; }
.chat-head img { width: 26px; height: 26px; border-radius: 8px; display: block; }
.chat-head .t { font-size: 14.5px; font-weight: 600; }
.chat-head .t small { display: block; font-weight: 400; font-size: 12.5px; color: var(--muted); }
.chat-log { display: flex; flex-direction: column; gap: 9px; max-height: 128px;
  overflow-y: auto; padding-right: 2px; }
.b { max-width: 82%; padding: 9px 12px; font-size: 14.5px; line-height: 1.45; border-radius: 14px; }
.b.coko { background: var(--accent-soft); color: #143d26; border-top-left-radius: 4px; align-self: flex-start; }
.b.me { background: var(--accent); color: #fff; border-top-right-radius: 4px; align-self: flex-end; }
.b.espera { color: var(--muted); background: #f4f5f3; }
.chips { display: flex; flex-wrap: wrap; gap: 7px; margin-top: 11px; }
.chip-q { border: 1px solid #cfe2d6; background: #fff; color: var(--accent);
  font-family: var(--sans); font-size: 13px; padding: 5px 10px; border-radius: 999px; cursor: pointer; }
.chip-q:hover { background: var(--accent-soft); }
.chat-input { display: flex; gap: 8px; align-items: center; margin-top: 11px;
  border-top: 1px solid var(--border); padding-top: 11px; }
.chat-input input { flex: 1; border: 1px solid var(--border); border-radius: 999px;
  padding: 9px 14px; font-family: var(--sans); font-size: 17px; color: var(--text); outline: 0; }
.chat-input input:focus { border-color: var(--accent); }
.chat-input button { border: 0; background: var(--accent); width: 38px; height: 38px;
  border-radius: 50%; cursor: pointer; display: grid; place-items: center; flex: none; }
.chat-input button svg { width: 18px; height: 18px; stroke: #fff; fill: none; stroke-width: 2; }

/* Dinero */
.total-card { text-align: center; padding: 20px 16px; }
.total-card .sub { font-size: 12px; color: var(--muted); letter-spacing: .08em;
  text-transform: uppercase; font-weight: 600; }
.total-card .big { font-family: var(--serif); font-size: 38px; font-weight: 600;
  margin-top: 6px; font-variant-numeric: tabular-nums; }
.acc { display: flex; align-items: center; gap: 12px; padding: 13px 4px; }
.acc + .acc { border-top: 1px solid var(--border); }
.acc .ic { width: 38px; height: 38px; border-radius: 11px; background: var(--accent-soft);
  display: grid; place-items: center; flex: none; }
.acc .ic svg { width: 19px; height: 19px; stroke: var(--accent); fill: none; stroke-width: 1.9; }
.acc .txt { flex: 1; }
.acc .an { font-size: 15px; font-weight: 500; }
.acc .ab { font-size: 13px; color: var(--muted); }
.acc .rt { text-align: right; }
.acc .av { font-family: var(--serif); font-size: 17px; font-variant-numeric: tabular-nums; }
.acc .av.neg { color: var(--crit); }
.acc .mv { font-size: 12.5px; color: var(--muted); font-variant-numeric: tabular-nums; }
.note { display: flex; gap: 8px; font-size: 13px; line-height: 1.5; color: var(--muted);
  background: #f4f5f3; border: 1px solid var(--border); border-radius: 11px;
  padding: 10px 12px; margin-top: 12px; }
.note svg { flex: none; width: 15px; height: 15px; stroke: var(--muted); fill: none;
  stroke-width: 2; margin-top: 1px; }

/* Ahorro: el cerdito */
.pig-row { display: flex; align-items: center; gap: 18px; }
.pig-svg { flex: none; overflow: visible; }
.pig-txt { flex: 1; min-width: 0; }
.pig-bg { fill: #eef0ed; }
.pig-fill { fill: var(--accent); transform-origin: 50% 100%; transform: scaleY(0);
  transition: transform .9s cubic-bezier(.2,.8,.2,1); }
.pig-outline { fill: none; stroke: var(--accent); stroke-width: .9; }
.pig-details { fill: none; stroke: var(--accent); stroke-width: .9; stroke-linecap: round; stroke-linejoin: round; }
.pig-eye { fill: var(--accent); stroke: none; }
.pig-big { font-family: var(--serif); font-size: 24px; font-weight: 600;
  font-variant-numeric: tabular-nums; }
.pig-of { font-size: 12.5px; color: var(--muted); margin-top: 2px; }
.pig-bar { margin-top: 10px; }
.pig-bar-fill { background: var(--accent); }
@media (prefers-reduced-motion: reduce) { .pig-fill { transition: none; } }

/* Presupuestos / jerarquía Gastos */
.bg-item { display: flex; flex-direction: column; gap: 7px; }
.bg-item.with-donut { flex-direction: row; align-items: center; gap: 14px; }
.bg-item.with-donut .bg-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 7px; }
.donut-mini { width: 62px; height: 62px; flex: none; }
.bg-top { display: flex; justify-content: space-between; align-items: baseline; }
.bg-top .n { font-size: 15px; font-weight: 500; }
.bg-top .amt { font-size: 14px; color: var(--muted); font-variant-numeric: tabular-nums; }
.bg-bar { height: 9px; background: #eef0ed; border-radius: 999px; overflow: hidden; }
.bg-bar > span { display: block; height: 100%; border-radius: 999px;
  transition: width .8s cubic-bezier(.35,0,.25,1); }
.bg-foot { font-size: 13px; }
.fill-ok > span { background: var(--ok); } .fill-warn > span { background: var(--warn); }
.fill-crit > span { background: var(--crit); }
.t-ok { color: var(--ok); } .t-warn { color: var(--warn); } .t-crit { color: var(--crit); }

.crumb { display: flex; align-items: center; gap: 6px; font-size: 13.5px;
  margin: 0 2px 2px; flex-wrap: wrap; }
.crumb .back { color: var(--accent); cursor: pointer; font-size: 19px; line-height: 1; margin-right: 2px; }
.crumb button { border: 0; background: none; color: var(--accent); font-family: var(--sans);
  font-size: 13.5px; cursor: pointer; padding: 0; }
.crumb .sep { color: var(--muted); }
.crumb .cur { color: var(--text); font-weight: 600; }
.grow { display: flex; flex-direction: column; gap: 8px; cursor: pointer;
  padding: 12px 4px; border-top: 1px solid var(--border); }
.grow.first { border-top: 0; }
.grow .g-top { display: flex; align-items: center; gap: 10px; }
.grow .g-dot { width: 10px; height: 10px; border-radius: 3px; flex: none; }
.grow .g-name { flex: 1; min-width: 0; font-size: 15px; font-weight: 500; display: flex;
  align-items: center; gap: 7px; }
/* El nombre se recorta CON puntos suspensivos si no cabe; las etiquetas (auto,
   ingreso, recurrente) son aparte y NUNCA se recortan ni desaparecen. «auto» es
   texto corto (se entiende solo); «ingreso» y «recurrente» son iconos (↑, ↻):
   flechas ya reconocibles, sin necesitar la palabra al lado. */
.grow .g-name-txt { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.grow .autochip { flex: none; }
.grow .g-amt { font-size: 13.5px; color: var(--muted); font-variant-numeric: tabular-nums; }
.grow .g-chev { color: var(--muted); font-size: 17px; }
.grow:active { background: #fafbfa; }
.autochip { font-size: 10.5px; font-weight: 600; color: var(--accent);
  background: var(--accent-soft); border: 1px solid #cfe2d6; padding: 1px 6px; border-radius: 999px; flex: none; }
.inchip { font-size: 10.5px; font-weight: 700; color: #fff; background: var(--income);
  padding: 1px 7px; border-radius: 999px; flex: none; }
/* Recurrente: ámbar, para distinguirlo de un vistazo del «auto» (verde) y del
   «ingreso». Marca tanto un apunte que viene de un recurrente como la categoría
   que tiene recurrentes dentro, y así se localiza sin recorrer el árbol. */
.recchip { font-size: 10.5px; font-weight: 700; color: var(--warn); background: #fbf3e3;
  border: 1px solid #eeddbb; padding: 1px 7px; border-radius: 999px; flex: none;
  white-space: nowrap; margin-left: 5px; }
.mv-sub .recchip, .mov-head .recchip { margin-left: 0; }

/* Movimientos */
.day-label { font-size: 12px; letter-spacing: .08em; text-transform: uppercase;
  color: var(--muted); font-weight: 600; margin: 4px 2px 2px; }
.mv { display: flex; align-items: center; gap: 12px; padding: 11px 4px; }
.mv + .mv { border-top: 1px solid var(--border); }
.mv .ic { width: 34px; height: 34px; border-radius: 10px; background: var(--accent-soft);
  display: grid; place-items: center; flex: none; }
.mv .ic svg { width: 17px; height: 17px; stroke: var(--accent); fill: none; stroke-width: 2; }
.mv .txt { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.mv .cpt { display: block; font-size: 15px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.mv .mv-sub { display: flex; align-items: center; gap: 8px; margin-top: 4px; min-width: 0; }
.mv .tag { min-width: 0; font-size: 12px; color: var(--accent); background: var(--accent-soft);
  border: 1px solid #cfe2d6; padding: 1px 8px; border-radius: 999px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.mv .mv-date { flex: none; font-size: 12px; color: var(--muted); font-variant-numeric: tabular-nums; }
/* La cuenta del movimiento, en una o dos letras. Cuadrada y del ancho fijo de
   dos letras para que la columna no baile de fila en fila; en gris, no en el
   verde de la categoría, porque es un dato secundario y compite con ella. */
.mv .mv-cta { flex: none; min-width: 22px; text-align: center; font-size: 11px;
  font-weight: 700; letter-spacing: .2px; color: var(--muted);
  background: #f4f5f3; border: 1px solid var(--border);
  padding: 1px 5px; border-radius: 6px; }
.mv .num { font-family: var(--serif); font-size: 16px; font-variant-numeric: tabular-nums;
  white-space: nowrap; }
.mv .num.in { color: var(--income); }

/* Cokonsejos */
.coach-intro { font-size: 14px; color: var(--muted); line-height: 1.5; padding: 2px 4px; }
/* La línea del cupo de IA, arriba de Cokonsejos. Discreta a propósito: informa
   y se puede tocar, pero no es un banner ni compite con la conversación. */
.cupo-bar { display: block; width: 100%; text-align: left; font-size: 12.5px;
  line-height: 1.45; color: var(--muted); background: var(--accent-soft);
  border: 1px solid var(--border); border-radius: 12px; padding: 9px 12px;
  font-family: inherit; cursor: pointer; }
.cupo-bar.seco { background: #fdf4e6; color: var(--warn); }
.msg { display: flex; gap: 11px; }
.msg img { width: 32px; height: 32px; border-radius: 9px; flex: none; display: block; }
.msg .bubble { background: var(--card); border: 1px solid var(--border); border-radius: 14px;
  border-top-left-radius: 4px; padding: 12px 14px; }
.msg .bubble p { margin: 0; font-size: 15px; line-height: 1.5; }
.msg .chip { display: inline-block; margin-top: 8px; font-size: 12px; color: var(--muted);
  background: #f4f5f3; border: 1px solid var(--border); padding: 2px 8px; border-radius: 999px; }

/* Barra inferior + FAB */
.tabbar { position: fixed; bottom: 0; left: 50%; transform: translateX(-50%);
  width: 100%; max-width: 480px; display: flex; border-top: 1px solid var(--border);
  background: var(--card); padding-bottom: env(safe-area-inset-bottom); z-index: 10; }
.tab { flex: 1; border: 0; background: transparent; cursor: pointer; padding: 9px 2px 10px;
  display: flex; flex-direction: column; align-items: center; gap: 3px; color: var(--muted);
  font-family: var(--sans); font-size: 10.5px; font-weight: 500; }
.tab svg { width: 21px; height: 21px; stroke: var(--muted); fill: none; stroke-width: 1.9; }
.tab.active { color: var(--accent); } .tab.active svg { stroke: var(--accent); }
.tab-gap { flex: 1; }
.tabbar.no-gap .tab-gap { display: none; }
/* Se suma `--kb` para que, cuando la barra de escribir sube con el teclado (iOS),
   la conversación no quede escondida detrás de ella. */
#appBody.with-chatbar { padding-bottom: calc(122px + env(safe-area-inset-bottom) + var(--kb, 0px)); }
/* Cuánto sitio hay que reservar abajo depende de si la barra de escribir se ha
   SUBIDO por encima de las pestañas, y eso no es lo mismo que «hay teclado».
   Son dos clases a propósito (se juntaron en una el 2026-08-06 y rompió el
   scroll del chat en iPhone):

   · `html.teclado` — hay un campo con el foco. El navegador puede haber encogido
     la página él solo (Android, y el iOS de Lusendo): entonces las DOS barras
     siguen a la vista sobre el teclado y hay que seguir reservando las dos. Lo
     único que sobra es el margen de la rayita del gesto, que el teclado tapa.
   · `html.alzada` — además hizo falta subir la barra de escribir a mano
     (`--kb` > 0, iOS que NO encoge la página). Ahí sí queda la de pestañas
     tapada detrás y solo hay que reservar la de escribir (~60px, medido). */
html.teclado #appBody.with-chatbar { padding-bottom: calc(122px + var(--kb, 0px)); }
html.alzada #appBody.with-chatbar { padding-bottom: calc(70px + var(--kb, 0px)); }
/* Con el teclado arriba, las barras de abajo pierden el margen de la rayita del
   gesto: esa rayita está TAPADA por el teclado, así que ese margen no protege
   nada y se ve como una franja blanca vacía entre la barra de pestañas y el
   teclado. Es el hueco que Lusendo veía en su iPhone (capturas del 2026-08-06):
   no estaba entre el teclado y la barra de escribir, estaba DEBAJO de las
   pestañas, y era blanco porque es el relleno de la propia barra.
   En Android no se notaba porque ahí ese margen ya vale 0 con el teclado. */
html.teclado .tabbar { padding-bottom: 0; }
html.teclado .chatbar { bottom: max(52px, var(--kb, 0px)); }
html.teclado .fab { bottom: 26px; }
.tab.pinged { position: relative; }
.tab.pinged::after { content: ''; position: absolute; top: 5px; right: calc(50% - 15px);
  width: 7px; height: 7px; border-radius: 50%; background: var(--accent);
  box-shadow: 0 0 0 2px var(--card); }

.fab { position: fixed; left: 50%; bottom: calc(26px + env(safe-area-inset-bottom));
  transform: translateX(-50%); z-index: 15; width: 62px; height: 62px; border-radius: 50%;
  background: var(--accent); border: 4px solid var(--card);
  box-shadow: 0 6px 18px rgba(26,107,60,.45); display: grid; place-items: center; cursor: pointer; }
.fab:active { transform: translateX(-50%) scale(.94); }
.fab svg { width: 26px; height: 26px; stroke: #fff; stroke-width: 2.4; fill: none; }

/* Barra de chat fija «Habla con Coko» — sobre las pestañas; el + flota encima */
.chatbar { position: fixed; bottom: max(calc(52px + env(safe-area-inset-bottom)), var(--kb, 0px)); left: 50%;
  transform: translateX(-50%); width: 100%; max-width: 480px; z-index: 16;
  display: flex; align-items: center; gap: 10px; padding: 9px 14px;
  background: var(--card); border-top: 1px solid var(--border); }
.chatbar[hidden] { display: none; }
.chatbar input { flex: 1; min-width: 0; border: 1px solid var(--border); border-radius: 999px;
  padding: 10px 16px; font-family: var(--sans); font-size: 17px; color: var(--text); outline: 0; background: #f4f5f3; }
.chatbar input:focus { border-color: var(--accent); background: #fff; }
.chatbar .cb-send { flex: none; border: 0; background: var(--accent); width: 40px; height: 40px;
  border-radius: 50%; display: grid; place-items: center; cursor: pointer; }
.chatbar .cb-send svg { width: 19px; height: 19px; stroke: #fff; fill: none; stroke-width: 2; }

/* ── Escritorio Y tablet ancha: pestañas → sidebar fija, grid de tarjetas ──
   2026-08-19: esto empezó exigiendo `pointer: fine` (ratón), pero se decidió
   ampliarlo a tablet táctil ancha — el casco/grid se aprovecha igual con el
   dedo, lo único que sigue siendo cosa de ratón es la columna fija de
   Cokonsejos, más abajo. `min-height: 550px` es el guardián de verdad: sin
   él, un móvil grande tumbado (pasa de 900px de ancho en horizontal, p. ej.
   un iPhone Pro Max mide 932px) entraría aquí con solo ~430px de alto y se
   vería apretado. Una tablet en horizontal ronda 700-800px de alto, así que
   550 separa limpio los dos casos sin tocar el ancho.
   Los objetivos táctiles (flechas de mes, botones del pie) se agrandan en un
   bloque `(pointer: coarse)` aparte, más abajo — este bloque de aquí es el
   casco compartido por ratón y dedo. */
@media (min-width: 900px) and (min-height: 550px) {
  #appShell { max-width: none; margin: 0; border: 0; }

  /* El asistente de alta (crear la contabilidad) no tiene sidebar ni cabecera
     propias — es el único hijo directo de `#appShell` que queda a merced de
     su ancho. Sin este tope, sus botones (`.alta-opt`/`.alta-btn`, a
     `width:100%` a propósito para el móvil) se estiran de punta a punta de
     la pantalla. El login (`#loginView`) no necesita el mismo arreglo: sus
     hijos son de ancho automático (imagen, título, botón de Google), así que
     ya quedan centrados solos por el `align-items:center` que ya tenía. */
  #altaCuerpo { max-width: 460px; margin: 0 auto; width: 100%; }

  .app-head { left: 220px; transform: none; width: calc(100% - 220px); max-width: none;
    padding-left: 32px; padding-right: 32px; justify-content: flex-start; }

  /* Mes, ojo y ajustes: la sidebar solo tiene 4 pestañas arriba y se queda
     vacía por abajo, así que en vez de dejarla desaprovechada estos
     controles bajan ahí como un pie fijo — ya son `position:fixed`, así que
     no importa dónde vivan en el HTML (siguen dentro de `.app-head`), solo
     dónde los pinta el navegador. La cabecera se queda solo con la marca.
     Rejilla de 3 columnas: el mes ocupa una fila (‹ pill ›) bajo su
     etiqueta, y el ojo y el engranaje bajan a fila completa cada uno, con
     el mismo idioma que las pestañas de arriba (icono + texto a la
     izquierda) en vez de dos iconos sueltos apretados. */
  .head-right { position: fixed; left: 0; bottom: 0; top: auto; width: 220px; z-index: 13;
    display: grid; grid-template-columns: auto 1fr auto; align-items: center;
    gap: 7px 5px; padding: 14px 14px calc(14px + env(safe-area-inset-bottom));
    border-top: 1px solid var(--border); background: var(--card); }
  /* Etiqueta «Mes» sobre el selector: da aire y explica el bloque sin meter
     un elemento nuevo en el HTML (que se vería también en móvil). */
  .head-right::before { content: 'Mes'; grid-column: 1 / -1;
    font-size: 11px; letter-spacing: .1em; text-transform: uppercase;
    color: var(--muted); font-weight: 600; padding-left: 2px; }
  .month-pill { max-width: none; width: 100%; justify-content: center; }
  /* El ojo y el engranaje dejan de ser cuadraditos y pasan a fila completa
     con su nombre al lado (el texto lo pone el `::after` de aquí abajo, no
     el HTML: `app.js` reescribe el `innerHTML` del ojo al alternarlo, así
     que una etiqueta metida dentro del botón se borraría en el primer clic). */
  .head-right .icon-btn { grid-column: 1 / -1; width: auto; height: auto;
    display: flex; align-items: center; gap: 12px; justify-content: flex-start;
    padding: 9px 10px; border-radius: 10px; border-color: transparent;
    background: transparent; color: var(--muted);
    font-family: var(--sans); font-size: 14px; font-weight: 500; }
  .head-right .icon-btn:hover { background: #f4f5f3; }
  .head-right .icon-btn svg { width: 20px; height: 20px; flex: none; }
  .head-right .icon-btn::after { white-space: nowrap; }
  #eyeBtn::after { content: 'Modo privado'; }
  /* Con las cifras tapadas el botón lo dice, en vez de dejar solo el icono
     tachado como única pista de que está puesto. */
  #appView.money-blur #eyeBtn { color: var(--accent); }
  #appView.money-blur #eyeBtn svg { stroke: var(--accent); }
  #appView.money-blur #eyeBtn::after { content: 'Cifras ocultas'; }
  #gearBtn::after { content: 'Ajustes'; }
  /* Un pelín de aire entre el bloque del mes y las dos filas de abajo. */
  #eyeBtn { margin-top: 5px; }
  /* El desplegable de meses se abría pegado a la cabecera (relativo a
     `.app-head`, que sigue arriba): si el pill se ha ido abajo, el menú tiene
     que abrirse a su lado, no donde estaba el pill antes. */
  .month-menu { position: fixed; top: auto; right: auto; left: 16px;
    bottom: calc(64px + env(safe-area-inset-bottom)); }

  .app-body { padding: calc(76px + env(safe-area-inset-top)) 32px 48px 252px;
    max-width: 980px; }
  #appBody.with-chatbar { padding-bottom: 100px; }

  .tabbar { top: 0; left: 0; bottom: 0; transform: none; width: 220px; max-width: 220px;
    flex-direction: column; align-items: stretch; border-top: 0;
    border-right: 1px solid var(--border);
    padding: calc(20px + env(safe-area-inset-top)) 0 16px; gap: 2px; }
  .tab { flex: 0 0 auto; flex-direction: row; justify-content: flex-start;
    gap: 12px; padding: 11px 24px; font-size: 14px; }
  .tab svg { width: 20px; height: 20px; }
  .tab-gap { display: none; }
  .tab.pinged::after { top: 12px; right: auto; left: 46px; }

  /* El «+» a secas se entiende en un móvil (es el gesto de siempre), pero en
     escritorio, suelto en una esquina y con sitio de sobra, no dice qué hace:
     aquí pasa a botón con su nombre al lado. La etiqueta va por CSS y no en el
     HTML para no colarla también en el móvil, donde el redondo se queda. */
  .fab { left: auto; right: 36px; transform: none;
    width: auto; height: 58px; border-radius: 999px;
    display: flex; align-items: center; gap: 10px; padding: 0 26px 0 21px;
    font-family: var(--sans); font-size: 16px; font-weight: 600; color: #fff;
    box-shadow: 0 8px 24px rgba(26,107,60,.42); }
  .fab::after { content: 'Apuntar'; white-space: nowrap; }
  .fab svg { width: 23px; height: 23px; }
  .fab:hover { background: #175c34; }
  .fab:active { transform: scale(.97); }

  /* `max-width: 880px` = los 1100px de `.app-body` menos los 220px de la
     sidebar: así el hueco de contenido del chatbar (tras su padding) mide
     EXACTAMENTE lo mismo que el de `.app-body`, y el input queda centrado
     justo donde caen las burbujas de arriba, no en todo el ancho libre. */
  .chatbar { left: 220px; transform: none; width: calc(100% - 220px); max-width: 880px;
    justify-content: center; padding-left: 32px; padding-right: 32px; }
  /* 590 = los 640 del chat menos el botón de enviar (40) y su hueco (10): así
     el GRUPO entero (campo + botón) mide lo mismo que la columna de burbujas
     de arriba y queda justo debajo de ella, en vez de que el botón empuje el
     centrado 25px hacia la izquierda. */
  .chatbar input { max-width: 590px; }

  /* Paso 2: grid de Resumen y Dinero. Se engancha por `data-tab` en #appBody
     (lo pone render(), app.js) y no por nth-child, porque el orden de
     tarjetas cambia: el sankey solo sale si el mes tiene ingresos y gastos,
     y las misiones del tutorial solo mientras queden pendientes. Por
     defecto cada tarjeta ocupa toda la fila (igual que en móvil); solo las
     que se emparejan a propósito se estrechan a una columna. */
  .app-body { max-width: 1100px; }

  #appBody[data-tab="resumen"] .screen,
  #appBody[data-tab="cuentas"] .screen {
    display: grid; grid-template-columns: 1fr 1fr; align-items: start; gap: 14px;
  }
  #appBody[data-tab="resumen"] .screen > *,
  #appBody[data-tab="cuentas"] .screen > * { grid-column: 1 / -1; }

  /* Resumen: el sankey («de dónde a dónde») y el donut («en qué se fue») uno
     al lado del otro. Sin sankey (mes sin ingresos), el donut se queda solo
     y pasa a ancho completo en vez de dejar la otra columna vacía. */
  #appBody[data-tab="resumen"] .card:has(.sankey) { grid-column: 1; }
  #appBody[data-tab="resumen"] .card:has(.donut-wrap) { grid-column: 2; }
  #appBody[data-tab="resumen"] .screen:not(:has(.sankey)) .card:has(.donut-wrap) { grid-column: 1 / -1; }

  /* Dinero: la lista de cuentas a la izquierda (ocupa las dos filas de la
     derecha), ahorro e inversiones apiladas a la derecha. */
  #appBody[data-tab="cuentas"] .screen { grid-template-columns: 1.4fr 1fr; }
  #appBody[data-tab="cuentas"] .card:has(.acc) { grid-column: 1; grid-row: span 2; }
  #appBody[data-tab="cuentas"] .pig-card,
  #appBody[data-tab="cuentas"] .card:has(.donut-wrap):not(.total-card) { grid-column: 2; }

  /* Paso 3: Gastos. `paintGastos()` (app.js) repinta `#gastosView` entero por
     `innerHTML`, así que el gancho es ese contenedor, no `.screen` (que aquí
     solo tiene un hijo). Tres formas según el nivel — portada, categoría con
     hijos, categoría hoja — así que las tarjetas que se emparejan llevan una
     clase propia puesta en `app.js` (`gv-movs`/`gv-cats`/`gv-donut`) en vez
     de detectarse por `:has()` sobre su contenido: `:has()` no admite otro
     `:has()` anidado dentro (p. ej. para enganchar la etiqueta suelta que
     antecede a la tarjeta), y usarlo invalidaba la regla entera sin avisar. */
  /* `dense`: sin esto, la etiqueta suelta de la segunda tarjeta («toca una
     categoría») empuja toda la fila y las dos tarjetas dejan de quedar a la
     misma altura — dense rellena el hueco que deja la primera etiqueta en
     vez de abrir una fila nueva. */
  #appBody[data-tab="gastos"] #gastosView {
    display: grid; grid-template-columns: 1fr 1fr; grid-auto-flow: row dense;
    align-items: start; gap: 14px;
  }
  #appBody[data-tab="gastos"] #gastosView > * { grid-column: 1 / -1; }
  /* Las etiquetas («Últimos movimientos», «toca una categoría»…) son un <p>
     SUELTO justo antes de su tarjeta, no van dentro — por eso se enganchan por
     lo que LES SIGUE (`:has(+ …)`), para que caigan en la misma columna que
     la tarjeta a la que pertenecen y no partan la fila en dos. */
  /* Portada: «últimos movimientos» junto al árbol de categorías. */
  #appBody[data-tab="gastos"] #gastosView > .gv-movs,
  #appBody[data-tab="gastos"] #gastosView > p.card-label:has(+ .gv-movs) { grid-column: 1; }
  /* Categoría con hijos: el donut de subcategorías junto al desglose. */
  #appBody[data-tab="gastos"] #gastosView > .gv-donut { grid-column: 1; }
  #appBody[data-tab="gastos"] #gastosView > .gv-cats,
  #appBody[data-tab="gastos"] #gastosView > p.card-label:has(+ .gv-cats) { grid-column: 2; }
  /* Sin compañero (p. ej. categoría sin donut, o mes sin movimientos): a ancho completo. */
  #appBody[data-tab="gastos"] #gastosView:not(:has(.gv-cats)) .gv-movs,
  #appBody[data-tab="gastos"] #gastosView:not(:has(.gv-cats)) .gv-donut,
  #appBody[data-tab="gastos"] #gastosView:not(:has(.gv-movs)):not(:has(.gv-donut)) .gv-cats,
  #appBody[data-tab="gastos"] #gastosView:not(:has(.gv-cats)) p.card-label:has(+ .gv-movs),
  #appBody[data-tab="gastos"] #gastosView:not(:has(.gv-movs)):not(:has(.gv-donut)) p.card-label:has(+ .gv-cats)
    { grid-column: 1 / -1; }

  /* Paso 4: Cokonsejos (el chat) y los paneles/avisos flotantes.
     Cokonsejos se queda de una columna a propósito (burbujas de chat), pero
     sin capar el ancho se estiraría a los ~800px del área de contenido —
     una burbuja de un renglón ocupando media pantalla. Se limita y se centra
     dentro de esa área. */
  #appBody[data-tab="coko"] .screen { max-width: 640px; margin: 0 auto; }

  /* Paneles (hojas), toasts y avisos: se centraban sobre TODO el viewport
     (`left: 50%`), que a partir de 900px justo empieza a solapar la sidebar
     (a 900px de ancho, el hueco de contenido es más estrecho que el propio
     panel de 480px). Se recentran dentro del área de contenido —a la
     derecha de los 220px de la sidebar— con la misma cuenta que usa el
     `chatbar`: centro del hueco = mitad del viewport + mitad de la sidebar.
     `#appShell` de más en el selector NO es decorativo: estas reglas base
     viven MÁS ABAJO en el fichero, y con la misma especificidad gana la que
     sale después — sin ese empujón de especificidad este override perdía
     en silencio (pasó de verdad, visto en el navegador). */
  #appShell .sheet, #appShell .mov-toast, #appShell .install-banner, #appShell .stale-bar
    { left: calc(50% + 110px); }
}

/* ── Cokonsejos SIEMPRE a la vista: tercera columna (escritorio ancho) ────────
   A 1200px y no a 900: con la sidebar (220) y esta columna (330) puestas, por
   debajo de ese ancho el contenido se quedaría más estrecho que en un móvil, y
   las dos rejillas de Resumen/Dinero/Gastos no tendrían sitio. Por debajo, el
   chat vuelve a ser una pestaña, exactamente como antes.
   Esta SÍ sigue exigiendo `pointer: fine` (a diferencia del casco de arriba,
   ampliado a tablet táctil el 2026-08-19): una columna de chat permanente al
   lado, sin ratón para hacer clic con precisión, es justo lo que se decidió
   NO llevar a tablet — ahí el chat se queda como pestaña.
   `app.js` decide si la pinta (`colCokoActiva()`, MISMA condición exacta que
   aquí abajo — si se toca una, hay que tocar la otra o saldría vacía o
   pintada sin sitio donde ponerse). */
@media (min-width: 1200px) and (pointer: fine) and (min-height: 550px) {
  .coko-col { position: fixed; top: 0; right: 0; bottom: 0; width: 330px; z-index: 11;
    display: flex; flex-direction: column;
    background: var(--card); border-left: 1px solid var(--border); }
  .coko-col[hidden] { display: none; }
  .cc-head { flex: none; display: flex; align-items: center; gap: 9px;
    padding: calc(15px + env(safe-area-inset-top)) 18px 14px;
    border-bottom: 1px solid var(--border); }
  .cc-head img { width: 24px; height: 24px; border-radius: 7px; display: block; }
  .cc-head span { font-family: var(--serif); font-weight: 600; font-size: 16px; }
  /* El scroll es SUYO (no el de la página): así se leen los números de la
     izquierda y la conversación por separado, sin que uno arrastre al otro.
     `bajarChat()` (app.js) baja esta caja, no la ventana, cuando está activa. */
  .cc-body { flex: 1; overflow-y: auto; overscroll-behavior: contain; padding: 16px 16px 8px; }
  /* Aquí el chat NO se centra ni se capa como en la pestaña: la columna ya es
     estrecha, y ese `max-width: 640px` le robaría el ancho que tiene. */
  .cc-body .coko-screen { max-width: none; margin: 0; }
  /* La barra de escribir de la columna es parte de ella (en flujo), no una
     barra fija sobre la ventana como la de la pestaña: hay que deshacerle todo
     el `position: fixed` que trae de `.chatbar`. */
  .coko-col .cc-bar { position: static; left: auto; bottom: auto; transform: none;
    width: auto; max-width: none; flex: none; padding: 10px 14px calc(12px + env(safe-area-inset-bottom)); }
  .coko-col .cc-bar input { max-width: none; }

  /* Todo lo fijo de la izquierda cede los 330px de la derecha. */
  .app-head { width: calc(100% - 220px - 330px); }
  .app-body { max-width: none; margin-right: 330px; }
  /* El «+» se queda dentro del contenido, no debajo de la columna. */
  .fab { right: calc(330px + 36px); }
  #appShell .sheet, #appShell .mov-toast, #appShell .install-banner, #appShell .stale-bar
    { left: calc(50% + 110px - 165px); }
  /* Su pestaña sobra: el chat ya está puesto. `render()` saca de 'coko' a quien
     estuviera ahí al ensanchar, así que esta pestaña nunca queda activa e
     invisible. El hueco central del tabbar tampoco pinta nada ya. */
  .tab[data-tab="coko"], .tab-gap { display: none; }
}

/* ── Tablet táctil: mismo casco de arriba, objetivos más grandes ─────────────
   2026-08-19. El casco (900px + 550px de alto) ya entra sin exigir ratón; lo
   que sí sigue haciendo falta es agrandar lo que se diseñó pensando en un
   cursor de precisión, no en un dedo. Regla de oro (Apple/Google): mínimo
   ~44px de objetivo táctil; lo de aquí abajo estaba entre 28 y 38px.
   Nada de esto toca el layout — mismas posiciones, mismos textos, solo más
   aire alrededor de lo que se pulsa. */
@media (min-width: 900px) and (min-height: 550px) and (pointer: coarse) {
  .mes-nav { width: 40px; height: 40px; }
  .month-pill { padding: 11px 9px; }
  .head-right { gap: 10px 6px; }
  .head-right .icon-btn { padding: 13px 10px; }
  .tab { padding: 14px 24px; }
}

/* Pestaña Cokonsejos = chat: proactivos (tarjetas) + conversación (burbujas) */
.coko-screen { gap: 12px; }
.msg .msg-lbl { font-size: 11px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: var(--accent); margin-bottom: 4px; }
.cbub { max-width: 84%; padding: 10px 13px; font-size: 15px; line-height: 1.45; border-radius: 15px; }
.cbub.me { align-self: flex-end; background: var(--accent); color: #fff; border-bottom-right-radius: 4px; }
.cbub.coko { align-self: flex-start; background: var(--accent-soft); color: #143d26; border-bottom-left-radius: 4px;
  display: flex; gap: 8px; align-items: flex-start; }
.cbub.coko .cbub-av { width: 22px; height: 22px; border-radius: 6px; flex: none; margin-top: 1px; }
.cbub.espera { opacity: .7; font-style: italic; }
/* Las respuestas de Coko pueden traer varias líneas (p. ej. la vista previa de un
   apunte rápido): se respetan los saltos, pero el texto sigue ajustándose. */
.cbub.coko > span, .ask-a { white-space: pre-line; }
.coko-chips { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 4px; }

/* Elegir la etiqueta de un apunte ya escrito (fase 2). El apunte YA está
   guardado: esto no confirma nada, solo responde a «esa etiqueta está en varios
   sitios, ¿cuál es?». Van pegados bajo la tarjeta y alineados con ella: son la
   continuación de lo que Coko acaba de decir, no una acción suelta.
   Prefijo `apu-` (apunte) a propósito: `acc-` ya es de las CUENTAS de Dinero
   (`.acc`, `.acc-movs`, línea 193). Este bloque nació como `.acc` y le pisó el
   estilo a las filas de cuentas, que salían en columna y con sangría. */
.apu-acc { align-self: flex-start; display: flex; flex-direction: column; gap: 8px;
  max-width: 84%; margin: -2px 0 2px 30px; }
.apu-cands { display: flex; flex-wrap: wrap; gap: 6px; }
.apu-cand { border: 1px solid #cfe2d6; background: #fff; color: var(--accent);
  font-family: var(--sans); font-size: 13px; padding: 5px 10px; border-radius: 999px; cursor: pointer; }
.apu-cand:hover { background: var(--accent-soft); }
/* «Sí, ponle esa»: la sugerencia es UNA sola opción, así que va rellena — es la
   respuesta esperada, no una más de una lista. */
.apu-cand.si { background: var(--accent); border-color: var(--accent); color: #fff; }
.apu-cand.si:hover { background: #155c33; }
/* Mientras se guarda: apagados, para que dos toques seguidos no manden dos
   reescrituras de la misma fila. */
.apu-cand:disabled { opacity: .5; cursor: default; }
/* El aviso de «hace falta la IA» dentro del chat (accHTML, acc.pedirIA). */
.ia-inline-nota { margin: 0; font-size: 12.5px; color: var(--muted); line-height: 1.4; }

/* Editar · Eliminar · Listo — las mismas acciones que el bot pone bajo cada
   apunte recién guardado. Discretas (contorno, no relleno): la tarjeta ya dice
   lo importante, esto es lo que puedes hacerle. */
.apu-ops { display: flex; flex-wrap: wrap; gap: 6px; }
.apu-op { display: inline-flex; align-items: center; gap: 5px; border: 1px solid var(--border);
  background: #fff; color: var(--text); font-family: var(--sans); font-size: 13px;
  padding: 6px 11px; border-radius: 999px; cursor: pointer; }
.apu-op svg { width: 14px; height: 14px; stroke: currentColor; fill: none; stroke-width: 2;
  stroke-linecap: round; stroke-linejoin: round; }
.apu-op:hover { border-color: var(--accent); color: var(--accent); }
/* Eliminar en rojo, pero SIN gritar: es reversible escribiéndolo otra vez, no
   el borrado de una contabilidad. */
.apu-op.peligro { color: var(--crit); }
.apu-op.peligro:hover { border-color: var(--crit); color: var(--crit); }
/* «Editar» aún no opera: el mismo punto que marca lo pendiente en Ajustes. */
.apu-op.soon::after { content: ''; width: 5px; height: 5px; border-radius: 50%;
  background: var(--warn); margin-left: 1px; }
.apu-op:disabled { opacity: .5; cursor: default; }

/* «Pregúntale a Coko» (ventana fija en Resumen) + input del chat en Cokonsejos */
.ask-card { display: flex; flex-direction: column; gap: 11px; border-color: #cfe2d6; }
.ask-head { display: flex; align-items: center; gap: 9px; }
.ask-head img { width: 26px; height: 26px; border-radius: 8px; }
.ask-head span { font-size: 15px; font-weight: 600; }
.ask-conv { display: flex; flex-direction: column; gap: 8px; }
.ask-q { align-self: flex-end; max-width: 88%; background: var(--accent); color: #fff;
  padding: 8px 12px; border-radius: 14px; border-bottom-right-radius: 4px; font-size: 14.5px; line-height: 1.4; }
.ask-a { align-self: flex-start; max-width: 92%; background: var(--accent-soft); color: #143d26;
  padding: 8px 12px; border-radius: 14px; border-bottom-left-radius: 4px; font-size: 14.5px; line-height: 1.45; }
.ask-a.espera { opacity: .7; font-style: italic; }
.ask-more { align-self: flex-start; border: 0; background: none; color: var(--accent);
  font-family: var(--sans); font-size: 13.5px; font-weight: 600; cursor: pointer; padding: 0; }
/* `.ask-input` (el campo de escribir de esta tarjeta) se quitó el 2026-08-06:
   se parecía a la barra fija de Cokonsejos pero se iba con el scroll, y dos
   cosas casi iguales comportándose distinto chirrían. Se escribe en un solo
   sitio. Su CSS se va con él para no dejar reglas muertas. */
.coko-ask { margin-top: 6px; }

/* Paneles (bottom sheets) */
.backdrop { position: fixed; inset: 0; background: rgba(0,0,0,.34); z-index: 30; }
.backdrop[hidden] { display: none; }
/* Un panel NUNCA debe pasar de la pantalla: sin este tope, en un móvil bajito el
   final del panel (p. ej. «Cerrar sesión») se salía por abajo y no había forma de
   llegar a él. Con max-height + scroll interno, como mucho se desliza dentro. */
/* `bottom: var(--kb)`: con el teclado abierto (iOS, donde la ventana no encoge)
   el panel sube con él. Sin esto, escribir un concepto o una cantidad se hacía
   a ciegas, detrás del teclado. Y el alto máximo descuenta ese hueco. */
.sheet { position: fixed; left: 50%; transform: translateX(-50%); width: 100%;
  max-width: 480px; bottom: var(--kb, 0px); background: var(--card); border-radius: 20px 20px 0 0;
  z-index: 31; padding: 8px 18px calc(22px + env(safe-area-inset-bottom));
  box-shadow: 0 -8px 30px rgba(0,0,0,.18); touch-action: pan-y;
  max-height: calc(90dvh - var(--kb, 0px)); overflow-y: auto; overscroll-behavior: contain; }
.sheet[hidden] { display: none; }
@media (prefers-reduced-motion: no-preference) {
  .sheet:not([hidden]) { animation: sheetUp .28s cubic-bezier(.3,0,.2,1); }
}
@keyframes sheetUp { from { transform: translate(-50%, 100%); } to { transform: translate(-50%, 0); } }
/* El ASA es la zona por la que se arrastra el panel para cerrarlo. Necesita
   `touch-action: none` para que el dedo no se lo lleve el scroll del navegador;
   por eso el arrastre vive AQUÍ y no en todo el panel (el resto tiene que poder
   deslizarse para leer). Se le da alto de sobra para acertar sin mirar. */
.sheet-asa { touch-action: none; cursor: grab; padding: 4px 0 8px; margin: 0 -18px;
  display: block; }
.sheet-asa:active { cursor: grabbing; }
.grabber { width: 40px; height: 5px; background: #d7dbd7; border-radius: 999px; margin: 6px auto 6px; }
/* Con un panel abierto, el fondo NO se mueve: antes el dedo arrastraba la
   pantalla de debajo en vez de cerrar el panel. */
body.con-sheet { overflow: hidden; }
.sheet h3 { font-family: var(--serif); font-size: 19px; margin: 0 0 4px; }
.sheet .s-sub { font-size: 13.5px; color: var(--muted); margin: 0 0 15px; line-height: 1.5; }
.badge2 { display: inline-block; font-size: 12px; font-weight: 600; color: var(--warn);
  background: #fbf3e3; border: 1px solid #eeddbb; padding: 2px 9px; border-radius: 999px;
  margin-bottom: 10px; }
/* Cuentas desplegables: los movimientos de una cuenta, dentro de su propia fila. */
.acc { cursor: pointer; }
.acc .g-chev { color: var(--muted); font-size: 17px; margin-left: 2px;
  transition: transform .18s ease; }
.acc.open .g-chev { transform: rotate(90deg); }
.acc-movs { padding: 2px 0 10px 12px; border-left: 2px solid var(--accent-soft); margin: 0 0 4px 18px; }
.acc-movs[hidden] { display: none; }
.acc-movs .mv:first-child { border-top: 0; }
.acc-vacio { font-size: 13.5px; color: var(--muted); margin: 8px 0 4px; }
@media (prefers-reduced-motion: no-preference) {
  .acc-movs:not([hidden]) { animation: fadeUp .22s ease both; }
}

/* Barra de presupuesto pulsable (abre su ajuste). El lápiz avisa de que se toca. */
.bg-item.bg-edit { cursor: pointer; }
.bg-pencil { display: inline-grid; place-items: center; width: 22px; height: 22px;
  border-radius: 7px; background: var(--accent-soft); margin-left: 8px; flex: none; }
.bg-pencil svg { width: 13px; height: 13px; stroke: var(--accent); fill: none; stroke-width: 2; }
/* Con lápiz hay 3 hijos: el nombre empuja, e importe y lápiz quedan juntos a la derecha. */
.bg-item.bg-edit .bg-top { align-items: center; }
.bg-item.bg-edit .bg-top .n { flex: 1; }

/* «Ver todos los movimientos» (pie del acordeón de una cuenta) y «Ver más»
   (paginación del histórico en la pantalla de la cuenta). */
.ver-todos { display: flex; align-items: center; gap: 6px; width: 100%;
  border: 0; background: none; padding: 11px 4px 4px; margin-top: 2px;
  border-top: 1px solid var(--border); color: var(--accent);
  font-family: var(--sans); font-size: 14px; font-weight: 600; cursor: pointer; }
.ver-todos span { font-size: 16px; }
.ver-mas { display: block; width: 100%; margin: 10px 0 2px; padding: 12px;
  border: 1px solid var(--border); border-radius: 12px; background: #fff;
  color: var(--accent); font-family: var(--sans); font-size: 15px; font-weight: 600;
  cursor: pointer; }
.ver-mas span { color: var(--muted); font-weight: 400; }
.ver-mas:disabled { color: var(--muted); }
.total-card .big.neg { color: var(--crit); }
.cta-tot { font-size: 13px; color: var(--muted); margin-top: 4px; }

/* Buscar un movimiento por concepto (pantalla propia bajo Gastos). */
.gv-buscar { margin-top: 12px; }
.busca-card { display: flex; align-items: center; gap: 8px; padding: 8px; }
.busca-input { flex: 1; min-width: 0; border: 0; background: none; outline: none;
  font-family: var(--sans); font-size: 16px; color: var(--text); padding: 6px 4px; }
.busca-input::placeholder { color: var(--muted); }
.busca-go { flex: none; width: 38px; height: 38px; border: 0; border-radius: 10px;
  background: var(--accent-soft); color: var(--accent); cursor: pointer;
  display: flex; align-items: center; justify-content: center; }
.busca-go svg { width: 20px; height: 20px; fill: none; stroke: currentColor;
  stroke-width: 2; stroke-linecap: round; }
.busca-hint { font-size: 14px; color: var(--muted); padding: 14px 4px; line-height: 1.5; }

/* Cabecera de la hoja de un movimiento: el apunte que se está mirando. */
/* La nota de un movimiento: texto del usuario, no una cifra. Va en cursiva y en
   el gris secundario para que se lea como lo que es —una anotación al margen— y
   no compita con el importe de arriba. `pre-wrap` porque puede llevar saltos. */
.mov-nota { margin: -6px 0 12px; padding: 9px 11px; border-radius: 10px;
  background: var(--bg); color: var(--muted); font-style: italic;
  font-size: 13.5px; line-height: 1.45; white-space: pre-wrap;
  border-left: 3px solid var(--accent-soft); }
/* El ticket archivado dentro de la hoja de un movimiento. Con tope de altura:
   un ticket de caja es una tira larguísima y sin esto empuja la rejilla de
   opciones fuera de la pantalla. */
.mov-tck { margin: 0 0 12px; }
.mov-tck-img { display: block; width: 100%; max-height: 320px; object-fit: contain;
  object-position: top; border-radius: 10px; background: var(--bg); }
.mov-tck-x { margin-top: 8px; width: 100%; padding: 9px; border-radius: 10px;
  border: 1px solid var(--border); background: var(--card); color: var(--crit);
  font: inherit; font-size: 13.5px; cursor: pointer; }

.me-area { min-height: 76px; resize: vertical; font-family: inherit; }

.mov-head { display: flex; align-items: center; gap: 12px; padding: 0 0 13px;
  border-bottom: 1px solid var(--border); margin-bottom: 14px; }
.mov-head .ic { width: 40px; height: 40px; border-radius: 12px; background: var(--accent-soft);
  display: grid; place-items: center; flex: none; }
.mov-head .ic svg { width: 20px; height: 20px; stroke: var(--accent); fill: none; stroke-width: 1.9; }
.mov-head .txt { flex: 1; min-width: 0; }
.mov-head .cpt { font-family: var(--serif); font-size: 17px; font-weight: 600;
  display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.mov-head .meta { display: flex; align-items: center; gap: 8px; margin-top: 4px; min-width: 0; }
.mov-head .tag { min-width: 0; font-size: 12px; color: var(--accent); background: var(--accent-soft);
  padding: 2px 8px; border-radius: 999px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.mov-head .fch { flex: none; font-size: 12px; color: var(--muted); font-variant-numeric: tabular-nums; }
.mov-head .num { font-family: var(--serif); font-size: 19px; flex: none;
  font-variant-numeric: tabular-nums; }
.mov-head .num.in { color: var(--income); }
/* Opciones aún no operativas: se ven, pero se nota que no van (fase 2). */
.opt.soon { opacity: .62; }
.opt-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; }
.opt { display: flex; flex-direction: column; align-items: center; gap: 7px;
  padding: 13px 6px; border: 1px solid var(--border); border-radius: 14px; background: #fafbfa; }
.opt .oi { width: 40px; height: 40px; border-radius: 12px; background: var(--accent-soft);
  display: grid; place-items: center; }
.opt .oi svg { width: 20px; height: 20px; stroke: var(--accent); fill: none; stroke-width: 1.9; }
.opt .ol { font-size: 13px; text-align: center; }
/* La única opción del «+» que ya opera: se marca para que no parezca una más de
   las que todavía remiten a Telegram. */
.opt.opt-ok { border-color: var(--accent); background: #fff; cursor: pointer; }
.opt.opt-ok .ol { font-weight: 600; color: var(--accent); }
/* «Eliminar» dentro de la rejilla de un movimiento: en rojo, pero sin gritar. */
.opt.opt-del:not(.soon) .oi { background: #fbecea; }
.opt.opt-del:not(.soon) .oi svg { stroke: var(--crit); }
.opt.opt-del:not(.soon) .ol { color: var(--crit); }

/* Editar un movimiento: el panel que sustituye a la rejilla mientras escribes
   un valor o eliges de una lista. Va DENTRO de la misma hoja para no encadenar
   paneles (en un móvil, un panel sobre otro se pierde de vista). */
/* Mientras se edita, la rejilla de 3 columnas deja paso a un panel a todo el
   ancho: un campo de texto o una lista de categorías en un tercio no se leen. */
.opt-grid.editando { display: block; }
.mov-edit { display: flex; flex-direction: column; gap: 10px; }
.me-lbl { font-size: 13px; color: var(--muted); letter-spacing: .04em; text-transform: uppercase; }
.me-lbl.peligro, .me-nota.peligro { color: var(--crit); }
.me-nota { font-size: 14px; color: var(--muted); margin: 0; line-height: 1.45; }
.me-in { border: 1px solid var(--border); border-radius: 12px; padding: 12px 14px;
  font-family: var(--sans); font-size: 17px; color: var(--text); outline: 0; width: 100%; }
.me-in:focus { border-color: var(--accent); }
/* Un `input[type=date]` sin tocar se ve como un cuerpo extraño dentro del panel:
   Safari le pone su propio fondo, lo alinea al centro, lo encoge a lo que mida
   el texto y lo pega arriba. Esto lo devuelve a la misma caja blanca que los
   demás campos, del mismo alto (44px, lo mínimo que se toca bien con el dedo) y
   con el texto donde está en el resto. `-webkit-appearance:none` es lo que quita
   el estilo nativo; sin él, lo de abajo no se aplica en iPhone. */
.me-in[type="date"] { -webkit-appearance: none; appearance: none; background: #fff;
  min-height: 44px; display: block; text-align: left; }
/* El iconito del calendario, a la derecha y en el verde de la app (viene azul
   por defecto y desentona con todo lo demás). */
.me-in[type="date"]::-webkit-calendar-picker-indicator { margin-left: auto; opacity: .6;
  cursor: pointer; }
/* Un campo de fecha VACÍO enseña «dd/mm/aaaa» en gris clarísimo, casi invisible:
   parece un campo roto en vez de uno por rellenar. */
.me-in[type="date"]::-webkit-datetime-edit { color: var(--text); }
.me-in[type="date"]:invalid::-webkit-datetime-edit { color: var(--muted); }
.me-lista { display: flex; flex-direction: column; gap: 6px; max-height: 46vh; overflow-y: auto; }
.me-op { text-align: left; border: 1px solid var(--border); background: #fff; color: var(--text);
  font-family: var(--sans); font-size: 15px; padding: 11px 14px; border-radius: 12px; cursor: pointer; }
.me-op:hover { border-color: var(--accent); color: var(--accent); }
.me-op-x { color: var(--muted); font-style: italic; }
.me-btns { display: flex; gap: 8px; justify-content: flex-end; }
.me-x { border: 0; background: none; color: var(--muted); font-family: var(--sans);
  font-size: 15px; padding: 11px 14px; cursor: pointer; }
.me-ok { border: 0; background: var(--accent); color: #fff; font-family: var(--sans);
  font-size: 15px; font-weight: 600; padding: 11px 20px; border-radius: 12px; cursor: pointer; }
.me-ok:disabled { background: #cfd6d1; color: #6a736e; cursor: default; }
.me-ok-del { background: var(--crit); }
/* La ficha de un recurrente recién creado: la tarjeta del bot, línea a línea. */
.me-ficha { list-style: none; margin: 0; padding: 12px 14px; display: flex; flex-direction: column;
  gap: 4px; border: 1px solid var(--border); border-radius: 12px; background: var(--card); }

/* El enlace de «Recomendar Coko»: se lee entero, no se corta. */
.reco-link { font-size: 13.5px; color: var(--text); word-break: break-all;
  border: 1px solid var(--border); border-radius: 12px; padding: 12px 14px;
  background: var(--card); margin: 12px 0; }
.me-ficha li { font-size: 14px; color: var(--muted); line-height: 1.45; }
.me-ficha .tit { font-size: 17px; font-weight: 700; color: var(--text); }

/* La lista de recurrentes (pantalla de Ajustes): una tarjeta por recurrente,
   separadas. Los pausados se ven apagados pero se ven: esconderlos dejaría a
   alguien buscando uno que sí existe. */
#recCuerpo .me-ficha { margin-top: 10px; }
.me-ficha.rec-pausado { opacity: .55; }
/* Tocar la tarjeta abre el menú de acciones, como el nombre de una cuenta. */
.me-ficha.rec-item { cursor: pointer; }
.me-ficha.rec-item:active { background: var(--bg); }

/* Lo que Coko recuerda de ti: una línea por cosa, con su fecha y su × al lado.
   La fecha se ve para que uno de hace dos años se note viejo de un vistazo, y
   la × está siempre a la vista —no escondida detrás de un deslizamiento ni de
   un «¿seguro?»—: es su memoria y la última palabra es suya. */
.mem-lista { list-style: none; margin: 12px 0 0; padding: 0; display: flex;
  flex-direction: column; gap: 8px; }
.mem-lista li { display: grid; grid-template-columns: 1fr auto auto;
  align-items: center; gap: 10px; border: 1px solid var(--border);
  border-radius: 12px; padding: 10px 12px; background: var(--card); }
.mem-h { font-size: 14.5px; color: var(--text); line-height: 1.4; }
.mem-d { font-size: 12px; color: var(--muted); font-variant-numeric: tabular-nums;
  white-space: nowrap; }
.mem-x { border: 0; background: none; color: var(--muted); font-size: 20px;
  line-height: 1; padding: 4px 6px; border-radius: 8px; cursor: pointer;
  font-family: var(--sans); }
.mem-x:active { background: var(--bg); color: var(--text); }
.mem-x:disabled { opacity: .4; }

/* El formulario del «+». Reutiliza .mov-edit y los .me-* de la hoja de edición
   (mismo campo, mismo botón, mismo desplegable en las dos puertas) y añade solo
   lo que allí no existe: el selector de tipo de arriba y las filas que abren un
   desplegable. */
.ap-tipos { display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px;
  background: var(--bg); border-radius: 14px; padding: 4px; margin-bottom: 14px; }
.ap-tipo { border: 0; background: none; color: var(--muted); font-family: var(--sans);
  font-size: 15px; padding: 9px 6px; border-radius: 11px; cursor: pointer; }
.ap-tipo.on { background: var(--card); color: var(--accent); font-weight: 600;
  box-shadow: 0 1px 3px rgba(0,0,0,.08); }
/* Una fila «etiqueta → valor ›»: el valor no se teclea, se elige de una lista. */
.ap-fila { display: flex; align-items: center; gap: 10px; width: 100%;
  border: 1px solid var(--border); border-radius: 12px; background: var(--card);
  font-family: var(--sans); padding: 12px 14px; cursor: pointer; text-align: left; }
.ap-fila:hover { border-color: var(--accent); }
.ap-k { font-size: 13px; color: var(--muted); letter-spacing: .04em;
  text-transform: uppercase; flex: 0 0 auto; }
.ap-v { flex: 1; font-size: 16px; color: var(--text); text-align: right;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ap-v.vacio { color: var(--muted); font-style: italic; }
.ap-chev { color: var(--muted); font-size: 18px; flex: 0 0 auto; }
/* Concepto/Cantidad: la MISMA fila de arriba, pero con un <input> de verdad en
   vez de un valor fijo — así el «Ej.: Súper» hace de placeholder, pegado a la
   derecha, y no gasta una línea de etiqueta propia encima (2026-08-19, panel
   de Apuntar demasiado largo para caber sin scroll). */
.ap-fila-in { cursor: text; }
.ap-fila-in .ap-v { border: 0; background: none; padding: 0; font-family: inherit; min-width: 0; }
.ap-fila-in .ap-v::placeholder { color: var(--muted); font-style: italic; opacity: 1; }
/* «Se repite»: el asistente del recurrente se encadena después de apuntar. */
.ap-check { display: flex; align-items: flex-start; gap: 10px; cursor: pointer;
  border: 1px solid var(--border); border-radius: 12px; padding: 12px 14px;
  font-size: 14px; color: var(--muted); line-height: 1.45; }
.ap-check input { margin-top: 2px; width: 18px; height: 18px; accent-color: var(--accent); }
.ap-check b { color: var(--text); font-size: 15px; }
.ap-form .me-btns { margin-top: 4px; }
/* Ticket y extracto, ENCIMA del formulario manual (2026-08-19: es lo
   diferencial de Coko, no puede quedar bajo scroll). Son DOS, no tres, así
   que la rejilla genérica de 3 columnas los dejaría descolgados a un lado. */
.ap-mas { grid-template-columns: repeat(2, 1fr); margin-bottom: 4px; }
/* Icono a la izquierda, texto a la derecha (en vez de apilados) — la misma
   opción, en la mitad de alto. Solo aquí (`.ap-mas`), sin tocar `.opt` en
   general: el menú del «+» y el resto de rejillas se quedan como estaban. */
.ap-mas .opt { cursor: pointer; flex-direction: row; justify-content: flex-start;
  gap: 9px; padding: 10px; }
.ap-mas .opt .oi { width: 32px; height: 32px; flex: none; }
.ap-mas .opt .oi svg { width: 16px; height: 16px; }
.ap-mas .opt .ol { text-align: left; }

/* Confirmación breve tras editar. Se va sola; no es el toast de Cokonsejos. */
.mov-toast { position: fixed; left: 50%; transform: translateX(-50%); bottom: 92px;
  z-index: 60; max-width: 88%; background: #1c1f1d; color: #fff; font-size: 14px;
  line-height: 1.4; padding: 11px 16px; border-radius: 12px; white-space: pre-line;
  box-shadow: 0 6px 20px rgba(0,0,0,.22); transition: opacity .4s ease; }
.mov-toast.ir { opacity: 0; }
.tg-cta[hidden] { display: none; }
.tg-cta { display: flex; align-items: center; justify-content: center; gap: 8px;
  margin-top: 14px; background: var(--accent); color: #fff; text-decoration: none;
  font-size: 15px; font-weight: 600; padding: 12px; border-radius: 12px; }
.tg-cta svg { width: 17px; height: 17px; stroke: #fff; fill: none; stroke-width: 2; }
/* Reparto del total en Dinero + accesos a Gastos desde Resumen. */
.rep-nota { font-size: 12px; color: var(--muted); margin-top: 4px; }
.a-gastos { cursor: pointer; }
.cl-mas { float: right; color: var(--accent); text-transform: none; letter-spacing: 0;
  font-weight: 600; font-size: 12px; }

/* Tu objetivo, bajo el balance del mes (solo si lo tienes puesto). */
.obj-linea { display: flex; align-items: center; gap: 8px; margin-top: 12px;
  padding-top: 11px; border-top: 1px solid var(--border); cursor: pointer; }
.obj-linea svg { width: 15px; height: 15px; stroke: var(--accent); fill: none;
  stroke-width: 1.9; flex: none; }
.obj-linea span { font-size: 13.5px; color: var(--muted); min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Premium. Destaca sin gritar: no es un ajuste, es una oferta — pero tampoco
   un banner agresivo. Verde suave, y si YA eres Premium cambia a nota de gracias. */
.prem-card { display: block; width: 100%; text-align: left; margin: 14px 0 2px;
  padding: 13px 14px; border: 1px solid #cfe2d6; border-radius: 14px;
  background: linear-gradient(180deg, #f4faf6, #eef6f1); cursor: pointer;
  font-family: var(--sans); }
.prem-top { display: flex; align-items: center; gap: 10px; }
.prem-ico { width: 30px; height: 30px; border-radius: 9px; background: var(--accent);
  display: grid; place-items: center; flex: none; }
.prem-ico svg { width: 17px; height: 17px; stroke: #fff; fill: none; stroke-width: 1.8; }
.prem-t { flex: 1; font-size: 15.5px; font-weight: 600; color: var(--text); }
.prem-chev { color: var(--accent); font-size: 18px; }
.prem-sub { display: block; font-size: 13px; color: var(--muted); margin: 6px 0 0 40px; }
.prem-card.ya { background: #fff; border-color: var(--border); }

.prem-lista { display: flex; flex-direction: column; gap: 13px; margin: 4px 0 4px; }
.prem-item { display: flex; align-items: flex-start; gap: 11px; font-size: 14px;
  line-height: 1.45; }
.prem-item .pi { width: 32px; height: 32px; border-radius: 10px;
  background: var(--accent-soft); display: grid; place-items: center; flex: none; }
.prem-item .pi svg { width: 16px; height: 16px; stroke: var(--accent); fill: none;
  stroke-width: 1.9; }
.prem-nota { margin-top: 14px !important; }
/* La salida para quien no tiene monedero Lightning. Discreta a propósito: es
   una puerta abierta, no una segunda venta. */
.prem-euros { margin-top: 12px !important; text-align: center; }
.prem-euros a { color: var(--accent); }

/* «Y además» del panel de apuntar: separa los tres principales del resto. */
.opt-mas { font-size: 11px; letter-spacing: .1em; text-transform: uppercase;
  color: var(--muted); font-weight: 600; margin: 16px 2px 9px; }

/* Volver al menú de arriba desde un submenú (en vez de cerrarlo todo). */
.sheet-back { border: 0; background: none; padding: 0 0 6px; margin: 0;
  color: var(--accent); font-family: var(--sans); font-size: 14px; font-weight: 600;
  cursor: pointer; display: block; }

/* Ajustes: el perfil va en la cabecera, en pequeño, para no gastar una fila. */
.aj-cab { display: flex; align-items: baseline; justify-content: space-between;
  gap: 10px; margin-bottom: 12px; }
.aj-cab h3 { margin: 0; }
.aj-uid { display: inline-flex; flex-direction: column; align-items: flex-end; gap: 1px;
  font-size: 12px; color: var(--muted); flex: none; min-width: 0; }
.aj-uid-l { display: inline-flex; align-items: center; gap: 5px; }
.aj-uid svg { width: 13px; height: 13px; stroke: var(--accent); fill: none; stroke-width: 2; }
/* El correo, en segunda línea y más discreto: identifica, no protagoniza. Se
   recorta en vez de empujar el título si la cuenta tiene un correo larguísimo. */
.aj-mail { font-size: 11px; opacity: .75; max-width: 100%; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap; }

/* Recomendar Coko, colgando de la tarjeta de Premium (no gasta fila propia). */
.prem-ref { display: block; width: 100%; text-align: left; border: 0; background: none;
  padding: 8px 2px 12px; color: var(--accent); font-family: var(--sans);
  font-size: 12.5px; font-weight: 600; cursor: pointer; }

/* «Invítame a…»: lo que ve un Premium en vez del CTA de hacerse Premium.
   Mismo verde suave que la tarjeta de Premium, sin la vehemencia de un CTA:
   son tarifas para elegir, no una barra de progreso hacia nada. */
.dona-lista { display: flex; flex-direction: column; gap: 10px; margin-top: 10px; }
.dona-tier { border: 1px solid var(--border); border-radius: 14px; overflow: hidden; }
.dona-tier-btn { display: flex; align-items: center; justify-content: space-between;
  gap: 10px; width: 100%; text-align: left; border: 0; background: #fff;
  padding: 12px 14px; cursor: pointer; font-family: var(--sans); }
.dt-t { font-size: 14px; color: var(--text); line-height: 1.4; }
.dt-sub { font-size: 12.5px; color: var(--muted); font-weight: 400; }
.dt-precio { flex: none; font-size: 14.5px; font-weight: 700; color: var(--accent); }
.dona-metodos[hidden] { display: none; }
.dona-metodos { display: flex; flex-wrap: wrap; gap: 8px; padding: 0 14px 13px; }
.dona-metodo { flex: 1 1 auto; text-align: center; text-decoration: none;
  font-size: 12.5px; font-weight: 600; color: var(--accent); background: var(--accent-soft);
  border-radius: 10px; padding: 8px 10px; }
.dona-metodo.soon { opacity: .62; }
/* Los métodos también salen como <button> (pagar Premium), no solo como <a>:
   el navegador no les da la tipografía del resto, hay que decírselo. */
button.dona-metodo { border: 0; font-family: inherit; cursor: pointer; }
.dona-nota { flex-basis: 100%; margin: 2px 0 0; font-size: 12px; color: var(--muted); }

/* ── La factura Lightning ─────────────────────────────────────────────────── */
/* El QR va SIEMPRE en negro sobre blanco, tema oscuro incluido: su trabajo es
   que la cámara lo lea a la primera, no combinar con la pantalla. Por eso el
   fondo blanco es fijo y no una variable de tema. */
.pago-qr { flex-basis: 100%; display: flex; justify-content: center;
  background: #fff; border-radius: 12px; padding: 10px; margin: 2px 0 4px; }
.pago-qr svg { width: 100%; max-width: 210px; height: auto; display: block; }
.pago-importe { flex-basis: 100%; margin: 0 0 4px; text-align: center; font-size: 14px; }
.pago-importe span { color: var(--muted); margin-left: 6px; font-size: 12.5px; }
.pago-ok { text-align: center; color: var(--accent); font-weight: 600; font-size: 13px; }
/* La segunda línea de un método (p. ej. una aclaración bajo el nombre): más
   pequeña, para que informe sin competir con el nombre del método. */
.dona-metodo small { display: block; font-weight: 500; font-size: 10.5px;
  opacity: .75; margin-top: 1px; }

/* Lo que borra de verdad se ve distinto ANTES de tocarlo. */
.set-row.peligro .st { color: var(--crit); }
.set-row.peligro .si { background: #fbeae8; }
.set-row.peligro .si svg { stroke: var(--crit); }
.peligro-badge { color: var(--crit) !important; background: #fbeae8 !important;
  border-color: #f0cdc8 !important; }
.peligro-cta { background: var(--crit) !important; }
.borrar-lista { display: flex; flex-direction: column; gap: 11px; margin-top: 4px; }
.bo-item { display: flex; gap: 11px; font-size: 13px; line-height: 1.45; }
.bo-item > span:first-child { flex: none; width: 22px; height: 22px; border-radius: 50%;
  background: #fbeae8; color: var(--crit); font-weight: 700; font-size: 12px;
  display: grid; place-items: center; }
/* Qué contabilidad se borra. Va en el color del texto y no en el gris de las
   notas: de todo lo que hay en esta pantalla, es lo único que hay que LEER
   antes de tocar nada, y en gris pequeño se lee como pie de página. */
.bo-cual { margin: 15px 0 12px; font-size: 15px; line-height: 1.45; color: var(--text); }

/* Ajustes: grupos, filas-enlace y filas que aún no se pueden tocar (fase 2). */
.set-grupo { font-size: 11px; letter-spacing: .1em; text-transform: uppercase;
  color: var(--muted); font-weight: 600; margin: 16px 2px 0; }
a.set-row { text-decoration: none; color: inherit; }
.set-row[data-aj] { cursor: pointer; }
.set-row.soon .st::after { content: 'pronto'; font-size: 10px; font-weight: 700;
  letter-spacing: .04em; color: var(--warn); background: #fbf3e3;
  border: 1px solid #eeddbb; padding: 1px 6px; border-radius: 999px;
  margin-left: 7px; vertical-align: 1px; text-transform: uppercase; }
.info-cuerpo { white-space: pre-line; }
/* Pantalla «Cuentas y categorías» de Ajustes: árbol plano indentado (no es
   navegación como en Gastos, es una lista para ver todo y añadir). */
.cc-list { padding: 6px 12px; }
.cc-row { display: flex; align-items: center; justify-content: space-between;
  gap: 8px; padding: 9px 2px; border-top: 1px solid var(--border); font-size: 15px; }
.cc-list .cc-row:first-child { border-top: 0; }
.cc-row.cc-sub span { padding-left: 16px; color: var(--muted); }
.cc-row.cc-sub span::before { content: '› '; }
.cc-row.cc-subsub span { padding-left: 32px; color: var(--muted); font-size: 14px; }
.cc-row.cc-subsub span::before { content: '· '; }
.cc-add { border: 1px solid var(--border); background: var(--card); color: var(--accent);
  padding: 4px 10px; border-radius: 999px; font-size: 12.5px; font-family: var(--sans);
  cursor: pointer; flex: none; }
.cc-add:hover { border-color: var(--accent); }
.cc-ren { cursor: pointer; flex: 1; }
/* Reordenar las cuentas. Los botones son cuadrados y de 30px porque se tocan con
   el dedo en una lista apretada: más pequeños y se falla de fila. Deshabilitados
   (la primera hacia arriba, la última hacia abajo) se atenúan en vez de
   desaparecer, para que la fila no cambie de ancho al moverse. */
/* ── Tutorial de inicio (fase 3, etapa 8) ─────────────────────────────────── */
.tuto-paso { font-size: 12px; font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase; color: var(--accent); margin: 0 0 4px; }
.tuto-t { margin: 0 0 6px; font-family: var(--serif); font-size: 21px; }

/* La tarjeta «Te queda esto» del inicio. Cada fila es un botón grande (se toca
   con el pulgar) y una equis pequeña pero separada, para no descartar sin
   querer lo que se quería abrir. */
.mi-card { padding: 12px 14px; }
.mi-cuenta { float: right; font-weight: 400; color: var(--muted); }
.mi-row { display: flex; align-items: flex-start; gap: 6px;
  border-top: 1px solid var(--border); padding: 10px 0; }
.mi-card .mi-row:first-of-type { border-top: 0; padding-top: 4px; }
.mi-go { flex: 1; min-width: 0; text-align: left; background: none; border: 0;
  padding: 0; cursor: pointer; font-family: var(--sans); }
.mi-t { display: block; font-size: 15px; color: var(--text); }
.mi-t::after { content: ' ›'; color: var(--muted); }
.mi-s { display: block; font-size: 13px; color: var(--muted); line-height: 1.4;
  margin-top: 2px; }
.mi-x { flex: none; width: 30px; height: 30px; border: 0; background: none;
  color: var(--muted); font-size: 20px; line-height: 1; cursor: pointer;
  border-radius: 8px; }
.mi-x:hover { background: #f4f5f3; color: var(--text); }

/* Quién tiene acceso a la contabilidad. Reutiliza .mi-x (la × de las misiones):
   es el mismo gesto de «quitar esto de aquí» y no merece un botón nuevo. */
.eq-lista { margin: 4px 0 14px; }
.eq-row { display: flex; align-items: center; gap: 6px;
  border-top: 1px solid var(--border); padding: 9px 0; }
.eq-lista .eq-row:first-child { border-top: 0; }
.eq-n { flex: 1; min-width: 0; font-size: 15px; color: var(--text); }
.eq-r { display: block; font-size: 13px; color: var(--muted); margin-top: 1px; }

.cc-ord { display: flex; gap: 4px; flex: none; }
.cc-mv { width: 30px; height: 30px; border: 1px solid var(--border); background: #f4f5f3;
  color: var(--text); border-radius: 8px; font-size: 14px; line-height: 1;
  font-family: var(--sans); cursor: pointer; }
.cc-mv:disabled { opacity: .3; cursor: default; }
.cc-mv:not(:disabled):hover { border-color: var(--accent); color: var(--accent); }
.cc-ren:hover { color: var(--accent); }
.set-row { display: flex; align-items: center; gap: 12px; padding: 13px 2px;
  border-top: 1px solid var(--border); }
.set-row.first { border-top: 0; }
.set-row .si { width: 34px; height: 34px; border-radius: 10px; background: var(--accent-soft);
  display: grid; place-items: center; flex: none; }
.set-row .si svg { width: 17px; height: 17px; stroke: var(--accent); fill: none; stroke-width: 1.9; }
.set-row .st { flex: 1; font-size: 15px; }
.set-row .sv { font-size: 13px; color: var(--muted); }
.set-row.link { cursor: pointer; }
.set-tele { margin-top: 12px; display: flex; gap: 9px; font-size: 13.5px; line-height: 1.5;
  color: var(--muted); background: var(--accent-soft); border: 1px solid #cfe2d6;
  border-radius: 12px; padding: 11px 12px; }
.set-tele svg { flex: none; width: 16px; height: 16px; stroke: var(--accent); fill: none;
  stroke-width: 1.9; margin-top: 1px; }

@keyframes popUp { from { transform: translate(-50%, 130%); opacity: 0; }
  to { transform: translate(-50%, 0); opacity: 1; } }

/* Banner "Instala Coko" (PWA) */
.install-banner { position: fixed; bottom: calc(98px + env(safe-area-inset-bottom)); left: 50%;
  transform: translateX(-50%); width: calc(100% - 24px); max-width: 440px; z-index: 24;
  background: var(--card); border: 1px solid #cfe2d6; border-radius: 18px;
  box-shadow: 0 18px 46px rgba(0,0,0,.26); padding: 16px; }
@media (prefers-reduced-motion: no-preference) { .install-banner:not([hidden]) { animation: popUp .5s cubic-bezier(.34,1.4,.64,1); } }
.install-banner[hidden] { display: none; }
.install-banner .ib-top { display: flex; align-items: center; gap: 11px; }
.install-banner .ib-top img { width: 40px; height: 40px; border-radius: 11px; flex: none; }
.install-banner .ib-txt { flex: 1; display: flex; flex-direction: column; line-height: 1.35; }
.install-banner .ib-txt b { font-size: 16px; }
.install-banner .ib-txt span { font-size: 13.5px; color: var(--muted); }
.install-banner .ib-actions { display: flex; gap: 10px; margin-top: 14px; }
.install-banner .ib-go { flex: 1; border: 0; background: var(--accent); color: #fff; font-family: var(--sans);
  font-size: 16px; font-weight: 600; padding: 12px; border-radius: 12px; cursor: pointer; }
.install-banner .ib-x { border: 0; background: #f4f5f3; color: var(--muted); font-family: var(--sans);
  font-size: 15px; padding: 12px 16px; border-radius: 12px; cursor: pointer; }

/* Aviso de datos desactualizados: una barra fina, sin alarma (nada de rojo). */
.stale-bar { position: fixed; bottom: calc(98px + env(safe-area-inset-bottom)); left: 50%;
  transform: translateX(-50%); width: calc(100% - 24px); max-width: 440px; z-index: 23;
  display: flex; align-items: center; gap: 10px; cursor: pointer;
  background: var(--card); border: 1px solid var(--border); border-radius: 12px;
  box-shadow: 0 10px 28px rgba(0,0,0,.18); padding: 11px 14px; }
.stale-bar span { flex: 1; font-size: 13px; line-height: 1.4; color: var(--muted); }
.stale-bar b { flex: none; font-size: 13px; color: var(--accent); font-weight: 600; }
@media (prefers-reduced-motion: no-preference) { .stale-bar { animation: popUp .4s cubic-bezier(.34,1.4,.64,1); } }

/* Skeletons (primera carga sin caché) */
.skel { border-radius: 16px; background: linear-gradient(100deg, #ececea 40%, #f6f6f4 50%, #ececea 60%);
  background-size: 200% 100%; animation: skel 1.1s linear infinite; border: 1px solid var(--border); }
@keyframes skel { to { background-position: -200% 0; } }
@media (prefers-reduced-motion: reduce) { .skel { animation: none; } }

/* ── Alta: crear la contabilidad (fase 3) ───────────────────────────────────
   Pantalla propia, sin la cabecera ni las pestañas de la app: quien está aquí
   todavía no tiene nada que navegar, y enseñarle un menú que no lleva a ningún
   sitio es la manera de que se pregunte qué ha hecho mal. */
#altaView { flex: 1; display: flex; flex-direction: column; }
#altaCuerpo { flex: 1; display: flex; flex-direction: column; }

.alta-wrap { flex: 1; display: flex; flex-direction: column; gap: 12px;
  padding: 28px 22px calc(28px + env(safe-area-inset-bottom)); }
.alta-centro { align-items: center; justify-content: center; text-align: center; }

.alta-logo { width: 76px; height: 76px; border-radius: 20px; }
@media (prefers-reduced-motion: no-preference) {
  .alta-late { animation: latido 1.6s ease-in-out infinite; }
}

.alta-t { font-family: var(--serif); font-weight: 600; font-size: 25px;
  margin: 0; line-height: 1.25; }
.alta-s { margin: 0; color: var(--muted); font-size: 15px; line-height: 1.5; }
.alta-nota { margin: 2px 0 0; color: var(--muted); font-size: 13px; line-height: 1.5; }
/* El aviso de «ya usas Coko en Telegram». Con caja y borde, no como una nota
   más: es lo único de esta pantalla que, si no se lee, deja a alguien con dos
   contabilidades y sin forma de juntarlas. */
.alta-ojo { margin-top: 18px; text-align: left; background: #fbf3e3;
  border: 1px solid #ecdcb8; border-radius: 12px; padding: 11px 13px;
  color: var(--text); }
.alta-mini { display: block; margin-top: 4px; color: var(--muted); font-size: 12px; }

.alta-lista { margin: 4px 0; padding-left: 20px; display: flex; flex-direction: column;
  gap: 8px; color: var(--text); font-size: 15px; line-height: 1.45; }
.alta-lista-fina { font-size: 14px; color: var(--muted); gap: 5px; }
.alta-centro .alta-lista { text-align: left; }

/* Los tres caminos. La opción de IA va destacada para que no se confunda con
   las manuales: es el mismo criterio con el que el bot la pone la primera. */
.alta-opt { display: block; width: 100%; text-align: left; background: var(--card);
  border: 1px solid var(--border); border-radius: 16px; padding: 15px 16px;
  font: inherit; color: var(--text); cursor: pointer; }
.alta-opt b { display: block; font-size: 16px; margin-bottom: 3px; }
.alta-opt span { color: var(--muted); font-size: 13.5px; line-height: 1.4; }
.alta-opt:active { transform: scale(.985); }
.alta-opt-ia { border-color: var(--accent); background: var(--accent-soft); }

.alta-btn { width: 100%; padding: 14px 16px; border-radius: 14px; font: inherit;
  font-size: 16px; font-weight: 500; cursor: pointer; background: var(--card);
  color: var(--text); border: 1px solid var(--border); }
.alta-btn:active { transform: scale(.985); }
.alta-btn-fuerte { background: var(--accent); color: #fff; border-color: var(--accent);
  font-weight: 600; margin-top: 6px; }
.alta-btn-suave { background: none; border: none; color: var(--muted); font-size: 14.5px; }

.alta-atras { align-self: flex-start; background: none; border: none; padding: 0 0 4px;
  color: var(--muted); font: inherit; font-size: 15px; cursor: pointer; }

.alta-input { width: 100%; padding: 13px 14px; border-radius: 13px; font: inherit;
  font-size: 16px;               /* 16px o iOS hace zoom al enfocar */
  background: var(--card); color: var(--text); border: 1px solid var(--border); }
.alta-input:focus { outline: none; border-color: var(--accent); }
.alta-area { width: 100%; padding: 13px 14px; border-radius: 13px; font: inherit;
  font-size: 16px; line-height: 1.45; resize: vertical; background: var(--card);
  color: var(--text); border: 1px solid var(--border); }
.alta-area:focus { outline: none; border-color: var(--accent); }
select.alta-input { appearance: none; background-image:
  url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%236a736e' stroke-width='2'><path d='M6 9l6 6 6-6'/></svg>");
  background-repeat: no-repeat; background-position: right 12px center;
  background-size: 18px; padding-right: 38px; }

.alta-campo { display: flex; flex-direction: column; gap: 6px; }
.alta-campo > span { font-size: 13.5px; color: var(--muted); }
/* La casilla de la newsletter. Toda la fila es pulsable (el <label> envuelve al
   input): una casilla de 16 px es un blanco imposible con el dedo. */
.alta-check { display: flex; align-items: flex-start; gap: 10px; cursor: pointer;
  font-size: 14.5px; line-height: 1.45; padding: 4px 0; }
.alta-check input { flex: none; width: 20px; height: 20px; margin-top: 1px;
  accent-color: var(--accent); }
.alta-mail { margin-top: -2px; }
.alta-mail-nota { margin-top: -4px; }

.alta-check { display: flex; align-items: center; gap: 10px; padding: 12px 14px;
  background: var(--card); border: 1px solid var(--border); border-radius: 13px;
  font-size: 15px; cursor: pointer; }
.alta-check input { width: 20px; height: 20px; accent-color: var(--accent); }

.alta-resumen { background: var(--card); border: 1px solid var(--border);
  border-radius: 16px; padding: 14px 16px; }
.alta-r-t { margin: 10px 0 4px; font-size: 13px; color: var(--muted); }
.alta-r-t:first-child { margin-top: 0; }
.alta-r-l { margin: 0 0 3px; font-size: 14.5px; line-height: 1.45; }

/* Separador entre los dos modos de entrar. Solo se ve si hay más de uno
   (app.js lo enseña con el botón de Google): con un único login, una raya que
   dice «o» sin segunda opción es una promesa que no se cumple. */
#loginSep { display: flex; align-items: center; gap: 12px; width: 100%;
  max-width: 280px; color: var(--muted); font-size: 13px; }
#loginSep[hidden] { display: none; }
#loginSep::before, #loginSep::after { content: ''; flex: 1; height: 1px;
  background: var(--border); }
#googleBtn[hidden] { display: none; }
/* El botón lo pinta Google en un iframe con su propio ancho: se centra y se le
   deja su sitio sin pelearse con él por los estilos. */
#googleBtn { display: flex; justify-content: center; min-height: 44px; }

/* ── Ticket: la foto y su tarjeta de confirmación (fase 3, etapa 4) ────────── */
.tk-espera { display: flex; flex-direction: column; align-items: center; gap: 10px;
  padding: 26px 12px; text-align: center; }
.tk-logo { width: 52px; height: 52px; border-radius: 15px; }
@media (prefers-reduced-motion: no-preference) {
  .tk-logo { animation: latido 1.6s ease-in-out infinite; }
}
.tk-t { margin: 0; font-size: 15px; color: var(--muted); line-height: 1.45; }

.tk-cab { margin: 2px 0 10px; font-size: 15px; font-weight: 600; }
.tk-lista { display: flex; flex-direction: column; gap: 8px; }
.tk-mov { display: grid; grid-template-columns: auto 1fr; gap: 2px 10px;
  background: var(--card); border: 1px solid var(--border); border-radius: 13px;
  padding: 11px 13px; }
.tk-imp { grid-row: 1 / span 2; align-self: center; font-weight: 700;
  font-size: 15.5px; font-variant-numeric: tabular-nums; }
.tk-imp.gasto { color: var(--crit); }
.tk-imp.ingreso { color: var(--income); }
.tk-con { font-size: 15px; }
.tk-det { font-size: 12.5px; color: var(--muted); line-height: 1.35; }
.tk-nota { margin: 11px 0 0; font-size: 12.5px; color: var(--muted); line-height: 1.45; }

/* El consentimiento de IA (2026-08-10): no es un estado de espera ni un error,
   así que no lleva el logo latiendo — leería como «cargando» y no lo está. */
.ia-consent .tk-logo { animation: none; }
.ia-consent .tk-cab { font-size: 17px; }
.ia-consent .tk-nota:first-of-type { background: var(--accent-soft); color: var(--text);
  border-radius: 12px; padding: 9px 12px; margin-top: 14px; }
.ia-opcional { font-style: italic; }

/* Extracto: elegir cuenta y el resumen del lote (fase 3, etapa 5) */
.ex-preg { margin: 14px 0 8px; font-size: 15px; font-weight: 600; }
.ex-tot { display: flex; flex-direction: column; gap: 3px; margin: 0 0 12px;
  font-size: 13px; color: var(--muted); line-height: 1.45; }
.ex-tot .ex-g { color: var(--crit); }
.ex-tot .ex-i { color: var(--income); }
.ex-tot .ex-d { color: var(--warn); }
