/*
 * gx-base — Overrides y utilidades sobre el bundle compilado de TailAdmin.
 * Cargar SIEMPRE después de style.css en layouts/app.php.
 */

/*
 * .gx-select — select con chevron consistente en cualquier fondo.
 *
 * Por qué: los <select> con `bg-transparent` + `border-*` no muestran la flecha
 * nativa de forma confiable (varía por browser/tema; en algunos casos queda
 * invisible sobre fondos claros del bundle). El bundle TailAdmin usa el patrón
 * "wrapper <div class='relative'> + <svg> chevron absoluto" pero replicarlo
 * en cada filtro es ruidoso. Esta clase encapsula appearance-none + chevron
 * como background-image y deja el padding-right necesario para no chocar.
 *
 * Uso: <select class="gx-select h-11 rounded-lg border ..."> — agregar junto
 * a las clases de tamaño/borde habituales. NO combinar con `pr-*` arbitrario:
 * la clase ya reserva espacio para el icono.
 */
:root {
  --color-brand-50: #f4f9ed;
  --color-brand-100: #e7f2d8;
  --color-brand-200: #cfe5b2;
  --color-brand-300: #b4d686;
  --color-brand-400: #95c45d;
  --color-brand-500: #71a83b;
  --color-brand-600: #5f8e31;
  --color-brand-700: #4d7428;
  --color-brand-800: #3c5b1f;
  --color-brand-900: #2d4518;
  --color-brand-950: #17240c;
}


.gx-select {
    appearance: none;
    -webkit-appearance: none;
    -moz-appearance: none;
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16' fill='none'><path d='M3.8335 5.9165L8.00016 10.0832L12.1668 5.9165' stroke='%236B7280' stroke-width='1.2' stroke-linecap='round' stroke-linejoin='round'/></svg>");
    background-repeat: no-repeat;
    background-position: right 0.75rem center;
    background-size: 16px 16px;
    padding-right: 2.25rem;
}

.dark .gx-select {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16' fill='none'><path d='M3.8335 5.9165L8.00016 10.0832L12.1668 5.9165' stroke='%239CA3AF' stroke-width='1.2' stroke-linecap='round' stroke-linejoin='round'/></svg>");
}

/*
 * .gx-tooltip-* — ayuda junto al label sin `title` nativo.
 *
 * Por qué: el tooltip del browser tiene delay, estilo inconsistente y a veces
 * no aparece si el pointer “cruza” mal la zona. Este panel es CSS puro
 * (hover + focus-within), sin JS, aparece en el acto y respeta tema claro/oscuro.
 *
 * Uso: el trigger debe ser <button type="button"> para no enviar formularios.
 * El panel va después del botón, mismo .gx-tooltip-wrap. Conectá id +
 * aria-describedby para lectores de pantalla.
 *
 * Ojo: un ancestro con overflow:hidden puede recortar el panel; en ese caso
 * mové el wrap fuera del contenedor recortado o abrí el panel hacia adentro
 * (cambiá top/left en una variante local si hace falta).
 */
.gx-tooltip-wrap {
    position: relative;
    display: inline-flex;
    align-items: center;
    vertical-align: middle;
}

.gx-tooltip-trigger {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    margin: 0;
    padding: 0;
    border: 0;
    background: transparent;
    line-height: 1;
    border-radius: 9999px;
    cursor: help;
    color: rgb(156 163 175); /* gray-400 */
}

.gx-tooltip-trigger:hover,
.gx-tooltip-trigger:focus-visible {
    color: rgb(107 114 128); /* gray-500 */
    outline: none;
}

.gx-tooltip-trigger:focus-visible {
    box-shadow: 0 0 0 2px rgb(255 255 255), 0 0 0 4px rgb(60 80 224); /* ring brand-ish */
}

.dark .gx-tooltip-trigger {
    color: rgb(156 163 175);
}

.dark .gx-tooltip-trigger:hover,
.dark .gx-tooltip-trigger:focus-visible {
    color: rgb(209 213 219); /* gray-300 */
}

.dark .gx-tooltip-trigger:focus-visible {
    box-shadow: 0 0 0 2px rgb(17 24 39), 0 0 0 4px rgb(96 125 239);
}

.gx-tooltip-panel {
    position: absolute;
    left: 50%;
    top: 100%;
    z-index: 50;
    margin-top: 0.25rem;
    width: max-content;
    max-width: min(18rem, calc(100vw - 2rem));
    transform: translateX(-50%);
    padding: 0.5rem 0.625rem;
    font-size: 0.75rem;
    line-height: 1.35;
    font-weight: 400;
    text-align: left;
    color: rgb(55 65 81); /* gray-700 */
    background-color: rgb(255 255 255);
    border: 1px solid rgb(229 231 235); /* gray-200 */
    border-radius: 0.5rem;
    box-shadow:
        0 4px 6px -1px rgb(0 0 0 / 0.08),
        0 2px 4px -2px rgb(0 0 0 / 0.06);
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
}

/* Puente invisible para no perder :hover al cruzar el margen entre ícono y panel. */
.gx-tooltip-panel::before {
    content: '';
    position: absolute;
    left: 0;
    right: 0;
    bottom: 100%;
    height: 0.375rem;
}

.gx-tooltip-wrap:hover .gx-tooltip-panel,
.gx-tooltip-wrap:focus-within .gx-tooltip-panel {
    opacity: 1;
    visibility: visible;
    pointer-events: auto;
}

.dark .gx-tooltip-panel {
    color: rgb(229 231 235);
    background-color: rgb(31 41 55); /* gray-800 */
    border-color: rgb(55 65 81);
    box-shadow:
        0 10px 15px -3px rgb(0 0 0 / 0.35),
        0 4px 6px -4px rgb(0 0 0 / 0.25);
}

/* Chrome/Safari: ocultar el chevron nativo si el browser lo intenta dibujar igual. */
.gx-select::-ms-expand {
    display: none;
}

/* Checkboxes/radios: anillo brand sutil en lugar del azul nativo del browser.
 * Los inputs/textarea/select normales se cubren más abajo (sección "[type='text']:focus...")
 * con un outline brand consistente que NO se recorta en modales scrolleables. */
input[type=checkbox]:focus-visible,
input[type=radio]:focus-visible {
    outline: 2px solid var(--color-brand-500);
    outline-offset: 2px;
}

/* ============================================================
 * Utilities ausentes en el bundle precompilado de TailAdmin.
 * El bundle es estático (no hay tailwind.config + build local), así que
 * agregamos acá las clases verificadamente necesarias y de uso transversal.
 *
 * Convención: antes de SUMAR una utility nueva, verificar que no exista en
 * el bundle:
 *     grep -F '.la-clase' public/assets/css/style.css
 * Y si solo se usa una vez en todo el proyecto, mejor inline-style en lugar
 * de polucionar este archivo.
 * ============================================================ */

/* min-w-0 — sin esto `truncate` no recorta dentro de flex/grid items y el
 * contenido se desborda sobre la celda vecina. Crítico para data-tables. */
.min-w-0 { min-width: 0; }
.min-h-0 { min-height: 0; }

/* lg:w-[400px] — ancho fijo del sidebar de tickets en lg+. En mobile la
 * lista ocupa w-full (default) y se oculta con `hidden lg:flex` cuando hay
 * detalle abierto. El bundle solo trae lg:w-[634px] y lg:w-auto; ninguno
 * sirve para la lista densa de Support. */
@media (min-width: 1024px) {
    .lg\:w-\[400px\] { width: 400px; }
}

/* sm:items-end / lg:items-end — el bundle trae `items-end` e `items-center`
 * (y `sm:items-center`) pero NO las variantes `sm:items-end` ni `lg:items-end`.
 * Sin ellas, las toolbars con `sm:flex-row sm:items-end` caen a align-items:stretch
 * en desktop y los botones sin label (Buscar/Publicar) se estiran y quedan arriba.
 * Usadas en toolbars de filtros (scheduling, reporte de cumplimiento, finanzas). */
@media (min-width: 640px) {
    .sm\:items-end { align-items: flex-end; }
}
@media (min-width: 1024px) {
    .lg\:items-end { align-items: flex-end; }
}

/* col-span-5..11 — el bundle solo trae 1, 2, 3, 4 y 12 sin breakpoint.
 * Necesario para grids 12-col asimétricos (ej. nombre col-span-7 + acción
 * col-span-1 en data-tables con columna primaria amplia). */
.col-span-5  { grid-column: span 5 / span 5;   }
.col-span-6  { grid-column: span 6 / span 6;   }
.col-span-7  { grid-column: span 7 / span 7;   }
.col-span-8  { grid-column: span 8 / span 8;   }
.col-span-9  { grid-column: span 9 / span 9;   }
.col-span-10 { grid-column: span 10 / span 10; }
.col-span-11 { grid-column: span 11 / span 11; }

/* grid-cols-3/5/6/7 — el bundle trae 1, 2, 4, 11, 12. Útil para KPI strips
 * de 3 o 6 elementos iguales sin tener que ir al patrón 12+col-span, y para
 * calendarios mensuales (7 = días de la semana). */
.grid-cols-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.grid-cols-5 { grid-template-columns: repeat(5, minmax(0, 1fr)); }
.grid-cols-6 { grid-template-columns: repeat(6, minmax(0, 1fr)); }
.grid-cols-7 { grid-template-columns: repeat(7, minmax(0, 1fr)); }

/* grid-cols-14 + col-span-14 — para data-tables que necesitan más de 6
 * columnas visibles sin asfixiar los spans (ej. Usuarios y Roles). */
.grid-cols-14 { grid-template-columns: repeat(14, minmax(0, 1fr)); }
.col-span-14  { grid-column: span 14 / span 14; }

/* min-w-[1200px] — ancho mínimo del scroll horizontal de la tabla de
 * Usuarios y Roles (14 columnas). El bundle solo precompila 1102px. */
.min-w-\[1200px\] { min-width: 1200px; }

/* gap-x-3 / gap-x-4 / gap-y-1.5 — el bundle compila solo las gaps que algún
 * componente original de TailAdmin usó (gap-x-1, gap-x-3.5, gap-x-6, gap-x-8,
 * gap-y-2, gap-y-5). Sin estas, layouts con muchos items en celda quedan sin
 * separación efectiva — caso típico: matriz de permisos, columna "Acciones
 * extra" cuyo checkbox parecía pegado al label del siguiente item. */
.gap-x-3   { -webkit-column-gap: calc(var(--spacing) * 3); -moz-column-gap: calc(var(--spacing) * 3); column-gap: calc(var(--spacing) * 3); }
.gap-x-4   { -webkit-column-gap: calc(var(--spacing) * 4); -moz-column-gap: calc(var(--spacing) * 4); column-gap: calc(var(--spacing) * 4); }
.gap-y-1\.5 { row-gap: calc(var(--spacing) * 1.5); }

/* rotate-90 — el bundle trae 0, 45, 180 y -45 pero no 90. Necesario para
 * carets de treegrid (indicador de "rama expandida"). */
.rotate-90 { transform: rotate(90deg); }

/* gx-tl-dim — atenúa una línea de tiempo (barra + track) para que las filas hijas
 * (compañeros de zona en "Mis horarios") recedan frente al registro principal. El
 * bundle solo trae opacity-40/50/75; 0.6 es el punto justo (apagado pero legible). */
.gx-tl-dim { opacity: 0.6; }

/* gx-evt-line / gx-evt-dash — marcador de checada real (4px) sobre la línea de tiempo
 * ("Mis horarios" y Reporte de cumplimiento). El color sale de `currentColor` (clase
 * text-*): dirección → color (entrada/regreso oscuro, salida/salida-comida rojo). El
 * estilo distingue categoría: sólida = trabajo (entrada/salida), punteada = comida
 * (salida/regreso). El bundle no trae estos anchos ni border-l-*, por eso van acá. */
.gx-evt-line { width: 4px; background-color: currentColor; }
.gx-evt-dash { width: 4px; background-image: repeating-linear-gradient(to bottom, currentColor 0 3px, transparent 3px 6px); }

/* bottom-4 / top-4 (top-4 ya existe en el bundle, bottom-4 no) — necesarias
 * para anclar contenedores fijos a 1rem del borde inferior. El bundle trae
 * bottom-0/5/6/10/full pero no bottom-4 (la escala más usada). Lo usa el
 * contenedor global de toasts y cualquier overlay flotante. */
.bottom-4 { bottom: calc(var(--spacing) * 4); }

/* pointer-events-{none,auto} — none existe pero auto no. Necesario para
 * "contenedor sin captura + items con captura" (toast stack: el wrapper deja
 * pasar clicks al fondo, cada toast los captura). */
.pointer-events-auto { pointer-events: auto; }

/* left-1/2 + translate-y-{0,2,-2} — para centrar contenedores horizontalmente
 * (top-center / bottom-center del toast stack) y para animaciones de slide-in
 * verticales (x-transition de Alpine). El bundle trae -translate-x-1/2 y
 * translate-x-0 pero no los hermanos. */
.left-1\/2 { left: 50%; }
.translate-y-0 { --tw-translate-y: 0; transform: translate3d(var(--tw-translate-x,0), var(--tw-translate-y,0), 0); }
.translate-y-2 { --tw-translate-y: calc(var(--spacing) * 2); transform: translate3d(var(--tw-translate-x,0), var(--tw-translate-y,0), 0); }
.-translate-y-2 { --tw-translate-y: calc(var(--spacing) * -2); transform: translate3d(var(--tw-translate-x,0), var(--tw-translate-y,0), 0); }

/* ============================================================
 * Toasts globales — utility para el botón CTA dentro del toast.
 *
 * Por qué un utility custom y no clases Tailwind: el bundle no incluye
 * `hover:underline` ni hovers de paleta extendida (success-800, error-800,
 * blue-light-800, warning-800). Encapsulamos el patrón "link-like sobre toast"
 * en una sola clase que se combina con el color base que sí está en el bundle
 * (text-success-700, text-error-700, etc.). Tipografía y peso vienen del
 * markup (text-sm font-semibold).
 * ============================================================ */
.gx-toast-cta {
    text-underline-offset: 2px;
}
.gx-toast-cta:hover {
    text-decoration: underline;
    filter: brightness(0.85);
}

/* Barra de progreso del auto-dismiss.
 *
 * Se anima vía CSS (no JS) para que el navegador la pinte en su capa de
 * compositor — el thread JS puede estar ocupado y la barra sigue fluida.
 * `transform-origin: left` + `scaleX` (no width) evita reflows.
 *
 * Pause: cuando el usuario hace hover, el store seta `_paused: true` en el
 * item y nosotros congelamos la animación con `animation-play-state`. Al salir,
 * vuelve a `running` y la animación retoma desde el progreso exacto que tenía
 * (esto lo maneja el browser, no requiere recalcular tiempo restante). El JS
 * de pausa/resume del timer va en paralelo y queda en sync porque ambos
 * eventos (mouseenter/leave) disparan en el mismo instante.
 *
 * La duración se pasa por inline-style (`animation-duration`) para que cada
 * toast use su propio timeoutMs sin generar N reglas CSS. */
.gx-toast-progress {
    position: absolute;
    left: 0;
    bottom: 0;
    height: 3px;
    width: 100%;
    transform-origin: left;
    animation: gx-toast-shrink linear forwards;
    /* Opacidad sobre el color del border del toast — funciona en claro y oscuro. */
    background-color: currentColor;
    opacity: 0.45;
    pointer-events: none;
}
.gx-toast-progress.is-paused {
    animation-play-state: paused;
}
@keyframes gx-toast-shrink {
    from { transform: scaleX(1); }
    to   { transform: scaleX(0); }
}

/* ============================================================
 * Flatpickr — fix de alineación de la columna "Sem" (week numbers).
 *
 * Problema: TailAdmin override (style.css ~7382) le da margin-top:24px y
 * margin-bottom:16px a `.flatpickr-weekdays` (la fila Lun-Dom de la derecha),
 * pero no aplica el mismo margen al header "Sem" del lado izquierdo
 * (`.flatpickr-weekwrapper > span.flatpickr-weekday`), porque está fuera
 * del contenedor `.flatpickr-weekdays`.
 *
 * Resultado visible: la columna entera de números de semana queda corrida
 * una fila hacia arriba — "Sem 18" aparece a la altura de "Lun Mar Mié...".
 *
 * Fix: replicar el mismo margin en el header del wrapper de semanas.
 * Si en el futuro se reemplaza el bundle y este override desaparece, esta
 * regla se vuelve no-op y se puede limpiar.
 * ============================================================ */
.flatpickr-weekwrapper .flatpickr-weekday {
    margin-top:    calc(var(--spacing) * 6);
    margin-bottom: calc(var(--spacing) * 4);
}

/* ============================================================
 * Form controls — focus ring que no se recorta dentro de overflow:auto.
 *
 * Problema: TailAdmin (style.css ~L8133) aplica el ring de focus a inputs/
 * textareas/selects vía `box-shadow` (1px ring). Cuando el control está
 * dentro de un contenedor con `overflow-y-auto` (modales con header/footer
 * fijos + body scrolleable), el box-shadow se recorta al edge del clip
 * rectangle del scroll container → el ring aparece incompleto en el borde
 * superior o inferior según dónde quedó pegado el input.
 *
 * Fix: reemplazar el ring de box-shadow por `outline`. Los outlines se
 * pintan en una capa separada y NO se recortan por overflow del padre.
 * Mantenemos el cambio de border-color (es el border del propio control,
 * no se recorta) y suprimimos el outline transparente que TailAdmin usa
 * como spacer.
 *
 * Aplicamos solo a los tipos de control que TailAdmin estilea en su capa
 * @layer base (mismo selector que el bundle), para no afectar al picker
 * de fechas (flatpickr renderiza un <input> que ya tiene su propio focus).
 * ============================================================ */
[type='text']:focus,
input:where(:not([type])):focus,
[type='email']:focus,
[type='url']:focus,
[type='password']:focus,
[type='number']:focus,
[type='search']:focus,
[type='tel']:focus,
[type='datetime-local']:focus,
[type='month']:focus,
[type='time']:focus,
[type='week']:focus,
[multiple]:focus,
textarea:focus,
select:focus {
    /* Brand verde del proyecto (override de --color-brand-500 = #71a83b).
     * Usamos outline en lugar de box-shadow para que el ring no se recorte
     * por el overflow:auto de modales scrolleables (issue conocido en flatpickr-
     * embedded forms y modales con header/footer fijos). */
    outline: 1px solid var(--color-brand-500);
    outline-offset: 0;
    border-color: var(--color-brand-500);
    box-shadow: var(--tw-inset-shadow, 0 0 #0000), var(--tw-shadow, 0 0 #0000);
}

/* ============================================================
 * gxa-* — componentes Alpine-driven (gx + alpine).
 *
 * Distintos del bundle estático (TailAdmin compilado) y de los helpers gx.*
 * (estado puro, sin UI). Estos se construyen en tiempo de render con HTML
 * dinámico generado por Alpine. Convención: prefijo `.gxa-<componente>__*`
 * BEM-ish para evitar choques con el bundle.
 *
 * Componentes:
 *   - .gxa-combobox  — select rico (píldora + label + chip secundario + badges)
 * ============================================================ */

/* ---- gxa-combobox ---- */

.gxa-combobox {
    position: relative;
}

.gxa-combobox__trigger {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    width: 100%;
    min-width: 0;
    min-height: 2.75rem;
    padding: 0.5rem 0.75rem;
    border: 1px solid rgb(209 213 219); /* gray-300 — match h-11 selects */
    border-radius: 0.5rem;
    background: transparent;
    font-size: 0.875rem;
    text-align: left;
    cursor: pointer;
    transition: border-color 0.15s;
}
.dark .gxa-combobox__trigger { border-color: rgb(55 65 81); /* gray-700 */ }
.gxa-combobox__trigger:hover { border-color: rgb(156 163 175); /* gray-400 */ }
.gxa-combobox__trigger--open { border-color: var(--color-brand-500); }
.gxa-combobox__trigger--error { border-color: rgb(240 68 56); /* error-500 */ }

.gxa-combobox__trigger-content {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    flex: 1;
    min-width: 0;
    /* Clipa solo el área del texto (el label trunca con elipsis); los iconos
     * —flecha y limpiar— son hermanos y conservan su espacio (shrink-0). */
    overflow: hidden;
}

.gxa-combobox__trigger-label {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: rgb(31 41 55); /* gray-800 */
}
.dark .gxa-combobox__trigger-label { color: rgb(255 255 255 / 0.9); }

.gxa-combobox__placeholder { color: rgb(31 41 55); /* gray-800 — match native <select> text */ }
.dark .gxa-combobox__placeholder { color: rgb(255 255 255 / 0.9); }

.gxa-combobox__trigger-icons {
    display: flex;
    align-items: center;
    gap: 0.25rem;
    flex-shrink: 0;
    color: rgb(107 114 128); /* gray-500 */
}

.gxa-combobox__clear {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.25rem;
    height: 1.25rem;
    border-radius: 9999px;
    background: transparent;
    color: rgb(107 114 128);
    cursor: pointer;
    border: 0;
    padding: 0;
    line-height: 1;
}
.gxa-combobox__clear:hover { background: rgb(243 244 246); color: rgb(31 41 55); }
.dark .gxa-combobox__clear:hover { background: rgb(31 41 55); color: rgb(255 255 255 / 0.9); }

.gxa-combobox__chevron {
    width: 16px;
    height: 16px;
    transition: transform 0.15s;
}

.gxa-combobox__menu {
    /* position: fixed + coords por JS (gxa-combobox.js _positionMenu): así el
     * menú escapa el overflow-hidden de la tarjeta data-table-03, que lo
     * recortaba cuando la tabla se achicaba al filtrar. top/left/width vienen
     * del inline :style; aquí solo el resto. */
    position: fixed;
    z-index: 60;
    /* El menú nunca es más angosto que ~24rem aunque el trigger sea chico
     * (ej. filtros estrechos): así las opciones con código + label largo +
     * chip de tipo entran cómodas. min() evita desborde en pantallas chicas. */
    min-width: min(24rem, calc(100vw - 2rem));
    max-height: min(40rem, 80vh);
    display: flex;
    flex-direction: column;
    border: 1px solid rgb(229 231 235);
    border-radius: 0.5rem;
    background: rgb(255 255 255);
    box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
    overflow: hidden;
}
.dark .gxa-combobox__menu {
    border-color: rgb(31 41 55);
    background: rgb(17 24 39);
}

/* Píldoras de filtro rápido (ej. tipo de zona) debajo del buscador. Click =
 * selección masiva. El color "activo" lo aporta badgeClasses() inline; el
 * estado --off es el reposo (outline gris). */
.gxa-combobox__kinds {
    display: flex;
    flex-wrap: wrap;
    gap: 0.375rem;
    padding: 0.5rem;
    border-bottom: 1px solid rgb(229 231 235); /* gray-200 */
}
.dark .gxa-combobox__kinds { border-bottom-color: rgb(31 41 55); }
.gxa-combobox__kind {
    display: inline-flex;
    align-items: center;
    border-radius: 9999px;
    padding: 0.125rem 0.625rem;
    font-size: 0.75rem;
    font-weight: 500;
    line-height: 1.25rem;
    border: 1px solid transparent;
    cursor: pointer;
    transition: background-color 0.1s, color 0.1s, border-color 0.1s;
}
.gxa-combobox__kind--off {
    background: transparent;
    color: rgb(107 114 128); /* gray-500 */
    border-color: rgb(209 213 219); /* gray-300 */
}
.dark .gxa-combobox__kind--off {
    color: rgb(156 163 175); /* gray-400 */
    border-color: rgb(55 65 81); /* gray-700 */
}

/* Control de estado (Activas/Inactivas/Todas) debajo del buscador. */
.gxa-combobox__status {
    display: flex;
    gap: 0.25rem;
    padding: 0.5rem 0.5rem 0;
}
.gxa-combobox__status button {
    flex: 1;
    padding: 0.25rem 0.5rem;
    font-size: 0.6875rem;
    font-weight: 500;
    border-radius: 0.375rem;
    border: 1px solid rgb(229 231 235); /* gray-200 */
    background: transparent;
    color: rgb(107 114 128); /* gray-500 */
    cursor: pointer;
    transition: background-color 0.1s, color 0.1s, border-color 0.1s;
}
.dark .gxa-combobox__status button { border-color: rgb(55 65 81); color: rgb(156 163 175); }
.gxa-combobox__status button.is-active {
    background: var(--color-brand-500, rgb(70 95 255));
    border-color: var(--color-brand-500, rgb(70 95 255));
    color: #fff;
}

/* Foco/estado por opción (getDot). Punto de 8px; color por modificador. */
.gxa-combobox__dot {
    flex-shrink: 0;
    width: 0.5rem;
    height: 0.5rem;
    border-radius: 9999px;
}
.gxa-combobox__dot--success { background: rgb(18 183 106); }
.gxa-combobox__dot--gray    { background: rgb(152 162 179); }
.gxa-combobox__dot--error   { background: rgb(240 68 56); }
.gxa-combobox__dot--warning { background: rgb(247 144 9); }
.gxa-combobox__dot--brand   { background: rgb(70 95 255); }
.gxa-combobox__dot--info    { background: rgb(54 191 250); }

.gxa-combobox__search {
    padding: 0.5rem;
    border-bottom: 1px solid rgb(243 244 246);
}
.dark .gxa-combobox__search { border-bottom-color: rgb(31 41 55); }

.gxa-combobox__search input {
    width: 100%;
    padding: 0.5rem 0.75rem;
    border: 1px solid rgb(229 231 235);
    border-radius: 0.375rem;
    background: transparent;
    font-size: 0.875rem;
    color: inherit;
}
.dark .gxa-combobox__search input { border-color: rgb(31 41 55); }
.gxa-combobox__search input:focus {
    outline: none;
    border-color: rgb(70 95 255);
    box-shadow: 0 0 0 3px rgb(70 95 255 / 0.1);
}

.gxa-combobox__list {
    flex: 1;
    overflow-y: auto;
    margin: 0;
    padding: 0.25rem;
    list-style: none;
}

/* Agrupación (groupBy): bloque sin estilo propio + encabezado sticky. La
 * lista anidada resetea márgenes/padding para que las opciones se alineen
 * igual que en modo plano. */
.gxa-combobox__group-block { list-style: none; }
.gxa-combobox__group-list { margin: 0; padding: 0; list-style: none; }
.gxa-combobox__group {
    position: sticky;
    top: 0;
    z-index: 1;
    display: flex;
    align-items: center;
    gap: 0.375rem;
    padding: 0.375rem 0.625rem 0.25rem;
    font-size: 0.6875rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: rgb(107 114 128); /* gray-500 */
    background: #fff;
}
.dark .gxa-combobox__group {
    color: rgb(156 163 175); /* gray-400 */
    background: rgb(17 24 39); /* gray-900 — match menu */
}
/* Encabezado de grupo como selector masivo (multi + groupSelectable). */
.gxa-combobox__group--selectable {
    cursor: pointer;
    border-radius: 0.375rem;
    transition: background-color 0.1s;
}
.gxa-combobox__group--selectable:hover { background: rgb(245 247 255); /* brand-50 */ }
.dark .gxa-combobox__group--selectable:hover { background: rgb(70 95 255 / 0.12); }

.gxa-combobox__option {
    display: flex;
    flex-direction: row;
    align-items: center;
    gap: 0.5rem;
    padding: 0.5rem 0.625rem;
    border-radius: 0.375rem;
    cursor: pointer;
    transition: background-color 0.1s;
}
.gxa-combobox__option--active {
    background-color: rgb(245 247 255); /* brand-50 */
}
.dark .gxa-combobox__option--active {
    background-color: rgb(70 95 255 / 0.12);
}
.gxa-combobox__option--disabled {
    opacity: 0.5;
    cursor: not-allowed;
}
.gxa-combobox__option--selected {
    background-color: rgb(245 247 255); /* brand-50 — sutil para el seleccionado */
}
.dark .gxa-combobox__option--selected {
    background-color: rgb(70 95 255 / 0.08);
}

/* Checkbox visual para modo multi-select. Caja 16x16 con borde gris;
 * cuando --checked, fondo brand y SVG check visible. */
.gxa-combobox__check {
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 16px;
    height: 16px;
    border: 1px solid rgb(209 213 219); /* gray-300 */
    border-radius: 0.25rem;
    background: #fff;
    color: transparent;
    transition: background-color 0.1s, border-color 0.1s, color 0.1s;
}
.dark .gxa-combobox__check {
    border-color: rgb(55 65 81); /* gray-700 */
    background: rgb(17 24 39); /* gray-900 */
}
.gxa-combobox__check--checked {
    background: var(--color-brand-500, rgb(70 95 255));
    border-color: var(--color-brand-500, rgb(70 95 255));
    color: #fff;
}
.dark .gxa-combobox__check--checked {
    background: var(--color-brand-500, rgb(70 95 255));
    border-color: var(--color-brand-500, rgb(70 95 255));
    color: #fff;
}

/* Cada opción en dos renglones: el nombre ocupa el primer renglón completo
 * (order:-1 + flex-basis:100%); la clave (pill), el tipo (chip) y los badges
 * envuelven juntos en el segundo. row-gap separa las dos líneas, column-gap
 * separa los chips entre sí. El nombre no se trunca: envuelve si fuera enorme. */
.gxa-combobox__option-main {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.25rem 0.375rem;
    flex: 1 1 auto;
    min-width: 0;
}

.gxa-combobox__option-label {
    order: -1;
    flex-basis: 100%;
    white-space: normal;
    overflow-wrap: anywhere;
    font-size: 0.875rem;
    font-weight: 400;
    color: rgb(31 41 55);
}
.dark .gxa-combobox__option-label { color: rgb(255 255 255 / 0.9); }

.gxa-combobox__option-secondary {
    font-size: 0.75rem;
    color: rgb(107 114 128);
}
.dark .gxa-combobox__option-secondary { color: rgb(156 163 175); }

.gxa-combobox__empty {
    padding: 1rem;
    text-align: center;
    color: rgb(107 114 128);
    font-size: 0.875rem;
}

/* ============================================================
 * Vacation calendar — color-coded blocked days (flatpickr inline + mode:multiple)
 * Usado en app/Modules/Rh/Views/vacations/my_requests.php para que el usuario
 * marque uno o más días de descanso. Las clases las agrega `onDayCreate` del
 * datepicker leyendo el calendar API (/rh/vacation-requests/calendar).
 * Receta: docs/VACATION-CALENDAR-RECIPE.md.
 * ============================================================ */
/* Chip de leyenda: replica el tratamiento de las celdas (rounded-rect)
 * para que el usuario asocie el chip con el día real en el calendario. */
.gx-legend-chip {
    display: inline-block;
    width: 14px;
    height: 14px;
    border-radius: 4px;
    flex-shrink: 0;
}
.gx-legend-chip.gx-day-rest      { background: repeating-linear-gradient(135deg, rgba(107,114,128,.35) 0 3px, rgba(107,114,128,.10) 3px 6px); }
.gx-legend-chip.gx-day-holiday   { background: rgba(245,158,11,.45); }
.gx-legend-chip.gx-day-pending   { background: rgba(245,158,11,.30); border: 1px dashed rgb(217 119 6); }
.gx-legend-chip.gx-day-approved  { background: rgba(34,197,94,.55); }
.gx-legend-chip.gx-day-rejected  { background: rgba(239,68,68,.45); }
.gx-legend-chip.gx-day-peer-blocked { background: rgba(59,130,246,.45); }
.gx-legend-chip.gx-day-min-notice { background: rgba(100,116,139,.20); border: 1px dashed rgb(100 116 139); }
.gx-legend-chip.gx-day-blocked-admin { background: rgba(168,85,247,.45); }
.gx-legend-chip.gx-day-incapacity { background: rgba(244,63,94,.45); }

/* Estado base: días no seleccionables del calendario de vacaciones.
 * Diferenciación visual respecto a la selección:
 *   - estados (rest/holiday/pending/approved/rejected) usan rounded-rect (radius 6px)
 *   - selección del usuario y "hoy" mantienen el círculo brand de flatpickr
 * Esto evita que un sábado de descanso se confunda con un día ya seleccionado. */
.flatpickr-day.gx-day-rest,
.flatpickr-day.gx-day-holiday,
.flatpickr-day.gx-day-pending,
.flatpickr-day.gx-day-approved,
.flatpickr-day.gx-day-rejected,
.flatpickr-day.gx-day-peer-blocked,
.flatpickr-day.gx-day-min-notice,
.flatpickr-day.gx-day-blocked-admin,
.flatpickr-day.gx-day-incapacity {
    border-radius: 6px;
    border-color: transparent;
    font-weight: 500;
}
/* peer-blocked, min-notice y blocked-admin son seleccionables para RH (override con
 * confirmación), por eso no fuerzan cursor:not-allowed; cuando flatpickr los deshabilita
 * (usuario normal) aplica su propio .flatpickr-disabled. */
/* 'holiday' NO va aquí: es marca solo visual y el día sigue siendo seleccionable. */
.flatpickr-day.gx-day-rest,
.flatpickr-day.gx-day-pending,
.flatpickr-day.gx-day-approved,
.flatpickr-day.gx-day-rejected,
.flatpickr-day.gx-day-incapacity { cursor: not-allowed; }

.flatpickr-day.gx-day-rest        { background: repeating-linear-gradient(135deg, rgba(107,114,128,.10) 0 4px, rgba(107,114,128,.04) 4px 8px); color: rgb(75 85 99); }
.flatpickr-day.gx-day-holiday     { background: rgba(245,158,11,.18); color: rgb(146 64 14); }
.flatpickr-day.gx-day-pending     { background: rgba(245,158,11,.30); color: rgb(146 64 14); border: 1px dashed rgb(217 119 6); }
.flatpickr-day.gx-day-approved    { background: rgba(34,197,94,.28);  color: rgb(21 128 61); }
.flatpickr-day.gx-day-rejected    { background: rgba(239,68,68,.20);  color: rgb(185 28 28); text-decoration: line-through; }
.flatpickr-day.gx-day-peer-blocked { background: rgba(59,130,246,.22);  color: rgb(29 78 216); }
.flatpickr-day.gx-day-min-notice  { background: rgba(100,116,139,.12); color: rgb(100 116 139); border: 1px dashed rgba(100,116,139,.55); }
.flatpickr-day.gx-day-blocked-admin { background: rgba(168,85,247,.18); color: rgb(126 34 206); }
.flatpickr-day.gx-day-incapacity  { background: rgba(244,63,94,.20);  color: rgb(190 24 93); }

/* Mantener color al hover (sobreescribe el hover gris default de flatpickr) */
.flatpickr-day.gx-day-rest:hover,
.flatpickr-day.gx-day-holiday:hover,
.flatpickr-day.gx-day-pending:hover,
.flatpickr-day.gx-day-approved:hover,
.flatpickr-day.gx-day-rejected:hover,
.flatpickr-day.gx-day-peer-blocked:hover,
.flatpickr-day.gx-day-min-notice:hover,
.flatpickr-day.gx-day-blocked-admin:hover,
.flatpickr-day.gx-day-incapacity:hover { background-color: inherit; border-color: transparent; }
.flatpickr-day.gx-day-min-notice:hover { border: 1px dashed rgba(100,116,139,.55); }
.flatpickr-day.gx-day-pending:hover { border: 1px dashed rgb(217 119 6); }

/* Día peer-blocked seleccionado por RH (override): conserva el fill verde de
 * "seleccionado" pero le suma un anillo azul para señalar que es un conflicto
 * forzado. El fill viene del tema (!important), por eso solo tocamos el box-shadow. */
.flatpickr-day.gx-day-peer-blocked.selected,
.flatpickr-day.gx-day-peer-blocked.selected:hover,
.flatpickr-day.gx-day-peer-blocked.selected:focus {
    box-shadow: inset 0 0 0 2px rgb(59 130 246) !important;
}

/* Día min-notice seleccionado por RH (override): mismo principio que peer-blocked,
 * con anillo slate para señalar que se forzó la anticipación mínima. */
.flatpickr-day.gx-day-min-notice.selected,
.flatpickr-day.gx-day-min-notice.selected:hover,
.flatpickr-day.gx-day-min-notice.selected:focus {
    box-shadow: inset 0 0 0 2px rgb(100 116 139) !important;
}

/* Día blocked-admin seleccionado por RH (override): anillo violeta para señalar que se
 * forzó un período bloqueado (temporada alta / política). */
.flatpickr-day.gx-day-blocked-admin.selected,
.flatpickr-day.gx-day-blocked-admin.selected:hover,
.flatpickr-day.gx-day-blocked-admin.selected:focus {
    box-shadow: inset 0 0 0 2px rgb(168 85 247) !important;
}

/* Ancho fijo de la columna de compañeros en el modal de solicitud (no está en el bundle). */
@media (min-width: 1024px) {
    .lg\:w-72 { width: 18rem; }
}

/* "Hoy" — borde brand para diferenciarlo del estado de descanso (gris).
 * flatpickr aplica .today por defecto pero con borde gris poco legible. */
.flatpickr-day.today:not(.selected) {
    border: 1.5px solid var(--color-brand-500);
    color: var(--color-brand-500);
    background: transparent;
}
.flatpickr-day.today.gx-day-rest,
.flatpickr-day.today.gx-day-holiday,
.flatpickr-day.today.gx-day-pending,
.flatpickr-day.today.gx-day-approved,
.flatpickr-day.today.gx-day-rejected,
.flatpickr-day.today.gx-day-min-notice,
.flatpickr-day.today.gx-day-blocked-admin,
.flatpickr-day.today.gx-day-incapacity {
    box-shadow: inset 0 0 0 1.5px var(--color-brand-500);
    border-color: transparent;
}

/* En modo inline (calendario de vacaciones), el calendario ocupa todo el ancho del
 * contenedor padre. Reemplazamos el layout flex/space-around default de flatpickr por
 * un grid explícito de 7 columnas para que:
 *   - Cada día ocupe exactamente 1/7 del ancho (sin huecos producidos por max-width 39px).
 *   - La altura de fila sea uniforme y coincida con la columna "Sem" → ambas grillas
 *     alineadas visualmente fila por fila.
 *   - Los nombres de día (Lun, Mar...) se distribuyan parejos arriba.
 * Receta: docs/VACATION-CALENDAR-RECIPE.md. */
.flatpickr-calendar.inline { box-shadow: none; border: 0; width: 100%; max-width: 100%; }
.flatpickr-calendar.inline .flatpickr-innerContainer { display: flex; width: 100%; align-items: stretch; }
.flatpickr-calendar.inline .flatpickr-rContainer { flex: 1 1 auto; min-width: 0; display: block; }
.flatpickr-calendar.inline .flatpickr-days { width: 100%; }
.flatpickr-calendar.inline .dayContainer {
    display: grid;
    grid-template-columns: repeat(7, minmax(0, 1fr));
    grid-auto-rows: 40px;
    width: 100%;
    min-width: 0;
    max-width: none;
    box-shadow: none;
}
/* Cada día se renderiza como cuadro 40×40 centrado dentro de su columna 1fr del grid.
 * Mantener tamaño fijo es lo que permite que el border-radius (sea pill para selected
 * o rounded-rect para estados) produzca formas correctas en lugar de óvalos estirados. */
.flatpickr-calendar.inline .flatpickr-day {
    width: 40px;
    max-width: 40px;
    flex-basis: auto;
    height: 40px;
    line-height: 38px;
    margin: 0;
    place-self: center;
}
.flatpickr-calendar.inline .flatpickr-day.gx-day-rest,
.flatpickr-calendar.inline .flatpickr-day.gx-day-holiday,
.flatpickr-calendar.inline .flatpickr-day.gx-day-pending,
.flatpickr-calendar.inline .flatpickr-day.gx-day-approved,
.flatpickr-calendar.inline .flatpickr-day.gx-day-rejected,
.flatpickr-calendar.inline .flatpickr-day.gx-day-min-notice,
.flatpickr-calendar.inline .flatpickr-day.gx-day-blocked-admin,
.flatpickr-calendar.inline .flatpickr-day.gx-day-incapacity {
    width: 36px;
    height: 36px;
    line-height: 34px;
}
/* Encabezado de días (Lun-Dom) con la misma grilla 7-col para que alineen con cada columna del día */
.flatpickr-calendar.inline .flatpickr-weekdays { width: 100%; }
.flatpickr-calendar.inline .flatpickr-weekdaycontainer {
    display: grid;
    grid-template-columns: repeat(7, minmax(0, 1fr));
    width: 100%;
    flex: 1 1 auto;
}
.flatpickr-calendar.inline .flatpickr-weekday { flex: none; width: 100%; }
/* Columna "Sem": misma altura de fila (40px) y padding compacto para que los números
 * de semana queden centrados verticalmente con la fila de días correspondiente. */
.flatpickr-calendar.inline .flatpickr-weekwrapper { flex: 0 0 auto; float: none; }
.flatpickr-calendar.inline .flatpickr-weekwrapper .flatpickr-weeks { padding: 0 10px; box-shadow: 1px 0 0 rgb(229 231 235); }
.dark .flatpickr-calendar.inline .flatpickr-weekwrapper .flatpickr-weeks { box-shadow: 1px 0 0 rgb(55 65 81); }
.flatpickr-calendar.inline .flatpickr-weekwrapper span.flatpickr-day {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    height: 40px;
    line-height: 1;
    max-width: none;
    margin: 0;
}

/* Dark mode: oscurecer los días bloqueados sin cambiar la semántica */
.dark .flatpickr-day.gx-day-rest        { background: repeating-linear-gradient(135deg, rgba(156,163,175,.16) 0 4px, rgba(156,163,175,.06) 4px 8px); color: rgb(209 213 219); }
.dark .flatpickr-day.gx-day-holiday     { background: rgba(252,211,77,.18);  color: rgb(252 211 77); }
.dark .flatpickr-day.gx-day-pending     { background: rgba(252,211,77,.24);  color: rgb(252 211 77); border: 1px dashed rgb(252 211 77); }
.dark .flatpickr-day.gx-day-approved    { background: rgba(74,222,128,.24);  color: rgb(134 239 172); }
.dark .flatpickr-day.gx-day-rejected    { background: rgba(248,113,113,.26); color: rgb(252 165 165); }
.dark .flatpickr-day.gx-day-peer-blocked { background: rgba(96,165,250,.22);  color: rgb(147 197 253); }
.dark .flatpickr-day.gx-day-blocked-admin { background: rgba(192,132,252,.22); color: rgb(216 180 254); }
.dark .flatpickr-day.gx-day-incapacity  { background: rgba(251,113,133,.24); color: rgb(253 164 175); }

/* whitespace-pre-line — el bundle no la trae. Preserva `\n` como salto visual
 * y colapsa runs de espacios. Necesaria para renderizar replies/descripciones
 * de tickets con saltos de línea capturados desde un <textarea>. */
.whitespace-pre-line { white-space: pre-line; }

/* max-h-* — el bundle solo trae `max-h-full`. Estas escalas son necesarias para
 * cap-ear dropdowns/menus de pickers async (combobox de soporte, etc.) y dejar
 * que el scroll interno funcione sin desbordar el modal contenedor. */
.max-h-40 { max-height: 10rem; }
.max-h-48 { max-height: 12rem; }
.max-h-56 { max-height: 14rem; }
.max-h-60 { max-height: 15rem; }
.max-h-64 { max-height: 16rem; }
.max-h-72 { max-height: 18rem; }
.max-h-80 { max-height: 20rem; }
.max-h-96 { max-height: 24rem; }

/* pr-7 / pr-9 — el bundle TailAdmin sólo trae 2..5, 8, 10..14. Estos dos faltan
 * y se usan en selects con chevron absoluto (picker de reasignar / agregar
 * colaboradores) para que el ícono no se solape con el texto. */
.pr-7 { padding-right: 1.75rem; }
.pr-9 { padding-right: 2.25rem; }

/* bg-ticket-thread — tono crema cálido específico para el fondo del hilo de
 * conversación del detalle de ticket. Imita el "papel" de un chat estilo
 * mensajería y diferencia visualmente la sección del resto de la UI. No vive
 * en el bundle de TailAdmin porque es un color de uso muy puntual. */
.bg-ticket-thread { background-color: #f7f3e8; }
.dark .bg-ticket-thread { background-color: #2a2620; }

/* Chat — mismo tratamiento visual que el thread de tickets (mismo bundle,
 * misma paleta) pero con nombres genéricos para que los módulos próximos
 * puedan reusar sin alias. */
.bg-chat-thread { background-color: #f7f3e8; }
.dark .bg-chat-thread { background-color: #2a2620; }

.chat-thread-scroll { overflow-y: auto; }
.chat-thread-scroll::-webkit-scrollbar { width: 6px; }
.chat-thread-scroll::-webkit-scrollbar-thumb { background: rgb(209 213 219); border-radius: 3px; }
.dark .chat-thread-scroll::-webkit-scrollbar-thumb { background: rgb(55 65 81); }

/* gx-ticket-event-pill — pastilla de eventos audit (creó, reasignó, status…) en
 * el hilo de conversación del detalle del ticket. Va en tonos crema que
 * armonizan con `.bg-ticket-thread`, y a 30% de opacidad por default para que
 * no compita con las burbujas de mensajes. Al hacer hover sube a 100% por
 * legibilidad cuando el usuario quiere leerlo. */
.gx-ticket-event-pill {
    background-color: #e8e0cc;
    color: #6b6149;
    opacity: 0.3;
    transition: opacity 0.15s ease-in-out;
}
.gx-ticket-event-pill:hover { opacity: 1; }
.dark .gx-ticket-event-pill {
    background-color: #3a342a;
    color: #b8ad94;
}

/* ticket-replies-scroll — scroll interno del hilo de mensajes del detalle de
 * ticket. El alto lo define el contenedor padre (layout 2-col con
 * h-[calc(100vh-186px)]); este selector solo activa el scroll y el styling del
 * scrollbar (espejo de .chat-thread-scroll). */
.ticket-replies-scroll { overflow-y: auto; }
.ticket-replies-scroll::-webkit-scrollbar { width: 6px; }
.ticket-replies-scroll::-webkit-scrollbar-thumb { background: rgb(209 213 219); border-radius: 3px; }
.dark .ticket-replies-scroll::-webkit-scrollbar-thumb { background: rgb(55 65 81); }

/* ---------------------------------------------------------------------------
 * Support · Tickets — Reacciones estilo WhatsApp/Slack
 * Controla la afordancia hover del botón "…" sobre cada burbuja, los chips
 * agrupados debajo, y la integración del web-component <emoji-picker>.
 * ------------------------------------------------------------------------- */

/* Botón de reacción 🙂 + quick-strip: aparece SOLO al hover del bubble (o
 * cuando el quick-strip está abierto/focus). Mantengo pointer-events:none en
 * el reposo para que no interfiera con clicks accidentales en el bubble. */
.gx-bubble-actions {
    opacity: 0;
    transition: opacity 0.12s ease-in-out;
    pointer-events: none;
}
.group\/bubble:hover .gx-bubble-actions,
.gx-bubble-actions:focus-within,
.gx-bubble-actions:hover {
    opacity: 1;
    pointer-events: auto;
}

/* Chip de reacción: sin fondo ni borde (estilo WhatsApp). Solo emoji +
 * contador (cuando count>=2). Hover con scale para feedback táctil. */
.gx-reaction-chip {
    line-height: 1.1;
    background: transparent;
    border: 0;
    padding: 0;
    transition: transform 0.08s ease-in-out;
}
.gx-reaction-chip:hover { transform: scale(1.12); }
.gx-reaction-chip:active { transform: scale(1); }

/* Fila de reacciones: ligeramente superpuesta al borde inferior del bubble
 * (overlap ~10px). z-index la deja sobre la sombra del bubble. */
.gx-reactions-row {
    margin-top: -10px;
    position: relative;
    z-index: 1;
}

/* <emoji-picker>: el web-component expone CSS vars para custom theming.
 * Lo afinamos al look TailAdmin (radio, sombra, fuente). El modo oscuro lo
 * habilita la clase `.dark` propagada desde el binding `:class` en la vista. */
.gx-emoji-picker {
    --border-radius: 12px;
    --background: #ffffff;
    --border-color: rgb(229 231 235);
    --indicator-color: rgb(70 95 255); /* brand-500 aprox */
    --input-border-color: rgb(229 231 235);
    --input-padding: 0.5rem 0.75rem;
    --num-columns: 8;
    width: 320px;
    height: 360px;
    box-shadow: 0 10px 25px -5px rgba(0,0,0,0.10), 0 8px 10px -6px rgba(0,0,0,0.08);
    border: 1px solid rgb(229 231 235);
    border-radius: 12px;
}
.gx-emoji-picker.dark {
    --background: rgb(17 24 39);
    --border-color: rgb(55 65 81);
    --input-border-color: rgb(55 65 81);
    --input-font-color: rgb(229 231 235);
    --category-emoji-padding: 0.25rem;
    --button-active-background: rgb(31 41 55);
    --button-hover-background: rgb(31 41 55);
    color-scheme: dark;
    border-color: rgb(55 65 81);
}

/* ---------------------------------------------------------------------------
 * Support · Tickets — Quote / Responder (estilo WhatsApp)
 * ------------------------------------------------------------------------- */

/* Bloque de cita: borde lateral brand-500 y fondo sutil. Truncate a 2 líneas. */
.gx-quote-block {
    border-left: 3px solid rgb(70 95 255); /* brand-500 */
    transition: background-color 0.12s ease-in-out;
}

/* line-clamp-2 (truncate multilinea) — no está compilado en el bundle. */
.line-clamp-2 {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

/* Flash visual al hacer scroll a una reply citada (click sobre el quote). */
@keyframes gx-quote-flash {
    0%   { box-shadow: 0 0 0 0 rgba(70, 95, 255, 0); }
    20%  { box-shadow: 0 0 0 4px rgba(70, 95, 255, 0.35); }
    100% { box-shadow: 0 0 0 0 rgba(70, 95, 255, 0); }
}
.gx-quote-flash { animation: gx-quote-flash 1.2s ease-out; }

/* Compose textarea (estilo WhatsApp): altura mínima de 1 línea, crece hasta
 * el cap del autoGrowCompose() en JS. Sin esto el rows=1 inicial rinde 1.5x
 * en algunos browsers por line-height. */
.gx-compose-textarea {
    min-height: 40px;
    max-height: 160px;
    line-height: 1.4;
}

/* Utilities transversales ausentes en el bundle compilado. Agregadas aquí
 * (en vez de reemplazarlas en HTML) porque tienen sentido semántico. */
.w-52 { width: 13rem; }   /* 208px — dropdowns medianos (ej. menú [+] del compose) */
.w-80 { width: 20rem; }   /* 320px — dropdown de plantillas (canned responses) */
/* w-3.5: el bundle trae h-3.5 pero NO w-3.5; SVGs con `h-3.5 w-3.5`
 * quedaban con ancho 0 en silencio. Pareo con la formula de h-3.5. */
.w-3\.5 { width: calc(var(--spacing) * 3.5); }
.gap-y-1 { row-gap: 0.25rem; }
.leading-none { line-height: 1; }

/* Shades 600 (hover de send button) — el bundle solo trae 500. Usamos las
 * vars brand-* del :root + un warning-600 calculado a mano. */
.bg-brand-600   { background-color: var(--color-brand-600); }
.bg-warning-600 { background-color: #b45309; } /* warning más oscuro que el 500 */

/* hover:* equivalentes para las shades 600 (Tailwind no genera estas reglas
 * porque la utility base no existe en el bundle). */
.hover\:bg-brand-600:hover   { background-color: var(--color-brand-600); }
.hover\:bg-warning-600:hover { background-color: #b45309; }

/* text-brand-700/800 — texto verde oscuro para el item activo del sidebar
 * (píldora bg-brand-200). El bundle solo trae text-brand-500. */
.text-brand-700 { color: var(--color-brand-700); }
.text-brand-800 { color: var(--color-brand-800); }

/* tracking-wide — el badge "Interna" en el compose lo usa. */
.tracking-wide { letter-spacing: 0.025em; }

/* Paleta meta-3 ausente del bundle. Solo agregamos los tones que efectivamente
 * usamos (verde tipo "foto/imagen" en el menú [+]). */
.bg-meta-3\/10 { background-color: rgb(16 185 129 / 0.10); } /* emerald-500 @ 10% */
.text-meta-3   { color: rgb(16 185 129); }

/* bg-warning-50/10 — fondo sutil del textarea cuando hay nota interna. */
.bg-warning-50\/10 { background-color: rgb(252 233 215 / 0.10); }

/* h-[598px] — usado por el modal de administrar favoritos (alto fijo).
 * El bundle trae max-h-[598px] pero no h-[598px]; sin esto el modal
 * colapsa al tamaño del contenido cuando hay pocos items. */
.h-\[598px\] { height: 598px; }

/* h-[490px] — usado por los modales "Nuevo grupo" y "Reenviar mensaje".
 * Mismo motivo que h-[598px]: el bundle no compila esta altura específica
 * y sin ella los modales colapsan al contenido. */
.h-\[490px\] { height: 490px; }

/* max-h-[90vh] — cap de altura de modales scrollables (header/footer shrink-0 +
 * body flex-1 overflow-y-auto). El bundle no la compila; sin ella el body no tiene
 * padre acotado y el overflow-y-auto no se activa. La usan scheduling/detail y los
 * modales de incapacidades. */
.max-h-\[90vh\] { max-height: 90vh; }


/* Utilities de posición/spacing pequeñas que el bundle NO trae compiladas
 * (solo trae top-0/3/4/5/6/8/10/16 y right-0/2/3/4/5/6/10). Sin estas, los
 * `absolute top-1 right-1` fallan en silencio y el elemento cae al origen
 * del padre (default top:0; right:auto;) → aparece a la izquierda. */
.top-1  { top:  0.25rem; }
.top-2  { top:  0.5rem;  }
.right-1 { right: 0.25rem; }

/* gx-bubble-menu-trigger — chevron del menú anclado en el top-right interno
 * del bubble. Visibilidad por hover del grupo (.group/bubble) o focus-within,
 * mismo patrón que .gx-bubble-actions. Sin esto el chevron se ve permanente
 * y rompe la vibra "se asoma al pasar por encima". */
.gx-bubble-menu-trigger {
    opacity: 0;
    transition: opacity 0.12s ease-in-out;
    pointer-events: none;
}
.group\/bubble:hover .gx-bubble-menu-trigger,
.gx-bubble-menu-trigger:focus-within,
.gx-bubble-menu-trigger:focus {
    opacity: 1;
    pointer-events: auto;
}

/* text-receipt-read — azul WhatsApp clásico para las palomitas de "leído"
 * (doble check). El bundle no trae paleta sky/cyan/blue; brand-500 (#3C50E0)
 * es demasiado violáceo. WhatsApp usa #53BDEB en sus apps oficiales. */
.text-receipt-read { color: #53BDEB; }

/* Búsqueda en el thread:
 * - gx-search-mark: highlight inline de matches dentro del body del mensaje.
 *   El bundle no incluye estilos para <mark>; sin esto sale negro sobre amarillo
 *   navegador-default y rompe el contraste en dark mode.
 * - gx-search-flash: flash temporal cuando se navega a un match (jumpToSearchMatch).
 *   Hereda el patrón de scrollToReply existente, pero con tono ámbar para reforzar
 *   que viene del buscador, no de un quote. */
.gx-search-mark {
    background-color: #FEF08A;     /* amber-200 */
    color: #1F2937;                /* gray-800 */
    border-radius: 2px;
    padding: 0 1px;
}
.dark .gx-search-mark {
    background-color: #FACC15;     /* amber-400 — más punchy en dark */
    color: #111827;                /* gray-900 */
}
.gx-search-flash {
    animation: gx-search-flash-kf 1.4s ease-out;
    border-radius: 12px;
}
@keyframes gx-search-flash-kf {
    0%   { background-color: rgba(250, 204, 21, 0.45); }   /* amber-400 @ 45% */
    100% { background-color: rgba(250, 204, 21, 0);    }
}

/* Grillas pivote de asistencia (scheduling/index + attendance_report/index) —
 * ancho mínimo de las columnas de día. El bundle solo compila min-w-[260px]
 * (col Empleado) pero NO los anchos chicos de las columnas de fecha; sin esto
 * colapsan al contenido y se desalinean. Programación usa 90px (1 línea);
 * el Reporte usa 104px (2 líneas: horario + slot de cumplimiento). */
.min-w-\[38px\]  { min-width: 38px; }
.min-w-\[90px\]  { min-width: 90px; }
.min-w-\[104px\] { min-width: 104px; }
/* Ancho mínimo de la tabla de días bloqueados (vacaciones) para que las columnas
 * de la grilla data-table-03 no colapsen al contenido en pantallas chicas. */
.min-w-\[900px\] { min-width: 900px; }

/* vertical-align: el bundle no trae ninguna utility .align-*. La grilla del
 * reporte necesita top para que las celdas de 1 y 2 líneas queden parejas
 * arriba. */
.align-top { vertical-align: top; }
.align-middle { vertical-align: middle; }

/* text-2xs — escalón por debajo de text-xs (0.75rem/12px). El bundle no baja
 * de text-xs; este es el 10px del sistema para metadatos ultra-compactos
 * (claves de empleado, chips densos, sub-labels). line-height proporcional a
 * la fórmula de TailAdmin (--text-xs--line-height = calc(1/0.75)) para que el
 * interlineado acompañe el tamaño: 0.625rem * (0.875/0.625) = 0.875rem/14px. */
.text-2xs {
    font-size: 0.625rem;     /* 10px */
    line-height: 0.875rem;   /* 14px */
}
/* Variantes responsive de text-2xs. El bundle no las genera (no hay build de
 * Tailwind), así que las declaramos a mano con los breakpoints estándar y la
 * misma sintaxis `@media (width >= …)` que usa el bundle compilado. */
@media (width >= 640px)  { .sm\:text-2xs  { font-size: 0.625rem; line-height: 0.875rem; } }
@media (width >= 768px)  { .md\:text-2xs  { font-size: 0.625rem; line-height: 0.875rem; } }
@media (width >= 1024px) { .lg\:text-2xs  { font-size: 0.625rem; line-height: 0.875rem; } }
@media (width >= 1280px) { .xl\:text-2xs  { font-size: 0.625rem; line-height: 0.875rem; } }
@media (width >= 1536px) { .\32xl\:text-2xs { font-size: 0.625rem; line-height: 0.875rem; } }
/* Variantes de estado hover/focus (misma dinámica que el resto de utilities
 * de estado del archivo, ej. .hover\:bg-brand-600). El bundle envuelve sus
 * hover en `@media (hover:hover)`; acá mantenemos la forma plana ya usada en
 * custom.css por simplicidad y consistencia interna. */
.hover\:text-2xs:hover { font-size: 0.625rem; line-height: 0.875rem; }
.focus\:text-2xs:focus { font-size: 0.625rem; line-height: 0.875rem; }

/* ── Programación de horarios: indicadores de festivo y vacaciones ──────────
 * Espejo de los colores del calendario de solicitud de vacaciones, pero como
 * utilities del bundle estático (las variantes blue-light dark/* no están
 * compiladas). Festivo = solo indicador (franja ámbar) sobre el día, que
 * conserva su horario. Vacaciones = celda azul, sin horario (como descanso).
 * Azul rgb(59 130 246) = mismo tono que .gx-day-peer-blocked del calendario. */
.gx-sched-holiday-accent      { box-shadow: inset 4px 0 0 0 rgb(245 158 11); }
.dark .gx-sched-holiday-accent { box-shadow: inset 4px 0 0 0 rgb(251 191 36); }
.gx-sched-holiday-cell        { background: rgba(245, 158, 11, .16); }
.dark .gx-sched-holiday-cell  { background: rgba(245, 158, 11, .24); }
.gx-sched-holiday-text        { color: rgb(180 83 9); }
.dark .gx-sched-holiday-text  { color: rgb(251 191 36); }
.gx-sched-vacation            { background: rgba(59, 130, 246, .12); }
.dark .gx-sched-vacation      { background: rgba(59, 130, 246, .22); }
.gx-sched-vacation-text       { color: rgb(37 99 235); }
.dark .gx-sched-vacation-text { color: rgb(147 197 253); }
/* Incapacidad (rosa) — distinto del azul de vacaciones. */
.gx-sched-incapacity            { background: rgba(244, 63, 94, .12); }
.dark .gx-sched-incapacity      { background: rgba(244, 63, 94, .22); }
.gx-sched-incapacity-text       { color: rgb(190 24 93); }
.dark .gx-sched-incapacity-text { color: rgb(251 207 232); }

/* ============================================================
 * Modo compacto / densidad — toggle por usuario (clase .compact en <body>)
 * --------------------------------------------------------------
 * TailAdmin (Tailwind v4) compila TODO el espaciado contra una sola variable
 * (--spacing) y las tipografías contra --text-*. Sobrescribirlas dentro de
 * .compact re-escala toda la UI de golpe — sin recompilar ni tocar style.css.
 * El toggle vive en el header (espejo de darkMode) y persiste en localStorage.
 * Como las custom properties heredan, llega a todo lo que cuelga de <body>,
 * incluidos los modales con x-teleport="body".
 *
 * Rollback total: borrar este bloque. Por usuario: apagar el toggle.
 * Intensidad: MEDIA. Calibrar subiendo/bajando los valores de abajo.
 * ============================================================ */
.compact {
  /* Perilla principal: re-escala TODO el espaciado (p/px/py/gap/h/w/space-y/m/inset…) */
  --spacing: 0.19rem;            /* 0.25rem → ~24% más compacto */

  /* Texto −1 escalón (rem) + interlineado más junto */
  --text-xs:   0.6875rem;        /* 11px (era 12px) */
  --text-sm:   0.8125rem;        /* 13px (era 14px) */
  --text-base: 0.875rem;         /* 14px (era 16px) */
  --text-xs--line-height:   0.95rem;
  --text-sm--line-height:   1.1rem;
  --text-base--line-height: 1.25rem;

  /* Texto de TABLAS (theme vars en px) −1 escalón */
  --text-theme-xs: 11px;  --text-theme-xs--line-height: 15px;   /* era 12/18 */
  --text-theme-sm: 13px;  --text-theme-sm--line-height: 17px;   /* era 14/20 */
}

/*
 * gxa-combobox en modo compacto.
 * El combobox rico (familia gxa-*, incluido el selector estándar de zonas) se
 * estiliza con valores rem/px FIJOS arriba (no usa --spacing/--text-*), así que
 * NO se re-escala solo con .compact y quedaba más alto/holgado que los inputs
 * vecinos (un <select> h-11 baja a ~2.09rem; el trigger seguía en 2.75rem).
 * Estos overrides bajan trigger, menú, buscador y opciones a la misma densidad.
 * Los chips internos (px/py + text-theme-xs) ya escalan solos vía variables.
 */
.compact .gxa-combobox__trigger {
  min-height: 2.25rem;
  padding: 0.375rem 0.625rem;
  gap: 0.375rem;
  font-size: 0.8125rem;
}
.compact .gxa-combobox__trigger-content { gap: 0.375rem; }
.compact .gxa-combobox__clear { width: 1.125rem; height: 1.125rem; }

.compact .gxa-combobox__search { padding: 0.375rem; }
.compact .gxa-combobox__search input { padding: 0.375rem 0.5rem; font-size: 0.8125rem; }

.compact .gxa-combobox__status { padding: 0.375rem 0.375rem 0; }
.compact .gxa-combobox__status button { padding: 0.1875rem 0.375rem; font-size: 0.625rem; }

.compact .gxa-combobox__kinds { padding: 0.375rem; gap: 0.25rem; }
.compact .gxa-combobox__kind { padding: 0.0625rem 0.5rem; font-size: 0.6875rem; line-height: 1.1rem; }

.compact .gxa-combobox__list { padding: 0.1875rem; }
.compact .gxa-combobox__group { padding: 0.25rem 0.5rem 0.1875rem; }
.compact .gxa-combobox__option { padding: 0.3125rem 0.5rem; gap: 0.375rem; }
.compact .gxa-combobox__option-label { font-size: 0.8125rem; }
.compact .gxa-combobox__option-secondary { font-size: 0.6875rem; }
.compact .gxa-combobox__check { width: 14px; height: 14px; }
.compact .gxa-combobox__empty { padding: 0.625rem; font-size: 0.8125rem; }

/*
 * .font-mono — utilidad monoespaciada ausente del bundle compilado.
 * Usada por el tag de debug de permisos (partials/debug-permission-tag) para
 * los strings de permiso. Stack mono estándar.
 */
.font-mono {
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
}

/*
 * .gx-doc — tipografía para Markdown renderizado (modal de documentación por
 * sección, partials/section-help.php). El bundle no trae `prose`; estos estilos
 * dan jerarquía legible al HTML que produce CommonMark. Paleta alineada a
 * TailAdmin (gray-* / brand-*) con variante dark.
 */
.gx-doc {
  font-size: 0.9375rem;
  line-height: 1.65;
  color: #344054; /* gray-700 */
}
.dark .gx-doc { color: #d0d5dd; } /* gray-300 */

.gx-doc > :first-child { margin-top: 0; }
.gx-doc > :last-child { margin-bottom: 0; }

.gx-doc h1 { font-size: 1.5rem;  font-weight: 700; line-height: 1.25; margin: 1.5rem 0 0.75rem; color: #1d2939; }
.gx-doc h2 { font-size: 1.25rem; font-weight: 600; line-height: 1.3;  margin: 1.5rem 0 0.5rem;  color: #1d2939; padding-bottom: 0.3rem; border-bottom: 1px solid #eaecf0; }
.gx-doc h3 { font-size: 1.05rem; font-weight: 600; line-height: 1.35; margin: 1.25rem 0 0.4rem; color: #1d2939; }
.gx-doc h4 { font-size: 0.95rem; font-weight: 600; margin: 1rem 0 0.3rem; color: #1d2939; }
.dark .gx-doc h1, .dark .gx-doc h2, .dark .gx-doc h3, .dark .gx-doc h4 { color: #f2f4f7; }
.dark .gx-doc h2 { border-bottom-color: #1d2939; }

.gx-doc p { margin: 0.6rem 0; }
.gx-doc ul, .gx-doc ol { margin: 0.6rem 0; padding-left: 1.4rem; }
.gx-doc ul { list-style: disc; }
.gx-doc ol { list-style: decimal; }
.gx-doc li { margin: 0.25rem 0; }
.gx-doc li > ul, .gx-doc li > ol { margin: 0.25rem 0; }

.gx-doc a { color: var(--color-brand-500); text-decoration: underline; text-underline-offset: 2px; }
.gx-doc a:hover { color: var(--color-brand-600); }
.dark .gx-doc a { color: var(--color-brand-400); }

.gx-doc strong { font-weight: 600; color: #1d2939; }
.dark .gx-doc strong { color: #f2f4f7; }
.gx-doc em { font-style: italic; }

.gx-doc code {
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
  font-size: 0.85em;
  background: #f2f4f7;
  color: #344054;
  padding: 0.15em 0.4em;
  border-radius: 0.3rem;
}
.dark .gx-doc code { background: #1d2939; color: #d0d5dd; }

.gx-doc pre {
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
  font-size: 0.85rem;
  line-height: 1.5;
  background: #1d2939;
  color: #e4e7ec;
  padding: 1rem;
  border-radius: 0.6rem;
  overflow-x: auto;
  margin: 0.9rem 0;
}
.gx-doc pre code { background: transparent; color: inherit; padding: 0; font-size: inherit; }

.gx-doc blockquote {
  border-left: 3px solid var(--color-brand-500);
  background: #f9fafb;
  padding: 0.5rem 1rem;
  margin: 0.9rem 0;
  color: #475467;
  border-radius: 0 0.4rem 0.4rem 0;
}
.dark .gx-doc blockquote { background: #ffffff08; color: #98a2b3; }

.gx-doc hr { border: 0; border-top: 1px solid #eaecf0; margin: 1.5rem 0; }
.dark .gx-doc hr { border-top-color: #1d2939; }

.gx-doc table { width: 100%; border-collapse: collapse; margin: 0.9rem 0; font-size: 0.875rem; }
.gx-doc th, .gx-doc td { border: 1px solid #eaecf0; padding: 0.5rem 0.75rem; text-align: left; vertical-align: top; }
.gx-doc th { background: #f9fafb; font-weight: 600; color: #1d2939; }
.dark .gx-doc th, .dark .gx-doc td { border-color: #1d2939; }
.dark .gx-doc th { background: #ffffff08; color: #f2f4f7; }

.gx-doc img { max-width: 100%; height: auto; border-radius: 0.5rem; margin: 0.6rem 0; }

.gx-doc input[type="checkbox"] { margin-right: 0.4rem; }

/* Utilities faltantes en el bundle, usadas por bloques de salida/código
   (Herramientas de mantenimiento → diagnóstico HEIC). */
.whitespace-pre-wrap { white-space: pre-wrap; }
.break-all { word-break: break-all; }

/* Anchos/flex responsivos faltantes en el bundle (filtros del reporte
   Desglose de Ingresos Global: Periodo + Zona fijos, Conceptos toma el resto). */
@media (min-width: 640px) {
    .sm\:w-44   { width: 11rem; }
    .sm\:w-56   { width: 14rem; }
    .sm\:w-60   { width: 15rem; }
    .sm\:w-72   { width: 18rem; }
    .sm\:flex-1 { flex: 1 1 0%; }
}

/* Ancho fijo del botón Buscar para que el cambio de texto
   ("Buscar" ↔ "Buscando…") no redimensione ni desborde los conceptos. */
@media (min-width: 1024px) {
    .lg\:w-32 { width: 8rem; }
}

/* Utilities faltantes en el bundle, usadas por la tabla del reporte
   Desglose de Ingresos Global (columnas dinámicas, headers multilínea, totales). */
.whitespace-pre   { white-space: pre; }
.tabular-nums     { font-variant-numeric: tabular-nums; }
.border-t-2       { border-top-width: 2px; }
.last\:border-r-0:last-child { border-right-width: 0; }
/* Línea sutil bajo el thead sticky (el bundle no trae este arbitrary value). */
.shadow-\[0_1px_0_0_rgba\(0\2c 0\2c 0\2c 0\.05\)\] { box-shadow: 0 1px 0 0 rgba(0, 0, 0, 0.05); }

/* Tintes de fondo por grupo de columna (reporte Desglose de Ingresos Global):
   base = Costo Prom. + Total c/IVA · total = Total por forma de pago ·
   flow = Ingreso/Egreso. Replica bg_base/bg_total/bg_otros del legacy.
   En dark mode, tinte oscuro tenue equivalente (no el pastel claro). */
.gx-cell-base { background-color: rgb(225, 236, 249); }
.gx-cell-total { background-color: rgb(222, 246, 236); }
.gx-cell-flow { background-color: rgb(235, 233, 249); }
.dark .gx-cell-base  { background-color: rgba(96, 165, 250, 0.12); }
.dark .gx-cell-total { background-color: rgba(52, 211, 153, 0.12); }
.dark .gx-cell-flow  { background-color: rgba(167, 139, 250, 0.12); }

/* Hover de fila: las celdas tinteadas (y la sticky con bg propio) tapan el
   hover:bg-gray-50 del <tr>, así que aquí se oscurece cada una un escalón al
   pasar el cursor por su fila — incluida la columna fija (ID Tienda). */
.gx-desglose-table tbody tr:hover .gx-cell-base  { background-color: rgb(205, 222, 244); }
.gx-desglose-table tbody tr:hover .gx-cell-total { background-color: rgb(202, 238, 224); }
.gx-desglose-table tbody tr:hover .gx-cell-flow  { background-color: rgb(223, 219, 245); }
.gx-desglose-table tbody tr:hover td.sticky      { background-color: rgb(249, 250, 251); }
.dark .gx-desglose-table tbody tr:hover .gx-cell-base  { background-color: rgba(96, 165, 250, 0.20); }
.dark .gx-desglose-table tbody tr:hover .gx-cell-total { background-color: rgba(52, 211, 153, 0.20); }
.dark .gx-desglose-table tbody tr:hover .gx-cell-flow  { background-color: rgba(167, 139, 250, 0.20); }
.dark .gx-desglose-table tbody tr:hover td.sticky      { background-color: rgb(24, 31, 42); }

/* Modal del Ticket (detalle de tienda): un poco más ancho que max-w-3xl y altura
   fija al 90% del viewport desde el montaje, para que no haya saltos visuales
   entre el estado "cargando" y el ticket cargado. El bundle no trae max-w-4xl
   ni h-[90vh]. El scroll vive en el body general (no en tablas internas). */
.gx-ticket-modal { width: 100%; max-width: 56rem; height: 90vh; }

/* Utilities estándar de Tailwind ausentes del bundle compilado. */
.table-fixed { table-layout: fixed; }
.min-w-0 { min-width: 0; }

/* Grid de 5 KPIs (Resumen de tienda): el bundle no trae grid-cols-5. 2 cols en
   móvil → 5 en lg. Mobile-first, sin tocar el bundle. */
.gx-grid-kpi { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1rem; }
@media (min-width: 1024px) { .gx-grid-kpi { grid-template-columns: repeat(5, minmax(0, 1fr)); } }

/* Badges pastel genéricos por color (reutilizables): texto + fondo tenue,
   con variante dark. El bundle no trae purple-50 ni los bg-*-500/10 dark de
   varias paletas, así que se definen aquí (norma: utilities faltantes →
   custom.css). Pensados para píldoras `rounded-full px-2 py-0.5 text-xs`. */
.gx-badge-gray   { background-color: rgb(243, 244, 246); color: rgb(75, 85, 99); }
.gx-badge-green  { background-color: rgb(220, 252, 231); color: rgb(21, 128, 61); }
.gx-badge-red    { background-color: rgb(254, 226, 226); color: rgb(185, 28, 28); }
.gx-badge-yellow { background-color: rgb(254, 243, 199); color: rgb(161, 98, 7); }
.gx-badge-purple { background-color: rgb(237, 233, 254); color: rgb(109, 40, 217); }
.gx-badge-blue   { background-color: rgb(224, 242, 254); color: rgb(2, 132, 199); }
.gx-badge-orange { background-color: rgb(255, 237, 213); color: rgb(194, 65, 12); }
.dark .gx-badge-gray   { background-color: rgba(156, 163, 175, 0.15); color: rgb(209, 213, 219); }
.dark .gx-badge-green  { background-color: rgba(34, 197, 94, 0.15);  color: rgb(74, 222, 128); }
.dark .gx-badge-red    { background-color: rgba(239, 68, 68, 0.15);  color: rgb(248, 113, 113); }
.dark .gx-badge-yellow { background-color: rgba(234, 179, 8, 0.15);  color: rgb(250, 204, 21); }
.dark .gx-badge-purple { background-color: rgba(124, 90, 248, 0.18); color: rgb(196, 181, 253); }
.dark .gx-badge-blue   { background-color: rgba(11, 165, 236, 0.15); color: rgb(125, 211, 252); }
.dark .gx-badge-orange { background-color: rgba(249, 115, 22, 0.15); color: rgb(253, 186, 116); }

/* ---------------------------------------------------------------------------
 * Portal de clientes (/customer/*) — utilities ausentes del bundle.
 * `h-dvh` no está precompilado (solo min-h-dvh); el portal lo usa como alto
 * del documento para que el scroll viva adentro de la tarjeta (correcto en
 * iframe y en mobile con barra de URL dinámica). Fallback 100vh para
 * navegadores sin dvh.
 * ------------------------------------------------------------------------- */
.h-dvh { height: 100vh; height: 100dvh; }

/* Utilities del portal de clientes ausentes del bundle (verificadas con
 * grep -F antes de agregar — norma del proyecto). */
.self-end { align-self: flex-end; }
.hover\:bg-white\/10:hover { background-color: rgb(255 255 255 / 0.1); }
.max-w-\[85\%\] { max-width: 85%; }
@media (min-width: 640px) {
  .sm\:max-w-\[75\%\] { max-width: 75%; }
}
@media (min-width: 1024px) {
  .lg\:border-r { border-right-style: var(--tw-border-style, solid); border-right-width: 1px; }
}
