/* ===============================
   B-DESK PRO - components.css
   Componentes compartidos
   =============================== */

/* `hidden` SIEMPRE oculta, en toda la app. El estilo del navegador para
   [hidden] es un display:none SIN prioridad: cualquier regla con display
   (flex, inline-flex…) le gana y el elemento sigue visible aunque el JS lo
   haya ocultado. Pasó dos veces el 2026-10-15 (el «Confirmar» de la vista
   previa del import, por .btn-pro, y el «Forzar reimportación», por su
   display:flex). Los parches puntuales `.x[hidden]{display:none}` que había
   en los CSS de módulo se sacaron el 2026-10-16: no escribir otros.
   Verificado antes de agregarlo: ningún elemento con `hidden` depende de
   seguir visible (los que se muestran lo hacen sacando el atributo). */
[hidden]{ display: none !important; }

/* Helpers */
.muted{ color: var(--muted); }

/* Flash messages */
.flash-wrap{ display:grid; gap:10px; margin: 0 0 14px; }
.flash{
  border: 1px solid var(--stroke);
  background: rgba(255,255,255,.06);
  border-radius: 14px;
  padding: 12px 14px;
  font-weight: 700;
}
.flash-success{ border-color: var(--ok-border); background: var(--ok-bg); }
.flash-error{ border-color: rgba(255,93,108,.25); background: rgba(255,93,108,.08); }
.flash-warning{ border-color: rgba(255,200,80,.25); background: rgba(255,200,80,.08); }
.flash-info{ border-color: rgba(51,214,255,.22); background: rgba(51,214,255,.08); }

/* Buttons PRO */
.btn-pro{
  height: 46px;
  padding: 0 18px;
  border-radius: 999px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  font-family: var(--font-display);
  font-weight:700;
  font-size:15px;
  line-height: 1;
  letter-spacing: .2px;
  cursor: pointer;
  user-select: none;
  text-decoration: none;
  border: 1px solid transparent;
  /* Fase B — transición unificada (timing único .14s) para que el hover de
     todas las variantes (ghost/gradient) anime de forma consistente. Antes
     .btn-pro base no tenía transición y el cambio de fondo del ghost era seco. */
  transition: background .14s ease, border-color .14s ease, color .14s ease,
              transform .14s ease, box-shadow .14s ease, filter .14s ease;
}

/* Hover global de botones principales: capa oscura SOBRE el fondo (inset
   box-shadow) en vez de filter:brightness — así oscurece el FONDO pero el
   TEXTO queda intacto y legible. Aplica a todas las variantes .btn-pro. */
.btn-pro:hover,
.btn-pro-gradient:hover{
  box-shadow: inset 0 0 0 9999px rgba(0, 0, 0, 0.15);
  filter: none;
}

.btn-pro-ghost{
  background: rgba(255, 255, 255, 0.06);
  border-color: rgba(255, 255, 255, 0.14);
  color: rgba(255, 255, 255, 0.92);
}

.btn-pro-gradient{
  background: linear-gradient(135deg, var(--cyan), var(--violet));
  border: 0;
  color: #071018;
  font-weight:700;
  box-shadow: 0 10px 28px rgba(51,214,255,.20), 0 10px 28px rgba(139,92,255,.18);
}
.btn-pro-gradient:hover{ transform: translateY(-1px); }
.btn-pro-gradient:active{ transform: translateY(0); }

/* theme.css define un a:hover{ color: cyan } global. Como los botones suelen ser
   <a>, en hover el TEXTO se volvía cyan e ilegible sobre su propio fondo. Fijamos
   el color del texto por variante en hover (mayor especificidad que a:hover, y
   también -webkit-text-fill-color que webkit usa por encima de color). El overlay
   oscuro del fondo se mantiene intacto. */
.btn-pro-gradient:hover{ color: #071018; -webkit-text-fill-color: #071018; }
.btn-pro-ghost:hover{ color: rgba(255,255,255,.92); -webkit-text-fill-color: rgba(255,255,255,.92); }
/* Hover del botón secundario (05/10/2026): antes sólo una sombra negra del
   15% sobre fondo oscuro — casi invisible. Ahora se aclara y el borde toma un
   cyan suave: se nota que es tocable sin competir con el CTA con gradiente. */
.btn-pro-ghost:not(:disabled):not(.is-disabled):hover{
  background: rgba(255, 255, 255, 0.11);
  border-color: rgba(34, 211, 238, 0.45);
  box-shadow: none;
  color: #fff; -webkit-text-fill-color: #fff;
}
.btn-pro-ghost:not(:disabled):not(.is-disabled):active{ background: rgba(255, 255, 255, 0.08); }
.btn--primary:hover,
.btn--soft:hover,
.btn--ghost:hover{ color: #0b0f19; -webkit-text-fill-color: #0b0f19; }

/* Cards */
.card, .pro-card{
  background: var(--panel);
  border: 1px solid var(--stroke);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}

.pro-card{ padding: 18px; }

/* ──────────────────────────────────────────────────────────────────────
   FIX mobile (<=900px) — "banda/sombra oscura" al costado de las cards/tablas
   en Android Chrome. La sombra global var(--shadow) (0 20px 60px, blur 60)
   se derrama ~30px hacia los gutters; con las cards casi full-width en mobile
   eso pinta una franja oscura a los lados (sobre todo izquierda) que Blink
   rasteriza con banding más visible que WebKit (de ahí "iOS mejor, Android
   peor"). En mobile la quitamos por completo (box-shadow:none) → el gutter
   queda igual al fondo de página, sin ninguna banda en Android real. Las
   cards van casi full-width en mobile, así que no pierden definición (siguen
   con borde + radio). Scopeado a páginas de módulo (.fp) → NO afecta modales
   (.fp-modal-card) ni desktop (que mantiene la sombra var(--shadow)).
   Solo presentación. */
@media (max-width: 900px){
  .fp .card,
  .fp .pro-card{
    box-shadow: none;
  }
}

.pro-card-head{
  display:flex;
  justify-content:space-between;
  align-items:center;
  margin-bottom: 14px;
}
.pro-card-title{
  margin:0;
  font-size:17px;
  font-family: var(--font-display);
}

/* KPIs base */
.kpis{
  display:grid;
  gap: 18px;
}
.kpi{
  border-radius: var(--radius);
  border: 1px solid var(--stroke);
  background: var(--panel);
  box-shadow: var(--shadow);
  padding: 18px;
}
.kpi-label{
  font-family: var(--font-display);
  font-weight:700;
  letter-spacing: .18em;
  text-transform: uppercase;
  font-size:13px;
  opacity: .9;
  text-align:center;
}
.kpi-value{
  font-family: var(--font-display);
  font-weight:700;
  font-variant-numeric: tabular-nums;
  font-size:34px;
  line-height: 1.05;
  margin: 10px 0 8px;
  text-align:center;
}
.kpi-foot{
  color: var(--muted);
  font-size:13px;
  text-align:center;
}

.kpi-value-cyan{ color: var(--cyan); }
.kpi-value-violet{ color: var(--violet); }
.kpi-value-danger{ color: var(--red); }
.kpi-value-white{ color: rgba(255,255,255,.92); }

/* Table */
.pro-table-wrap{
  overflow-x:auto;
  border-radius: 14px;
  border: 1px solid var(--stroke);
  background: rgba(0,0,0,.15);
}
.pro-table{
  width:100%;
  border-collapse: collapse;
}
.pro-table th,
.pro-table td{
  padding: 14px 16px;
  text-align: center;
  border-bottom: 1px solid rgba(255,255,255,.06);
  vertical-align: middle;
  white-space: nowrap;
}
.pro-table th{
  color: var(--muted);
  font-size:11px;
  text-transform: uppercase;
  letter-spacing: .1em;
  font-weight:700;
  background: rgba(255,255,255,.03);
}
.pro-table tbody tr:last-child td{ border-bottom:none; }
.pro-table tbody tr:hover{ background: rgba(255,255,255,.03); }

/* Tags */
.tag{
  display:inline-flex;
  align-items:center;
  padding: 6px 12px;
  border-radius: 999px;
  font-weight:700;
  font-size:11px;
  text-transform: uppercase;
  letter-spacing: .05em;
  border: 1px solid var(--stroke);
  background: rgba(255,255,255,.06);
}
.tag-ingreso{
  border-color: rgba(51,214,255,.35);
  background: rgba(51,214,255,.10);
  color: var(--cyan);
}
.tag-gasto{
  border-color: rgba(139,92,255,.35);
  background: rgba(139,92,255,.10);
  color: var(--violet);
}
/* Badge "Cuota X/N" para series de cuotas limitadas en CxC/CxP. Menor
   densidad que un estado: chip discreto al lado del concepto, no la columna
   protagónica. */
.tag-cuota{
  margin-left: 6px;
  padding: 3px 8px;
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: .04em;
  border-color: rgba(34,211,238,.32);
  background: rgba(34,211,238,.10);
  color: rgba(34,211,238,.95);
}

/* Icon buttons */
.actions-wrap{ display:flex; justify-content:center; gap:6px; }
.inline-form{ display:inline; margin:0; }

/* Eliminar serie: mismo ícono trash que el delete normal, diferenciado por
   color ámbar/naranja (la acción afecta a TODA la serie pendiente, no a una
   sola cuota). El stroke usa currentColor, así que basta con `color`. */
.btn-icon-serie{ color: rgba(251,191,36,.95); }
.btn-icon-serie:hover{ border-color: rgba(251,191,36,.45); color: rgba(251,191,36,1); }

.btn-icon{
  display:inline-flex;
  align-items:center;
  justify-content:center;
  width:32px;
  height:32px;
  flex: 0 0 auto;            /* footprint fijo: nunca se comprime en la fila */
  border: 1px solid var(--stroke);
  border-radius: 12px;       /* más redondeado / premium (antes 10px) */
  background: rgba(255,255,255,.04);
  color: var(--muted);
  cursor:pointer;
  /* Hover reactivo: solo las props que cambian, rápido y suave. */
  transition: background .12s ease, color .12s ease,
              border-color .12s ease, transform .12s ease, box-shadow .12s ease;
}
.btn-icon:hover{
  background: rgba(255,255,255,.10);
  color: var(--text);
  transform: translateY(-1px);
}
/* Regla DS: el hover NO cambia el color del botón.
   - Edit: solo intensidad de borde (alpha shift sobre el neutro). El bg y el
     color de texto ya los modula .btn-icon:hover (intensidad + lift).
   - Delete: excepción controlada -> rojo SOLO en border-color (señal
     destructiva, convención universal). NO pinta el fondo de rojo NI
     cambia el color del ícono. */
.btn-icon-edit:hover  { border-color: rgba(255,255,255,.22); }
.btn-icon-delete:hover{ border-color: rgba(255,93,108,.40); }

/* Export legacy */
.btn-export{
  display:inline-flex;
  align-items:center;
  gap:8px;
  padding: 6px 10px;
  border-radius: 10px;
  font-size:13px;
  background: rgba(51,214,255,.10);
  border: 1px solid rgba(51,214,255,.20);
  color: var(--cyan);
  font-weight:700;
  text-decoration:none !important;
  transition: transform .12s ease, background .12s ease, box-shadow .12s ease;
}
.btn-export:hover{
  background: rgba(51,214,255,.16);
  box-shadow: 0 10px 22px rgba(51,214,255,.10);
  transform: translateY(-1px);
}

/* =========================================================
   EXPORTAR — COMPONENTE GLOBAL UNIFICADO
   ========================================================= */
.bdesk-export{
  position: relative;
  display: inline-block;
}

/* Exportar = un dropdown más del sistema (mismo look que .fp-dd-btn/.fp-pill):
   dark normal + borde sutil; al abrir, borde cyan + glow suave (interior
   sigue dark). NO es CTA: Filtrar es el único primario. Conserva ícono+caret. */
.bdesk-export-btn{
  height: 46px;              /* alinea con btn-pro (Filtrar/Limpiar) de la fila */
  padding: 0 16px;
  border-radius: 999px;
  border: 1px solid rgba(255,255,255,.12);
  background: rgba(0,0,0,.18);
  color: #fff;
  font-family: var(--font-display);
  font-weight:700;
  font-size:15px;
  line-height: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  cursor: pointer;
  text-decoration: none;
  box-shadow: none;
  transition: border-color .15s ease, background .15s ease, box-shadow .15s ease;
}
/* Hover: borde apenas más claro (como .fp-pill:hover). Sin lift ni gradiente. */
.bdesk-export-btn:hover{
  border-color: rgba(255,255,255,.18);
  background: rgba(0,0,0,.22);
}
/* Abierto/focus: borde cyan sutil + glow suave (como .fp-pill:focus). Dark. */
.bdesk-export-btn[aria-expanded="true"],
.bdesk-export-btn:focus-visible{
  border-color: rgba(34,211,238,.45);
  background: rgba(0,0,0,.22);
  box-shadow: 0 0 0 3px rgba(34,211,238,.12);
  outline: none;
}
.bdesk-export-btn:active{ transform: none; }

/* Ícono de descarga del botón (sutil; sin tinte fuerte). */
.bdesk-export-ico{ flex: 0 0 15px; opacity: .75; }
.bdesk-export-btn[aria-expanded="true"] .bdesk-export-ico{ opacity: 1; color: var(--cyan); }

.bdesk-export-caret{
  font-size:11px;
  opacity: .8;
  line-height: 1;
  transition: transform .15s ease;
}
.bdesk-export-btn[aria-expanded="true"] .bdesk-export-caret{ transform: rotate(180deg); }

/* ⚠️ PANEL OPACO — mismo tratamiento que .fp-dd-menu, y por el mismo motivo.
   Tenía `background: rgba(10,16,24,.96)` sin backdrop-filter: ese 4% deja leer
   el contenido de atrás A TRAVÉS del panel, y este menú flota justo sobre la
   toolbar de filtros y la tabla. El comentario de más arriba ya pedía que
   Exportar se viera "igual que .fp-dd-menu"; esto lo cumple de verdad. */
.bdesk-export-menu{
  position: absolute;
  top: calc(100% + 8px);
  left: 0;
  min-width: 220px;
  padding: 8px;
  border-radius: 18px;
  border: 1px solid rgba(255,255,255,.12);
  background: linear-gradient(180deg,rgba(7,14,24,.985),rgba(4,9,18,.985));
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  box-shadow: 0 20px 60px rgba(0,0,0,.45);
  display: none;
  z-index: 140;
}

.bdesk-export-menu.is-open{
  display: block;
  animation: bdesk-export-in .13s ease;
  transform-origin: top right;
}
@keyframes bdesk-export-in{
  from{ opacity: 0; transform: translateY(-4px) scale(.98); }
  to  { opacity: 1; transform: translateY(0) scale(1); }
}
@media (prefers-reduced-motion: reduce){
  .bdesk-export-menu.is-open{ animation: none; }
}

.bdesk-export-link{
  display: flex;
  align-items: center;
  width: 100%;
  min-height: 44px;
  padding: 0 14px;
  border-radius: 14px;
  border: 1px solid transparent;
  background: transparent;
  color: rgba(255,255,255,.92);
  text-decoration: none !important;
  font-family: var(--font-display);
  font-weight:700;
  font-size:15px;
  line-height: 1;
  transition: background .12s ease, color .12s ease, border-color .12s ease;
}

/* Regla DS: hover/focus NO cambian el hue. Feedback de intensidad (alpha del
   fondo) + borde sutil. No se setea `outline:none` -> el anillo global de
   :focus-visible (bdesk-focus-visible.css) aplica para navegación por teclado. */
.bdesk-export-link:hover,
.bdesk-export-link:focus{
  background: rgba(255,255,255,.06);
  border-color: rgba(255,255,255,.12);
  /* ⚠️ `color` es obligatorio acá aunque parezca redundante: sin declararlo
     gana `theme.css:81  a:hover{ color: rgba(51,214,255,.92) }` y el texto se
     pone CYAN, que es exactamente el cambio de hue que esta regla dice evitar.
     Estuvo así siempre; no se veía porque el degradado forzaba texto oscuro en
     reposo y en hover. Salió a la luz al revertir el degradado (2026-08-17). */
  color: #fff;
}
/* Estado seleccionado/actual (Categoría B): se conserva el gradiente como
   indicador semántico de "opción actual" (NO es feedback de interacción). */
.bdesk-export-link.is-active{
  background: linear-gradient(135deg, var(--cyan), var(--violet));
  color: #071018 !important;
  border-color: transparent;
}

.bdesk-export-link + .bdesk-export-link{
  margin-top: 6px;
}

/* Variante agrupada y compacta del menú export (módulos con varias
   fuentes de datos, ej. Inventario: Productos/Compras/Ventas). Reutiliza
   .bdesk-export-link; solo achica densidad y agrega encabezados de grupo. */
/* Variante usada por todos los módulos. Coincide con el menú de filtros
   (.fp-dd-menu): dark glass, borde sutil, sombra premium, mismo radio y
   densidad. La opción se ve como una .fp-dd-opt (pill); el degradado
   cyan→violeta queda para la opción activa. */
.bdesk-export-menu--grouped{
  min-width: 178px; padding: 8px; border-radius: 16px;
  top: calc(100% + 8px);
  left: auto; right: 0;   /* ancla a la derecha: el trigger está al final
                             de la fila de filtros; evita overflow. */
}
.bdesk-export-menu--grouped .bdesk-export-group + .bdesk-export-group{
  margin-top: 6px; padding-top: 6px;
  border-top: 1px solid rgba(255,255,255,.06);
}
.bdesk-export-group-label{
  display: block;
  padding: 2px 12px 6px;
  font-family: var(--font-display);
  font-size:11px;
  font-weight:700;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: rgba(255,255,255,.42);
}
/* Opción = pill oscura. El degradado cyan→violeta es ESTADO, no default:
   mismo criterio que `.fp-dd-opt` (el dropdown de Moneda) y que los modales
   de Cajas/Plans — reposo oscuro, hover blanco sutil, degradado sólo para la
   opción seleccionada.

   ⚠️ REVERSIÓN 2026-08-17. Hasta hoy esta regla pintaba Excel/CSV con
   degradado PERMANENTE y decía "pedido explícito: las opciones Excel/CSV son
   botones degradados, no pills oscuras". Esa decisión queda revertida por
   pedido explícito de hoy. Si alguien vuelve a ver degradado en reposo, es
   una regresión — no el diseño original.

   Sólo se conserva la DENSIDAD de la variante; los colores los pone la regla
   base `.bdesk-export-link` (más arriba), que ya era esta pill oscura y hasta
   hoy quedaba pisada.

   ⚠️ Esta regla NO debe declarar `background` — ni siquiera `transparent`.
   `.bdesk-export-menu--grouped .bdesk-export-link` y `.bdesk-export-link:hover`
   tienen la MISMA especificidad (0,2,0), y ésta va después en el archivo: si
   pone un background, gana también en hover y el hover deja de verse. Medido:
   con `background:transparent` acá, reposo y hover daban el mismo color
   computado en los 6 módulos.

   Aplica a TODOS los módulos que usan el componente: Finanzas, CxC, CxP, P2P,
   Trading y Cajas, más Inventario (detrás de su feature flag). La lista vieja
   decía "Inventario" y no "Cajas": era anterior al export de Cajas. */
.bdesk-export-menu--grouped .bdesk-export-link{
  min-height: 38px;
  padding: 0 14px;
  gap: 9px;
  font-size:13px;
  font-weight:700;
  border-radius: 999px;
}
.bdesk-export-menu--grouped .bdesk-export-link + .bdesk-export-link{ margin-top: 6px; }
.bdesk-export-menu--grouped .bdesk-export-link svg{
  width: 14px; height: 14px; flex: 0 0 14px;
  opacity: .75; color: currentColor;   /* seguía el texto oscuro del degradado */
}

/* Hover/focus NO se re-declara acá a propósito: lo da la regla base
   `.bdesk-export-link:hover` (background rgba(255,255,255,.06) + borde
   sutil). Duplicarlo era lo que obligaba a los `!important` que se fueron
   con esta reversión. */

/* Estado seleccionado/actual: acá SÍ va el degradado — es el indicador
   semántico de "opción actual", no feedback de interacción.
   ⚠️ Hoy es INALCANZABLE: nada setea `is-active` en un link de export (son
   <a> que navegan y descargan). Se conserva para cuando exista un "último
   formato usado"; si se quita, hay que quitarlo también de `.fp-dd-opt` para
   no partir la regla del design system. */
.bdesk-export-menu--grouped .bdesk-export-link.is-active{
  background: linear-gradient(135deg, #22d3ee, #a855f7);
  color: #071018;
  border-color: transparent;
  opacity: 1;
}
.bdesk-export-menu--grouped .bdesk-export-link.is-active svg{ opacity: 1; color: #071018; }

/* ─────────────────────────────────────────────────────────────
   Tooltip global rápido (premium dark cyan/violet). Se activa con
   el atributo [data-tip]; un script en base_user.html mueve
   title→data-tip en botones de acción (icon-only, export, etc.)
   para reemplazar el tooltip nativo lento (~500ms). aria-label se
   conserva para accesibilidad. Aparición ~140ms con leve delay;
   salida inmediata, sin parpadeo.
   ───────────────────────────────────────────────────────────── */
[data-tip]{ position: relative; }
[data-tip]::after{
  content: attr(data-tip);
  position: absolute;
  bottom: calc(100% + 7px);
  left: 50%;
  transform: translateX(-50%) translateY(3px);
  white-space: nowrap;
  background: rgba(10,14,22,.97);
  color: rgba(255,255,255,.94);
  border: 1px solid rgba(255,255,255,.12);
  border-radius: 10px;
  padding: 6px 9px;
  font-family: var(--font-display, inherit);
  font-size:13px;
  font-weight: 700;
  letter-spacing: .01em;
  line-height: 1;
  box-shadow: 0 10px 26px rgba(0,0,0,.40);
  pointer-events: none;
  z-index: 300;
  /* display:none y no solo opacity:0. Con opacity el tooltip queda MAQUETADO
     aunque sea invisible, así que un tooltip ancho extiende la región
     scrolleable de la página: el dashboard desbordaba +208px a 390px de
     viewport sin que nada se viera. `display .1s allow-discrete` conserva el
     fade de ~140ms pese al cambio de display; si el navegador no lo soporta,
     el tooltip aparece de golpe y el arreglo sigue en pie. */
  display: none;
  opacity: 0;
  transition: opacity .1s ease, transform .1s ease,
              display .1s allow-discrete;              /* salida rápida */
}
[data-tip]:hover::after,
[data-tip]:focus-visible::after{
  display: block;
  opacity: 1;
  transform: translateX(-50%) translateY(0);
  transition: opacity .13s ease .14s, transform .13s ease .14s,
              display .13s allow-discrete .14s;        /* aparición ~140ms */
}
/* Sin esto el tooltip entraría con opacity ya en 1 (no hay estado previo del
   que animar cuando el elemento pasa de display:none a block). */
@starting-style{
  [data-tip]:hover::after,
  [data-tip]:focus-visible::after{ opacity: 0; }
}
/* ── Anclaje a la derecha, para tooltips pegados al borde de la pantalla ──
   El tooltip se centra sobre su ancla (left:50% + translateX(-50%)). Si el
   ancla está contra el borde derecho, la mitad que sobresale EXTIENDE la
   región scrolleable mientras el tooltip se muestra. Medido en Cajas: +34px
   a 1280 y 390 al hacer hover sobre "Eliminar permanentemente", que es el
   último botón de la card. Es el mismo mecanismo que desbordó el dashboard.

   ⚠️ Achicar el tooltip NO alcanza: se probó `white-space:normal` +
   `max-width` y el overflow quedó igual en 34px. El problema es el ANCLAJE,
   no el ancho. Y `overflow-x: clip` en el contenedor lleva el número a 0
   pero CORTA el texto ("Eliminar permanenteme…"), o sea arregla la métrica
   rompiendo la función.

   Este modificador ancla el tooltip por su borde derecho: medido, deja el
   overflow en 0 a 1440/1280/390 y el texto entero. Se aplica a mano en el
   último botón de un grupo de acciones. */
[data-tip][data-tip-align="right"]::after{
  left: auto; right: 0;
  transform: translateX(0) translateY(3px);
}
[data-tip][data-tip-align="right"]:hover::after,
[data-tip][data-tip-align="right"]:focus-visible::after{
  transform: translateX(0) translateY(0);
}

/* ── Mensaje de validación propio (bdesk_validate.js) ──────────────────
   Reemplaza la burbuja nativa, que no tiene estilo de la app y está en
   inglés. Reusa el lenguaje visual de [data-tip] (mismo panel dark, radio,
   sombra y tipografía) con el borde en rojo del sistema.

   ⚠️ Va EN FLUJO debajo del campo, no flotando. Un panel flotante junto al
   borde derecho extiende el scroll horizontal mientras se muestra — es
   exactamente lo que hubo que arreglar con data-tip-align acá arriba. En
   flujo el problema no existe, y además el mensaje no se va al mover el
   mouse. */
.bdesk-invalid-msg{
  display: block;
  margin-top: 6px;
  background: rgba(10,14,22,.97);
  color: rgba(255,255,255,.94);
  border: 1px solid rgba(255,93,108,.45);
  border-radius: 10px;
  padding: 6px 9px;
  font-family: var(--font-display, inherit);
  font-size:13px;
  font-weight: 700;
  letter-spacing: .01em;
  line-height: 1.3;
  box-shadow: 0 10px 26px rgba(0,0,0,.40);
}
/* El campo en falta: borde rojo, sin mover nada de sitio. */
.is-invalid,
.fp-dd.is-invalid .fp-dd-btn{
  border-color: rgba(255,93,108,.55) !important;
  box-shadow: 0 0 0 2px rgba(255,93,108,.12) !important;
}

[data-tip=""]::after{ content: none; }
/* Sin tooltip en touch. Las tres ramas son necesarias: `[data-tip]:hover::after`
   (0,2,1) le gana a `[data-tip]::after` (0,1,1), y en los navegadores donde
   tocar activa :hover (iOS Safari) el tooltip volvería a aparecer — y con él,
   el scroll horizontal que este bloque evita. */
@media (hover: none){
  [data-tip]::after,
  [data-tip]:hover::after,
  [data-tip]:focus-visible::after{ display: none !important; }
}

/* Toasts */
.bdesk-toast-wrap{
  position: fixed;
  top: 16px;
  right: 16px;
  z-index: 99999;
  display: grid;
  gap: 10px;
  width: min(420px, calc(100vw - 24px));
}

.bdesk-toast{
  position: relative;
  display: grid;
  grid-template-columns: 1fr 30px;
  align-items: center;
  gap: 10px;
  padding: 12px 12px 12px 14px;
  border-radius: 16px;
  border: 1px solid rgba(255,255,255,.10);
  background: rgba(10,14,22,.92);
  color: rgba(255,255,255,.92);
  box-shadow: 0 18px 40px rgba(0,0,0,.45);
  backdrop-filter: blur(10px);
  overflow: hidden;
}

.bdesk-toast::before{
  content:"";
  position:absolute;
  left:0; top:0; bottom:0;
  width: 4px;
  background: linear-gradient(180deg, rgba(34,211,238,.95), rgba(168,85,247,.95));
  opacity: .95;
}

.bdesk-toast-warning::before{
  background: linear-gradient(180deg, rgba(251,191,36,.95), rgba(245,158,11,.95));
}

.bdesk-toast-error::before,
.bdesk-toast-danger::before{
  background: linear-gradient(180deg, rgba(248,113,113,.95), rgba(244,63,94,.95));
}

.bdesk-toast-msg{
  font-weight: 700;
  font-size:15px;
  line-height: 1.25;
  /* Permite una segunda línea en la MISMA notificación cuando el mensaje trae
     un salto (\n). Sin '\n' se comporta igual que antes (no regresión). */
  white-space: pre-line;
}

/* Link "Descargar plantilla" en el card-head de Importar (P2P y Trading).
   Compacto, acento cyan, no es CTA. Va a la derecha del título (card-head es
   flex space-between). */
.bdesk-plantilla-link{
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: var(--font-display);
  font-weight:700;
  font-size:13px;
  letter-spacing: .02em;
  color: rgba(34, 211, 238, .92);
  text-decoration: none;
  white-space: nowrap;
  transition: color .15s ease;
}
.bdesk-plantilla-link svg{ width: 14px; height: 14px; opacity: .9; }
.bdesk-plantilla-link:hover{ color: var(--cyan); text-decoration: underline; }
.bdesk-plantilla-link:focus-visible{
  outline: none;
  color: var(--cyan);
  text-decoration: underline;
}
/* Ayuda compacta de campos obligatorios/recomendados bajo el head de Importar.
   Una sola línea (wrap natural en angosto), no agranda la card. */
.bdesk-plantilla-hint{
  margin: 2px 0 0;
  font-size:13px;
  line-height: 1.45;
  color: rgba(255,255,255,.55);
}
.bdesk-plantilla-hint b{ color: rgba(255,255,255,.82); font-weight:700; }

/* =========================================================
   HISTORIAL DE IMPORTACIONES (Fase 3C) — clases genéricas,
   reutilizables por cualquier módulo (P2P ahora; Trading luego).
   La tabla scrollea dentro de .pro-table-wrap (no overflow de página).
   ========================================================= */
.import-history-table{ font-size:13px; }
.import-history-table th,
.import-history-table td{ white-space: nowrap; vertical-align: middle; }
.import-history-table .ih-num{ text-align: center; font-variant-numeric: tabular-nums; }
.import-history-table .ih-nowrap{ white-space: nowrap; }
.import-history-table .ih-estado{ text-align: center; }
.import-history-table .ih-actions{ text-align: right; }

.import-history-file{
  max-width: 220px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-weight: 700;
}
.import-history-hash{
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size:11px;
  color: rgba(255,255,255,.42);
  margin-top: 2px;
}

.import-history-estado{
  display: inline-block;
  font-size:11px;
  font-weight:700;
  letter-spacing: .03em;
  border-radius: 999px;
  padding: 3px 10px;
  white-space: nowrap;
}
.import-history-estado.estado-ok{
  color: rgba(34,211,238,.95);
  background: rgba(34,211,238,.10);
  border: 1px solid rgba(34,211,238,.28);
}
.import-history-estado.estado-warn{
  color: rgba(251,191,36,.95);
  background: rgba(251,191,36,.10);
  border: 1px solid rgba(251,191,36,.28);
}
.import-history-estado.estado-neutral{
  color: rgba(255,255,255,.7);
  background: rgba(255,255,255,.06);
  border: 1px solid rgba(255,255,255,.14);
}

/* "Ver errores" (Fase 3D): acción de tabla, ghost dark con hover cyan. */
.import-history-errs{
  font-family: var(--font-display);
  font-size:13px;
  font-weight:700;
  border-radius: 999px;
  padding: 5px 12px;
  border: 1px solid rgba(255,255,255,.12);
  background: rgba(0,0,0,.18);
  color: rgba(255,255,255,.72);
  cursor: pointer;
  white-space: nowrap;
  transition: color .15s ease, border-color .15s ease, background .15s ease;
}
.import-history-errs:hover{
  color: var(--cyan);
  border-color: rgba(34,211,238,.45);
  background: rgba(34,211,238,.08);
}
.import-history-errs:focus-visible{
  outline: none;
  border-color: rgba(34,211,238,.55);
  color: var(--cyan);
}
.import-history-errs:disabled{ opacity: .55; cursor: not-allowed; }

.import-history-empty{
  padding: 18px 4px;
  text-align: center;
  font-weight: 700;
  color: rgba(255,255,255,.55);
}

/* Detalle de errores por fila (Fase 3D) — modal compacto, reutilizable. */
.import-errors-list{
  max-height: 300px;
  overflow: auto;
  margin-bottom: 8px;
}
.import-errors-subtitle{
  font-size:11px;
  font-weight:700;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: rgba(255,255,255,.55);
  margin: 12px 0 6px;
}
.import-errors-subtitle:first-child{ margin-top: 0; }
.import-errors-item{
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 10px;
  padding: 8px 10px;
  border: 1px solid rgba(255,255,255,.08);
  background: rgba(0,0,0,.18);
  border-radius: 10px;
  margin-bottom: 6px;
}
.import-errors-reason{
  font-size:13px;
  font-weight: 700;
  color: rgba(255,255,255,.9);
  min-width: 0;
  word-break: break-word;
}
.import-errors-count{
  flex: 0 0 auto;
  font-size:13px;
  font-weight:700;
  color: rgba(251,191,36,.95);
}
.import-errors-msg{
  font-size:13px;
  font-weight: 700;
  color: rgba(255,255,255,.85);
  border: 1px solid rgba(255,255,255,.1);
  background: rgba(0,0,0,.18);
  border-radius: 12px;
  padding: 12px 14px;
}
.import-errors-more{
  font-size:13px;
  color: rgba(255,255,255,.55);
  font-weight: 700;
  text-align: center;
  padding-top: 4px;
}

.bdesk-toast-close{
  width: 30px;
  height: 30px;
  border-radius: 10px;
  border: 1px solid rgba(255,255,255,.10);
  background: rgba(255,255,255,.04);
  color: rgba(255,255,255,.85);
  cursor: pointer;
}

.bdesk-toast-close:hover{
  background: rgba(255,255,255,.08);
}

.bdesk-toast.is-hide{
  opacity: 0;
  transform: translateY(-6px);
  transition: .18s ease;
}

/* Flash PRO */
.flash{
  border: 1px solid rgba(255,255,255,.12);
  background: rgba(10,14,22,.72);
  backdrop-filter: blur(10px);
}

/* Ícono del aviso. Los colores por variante ya estaban (abajo); faltaba la
   GEOMETRÍA, porque ningún markup lo usaba. Con el ícono, los tipos de aviso
   se distinguen por FORMA y no sólo por color (borde al 22%: 1.2–1.6:1
   contra el fondo de un modal, medido 2026-10-15). */
.flash-ico{
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  border-radius: 8px;
  border: 1px solid rgba(255,255,255,.12);
  background: rgba(255,255,255,.06);
  color: rgba(255,255,255,.80);
}
.flash-ico .bd-ico{ width: 14px; height: 14px; }

.flash-success{
  border-color: var(--ok-border);
}
.flash-success .flash-ico{
  background: var(--ok-bg);
  border-color: var(--ok-border);
  color: var(--ok);
}

.flash-warning{
  border-color: rgba(251,191,36,.22);
}
.flash-warning .flash-ico{
  background: rgba(251,191,36,.10);
  border-color: rgba(251,191,36,.22);
  color: rgba(251,191,36,.95);
}

.flash-error, .flash-danger{
  border-color: rgba(244,63,94,.22);
}
.flash-error .flash-ico, .flash-danger .flash-ico{
  background: rgba(244,63,94,.10);
  border-color: rgba(244,63,94,.22);
  color: rgba(244,63,94,.95);
}

.flash-info{
  border-color: rgba(168,85,247,.22);
}
.flash-info .flash-ico{
  background: rgba(168,85,247,.10);
  border-color: rgba(168,85,247,.22);
  color: rgba(168,85,247,.95);
}

/* =========================================================
   BDESK-SECTION — patrón único de bloque expandible/colapsable
   Referencia: .p2p-section-* en p2p.html.
   Uso global: Trading, P2P, Finanzas, CxC, CxP.

   Estructura:
     <div class="card pro-card bdesk-section-card">
       <div class="pro-card-head bdesk-section-head">
         <h2 class="pro-card-title">Título</h2>
         <button class="bdesk-section-toggle"
                 data-target="#miBody"
                 data-store="clave_open">Mostrar</button>
       </div>
       <div class="bdesk-section-body is-hidden" id="miBody">...</div>
     </div>

   JS: los módulos deben inicializar con un helper initToggle(btnSel)
   que lea data-target + data-store y alterne .is-hidden + .is-active
   + textContent "Mostrar"/"Ocultar". Ver p2p.html#initToggle para la
   implementación canónica.
   ========================================================= */
.bdesk-section-card{
  margin-top:14px;
}

.bdesk-section-head{
  display:flex !important;
  align-items:center !important;
  justify-content:space-between !important;
  gap:12px !important;
  flex-wrap:wrap !important;
  padding-bottom:4px !important;
}

.bdesk-section-body.is-hidden{
  display:none !important;
}

/* Toggle "Mostrar / Ocultar" (fase 3a, 05/10/2026). Antes era un CTA con
   gradiente, emoji 📊 y mayúsculas, repetido 3–4 veces por pantalla: competía
   con "Nuevo …" y "Filtrar", que son las acciones reales. Ahora es un control
   discreto (contorno) con una flecha que gira al abrir; el gradiente queda
   solo para la acción principal de cada zona. */
.bdesk-section-toggle,
.fp.p2p .p2p-section-toggle{
  height:44px !important;
  min-width:0 !important;
  padding:0 14px 0 16px !important;
  border-radius:12px !important;
  border:1px solid var(--stroke) !important;
  background:rgba(255,255,255,.03) !important;
  color:rgba(255,255,255,.86) !important;
  box-shadow:none !important;
  font-weight:600 !important;
  font-size:13px !important;
  letter-spacing:0 !important;
  text-transform:none !important;
  cursor:pointer !important;
  display:inline-flex !important;
  align-items:center !important;
  justify-content:center !important;
  gap:8px !important;
  transition:background .2s ease, border-color .2s ease, color .2s ease !important;
}
.bdesk-section-toggle::before{ content:none; }
.bdesk-section-toggle::after,
.fp.p2p .p2p-section-toggle::after{
  content:"";
  width:8px; height:8px;
  border-right:2px solid currentColor; border-bottom:2px solid currentColor;
  transform:translateY(-2px) rotate(45deg);
  transition:transform .25s cubic-bezier(.22,1,.36,1);
  opacity:.8;
}
.bdesk-section-toggle:hover,
.fp.p2p .p2p-section-toggle:hover{
  background:rgba(255,255,255,.07) !important;
  border-color:rgba(34,211,238,.35) !important;
  transform:none;
  filter:none;
}
.bdesk-section-toggle.is-active,
.fp.p2p .p2p-section-toggle.is-active{
  border-color:rgba(34,211,238,.45) !important;
  color:var(--cyan) !important;
  box-shadow:none !important;
}
.bdesk-section-toggle.is-active::after,
.fp.p2p .p2p-section-toggle.is-active::after{ transform:translateY(2px) rotate(-135deg); }
@media (prefers-reduced-motion: reduce){
  .bdesk-section-toggle::after, .fp.p2p .p2p-section-toggle::after{ transition:none; }
}

/* Pill contador al lado del título del card (ops count, etc.) */
.bdesk-count-pill{
  display:inline-flex;
  align-items:center;
  justify-content:center;
  min-width:30px;
  height:24px;
  padding:0 10px;
  border-radius:999px;
  background:rgba(34,211,238,.12);
  border:1px solid rgba(34,211,238,.28);
  color:rgba(125,211,252,.98);
  font-size:13px;
  font-weight:700;
  font-variant-numeric:tabular-nums;
  letter-spacing:.02em;
}

/* Aviso de conjunto TRUNCADO (macro templates/_trunc_notice.html). Ámbar, como la
   pill de período fuera del default: el significado es "atención, lo que ves es
   parcial". Global porque lo usan Finanzas y el Dashboard. */
.bdesk-trunc-notice{
  display:flex;
  align-items:flex-start;
  gap:9px;
  margin:0 0 14px;
  padding:11px 14px;
  border-radius:12px;
  background:rgba(245,158,11,.12);
  border:1px solid rgba(245,158,11,.42);
  color:rgba(253,230,138,.98);
  font-size:13px;
  font-weight:600;
  line-height:1.45;
}
.bdesk-trunc-notice-ico{ flex:0 0 auto; font-size:13px; line-height:1.45; }
.bdesk-trunc-notice-txt{ min-width:0; }
.bdesk-trunc-notice b{
  font-weight:700;
  color:#fde68a;
  font-variant-numeric:tabular-nums;
}

/* Pie de paginación: rango de filas ("701–800 de 2218"). Jerarquía deliberada —
   los NÚMEROS son el dato y llevan el peso; "de" es una preposición y se apaga.
   Antes el total ("2218 ops") iba en gris muted y se perdía, cuando es justamente
   lo que el usuario quiere saber. Global (no por módulo): Trading tiene el mismo
   pie y debería reusar esto. */
.bdesk-pag-range{
  display:inline-flex;
  align-items:baseline;
  gap:6px;
  font-size:13px;
  color:rgba(226,232,240,.96);
  font-variant-numeric:tabular-nums;
  white-space:nowrap;
}
.bdesk-pag-range b,
.bdesk-pag-max{
  font-weight:700;
  color:rgba(241,245,249,.99);
  font-variant-numeric:tabular-nums;
}
.bdesk-pag-sep{
  font-weight:600;
  font-size:13px;
  color:rgba(148,163,184,.72);
}

/* Pill del PERÍODO ACTIVO (macro templates/_period_chip.html). Siempre visible.
   Neutra = el período es el default del módulo. Ámbar = NO lo es: el usuario
   está mirando datos de otro período y necesita saberlo. Ni cyan ni violeta:
   esos leen como "activo/primario" y acá el significado es "atención". */
.bdesk-period-chip{
  display:inline-flex;
  align-items:center;
  gap:7px;
  margin-top:8px;
  padding:5px 11px;
  border-radius:999px;
  background:rgba(148,163,184,.10);
  border:1px solid rgba(148,163,184,.22);
  color:rgba(203,213,225,.90);
  font-size:13px;
  font-weight:600;
  line-height:1.2;
  max-width:100%;
  min-width:0;
}
.bdesk-period-chip-txt{
  min-width:0;
  overflow:hidden;
  text-overflow:ellipsis;
  white-space:nowrap;
}
.bdesk-period-chip-txt strong{ font-weight:700; color:rgba(226,232,240,.98); }
.bdesk-period-chip-ico{ font-size:13px; line-height:1; flex:0 0 auto; }

.bdesk-period-chip.is-alert{
  background:rgba(245,158,11,.12);
  border-color:rgba(245,158,11,.42);
  color:rgba(253,230,138,.98);
}
.bdesk-period-chip.is-alert .bdesk-period-chip-txt strong{ color:#fde68a; }

.bdesk-period-chip-reset{
  flex:0 0 auto;
  padding:2px 9px;
  border-radius:999px;
  background:rgba(245,158,11,.16);
  border:1px solid rgba(245,158,11,.40);
  color:#fde68a;
  font-size:11px;
  font-weight:700;
  text-decoration:none;
  white-space:nowrap;
  transition:background .14s ease, border-color .14s ease;
}
.bdesk-period-chip-reset:hover{
  background:rgba(245,158,11,.26);
  border-color:rgba(245,158,11,.62);
}

/* Mobile: el contenido envuelve a varias líneas y el radio de 999px deforma la
   cápsula. Al envolver deja de ser pill y pasa a ser una tarjetita. */
@media (max-width: 640px){
  .bdesk-period-chip{
    display:flex;
    flex-wrap:wrap;
    align-items:flex-start;
    gap:4px 7px;
    border-radius:12px;
    padding:8px 11px;
  }
  .bdesk-period-chip-txt{ white-space:normal; overflow:visible; }
  .bdesk-period-chip-ico{ margin-top:2px; }
  .bdesk-period-chip-reset{ margin-top:2px; }
}

/* Pill NEUTRA para marcar datos que no responden a los filtros de la página
   (ej: "Estado actual" en capital en posición). Deliberadamente apagada: el
   cian de .bdesk-count-pill lee como "activo/primario" y acá significa lo
   contrario — este dato ignora el filtro. */
.bdesk-state-pill{
  display:inline-flex;
  align-items:center;
  gap:5px;
  height:20px;
  padding:0 8px;
  border-radius:999px;
  background:rgba(148,163,184,.10);
  border:1px solid rgba(148,163,184,.24);
  color:rgba(203,213,225,.92);
  font-size:11px;
  font-weight:700;
  letter-spacing:.03em;
  text-transform:uppercase;
  white-space:nowrap;
}

/* =========================================================================
   SWITCH (toggle de "Cargar en otra moneda" y similares) — fuente única
   HTML esperado:
     <div class="fp-switch-field">
       <label>Texto del campo</label>
       <label class="fp-switch">
         <input type="checkbox" name="...">
         <span class="fp-switch-slider"></span>
       </label>
     </div>
   Box model: el slider usa border-box (50x28 incluye el border de 1px).
   Knob: 22x22, top:3px (centrado vertical: (28-22)/2=3).
   ON: translateX(20px) — left:3 + 20 + width:22 + right:3 + 2 border = 50.
   ========================================================================= */
.fp-switch-field{
  display:flex;
  flex-direction:column;
  gap:10px;
  min-width:0;
}

.fp-switch{
  position:relative;
  width:100%;
  height:52px;
  border-radius:999px;
  border:1px solid rgba(255,255,255,.12);
  background:rgba(0,0,0,.18);
  display:flex;
  align-items:center;
  justify-content:center;
  cursor:pointer;
  box-sizing:border-box;
  user-select:none;
  transition:border-color .15s ease, background .15s ease, box-shadow .15s ease;
}
.fp-switch:hover{
  border-color:rgba(255,255,255,.18);
  background:rgba(0,0,0,.22);
}

.fp-switch input{
  position:absolute;
  opacity:0;
  width:1px;
  height:1px;
  pointer-events:none;
}

.fp-switch-slider{
  position:relative;
  width:50px;
  height:28px;
  border-radius:999px;
  background:rgba(255,255,255,.12);
  border:1px solid rgba(255,255,255,.14);
  box-sizing:border-box;
  flex:0 0 auto;
  transition:background .15s ease, border-color .15s ease;
}

.fp-switch-slider::after{
  content:"";
  position:absolute;
  top:3px;
  left:3px;
  width:22px;
  height:22px;
  border-radius:999px;
  background:rgba(0,0,0,.45);
  transform:translateX(0);
  transition:transform .15s ease, background .15s ease;
}

.fp-switch input:checked + .fp-switch-slider{
  background:linear-gradient(135deg, rgba(34,211,238,.75), rgba(168,85,247,.75));
  border-color:rgba(34,211,238,.35);
}

.fp-switch input:checked + .fp-switch-slider::after{
  transform:translateX(20px);
  background:rgba(0,0,0,.25);
}

.fp-switch.is-on{
  border-color:rgba(34,211,238,.35);
  box-shadow:0 0 0 3px rgba(34,211,238,.10), 0 0 0 6px rgba(168,85,247,.08);
  background:rgba(0,0,0,.22);
}
/* =========================================================================
   TOTALES POR MONEDA — componente reutilizable (Fase 2)
   Strip compacto bajo los KPIs. Solo presenta totales por moneda (sin sumar
   monedas distintas). Reusa tokens del design system (cyan/violet, --stroke).
   El colapso responsive + "+N más" los maneja bdesk_money_summary.js.
   ========================================================================= */
.bdesk-ccy-summary{
  display:flex;
  align-items:center;
  flex-wrap:wrap;
  gap:10px 12px;
  margin-top:12px;
  min-width:0;
}
.bdesk-ccy-summary-label{
  font-family:"Baloo 2", system-ui;
  font-weight:700;
  font-size:11px;
  letter-spacing:.16em;
  text-transform:uppercase;
  color:var(--muted, rgba(255,255,255,.65));
  flex:0 0 auto;
}
.bdesk-ccy-chips{
  display:flex;
  align-items:center;
  flex-wrap:wrap;
  gap:8px;
  min-width:0;
}
.bdesk-ccy-chip{
  display:inline-flex;
  align-items:baseline;
  gap:6px;
  padding:6px 12px;
  border-radius:999px;
  border:1px solid var(--stroke, rgba(255,255,255,.10));
  background:rgba(255,255,255,.05);
  font-variant-numeric:tabular-nums;
  white-space:nowrap;
}
.bdesk-ccy-chip .bdesk-ccy-amt{
  font-family:"Baloo 2", system-ui;
  font-weight:700;
  font-size:15px;
  color:rgba(255,255,255,.95);
}
.bdesk-ccy-chip .bdesk-ccy-code{
  font-style:normal;
  font-weight:700;
  font-size:11px;
  letter-spacing:.06em;
  color:var(--muted, rgba(255,255,255,.6));
}
/* La moneda base/valuación: borde gradiente cyan/violeta (acento del sistema). */
.bdesk-ccy-chip.is-base{
  border-color:transparent;
  background:
    linear-gradient(rgba(10,16,24,.92), rgba(10,16,24,.92)) padding-box,
    linear-gradient(135deg, #22d3ee, #a855f7) border-box;
}
.bdesk-ccy-chip.is-base .bdesk-ccy-code{
  color:rgba(125,211,252,.95);
}

/* "+N más" / "Ver menos" — pill estilo bdesk-count-pill. */
.bdesk-ccy-more{
  display:inline-flex;
  align-items:center;
  justify-content:center;
  height:30px;
  padding:0 12px;
  border-radius:999px;
  background:rgba(34,211,238,.12);
  border:1px solid rgba(34,211,238,.28);
  color:rgba(125,211,252,.98);
  font-family:"Baloo 2", system-ui;
  font-weight:700;
  font-size:13px;
  letter-spacing:.02em;
  cursor:pointer;
  transition:background .12s ease, border-color .12s ease, transform .12s ease;
}
.bdesk-ccy-more:hover{
  background:rgba(34,211,238,.18);
  transform:translateY(-1px);
}

@media (max-width:560px){
  .bdesk-ccy-summary{ width:100%; }
  .bdesk-ccy-summary-label{ flex:1 0 100%; }
  .bdesk-ccy-chips{ width:100%; }
  .bdesk-ccy-chip{ flex:1 1 auto; justify-content:center; }
}

/* =========================================================================
   DROPDOWN CUSTOM (.fp-dd) — NÚCLEO GLOBAL DEL DESIGN SYSTEM
   -------------------------------------------------------------------------
   Dueño único del componente que reemplaza al <select> nativo (que no se
   puede estilar: se ve azul/plano del browser, fuera del dark theme).

   ⚠️ ORIGEN: estas reglas son las de modules/finanzas.css:217-264, copiadas
   SIN cambios de valor. finanzas.css venía actuando como stylesheet global
   de facto (base_admin.html lo carga para TODO /admin). Se promueven acá
   para que el componente sea portable y para que los módulos puedan dejar
   de redefinirlo (fase 3: hay ~250 selectores .fp-dd duplicados en 8 CSS
   de módulo).

   ⚠️ NO llevan !important a propósito. components.css carga ANTES que los
   CSS de módulo en las 3 bases, así que los overrides de finanzas/p2p/
   trading/cxc/cxp/inventario siguen ganando. Agregar este bloque es
   no-destructivo: ningún .fp-dd existente cambia de aspecto.
   ========================================================================= */

/* Base del control. .fp-dd-btn la usa como cimiento, igual que los inputs
   de filtro — por eso vive acá y no dentro de .fp-dd. */
.fp-pill {
  width:100%; height:48px; border-radius:999px;
  border:1px solid rgba(255,255,255,.12); background:rgba(0,0,0,.18); color:#fff;
  padding:0 16px; backdrop-filter:blur(10px);
  font-family:"Baloo 2",system-ui,-apple-system,Segoe UI,Roboto,Arial,sans-serif;
  font-weight:700; font-size:15px; text-align:center;
  outline:none; cursor:pointer; transition:all .15s ease;
}
.fp-pill:hover { border-color:rgba(255,255,255,.18); background:rgba(0,0,0,.22); }
.fp-pill:focus { border-color:rgba(34,211,238,.45); box-shadow:0 0 0 3px rgba(34,211,238,.12); }
.fp-pill::placeholder { opacity:.7; font-weight:700; }

.fp-dd { position:relative; }

.fp-dd-btn {
  font-family:"Baloo 2",system-ui,-apple-system,Segoe UI,Roboto,Arial,sans-serif;
  font-weight:700; justify-content:center; position:relative; padding-right:44px;
}
.fp-dd-btn [data-dd-label] {
  display:block; width:100%; text-align:center;
  overflow:hidden; white-space:nowrap; text-overflow:ellipsis; min-width:0;
}
/* Placeholder: el valor todavía no fue elegido. Lo pone/saca bdesk_dd.js. */
.fp-dd-btn.is-empty [data-dd-label] { color:rgba(255,255,255,.52); }
.fp-dd-btn .fp-caret {
  position:absolute; right:16px; top:50%; transform:translateY(-50%);
  font-size:13px; opacity:.85;
}

/* ⚠️ PANEL OPACO — no es cosmético.
   El menú flota sobre contenido denso: los campos de un modal, las filas de
   una tabla. Con un fondo translúcido y sin backdrop-filter, los labels de
   atrás se leen A TRAVÉS del panel y la pantalla parece desalineada. Era el
   síntoma del modal de Cajas ("se ve transparentado").
   Los tres lugares que ya lo tenían resuelto —admin/users, admin/audit y el
   modal de Finanzas— convergieron en lo mismo: gradiente casi opaco. Esto lo
   unifica en el núcleo. La sombra sigue siendo el token --shadow, que ya era
   equivalente a la que usaban esos tres. */
.fp-dd-menu {
  position:absolute; top:calc(100% + 10px); left:0; width:100%;
  overflow:hidden; z-index:120;
  background:linear-gradient(180deg,rgba(7,14,24,.985),rgba(4,9,18,.985));
  backdrop-filter:blur(14px); -webkit-backdrop-filter:blur(14px);
  border:1px solid rgba(255,255,255,.12);
  border-radius:18px; padding:10px; box-shadow:var(--shadow); display:none;
}
.fp-dd-menu.is-open { display:block; }

.fp-dd-opt {
  width:100%; overflow:hidden; white-space:nowrap; text-overflow:ellipsis;
  border:0; background:transparent; color:#fff;
  font-family:"Baloo 2",system-ui,-apple-system,Segoe UI,Roboto,Arial,sans-serif;
  font-weight:700; border-radius:999px; padding:10px 12px;
  text-align:left; cursor:pointer; opacity:.9;
}
.fp-dd-opt:hover { background:rgba(255,255,255,.06); opacity:1; }
/* Opción activa = pill gradiente cyan/violeta (regla del design system). */
.fp-dd-opt.is-active { background:linear-gradient(135deg,#22d3ee,#a855f7); color:#071018; opacity:1; }
/* Navegación por teclado: visible sin depender de :focus (las opts van
   outline:none, así que sin esto el foco se movía pero no se veía). */
.fp-dd-opt.is-focus { background:rgba(34,211,238,.10); color:rgba(34,211,238,.98); opacity:1; }
.fp-dd-opt.is-hidden { display:none; }

/* =========================================================================
   fp-dd SEARCHABLE — fallback global de búsqueda/free-entry.
   Las clases fp-dd-menu/opt ya están estiladas por el CSS de cada módulo;
   acá solo agregamos el search box, la lista scrolleable y el botón "Usar X"
   para los módulos que no los traen (CxC/CxP). Finanzas los sobre-escribe con
   su propio módulo (carga después). Usado por bdesk_searchable_dd.js.
   ========================================================================= */
.fp-dd-menu .fp-dd-opts{ display:flex; flex-direction:column; gap:4px; max-height:240px; overflow:auto; }
.fp-dd-search{ margin-bottom:8px; }
.fp-dd-search input{
  width:100%;
  height:38px;
  padding:0 12px;
  border-radius:10px;
  border:1px solid rgba(255,255,255,.12);
  background:rgba(255,255,255,.04);
  color:rgba(255,255,255,.92);
  font-family:"Baloo 2", system-ui;
  font-weight:700;
  font-size:15px;
  outline:none;
}
.fp-dd-search input:focus{ border-color:rgba(34,211,238,.45); box-shadow:0 0 0 2px rgba(34,211,238,.12); }
.fp-dd-create{
  width:100%;
  margin-top:6px;
  border:1px dashed rgba(34,211,238,.35);
  background:rgba(34,211,238,.08);
  color:rgba(125,211,252,.98);
  font-family:"Baloo 2", system-ui;
  font-weight:700;
  font-size:13px;
  border-radius:10px;
  padding:9px 12px;
  text-align:left;
  cursor:pointer;
}
.fp-dd-create:hover{ background:rgba(34,211,238,.14); }

/* KPI multimoneda: con >1 moneda NO se suma. Se muestra la CANTIDAD como valor
   principal (número grande, neutro) y "{unidad} · varias monedas" en el footer.
   Los importes reales por moneda van en el strip "Saldo/Resultado por moneda". */
.kpi-value.kpi-value-count{
  color: rgba(255,255,255,.92);
}

/* Mini-card del strip "Saldo/Resultado por moneda" (Finanzas/CxC/CxP).
   Contenedor sutil e integrado (no usa la sombra fuerte de .pro-card). */
.bdesk-ccy-card{
  border:1px solid var(--stroke, rgba(255,255,255,.10));
  background:rgba(255,255,255,.03);
  border-radius:14px;
  padding:12px 16px;
}
.bdesk-ccy-card .bdesk-ccy-summary{ margin-top:0; }

/* Flip-up del dropdown searchable (bdesk_searchable_dd.js): cuando no hay
   espacio abajo, el menú abre hacia arriba para no cortarse ni salir del modal. */
[data-sdd].bdesk-sdd-up [data-dd-menu]{
  top:auto !important;
  bottom:calc(100% + 8px) !important;
}

/* =========================================================================
   DETALLE POR MONEDA (card multi-métrica) — Finanzas/CxC/CxP/Dashboard.
   Desktop: una card por moneda en grid (auto-fit). Mobile: apiladas.
   Excluye la moneda principal (va en los KPIs). Colapsable "Ver detalle".
   ========================================================================= */
.bdesk-ccy-detail{
  border:1px solid var(--stroke, rgba(255,255,255,.10));
  background:rgba(255,255,255,.03);
  border-radius:14px;
  padding:12px 16px;
}
.bdesk-ccy-detail-head{
  display:flex; align-items:center; justify-content:space-between; gap:12px;
}
.bdesk-ccy-detail-title{
  font-family:"Baloo 2", system-ui; font-weight:700; font-size:11px;
  letter-spacing:.16em; text-transform:uppercase; color:var(--muted, rgba(255,255,255,.65));
}
.bdesk-ccy-detail-toggle{
  height:30px; padding:0 14px; border-radius:999px;
  background:rgba(34,211,238,.12); border:1px solid rgba(34,211,238,.28);
  color:rgba(125,211,252,.98); font-family:"Baloo 2", system-ui; font-weight:700;
  font-size:13px; cursor:pointer; transition:background .12s ease, transform .12s ease;
}
.bdesk-ccy-detail-toggle:hover{ background:rgba(34,211,238,.18); transform:translateY(-1px); }
.bdesk-ccy-detail-body{ margin-top:12px; }
.bdesk-ccy-detail-body.is-hidden{ display:none; }
.bdesk-ccy-detail-grid{
  display:grid;
  grid-template-columns:repeat(auto-fit, minmax(180px, 1fr));
  gap:10px;
}
.bdesk-ccy-detail-card{
  border:1px solid var(--stroke, rgba(255,255,255,.10));
  background:rgba(255,255,255,.04);
  border-radius:12px;
  padding:10px 12px;
  min-width:0;
}
.bdesk-ccy-detail-code{
  font-family:"Baloo 2", system-ui; font-weight:700; font-size:13px;
  letter-spacing:.04em; color:rgba(125,211,252,.95); margin-bottom:6px;
}
.bdesk-ccy-detail-row{
  display:flex; align-items:baseline; justify-content:space-between; gap:10px; padding:3px 0;
}
.bdesk-ccy-detail-row span{ color:var(--muted, rgba(255,255,255,.6)); font-size:13px; }
/* Color semántico SUTIL en el label/indicador (el valor queda blanco). */
.bdesk-ccy-detail-row span.tone-cyan{   color:rgba(34,211,238,.95);   font-weight:700; }
.bdesk-ccy-detail-row span.tone-violet{ color:rgba(168,85,247,.95);   font-weight:700; }
.bdesk-ccy-detail-row span.tone-amber{  color:#fbbf24;                font-weight:700; }
.bdesk-ccy-detail-row span.tone-red{    color:var(--danger, #ff5d6c); font-weight:700; }
.bdesk-ccy-detail-row strong{
  font-variant-numeric:tabular-nums; color:rgba(255,255,255,.95);
  font-weight:700; font-size:13px; white-space:nowrap;
}
@media (max-width:560px){ .bdesk-ccy-detail-grid{ grid-template-columns:1fr; } }

/* ─────────────────────────────────────────────────────────────────────
   Empty state unificado (Fase A — design system)
   Mensaje de "no hay datos" consistente en todos los módulos. Sirve tanto
   como bloque (<p>/<div> cuando se reemplaza una tabla entera) como celda
   (<td colspan=N> dentro de una tabla vacía). Reemplaza los estilos inline
   ad-hoc (class="muted" style="padding:16px") que estaban dispersos.
   ───────────────────────────────────────────────────────────────────── */
.empty-state{
  padding:16px;
  text-align:center;
  color:rgba(255,255,255,.58);
  font-weight:700;
  font-size:13px;
  margin:0;
}
td.empty-state{ padding:18px 12px; }

/* =========================================================================
   EMPTY STATE inteligente — componente global (onboarding Fase 2).
   Título + texto + acciones; reusa btn-pro. Sin ilustraciones ni overlays.
   Uso:
     <div class="bdesk-empty">
       <div class="bdesk-empty-title">…</div>
       <p class="bdesk-empty-text">…</p>
       <div class="bdesk-empty-actions"><button class="btn-pro …">…</button></div>
     </div>
   ========================================================================= */
.bdesk-empty{
  display:flex;
  flex-direction:column;
  align-items:center;
  text-align:center;
  gap:8px;
  padding:38px 20px;
}
.bdesk-empty-title{
  font-size:15px;
  font-weight:700;
  color:rgba(255,255,255,.92);
}
.bdesk-empty-text{
  margin:0;
  font-size:13px;
  font-weight:600;
  color:rgba(255,255,255,.55);
  line-height:1.55;
  max-width:440px;
}
.bdesk-empty-actions{
  display:flex;
  gap:10px;
  margin-top:10px;
  flex-wrap:wrap;
  justify-content:center;
}

/* ===============================================================
   Analytics bloqueado (plan Gratis) — KPIs/gráficos con overlay
   difuminado + candado + badge del plan requerido + CTA "Ver planes".
   Reutiliza el lenguaje visual del candado del dashboard; scopeado a
   los módulos .fp (Finanzas / CxP / CxC).
   =============================================================== */
.fp .analytics-locked{
  position: relative;
  border-radius: 16px;
  overflow: hidden;
  isolation: isolate;
}
.fp .analytics-locked-skel{
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 14px;
  filter: blur(6px);
  opacity: .5;
  pointer-events: none;
  user-select: none;
}
.fp .analytics-locked--charts .analytics-locked-skel{
  grid-template-columns: repeat(2, 1fr);
}
.fp .analytics-locked-card{
  display: flex;
  flex-direction: column;
  gap: 12px;
  min-height: 104px;
  padding: 18px 16px;
  border-radius: 16px;
  background: rgba(255,255,255,.03);
  border: 1px solid rgba(255,255,255,.06);
}
.fp .analytics-locked--charts .analytics-locked-card{ min-height: 220px; }
.fp .al-skel-line{
  height: 14px;
  border-radius: 7px;
  background: linear-gradient(90deg, rgba(255,255,255,.05), rgba(255,255,255,.10), rgba(255,255,255,.05));
}
.fp .al-skel-sm{ width: 42%; }
.fp .al-skel-md{ width: 58%; }
.fp .al-skel-lg{ width: 80%; height: 26px; }

.fp .analytics-locked-overlay{
  position: absolute;
  inset: 0;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 16px;
  text-align: center;
  background: radial-gradient(120% 120% at 50% 50%, rgba(6,10,16,.55), rgba(6,10,16,.80));
}
.fp .analytics-locked-ico{
  width: 44px; height: 44px;
  display: flex; align-items: center; justify-content: center;
  border-radius: 13px;
  color: #22d3ee;
  background: rgba(34,211,238,.08);
  border: 1px solid rgba(34,211,238,.22);
}
.fp .analytics-locked-badge{
  font-size:13px;
  font-weight:700;
  text-transform: uppercase;
  letter-spacing: .05em;
  color: rgba(255,255,255,.80);
  padding: 5px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,.05);
  border: 1px solid rgba(255,255,255,.10);
}
.fp .analytics-locked-cta{ margin-top: 2px; }

@media (max-width: 720px){
  .fp .analytics-locked-skel,
  .fp .analytics-locked--charts .analytics-locked-skel{ grid-template-columns: 1fr; }
}

/* ===== Footer legal de la app (base.html / base_user.html) =====
   Franja discreta al pie del contenido con links a Términos y
   Privacidad. Aparece en páginas app y públicas servidas por las
   bases. Tono bajo para no competir con el contenido. */
.app-legal-footer{
  margin-top: 40px;
  padding: 18px 8px 6px;
  border-top: 1px solid rgba(255,255,255,.07);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 6px 14px;
  font-size:13px;
  color: rgba(255,255,255,.40);
}
.app-legal-footer a{
  color: rgba(255,255,255,.62);
  font-weight: 700;
  text-decoration: none;
}
.app-legal-footer a:hover{ color: var(--cyan, #22d3ee); text-decoration: underline; }
.app-legal-footer .app-legal-footer__sep{ opacity: .4; }
.app-legal-footer .app-legal-footer__copy{ opacity: .7; }

/* El landing ya tiene su propio <footer class="footer"> con links legales
   dentro de su content block — evitar el footer legal duplicado. */
.landing-page .app-legal-footer{ display: none; }

/* =========================================================
   SELECTOR DE MES — barra de año (.fp-month-yearbar)
   =========================================================
   Núcleo compartido por el componente `_month_picker.html`. Va acá y no en
   un módulo porque el control es de los 7 lugares que lo usan; duplicarlo
   por módulo es exactamente cómo el selector terminó con 7 copias que
   derivaron entre sí.

   ⚠️ Sólo aplica donde EXISTE el markup del macro. Un módulo que todavía no
   se migró no tiene `.fp-month-yearbar` en su DOM, así que estas reglas no
   lo tocan: la migración puede ir de a un módulo sin mover píxeles en los
   demás.

   El skin por módulo (fondo, radios, gradiente del activo) sigue viviendo en
   su CSS — acá va sólo lo que el control necesita para funcionar igual en
   todos. */
.fp-month-yearbar{
  display:flex;
  align-items:center;
  justify-content:space-between;
  gap:10px;
  margin-bottom:12px;
}

.fp-year-nav{
  width:34px;
  height:34px;
  border-radius:999px;
  border:1px solid rgba(255,255,255,.12);
  background:rgba(255,255,255,.06);
  color:rgba(255,255,255,.92);
  font-weight:700;
  font-size:17px;
  line-height:1;
  cursor:pointer;
  transition:.12s ease;
}

.fp-year-nav:hover{
  border-color:rgba(34,211,238,.22);
  background:rgba(34,211,238,.06);
  color:rgba(255,255,255,.98);
}

.fp-year-nav:disabled{
  opacity:.35;
  cursor:default;
}

/* El label del botón lleva mes Y AÑO ("AGO 2026"), así que es casi el doble de
   largo que antes. Sin `nowrap` se parte en dos o tres líneas y el botón queda
   más alto que el resto de la fila de filtros.
   ⚠️ Va acá y no por módulo: en P2P se arregló con una regla apuntando a
   `#p2pMonthBtnText`, que no cubre a nadie más — CxC se rompió exactamente por
   eso al migrar. El ANCHO de la columna sí es de cada módulo (cada toolbar
   tiene su grilla); lo que es del control es que no se parta. */
.fp-month-btn [data-mp-label]{
  white-space:nowrap;
}

.fp-year-label{
  font-weight:700;
  font-size:15px;
  letter-spacing:.02em;
  color:rgba(255,255,255,.96);
  font-variant-numeric:tabular-nums;
}
