/* =====================================================================
   tokens.css — Design tokens estilo IBM Carbon Design System
   Tema claro (White) por defecto + tema oscuro (Gray 100) preparado.
   Cambia el tema con  <html data-theme="dark">  (ver app.js / AppHeader).
   ===================================================================== */

/* ---- Tipografia ----
   IBM Plex se carga con <link> desde el <head>, no con @import: un @import
   dentro del CSS no se descubre hasta haber descargado y parseado este
   archivo, encadenando dos viajes antes de pintar texto. Medido en local, la
   hoja de fuentes no se pedia hasta los 965ms y los .woff2 hasta los 1855ms.
   El <link> con preconnect los lanza de inmediato. --font-sans y --font-mono
   quedan mas abajo, con su pila de reserva. */

:root {
  /* ---------- Paleta Carbon ---------- */
  --cds-white: #ffffff;

  /* Acentos de marca. El branding por empresa elige una familia y de sus pasos
     salen los tokens: 10 fondo suave, 40 tinta en tema oscuro, 60 base,
     80 activo. El hover es el medio paso entre el 60 y el 70, que Carbon deja
     fuera de la escala. Ver config/branding.php */
  --cds-blue-10: #edf5ff;
  --cds-blue-20: #d0e2ff;
  --cds-blue-40: #78a9ff;
  --cds-blue-50: #4589ff;
  --cds-blue-60: #0f62fe;   /* interactive primary */
  --cds-blue-70: #0043ce;
  --cds-blue-80: #002d9c;
  --cds-blue-90: #001d6c;

  --cds-cyan-10: #e5f6ff;
  --cds-cyan-20: #bae6ff;
  --cds-cyan-40: #33b1ff;
  --cds-cyan-50: #1192e8;
  --cds-cyan-60: #0072c3;
  --cds-cyan-70: #00539a;
  --cds-cyan-80: #003a6d;

  --cds-teal-10: #d9fbfb;
  --cds-teal-20: #9ef0f0;
  --cds-teal-40: #08bdba;
  --cds-teal-50: #009d9a;
  --cds-teal-60: #007d79;
  --cds-teal-70: #005d5d;
  --cds-teal-80: #004144;

  --cds-purple-10: #f6f2ff;
  --cds-purple-20: #e8daff;
  --cds-purple-40: #be95ff;
  --cds-purple-50: #a56eff;
  --cds-purple-60: #8a3ffc;
  --cds-purple-70: #6929c4;
  --cds-purple-80: #491d8b;

  --cds-magenta-10: #fff0f7;
  --cds-magenta-20: #ffd6e8;
  --cds-magenta-40: #ff7eb6;
  --cds-magenta-60: #d02670;
  --cds-magenta-70: #9f1853;
  --cds-magenta-80: #740937;

  /* Estados. Reservados por Carbon para exito, error y advertencia: no se
     ofrecen como acento de marca para que un boton no se confunda con una
     confirmacion */
  --cds-green-10: #defbe6;
  --cds-green-20: #a7f0ba;
  --cds-green-40: #42be65;
  --cds-green-50: #24a148;
  --cds-green-60: #198038;
  --cds-green-70: #0e6027;

  --cds-red-10: #fff1f1;
  --cds-red-20: #ffd7d9;
  --cds-red-40: #ff8389;
  --cds-red-50: #fa4d56;
  --cds-red-60: #da1e28;
  --cds-red-70: #a2191f;
  --cds-red-80: #750e13;

  --cds-yellow-10: #fcf4d6;
  --cds-yellow-20: #fddc69;
  --cds-yellow-30: #f1c21b;
  /* El paquete oficial IBM_Colors_RGB_HEX_v2.1 trae las familias completas de
     azul, cian, teal, purpura, magenta, verde, rojo y gris, pero de amarillo y
     naranja solo incluye un tono cada una: Yellow_30 y Orange_40. El 70 de
     amarillo se conserva con el valor que ya usaba la notificacion de
     advertencia; no se ha podido contrastar con la fuente. */
  --cds-yellow-70: #684e00;
  --cds-yellow-60: #8e6a00;

  --cds-orange-20: #ffd9be;
  --cds-orange-40: #ff832b;
  --cds-orange-70: #8a3800;

  /* Neutros. `cool-gray` es la variante fria que Carbon ofrece junto al gris
     neutro; la interfaz la usa en un par de superficies. */
  --cds-cool-gray-10: #f2f4f8;
  --cds-cool-gray-20: #dde1e6;
  --cds-cool-gray-60: #697077;

  --cds-gray-10: #f4f4f4;
  --cds-gray-20: #e0e0e0;
  --cds-gray-30: #c6c6c6;
  --cds-gray-40: #a8a8a8;
  --cds-gray-50: #8d8d8d;
  --cds-gray-60: #6f6f6f;
  --cds-gray-70: #525252;
  --cds-gray-80: #393939;
  --cds-gray-90: #262626;
  --cds-gray-100: #161616;

  /* ---------- Tokens semánticos (TEMA CLARO) ---------- */
  --background:            var(--cds-white);
  --layer-01:              var(--cds-gray-10);
  --layer-02:              var(--cds-white);
  --layer-hover:           #e8e8e8;
  --layer-selected:        var(--cds-gray-20);
  /* Un escalon por debajo del acento de capa. Es el fondo que Carbon da a la
     cabecera ordenada y al pasar por encima de una ordenable: sobre
     layer-accent hay que oscurecer, no aclarar, o el resalte va al reves. */
  --layer-selected-hover:  #d1d1d1;
  /* Carbon distingue la capa del acento de capa: layer-01 es el fondo de un
     panel y layer-accent-01 es un escalon mas oscuro, reservado para cosas
     como la cabecera de una tabla. Faltaba, y por eso el thead usaba layer-01
     y se confundia con el cuerpo. */
  --layer-accent:          var(--cds-gray-20);
  /* Carbon distingue el hover de una CAPA (layer-hover, opaco, para
     superficies apiladas) del hover sobre el FONDO de pagina, que es un velo
     translucido de gray-50 al 12%. Los controles que se apoyan directamente
     en el fondo -paginacion, por ejemplo- usan este. */
  --background-hover:      rgba(141, 141, 141, .12);
  --field-01:              var(--cds-gray-10);
  --field-02:              var(--cds-white);
  --border-subtle:         var(--cds-gray-20);
  /* El escalon que el token de arriba aplana. `--border-subtle` vale lo que
     Carbon pide sobre layer-02, que es la superficie de casi todo aqui, pero
     un acordeon anidado se dibuja sobre layer-01 y alli la linea tiene que
     ser un paso mas oscura: gray-30, no gray-20, que sobre #f4f4f4 se queda
     en 1.06 de contraste y desaparece. Solo lo usa quien va sobre layer-01. */
  --border-subtle-01:      var(--cds-gray-30);
  --border-strong:         var(--cds-gray-50);
  --border-interactive:    var(--cds-blue-60);

  --text-primary:          var(--cds-gray-100);
  --text-secondary:        var(--cds-gray-70);
  --text-placeholder:      var(--cds-gray-40);
  --text-on-color:         var(--cds-white);
  --text-on-color-disabled: var(--cds-gray-50);
  --text-helper:           var(--cds-gray-60);
  --text-disabled:         var(--cds-gray-30);
  --link-primary:          var(--cds-blue-60);
  /* Texto de error sobre una capa. No vale --support-error: ese tono esta
     calibrado para hacer de fondo o de borde, y como tinta sobre la capa
     oscura se queda en 3,44:1. Carbon sube un escalon la paleta cuando el
     color de estado hace de texto. */
  --text-error:            var(--cds-red-60);

  --interactive:           var(--cds-blue-60);

  /* Foco. components.css lo pedia como `var(--focus, var(--interactive))` y
     nadie lo habia definido: en tema claro el respaldo acierta por casualidad
     (Carbon tambien usa blue-60), pero en oscuro Carbon cambia a blanco y el
     respaldo habria seguido pintando azul sobre gray-100. */
  --focus:                 var(--cds-blue-60);
  --focus-inset:           var(--cds-white);
  --focus-inverse:         var(--cds-white);

  /* Botones. Los tres primarios y sus hover ya coincidian exactos con Carbon
     (#0050e6 es blue-60-hover y #474747 es gray-80-hover). Faltaban los
     estados active, el deshabilitado, el separador y toda la familia
     tertiary, que Carbon define y aqui no existia.
     --button-danger-hover estaba en #b81922 y la especificacion dice #b81921. */
  --button-primary:          var(--cds-blue-60);
  --button-primary-hover:    #0050e6;
  --button-primary-active:   var(--cds-blue-80);
  --button-secondary:        var(--cds-gray-80);
  --button-secondary-hover:  #474747;
  --button-secondary-active: var(--cds-gray-60);
  --button-tertiary:         var(--cds-blue-60);
  --button-tertiary-hover:   #0050e6;
  --button-tertiary-active:  var(--cds-blue-80);
  --button-danger-hover:     #b81921;
  --button-danger-active:    var(--cds-red-80);
  --button-disabled:         var(--cds-gray-30);
  --button-separator:        var(--cds-gray-20);
  /* Carbon lo llama button-danger-primary; se conserva el nombre corto que ya
     usaba el ERP y se anade el oficial como sinonimo. */
  --button-danger:           var(--cds-red-60);
  --button-danger-primary:   var(--cds-red-60);
  --button-danger-secondary: var(--cds-red-60);

  --support-success:       var(--cds-green-50);
  --support-error:         var(--cds-red-60);
  --support-warning:       var(--cds-yellow-30);
  --support-info:          var(--cds-blue-60);

  /* ---------- Tag (etiquetas de estado) ----------
     Formula oficial del tema White, de packages/themes/src/dtcg/components/
     tag.json: fondo = paso 20 de la familia, texto = paso 70, borde = paso 40.
     Son colores solidos de la paleta, no capas translucidas: el ERP venia
     pintando estos fondos con rgba(...,.12-.18) calculados a ojo, que sobre
     una fila con hover cambian de tono porque dejan pasar el fondo de debajo.

     Carbon define diez familias de tag y ninguna es amarilla ni naranja.
     Como el ERP necesita marcar advertencias, --tag-*-warning y --tag-*-caution
     quedan abajo como EXTENSION PROPIA, construidas con la misma formula
     20/70 para que no desentonen. Estan aparte a proposito: quien lea esto
     debe saber que ese par no viene de Carbon. */
  --tag-background-gray:    var(--cds-gray-20);
  --tag-color-gray:         var(--cds-gray-100);
  --tag-background-blue:    var(--cds-blue-20);
  --tag-color-blue:         var(--cds-blue-70);
  --tag-background-green:   var(--cds-green-20);
  --tag-color-green:        var(--cds-green-70);
  --tag-background-red:     var(--cds-red-20);
  --tag-color-red:          var(--cds-red-70);
  --tag-background-purple:  var(--cds-purple-20);
  --tag-color-purple:       var(--cds-purple-70);
  --tag-background-magenta: var(--cds-magenta-20);
  --tag-color-magenta:      var(--cds-magenta-70);
  --tag-background-teal:    var(--cds-teal-20);
  --tag-color-teal:         var(--cds-teal-70);
  --tag-background-cyan:    var(--cds-cyan-20);
  --tag-color-cyan:         var(--cds-cyan-70);

  /* Extension propia: Carbon no publica tag amarillo ni naranja. */
  --tag-background-warning: var(--cds-orange-20);
  --tag-color-warning:      var(--cds-orange-70);
  --tag-background-caution: var(--cds-yellow-20);
  --tag-color-caution:      var(--cds-yellow-70);

  --icon-primary:          var(--cds-gray-100);
  --icon-secondary:        var(--cds-gray-70);

  --overlay:               rgba(22,22,22,.5);
  --skeleton-bg:           #e5e5e5;
  --skeleton-shine:        var(--cds-gray-10);
  --shadow-sm:             0 2px 6px rgba(0,0,0,.10);
  --shadow-md:             0 4px 16px rgba(0,0,0,.16);

  /* ---------- Layout ---------- */
  --header-h: 48px;
  /* 256px = 32 mini-unidades de 8px, el ancho del side nav expandido de
     Carbon (ui-shell/side-nav/_side-nav.scss, que lo usa como medida y como
     tope). Estaba en 280px, que no es una anchura del sistema. El margen
     izquierdo del contenido cuelga de este mismo token, asi que se corrige
     solo. */
  --sidebar-w: 16rem;
  --sidebar-collapsed-w: 48px;
  --font-sans: 'IBM Plex Sans', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
  --font-mono: 'IBM Plex Mono', ui-monospace, monospace;

  /* ---------- Movimiento (escala oficial de Carbon) ----------
     Los seis pasos y las seis curvas salen de @carbon/motion:
     packages/motion/src/dtcg/motion.json. Antes habia tres duraciones
     inventadas (.2s/.3s/.45s) que no correspondian a ningun token de Carbon.

     Productive es el modo de una herramienta de trabajo: el movimiento informa
     y se aparta. Expressive queda para lo que debe reclamar atencion, como un
     error que interrumpe. Un ERP vive casi entero en productive.

     Entrance y exit no son la misma curva: lo que entra arranca a velocidad
     cero y desacelera; lo que sale arranca ya en movimiento y acelera al irse.
     Usar `standard` para las tres es lo que hacia el sistema hasta ahora. */
  --dur-fast-01: 70ms;      /* microinteraccion: boton, toggle */
  --dur-fast-02: 110ms;     /* fundido de elementos pequenios */
  --dur-moderate-01: 150ms; /* velocidad de transicion por defecto */
  --dur-moderate-02: 240ms; /* expansion, toast, avisos del sistema */
  --dur-slow-01: 400ms;     /* expansion grande, notificacion importante */
  --dur-slow-02: 700ms;     /* atenuado de fondo, transicion de portada */

  --ease-standard: cubic-bezier(.2, 0, .38, .9);
  --ease-entrance: cubic-bezier(0, 0, .38, .9);
  --ease-exit:     cubic-bezier(.2, 0, 1, .9);
  --ease-standard-expressive: cubic-bezier(.4, .14, .3, 1);
  --ease-entrance-expressive: cubic-bezier(0, 0, .3, 1);
  --ease-exit-expressive:     cubic-bezier(.4, .14, 1, 1);

  /* Alias de compatibilidad. Los 17 usos que ya existian en el CSS apuntan
     aqui y quedan alineados a Carbon sin tocar cada declaracion. Al migrar
     esas hojas a los nombres de arriba, estos tres se borran. */
  --dur-fast: var(--dur-fast-02);
  --dur-base: var(--dur-moderate-01);
  --dur-slow: var(--dur-slow-01);
  --ease: var(--ease-standard);

  /* ---------- Acento de marca dinámico (branding por empresa) ---------- */
  --brand: var(--cds-blue-60);
  --brand-soft: var(--cds-blue-10);

  /* ---------- Escala de espaciado Carbon ----------
     Todos los pasos son multiplos de la mini-unidad de 8px
     (packages/layout/src/index.ts): 0.25, 0.5, 1, 1.5, 2, 3, 4, 5, 6, 8, 10,
     12 y 20 mini-unidades. Del 01 al 09 ya estaban y coinciden exactos; del 10
     al 13 faltaban, que son los que Carbon usa para margenes de pagina y
     separacion entre secciones grandes. */
  --sp-01: .125rem; --sp-02: .25rem; --sp-03: .5rem; --sp-04: .75rem;
  --sp-05: 1rem; --sp-06: 1.5rem; --sp-07: 2rem; --sp-08: 2.5rem; --sp-09: 3rem;
  --sp-10: 4rem;    /* 64px  */
  --sp-11: 5rem;    /* 80px  */
  --sp-12: 6rem;    /* 96px  */
  --sp-13: 10rem;   /* 160px */

  /* ---------- Escala tipografica ----------
     Carbon type scale sobre una raiz de 16px. Antes de estos tokens la
     tipografia vivia en las vistas: 2042 declaraciones de `font-size` con 62
     valores distintos, entre ellos siete tamanos entre 9,9px y 11,5px que
     nadie puede distinguir. Los pasos de abajo son el destino al que se
     absorben; los huerfanos mas comunes son 0.8125rem (13px), que baja a
     `--type-size-01` o sube a `--type-size-02` segun el rol, y 0.6875rem
     (11px), que sube a `--type-size-01`.
     El cuerpo de la aplicacion es `--type-size-02` (14px). En movil se queda
     corto y ademas dispara el zoom automatico de iOS, que reacciona por
     debajo de 16px; subirlo es un cambio visual y va aparte. */
  --type-size-01: 0.75rem;    /* 12px  etiquetas, pies, texto de ayuda */
  --type-size-02: 0.875rem;   /* 14px  cuerpo por defecto */
  --type-size-03: 1rem;       /* 16px  cuerpo largo, minimo comodo en movil */
  --type-size-04: 1.125rem;   /* 18px */
  --type-size-05: 1.25rem;    /* 20px */
  --type-size-06: 1.5rem;     /* 24px  titulo de pagina */
  --type-size-07: 1.75rem;    /* 28px */
  --type-size-08: 2rem;       /* 32px */
  --type-size-09: 2.25rem;    /* 36px  cifras de tarjeta resumen */

  /* Roles: nombran el uso, no el tamano. Una vista pide `--type-body`, no
     14px, y el dia que el cuerpo suba a 16px no hay que tocar la vista. */
  --type-caption:     var(--type-size-01);
  --type-body:        var(--type-size-02);
  --type-body-lg:     var(--type-size-03);
  --type-heading-sm:  var(--type-size-05);
  --type-heading:     var(--type-size-06);
  --type-heading-lg:  var(--type-size-07);
  --type-display:     var(--type-size-09);

  /* Pesos. Carbon define TRES y solo tres (packages/type/src/fontWeight.ts):
     light 300, regular 400, semibold 600. No existe el 500 ni el 700.
     El semibold se usa hoy cuatro veces mas que el regular porque la jerarquia
     se venia construyendo engrosando el texto en vez de con la escala de
     tamanos. Con la escala disponible, el cuerpo deberia volver a regular. */
  --type-weight-light:    300;
  --type-weight-regular:  400;
  --type-weight-semibold: 600;

  /* Alias en retirada. `medium` (500) y `bold` (700) no son pesos de Carbon,
     pero quedan 315 usos en las vistas y 16 en las hojas propias. Borrarlos
     dejaria ese texto sin font-weight; por eso apuntan al semibold, que es el
     peso legal mas cercano y conserva el enfasis que buscaban: ambos se usan
     casi siempre en encabezados y celdas destacadas.
     Al migrar las vistas se sustituyen por --type-weight-semibold y se borran.
     Ojo: en un componente concreto manda su spec, no este alias. El Tag de
     Carbon, por ejemplo, es label-01 y va en regular 400, no en semibold. */
  --type-weight-medium:   var(--type-weight-semibold);
  --type-weight-bold:     var(--type-weight-semibold);

  /* Interlineado */
  --type-leading-tight:   1.25;
  --type-leading-base:    1.43;
  --type-leading-relaxed: 1.6;

  /* ---------- Superficie del sidenav (claro por defecto) ---------- */
  --sidenav-bg: var(--cds-white);
  --sidenav-active-bg: var(--cds-gray-10);
  --sidenav-text: var(--cds-gray-70);
  --sidenav-text-strong: var(--cds-gray-100);
  --sidenav-hover: var(--cds-gray-10);
  --sidenav-border: var(--cds-gray-20);

  /* ---------- Notificaciones ----------
     Fondos y textos de las notificaciones inline de Carbon. Existen como
     tokens porque el color de estado no puede ir escrito a mano en la vista:
     en tema oscuro un #defbe6 fijo deja un bloque claro sobre fondo negro. */
  --notification-bg-success:  var(--cds-green-10);
  --notification-bg-error:    var(--cds-red-10);
  --notification-bg-warning:  #fdf6dd;
  --notification-bg-info:     var(--cds-blue-10);
  --notification-text-success: var(--cds-green-70);
  --notification-text-error:   var(--cds-red-70);
  --notification-text-warning: var(--cds-yellow-70);
  --notification-text-info:    var(--cds-blue-70);

  /* ---------- Carbon for AI ----------
     Marcan contenido generado o sugerido por IA. Carbon lo resuelve con
     "efectos de luz: brillo, resplandor y degradados" naciendo en los bordes
     del contenedor, con difusion contenida para no perder contraste.
     El degradado va de blue-60 a purple-60, que ya estan en la paleta.
     Regla de Carbon: nunca usarlos como decoracion. Si un elemento los lleva,
     es porque hay IA detras; si el usuario edita el valor, se le quitan.
     Ver docs/desarrollo/carbon-for-ai.md */
  --ai-aura-start:      rgba(69, 137, 255, 0.16);
  --ai-aura-end:        rgba(138, 63, 252, 0);
  --ai-border-start:    var(--cds-blue-50);
  --ai-border-end:      var(--cds-purple-60);
  --ai-inner-shadow:    rgba(69, 137, 255, 0.10);
  --ai-popover-bg:      var(--cds-white);
  --ai-text:            var(--cds-blue-70);
  --ai-skeleton:        rgba(69, 137, 255, 0.20);
}

/* ---------- TEMA OSCURO (Gray 100) ---------- */
[data-theme="dark"] {
  --background:            var(--cds-gray-100);
  --layer-01:              var(--cds-gray-90);
  --layer-02:              var(--cds-gray-80);
  --layer-hover:           #333333;
  --layer-selected:        var(--cds-gray-80);
  /* g100 tiene dos pasos: layer-accent-01 gray-80, para lo que se apoya en
     layer-01, y layer-accent-02 gray-70, para lo que se apoya en layer-02.
     Va el segundo porque las tablas y las tarjetas de esta app son layer-02:
     con gray-80 la cabecera de la tabla salia del mismo color exacto que su
     cuerpo y no se distinguia de el. En claro los dos pasos valen gray-20,
     asi que alli esto no mueve nada. */
  --layer-accent:          var(--cds-gray-70);
  --layer-selected-hover:  #474747;
  --field-01:              var(--cds-gray-90);
  --field-02:              var(--cds-gray-80);
  /* Mismo caso. g100 separa border-subtle-01 gray-80, para lo dibujado sobre
     layer-01, de border-subtle-02 gray-70, para lo dibujado sobre layer-02.
     Este tema aplana los dos en un token, asi que toma el segundo: tarjetas,
     tablas, modales, cajones, popovers y barras son todos layer-02, y con
     gray-80 la linea salia del color exacto de la superficie que tenia
     debajo. Contraste 1.00: no es que se viera poco, es que no estaba. */
  --border-subtle:         var(--cds-gray-70);
  /* El mismo escalon en g100: sobre layer-01 (gray-90) la linea es gray-80. */
  --border-subtle-01:      var(--cds-gray-80);
  --border-strong:         var(--cds-gray-60);
  --border-interactive:    var(--cds-blue-50);

  --text-primary:          var(--cds-gray-10);
  --text-secondary:        var(--cds-gray-30);
  --text-placeholder:      var(--cds-gray-60);
  --text-on-color:         var(--cds-white);
  --text-helper:           var(--cds-gray-50);
  --text-disabled:         var(--cds-gray-70);
  --link-primary:          var(--cds-blue-40);
  --text-error:            var(--cds-red-40);

  --interactive:           var(--cds-blue-50);

  /* En g100 el anillo de foco es blanco, no azul. */
  --focus:                 var(--cds-white);
  --focus-inverse:         var(--cds-blue-60);

  --button-primary:        var(--cds-blue-60);
  --button-primary-hover:  #0353e9;
  --button-secondary:      var(--cds-gray-60);
  --button-secondary-hover:#5e5e5e;

  --icon-primary:          var(--cds-gray-10);
  --icon-secondary:        var(--cds-gray-30);

  /* Estados: sin redefinir heredaban del tema claro, pensado para fondo blanco.
     El verde 50 sobre Gray 100 se queda en 4.0:1, por debajo del minimo AA de
     4.5:1. Carbon sube un escalon la paleta de estado en oscuro. */
  --support-success:       var(--cds-green-40);
  --support-error:         var(--cds-red-50);
  --support-warning:       var(--cds-yellow-30);
  --support-info:          var(--cds-blue-50);

  /* Tag en oscuro: la formula se invierte respecto al tema claro. Carbon g100
     pone el fondo en el paso 70 y la tinta en el 20, para conservar el
     contraste sobre gray-100. El gris es la excepcion: 70 sobre 10. */
  --tag-background-gray:    var(--cds-gray-70);
  --tag-color-gray:         var(--cds-gray-10);
  --tag-background-blue:    var(--cds-blue-70);
  --tag-color-blue:         var(--cds-blue-20);
  --tag-background-green:   var(--cds-green-70);
  --tag-color-green:        var(--cds-green-20);
  --tag-background-red:     var(--cds-red-70);
  --tag-color-red:          var(--cds-red-20);
  --tag-background-purple:  var(--cds-purple-70);
  --tag-color-purple:       var(--cds-purple-20);
  --tag-background-magenta: var(--cds-magenta-70);
  --tag-color-magenta:      var(--cds-magenta-20);
  --tag-background-teal:    var(--cds-teal-70);
  --tag-color-teal:         var(--cds-teal-20);
  --tag-background-cyan:    var(--cds-cyan-70);
  --tag-color-cyan:         var(--cds-cyan-20);

  /* Extension propia, misma inversion. */
  --tag-background-warning: var(--cds-orange-70);
  --tag-color-warning:      var(--cds-orange-20);
  --tag-background-caution: var(--cds-yellow-70);
  --tag-color-caution:      var(--cds-yellow-20);

  /* El acento de marca acompana a --interactive, que en oscuro ya sube a
     blue-50. Dejarlo en blue-60 partia en dos los acentos de la interfaz:
     el borde activo del sidenav se veia mas apagado que sus iconos. */
  --brand:                 var(--cds-blue-50);

  --overlay:               rgba(0,0,0,.65);
  --skeleton-bg:           #333333;
  --skeleton-shine:        #4a4a4a;
  --shadow-sm:             0 2px 6px rgba(0,0,0,.4);
  --shadow-md:             0 4px 16px rgba(0,0,0,.5);

  /* Sidenav en tema oscuro */
  --brand-soft:            rgba(69,137,255,.16);
  --sidenav-bg:            var(--cds-gray-100);
  --sidenav-active-bg:     var(--cds-gray-90);
  --sidenav-text:          var(--cds-gray-30);
  --sidenav-text-strong:   var(--cds-gray-10);
  --sidenav-hover:         var(--cds-gray-90);
  --sidenav-border:        var(--cds-gray-80);

  /* ---------- Notificaciones (oscuro) ----------
     Carbon no aclara el fondo en tema oscuro: usa la capa y deja que el borde
     y el icono lleven el color de estado. Un tinte pastel sobre fondo negro
     seria un parche luminoso y perderia la jerarquia de la pagina. */
  --notification-bg-success:   var(--cds-gray-80);
  --notification-bg-error:     var(--cds-gray-80);
  --notification-bg-warning:   var(--cds-gray-80);
  --notification-bg-info:      var(--cds-gray-80);
  --notification-text-success: var(--cds-gray-10);
  --notification-text-error:   var(--cds-gray-10);
  --notification-text-warning: var(--cds-gray-10);
  --notification-text-info:    var(--cds-gray-10);

  /* ---------- Carbon for AI (oscuro) ----------
     Sobre fondo oscuro el resplandor se ve mas, asi que baja de opacidad, y
     los bordes suben un escalon de la paleta para mantener el contraste. */
  --ai-aura-start:         rgba(120, 169, 255, 0.13);
  --ai-aura-end:           rgba(165, 110, 255, 0);
  --ai-border-start:       var(--cds-blue-40);
  --ai-border-end:         var(--cds-purple-50);
  --ai-inner-shadow:       rgba(120, 169, 255, 0.08);
  --ai-popover-bg:         var(--cds-gray-90);
  --ai-text:               var(--cds-blue-40);
  --ai-skeleton:           rgba(120, 169, 255, 0.16);
}

/* =====================================================================
   base.css — Reset + tipografía + utilidades base (Carbon)
   ===================================================================== */
*, *::before, *::after { box-sizing: border-box; }
html, body { height: 100%; }
body {
  margin: 0;
  font-family: var(--font-sans);
  font-size: 14px;
  line-height: 1.4;
  color: var(--text-primary);
  background: var(--background);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}
a { color: var(--link-primary); text-decoration: none; }
a:hover { text-decoration: underline; }
button { font-family: inherit; cursor: pointer; }
h1,h2,h3,h4,h5 { margin: 0; font-weight: var(--type-weight-semibold); color: var(--text-primary); }
h1 { font-size: 28px; line-height: 1.25; }
h2 { font-size: 20px; }
h3 { font-size: 16px; }
p { margin: 0; }
code, .mono { font-family: var(--font-mono); }
::selection { background: var(--cds-blue-20); }

/* Scrollbar discreto estilo Carbon */
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-thumb { background: var(--border-strong); border-radius: 0; }
::-webkit-scrollbar-track { background: transparent; }

/* ---- Helpers ---- */
.u-flex { display: flex; }
.u-between { display: flex; align-items: center; justify-content: space-between; }
.u-center { display: flex; align-items: center; }
.u-gap-4 { gap: 4px; } .u-gap-8 { gap: 8px; } .u-gap-12 { gap: 12px; } .u-gap-16 { gap: 16px; }
.u-grow { flex: 1; }
.u-muted { color: var(--text-secondary); }
.u-helper { color: var(--text-helper); font-size: 12px; }
.u-mono { font-family: var(--font-mono); font-size: 12px; }
.u-right { text-align: right; }
.u-nowrap { white-space: nowrap; }
.u-truncate { max-width: 240px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.u-hidden { display: none !important; }
.u-mt-8 { margin-top: 8px; } .u-mt-16 { margin-top: 16px; } .u-mt-24 { margin-top: 24px; }
.u-mb-8 { margin-bottom: 8px; } .u-mb-16 { margin-bottom: 16px; } .u-mb-24 { margin-bottom: 24px; }

/* ---- Botones Carbon ---- */
.btn {
  display: inline-flex; align-items: center; gap: 8px;
  height: 40px; padding: 0 16px; border: 1px solid transparent;
  font-size: 14px; font-weight: var(--type-weight-regular); letter-spacing: .16px;
  transition: background var(--dur-fast) var(--ease), border-color var(--dur-fast);
  white-space: nowrap; user-select: none; min-width: 0;
}
.btn svg { width: 16px; height: 16px; flex: none; }
.btn--primary { background: var(--button-primary); color: var(--text-on-color); }
.btn--primary:hover { background: var(--button-primary-hover); }
.btn--primary:active { background: var(--button-primary-active); }
.btn--secondary { background: var(--button-secondary); color: var(--text-on-color); }
.btn--secondary:hover { background: var(--button-secondary-hover); }
.btn--danger { background: var(--button-danger); color: var(--text-on-color); }
.btn--danger:hover { background: var(--button-danger-hover); }
.btn--ghost { background: transparent; color: var(--link-primary); padding: 0 12px; }
.btn--ghost:hover { background: var(--layer-hover); }
.btn--tertiary { background: transparent; color: var(--interactive); border-color: var(--interactive); }
.btn--tertiary:hover { background: var(--interactive); color: var(--text-on-color); }
.btn--sm { height: 32px; padding: 0 12px; font-size: 13px; }
.btn--icon { width: 40px; height: 40px; padding: 0; justify-content: center; background: transparent; color: var(--icon-primary); }
.btn--icon:hover { background: var(--layer-hover); }
.btn:disabled { background: var(--text-disabled); color: var(--text-on-color); cursor: not-allowed; }

/* ---- Campos de formulario Carbon ---- */
.field { display: flex; flex-direction: column; gap: 6px; margin-bottom: 16px; }
.field__label { font-size: 12px; color: var(--text-secondary); }
.field__label .req { color: var(--support-error); }
.field__control,
.field input[type=text], .field input[type=email], .field input[type=number],
.field input[type=password], .field input[type=date], .field input[type=url],
.field input[type=color], .field select, .field textarea {
  width: 100%; height: 40px; padding: 0 12px;
  background: var(--field-01); color: var(--text-primary);
  border: none; border-bottom: 1px solid var(--border-strong);
  font-family: inherit; font-size: 14px; outline: none;
  transition: outline var(--dur-fast);
}
.field textarea { height: auto; min-height: 96px; padding: 10px 12px; resize: vertical; line-height: 1.45; }
.field input:focus, .field select:focus, .field textarea:focus {
  outline: 2px solid var(--border-interactive); outline-offset: -2px;
}
.field input::placeholder, .field textarea::placeholder { color: var(--text-placeholder); }
.field input[type=color] { padding: 4px; height: 40px; cursor: pointer; }
.field__help { font-size: 12px; color: var(--text-helper); }
.field--inline { flex-direction: row; align-items: center; gap: 10px; }
.field--checkbox { flex-direction: row; align-items: center; gap: 10px; cursor: pointer; }
.field--checkbox input { width: 18px; height: 18px; accent-color: var(--interactive); }
.form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 0 24px; }
.form-grid .field--full { grid-column: 1 / -1; }
.form-section-title { font-size: 12px; font-weight: var(--type-weight-semibold); text-transform: uppercase; letter-spacing: .5px;
  color: var(--text-helper); margin: 8px 0 12px; grid-column: 1 / -1; border-bottom: 1px solid var(--border-subtle); padding-bottom: 6px; }

/* ---------- Texto solo para lectores de pantalla ----------
   Lo que el diseno comunica con color o forma tiene que llegar tambien como
   texto: un estado pintado de verde no existe para quien no ve la pantalla.
   No se usa display:none, que lo sacaria tambien del lector. */
.solo-lectores { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; border: 0; }

/* =====================================================================
   layout.css — Shell: Header (marca cuadrada + switcher), Sidenav clara,
   Breadcrumb y Content. Línea visual basada en auth-multiempresa-carbon.
   ===================================================================== */
.app-shell { min-height: 100vh; }

/* ====================== Header superior ====================== */
.app-header {
  position: fixed; top: 0; left: 0; right: 0; height: var(--header-h); z-index: 8000;
  display: flex; align-items: center; background: var(--cds-gray-100); color: var(--text-on-color);
  border-bottom: 1px solid var(--cds-gray-80);
}
/* El header es una superficie Gray 100 fija, no sigue el tema de la pagina. Por
   eso toma pasos de paleta y no tokens semanticos: en claro quedaria un borde
   gris claro bajo una barra oscura. En oscuro el fondo de pagina tambien es
   gray-100, y lo que separa las dos superficies es el borde inferior, que es
   como Carbon resuelve el UI Shell. Antes se forzaba #000, un negro que la
   paleta no tiene: se leia mas duro que el resto de la interfaz. */

.app-header__menu { width: 48px; height: 48px; display: grid; place-items: center; color: var(--text-on-color); background: transparent; border: none; }
.app-header__menu:hover { background: var(--cds-gray-90); }

.app-header__brand { display: flex; align-items: center; gap: var(--sp-03); padding: 0 var(--sp-05) 0 var(--sp-02); height: 100%; }
.app-header__brand:hover { text-decoration: none; }
.brand-sq { width: 24px; height: 24px; background: var(--brand); display: grid; place-items: center;
  font-size: var(--type-size-01); font-weight: var(--type-weight-bold); color: #fff; flex: none; transition: background var(--dur-base) var(--ease); }
.app-header__brand b { font-weight: var(--type-weight-semibold); color: #fff; }
.app-header__brand .sep { color: var(--cds-gray-60); }
.app-header__brand .brand-company { color: var(--cds-gray-40); max-width: 16rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.app-header__spacer { flex: 1; }
.h-divider { width: 1px; height: 1.5rem; background: var(--cds-gray-80); flex: none; }

/* Company switcher (multiempresa) */
.switcher { position: relative; height: 100%; }
.switcher__btn { height: 100%; display: flex; align-items: center; gap: var(--sp-03); padding: 0 var(--sp-05);
  color: #fff; background: transparent; border: none; font-size: var(--type-size-02); transition: background var(--dur-fast); }
.switcher__btn:hover, .switcher__btn[aria-expanded="true"] { background: var(--cds-gray-90); }
.sw-dot { width: 10px; height: 10px; background: var(--brand); flex: none; transition: background var(--dur-base) var(--ease); }
.sw-name { max-width: 11rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.switcher__btn .chev { transition: transform .15s; width: 16px; height: 16px; }
.switcher__btn[aria-expanded="true"] .chev { transform: rotate(180deg); }
.switcher__panel { position: absolute; top: var(--header-h); right: 0; width: 22rem; background: var(--cds-gray-90);
  display: none; box-shadow: var(--shadow-md); z-index: 9500; max-height: 70vh; overflow-y: auto; }
.switcher__panel.open { display: block; }
.switcher__label { font-size: var(--type-size-01); letter-spacing: .32px; color: var(--cds-gray-50); padding: var(--sp-04) var(--sp-05) var(--sp-02); }
.sw-item { display: flex; align-items: center; gap: var(--sp-04); width: 100%; text-align: left;
  padding: var(--sp-04) var(--sp-05); color: #fff; background: transparent; border: none; font-size: var(--type-size-02); }
.sw-item:hover { background: var(--cds-gray-80); }
.sw-item .swi-logo { width: 28px; height: 28px; flex: none; display: grid; place-items: center; font-size: var(--type-size-01); font-weight: var(--type-weight-bold); color: #fff; }
.sw-item .swi-info { flex: 1; min-width: 0; }
.sw-item .swi-info b { display: block; font-weight: var(--type-weight-semibold); font-size: var(--type-size-02); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sw-item .swi-info span { font-size: var(--type-size-01); color: var(--cds-gray-40); }
.sw-item .check { color: var(--cds-blue-40); flex: none; opacity: 0; width: 18px; height: 18px; }
.sw-item.active .check { opacity: 1; }
.sw-item .swi-logo svg { width: 14px; height: 14px; }

/* Acciones del header */
.app-header__actions { display: flex; align-items: center; height: 100%; }
.app-header__btn { width: 48px; height: 48px; display: grid; place-items: center; color: #fff; background: transparent; border: none; position: relative; }
.app-header__btn:hover { background: var(--cds-gray-90); }
.app-header__btn .dot { position: absolute; top: 12px; right: 12px; width: 8px; height: 8px; border-radius: 50%;
  background: var(--support-error); border: 2px solid var(--cds-gray-100); }
.app-header__user { display: flex; align-items: center; gap: var(--sp-03); padding: 0 var(--sp-05); height: 100%; color: #fff; background: transparent; border: none; }
.app-header__user .hu-meta { line-height: 1.1; text-align: right; }
.app-header__user .hu-meta b { display: block; font-weight: var(--type-weight-semibold); font-size: var(--type-size-02); }
.app-header__user .hu-meta span { font-size: var(--type-size-01); color: var(--cds-gray-40); }
.app-header__avatar { width: 28px; height: 28px; border-radius: 50%; background: var(--brand); display: grid; place-items: center;
  font-size: var(--type-size-01); font-weight: var(--type-weight-bold); color: #fff; flex: none; transition: background var(--dur-base) var(--ease); }

/* ====================== Sidenav (clara) ====================== */
.app-sidebar {
  position: fixed; top: var(--header-h); bottom: 0; left: 0; width: var(--sidebar-w); z-index: 7000;
  display: flex; flex-direction: column; background: var(--sidenav-bg); color: var(--sidenav-text); overflow: hidden;
  transition: width var(--dur-base) var(--ease); border-right: 1px solid var(--sidenav-border);
}
.app-sidebar__nav { display: flex; flex-direction: column; height: 100%; min-height: 0; }
.app-sidebar__scroll { flex: 1; min-height: 0; overflow-y: auto; overflow-x: hidden; padding: var(--sp-03) 0 var(--sp-04); }
.app-sidebar__footer { flex: none; padding: var(--sp-05); border-top: 1px solid var(--sidenav-border); background: var(--sidenav-bg); }
/* Es un boton, pero se ve exactamente igual que el texto gris que habia antes:
   el guiño que esconde (ico-taller.js) no se anuncia. De ahi `cursor: default`
   y el reset completo de la apariencia de boton.

   `user-select: none` no es cosmetico: el gesto son tres clics seguidos y un
   triple clic sobre texto normal selecciona la linea entera, asi que el pie
   quedaba resaltado en azul justo cuando Ico aparece.

   El `min-height` reserva de una vez el alto que ocupa Ico (19px contra los
   16 de la linea de texto). Sin el, el pie del menu daba un salto de tres
   pixeles en el momento exacto en que Ico entra, que es cuando menos falta
   hace que se mueva algo mas. */
.app-sidebar__version {
  /* `max-width` porque un <button> se dimensiona a su contenido aunque sea
     un contenedor flex: sin el, el boton crecia mas que el menu y no habia
     nada que comprimir, asi que el `min-width: 0` de abajo no llegaba a
     servir de nada y era Ico el que se salia. */
  display: flex; align-items: center; gap: var(--sp-03); min-height: 20px; max-width: 100%;
  font-size: var(--type-size-01); color: var(--text-helper);
  background: none; border: 0; padding: 0; margin: 0;
  font-family: inherit; text-align: left; cursor: default;
  user-select: none; -webkit-tap-highlight-color: transparent;
  transition: color var(--dur-fast);
}
/* El numero se acorta antes que empujar a Ico fuera del menu.
   `min-width: 0` es lo que lo hace posible: dentro de un flex un hijo con
   texto arranca en `min-width: auto`, que le impide encogerse por debajo de
   su contenido. Sin esta linea el `text-overflow` no llegaba a actuar nunca,
   el texto se quedaba entero y era Ico -que va con `flex: none`- el que se
   salia por la derecha y lo recortaba el sidebar. Se ve en cuanto el menu
   baja a 13rem, por debajo de 1056px de ventana. */
.app-sidebar__version-txt { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Unico rastro: el numero se aclara mientras se pulsa. Suficiente para que
   quien este tanteando sepa que algo responde. */
.app-sidebar__version:active { color: var(--text-secondary); }
.app-sidebar__version:focus-visible { outline: 2px solid var(--border-interactive); outline-offset: 2px; }
.app-sidebar__group-label { font-size: var(--type-size-01); text-transform: uppercase; letter-spacing: .6px; color: var(--cds-gray-60);
  padding: var(--sp-05) var(--sp-05) var(--sp-03); font-weight: var(--type-weight-semibold); white-space: nowrap; }
/* 32px es la altura del enlace del side nav de Carbon
   (ui-shell/side-nav/_side-nav.scss: min-block-size de 4 mini-unidades). Los
   40px que habia no corresponden a ningun enlace del sistema: Carbon solo
   define 32px y, con el modificador large, 48px. Va como min-height y no como
   height para que una etiqueta larga que envuelva no se corte. */
.app-sidebar__link { display: flex; align-items: center; gap: var(--sp-04); min-height: 2rem; padding: 0 var(--sp-05);
  color: var(--sidenav-text); font-size: var(--type-size-02); white-space: nowrap; border-left: 3px solid transparent;
  transition: background var(--dur-fast-01) var(--ease-standard), color var(--dur-fast-01) var(--ease-standard); }
.app-sidebar__link:hover { background: var(--sidenav-hover); color: var(--sidenav-text-strong); text-decoration: none; }
.app-sidebar__link.is-active { background: var(--sidenav-active-bg); color: var(--sidenav-text-strong); border-left-color: var(--brand); font-weight: var(--type-weight-semibold); }
.app-sidebar__link svg { width: 16px; height: 16px; flex: none; color: var(--cds-gray-60); }
.app-sidebar__link:hover svg, .app-sidebar__link.is-active svg { color: var(--brand); }
.app-sidebar__dot { width: 4px; height: 4px; margin: 0 6px; border-radius: 50%; background: var(--cds-gray-50); flex: none; }
.app-sidebar__link:hover .app-sidebar__dot, .app-sidebar__link.is-active .app-sidebar__dot { background: var(--brand); }
.app-sidebar__link .lbl { overflow: hidden; text-overflow: ellipsis; min-width: 0; }

/* Sangria por nivel. Vivian como estilos inline en el blade, donde ganaban al
   rail colapsado y le dejaban el texto desplazado fuera de vista. */
.app-sidebar__link--l2 { padding-left: var(--sp-07); }
/* Los 48px solo funcionan porque el nivel 3 lleva punto, igual que el 2: el
   texto acaba cayendo en 76, un escalon justo por debajo de los 60 del
   padre. Sin punto -como estaba- el texto se plantaba en los 48 de la
   sangria, doce pixeles a la IZQUIERDA del de su padre, y el ultimo nivel
   parecia salirse del grupo en vez de entrar en el.

   Tampoco encoge ya la letra. La profundidad se dice con la sangria: Carbon
   no cambia el cuerpo por nivel, SideNavMenuItem usa el mismo este donde
   este, y a 12px el ultimo nivel se leia como un pie de pagina. */
.app-sidebar__link--l3 { padding-left: var(--sp-09); }

/* Colapsado (rail de iconos en escritorio).
   Encerrado en su breakpoint a proposito: por debajo de 880px el sidebar es un
   panel deslizante, no un rail. Sueltas, estas reglas tienen mas especificidad
   que la anchura del bloque movil, asi que un `app--collapsed` que sobreviviera
   a un cambio de tamano dejaba el panel en 48px y sin textos. */
@media (min-width: 881px) {
  .app--collapsed .app-sidebar { width: var(--sidebar-collapsed-w); }
  .app--collapsed .app-sidebar__link { padding: 0; justify-content: center; gap: 0; }
  .app--collapsed .app-sidebar__link .lbl { display: none; }
  .app--collapsed .app-sidebar__group-label {
    font-size: 0; padding: 0; height: 1px; margin: var(--sp-03) var(--sp-04);
    background: var(--sidenav-border); overflow: hidden; letter-spacing: 0;
  }
  .app--collapsed .app-main { margin-left: var(--sidebar-collapsed-w); }

  /* En el rail solo caben iconos. Un grupo que quedara abierto seguia soltando
     sus enlaces, y como ahi las etiquetas van ocultas, lo que aparecia era una
     columna de puntos sueltos: 13 enlaces de 40px sin nada que los explique.
     Se oculta el contenido, no se cierra el grupo, para que al expandir de
     nuevo el usuario recupere donde estaba. */
  /* `!important` porque Blade emite el contenedor de cada grupo con un
     `style="display:flex"` inline, y el inline gana a cualquier selector. */
  .app--collapsed .app-sidebar details > *:not(summary) { display: none !important; }
  .app--collapsed .app-sidebar details summary .arrow { display: none; }
  /* Mismo caso: el summary trae `justify-content: space-between` inline para
     empujar la flecha al extremo. Con la flecha oculta y el rail en 48px, eso
     dejaba el icono pegado al borde izquierdo en vez de centrado. */
  .app--collapsed .app-sidebar details summary { justify-content: center !important; padding: 0; gap: 0; }

  /* El pie no entra en 48px: el numero de version se partia en tres lineas.
     Se va con el, de paso, el taller de Ico: en un rail de iconos no cabe. */
  .app--collapsed .app-sidebar__footer { display: none; }
}

/* ====================== Contenido ====================== */
.app-main { margin-left: var(--sidebar-w); margin-top: var(--header-h);
  transition: margin-left var(--dur-base) var(--ease); min-height: calc(100vh - var(--header-h)); background: var(--layer-01); }
.app-content { padding: var(--sp-07) var(--sp-08) var(--sp-09); max-width: 1640px; }

/* ====================== Breadcrumb ====================== */
/* Breadcrumb de Carbon (components/breadcrumb/_breadcrumb.scss).
   El tamano era 12px, que en Carbon corresponde solo a la variante --sm; el
   por defecto es body-compact-01, 14px.
   Y el nodo actual iba en azul, el mismo color que los enlaces navegables:
   Carbon lo pinta en gris 100 precisamente para que NO se lea como enlace,
   porque es donde ya estas. */
.breadcrumb { display: flex; align-items: center; gap: var(--sp-03); font-size: var(--type-size-02);
  line-height: 1.28572; letter-spacing: .16px; color: var(--text-secondary); margin-bottom: var(--sp-04); flex-wrap: wrap; }
.breadcrumb a { color: var(--link-primary); }
.breadcrumb .sep { color: var(--text-placeholder); }
.breadcrumb .current { color: var(--text-primary); cursor: auto; }
.breadcrumb .current:hover { text-decoration: none; }

/* ====================== Encabezado de módulo ====================== */
.page-head { margin-bottom: var(--sp-06); }
.page-head__title { display: flex; align-items: center; gap: var(--sp-04); }
.page-head__title > span { color: var(--brand); display: inline-flex; }
.page-head__title > span svg { width: 22px; height: 22px; }
.page-head h1 { font-size: var(--type-size-07); font-weight: var(--type-weight-light); letter-spacing: -.02em; }
.page-head__desc { color: var(--text-secondary); margin-top: var(--sp-02); max-width: 760px; font-size: var(--type-size-02); }
.page-head__row { display: flex; align-items: flex-end; justify-content: space-between; gap: var(--sp-05); flex-wrap: wrap; }

/* ====================== Responsive ====================== */
@media (max-width: 1056px) {
  .app-content { padding: var(--sp-06); }
  .app-sidebar { width: 13rem; }
  .app-main { margin-left: 13rem; }
  .app--collapsed .app-main { margin-left: var(--sidebar-collapsed-w); }
}
@media (max-width: 880px) {
  .app-sidebar { transform: translateX(-100%); transition: transform var(--dur-base) var(--ease); width: var(--sidebar-w); z-index: 7500; }
  .app--mobile-open .app-sidebar { transform: translateX(0); }
  .app-main, .app--collapsed .app-main { margin-left: 0 !important; }
  .app-header__user .hu-meta { display: none; }
  .app-header__brand .brand-company, .app-header__brand .sep { display: none; }
  .sw-name { max-width: 7rem; }
}
@media (max-width: 672px) {
  .app-content { padding: var(--sp-05) var(--sp-04) var(--sp-08); }
  .page-head h1 { font-size: var(--type-size-06); }
  .switcher__btn .sw-name { display: none; }
  /* Anclado al boton con `right: -56px` y 100vw de ancho, el panel se salia
     101px por la izquierda de la pantalla: se leia "ONTEXTO" y "a Inicial".
     En movil se ancla al viewport, que es lo que ocupa. */
  .switcher__panel { position: fixed; left: 0; right: auto; width: 100vw; }
  .app-header__brand b { display: none; }
}

/* ---------- Foco de teclado del shell ----------
   layout.css no tenia ni una sola regla de foco: ni la cabecera, ni el
   conmutador de empresa, ni un solo enlace de la barra lateral. Quien navega
   con el tabulador no veia donde estaba, y eso atraviesa todas las pantallas
   del ERP porque el shell es el mismo en todas.

   Carbon marca el foco con un anillo de 2px del token focus, hacia dentro
   (utilities/_focus-outline.scss). Sobre la barra lateral oscura el token ya
   resuelve a blanco en tema oscuro, asi que contrasta en ambos temas. */
.app-header__btn:focus-visible,
.app-header__menu:focus-visible,
.app-header__brand:focus-visible,
.app-header__user:focus-visible,
.app-sidebar__link:focus-visible,
.switcher__btn:focus-visible,
.sw-item:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: -2px;
}

/* El enlace es la excepcion: Carbon usa para el el anillo de 1px pegado al
   texto y le anade subrayado, no el de 2px hacia dentro de los controles
   (components/link/_link.scss). */
.breadcrumb a:focus-visible {
  outline: 1px solid var(--focus);
  outline-offset: 0;
  text-decoration: underline;
}

/* =====================================================================
   components.css — Button, DataTable, Toolbar, Modal, Drawer, Badge, Tag,
   Toast, Notification, Skeleton, Pagination, Empty/Loading states
   ===================================================================== */

/* ---------- Icono ----------
   Ocultar un <x-icono> con el atributo `hidden` no funciona solo. La hoja
   del navegador declara `[hidden] { display: none }` dentro del espacio de
   nombres de HTML, y un <svg> esta en el de SVG: la regla no le alcanza
   nunca, por mucho que la propiedad `hidden` del elemento sea true. A eso
   se suma que llega con especificidad cero.

   Lo mismo que ya resuelve ico.css para `.ico[hidden]`. Hace falta, por
   ejemplo, en el boton de tema de la cabecera, que lleva el sol y la luna
   dibujados y solo alterna cual se ve. */
.icono[hidden] { display: none; }

/* ---------- Button ----------
   Estaba dentro de un bloque <style> de layouts/app.blade.php, que es el
   ultimo sitio donde uno busca la definicion del boton primario de un sistema
   de diseno. Se trae aqui y se deduplica: las tres variantes repetian el mismo
   bloque de nueve propiedades y solo cambiaba el fondo.

   Valores de packages/styles/scss/components/button/_vars.scss y el estilo
   body-compact-01: 14px, peso 400, interlineado 1.28572, letter-spacing
   0.16px, radio 0. El radio y el peso ya estaban bien; lo que faltaba era la
   altura fija, el letter-spacing y una transicion con nombre.

   Alto 40px, que es el tamano field de Carbon. Antes no habia altura y los
   botones median entre 34 y 42px segun los estilos inline de cada vista;
   medido en Operaciones > Servicios habia tres alturas distintas en la misma
   pantalla.

   PENDIENTE, y a proposito: Carbon usa padding lateral asimetrico (15px a la
   izquierda, 63px a la derecha) con justify-content:space-between, para dejar
   el canalon donde vive el icono. No se aplica aqui porque el ERP escribe el
   icono ANTES de la etiqueta y Carbon lo pone despues; con space-between el
   icono se iria al extremo izquierdo y el texto al derecho, separados por 63px.
   Arreglarlo pide invertir el marcado en las vistas, que es otra tarea. */
.btn-carbon,
.btn-carbon-secondary,
.btn-carbon-danger {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-03);
  min-block-size: 40px;
  padding: 0 var(--sp-05);
  /* Carbon no pone `border: none` sino un borde de 1px transparente
     (button-outline-width en _mixins.scss). Asi las variantes que si llevan
     borde -secondary con contorno, tertiary- no cambian de tamano al
     mostrarlo, y el anillo de foco tiene sobre que asentarse.
     El box-sizing global es border-box (base.css:4), asi que el pixel no
     altera los 40px. */
  border: 1px solid transparent;
  border-radius: 0;
  max-inline-size: 320px;
  font-family: var(--font-sans);
  font-size: var(--type-size-02);
  font-weight: var(--type-weight-regular);
  line-height: 1.28572;
  letter-spacing: .16px;
  color: var(--text-on-color);
  text-decoration: none;
  cursor: pointer;
  transition: background var(--dur-fast-01) var(--ease-entrance);
}

.btn-carbon           { background: var(--button-primary); }
.btn-carbon:active    { background: var(--button-primary-active); }
.btn-carbon-secondary        { background: var(--button-secondary); }
.btn-carbon-secondary:active { background: var(--button-secondary-active); }
.btn-carbon-danger        { background: var(--button-danger); }
.btn-carbon-danger:active { background: var(--button-danger-active); }

/* Carbon condiciona el hover a que el dispositivo pueda apuntar. En una
   tactil, un :hover sin esta guarda se queda pegado despues del toque y el
   boton parece seleccionado hasta que tocas en otro sitio. */
@media (any-hover: hover) {
  .btn-carbon:hover           { background: var(--button-primary-hover); }
  .btn-carbon-secondary:hover { background: var(--button-secondary-hover); }
  .btn-carbon-danger:hover    { background: var(--button-danger-hover); }
}

/* Tamano pequenio. Las vistas lo improvisan hoy con estilos en linea que
   encogen la letra a 12px; Carbon nunca cambia la tipografia entre tamanos,
   solo la altura. El texto se queda en 14px. */
.btn-carbon--sm,
.btn-carbon-secondary.btn-carbon--sm,
.btn-carbon-danger.btn-carbon--sm { min-block-size: 32px; }

/* ---------- Campo con acción al lado ----------
   Un campo con su botón pegado: consultar en SUNAT, buscar, añadir. Cinco
   vistas lo montaban con un flex escrito en el atributo style, y en las cinco
   el campo se quedaba sin crecer -el botón ocupaba lo suyo y al campo le
   sobraban 34px de ancho-, porque nadie le decía que estirase.

   El botón mide lo mismo que el campo y no menos. En Carbon un control y su
   acción comparten altura; con el botón pequeño al lado de un campo de 40px
   quedaban dos alturas distintas en la misma línea. La regla va aquí y no en
   la vista para que siga valiendo aunque alguien le ponga --sm. */
/* Con tope: sin el, al darle el sitio de dos columnas el campo se estiraba a
   593px para escribir un RUC de once digitos. */
.campo-accion { display: flex; gap: var(--sp-03); align-items: flex-start; max-inline-size: 24rem; }
.campo-accion .form-control { flex: 1; min-inline-size: 0; }
.campo-accion .btn-carbon,
.campo-accion .btn-carbon-secondary,
.campo-accion .btn-carbon-danger { flex: none; white-space: nowrap; min-block-size: 40px; }

/* Y ocupa el sitio de dos campos cuando está dentro de una rejilla: el botón
   se lleva media columna, y lo que queda no da ni para un RUC. Fuera de una
   rejilla la regla no hace nada.

   `1 / -1` y no `span 2`: en una rejilla de UNA sola columna -que es como
   quedan estos formularios en el movil- pedir dos columnas no encoge el
   campo, sino que le inventa a la rejilla una segunda columna implicita,
   ancha como su contenido. El formulario de gastos se salia 37px por la
   derecha con el "Consultar" del RUC cortado, y el modal no tenia como
   desplazarse. `1 / -1` dice "de la primera a la ultima", que con una columna
   es esa misma y con dos son las dos. */
.form-group:has(.campo-accion) { grid-column: 1 / -1; }

/* La línea de resultado que deja la consulta: "Consultando...", el nombre que
   devolvió SUNAT, o el error. Vivía como .document-lookup-status en dos vistas
   y como .fleet-lookup-status en otra, con el mismo dibujo. */
.campo-accion__resultado { display: flex; align-items: center; gap: var(--sp-03);
  margin-top: var(--sp-02); min-block-size: 1.2rem; }
.campo-accion__estado { display: block; font-size: var(--type-size-01); color: var(--text-secondary); }
.campo-accion__estado.is-error   { color: var(--support-error); }
.campo-accion__estado.is-success { color: var(--support-success); }

/* Foco: Carbon pide un anillo de 2px con el token focus, hacia dentro para
   que no desplace al vecino. No existia ninguno en los botones. */
.btn-carbon:focus-visible,
.btn-carbon-secondary:focus-visible,
.btn-carbon-danger:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: -2px;
}

/* Deshabilitado: tampoco existia, asi que un boton inerte se veia identico a
   uno pulsable. */
.btn-carbon:disabled,
.btn-carbon-secondary:disabled,
.btn-carbon-danger:disabled,
.btn-carbon[aria-disabled="true"],
.btn-carbon-secondary[aria-disabled="true"],
.btn-carbon-danger[aria-disabled="true"] {
  background: var(--button-disabled);
  color: var(--text-on-color-disabled, var(--text-disabled));
  cursor: not-allowed;
}

/* ---------- Text input / Select / Textarea ----------
   De packages/styles/scss/components/text-input/_text-input.scss. Tambien
   vivia en el <style> de layouts/app.blade.php, como el boton.

   El cambio visible es el borde. Carbon no encierra el campo en una caja:
   pone `border: none` y una sola linea inferior de 1px en border-strong
   (gray-50). El ERP dibujaba el recuadro completo y ademas con border-subtle
   (gray-20), un gris tan claro que el campo casi no se distinguia del fondo.

   Carbon separa TextInput, Select y TextArea en componentes distintos, y aqui
   las tres cosas comparten la clase .form-control: 56 vistas la ponen en un
   <select> y 35 en un <textarea> con rows. Por eso la altura fija de 40px se
   aplica solo a input y select; el textarea conserva la altura que le dan sus
   filas y recibe padding vertical en su lugar. Fijarle 40px a todos habria
   aplastado los textarea de rows="5" a una sola linea. */
.form-control {
  width: 100%;
  background: var(--field-01);
  border: none;
  border-bottom: 1px solid var(--border-strong);
  padding-inline: var(--sp-05);
  color: var(--text-primary);
  font-family: var(--font-sans);
  font-size: var(--type-size-02);
  font-weight: var(--type-weight-regular);
  line-height: 1.28572;
  letter-spacing: .16px;
  /* Anillo reservado en transparente: si apareciera solo al enfocar, el campo
     daria un salto de 2px al recibir el foco. */
  outline: 2px solid transparent;
  outline-offset: -2px;
  transition: background-color var(--dur-fast-01) var(--ease-standard),
              outline var(--dur-fast-01) var(--ease-standard);
}
input.form-control,
select.form-control { block-size: 40px; }
textarea.form-control { padding-block: var(--sp-04); min-block-size: 40px; }

/* El galon del combo. Medido en components-select--default: Carbon apaga la
   flecha del navegador con `appearance: none` y dibuja la suya, 16px de lado,
   pegada a 16px del borde derecho, y reserva 48px de relleno para que ningun
   texto se le meta debajo.

   Va como imagen de fondo y no como pseudoelemento porque un <select> no
   admite ::before ni ::after: el navegador no deja meterle nada dentro. Y una
   imagen de fondo no entiende de `currentColor`, asi que el glifo hay que
   escribirlo una vez por cada color que necesita. Se guardan aqui, con nombre,
   en lugar de repetirlos en cada regla. El trazado es el mismo `chevron--down`
   que sirve <x-icono>, y el gris apagado es --text-disabled, que es el que ya
   usa el resto del campo cuando se deshabilita. */
:root {
  --galon-abajo: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23161616'%3E%3Cpath d='M8 11 3 6 3.7 5.3 8 9.6 12.3 5.3 13 6z'/%3E%3C/svg%3E");
  --galon-abajo-inerte: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23c6c6c6'%3E%3Cpath d='M8 11 3 6 3.7 5.3 8 9.6 12.3 5.3 13 6z'/%3E%3C/svg%3E");
}
[data-theme="dark"] {
  --galon-abajo: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23f4f4f4'%3E%3Cpath d='M8 11 3 6 3.7 5.3 8 9.6 12.3 5.3 13 6z'/%3E%3C/svg%3E");
  --galon-abajo-inerte: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23525252'%3E%3Cpath d='M8 11 3 6 3.7 5.3 8 9.6 12.3 5.3 13 6z'/%3E%3C/svg%3E");
}

select.form-control {
  appearance: none;
  -webkit-appearance: none;
  padding-inline-end: var(--sp-09);
  background-image: var(--galon-abajo);
  background-repeat: no-repeat;
  background-position: right var(--sp-05) center;
  background-size: 16px 16px;
}
select.form-control:disabled { background-image: var(--galon-abajo-inerte); }

/* Carbon marca el foco con el anillo, no tinendo un borde de 1px: un pixel de
   color no alcanza el contraste que pide la norma de accesibilidad. La regla
   anterior ademas hacia `outline: none`, que deja sin rastro visible a quien
   navega con el tabulador. */
.form-control:focus {
  outline: 2px solid var(--focus);
  outline-offset: -2px;
}

.form-control::placeholder {
  color: var(--text-placeholder);
  /* Firefox rebaja la opacidad del placeholder por su cuenta y desvia el
     color respecto al token. */
  opacity: 1;
}

/* Un campo apagado se veia identico a uno editable. */
/* Solo lectura no es lo mismo que deshabilitado, y Carbon los dibuja
   distinto: el valor de un campo de solo lectura se lee y se copia, asi que
   no se apaga ni se le pone el cursor de prohibido. Se le quita el fondo y se
   deja la linea inferior, que es lo que hace Carbon en su read-only. */
/* `background-color` y no `background`: el atajo tambien reinicia la imagen,
   la repeticion y la posicion, y al combo le borraria el galon -o peor, se lo
   dejaria repetido en mosaico y arrancando en la esquina. */
.form-control[readonly] {
  background-color: transparent;
  border-bottom-color: var(--border-subtle);
}

.form-control:disabled {
  background-color: var(--field-01);
  color: var(--text-disabled);
  -webkit-text-fill-color: var(--text-disabled);
  border-bottom-color: transparent;
  cursor: not-allowed;
}

/* El texto que explica por que un campo esta mal. Estaba escrito solo en
   login.css, que la aplicacion no carga: las pantallas de dentro que lo usaban
   -las guias de remision- pintaban el aviso en el gris del texto normal, sin
   nada que lo distinguiera de la linea de ayuda de al lado. */
.helper-error {
  display: block;
  margin-top: var(--sp-02);
  font-size: var(--type-size-01);
  line-height: 1.33333;
  color: var(--support-error);
}

/* `[hidden]` lo pone la hoja del navegador, y cualquier `display` escrito aqui
   le gana: sin esta linea, un aviso que nace oculto se ve desde el principio.
   Ya paso con `.marca` y con `.notificacion`. */
.helper-error[hidden] { display: none; }

/* ---------- Info rápida (sobre la tabla) ---------- */
.quickinfo { display: flex; align-items: center; gap: var(--sp-05); flex-wrap: wrap;
  background: var(--layer-02); border: 1px solid var(--border-subtle); border-bottom: none;
  padding: 0 var(--sp-05); min-height: 3rem; }
.qi-total { font-size: var(--type-size-02); color: var(--text-secondary); white-space: nowrap; }
.qi-total b { font-size: var(--type-size-05); font-weight: var(--type-weight-light); color: var(--text-primary); margin-right: 6px; }
.qi-sep { width: 1px; height: 1.5rem; background: var(--border-subtle); flex: none; }
.qi-chips { display: flex; align-items: center; gap: var(--sp-05); flex-wrap: wrap; }
.qi-chip { display: inline-flex; align-items: center; gap: 7px; font-size: var(--type-size-02); color: var(--text-secondary); white-space: nowrap; }
.qi-chip .qi-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--cds-gray-40); flex: none; }
.qi-chip b { color: var(--text-primary); font-weight: var(--type-weight-semibold); }
.qi-dot.tone-green { background: var(--cds-green-50); } .qi-dot.tone-red { background: var(--cds-red-50); }
.qi-dot.tone-yellow { background: var(--cds-yellow-30); } .qi-dot.tone-blue { background: var(--cds-blue-60); }
.qi-dot.tone-gray { background: var(--cds-gray-40); } .qi-dot.tone-purple { background: var(--cds-purple-60); }
.qi-dot.tone-orange { background: var(--cds-orange-40); }
.qi-spacer { flex: 1; min-width: 12px; }
.qi-meta { font-size: var(--type-size-01); color: var(--text-helper); white-space: nowrap; }

/* ---------- Toolbar (buscador + filtros) ---------- */
.toolbar { display: flex; align-items: stretch; background: var(--layer-02);
  border: 1px solid var(--border-subtle); border-bottom: none; min-height: 3rem; }
.toolbar__search { position: relative; flex: 1; display: flex; align-items: center; min-width: 0; }
.toolbar__search svg { position: absolute; left: var(--sp-05); width: 16px; height: 16px; color: var(--icon-secondary); pointer-events: none; }
.toolbar__search input { width: 100%; height: 3rem; padding: 0 var(--sp-05) 0 2.75rem; border: none; background: transparent;
  color: var(--text-primary); font-family: inherit; font-size: var(--type-size-02); outline: none; }
.toolbar__search input:focus { outline: 2px solid var(--border-interactive); outline-offset: -2px; }
.toolbar__divider { width: 1px; background: var(--border-subtle); flex: none; }
.toolbar__btn { display: flex; align-items: center; gap: var(--sp-03); height: 3rem; padding: 0 var(--sp-05); background: transparent;
  border: none; color: var(--text-primary); font-size: var(--type-size-02); white-space: nowrap; flex: none; }
.toolbar__btn:hover { background: var(--layer-hover); }
.toolbar__btn.is-active { background: var(--cds-gray-100); color: #fff; }
.toolbar__btn svg { width: 16px; height: 16px; }

/* Panel de filtros */
.filters-panel { background: var(--layer-02); border: 1px solid var(--border-subtle); border-bottom: none;
  padding: 16px 16px 4px; display: none; }
.filters-panel.is-open { display: block; }
.filters-panel__grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 0 16px; }
.filters-panel__foot { display: flex; gap: 8px; padding: 8px 0 4px; }

/* ---------- DataTable ----------
   De packages/styles/scss/components/data-table/_data-table.scss.
   La altura de fila (48px = spacing-09) y el padding lateral de 16px ya
   coincidian. Lo que se corrige:

   - thead: la cabecera iba en 13px, un tamano que no esta en la escala de
     Carbon. heading-compact-01 son 14px con peso 600. Y el fondo pasa de
     layer-01 a layer-accent: Carbon reserva el acento de capa justo para
     esto, y con layer-01 la cabecera tenia el mismo tono que el cuerpo.
   - tbody: faltaban el interlineado y el letter-spacing de body-compact-01.
   - transicion: era `background` con la duracion generica; Carbon especifica
     background-color con fast-01 (70ms) y curva entrance productive.

   Esta clase no la usa ninguna vista todavia (72 vistas tienen <table> y
   ninguna la aplica). Se corrige AHORA justamente por eso: cuando se difunda,
   debe difundirse ya conforme. Es la leccion del status-tag. */
/* La tabla y su barra de paginacion son un componente, no dos piezas que se
   colocan cerca.

   Sueltas eran dos hijos del contenedor de pagina, que es un flex con `gap`,
   y ese hueco las separaba: 24px en cuarenta y dos pantallas, 6 en Viajes y
   32 en Suscripciones. Cancelarlo con un margen negativo obligaba a acertar
   el numero de cada una, y en Viajes habria solapado la tabla. Envueltas, la
   barra queda pegada valga lo que valga el gap de la pantalla.

   Y la barra tiene que ir FUERA del envoltorio que hace scroll: dentro se
   desplazaba con la tabla, asi que en un listado ancho habia que arrastrar a
   la derecha para encontrar los controles de pagina. */
/* Texto que solo leen los lectores de pantalla. Se usa donde una cabecera de
   columna no debe verse -la de acciones no nombra un dato- pero la tabla
   necesita igual decir que hay ahi. `clip-path` y no `display: none`, que
   apagaria tambien el anuncio. */
.visualmente-oculto {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.tabla { display: flex; flex-direction: column; min-width: 0; }

/* ---------- Barra de herramientas de la tabla ----------
   Va encima de la tabla y dentro de `.tabla`, como la paginacion va debajo:
   las tres piezas son un componente.

   Reune lo que hoy cada pantalla resuelve por su cuenta. Catorce ventanas
   filtran y no hay dos que lo hagan igual, porque no existia donde ponerlo.

   Carbon la empareja por altura: 48px con filas lg y xl, 32 con sm y xs. Para
   md no dice nada y aqui se queda en 48, que es decision nuestra y no norma
   heredada.

   La busqueda va SIEMPRE abierta, que es la otra variante que Carbon publica.
   La plegada ahorra sitio a cambio de un clic, y en un ERP donde filtrar un
   listado es la tarea principal ese clic se paga en todas las pantallas y
   todos los dias. Ademas no necesita JS para abrirse.

   Las acciones van a la derecha y la busqueda se come el resto: es el orden
   en que se leen -primero acoto, luego actuo- y deja el boton primario en la
   esquina, donde el ojo lo busca. */
.data-table-toolbar {
  display: flex;
  align-items: center;
  /* Todo pegado a la derecha. Sin esto el grupo se quedaba a la izquierda y al
     abrir la busqueda los iconos se iban hacia la derecha, que es lo que se
     leia como que la barra se contraia. Anclados al borde, el campo crece
     hacia la izquierda y ningun boton se mueve de sitio. */
  justify-content: flex-end;
  min-height: 48px;
  background: var(--layer-01);
  border: 1px solid var(--border-subtle);
  border-bottom: 0;
}
.data-table-toolbar--sm { min-height: 32px; }

/* Busqueda. No es un boton que abre un campo: es UN campo que mide 48px con
   la lupa encima, y al enfocarlo crece. Por eso no se contrae nada ni aparece
   nada nuevo, solo cambia el ancho.

   Lo tenia montado como boton mas campo aparte, y se notaba: al abrirlo unas
   piezas desaparecian y otras salian. Modelo y medidas son los del componente:
   48px cerrado, `width: 100%` abierto -que el flex encoge al hueco que quede-,
   y 300ms sobre cubic-bezier(.5, 0, .1, 1).

   Abre con `:focus-within` y se queda abierta mientras haya texto, con
   `:has(...:not(:placeholder-shown))`. Sin JS: el navegador ya sabe cuando un
   campo tiene el foco y cuando tiene contenido. */
.busqueda-tabla {
  position: relative;
  display: flex;
  align-self: stretch;
  flex: 0 1 auto;
  width: 48px;
  transition: width .3s cubic-bezier(.5, 0, .1, 1);
}
.busqueda-tabla:focus-within,
.busqueda-tabla:has(.busqueda-tabla__campo:not(:placeholder-shown)) { width: 100%; }

/* La lupa no intercepta el clic: debajo esta el campo, y pulsar el icono
   tiene que enfocarlo igual que pulsar al lado. */
.busqueda-tabla__lupa {
  position: absolute;
  left: var(--sp-05);
  top: 50%;
  transform: translateY(-50%);
  pointer-events: none;
  color: var(--icon-primary);
}
.busqueda-tabla__campo {
  width: 100%;
  align-self: stretch;
  border: 0;
  background: transparent;
  /* 48 a la izquierda es el hueco de la lupa. A la derecha Carbon reserva
     otros 48 para su boton de limpiar; sin ese boton se deja el paso del
     sistema. */
  padding: 0 var(--sp-05) 0 48px;
  font: inherit;
  font-size: var(--type-size-02);
  color: var(--text-primary);
  /* Cerrada se lee como un boton, asi que el puntero dice lo mismo. */
  cursor: pointer;
}
.busqueda-tabla__campo::placeholder { color: var(--text-placeholder); }
.busqueda-tabla__campo:focus { outline: 2px solid var(--focus); outline-offset: -2px; cursor: text; }
@media (prefers-reduced-motion: reduce) {
  .busqueda-tabla { transition: none; }
}

.data-table-toolbar__accion {
  width: 48px;
  align-self: stretch;
  flex: none;
  display: grid;
  place-items: center;
  border: 0;
  background: transparent;
  color: var(--icon-primary);
  cursor: pointer;
  transition: background-color var(--dur-fast-01) var(--ease-entrance);
}
.data-table-toolbar--sm .data-table-toolbar__accion { width: 32px; }
.data-table-toolbar__accion:hover { background: var(--layer-hover); }
.data-table-toolbar__accion:focus-visible { outline: 2px solid var(--focus); outline-offset: -2px; }
/* Pulsada mientras su panel esta abierto: el filtro tiene que decir que hay
   un panel desplegado, o el usuario no sabe de donde ha salido. */
.data-table-toolbar__accion[aria-expanded="true"] { background: var(--layer-selected); }
/* Y con filtros puestos se queda encendido aunque el panel este cerrado: la
   tabla muestra menos filas de las que hay y algo tiene que decir por que. */
.data-table-toolbar__accion.esta-activo { box-shadow: inset 0 -2px 0 var(--interactive); color: var(--interactive); }

/* El boton primario llega hasta el borde y toma el alto de la barra: en
   Carbon cierra la esquina, sin margen que lo separe. */
.data-table-toolbar .btn-carbon { align-self: stretch; flex: none; }

/* ---------- Panel de filtro ----------
   Cuelga del boton del embudo y se superpone a la tabla. Se superpone a
   proposito: empujar la tabla hacia abajo mueve las filas justo cuando el
   usuario esta mirando cuales quiere acotar, y al cerrar volverian a saltar.
   Tapar dos columnas durante unos segundos molesta menos que mover todo.

   Medidas del componente real: 308px de ancho, fondo de capa, sin borde, y la
   sombra como `drop-shadow` y no como `box-shadow` -asi la proyecta la forma
   y no la caja-. El pie son dos botones a mitad y mitad, secundario a la
   izquierda y primario a la derecha. */
.filtro-tabla { position: relative; display: flex; align-self: stretch; flex: none; }

.filtro-tabla__panel {
  position: absolute;
  top: 100%;
  right: 0;
  z-index: 6000;
  width: 19.25rem;
  max-width: calc(100vw - var(--sp-07));
  background: var(--layer-02);
  filter: drop-shadow(0 2px 2px rgba(0, 0, 0, .2));
}
/* ---------- Menu de la barra y de la fila ----------
   El engranaje de la barra no es un boton suelto: es el disparador de un
   menu, que es lo que Carbon llama overflow menu. Y los tres puntos de la
   fila cuelgan del mismo. Ahi van las acciones que no caben sueltas
   -exportar, imprimir, elegir columnas- sin gastar un boton por cada una.

   Medidas del componente: 160 de ancho, opciones de 40 con 16 de relleno, y
   sombra de caja -aqui si, no `drop-shadow`: es un rectangulo y no una forma
   con pico-. Se alinea por la derecha con su boton. */
.menu-tabla { position: relative; display: flex; align-self: stretch; flex: none; }
.menu-tabla__opciones {
  position: absolute;
  top: 100%;
  right: 0;
  z-index: 6000;
  width: 10rem;
  margin: 0;
  padding: 0;
  list-style: none;
  background: var(--layer-02);
  box-shadow: 0 2px 6px rgba(0, 0, 0, .3);
}
.menu-tabla__opcion {
  display: flex;
  align-items: center;
  width: 100%;
  height: 40px;
  padding: 0 var(--sp-05);
  border: 0;
  background: transparent;
  font: inherit;
  font-size: var(--type-size-02);
  color: var(--text-secondary);
  text-align: left;
  cursor: pointer;
}
.menu-tabla__opcion:hover { background: var(--layer-hover); color: var(--text-primary); }
.menu-tabla__opcion:focus-visible { outline: 2px solid var(--focus); outline-offset: -2px; }
/* La accion que destruye se marca en el menu y no solo en el aviso posterior:
   quien la busca la encuentra, y quien no, la esquiva. */
.menu-tabla__opcion--peligro { color: var(--text-error); }
/* Una opcion que no se puede usar se queda en el menu, apagada y sin hover.
   Esconderla seria peor: quien busca "Eliminar" y no lo encuentra no sabe si
   no existe o si no puede, y el `title` explica cual de las dos. */
.menu-tabla__opcion:disabled { color: var(--text-disabled); cursor: not-allowed; }
.menu-tabla__opcion:disabled:hover { background: transparent; color: var(--text-disabled); }

/* Grupo de casillas. No es un <fieldset> con <legend>, y no por capricho: el
   navegador saca el legend del flujo normal y lo coloca sobre el borde, asi
   que el `padding-top` de la caja se suma DESPUES de el -16 mas los 8 del
   rotulo daban 24 de hueco donde Carbon tiene 6- y no hay forma limpia de
   cuadrarlo. `role="group"` con `aria-labelledby` dice lo mismo a un lector de
   pantalla y se maqueta como cualquier caja. */
.filtro-tabla__opciones {
  border: 0;
  margin: 0;
  padding: var(--sp-05);
  max-height: 15rem;
  overflow-y: auto;
}
/* El rotulo es una etiqueta de Carbon, no texto pequenio a secas: 12 sobre 16
   de linea y 0,32 de espaciado. */
.filtro-tabla__rotulo {
  padding: 0;
  margin-bottom: var(--sp-03);
  font-size: var(--type-size-01);
  line-height: 16px;
  letter-spacing: .32px;
  color: var(--text-secondary);
}

/* La casilla se dibuja, no se hereda del navegador.

   La nativa sale a 20px con el estilo del sistema operativo, que no es el de
   Carbon ni cambia de un equipo a otro igual. Carbon esconde el input y pinta
   una caja de 16 con `::before` y el check con `::after`: mismo dibujo en
   todas partes. Marcada va en `icon-primary` -negro, no azul: el azul en
   Carbon es para lo que se puede pulsar, y una casilla marcada no es una
   accion- con el check en blanco.

   Los numeros salen medidos de la historia de filtrado de Carbon, margenes
   incluidos, y los margenes no son adorno: la caja no se apoya en `left: 0`
   sino tres pixeles a la derecha y uno mas abajo. Sin ellos queda alta
   respecto a la linea de texto -que es lo que se veia descentrado- y pegada
   a la palabra, porque el hueco de once pixeles que Carbon deja entre caja y
   texto sale de sumar ese margen al relleno de la etiqueta. */
.filtro-tabla__opcion {
  position: relative;
  display: block;
  padding-top: 1px;
  padding-left: 30px;
  min-height: 20px;
  font-size: var(--type-size-02);
  line-height: 18px;
  letter-spacing: .16px;
  color: var(--text-primary);
  cursor: pointer;
  user-select: none;
}
.filtro-tabla__opcion + .filtro-tabla__opcion { margin-top: 6px; }

.filtro-tabla__opcion input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  margin: 0;
}
.filtro-tabla__opcion::before {
  content: "";
  position: absolute;
  left: 0;
  top: 2px;
  width: 16px;
  height: 16px;
  margin: 1px 0 2px 3px;
  border: 1px solid var(--icon-primary);
  border-radius: 2px;
  background: transparent;
}
/* El check son dos lados de una caja girada: sin imagen ni svg que mantener. */
.filtro-tabla__opcion::after {
  content: "";
  position: absolute;
  left: 7px;
  top: 6.5px;
  width: 9px;
  height: 5px;
  border-left: 1.5px solid var(--text-on-color);
  border-bottom: 1.5px solid var(--text-on-color);
  transform: scale(0) rotate(-45deg);
  transform-origin: 100% 100%;
  margin-top: -3px;
}
.filtro-tabla__opcion:has(input:checked)::before {
  background: var(--icon-primary);
  border-color: var(--icon-primary);
}
.filtro-tabla__opcion:has(input:checked)::after { transform: scale(1) rotate(-45deg); }
.filtro-tabla__opcion:has(input:focus-visible)::before {
  outline: 2px solid var(--focus);
  outline-offset: 1px;
}

.filtro-tabla__pie { display: flex; }
.filtro-tabla .filtro-tabla__pie > * {
  flex: 1 1 50%;
  min-width: 0;
  align-self: auto;
  justify-content: center;
}

/* Mientras la tabla se esta reemplazando. Atenuar es suficiente: el cambio
   dura decimas y una barra de progreso parpadeando molesta mas que informa.
   Se bloquea el puntero para que no se encadenen dos ordenaciones. */
.tabla[aria-busy="true"] { opacity: .6; pointer-events: none; transition: opacity .15s; }

.table-wrap { border: 1px solid var(--border-subtle); background: var(--layer-02); overflow-x: auto; }
table.data-table { width: 100%; border-collapse: collapse; border-spacing: 0; font-size: var(--type-size-02); }
.data-table thead th {
  text-align: left; color: var(--text-primary);
  font-size: var(--type-size-02); font-weight: var(--type-weight-semibold);
  line-height: 1.28572; letter-spacing: .16px;
  background: var(--layer-accent); height: 48px; padding: 0 var(--sp-05); white-space: nowrap;
  border-bottom: 1px solid var(--border-subtle); position: sticky; top: 0; user-select: none;
}
/* Ordenacion.

   Quien manda es un <button> que llena la celda, no el <th> con un tabindex:
   la celda de una tabla no es un control y un lector de pantalla no la
   anuncia como tal. El th se queda sin relleno y lo pone el boton.

   La etiqueta va a la izquierda y el icono empujado al borde derecho por
   `space-between`, que es donde Carbon lo coloca; no pegado detras del texto.
   Y son dos iconos que se alternan por `display`, no uno que cambia de
   glifo: la flecha simple para la columna ordenada y la doble para las
   demas, esta ultima presente siempre pero transparente hasta que la senalas.

   La columna ordenada SI cambia de fondo, un escalon por debajo del resto de
   la cabecera. Lo dije al reves en su momento; la regla de Carbon es
   `.cds--table-sort--active { background: layer-selected-hover }`, y el hover
   de una ordenable usa ese mismo color. */
.data-table thead th.is-sortable { padding: 0; }
.data-table .table-sort {
  display: flex; align-items: center; justify-content: space-between;
  width: 100%; height: 48px; margin: 0; padding: 0 0 0 var(--sp-05);
  border: 0; background: transparent; cursor: pointer;
  font: inherit; font-size: var(--type-size-02);
  font-weight: var(--type-weight-semibold); letter-spacing: .16px;
  color: inherit; text-align: left;
  /* Es un enlace y no un boton: navega a la misma pantalla ordenada por esa
     columna. Asi ordena sin JS, se puede abrir en otra pestania y el orden
     viaja en la URL, que es lo que hace que se pueda compartir. Un enlace
     trae subrayado; aqui sobra. */
  text-decoration: none;
}
.data-table .table-sort:hover,
.data-table .table-sort--activo { background: var(--layer-selected-hover); }
.data-table .table-sort svg {
  width: 20px; height: 20px; margin: 0 var(--sp-03); flex: none; fill: currentColor;
}
.data-table .table-sort .sort-ord { display: none; }
.data-table .table-sort .sort-sin { display: block; opacity: 0; }
.data-table .table-sort:hover .sort-sin,
.data-table .table-sort:focus-visible .sort-sin { opacity: 1; }
.data-table .table-sort--activo .sort-ord { display: block; }
.data-table .table-sort--activo .sort-sin { display: none; }

/* Ascendente y descendente son la MISMA flecha girada media vuelta, no dos
   dibujos distintos. Faltaba el giro, asi que cambiar de sentido reordenaba
   las filas pero la cabecera seguia enseniando la flecha hacia arriba y no
   habia manera de saber en que sentido estabas.

   El giro se anima, que es lo que lo hace legible: la flecha da la vuelta
   delante de ti en vez de aparecer ya cambiada. */
.data-table .table-sort .sort-ord {
  transform: rotate(0deg);
  transition: transform .25s cubic-bezier(.5, 0, .1, 1);
}
.data-table .table-sort--descendente .sort-ord { transform: rotate(180deg); }

/* Quien haya pedido no animar, no se anima: girar una flecha es decorativo y
   hay gente a la que el movimiento le sienta mal. */
@media (prefers-reduced-motion: reduce) {
  .data-table .table-sort .sort-ord { transition: none; }
}

/* Foco de teclado: no habia ninguna regla :focus en toda la tabla, asi que
   ordenar por una columna con el tabulador era invisible. Carbon lo resuelve
   con un anillo de 2px hacia dentro. El del menu de fila va con su propia
   regla, mas abajo. */
.data-table .table-sort:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: -2px;
}
/* El nowrap se queda solo en la cabecera, que es donde lo pone Carbon. En las
   celdas no es suyo, y ademas rompia los listados con texto largo: la
   descripcion de un rol o el nombre de un proveedor salian en una sola linea
   y empujaban la tabla a scroll horizontal. La altura de 48px actua de minimo,
   asi que una celda que envuelve crece sin romper la retícula. */
.data-table tbody td { height: 48px; padding: var(--sp-04) var(--sp-05); border-bottom: 1px solid var(--border-subtle);
  color: var(--text-secondary); vertical-align: middle;
  font-size: var(--type-size-02); font-weight: var(--type-weight-regular);
  line-height: 1.28572; letter-spacing: .16px; }
.data-table tbody tr,
.data-table tbody tr td { transition: background-color var(--dur-fast-01) var(--ease-entrance); }
.data-table tbody tr:hover { background: var(--layer-hover); }
/* En hover Carbon tine tambien los bordes de la celda con el color del propio
   hover, para que la fila se lea como un bloque solido y no cortada por
   lineas, y sube el texto a text-primary. */
.data-table tbody tr:hover td { color: var(--text-primary); border-bottom-color: var(--layer-hover); }

/* ---------- Las cinco alturas de fila ----------
   Carbon publica cinco y el ERP solo tenia una, la de 48. Ese hueco es el que
   hacia aparecer clases propias: quien necesitaba algo mas compacto dentro de
   un formulario se inventaba `detail-table`, `personal-license-table` o
   `provider-detail-table`, tres nombres para lo mismo que ademas habian
   derivado entre si.

   La cabecera lleva SIEMPRE el mismo alto que la fila; en Carbon no es
   opcional, asi que cada variante mueve las dos.

   Los 48 se quedan de base para que las cuarenta y cinco pantallas que ya
   existen no cambien al adoptar esto. `xl` solo cuando de verdad se esperan
   dos lineas en la celda, que es la unica condicion con la que Carbon lo
   recomienda; en el ERP son nueve listados, los que apilan un dato con su
   aclaracion debajo. */
.data-table--xs thead th, .data-table--xs .table-sort, .data-table--xs tbody td { height: 24px; }
.data-table--sm thead th, .data-table--sm .table-sort, .data-table--sm tbody td { height: 32px; }
.data-table--md thead th, .data-table--md .table-sort, .data-table--md tbody td { height: 40px; }
.data-table--lg thead th, .data-table--lg .table-sort, .data-table--lg tbody td { height: 48px; }
.data-table--xl thead th, .data-table--xl tbody td { height: 64px; }
/* En xl el texto no se centra: Carbon lo sube y lo compensa con 16px de
   respiro, porque con dos lineas el centrado deja la primera flotando. */
.data-table--xl thead th, .data-table--xl tbody td { vertical-align: top; padding-top: var(--sp-05); }
.data-table--xl .table-sort { height: 64px; align-items: flex-start; padding-top: var(--sp-05); }

/* Por debajo de lg el relleno vertical sobra y ademas descuadra: la altura de
   la fila actua de minimo, asi que 18px de linea mas los 24 del padding dan
   42 y `md` -que pide 40- se iba a 43. Quien fija el alto en estas tallas es
   la fila, no el relleno. */
.data-table--xs tbody td,
.data-table--sm tbody td,
.data-table--md tbody td { padding-top: 0; padding-bottom: 0; }

/* ---------- Zebra ----------
   Filas alternas en `layer-accent`, el mismo tono de la cabecera. Ayuda a
   seguir una fila larga con la vista; en una tabla de pocas columnas es ruido
   y no se pone. El hover manda por encima, o la fila bajo el puntero se
   perderia justo en las pares. */
.data-table--zebra tbody tr:nth-child(even) td { background: var(--layer-accent); }
.data-table--zebra tbody tr:hover td { background: var(--layer-hover); }

.data-table tbody td.col-actions { text-align: right; }
/* El boton de los tres puntos: 32px, sin borde y con el icono en primario.
   `.btn--icon` de base.css no quita el borde -se usara siempre junto a un
   `.btn` que si lo hace-, y aqui se usa suelto, asi que salia con el borde
   `outset` que pone el navegador por defecto y los tres puntos aparecian
   metidos en una caja. */
.menu-fila > .btn--icon {
  width: 32px;
  height: 32px;
  border: 0;
  color: var(--icon-primary);
  cursor: pointer;
}
.menu-fila > .btn--icon:hover { background: var(--layer-hover); }
.menu-fila > .btn--icon:focus-visible { outline: 2px solid var(--focus); outline-offset: -2px; }
/* Los tres puntos de la fila. Mismo menu que el de la barra -160 de ancho,
   opciones de 40- colgando de un boton de 32, que es el alto de una accion de
   fila y no el de la barra.

   Cuando ponerlo y cuando no lo dice la especificacion, y no es "siempre":
   por debajo de tres opciones las acciones se quedan a la vista como botones
   de icono, porque asi se ahorra un clic y se ve de un vistazo lo que se
   puede hacer. En el ERP eso son 41 listados con dos acciones, que NO llevan
   menu; los tres puntos son para los nueve que tienen tres o mas -Servicios
   con cinco, el detalle de Informes con seis-. */
.menu-fila { position: relative; display: inline-flex; }
.menu-fila > .menu-tabla__opciones { top: 100%; right: 0; }
/* El enfasis dentro de una celda es semibold 600 en Carbon, no el 500 que no
   existe en su escala. */
/* La columna que da nombre a la fila. Destaca por COLOR y no por peso.

   Llevaba `semibold`, y el texto de fila en Carbon es Regular 400 sin
   excepciones: la unica pieza de la tabla en 600 es la cabecera de columna.
   Comprobado contra el componente real ademas de contra la tabla de
   tipografia: las celdas miden 400/14 todas, la primera columna incluida, y
   no hay un solo <strong> en el cuerpo.

   El color si es una distincion que el sistema ya hace: la fila va en
   `text-secondary` y esta columna sube a `text-primary`, que es el mismo
   salto que da el hover. Se lee que manda sin engordar la letra. */
.data-table .col-strong { color: var(--text-primary); }
/* col-id es para el identificador interno de un registro -un #1234 que casi
   nunca se lee-, por eso va atenuado y a 12px.
   col-codigo es otra cosa: un codigo que la gente usa para nombrar la fila,
   como la abreviatura de un banco o el numero de un fondo. Comparte la
   monoespaciada, que alinea los caracteres y hace comparables dos codigos,
   pero conserva el tamano y el color del resto de la tabla. */
.data-table .col-id { color: var(--text-helper); font-family: var(--font-mono); font-size: var(--type-size-01); }
/* Un codigo no se parte: "EG07 - 529" en dos lineas se lee como dos datos. */
.data-table .col-codigo { color: var(--text-primary); font-family: var(--font-mono); white-space: nowrap; }
/* Importes a la derecha, cabecera incluida. Alinear solo la celda y dejar el
   rotulo a la izquierda es lo que hacia la pantalla de cuentas y se lee mal:
   la columna deja de tener un borde comun por el que comparar cifras. */
.data-table .col-num { text-align: right; font-variant-numeric: tabular-nums; }
.data-table th.col-num .table-sort { justify-content: flex-end; gap: var(--sp-03); }
/* La segunda linea de una celda: el numero de serie bajo el tipo de
   comprobante, el RUC bajo la razon social, la fecha bajo el titulo. Media
   docena de pantallas la repetian con estilo en linea o con una clase propia,
   y cada una con su tamano. Va atenuada y en su propia linea, que es lo que la
   distingue del dato principal sin competir con el. */
.data-table .celda-sub { display: block; margin-top: var(--sp-02); color: var(--text-secondary); font-size: var(--type-size-01); }
/* Tabla que es un formulario, no un listado: las unidades que pide una
   solicitud, las sedes de un cliente, sus cuentas bancarias. Sus filas no son
   registros sobre los que actuar sino campos que se rellenan, asi que no se
   resaltan al pasar el raton: el hover de Carbon dice "esta fila hace algo si
   la pulsas", y aqui no hace nada. Se lee como si la fila estuviera
   seleccionandose sola. */
.data-table--formulario tbody tr:hover { background: transparent; }
.data-table--formulario tbody tr:hover td { color: inherit; border-bottom-color: var(--border-subtle); }
/* Y le devuelve el relleno vertical que las tallas cortas quitan.
   `--sm` lo pone a cero a proposito, porque en una fila de texto quien fija la
   altura es la fila y el relleno sobra. Con un campo dentro deja de ser
   verdad: el control mide 40px, mas que los 32 de la fila, asi que la empuja
   y se queda pegado al borde -un pixel arriba y otro abajo-. Aqui la altura
   la manda el campo, y el relleno vuelve a hacer falta. */
.data-table--formulario tbody td { padding-top: var(--sp-03); padding-bottom: var(--sp-03); }
/* La altura de 48px ya era conforme; el tamano de letra estaba en 13px, que
   no pertenece a la escala de Carbon (12/14/16/18/20/24/28/32). */
.table-foot { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-05);
  border: 1px solid var(--border-subtle); border-top: none; background: var(--layer-02);
  padding: 0 var(--sp-05); height: 48px; font-size: var(--type-size-02);
  line-height: 1.28572; letter-spacing: .16px; color: var(--text-secondary); flex-wrap: wrap; }

/* Selección por checkbox */
.data-table .col-check { width: 20px; }
.data-table input[type=checkbox] { width: 18px; height: 18px; accent-color: var(--interactive); }

/* ---------- Paginación ---------- */
.pagination { display: flex; align-items: center; gap: 4px; }
.pagination select { height: 32px; background: var(--field-01); border: none; border-bottom: 1px solid var(--border-strong);
  color: var(--text-primary); padding: 0 24px 0 8px; font-family: inherit; }
.pagination__btn { width: 32px; height: 32px; display: flex; align-items: center; justify-content: center;
  background: transparent; border: none; color: var(--icon-primary); }
.pagination__btn:hover:not(:disabled) { background: var(--layer-hover); }
.pagination__btn:disabled { color: var(--text-disabled); cursor: not-allowed; }
.pagination__info { padding: 0 12px; color: var(--text-secondary); }

/* ---------- Badge & Status Tag ---------- */
/* .badge era un segundo tag con otra geometria (20px de alto, radio 10px,
   peso 500). Carbon no tiene un componente "badge" de este tipo: lo que
   describe es un Tag gris. Se alinea a la misma spec para que el sistema no
   ofrezca dos pildoras que se parecen pero no encajan entre si. */
.badge { display: inline-flex; align-items: center; justify-content: center;
  min-block-size: 24px; min-inline-size: 32px; padding-inline: var(--sp-03);
  border-radius: 0; font-size: var(--type-size-01);
  font-weight: var(--type-weight-regular); line-height: 1.33333;
  letter-spacing: .32px;
  background: var(--tag-background-gray); color: var(--tag-color-gray); }
/* Tag de Carbon. Medidas de packages/styles/scss/components/tag/_tag.scss y
   tipografia de label-01 (packages/type/src/styles.ts): 12px, peso regular 400,
   interlineado 1.33333 y letter-spacing 0.32px.

   Lo que cambio respecto a la version anterior y por que:
   - alto 22px -> 24px, que es el tamano md de Carbon (los otros son 18 y 32).
   - radio 4px -> 16px. El Tag de Carbon es una pildora, no un rectangulo.
   - padding 0 8px 0 7px -> 8px simetrico. El pixel de menos a la izquierda
     compensaba el punto que iba delante; sin punto ya no hace falta.
   - peso 500 -> 400. label-01 va en regular, y ademas el 500 no existe en Carbon.
   - fondos rgba(...) -> tokens solidos. Los translucidos dejaban pasar el color
     de debajo, asi que el mismo estado se veia distinto sobre una fila con hover
     que sobre uno sin el.
   - se retira el punto ::before, que Carbon no incluye en el Tag.
     Si hace falta distinguir estados sin depender del color (daltonismo), la
     respuesta de Carbon no es un punto de color sino el componente
     shape-indicator, que usa una forma distinta por estado.

   DESVIACION DELIBERADA: el radio va en 0, no en los 16px que especifica
   Carbon ("ensures tag stays pill shaped" en _tag.scss). Carbon redondea el
   Tag a proposito, para que lo que solo informa no se confunda con lo que se
   pulsa, que va cuadrado. Aqui se elige la coherencia de forma con el resto
   del sistema -botones, campos y tarjetas, todos rectos- por decision
   explicita del equipo. Es el unico punto donde este componente se aparta de
   la especificacion: si algun dia se quiere volver a Carbon estricto, basta
   con devolver este valor a 16px. */
.status-tag {
  display: inline-flex; align-items: center; justify-content: center;
  min-block-size: 24px; min-inline-size: 32px; max-inline-size: 208px;
  padding-inline: var(--sp-03);
  border-radius: 0;
  font-size: var(--type-size-01);
  font-weight: var(--type-weight-regular);
  line-height: 1.33333;
  letter-spacing: .32px;
  vertical-align: middle;
  /* Carbon mete el texto en un .tag__label con nowrap y elipsis; el
     word-break del contenedor es solo la red de seguridad de debajo. Aqui el
     texto cuelga directo del tag, sin ese envoltorio, asi que las reglas del
     label van sobre el propio tag. Sin esto, en una columna estrecha
     "Registrada" se parte en "Regi/strad/a" y el tag crece a tres lineas. */
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.status-tag--gray    { background: var(--tag-background-gray);    color: var(--tag-color-gray); }
.status-tag--blue    { background: var(--tag-background-blue);    color: var(--tag-color-blue); }
.status-tag--green   { background: var(--tag-background-green);   color: var(--tag-color-green); }
.status-tag--red     { background: var(--tag-background-red);     color: var(--tag-color-red); }
.status-tag--purple  { background: var(--tag-background-purple);  color: var(--tag-color-purple); }
.status-tag--magenta { background: var(--tag-background-magenta); color: var(--tag-color-magenta); }
.status-tag--teal    { background: var(--tag-background-teal);    color: var(--tag-color-teal); }
.status-tag--cyan    { background: var(--tag-background-cyan);    color: var(--tag-color-cyan); }

/* Extension propia: Carbon no publica tag naranja ni amarillo, pero el ERP
   necesita marcar advertencias. Misma formula 20/70 para que no desentonen.
   --yellow queda como alias de --caution por los usos que ya existian. */
.status-tag--orange,
.status-tag--warning { background: var(--tag-background-warning); color: var(--tag-color-warning); }
.status-tag--yellow,
.status-tag--caution { background: var(--tag-background-caution); color: var(--tag-color-caution); }
.bool-pill { display:inline-flex;align-items:center;gap:6px;font-size:12px;color:var(--text-secondary); }
.bool-pill svg { width:14px;height:14px; }
.bool-pill.yes { color: var(--support-success); }
.bool-pill.no { color: var(--text-placeholder); }

/* ---------- Modal ----------
   Para una ventana nueva: `.ventana`, mas abajo, que es la del styleguide. */
.overlay { position: fixed; inset: 0; background: var(--overlay); z-index: 9000;
  display: flex; align-items: flex-start; justify-content: center; padding: 56px 16px; overflow-y: auto; }
.modal { background: var(--layer-02); width: 100%; max-width: 640px; box-shadow: var(--shadow-md);
  display: flex; flex-direction: column; max-height: calc(100vh - 112px); }
.modal--lg { max-width: 880px; }
.modal--sm { max-width: 480px; }
.modal__head { display: flex; align-items: flex-start; justify-content: space-between; padding: 20px 20px 8px; }
.modal__head h3 { font-size: 20px; font-weight: var(--type-weight-regular); }
.modal__head .sub { font-size: 13px; color: var(--text-helper); margin-top: 2px; }
.modal__close { width: 40px; height: 40px; display: flex; align-items: center; justify-content: center;
  background: transparent; border: none; color: var(--icon-primary); margin: -8px -8px 0 0; }
.modal__close:hover { background: var(--layer-hover); }
.modal__body { padding: 8px 20px 20px; overflow-y: auto; }
.modal__foot { display: flex; border-top: 1px solid var(--border-subtle); }
.modal__foot .btn { flex: 1; height: 64px; justify-content: flex-start; padding-left: 16px; }
.modal__foot .btn + .btn { border-left: 1px solid rgba(255,255,255,.1); }

/* ---------- Ventana ----------
   El Modal de Carbon, medido en components-modal--default del Storybook de
   @carbon/react. Es la ventana del styleguide y la que va en las pantallas
   nuevas.

   El sistema tenia tres ventanas hechas a mano y ninguna en el styleguide:
   `.modal` de aqui arriba -que en realidad no usa nadie: la unica vista con
   esa clase la pone en el velo, con estilos en linea-, `.catalog-modal` y la
   de Viajes, escrita dentro de su propia vista.

   Lo que dan las medidas, a 877px de ventana:
     caja     84% del ancho, fondo layer-01, borde de 1px border-subtle-01 y
              ninguna sombra
     cabecera 16px arriba y a la izquierda, 48 a la derecha -lo que ocupa el
              aspa- y 8 debajo; titulo de 20/28 en peso normal
     aspa     48x48 pegada a la esquina, icono de 20
     cuerpo   8 arriba, 16 a los lados y 48 debajo
     pie      64px, dos botones al 50% con el texto arriba a la izquierda */
.ventana {
  position: fixed;
  inset: 0;
  /* 9800 y no el 9000 de Carbon: es el nivel de modal de este sistema, el de
     `.catalog-modal`. Con 9000 los menus de la cabecera y el de exportar, que
     van en 9500, quedarian por encima del velo. */
  z-index: 9800;
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: var(--overlay);
  /* La salida funde antes de desaparecer: `allow-discrete` retrasa el
     `display: none` de [hidden] hasta que acaba la opacidad. Donde no se
     entiende, la ventana se cierra de golpe, que tambien vale. */
  transition: opacity var(--dur-moderate-02) var(--ease-exit-expressive),
              display var(--dur-moderate-02) allow-discrete;
}
/* El `display: flex` de arriba le gana a la regla del navegador para
   [hidden]: sin esta linea la ventana no se cerraria nunca. */
.ventana[hidden] { display: none; opacity: 0; }

.ventana__caja {
  position: relative;
  display: grid;
  /* Cabecera, cuerpo que se desplaza, nota y pie. La nota es una fila
     aparte para que no se vaya con el scroll del cuerpo. */
  grid-template-rows: auto 1fr auto auto;
  grid-template-columns: 100%;
  inline-size: 100%;
  max-block-size: 100%;
  background-color: var(--layer-01);
  border: 1px solid var(--border-subtle-01);
  outline: 3px solid transparent;
  outline-offset: -3px;
  transition: transform var(--dur-moderate-02) var(--ease-entrance-expressive);
}
/* Un formulario que envuelve cabecera, cuerpo y pie no desarma la rejilla:
   Carbon hace lo mismo con `.cds--modal-container-body`. */
.ventana__caja > form { display: contents; }

/* Entrada: el velo aparece y la caja baja 24px hasta su sitio. Salida: la
   caja vuelve a subir mientras el velo se funde. */
@starting-style {
  .ventana { opacity: 0; }
  .ventana__caja { transform: translateY(-24px); }
}
.ventana[hidden] .ventana__caja {
  transform: translateY(-24px);
  transition-timing-function: var(--ease-exit-expressive);
}
.ventana:not([hidden]) { transition-timing-function: var(--ease-entrance-expressive); }
@media (prefers-reduced-motion: reduce) {
  .ventana, .ventana__caja { transition: none; }
}

/* En el movil la caja se pega arriba, como en Carbon, y no queda flotando en
   medio de la pantalla. */
@media (max-width: 41.98rem) {
  .ventana { align-items: flex-start; }
}
@media (min-width: 42rem) { .ventana__caja { inline-size: 84%; max-block-size: 90%; } }
@media (min-width: 66rem) { .ventana__caja { inline-size: 60%; max-block-size: 84%; } }
@media (min-width: 82rem) { .ventana__caja { inline-size: 48%; } }

/* Tallas de Carbon: pequeña para confirmar, grande para lo que lleva tabla. */
@media (min-width: 42rem) { .ventana--sm .ventana__caja { inline-size: 60%; } }
@media (min-width: 66rem) { .ventana--sm .ventana__caja { inline-size: 42%; max-block-size: 72%; } }
@media (min-width: 82rem) { .ventana--sm .ventana__caja { inline-size: 36%; } }
@media (min-width: 42rem) { .ventana--lg .ventana__caja { inline-size: 96%; } }
@media (min-width: 66rem) { .ventana--lg .ventana__caja { inline-size: 84%; max-block-size: 96%; } }
@media (min-width: 82rem) { .ventana--lg .ventana__caja { inline-size: 72%; } }

.ventana__cabecera {
  grid-row: 1;
  max-block-size: 50vh;
  overflow-y: auto;
  margin-block-end: var(--sp-03);
  padding: var(--sp-05) var(--sp-09) 0 var(--sp-05);
}
/* Lo que dice de que va la ventana antes del titulo: el numero del viaje,
   el documento. Es el `modal-header__label` de Carbon. */
.ventana__rotulo {
  margin: 0 0 var(--sp-02);
  font-size: var(--type-size-01);
  line-height: 1.33333;
  letter-spacing: .32px;
  color: var(--text-secondary);
}
.ventana__titulo {
  margin: 0;
  padding-inline-end: calc(20% - 3rem);
  font-size: var(--type-size-05);
  font-weight: var(--type-weight-regular);
  line-height: 1.4;
  color: var(--text-primary);
}

.ventana__cerrar {
  position: absolute;
  inset-block-start: 0;
  inset-inline-end: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  inline-size: 3rem;
  block-size: 3rem;
  padding: var(--sp-04);
  background-color: transparent;
  border: 2px solid transparent;
  color: var(--icon-primary);
  cursor: pointer;
  transition: background-color var(--dur-fast-02) var(--ease-standard);
}
.ventana__cerrar:hover { background-color: var(--layer-hover); }
/* Carbon lo pinta con :focus. Aqui :focus-visible, como el resto de botones
   del sistema: el anillo al tabular, no al pulsar con el raton. */
.ventana__cerrar:focus-visible { border-color: var(--focus); outline: none; }
.ventana__cerrar svg { inline-size: 1.25rem; block-size: 1.25rem; fill: currentColor; }

.ventana__cuerpo {
  grid-row: 2;
  position: relative;
  min-block-size: 0;
  overflow-y: auto;
  padding: var(--sp-03) var(--sp-05) var(--sp-09);
  font-size: var(--type-size-02);
  line-height: 1.42857;
  letter-spacing: .16px;
  color: var(--text-primary);
}
.ventana__cuerpo:focus { outline: 2px solid var(--focus); outline-offset: -2px; }
/* El texto corrido no llega al borde derecho: una linea que cruza toda una
   ventana grande no se lee. Los formularios si lo usan entero. */
.ventana__cuerpo > p { padding-inline-end: calc(20% - 2rem); }

/* Capas. La caja es layer-01, asi que un campo dentro va en field-02 -blanco
   en el tema claro-: con field-01 seria del mismo gris que la ventana y solo
   se veria la linea de abajo. Es lo que Carbon hace con `cds--layer-two`.
   Una tabla dentro es layer-02, blanca, y sus campos vuelven a field-01.
   `background-color` y no `background`: el atajo borraria el galon de los
   combos, que va en background-image. */
.ventana__cuerpo .form-control:not([readonly]):not(:disabled) { background-color: var(--field-02); }
.ventana__cuerpo .table-wrap .form-control:not([readonly]):not(:disabled) { background-color: var(--field-01); }

/* Por que la accion principal no se puede pulsar todavia. Carbon no pone
   texto en el pie -los botones lo ocupan entero-, y un boton inhabilitado
   que no se explica deja mirando la pantalla sin saber donde tocar. Va en su
   propia fila, pegada al pie, fuera del scroll del cuerpo. */
.ventana__nota {
  grid-row: 3;
  margin: 0;
  padding: var(--sp-03) var(--sp-05);
  font-size: var(--type-size-01);
  line-height: 1.33333;
  letter-spacing: .32px;
  color: var(--text-helper);
}
.ventana__nota:empty { display: none; }

.ventana__pie {
  grid-row: 4;
  display: flex;
  justify-content: flex-end;
  block-size: 4rem;
}
/* El boton de Carbon en el pie: medio pie cada uno, 64px de alto y el texto
   arriba a la izquierda. 15px de relleno y no 16 porque el boton ya lleva un
   borde de 1px transparente. */
.ventana__pie > .btn-carbon,
.ventana__pie > .btn-carbon-secondary,
.ventana__pie > .btn-carbon-danger {
  flex: 0 1 50%;
  max-inline-size: none;
  block-size: 4rem;
  margin: 0;
  align-items: baseline;
  padding: .875rem calc(var(--sp-05) - 1px) 2rem;
}

/* Modal de confirmación de borrado */
.confirm-icon { width: 20px; height: 20px; color: var(--support-error); flex: none; margin-top: 2px; }

/* ---------- Modal de catálogo ----------
   Este bloque vivia copiado palabra por palabra dentro del <style> de veinte
   vistas de catalogo, mas una copia en partials/catalog-modal. Aqui vive una
   vez. Se diferencia de .modal en que lo abre y lo cierra el propio listado
   por clase; cuando las dos se unifiquen, la que sobra es esta. */
.catalog-modal { align-items: center; display: none; inset: 0; justify-content: center;
  padding: var(--sp-05); position: fixed; z-index: 9800; }
.catalog-modal.open { display: flex; }
/* El velo y la sombra salian de un rgba fijo, que en tema oscuro tapaba de
   menos de lo que debia. Los tokens si cambian con el tema. */
.catalog-modal__overlay { background: var(--overlay); inset: 0; position: absolute; }
.catalog-modal__card { background: var(--layer-02); border: 1px solid var(--border-subtle);
  box-shadow: var(--shadow-md); max-height: calc(100vh - 2rem); max-width: 560px;
  overflow: hidden; position: relative; width: min(100%, 560px); }
.catalog-modal__head { align-items: flex-start; border-bottom: 1px solid var(--border-subtle);
  display: flex; justify-content: space-between; padding: var(--sp-05) var(--sp-06); }
/* Sin mayusculas: Carbon no las tiene en ningun punto de su escala. */
.catalog-modal__head p { color: var(--text-secondary); font-size: var(--type-size-01);
  font-weight: var(--type-weight-semibold); margin: 0 0 var(--sp-02); }
.catalog-modal__head h2 { color: var(--text-primary); font-size: var(--type-size-05);
  font-weight: var(--type-weight-regular); margin: 0; }
.catalog-modal__close { background: transparent; border: 0; color: var(--text-secondary);
  cursor: pointer; font-size: var(--type-size-07); line-height: 1; padding: 0; }
.catalog-modal__body { max-height: calc(100vh - 8rem); overflow-y: auto; padding: var(--sp-06); }
/* Los modales de documentos traen pie de acciones; los de catalogo llevan los
   botones dentro del formulario. Misma caja para los dos. */
.catalog-modal__foot { align-items: center; border-top: 1px solid var(--border-subtle);
  display: flex; gap: var(--sp-04); justify-content: flex-end; padding: var(--sp-05) var(--sp-06); }
/* Los tokens de notificacion si son los que tocan aqui: esto es un aviso en
   linea, no una etiqueta de estado. */
.catalog-modal__error { background: var(--notification-bg-error);
  border-left: 4px solid var(--support-error); color: var(--support-error);
  font-size: var(--type-size-02); margin-bottom: var(--sp-05); padding: var(--sp-04) var(--sp-05); }
/* Los 560px valen para un formulario de tres o cuatro campos. El de Personal
   trae pestañas y quince campos en tres columnas, que a ese ancho salen a
   159px cada una: no cabe ni un campo con su botón al lado. Carbon publica
   varios tamaños de modal justamente para esto. */
.catalog-modal--ancho .catalog-modal__card { max-width: 768px; width: min(100%, 768px); }
/* Y 768 tampoco alcanzan cuando el modal no lleva un formulario sino dos
   paneles: el de Gastos pone el comprobante a la izquierda y los campos que
   la IA va rellenando a la derecha. La columna de la imagen ya pide 520px,
   asi que a 768 el lado de los campos se queda en 216 y el split se desarma.

   1320 es esa cuenta al derecho: 520 de comprobante, 32 de padding y los
   768 que este mismo archivo ya reconoce como el ancho minimo de un
   formulario que se deja usar.

   Antes del refactor esta vista se lo daba a si misma con un `max-width`
   suelto en su `<style>`. Al unificar los tres modales ese ancho se perdio y
   el modal cayo a los 560 de la base, que es menos de la mitad. Vuelve, pero
   como un tamaño mas del sistema y no como una excepcion escrita en la
   vista. */
/* Mientras el formulario viaja. Ocupa sitio para que el dialogo no se abra
   del tamanio de una linea y pegue un salto al llegar el contenido. */
.modal-remoto__espera,
.modal-remoto__error { padding: var(--sp-07) var(--sp-05); text-align: center; color: var(--text-secondary); }
.modal-remoto__error { color: var(--text-error); }

.catalog-modal--doble .catalog-modal__card { max-width: 1320px; width: min(100%, 1320px); }
@media (max-width: 640px) { .catalog-modal__card { width: 100%; } }

/* ---------- Drawer lateral (detalle) ---------- */
.drawer-overlay { position: fixed; inset: 0; background: var(--overlay); z-index: 9000; }
.drawer { position: fixed; top: 0; right: 0; bottom: 0; width: 480px; max-width: 92vw; background: var(--layer-02);
  z-index: 9001; box-shadow: var(--shadow-md); display: flex; flex-direction: column; }
.drawer__head { display: flex; align-items: flex-start; justify-content: space-between; padding: 20px 20px 12px;
  border-bottom: 1px solid var(--border-subtle); }
.drawer__head h3 { font-size: 18px; font-weight: var(--type-weight-medium); }
.drawer__head .sub { font-size: 12px; color: var(--text-helper); font-family: var(--font-mono); margin-top: 2px; }
.drawer__body { padding: 16px 20px; overflow-y: auto; flex: 1; }
.drawer__foot { padding: 12px 20px; border-top: 1px solid var(--border-subtle); display: flex; gap: 8px; }
.detail-row { display: grid; grid-template-columns: 180px 1fr; gap: 12px; padding: 10px 0;
  border-bottom: 1px solid var(--border-subtle); font-size: 14px; }
.detail-row dt { color: var(--text-helper); font-size: 12px; }
.detail-row dd { margin: 0; color: var(--text-primary); word-break: break-word; }
.detail-section { font-size: 11px; text-transform: uppercase; letter-spacing: .6px; color: var(--text-helper);
  font-weight: var(--type-weight-semibold); margin: 18px 0 4px; }
.json-box { background: var(--field-01); border: 1px solid var(--border-subtle); padding: 12px;
  font-family: var(--font-mono); font-size: 12px; white-space: pre-wrap; word-break: break-word; max-height: 220px; overflow: auto; }

/* ---------- Toast & Notification ---------- */
.toast-stack { position: fixed; top: calc(var(--header-h) + 12px); right: 16px; z-index: 10000;
  display: flex; flex-direction: column; gap: 8px; width: 360px; max-width: calc(100vw - 32px); }
.toast { display: flex; gap: 12px; padding: 14px; background: var(--layer-02); box-shadow: var(--shadow-md);
  border-left: 3px solid var(--support-info); align-items: flex-start; }
.toast--success { border-left-color: var(--support-success); }
.toast--error { border-left-color: var(--support-error); }
.toast--warning { border-left-color: var(--support-warning); }
.toast__icon { width: 20px; height: 20px; flex: none; margin-top: 1px; }
.toast--success .toast__icon { color: var(--support-success); }
.toast--error .toast__icon { color: var(--support-error); }
.toast--warning .toast__icon { color: var(--support-warning); }
.toast--info .toast__icon { color: var(--support-info); }
.toast__body { flex: 1; }
.toast__title { font-size: 14px; font-weight: var(--type-weight-semibold); }
.toast__msg { font-size: 13px; color: var(--text-secondary); margin-top: 2px; }
.toast__close { background: transparent; border: none; color: var(--icon-secondary); width: 20px; height: 20px; padding: 0; }

.inline-note { display: flex; gap: 12px; padding: 14px 16px; background: var(--cds-blue-10); border-left: 3px solid var(--support-info);
  font-size: 13px; color: var(--text-primary); margin-bottom: 16px; align-items: flex-start; }
[data-theme="dark"] .inline-note { background: rgba(15,98,254,.12); }
.inline-note svg { width: 18px; height: 18px; flex: none; color: var(--support-info); margin-top: 1px; }
.inline-note--warning { background: rgba(241,194,27,.16); border-left-color: var(--support-warning); }
.inline-note--warning svg { color: #8a6d00; }

/* ---------- Estados Vacío / Carga ---------- */
/* Nacio para ir pegado debajo de una tabla, por eso se comia el borde de
   arriba. Pero la mayoria de los estados vacios del ERP van sueltos sobre el
   fondo de la pagina, y sin borde superior quedaban abiertos por arriba. El
   caso suelto pasa a ser el normal y el de debajo de tabla, la variante. */
.empty-state { text-align: center; padding: var(--sp-10) var(--sp-06); color: var(--text-secondary);
  background: var(--layer-02); border: 1px solid var(--border-subtle); }
.empty-state--bajo-tabla { border-top: none; }
.empty-state svg { width: 48px; height: 48px; color: var(--text-disabled); margin-bottom: var(--sp-05); }
.empty-state h3 { font-size: var(--type-size-03); color: var(--text-primary); margin-bottom: var(--sp-02); }
.empty-state p { font-size: var(--type-size-02); margin-bottom: var(--sp-05); }

/* ---------- Skeleton ---------- */
.skel { position: relative; overflow: hidden; background: var(--skeleton-bg); border-radius: 2px; }
.skel::after { content: ""; position: absolute; inset: 0; transform: translateX(-100%);
  background: linear-gradient(90deg, transparent, var(--skeleton-shine), transparent);
  animation: skel-shine 1.2s infinite; }
@keyframes skel-shine { 100% { transform: translateX(100%); } }
.skel-line { height: 12px; margin: 8px 0; }
.skel-row { display: flex; gap: 16px; align-items: center; height: 48px; padding: 0 16px; border-bottom: 1px solid var(--border-subtle); }
.skel-card { background: var(--layer-02); border: 1px solid var(--border-subtle); padding: 20px; }
.skel-toolbar { height: 48px; background: var(--layer-02); border: 1px solid var(--border-subtle); border-bottom: none; }

/* ---------- Tabs ----------
   Medido del Storybook de Carbon, variantes `default` (linea) y `contained`.

   La linea de debajo la pinta CADA pestana con su propio `border-bottom` de
   2px, no el contenedor: en Carbon la raya empieza y acaba con las pestanas,
   no cruza la pantalla. Aqui era 1px en el contenedor mas 2px transparentes en
   la pestana, asi que la raya iba de punta a punta y ademas era mas fina que
   la marca de la activa: dos grosores para la misma linea. */
.tabs { display: flex; gap: 0; margin-bottom: 16px; overflow-x: auto; }
/* La pestaña puede ser un boton o un enlace: cuando cambia de contenido sin
   salir de la pagina es un boton, y cuando navega a otra URL es un enlace y
   debe poder abrirse en otra pestana del navegador. Antes solo se estilaba el
   boton, asi que las vistas que navegan lo escribian a mano. */
.tabs a,
.tabs button { height: 40px; padding: 0 16px; background: transparent; border: none;
  border-bottom: 2px solid var(--border-subtle);
  color: var(--text-secondary); font-size: var(--type-size-02); letter-spacing: .16px;
  white-space: nowrap; text-decoration: none;
  display: inline-flex; align-items: center;
  transition: border var(--dur-fast-01) var(--ease-standard); }
/* `hidden` tiene que poder con el `display` de arriba. El atributo solo trae
   `display: none` de la hoja del navegador, y cualquier `display` de autor le
   gana: la pestana marcada como escondida se seguia viendo. Aparecio con la de
   Combustible, que desaparece cuando la clase del vehiculo no gasta. */
.tabs a[hidden],
.tabs button[hidden] { display: none; }

/* Carbon oscurece la raya al pasar por encima, no la pinta de azul: el azul es
   la activa y solo hay una. */
.tabs a:hover,
.tabs button:hover { border-bottom-color: var(--border-strong); color: var(--text-primary); }
.tabs a.is-active,
.tabs button.is-active { color: var(--text-primary); border-bottom-color: var(--interactive);
  font-weight: var(--type-weight-semibold); transition: color var(--dur-fast-01) var(--ease-standard); }
.tabs a:focus-visible,
.tabs button:focus-visible { outline: 2px solid var(--focus); outline-offset: -2px; }

/* Carbon desplaza las pestanas cuando no caben, y para un detalle de tres o
   cuatro esta bien. Para un listado con seis filtros no: en movil el scroll
   escondia las unicas pestanas con viajes detras de las que estaban a cero, y
   nada anunciaba que hubiera mas. Con esto envuelven. Es una desviacion
   deliberada de Carbon, por eso es un modificador y no el comportamiento. */
.tabs--envuelve { flex-wrap: wrap; overflow-x: visible; }

/* Contador dentro de la pestana. Carbon no lo trae -sus tabs cambian de vista,
   no filtran-, pero en un listado la pestana sin numero obliga a entrar para
   saber si hay algo. Va en gris y a `--type-size-01` para que se lea como un
   apunte de la etiqueta y no compita con ella. */
.tabs__conteo { margin-left: var(--sp-03); padding: 1px 7px;
  font-size: var(--type-size-01); font-weight: var(--type-weight-regular);
  background: var(--layer-01); }
.tabs--contenida .tabs__conteo { background: var(--layer-02); }

/* Variante `contained`: cajas pegadas en vez de raya. Sirve para un segundo eje
   de filtrado junto a las pestanas de linea, donde repetir la raya haria que
   los dos ejes parecieran el mismo. La activa se aclara un escalon -de accent a
   layer-01- y se corona con 2px de azul por dentro. */
.tabs--contenida { border-bottom: 0; }
.tabs--contenida a,
.tabs--contenida button { height: 48px; border-bottom: 0; background: var(--layer-accent);
  box-shadow: -1px 0 0 0 var(--border-strong); }
/* Carbon no exceptua la primera y pinta esa raya fuera de la lista; aqui si,
   que asomando por la izquierda parece el borde de otra cosa. */
.tabs--contenida a:first-child,
.tabs--contenida button:first-child { box-shadow: none; }
.tabs--contenida a:hover,
.tabs--contenida button:hover { background: var(--layer-hover); color: var(--text-primary); }
.tabs--contenida a.is-active,
.tabs--contenida button.is-active { background: var(--layer-01); color: var(--text-primary);
  box-shadow: inset 0 2px 0 var(--interactive); }
.tabs--contenida a.is-active + a,
.tabs--contenida button.is-active + button { box-shadow: none; }

/* ---------- Header popovers (notificaciones / usuario) ---------- */
/* Cuelga del header, que es una superficie Gray 100 fija y por eso lleva
   `color` blanco, pero el popover tiene fondo propio -layer-02, blanco en
   claro-. Sin reponer el color, lo que no traiga el suyo hereda el blanco del
   header: el nombre del usuario salia blanco sobre blanco. Le pasa a los dos,
   al de usuario y al de notificaciones. */
.hdr-popover { width: 300px; background: var(--layer-02); color: var(--text-primary); box-shadow: var(--shadow-md); border: 1px solid var(--border-subtle); }
.pop-head { padding: 12px 16px; font-weight: var(--type-weight-semibold); font-size: 13px; border-bottom: 1px solid var(--border-subtle); }
.pop-foot { display: block; padding: 12px 16px; font-size: 13px; border-top: 1px solid var(--border-subtle); }
.pop-notif { display: flex; gap: 10px; padding: 12px 16px; border-bottom: 1px solid var(--border-subtle); font-size: 13px; }
.pop-notif svg { width: 18px; height: 18px; color: var(--icon-secondary); flex: none; margin-top: 2px; }
.pop-notif b { font-size: 13px; font-weight: var(--type-weight-medium); }
.pop-user { display: flex; gap: 10px; align-items: center; padding: 14px 16px; border-bottom: 1px solid var(--border-subtle); }
.pop-item { display: flex; align-items: center; gap: 10px; width: 100%; padding: 12px 16px; background: transparent; border: none;
  font-size: 14px; color: var(--text-primary); text-align: left; }
.pop-item:hover { background: var(--layer-hover); }
.pop-item svg { width: 16px; height: 16px; color: var(--icon-secondary); }

/* ---------- Backdrop sidebar móvil ---------- */
.sidebar-backdrop { position: fixed; inset: var(--header-h) 0 0 0; background: var(--overlay); z-index: 6500; display: none; }
/* Solo en movil: el velo acompana al panel deslizante. Sin el breakpoint, un
   `app--mobile-open` que sobreviviera al volver a escritorio dejaba la capa
   encima de todo y se comia cada clic de la pantalla. */
@media (max-width: 880px) {
  .app--mobile-open .sidebar-backdrop { display: block; }
}

/* ---------- Acciones de cabecera de página ---------- */
.page-actions { display: flex; gap: 8px; align-items: center; }
.export-menu { position: absolute; background: var(--layer-02); box-shadow: var(--shadow-md); border: 1px solid var(--border-subtle); z-index: 9500; min-width: 180px; }
.export-menu button { display: flex; align-items: center; gap: 10px; width: 100%; padding: 12px 14px; background: transparent; border: none;
  font-size: 14px; color: var(--text-primary); text-align: left; }
.export-menu button:hover { background: var(--layer-hover); }
.export-menu svg { width: 16px; height: 16px; color: var(--icon-secondary); }
.filter-count { display: inline-flex; align-items: center; justify-content: center; min-width: 18px; height: 18px; padding: 0 5px;
  background: var(--brand); color: #fff; border-radius: 9px; font-size: 11px; margin-left: 2px; }

/* ---------- Rejilla de tiles (líneas de 1px, estilo Carbon) ---------- */
/* La linea de separacion la pinta cada tarjeta con box-shadow, que no ocupa
   espacio. Antes era el fondo del contenedor asomando por un gap de 1px, y
   con un numero de tarjetas que no llena la ultima fila (5 en dos columnas,
   por ejemplo) el hueco sobrante se veia como una mancha gris. */
.tile-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
  gap: 0; border: 1px solid var(--border-subtle); overflow: hidden; }
.tile { background: var(--layer-02); padding: var(--sp-05); min-height: 9rem; display: flex; flex-direction: column;
  text-align: left; border: none; transition: background var(--dur-fast); position: relative; color: inherit; text-decoration: none;
  box-shadow: 1px 0 0 var(--border-subtle), 0 1px 0 var(--border-subtle); }
.tile:hover { text-decoration: none; }
.tile:hover { background: var(--layer-hover); }
.tile:hover .tile__arrow { transform: translateX(4px); opacity: 1; }
.tile__icon { width: 36px; height: 36px; display: grid; place-items: center; background: var(--brand-soft); color: var(--brand); margin-bottom: var(--sp-04); }
.tile__icon svg { width: 18px; height: 18px; }
.tile b { font-weight: var(--type-weight-semibold); font-size: var(--type-size-03); margin-bottom: var(--sp-02); color: var(--text-primary); }
.tile p { font-size: var(--type-size-02); color: var(--text-secondary); line-height: 1.45; flex: 1; }
.tile__foot { display: flex; align-items: center; justify-content: space-between; margin-top: var(--sp-04); font-size: var(--type-size-01); color: var(--brand); }
.tile__arrow { transition: transform .15s, opacity .15s; opacity: .55; width: 14px; height: 14px; }

/* ---------- Responsive componentes ---------- */
@media (max-width: 880px) {
  .toolbar { flex-wrap: wrap; }
  .toolbar__search { min-width: 60%; }
  .form-grid { grid-template-columns: 1fr; }
}
@media (max-width: 672px) {
  .overlay { padding: 0; align-items: stretch; }
  .modal, .modal--lg, .modal--sm { max-width: 100%; max-height: 100vh; height: 100vh; }
  .modal__body { flex: 1; }
  .drawer { width: 100%; max-width: 100%; }
  .table-foot { gap: var(--sp-03); padding: var(--sp-03) var(--sp-04); }
  .detail-row { grid-template-columns: 1fr; gap: 2px; }
  .page-actions { width: 100%; }
  .page-actions .btn { flex: 1; justify-content: center; }
}

/* ---------- Mi perfil (drawer) ---------- */
.profile-hero { display: flex; gap: var(--sp-04); align-items: center; padding-bottom: var(--sp-05);
  border-bottom: 1px solid var(--border-subtle); margin-bottom: var(--sp-05); }
.profile-avatar { width: 56px; height: 56px; border-radius: 50%; background: var(--brand); color: #fff;
  display: grid; place-items: center; font-size: var(--type-size-05); font-weight: var(--type-weight-bold); flex: none; }
.profile-name { font-size: var(--type-size-04); font-weight: var(--type-weight-semibold); color: var(--text-primary); }

/* ---------- Notificacion inline (Carbon) ----------
   Barra de estado con borde de 3px en el color del estado, icono y mensaje.
   Reemplaza a los divs con estilos escritos a mano en cada vista, que fijaban
   el color en claro y quedaban como parches luminosos en tema oscuro.
   El icono acompana al color: el color solo no es informacion accesible. */
.notificacion { display: flex; align-items: flex-start; gap: var(--sp-04);
  border-left: 3px solid var(--support-info); background: var(--notification-bg-info);
  color: var(--notification-text-info); font-size: var(--type-size-02); padding: var(--sp-04) var(--sp-05); }
.notificacion__icono { flex: none; width: 16px; height: 16px; margin-top: 1px;
  fill: none; stroke: currentColor; stroke-width: 1.4; }
.notificacion__texto { min-width: 0; }
.notificacion--success { border-left-color: var(--support-success);
  background: var(--notification-bg-success); color: var(--notification-text-success); }
.notificacion--error { border-left-color: var(--support-error);
  background: var(--notification-bg-error); color: var(--notification-text-error); }
.notificacion--warning { border-left-color: var(--support-warning);
  background: var(--notification-bg-warning); color: var(--notification-text-warning); }

/* ============ Interfaz tactil ============
   Safari en iOS amplia la pagina al enfocar cualquier campo cuyo texto mida
   menos de 16px, y no deshace el zoom al salir: en el formulario de gastos, con
   diez campos por debajo de ese umbral, registrar un comprobante se convertia en
   una pelea con la lupa. El umbral es exacto, asi que basta con alcanzarlo.

   Se aplica por `pointer: coarse` y no por ancho de pantalla: lo que importa es
   que el dispositivo se maneje con el dedo, no que la ventana sea estrecha. */
@media (pointer: coarse) {
  input, select, textarea {
    font-size: var(--type-size-03);
  }

  /* 44x44 es el area minima para acertar con el pulgar. Los controles que
     dependian solo de su tipografia se quedaban cortos: la aspa de cerrar un
     modal medía 26x33 y era el camino habitual para salir. */
  .catalog-modal__close,
  .btn-validar-cpe,
  .pw-toggle {
    min-width: 44px;
    min-height: 44px;
  }
}

/* ============ Tablas apilables ============
   Una tabla ancha en un movil no se arregla con scroll horizontal: en Mis
   Fondos la tabla medía 812px dentro de 318 disponibles, asi que se veia el 39%
   y la columna del monto -lo primero que el conductor entra a mirar- quedaba
   fuera de la pantalla. En Gastos era peor: 1180px en 350.

   Con `tabla-apilable` cada fila pasa a ser una tarjeta y cada celda muestra su
   encabezado al lado del dato, que es el patron que ya usa Viajes. El encabezado
   sale del propio `thead`, copiado por `apilarTablas()`, de modo que no hay que
   repetirlo en el HTML ni mantenerlo en dos sitios. */
@media (max-width: 672px) {
  .tabla-apilable thead {
    /* Oculto para la vista, presente para los lectores de pantalla */
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
  }

  /* `!important` aqui no es pereza: muchas celdas traen su layout de escritorio
     en un atributo `style` -por ejemplo `display: flex; justify-content: flex-end`
     en las de acciones-, y un estilo en linea solo se puede anular asi. Sin esto
     la celda seguia en flex, el rotulo se encogia hasta cortarse y de "ACCIONES"
     solo se leia "ES". Va acotado a la media query movil. */
  .tabla-apilable,
  .tabla-apilable tbody,
  .tabla-apilable tr,
  .tabla-apilable td {
    display: block !important;
    width: auto;
    min-width: 0;
  }

  .tabla-apilable tr {
    border: 1px solid var(--border-subtle);
    background: var(--layer-02);
    margin-bottom: var(--sp-03);
    padding: var(--sp-03) var(--sp-04);
  }

  .tabla-apilable td {
    display: grid !important;
    grid-template-columns: minmax(6rem, 40%) 1fr;
    gap: var(--sp-04);
    align-items: baseline;
    border: 0;
    border-bottom: 1px solid var(--border-subtle);
    padding: var(--sp-03) 0 !important;
    text-align: left !important;
  }

  /* La celda de escritorio mide 48px fijos. Apilada, un valor de tres lineas
     -una razon social con su sede- se salia de esos 48 y se montaba encima de
     la fila de abajo. Con `tbody` en el selector para empatar con el
     `.data-table tbody td` que fija la altura: empatados, gana esta por ir
     despues en el archivo. */
  .tabla-apilable tbody td { height: auto; }

  .tabla-apilable tr td:last-child { border-bottom: 0; padding-bottom: 0; }

  /* El rotulo ocupa la columna izquierda entera y todo el contenido de la
     celda cae en la derecha. Sin esto, una celda con varios elementos -un valor
     mas su aclaracion- desbordaba a la siguiente fila del grid y la aclaracion
     aparecia bajo el rotulo, descolgada y sin encabezado. */
  .tabla-apilable td::before {
    grid-column: 1;
    grid-row: 1 / -1;
    content: attr(data-titulo);
    /* Explicita: el rotulo heredaba la fuente de la celda, y en una columna
       de codigo salia en monoespaciada. */
    font-family: var(--font-sans);
    font-size: var(--type-size-01);
    font-weight: var(--type-weight-semibold);
    color: var(--text-secondary);
    /* Mayuscula solo inicial, como el rotulo de la columna del que se copia:
       en escritorio "Cliente y sede" y en el movil no puede ser otra cosa. */
  }

  .tabla-apilable td > * { grid-column: 2; }

  /* Una celda sin encabezado -acciones, casillas- ocupa el ancho entero */
  .tabla-apilable td[data-titulo=""] { grid-template-columns: 1fr; }
  .tabla-apilable td[data-titulo=""]::before { display: none; }

  /* Una celda con controles tampoco cabe en el 60% que deja el rotulo: los
     botones se salian por la izquierda y del rotulo solo se leia el final.
     El rotulo pasa arriba y los controles ocupan la fila entera. */
  .tabla-apilable td:has(button),
  .tabla-apilable td:has(form),
  .tabla-apilable td:has(.btn-carbon) {
    display: flex !important;
    flex-wrap: wrap;
    gap: var(--sp-03);
    align-items: center;
  }
  /* El rotulo ocupa su propia linea y los controles fluyen debajo */
  .tabla-apilable td:has(button)::before,
  .tabla-apilable td:has(form)::before,
  .tabla-apilable td:has(.btn-carbon)::before {
    flex: 0 0 100%;
  }


  /* El contenedor deja de necesitar scroll: ya no hay nada que desbordar */
  .tabla-apilable-wrap { overflow-x: visible; }
}


/* =====================================================================
   SELECT BUSCABLE
   Combo con filtro para catalogos largos (ubigeos, clientes). El <select>
   real sigue en el formulario, tapado por el campo de texto: se mantiene
   en el flujo, no en `display: none`, para que el navegador pueda anclar
   ahi el globo de validacion nativa. Ver select-buscable.js.
   ===================================================================== */
.select-buscable {
  position: relative;
}

.select-buscable__nativo {
  position: absolute;
  inset: 0;
  width: 100%;
  opacity: 0;
  pointer-events: none;
}

/* Los mismos 48px que reserva el <select> de arriba: el galon ocupa el sitio
   y el texto largo se corta antes de llegar a el. */
.select-buscable__campo {
  padding-inline-end: var(--sp-09);
}

/* El galon, igual que el del combo normal pero dibujado con `mask`: aqui si
   hay pseudoelemento donde ponerlo, asi que el color sale de un token y no
   hace falta repetir el glifo una vez por tema. Medido en
   components-combobox--default: 16px de lado, a 16px del borde, y gira 180
   grados al abrir en los mismos 70ms que el resto de microinteracciones. */
.select-buscable::after {
  content: '';
  position: absolute;
  inset-block-start: 50%;
  inset-inline-end: var(--sp-05);
  inline-size: 16px;
  block-size: 16px;
  transform: translateY(-50%);
  background-color: var(--icon-primary);
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M8 11 3 6 3.7 5.3 8 9.6 12.3 5.3 13 6z'/%3E%3C/svg%3E") center / 16px 16px no-repeat;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M8 11 3 6 3.7 5.3 8 9.6 12.3 5.3 13 6z'/%3E%3C/svg%3E") center / 16px 16px no-repeat;
  transition: transform var(--dur-fast-01) var(--ease-standard);
  pointer-events: none;
}

.select-buscable.is-abierto::after {
  transform: translateY(-50%) rotate(180deg);
}

/* Con la lista abierta, Carbon aclara la linea del campo: deja de ser el
   borde fuerte del control cerrado y pasa a ser la costura entre el campo y
   el panel que le cuelga debajo. */
.select-buscable.is-abierto .select-buscable__campo {
  border-bottom-color: var(--border-subtle);
}

/* Y cuando ademas hay una fila marcada, el anillo del campo adelgaza a 1px.
   Con los dos a 2px se veian dos recuadros azules apilados, uno cerrando
   justo encima del otro. Carbon los junta en una sola caja: este lado y el de
   arriba de la fila -la regla de abajo- valen 1px cada uno, asi que la
   costura se lee como una linea y no como una barra. */
.select-buscable.is-abierto:has(.select-buscable__opcion.is-activa) .select-buscable__campo:focus {
  outline-width: 1px;
  outline-offset: -1px;
}

/* El panel no lleva borde: lo que lo separa del fondo es la sombra, la misma
   que usa el menu de la tabla. Cinco filas y media de alto -220px sobre filas
   de 40- para que se vea cortado y se entienda que hay mas abajo. */
.select-buscable__lista {
  position: absolute;
  z-index: 9100;
  inset-block-start: 100%;
  inset-inline: 0;
  max-block-size: 220px;
  overflow-y: auto;
  margin: 0;
  padding: 0;
  list-style: none;
  background: var(--layer-01);
  box-shadow: 0 2px 6px rgba(0, 0, 0, .3);
}

/* La fila es un bloque y no una caja flexible aunque el texto vaya centrado:
   `text-overflow` necesita un bloque para poner los puntos suspensivos, y en
   flex el texto suelto no es uno. Se centra con el relleno, 12 arriba y 12
   abajo sobre una linea de 16, que son los 40 de alto. El hueco de 40 a la
   derecha es para la marca de la fila elegida. */
.select-buscable__opcion {
  position: relative;
  block-size: 40px;
  padding-block: var(--sp-04);
  padding-inline: var(--sp-05) var(--sp-08);
  font-size: var(--type-size-02);
  line-height: 1rem;
  letter-spacing: .16px;
  color: var(--text-secondary);
  cursor: pointer;
  user-select: none;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  transition: background-color var(--dur-fast-01) var(--ease-standard),
              color var(--dur-fast-01) var(--ease-standard);
}

/* El separador entre filas va sangrado 16px por cada lado, asi que no puede
   ser el borde de la fila: es una linea aparte. Carbon lo esconde encima y
   debajo de la fila marcada, para que el realce se lea como un bloque entero
   y no como una celda con costuras. */
.select-buscable__opcion::before {
  content: '';
  position: absolute;
  inset-block-start: 0;
  inset-inline: var(--sp-05);
  block-size: 1px;
  background: var(--border-subtle-01);
  transition: background-color var(--dur-fast-01) var(--ease-standard);
}

.select-buscable__opcion:first-child::before,
.select-buscable__opcion:hover::before,
.select-buscable__opcion:hover + .select-buscable__opcion::before,
.select-buscable__opcion.is-activa::before,
.select-buscable__opcion.is-activa + .select-buscable__opcion::before,
.select-buscable__opcion.is-elegida::before,
.select-buscable__opcion.is-elegida + .select-buscable__opcion::before {
  background: transparent;
}

.select-buscable__opcion:hover {
  background: var(--layer-hover);
  color: var(--text-primary);
}

/* La ya elegida se marca con fondo y una marca de verificacion a la derecha,
   que es el sitio que reserva el relleno de 40px de la fila. Antes iba en
   negrita: la negrita dice "importante", no "esta es la que tienes puesta". */
.select-buscable__opcion.is-elegida {
  background: var(--layer-selected);
  color: var(--text-primary);
}

.select-buscable__opcion.is-elegida::after {
  content: '';
  position: absolute;
  inset-block-start: 50%;
  inset-inline-end: var(--sp-05);
  inline-size: 16px;
  block-size: 16px;
  transform: translateY(-50%);
  background-color: var(--icon-primary);
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Cpath d='M13 24 4 15 5.414 13.586 13 21.171 26.586 7.586 28 9 13 24z'/%3E%3C/svg%3E") center / 16px 16px no-repeat;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Cpath d='M13 24 4 15 5.414 13.586 13 21.171 26.586 7.586 28 9 13 24z'/%3E%3C/svg%3E") center / 16px 16px no-repeat;
}

.select-buscable__opcion.is-elegida:hover {
  background: var(--layer-selected-hover);
}

/* La fila que Enter va a confirmar. Carbon no la tine: le pone el anillo de
   foco, el mismo que marca donde esta el teclado en cualquier otro control.
   Antes era un fondo mas una barra azul a la izquierda, que se confundia con
   la fila elegida ahora que esa si lleva fondo. */
.select-buscable__opcion.is-activa {
  outline: 2px solid var(--focus);
  outline-offset: -2px;
  color: var(--text-primary);
}

/* La primera fila pega con el campo, asi que su anillo no puede ser un
   anillo: seria una segunda linea sobre la del campo. Se dibuja como borde
   reaprovechando el separador -que en la primera fila esta apagado- y con el
   lado de arriba a 1px, que sumado al 1px del campo cierra la caja con una
   sola linea. Es lo que hace Carbon, y por eso la fila se queda sin outline
   propio. */
.select-buscable__opcion:first-child.is-activa {
  outline: none;
}

.select-buscable__opcion:first-child.is-activa::before {
  inset-inline: 0;
  block-size: 100%;
  background: transparent;
  border: 2px solid var(--focus);
  border-block-start: 1px solid var(--focus);
}

.select-buscable__opcion[aria-disabled='true'] {
  color: var(--text-disabled);
  cursor: not-allowed;
}

.select-buscable__opcion[aria-disabled='true']:hover {
  background: transparent;
  color: var(--text-disabled);
}

/* Ninguna de estas dos filas es de Carbon: son de la casa. Una avisa de que
   no hay coincidencias y la otra de que la lista viene recortada. No se
   eligen, asi que no se comportan como opcion: ni cursor ni realce. */
.select-buscable__vacio,
.select-buscable__resto {
  padding: var(--sp-04) var(--sp-05);
  font-size: var(--type-size-01);
  line-height: 1.33333;
  color: var(--text-secondary);
}

.select-buscable__resto {
  border-top: 1px solid var(--border-subtle-01);
}


/* =====================================================================
   CAMPO CALCULADO (solo lectura)
   Valores que pone el sistema y el usuario no teclea: el correlativo del
   documento, el dato copiado del maestro, una tasa que es 1 por definicion.

   Sigue el estado *read-only* de Carbon, no el disabled. Carbon deshabilita
   conservando el fondo del campo y apagando el texto a `$text-disabled`; en
   read-only, en cambio, quita el fondo (`background: transparent`) y deja
   solo el borde inferior en `$border-subtle`, con el texto legible. Eso es
   lo que corresponde aca: el dato importa y hay que leerlo, lo que no se
   puede es escribirlo. Ademas el fondo ya no sirve como senal en este
   sistema, porque `--layer-01` y `--field-01` son el mismo gris: el campo
   "apagado" se veia igual que uno editable.
   ===================================================================== */
/* El doble nombre venia de cuando `.form-control` vivia en un <style> del
   layout: el navegador lo leia despues de esta hoja y con la misma
   especificidad le ganaba. Ahora ambas reglas estan en este archivo, pero se
   conserva el selector de dos clases porque .form-control aparece mas arriba
   y necesita mas peso para imponerse. */
.form-control.campo-calculado,
.campo-calculado {
  background: transparent;
  border-color: transparent;
  border-bottom-color: var(--border-subtle);
  color: var(--text-primary);
  cursor: not-allowed;
  pointer-events: none;
  user-select: none;
}


/* Texto de ayuda bajo un campo: el `helper text` de Carbon, que cuelga del
   campo y usa `$text-helper`. Las filas que lo lleven tienen que alinear por
   arriba (`align-items: start`), o el campo con ayuda levanta a los demas. */
.form-ayuda {
  color: var(--text-helper);
  font-size: var(--type-size-01);
  margin: 0.25rem 0 0;
}

/* Sin texto no deja hueco, para que la fila no salte al aparecer y
   desaparecer el mensaje. */
.form-ayuda:empty {
  display: none;
}

/* ---------- Grupo de campos ----------
   El FormGroup de Carbon, medido en components-formgroup--default: un
   <fieldset> sin borde, sin relleno y sin margen. La caja gris con la leyenda
   cortando la linea es lo que el navegador le pone de fabrica, y no existe en
   Carbon.

   La leyenda de Carbon mide como el rotulo de un campo -12px, text-secondary-
   porque la pensaron para agrupar casillas o radios. Aqui el grupo parte un
   formulario en secciones, y con la leyenda al tamanio del rotulo la seccion
   no se distinguiria de sus propios campos: va en heading-compact-01, el
   titulo de componente de Carbon (14/18, semibold, .16px). */
.grupo-campos {
  min-inline-size: 0;  /* un fieldset no encoge por debajo de su contenido sin esto */
  margin: 0;
  padding: 0;
  border: 0;
}
.grupo-campos + .grupo-campos { margin-block-start: var(--sp-07); }
.grupo-campos__titulo {
  margin: 0 0 var(--sp-02);
  padding: 0;
  font-size: var(--type-size-02);
  font-weight: var(--type-weight-semibold);
  line-height: 1.28572;
  letter-spacing: .16px;
  color: var(--text-primary);
}
.grupo-campos__ayuda {
  margin: 0 0 var(--sp-05);
  font-size: var(--type-size-01);
  line-height: 1.33333;
  letter-spacing: .32px;
  color: var(--text-helper);
}
/* Los campos del grupo, en tantas columnas como quepan de 12rem. Mismo hueco
   que .form-grid entre columnas, y el de .form-group entre filas.
   `auto-fill` y no `auto-fit`: con `auto-fit` las columnas vacias se pliegan
   y un campo solo se estira a todo el ancho -un total de cinco cifras en una
   caja de mil pixeles-. Asi ocupa su columna y el resto queda libre. */
.grupo-campos__campos {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(12rem, 1fr));
  gap: var(--sp-05) var(--sp-06);
  align-items: start;
}
.grupo-campos__campos > .form-group { margin: 0; }
/* Los campos que siguen a una tabla del grupo -el total bajo la lista que
   suma- no van pegados a ella. */
.grupo-campos > .table-wrap + .grupo-campos__campos { margin-block-start: var(--sp-06); }


/* ---------- Proceso en curso ----------
   Cubre la pantalla mientras el navegador envia un formulario que tarda de
   verdad: una importacion, una carga de archivos. Ico en cola marca el ritmo
   y cada fila del riel es uno de los modulos que se estan cargando, asi que
   el riel no es adorno: se pinta con los que el usuario eligio.

   La cola no promete un porcentaje. Se anima en bucle y dura exactamente lo
   que dura la peticion, porque en un envio de formulario normal el navegador
   no puede saber por donde va el servidor. Prometer un avance seria inventar. */
.proceso { position: fixed; inset: 0; z-index: 9000; display: none;
  align-items: center; justify-content: center; background: var(--overlay); padding: var(--sp-05); }
.proceso.is-abierto { display: flex; }
.proceso__caja { background: var(--layer-02); border: 1px solid var(--border-subtle);
  box-shadow: var(--shadow-md); padding: var(--sp-07); width: min(28rem, 100%); text-align: center; }
.proceso__caja .ico { margin-bottom: var(--sp-06); }
.proceso__titulo { font-size: var(--type-size-05); font-weight: var(--type-weight-light);
  color: var(--text-primary); margin: 0 0 var(--sp-03); }
.proceso__nota { font-size: var(--type-size-02); color: var(--text-secondary); margin: 0; }

/* Envoltorio del indicador de espera de un filtro: junta el boton de enviar
   con su Ico sin obligar a cada vista a tocar su propio layout, que en unas
   es rejilla y en otras flex. */
.filtro-espera { display: inline-flex; align-items: center; gap: var(--sp-03); }


/* =====================================================================
   Paginacion

   Una sola barra para todo el ERP: la pinta vendor/pagination/carbon.blade.php,
   registrada como plantilla por defecto.

   Es el componente Pagination de Carbon, que es el que el DataTable empareja.
   Antes esto era PaginationNav -enlaces numerados con "Anterior" y
   "Siguiente" en texto-, que es otro componente de Carbon y no el que
   acompania a una tabla. Ahora el recuento va a la izquierda, y a la derecha
   el salto de pagina y los dos pasos.

   Y va PEGADA al pie de la tabla, que es donde Carbon la pone: sin
   `margin-top` y sin borde superior, porque el borde de la tabla ya esta ahi.
   Antes flotaba a un --sp-05 de distancia y se leia como otro bloque de la
   pantalla en lugar de como parte de la tabla.
   ===================================================================== */
.paginacion {
  display: flex;
  align-items: stretch;
  justify-content: space-between;
  flex-wrap: wrap;
  min-height: 48px;
  background: var(--layer-01);
  border: 1px solid var(--border-subtle);
  border-top: 0;
  font-size: var(--type-size-02);
  color: var(--text-primary);
}
.paginacion__lado {
  display: flex;
  align-items: center;
  min-width: 0;
}

.paginacion__conteo,
.paginacion__texto {
  margin: 0;
  padding: 0 var(--sp-05);
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.paginacion__conteo b { font-weight: var(--type-weight-semibold); }

/* Selector de pagina. El galon se dibuja con dos degradados: ni imagen que
   cargar ni SVG que mantener aparte. */
.paginacion__salto {
  font: inherit;
  font-size: var(--type-size-02);
  color: var(--text-primary);
  background: transparent;
  border: 0;
  border-bottom: 1px solid var(--border-strong);
  height: 24px;
  margin-left: var(--sp-05);
  padding: 0 var(--sp-06) 0 var(--sp-03);
  cursor: pointer;
  appearance: none;
  background-image:
    linear-gradient(45deg, transparent 50%, currentColor 50%),
    linear-gradient(135deg, currentColor 50%, transparent 50%);
  background-position: calc(100% - 11px) 10px, calc(100% - 6px) 10px;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
}
.paginacion__salto:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }

/* Los pasos: cuadrados del alto de la barra y separados por una linea, como
   los publica Carbon. Antes eran dos enlaces de texto. */
.paginacion__paso {
  width: 48px;
  flex: none;
  display: grid;
  place-items: center;
  border: 0;
  border-left: 1px solid var(--border-subtle);
  background: transparent;
  color: var(--text-primary);
  cursor: pointer;
  text-decoration: none;
  transition: background-color var(--dur-fast-01) var(--ease-entrance);
}
.paginacion__paso:hover { background: var(--layer-hover); }
.paginacion__paso:focus-visible { outline: 2px solid var(--focus); outline-offset: -2px; }
.paginacion__paso svg { width: 16px; height: 16px; fill: currentColor; }

/* Inerte y no ausente: el paso conserva su sitio para que la barra no cambie
   de ancho al llegar a la primera pagina o a la ultima. */
.paginacion__paso--inerte {
  color: var(--text-disabled);
  cursor: not-allowed;
  pointer-events: none;
}

/* La pagina que no existe no lleva navegacion: lleva la salida. */
.paginacion__aviso { padding: var(--sp-04) var(--sp-05); margin: 0; }
.paginacion__aviso a { color: var(--link-primary); }

/* En estrecho se van los dos selectores y se queda lo imprescindible: donde
   estas y como avanzar. Es lo que hace Carbon, medido sobre el componente: a
   partir de 672px -su breakpoint `md`- desaparecen el "por pagina" y el salto
   de pagina, se conserva el rango, y la barra NO se parte en dos filas.

   Antes aqui se apilaban los dos lados. Cabia todo, pero la barra pasaba a
   medir el doble justo donde menos alto sobra, y elegir cuantos por pagina en
   un movil no es una tarea real: se ajusta una vez desde el escritorio. */
@media (max-width: 42rem) {
  .paginacion__salto,
  .paginacion__texto { display: none; }
}


/* ---------- Marca de estado ----------
   El vocabulario sale del riel de Ico y esta documentado en ico.css. La marca
   se saca de ahi para poder usarla suelta: en una fila de reparto, en el
   rotulo de una tarjeta o en una celda de tabla.

     futura   rombo hueco     todavia no empezo
     activa   rombo lleno     en curso
     mitad    rombo partido   a medias
     parcial  rombo partido   a medias, y avisa
     ok       check           cerrado bien
     error    equis           cerrado mal
     neutra   rombo gris      sin estado propio

   La forma dice QUE estado es, y nada mas. Cuando un recuento esta en cero se
   apaga la fila con .es-cero, pero la marca se queda: si el cero cambiara la
   forma, cuatro estados distintos se verian iguales y habria que leer la
   etiqueta para distinguirlos.

   Seis formas y no seis colores: asi el estado se sigue leyendo sin depender
   de la vista cromatica. Es lo que Carbon resuelve con shape-indicator y que
   Ico ya tenia. */
.marca { display: inline-flex; align-items: center; gap: var(--sp-03); }
/* `[hidden]` lo pone la hoja del navegador y cualquier `display` de hoja de
   autor le gana, asi que una marca con `hidden` seguia viendose. Hace falta
   siempre que dos marcas se turnen para decir un estado que cambia. */
.marca[hidden] { display: none; }
.marca__f { width: 12px; height: 12px; flex: none; }
.marca__txt { font-size: var(--type-size-02); line-height: 1.28572; letter-spacing: .16px; color: var(--text-secondary); }

/* Los rombos son un cuadrado girado, igual que .ico__rombo. */
.marca--neutra .marca__f,
.marca--futura .marca__f,
.marca--activa .marca__f { transform: rotate(45deg); }
.marca--neutra rect { fill: var(--cds-gray-50); }
.marca--activa rect { fill: var(--interactive); }
.marca--futura rect { fill: none; stroke: var(--cds-gray-50); stroke-width: 1.6; }

/* Remates en escuadra, como los del riel: el sistema es cuadrado tambien aqui. */
.marca--ok    path { fill: none; stroke: var(--support-success); stroke-width: 2.2; stroke-linecap: square; stroke-linejoin: miter; }
.marca--error path { fill: none; stroke: var(--support-error); stroke-width: 2; stroke-linecap: square; }

.marca--mitad   { color: var(--interactive); }
.marca--parcial { color: var(--support-warning); }
.marca--mitad .marca__borde,
.marca--parcial .marca__borde { fill: none; stroke: currentColor; stroke-width: 2; }
.marca--mitad .marca__lleno,
.marca--parcial .marca__lleno { fill: currentColor; }

/* Aviso: triangulo lleno, la unica figura del vocabulario que no sale del
   rombo. Antes esto era un rombo lleno ambar, igual de forma que `activa`
   -rombo lleno azul-, o sea el color decidiendo el significado. */
.marca--alerta path { fill: var(--support-warning); }

/* ---------- Fila de reparto ----------
   Una etiqueta, una barra proporcional y una cifra, con la marca delante. Es
   la misma fila que el riel de Ico dibuja para cada modulo; aqui sirve para
   repartir un total entre sus estados.

   Las filas en cero no desaparecen: si aparecieran y se fueran segun el dato,
   la pantalla cambiaria de forma cada dia y no se podrian comparar dos visitas
   de un vistazo. */
.reparto-fila { display: grid; grid-template-columns: 12px minmax(5rem, auto) 1fr auto;
  gap: var(--sp-04); align-items: center; margin-bottom: var(--sp-04); }
.reparto-fila:last-child { margin-bottom: 0; }
.reparto-fila__rotulo { font-size: var(--type-size-02); line-height: 1.28572; letter-spacing: .16px; color: var(--text-secondary); white-space: nowrap; }
.reparto-fila__pista { display: block; height: 4px; background: var(--border-subtle); }
.reparto-fila__marca { display: block; height: 100%; width: var(--valor, 0%);
  background: var(--color-estado, var(--interactive));
  transition: width var(--dur-slow-01) var(--ease-standard); }

/* El color de la barra sigue al estado, con el mismo criterio que la marca
   que va delante: solo los que cierran algo o estan en curso lo llevan, y los
   de transito se quedan en el gris de la pista. Este mapa vivia copiado en
   cada vista que dibujaba un reparto; aqui vive una vez. */
.reparto-fila--activa  { --color-estado: var(--interactive); }
.reparto-fila--mitad   { --color-estado: var(--interactive); }
.reparto-fila--ok      { --color-estado: var(--support-success); }
.reparto-fila--parcial { --color-estado: var(--support-warning); }
.reparto-fila--alerta  { --color-estado: var(--support-warning); }
.reparto-fila--error   { --color-estado: var(--support-error); }
.reparto-fila--futura  { --color-estado: var(--border-strong); }
.reparto-fila--neutra  { --color-estado: var(--border-strong); }

/* Variante para los repartos que ademas del recuento llevan importe. Las dos
   cifras van juntas al final, la del recuento primero porque es la que se
   compara con la barra. */
.reparto-fila--monto { grid-template-columns: 12px minmax(6rem, auto) 1fr auto auto; }
.reparto-fila__monto { font-size: var(--type-size-01); color: var(--text-secondary);
  font-variant-numeric: tabular-nums; min-width: 5.5rem; text-align: right; white-space: nowrap; }
.reparto-fila__valor { min-width: 2rem; text-align: right; font-size: var(--type-size-02);
  color: var(--text-primary); font-variant-numeric: tabular-nums; }
.reparto-fila.es-cero { opacity: .45; }

/* ---------- Resumen y reparto ----------
   La forma que toma un grupo de estados cuando son CINCO O MAS, o cuando son
   partes de un mismo total. Cinco tarjetas iguales dicen que las cinco cifras
   son independientes, y no lo son: "vigentes", "por vencer" y "vencidos" son
   trozos de "obligatorios". Ademas .kpi-grid tiene cuatro columnas, asi que la
   quinta tarjeta se quedaba sola ocupando el ancho de cuatro.

   A la izquierda los totales que resumen; a la derecha el reparto en filas,
   donde las cifras caen sobre el mismo eje y se comparan de un vistazo. */
.resumen-reparto { display: grid; grid-template-columns: minmax(14rem, 17rem) 1fr;
  gap: var(--sp-05); align-items: start; }
.resumen-reparto__totales { display: grid; gap: var(--sp-05); }
@media (max-width: 52rem) { .resumen-reparto { grid-template-columns: 1fr; } }

/* ---------- Acordeon (Carbon) ----------
   Las reglas salen medidas del Storybook, no de memoria: cabecera de 2.5rem,
   chevron de 16px que gira de -270deg a -90deg en 110ms con la curva de
   entrada, titulo body-01 con 1rem de sangria, hover cubriendo la cabecera
   entera y cuerpo con 0.5rem arriba y 1.5rem abajo.

   Lo que habia antes eran `<details>` con estilos propios repetidos en cada
   vista: tarjeta con borde completo, 1.25rem de relleno y ningun chevron -el
   marcador nativo se ocultaba y no se reemplazaba por nada-, de modo que nada
   decia que aquello se abriera. Carbon hace lo contrario: no dibuja caja, solo
   una linea de 1px entre items, y deja ver la capa que tiene debajo. Por eso
   aqui no hay `background`: el acordeon toma el color del sitio donde se pone.

   Va sobre `<details>` y no sobre el boton con aria-expanded de Carbon React
   porque abre y cierra sin JS, que es como funciona el resto de esta app, y
   porque `<summary>` ya se anuncia como control desplegable sin ARIA que
   mantener en dos sitios. */
.acordeon { --acordeon-alto: var(--sp-08); }
.acordeon--sm { --acordeon-alto: var(--sp-07); }
.acordeon--lg { --acordeon-alto: var(--sp-09); }

.acordeon__item { border-top: 1px solid var(--border-subtle);
  transition: border-color 110ms cubic-bezier(.2, 0, .38, .9); }
.acordeon__item:last-child { border-bottom: 1px solid var(--border-subtle); }

/* row-reverse con el chevron primero en el HTML: el titulo ocupa el 100% y
   empuja la flecha al extremo, que es como Carbon coloca la variante `--end`
   sin necesitar un `order` por elemento. */
.acordeon__cabecera { display: flex; flex-direction: row-reverse;
  justify-content: flex-start; align-items: center; gap: 0;
  min-height: var(--acordeon-alto); padding-right: var(--sp-05);
  color: var(--text-primary); cursor: pointer; list-style: none;
  transition: background-color 110ms cubic-bezier(.2, 0, .38, .9); }
.acordeon__cabecera::-webkit-details-marker { display: none; }
.acordeon__cabecera:hover { background: var(--layer-hover); }
.acordeon__cabecera:focus-visible { outline: 2px solid var(--focus); outline-offset: -2px; }

.acordeon__flecha { flex: 0 0 1rem; width: 1rem; height: 1rem;
  color: var(--icon-primary); transform: rotate(-270deg);
  transition: transform 110ms cubic-bezier(.2, 0, .38, .9); }
.acordeon__item[open] > .acordeon__cabecera .acordeon__flecha { transform: rotate(-90deg); }

.acordeon__titulo { display: flex; align-items: center; justify-content: space-between;
  gap: var(--sp-05); width: 100%; min-width: 0; padding-left: var(--sp-05);
  text-align: start; font-size: var(--type-size-02);
  font-weight: var(--type-weight-regular); line-height: 1.42857; letter-spacing: .16px; }
.acordeon__extremo { flex: none; display: flex; align-items: center; gap: var(--sp-03); }

.acordeon__cuerpo { padding: var(--sp-03) var(--sp-05) var(--sp-06); }

/* Un acordeon dentro de otro se apoya en layer-01 para que se vea donde
   empieza, y esa capa se lleva su propio border-subtle: con el plano la linea
   caia a 1.06 de contraste sobre #f4f4f4 y el anidado parecia un bloque suelto
   sin separaciones. Es el caso que Carbon ensena en la story "with layer". */
.acordeon--anidado { background: var(--layer-01); }
.acordeon--anidado > .acordeon__item { border-color: var(--border-subtle-01); }

/* Sin caja no queda borde donde poner el color de aviso, asi que lo toman las
   dos lineas del item: es el unico trazo que el componente dibuja. */
.acordeon__item--aviso { border-color: var(--support-warning); }
.acordeon__item--aviso + .acordeon__item { border-top-color: var(--support-warning); }

/* La cuenta que acompana al titulo. Sin pildora y sin color: llevaba fondo azul
   y borde, y en una fila de 40px eso ya no se leia como un dato sino como un
   control que se puede pulsar. Cifras tabulares para que los numeros de varias
   filas caigan sobre el mismo eje. */
.acordeon__cuenta { color: var(--text-secondary); font-size: var(--type-size-01);
  font-variant-numeric: tabular-nums; white-space: nowrap; }

/* La linea que explica de que va el grupo. Vivia en la cabecera y la estiraba a
   41px dentro de una caja de 40; aqui arriba del cuerpo se lee mejor y deja el
   ritmo de Carbon intacto. */
.acordeon__nota { margin: 0 0 var(--sp-05); color: var(--text-secondary);
  font-size: var(--type-size-02); max-width: 60ch; }

/* En estrecho el titulo y lo que va a su derecha dejan de caber en una linea:
   antes de que el boton de "agregar requisito" empuje al titulo a partirse
   letra a letra, se apilan. El chevron se queda donde esta. */
@media (max-width: 40rem) {
  .acordeon__titulo { flex-direction: column; align-items: flex-start; gap: var(--sp-03); }
}

/* Las acciones del item, al final de su cuerpo. Estaban en la cabecera y de
   ahi salieron: un boton secundario mide 158x40 en gris casi negro, y metido
   en una fila de 40px pesaba mas que el titulo del grupo al que pertenecia.
   Abajo del todo leen como lo que son -lo que puedes hacer con lo que acabas
   de abrir- y ya no compiten con nada. */
.acordeon__acciones { display: flex; flex-wrap: wrap; gap: var(--sp-03);
  margin-top: var(--sp-05); }
.acordeon__nota code { font-family: var(--font-mono); font-size: var(--type-size-01); }

/* ---------- Subida de archivos (Carbon) ----------
   Medido del Storybook de Carbon, no reconstruido: rotulo heading-compact-01
   con 8px debajo, ayuda body-compact-01 en texto secundario con 16px, lista a
   16px del disparador, y cada archivo en una fila de 40px sobre layer-01.

   El ancho de 320px no es una eleccion de esta app: es el `max-width` que
   Carbon le pone al componente entero -zona, boton y filas- para que el nombre
   de archivo tenga un limite donde truncarse. Si una pantalla necesita mas,
   que lo suba ella; el valor por defecto es el de Carbon.

   La zona de arrastre es un `<label>` con el input dentro y oculto: asi
   arrastrar, pulsar y llegar con el tabulador son la misma cosa y no hace
   falta JS para abrir el selector de archivos. */
.subida { max-width: 20rem; }
.subida__rotulo { margin: 0 0 var(--sp-03); color: var(--text-primary);
  font-size: var(--type-size-02); font-weight: var(--type-weight-semibold);
  line-height: 1.28572; letter-spacing: .16px; }
.subida__ayuda { margin: 0 0 var(--sp-05); color: var(--text-secondary);
  font-size: var(--type-size-02); line-height: 1.28572; letter-spacing: .16px; }

/* Discontinuo y sin relleno: la zona anuncia que espera algo, no que ya lo
   tenga. El borde es `border-strong` -no `subtle`- porque tiene que verse a
   traves de toda la caja vacia. */
.subida__zona { display: flex; align-items: flex-start; justify-content: space-between;
  gap: var(--sp-05); height: 6rem; padding: var(--sp-05);
  border: 1px dashed var(--border-strong); background: none;
  color: var(--link-primary); cursor: pointer;
  font-size: var(--type-size-02); line-height: 1.28572; letter-spacing: .16px; }
.subida__zona:hover { background: var(--layer-hover); }
.subida__zona:focus-within,
.subida__zona--encima { outline: 2px solid var(--focus); outline-offset: -2px; }

.subida__lista { list-style: none; margin: var(--sp-05) 0 0; padding: 0; }

.subida__archivo { display: grid; grid-template-columns: 1fr 2.25rem;
  align-items: center; min-height: var(--subida-alto, var(--sp-08));
  background: var(--layer-01); color: var(--text-primary);
  font-size: var(--type-size-02); word-break: break-word; }
.subida__archivo + .subida__archivo { margin-top: 1px; }
.subida--sm { --subida-alto: var(--sp-07); }
.subida--lg { --subida-alto: var(--sp-09); }

/* El nombre se trunca con puntos suspensivos y no parte en dos lineas: la
   fila mide 40px y un nombre largo la rompia. El nombre completo sigue estando
   en el `title` para quien pase por encima. */
.subida__nombre { padding-left: var(--sp-05); min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* 36px con el aspa sola; 52px cuando ademas hay que ensenar el aviso, que es
   16 de icono mas 24 de boton mas los 12 de aire a la derecha. */
.subida__estado { display: flex; align-items: center; justify-content: center;
  width: 2.25rem; height: 1.5rem; padding-right: var(--sp-04); }
.subida__estado .icono { color: var(--icon-primary); }

.subida__quitar { display: flex; align-items: center; justify-content: center;
  width: 1.5rem; height: 1.5rem; padding: 0; border: 0; background: none;
  color: var(--icon-primary); cursor: pointer; }
.subida__quitar:focus-visible { outline: 2px solid var(--focus); outline-offset: -2px; }

/* Terminado en azul y no en verde: Carbon reserva el verde para "todo el
   proceso salio bien", y un archivo subido es un paso, no un desenlace. */
.subida__archivo--completo .icono { color: var(--link-primary); }

/* El error se marca con el contorno y no pintando la fila: el nombre del
   archivo tiene que seguir leyendose igual de bien para poder cambiarlo. La
   fila rechazada crece a dos renglones, gana 8px de aire arriba y abajo, y
   conserva el aspa: un archivo que no vale es justo el que hay que poder
   quitar. */
.subida__archivo--invalido { grid-template-columns: 1fr 3.25rem;
  padding: var(--sp-03) 0; row-gap: var(--sp-03);
  outline: 2px solid var(--support-error); outline-offset: -2px; }
.subida__archivo--invalido .subida__estado { width: 3.25rem; }
.subida__archivo--invalido .subida__estado > .icono { color: var(--support-error); }

/* El mensaje va en dos partes: que fallo, en rojo, y que hacer, en texto
   normal. Las dos son label-01. Poner tambien el detalle en rojo no anade
   informacion y lo hace mas dificil de leer, que es la parte que hay que
   leer entera. */
.subida__error { grid-column: 1 / -1; margin: 0; padding: 11px 0 0; overflow: hidden; }
.subida__error-titulo,
.subida__error-detalle { margin: 0; padding: 0 var(--sp-05);
  font-size: var(--type-size-01); line-height: 1.33333; letter-spacing: .32px; }
.subida__error-titulo { color: var(--support-error); }
.subida__error-detalle { color: var(--text-primary); }

/* Dos subidas lado a lado con sus piezas alineadas.
   Sin esto cada bloque se apila por su cuenta y, en cuanto una linea de ayuda
   ocupa dos renglones y la otra uno, las zonas arrancan a distinta altura. Con
   `subgrid` las tres filas -rotulo, ayuda, zona- las manda la rejilla de
   fuera, asi que caen a la misma altura sin fijar alturas a ojo. Donde no haya
   subgrid la declaracion se ignora y queda como estaba: desalineado, no roto. */
.subida-pareja { display: grid; grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
  grid-template-rows: auto auto auto auto; gap: var(--sp-04); }
.subida-pareja > .subida { display: grid; grid-row: span 4; grid-template-rows: subgrid; gap: 0; }

/* Con el dedo, no con el raton.
   El aspa medía 24x24, por debajo de los 44 que este mismo archivo ya exige
   para los demas controles. Crece, y con ella la fila y su hueco de estado:
   un boton de 44 en una fila de 40 la reventaria. */
@media (pointer: coarse) {
  .subida { --subida-alto: 3rem; }
  .subida__archivo { grid-template-columns: 1fr 3.5rem; }
  .subida__estado { width: 3.5rem; padding-right: var(--sp-03); }
  .subida__quitar { min-width: 44px; min-height: 44px; }
  /* Mas alta y con el texto mas grande: es el blanco que se pulsa para abrir
     la camara o la galeria, y es la accion principal de esta pantalla. */
  .subida__zona { min-height: 5.5rem; font-size: var(--type-size-03); }
  /* Y lo mismo cuando el disparador es un boton. Los botones de esta interfaz
     miden 40px, cuatro por debajo de los 44 que este archivo exige mas arriba
     para el pulgar; se sube solo aqui, donde el boton es la accion principal,
     y no en `.btn-carbon`, que cambiaria la altura de toda la aplicacion. */
  .subida .btn-carbon,
  .subida .btn-carbon-secondary { min-block-size: 44px; }
}

/* =====================================================================
   login.css — Pantalla de acceso multiempresa (línea auth-carbon)
   Carga junto a tokens.css + base.css. Autocontenida.
   ===================================================================== */
body { overflow: hidden; }

/* ---------------- Layout dos columnas ---------------- */
.screen-login { position: fixed; inset: 0; display: grid; grid-template-columns: 1fr 1fr; background: var(--background); z-index: 10; }

/* `flex-end` y no `space-between`: el texto va abajo, que es donde estaba. El
   `space-between` lo repartia entre dos hijos -la marca arriba y el texto
   abajo-, asi que al quitar la marca el texto se quedo solo y subio al hueco
   que dejo. No es una decision nueva de composicion, es la de siempre escrita
   sin depender de un elemento que ya no existe. */
.login-brand { background: var(--cds-gray-100); color: #fff; display: flex; flex-direction: column; justify-content: flex-end;
  padding: var(--sp-09); position: relative; overflow: hidden; }
.login-brand::after { content: ""; position: absolute; inset: 0; pointer-events: none;
  background-image: linear-gradient(rgba(255,255,255,.045) 1px, transparent 1px), linear-gradient(90deg, rgba(255,255,255,.045) 1px, transparent 1px);
  background-size: 48px 48px; }
.brand-copy { z-index: 1; max-width: 27rem; }
/* El blanco hay que decirlo: base.css pinta todo h1 con --text-primary, que
   le gana al color heredado del panel, y la primera linea salia gris 100 sobre
   gris 100. Solo se leia la parte en azul. */
.brand-copy h1 { font-size: var(--type-size-09); font-weight: var(--type-weight-light); line-height: 1.2; margin-bottom: var(--sp-05); color: #fff; }
.brand-copy h1 strong { font-weight: var(--type-weight-semibold); color: var(--cds-blue-40); }
.brand-copy p { color: var(--cds-gray-40); font-size: var(--type-size-03); line-height: 1.55; }
/* Los rotulos son texto, no cifras de un digito: a 1.75rem los tres no entran
   en la columna y "Por plan" se parte en dos lineas. */
.brand-stats { display: flex; gap: var(--sp-06); margin-top: var(--sp-07); z-index: 1; flex-wrap: wrap; }
.brand-stats div { flex: 1 1 0; min-width: 8rem; }
.brand-stats div b { display: block; font-size: var(--type-size-04); font-weight: var(--type-weight-regular); color: #fff; white-space: nowrap; }
.brand-stats div span { display: block; margin-top: var(--sp-02); font-size: var(--type-size-01); line-height: 1.4; color: var(--cds-gray-50); }
.brand-foot { z-index: 1; color: var(--cds-gray-60); font-size: var(--type-size-01); }

.login-form-col { display: flex; align-items: center; justify-content: center; padding: var(--sp-07); overflow-y: auto; background: var(--background); }
.login-card { width: 100%; max-width: 25rem; }
.login-card .eyebrow { font-size: var(--type-size-01); letter-spacing: .32px; color: var(--text-secondary); margin-bottom: var(--sp-03); }
.login-card h2 { font-size: var(--type-size-07); font-weight: var(--type-weight-regular); margin-bottom: var(--sp-02); color: var(--text-primary); }
.login-card .sub { color: var(--text-secondary); margin-bottom: var(--sp-07); font-size: var(--type-size-02); }

/* ---------------- Campos ---------------- */
.lg-field { margin-bottom: var(--sp-06); }
.lg-field label { display: block; font-size: var(--type-size-01); color: var(--text-secondary); letter-spacing: .32px; margin-bottom: var(--sp-03); }
.lg-input-wrap { position: relative; }
.lg-input { width: 100%; height: 2.5rem; border: none; outline: 2px solid transparent; outline-offset: -2px;
  background: var(--field-01); border-bottom: 1px solid var(--border-strong); padding: 0 var(--sp-05);
  font-family: inherit; font-size: var(--type-size-02); color: var(--text-primary); transition: outline-color .11s var(--ease); }
.lg-input::placeholder { color: var(--text-placeholder); }
.lg-input:focus { outline-color: var(--brand); }
.lg-field.invalid .lg-input { outline-color: var(--support-error); }
.lg-field .helper-error { display: none; font-size: var(--type-size-01); color: var(--support-error); margin-top: var(--sp-02); }
.lg-field.invalid .helper-error { display: block; }
.pw-toggle { position: absolute; right: 0; top: 0; height: 2.5rem; width: 2.5rem; display: grid; place-items: center; color: var(--text-secondary); background: transparent; border: none; }
.pw-toggle:hover { background: var(--layer-hover); }
.pw-toggle svg { width: 16px; height: 16px; }

/* ---------------- Botón primario Carbon ---------------- */
.lg-btn { display: inline-flex; align-items: center; justify-content: space-between; min-height: 3rem; padding: 0 var(--sp-05); width: 100%;
  background: var(--button-primary); color: #fff; font-size: var(--type-size-02); text-align: left; letter-spacing: .16px; border: none;
  transition: background .11s var(--ease); }
.lg-btn:hover { background: var(--button-primary-hover); }
.lg-btn:active { background: var(--button-primary-active); }
.lg-btn[disabled] { background: var(--text-disabled); color: #fff; cursor: not-allowed; }
.lg-btn svg { flex: none; margin-left: var(--sp-07); width: 16px; height: 16px; }
.lg-btn .btn-spinner { display: none; }
.lg-btn.loading .btn-spinner { display: block; }
.lg-btn.loading .btn-arrow { display: none; }

/* ---------------- Notificación inline ---------------- */
.inline-notif { display: none; align-items: flex-start; gap: var(--sp-04); background: var(--cds-red-10, #fff1f1);
  border-left: 3px solid var(--support-error); border-top: 1px solid #ffd7d9; border-right: 1px solid #ffd7d9; border-bottom: 1px solid #ffd7d9;
  padding: var(--sp-04) var(--sp-05); margin-bottom: var(--sp-06); }
[data-theme="dark"] .inline-notif { background: rgba(218,30,40,.14); border-color: rgba(218,30,40,.4); }
.inline-notif.show { display: flex; }
.inline-notif svg { flex: none; margin-top: 1px; color: var(--support-error); width: 18px; height: 18px; }
.inline-notif b { display: block; font-weight: var(--type-weight-semibold); font-size: var(--type-size-02); }
.inline-notif span { font-size: var(--type-size-02); color: var(--text-secondary); }

/* ---------------- Modal selección de empresa ---------------- */
.company-modal { position: fixed; inset: 0; z-index: 40; display: none; align-items: center; justify-content: center; }
.company-modal.open { display: flex; }
.modal-ovl { position: absolute; inset: 0; background: var(--overlay); }
.modal-card { position: relative; background: var(--layer-02); width: min(40rem, calc(100% - 2rem)); max-height: calc(100vh - 4rem);
  display: flex; flex-direction: column; box-shadow: var(--shadow-md); }
.modal-head { padding: var(--sp-05) var(--sp-05) var(--sp-03); display: flex; justify-content: space-between; align-items: flex-start; }
.modal-head .mh-label { font-size: var(--type-size-01); color: var(--text-secondary); margin-bottom: var(--sp-02); }
.modal-head h3 { font-size: var(--type-size-05); font-weight: var(--type-weight-regular); color: var(--text-primary); }
.modal-x { width: 3rem; height: 3rem; display: grid; place-items: center; margin: -1rem -1rem 0 0; color: var(--icon-primary); background: transparent; border: none; }
.modal-x:hover { background: var(--layer-hover); }
.modal-bd { padding: var(--sp-03) var(--sp-05) var(--sp-06); overflow-y: auto; }
.company-option { display: flex; align-items: center; gap: var(--sp-05); width: 100%; text-align: left; padding: var(--sp-05);
  border: 1px solid var(--border-subtle); margin-bottom: var(--sp-03); background: var(--layer-02); transition: border-color .11s, background .11s; }
.company-option:hover { background: var(--layer-01); border-color: var(--border-strong); }
.company-option .co-logo { width: 48px; height: 48px; flex: none; display: grid; place-items: center; color: #fff; font-weight: var(--type-weight-bold); font-size: var(--type-size-03); }
.company-option .co-info { flex: 1; min-width: 0; }
.company-option .co-info b { display: block; font-weight: var(--type-weight-semibold); font-size: var(--type-size-03); margin-bottom: 2px; color: var(--text-primary); }
.company-option .co-info span { font-size: var(--type-size-02); color: var(--text-secondary); }
.company-option .co-meta { font-size: var(--type-size-01); color: var(--text-helper); white-space: nowrap; display: flex; flex-direction: column; align-items: flex-end; gap: 4px; }
.company-option .co-role { color: #fff; padding: 0 var(--sp-03); line-height: 1.25rem; border-radius: .75rem; font-size: var(--type-size-01); }
.company-option .co-arrow { color: var(--brand); flex: none; width: 16px; height: 16px; }

/* ---------------- Loader ---------------- */
.loader { position: fixed; inset: 0; background: var(--cds-gray-100); z-index: 50; display: none; align-items: center; justify-content: center; color: #fff; }
.loader.open { display: flex; }
.loader-inner { text-align: center; }
.loader-logo { width: 64px; height: 64px; margin: 0 auto var(--sp-05); display: grid; place-items: center; font-size: var(--type-size-06); font-weight: var(--type-weight-bold); color: #fff; }
.loader-name { font-size: var(--type-size-04); font-weight: var(--type-weight-regular); margin-bottom: var(--sp-02); }
.loader-sub { font-size: var(--type-size-02); color: var(--cds-gray-50); margin-bottom: var(--sp-06); }
.loader-bar { width: 14rem; height: 2px; background: var(--cds-gray-80); margin: 0 auto; overflow: hidden; }
.loader-bar i { display: block; height: 100%; width: 100%; background: var(--cds-blue-40); transform: scaleX(0); transform-origin: left; }

/* ---------------- Spinner ---------------- */
.lg-spinner { animation: lg-spin .69s linear infinite; }
@keyframes lg-spin { to { transform: rotate(360deg); } }
.lg-spinner circle { stroke: currentColor; stroke-dasharray: 60; stroke-dashoffset: 20; fill: none; stroke-width: 3; }

/* ---------------- Responsive ---------------- */
@media (max-width: 880px) {
  .screen-login { grid-template-columns: 1fr; }
  .login-brand { display: none; }
}
@media (prefers-reduced-motion: reduce) { .lg-spinner { animation-duration: 1.5s; } }


/* ---------------- Ico en el acceso ----------------
   Ico va al costado del encabezado y entra con sus tres lineas. Se apoya en
   la linea del subtitulo: alineado arriba quedaba flotando sobre el bloque.
   El margen inferior lo lleva .login-head, ya no la .sub. */
.login-head { display: flex; align-items: flex-end; justify-content: space-between;
  gap: var(--sp-05); margin-bottom: var(--sp-07); }
.login-head-txt { min-width: 0; }
.login-head-txt .sub { margin-bottom: 0; }
/* El riel se queda solo con los rombos: aqui ninguna fila lleva un valor
   detras, asi que la barra seria un contenedor vacio. */
.login-head .ico__barra { display: none; }

/* validation.css pinta su icono de error como fondo del input en
   "right 12px", justo debajo del ojo de ver contrasena, que es un boton
   absoluto de 40px pegado a la derecha; y su "padding-right: 36px !important"
   se come el hueco que el campo reservaba para ese boton. Aqui el icono se
   corre a la izquierda del ojo y el padding deja sitio a los dos. */
#field-pass input.fv-invalid { background-position: right 46px center; padding-right: 68px !important; }

/* En pantallas estrechas Ico le devuelve el ancho al titulo: baja a sm y
   suelta el riel. Con los 87px del riel puesto, a 320px la tarjeta deja 153px
   de texto y "Iniciar sesion" se parte en dos lineas. */
@media (max-width: 480px) {
  .login-head .ico { --ico-esc: .5; }
  .login-head .ico__riel { display: none; }
}
