/* ======================================================================================
   COMPONENTES BASE DE FITINTRADE (Hito 1.5)
   ======================================================================================

   DERIVADOS, NO INVENTADOS
   --------------------------------------------------------------------------------------
   Un sistema de diseño se rompe inventando componentes en el vacío y congelándolos antes
   de conocer los casos de uso. Aquí no se ha inventado casi nada: la auditoría
   (`tools_auditar_estilos.py`) dice que 12 de los 13 tipos de componente YA existen
   repartidos por la app —tabla en 16 ficheros, input en 16, tabs en 9, tarjeta en 13—, así
   que la forma canónica sale de comparar lo que hay, no de proponer.

   Ejemplo: `.card` ya estaba escrita, idéntica, en dos ficheros
   (`background:var(--panel); border:1px solid var(--line); border-radius:14px`). No hay
   nada que decidir ahí: eso ES la tarjeta de esta casa. Se le pone nombre y ya.

   LOS DOS QUE SÍ SE INVENTAN, Y SE DICE
   --------------------------------------------------------------------------------------
   · BOTÓN PRIMARIO: no existe. En toda la aplicación no hay un solo botón de acción con
     fondo verde sólido; el verde macizo solo se usa en avatares y en barras de progreso.
     Así que este se propone, no se deriva.
   · SKELETON: 3 reglas en 1 fichero. Un precedente no es un patrón.
   Los dos quedan marcados como propuesta en /admin/design-system. Si al cerrar el primer
   módulo que los necesite resulta que la forma no encaja, se cambian: no se congelan como
   si estuvieran validados, porque no lo están.

   NO HAY UNA SOLA REGLA GLOBAL
   --------------------------------------------------------------------------------------
   Ni `button{}`, ni `input{}`, ni `table{}`, ni `a{}`. Todo cuelga de una clase `.fit-*`.
   Y no es purismo: las páginas legacy heredan de lo global y una regla suelta sobre
   `input` les cambiaría los formularios a las trece sin que nadie lo pidiera. Este fichero
   se carga en todas las páginas del App Shell desde hoy; si tuviera reglas de elemento,
   las trece cambiarían de aspecto esta misma tarde.

   Por eso este fichero, hoy, no cambia NADA: nadie usa todavía las clases `.fit-*`. Las
   estrena la página de referencia. Los módulos las adoptan cuando les toque cerrarse.
   ====================================================================================== */

/* ======================================================================================
   TIPOGRAFÍA — los nueve papeles
   ======================================================================================
   Los tokens dan el tamaño; esto da el papel completo (tamaño + peso + interlineado +
   espaciado), que es lo que de verdad se reutiliza. Nadie debería volver a escribir
   `font-size: 13px; color: var(--gray)`: eso es `.fit-secondary`. */
.fit-h1 {
  font-size: var(--fit-fs-h1); font-weight: var(--fit-fw-black);
  line-height: var(--fit-lh-tight); letter-spacing: var(--fit-ls-h1);
  color: var(--fit-text); margin: 0;
  text-wrap: balance;   /* un titular partido en «de» + «inversión» se lee peor */
}
.fit-h2 {
  font-size: var(--fit-fs-h2); font-weight: var(--fit-fw-bold);
  line-height: var(--fit-lh-tight); letter-spacing: -.015em;
  color: var(--fit-text); margin: 0;
}
.fit-h3 {
  font-size: var(--fit-fs-h3); font-weight: var(--fit-fw-semi);
  line-height: var(--fit-lh-normal); color: var(--fit-text); margin: 0;
}
.fit-body {
  font-size: var(--fit-fs-body); font-weight: var(--fit-fw-normal);
  line-height: var(--fit-lh-text); color: var(--fit-text);
}
.fit-secondary {
  font-size: var(--fit-fs-secondary); line-height: var(--fit-lh-normal);
  color: var(--fit-text-2);
}
.fit-muted { color: var(--fit-text-3); }
.fit-label {
  font-size: var(--fit-fs-label); font-weight: var(--fit-fw-black);
  letter-spacing: var(--fit-ls-label); text-transform: uppercase;
  color: var(--fit-text-2); line-height: var(--fit-lh-normal);
}

/* Cifras. `tabular-nums` no es un detalle: sin él, en una columna de precios el 1 ocupa
   menos que el 8 y las comas no se alinean. En una app de datos financieros eso es un
   defecto, no un matiz. */
.fit-metric {
  font-size: var(--fit-fs-metric); font-weight: var(--fit-fw-black);
  line-height: var(--fit-lh-tight); letter-spacing: -.02em;
  color: var(--fit-text); font-variant-numeric: tabular-nums;
}
.fit-metric-sm {
  font-size: var(--fit-fs-metric-sm); font-weight: var(--fit-fw-bold);
  line-height: var(--fit-lh-tight); color: var(--fit-text);
  font-variant-numeric: tabular-nums;
}
.fit-num { font-variant-numeric: tabular-nums; }

/* El signo del dato. Ojo: el color NO puede ser la única señal —quien no distingue rojo
   de verde se queda sin la información—, así que el número lleva su signo delante. El
   color acompaña, no informa solo. */
.fit-pos { color: var(--fit-positive); }
.fit-neg { color: var(--fit-negative); }
.fit-neu { color: var(--fit-neutral); }

/* ======================================================================================
   SUPERFICIES
   ====================================================================================== */
/* Derivada: ya estaba escrita igual en dos sitios. */
.fit-card {
  background: var(--fit-surface);
  border: 1px solid var(--fit-border);
  border-radius: var(--fit-radius-lg);
  padding: var(--fit-sp-4);
}
.fit-card-raised { box-shadow: var(--fit-shadow-1); }
.fit-card-flat { background: var(--fit-surface-sunken); border-color: transparent; }

/* ======================================================================================
   CONTROLES
   ======================================================================================
   Alto mínimo `--fit-control-h`, que en móvil sube a 44px solo. Un botón que mide bien en
   el ratón y falla con el pulgar no está bien medido: está medido para la mitad. */
.fit-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--fit-sp-2);
  min-height: var(--fit-control-h);
  padding: 0 var(--fit-sp-4);
  border-radius: var(--fit-radius);
  border: 1px solid transparent;
  font-family: inherit; font-size: var(--fit-fs-body); font-weight: var(--fit-fw-medium);
  line-height: 1; cursor: pointer; text-decoration: none;
  transition: background .13s, border-color .13s, color .13s;
}
.fit-btn:disabled, .fit-btn[aria-disabled="true"] { opacity: .45; cursor: not-allowed; }
.fit-btn:focus-visible {
  outline: 2px solid var(--fit-focus); outline-offset: 2px;
}

/* PROPUESTO, no derivado: no existe ningún botón primario en la app. */
.fit-btn-primary {
  background: var(--fit-brand); color: var(--fit-text-on-brand);
  font-weight: var(--fit-fw-bold);
}
.fit-btn-primary:hover:not(:disabled) { background: var(--fit-brand-deep); color: #fff; }

.fit-btn-secondary {
  background: var(--fit-surface); color: var(--fit-text);
  border-color: var(--fit-border-strong);
}
.fit-btn-secondary:hover:not(:disabled) { background: var(--fit-surface-sunken); }

/* Peligro: NO va rojo macizo. Un botón rojo grande invita a pulsarlo por contraste, que
   es lo contrario de lo que se quiere de un botón que borra algo. Rojo sobre fondo
   tenue: se ve, se lee, y no llama. */
.fit-btn-danger {
  background: rgba(229, 72, 77, .10); color: var(--fit-error);
  border-color: rgba(229, 72, 77, .25); font-weight: var(--fit-fw-medium);
}
.fit-btn-danger:hover:not(:disabled) { background: rgba(229, 72, 77, .18); }

.fit-btn-ghost { background: transparent; color: var(--fit-text-2); }
.fit-btn-ghost:hover:not(:disabled) { background: var(--fit-surface-sunken); color: var(--fit-text); }

/* Derivados de `.ex-sel` y `.wl-input`, que ya coincidían en padding (10/12) y borde y
   solo discrepaban en el radio (12 vs 10) y el tamaño (13,5 vs 15). Se toma 10 y el
   cuerpo, que es lo que dice la escala. */
.fit-input, .fit-select, .fit-textarea {
  width: 100%; max-width: 100%;   /* un <select> se mide por su opción más larga y estira
                                      la página: ya pasó, y a 360px basta con 2px */
  min-height: var(--fit-control-h);
  padding: var(--fit-sp-2) var(--fit-sp-3);
  border: 1px solid var(--fit-border); border-radius: var(--fit-radius);
  background: var(--fit-surface); color: var(--fit-text);
  font-family: inherit; font-size: var(--fit-fs-body);
}
.fit-input:focus, .fit-select:focus, .fit-textarea:focus {
  outline: 2px solid var(--fit-focus); outline-offset: 1px;
  border-color: var(--fit-brand);
}
.fit-input::placeholder, .fit-textarea::placeholder { color: var(--fit-text-3); }
.fit-input[aria-invalid="true"], .fit-select[aria-invalid="true"] {
  border-color: var(--fit-error);
}
.fit-field { display: flex; flex-direction: column; gap: var(--fit-sp-1); }

/* Tabs. Derivadas: existen en 9 ficheros con la misma forma —subrayado, no pestaña—. */
.fit-tabs {
  display: flex; gap: var(--fit-sp-1);
  border-bottom: 1px solid var(--fit-border);
  overflow-x: auto;              /* en móvil se deslizan; no se apilan ni se encogen */
  scrollbar-width: none;
}
.fit-tabs::-webkit-scrollbar { display: none; }
.fit-tab {
  background: none; border: 0; cursor: pointer; font-family: inherit;
  padding: var(--fit-sp-3) var(--fit-sp-3);
  min-height: var(--fit-touch);
  font-size: var(--fit-fs-body); font-weight: var(--fit-fw-medium);
  color: var(--fit-text-2); white-space: nowrap;
  border-bottom: 2px solid transparent; margin-bottom: -1px;
}
.fit-tab:hover { color: var(--fit-text); }
.fit-tab[aria-selected="true"], .fit-tab.on {
  color: var(--fit-text); font-weight: var(--fit-fw-semi);
  border-bottom-color: var(--fit-brand);
}
.fit-tab:focus-visible { outline: 2px solid var(--fit-focus); outline-offset: -2px; }

/* ======================================================================================
   SEÑALES
   ======================================================================================
   Badge derivado de la familia `.b-green` / `.b-gray` / `.b-amber` / `.b-red`, que ya
   existía: fondo teñido + texto del color. */
.fit-badge {
  display: inline-flex; align-items: center; gap: var(--fit-sp-1);
  padding: 3px var(--fit-sp-2); border-radius: var(--fit-radius-sm);
  font-size: var(--fit-fs-label); font-weight: var(--fit-fw-bold);
  line-height: 1.4; white-space: nowrap;
  background: var(--fit-surface-sunken); color: var(--fit-text-2);
}
.fit-badge-brand { background: var(--fit-brand-soft); color: var(--fit-brand-deep); }
.fit-badge-pos { background: var(--fit-brand-soft); color: var(--fit-positive); }
.fit-badge-neg { background: rgba(229, 72, 77, .10); color: var(--fit-negative); }
.fit-badge-warn { background: rgba(200, 134, 13, .12); color: var(--fit-warning); }
.fit-badge-info { background: rgba(47, 111, 237, .10); color: var(--fit-info); }

/* Banner. Derivado de `.tec-honesto` y familia: barra de color a la izquierda, fondo
   tenue. Es el patrón que la app ya usa para los avisos metodológicos. */
.fit-banner {
  border-left: 3px solid var(--fit-neutral);
  background: var(--fit-surface-sunken);
  padding: var(--fit-sp-3) var(--fit-sp-4);
  border-radius: 0 var(--fit-radius-sm) var(--fit-radius-sm) 0;
  font-size: var(--fit-fs-secondary); line-height: var(--fit-lh-text);
  color: var(--fit-text-2);
}
.fit-banner-info { border-left-color: var(--fit-info); background: rgba(47, 111, 237, .05); }
.fit-banner-warn { border-left-color: var(--fit-warning); background: rgba(200, 134, 13, .06); }
.fit-banner-error { border-left-color: var(--fit-error); background: rgba(229, 72, 77, .05); }

.fit-error-msg {
  display: flex; align-items: flex-start; gap: var(--fit-sp-2);
  color: var(--fit-error); font-size: var(--fit-fs-secondary);
  line-height: var(--fit-lh-normal);
}

/* Estado vacío. Derivado: existe en 8 ficheros. Lo importante no es el dibujo: es que
   diga qué hacer. Un «sin datos» a secas deja al usuario parado. */
.fit-empty {
  text-align: center; padding: var(--fit-sp-6) var(--fit-sp-4);
  color: var(--fit-text-2);
}
.fit-empty h3 {
  font-size: var(--fit-fs-h3); font-weight: var(--fit-fw-semi);
  color: var(--fit-text); margin: 0 0 var(--fit-sp-1);
}
.fit-empty p { font-size: var(--fit-fs-secondary); margin: 0 0 var(--fit-sp-4); }

/* Tooltip. Se abre con :hover Y con :focus-visible: si solo fuera hover, quien navega con
   teclado -o con el dedo- se queda sin la explicación. */
.fit-tip { position: relative; }
.fit-tip::after {
  content: attr(data-tip);
  position: absolute; left: 50%; bottom: calc(100% + 6px); transform: translateX(-50%);
  background: var(--fit-text); color: var(--fit-surface);
  padding: var(--fit-sp-1) var(--fit-sp-2); border-radius: var(--fit-radius-sm);
  font-size: var(--fit-fs-label); font-weight: var(--fit-fw-medium);
  letter-spacing: 0; text-transform: none; white-space: nowrap;
  opacity: 0; pointer-events: none; transition: opacity .12s; z-index: 60;
}
.fit-tip:hover::after, .fit-tip:focus-visible::after { opacity: 1; }

/* PROPUESTO, no derivado: 3 reglas en 1 fichero no es un patrón. */
.fit-skeleton {
  background: linear-gradient(90deg,
    var(--fit-surface-sunken) 25%, #ececed 50%, var(--fit-surface-sunken) 75%);
  background-size: 200% 100%;
  animation: fit-shimmer 1.3s linear infinite;
  border-radius: var(--fit-radius-sm);
  min-height: 1em;
}
@keyframes fit-shimmer { to { background-position: -200% 0; } }
@media (prefers-reduced-motion: reduce) {
  .fit-skeleton { animation: none; background: var(--fit-surface-sunken); }
}

/* ======================================================================================
   DATOS
   ======================================================================================
   La tabla NO lleva `overflow` puesto: lo lleva su envoltorio. Es a propósito. Una tabla
   ancha tiene que desplazarse DENTRO de su caja y nunca estirar la página: 2px de más y
   aparece el scroll horizontal global y el móvil se mueve de lado. Ya pasó. */
.fit-table-wrap {
  overflow-x: auto;
  border: 1px solid var(--fit-border); border-radius: var(--fit-radius-lg);
  background: var(--fit-surface);
  -webkit-overflow-scrolling: touch;
}
.fit-table {
  width: 100%; border-collapse: collapse;
  font-size: var(--fit-fs-table);
}
.fit-table th, .fit-table td {
  padding: var(--fit-sp-3) var(--fit-sp-4);
  text-align: left; border-bottom: 1px solid var(--fit-border);
}
.fit-table th {
  font-size: var(--fit-fs-label); font-weight: var(--fit-fw-black);
  letter-spacing: var(--fit-ls-label); text-transform: uppercase;
  color: var(--fit-text-2); background: var(--fit-surface-sunken);
  white-space: nowrap; position: sticky; top: 0; z-index: 1;
}
.fit-table tbody tr:last-child td { border-bottom: 0; }
.fit-table td.num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }

/* El contenedor del gráfico. Existe para una razón concreta: reservar el hueco ANTES de
   que el gráfico cargue. Sin `aspect-ratio`, la página salta cuando llegan los datos y el
   usuario pierde de vista lo que estaba leyendo. */
.fit-chart {
  position: relative; width: 100%;
  aspect-ratio: 16 / 9;
  background: var(--fit-surface); border-radius: var(--fit-radius-lg);
  overflow: hidden;
}
.fit-chart > canvas, .fit-chart > svg { display: block; width: 100%; height: 100%; }
@media (max-width: 767px) {
  .fit-chart { aspect-ratio: 4 / 3; }   /* en vertical, 16:9 deja una tira ilegible */
}

/* ======================================================================================
   MODAL
   ====================================================================================== */
.fit-modal-scrim {
  position: fixed; inset: 0; z-index: 90;
  background: rgba(10, 12, 11, .5);
  display: flex; align-items: center; justify-content: center;
  padding: var(--fit-sp-4);
}
.fit-modal {
  background: var(--fit-surface); border-radius: var(--fit-radius-lg);
  box-shadow: var(--fit-shadow-3);
  padding: var(--fit-sp-5);
  width: 100%; max-width: 560px;
  max-height: calc(100dvh - var(--fit-sp-7));   /* dvh: en móvil la barra del navegador se mueve */
  overflow-y: auto;
}
/* En móvil sube desde abajo y ocupa el ancho: un cuadro centrado y estrecho en un
   teléfono desperdicia la pantalla y deja el botón lejos del pulgar. */
@media (max-width: 767px) {
  .fit-modal-scrim { align-items: flex-end; padding: 0; }
  .fit-modal {
    max-width: none; border-radius: var(--fit-radius-lg) var(--fit-radius-lg) 0 0;
    padding-bottom: calc(var(--fit-sp-5) + var(--fit-safe-b));
    max-height: 88dvh;
  }
}

/* ======================================================================================
   UTILIDADES — las justas
   ======================================================================================
   No es un framework de utilidades. Son las cuatro cosas que se repiten en todas las
   páginas y que, si no están aquí, cada módulo se las vuelve a escribir. */
.fit-stack   { display: flex; flex-direction: column; gap: var(--fit-sp-3); }
.fit-row     { display: flex; align-items: center; gap: var(--fit-sp-2); flex-wrap: wrap; }
.fit-grid    { display: grid; gap: var(--fit-sp-3); }
.fit-section { display: flex; flex-direction: column; gap: var(--fit-sp-4); }
.fit-section + .fit-section { margin-top: var(--fit-sp-6); }

/* Se ve solo con lector de pantalla. Hace falta para que un icono sin texto tenga nombre. */
.fit-sr {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}
