/* Droguería Garzón — tema compartido del portal (Fase 3, IA Aplicada) */
/* Reescrito con tokens verificados del Material 3 Design Kit oficial de Figma (Community),
   extraídos vía Figma MCP de los componentes reales Text field (52798:24373) y Button
   (57994:2227): colores de rol (on-surface, on-surface-variant, outline, surface), shape
   (botones pill 100px, inputs outlined 4px) — la tipografía original del kit era Roboto, con
   los tracking exactos; reemplazada por Figtree en toda la plataforma el 2026-08-31 tras probar
   varias opciones en preview (Poppins, DM Sans, Figtree), tracking/spacing sin ajustar.
   Celeste de marca (#0069B4) reemplaza el "primary" morado (#6750A4) del seed color default.
   Los botones usan padding compactado respecto al spec (24px/16px) para no romper tablas
   densas — el shape/color sí son fieles al componente real. */

@import url('https://fonts.googleapis.com/css2?family=Google+Sans+Flex:opsz,wght@6..144,100..1000&display=swap');
@import url('https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200&display=swap');

:root{
  --dg-blue: #0069B4;              /* M3 primary (sustituye #6750A4) */
  --dg-blue-dark: #004C80;         /* hover/pressed de primary */
  --dg-blue-light: rgba(0,105,180,0.16); /* pill "seleccionado" de sidebar/tabs, fiel al rgba(66,133,244,0.3) real de Gmail */
  --dg-blue-tint: #EAF1FB;         /* mismo tono de fondo que la search bar de Gmail (#eaf1fb) */
  --dg-navy: #035793;              /* decorativo de marca, no es un token M3 puntual */
  --dg-navy-deep: #023D69;

  --dg-bg: #F6F8FC;                /* fondo general Y de la sidebar (mismo tono, sin línea divisoria — spec real de Gmail) */
  --dg-bg-hover: #F2F6F7;          /* fondo de fila "leída" en listas, spec real de Gmail (frame 1:48) */
  --dg-hover-strong: #E3E8F0;      /* hover con contraste real sobre --dg-bg (ej. sidebar) — --dg-bg-hover casi no se distingue ahí */
  --dg-surface: #FFFFFF;           /* M3/sys/light/surface real es #FEF7FF (tinte cálido) — probado y revertido a blanco puro:
                                       el resto de la paleta (--dg-bg, --dg-bg-hover, --dg-blue-tint) es azul/fría a propósito
                                       (spec de Gmail), y mezclar un tono cálido de M3 ahí generaba un fondo turbio, sin
                                       contraste limpio. Regla: no se puede tomar un token de M3 aislado sin chequear que
                                       coordine con el resto de la paleta ya establecida. */
  --dg-outline: #79747E;           /* M3/sys/light/outline (verificado) */
  --dg-outline-variant: #CAC4D0;   /* M3/sys/light/outline-variant (verificado) — bordes sutiles (chips, dividers) */
  --dg-surface-container-low: #F7F2FA;  /* M3/sys/light/surface-container-low real — NO USAR para fondos grandes por el mismo
                                            motivo que --dg-surface arriba (choca con la paleta azul). Queda documentado por
                                            si hace falta en un contexto aislado, pero el Menu ya no lo usa (ver abajo). */
  --dg-secondary-container: #E8DEF8;    /* M3/sys/light/secondary-container (verificado) — chip seleccionado */
  --dg-on-secondary-container: #4A4459; /* M3/sys/light/on-secondary-container (verificado) */

  /* ---------- Prueba (2026-08-27): sidebar "sin soporte" + contenido sobre superficie blanca,
     estilo M3 Expressive — tokens sacados vía Figma MCP del kit de referencia (seed morado
     original #6750A4, sin reemplazar por el celeste de marca como el resto de la paleta de
     arriba). Uso acotado a punto: solo .dg-shell/.dg-sidebar/.dg-main, no toca --dg-blue ni
     ningún botón/badge/link existente. Fácil de buscar y revertir por el prefijo -m3x-. */
  /* 2026-08-27: reemplazado el lavanda del kit por el celeste de marca — reusa --dg-blue-tint
     (ya calibrado, mismo tono que la search bar de Gmail) en vez de un tercer tono nuevo. */
  --dg-m3x-page-bg: var(--dg-blue-tint);
  --dg-m3x-primary: #6750A4;            /* M3/sys/light/primary, seed original del kit — sin uso por ahora */
  --dg-m3x-primary-container: #EADDFF;  /* sin uso — la píldora activa volvió a los tonos celestes de marca, ver .dg-sidebar-link.active */
  --dg-m3x-on-primary-container: #4F378A; /* M3/sys/light/on-primary-container */
  --dg-border: #ededed;            /* hairline real de Gmail entre filas de lista (frame 1:48/1:50) — no para cards */
  --dg-text: #1D1B20;              /* M3/sys/light/on-surface (verificado) */
  --dg-text-muted: #49454F;        /* M3/sys/light/on-surface-variant (verificado) */
  --dg-text-soft: #79747E;         /* = outline, reutilizado para texto muy tenue */

  /* M3 Elevation — verificado vía Figma MCP (kit oficial, node 50732:11519 "Light"). Cada nivel son
     DOS sombras superpuestas (key + ambient), no una difusa sola como tenía antes. Card = Elevation 1
     (superficie en reposo). Pop (menús/dropdowns) = Elevation 3 (mismo nivel que Dialogs en el spec). */
  --dg-shadow-card: 0px 1px 2px 0px rgba(0,0,0,0.3), 0px 1px 3px 1px rgba(0,0,0,0.15); /* Elevation 1 */
  --dg-shadow-pop: 0px 1px 3px 0px rgba(0,0,0,0.3), 0px 4px 8px 3px rgba(0,0,0,0.15); /* Elevation 3 */

  --dg-crit-bg: #F9DEDC;   --dg-crit-text: #B3261E;  --dg-crit-border: #F3C6C6; /* M3/sys/light/error-container + error (verificado, corregido de #FCE9E9) */
  --dg-warn-bg: #FDF1E3;   --dg-warn-text: #B5651D;  --dg-warn-border: #F3DBB9; /* sin rol M3 estándar — "warning" no existe en el scheme base, agregado a criterio */
  --dg-ok-bg: #E7F5EC;     --dg-ok-text: #1E7A46;    --dg-ok-border: #BFE6CE;   /* ídem — sin rol "success" en M3 base */
  --dg-info-bg: #E6F1FB;   --dg-info-text: #0C447C;  --dg-info-border: #B5D4F4; /* ídem — sin rol "info" en M3 base */

  /* Motion — set completo de easings reales, leídos del código fuente oficial de
     @material/web (internal/motion/animation.ts) el 2026-08-26, no aproximados a ojo. */
  --dg-ease-standard: cubic-bezier(0.2, 0, 0, 1);
  --dg-ease-standard-accel: cubic-bezier(0.3, 0, 1, 1);
  --dg-ease-standard-decel: cubic-bezier(0, 0, 0, 1);
  --dg-ease-emphasized: cubic-bezier(0.3, 0, 0, 1);
  --dg-ease-emphasized-accel: cubic-bezier(0.3, 0, 0.8, 0.15);
  --dg-ease-emphasized-decel: cubic-bezier(0.05, 0.7, 0.1, 1);
  /* "Spring" — no es una aproximación nuestra: es la curva real que usa el switch de
     @material/web para el desplazamiento del thumb (switch/internal/_handle.scss,
     transition: margin 300ms cubic-bezier(0.175,0.885,0.32,1.275)) — el único lugar del
     código fuente de Google donde vimos overshoot real (pasa de 1.0 antes de asentar). La
     reusamos acá para el feedback de press en botones/chips/ítems interactivos. */
  --dg-ease-spring: cubic-bezier(0.175, 0.885, 0.32, 1.275);
}

/* ---------- Dark mode — PRUEBA, 2026-09-02 ----------
   Prendida solo con [data-theme="dark"] en <html> (hoy solo storybook.html tiene el toggle) —
   no hay @media (prefers-color-scheme) todavía, para no cambiarle el tema a nadie sin que lo
   pida. Redefine los mismos nombres de token que :root de arriba; como casi todos los componentes
   ya se apoyan en var(--dg-*) en vez de hex sueltos, con esto alcanza para repintar el sistema
   entero sin tocar cada .html — los pocos hex sueltos que quedan (blanco sobre botón celeste,
   por ejemplo) siguen leyéndose bien en los dos modos porque son texto sobre un color de marca,
   no sobre la superficie. Paleta M3-dark: mismo celeste de marca pero aclarado para contraste
   sobre fondo oscuro (el #0069B4 original pierde legibilidad ahí), semánticos (crítico/warning/
   ok/info) con el patrón fondo-oscuro-desaturado + texto-claro-saturado en vez del inverso. */
[data-theme="dark"]{
  --dg-blue: #7FC1FF;
  --dg-blue-dark: #A8D6FF;
  --dg-blue-light: rgba(127,193,255,0.18);
  --dg-blue-tint: #16232E;
  --dg-navy: #6BB3E8;
  --dg-navy-deep: #4A8DC2;

  --dg-bg: #10141A;
  --dg-bg-hover: #1B2129;
  --dg-hover-strong: #242C36;
  --dg-surface: #171C23;
  --dg-outline: #8D9199;
  --dg-outline-variant: #3A4149;
  --dg-surface-container-low: #1B2129;
  --dg-secondary-container: #332D41;
  --dg-on-secondary-container: #E4DAF3;

  --dg-m3x-page-bg: var(--dg-blue-tint);
  --dg-m3x-primary: #C9B7F5;
  --dg-m3x-primary-container: #4A3F6B;
  --dg-m3x-on-primary-container: #E9DFFC;
  --dg-border: #262C33;
  --dg-text: #E7E9EC;
  --dg-text-muted: #C0C4CC;
  --dg-text-soft: #8D9199;

  --dg-shadow-card: 0px 1px 2px 0px rgba(0,0,0,0.55), 0px 1px 3px 1px rgba(0,0,0,0.4);
  --dg-shadow-pop: 0px 1px 3px 0px rgba(0,0,0,0.55), 0px 4px 8px 3px rgba(0,0,0,0.4);

  --dg-crit-bg: #3A2224;   --dg-crit-text: #FFB4AB;  --dg-crit-border: #5C2D2D;
  --dg-warn-bg: #3A2E1A;   --dg-warn-text: #FFD599;  --dg-warn-border: #5C4526;
  --dg-ok-bg: #17301F;     --dg-ok-text: #8FD9A8;    --dg-ok-border: #2A4A34;
  --dg-info-bg: #16232E;   --dg-info-text: #9CC7F0;  --dg-info-border: #294357;
}

/* ---------- Escala tipográfica M3 (verificada vía Figma MCP, kit oficial Material 3 Design Kit —
   Community, node 58186:19244 "typescale") ---------- */
.dg-display-l{ font-family:'Google Sans Flex',sans-serif; font-weight:400; font-size:57px; line-height:64px; letter-spacing:-0.25px; }
.dg-display-m{ font-family:'Google Sans Flex',sans-serif; font-weight:400; font-size:45px; line-height:52px; letter-spacing:0; }
.dg-display-s{ font-family:'Google Sans Flex',sans-serif; font-weight:400; font-size:36px; line-height:44px; letter-spacing:0; }
.dg-headline-l{ font-family:'Google Sans Flex',sans-serif; font-weight:400; font-size:32px; line-height:40px; letter-spacing:0; }
.dg-headline-m{ font-family:'Google Sans Flex',sans-serif; font-weight:400; font-size:28px; line-height:36px; letter-spacing:0; }
.dg-headline-s{ font-family:'Google Sans Flex',sans-serif; font-weight:400; font-size:24px; line-height:32px; letter-spacing:0; }
.dg-title-l{ font-family:'Google Sans Flex',sans-serif; font-weight:400; font-size:22px; line-height:28px; letter-spacing:0; }
.dg-title-m{ font-family:'Google Sans Flex',sans-serif; font-weight:500; font-size:16px; line-height:24px; letter-spacing:0.15px; }
.dg-title-s{ font-family:'Google Sans Flex',sans-serif; font-weight:500; font-size:14px; line-height:20px; letter-spacing:0.1px; }
.dg-body-l{ font-family:'Google Sans Flex',sans-serif; font-weight:400; font-size:16px; line-height:24px; letter-spacing:0.5px; }
.dg-body-m{ font-family:'Google Sans Flex',sans-serif; font-weight:400; font-size:14px; line-height:20px; letter-spacing:0.25px; }
.dg-body-s{ font-family:'Google Sans Flex',sans-serif; font-weight:400; font-size:12px; line-height:16px; letter-spacing:0.4px; }
.dg-label-l{ font-family:'Google Sans Flex',sans-serif; font-weight:500; font-size:14px; line-height:20px; letter-spacing:0.1px; }
.dg-label-m{ font-family:'Google Sans Flex',sans-serif; font-weight:500; font-size:12px; line-height:16px; letter-spacing:0.5px; }
.dg-label-s{ font-family:'Google Sans Flex',sans-serif; font-weight:500; font-size:11px; line-height:16px; letter-spacing:0.5px; }

/* Texto de ayuda/estado vacío (2026-09-16) — se usaba en varias pantallas (viajes.html,
   conductor-detalle.html) sin estar nunca definida acá, solo copiada a mano una vez en
   conductor-detalle.html — el resto caía al estilo por defecto del navegador (bug real
   reportado: texto grande y sin el cuerpo que corresponde). Queda centralizada en el tema
   compartido para que cualquier página que la use se vea igual. */
.info-vacio{ font-family:'Google Sans Flex',sans-serif; font-size:12.5px; color: var(--dg-text-soft); line-height:1.55; }

/* ---------- List (baseline) M3 — verificado vía Figma MCP (kit oficial, node 51964:62995).
   56px de alto, padding 16px/8px, gap 16px, avatar leading 40px (Title Medium), texto Body Large,
   color de marca (--dg-blue) en vez del primary morado default del kit. ---------- */
/* Lista — Expressive (2026-08-25): contenedor tonal agrupado (radio grande, fondo
   --dg-blue-tint) con los ítems como bloques blancos internos de radio chico, primero/último
   heredan el radio del contenedor — mismo patrón real encontrado en material-expressive-react
   (mer-list: contenedor + --mer-list-item-radius chico + esquinas del primer/último ítem
   redondeadas al radio del contenedor). Reemplaza el divider de línea entre ítems por el gap
   entre bloques. */
.dg-list{ display:flex; flex-direction:column; width:100%; background: var(--dg-blue-tint); border-radius:20px; padding:6px; gap:2px; }
.dg-list-item{
  display:flex; align-items:center; gap:16px; min-height:56px; width:100%;
  padding:8px 16px; border-radius:6px; background: var(--dg-surface);
  transition: background .15s var(--dg-ease-standard);
}
.dg-list-item:first-child{ border-top-left-radius:16px; border-top-right-radius:16px; }
.dg-list-item:last-child{ border-bottom-left-radius:16px; border-bottom-right-radius:16px; }
.dg-list-item.clickable{ cursor:pointer; }
.dg-list-item:hover{ background: var(--dg-bg-hover); }
.dg-list-item.selected:hover{ background: var(--dg-blue); }
.dg-list-item.selected{ background: var(--dg-blue); }
.dg-list-item.selected .dg-list-headline, .dg-list-item.selected .dg-list-trailing{ color:#fff; }
.dg-list-item.selected .dg-list-supporting{ color: rgba(255,255,255,0.75); }
.dg-list-item .dg-list-avatar{
  width:40px; height:40px; border-radius:100px; background: var(--dg-blue-tint); color: var(--dg-navy-deep);
  display:flex; align-items:center; justify-content:center; flex-shrink:0;
  font-family:'Google Sans Flex',sans-serif; font-weight:500; font-size:16px; line-height:24px; letter-spacing:0.15px;
}
.dg-list-item .dg-list-content{ flex:1; min-width:0; display:flex; flex-direction:column; justify-content:center; }
/* Peso 700 (2026-08-25, dirección Expressive) — sobrepisa el peso 500 "Label Large" que
   habíamos corregido según el código fuente oficial de @material/web. Decisión consciente:
   Expressive privilegia tipografía más pesada en los puntos de énfasis (mer-list real usa
   font-weight:650) por sobre el default no-Expressive de Google. Tamaño/tracking de Label
   Large (14px/0.1) se mantienen, solo cambia el peso. */
/* Sin ".dg-list-item" adelante (2026-09-02) — las mismas dos clases se usan también sueltas
   dentro de una celda de .dg-table (ej. columna "Conductor" en home-logistica.html/usuarios.html),
   donde no hay ningún ancestro .dg-list-item; sin esta versión no escopeada, nombre y mail
   heredaban el mismo estilo de <td> y no había jerarquía visible entre los dos renglones. */
.dg-list-headline{
  font-family:'Google Sans Flex',sans-serif; font-weight:700; font-size:14px; line-height:20px; letter-spacing:0.1px;
  color: var(--dg-text); overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}
.dg-list-supporting{
  font-family:'Google Sans Flex',sans-serif; font-weight:400; font-size:12.5px; line-height:18px; letter-spacing:0.25px;
  color: var(--dg-text-muted); overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}
.dg-list-item .dg-list-trailing{
  flex-shrink:0; font-family:'Google Sans Flex',sans-serif; font-weight:700; font-size:14px; line-height:20px; letter-spacing:0.1px;
  color: var(--dg-blue); white-space:nowrap;
}

/* ---------- Filter chip M3 — verificado vía Figma MCP (kit oficial, node 53923:28270).
   Uso correcto según spec M3: para sets CHICOS de opciones (5-8) — ej. "Hoy / Esta semana / Este mes".
   Para listas largas (decenas de vendedores/proveedores) el componente correcto sigue siendo Select,
   no chips — no forzar esto donde no corresponde. ---------- */
.dg-chip-row{ display:flex; gap:8px; flex-wrap:wrap; }
/* Chip — Expressive (2026-08-25): pill completo (100px, antes 8px), peso 600, seleccionado
   con azul de marca sólido (antes secondary-container morado del kit M3 base). */
.dg-chip{
  display:inline-flex; align-items:center; justify-content:center; height:36px; padding:8px 18px;
  border-radius:100px; border:1px solid var(--dg-outline-variant); background:none; cursor:pointer;
  font-family:'Google Sans Flex',sans-serif; font-weight:600; font-size:14px; line-height:20px; letter-spacing:0.1px;
  color: var(--dg-text-muted); transition: background .15s var(--dg-ease-standard), transform .15s var(--dg-ease-spring);
}
.dg-chip:hover{ background: var(--dg-bg-hover); }
.dg-chip:active{ transform: scale(0.96); }
.dg-chip.selected{ border-color:transparent; background: var(--dg-blue); color:#fff; }

/* ---------- Text field M3, uso simple (sin label flotante) — mismo spec verificado que .auth-field
   (node 52798:24373/24397), para inputs sueltos como buscadores donde no hace falta el label que
   corta el borde. Style=Outlined, Text configurations=Placeholder text. ---------- */
/* Expressive (2026-08-25): pill completo (100px, antes 4px) para buscadores/filtros del
   dashboard — NO para .auth-field (login/registro), que mantiene el outlined spec real con
   label flotante tal cual, sin tocar. */
/* 2026-09-15: mismo alto que .dg-select-filtro (14px/9px de padding/línea de 20px) — antes
   .dg-text-field usaba el spec M3 más grande (16px/16px de padding) y quedaba visiblemente más
   alto al lado de un select de filtro en la misma fila (buscadores de viajes.html, etc.),
   pedido explícito de emparejarlos. */
.dg-text-field{
  width:100%; font-family:'Google Sans Flex',sans-serif; font-size:14px; line-height:20px; letter-spacing:0.1px; font-weight:400;
  padding:9px 20px; border:1.5px solid var(--dg-outline); border-radius:100px;
  background: transparent; color: var(--dg-text);
}
.dg-text-field:focus{ outline:none; border:2px solid var(--dg-blue); padding:8.5px 19.5px; }
.dg-text-field::placeholder{ color: var(--dg-text-muted); opacity:0.7; }

/* Select de filtro — un <select> nativo no puede restylearse por dentro (el menú desplegable lo
   pinta el navegador), pero el contenedor cerrado sí puede seguir el mismo spec de Text field. */
/* appearance:none + chevron SVG propio (2026-08-25) — el <select> nativo dibujaba su propia
   flecha cuadrada, pegada al borde, que no combinaba con la píldora redondeada. Mismo patrón
   que .role-picker (chevron a 10px del borde, ícono on-surface-variant). */
.dg-select-filtro{
  appearance:none; -webkit-appearance:none; -moz-appearance:none;
  font-family:'Google Sans Flex',sans-serif; font-size:14px; line-height:20px; font-weight:600; letter-spacing:0.1px;
  padding:9px 34px 9px 16px; border-radius:100px; border:1.5px solid var(--dg-outline);
  background: var(--dg-surface) url("data:image/svg+xml;charset=UTF-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='18' height='18'%3E%3Cpath fill='%2349454F' d='M7 10l5 5 5-5z'/%3E%3C/svg%3E") no-repeat right 12px center;
  color: var(--dg-text); cursor:pointer;
}
.dg-select-filtro:focus{ outline:none; border:2px solid var(--dg-blue); padding:8.5px 33.5px 8.5px 15.5px; }

*{ box-sizing: border-box; }

body{
  margin:0;
  font-family: 'Google Sans Flex', sans-serif;
  background: var(--dg-bg);
  color: var(--dg-text);
  -webkit-font-smoothing: antialiased;
}

a{ text-decoration:none; color:inherit; }

img{ max-width:100%; display:block; }

.material-symbols-outlined{
  font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 24;
  font-size: 20px; line-height:1; display:inline-block; vertical-align:middle;
}

/* ---------- topbar + marketing header ---------- */

.dg-topbar{ height:6px; background: linear-gradient(90deg, var(--dg-navy), var(--dg-blue)); }

header.dg-header{
  background:var(--dg-surface);
  display:flex;
  align-items:center;
  justify-content:center;
  padding: clamp(16px, 3vw, 24px) clamp(16px, 4vw, 48px);
  box-shadow: 0 1px 0 rgba(0,0,0,0.06);
  flex-wrap:wrap;
  gap:12px;
}
.dg-brand{ display:flex; align-items:center; gap:12px; }
.dg-brand img{ height:64px; }

nav.dg-nav{ display:flex; align-items:center; gap: clamp(10px, 2vw, 26px); flex-wrap:wrap; }
nav.dg-nav a{ color: var(--dg-text); font-weight:700; font-size:12.5px; letter-spacing:0.3px; }
nav.dg-nav a.cta{ background: var(--dg-blue); color:#fff; padding:9px 20px; border-radius:100px; font-weight:700; }
nav.dg-nav a.back{ color: var(--dg-blue); font-weight:700; font-size:12.5px; display:inline-flex; align-items:center; gap:6px; }

/* ---------- hero ---------- */

.dg-hero{ max-width:900px; margin:0 auto; padding: clamp(28px,5vw,56px) clamp(16px,4vw,24px) 8px; text-align:center; }
.dg-eyebrow{ display:inline-block; background: var(--dg-blue-light); color: var(--dg-blue); font-weight:700; font-size:11px; letter-spacing:1.4px; padding:6px 16px; border-radius:100px; margin-bottom:16px; }
.dg-hero h1{ font-size: clamp(20px, 4vw, 30px); font-weight:700; color: var(--dg-navy); margin:0 0 12px; line-height:1.3; }
.dg-hero p{ max-width:600px; margin:0 auto; color: var(--dg-text-muted); font-size:14px; line-height:1.7; }

/* ---------- cards grid ---------- */

.dg-grid{ max-width:1100px; margin: 32px auto 56px; padding: 0 clamp(16px,4vw,32px); display:grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: clamp(14px,2vw,22px); }
.dg-card{ background: var(--dg-blue); border-radius:16px; padding: clamp(20px,3vw,28px); color:#fff; display:flex; flex-direction:column; gap:12px; transition: background .2s ease, transform .2s ease; }
.dg-card:hover{ background: var(--dg-blue-dark); transform: translateY(-3px); }
.dg-card .dg-icon{ width:46px; height:46px; border-radius:50%; border:2px solid rgba(255,255,255,0.55); display:flex; align-items:center; justify-content:center; flex-shrink:0; }
.dg-card .dg-icon svg{ width:22px; height:22px; }
.dg-card .dg-tag{ font-size:10.5px; font-weight:700; letter-spacing:1.2px; color: rgba(255,255,255,0.75); }
.dg-card h3{ margin:0; font-size:17px; font-weight:700; }
.dg-card p{ margin:0; font-size:12.5px; line-height:1.65; color: rgba(255,255,255,0.85); }
.dg-card .dg-stat{ font-size:11.5px; font-weight:700; color:#fff; background: rgba(255,255,255,0.16); display:inline-block; padding:5px 13px; border-radius:100px; width:fit-content; }
.dg-card .dg-go{ margin-top:4px; display:inline-flex; align-items:center; gap:6px; background:var(--dg-surface); color: var(--dg-blue); font-weight:700; font-size:12px; letter-spacing:0.3px; padding:9px 18px; border-radius:100px; width:fit-content; }
.dg-go-btn{ margin-top:4px; display:inline-flex; align-items:center; gap:6px; background:var(--dg-surface); color: var(--dg-blue); font-weight:700; font-size:12px; letter-spacing:0.3px; padding:9px 18px; border-radius:100px; width:fit-content; }

/* ---------- grid/cards compactas (portal autenticado) ---------- */

.dg-grid-compact{ max-width:900px; margin: 24px auto 48px; }
.dg-card-compact{ padding: clamp(18px,2.5vw,22px); gap:10px; text-align:center; align-items:center; }
.dg-card-compact .dg-icon{ margin: 0 auto; }
.dg-card-compact h3{ font-size:15px; }

/* ---------- footer ---------- */

footer.dg-footer{ background: var(--dg-navy); color:#fff; padding: 28px clamp(16px,4vw,32px) 22px; display:flex; justify-content:space-between; flex-wrap:wrap; gap:18px; }
footer.dg-footer .dg-brand-foot{ display:flex; align-items:center; gap:8px; }
footer.dg-footer .dg-brand-foot img{ height:24px; filter: brightness(0) invert(1); }
footer.dg-footer .dg-brand-foot span{ font-weight:700; font-size:12.5px; }
footer.dg-footer p{ max-width:300px; font-size:11.5px; color: rgba(255,255,255,0.75); line-height:1.6; margin: 10px 0 0; }
.dg-note{ font-size:10.5px; color: rgba(255,255,255,0.55); }

/* ---------- app shell (used by the 4 module mockups) ---------- */

.app-topbar{ background: var(--dg-bg); display:flex; align-items:center; justify-content:space-between; padding: 12px clamp(16px,3vw,28px); border-bottom:none; flex-wrap:wrap; gap:10px; }
.app-topbar .app-title{ display:flex; align-items:center; gap:12px; }
.app-topbar .app-title .dot{ width:10px; height:10px; border-radius:50%; background: var(--dg-blue); }
.app-topbar .app-title h2{ margin:0; font-size:15px; font-weight:700; color: var(--dg-navy); }
.app-topbar .app-title span{ font-size:11px; color: var(--dg-text-muted); font-weight:400; }

.app-body{ max-width:1180px; margin:0 auto; padding: clamp(16px,3vw,28px); }

.kpi-row{ display:grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap:14px; margin-bottom:20px; }
/* Dirección "Expressive" (2026-08-25): borde fino en vez de sombra dura, radio más grande,
   tipografía de énfasis más pesada — inspirado en material-expressive-react, aprobado por Julio
   sobre una comparación antes/después de todos los componentes. .kpi-card.accent es el modificador
   opcional para destacar el KPI principal de una fila (fondo azul sólido, texto blanco). */
.kpi-card{ background: var(--dg-surface); border:1px solid var(--dg-border); box-shadow:none; border-radius:20px; padding:16px 18px; transition: border-color .2s var(--dg-ease-standard); }
.kpi-card .label{ font-size:11.5px; color: var(--dg-text-muted); font-weight:600; text-transform:uppercase; letter-spacing:0.03em; margin-bottom:6px; }
.kpi-card .value{ font-size: clamp(20px, 3vw, 24px); font-weight:800; color: var(--dg-text); }
.kpi-card .delta{ font-size:11.5px; font-weight:700; margin-top:4px; }
.kpi-card .delta.up{ color: var(--dg-ok-text); }
.kpi-card .delta.down{ color: var(--dg-crit-text); }
.kpi-card.accent{ background: var(--dg-blue); border-color: var(--dg-blue); }
.kpi-card.accent .label{ color: rgba(255,255,255,0.8); }
.kpi-card.accent .value{ color:#fff; }

.panel{ background: var(--dg-surface); border:1px solid var(--dg-border); box-shadow:none; border-radius:20px; padding: clamp(16px,2.5vw,22px); margin-bottom:18px; }
.panel .panel-head{ display:flex; align-items:center; justify-content:space-between; margin-bottom:16px; flex-wrap:wrap; gap:10px; }
.panel .panel-head h3{ margin:0; font-size:14.5px; font-weight:700; color: var(--dg-text); }

.filter-bar{ display:flex; flex-wrap:wrap; gap:10px; align-items:center; }
.filter-bar select, .filter-bar input{
  font-family:'Google Sans Flex', sans-serif; font-size:12.5px; padding:9px 14px; border-radius:100px; border:none; background: var(--dg-blue-tint); color: var(--dg-text);
}

/* ---------- Button — dirección "Expressive" (2026-08-25): peso 700 (antes 500), padding más
   generoso, y feedback de press con leve "hundimiento" (scale + easing spring) en vez de un
   cambio de color seco. Shape pill 100px se mantiene (ya era fiel al spec real del kit). ---------- */
.btn-primary{ background: var(--dg-blue); color:#fff; border:none; font-weight:700; font-size:14px; letter-spacing:0.15px; padding:12px 24px; border-radius:100px; cursor:pointer; display:inline-flex; align-items:center; gap:8px; transition: background .15s var(--dg-ease-standard), transform .15s var(--dg-ease-spring); }
/* Variante destructiva — botón "Confirmar" de dgConfirm() cuando la acción borra algo. */
.btn-primary.dg-btn-crit{ background: var(--dg-crit-text); }
.btn-primary.dg-btn-crit:hover{ background: #8f1f19; }
.btn-primary.dg-btn-ok{ background: var(--dg-ok-text); }
.btn-primary.dg-btn-ok:hover{ background: #145c33; }
.btn-primary:hover{ background: var(--dg-blue-dark); }
.btn-primary:active{ transform: scale(0.96); }
.btn-primary:disabled{ opacity:0.38; cursor:default; }
.btn-outline{ background: transparent; color: var(--dg-blue); border:1.5px solid var(--dg-blue); font-weight:700; font-size:14px; letter-spacing:0.15px; padding:11px 23px; border-radius:100px; cursor:pointer; display:inline-flex; align-items:center; gap:8px; transition: background .15s var(--dg-ease-standard), transform .15s var(--dg-ease-spring); }
.btn-outline:hover{ background: var(--dg-blue-tint); }
.btn-outline:active{ transform: scale(0.96); }
.btn-outline.dg-btn-crit{ color: var(--dg-crit-text); border-color: var(--dg-crit-border); }
.btn-outline.dg-btn-crit:hover{ background: var(--dg-crit-bg); }
.btn-outline.dg-btn-warn{ color: var(--dg-warn-text); border-color: var(--dg-warn-border); }
.btn-outline.dg-btn-warn:hover{ background: var(--dg-warn-bg); }

/* Tonal, Elevated, Text (2026-08-28) — completan los 5 tipos de botón de la spec M3 (ver
   referencia en Storybook), con nuestros colores de marca en vez del morado del kit. */
.btn-tonal{ background: var(--dg-blue-tint); color: var(--dg-blue-dark); border:none; font-weight:700; font-size:14px; letter-spacing:0.15px; padding:12px 24px; border-radius:100px; cursor:pointer; display:inline-flex; align-items:center; gap:8px; transition: background .15s var(--dg-ease-standard), transform .15s var(--dg-ease-spring); }
.btn-tonal:hover{ background: var(--dg-blue-light); }
.btn-tonal:active{ transform: scale(0.96); }
.btn-elevated{ background: var(--dg-surface); color: var(--dg-blue); border:none; font-weight:700; font-size:14px; letter-spacing:0.15px; padding:12px 24px; border-radius:100px; cursor:pointer; display:inline-flex; align-items:center; gap:8px; box-shadow: var(--dg-shadow-pop); transition: background .15s var(--dg-ease-standard), box-shadow .15s var(--dg-ease-standard), transform .15s var(--dg-ease-spring); }
.btn-elevated:hover{ background: var(--dg-blue-tint); box-shadow: 0 4px 14px rgba(2,61,105,0.18); }
.btn-elevated:active{ transform: scale(0.96); }
.btn-text{ background:none; color: var(--dg-blue); border:none; font-weight:700; font-size:14px; letter-spacing:0.15px; padding:11px 16px; border-radius:100px; cursor:pointer; display:inline-flex; align-items:center; gap:8px; transition: background .15s var(--dg-ease-standard), transform .15s var(--dg-ease-spring); }
.btn-text:hover{ background: var(--dg-blue-tint); }
.btn-text:active{ transform: scale(0.96); }

/* Tamaño chico (2026-08-28) — para acciones secundarias/utilitarias que no necesitan el mismo
   peso visual que un botón primario (ej. "Configura tu inicio"). Combina con cualquiera de los
   5 tipos de arriba: class="btn-outline btn-sm". */
.btn-primary.btn-sm, .btn-outline.btn-sm, .btn-tonal.btn-sm, .btn-elevated.btn-sm, .btn-text.btn-sm{
  padding:7px 16px; font-size:12.5px; gap:6px;
}

/* Fila de tabla — spec real de Gmail (Frame 5, node 1:49) para el contenido; contenedor con
   borde fino + radio grande (Expressive, 2026-08-25) en vez de la sombra dura anterior. */
.table-wrap{ background: var(--dg-surface); border:1px solid var(--dg-border); border-radius:20px; overflow:hidden; }
.dg-table{ width:100%; border-collapse:collapse; font-size:14px; }
.dg-table th{ text-align:left; color: var(--dg-text-muted); font-weight:700; font-size:11px; text-transform:uppercase; letter-spacing:0.03em; padding:12px 16px; background: var(--dg-blue-tint); white-space:nowrap; }
.dg-table td{ padding:12px 16px; border-bottom:1px solid var(--dg-border); color: var(--dg-text); font-weight:500; vertical-align:middle; height:44px; }
.dg-table tr:last-child td{ border-bottom:none; }
.dg-table tbody tr{ transition: background .1s ease; }
.dg-table tbody tr:hover{ background: var(--dg-bg-hover); }
.dg-table .row-actions{ opacity:0; transition: opacity .1s ease; }
.dg-table tbody tr:hover .row-actions{ opacity:1; }
.table-scroll{ overflow-x:auto; }

/* ---------- Jerarquía visual dentro de .dg-table (2026-09-28) ----------
   Cebrado sutil + primera columna como dato principal (bold, texto fuerte) y el resto
   como secundario (peso normal, texto atenuado) — mismo criterio que la herramienta de
   referencia de Lucas (Maestro Garzón): la fila se lee de un vistazo, no todo pesa igual. */
.dg-table td{ font-variant-numeric: tabular-nums; }
.dg-table td:first-child{ font-weight:700; color: var(--dg-text); }
.dg-table td:not(:first-child){ color: var(--dg-text-muted); }
.dg-table td.num{ text-align:right; }
.dg-table td.strong{ font-weight:700; color: var(--dg-text); }

/* Badge de porcentaje/valor con color semántico — reusar en descuentos, márgenes, deltas. */
.dg-pct{ display:inline-flex; align-items:center; font-weight:700; border-radius:100px; padding:2px 9px; font-size:12px; }
.dg-pct.pos{ color:#1e8e44; background: rgba(52,199,89,.14); }
.dg-pct.neg{ color: var(--dg-crit-text); background: var(--dg-crit-bg, rgba(255,59,48,.12)); }
.dg-pct.neutral{ color: var(--dg-blue-dark); background: var(--dg-blue-light); }
.dg-pct.muted{ color: var(--dg-text-soft); background: var(--dg-page-bg, var(--dg-m3x-page-bg)); }

/* Barra de participación/peso horizontal, mismo patrón visual que "PARTICIPACIÓN"/"PESO" de
   la referencia — barra corta con relleno proporcional al lado del número. */
.dg-bar-cell{ display:flex; align-items:center; gap:8px; min-width:90px; }
.dg-bar-track{ flex:1; height:6px; border-radius:100px; background: var(--dg-border); overflow:hidden; }
.dg-bar-fill{ height:100%; border-radius:100px; background: var(--dg-blue); }

/* Selector tipo pill — mismo patrón que el dropdown "Active ▾" de la search bar de Gmail
   (Frame 47, node 101:976): fondo tonal, sin borde, chevron a la derecha. */
.role-picker{
  appearance:none; -webkit-appearance:none; -moz-appearance:none;
  font-family:'Google Sans Flex',sans-serif; font-size:14px; line-height:20px; font-weight:500; color: var(--dg-text);
  background: var(--dg-blue-tint) url("data:image/svg+xml;charset=UTF-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='18' height='18'%3E%3Cpath fill='%2355595E' d='M7 10l5 5 5-5z'/%3E%3C/svg%3E") no-repeat right 10px center;
  /* Borde transparente de 1.5px (2026-09-15) — sin línea visible, pero mismo box model que
     .dg-select-filtro/.dg-text-field (que sí tienen borde) para que el alto coincida exacto
     cuando quedan uno al lado del otro (usuarios.html, sub-scope de colaborador). */
  border:1.5px solid transparent; border-radius:100px; padding:9px 34px 9px 14px; cursor:pointer;
}

/* Badges — Expressive (2026-08-25): relleno sólido + texto blanco en vez de contenedor tonal
   con borde, peso 800. Más contraste/personalidad, mismo criterio que KPI cards .accent. */
/* ---------- Ripple (state layer) — 2026-08-26. Timing real de @material/web
   (ripple/internal/ripple.ts): crece de 20% a 100% de escala en 450ms con easing standard,
   queda visible un mínimo de 225ms. El JS que lo dispara (delegado en document, funciona con
   contenido inyectado dinámicamente) vive en dg-common.js — acá solo el círculo. ---------- */
.dg-ripple-surface{ position:relative; overflow:hidden; }
.dg-ripple-el{ position:absolute; border-radius:50%; background:currentColor; pointer-events:none; will-change:transform,opacity; }

/* ---------- Switch — 2026-08-26. Único lugar del código fuente oficial con overshoot real
   (switch/internal/_handle.scss): el thumb se desplaza con
   cubic-bezier(0.175,0.885,0.32,1.275) en 300ms — --dg-ease-spring reusa exactamente ese
   valor. No reemplaza nada existente todavía, queda disponible para el próximo toggle real
   que necesitemos (ej. activar/desactivar un usuario). ---------- */
.dg-switch{ display:inline-flex; align-items:center; gap:10px; cursor:pointer; }
.dg-switch input{ position:absolute; opacity:0; width:1px; height:1px; }
.dg-switch-track{
  width:52px; height:32px; border-radius:100px; background:var(--dg-outline-variant);
  border:2px solid var(--dg-outline-variant); position:relative; flex-shrink:0;
  transition: background .2s var(--dg-ease-standard), border-color .2s var(--dg-ease-standard);
}
.dg-switch-thumb{
  position:absolute; top:50%; left:4px; transform:translateY(-50%);
  width:16px; height:16px; border-radius:50%; background:var(--dg-surface);
  box-shadow:0 1px 2px rgba(0,0,0,.3);
  transition: left .3s var(--dg-ease-spring), width .15s var(--dg-ease-standard), height .15s var(--dg-ease-standard);
}
.dg-switch input:checked + .dg-switch-track{ background:var(--dg-blue); border-color:var(--dg-blue); }
.dg-switch input:checked + .dg-switch-track .dg-switch-thumb{ left:24px; width:24px; height:24px; background:var(--dg-surface); }
.dg-switch input:focus-visible + .dg-switch-track{ outline:2px solid var(--dg-blue); outline-offset:2px; }
.dg-switch-label{ font-size:13.5px; color:var(--dg-text); font-weight:500; }

/* ---------- Checkbox — 2026-08-26. Tamaños reales de @material/web (tokens/_md-comp-checkbox):
   caja 18px, radio 2px (casi recta, no pill), touch target de 40px vía el padding del label.
   Construido a mano (el <input> nativo no se puede restylear igual entre navegadores) —
   mismo patrón que .dg-switch. ---------- */
.dg-checkbox{ display:inline-flex; align-items:center; gap:10px; cursor:pointer; padding:11px; margin:-11px; }
.dg-checkbox input{ position:absolute; opacity:0; width:1px; height:1px; }
.dg-checkbox-box{
  width:18px; height:18px; border-radius:2px; border:2px solid var(--dg-outline); flex-shrink:0;
  display:inline-flex; align-items:center; justify-content:center; background:transparent;
  transition: background .15s var(--dg-ease-standard), border-color .15s var(--dg-ease-standard);
}
.dg-checkbox-box svg{ width:14px; height:14px; color:#fff; opacity:0; transform:scale(0.4); transition: opacity .1s linear, transform .15s var(--dg-ease-spring); }
.dg-checkbox input:checked + .dg-checkbox-box{ background:var(--dg-blue); border-color:var(--dg-blue); }
.dg-checkbox input:checked + .dg-checkbox-box svg{ opacity:1; transform:scale(1); }
.dg-checkbox input:focus-visible + .dg-checkbox-box{ outline:2px solid var(--dg-blue); outline-offset:2px; }
.dg-checkbox-label{ font-size:13.5px; color:var(--dg-text); }

/* ---------- Lista — selección con checkbox + acción overflow (⋮), 2026-08-26. El checkbox
   reemplaza al avatar/ícono leading; el botón overflow (36px, ícono 24px, spec real de
   icon-button) aparece solo al hover de la fila — mismo patrón "revelar en hover" que ya
   usábamos en .dg-table .row-actions. ---------- */
.dg-list-item .dg-list-overflow{
  width:36px; height:36px; border-radius:50%; border:none; background:transparent; flex-shrink:0;
  color:var(--dg-text-muted); display:flex; align-items:center; justify-content:center; cursor:pointer;
  opacity:0; transition: background .15s var(--dg-ease-standard), opacity .15s var(--dg-ease-standard);
}
.dg-list-item:hover .dg-list-overflow, .dg-list-item .dg-list-overflow:focus-visible{ opacity:1; }
.dg-list-item .dg-list-overflow:hover{ background:var(--dg-bg-hover); }
.dg-list-item .dg-list-overflow[aria-expanded="true"]{ opacity:1; background:var(--dg-bg-hover); }

/* ---------- Menú desplegable de fila (⋮ → ej. Descargar/Actualizar/Borrar), 2026-08-26 —
   primer uso real del botón overflow de arriba (antes solo maquetado en el Storybook). Misma
   coreografía scale+fade que .dg-user-dropdown/.dg-notif-panel — sin motion nueva inventada. ---------- */
.dg-row-menu-wrap{ position:relative; flex-shrink:0; }
.dg-row-menu{
  position:absolute; top:calc(100% + 4px); right:0; min-width:170px; z-index:60;
  background:var(--dg-surface); border:1px solid var(--dg-border); border-radius:16px; padding:6px;
  box-shadow:0 8px 28px rgba(2,61,105,0.18);
  transform:scale(0.85) translateY(-6px); opacity:0; visibility:hidden;
  transition: transform .13s var(--dg-ease-emphasized-accel), opacity .13s var(--dg-ease-emphasized-accel), visibility 0s linear .13s;
}
.dg-row-menu.open{
  transform:none; opacity:1; visibility:visible;
  transition: transform .22s var(--dg-ease-emphasized), opacity .18s var(--dg-ease-standard), visibility 0s linear 0s;
}
.dg-row-menu button{
  display:flex; align-items:center; gap:10px; width:100%; text-align:left; padding:9px 12px; border:none;
  background:none; border-radius:10px; font-family:'Google Sans Flex',sans-serif; font-size:12.5px; font-weight:600;
  color:var(--dg-text); cursor:pointer; transition: background .15s var(--dg-ease-standard);
}
.dg-row-menu button:hover{ background:var(--dg-bg-hover); }
.dg-row-menu button.crit{ color:var(--dg-crit-text); }
.dg-row-menu button.crit:hover{ background:var(--dg-crit-bg); }
@media (prefers-reduced-motion: reduce){ .dg-row-menu{ transition-duration:.01ms !important; } }

/* ---------- Botón-ícono de fila (ej. chat/eliminar en Usuarios y Logística), 2026-09-02 —
   mismo círculo/hover que .dg-notif-bell (más chico, pensado para vivir dentro de una fila de
   tabla) en vez de un botón de texto: acción clara sin competir en peso visual con el resto de
   la fila. .danger reusa los tokens de error (mismo criterio que .dg-row-menu button.crit) para
   el estado hover, no en reposo — no hace falta gritar "peligro" hasta que el usuario interactúa. */
.dg-row-icon-btn{
  position:relative; flex-shrink:0; width:34px; height:34px; border-radius:50%; border:none;
  background:none; color:var(--dg-text-muted); display:inline-flex; align-items:center; justify-content:center;
  cursor:pointer; transition: background .15s var(--dg-ease-standard), color .15s var(--dg-ease-standard);
}
/* Celeste, no gris (2026-09-02) — dentro de una fila que ya cambia a var(--dg-bg-hover) entera
   al pasar el mouse (ver .conductor-fila:hover td), un hover gris sobre el ícono quedaba
   invisible por ser el mismo color que el fondo de la fila. */
.dg-row-icon-btn:hover{ background:var(--dg-blue-tint); color:var(--dg-blue-dark); }
.dg-row-icon-btn.danger:hover{ background:var(--dg-crit-bg); color:var(--dg-crit-text); }
/* Punto de "sin leer" — mismo lenguaje visual que .dg-notif-badge pero sin número, solo presencia. */
.dg-row-icon-badge{
  position:absolute; top:3px; right:3px; width:9px; height:9px; border-radius:50%;
  background:var(--dg-crit-text); border:2px solid var(--dg-surface);
}

/* ---------- Spinner de carga — 2026-08-26. Simplificación del indeterminate circular
   progress real de @material/web (progress/internal/_circular-progress.scss): la versión de
   Google compone 3 animaciones (rotación + arco que crece/achica + ciclo de 4 colores) sobre
   1333ms de arco base; acá va una sola animación de rotación con esa misma duración real, sin
   el ciclo de color (no lo necesitamos con un solo azul de marca). Uso: reemplaza el texto
   plano "Cargando…" en los estados de carga de los dashboards. ---------- */
.dg-spinner{
  width:20px; height:20px; border-radius:50%; display:inline-block; vertical-align:middle;
  border:2.5px solid var(--dg-blue-tint); border-top-color: var(--dg-blue);
  animation: dg-spin 1333ms linear infinite;
}
@keyframes dg-spin{ to{ transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce){ .dg-spinner{ animation-duration: 2.2s; } }
.bi-empty.loading{ display:flex; align-items:center; justify-content:center; gap:10px; }

/* Barra lineal indeterminada — 2026-08-26. Keyframes exactos de Google, no aproximados: dos
   barras (primary/secondary) cada una con translate + scale compuestos, 2000ms, tomado literal
   de progress/internal/_linear-progress.scss (@keyframes primary/secondary-indeterminate-
   translate/scale). Es la animación clásica de "barra de carga" de Material, sin cambios. */
.dg-linear-progress{ position:relative; width:100%; height:4px; border-radius:100px; background: var(--dg-blue-tint); overflow:hidden; }
.dg-linear-progress .bar{ position:absolute; inset:0; }
.dg-linear-progress .bar-inner{ position:absolute; inset:0; background: var(--dg-blue); transform-origin: left; }
.dg-linear-progress .primary-bar{ animation: dg-primary-translate 2s infinite linear; }
.dg-linear-progress .primary-bar .bar-inner{ animation: dg-primary-scale 2s infinite linear; }
.dg-linear-progress .secondary-bar{ animation: dg-secondary-translate 2s infinite linear; }
.dg-linear-progress .secondary-bar .bar-inner{ animation: dg-secondary-scale 2s infinite linear; }
@keyframes dg-primary-translate{
  0%{ transform: translateX(0); }
  20%{ animation-timing-function: cubic-bezier(0.5,0,0.701732,0.495819); transform: translateX(0); }
  59.15%{ animation-timing-function: cubic-bezier(0.302435,0.381352,0.55,0.956352); transform: translateX(83.6714%); }
  100%{ transform: translateX(200.611%); }
}
@keyframes dg-primary-scale{
  0%{ transform: scaleX(0.08); }
  36.65%{ animation-timing-function: cubic-bezier(0.334731,0.12482,0.785844,1); transform: scaleX(0.08); }
  69.15%{ animation-timing-function: cubic-bezier(0.06,0.11,0.6,1); transform: scaleX(0.661479); }
  100%{ transform: scaleX(0.08); }
}
@keyframes dg-secondary-translate{
  0%{ animation-timing-function: cubic-bezier(0.15,0,0.515058,0.409685); transform: translateX(0); }
  25%{ animation-timing-function: cubic-bezier(0.31033,0.284058,0.8,0.733712); transform: translateX(37.6519%); }
  48.35%{ animation-timing-function: cubic-bezier(0.4,0.627035,0.6,0.902026); transform: translateX(84.3862%); }
  100%{ transform: translateX(160.278%); }
}
@keyframes dg-secondary-scale{
  0%{ animation-timing-function: cubic-bezier(0.205028,0.057051,0.57661,0.453971); transform: scaleX(0.08); }
  19.15%{ animation-timing-function: cubic-bezier(0.152313,0.196432,0.648374,1.00432); transform: scaleX(0.457104); }
  44.15%{ animation-timing-function: cubic-bezier(0.257759,-0.003163,0.211762,1.38179); transform: scaleX(0.72796); }
  100%{ transform: scaleX(0.08); }
}
@media (prefers-reduced-motion: reduce){
  .dg-linear-progress .primary-bar, .dg-linear-progress .primary-bar .bar-inner,
  .dg-linear-progress .secondary-bar, .dg-linear-progress .secondary-bar .bar-inner{ animation-duration: 4s; }
}

/* Skeleton (shimmer) — 2026-08-26. No es spec M3 (Material no define un componente de
   skeleton), es un patrón estándar de la industria que sumamos nosotros para las filas de
   tabla/lista mientras cargan — encaja mejor que el spinner cuando ya sabemos la forma del
   contenido (cuántas columnas/filas va a tener). Barrido con el mismo --dg-ease-standard. */
.dg-skeleton{
  border-radius:8px; background: var(--dg-border);
  background-image: linear-gradient(90deg, var(--dg-border) 0%, var(--dg-bg-hover) 50%, var(--dg-border) 100%);
  background-size: 200% 100%; animation: dg-shimmer 1.6s infinite var(--dg-ease-standard);
}
@keyframes dg-shimmer{ 0%{ background-position: 200% 0; } 100%{ background-position: -200% 0; } }
@media (prefers-reduced-motion: reduce){ .dg-skeleton{ animation:none; background: var(--dg-border); } }

/* ---------- Date picker (M3) — 2026-08-27. Popup de calendario propio, anclado al input que lo
   dispara (dgAttachDatePicker en dg-common.js), en vez del <input type="date"> nativo del
   navegador (se ve distinto en cada SO/browser y no se puede stylear). Selección en azul de marca
   en vez del morado M3 original, coherente con el resto del portal. ---------- */
.dg-dp{
  position:absolute; z-index:60; width:296px; background: var(--dg-surface); border-radius:20px;
  border:1px solid var(--dg-border); box-shadow:0 8px 28px rgba(0,0,0,.14); padding:12px;
  opacity:0; transform: scale(0.92) translateY(-6px); transform-origin: top left;
  pointer-events:none; transition: opacity .16s var(--dg-ease-standard), transform .16s var(--dg-ease-standard);
}
.dg-dp.open{ opacity:1; transform: scale(1) translateY(0); pointer-events:auto; }
.dg-dp-head{ display:flex; align-items:center; justify-content:space-between; padding:4px 4px 10px; }
.dg-dp-month{ font-size:13.5px; font-weight:700; color: var(--dg-text); text-transform:capitalize; }
.dg-dp-nav{ display:flex; gap:2px; }
.dg-dp-nav button{
  width:32px; height:32px; border-radius:50%; border:none; background:none; color: var(--dg-text-muted);
  display:flex; align-items:center; justify-content:center; cursor:pointer; transition: background .12s ease;
}
.dg-dp-nav button:hover{ background: var(--dg-blue-tint); color: var(--dg-blue); }
.dg-dp-grid{ display:grid; grid-template-columns: repeat(7,1fr); gap:2px; }
.dg-dp-dow{ font-size:10.5px; font-weight:700; color: var(--dg-text-soft); text-align:center; padding:6px 0 8px; text-transform:uppercase; }
.dg-dp-day{
  position:relative; width:100%; aspect-ratio:1; border:none; background:none; border-radius:50%;
  font-size:12.5px; font-weight:500; color: var(--dg-text); cursor:pointer; transition: background .12s ease;
}
.dg-dp-day:hover{ background: var(--dg-blue-tint); }
.dg-dp-day.outside{ color: var(--dg-text-soft); opacity:.45; }
.dg-dp-day.today{ font-weight:800; color: var(--dg-blue); }
.dg-dp-day.today::after{
  content:''; position:absolute; left:50%; bottom:3px; width:4px; height:4px; border-radius:50%;
  background: var(--dg-blue); transform: translateX(-50%);
}
.dg-dp-day.selected{ background: var(--dg-blue); color:#fff; font-weight:700; }
.dg-dp-day.selected::after{ display:none; }
.dg-dp-foot{ display:flex; justify-content:flex-end; gap:6px; padding-top:10px; margin-top:6px; border-top:1px solid var(--dg-border); }
.dg-dp-foot button{ font-size:12.5px; font-weight:600; padding:7px 14px; border-radius:100px; border:none; cursor:pointer; }
.dg-dp-hoy{ background:none; color: var(--dg-blue); }
.dg-dp-hoy:hover{ background: var(--dg-blue-tint); }
@media (prefers-reduced-motion: reduce){ .dg-dp{ transition-duration:.01ms !important; } }

/* Loader de puntos "shape-morph" — 2026-08-26, inspirado en la idea de shape morphing de M3
   Expressive (no existe un componente web oficial para esto — Expressive es Android/Compose
   primero, ver hallazgo de la sesión anterior — así que esto es interpretación nuestra, no un
   port de código fuente real como el resto de los loaders de acá arriba). Tres puntos que
   cambian de círculo a squircle mientras rebotan, con la curva de rebote real del switch. */
.dg-dots{ display:inline-flex; gap:6px; align-items:center; }
.dg-dots span{
  width:9px; height:9px; background: var(--dg-blue); border-radius:50%;
  animation: dg-dot-morph 1.1s infinite var(--dg-ease-spring);
}
.dg-dots span:nth-child(2){ animation-delay: .12s; }
.dg-dots span:nth-child(3){ animation-delay: .24s; }
@keyframes dg-dot-morph{
  0%, 100%{ transform: translateY(0) scale(1); border-radius:50%; }
  35%{ transform: translateY(-7px) scale(1.15); border-radius:30%; }
}
@media (prefers-reduced-motion: reduce){ .dg-dots span{ animation:none; } }

.badge{ display:inline-block; font-size:11px; font-weight:800; padding:5px 13px; border-radius:100px; border:none; white-space:nowrap; }
.badge.crit{ background: var(--dg-crit-text); color:#fff; }
.badge.warn{ background: var(--dg-warn-text); color:#fff; }
.badge.ok{ background: var(--dg-ok-text); color:#fff; }
.badge.info{ background: var(--dg-info-text); color:#fff; }

/* Botón "Aprobar" (Usuarios y roles, cuentas con estado pendiente) — mismo shape/tamaño que
   .row-guardar-btn pero en verde (ok), y siempre visible cuando aparece (no usa el truco de
   visibility:hidden porque no depende de una interacción posterior del usuario). */
.row-aprobar-btn{
  background: var(--dg-ok-text); color:#fff; border:none; font-weight:500;
  font-size:12.5px; letter-spacing:0.15px; padding:7px 16px; border-radius:100px; cursor:pointer;
  transition: background .15s ease;
}
.row-aprobar-btn:hover{ background:#155c34; }

/* ---------- chat mockup (Módulo B) ---------- */

.chat-shell{ display:flex; background: var(--dg-surface); border:none; border-radius:16px; overflow:hidden; height: min(600px, 75vh); }
.chat-sidebar{ width:220px; flex-shrink:0; border-right:1px solid var(--dg-border); overflow-y:auto; display:none; }
.chat-sidebar .cs-head{ padding:14px 16px; font-size:11.5px; font-weight:700; color: var(--dg-text-muted); letter-spacing:0.3px; }
.chat-sidebar .cs-item{ padding:12px 16px; border-bottom:1px solid var(--dg-border); cursor:pointer; }
.chat-sidebar .cs-item:hover{ background: var(--dg-bg-hover); }
.chat-sidebar .cs-item.active{ background: var(--dg-blue-light); }
.chat-sidebar .cs-item .cs-name{ font-size:12.5px; font-weight:700; color: var(--dg-text); }
.chat-sidebar .cs-item .cs-preview{ font-size:11px; color: var(--dg-text-muted); margin-top:2px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.chat-main{ flex:1; display:flex; flex-direction:column; min-width:0; }
.chat-main .cm-head{ padding:14px 18px; border-bottom:1px solid var(--dg-border); display:flex; align-items:center; gap:10px; }
.chat-main .cm-head .status-dot{ width:8px; height:8px; border-radius:50%; background: var(--dg-ok-text); }
.chat-messages{ flex:1; overflow-y:auto; padding: 18px; display:flex; flex-direction:column; gap:12px; }
.msg{ max-width:72%; font-size:13px; line-height:1.55; padding:10px 14px; border-radius:14px; }
.msg.bot{ background: var(--dg-bg); border:1px solid var(--dg-border); align-self:flex-start; border-bottom-left-radius:4px; }
.msg.user{ background: var(--dg-blue); color:#fff; align-self:flex-end; border-bottom-right-radius:4px; }
.chat-input-bar{ display:flex; gap:10px; padding:14px 16px; border-top:1px solid var(--dg-border); }
.chat-input-bar input{ flex:1; border:1px solid var(--dg-border); border-radius:100px; padding:10px 16px; font-family:'Google Sans Flex',sans-serif; font-size:12.5px; }

@media (min-width: 720px){
  .chat-sidebar{ display:block; }
}

/* ---------- route list (Módulo D) ---------- */

.route-layout{ display:grid; grid-template-columns: 1.1fr 1fr; gap:16px; }
.route-item{ display:flex; align-items:center; justify-content:space-between; padding:12px 0; border-bottom:1px solid var(--dg-border); gap:10px; flex-wrap:wrap; }
.route-item:last-child{ border-bottom:none; }
.route-item .r-main{ font-size:13px; font-weight:700; color: var(--dg-text); }
.route-item .r-sub{ font-size:11.5px; color: var(--dg-text-muted); margin-top:2px; }

@media (max-width: 860px){
  .route-layout{ grid-template-columns: 1fr; }
}

/* ---------- generic responsive helpers ---------- */

@media (max-width: 640px){
  .kpi-row{ grid-template-columns: repeat(2, 1fr); }
  nav.dg-nav{ justify-content:center; width:100%; }
  header.dg-header{ justify-content:center; text-align:center; }
}

/* ---------- module switcher (portal de gestión) ---------- */

.mod-switch{ display:flex; align-items:center; gap:6px; }
.mod-switch a.modlink{
  width:30px; height:30px; border-radius:50%; display:inline-flex; align-items:center; justify-content:center;
  font-weight:700; font-size:12px; color: var(--dg-text-muted); border:none; background: var(--dg-bg-hover); flex-shrink:0;
  transition: all .15s ease;
}
.mod-switch a.modlink:hover{ border-color: var(--dg-blue); color: var(--dg-blue); }
.mod-switch a.modlink.active{ background: var(--dg-blue); color:#fff; border-color: var(--dg-blue); }

/* ---------- toast (feedback de acciones simuladas) — Snackbar M3, verificado vía Figma MCP
   (kit oficial, node 53977:33611). Radio real 4px (casi recto, no pill como tenía antes) y
   tipografía Body Medium real (14px/400, tracking 0.25 — antes 13.5px/600). Posición arriba-centro
   y fondo navy se mantienen: son decisiones ya tomadas (arriba-centro por pedido explícito de
   Julio; navy en vez del gris oscuro real de M3 para ser consistente con el resto de la marca). */
/* Motion corregido (2026-08-26) contra el código fuente real de Google — @material/web no
   tiene snackbar (ni siquiera en labs/), así que la referencia real es MDC (M2):
   packages/mdc-snackbar/_snackbar.scss entra con scale(0.8)→1 + fade en 150ms (decelerate) y
   sale solo con fade en 75ms (accelerate) — no desliza, escala. Antes usábamos un slide
   (translateY) con timing genérico. Radio subido a 16px (antes 4px, spec M3 "clásico" real
   verificado en Figma) para quedar consistente con el resto de contenedores ya redondeados
   esta sesión (diálogo 32px, paneles/tabla 20px) — único punto sin fuente oficial, ajustado a
   criterio para mantener el lenguaje visual parejo. Posición arriba-centro y fondo navy se
   mantienen (decisiones de marca ya tomadas, documentadas abajo). */
#dg-toast{
  position:fixed; top:22px; left:50%; transform:translateX(-50%) scale(0.8);
  background: var(--dg-navy-deep); color:#fff; font-family:'Google Sans Flex',sans-serif;
  font-size:14px; font-weight:400; letter-spacing:0.25px; line-height:20px;
  padding:14px 26px; border-radius:16px; opacity:0; pointer-events:none; z-index:999;
  width:min(560px, 90vw); text-align:center; overflow:hidden;
  transition: opacity .075s var(--dg-ease-standard-accel), transform .075s var(--dg-ease-standard-accel);
  box-shadow: var(--dg-shadow-pop);
}
#dg-toast.show{
  opacity:1; transform:translateX(-50%) scale(1);
  transition: opacity .15s var(--dg-ease-standard-decel), transform .15s var(--dg-ease-standard-decel);
}
#dg-toast .dg-toast-text{ display:block; line-height:1.5; }
#dg-toast .dg-toast-bar{
  position:absolute; left:0; bottom:0; height:3px; background: rgba(255,255,255,0.55);
  width:100%; transform-origin:left; transform:scaleX(1);
}
#dg-toast.show .dg-toast-bar{ transition: transform linear; }
@media (max-width:600px){ #dg-toast{ top:14px; width:min(92vw, 520px); padding:14px 18px; } }
@media (prefers-reduced-motion: reduce){ #dg-toast, #dg-toast.show{ transition-duration:.01ms !important; } }

/* ---------- card con doble acceso (Módulo B: público + admin) ---------- */

.dg-card .dg-actions{ display:flex; gap:8px; flex-wrap:wrap; margin-top:4px; }
.dg-card .dg-actions a{
  font-weight:700; font-size:11.5px; letter-spacing:0.2px; padding:9px 16px; border-radius:100px; display:inline-flex; align-items:center; gap:5px;
}
.dg-card .dg-actions a.primary{ background:var(--dg-surface); color: var(--dg-blue); }
.dg-card .dg-actions a.secondary{ background: rgba(255,255,255,0.18); color:#fff; border:1px solid rgba(255,255,255,0.4); }
.dg-card .dg-actions a.secondary:hover{ background: rgba(255,255,255,0.28); }

/* ---------- badge de estado de módulo (home) ---------- */

.dg-modstatus{ font-size:10px; font-weight:700; letter-spacing:0.5px; padding:4px 10px; border-radius:12px; display:inline-flex; align-items:center; gap:5px; width:fit-content; }
.dg-modstatus.live{ background: rgba(255,255,255,0.9); color: var(--dg-ok-text); }
.dg-modstatus.live::before{ content:''; width:6px; height:6px; border-radius:50%; background: var(--dg-ok-text); }
.dg-modstatus.mock{ background: rgba(255,255,255,0.18); color: rgba(255,255,255,0.85); }
.dg-modstatus.mock::before{ content:''; width:6px; height:6px; border-radius:50%; background: rgba(255,255,255,0.7); }

/* ---------- admin: sidebar más ancho + filtros ---------- */

.chat-shell.admin{ height: min(660px, 78vh); }
.chat-shell.admin .chat-sidebar{ width:270px; display:flex; flex-direction:column; }
.chat-sidebar .cs-filters{ padding: 10px 14px; border-bottom:1px solid var(--dg-border); display:flex; flex-direction:column; gap:8px; }
.chat-sidebar .cs-filters input{ width:100%; font-family:'Google Sans Flex',sans-serif; font-size:12px; padding:8px 10px; border-radius:8px; border:1px solid var(--dg-outline); }
.chat-sidebar .cs-filters .chip-row{ display:flex; gap:6px; flex-wrap:wrap; }
.chip{ font-size:10.5px; font-weight:700; padding:5px 10px; border-radius:100px; border:none; color: var(--dg-text-muted); cursor:pointer; background: var(--dg-bg-hover); }
.chip.active{ background: var(--dg-blue); color:#fff; }
.chat-sidebar .cs-list{ flex:1; overflow-y:auto; }
.chat-sidebar .cs-item .cs-meta{ display:flex; align-items:center; justify-content:space-between; gap:6px; margin-top:4px; }
.chat-sidebar .cs-item .cs-meta .badge{ font-size:9.5px; padding:2px 8px; }
.cs-empty{ padding:24px 16px; text-align:center; font-size:12px; color: var(--dg-text-soft); }
.chat-main .cm-head .cm-actions{ margin-left:auto; display:flex; gap:8px; }
.chat-main .cm-head .cm-actions button{ font-size:11px; padding:7px 13px; }

@media (max-width: 719px){
  .chat-shell.admin{ flex-direction:column; height:auto; }
  .chat-shell.admin .chat-sidebar{ display:flex; width:100%; max-height:320px; border-right:none; border-bottom:1px solid var(--dg-border); }
}

/* ---------- burbujas de chat tipo widget (panel admin) ---------- */

.bubble-row{ display:flex; align-items:flex-end; gap:8px; max-width:78%; }
.bubble-row.user{ align-self:flex-end; flex-direction:row-reverse; }
.bubble-row.bot{ align-self:flex-start; }
.bubble-avatar{
  width:26px; height:26px; border-radius:50%; background: var(--dg-blue); color:#fff;
  font-size:10.5px; font-weight:700; display:flex; align-items:center; justify-content:center; flex-shrink:0;
}
.bubble{ padding:10px 14px; border-radius:14px; font-size:13px; line-height:1.55; }
.bubble ol, .bubble ul{ margin:6px 0; padding-left:20px; }
.bubble li{ margin-bottom:3px; }
.bubble.bot{ background: var(--dg-bg); border:1px solid var(--dg-border); color: var(--dg-text); border-bottom-left-radius:4px; }
.bubble.user{ background: var(--dg-blue); color:#fff; border-bottom-right-radius:4px; }
.bubble-meta{ font-size:10.5px; color: var(--dg-text-soft); margin-top:4px; padding:0 4px; }
.bubble-meta.user{ text-align:right; }

.option-chips-static{ display:flex; flex-direction:column; align-items:flex-start; gap:6px; padding:2px 0 2px 34px; }
.option-chip-static{
  border:1.5px solid var(--dg-blue); color: var(--dg-blue); background:var(--dg-surface); border-radius:100px;
  padding:6px 14px; font-size:12px; font-weight:600;
}

/* ---------- Chat flotante (Cerebro) — 2026-08-25 ----------
   Antes era una sección más del sidebar (chat.html); ahora es un widget global (botón flotante
   + panel) montado por dg-common.js en TODAS las páginas autenticadas, para no depender de que
   el usuario navegue a una página aparte. El botón entra con un pop suave al cargar la página
   (EMPHASIZED_DECELERATE) y tiene un pulso sutil de "disponible" en el ícono — motion propio
   del portal, no un port de un componente real de @material/web (no existe un FAB de chat en
   el kit oficial). El panel reusa la misma coreografía scale+fade que .dg-modal-overlay
   (dialog/internal/animations.ts), anclada abajo a la derecha en vez de centrada. */
.dg-chat-fab{
  position:fixed; right:20px; bottom:20px; z-index:1200;
  display:flex; align-items:center; gap:10px; border:none; cursor:pointer;
  background: var(--dg-blue); color:#fff; border-radius:100px; padding:8px 20px 8px 8px;
  font-family:'Google Sans Flex',sans-serif; box-shadow: 0 4px 18px rgba(2,61,105,0.28);
  animation: dg-chat-fab-in .4s var(--dg-ease-emphasized-decel) both;
  transition: transform .15s var(--dg-ease-spring), box-shadow .2s var(--dg-ease-standard),
              opacity .13s var(--dg-ease-emphasized-accel), visibility 0s linear .13s;
}
.dg-chat-fab:hover{ box-shadow: 0 6px 22px rgba(2,61,105,0.36); }
.dg-chat-fab:active{ transform: scale(0.96); }
.dg-chat-fab.hide{ opacity:0; visibility:hidden; transform: scale(0.85); pointer-events:none; }
.dg-chat-fab-icon{
  width:36px; height:36px; border-radius:50%; background:rgba(255,255,255,0.18);
  display:flex; align-items:center; justify-content:center; flex-shrink:0; position:relative;
}
.dg-chat-fab-icon svg{ width:21px; height:21px; position:relative; z-index:1; animation: dg-chat-icon-spin 2s linear infinite; }
/* Ícono "de forma" (2026-08-26, ajustado) — reemplaza el ícono fijo de diálogo por un blob que
   muta entre 5 siluetas bien diferenciadas (burbuja → chispa/sunny → cookie festoneado → trébol
   → píldora), tomando como referencia el Loading Indicator real de M3 Expressive
   (m3.material.io/components/loading-indicator/overview): esa pieza cicla por 7 formas del kit
   oficial (soft burst, cookie, pentágono, pill, sunny...) con un spring de mayor contraste entre
   radios (no una variación sutil como el primer intento acá) + rotación continua para que la
   mutación se note de verdad. Cada forma es un RoundedPolygon (8 anclas + curvas cúbicas) con la
   MISMA cantidad y tipo de comandos SVG que las demás — condición necesaria para que el navegador
   interpole el atributo `d` como una animación real de forma, no un cross-fade de íconos. Easing
   con overshoot (--dg-ease-spring) como aproximación CSS del spring físico real de M3 (CSS no
   tiene motor de springs nativo). Se degrada con gracia en navegadores sin soporte de `d`
   animable (Safari): queda la forma inicial fija, sin romper nada. */
.dg-chat-blob{ fill:#fff; animation: dg-chat-blob-morph 1.8s linear infinite; }
@keyframes dg-chat-icon-spin{ from{ transform:rotate(0deg); } to{ transform:rotate(360deg); } }
/* Cada forma se mantiene fija un rato ("hold") y después salta a la siguiente en una ventana
   corta con overshoot (--dg-ease-spring) — en vez de una interpolación continua y pareja entre
   los 5 stops, que se sentía más como un fundido que como un salto real de forma. El
   timing-function puesto en el keyframe de INICIO de cada ventana de salto es el que CSS aplica
   a ESE tramo (spec: la curva de un keyframe rige el segmento hacia el siguiente), por eso el
   spring está en los frames de "fin de hold", no en los de "forma ya asentada". Así se aproxima
   mejor el spring real de M3 (mantiene la forma, después un pop rápido con rebote a la próxima). */
@keyframes dg-chat-blob-morph{
  0%, 14%{ d: path("M12.00,3.00 C16.97,3.00 14.85,2.12 18.36,5.64 C21.88,9.15 21.00,7.03 21.00,12.00 C21.00,16.97 21.88,14.85 18.36,18.36 C14.85,21.88 16.97,21.00 12.00,21.00 C7.03,21.00 9.15,21.88 5.64,18.36 C2.12,14.85 3.00,16.97 3.00,12.00 C3.00,7.03 2.12,9.15 5.64,5.64 C9.15,2.12 7.03,3.00 12.00,3.00 Z"); }
  14%{ animation-timing-function: var(--dg-ease-spring); }
  20%, 34%{ d: path("M12.00,1.50 C15.15,1.50 14.08,8.14 14.97,9.03 C15.86,9.92 22.50,8.85 22.50,12.00 C22.50,15.15 15.86,14.08 14.97,14.97 C14.08,15.86 15.15,22.50 12.00,22.50 C8.85,22.50 9.92,15.86 9.03,14.97 C8.14,14.08 1.50,15.15 1.50,12.00 C1.50,8.85 8.14,9.92 9.03,9.03 C9.92,8.14 8.85,1.50 12.00,1.50 Z"); }
  34%{ animation-timing-function: var(--dg-ease-spring); }
  40%, 54%{ d: path("M12.00,2.20 C18.08,2.20 14.04,3.29 17.37,6.63 C20.71,9.96 21.80,5.92 21.80,12.00 C21.80,18.08 20.71,14.04 17.37,17.37 C14.04,20.71 18.08,21.80 12.00,21.80 C5.92,21.80 9.96,20.71 6.63,17.37 C3.29,14.04 2.20,18.08 2.20,12.00 C2.20,5.92 3.29,9.96 6.63,6.63 C9.96,3.29 5.92,2.20 12.00,2.20 Z"); }
  54%{ animation-timing-function: var(--dg-ease-spring); }
  60%, 74%{ d: path("M12.00,1.50 C18.09,1.50 15.61,3.59 18.01,5.99 C20.41,8.39 15.00,10.26 15.00,12.00 C15.00,13.74 20.41,15.61 18.01,18.01 C15.61,20.41 18.09,22.50 12.00,22.50 C5.91,22.50 8.39,20.41 5.99,18.01 C3.59,15.61 9.00,13.74 9.00,12.00 C9.00,10.26 3.59,8.39 5.99,5.99 C8.39,3.59 5.91,1.50 12.00,1.50 Z"); }
  74%{ animation-timing-function: var(--dg-ease-spring); }
  80%, 94%{ d: path("M12.00,5.20 C15.94,5.20 14.90,1.08 18.91,5.09 C22.92,9.10 23.00,5.62 23.00,12.00 C23.00,18.38 22.92,14.90 18.91,18.91 C14.90,22.92 15.94,18.80 12.00,18.80 C8.06,18.80 9.10,22.92 5.09,18.91 C1.08,14.90 1.00,18.38 1.00,12.00 C1.00,5.62 1.08,9.10 5.09,5.09 C9.10,1.08 8.06,5.20 12.00,5.20 Z"); }
  94%{ animation-timing-function: var(--dg-ease-spring); }
  100%{ d: path("M12.00,3.00 C16.97,3.00 14.85,2.12 18.36,5.64 C21.88,9.15 21.00,7.03 21.00,12.00 C21.00,16.97 21.88,14.85 18.36,18.36 C14.85,21.88 16.97,21.00 12.00,21.00 C7.03,21.00 9.15,21.88 5.64,18.36 C2.12,14.85 3.00,16.97 3.00,12.00 C3.00,7.03 2.12,9.15 5.64,5.64 C9.15,2.12 7.03,3.00 12.00,3.00 Z"); }
}
/* Texto que rota entre las dos frases (2026-08-25) en vez de mostrarlas juntas: primero "¿Necesitás
   ayuda?" se va deslizando hacia arriba mientras se desvanece, después entra "Preguntame lo que
   quieras" desde abajo — dgChatCiclarFabTexto en dg-common.js alterna la clase .active cada 2.8s. */
.dg-chat-fab-text{ position:relative; min-width:172px; height:16px; text-align:left; }
.dg-chat-fab-msg{
  position:absolute; inset:0; display:flex; align-items:center; white-space:nowrap;
  font-size:12.5px; font-weight:700; opacity:0; transform:translateY(7px);
  transition: opacity .3s var(--dg-ease-emphasized), transform .3s var(--dg-ease-emphasized);
}
.dg-chat-fab-msg.active{ opacity:1; transform:translateY(0); }
.dg-chat-fab-msg.leaving{ opacity:0; transform:translateY(-7px); transition: opacity .2s var(--dg-ease-emphasized-accel), transform .2s var(--dg-ease-emphasized-accel); }
@keyframes dg-chat-fab-in{ from{ opacity:0; transform: translateY(18px) scale(0.85); } to{ opacity:1; transform:none; } }
@media (prefers-reduced-motion: reduce){
  .dg-chat-fab{ animation:none; transition-duration:.01ms !important; }
  .dg-chat-blob, .dg-chat-fab-icon svg{ animation:none; }
  .dg-chat-fab-msg{ transition-duration:.01ms !important; }
}
@media (max-width:600px){
  .dg-chat-fab{ right:16px; bottom:16px; padding:8px; }
  .dg-chat-fab-text{ display:none; }
}

.dg-chat-panel{
  position:fixed; right:20px; bottom:20px; z-index:1200;
  /* +25% en desktop (pedido explícito, 2026-09-15): 392px→490px, 640px→800px. */
  width:490px; max-width:calc(100vw - 32px); height:min(800px, 90vh);
  background: var(--dg-surface); border:1px solid var(--dg-border); border-radius:28px;
  display:flex; flex-direction:column; overflow:hidden; box-shadow: 0 16px 44px rgba(2,61,105,0.24);
  transform-origin: bottom right; transform: scale(0.85) translateY(14px); opacity:0; visibility:hidden;
  transition: transform .16s var(--dg-ease-emphasized-accel), opacity .16s linear, visibility 0s linear .16s;
}
.dg-chat-panel.open{
  transform:none; opacity:1; visibility:visible;
  transition: transform .35s var(--dg-ease-emphasized), opacity .3s linear, visibility 0s linear 0s;
}
@media (prefers-reduced-motion: reduce){ .dg-chat-panel{ transition-duration:.01ms !important; } }
@media (max-width:600px){
  .dg-chat-panel{
    right:0; bottom:0; left:0; top:0; width:100%; max-width:100%; height:100%; height:100dvh;
    border-radius:0; transform: scale(1) translateY(100%);
  }
  .dg-chat-panel.open{ transform:none; }
}

.dg-chat-panel-head{ display:flex; align-items:center; gap:6px; padding:12px 8px 12px 14px; border-bottom:1px solid var(--dg-border); flex-shrink:0; }
.dg-chat-panel-head h4{ margin:0; flex:1; font-size:14px; font-weight:700; color: var(--dg-navy); }
.dg-chat-panel-back, .dg-chat-panel-close{
  width:32px; height:32px; border-radius:50%; border:none; background:transparent; color: var(--dg-text-muted);
  display:flex; align-items:center; justify-content:center; cursor:pointer; flex-shrink:0;
  transition: background .15s var(--dg-ease-standard);
}
.dg-chat-panel-back:hover, .dg-chat-panel-close:hover{ background: var(--dg-bg-hover); color: var(--dg-text); }
.dg-chat-panel-back{ display:none; }
.dg-chat-panel.view-thread .dg-chat-panel-back{ display:flex; }

.dg-chat-panel-body{ flex:1; min-height:0; position:relative; overflow:hidden; }
.dg-chat-view{
  position:absolute; inset:0; display:flex; flex-direction:column; opacity:1; transform:translateX(0);
  transition: opacity .2s var(--dg-ease-standard), transform .2s var(--dg-ease-standard), visibility 0s linear 0s;
}
.dg-chat-panel.view-list .dg-chat-view-thread{ opacity:0; transform:translateX(16px); visibility:hidden; pointer-events:none; transition: opacity .13s var(--dg-ease-emphasized-accel), transform .13s var(--dg-ease-emphasized-accel), visibility 0s linear .13s; }
.dg-chat-panel.view-thread .dg-chat-view-list{ opacity:0; transform:translateX(-16px); visibility:hidden; pointer-events:none; transition: opacity .13s var(--dg-ease-emphasized-accel), transform .13s var(--dg-ease-emphasized-accel), visibility 0s linear .13s; }
@media (prefers-reduced-motion: reduce){ .dg-chat-view{ transition-duration:.01ms !important; } }

/* Lista de conversaciones (2026-08-26) — antes tenía su propio patrón (.dg-chat-conv-item),
   ahora reusa el componente de lista compartido (.dg-list/.dg-list-item, contenedor tonal +
   ítems blancos) para ser consistente con el resto de la plataforma. El label de grupo por
   fecha ("Hoy"/"Ayer") queda afuera del contenedor tonal, como separador simple. */
.dg-chat-conv-list{ flex:1; overflow-y:auto; padding:4px 8px 8px; }
/* Vuelve a estar fijo abajo de la ventana (2026-08-26) — se probó como ícono en el header, pero
   se pidió volver al botón de siempre: pill azul con texto, último hijo del flex-column de la
   vista de lista (no scrollea con las conversaciones, queda siempre visible mientras esa vista
   está activa). */
.dg-chat-nueva-btn{
  flex-shrink:0; margin:8px 14px 12px; display:flex; align-items:center; justify-content:center; gap:8px;
  background: var(--dg-blue); color:#fff; border:none; border-radius:100px; padding:10px 14px;
  font-family:'Google Sans Flex',sans-serif; font-size:12.5px; font-weight:700; cursor:pointer;
  transition: background .15s var(--dg-ease-standard), transform .15s var(--dg-ease-spring);
}
.dg-chat-nueva-btn:hover{ background: var(--dg-blue-dark); }
.dg-chat-nueva-btn:active{ transform: scale(0.97); }
.dg-chat-conv-list .dg-list{ margin-bottom:10px; }
.dg-chat-conv-grupo{ padding:8px 6px 6px; font-size:10.5px; font-weight:700; color: var(--dg-text-soft); text-transform:uppercase; letter-spacing:0.4px; }
.dg-chat-conv-list .dg-chat-conv-grupo:first-child{ padding-top:2px; }
.dg-chat-conv-empty{ padding:30px 20px; text-align:center; font-size:12.5px; color: var(--dg-text-soft); }

.dg-chat-empty{ flex:1; display:flex; flex-direction:column; align-items:center; justify-content:center; gap:16px; padding:20px; text-align:center; overflow-y:auto; }
.dg-chat-empty h5{ font-size:15px; font-weight:700; color: var(--dg-navy); margin:0; }
.dg-chat-empty p{ font-size:12px; color: var(--dg-text-muted); margin:0; max-width:280px; }
.dg-chat-sugerencias{ display:flex; flex-direction:column; gap:8px; width:100%; max-width:280px; }
.dg-chat-sugerencia-chip{
  border:1px solid var(--dg-border); background: var(--dg-surface); color: var(--dg-text); border-radius:16px;
  padding:9px 14px; font-size:12px; cursor:pointer; text-align:left; transition: border-color .15s var(--dg-ease-standard);
}
.dg-chat-sugerencia-chip:hover{ border-color: var(--dg-blue); color: var(--dg-blue); }

.dg-chat-messages{ flex:1; overflow-y:auto; display:flex; flex-direction:column; gap:10px; padding:14px; }
.dg-chat-option-chips{ display:flex; flex-direction:column; align-items:flex-start; gap:6px; padding:0 0 2px 34px; }
.dg-chat-option-chip{
  border:1.5px solid var(--dg-blue); color: var(--dg-blue); background:var(--dg-surface); border-radius:100px;
  padding:7px 14px; font-size:12px; font-weight:600; cursor:pointer;
  transition: background .15s var(--dg-ease-standard), color .15s var(--dg-ease-standard), transform .15s var(--dg-ease-spring);
}
.dg-chat-option-chip:hover:not(:disabled){ background: var(--dg-blue); color:#fff; }
.dg-chat-option-chip:active:not(:disabled){ transform: scale(0.96); }
.dg-chat-option-chip:disabled{ opacity:0.4; cursor:default; }
.dg-chat-fuentes-row{ display:flex; gap:6px; flex-wrap:wrap; padding:0 0 0 34px; }
.dg-chat-fuente-chip{ font-size:10px; color: var(--dg-text-soft); background: var(--dg-bg-hover); padding:3px 9px; border-radius:100px; }
.dg-chat-typing-dots{ display:inline-flex; gap:3px; padding:4px 0; }
.dg-chat-typing-dots span{ width:6px; height:6px; border-radius:50%; background: var(--dg-text-soft); animation: dg-chat-typing 1.2s infinite ease-in-out; }
.dg-chat-typing-dots span:nth-child(2){ animation-delay:.2s; }
.dg-chat-typing-dots span:nth-child(3){ animation-delay:.4s; }
@keyframes dg-chat-typing{ 0%,60%,100%{ opacity:.3; transform:translateY(0); } 30%{ opacity:1; transform:translateY(-3px); } }

.dg-chat-input-bar{ display:flex; align-items:center; gap:10px; padding:12px 14px; border-top:1px solid var(--dg-border); flex-shrink:0; }
.dg-chat-input-bar input{
  flex:1; border:1px solid var(--dg-border); border-radius:100px; padding:10px 16px; font-family:'Google Sans Flex',sans-serif; font-size:13px;
}
.dg-chat-input-bar input:focus{ outline:none; border-color: var(--dg-blue); }
/* iOS Safari hace zoom automático al enfocar cualquier input con font-size menor a 16px —
   no es algo que se pueda desactivar con user-scalable=no sin romper el pinch-zoom de todo el
   portal, la única forma real de evitarlo es que el campo mida 16px+ en mobile. Tiene que
   quedar DESPUÉS de la regla base de arriba (misma especificidad — gana la última en orden
   de aparición, no la del media query si aparece antes en el archivo). */
@media (max-width:600px){ .dg-chat-input-bar input{ font-size:16px; } }
.dg-chat-input-bar button{
  width:36px; height:36px; border-radius:50%; border:none; background: var(--dg-blue); color:#fff;
  display:flex; align-items:center; justify-content:center; cursor:pointer; flex-shrink:0;
  transition: background .15s var(--dg-ease-standard), transform .15s var(--dg-ease-spring);
}
.dg-chat-input-bar button:hover:not(:disabled){ background: var(--dg-blue-dark); }
.dg-chat-input-bar button:disabled{ opacity:0.5; cursor:default; }

/* ---------- modal genérico (alta de cliente, etc.) ---------- */

/* Animación real de apertura/cierre (2026-08-26) — coreografía tomada del código fuente
   oficial de @material/web (dialog/internal/animations.ts): el diálogo real de Google desliza
   -50px→0 en 500ms EMPHASIZED al abrir y 0→-50px en 150ms EMPHASIZED_ACCELERATE al cerrar, con
   el scrim en fade lineal. Acá se logra 100% con CSS (sin tocar el JS de apertura/cierre de
   ninguna página — todas ya usan el mismo patrón classList.toggle('show')): la superposición
   pasa de display:none/flex a opacity+visibility, así el toggle de la clase .show dispara la
   transición en ambos sentidos solo. Duraciones acortadas (350ms/160ms) para sentirse ágil en
   web sin perder la asimetría real (abrir más lento y "importante", cerrar rápido). */
.dg-modal-overlay{
  position:fixed; inset:0; background: rgba(2,61,105,0.45); display:flex; align-items:center; justify-content:center;
  padding:20px; z-index:1300; opacity:0; visibility:hidden;
  transition: opacity .16s var(--dg-ease-emphasized-accel), visibility 0s linear .16s;
}
/* z-index 1300 (2026-08-26, antes 1000) — dgConfirm() se usa para confirmar el borrado de una
   conversación desde ADENTRO del panel de chat flotante (z-index:1200), así que el diálogo de
   confirmación tiene que quedar por encima de eso, no solo del contenido normal de la página. */
.dg-modal-overlay.show{
  opacity:1; visibility:visible;
  transition: opacity .35s var(--dg-ease-emphasized), visibility 0s linear 0s;
}
.dg-modal-overlay .dg-modal{
  transform: translateY(-24px); opacity:0;
  transition: transform .16s var(--dg-ease-emphasized-accel), opacity .16s linear;
}
.dg-modal-overlay.show .dg-modal{
  transform: translateY(0); opacity:1;
  transition: transform .35s var(--dg-ease-emphasized), opacity .3s linear;
}
@media (prefers-reduced-motion: reduce){
  .dg-modal-overlay, .dg-modal-overlay .dg-modal{ transition-duration: .01ms !important; }
}
/* Dialog M3 — verificado vía Figma MCP (kit oficial, node 50723:10948 "Basic dialog"). Radio 28px
   (no 18px), título en Headline Small real (24px/32, weight 400). Fondo se mantiene blanco (no
   surface-container-high real #ECE6F0) por la misma razón que Card/Menu — coordinar con la paleta
   azul ya establecida en vez de mezclar el tono cálido de M3. */
/* Borde fino en vez de sombra (Expressive, 2026-08-25), radio 32px (antes 28px). */
.dg-modal{
  background: var(--dg-surface); border-radius:32px; padding: clamp(20px,3vw,26px); max-width:540px; width:100%;
  max-height:88vh; overflow-y:auto; border:1px solid var(--dg-border);
}
.dg-modal-head{ display:flex; align-items:center; justify-content:space-between; margin-bottom:16px; }
.dg-modal-head h3{ margin:0; font-family:'Google Sans Flex',sans-serif; font-weight:400; font-size:24px; line-height:32px; letter-spacing:0; color: var(--dg-text); }
.dg-modal-close{ background:none; border:none; font-size:22px; line-height:1; cursor:pointer; color: var(--dg-text-muted); padding:4px 8px; }
.dg-modal-close:hover{ color: var(--dg-text); }

/* ---------- shell con sidebar de navegación (estructura base de la plataforma) ---------- */

/* Prueba M3 Expressive (2026-08-27): fondo lavanda de --dg-m3x-page-bg detrás del riel
   "sin soporte" y alrededor de la tarjeta de contenido de .dg-main (ver abajo). */
.dg-shell{ display:flex; min-height:100vh; min-height:100dvh; align-items:stretch; background: var(--dg-m3x-page-bg); }

/* Riel "sin soporte" (prueba 2026-08-27, referencia Figma M3 Design Kit): antes era un drawer
   flotante con fondo propio y radio 24px (ver git history) — ahora los ítems van directo sobre
   el fondo de .dg-shell, sin tarjeta ni borde, como en la referencia. La tarjeta de contenido
   pasó a .dg-main, invirtiendo qué elemento "flota" en la jerarquía visual. */
/* Riel angosto fijo (2026-08-28) — después de varias vueltas tratando de animar bien el
   expandir/colapsar (ver git history si hace falta rescatar algo), se simplifica a un solo
   estado permanente: ícono + nombre de sección abajo, siempre. La hamburguesa queda como
   referencia visual del kit M3, sin función de expandir — ya no hay dgToggleSidebar ni GSAP acá. */
.dg-sidebar{
  /* 88px→92px (2026-09-15) — el mínimo extra que necesita el label agrandado. Se probó el ancho
     96px + ícono 24px literal del kit de Figma y quedó "grande, raro" (feedback directo) — el
     ícono vuelve a su tamaño original, ver .dg-sidebar-icon-wrap más abajo. */
  width:92px; flex-shrink:0; background:transparent;
  display:flex; flex-direction:column; padding:20px 8px; gap:28px;
  position:sticky; top:0; height:100vh; height:100dvh;
  margin:0;
  overflow-y:auto; overflow-x:hidden;
  transition: background-color .25s ease;
}
/* 2026-09-29: se prueba diferenciar el riel por color de fondo en vez de la línea divisoria
   (revertido el criterio de 2026-09-04, pedido explícito de Julio: sacar el border-right y
   que el riel tome un fondo levemente más oscuro con el submenú de área expandido, con un
   fade suave en vez de un corte). --dg-hover-strong ya está pensado para dar contraste real
   sobre --dg-bg en el sidebar (ver definición de la variable). */
.dg-shell.has-submenu:not(.submenu-collapsed) .dg-sidebar{
  background: var(--dg-hover-strong);
}
.dg-sidebar-brand{ padding:0; }

.dg-sidebar-toggle{
  display:flex; align-items:center; justify-content:center; gap:0; width:100%; padding:11px; border-radius:100px;
  border:none; background:none; font-family:'Google Sans Flex',sans-serif; font-size:14px; font-weight:500;
  color: var(--dg-text-muted); text-align:left; cursor:pointer;
  transition: background .15s ease, color .15s ease;
}
.dg-sidebar-toggle svg{ flex-shrink:0; }
.dg-sidebar-toggle:hover{ background: var(--dg-blue-light); color: var(--dg-text); }
.dg-sidebar-toggle > span{ opacity:0; width:0; overflow:hidden; white-space:nowrap; }

.dg-sidebar-link.active::after{ display:none; }
/* Tipografía más grande que el original (2026-09-15) — 10px→12px, pero el ícono/wrap vuelven a
   su tamaño de siempre (ver nota abajo) tras dos rondas de feedback: agrandar el ícono también
   "se ve raro" en este layout, aunque sea el tamaño literal del M3 Design Kit de Figma. El wrap
   automático a 2 líneas no rompe de forma confiable en nombres con "/" sin espacio
   ("Compras/Facturación" terminaba truncado en una sola línea, "Compras/Fac…") — se arregla con
   un <br> a mano en el label mismo (ver DG_AREA_LABEL_SIDEBAR en dg-common.js), mismo patrón que
   ya usaba "Usuarios y roles". line-clamp queda como red de seguridad, no como mecanismo
   principal de wrap. */
.dg-sidebar-link > span:not(.dg-sidebar-icon-wrap){
  font-size:12px; line-height:14px; font-weight:500; white-space:normal;
  display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden; text-overflow:ellipsis;
  width:100%; text-align:center; opacity:1;
}
/* Óvalo de "seleccionado"/"hover" solo alrededor del ícono (referencia M3, 2026-08-28) — no
   sobre toda la fila (eso taparía el nombre de abajo). El fondo "crece desde el centro" con un
   ::before escalado en vez de aparecer de golpe (pedido explícito) — el tamaño del wrapper en sí
   es siempre el mismo, así nada empuja al label de abajo al pasar el mouse. */
.dg-sidebar-link.active,
.dg-sidebar-link:hover{ background:none; }
.dg-sidebar-icon-wrap{
  position:relative; display:flex; align-items:center; justify-content:center; flex-shrink:0;
  /* Tamaño original 44×28 (revertido dos veces ya — ni 52×34 ni el 56×32 literal de Figma
     quedaron bien acá, feedback directo del usuario en ambos casos). */
  width:44px; height:28px;
}
.dg-sidebar-icon-wrap::before{
  content:''; position:absolute; inset:0; border-radius:100px; background: var(--dg-blue-light);
  transform: scale(0); transition: transform .18s var(--dg-ease-standard); z-index:0;
}
.dg-sidebar-link.active .dg-sidebar-icon-wrap::before,
.dg-sidebar-link:hover .dg-sidebar-icon-wrap::before{ transform: scale(1); }
.dg-sidebar-icon-wrap .material-symbols-outlined{ position:relative; z-index:1; }
/* Ítem activo: ícono en fill (referencia M3) — el resto queda outlined. */
.dg-sidebar-link.active .material-symbols-outlined{
  font-variation-settings: 'FILL' 1, 'wght' 400, 'GRAD' 0, 'opsz' 24;
}

/* La cabecera de página (dg-page-head) muestra solo el logo, sin título ni subtítulo —
   dgRenderPageHeadLogo() en dg-common.js vacía .app-title y deja únicamente esta imagen. */
.page-head-logo{ height:50px; }
/* El archivo real (logo_DG_SF_LN.webp — "sin fondo, letras negras") solo existe en negro; no hay
   una versión blanca alojada en drogueriagarzon.com (probado, devuelve el fallback HTML del sitio
   para cualquier otro nombre). brightness(0) invert(1) lo pasa a blanco sólido sin necesitar un
   asset nuevo — funciona porque el logo es de un solo color sobre fondo transparente. */
[data-theme="dark"] .page-head-logo{ filter: brightness(0) invert(1); }

.dg-sidebar-nav{ display:flex; flex-direction:column; gap:4px; flex:1; }
.dg-sidebar-link{
  /* 56px→62px (2026-09-15) — el margen justo para el label agrandado (hasta 2 líneas), con el
     ícono en su tamaño original de siempre. */
  display:flex; flex-direction:column; justify-content:center; align-items:center; gap:3px;
  padding:9px 2px; border-radius:16px; position:relative; min-height:62px;
  font-size:14px; font-weight:500; color: var(--dg-text-muted);
  transition: background .15s ease, color .15s ease;
}
/* Color del texto en "seleccionado" — el fondo va en el óvalo del ícono (ver bloque de arriba),
   no acá. */
.dg-sidebar-link.active{ color: var(--dg-blue-dark); font-weight:600; }

/* Bloque fijo al fondo del riel (ej. "Cerebro") — al ser hermano de .dg-sidebar-nav (que
   tiene flex:1), queda empujado hasta abajo del todo sin necesitar position/margin extra. */
.dg-sidebar-nav-bottom{ display:flex; flex-direction:column; gap:4px; }
/* Separa el nav de áreas del bloque de herramientas internas (Usuarios y roles, Cerebro,
   Storybook) — hermano flex de ambos <nav>, el gap:28px de .dg-sidebar ya le da aire arriba/abajo. */
.dg-sidebar-divider{ height:1px; background: var(--dg-border); flex-shrink:0; }

/* Panel de submenú de área (PRUEBA, 2026-09-04) — hermano de .dg-sidebar, se inyecta por JS
   (dgRenderSubmenu en dg-common.js) solo cuando el área activa tiene subitems en DG_SUBMENU.
   "Sin soporte" como el riel de íconos (sin tarjeta, sin borde, sin sombra) — referencia real:
   Gmail, donde el riel de Mail/Chat/Meet y la columna de Redactar/Recibidos/Etiquetas son dos
   franjas pegadas, cada una con su propio fondo plano, sin card que las separe. Acá comparte
   --dg-m3x-page-bg con el fondo general de .dg-shell (se "funde" con él, mismo fondo que el
   riel) — lo que diferencia al riel es la línea de borde de arriba (.has-submenu), no un color
   de fondo distinto (probado y descartado a pedido). .dg-main (que sí es card, con margen y
   radio) sigue flotando a la derecha de todo esto sin cambios. padding-top calculado para que
   el primer link arranque a la misma altura que el primer ícono del riel (20px de padding del
   riel + ~42px de alto del botón hamburguesa + 28px de gap = 90px). Al colapsar (hamburguesa
   del riel) se achica a 0 con transición — .dg-main, con flex:1, ocupa el espacio liberado
   solo, sin JS extra. */
.dg-submenu{
  width:220px; flex-shrink:0; overflow:hidden;
  background: var(--dg-m3x-page-bg);
  padding:90px 12px 20px;
  display:flex; flex-direction:column; gap:2px;
  position:sticky; top:0; height:100vh; height:100dvh;
  transition: width .22s var(--dg-ease-standard), padding .22s var(--dg-ease-standard), opacity .16s ease;
}
.dg-submenu-title{
  font-size:11px; font-weight:700; text-transform:uppercase; letter-spacing:.06em;
  color: var(--dg-text-soft); padding:0 12px 10px; white-space:nowrap;
}
.dg-submenu-link{
  display:flex; align-items:center; gap:12px; padding:10px 14px; border-radius:100px;
  font-size:12px; font-weight:400; color: var(--dg-text-muted); white-space:nowrap;
  overflow:hidden; text-overflow:ellipsis;
  transition: background .15s ease, color .15s ease;
}
.dg-submenu-link .material-symbols-outlined{ font-size:20px; flex-shrink:0; }
.dg-submenu-link:hover{ background: var(--dg-blue-light); color: var(--dg-text); }
.dg-submenu-link.active{ background: var(--dg-blue-light); color: var(--dg-blue-dark); font-weight:600; }
/* Ítem activo: ícono en fill, mismo criterio que el riel (ver .dg-sidebar-link.active). */
.dg-submenu-link.active .material-symbols-outlined{
  font-variation-settings: 'FILL' 1, 'wght' 400, 'GRAD' 0, 'opsz' 24;
}
/* Badge para ítems de submenú cuya fuente de datos todavía no existe (ej. "Pedidos" en Compras
   y Facturación — no hay Libro de pedido en ninguna fuente hoy). La página sigue siendo un link
   normal y clickeable: adentro explica el gap, en vez de deshabilitar la navegación. */
.dg-submenu-badge{
  margin-left:auto; flex-shrink:0; font-size:9.5px; font-weight:700; text-transform:uppercase;
  letter-spacing:.03em; color: var(--dg-warn-text); background: var(--dg-warn-bg, rgba(255,159,10,.14));
  padding:2px 7px; border-radius:100px; white-space:nowrap;
}
.dg-shell.submenu-collapsed .dg-submenu{
  width:0; padding:90px 0 20px; opacity:0; pointer-events:none;
}
@media (max-width:780px){
  .dg-submenu{ display:none; }
}

/* Superficie blanca de contenido (prueba M3 Expressive, 2026-08-27) — antes era la sidebar la
   que "flotaba" como tarjeta sobre el fondo; acá se invierte: el riel queda sin soporte y todo
   el contenido del dashboard pasa a vivir dentro de esta tarjeta blanca, radio Corner/Extra-large
   (28px) del kit de referencia. */
.dg-main{
  flex:1; min-width:0; padding: 0 clamp(16px,3vw,32px);
  background: var(--dg-surface); border-radius:28px;
  margin:12px 12px 12px 0;
}
.dg-main .app-body{ max-width:none; margin:0; padding:0 0 32px; }

/* Encabezado de cada dashboard de área (Ventas, Comercial, Recepción, etc.) — barra blanca
   sticky con punto + título + subtítulo, mismo tratamiento que el .hdr original de Recepción
   (node de referencia: dashboard_recepcion_template.html de Lucas), generalizado para el resto
   de las áreas. z-index bajo a propósito: el menú de usuario/notificaciones (dg-user-dropdown,
   z-index:1100 — subido desde 120 el 2026-08-26 porque el mapa de Leaflet en Logística usa
   z-index internos de hasta ~1000 en sus controles, y se comía el dropdown) siempre tiene que
   quedar por encima de esta barra al hacer scroll. */
.dg-dash-hdr{
  background:var(--dg-surface); border-bottom:1px solid var(--dg-border); padding:14px 20px;
  display:flex; align-items:center; gap:12px; position:sticky; top:0; z-index:10;
  margin-bottom:20px;
}
.dg-dash-hdr .dot{ width:10px; height:10px; border-radius:50%; background: var(--dg-blue); flex-shrink:0; }
.dg-dash-hdr h1{ margin:0; font-family:'Google Sans Flex',sans-serif; font-weight:700; font-size:16px; color: var(--dg-navy); }
.dg-dash-hdr p{ margin:2px 0 0; font-family:'Google Sans Flex',sans-serif; font-size:11px; color: var(--dg-text-muted); }

.dg-page-head{ display:flex; align-items:center; justify-content:space-between; padding: 24px 4px 24px; flex-wrap:wrap; gap:14px; }
.dg-page-head .app-title{ display:flex; align-items:center; gap:12px; }
.dg-page-head .app-title .dot{ width:10px; height:10px; border-radius:50%; background: var(--dg-blue); }
.dg-page-head .app-title h2{ margin:0; font-size:20px; font-weight:700; color: var(--dg-text); }
.dg-page-head .app-title span{ font-size:11.5px; color: var(--dg-text-muted); font-weight:400; }

.dg-topright{ display:flex; align-items:center; gap:10px; }

/* ---------- Metabar de Compras y Facturación (Productos/Laboratorios/Proveedores/Ajustes) ---------- */
.dg-metabar{
  display:flex; align-items:center; gap:22px; flex-wrap:wrap;
  padding:9px 4px; margin:-10px 0 18px;
  border-top:1px solid var(--dg-border); border-bottom:1px solid var(--dg-border);
  font-size:11.5px; color: var(--dg-text-muted);
}
.dg-metabar .m b{ color: var(--dg-text); font-weight:700; margin-left:4px; }
.dg-metabar-sp{ flex:1; }
.dg-metabar-sync{ display:flex; align-items:center; gap:6px; font-size:11px; color: var(--dg-text-soft); }
.dg-metabar-dot{ width:7px; height:7px; border-radius:50%; background: var(--dg-text-soft); flex-shrink:0; }
.dg-metabar-dot.ok{ background: #34c759; }

/* ---------- Drawer lateral (detalle al click en una fila) ---------- */
.dg-drawer-overlay{
  position:fixed; inset:0; background: rgba(0,0,0,.28); opacity:0; pointer-events:none;
  transition: opacity .2s ease; z-index:60;
}
.dg-drawer-overlay.open{ opacity:1; pointer-events:auto; }
.dg-drawer{
  position:fixed; top:0; right:0; bottom:0; width:420px; max-width:92vw;
  background: var(--dg-surface); border-left:1px solid var(--dg-border);
  box-shadow: -8px 0 28px rgba(0,0,0,.12);
  transform: translateX(100%); transition: transform .22s var(--dg-ease-standard, ease);
  z-index:61; display:flex; flex-direction:column;
}
.dg-drawer.open{ transform: translateX(0); }
.dg-drawer-head{
  display:flex; align-items:flex-start; justify-content:space-between; gap:12px;
  padding:20px 20px 14px; border-bottom:1px solid var(--dg-border);
}
.dg-drawer-titulo{ font-size:15px; font-weight:700; color: var(--dg-text); line-height:1.4; }
.dg-drawer-close{
  background:none; border:none; font-size:22px; line-height:1; color: var(--dg-text-soft);
  cursor:pointer; padding:2px 4px; flex-shrink:0;
}
.dg-drawer-close:hover{ color: var(--dg-text); }
.dg-drawer-body{ padding:18px 20px; overflow-y:auto; flex:1; }
.dg-drawer-row{
  display:flex; align-items:center; justify-content:space-between; gap:12px;
  padding:10px 0; border-bottom:1px solid var(--dg-border); font-size:12.5px;
}
.dg-drawer-row:last-child{ border-bottom:none; }
.dg-drawer-row .lbl{ color: var(--dg-text-muted); }
.dg-drawer-row .val{ color: var(--dg-text); font-weight:600; text-align:right; }
.dg-table tbody tr.clickable{ cursor:pointer; }
.dg-table tbody tr.clickable:hover{ background: var(--dg-blue-light); }

/* ---------- Campanita de notificaciones ---------- */
.dg-notif-wrap{ position:relative; }
.dg-notif-bell{
  position:relative; width:40px; height:40px; border-radius:50%; border:none; background: var(--dg-blue-tint);
  display:flex; align-items:center; justify-content:center; color: var(--dg-text-muted); cursor:pointer;
  transition: color .15s ease;
}
.dg-notif-bell:hover{ color: var(--dg-text); }
.dg-notif-badge{
  position:absolute; top:2px; right:2px; min-width:16px; height:16px; padding:0 4px; border-radius:100px;
  background: var(--dg-crit-text); color:#fff; font-size:10px; font-weight:700; letter-spacing:0.2px;
  display:flex; align-items:center; justify-content:center;
}
/* Mismo motion/radio que .dg-user-dropdown (2026-08-26) — antes display:none/block seco, sin
   animación; ahora scale+fade con la misma coreografía real de menu/internal/menu.ts. */
.dg-notif-preview, .dg-notif-panel{
  position:absolute; top: calc(100% + 8px); right:0; background: var(--dg-surface); border-radius:16px;
  box-shadow: var(--dg-shadow-pop); width:300px; padding:6px; z-index:1100;
  transform-origin: top right; transform: scale(0.85); opacity:0; visibility:hidden; pointer-events:none;
  transition: transform .13s var(--dg-ease-emphasized-accel), opacity .13s var(--dg-ease-emphasized-accel), visibility 0s linear .13s;
}
/* Preview (hover): solo un vistazo a las últimas 3, no marca nada como leído. */
.dg-notif-wrap:hover .dg-notif-preview{
  transform: scale(1); opacity:1; visibility:visible; pointer-events:auto;
  transition: transform .3s var(--dg-ease-emphasized), opacity .22s var(--dg-ease-standard), visibility 0s linear 0s;
}
.dg-notif-wrap.open .dg-notif-preview{ transform: scale(0.85); opacity:0; visibility:hidden; pointer-events:none; }
/* Panel completo (click): últimos 7 días, abrirlo marca todo como leído. */
.dg-notif-wrap.open .dg-notif-panel{
  transform: scale(1); opacity:1; visibility:visible; pointer-events:auto;
  transition: transform .3s var(--dg-ease-emphasized), opacity .22s var(--dg-ease-standard), visibility 0s linear 0s;
}
@media (prefers-reduced-motion: reduce){ .dg-notif-preview, .dg-notif-panel{ transition-duration:.01ms !important; } }
.dg-notif-panel{ max-height:380px; overflow-y:auto; }
.dg-notif-preview-head, .dg-notif-panel-head{
  font-size:10.5px; font-weight:700; color: var(--dg-text-soft); text-transform:uppercase; letter-spacing:0.4px;
  padding:8px 8px 6px;
}
.dg-notif-panel-sub{ text-transform:none; font-weight:500; color: var(--dg-text-soft); letter-spacing:0; }
.dg-notif-item{ display:flex; align-items:flex-start; gap:8px; padding:8px; border-radius:10px; transition: background .15s var(--dg-ease-standard); }
.dg-notif-item:hover{ background: var(--dg-bg-hover); }
.dg-notif-item .dg-notif-dot{ width:8px; height:8px; border-radius:50%; background: transparent; margin-top:6px; flex-shrink:0; }
.dg-notif-item.unread .dg-notif-dot{ background: var(--dg-blue); }
.dg-notif-text{ font-size:12.5px; color: var(--dg-text); line-height:1.4; }
.dg-notif-time{ font-size:10.5px; color: var(--dg-text-soft); margin-top:2px; }
.dg-notif-empty{ padding:18px 8px; text-align:center; font-size:12px; color: var(--dg-text-soft); }

.dg-user-menu{ position:relative; }
.dg-user-trigger{
  display:flex; align-items:center; gap:10px; background: var(--dg-blue-tint); border:none; border-radius:100px;
  padding:6px 16px 6px 6px; cursor:pointer; font-family:'Google Sans Flex',sans-serif;
  transition: transform .15s var(--dg-ease-spring);
}
.dg-user-trigger:active{ transform: scale(0.96); }
.dg-user-avatar{
  width:32px; height:32px; border-radius:50%; background: var(--dg-blue);
  color:#fff; font-weight:700; font-size:12px; letter-spacing:0.3px; display:flex; align-items:center; justify-content:center; flex-shrink:0;
}
.dg-user-info{ text-align:left; line-height:1.25; }
.dg-user-name{ display:block; font-size:12.5px; font-weight:700; color: var(--dg-text); }
.dg-user-rol{ display:block; font-size:10.5px; color: var(--dg-text-muted); }
.dg-user-trigger .chev{ color: var(--dg-text-soft); transition: transform .15s ease; flex-shrink:0; }
.dg-user-menu.open .dg-user-trigger .chev{ transform: rotate(180deg); }
/* Menu — 2026-08-26, actualizado a la dirección Expressive (esto se nos había pasado en el
   rollout general: quedó con el radio/shadow/timing viejo mientras el resto de la plataforma
   ya estaba actualizada). Radio 16px (antes 12px), ítems con radio 8px (antes 4px) y motion real:
   coreografía tomada de menu/internal/menu.ts de @material/web (abre 500ms EMPHASIZED, cierra
   150ms EMPHASIZED_ACCELERATE — acá acortado a 300/130ms para sentirse ágil en web), mismo
   técnica 100% CSS que el diálogo (opacity+visibility+transform, sin tocar el JS de
   dgToggleUserMenu). Superficie blanca — ver nota histórica sobre --dg-surface en :root. */
.dg-user-dropdown{
  position:absolute; top: calc(100% + 8px); right:0; background: var(--dg-surface); border:none; border-radius:16px;
  box-shadow: var(--dg-shadow-pop); padding:4px; min-width:190px; z-index:1100;
  transform-origin: top right; transform: scale(0.85); opacity:0; visibility:hidden; pointer-events:none;
  transition: transform .13s var(--dg-ease-emphasized-accel), opacity .13s var(--dg-ease-emphasized-accel), visibility 0s linear .13s;
}
.dg-user-menu.open .dg-user-dropdown{
  transform: scale(1); opacity:1; visibility:visible; pointer-events:auto;
  transition: transform .3s var(--dg-ease-emphasized), opacity .22s var(--dg-ease-standard), visibility 0s linear 0s;
}
@media (prefers-reduced-motion: reduce){ .dg-user-dropdown{ transition-duration:.01ms !important; } }
.dg-user-dropdown > button{
  width:100%; text-align:left; background:none; border:none; padding:12px; border-radius:8px;
  font-family:'Google Sans Flex',sans-serif; font-size:14px; font-weight:500; letter-spacing:0.1px; line-height:20px;
  color: var(--dg-crit-text); cursor:pointer; transition: background .15s var(--dg-ease-standard);
}
.dg-user-dropdown > button:hover{ background: var(--dg-crit-bg); }
.dg-user-dropdown-link{
  display:block; width:100%; text-align:left; padding:12px; border-radius:8px;
  font-family:'Google Sans Flex',sans-serif; font-size:14px; font-weight:500; letter-spacing:0.1px; line-height:20px;
  color: var(--dg-text); cursor:pointer; transition: background .15s var(--dg-ease-standard);
}
/* Hover real M3: state layer on-surface al 8% de opacidad, NO un color sólido distinto — con fondo
   surface-container-low (#F7F2FA), un gris sólido tipo --dg-bg-hover quedaba casi invisible. */
.dg-user-dropdown-link:hover{ background: rgba(29,27,32,0.08); }

/* Hamburguesa de la barra móvil (dg-page-head) — solo visible bajo 780px. Distinta del
   .dg-sidebar-toggle de escritorio (que colapsa a solo íconos): en mobile no hay estado
   "colapsado", el riel es un drawer que está abierto o cerrado del todo. */
.dg-mobile-hamburger{
  display:none; width:40px; height:40px; border-radius:50%; border:none; background:transparent;
  cursor:pointer; align-items:center; justify-content:center; color: var(--dg-text-muted); flex-shrink:0;
}
.dg-mobile-hamburger:hover{ background: var(--dg-hover-strong); color: var(--dg-text); }

.dg-mobile-overlay{
  display:none; position:fixed; inset:0; background: rgba(2,61,105,0.45); z-index:150;
  opacity:0; transition: opacity .22s ease;
}
.dg-mobile-overlay.show{ display:block; opacity:1; }

@media (max-width: 780px){
  .dg-mobile-hamburger{ display:flex; }

  .dg-shell{ flex-direction:column; }

  /* El riel pasa a ser un drawer fijo que entra desde la izquierda (mismo patrón que el menú
     lateral de Gmail en mobile) — oculto por defecto, se abre con la hamburguesa de dg-page-head.
     El riel angosto (88px, ícono+caption) es solo para escritorio — en mobile siempre se ve
     expandido (fila, ícono+label, píldora de toda la fila), sin excepción, ya no depende de
     ningún estado (el toggle de escritorio se eliminó del todo, ver dg-common.js). */
  .dg-sidebar{
    position:fixed; top:0; left:0; width:260px; max-width:82vw; height:100vh; height:100dvh;
    margin:0; border-radius:0; background: var(--dg-surface);
    padding:24px 16px; gap:24px; overflow-y:auto; overflow-x:hidden;
    box-shadow: var(--dg-shadow-pop); z-index:200;
    transform: translateX(-100%); transition: transform .28s cubic-bezier(0.4,0,0.2,1);
  }
  .dg-sidebar.mobile-open{ transform: translateX(0); }
  .dg-sidebar-brand{ display:none; }
  .dg-sidebar-nav{ flex-direction:column; }
  .dg-sidebar-link.active::after{ display:none; }
  .dg-sidebar-link{
    padding:12px 16px; gap:12px; flex-direction:row; justify-content:flex-start; align-items:center;
    min-height:auto; border-radius:100px;
  }
  .dg-sidebar-link > span:not(.dg-sidebar-icon-wrap){
    opacity:1; width:auto; max-width:none; font-size:14px; line-height:normal; white-space:nowrap; text-align:left;
  }
  .dg-sidebar-link.active,
  .dg-sidebar-link:hover{ background: var(--dg-blue-light); }
  .dg-sidebar-icon-wrap{ width:auto; height:auto; }
  .dg-sidebar-icon-wrap::before{ display:none; }

  .dg-main{ padding: 0 14px; margin:12px; border-radius:20px; }

  /* Logo centrado de verdad (position:absolute) sin importar el ancho de los elementos
     a los costados — hamburguesa a la izquierda, avatar de usuario a la derecha. */
  .dg-page-head{ position:relative; padding:14px 4px; }
  .dg-page-head .app-title{ position:absolute; left:50%; top:50%; transform: translate(-50%, -50%); }
  .page-head-logo{ height:37.5px; }

  .dg-user-info{ display:none; }
  .dg-user-trigger{ padding:4px; }
}

/* ---------- auth (login / registro) — spec real de Text field Outlined (52798:24407) ---------- */

.auth-wrap{ min-height:100vh; display:flex; background: var(--dg-navy); }

.auth-hero{ flex:1; background: var(--dg-blue); }

.auth-form-panel{
  width:min(54%, 720px); flex-shrink:0; background: var(--dg-surface); display:flex; align-items:flex-start;
  justify-content:center; padding: 96px clamp(28px,6vw,96px) 40px; overflow-y:auto;
}
.auth-card{ width:100%; max-width:360px; }
.auth-card .auth-brand{ display:flex; align-items:center; gap:10px; margin-bottom:36px; }
.auth-card .auth-brand img{ height:48px; }
.auth-card h1{ font-family:'Google Sans Flex',sans-serif; font-weight:400; font-size:26px; line-height:1.3; color: var(--dg-text); margin:0 0 8px; }
.auth-card .auth-sub{ font-size:13px; color: var(--dg-text-muted); margin:0 0 28px; line-height:1.6; }

/* Outlined: borde 1px en las 4 esquinas (radio 4px), label flotante que corta el borde
   con un recorte del color de superficie detrás (no filled con fondo tonal). */
.auth-field{ margin-bottom:24px; margin-top:12px; position:relative; }
.auth-field label{
  position:absolute; top:0; left:12px; transform: translateY(-50%);
  font-family:'Google Sans Flex',sans-serif; font-size:12px; line-height:16px; letter-spacing:0.4px;
  color: var(--dg-text-muted); background: var(--dg-surface); padding:0 4px;
}
.auth-field input, .auth-field select{
  width:100%; height:56px; font-family:'Google Sans Flex',sans-serif; font-size:16px; line-height:24px; letter-spacing:0.5px; font-weight:400;
  padding:16px 48px 16px 16px; border:1px solid var(--dg-outline);
  background: transparent; color: var(--dg-text);
  border-radius:8px;
}
/* Prueba de preview del 2026-08-29 (design system Airbnb) — validado en las dos pantallas de
   auth, se quedó solo el radio 8px y el foco en tinta (sin glow); el resto del reskin se
   descartó, ver rama preview/airbnb-design-test. */
.auth-field input:focus, .auth-field select:focus{ outline:none; border:2px solid var(--dg-text); padding:15px 47px 15px 15px; }
.auth-field:focus-within label{ color: var(--dg-text); }
/* Variante sin el label "cortando" un borde (2026-09-16) — .auth-field label es absoluto,
   pensado para flotar sobre el borde superior de un <input>/<select> real; en un campo que en
   vez de eso tiene un botón u otro contenido (ej. "Foto del remito" con un botón de subir en
   vez de un input), el label quedaba flotando encima y se superponía — bug real reportado. Se
   agrega esta clase al .auth-field cuando no hay un input/select adentro. */
.auth-field.auth-field-sinborde label{
  position:static; display:block; transform:none; padding:0; margin-bottom:8px; background:none;
}
.auth-field input::placeholder{ color: var(--dg-text-muted); opacity:0.7; }
.auth-field .field-icon{
  position:absolute; right:12px; top:50%; transform: translateY(-50%); width:24px; height:24px;
  color: var(--dg-text-muted); pointer-events:none; display:flex; align-items:center; justify-content:center;
}
/* El ícono de mail/lock es decorativo (pointer-events:none) — el de mostrar/ocultar
   contraseña sí tiene que ser clickeable, por eso reactiva pointer-events acá. */
.auth-field .field-icon.field-toggle-pass{
  pointer-events:auto; cursor:pointer; background:none; border:none; padding:0;
}

.auth-row{ display:flex; align-items:center; justify-content:space-between; margin:18px 0 40px; flex-wrap:wrap; gap:10px; }
.auth-remember{ display:flex; align-items:center; gap:8px; font-size:13.5px; font-weight:500; color: var(--dg-text); cursor:pointer; }
.auth-remember input{ display:none; }
.auth-remember .radio-dot{ width:18px; height:18px; border-radius:50%; border:2px solid var(--dg-outline); position:relative; flex-shrink:0; }
.auth-remember .radio-dot::after{ content:''; position:absolute; inset:3px; border-radius:50%; background: var(--dg-blue); }
.auth-link-muted{ font-size:13.5px; font-weight:500; color: var(--dg-blue); cursor:pointer; background:none; border:none; padding:0; font-family:'Google Sans Flex',sans-serif; }

.auth-error{ background: var(--dg-crit-bg); color: var(--dg-crit-text); border:none; font-size:12px; font-weight:500; padding:10px 14px; border-radius:4px; margin-bottom:16px; display:none; }
.auth-error.show{ display:block; }
.auth-ok{ background: var(--dg-ok-bg); color: var(--dg-ok-text); border:none; font-size:12px; font-weight:500; padding:10px 14px; border-radius:4px; margin-bottom:16px; display:none; }
.auth-ok.show{ display:block; }
.auth-card .btn-primary{ padding:14px 24px; font-size:15px; }
.auth-card .btn-primary:disabled{ opacity:0.38; cursor:default; }
.auth-actions{ display:flex; gap:16px; align-items:center; }
.auth-actions .btn-primary, .auth-actions .btn-outline{ flex:1; justify-content:center; padding:14px 20px; font-size:15px; }

.auth-foot{ text-align:left; font-size:12.5px; color: var(--dg-text-muted); margin-top:22px; }
.auth-foot a{ color: var(--dg-blue); font-weight:700; }

@media (max-width: 900px){
  .auth-hero{ display:none; }
  .auth-form-panel{ width:100%; padding: 32px 20px; }
}
