/* deploy-hash: 20260523T172500 */

/* =====================================================
   SHELL.CSS — Paleta de Obra (modo claro)
   Topbar + sidebar + auth pages, todo pensado para
   legibilidad bajo sol caribeño.
   ===================================================== */

/* =====================================================
   SHELL LAYOUT
   ===================================================== */
.shell {
  /* Altura del topbar, centralizada: la usan la fila del grid (spacer), el
     propio topbar (fixed) y el offset sticky de #trial-banners. Mobile la
     baja a 56px (ver media query). */
  --topbar-h: 60px;
  display: grid;
  grid-template-columns: 240px 1fr;
  /* Fila "banners" (auto) entre topbar y content: los avisos de prueba viven
     ahí. Sin avisos, auto colapsa a 0px. Antes #trial-banners (hijo del grid
     sin área) caía en una fila implícita al fondo, sobre la bottom nav. */
  grid-template-rows: var(--topbar-h) auto 1fr;
  grid-template-areas:
    "topbar  topbar"
    "banners banners"
    "sidebar content";
  min-height: 100dvh;
  width: 100%;
  max-width: 100vw;
  /* OJO: no poner overflow-x:hidden aquí. Por spec, overflow-x≠visible obliga a
     overflow-y a computar `auto` → .shell se vuelve un scroll container que NO
     scrollea (lo hace el body) → rompe el `position:sticky` del sidebar. El
     recorte horizontal vive en .shell-content (min-width:0 + overflow-x:hidden). */
}
/* Modifier para páginas full-width sin sidebar (ej. /modules, /upgrade,
   onboarding). El grid colapsa a 1 columna; el content ocupa toda la
   superficie. La topbar mantiene el sticky behavior y dropdown. */
.shell.shell--no-sidebar {
  grid-template-columns: 1fr;
  grid-template-areas:
    "topbar"
    "banners"
    "content";
}
/* Contenedor de avisos de prueba (countdown de trial), inyectado por auth.js.
   Ocupa su fila propia full-width bajo la topbar (no cae sobre la bottom nav).
   z-index 9: bajo la topbar (10), loader (50), modales (80), toast (100). */
#trial-banners {
  grid-area: banners;
  position: sticky;
  top: var(--topbar-h);
  z-index: 9;
  display: flex;
  flex-direction: column;
}

/* ===== TOPBAR ===== */
.shell-topbar {
  grid-area: topbar;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 24px;
  background: var(--bg-elev);
  border-bottom: 1px solid var(--border);
  box-shadow: var(--shadow-sm);
  /* Congelado (fixed, NO sticky): un grid item sticky cuya área == su propia
     altura no tiene recorrido y se va con el scroll (por eso "no se congelaba").
     Fixed lo ancla al viewport; la fila topbar del grid (var(--topbar-h)) queda
     como spacer que reserva su espacio. El body sigue siendo el scroller, así
     que el scroll-lock de modales (ui.js) y los stickies de fondo no cambian. */
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  height: var(--topbar-h);
  z-index: 10;
}
.shell-topbar-brand {
  font-size: 16px;
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--text);
  display: flex;
  align-items: center;
  gap: 12px;
}

/* Brand lockup — render estructurado del nombre de la app en dos palabras
   con tipografía y colores del logo Mabrick (primera palabra navy bold,
   segunda palabra naranja regular). Lo aplica brand.js a [data-brand] cuando
   el span vive junto a un .shell-brand-mark (topbar, auth pages, approval).
   Para nombres de 1 o 3+ palabras vuelve a texto plano. */
.brand-lockup {
  display: inline-flex;
  align-items: baseline;
  gap: 4px;
  text-transform: uppercase;
  letter-spacing: -0.01em;
  line-height: 1;
  /* Hereda font-size del contenedor (.shell-topbar-brand=16px, .ap-brand-name=14px, etc.) */
}
.brand-lockup .brand-word--primary {
  color: #1A2547;            /* navy del logo */
  font-weight: 900;
}
.brand-lockup .brand-word--accent {
  color: #EA580C;            /* orange del logo */
  font-weight: 400;
}

/* Brand mark — contenedor base.
   Estado inicial: vacío (placeholder neutro mientras JS resuelve el variant
   correcto). Antes pintábamos el diamond default desde aquí, pero eso causaba
   FOUC: al navegar de página se veía el diamond por unos ms antes de aparecer
   el emoji del módulo o el logo del Hub. Ahora el diamond va en su propio
   modifier (.shell-brand-mark--diamond) que JS aplica explícitamente.
   Para minimizar el "salto", páginas con body[data-module] ya muestran el
   tinte gris del cuadrito del módulo desde el CSS (sin esperar JS).
   Tamaño 40x40 unificado desktop+mobile para hacer pareja con el engranaje
   de config y dar identidad visual prominente. */
.shell-brand-mark {
  width: 40px;
  height: 40px;
  border-radius: 9px;
  background: transparent;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  position: relative;
  /* Reset cuando se usa como <a> (link clickeable a /): hereda sin
     underline, color del texto del topbar, y cursor pointer. Hover
     sutil para indicar que es interactivo sin distraer del módulo. */
  text-decoration: none;
  color: inherit;
  cursor: pointer;
  transition: transform 0.15s ease, box-shadow 0.15s ease;
}
a.shell-brand-mark:hover { transform: translateY(-1px); }
a.shell-brand-mark:active { transform: translateY(0); }
a.shell-brand-mark:focus-visible {
  outline: 2px solid var(--amber);
  outline-offset: 2px;
}
.shell-brand-mark::after {
  content: '';
  display: none;          /* solo visible vía .shell-brand-mark--diamond */
  width: 15px; height: 15px;
  background: var(--text);
  border-radius: 2px;
  transform: rotate(45deg);
}

/* Variante: diamond default — cuadrado amarillo Caterpillar con diamante
   azul plano. Se aplica desde brand.js cuando la página es global y NO hay
   logo del Hub subido. */
.shell-brand-mark--diamond {
  background: var(--amber);
  box-shadow: 0 2px 6px rgba(234, 179, 8, 0.4), inset 0 1px 0 rgba(255, 255, 255, 0.3);
}
.shell-brand-mark--diamond::after { display: block; }

/* Placeholder del cuadrito de módulo aplicado desde el HTML — para que al
   navegar a /caja/* ya se vea el tinte gris correcto antes de que JS
   inyecte el emoji. Sin esto, había flash blanco al cambiar de página. */
body[data-module] .shell-brand-mark {
  background: var(--bg-soft);
  box-shadow: inset 0 0 0 1px var(--border);
}

/* Placeholder pre-JS en /config/* — coherente con cómo se ve el logo
   del Hub mientras carga en otras páginas: cuadrito blanco con sombra
   sutil. Cuando JS resuelve, aplica --org-logo (mismo estilo + imagen)
   o --placeholder (gris con "LOGO" cuando la empresa no tiene logo
   subido). El :not() evita competir con los modifiers de JS. */
body[data-page="config"] .shell-brand-mark:not([class*="shell-brand-mark--"]) {
  background-color: var(--bg-elev);
  box-shadow: 0 2px 6px rgba(15, 23, 42, 0.12), inset 0 0 0 1px rgba(15, 23, 42, 0.04);
}
/* Variante: logo del app (Hub) — subido por super admin desde /admin/marca.html.
   Reemplaza el diamond default cuando platform_config.app_logo_url está seteado.
   Se aplica en TODAS las páginas globales (Hub, admin, config, login, modules,
   upgrade, perfil, onboarding). NO se aplica en páginas de módulos (ahí va
   el emoji del catálogo via .shell-brand-mark--module).
   Sin fondo ni padding: el PNG subido (la M Mabrick transparente) se renderiza
   edge-to-edge sobre el topbar. Antes pintábamos un squircle blanco protector
   para PNGs sin fondo propio, pero el activo de marca actual lleva su propia
   transparencia. */
.shell-brand-mark--logo-app {
  background-color: transparent;
  background-size: contain;
  background-position: center;
  background-repeat: no-repeat;
}
.shell-brand-mark--logo-app::after { display: none; }

/* Variante: emoji del módulo del catálogo — body[data-module="caja-chica"] etc.
   Tinte suave neutro para no competir con el color de marca de la empresa. */
.shell-brand-mark--module {
  background: var(--bg-soft);
  box-shadow: inset 0 0 0 1px var(--border);
  font-size: 22px;
  line-height: 1;
  font-family: 'Apple Color Emoji', 'Segoe UI Emoji', 'Noto Color Emoji', sans-serif;
}
.shell-brand-mark--module::after { display: none; }

/* Compat legacy: en sesiones anteriores el brand-mark mostraba el logo de
   empresa. Esa clase ya no se aplica (org-shell limpió), pero algún HTML
   en cache podría tenerla. Tratarla como logo-app por seguridad. */
.shell-brand-mark--logo {
  background-color: var(--bg-elev);
  background-size: contain;
  background-position: center;
  background-repeat: no-repeat;
  padding: 3px;
  box-shadow: 0 2px 6px rgba(15, 23, 42, 0.12), inset 0 0 0 1px rgba(15, 23, 42, 0.04);
}
.shell-brand-mark--logo::after { display: none; }

/* Variante: logo de la EMPRESA ACTIVA — solo se aplica en /config/* donde
   el contexto es configurar la empresa. Excepción consciente a la regla
   "logo empresa solo en reportes". No se aplica en otras páginas. */
.shell-brand-mark--org-logo {
  background-color: var(--bg-elev);
  background-size: contain;
  background-position: center;
  background-repeat: no-repeat;
  padding: 3px;
  box-shadow: 0 2px 6px rgba(15, 23, 42, 0.12), inset 0 0 0 1px rgba(15, 23, 42, 0.04);
}
.shell-brand-mark--org-logo::after { display: none; }

/* Placeholder cuando se intenta mostrar el logo de la empresa activa pero
   la empresa no lo tiene subido aún. Cuadrito con label "LOGO" en gris. */
.shell-brand-mark--placeholder {
  background: var(--bg-soft);
  box-shadow: inset 0 0 0 1.5px var(--border-strong);
  font-size: 9px;
  font-weight: 800;
  letter-spacing: 0.12em;
  color: var(--text3);
  text-transform: uppercase;
  line-height: 1;
}
.shell-brand-mark--placeholder::after { display: none; }

.shell-org-switcher {
  display: flex;
  align-items: center;
  gap: 10px;
}
.shell-org-name {
  font-size: 13px;
  font-weight: 600;
  color: var(--text);
  padding: 8px 14px 8px 12px;
  background: var(--bg-soft);
  border: 1px solid var(--border);
  border-radius: 100px;
  cursor: pointer;
  user-select: none;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  white-space: nowrap;
  transition: all 0.12s ease;
}

/* Back-arrow del topbar — utilitario (acción secundaria de navegación).
   Sin background ni border para no competir con el cuadrito del módulo
   que es la identidad visual principal. Tap area 40x40 Apple-compliant,
   hover muestra fondo sutil. Reemplaza el <a> con style inline que vivía
   repetido en cada HTML con back-arrow.
   Uso:
     <a href="/" class="shell-back-btn" aria-label="Volver al Hub">
       <svg ...><path d="M15 18l-6-6 6-6"/></svg>
     </a>
*/
.shell-back-btn {
  width: 40px;
  height: 40px;
  border-radius: 100px;
  background: transparent;
  border: 0;
  color: var(--text2);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  margin-left: -10px;
  text-decoration: none;
  transition: all 0.12s ease;
  cursor: pointer;
}
.shell-back-btn:hover {
  background: var(--bg-soft);
  color: var(--text);
}
.shell-back-btn:active {
  background: var(--border);
  transform: scale(0.92);
}
/* Ícono CENTRALIZADO: el botón "volver al Hub" muestra una CASA (home), que
   comunica la acción real (ir al inicio) mejor que el chevron "‹" (que sugiere
   "atrás"). El SVG inline del chevron que traen las 30 páginas queda oculto y el
   ícono se pinta aquí con mask + currentColor → respeta color/hover y lo heredan
   todas las páginas (actuales y futuras) sin editar cada HTML. */
.shell-back-btn svg { display: none; }
.shell-back-btn::before {
  content: "";
  width: 30px; height: 30px;
  background-color: currentColor;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z'/%3E%3C/svg%3E") center / contain no-repeat;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z'/%3E%3C/svg%3E") center / contain no-repeat;
}

/* Nombre del contexto activo en el topbar — módulo ("Caja Chica") o
   página global ("Mabrick Hub", "Panel", "Empresas", etc.).
   Tamaño 20px para hacer pareja con el brand mark 40x40. Aplica a todos
   los textos del topbar de forma homogénea (módulos y páginas globales).
   En mobile el .shell-module-name se oculta para liberar espacio al pill;
   el [data-brand] del Hub se reduce levemente a 19px. */
.shell-module-name,
.shell-topbar-brand [data-brand],
.shell-topbar-brand > span:not(.shell-brand-mark):not(.shell-page-icon):not(.sa-pill) {
  font-size: 20px;
  font-weight: 700;
  color: var(--text);
  letter-spacing: -0.01em;
}

/* Icono engranaje del título — solo en mobile. En desktop el texto
   "Configuración" se ve normal (regla mobile lo cambia). */
.shell-page-icon { display: none; }
.shell-org-name::after {
  content: '';
  width: 0; height: 0;
  border-left: 4px solid transparent;
  border-right: 4px solid transparent;
  border-top: 5px solid var(--text2);
}
.shell-org-name:hover {
  background: var(--bg-elev);
  border-color: var(--border-strong);
}

.shell-user-menu {
  width: 40px;
  height: 40px;
  border-radius: 10px;
  background: var(--bg-soft);
  border: 1px solid var(--border);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 16px;
  color: var(--text2);
  cursor: pointer;
  transition: all 0.12s ease;
}
.shell-user-menu:hover {
  background: var(--bg-elev);
  color: var(--text);
  border-color: var(--border-strong);
}

/* ===== SIDEBAR ===== */
.shell-sidebar {
  grid-area: sidebar;
  background: var(--bg-elev);
  border-right: 1px solid var(--border);
  padding: 20px 14px;
  display: flex;
  flex-direction: column;
  gap: 3px;
  overflow-y: auto;
  /* Congelado en desktop: el sidebar es un grid item cuya área (fila content,
     1fr) es tan alta como el contenido → un sticky con altura propia (no
     estirada) tiene recorrido y se queda fijo al hacer scroll. align-self:start
     evita el stretch; height = viewport−topbar mantiene el divisor a toda
     altura y deja que el nav scrollee solo si no cabe. El body sigue siendo el
     scroller (no rompe el scroll-lock de modales). Mobile lo revierte (bottom
     bar fija, ver media query). */
  position: sticky;
  top: var(--topbar-h);
  align-self: start;
  height: calc(100dvh - var(--topbar-h));
}

.shell-nav-item {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 12px;
  border-radius: 8px;
  color: var(--text2);
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  text-decoration: none;
  user-select: none;
  white-space: nowrap;
  transition: all 0.1s ease;
  position: relative;
}
.shell-nav-item:hover {
  background: var(--bg-soft);
  color: var(--text);
}
/* Hover «elevado» — coherente con el lenguaje de cards (.lift-card): el nombre de
   la página se levanta + sombra suave + barra ámbar tenue (eco del item activo).
   Gateado a hover:hover para que en touch no quede pegado tras el tap. */
@media (hover: hover) and (pointer: fine) {
  .shell-nav-item:hover {
    transform: translateY(-1px);
    box-shadow: 0 4px 10px -4px hsl(222deg 39% 18% / .18);
  }
  .shell-nav-item:not(.active):hover::before {
    content: '';
    position: absolute;
    left: -14px; top: 8px; bottom: 8px;
    width: 3px;
    background: var(--amber);
    border-radius: 0 3px 3px 0;
    opacity: .5;
  }
}
/* Badge de alerta en un item del nav (ej. Avance con responsables atrasados) */
.shell-nav-item .nav-alert {
  margin-left: auto;
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 18px; height: 18px; padding: 0 5px;
  border-radius: 100px; background: var(--red, #DC2626); color: #fff;
  font-family: var(--mono); font-size: 11px; font-weight: 800; line-height: 1;
}
.shell-nav-item.active {
  background: var(--amber-soft);
  color: var(--text);
  font-weight: 700;
}
.shell-nav-item.active::before {
  content: '';
  position: absolute;
  left: -14px;
  top: 6px;
  bottom: 6px;
  width: 3px;
  background: var(--amber);
  border-radius: 0 3px 3px 0;
}
.shell-nav-item svg {
  width: 18px;
  height: 18px;
  flex-shrink: 0;
  opacity: 0.9;
}
.shell-nav-item.active svg {
  opacity: 1;
  color: var(--amber-deep);
}

/* Items de nav admin-only (ej. "Usuarios" de Caja/Personal): ocultos por
   default y revelados SOLO cuando <html> tiene .org-admin. La clase la setea
   auth-gate.js pre-paint (desde cache del último rol conocido de la org
   activa) y la reconcilia org-shell.js tras confirmar el rol. Antes el item
   arrancaba con style="display:none" inline y se revelaba tras 2 round-trips
   async (isPlatformAdmin + memberships) → parpadeo visible en cada carga para
   owners/admins. Con el reveal por clase desde cache, la pestaña se pinta en
   el primer frame: cero flicker. data-admin-only vive siempre en un
   .shell-nav-item, así que display:flex es el valor correcto al revelar. */
.shell-nav-item[data-admin-only] { display: none; }
html.org-admin .shell-nav-item[data-admin-only],
html.org-gerente .shell-nav-item[data-admin-only] { display: flex; }

/* data-orgadmin-only: SOLO Dueño/Administrador (o SA) — NO el gerente de obra.
   A diferencia de data-admin-only (que sí revela al gerente para el item
   "Usuarios" del módulo), la Configuración de empresa es exclusiva de
   owner/admin. Por eso se revela únicamente con html.org-admin. */
.shell-nav-item[data-orgadmin-only],
.shell-nav-section[data-orgadmin-only] { display: none; }
html.org-admin .shell-nav-item[data-orgadmin-only] { display: flex; }
html.org-admin .shell-nav-section[data-orgadmin-only] { display: block; }

/* Guía in-app: el Super Admin puede ocultar el enlace "Guía" a ciertos roles
   (config global guide_role_visibility). org-shell.js pone html.guide-hidden
   cuando el rol del usuario NO está habilitado → se oculta cualquier enlace a
   /guia/ (dropdown del topbar, perfil, etc.). Falla-abierta: sin la clase, visible. */
html.guide-hidden a[href="/guia/"],
html.guide-hidden a[href="/guia/index.html"] { display: none !important; }

/* Ítem "Guía" inyectado al final del menú de cada módulo (org-shell.js,
   injectModuleGuideLink). En desktop se ancla al fondo del sidebar (flex column);
   respeta la misma visibilidad por rol que el resto de enlaces a la guía. */
.shell-sidebar .shell-guide-link { margin-top: auto; }
html.guide-hidden .shell-guide-link { display: none !important; }

/* RESALTAR la Guía: ícono + texto en el naranja del Hub (--orange, el mismo del
   brand-mark). Se colorea por DESTINO (cualquier ítem de nav que apunte a /guia/)
   → lo heredan tanto el ítem del HUB (estático en index.html) como el inyectado en
   cada módulo (.shell-guide-link). Los demás ítems son gris → la Guía sobresale sin
   fondo cargado. Igual en sidebar desktop y bottom-bar móvil. Joel 2026-06-27. */
.shell-sidebar .shell-nav-item[href^="/guia/"] { color: var(--orange); font-weight: 700; }
.shell-sidebar .shell-nav-item[href^="/guia/"] svg { color: var(--orange); opacity: 1; }
.shell-sidebar .shell-nav-item[href^="/guia/"]:hover { color: var(--orange-deep); background: var(--orange-soft); }
.shell-sidebar .shell-nav-item[href^="/guia/"]:hover svg { color: var(--orange-deep); }

/* Panel (Super Admin del HUB): ícono + palabra en el ROJO de "Cerrar sesión"
   (--red, mismo patrón danger del logout) para que NO se confunda con los ítems
   normales del sidebar y se lea como acceso especial. Acotado al ítem del Hub vía
   [data-sa-only] para NO pintar el "Dashboard" de las páginas /admin/*. Joel 2026-06-27. */
.shell-sidebar .shell-nav-item[data-sa-only][href="/admin/"] { color: var(--red); }
.shell-sidebar .shell-nav-item[data-sa-only][href="/admin/"] svg { color: var(--red); opacity: 1; }
.shell-sidebar .shell-nav-item[data-sa-only][href="/admin/"]:hover { background: var(--red-soft); }

.shell-nav-section {
  font-size: 10px;
  font-weight: 700;
  color: var(--text3);
  text-transform: uppercase;
  letter-spacing: 0.1em;
  padding: 18px 12px 8px;
}

/* Spacer + divider + variante --logout para el bottom bar mobile de
   /admin/*. Solo aplican en mobile porque ahí el pill empresa se oculta
   (body[data-page="admin"] .shell-org-switcher display:none, ver media
   query abajo) y el dropdown del topbar deja de ser accesible. En
   desktop el dropdown del pill sigue siendo el único acceso al logout,
   tal como en /caja/, /config/, etc. — el bloque queda inerte. */
.shell-nav-spacer,
.shell-nav-divider,
.shell-nav-item--logout { display: none; }

/* Wrapper #sidebar-modules — display:contents para que los <a> hijos
   sean tratados como hijos directos del .shell-sidebar (flex/grid
   container). Sin esto, en mobile bottom-bar los items dinámicos
   quedaban apilados verticalmente dentro de un mismo slot del flex
   row → se veían en 2 filas en el pill flotante. */
#sidebar-modules { display: contents; }

/* Items dinámicos de módulos en el sidebar: emoji + label. En desktop
   se ven ambos (mismo look que los hardcoded SVG + texto). En mobile
   bottom-bar el label se oculta (ver media query). */
.bottom-nav-emoji {
  width: 24px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 18px;
  line-height: 1;
  flex-shrink: 0;
  font-family: 'Apple Color Emoji', 'Segoe UI Emoji', 'Noto Color Emoji', sans-serif;
}
/* Iconos SVG de módulo (F2.7) dentro del brand mark (topbar) y del nav móvil:
   tamaño fijo por CSS (el contenedor del nav es width:auto → un % no sirve). */
.shell-brand-mark svg { width: 24px; height: 24px; display: block; }
.bottom-nav-emoji svg { width: 22px; height: 22px; display: block; }

/* Sidebar de ESCRITORIO: el glifo de módulo (.bottom-nav-emoji) traía una caja
   de 24px (svg 22) mientras los <svg> directos del nav son 18px → el texto de
   Caja/Personal arrancaba 6px más a la derecha que el resto. Igualamos la caja
   del glifo a 18px (como los demás) para que TODOS los íconos compartan eje y
   las etiquetas arranquen en la misma vertical. Solo desktop: el bottom-nav
   móvil (@media max-width:768) conserva su tamaño. */
@media (min-width: 769px) {
  .shell-sidebar .shell-nav-item > .bottom-nav-emoji { width: 18px; }
  .shell-sidebar .shell-nav-item > .bottom-nav-emoji > svg { width: 18px; height: 18px; }
}

.shell-content {
  grid-area: content;
  padding: 28px 32px;
  overflow-y: auto;
  /* min-width:0 evita el "grid blowout" (el track 1fr tiene min-width:auto =
     min-content y un elemento ancho lo empujaría más allá del viewport). El
     recorte horizontal vive aquí, no en .shell (ver nota arriba). */
  min-width: 0;
  overflow-x: hidden;
}

/* =====================================================
   RESPONSIVE — mobile: sidebar se vuelve bottom bar flotante
   ===================================================== */
@media (max-width: 768px) {
  .shell {
    /* topbar 56px en mobile → grid-rows, altura del topbar fixed y offset del
       aviso (#trial-banners top:var(--topbar-h)) siguen este valor solo. */
    --topbar-h: 56px;
    grid-template-columns: 1fr;
    /* misma fila "banners" que en desktop: si no, los avisos caerían en fila
       implícita al fondo, sobre la bottom bar flotante (bug original). */
    grid-template-rows: var(--topbar-h) auto 1fr;
    grid-template-areas:
      "topbar"
      "banners"
      "content";
  }
  .shell-topbar { padding: 0 16px; gap: 10px; }
  .shell-topbar-brand { gap: 10px; min-width: 0; }
  /* Texto del nombre en mobile:
     - En MÓDULOS (/caja/*, futuros) se oculta: el emoji ya identifica
       el módulo y libera espacio para el pill empresa.
     - En el Hub y otras páginas globales, el texto se queda visible
       al tamaño base 20px (la app es ya legible en desktop y mobile).
     - Si el pill no entra, comportamiento por data-page (ver más abajo).
  */
  .shell-module-name { display: none; }
  /* Pill empresa — comportamiento por página (mobile):
     · Hub (data-page=hub):    nunca trunca. Expande libremente
     · Modules (data-page=modules): se expande hasta el texto "Módulos"; si
       sobrepasa, trunca con ellipsis (comportamiento natural flex)
     · Admin (data-page=admin): se OCULTA el pill (cross-empresa, no aplica)
     · Config (data-page=config): se reemplaza el texto por icono engranaje
     · Resto: trunca con ellipsis si no entra (default seguro) */
  .shell-org-name .shell-org-name-text {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 0;
  }
  body[data-page="hub"] .shell-org-name {
    flex-shrink: 0;       /* no se comprime, expande libremente */
    max-width: none;
  }
  body[data-page="modules"] .shell-org-name {
    flex-shrink: 1;       /* se reduce cuando topa con el título */
    min-width: 0;
  }
  body[data-page="admin"] .shell-org-switcher {
    display: none;        /* cross-empresa: el SA no necesita ver una empresa específica */
  }

  /* Icono engranaje como título de /config/* solo en mobile. En desktop
     se ve el texto "Configuración" como antes. Mismo tamaño que el
     brand mark (40x40) pero sin recuadro/background — solo el SVG en
     color text2. */
  .shell-page-icon {
    width: 40px;
    height: 40px;
    color: var(--text2);
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }
  .shell-page-icon svg {
    width: 100%;
    height: 100%;
  }
  /* Pill empresa: más legible, sin truncate. Se queda el dropdown principal
     del Hub — debe sentirse prominente y completo. */
  .shell-org-name {
    padding: 9px 16px 9px 14px;
    font-size: 14px;
    font-weight: 600;
  }
  .shell-user-menu { width: 38px; height: 38px; font-size: 15px; }
  /* Bottom bar flotante. Out of grid (position: fixed). Respeta safe-area
     del home indicator iOS para no chocar con el gesture nativo de switch
     entre apps. Pill style con sombra para que se vea separada del fondo
     y siempre visible aunque el content scrollee. */
  .shell-sidebar {
    grid-area: unset;
    /* Reset del sticky/altura desktop: aquí es bottom bar flotante (thin row). */
    top: auto;
    height: auto;
    align-self: auto;
    position: fixed;
    left: 10px;
    right: 10px;
    bottom: calc(env(safe-area-inset-bottom, 0px) + 10px);
    /* z-index 40: debajo del loader (50), modales (80) y toast (100) */
    z-index: 40;
    flex-direction: row;
    overflow-x: auto;
    overflow-y: hidden;
    border: 1px solid rgba(226, 232, 240, 0.6);
    border-radius: 100px;
    padding: 6px 8px;
    gap: 4px;
    /* SIN backdrop-filter: en iOS un position:fixed + backdrop-filter hace que la barra
       salte a media pantalla y quede pegada hasta reiniciar la app (bug WebKit conocido).
       Fondo casi sólido (tinte cemento) → sigue leyéndose como pill flotante. */
    background: rgba(241, 245, 249, 0.97);
    box-shadow:
      0 12px 28px rgba(15, 23, 42, 0.10),
      0 4px 10px rgba(15, 23, 42, 0.05);
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    padding: 7px 10px;
    gap: 10px;
  }
  .shell-sidebar::-webkit-scrollbar { display: none; }
  /* Headers de sección = etiquetas del sidebar DESKTOP; en el bottom bar mobile
     NUNCA van. !important para ganarle a la regla global de revelado por rol
     (`html.org-admin .shell-nav-section[data-orgadmin-only]{display:block}`, de
     mayor especificidad) que, si no, colaba "Configuración" en la barra inferior
     del Dueño/Admin en móvil. Invariante: ningún header de sección en mobile. */
  .shell-nav-section { display: none !important; }
  .shell-nav-item {
    padding: 11px 16px;
    font-size: 12.5px;
    font-weight: 600;
    flex-shrink: 0;
    border-radius: 100px;
  }
  .shell-nav-item.active::before { display: none; }
  .shell-nav-item.active {
    background: var(--amber);
    color: var(--text);
  }
  /* Items dinámicos de módulos en bottom bar mobile: 40x40 fijos con
     emoji centrado, sin background visible. Entre dos emojis vecinos
     el ojo ve gap(10) + 9px (padding interno hacia el emoji centrado)
     a cada lado = 28px. Entre un pill con bg visible (Resumen/Catálogo)
     y el emoji invisible, solo es gap(10) + 9px = 19px → asimétrico.
     Fix: margin-left/right en el primer/último dinámico para compensar
     los 9px que "le faltan" al lado del pill visible. */
  #sidebar-modules .shell-nav-item {
    width: 40px;
    height: 40px;
    padding: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }
  /* Solo separación extra entre el primer hardcoded (Resumen) y el
     primer item dinámico. Sin tocar el último item. */
  #sidebar-modules .shell-nav-item:first-child { margin-left: 9px; }
  #sidebar-modules .bottom-nav-emoji { font-size: 22px; line-height: 1; width: auto; }
  #sidebar-modules .bottom-nav-label { display: none; }

  /* Logout en bottom bar mobile: divider vertical sutil + ítem 40x40
     icon-only (sin texto). Mismo tamaño que los emojis dinámicos para
     respetar tap target Apple HIG. Reset de defaults del <button> para
     que no traiga background/border/font del browser. */
  .shell-nav-divider {
    display: block;
    width: 1px;
    height: auto;
    background: rgba(15, 23, 42, 0.15);
    margin: 6px 2px;
    flex-shrink: 0;
  }
  .shell-nav-item--logout {
    display: inline-flex;
    width: 40px;
    height: 40px;
    padding: 0;
    align-items: center;
    justify-content: center;
    background: transparent;
    border: 0;
    font: inherit;
    color: var(--text2);
    cursor: pointer;
    flex-shrink: 0;
  }
  .shell-nav-item--logout:hover { color: var(--red); }
  .shell-nav-item--logout span { display: none; }
  .shell-nav-item--logout svg { width: 18px; height: 18px; opacity: 0.85; }

  .shell-content {
    padding: 20px 18px;
    /* Espacio inferior = altura de la bar flotante + margen + safe-area
       para que el último elemento no quede tapado por la bar fija. */
    padding-bottom: calc(env(safe-area-inset-bottom, 0px) + 90px);
  }
}

/* =====================================================
   AUTH PAGES — login, onboarding, callback
   ===================================================== */
.auth-page {
  min-height: 100dvh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  background: var(--bg);
  position: relative;
}

/* Background pattern sutil para diferenciar de pantalla blanca pura
   (líneas técnicas tipo blueprint, muy discretas) */
.auth-page::before {
  content: '';
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(rgba(15, 23, 42, 0.025) 1px, transparent 1px),
    linear-gradient(90deg, rgba(15, 23, 42, 0.025) 1px, transparent 1px);
  background-size: 32px 32px;
  pointer-events: none;
}

.auth-box {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: 400px;
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  padding: 36px 32px;
  box-shadow: var(--shadow-lg);
}
.auth-brand {
  font-size: 24px;
  font-weight: 700;
  letter-spacing: -0.02em;
  color: var(--text);
  margin-bottom: 6px;
  display: flex;
  align-items: center;
  gap: 12px;
}
.auth-brand .shell-brand-mark {
  width: 32px;
  height: 32px;
  border-radius: 8px;
}
.auth-brand .shell-brand-mark::after {
  width: 13px;
  height: 13px;
}
.auth-sub {
  font-size: 13.5px;
  color: var(--text2);
  font-weight: 500;
  margin-bottom: 28px;
  line-height: 1.5;
}

/* Variants para auth-brand sin icon (compatibility) */
.auth-brand-text-only {
  text-align: center;
  display: block;
  font-size: 26px;
  margin-bottom: 8px;
}
.auth-sub-center {
  text-align: center;
}

/* =====================================================
   TOPBAR DROPDOWN (org switcher + config + logout)
   ===================================================== */
.topbar-dropdown {
  position: fixed;
  z-index: 70;
  min-width: 240px;
  max-width: 320px;
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: 12px;
  box-shadow: 0 16px 36px rgba(15, 23, 42, 0.14), 0 4px 12px rgba(15, 23, 42, 0.06);
  padding: 6px;
  opacity: 0;
  transform: translateY(-6px) scale(0.97);
  pointer-events: none;
  transition: opacity 0.12s, transform 0.12s;
}
.topbar-dropdown.show {
  opacity: 1;
  transform: translateY(0) scale(1);
  pointer-events: auto;
}
.topbar-dropdown-header {
  padding: 10px 12px 12px;
  border-bottom: 1px solid var(--border);
  margin-bottom: 6px;
}
.topbar-dropdown-org {
  font-size: 14px;
  font-weight: 700;
  color: var(--text);
  line-height: 1.3;
  word-break: break-word;
}
.topbar-dropdown-rnc {
  font-size: 11.5px;
  font-weight: 600;
  font-family: var(--mono);
  color: var(--text3);
  margin-top: 4px;
  letter-spacing: 0.02em;
}
.topbar-dropdown-section-label {
  font-size: 10px;
  font-weight: 700;
  color: var(--text3);
  text-transform: uppercase;
  letter-spacing: 0.1em;
  padding: 8px 12px 4px;
}
.topbar-dropdown-item {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 9px 12px;
  border-radius: 8px;
  background: transparent;
  border: 0;
  font: inherit;
  font-size: 13.5px;
  font-weight: 600;
  color: var(--text);
  cursor: pointer;
  text-align: left;
  text-decoration: none;
  transition: background 0.1s;
}
.topbar-dropdown-item:hover,
.topbar-dropdown-item:focus-visible {
  background: var(--bg-soft);
  outline: none;
}
.topbar-dropdown-item svg {
  width: 16px;
  height: 16px;
  color: var(--text3);
  flex-shrink: 0;
}
.topbar-dropdown-item:hover svg { color: var(--text2); }
.topbar-dropdown-item--danger { color: var(--red); }
.topbar-dropdown-item--danger svg { color: var(--red); opacity: 0.8; }
.topbar-dropdown-item--danger:hover { background: var(--red-soft); }

/* Empresa activa: tipografía marcada + check ámbar, no clickeable */
.topbar-dropdown-item--active {
  cursor: default;
  color: var(--text);
  font-weight: 800;
  background: var(--bg-soft);
}
.topbar-dropdown-item--active:hover { background: var(--bg-soft); }
.topbar-dropdown-item--active svg { color: var(--amber); }
.topbar-dropdown-badge {
  margin-left: auto;
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--amber);
  background: var(--amber-soft);
  border: 1px solid rgba(245, 158, 11, 0.35);
  padding: 2px 7px;
  border-radius: 100px;
}

/* Super Admin: acento distinto (verde azulado) para diferenciar del resto */
.topbar-dropdown-item--sa {
  color: #0e7490;
  font-weight: 700;
}
.topbar-dropdown-item--sa svg { color: #0e7490; }
.topbar-dropdown-item--sa:hover { background: rgba(14, 116, 144, 0.08); }
.topbar-dropdown-item--sa:hover svg { color: #0e7490; }

.topbar-dropdown-divider {
  height: 1px;
  background: var(--border);
  margin: 6px 4px;
}

/* ===== Banner de vista de soporte (super admin) ===== */
.support-view-banner {
  position: sticky;
  top: 0;
  left: 0;
  right: 0;
  z-index: 150;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 16px;
  background: linear-gradient(90deg, #fef3c7, #fde68a);
  border-bottom: 1px solid rgba(146, 64, 14, 0.25);
  color: #78350f;
  font-size: 13px;
  font-weight: 600;
  box-shadow: 0 1px 0 rgba(0,0,0,0.04);
}
.support-view-banner-icon svg {
  width: 16px;
  height: 16px;
  color: #b45309;
  display: block;
}
.support-view-banner-text {
  flex: 1;
  min-width: 0;
}
.support-view-banner-text strong { font-weight: 800; }
.support-view-banner-exit {
  background: rgba(146, 64, 14, 0.85);
  color: #fff;
  border: 0;
  border-radius: 100px;
  font: inherit;
  font-size: 12px;
  font-weight: 700;
  padding: 5px 14px;
  cursor: pointer;
  transition: background 0.1s;
}
.support-view-banner-exit:hover { background: #78350f; }
/* En vista de soporte (SA) el banner sticky (z-150, hijo de body, antes de
   .shell) ocupa el top:0; si el topbar quedara fixed top:0 colisionarían.
   Revertimos el topbar a sticky en ese modo: conserva el comportamiento
   actual exacto (el banner manda arriba). Edge case SA, transitorio. */
body.has-support-banner .shell-topbar { position: sticky; top: 0; }
@media (max-width: 600px) {
  .support-view-banner { font-size: 12px; padding: 8px 12px; }
  .support-view-banner-text { line-height: 1.3; }
}

/* =====================================================
   SUPER ADMIN MODAL (sa-modal-*)
   =====================================================
   Modal del panel admin, usado en /admin/usuarios y
   /admin/seguridad para detalles de user, confirmar
   delete, rechazar solicitud, etc.

   !important + z-index altísimo defensivo: garantiza
   que quede sobre cualquier ancestor con transform/
   contain/will-change que pudiera romper position:fixed.
   ===================================================== */
.sa-modal-overlay {
  position: fixed !important;
  inset: 0 !important;
  background: rgba(28, 25, 23, 0.55);
  backdrop-filter: blur(2px);
  z-index: 9999 !important;
  display: flex; align-items: center; justify-content: center;
  padding: 16px;
  overflow-y: auto;
}
.sa-modal-overlay.hidden { display: none; }
.sa-modal {
  background: var(--bg-elev);
  border-radius: var(--r);
  box-shadow: 0 25px 50px -12px rgba(0,0,0,0.25);
  width: 100%; max-width: 540px;
  max-height: 90vh;
  display: flex; flex-direction: column;
}
.sa-modal-header {
  padding: 16px 20px;
  border-bottom: 1px solid var(--border);
  display: flex; align-items: center; justify-content: space-between;
}
.sa-modal-header h2 { margin: 0; font-size: 16px; font-weight: 800; }
.sa-modal-close {
  background: transparent; border: 0; font-size: 22px;
  color: var(--text3); cursor: pointer; padding: 0;
  width: 32px; height: 32px;
  display: flex; align-items: center; justify-content: center;
  border-radius: 8px;
}
.sa-modal-close:hover { background: var(--bg-soft); color: var(--text); }
.sa-modal-body { padding: 18px 20px; overflow-y: auto; }
.sa-modal-footer {
  padding: 16px 22px;
  border-top: 1px solid var(--border);
  display: flex; gap: 12px; justify-content: flex-end;
}
/* Override del .btn { width: 100% } global — en el footer del modal los
   botones son auto-width alineados a la derecha, no full-width apilados. */
.sa-modal-footer .btn { width: auto; min-width: 110px; }
