/* MICHEMICALDATALAB — FACTURACIÓN INTERNAL V2 (preview) — panel autenticado de clientes
   ------------------------------------------------------------------------
   Carga JUNTO a /styles.css + /pos-modulos.css + /pos-ingresos.css + /pos-kardex.css +
   /pos-movimientos.css + /pos-reportes.css (TODOS reales, sin tocar, en el mismo orden real
   de panel.html) y /home-v2.css (SOLO para :root tokens + @font-face — NO se usa su shell
   #pf-grid/#pf-glow/#pf-fluid/.pf-header/.pf-techbar/.pf-wa-float, por decisión explícita de
   la Etapa 2: PASO 22-26 del brief piden NO agregar fluid/stickers/warp/WhatsApp
   flotante/tech bar automáticamente a un panel administrativo — prioridad = legibilidad/
   rendimiento/formularios/tablas, no decoración pública). Reutiliza el mismo criterio ya
   aprobado en facturacion-v2.css (styles.css primero, home-v2.css tokens encima, override
   local sin tocar ningún ancestro de #feAppArea) — mismo mecanismo, archivo nuevo porque el
   alcance/selectores de esta página (header .fe-client-topbar, sin body.pf) son distintos.

   ALCANCE (ver brief): SÍ reskinea shell autenticado (header/sidebar/fondo/tipografía/
   cards/buttons/forms/tables/modals genéricos) + módulos Empresa/Certificado/Tokens
   API/Comprobantes/Usuarios + SOLO el landing de 7 tarjetas de Punto de Venta
   (.fe-pos-grid/.fe-pos-card). NO reskinea absolutamente nada dentro de
   .fe-pos-module-view/.pos-admin-*/.pos-maestro-*/#fePosSales/.fe-pos-terminal (los 7
   módulos POS protegidos: Ventas/Productos/Categorías/Ingresos/Kardex/Movimientos/
   Reportes) — ningún selector de este archivo los alcanza, verificado por construcción
   (mismo criterio ya probado en facturacion-v2.css: ningún botón/tabla de esos módulos usa
   las clases genéricas .btn/.form-control/.fe-table que si se reskinean aquí).

   ============ ETAPA 4 — INVESTIGACIÓN "CSSOM ROOT CAUSE" (ver REPORTE FINAL) ============
   Auditoría estática de este archivo (brace-balance 48/48, sin BOM, sin caracteres de
   control, la regla body.fe-client-panel-body es un bloque autocontenido de 3 líneas sin
   ningún defecto de sintaxis plausible) NO encontró evidencia de un fallo de parseo real.
   Lo que SÍ explica el síntoma reportado (subtítulos/chips/botones/logout en Poppins pese a
   que h1/h2/h3 SÍ reciben TikTok Sans) es un mecanismo de CASCADA normal, no de parseo:
   styles.css declara font-family EXPLÍCITO y más específico directamente sobre esos
   componentes (.btn, chips, celdas de tabla, etc.) — la herencia de body.fe-client-panel-body
   SOLO alcanza elementos que no tienen su propia declaración explícita, y la mayoría de los
   elementos reportados sí la tienen. FIX: declarar font-family DIRECTO sobre cada selector
   de componente real (mismo patrón que ya usaban h1/h2/h3), no depender de la herencia de
   body ni usar !important. */

/* ============ TIPOGRAFÍA — mismos tokens reales de home-v2.css:26-37, sin redeclarar el
   shell (grid/glow/fluid/header/techbar/wa-float NO se cargan aquí). Organizada por rol
   real (PASO 3 de esta etapa), declarada DIRECTO sobre cada componente. ============ */
body.fe-client-panel-body {
  font-family: var(--font-mono), Poppins, sans-serif;
}

/* TÍTULOS PRINCIPALES — TikTok Sans / var(--font-display). ETAPA 5: la marca del header ya
   no usa esta regla — migró a .pf-brandname (font-label real, ver sección HEADER), igual
   que el resto del ecosistema V2 (index.html:78, MICHEMICALDATALAB en Departure Mono, no
   TikTok Sans). */
.fe-side-brand strong,
h1, h2, h3 {
  font-family: var(--font-display), Fredoka, sans-serif;
}
/* ETAPA 5 — FIX DE ESPECIFICIDAD: "Datos de la empresa"/"PEM / PFX por empresa"/
   "Usuarios y permisos" (y el resto de títulos de sección) seguían en Fredoka porque
   styles.css:268 declara font-family EXPLÍCITO sobre el selector `.section-head h2`
   (especificidad 0,1,1 — 1 clase + 1 elemento), que le gana al `h2` genérico de arriba
   (especificidad 0,0,1). Fix: mismo selector exacto que el legacy (no uno más agresivo
   como body.fe-client-panel-body .section-head h2, que no hacía falta) — con especificidad
   IGUAL (0,1,1), gana por orden de carga (este archivo se enlaza después de styles.css en
   panel-v2-preview.html), sin necesitar !important. Cubre TODOS los títulos permitidos:
   Empresa, Certificado, Tokens API, Comprobantes, Usuarios (todos usan .section-head h2 en
   el DOM real). Punto de Venta landing no tiene un <h2> propio en panel.html (va directo a
   las 7 tarjetas), así que no hay título que corregir ahí. */
.section-head h2 {
  font-family: var(--font-display), Fredoka, sans-serif;
}

/* BODY / TEXTOS DE PANEL — Geist Mono / var(--font-mono). Declarado DIRECTO: styles.css ya
   fija font-family explícito y de mayor especificidad sobre estos mismos selectores, así que
   la herencia de body.fe-client-panel-body no los alcanza (ver nota CSSOM más arriba). */
.section-head p,
.fe-user-info p,
#feUsersLimitText,
#feUsersPlanText,
.fe-client-topbar .fe-client-url,
.fe-table td {
  font-family: var(--font-mono), Poppins, sans-serif;
}

/* LABELS TÉCNICOS — Departure Mono / var(--font-label): badges, chips, encabezados de
   tabla, labels de formulario, textos uppercase pequeños. */
.mini-title,
.fe-side-menu-title,
.fe-side-brand span,
.form-label span,
.fe-chip, .fe-chip-soft, .fe-chip-ok, .fe-chip-danger,
.fe-user-perm-tags span,
.fe-user-status,
.fe-table th {
  font-family: var(--font-label), Poppins, sans-serif;
}

/* BOTONES — misma familia real ya usada en los botones V2 productivos (apis-v2.css/
   gratis-v2.css/carrito-v2.css: font-family:var(--font-label)). */
.btn, .fe-mobile-drawer-handle {
  font-family: var(--font-label), Poppins, sans-serif;
}

/* ============ HEADER — ETAPA 5, MIGRADO AL SHELL V2 REAL. El header ya no es una barra
   legacy propia: usa el MISMO contenedor visual .pf-header/.pf-bar y el MISMO bloque de
   marca .pf-brand/.pf-mark/.pf-brandname que Home/Catálogo/APIs/Facturación pública/
   Academia/Gratis/Carrito (valores reales releídos de home-v2.css:108-123, confirmados en
   el DOM real de index.html:74-93). Esas 5 clases NO se redeclaran aquí — /home-v2.css
   (ya cargado en panel-v2-preview.html) las aporta tal cual, mismos valores que el resto
   del ecosistema. Esta sección SOLO añade lo específico del contenido administrativo
   (tenant dinámico + logout) que reemplaza la nav pública/carrito del shell real — sin
   agregar .pf-nav ni .pf-cart al panel (PASO "NO AGREGAR NAV PÚBLICO" de esta etapa).
   Preserva #feClientHostLabel/#feLogoutBtn (hooks reales, sin tocar). ============ */
body.fe-client-panel-body .pf-header {
  /* home-v2.css:108 usa position:fixed (flota sobre el hero público, que aquí no existe).
     Se ancla en flujo (sticky) para no tapar el contenido, mismo comportamiento del
     .topbar legacy que reemplaza (styles.css:96-98, sticky/top:0) — margin/padding/radius/
     blur/color/gap de .pf-bar (home-v2.css) quedan exactamente iguales, sin tocar. */
  position: sticky;
}
.fe-admin-brand { min-width: 0; }
.fe-admin-brandtext { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.fe-admin-subtitle {
  font-family: var(--font-label), Poppins, sans-serif;
  font-size: 11px;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--muted);
}
.fe-admin-actions { display: flex; align-items: center; gap: 14px; }
.fe-client-topbar .fe-client-url { color: var(--muted); }
/* ETAPA 7 — ALTURA DEL HEADER: .pf-bar (home-v2.css:109-119) usa align-items:center, así
   que la altura visual de la barra la determina su hijo más alto. Medido en esta etapa:
   brand block ~30.89px vs #feLogoutBtn ~50px — el botón es el que infla la barra, NO la
   marca de dos líneas (que se conserva intacta). #feLogoutBtn hereda `.btn` (styles.css:
   145-146, min-height:50px, padding:0 22px, border-radius:999px, sombra/gradiente) — ese
   es el mismo tamaño de botón "de acción primaria" usado en formularios, sobredimensionado
   para vivir dentro de una barra de header. La acción comparable real en el header V2
   público (Home/Gratis/Carrito/APIs) es `.pf-cart` (home-v2.css:148-152): sin min-height
   propio (se dimensiona por padding+contenido), padding:8px 14px, border:1px solid
   var(--line), border-radius:999px, font-family:var(--font-label), font-size:13px,
   letter-spacing:.04em. Se reutilizan esos valores EXACTOS sobre #feLogoutBtn — con
   min-height:auto quitando el piso de 50px de `.btn` (no se fija un height nuevo, se deja
   que resulte del padding+línea de texto, igual que .pf-cart) — así el hijo más alto de
   .pf-bar vuelve a ser comparable al del header público, y la altura de la barra baja a
   la que resulta naturalmente del padding real de .pf-bar + este botón, sin tocar
   margin/radius/background/blur de .pf-bar ni el bloque de marca de dos líneas. */
.fe-client-topbar #feLogoutBtn.btn.secondary {
  min-height: auto;
  padding: 8px 14px;
  border-radius: 999px;
  border: 1px solid var(--line);
  font-family: var(--font-label), Poppins, sans-serif;
  font-size: 13px;
  letter-spacing: .04em;
  color: var(--ink);
  background: transparent;
  box-shadow: none;
}

/* ============ FONDO — grid técnico sutil opcional (PASO 22), decisión de esta etapa: NO
   se incluye en la primera versión (prioridad = legibilidad/formularios/tablas, sin RAF ni
   WebGL adicional, ver REPORTE FINAL "GRID: NO"). Solo el degradé real ya definido en el
   <style> inline de panel.html (body.fe-client-panel-body) se conserva sin tocar. ============ */

/* ============ LOGIN — mismos valores REALES ya aprobados en facturacion-v2.css:117-199
   (body.fe-auth-mode), portados aquí porque panel.html usa el MISMO gate/clases exactos. ============ */
body.fe-auth-mode { --ink: #0a0e14; --muted: rgba(10,14,20,.62); --line: rgba(10,14,20,.10); }
body.fe-auth-mode .fe-login-brand h2 {
  font-family: var(--font-display); font-size: 25.6px; font-weight: 800; line-height: normal; letter-spacing: -.64px; color: var(--ink);
}
body.fe-auth-mode .fe-login-form--compact .form-label span {
  font-family: var(--font-label); font-size: 11px; font-weight: 400; letter-spacing: .1em; text-transform: uppercase; color: var(--muted);
}
body.fe-auth-mode .fe-login-form--compact .form-control {
  font-family: var(--font-mono); font-weight: 500; background: rgba(255,255,255,.7); border-color: var(--line); border-radius: 10px; box-shadow: none;
}
body.fe-auth-mode .fe-login-form--compact .form-control:focus {
  background: rgba(255,255,255,.9); border-color: rgb(192, 254, 4); box-shadow: 0 0 0 3px rgba(192, 254, 4, .35);
}
body.fe-auth-mode .fe-login-form--compact .fe-login-actions .btn {
  letter-spacing: .06em; text-transform: uppercase;
}
body.fe-auth-mode .fe-login-form--compact .fe-login-remember {
  background: rgba(255,255,255,.5); border: 1px solid var(--line); border-radius: 10px; box-shadow: none;
}
body.fe-auth-mode .fe-login-form--compact .fe-login-remember span { font-family: var(--font-mono); font-size: 13px; color: var(--ink); }
body.fe-auth-mode .fe-auth-card { background: #fff; border: 1px solid var(--line); border-radius: 18px; box-shadow: none; }
body.fe-auth-mode .fe-welcome-bubble { font-family: var(--font-mono); font-weight: 500; color: var(--ink); border-color: var(--line); box-shadow: none; }
body.fe-auth-mode .fe-welcome-lottie--static { border: 1px solid var(--line); border-radius: 18px; }

/* ============ BOTÓN LIMA — valores EXACTOS de facturacion-v2.css:64-72, ya verificado
   estructuralmente incapaz de alcanzar los módulos POS protegidos (ninguno usa .btn). ============ */
.btn:not(.secondary) {
  background: rgb(192, 254, 4);
  color: rgb(0, 0, 0);
  border-radius: 6px;
}
.btn:not(.secondary):hover {
  background: rgb(170, 238, 0);
  transform: translateY(-1px);
}

/* ============ SIDEBAR — ETAPA 5, RESTAURACIÓN DEL FONDO OSCURO ORIGINAL ============
   La Etapa 4 cambió la SUPERFICIE del sidebar a blanco para resolver un problema de
   contraste que en realidad lo había causado ella misma (Etapa 2: `color:var(--ink)` sobre
   el fondo oscuro real). El usuario NO quiere el sidebar blanco — quiere el fondo oscuro
   original con el texto claro que YA era legible en styles.css antes de tocar nada.

   Valores REALES releídos y confirmados de nuevo en styles.css antes de aplicar (sin usar
   memoria de la etapa anterior):
   - Fondo: styles.css:4368-4370 (.fe-side-menu, gradiente radial azul/negro)
   - Borde/sombra: styles.css:4371-4372
   - Texto inactivo: styles.css:4428 → rgba(255,255,255,.78) (contraste ~11.58:1 sobre el
     fondo oscuro real, ya legible, no se inventa)
   - Hover: styles.css:4433-4437 → color #fff, background rgba(255,255,255,.10)
     (contraste ~14.51:1)
   - Marca/título/icono: styles.css:4407-4408 (#fff / rgba(255,255,255,.68)), :4412
     (rgba(255,255,255,.62)), :4394-4395 (fondo/borde de .fe-side-brand), :4402 (fondo de
     .fe-side-brand img), :4453-4454 (fondo/borde de .fe-tab-icon)

   Se re-declaran aquí EXPLÍCITAMENTE (en vez de solo eliminar el override de la Etapa 4)
   para que el valor correcto quede documentado y visible en este archivo, no dependiendo
   silenciosamente de la ausencia de una regla. El ÚNICO valor que SÍ se conserva distinto
   del legacy original es el estado ACTIVO (lima V2, ya aprobado — el usuario pidió
   explícitamente NO volver al azul legacy ahí). */
.fe-side-menu {
  background:
    linear-gradient(180deg, rgba(2,6,23,.94), rgba(17,24,39,.90)),
    linear-gradient(135deg, rgba(47,128,237,.30), rgba(0,194,168,.18));
  border: 1px solid rgba(255,255,255,.14);
  box-shadow: 0 28px 70px rgba(2,6,23,.18);
}
.fe-side-brand {
  background: rgba(255,255,255,.10);
  border: 1px solid rgba(255,255,255,.13);
}
.fe-side-brand img {
  background: rgba(255,255,255,.92);
  border: none;
}
.fe-side-brand strong { color: #fff; }
.fe-side-brand span { color: rgba(255,255,255,.68); }
.fe-side-menu-title { color: rgba(255,255,255,.62); }
.fe-side-menu .fe-tab {
  color: rgba(255,255,255,.78);
  background: transparent;
}
.fe-side-menu .fe-tab:hover {
  color: #fff;
  background: rgba(255,255,255,.10);
  border-color: rgba(255,255,255,.12);
  transform: translateX(3px);
}
.fe-side-menu .fe-tab-icon {
  background: rgba(255,255,255,.12);
  border: 1px solid rgba(255,255,255,.12);
}
/* ACTIVO — lima V2 ya aprobado, se mantiene sin cambios respecto a la Etapa 4 (NO volver
   al azul legacy `linear-gradient(135deg,var(--accent),var(--accent-2))` de styles.css:4441). */
.fe-side-menu .fe-tab.active,
.fe-module-menu .fe-tab.active {
  background: rgb(192, 254, 4);
  color: rgb(0, 0, 0);
  border-color: transparent;
  box-shadow: none;
}
.fe-side-menu .fe-tab.active .fe-tab-icon {
  background: rgba(0,0,0,.12);
  border-color: rgba(0,0,0,.18);
}
.fe-mobile-drawer-handle {
  background: rgb(192, 254, 4); color: rgb(0,0,0); border: none; box-shadow: 0 10px 24px rgba(10,14,20,.14);
}

/* ============ CARDS/PANELES GENÉRICOS — Empresa/Certificado/Tokens/Comprobantes/Usuarios
   comparten .panel-card/.fe-form-card/.fe-table-card/.fe-filter-card (reales). ============ */
.panel-card, .fe-form-card, .fe-table-card, .fe-filter-card {
  background: #fff; border: 1px solid var(--line); border-radius: 18px; box-shadow: none;
}
.section-head h2 { color: var(--ink); font-weight: 700; }
.section-head p, .mini-title { color: var(--muted); }

/* ============ FORMULARIOS — .form-control/.form-label reales, reskin V2, preservando
   type/name/id/value/readonly/disabled/required/dataset (0 cambios de markup). ============ */
.form-label span { font-weight: 700; letter-spacing: .04em; color: var(--muted); }
.form-control {
  background: rgba(255,255,255,.7); border: 1px solid var(--line); border-radius: 10px; color: var(--ink);
  transition: border-color .15s ease, box-shadow .15s ease, background .15s ease;
}
.form-control:focus { background: rgba(255,255,255,.9); border-color: rgb(192,254,4); box-shadow: 0 0 0 3px rgba(192,254,4,.35); }
.fe-cert-status { border: 1px solid var(--line); border-radius: 10px; }
.fe-secret-edit { color: var(--ink); }
.fe-chip-soft { background: rgba(192,254,4,.16); border: 1px solid rgba(192,254,4,.4); color: var(--ink); }

/* ============ TABLAS — .fe-table real (styles.css:2619-2655), reskin V2 sin tocar
   thead/tbody/data-sort/pagination hooks. ============ */
.fe-table th { background: #fbfaf4; color: var(--muted); letter-spacing: .04em; }
.fe-table td { color: var(--ink); border-color: var(--line); }
.fe-table tr:hover td { background: rgba(192,254,4,.06); }
.fe-pagination__page, .fe-pagination__info { font-family: var(--font-mono); color: var(--muted); }

/* ============ USUARIOS — .fe-user-item real (facturacion.js:2470-2489, renderUsers()),
   confirmado leyendo el template real (no está en el HTML estático: se inyecta al abrir el
   módulo). Reskin visual, 0 cambios de texto/datos/handlers/data-user-edit/reset/toggle. ============ */
.fe-user-item { border: 1px solid var(--line); background: #fff; }
.fe-user-item.inactive { opacity: .68; }
.fe-user-avatar { background: rgba(192,254,4,.16); color: var(--ink); border: 1px solid rgba(192,254,4,.4); }
.fe-user-info h3 { color: var(--ink); }
.fe-user-perm-tags span { background: rgba(10,14,20,.05); border: 1px solid var(--line); color: var(--muted); }
.fe-user-status.ok { background: rgba(192,254,4,.16); border: 1px solid rgba(192,254,4,.4); color: var(--ink); }
.fe-user-status.off { background: rgba(239,68,68,.08); border: 1px solid rgba(239,68,68,.22); color: #b42318; }

/* ============ MODALES GENÉRICOS — usados por Tokens/Usuarios (no confundir con los
   modales propios de los módulos POS protegidos, que este archivo no alcanza). ============ */
.modal-card, .modal-backdrop { border-radius: 18px; }

/* ============ TOKENS — ETAPA 6, BOTÓN "Nuevo token" ============
   Causa real confirmada: #feNewTokenBtn es hijo de .section-head (styles.css:267,
   display:flex, sin flex-wrap), y .btn (styles.css:134-145) no declara white-space ni
   protección de encogimiento — con flex-shrink:1 por defecto y el texto pudiendo envolver,
   el min-width automático del ítem flex cae al ancho de la palabra más larga, así que el
   botón se encoge por debajo del ancho de una sola línea cuando el título vecino
   ("Conexiones para POS, bots y webs") es largo. "Nuevo usuario" (mismo .btn, mismo
   .section-head) no muestra el problema solo porque su título vecino ("Usuarios y
   permisos") es más corto y deja más espacio libre — no por tener ninguna protección
   real. Fix: mismo patrón YA aprobado y en uso real en el ecosistema (styles.css:500,
   `.card-actions .btn { white-space: nowrap; }`) — con white-space:nowrap el ancho
   mínimo automático del ítem pasa a ser el del texto completo sin envolver, así que
   flex-shrink ya no tiene margen para partirlo en dos líneas. Solo flex-shrink:0 sin
   nowrap NO alcanza (el texto seguiría pudiendo envolver dentro del mismo ancho fijo);
   con nowrap solo, no hace falta declarar además flex-shrink:0. No se fija ningún width.
   Scope: selector por ID, no toca ningún otro .btn (Empresa/Certificado/Usuarios/POS
   landing quedan exactamente igual). Padding/tipografía/color lima/altura/handler de
   .btn no se tocan. ============ */
#feNewTokenBtn {
  white-space: nowrap;
}

/* ============ TOKENS — ETAPA 8, COLUMNA TOKEN (32 caracteres, sin espacios) ============
   Auditoría: el valor real del token vive en el DOM/dataset (`data-token` del botón
   Copiar, facturacion.js:1937) y es INDEPENDIENTE del texto visual de la celda
   (facturacion.js:6518, `copyBtn.dataset.token` — no lee `.textContent`). El valor
   funcional NO se toca aquí, solo la presentación de `<code>${t.token}</code>`
   (facturacion.js:1933).
   styles.css:2647-2654 YA declara un patrón real y existente para esto —
   `.fe-table code { display:inline-block; max-width:230px; overflow:hidden;
   text-overflow:ellipsis; ... }` — pero sin su propiedad compañera obligatoria
   `white-space:nowrap` (requisito del spec de CSS para que text-overflow:ellipsis
   tenga efecto visual consistente sobre una cadena sin puntos de quiebre como esta).
   Se completa ese mismo patrón ya existente (no se inventa uno nuevo ni se cambia el
   max-width real de 230px) agregando la propiedad que faltaba. Esto es el fallback
   "SOLO VISUALMENTE" que corresponde si, incluso con el container ampliado de esta
   etapa, la cadena de 32 caracteres sigue sin caber — el fix estructural primario para
   el scrollbar horizontal reportado es el ensanchado de `.container` (arriba), que
   ataca la causa real medida (exceso de 34px entre min-width:860px de la tabla y el
   wrapper de 826px), no el ancho del token en sí. `.fe-table code` no alcanza ninguna
   tabla de los módulos POS protegidos (ninguno usa `<code>` dentro de `.fe-table`,
   verificado) ni la tabla de Comprobantes (su render no usa `<code>`, verificado en
   facturacion.js) — el único lugar real donde este selector aplica es la celda TOKEN
   de Tokens API. Copiar/Eliminar (data-token/data-token-id/data-token-name/handlers)
   no se tocan. ============ */
.fe-table code {
  white-space: nowrap;
}

/* ============ COMPROBANTES — ETAPA 6, FILTROS (.fe-filters) ============
   Causa real confirmada: styles.css:2613-2614 fija `.fe-filters { grid-template-columns:
   repeat(6, minmax(0, 1fr)); }` — el mínimo EXPLÍCITO en 0 de cada track anula el mínimo
   automático de contenido de los items de grid, así que el track puede quedar más angosto
   que lo que su control realmente necesita. Con 6 tracks iguales (~124.6px medidos en el
   viewport auditado) los inputs type="date" (Desde/Hasta), que Chromium nunca renderiza
   por debajo de su mínimo nativo (~162px, medido), se desbordan de su track y se solapan
   con el siguiente campo (~21.46px medidos); Cliente, sin ningún track adicional, se queda
   sin espacio y trunca su placeholder ("RUC, DNI o nombre").
   Fix ESTRUCTURAL, no un ancho fijo por campo: Desde/Hasta reciben como mínimo el propio
   piso REAL medido de Chromium (162px, el mismo número de la auditoría, no uno inventado)
   dentro de minmax(162px, 1fr) — así nunca se desbordan pero sí pueden crecer. Tipo/Estado/
   Buscar quedan en minmax(0, 1fr) (sin mínimo especial: ningún control ahí tiene un piso
   nativo como el de <input type="date">). Cliente pasa a minmax(0, 2fr) — el doble de peso
   relativo que Tipo/Estado, sin fijar un px exacto, para darle "más espacio" tal como pide
   el brief sin adivinar un valor absoluto. NO son 6 columnas 1fr iguales.
   Aplica SOLO arriba del breakpoint móvil YA existente y real (styles.css:2724,
   `@media (max-width: 980px) { .fe-filters { grid-template-columns: 1fr; } }`) — se
   reutiliza ese mismo punto de corte (screen ≥981px) en vez de inventar uno nuevo; el
   colapso a 1 columna en móvil/tablet angosto NO se toca, sigue apilando correctamente.
   Scope: .fe-filters solo se usa en el DOM real en Comprobantes (verificado, único match
   en panel-v2-preview.html) — este bloque no alcanza Empresa/Certificado/Usuarios/POS
   landing aunque reutilicen .fe-form-grid/.form-control. Botón "Buscar": mismo patrón real
   de white-space:nowrap que #feNewTokenBtn arriba (styles.css:500), para que su texto
   tampoco pueda partirse al recibir un track más angosto que antes. Ningún handler/id/
   name/type/value/min/max de los campos se toca. ============ */
/* ============ COMPROBANTES — ETAPA 7, MÁS ANCHO SOLO PARA ESTA VISTA ============
   Auditoría real (viewport 1777px): .container (styles.css:93, `width: min(1180px,
   calc(100% - 34px))`) deja ~581px libres a los costados (290.56px izq + 306.44px der) —
   espacio real sin usar, no estimado. .fe-panel-shell (styles.css:4356-4358) es
   `grid-template-columns: 270px minmax(0, 1fr)`: el sidebar es un track de ANCHO FIJO
   (270px), así que ensanchar únicamente el .container que envuelve todo el
   .fe-dashboard-section (sidebar + contenido, ambos dentro del MISMO .container real)
   crece exclusivamente la columna de contenido (minmax(0,1fr)) — el sidebar no se mueve
   ni se ensancha, sigue alineado exactamente igual.
   PRINCIPIO reutilizado de body.fe-pos-fullscreen (styles.css:5086-5090, único patrón
   real ya existente de "container sin el límite normal de 1180px"): un selector de
   ESTADO que quita el límite del .container solo cuando corresponde — aquí, en vez de un
   ancho de body por JS (que tocaría facturacion.js, prohibido), se detecta el ESTADO real
   ya existente sin JS nuevo: la propia clase `.active` que facturacion.js YA aplica al
   panel de la pestaña abierta (facturacion.js:1087, `$('#fe-tab-${key}').classList.add
   ('active')` — comportamiento existente, no se toca), leída con `:has()` (soportado en
   Chromium, el motor real de este panel — mismo supuesto de motor ya usado en toda esta
   etapa para los mínimos nativos de <input type="date">).
   A diferencia de fe-pos-fullscreen (max-width:none — 100vw, edge-to-edge, expresamente
   NO deseado aquí: "no quiere que ocupe literalmente 100vw"), el cap numérico no se quita
   ni se inventa (nada de 1300/1400/1500px): se reutiliza 1320px, el MISMO valor real que
   ya existe en el ecosistema V2 como ancho de un contenido "ancho" (gratis-v2.css:51,
   `.gv2-section-inner { max-width: 1320px }`, la sección de directorio/grid real de
   Gratis). Se conserva la MISMA fórmula min()/gutter/centrado de styles.css:93 — solo
   cambia el cap de 1180 a ese 1320 real, y solo mientras Comprobantes esté activo. En
   viewports angostos, calc(100% - 34px) sigue dominando el min() igual que antes — el
   cambio de cap es estructuralmente inerte en móvil/tablet estrecho, sin necesitar una
   media query adicional. Scope: no alcanza Empresa/Certificado/Usuarios/POS
   landing (sus tabs no tienen `#fe-tab-comprobantes.active` ni `#fe-tab-tokens.active`
   como descendiente).
   ETAPA 8 — MISMO PATRÓN EXTENDIDO A TOKENS API: auditoría midió el mismo problema en
   Tokens (wrapper ~826px vs `.fe-table{min-width:860px}` real, exceso de ~34px →
   scrollbar horizontal), causado por el mismo `.container` legacy de 1180px. Se extiende
   la MISMA regla (no una nueva/paralela) agregando `#fe-tab-tokens.active` a la lista de
   `:has()` — `:has()` acepta una lista de selectores igual que `:is()`/`:where()`, así
   que esto sigue siendo UNA sola regla con el mismo cap 1320px real, no un valor nuevo.
   Empresa/Certificado/Usuarios/POS landing siguen sin match (ninguno de sus `<section>`
   activos es `#fe-tab-comprobantes` ni `#fe-tab-tokens`). ============ */
.fe-dashboard-section:has(#fe-tab-comprobantes.active, #fe-tab-tokens.active) > .container {
  width: min(1320px, calc(100% - 34px));
}

/* ============ COMPROBANTES — ETAPA 7, FILTROS (.fe-filters), AJUSTE FINAL ============
   La Etapa 6 protegió Desde/Hasta (piso real 162px) pero dejó Tipo/Estado/Buscar en
   `minmax(0, 1fr)` — el MISMO defecto estructural que causaba el desborde de fecha
   (mínimo EXPLÍCITO en 0 anula el mínimo automático de contenido del item de grid)
   seguía activo para esos tracks. Un <select> reserva espacio interno para su flecha
   nativa que getComputedStyle no refleja (confirmado en la auditoría de esta etapa), así
   que con track mínimo 0 el <select> puede quedar más angosto que su propio contenido
   ("Todos" + flecha) y recortarse visualmente. Fix: reemplazar el mínimo explícito 0 por
   `auto` en Tipo/Estado/Buscar — `auto` en la posición mínima de minmax() activa el
   "automatic minimum size" nativo del grid item (el mismo mecanismo de protección que ya
   usa el resto del sistema de grid sin declarar nada, y el mismo principio que el piso de
   162px le da a Desde/Hasta, pero derivado del propio control en vez de un px medido a
   mano) — el <select>/.btn nunca podrá quedar por debajo de su propio mínimo de
   contenido real, sin fijar un valor arbitrario. Cliente (texto libre, sin flecha nativa
   ni piso propio significativo) mantiene su ventaja proporcional de 2fr frente a Tipo/
   Estado (1fr) — el ancho extra real de esta etapa (container 1320 vs 1180) es lo que le
   da el espacio adicional que necesitaba para no truncar "RUC, DNI o nombre", no un
   cambio en su fr-weight (ya estaba en 2fr desde la Etapa 6). Sigue sin ser 6 columnas
   1fr iguales, y sigue aplicando solo arriba del breakpoint móvil real existente
   (styles.css:2724, ≥981px) — el colapso a 1 columna en móvil no se toca. ============ */
@media (min-width: 981px) {
  .fe-filters {
    grid-template-columns:
      minmax(162px, 1fr)
      minmax(162px, 1fr)
      minmax(auto, 1fr)
      minmax(auto, 2fr)
      minmax(auto, 1fr)
      minmax(auto, 1fr);
  }
}
.fe-filters .btn {
  white-space: nowrap;
}

/* ============ POS — SOLO EL LANDING DE 7 TARJETAS (.fe-pos-grid/.fe-pos-card,
   panel.html:391-429). NADA dentro de .fe-pos-module-view/.pos-admin-*/#fePosSales se
   toca — ningún selector de este bloque los alcanza. ============ */
#fePosHome .fe-pos-card {
  background: #fff; border: 1px solid var(--line); border-radius: 18px; box-shadow: none;
  transition: transform .2s ease, box-shadow .2s ease, border-color .2s ease;
}
#fePosHome .fe-pos-card:hover { transform: translateY(-3px); box-shadow: 0 16px 36px rgba(10,14,20,.08); border-color: rgba(192,254,4,.5); }
#fePosHome .fe-pos-card strong { color: var(--ink); font-family: var(--font-display); }
#fePosHome .fe-pos-card small { color: var(--muted); font-family: var(--font-mono); }
#fePosHome .fe-pos-card-icon { background: rgba(192,254,4,.14); border: 1px solid rgba(192,254,4,.4); }

/* ============ SEGURIDAD 320px — mismo fix ya aprobado en el resto del ecosistema V2. ============ */
@media (max-width: 400px) {
  .fe-client-topbar .fe-admin-subtitle { display: none; }
}

/* ============ ETAPA 9 — AISLAMIENTO DEL SHELL V2 DURANTE fe-pos-fullscreen ============
   Auditoría real: `body.fe-pos-fullscreen` es la clase real que `showSales()`
   (facturacion.js:2998-3022) agrega/quita al entrar/salir de Ventas (única acción real
   que la activa hoy — Productos/Categorías/Ingresos/Kardex/Movimientos/Reportes abren su
   `.fe-pos-module-view` embebida dentro del shell normal, sin tocar esta clase, así que
   no reproducen el bug reportado: no cubren pantalla completa, el header/sidebar
   alrededor de ellos ya era el comportamiento existente sin queja). styles.css:5080-5082
   ya oculta `.topbar` bajo esa clase (`body.fe-pos-fullscreen .topbar { display:none
   !important; }`) — pero `.topbar` ya NO existe en el DOM de este preview desde la
   Etapa 5 (el header real es `.pf-header.fe-client-topbar`), así que esa regla legacy
   nunca coincide aquí y el header V2 se queda visible encima del terminal POS. Se agrega
   el MISMO patrón (mismo selector de estado, mismo !important, mismo mecanismo) apuntando
   al selector real actual — se reutiliza `.fe-client-topbar` (la clase que YA convive en
   el mismo `<header>` junto a `.pf-header` desde la Etapa 5) en vez de `.pf-header`,
   porque es el nombre que ya tenía esta regla equivalente y evita cualquier colisión
   futura si `.pf-header` llegara a usarse para otra cosa. Sidebar NO se toca (ya se oculta
   correctamente vía `#feSideMenu`/`.fe-panel-shell.fe-pos-fullscreen-shell` reales,
   confirmado en styles.css:5091-5099) — nada dentro de Ventas/Productos/Categorías/
   Ingresos/Kardex/Movimientos/Reportes se modifica, el fix vive enteramente en el shell. */
body.fe-pos-fullscreen .fe-client-topbar {
  display: none !important;
}

/* ============ ETAPA 9 — INDICADOR LATERAL V2 OCULTO EN fe-pos-fullscreen ============
   El indicador (#pfScrollIndicator, id real insertado por facturacion-internal-v2-
   scroll.js — mismo id/markup que site-smooth-scroll.js usa en el sitio público) solo
   actualiza su opacity dentro del handler `lenis.on('scroll', ...)`; `lenis.stop()` (que
   el controlador dedicado llama al entrar a fe-pos-fullscreen) detiene el loop de avance
   pero NO dispara ese evento por sí solo, así que la opacity quedaría congelada en el
   valor que tenía justo antes de entrar al POS en vez de ocultarse. Se fuerza aquí,
   scoped al mismo estado real ya usado en todo este archivo, sin tocar geometría/color
   del indicador (eso vive intacto en site-scroll-indicator.css, sin tocar). */
body.fe-pos-fullscreen #pfScrollIndicator {
  display: none !important;
}

/* ============ COMPROBANTES — TABLA EN UNA SOLA LÍNEA ============
   Las celdas (Geist Mono) hacían wrap dentro de una tabla fija al 100% del wrapper: "2026-09-/25", "FC01-/1",
   "S//6.20", el chip "Anulado por/NC" y "XML · PDF · CDR ·/NOTA DE CRÉDITO". Solo presentación, scope
   #fe-tab-comprobantes (Tokens y el resto de .fe-table sin cambios):
   - celdas, chips de estado y enlaces de archivos: nowrap (unidades indivisibles);
   - la tabla toma el ancho de su contenido (max-content) y nunca menos que el wrapper (min-width:100%);
   - mientras Comprobantes está activo el contenedor usa hasta 1760px (misma fórmula min()/gutter que la regla
     1320px de arriba; el sidebar de 270px no cambia);
   - si aun así no entra (tablet/móvil o desktop angosto), .fe-table-wrap ya tiene overflow-x:auto -> scroll
     horizontal dentro de la tarjeta, nunca celdas partidas. */
.fe-dashboard-section:has(#fe-tab-comprobantes.active) > .container {
  width: min(1760px, calc(100% - 34px));
}
#fe-tab-comprobantes .fe-table {
  width: max-content;
  min-width: 100%;
}
#fe-tab-comprobantes .fe-table th,
#fe-tab-comprobantes .fe-table td,
#fe-tab-comprobantes .fe-table .fe-pill,
#fe-tab-comprobantes .fe-table .fe-doc-download {
  white-space: nowrap;
}
/* Padding horizontal algo menor SOLO en esta tabla (13px -> 10px): con nowrap la tabla mide ~985px y en laptops de
   1366px (wrapper ~962px) eso dejaba un scroll horizontal de ~23px; así entra completa. Vertical sin cambios. */
#fe-tab-comprobantes .fe-table th,
#fe-tab-comprobantes .fe-table td {
  padding-left: 10px;
  padding-right: 10px;
}
