/* ── css/lk-tokens.css ── */
/* ══════════════════════════════════════════════════════════════════════════════
   LUZOkit Design Tokens — Canonical Source
   Versión: 2.4 (+ mint tokens para FC2 escritorio)
   Fecha:   2026-04-19

   REGLAS:
   1. Este archivo es la UNICA fuente de verdad para tokens CSS.
   2. lk-theme.css ya NO existe — todo vive aquí.
   3. Tokens estructurales (spacing, radius, font, z-index, motion, blur,
      layout) van solo en :root — NO cambian por tema.
   4. Tokens de color/superficie van en :root + [data-theme="darkmode"] +
      [data-theme="midnight"] — SIEMPRE los tres.
   5. Convención canónica: --lk-<categoría>-<variante>
   6. Sección BRIDGE al final mapea nombres legacy → canónicos.
      Se elimina progresivamente en T2–T4 al reescribir cada archivo.
   ══════════════════════════════════════════════════════════════════════════════ */


/* ── Light (default) + Estructurales ───────────────────────────────────────── */

:root {
  color-scheme: light;

  /* ─ Estructurales (invariantes por tema) ─ */

  --lk-layout-top-h:      52px;
  --lk-layout-footer-h:   32px;
  --lk-footer-h:          var(--lk-layout-footer-h);  /* alias publico: consumidores usan --lk-footer-h */
  --lk-dock-h:            58px;                       /* alto del dock movil (.bn-bar) */
  --lk-layout-rail-w:     52px;
  --lk-layout-panel-w:    210px;

  /* ─ Breakpoints · CONTRATO ÚNICO DE RESPONSIVE (RESP-01) ─
     Fuente única de verdad para TODO el sistema. Dos ejes:

       · SHELL  (viewport)  → cortes 640 / 1024  (DEC-01)
           <640   teléfono   · sin rail/panel, bottom-nav + bottom-sheet
           640–1023 tablet   · rail + panel-cajón sobre scrim
           ≥1024  escritorio · rail + panel en línea (colapsable)

       · MÓDULO (contenedor) → cortes 600 / 900   (RESP-02)
           ≤600   compacto   · el módulo responde a SU ancho real (no al viewport),
           601–900 regular      robusto al estado del rail. Se activa con .lk-cq
           >900   amplio        (container-type:inline-size) en la raíz del módulo.

     OJO CSS: var() NO se resuelve dentro de @media()/@container(). Estos tokens
     son la referencia declarativa + los consume el JS (LK.bp). En las reglas
     @media/@container se escriben los MISMOS literales; nunca inventar otro corte. */
  --lk-bp-sm:       640px;   /* shell · teléfono → tablet      */
  --lk-bp-lg:      1024px;   /* shell · tablet → escritorio    */
  --lk-cq-compact:  600px;   /* módulo · contenedor angosto    */
  --lk-cq-regular:  900px;   /* módulo · contenedor medio→ancho*/

  --lk-space-1:   4px;
  --lk-space-2:   8px;
  --lk-space-3:  12px;
  --lk-space-4:  16px;

  --lk-radius-sm:   4px;
  --lk-radius-md:   8px;
  --lk-radius-lg:  12px;
  --lk-radius-xl:  18px;

  --lk-font-xs:   11px;
  --lk-font-sm:   12px;
  --lk-font-md:   13px;
  --lk-font-lg:   15px;
  --lk-font-xl:   18px;
  --lk-font-sans: system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
  --lk-font-mono: 'SF Mono', ui-monospace, Menlo, monospace;

  --lk-z-dropdown:  100;
  --lk-z-sticky:    200;
  --lk-z-modal:     850;
  /* CEREMONIA DE LA LLAVE · la capa de la firma, por encima de CUALQUIER modal.
     Segunda vez que sale por debajo de lo que la invocó, y las dos por lo mismo:
     `lk-components.css:1414` aplana con !important toda la pila de LK.modal (que
     pide 8000, 8010…) a --lk-z-modal, así que la ceremonia EMPATA en 850 con el
     modal que la llamó y el desempate lo decide el orden del DOM — que ella
     pierde en cuanto el invocador crea su propio contexto de apilamiento o se
     monta después. Un empate no es una jerarquía: necesita capa propia.
     Por qué 895 y no otro. Lo que hay HOY por encima de 850 en core/css:
       860  .lk-vd--suelto · visor de documento            → la ceremonia va encima
       890  .lk-dropdown en modal (--lk-z-modal + 40)      → la ceremonia va encima
       900  --lk-z-toast · el aviso flotante               → NO se le pasa por encima
       9000 .sv-tt-portal · 9500 .lk-avcard/.lk-ctx · 9600 tooltip · 9999 Spotlight
     Un aviso, un menú contextual o un tooltip DEBEN seguir viéndose sobre la
     ceremonia: son efímeros y no tapan la decisión que se está tomando. 895 es el
     último hueco antes del toast y queda por encima de todo lo que sí debe ir
     debajo. Lo consume `core/lk-llave.js::_css` — ver la nota de ahí. */
  --lk-z-llave:     895;
  --lk-z-toast:     900;

  --lk-transition-fast:    120ms ease;
  --lk-transition-normal:  220ms ease;

  --lk-blur-sm:  blur(8px);
  --lk-blur-md:  blur(16px);

  /* ─ Surfaces ─ */

  --lk-bg-body:      #f1f5f9;
  --lk-bg-card:      #ffffff;
  --lk-bg-surface:   #f8fafc;
  --lk-bg-sidebar:   #ffffff;
  --lk-bg-topbar:    rgba(255,255,255,.92);
  --lk-bg-hover:     rgba(0,0,0,.05);
  --lk-bg-active:    color-mix(in srgb, var(--lk-brand) 10%, transparent);
  --lk-bg-selected:  color-mix(in srgb, var(--lk-brand) 14%, var(--lk-bg-card));

  /* ─ Text ─ */

  --lk-text-primary:    #0f172a;
  --lk-text-secondary:  #334155;
  --lk-text-muted:      #475569;
  --lk-text-faint:      #94a3b8;
  --lk-text-inverse:    #ffffff;

  /* ─ Border ─ */

  --lk-border:       rgba(0,0,0,.12);
  --lk-border-soft:  rgba(0,0,0,.06);

  /* ─ Brand ─ */

  --lk-brand:           #7350ac;
  --lk-brand-soft:      #7c3aed;   /* tono propio de la rampa (mockup), NO derivado */
  --lk-brand-muted:     color-mix(in srgb, var(--lk-brand) 15%, transparent);
  --lk-brand-hover:     color-mix(in srgb, var(--lk-brand) 85%, transparent);
  --lk-brand-border:    color-mix(in srgb, var(--lk-brand) 30%, transparent);
  --lk-brand-shadow:    color-mix(in srgb, var(--lk-brand) 25%, transparent);

  /* ─ Semantic ─ */

  --lk-red:          #dc2626;
  --lk-red-soft:     rgba(220,38,38,.10);
  --lk-green:        #16a34a;
  --lk-green-soft:   rgba(22,163,74,.10);

  /* ─ Mint (FC2 escritorio · waiting state) ─ */

  --lk-mint:         #16a34a;
  --lk-mint-soft:    rgba(22,163,74,.10);
  --lk-mint-surface: #f0fdf4;
  --lk-mint-text-on: #ffffff;
  --lk-amber:        #d97706;
  --lk-amber-soft:   rgba(217,119,6,.10);
  --lk-blue:         #2563eb;
  --lk-blue-soft:    rgba(37,99,235,.10);
  --lk-teal:         #0891b2;
  --lk-teal-soft:    rgba(8,145,178,.10);

  /* ─ Elevation ─ */

  --lk-shadow-sm:    0 1px 3px rgba(0,0,0,.3);
  --lk-shadow-md:    0 4px 16px rgba(0,0,0,.4);
  --lk-shadow-lg:    0 12px 40px rgba(0,0,0,.5);
  --lk-ring-focus:   0 0 0 3px color-mix(in srgb, var(--lk-brand) 25%, transparent);
}


/* ══════════════════════════════════════════════════════════════════════════════
   Dark — Neutral Gray (estilo Claude)
   Grises puros, cero tinte azul. Brand purple resalta sobre fondo neutro.
   ══════════════════════════════════════════════════════════════════════════════ */

[data-theme="darkmode"] {
  color-scheme: dark;

  --lk-bg-body:      #0b0b0d;   /* base casi negra, neutro frío */
  --lk-bg-card:      #17171b;   /* superficie apoyada: se DESPEGA del fondo (ΔL perceptible) */
  --lk-bg-surface:   #101013;   /* hundido (campos, riel de horas) */
  --lk-bg-sidebar:   #0e0e11;
  --lk-bg-topbar:    rgba(20,20,24,.72);
  --lk-bg-hover:     rgba(255,255,255,.045);
  --lk-bg-active:    color-mix(in srgb, var(--lk-brand) 22%, transparent);
  --lk-bg-selected:  color-mix(in srgb, var(--lk-brand) 18%, transparent);

  --lk-text-primary:    #e8e8e8;
  --lk-text-secondary:  #c0c0c0;
  --lk-text-muted:      #a0a0a0;
  --lk-text-faint:      #5c5c5c;
  --lk-text-inverse:    #121212;

  --lk-border:       rgba(255,255,255,.085);
  --lk-border-soft:  rgba(255,255,255,.045);

  --lk-brand:           #9179c9;
  --lk-brand-soft:      #a78bfa;
  --lk-brand-muted:     color-mix(in srgb, var(--lk-brand) 25%, transparent);
  --lk-brand-hover:     color-mix(in srgb, var(--lk-brand) 85%, transparent);
  --lk-brand-border:    color-mix(in srgb, var(--lk-brand) 40%, transparent);
  --lk-brand-shadow:    color-mix(in srgb, var(--lk-brand) 30%, transparent);

  --lk-red:          #f85149;
  --lk-red-soft:     rgba(248,81,73,.12);
  --lk-green:        #3fb950;
  --lk-green-soft:   rgba(63,185,80,.12);

  --lk-mint:         #5EEAD4;
  --lk-mint-soft:    rgba(94,234,212,.10);
  --lk-mint-surface: #0d1f1d;
  --lk-mint-text-on: #052020;
  --lk-amber:        #d29922;
  --lk-amber-soft:   rgba(210,153,34,.12);
  --lk-blue:         #58a6ff;
  --lk-blue-soft:    rgba(88,166,255,.12);
  --lk-teal:         #39c5cf;
  --lk-teal-soft:    rgba(57,197,207,.12);

  --lk-shadow-sm:    0 1px 4px rgba(0,0,0,.5);
  --lk-shadow-md:    0 4px 20px rgba(0,0,0,.6);
  --lk-shadow-lg:    0 12px 48px rgba(0,0,0,.7);
  --lk-ring-focus:   0 0 0 3px color-mix(in srgb, var(--lk-brand) 40%, transparent);
}


/* ══════════════════════════════════════════════════════════════════════════════
   Midnight — Deep Blue
   Azul profundo oceánico. Más oscuro que dark, con saturación azul en todo:
   fondos, bordes, hovers. Para quienes trabajan de noche.
   ══════════════════════════════════════════════════════════════════════════════ */

[data-theme="midnight"] {
  color-scheme: dark;

  --lk-bg-body:      #06080f;
  --lk-bg-card:      #0f1318;
  --lk-bg-surface:   #0a0e16;
  --lk-bg-sidebar:   #0c1019;
  --lk-bg-topbar:    rgba(8,12,22,.97);
  --lk-bg-hover:     rgba(130,160,255,.05);
  --lk-bg-active:    color-mix(in srgb, var(--lk-brand) 18%, transparent);
  --lk-bg-selected:  color-mix(in srgb, var(--lk-brand) 14%, transparent);

  --lk-text-primary:    #d4dae5;
  --lk-text-secondary:  #a8b2c4;
  --lk-text-muted:      #7b8ba0;
  --lk-text-faint:      #3d4d63;
  --lk-text-inverse:    #06080f;

  --lk-border:       rgba(100,140,220,.10);
  --lk-border-soft:  rgba(100,140,220,.05);

  --lk-brand:           #a390d0;
  --lk-brand-soft:      #a78bfa;
  --lk-brand-muted:     color-mix(in srgb, var(--lk-brand) 20%, transparent);
  --lk-brand-hover:     color-mix(in srgb, var(--lk-brand) 85%, transparent);
  --lk-brand-border:    color-mix(in srgb, var(--lk-brand) 35%, transparent);
  --lk-brand-shadow:    color-mix(in srgb, var(--lk-brand) 22%, transparent);

  --lk-red:          #f85149;
  --lk-red-soft:     rgba(248,81,73,.10);
  --lk-green:        #3fb950;
  --lk-green-soft:   rgba(63,185,80,.10);

  --lk-mint:         #5EEAD4;
  --lk-mint-soft:    rgba(94,234,212,.08);
  --lk-mint-surface: #061a1c;
  --lk-mint-text-on: #052020;
  --lk-amber:        #d29922;
  --lk-amber-soft:   rgba(210,153,34,.10);
  --lk-blue:         #58a6ff;
  --lk-blue-soft:    rgba(88,166,255,.10);
  --lk-teal:         #39c5cf;
  --lk-teal-soft:    rgba(57,197,207,.10);

  --lk-shadow-sm:    0 1px 4px rgba(0,0,0,.6);
  --lk-shadow-md:    0 4px 20px rgba(0,0,0,.7);
  --lk-shadow-lg:    0 12px 48px rgba(0,0,0,.85);
  --lk-ring-focus:   0 0 0 3px color-mix(in srgb, var(--lk-brand) 35%, transparent);
}


/* ══════════════════════════════════════════════════════════════════════════════
   BRIDGE — Legacy names → --lk-* canónicos
   CSS custom properties resuelven lazily: var(--bg-body) apunta a
   var(--lk-bg-body) que se resuelve al valor del tema activo en runtime.
   ══════════════════════════════════════════════════════════════════════════════ */

:root,
[data-theme="darkmode"],
[data-theme="midnight"] {

  /* ─ Surfaces ─ */
  --bg-body:        var(--lk-bg-body);
  --bg-card:        var(--lk-bg-card);
  --bg-surface:     var(--lk-bg-surface);
  --bg-sidebar:     var(--lk-bg-sidebar);
  --bg-topbar:      var(--lk-bg-topbar);
  --bg-hover:       var(--lk-bg-hover);
  --bg-active:      var(--lk-bg-active);
  --bg-selected:    var(--lk-bg-selected);
  --bg-secondary:   var(--lk-bg-hover);
  --panel:          var(--lk-bg-card);
  --tx-surface:     var(--lk-bg-surface);
  --tx-surface-2:   var(--lk-bg-card);

  /* ─ Text ─ */
  --tx-base:        var(--lk-text-primary);
  --tx-text:        var(--lk-text-primary);
  --tx-primary:     var(--lk-text-primary);
  --tx-main:        var(--lk-text-primary);
  --tx-secondary:   var(--lk-text-secondary);
  --tx-text-sec:    var(--lk-text-secondary);
  --tx-muted:       var(--lk-text-muted);
  --tx-dim:         var(--lk-text-faint);
  --tx-inverse:     var(--lk-text-inverse);

  /* ─ Border ─ */
  --border:         var(--lk-border);
  --border-soft:    var(--lk-border-soft);
  --tx-line:        var(--lk-border);

  /* ─ Brand ─ */
  --c-accent:        var(--lk-brand);
  --c-accent-soft:   var(--lk-brand-soft);
  --c-accent-muted:  var(--lk-brand-muted);
  --c-accent-bd:     var(--lk-brand-muted);
  --c-accent-lt:     var(--lk-bg-active);
  --accent:         var(--lk-brand);
  --accent-bd:      var(--lk-brand-muted);
  --accent-hov:     var(--lk-brand-hover);
  --accent-lt:      var(--lk-bg-active);

  /* ─ Shell aliases (luzokit-shell.css) ─ */
  --luzo-accent:         var(--lk-brand);
  --luzo-accent-border:  var(--lk-brand-muted);
  --luzo-accent-light:   var(--lk-bg-active);
  --luzo-accent-shadow:  var(--lk-brand-shadow);

  /* ─ Semantic ─ */
  --tx-red:       var(--lk-red);
  --tx-green:     var(--lk-green);
  --tx-mint:      var(--lk-mint);
  --mint:         var(--lk-mint);
  --mint-soft:    var(--lk-mint-soft);
  --mint-surface: var(--lk-mint-surface);
  --mint-text-on: var(--lk-mint-text-on);
  --tx-amber:     var(--lk-amber);
  --tx-blue:      var(--lk-blue);
  --tx-teal:      var(--lk-teal);

  /* ─ Elevation ─ */
  --shadow-sm:    var(--lk-shadow-sm);
  --shadow-md:    var(--lk-shadow-md);
  --shadow-lg:    var(--lk-shadow-lg);

  /* ─ Module bridge (com-center, comunicaciones) ─ */
  --lk-surface:         var(--lk-bg-surface);
  --lk-mod-line:        var(--lk-border-soft);
  --lk-prim-radius-md:  var(--lk-radius-md);

  /* ─ Structural (legacy names) ─ */
  --font-xs:    var(--lk-font-xs);
  --font-sm:    var(--lk-font-sm);
  --font-md:    var(--lk-font-md);
  --font-lg:    var(--lk-font-lg);
  --font-xl:    var(--lk-font-xl);
  --font-sans:  var(--lk-font-sans);
  --font-mono:  var(--lk-font-mono);
  --font-ui:    var(--lk-font-sans);
  --radius-sm:  var(--lk-radius-sm);
  --radius-md:  var(--lk-radius-md);
  --radius-lg:  var(--lk-radius-lg);
  --radius-xl:  var(--lk-radius-xl);
  --space-1:    var(--lk-space-1);
  --space-2:    var(--lk-space-2);
  --space-3:    var(--lk-space-3);
  --space-4:    var(--lk-space-4);
  --top-h:            var(--lk-layout-top-h);
  --topbar-h:         var(--lk-layout-top-h);
  --shell-topbar-h:   var(--lk-layout-top-h);
  --footer-h:         var(--lk-layout-footer-h);
  --rail-w:           var(--lk-layout-rail-w);
  --z-dropdown:       var(--lk-z-dropdown);
  --z-sticky:         var(--lk-z-sticky);
  --z-modal:          var(--lk-z-modal);
  --z-llave:          var(--lk-z-llave);
  --z-toast:          var(--lk-z-toast);
  --transition-fast:   var(--lk-transition-fast);
  --transition-normal: var(--lk-transition-normal);
  --blur-sm:           var(--lk-blur-sm);
  --blur-md:           var(--lk-blur-md);
  --mod-topbar-h:      0px;
}

/* ══════════════════════════════════════════════════════════════════════════════
   Parche A · E4 — énfasis + escala + eje material (Doc 07 §5, DEC-02/04, SHELL-11/13)
   F1: renombre --c-accent, --font-base, data-mode/theme.  F3: escala cableada + vintage.
   ══════════════════════════════════════════════════════════════════════════════ */
:root {
  --font-base: 13px;                                   /* store lo mueve 90/100/115/130% (F3) */
  --lk-font-xs: calc(var(--font-base) * 0.846);        /* 11/13 */
  --lk-font-sm: calc(var(--font-base) * 0.923);        /* 12/13 */
  --lk-font-md: var(--font-base);                      /* 13/13 */
  --lk-font-lg: calc(var(--font-base) * 1.154);        /* 15/13 */
  --lk-font-xl: calc(var(--font-base) * 1.385);        /* 18/13 */
}
[data-theme="lightmode"] { color-scheme: light; }      /* alias explícito del default (:root) */

/* ══════════════════════════════════════════════════════════════════════════════
   EJE MATERIAL · core/css/lk-tokens.css
   Reemplaza el bloque `data-mode: modern / flat / vintage` (SHELL-13/15)
   ──────────────────────────────────────────────────────────────────────────────
   DOS EJES ORTOGONALES. Ninguno pisa al otro:

     data-theme  →  LA PALETA.      Cuánta luz hay y de qué color.
                    lightmode · darkmode · midnight
                    Define: fondos, textos, marca, colores semánticos.

     data-mode   →  EL MATERIAL.    De qué está hecha la superficie.
                    grafito · glass · tint
                    Define: elevación, canto, luz ambiente, solidez.

   La regla que hace que 3×3 sea sostenible: el material NUNCA declara un color
   de marca ni un color semántico. Solo declara ESTRUCTURA. Por eso alcanza con
   tres bloques base + tres ajustes para claro, en vez de nueve bloques a mano.

   El material sí puede mover el CONTRASTE de las superficies dentro de la familia
   de su tema (tint hunde el fondo, glass lo vuelve translúcido). Lo que no puede
   es cambiar de familia: en midnight sigue siendo azul, en claro sigue siendo claro.
   ══════════════════════════════════════════════════════════════════════════════ */


/* ── Contrato: todo material declara estos cuatro. Sin excepción. ─────────── */

/* ══════════════════════════════════════════════════════════════════════════════
   GEOMETRIA DE LAS CAPAS FLOTANTES · una perilla por familia de ELEMENTO COMUN
   ──────────────────────────────────────────────────────────────────────────────
   Medido el 31-jul-2026 en la app: dentro de la MISMA familia -los menus- habia
   4 radios distintos (10, 11, 12 y ninguno), 2 grosores de borde y 3 rellenos.
   Son el mismo tipo de superficie y se veian distintas segun quien la hubiera
   escrito. Estas cifras son ahora el unico sitio donde se deciden.

   No se colapsa TODO a un valor: un menu y un modal no son el mismo elemento y
   cada familia conserva el suyo. Lo que se unifica es lo COMUN.               */
:root {
  /* menus, contextuales, desplegables y popovers */
  --lk-menu-radius:      11px;
  --lk-menu-border:      .5px;
  --lk-menu-pad:         5px;
  --lk-menu-item-radius: 8px;
  --lk-menu-item-pad:    9px 10px;
  --lk-menu-gap:         10px;

  /* HOVER DE LOS MENUS · decision del dueno (31-jul-2026): lleva el color de
     ENFASIS, no un gris neutro. Se toma de la variable de acento, que brand.js
     fija POR TENANT — nunca un hex fijo, o el menu dejaria de seguir la marca
     del centro. Una sola perilla para las dos piezas de menu.
     EXCEPCION: las acciones destructivas conservan su rojo; sus reglas van
     despues y ganan. */
  /* JERARQUIA, que es lo que da la informacion:
       HOVER  = enfasis SUAVIZADO (solo el tinte de fondo). El texto se queda en
                el color normal para que el gesto del raton no compita.
       ACTIVO = enfasis PLENO (tinte mas fuerte Y texto de acento). Es un estado,
                y tiene que verse mas que un simple paso por encima.
     Si el hover usara el acento entero, activo y hover se verian igual y el
     acento dejaria de significar "esto esta seleccionado". */
  --lk-menu-hover-bg:  var(--c-accent-muted, var(--lk-brand-muted));
  --lk-menu-hover-fg:  var(--lk-text-primary);
  --lk-menu-active-bg: color-mix(in srgb, var(--c-accent, var(--lk-brand)) 40%, transparent);
  --lk-menu-active-fg: var(--c-accent, var(--lk-brand));

  /* modales y superficies grandes */
  --lk-modal-radius:     16px;
  --lk-modal-border:     .5px;
}

:root {
  --lk-specular:      none;   /* canto iluminado en el borde superior         */
  --lk-ambient:       none;   /* luz de ambiente, capa de fondo del body      */
  --lk-surface-blur:  none;   /* desenfoque de material translúcido           */
  /* MATERIAL DE SUPERFICIE PEGADA · el mismo vidrio, con el radio que corresponde
     a una situación física distinta. Una superficie quieta (modal, menú, panel)
     desenfoca su fondo UNA vez y el resultado se reutiliza mientras nada se mueva.
     Una barra `sticky`/`fixed` sobre contenido que scrollea tiene un fondo NUEVO en
     cada cuadro, así que la convolución se rehace 60 veces por segundo. El coste de
     un desenfoque gaussiano separable crece con el RADIO, no con lo bonito que
     queda: bajarlo de 30 a 14 es aproximadamente la mitad de trabajo por cuadro.
     Y a 56px de alto, sobre un fondo que ya es de poco detalle, la diferencia no se
     ve. No es menos vidrio: es el valor correcto para una barra pegada. */
  --lk-surface-blur-fijo: none;
  --lk-surface-fill:  var(--lk-bg-card);   /* relleno real de una superficie  */
}


/* ══════════════════════════════════════════════════════════════════════════════
   GRAFITO · sólido con luz
   Superficies opacas. La elevación NO aclara el fondo: sube por canto iluminado
   y sombra corta. Una sola fuente de luz ambiental. Es el material por defecto.
   Costo de render: el mismo que hoy.
   ══════════════════════════════════════════════════════════════════════════════ */

[data-mode="grafito"] {
  --lk-surface-fill: var(--lk-bg-card);
  --lk-surface-blur: none;

  /* apoyado: canto de luz arriba + sombra corta (el canto es lo que eleva en oscuro) */
  --lk-shadow-sm: 0 1px 2px rgba(0,0,0,.35), inset 0 .5px 0 rgba(255,255,255,.05);
  --lk-shadow-md: 0 6px 16px -4px rgba(0,0,0,.5), 0 2px 6px -2px rgba(0,0,0,.4), inset 0 .5px 0 rgba(255,255,255,.06);
  --lk-shadow-lg: 0 16px 40px -12px rgba(0,0,0,.7), 0 4px 12px -4px rgba(0,0,0,.5), inset 0 .5px 0 rgba(255,255,255,.08);

  --lk-specular: inset 0 .5px 0 rgba(255,255,255,.08);
  --lk-ambient:  radial-gradient(80% 60% at 16% -14%,
                   color-mix(in srgb, var(--lk-brand) 13%, transparent), transparent 64%);
}

/* En claro la luz no se lee como un canto blanco — se lee como sombra breve.  */
[data-theme="lightmode"][data-mode="grafito"] {
  --lk-shadow-sm: 0 1px 2px rgba(15,23,42,.06), 0 0 0 .5px rgba(15,23,42,.04);
  --lk-shadow-md: 0 8px 24px -8px rgba(15,23,42,.16), 0 0 0 .5px rgba(15,23,42,.05);
  --lk-shadow-lg: 0 18px 48px -14px rgba(15,23,42,.22), 0 0 0 .5px rgba(15,23,42,.06);
  --lk-specular:  inset 0 1px 0 rgba(255,255,255,.75);
  --lk-ambient:   radial-gradient(75% 55% at 18% -12%,
                    color-mix(in srgb, var(--lk-brand) 5%, transparent), transparent 62%);
}


/* ══════════════════════════════════════════════════════════════════════════════
   GLASS · material translúcido
   Las superficies dejan de ser opacas: dejan pasar lo que hay detrás, desenfocado
   y saturado. Es el sistema de materiales de macOS.

   COSTO REAL: `backdrop-filter` obliga al navegador a recomponer el fondo en cada
   cuadro. Por eso el desenfoque se aplica SOLO a barras y capas flotantes — nunca
   a una grilla con scroll, que es justo donde se nota.
   ══════════════════════════════════════════════════════════════════════════════ */

[data-mode="glass"] {
  /* ══════════════════════════════════════════════════════════════════════════
     LAS PERILLAS DEL VIDRIO · UNA SOLA CIFRA POR FAMILIA
     ─────────────────────────────────────────────────────────────────────────
     Antes cada regla llevaba su porcentaje escrito a mano, repartido por
     lk-glass.css y por el CSS de cada modulo. "Sube la transparencia de los
     menus" significaba buscarlos uno por uno y siempre quedaba alguno fuera:
     asi fue como los menus estuvieron al 88% mientras el resto del chasis iba
     al 42%, y nadie lo noto hasta que se veian identicos a grafito.

     AHORA: se cambia la cifra AQUI y se mueve todo el sistema a la vez.
     Cuanto MAS BAJO el numero, MAS transparente.                             */
  --lk-glass-chrome: 42%;   /* riel, panel, barra superior, pie, hoja movil   */
  --lk-glass-menu:   62%;   /* menus, contextuales, desplegables, popovers    */
  --lk-glass-modal:  72%;   /* modales, spotlight, superficies grandes        */
  --lk-glass-dock-a: 52%;   /* dock movil · borde superior del degradado      */
  --lk-glass-dock-b: 70%;   /* dock movil · borde inferior                    */

  /* Rellenos derivados. Ninguna regla vuelve a escribir un porcentaje: todas
     consumen una de estas cuatro. El color base es el OPACO a proposito, para
     no transparentar dos veces. */
  --lk-fill-chrome: color-mix(in srgb, var(--lk-bg-card-solid, var(--lk-bg-card)) var(--lk-glass-chrome), transparent);
  --lk-fill-menu:   color-mix(in srgb, var(--lk-bg-card-solid, var(--lk-bg-card)) var(--lk-glass-menu),   transparent);
  --lk-fill-modal:  color-mix(in srgb, var(--lk-bg-card-solid, var(--lk-bg-card)) var(--lk-glass-modal),  transparent);

  --lk-surface-fill: var(--lk-fill-chrome);
  --lk-surface-blur: blur(30px) saturate(200%);
  /* 30, NO 14. Cristián eligió el radio el 7-ago-2026 mirando el comparador, y manda
     el diseño: el vidrio de una barra pegada se ve igual que el de cualquier otra
     superficie, y bajarlo era ahorrar a costa de la función.
     CONSECUENCIA, que quede escrita: la barra pegada rehace la convolución en cada
     cuadro mientras se arrastra la lista, y a radio 30 eso cuesta lo que cuesta. El
     token NO se borra aunque hoy valga lo mismo que --lk-surface-blur: es la costura
     que separa «superficie quieta» de «superficie pegada», y sin ella el día que haya
     que afinar hay que volver a encontrar cuáles son cuáles. */
  --lk-surface-blur-fijo: blur(30px) saturate(200%);

  --lk-shadow-sm: 0 0 0 .5px rgba(255,255,255,.07);
  --lk-shadow-md: 0 10px 30px -8px rgba(0,0,0,.75), 0 0 0 .5px rgba(255,255,255,.09);
  --lk-shadow-lg: 0 20px 56px -14px rgba(0,0,0,.82), 0 0 0 .5px rgba(255,255,255,.10);

  --lk-specular: inset 0 .5px 0 rgba(255,255,255,.13);
  --lk-ambient:  radial-gradient(90% 60% at 22% -10%,
                   color-mix(in srgb, var(--lk-brand) 18%, transparent), transparent 60%),
                 radial-gradient(70% 50% at 92% 8%,
                   color-mix(in srgb, var(--lk-teal) 12%, transparent), transparent 62%),
                 radial-gradient(85% 45% at 50% 112%,
                   color-mix(in srgb, var(--lk-brand) 16%, transparent), transparent 60%);
}

[data-theme="lightmode"][data-mode="glass"] {
  --lk-surface-fill: rgba(255,255,255,.62);
  --lk-shadow-sm: 0 1px 2px rgba(15,23,42,.05), 0 0 0 .5px rgba(15,23,42,.05);
  --lk-shadow-md: 0 10px 30px -10px rgba(15,23,42,.18), 0 0 0 .5px rgba(15,23,42,.06);
  --lk-shadow-lg: 0 20px 56px -16px rgba(15,23,42,.24), 0 0 0 .5px rgba(15,23,42,.07);
  --lk-specular:  inset 0 1px 0 rgba(255,255,255,.9);
}

/* DESENFOQUE: solo donde flota o donde no hay scroll detrás. */
[data-mode="glass"] .lk-modal-box,
[data-mode="glass"] .lkctx,
[data-mode="glass"] .pop,
[data-mode="glass"] .sp3-modal {
  background: var(--lk-surface-fill);
  backdrop-filter: var(--lk-surface-blur);
  -webkit-backdrop-filter: var(--lk-surface-blur);
}

/* TRANSLUCIDEZ SIN DESENFOQUE · gratis.
   Detrás de una superficie grande y quieta solo está el degradado de ambiente,
   que es estático: alcanza con bajarle la opacidad al relleno. Se ve como vidrio
   y no cuesta un cuadro, porque el navegador no tiene que recomponer nada.
   Es lo que permite subirle el vidrio al material sin subirle la cuenta. */
[data-mode="glass"] .lk-card,
[data-mode="glass"] .lkm-sec {
  background: var(--lk-surface-fill);
}


/* ══════════════════════════════════════════════════════════════════════════════
   TINT · plano y mínimo
   Sin canto, sin luz ambiente, sin sombra de apoyo. Todo se separa por hairline
   y por espacio. Es lo más barato que puede renderizar un navegador y hereda el
   papel que cumplía `vintage`: la salida para equipos lentos.

   OJO · `vintage` además apagaba TODA animación. Eso es accesibilidad, no
   material, y no debe viajar acá: ver la nota al pie.
   ══════════════════════════════════════════════════════════════════════════════ */

[data-mode="tint"] {
  --lk-surface-fill: var(--lk-bg-card);
  --lk-surface-blur: none;

  --lk-shadow-sm: none;
  --lk-shadow-md: 0 8px 24px -4px rgba(0,0,0,.85);
  --lk-shadow-lg: 0 16px 40px -8px rgba(0,0,0,.90);

  --lk-specular: none;
  --lk-ambient:  none;
}

[data-theme="lightmode"][data-mode="tint"] {
  --lk-shadow-sm: none;
  --lk-shadow-md: 0 6px 18px -6px rgba(15,23,42,.14);
  --lk-shadow-lg: 0 14px 36px -10px rgba(15,23,42,.18);
}

/* Tint hunde el fondo dentro de la familia de su tema — no cambia de familia. */
[data-theme="darkmode"][data-mode="tint"] {
  --lk-bg-body:    #08080a;
  --lk-bg-card:    #121215;
  --lk-bg-surface: #0d0d10;
  --lk-border:     rgba(255,255,255,.07);
  --lk-border-soft:rgba(255,255,255,.038);
}
[data-theme="midnight"][data-mode="tint"] {
  --lk-bg-body:    #05070d;
  --lk-bg-card:    #0d1017;
  --lk-bg-surface: #080b11;
}


/* ══════════════════════════════════════════════════════════════════════════════
   MATERIAL PREDETERMINADO POR TEMA
   ──────────────────────────────────────────────────────────────────────────────
   Cada tema estrena con el material que mejor le queda; el usuario lo cambia
   cuando quiera y su elección manda desde ahí. Esto vive en el shell, no en CSS:
   se aplica solo si el usuario NUNCA eligió material (no hay `lz_mode` guardado).

   En lk-shell/shell.js, dentro de la restauración:

       const DEF_MODE = { midnight: 'glass', darkmode: 'grafito', lightmode: 'grafito' };
       const mo = _get('lz_mode');
       S.store.dispatch({ type: 'mode', value: mo || DEF_MODE[st.theme] || 'grafito' });

   Así midnight abre en vidrio sin que la paleta sepa nada de vidrio — que es lo
   que mantiene los dos ejes separados.
   ══════════════════════════════════════════════════════════════════════════════ */
[data-theme="lightmode"][data-mode="tint"] {
  --lk-bg-body:    #f4f6f9;
  --lk-bg-card:    #ffffff;
  --lk-bg-surface: #fafbfc;
  --lk-border:     rgba(15,23,42,.10);
  --lk-border-soft:rgba(15,23,42,.05);
}


/* ══════════════════════════════════════════════════════════════════════════════
   AJUSTE DE LOS TEMAS OSCUROS · jerarquía de texto por opacidad
   ──────────────────────────────────────────────────────────────────────────────
   Esto NO es material: es la paleta, y por eso va en el eje tema. Hoy `darkmode`
   usa grises fijos (#e8e8e8, #c0c0c0…) heredados de Material Design; al cambiar
   el fondo esos grises dejan de pertenecerle. Con opacidad, el texto siempre
   pertenece al fondo que tiene detrás.

   Es el único cambio a los temas existentes. Los fondos no se tocan.
   ══════════════════════════════════════════════════════════════════════════════ */

[data-theme="darkmode"] {
  --lk-text-primary:    rgba(255,255,255,.92);
  --lk-text-secondary:  rgba(255,255,255,.62);
  --lk-text-muted:      rgba(255,255,255,.45);
  --lk-text-faint:      rgba(255,255,255,.28);
}

/* MIDNIGHT · el azul va en el material, no en la tinta.
   Antes los separadores eran azules y el texto estaba teñido de azul: sobre un
   fondo con color, Apple deja separadores y texto en blanco NEUTRO con opacidad.
   Teñir la tinta es lo que lo hacía leer como tema de terceros.
   Además el fondo y la tarjeta estaban tan cerca (#06080f vs #0f1318) que la
   tarjeta no se despegaba y todo se aplanaba. */
[data-theme="midnight"] {
  --lk-bg-body:      #0b0e15;
  --lk-bg-card:      #141824;
  --lk-bg-surface:   #0e111a;
  --lk-bg-sidebar:   #101420;
  --lk-bg-topbar:    rgba(20,24,36,.94);
  --lk-bg-hover:     rgba(255,255,255,.06);

  --lk-text-primary:    rgba(255,255,255,.93);
  --lk-text-secondary:  rgba(255,255,255,.63);
  --lk-text-muted:      rgba(255,255,255,.46);
  --lk-text-faint:      rgba(255,255,255,.28);

  --lk-border:       rgba(255,255,255,.09);
  --lk-border-soft:  rgba(255,255,255,.05);

  --lk-brand:           #a390d0;
  --lk-brand-muted:     color-mix(in srgb, var(--lk-brand) 20%, transparent);
  --lk-brand-border:    color-mix(in srgb, var(--lk-brand) 36%, transparent);
  --lk-text-inverse:    #0b0e15;
}


/* ══════════════════════════════════════════════════════════════════════════════
   LO QUE HACÍA `vintage` Y NO DEBE PERDERSE
   ──────────────────────────────────────────────────────────────────────────────
   `vintage` apagaba todas las animaciones y transiciones. Eso es una necesidad
   de accesibilidad, no una elección de material: alguien con sensibilidad al
   movimiento la necesita en grafito y en glass también, no solo en tint.

   Por eso se separa del eje material y pasa a donde corresponde — la preferencia
   del sistema operativo, más una casilla propia en Apariencia para quien quiera
   forzarla sin cambiar la de su equipo.
   ══════════════════════════════════════════════════════════════════════════════ */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
}

html[data-motion="reduced"] *,
html[data-motion="reduced"] *::before,
html[data-motion="reduced"] *::after {
  animation-duration: .01ms !important;
  animation-iteration-count: 1 !important;
  transition-duration: .01ms !important;
}
html[data-motion="reduced"] .pop,
html[data-motion="reduced"] .spotlight-bar {
  backdrop-filter: none !important;
  -webkit-backdrop-filter: none !important;
}


/* ── css/lk-layout.css ── */
/* lk-layout.css — Shell grid structure */

*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

html, body {
  height: 100vh; height: 100dvh; font-family: var(--font-sans);
  font-size: var(--font-base, 13px);
  background-color: var(--bg-body); color: var(--tx-base);
  /* El login ya suavizaba (core/auth/login.css, refinado.css) y la app de
     dentro no: la misma tipografía se leía «pesada» al cruzar de una cara a
     la otra. Orden de Cristián, textual: «aplica el antialiasing a la
     aplicacion». Mismos valores que el login, para que las dos caras calcen. */
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  /* MATERIAL · luz de ambiente. Capa de fondo, no pseudo-elemento: no crea
     contexto de apilado ni intercepta el puntero. `fixed` la deja quieta
     mientras el contenido se desplaza, que es lo que la hace leer como luz. */
  background-image: var(--lk-ambient, none);
  background-repeat: no-repeat; /* iOS: sin attachment:fixed, que no pinta el safe-area inferior y deja franja negra en PWA */;
  overflow: hidden;
}

/* ── Shell grid ──────────────────────────────────────────────────────────────── */
#lz-shell {
  display: grid;
  grid-template-columns: var(--lk-layout-rail-w, 52px) var(--lk-layout-panel-w, 210px) 1fr;
  grid-template-rows: 1fr;
  /* El pie vive DENTRO de `.tx-main` (shell.js::mount), como tercer hijo del
     flex column junto a la barra superior y el contenido — así que el chasis
     mide la VENTANA ENTERA. Antes descontaba `--lk-footer-h` para un pie que
     ni siquiera estaba adentro (era hermano de #lz-shell, colgando del body):
     esos 32px quedaban como franja muerta, sin nada que hacer ahí, pegada al
     final de `#moduleContent` — fotografiado en producción. Orden de Cristián,
     textual: «el pie de página no puede estar allí». Mockup aprobado
     MOCKUP-FICHA-CLINICA.html:414-419. */
  height: 100dvh;
  transition: grid-template-columns var(--transition-normal);
}

/* ── UL0 Rail ────────────────────────────────────────────────────────────────── */
.ul0-rail {
  grid-column: 1; display: flex; flex-direction: column;
  align-items: center; padding: var(--space-2) 0;
  background: var(--bg-card); border-right: 1px solid var(--border-soft);
  gap: 2px; z-index: var(--z-sticky);
}

.ul0-logo { width: 36px; height: 36px; margin-bottom: var(--space-3);
  display: flex; align-items: center; justify-content: center; }
.ul0-logo img { width: 28px; height: 28px; border-radius: var(--radius-sm); }

.ul0-groups { display: flex; flex-direction: column; gap: 2px; flex: 1; width: 100%; padding: 0 var(--space-1); }
.ul0-system { display: flex; flex-direction: column; gap: 2px; width: 100%; padding: 0 var(--space-1); }

.ul0-btn {
  width: 40px; height: 40px; border-radius: var(--radius-md);
  border: none; background: transparent; cursor: pointer;
  color: var(--tx-muted); display: flex; align-items: center; justify-content: center;
  transition: background var(--transition-fast), color var(--transition-fast);
  position: relative;
}
.ul0-btn svg { width: 18px; height: 18px; flex-shrink: 0; stroke-width: 1.7; }
.ul0-btn:hover  { background: var(--bg-hover); color: var(--tx-base); }
.ul0-active, .ul0-btn.ul0-active { background: var(--bg-active); color: var(--c-accent-soft); }

/* ── UL1 Panel ───────────────────────────────────────────────────────────────── */
.ul1-panel {
  grid-column: 2; display: flex; flex-direction: column;
  background: var(--bg-card); border-right: 1px solid var(--border-soft);
  overflow: hidden; transition: width var(--transition-normal);
}
.ul1-scroll { flex: 1; overflow-y: auto; padding: var(--space-2); display: flex; flex-direction: column; gap: 2px; }

.ul1-item {
  width: 100%; display: flex; align-items: center; gap: var(--space-2);
  padding: 8px var(--space-2); border-radius: var(--radius-md);
  border: none; background: transparent; cursor: pointer;
  color: var(--tx-muted); font-size: var(--font-md); text-align: left;
  transition: background var(--transition-fast), color var(--transition-fast);
}
.ul1-item:hover  { background: var(--bg-hover); color: var(--tx-base); }
.ul1-item.active { background: var(--bg-active); color: var(--c-accent-soft); font-weight: 500; }
.ul1-icon { width: 22px; height: 22px; flex-shrink: 0; display: grid; place-items: center; opacity: .75; }
.ul1-icon svg { width: 18px; height: 18px; display: block; stroke-width: 1.7; }
.ul1-label { flex: 1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* ── TX Main ──────────────────────────────────────────────────────────────────── */
.tx-main { grid-column: 3; display: flex; flex-direction: column; min-width: 0; overflow: hidden; }

.tx-top {
  height: 52px; flex-shrink: 0; display: flex; align-items: center;
  padding: 0 var(--space-4); gap: var(--space-3);
  background: var(--bg-card); border-bottom: 1px solid var(--border-soft);
  position: relative; z-index: 650;
}

.top-hello    { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
/* El nombre de la pantalla. Sólo existe en teléfono (bloque de <640): en
   tablet y escritorio ya lo dicen el riel y el panel, y repetirlo arriba sería
   ruido. Vacío = no hay rótulo que dar; `:empty` lo retira para que no deje un
   hueco mudo donde debería ir un nombre.
   RESP-TITULO-AL-TOPBAR (12-ago-2026, mockup docs/disenos/mockup-titulo-al-
   topbar.html aprobado): es el RELEVO del título grande del propio módulo, no
   un rótulo fijo — el título del módulo NO se toca ni se mueve, sigue naciendo
   en su sitio. `shell.js::_reconectarTitleRelay` enciende/apaga la clase
   `.tt-on` según un IntersectionObserver sobre ese título; los dos nunca se ven
   a la vez. Se anima con opacity/transform (RESP-10), nunca con display ni con
   la maqueta: animar eso obliga a reflujo en cada fotograma. El
   `transition-duration` bajo `prefers-reduced-motion`/`data-motion="reduced"`
   ya lo neutraliza la regla global de lk-motion.css — no hace falta repetirlo
   aquí. */
.top-title    { display: none; margin: 0; min-width: 0;
  font-size: calc(var(--font-base) * 1.46); font-weight: 600; letter-spacing: -.02em;
  line-height: 1.15; color: var(--tx-base);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  opacity: 0; transform: translateY(-6px); pointer-events: none;
  transition: opacity var(--lk-dur-2, .18s) var(--lk-ease-out, ease),
              transform var(--lk-dur-2, .18s) var(--lk-ease-out, ease); }
.top-title:empty { display: none !important; }
.top-title.tt-on { opacity: 1; transform: translateY(0); pointer-events: auto; }
.top-greet    { font-size: var(--font-xs); color: var(--tx-muted); line-height: 1; }
.top-name     { font-size: var(--font-sm); font-weight: 500; color: var(--tx-base); white-space: nowrap; }
.top-center   { flex: 1; display: flex; justify-content: center; }
.top-right    { display: flex; align-items: center; gap: var(--space-2); margin-left: auto; }
.top-clock    { font-size: var(--font-sm); color: var(--tx-muted); font-variant-numeric: tabular-nums; }

.tx-content { flex: 1; overflow: hidden; position: relative; background: var(--bg-body); }
#moduleContent { width: 100%; height: 100%; overflow-y: auto; }

/* ══ EL CAMPO VIVO · luz de ambiente del contenido ═══════════════════════════
   spec-IMPL-INICIO-FONDO (mockup-inicio-fondo.html, E060, aprobado 12-ago-2026),
   generalizado del chasis 13-ago-2026: nació sólo en Inicio y el eje que lo
   gobierna (`data-fondo`, `LK.shell.setFondo`) ya vivía en el shell, pero el
   único CSS que lo pintaba era `.lz-in::before` — Cristián, 13-ago: «revisa
   todos los fondos, están todos con el mismo problema». El arreglo va en la
   RAÍZ del chasis, no repetido en cada módulo (regla 6 del método: el arreglo
   se generaliza).

   ANCLA EN `.tx-content`, el MARCO COMPLETO del área de contenido — no en la
   caja centrada de cada módulo. Ésa fue la causa de las franjas laterales que
   Cristián reportó («tiene franjas en los costados, ambos, que rompen el
   fondo»): en Inicio `.lz-in` y `.lz-in-v` son el MISMO elemento (inicio.js),
   y `.lz-in-v{max-width:1120px}` — el radial vivía dentro de esa columna de
   1120px encerrada en un marco de 1418px, y dejaba ~149px planos a cada lado.
   `.tx-content` es grid-column 3 a `1fr`: el ancho REAL del área de contenido,
   de borde a borde, sin costura — y ya es `position:relative;overflow:hidden`,
   así que no hace falta tocar nada más para contenerlo.

   VA `absolute`, NUNCA `fixed` — probado el 13-ago-2026: con `fixed` puesto en
   la caja del módulo (`.lz-in::before`, el intento anterior) el CONTENIDO
   dejaba de pintarse del todo — seguía en el DOM, pero la pantalla salía
   vacía. Con `absolute`, contenido por `.tx-content`, no vuelve a pasar.
   `#moduleContent` sube por encima con `position:relative;z-index:1` — así el
   contenido real pinta sobre el ambiente sin sacar el pseudo-elemento del
   flujo del documento. */
.tx-content::before{
  content: ''; position: absolute; inset: 0; z-index: 0; pointer-events: none;
  opacity: 0; transition: opacity .4s ease;
}
#moduleContent, #ldTaskbar{ position: relative; z-index: 1; }
[data-fondo="on"] .tx-content::before{ opacity: 1; }
/* Apagado también en los modos SIN materiales (Doc 07 §5): tint/vintage/flat
   son para equipos de poca GPU y no llevan fondo, aunque el eje esté en 'on'. */
[data-mode="tint"][data-fondo="on"] .tx-content::before,
[data-mode="vintage"][data-fondo="on"] .tx-content::before,
[data-mode="flat"][data-fondo="on"] .tx-content::before{ opacity: 0; }

/* LA CAPA OPACA DE ABAJO, `var(--lk-bg-body)` como ÚLTIMO fondo de la lista, es
   el arreglo del 13-ago-2026 (Cristián: «las pantallas de Inicio se ven
   borrosas o granuladas»). LA CAUSA, encontrada leyendo lk-material.css: en
   grafito y en glass, `body` YA pinta su propia luz de ambiente
   (`--lk-ambient`, lk-tokens.css) y `.tx-content` está forzada a
   `background:transparent!important` (lk-material.css:189-198, «FONDO ÚNICO
   CON LUZ») para dejarla pasar. Mi `::before` pintaba SUS radiales encima de
   ESA luz, sin taparla — dos degradados suaves del mismo color superpuestos,
   con bordes que no coinciden. Lo que se lee como «granulado» es eso: no es
   una foto de baja resolución, es el *banding* de dos gradientes translúcidos
   montados uno sobre el otro sumando sus paradas de color.
   Con un color SÓLIDO al fondo de la lista, mi glow pasa a ser la ÚNICA luz
   del área de contenido — ocluye la de `body` en vez de sumarse a ella — y
   desaparece la doble transparencia que generaba el ruido. Apagado
   (`data-fondo=off`) no cambia nada: `opacity:0` deja ver la luz de `body` de
   siempre, intacta. */
[data-theme="lightmode"] .tx-content::before{
  background:
    radial-gradient(1300px 820px at 6% -14%, color-mix(in srgb, var(--lk-brand) 22%, transparent), transparent 55%),
    radial-gradient(1000px 760px at 106% 18%, color-mix(in srgb, var(--lk-brand) 14%, transparent), transparent 54%),
    radial-gradient(1200px 700px at 46% 118%, color-mix(in srgb, var(--lk-brand) 10%, transparent), transparent 58%),
    var(--lk-bg-body);
}
[data-theme="darkmode"] .tx-content::before{
  background:
    radial-gradient(1300px 820px at 6% -14%, color-mix(in srgb, var(--lk-brand) 26%, transparent), transparent 55%),
    radial-gradient(1000px 760px at 106% 18%, color-mix(in srgb, var(--lk-brand) 16%, transparent), transparent 54%),
    radial-gradient(1200px 700px at 46% 118%, color-mix(in srgb, var(--lk-brand) 10%, transparent), transparent 58%),
    var(--lk-bg-body);
}
[data-theme="midnight"] .tx-content::before{
  background:
    radial-gradient(1300px 820px at 6% -14%, color-mix(in srgb, var(--lk-brand) 30%, transparent), transparent 55%),
    radial-gradient(1000px 760px at 106% 18%, color-mix(in srgb, var(--lk-brand) 18%, transparent), transparent 54%),
    radial-gradient(1200px 700px at 46% 118%, color-mix(in srgb, var(--lk-brand) 12%, transparent), transparent 58%),
    var(--lk-bg-body);
}

/* Teléfono: UN radial, más chico — no tres capas caras detrás de una lista que
   se desplaza. Excepción puntual autorizada dentro del terreno de luzoresp:
   sigue siendo la ÚNICA capa de fondo en 390px, sólo que ahora vive junto al
   resto del campo vivo en vez de duplicada en cada módulo. También lleva la
   base opaca: en teléfono `.tx-main/.tx-content/#moduleContent` se vuelven
   transparentes OTRA VEZ más abajo (`lk-layout.css`, «FONDO CONTINUO MÓVIL»)
   para el lienzo único del sistema — mismo defecto, mismo arreglo. */
[data-bp="phone"][data-theme="lightmode"] .tx-content::before{
  background: radial-gradient(900px 700px at 12% -18%, color-mix(in srgb, var(--lk-brand) 16%, transparent), transparent 60%), var(--lk-bg-body);
}
[data-bp="phone"][data-theme="darkmode"] .tx-content::before{
  background: radial-gradient(900px 700px at 12% -18%, color-mix(in srgb, var(--lk-brand) 19%, transparent), transparent 60%), var(--lk-bg-body);
}
[data-bp="phone"][data-theme="midnight"] .tx-content::before{
  background: radial-gradient(900px 700px at 12% -18%, color-mix(in srgb, var(--lk-brand) 22%, transparent), transparent 60%), var(--lk-bg-body);
}

/* ── Footer ──────────────────────────────────────────────────────────────────── */
.tx-footer {
  /* Ahora es el tercer hijo del flex column `.tx-main` (shell.js::mount), junto
     a `.tx-top` (que ya lleva flex-shrink:0) y `.tx-content` (flex:1). Sin este
     shrink:0 heredaría el 1 por omisión y, en una ventana muy baja, `.tx-content`
     podría empezar a cederle espacio en vez de ser quien absorbe el sobrante. */
  flex-shrink: 0;
  padding: var(--space-2) var(--space-4);
  font-size: var(--font-xs); color: var(--tx-dim);
  border-top: 1px solid var(--border-soft); background: var(--bg-card);
  display: flex; align-items: center; justify-content: space-between;
}

/* ══════════════════════════════════════════════════════════════════════════════
   Responsive · 3 formas (RESP-01 · cortes 640/1024 del contrato en lk-tokens)
   FUENTE DE VERDAD = @media (no data-bp). Así el layout es correcto en el PRIMER
   pintado y aunque el JS del shell tarde o falle (antes se veía el escritorio
   aplastado en móvil hasta bootear). El atributo data-bp se sigue fijando
   pre-pintado (bootstrap inline) + matchMedia para el JS y para consumidores
   declarativos (cfg, lk-home); NO gobierna el layout del chasis. vintage no
   recompone (SHELL-13). UN SOLO modelo alimenta rail/panel/bn-bar (SHELL-06).
   ══════════════════════════════════════════════════════════════════════════════ */
.bn-bar { display: none; }                 /* bottom-nav: solo en teléfono */
/* Sitio que el chasis reserva abajo. 0 mientras no haya dock (tablet y escritorio);
   el bloque de teléfono lo sube a 72px + área segura. Vive acá, fuera del corte,
   para que quien lo consuma (p.ej. #ldTaskbar en lk-components) tenga siempre un
   valor válido y no dependa de si la consulta de medios aplica. */
:root { --lk-dock-reserva: 0px; }
.cv-auto { content-visibility: auto; contain-intrinsic-size: auto 600px; }  /* PERF listas */

#shellScrim { position: fixed; inset: 0; background: rgba(0,0,0,.42); opacity: 0; pointer-events: none; transition: opacity .28s ease; z-index: 60; }
#shellScrim.open { opacity: 1; pointer-events: auto; }
/* HOJA INFERIOR DEL SHELL · pieza canónica (mockup 2118acd6, aprobado 4-ago-2026).
   Las cuatro hojas del sistema (ésta + p3m + rvm + informes) eran cuatro copias con
   material, recorrido y curva distintos. Ésta queda como la referencia y las otras
   tres la copian. Cambios respecto de lo anterior:
   · 82% → --lk-glass-chrome (42%), que es el nivel del riel, el panel y la barra
     superior: la hoja es chasis, no una tarjeta. Fallback literal porque el token
     sólo existe bajo [data-mode="glass"] y fuera de glass mantiene el mismo número.
   · blur(24) saturate(1.7) → blur(30) saturate(200%), el desenfoque único del
     sistema. Literal por el mismo motivo que el dock (ver .bn-bar).
   · recorrido 100% → 101%: a 100% quedaba una hebra de un píxel asomando en
     pantallas con escala fraccionaria.
   · .3s → .28s, la curva de resorte de las otras tres.
   · ÁREA SEGURA: es lo único que era un defecto y no una preferencia. Las tres
     hojas de módulo descuentan `env(safe-area-inset-bottom)`; ésta no, así que en
     modo aplicación su última fila podía quedar bajo la barra de gestos. */
#shellSheet { position: fixed; left: 0; right: 0; bottom: 0;
  background: color-mix(in srgb, var(--bg-card) var(--lk-glass-chrome, 42%), transparent);
  -webkit-backdrop-filter: blur(30px) saturate(200%); backdrop-filter: blur(30px) saturate(200%);
  border-top: 1px solid var(--border-soft);
  border-radius: 18px 18px 0 0; box-shadow: var(--lk-shadow-lg), var(--lk-specular, none); transform: translateY(101%); transition: transform .28s var(--spring, ease); z-index: 61;
  padding: 8px 14px calc(24px + env(safe-area-inset-bottom, 0px)); }
/* TEMA CLARO · la misma hoja, más densa. Medido en la app el 4-ago-2026: detrás de
   la hoja está el velo (#shellScrim, negro al 42%) y el desenfoque lo MUESTREA. En
   los temas oscuros da igual; en claro convierte el blanco en un gris turbio. No es
   preferencia: es que el vidrio recoge lo que tiene debajo, y debajo hay un velo.
   78% devuelve el carácter de panel claro conservando la translucidez. */
[data-theme="lightmode"] #shellSheet {
  background: color-mix(in srgb, var(--bg-card) 78%, transparent); }
#shellSheet.open { transform: translateY(0); }
#shellSheet .sheet-grab { width: 38px; height: 4px; border-radius: 3px; background: var(--border); margin: 2px auto 12px; }
#shellSheet .sheet-title { font-size: var(--lk-font-sm); text-transform: uppercase; letter-spacing: .06em; color: var(--tx-dim); padding: 0 4px 8px; }

/* ── Escritorio ≥1024 (base) · panel colapsable ── */
html.ul-collapsed #lz-shell { grid-template-columns: var(--lk-layout-rail-w, 52px) 0 1fr; }
html.ul-collapsed .ul1-panel { overflow: hidden; border-right: none; }

/* Modulo lanzador sin panel (p.ej. Configuracion): retrae la pista del panel a 0,
   igual que ul-collapsed pero forzado por el modulo. Solo aplica donde el panel es
   parte del grid (≥640): en teléfono el grid es 1fr y no hay pista que retraer.
   El shell es dueño de estas reglas (SHELL-06); el modulo solo pone/quita
   la clase html.ul-nopanel. */
@media (min-width: 640px) {
  html.ul-nopanel #lz-shell { grid-template-columns: var(--lk-layout-rail-w, 52px) 0 1fr; }
  html.ul-nopanel .ul1-panel { overflow: hidden; border-right: none; }
}

/* ── Tablet 640–1023 · panel = cajón sobre scrim ──
   FIX z-index (RESP-03): el cajón arranca BAJO el top-bar (top:top-h) para que el
   header (z alto) no tape los primeros ítems de navegación. Antes top:0 los ocultaba. */
@media (min-width: 640px) and (max-width: 1023.98px) {
  #lz-shell { grid-template-columns: var(--lk-layout-rail-w, 52px) 0 1fr; }
  .ul1-panel {
    position: fixed; left: var(--lk-layout-rail-w, 52px);
    top: var(--lk-layout-top-h, 52px); bottom: var(--lk-layout-footer-h, 32px);
    width: var(--lk-layout-panel-w, 210px); z-index: 62;
    transform: translateX(-115%); transition: transform .3s var(--spring, ease);
    box-shadow: var(--lk-shadow-lg); border-right: none;
  }
  html.ul-open .ul1-panel { transform: translateX(0); }
}

/* ── Teléfono <640 · sin rail/panel · bottom-nav (material modern) ── */
@media (max-width: 639.98px) {
  #lz-shell { grid-template-columns: 1fr; height: 100dvh; }
  .tx-main { grid-column: 1; }
  .ul0-rail, .ul1-panel { display: none; }
  /* El contenido corre por DEBAJO del dock (asi el desenfoque tiene algo que
     desenfocar). El espacio se reserva al final del recorrido, no como banda
     muerta: scroll-padding despeja el ultimo elemento sin levantar el resto. */
  .tx-content { padding-bottom: calc(12px + env(safe-area-inset-bottom, 0px)); }
  /* RESERVA DEL DOCK (RESP-06 · 4-ago-2026) — el chasis la hace, no los módulos.
     Antes se pedía en .tx-content y NO llegaba nunca:
       · scroll-padding-bottom es inerte ahí, porque .tx-content es overflow:hidden;
         quien scrollea es #moduleContent, y scroll-padding sólo lo lee el que scrollea.
       · el margen de `> *:last-child` caía SIEMPRE en #ldTaskbar, porque .tx-content
         tiene exactamente dos hijos (shell.js: _outletEl + ldTaskbar). Envolver o no
         la cara compacta era indiferente: la regla no la alcanzaba en ningún caso.
     Medido en la app el 4-ago: la última fila quedaba bajo el dock en 3 de 4 módulos
     (Reservas −19px y es un <button>, P360 −19px, Autorizaciones −5px). El único
     limpio era Configuración, el único que traía su propio pie.

     ── EL HERMANO QUE EL `::after` NO ALCANZABA (12-ago-2026) ──────────────────
     El `::after` fantasma sólo funciona si quien scrollea es #moduleContent. Un
     módulo que se declara `height:100%` y scrollea POR DENTRO no cumple esa
     condición: nace tan alto como el outlet, el fantasma le queda POR DEBAJO del
     borde inferior —fuera de la vista— y #moduleContent no se desplaza nunca. Su
     última fila termina exactamente donde empieza el dock, y ninguna medida del
     módulo lo arregla porque el módulo no sabe que hay un dock.
     Son varios, no uno: `.rv-root` (Reservas, reservas.css:62), `.cc-wrap`
     (Com Center, comcenter.css:4), `.ctr-mobile` (reagendar,
     lk-cita-reagendar.css:215) y `.cfg-pane` (cfg.css:436).

     Se cambia el fantasma por PADDING INFERIOR en el propio outlet, que hace las
     DOS cosas con una sola declaración y sin duplicar el hueco:
       · el módulo que scrollea con #moduleContent termina su recorrido 72px antes
         — idéntico a lo que hacía el `::after`;
       · el módulo que se pide `height:100%` lo resuelve contra la ALTURA DE
         CONTENIDO del outlet, que con `border-box` ya viene descontada: nace corto
         y su scroller interno acaba sobre el dock, no debajo.
     El vidrio del dock NO pierde nada: el contenido sigue pasando por debajo
     mientras se recorre la lista; el hueco sólo existe al final del recorrido,
     que es exactamente lo que hacía el fantasma. Volver al `::after` devuelve el
     defecto a los cuatro módulos de arriba. */
  :root { --lk-dock-reserva: calc(72px + env(safe-area-inset-bottom, 0px)); }
  #moduleContent { scroll-padding-bottom: var(--lk-dock-reserva);
    padding-bottom: var(--lk-dock-reserva); }
  .bn-bar { display: flex; }

  /* Una hoja fija vive dentro de #moduleContent. Ese contenedor ya crea un
     contexto de apilamiento (z-index:1), por lo que el z-index de la hoja no
     puede superar al dock si no elevamos el outlet completo. La condición es
     declarativa: la hoja se pinta sobre el dock desde el mismo recálculo CSS. */
  #moduleContent:has(.rvm.is-sheet .rvm-sheet),
  #moduleContent:has(.rvm.is-det .rvm-det) {
    z-index: 56;
  }

  /* Bottom-sheet: filas cómodas al dedo (touch ≥44px + aire entre opciones) */
  #shellSheet .ul1-item { padding: 13px var(--space-3); margin-bottom: 4px; font-size: var(--font-lg); border-radius: var(--radius-md); }
  #shellSheet .ul1-item:last-child { margin-bottom: 0; }
  #shellSheet .ul1-icon { width: 26px; height: 26px; }
  #shellSheet .ul1-icon svg { width: 20px; height: 20px; }

  /* Header "quietly modern": saludo + campana + avatar (sin spotlight/reloj/iconos
     secundarios); la barra inferior hace la navegación. */
  .tx-top { height: auto; padding: calc(env(safe-area-inset-top, 12px) + 12px) 18px 8px; gap: 12px; border-bottom: none; background: var(--bg-body); }
  /* DÓNDE ESTOY, EN LUGAR DEL SALUDO (12-ago-2026, orden de Cristián).
     En teléfono la franja más visible se gastaba en «Bienvenido/a · <nombre>»,
     que es igual en las veintiséis pantallas. Sin riel y sin panel, esta línea es
     lo único que puede decir en cuál estás. El saludo no desaparece del producto:
     sigue en la hoja del orbe (`.lkh-greet`), que es donde tiene sentido, y en
     tablet y escritorio la barra no cambia.
     RESP-TITULO-AL-TOPBAR: ahora es un RELEVO (ver comentario junto a
     `.top-title` arriba), así que `display:block` sólo habilita la caja —
     `opacity`/`.tt-on` deciden si se ve. Si el módulo no trae un título propio
     que observar (on-demand, fuera del nav) el relevo nunca se enciende y la
     línea queda muda: mejor sin línea que con una mentira. */
  .top-hello { display: none; }
  .top-title { display: block; }
  .top-name { white-space: nowrap; }
  .top-center { display: none; }
  .top-clock { display: none; }
  .tb-sec { display: none; }
  .top-right { gap: 8px; margin-left: auto; flex-shrink: 0; }
  .tx-footer { display: none; }
}

/* Dock (RESP-05). El material lo pone el eje data-mode via --lk-surface-*:
   solido en grafito, translucido en glass, plano en tint. Ya no lo decide aqui.
   Para que el vidrio sea REAL el contenido tiene que pasar por debajo: ver
   .tx-content abajo — antes reservaba 84px y nada llegaba nunca detras. */
/* El dock es vidrio SIEMPRE, sin importar el material (grafito/glass/tint): tiene
   su propio desenfoque fijo, no hereda --lk-surface-blur (que es none en grafito).
   UNIFICACIÓN 4-ago-2026 (mockup 2118acd6, aprobado):
   · Los porcentajes salen de --lk-glass-dock-a/b, que YA existían en lk-tokens
     describiendo este mismo dock y que nadie consumía: iban a mano 46/64 contra
     los 52/70 declarados. El literal del fallback repite el valor del token porque
     esos tokens sólo existen bajo [data-mode="glass"]; fuera de glass el dock
     conserva exactamente el mismo número, que es lo aprobado.
   · El desenfoque pasa de blur(34) saturate(1.8) a blur(30) saturate(200%), que es
     el valor del material del sistema (--lk-surface-blur en glass). Se escribe
     literal, NO con var(--lk-surface-blur): ese token vale `none` en los otros
     cuatro modos y el dock dejaría de ser vidrio, que no es lo que se aprobó. */
.bn-bar { position: fixed; left: 22px; right: 22px; bottom: calc(env(safe-area-inset-bottom, 8px) + 3px); height: var(--lk-dock-h, 58px);
  background: linear-gradient(180deg,
    color-mix(in srgb, var(--bg-card) var(--lk-glass-dock-a, 52%), transparent),
    color-mix(in srgb, var(--bg-card) var(--lk-glass-dock-b, 70%), transparent));
  -webkit-backdrop-filter: blur(30px) saturate(200%); backdrop-filter: blur(30px) saturate(200%);
  border: .5px solid rgba(255,255,255,.14); border-radius: 22px;
  box-shadow: var(--lk-shadow-lg), inset 0 1px 0 rgba(255,255,255,.16), inset 0 -.5px 0 rgba(255,255,255,.05);
  align-items: center; justify-content: space-between; gap: 2px; padding: 0 4px; z-index: 55; }

/* Quien pide reducir movimiento no paga desenfoque (accesibilidad, no material). */
html[data-motion="reduced"] .bn-bar, html[data-motion="reduced"] #shellSheet {
  -webkit-backdrop-filter: none; backdrop-filter: none; background: var(--bg-card);
}
.bn-tab { flex: 1 1 0; min-width: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 4px; border: none; background: transparent;
  color: var(--tx-muted); font: inherit; font-size: calc(var(--font-base) * 0.769); cursor: pointer; padding: 8px 4px; border-radius: 14px; transition: color var(--transition-fast, .12s); }
.bn-tab span { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; line-height: 1.1; }
.bn-tab.active { color: var(--c-accent-soft); }
.bn-tab svg { width: 22px; height: 22px; flex-shrink: 0; }

/* ── Accesibilidad · respeta "reducir movimiento": corta transiciones del shell ── */
@media (prefers-reduced-motion: reduce) {
  #lz-shell, .ul1-panel, #shellScrim, #shellSheet { transition: none !important; }
}


/* ── FONDO CONTINUO MOVIL · un solo lienzo, sin cortes ──────────────────────────
   En teléfono, ninguna capa del contenido pinta su propio fondo: todas dejan ver
   el body con la luz. Así no hay franja ni corte entre la barra y el contenido. */
@media (max-width: 639.98px){
  .tx-main, .tx-content, #moduleContent{ background: transparent !important; }
}

/* ── TELÉFONO · barra superior continua con el fondo + solo lo esencial ─────────
   En móvil la topbar es parte del lienzo (sin vidrio, sin canto, sin borde) y
   muestra solo orbe + campana + avatar. El escudo (Autorizaciones) se accede por
   el dock/navegación, no compite arriba. */
@media (max-width: 639.98px){
  .tx-top{
    background: transparent !important;
    -webkit-backdrop-filter: none !important;
    backdrop-filter: none !important;
    border-bottom: none !important;
    box-shadow: none !important;
  }
  .tx-top::after, .tx-top::before{ display: none !important; }
  #approvalBtn{ display: none !important; }

  /* ── EL DOCK DEJA DE DESENFOCAR EN TELEFONO ───────────────────────────────
     `.bn-bar` es una franja FIJA de borde a borde sobre contenido que scrollea.
     Un `backdrop-filter` ahí obliga al compositor a re-muestrear y re-desenfocar
     esa banda EN CADA CUADRO del desplazamiento: es el patron que mas cuesta en
     GPU de movil, y es la causa mas probable del lag que se siente al scrollear.

     La topbar ya habia tomado esta misma decision doce lineas mas arriba —en
     telefono es parte del lienzo, sin vidrio—; el dock quedo fuera de esa pasada.

     NO se pierde la lectura de dock flotante: el degradado de `--bg-card` con
     sus dos paradas se queda, mas el borde, el radio de 22 y la sombra. Lo unico
     que se va es el desenfoque EN VIVO de lo que pasa por debajo.

     ⚠ Contradice una decision de material aprobada (el comentario de `.bn-bar`
     dice que el literal se escribio a mano justamente para que el dock siguiera
     siendo vidrio en los cinco modos). Se revierte borrando este bloque. Si el
     dueño prefiere el vidrio y convivir con el coste, esa es su llamada — pero
     entonces conviene medirlo antes con Paint flashing en el aparato real. */
  .bn-bar{
    -webkit-backdrop-filter: none !important;
    backdrop-filter: none !important;
    background: linear-gradient(180deg,
      color-mix(in srgb, var(--bg-card) 92%, transparent),
      var(--bg-card));
  }
}


/* ── css/lk-components.css ── */
/* ══════════════════════════════════════════════════════════════════════════════
   CONVENCION DE NOMBRES · LUZOcrm MK-3   (acordada 31-jul-2026)
   ──────────────────────────────────────────────────────────────────────────────
   Se escribe aqui porque este archivo es el de las piezas compartidas: quien
   venga a crear una clase nueva pasa por aca.

   1 · `lk-*`  = PIEZA DEL CORE, compartida por todo el sistema.
       Solo el core crea clases `lk-`. Un modulo NUNCA define una.
       Si un modulo necesita variar una pieza, la tine con variables
       (p. ej. `.agw { --lkctx-accent: var(--ag); }`), no la duplica.

   2 · `<pfx>-*` = clase PROPIA de un modulo, con prefijo UNICO y registrado.
       Registro vigente:
         com-   Com Center            ctc-*/cc-  Control Center
         rv-    Reservas              op-        Reservas · Operaciones
         p3- p3e- p3l-  Paciente 360  sadm-      Salas (admin)
         sala-  Sala (consola)        agw-       Agenda
         cv-    Visor de cita         ctr-       Reagendar cita
         ev-    Eventos               rc- rvc-   Creador de citas
       ⚠️ `cc-` estuvo COMPARTIDO por Com Center y Control Center y produjo 4
       colisiones reales (.cc-chip .cc-dot .cc-preview-loading .cc-soon): dos
       duenos pintando la misma clase. Se resolvio pasando Com Center a `com-`.
       Antes de inventar un prefijo, comprobar que no exista.

   3 · ESTRUCTURA: `bloque__parte--variante` (BEM ligero).
       Ya lo usan `lk-compound__button`, `lk-compound__divider`,
       `lk-modulebar__title`. Las partes no se nombran sueltas.

   4 · ESTADOS: SIEMPRE `is-*` (`is-open`, `is-active`, `is-danger`,
       `is-disabled`). Nunca un estado suelto como `.open` o `.active`: eso
       colisiona con cualquiera.

   5 · PROHIBIDO el nombre generico sin prefijo. `.pop`, `.floatmenu`,
       `.ctxmenu`, `.bulk`, `.menu` son bombas de colision y varias ya
       estallaron. Todo nombre lleva prefijo de core o de modulo.

   6 · Si una clase deja de pintarse desde JS, se BORRA su CSS. El 31-jul-2026
       se retiraron 8 familias muertas (.bulk-estado-pop .cfg-pop .floatmenu
       .p3l-ctx .periodo-pop .profdd-pop .rv-tbm .tc-pop) que llevaban meses
       ocupando el bundle sin que nadie las montara.
   ══════════════════════════════════════════════════════════════════════════════ */

/* ══════════════════════════════════════════════════════════════════════════════
   lk-components.css — LUZOkit Reusable Components
   ──────────────────────────────────────────────────────────────────────────────
   T2b rewrite · 2026-04-19
   Rules:
     1. Zero hardcoded color values — everything via var(--token)
     2. Zero duplication — each selector defined ONCE
     3. Tokens come from lk-tokens.css (--lk-*) via bridge aliases
     4. Structural-only values (px, %, em) are inline — not tokenized
   ══════════════════════════════════════════════════════════════════════════════ */


/* ── Keyframes ──────────────────────────────────────────────────────────────── */

@keyframes blade-in    { from { transform: translateX(100%); } to { transform: translateX(0); } }
@keyframes mod-fade-in { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: translateY(0); } }
@keyframes up-shake    { 0%,100% { transform: translateX(0); } 20% { transform: translateX(-5px); } 40% { transform: translateX(5px); } 60% { transform: translateX(-4px); } 80% { transform: translateX(4px); } }


/* ═══════════════════════════════════════════════════════════════════════════
   1. ICON BUTTON
═══════════════════════════════════════════════════════════════════════════ */

.icon-btn {
  position: relative;
  width: 32px; height: 32px; border-radius: var(--radius-md);
  border: none; background: transparent; cursor: pointer;
  color: var(--tx-muted); display: flex; align-items: center; justify-content: center;
  font-family: inherit;
  transition: background var(--transition-fast), color var(--transition-fast);
}
.icon-btn:hover { background: var(--bg-hover); color: var(--tx-base); }
.icon-btn svg {
  width: 17px; height: 17px; flex-shrink: 0;
  fill: none; stroke: currentColor; stroke-width: 1.7;
  stroke-linecap: round; stroke-linejoin: round;
}


/* ═══════════════════════════════════════════════════════════════════════════
   2. AVATAR
═══════════════════════════════════════════════════════════════════════════ */

.avatar-btn {
  /* SIN `overflow:hidden` A PROPÓSITO desde spec-CORE-DOT-PRESENCIA (21-ago-2026):
     el círculo lo recorta `.avatar-photo` con su propio `border-radius:50%` (es
     un elemento reemplazado y el navegador lo respeta sin ayuda del padre), y el
     fondo de ESTE nodo también se recorta solo por su propio `border-radius`. Lo
     único que dependía del `overflow:hidden` era que `.lph-dot` (más abajo en
     este fichero) no se saliera — y ESE es justo el defecto que motivó el
     cambio: ver el comentario de `.lph-dot` para el porqué completo. */
  width: 32px; height: 32px; border-radius: 50%; border: none; cursor: pointer; position: relative;
  background: var(--c-accent-muted); display: flex; align-items: center; justify-content: center;
  transition: opacity var(--transition-fast);
}
.avatar-btn:hover { opacity: .85; }
.avatar-letters {
  font-size: var(--font-xs); font-weight: 500; color: var(--c-accent-soft);
}
.avatar-photo { position: absolute; inset: 0; width: 100%; height: 100%; display: block; object-fit: cover; border-radius: 50%; }

/* ── LK.avatar · el hueco existe antes que los bytes (AVATAR-02 · 12-ago-2026) ─
   Estas tres reglas gobiernan TODA <img> de cara del sistema, la ponga quien la
   ponga: `core/lk-avatar.js` la adopta al entrar al documento y le pone
   `data-lkav`. No hay clase nueva ni una medida nueva — la medida sigue siendo la
   que ya tenía cada sitio. Esto arregla un defecto; no mueve un píxel de lo
   aprobado.

   EL SALTO. Sin medida intrínseca el navegador no reserva el hueco: pintaba la
   foto a su tamaño natural (96×96) y la encogía después. `aspect-ratio:1` le da
   la proporción por adelantado, así que la caja tiene su forma desde el primer
   fotograma, cargue rápido o lento. En los sitios donde la <img> ya es
   `position:absolute` —`.avatar-photo`, `.cfg-us-face`— esto no cambia nada:
   ahí el salto ya era imposible y la regla es inofensiva.

   EL PARPADEO. Mientras no hay bytes la imagen está oculta y se ven las
   iniciales de debajo, que están SIEMPRE en el DOM. Nunca hay un hueco vacío ni
   el icono de imagen rota.

   Y LO QUE NO SE HACE: no se esconde el nodo con `display:none` ni se borra.
   `opacity` deja el elemento en su sitio, y `data-lkav-fallo` se queda escrito
   para que se pueda depurar POR QUÉ falta una cara. El manejador anterior hacía
   `t.remove()`, y borrar el nodo borraba también la prueba de haberlo intentado:
   por eso el diagnóstico previo concluyó que la barra superior «ni siquiera
   intenta la foto». Sí lo intentaba. */
img[data-lkav] { aspect-ratio: 1; object-fit: cover; }
img[data-lkav-pend], img[data-lkav-fallo] { opacity: 0; }
img[data-lkav] { transition: opacity var(--lk-dur-1, .12s) var(--lk-ease-out, ease); }
@media (prefers-reduced-motion: reduce) { img[data-lkav] { transition: none; } }

/* ══ MENÚ DE LA PERSONA · mockup APROBADO-inicio-elegir-vista.html ═════════════
   Port del `menuUsuario()` del aprobado (~línea 1496 de ese archivo) y de su
   bloque de estilo (líneas 596-646): `.umenu` en escritorio, `.hoja` con asa en
   teléfono, `.velo claro` que recoge el clic sin oscurecer la app.

   POR QUÉ EL PANEL YA CASI NO DEJA PASAR NADA
   El menú anterior iba a `color-mix(… var(--bg-card) 94%, transparent)` y ese 6%
   se medía en pantalla: la tarjeta que quedaba debajo se transparentaba y su
   borde cyan CRUZABA el panel por debajo de los ítems, compitiendo con ellos.
   Un menú tiene que ser legible por encima de lo que tape, sea lo que sea. Sube
   a 99%: el borde de detrás desaparece, el desenfoque saturado sigue vivo en ese
   1% y en el halo del borde, y el aprobado —que usa un `--raised` SÓLIDO— queda
   respetado. No se sube a 100% a propósito: ahí `backdrop-filter` deja de pintar
   y se pierde el vidrio del todo.

   CONTRASTE, MEDIDO (WCAG AA · 4,5:1 texto normal · 3:1 gráficos), sobre
   `--bg-card` en los tres temas y sus dos materiales oscuros:
     nombre            --tx-base       15,14 : 1  ·  17,85 : 1  (peor · mejor)
     rol · organización--tx-secondary   7,44 : 1  ·  10,35 : 1
     rótulo del ítem   --tx-base       15,14 : 1  ·  17,85 : 1
     insignia y galón  --tx-secondary   7,44 : 1  ·  10,35 : 1
     íconos            --tx-secondary   7,44 : 1  (mínimo 3:1)
   El aprobado pinta la línea de organización y la insignia con su tinta más
   apagada (`--ink-4`). Aquí NO se usa la equivalente `--tx-muted`: medida sobre
   `darkmode` + `grafito` da 4,48 : 1 y se queda por debajo del 4,5 exigido a los
   11px de esta línea. Se sube un escalón, a `--tx-secondary`. Es la única
   diferencia de color con el aprobado y la razón es esa cifra.
   ════════════════════════════════════════════════════════════════════════════ */
.lk-account-anchor { position: relative; }

/* El velo. En escritorio es TRANSPARENTE — «un menú no oscurece la app»,
   lo dice el propio aprobado— y sólo existe para recoger el clic de fuera.
   No lleva manejador: al no estar dentro de `#accountPop`, el clic cae en el
   `_closeAccountMenu()` que `shell.js` ya tenía al final de su cadena. */
.lk-account-velo { display: none; }
.lk-account-anchor:has(.lk-account-pop.open) .lk-account-velo {
  display: block; position: fixed; inset: 0;
  z-index: calc(var(--z-dropdown) - 1); background: transparent;
}

.lk-account-pop {
  position: absolute; top: calc(100% + 10px); right: 0; z-index: var(--z-dropdown);
  width: 262px; max-width: calc(100vw - 24px); display: none; overflow: hidden;
  padding: 7px;
  background: color-mix(in srgb, var(--bg-card) 99%, transparent);
  backdrop-filter: var(--blur-md) saturate(1.4);
  -webkit-backdrop-filter: var(--blur-md) saturate(1.4);
  border: 1px solid var(--border); border-radius: 15px;
  box-shadow: var(--shadow-lg);
  transform-origin: top right;
}
.lk-account-pop.open { display: block; animation: lk-account-asomar 180ms cubic-bezier(.22,.8,.3,1); }
@keyframes lk-account-asomar {
  from { opacity: 0; transform: scale(.97) translateY(-5px); }
  to   { opacity: 1; transform: none; }
}

/* El asa es de la hoja de teléfono; en escritorio no existe. */
.lk-account-asa { display: none; }

/* LA CABECERA · foto, y DETRÁS de ella el nombre y «rol · organización».
   La foto ANTECEDE (orden de Cristián, 13-ago-2026): va en la fila, a su escala.
   El menú viejo la ponía de 76px, centrada y presidiendo la tarjeta, y era
   justamente eso lo que se estaba reemplazando. */
.lk-account-id { display: flex; align-items: center; gap: 11px; padding: 11px 13px 13px; }
.lk-account-avatar {
  /* `position:relative` es OBLIGATORIO (13-ago-2026): `.avatar-photo` de adentro
     es `position:absolute;inset:0;width:100%;height:100%` y sin un ancestro
     posicionado aquí su marco de referencia salta hasta `.lk-account-pop` (que sí
     es absolute). La foto se estiraba a ocupar TODO el menú y tapaba el nombre y
     las acciones. Verificado en producción (transed.luzo.cl). Mismo defecto que
     documenta AVATAR-02 arriba, un nivel más abajo. */
  position: relative; flex: 0 0 auto;
  width: 34px; height: 34px; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--c-accent-muted);
  /* LEY DE DISEÑO (Cristián, 14-ago-2026): «todos los halos/avatar del sistema
     son avatares circulares... y no llevan ni anillos, ni aros». Llevaba
     `border: 1px solid var(--lk-brand-border)`; se retira.
     SIN `overflow:hidden` desde spec-CORE-DOT-PRESENCIA (21-ago-2026): mismo
     motivo que `.avatar-btn` arriba en este fichero — el círculo lo recorta
     `.avatar-photo` por su cuenta, y lo único que pedía el `overflow:hidden`
     era recortar `.lph-dot`, que es el defecto que este cambio arregla. */
}
.lk-account-avatar .avatar-letters { font-size: var(--font-sm); }
.lk-account-quien { min-width: 0; display: flex; flex-direction: column; gap: 4px; }
.lk-account-name {
  color: var(--tx-base); font-size: var(--font-md); font-weight: 500;
  letter-spacing: -.01em; overflow-wrap: anywhere;
}
.lk-account-org {
  color: var(--tx-secondary); font-size: var(--font-xs); overflow-wrap: anywhere;
}

.lk-account-sep { height: .5px; background: var(--border); margin: 6px 13px; }
.lk-account-actions { padding: 0; border: 0; }

.lk-account-action {
  width: 100%; display: flex; align-items: center; gap: 11px;
  padding: 9px 13px; border: none; border-radius: 10px;
  background: transparent; color: var(--tx-base); cursor: pointer;
  font: inherit; font-size: var(--font-sm); text-align: left;
  transition: background var(--transition-fast), color var(--transition-fast);
}
.lk-account-action:hover { background: var(--bg-hover); }
.lk-account-action:focus-visible { outline: 2px solid var(--c-accent-soft); outline-offset: -2px; }
.lk-account-action:disabled { cursor: not-allowed; opacity: .45; }
.lk-account-action:disabled:hover { background: transparent; }
.lk-account-action-label { min-width: 0; }
.lk-account-action-icon {
  width: 18px; height: 18px; display: grid; place-items: center;
  flex-shrink: 0; color: var(--tx-secondary);
}
.lk-account-action:hover .lk-account-action-icon { color: var(--tx-base); }
.lk-account-action-icon svg {
  width: 17px; height: 17px; fill: none; stroke: currentColor; stroke-width: 1.7;
  stroke-linecap: round; stroke-linejoin: round;
}
/* La insignia con la vista puesta. Nace vacía y la rellena el cableado al abrir
   el menú; `:empty` la retira para que no deje un hueco ni arrastre el galón. */
.lk-account-valor {
  margin-left: auto; color: var(--tx-secondary); font-size: var(--font-xs);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 11ch;
}
.lk-account-valor:empty { display: none; }
.lk-account-galon {
  margin-left: auto; display: grid; place-items: center; color: var(--tx-secondary);
}
/* Con insignia, el galón va pegado a ella y no vuelve a empujar. */
.lk-account-valor:not(:empty) + .lk-account-galon { margin-left: 0; }
/* El atajo de teclado de «Bloquear pantalla» (14-ago). No es una insignia de estado
   —no dice qué está puesto— sino una tecla: por eso va en mono, apagada y sin fondo,
   como la pista discreta que es. El atajo funciona desde antes; esto sólo lo cuenta.
   En teléfono no hay teclado físico y la fila se lee mejor sin él, así que se retira
   por `[data-bp]`, no por `@media`, para seguir el corte que declara el shell. */
.lk-account-kbd {
  margin-left: auto; color: var(--tx-muted, var(--tx-secondary));
  font-family: var(--lk-font-mono); font-size: var(--font-xs);
  letter-spacing: .02em; white-space: nowrap; flex-shrink: 0;
}
[data-bp="phone"] .lk-account-kbd { display: none; }
.lk-account-galon svg {
  width: 13px; height: 13px; fill: none; stroke: currentColor; stroke-width: 1.7;
  stroke-linecap: round; stroke-linejoin: round;
}

/* ── TELÉFONO · hoja inferior con asa (aprobado, `.hoja`) ────────────────────
   Mismos ítems, misma cabecera. Dos cambios que pide el aprobado y que no son
   cosméticos: el asa aparece —y por eso el separador de la cabecera SE RETIRA,
   porque el asa ya separa y dos rayas para lo mismo sobran— y el velo sí atenúa,
   como cualquier hoja del sistema. El popover no atenuaba porque flota junto a
   su disparador; la hoja tapa media pantalla y necesita decir que lo hace. */
[data-bp="phone"] .lk-account-anchor:has(.lk-account-pop.open) .lk-account-velo {
  z-index: calc(var(--z-modal) - 1);
  /* Tinta FIJA, no derivada del tema. Se intentó con `--lk-bg-body` y en tema
     claro el velo salía CLARO: en vez de atenuar el fondo, lo blanqueaba. Un
     velo atenúa siempre hacia lo oscuro. El valor es el que ya usa el velo de
     las hojas del chasis (`#shellScrim`, lk-layout.css:234), no uno nuevo. */
  background: rgba(0, 0, 0, .42);
  animation: lk-account-velar 200ms ease;
}
@keyframes lk-account-velar { from { opacity: 0; } to { opacity: 1; } }
[data-bp="phone"] .lk-account-pop {
  position: fixed; top: auto; right: 0; left: 0;
  bottom: 0; width: auto; max-width: none;
  z-index: var(--z-modal);
  padding: 9px 13px calc(env(safe-area-inset-bottom, 0px) + 20px);
  border: 0; border-radius: 22px 22px 0 0;
  max-height: 86%; overflow: auto;
}
[data-bp="phone"] .lk-account-pop.open { animation: lk-account-subir 260ms cubic-bezier(.22,.8,.3,1); }
@keyframes lk-account-subir { from { transform: translateY(20px); } to { transform: none; } }
[data-bp="phone"] .lk-account-asa {
  display: block; width: 38px; height: 4px; border-radius: 2px;
  background: var(--border); margin: 0 auto 16px;
}
[data-bp="phone"] .lk-account-id { padding: 0 0 14px; }
[data-bp="phone"] .lk-account-sep--cabecera { display: none; }

@media (prefers-reduced-motion: reduce) {
  .lk-account-pop.open,
  [data-bp="phone"] .lk-account-pop.open,
  [data-bp="phone"] .lk-account-anchor:has(.lk-account-pop.open) .lk-account-velo { animation: none; }
}

.notif-badge {
  position: absolute; top: 4px; right: 4px; min-width: 16px; height: 16px;
  border-radius: 99px; background: var(--tx-red); color: #fff;
  font-size: calc(var(--font-base) * 0.769); font-weight: 500; display: flex; align-items: center; justify-content: center;
  padding: 0 4px; pointer-events: none;
}
.notif-badge:empty { display: none; }


/* ═══════════════════════════════════════════════════════════════════════════
   3. POPUP / GLASSMORPHISM
═══════════════════════════════════════════════════════════════════════════ */

.pop {
  position: absolute; top: calc(100% + 8px); right: 0; min-width: 220px;
  background: color-mix(in srgb, var(--bg-card) 85%, transparent);
  backdrop-filter: var(--blur-md); -webkit-backdrop-filter: var(--blur-md);
  border: 1px solid var(--border); border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg); padding: var(--space-2);
  display: none; z-index: var(--z-dropdown);
}
.pop--open, .pop.open { display: block; animation: mod-fade-in 120ms ease; }

.pop-title { font-size: var(--font-sm); font-weight: 500; color: var(--tx-base); padding: var(--space-1) var(--space-2); }
.pop-sub   { font-size: var(--font-xs); color: var(--tx-muted); padding: 0 var(--space-2) var(--space-1); }
.pop-sep   { height: 1px; background: var(--border-soft); margin: var(--space-1) 0; }

.pop-btn {
  width: 100%; display: flex; align-items: center; gap: var(--space-2);
  padding: 8px var(--space-2); border-radius: var(--radius-md); border: none;
  background: transparent; cursor: pointer; color: var(--tx-base);
  font-size: var(--font-sm); text-align: left; font-family: inherit;
  transition: background var(--transition-fast);
}
.pop-btn:hover       { background: var(--bg-hover); }
.pop-btn--danger     { color: var(--tx-red); }
.pop-btn--danger:hover { background: var(--lk-red-soft); }

.pop-btn-ico     { width: 16px; height: 16px; display: grid; place-items: center; color: var(--tx-muted); flex-shrink: 0; }
.pop-btn-ico svg { width: 14px; height: 14px; fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }


/* ═══════════════════════════════════════════════════════════════════════════
   4. BADGES
═══════════════════════════════════════════════════════════════════════════ */

.cl-badge {
  display: inline-flex; align-items: center; padding: 2px 8px;
  border-radius: 99px; font-size: calc(var(--font-base) * 0.846); font-weight: 500;
}
.cl-badge--green { background: var(--lk-green-soft); color: var(--tx-green); border: 1px solid color-mix(in srgb, var(--tx-green) 30%, transparent); }
.cl-badge--red   { background: var(--lk-red-soft);   color: var(--tx-red);   border: 1px solid color-mix(in srgb, var(--tx-red) 30%, transparent); }
.cl-badge--amber { background: var(--lk-amber-soft); color: var(--tx-amber); border: 1px solid color-mix(in srgb, var(--tx-amber) 30%, transparent); }
.cl-badge--muted { background: var(--bg-hover);      color: var(--tx-muted); border: 1px solid var(--border-soft); }
.cl-badge--brand { background: var(--c-accent-muted); color: var(--c-accent-soft); border: 1px solid var(--lk-brand-border); }

/* ═══════════════════════════════════════════════════════════════════════════
   5. TOAST
═══════════════════════════════════════════════════════════════════════════ */

#lz-toast {
  position: absolute; bottom: var(--space-4); right: var(--space-4);
  z-index: var(--z-toast); display: flex; flex-direction: column; gap: var(--space-2);
}
.lz-toast {
  padding: 10px var(--space-4); border-radius: var(--radius-md);
  background: var(--bg-card); border: 1px solid var(--border);
  box-shadow: var(--shadow-md); font-size: var(--font-sm); color: var(--tx-base);
  animation: mod-fade-in 150ms ease;
}

/* ═══════════════════════════════════════════════════════════════════════════
   6. MODULE LAYOUT HELPERS
═══════════════════════════════════════════════════════════════════════════ */

.mod-page    { height: 100%; display: flex; flex-direction: column; overflow: hidden; }
.mod-toolbar { padding: var(--space-3) var(--space-4); display: flex; align-items: center; gap: var(--space-2); flex-shrink: 0; border-bottom: 1px solid var(--border-soft); }
.mod-split   { flex: 1; display: flex; overflow: hidden; }
.mod-left    { width: 280px; flex-shrink: 0; border-right: 1px solid var(--border-soft); overflow-y: auto; scrollbar-width: thin; overscroll-behavior: contain; }
.mod-right   { flex: 1; overflow-y: auto; scrollbar-width: thin; overscroll-behavior: contain; }


/* ═══════════════════════════════════════════════════════════════════════════
   7. BLADE SYSTEM
═══════════════════════════════════════════════════════════════════════════ */

/* ── Dimmer ── */
.ld-dimmer {
  position: absolute; inset: 0;
  background: rgba(0,0,0,.35);   /* always dark — theme-invariant */
  z-index: 500;
  opacity: 0; visibility: hidden; pointer-events: none;
  transition: opacity .28s, visibility .28s;
  contain: layout style;
}
.ld-dimmer.on { opacity: 1; visibility: visible; pointer-events: auto; }


/* ═══════════════════════════════════════════════════════════════════════════
   8. BLADE ACTIONS (footer bar)
═══════════════════════════════════════════════════════════════════════════ */

.blade-actions {
  display: flex; align-items: center; gap: 8px;
  padding: 10px 16px 12px;
  border-top: 1px solid var(--border-soft);
  position: sticky; bottom: 0;
  background: var(--bg-card);
}
.blade-actions-left  { display: flex; gap: 6px; }
.blade-actions-right { display: flex; gap: 8px; margin-left: auto; }

.blade-btn-primary {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 7px 14px; border-radius: 8px;
  background: var(--c-accent); color: #fff;
  border: none; font-size: calc(var(--font-base) * 0.962); font-weight: 500;
  cursor: pointer; font-family: inherit;
  transition: opacity .13s;
}
.blade-btn-primary:hover { opacity: .88; }
.blade-btn-primary svg   { width: 13px; height: 13px; flex-shrink: 0; }

.blade-btn-ghost {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 7px 12px; border-radius: 8px;
  background: transparent; color: var(--tx-muted);
  border: 1px solid var(--border); font-size: calc(var(--font-base) * 0.962); font-weight: 500;
  cursor: pointer; font-family: inherit;
  transition: border-color .12s, color .12s;
}
.blade-btn-ghost:hover { border-color: var(--border); color: var(--tx-base); }
.blade-btn-ghost svg   { width: 13px; height: 13px; flex-shrink: 0; }

.blade-btn-download {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 6px 10px; border-radius: 7px;
  background: transparent; color: var(--tx-muted);
  border: 1px solid var(--border-soft); font-size: calc(var(--font-base) * 0.885); font-weight: 500;
  cursor: pointer; font-family: inherit;
  transition: color .12s, border-color .12s;
}
.blade-btn-download:hover { color: var(--tx-base); border-color: var(--border); }
.blade-btn-download svg   { width: 12px; height: 12px; flex-shrink: 0; }

/* ── Info badge (left side of blade footer) ── */
.blade-info-badge {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: calc(var(--font-base) * 0.846); font-weight: 500; color: var(--tx-muted);
  padding: 0; background: none; border: none;
}
.blade-info-badge svg { width: 11px; height: 11px; flex-shrink: 0; opacity: .6; }

.blade-info-badge--legal     { color: var(--tx-amber); }
.blade-info-badge--legal svg { color: var(--tx-amber); }

.blade-info-badge--secure     { color: var(--lk-teal); }
.blade-info-badge--secure svg { color: var(--lk-teal); }

/* ── Error shake ── */
.blade-actions-left.up-error { animation: up-shake .4s ease; }
.blade-error-msg {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: calc(var(--font-base) * 0.846); font-weight: 500; color: var(--tx-red);
}
.blade-error-msg svg { width: 11px; height: 11px; flex-shrink: 0; }


/* ═══════════════════════════════════════════════════════════════════════════
   9. MODULE TOPBAR
═══════════════════════════════════════════════════════════════════════════ */

/* La barra de modulo canonica es `.lk-modulebar` (mas abajo), que YA usan 9
   modulos. Aqui vivio `.lz-mod-topbar`: una barra que NO pintaba nadie, existia
   solo en el CSS, y por eso en su dia cada modulo se hizo la suya. Retirada
   entera el 31-jul-2026 — dos canonicas es peor que ninguna. */


/* ═══════════════════════════════════════════════════════════════════════════
   10. FORM SYSTEM
═══════════════════════════════════════════════════════════════════════════ */

.lz-field { display: flex; flex-direction: column; gap: 4px; margin-bottom: 12px; }

.lz-field label,
.lz-label {
  font-size: calc(var(--font-base) * 0.846); font-weight: 500;
  color: var(--tx-muted); letter-spacing: .02em;
}
.lz-field label small { font-weight: 400; font-size: calc(var(--font-base) * 0.769); color: var(--tx-dim); }

.lz-input,
.lz-select,
.lz-field input:not([type=radio]):not([type=checkbox]),
.lz-field select,
.lz-field textarea {
  height: 32px;
  border: .5px solid var(--border);
  border-radius: 7px;
  background: var(--bg-surface);
  padding: 0 10px;
  font-size: calc(var(--font-base) * 1.0); font-family: inherit;
  color: var(--tx-base);
  width: 100%; outline: none;
  transition: border-color .12s;
  box-sizing: border-box;
}
.lz-field textarea { height: auto; min-height: 72px; padding: 8px 10px; resize: vertical; }

/* ── RESP-04 · Anti-zoom de iOS en campos (system-wide) ───────────────────────────
   iOS Safari hace zoom automático al enfocar un input con font-size < 16px y, como
   el shell es overflow:hidden + 100dvh, el zoom queda pegado hasta recargar. En
   punteros táctiles (teléfono/tablet) forzamos ≥16px en TODO control de texto —
   incluye el buscador del header y el spotlight. No se usa maximum-scale=1 (rompe
   el pinch-zoom = antipatrón de accesibilidad). En escritorio quedan los tamaños
   de diseño (13px), donde no hay auto-zoom. */
@media (pointer: coarse) {
  .lz-input, .lz-select,
  .lz-field input:not([type=radio]):not([type=checkbox]),
  .lz-field select, .lz-field textarea,
  .spotlight-input, .sp3-input,
  input[type=text], input[type=search], input[type=email], input[type=tel],
  input[type=number], input[type=password], input[type=url], input[type=date],
  input[type=datetime-local], input[type=time], textarea, select {
    font-size: calc(var(--font-base) * 1.231);
  }
}

.lz-input:focus,
.lz-select:focus,
.lz-field input:focus,
.lz-field select:focus,
.lz-field textarea:focus { border-color: var(--c-accent); }

.lz-field input.has-error,
.lz-field select.has-error { border-color: var(--tx-red); }

.lz-field-row        { display: flex; gap: 10px; }
.lz-field-row .lz-field { flex: 1; }

.lz-radio-group {
  display: flex; gap: 14px; margin-top: 2px;
}
.lz-radio-group label {
  display: flex; align-items: center; gap: 6px;
  font-size: calc(var(--font-base) * 1.0); font-weight: 400; color: var(--tx-base); cursor: pointer;
}

.lz-check-row {
  display: flex; align-items: center; justify-content: space-between;
  padding: 8px 0; border-top: .5px solid var(--border-soft); margin-top: 4px;
}
.lz-check-row label { font-size: calc(var(--font-base) * 1.0); color: var(--tx-base); }

/* ── Form errors (E1.3) ── */
.field-error { font-size: var(--font-xs); color: var(--tx-red); margin-top: 2px; display: block; }
.has-error   { border-color: var(--tx-red) !important; }

/* ── Blade form actions ── */
.lz-blade-actions {
  display: flex; gap: 8px; padding: 16px;
  border-top: .5px solid var(--border-soft);
  background: var(--bg-card); flex-shrink: 0;
}

/* ── Buttons ── */
.lz-btn-primary {
  height: 34px;
  background: var(--c-accent); color: #fff;
  border: none; border-radius: 8px; padding: 0 20px;
  font-size: calc(var(--font-base) * 1.0); font-weight: 500; cursor: pointer;
  font-family: inherit; transition: filter .12s;
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
}
.lz-btn-primary:hover    { filter: brightness(.88); }
.lz-btn-primary:disabled { opacity: .5; cursor: default; }

.lz-btn-ghost {
  height: 34px;
  background: transparent; color: var(--tx-base);
  border: .5px solid var(--border); border-radius: 8px; padding: 0 16px;
  font-size: calc(var(--font-base) * 1.0); cursor: pointer;
  font-family: inherit; transition: background .12s;
}
.lz-btn-ghost:hover { background: var(--bg-hover); }


/* ═══════════════════════════════════════════════════════════════════════════
   11. CUSTOM SELECT (LK.select)
═══════════════════════════════════════════════════════════════════════════ */

.lks-wrap { position: relative; width: 100%; }

.lks-trigger {
  width: 100%;
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  padding: 8px 12px;
  border: 1px solid var(--border);
  border-radius: 8px; background: var(--bg-card);
  font-size: calc(var(--font-base) * 1.0); font-family: inherit; color: var(--tx-muted);
  cursor: pointer; text-align: left;
  transition: border-color .14s, box-shadow .14s;
}
.lks-trigger svg {
  width: 14px; height: 14px; flex-shrink: 0;
  stroke: var(--tx-muted); transition: transform .18s;
}

.lks-wrap.lks-open .lks-trigger {
  border-color: var(--c-accent);
  box-shadow: var(--lk-ring-focus);
}
.lks-wrap.lks-open .lks-trigger svg { transform: rotate(180deg); }
.lks-wrap.lks-selected .lks-trigger { color: var(--tx-base); }
.lks-wrap.lks-disabled .lks-trigger { opacity: .5; cursor: not-allowed; }

.lks-drop {
  position: absolute; left: 0; right: 0; top: calc(100% + 4px);
  z-index: 650;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 10px;
  box-shadow: var(--shadow-lg);
  overflow: hidden; max-height: 260px;
  display: flex; flex-direction: column;
  opacity: 0; pointer-events: none;
  transform: translateY(-4px);
  transition: opacity .15s, transform .15s;
  contain: layout style;
}
.lks-wrap.lks-open .lks-drop { opacity: 1; pointer-events: auto; transform: translateY(0); display: flex; }
.lks-drop--up { top: auto; bottom: calc(100% + 4px); transform: translateY(4px); }
.lks-wrap.lks-open .lks-drop--up { transform: translateY(0); }

.lks-search-wrap { padding: 8px 8px 4px; flex-shrink: 0; border-bottom: 1px solid var(--border-soft); }
.lks-search {
  width: 100%; padding: 6px 10px;
  border: 1px solid var(--border); border-radius: 6px;
  font-size: calc(var(--font-base) * 0.923); font-family: inherit;
  background: var(--bg-surface); color: var(--tx-base);
  outline: none; transition: border-color .13s;
}
.lks-search:focus       { border-color: var(--c-accent); }
.lks-search::placeholder { color: var(--tx-muted); }

.lks-list { overflow-y: auto; flex: 1; padding: 4px; scrollbar-width: thin; overscroll-behavior: contain; }

.lks-item {
  width: 100%; display: block; padding: 7px 10px;
  border: none; border-radius: 6px;
  background: transparent;
  font-size: calc(var(--font-base) * 0.962); font-family: inherit; color: var(--tx-base);
  text-align: left; cursor: pointer;
  transition: background .1s, color .1s;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.lks-item:hover     { background: var(--bg-hover); }
.lks-item--active   { background: var(--c-accent-muted); color: var(--c-accent); font-weight: 500; }
.lks-item--disabled { color: var(--tx-dim); cursor: default; }
.lks-item--disabled:hover { background: transparent; }
.lks-empty { padding: 10px 12px; font-size: calc(var(--font-base) * 0.923); color: var(--tx-muted); text-align: center; font-style: italic; }


/* ═══════════════════════════════════════════════════════════════════════════
   12. USER PICKER (staff-promote blade)
═══════════════════════════════════════════════════════════════════════════ */

.up-user-list {
  display: flex; flex-direction: column; gap: 3px;
  overflow-y: auto;
  border: 1px solid var(--border); border-radius: 10px;
  padding: 4px; scrollbar-width: thin; overscroll-behavior: contain;
}
.up-user-card {
  display: flex; align-items: center; gap: 10px;
  width: 100%; padding: 7px 10px;
  border: none; border-radius: 7px;
  background: transparent; cursor: pointer; text-align: left; font-family: inherit;
  transition: background .12s;
}
.up-user-card:hover    { background: var(--bg-hover); }
.up-user-card.up-selected {
  background: var(--c-accent-muted);
  outline: 1.5px solid var(--c-accent);
}

.up-user-avatar {
  width: 30px; height: 30px; flex-shrink: 0;
  border-radius: 50%; overflow: hidden;
  background: var(--c-accent-muted);
  display: flex; align-items: center; justify-content: center;
}
.up-user-avatar img  { width: 100%; height: 100%; object-fit: cover; }
.up-user-avatar span { font-size: calc(var(--font-base) * 0.846); font-weight: 500; color: var(--c-accent); letter-spacing: .5px; }
.up-user-info  { min-width: 0; }
.up-user-name  { font-size: calc(var(--font-base) * 0.923); font-weight: 500; color: var(--tx-base); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.up-user-email { font-size: calc(var(--font-base) * 0.846); color: var(--tx-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* ── Toggle iOS ── */
.up-toggle-row  { display: flex; gap: 8px; }
.up-toggle-wrap {
  flex: 1; display: flex; align-items: center; justify-content: space-between;
  padding: 8px 12px;
  border: 1px solid var(--border); border-radius: 9px;
  cursor: pointer; user-select: none;
  transition: border-color .14s, background .14s;
}
.up-toggle-wrap:hover  { background: var(--bg-hover); }
.up-toggle-label { font-size: calc(var(--font-base) * 0.923); font-weight: 500; color: var(--tx-base); }
.up-toggle-track { position: relative; width: 36px; height: 20px; flex-shrink: 0; }
.up-toggle-input { position: absolute; opacity: 0; width: 0; height: 0; }
.up-toggle-thumb {
  position: absolute; inset: 0;
  background: var(--border); border-radius: 10px;
  transition: background .2s;
}
.up-toggle-thumb::after {
  content: ''; position: absolute; top: 2px; left: 2px;
  width: 16px; height: 16px;
  background: #fff; border-radius: 50%;
  box-shadow: var(--shadow-sm); transition: transform .2s;
}
.up-toggle-input:checked + .up-toggle-thumb { background: var(--c-accent); }
.up-toggle-input:checked + .up-toggle-thumb::after { transform: translateX(16px); }
.up-toggle-wrap:has(.up-toggle-input:checked) {
  border-color: var(--c-accent);
  background: var(--c-accent-muted);
}


/* ═══════════════════════════════════════════════════════════════════════════
   13. PROMOTE BLADE LAYOUT
═══════════════════════════════════════════════════════════════════════════ */

#form-staff-promote { display: flex; flex-direction: column; height: 100%; }
#form-staff-promote > div:first-child { flex: 1; overflow-y: hidden; padding: 6px 16px 8px; }
#form-staff-promote .lz-field       { margin-bottom: 5px; }
#form-staff-promote .lz-field-row   { margin-bottom: 5px; gap: 10px; }
#form-staff-promote .lz-field label { display: block; font-size: calc(var(--font-base) * 0.846); font-weight: 500; color: var(--tx-muted); margin-bottom: 3px; }
#form-staff-promote input[type="text"],
#form-staff-promote .lks-trigger    { padding: 6px 10px; font-size: calc(var(--font-base) * 0.962); box-sizing: border-box; width: 100%; }
#form-staff-promote .lks-trigger    { display: flex; align-items: center; justify-content: space-between; }
#form-staff-promote .lks-trigger svg { width: 14px; height: 14px; flex-shrink: 0; display: block; }
#form-staff-promote select          { display: none; }
#form-staff-promote .up-user-list   { height: 158px; min-height: 158px; margin-bottom: 8px; }
#form-staff-promote .up-toggle-row  { margin-top: 3px; }


/* ═══════════════════════════════════════════════════════════════════════════
   14. TASKBAR PILLS (minimized blades) — v4 final
   - Glass material + backdrop-filter
   - Botones siempre visibles · opacity .7 → 1 en hover
   - Tints por data-tint (paciente / staff / reserva / agenda)
   - Tokens scoped por tema (light fallback inline · midnight/dark via [data-theme])
   - Animaciones premium · pill-in micro-bounce + blade soft-min/soft-max
     (los keyframes blade-* esperan --gx --gy seteados desde lk-desk.js)
═══════════════════════════════════════════════════════════════════════════ */

/* Tokens por tema · scoped, conviven con cualquier definición en lk-tokens.css */
:where(:root, [data-theme="lightmode"]) {
  --lk-pill-bg:           rgba(255,255,255, .65);
  --lk-pill-bg-h:         rgba(255,255,255, .85);
  --lk-pill-bd-inset:     rgba(15,23,42, .06);
  --lk-pill-bd-active:    rgba(15,23,42, .08);
  --lk-pill-shadow:       0 -2px 12px rgba(15,23,42, .04);
}
[data-theme="midnight"] {
  --lk-pill-bg:           rgba(42,51,79, .65);
  --lk-pill-bg-h:         rgba(58,70,110, .85);
  --lk-pill-bd-inset:     rgba(255,255,255, .06);
  --lk-pill-bd-active:    rgba(255,255,255, .10);
  --lk-pill-shadow:       0 -2px 14px rgba(0,0,0, .25);
}
[data-theme="darkmode"] {
  --lk-pill-bg:           rgba(26,32,48, .70);
  --lk-pill-bg-h:         rgba(38,46,68, .90);
  --lk-pill-bd-inset:     rgba(255,255,255, .06);
  --lk-pill-bd-active:    rgba(255,255,255, .10);
  --lk-pill-shadow:       0 -2px 16px rgba(0,0,0, .40);
}

#ldTaskbar {
  position: absolute;
  /* El despeje sobre el dock es a propósito, no heredado (4-ago-2026). Antes esta
     barra quedaba libre por accidente: era el último hijo de .tx-content y le caía
     encima el `margin-bottom` que el chasis creía estar dándole al módulo. Medido en
     la app: 11px de aire sobre el dock. Al arreglar la reserva del dock ese margen
     desaparece, y como esta barra tiene z-index 90 contra los 55 del dock, se le
     habría sentado encima. --lk-dock-reserva vale 0px donde no hay dock (tablet y
     escritorio), así que fuera del teléfono esto es idéntico a `bottom: 0`. */
  left: 12px; right: 12px; bottom: var(--lk-dock-reserva, 0px);
  z-index: 90;
  display: none;
  align-items: flex-end;
  gap: 1px;
  pointer-events: none;
  overflow-x: auto;
  scrollbar-width: none;
}
#ldTaskbar::-webkit-scrollbar { display: none; }
#ldTaskbar.ld-pills           { display: flex; pointer-events: auto; }
#ldTaskbar > *                { pointer-events: auto; }

.ld-pill {
  position: relative;
  display: inline-flex; align-items: center;
  flex-shrink: 0;
  gap: 8px;
  width: 200px; min-width: 140px; height: 34px;
  padding: 0 8px 0 12px;

  background: var(--lk-pill-bg);
  -webkit-backdrop-filter: blur(24px) saturate(180%);
  backdrop-filter: blur(24px) saturate(180%);

  border: none;
  border-radius: 11px 11px 0 0;
  box-shadow: var(--lk-pill-shadow);

  color: var(--tx-muted);
  font-size: calc(var(--font-base) * 0.923);
  font-family: inherit;
  font-weight: 500;
  letter-spacing: -.005em;
  text-align: left;
  cursor: pointer;
  user-select: none;

  --tbpill-ico: var(--c-accent);

  transform-origin: bottom center;
  will-change: transform, opacity;
  animation: ld-pill-in 260ms cubic-bezier(.34, 1.56, .64, 1);
  transition: background 180ms cubic-bezier(.16, 1, .3, 1), color 180ms;
}
.ld-pill::before {
  content: '';
  position: absolute; inset: 0;
  border-radius: inherit;
  box-shadow: 0 0 0 .5px var(--lk-pill-bd-inset) inset;
  pointer-events: none;
}
.ld-pill:hover:not(.is-active) {
  background: var(--lk-pill-bg-h);
  color: var(--tx-base);
}
.ld-pill.is-active {
  background: var(--bg-card);
  color: var(--tx-base);
  font-weight: 500;
  z-index: 2;
}
.ld-pill.is-active::before {
  box-shadow: 0 0 0 .5px var(--lk-pill-bd-active) inset;
}
.ld-pill:focus-visible {
  outline: 2px solid var(--c-accent);
  outline-offset: -2px;
}

/* Tints por módulo · color del icono */
.ld-pill[data-tint="staff"]   { --tbpill-ico: var(--lk-teal,  #0d9488); }
.ld-pill[data-tint="reserva"] { --tbpill-ico: var(--lk-amber, #d97706); }
.ld-pill[data-tint="agenda"]  { --tbpill-ico: var(--lk-blue,  #2563eb); }

.ld-pill-ico {
  flex-shrink: 0;
  display: inline-flex; align-items: center;
}
.ld-pill-ico svg {
  width: 13px; height: 13px;
  stroke: var(--tbpill-ico);
  stroke-width: 1.7;
  stroke-linecap: round; stroke-linejoin: round;
  fill: none;
}

.ld-pill-txt {
  flex: 1; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* Acciones — siempre visibles */
.ld-pill-actions {
  display: inline-flex; align-items: center; gap: 1px;
  margin-left: 2px;
}
.ld-pill-btn {
  width: 22px; height: 22px;
  display: inline-grid; place-items: center;
  border: none; background: transparent;
  border-radius: 6px;
  color: var(--tx-dim, #94a3b8);
  cursor: pointer; padding: 0;
  opacity: .7;
  transition: opacity 120ms, background 140ms, color 140ms;
}
.ld-pill:hover .ld-pill-btn,
.ld-pill.is-active .ld-pill-btn { opacity: 1; }
.ld-pill-btn:hover { opacity: 1; }
.ld-pill-btn svg {
  width: 11px; height: 11px;
  stroke: currentColor; stroke-width: 2;
  stroke-linecap: round; stroke-linejoin: round;
  fill: none;
}
.ld-pill-btn--max:hover,
.ld-pill-btn[data-pill-restore]:hover {
  background: var(--lk-amber-soft, rgba(217,119,6, .10));
  color: var(--lk-amber, #d97706);
}
.ld-pill-btn--close:hover,
.ld-pill-btn[data-pill-close]:hover {
  background: var(--lk-red-soft, rgba(220,38,38, .10));
  color: var(--tx-red, #dc2626);
}
.ld-pill-btn:focus-visible {
  outline: 1.5px solid var(--c-accent);
  outline-offset: 1px;
  opacity: 1;
}

/* Animaciones · pill */
@keyframes ld-pill-in {
  0%   { opacity: 0; transform: translateY(-4px) scale(.92); }
  60%  { opacity: 1; transform: translateY(1px)  scale(1.02); }
  100% { opacity: 1; transform: translateY(0)    scale(1); }
}
@keyframes ld-pill-out {
  to { opacity: 0; transform: translateY(6px) scale(.94); }
}
.ld-pill.is-leaving {
  animation: ld-pill-out 200ms cubic-bezier(.4, 0, .68, .06) forwards;
  pointer-events: none;
}
.ld-pill.is-expanding {
  animation: ld-pill-expand 140ms cubic-bezier(.4, 0, 1, 1) forwards;
  pointer-events: none;
}
@keyframes ld-pill-expand {
  to { opacity: 0; transform: translateY(-2px) scale(.9); }
  100% { opacity: 0; transform: translate(calc(var(--gx, 0px) * .55), calc(var(--gy, 0px) * .85)) scale(.42); }
  100% { opacity: 1; transform: translate(0, 0) scale(1); }
}

@media (prefers-reduced-motion: reduce) {
  .ld-pill, .ld-pill-btn,
  .ld-pill:hover, .ld-pill.is-active,
  .ld-pill.is-leaving, .ld-pill.is-expanding {
    animation: none !important;
    transition: none !important;
    transform: none !important;
  }
  .ld-pill-btn { opacity: 1; }
}


/* ═══════════════════════════════════════════════════════════════════════════
   15. LEGACY TASKBAR TABS (luzokit-shell compat)
═══════════════════════════════════════════════════════════════════════════ */

.ld-taskbar {
  position: absolute; bottom: 0; left: 52px; right: 0; height: 40px;
  z-index: 480; display: flex; align-items: center; gap: 8px;
  padding: 0 12px; pointer-events: none;
}
.ld-taskbar > * { pointer-events: auto; }

.ld-tb-tab {
  pointer-events: auto;
  display: inline-flex; align-items: center; gap: 7px;
  padding: 6px 10px 7px 8px;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-bottom: none; border-right: none;
  border-radius: 8px 8px 0 0;
  cursor: pointer; font-family: inherit;
  transition: border-color .12s, background .12s;
  max-width: 200px;
  box-shadow: var(--shadow-sm);
}
.ld-tb-tab:last-child { border-right: 1px solid var(--border); }
.ld-tb-tab:hover      { border-color: var(--c-accent); }

.ld-tb-icon     { width: 18px; height: 18px; border-radius: 5px; display: grid; place-items: center; flex-shrink: 0; }
.ld-tb-icon svg { width: 10px; height: 10px; }
.ld-tb-icon--editor { background: var(--c-accent-muted); color: var(--c-accent); }
.ld-tb-icon--viewer { background: var(--lk-teal-soft); color: var(--lk-teal); }

.ld-tb-title {
  font-size: calc(var(--font-base) * 0.885); font-weight: 500; color: var(--tx-base);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 130px;
}
.ld-tb-close {
  width: 16px; height: 16px; border-radius: 3px;
  display: grid; place-items: center;
  cursor: pointer; color: var(--tx-muted);
  font-size: calc(var(--font-base) * 0.846); line-height: 1;
  transition: background .1s, color .1s; flex-shrink: 0;
}
.ld-tb-close:hover { background: var(--lk-red-soft); color: var(--tx-red); }
/* ─────────────────────────────────────────────────────────────────────────────
 * lk-photo.css — Estilos canónicos del helper LUZOPhoto v3.0
 *
 * El helper inyecta estilos inline críticos (color, size dinámico) directamente
 * en el HTML producido por LUZOPhoto.html(). Este archivo agrega:
 *
 *   - Reglas opcionales para casos de uso específicos (cursor, transitions,
 *     accesibilidad).
 *   - Override seguro si el módulo necesita cambiar el comportamiento default.
 *   - Patrón canónico documentado del halo glow del sistema.
 *
 * Patrón canónico (regla absoluta del sistema):
 *   - Halo = radial-gradient glow difuso. NUNCA anillos sólidos. NUNCA borders.
 *   - Selección = solo background sutil. NUNCA border-left.
 *
 * Concatenar al final de lk-components.css.
 * ─────────────────────────────────────────────────────────────────────────── */

/* Wrapper externo del avatar (creado por LUZOPhoto.html) */
.lph-wrap {
  position: relative;
  display: inline-flex;
  flex-shrink: 0;
  vertical-align: middle;
  border-radius: 50%;
}

/* Halo glow difuso (capa 0) — los colores los inyecta el helper inline */
.lph-halo {
  pointer-events: none;
  z-index: 0;
}

/* Imagen de la foto (capa 1) */
.lph-img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 50%;
  position: relative;
  z-index: 1;
  transition: transform .22s ease;
}

/* Iniciales fallback (capa 1, oculta cuando hay foto) */
.lph-ini {
  width: 100%;
  height: 100%;
  border-radius: 50%;
  align-items: center;
  justify-content: center;
  color: #fff;
  font-weight: 500;
  position: relative;
  z-index: 1;
  user-select: none;
}

/* Dot online/offline (capa 2) — color y animación lo inyecta el helper */
/* EL DOT DE PRESENCIA · recurso de TODA la casa, no de un módulo (Cristián,
   16-ago-2026): «agregales el dot de conexión... para que sea un recurso de
   todo el sistema y no sólo de un módulo en particular». Antes sólo lo pintaba
   `modules/cfg/cfg-usuarios.css` (`.cfg-us-pt`, mismo patrón de colores y
   mismo comentario de los tres estados); ahora lo emite `LK.avatar.html()` y
   `.pintar()` para cualquier halo/foto de persona o profesional del sistema
   (nunca clientes ni pacientes — eso lo decide quien llama, no este CSS).

   HISTORIAL DEL DEFECTO (spec-CORE-DOT-PRESENCIA, 21-ago-2026) — lo que decía
   este comentario antes ERA EL PLAN, y el plan falló en dos formas medidas:

   1) «Con right/bottom en positivo el punto queda dentro del borde y no hace
      falta tocar los contenedores.» FALSO en la práctica: a `1px` (el valor que
      quedó en el código) el anillo cae fuera del radio del halo — 21,3px del
      centro contra un radio de 20 en un halo de 40px — y `.avatar-btn` /
      `.lk-account-avatar` SÍ tenían `overflow:hidden`, así que lo recortaban:
      media luna en vez de círculo, reportado vivo en la aplicación.
   2) Se probó compensar metiendo el punto más adentro (`7px` en un halo de
      40px): dejó de recortarse, pero quedó ENCIMA de las iniciales/la cara.
      Cristián lo vio renderizado y lo rechazó: «el dot no va donde debería ir».

   Es geométrico y no tiene arreglo con un solo número: en un círculo con
   `overflow:hidden`, o el punto se sale por el borde y se corta, o se mete lo
   bastante para caber y entonces invade el retrato. LA SALIDA ES QUE EL PUNTO
   DEJE DE ESTAR DENTRO DE UN ELEMENTO QUE RECORTA. `.avatar-btn`,
   `.lk-account-avatar` y `.lk-avcard-photo` (los tres halos censados donde
   ancla `.lph-dot`) perdieron su `overflow:hidden` — el círculo de la foto lo
   sigue recortando `.avatar-photo` con su propio `border-radius:50%` (un
   elemento reemplazado se recorta solo, sin ayuda del padre) y el fondo del
   halo se recorta solo por su propio `border-radius`, así que nada de eso se
   perdió. Con el padre sin `overflow:hidden`, `.lph-dot` renderiza su círculo
   COMPLETO — nunca más cortado — apoyado en la esquina inferior derecha: la
   mayor parte de su superficie cae ya fuera del radio del halo, y sólo un borde
   mínimo pisa el círculo, exactamente donde un indicador de presencia se apoya
   en cualquier avatar circular (el mismo patrón que Slack/Discord/Teams). No
   hizo falta envolver el marcado de ningún módulo: los ~20 sitios que pintan un
   halo con `LK.avatar.html()`/`.pintar()` no cambiaron ni una línea, porque el
   contenedor que YA les pasan de vuelta es el mismo que dejó de recortar. El
   anillo de `box-shadow` con el color de fondo de la tarjeta sigue siendo lo
   que lo separa visualmente de la foto de debajo, en vez de un borde sólido
   (regla de la casa: nunca anillos ni borders en los halos). */
/* TAMAÑO Y SITIO, medidos pixel a pixel sobre la captura de Cristián
   (spec-AVATAR-CARD-CONSTRUIR, 21-ago-2026): 7×7 CSS (14 físicos en Retina),
   no los 9px que tenía. El centro del punto se apoya SOBRE la circunferencia
   del halo a 45º — la mitad sobresale, como en cualquier sistema — y por eso
   el offset NO es un número único: depende del radio R de cada halo.
   Fórmula: right = bottom = R − R·cos45° − 3,5 (3,5 = radio del punto).

   ── LA MISMA FÓRMULA, PERO SIN CENSO · 24-ago-2026 ────────────────────────
   Aquí había tres reglas, una por halo, y decía: «no hay un valor por omisión
   porque `.lph-dot` sólo vive dentro de los tres halos censados». Esa premisa
   dejó de ser verdad el mismo día en que `core/lk-avatar.js` empezó a pedir la
   presencia por su cuenta: el punto pasó a vivir en CUALQUIER halo que adopte
   una cara. Y en un halo sin regla, `right`/`bottom` se quedan en `auto`, así
   que el punto no va a la esquina: se queda en su posición estática y el grid
   del halo lo manda AL CENTRO, encima de la cara. Lo reportó Cristián en la
   pantalla de acceso y en Reservas, y estaba igual de mal en `.fp-av` y `.av`.

   El arreglo no cambia la geometría, sólo deja de depender de un censo. La
   fórmula del autor se expresa en PORCENTAJE del propio halo, y así vale para
   cualquier medida, presente o futura:

     R − R·cos45° − 3,5   con R = 50% del ancho
     = 50%·(1 − cos45°) − 3,5
     = 14,6447% − 3,5px

   Reproduce EXACTAMENTE los tres valores que estaban escritos a mano, que es
   la prueba de que es la misma decisión y no un rediseño:
     halo 32 px → 4,686 − 3,5 = 1,19 px   (decía 1.19)
     halo 34 px → 4,979 − 3,5 = 1,48 px   (decía 1.48)
     halo 40 px → 5,858 − 3,5 = 2,36 px   (decía 2.4)

   Los halos son circulares, o sea cuadrados, así que el % del ancho y el % del
   alto son el mismo número: `right` y `bottom` no se desalinean. */
.lph-dot {
  position: absolute;
  z-index: 3;
  right: calc(14.6447% - 3.5px);
  bottom: calc(14.6447% - 3.5px);
  width: 7px;
  height: 7px;
  border-radius: 50%;
  box-shadow: 0 0 0 2px var(--lk-bg-card);
  pointer-events: none;
}
/* La presencia es un estado, no una alerta: permanece opaca y estable. */
.lph-dot.is-on  { background: var(--lk-green); }
.lph-dot.is-off { background: var(--lk-red); }
.lph-dot.is-no  { background: var(--lk-red); }

/* Cursor pointer cuando el wrapper es clickeable */
.lph-wrap[data-clickable="true"] {
  cursor: pointer;
  transition: transform .15s ease;
}
.lph-wrap[data-clickable="true"]:hover .lph-img {
  transform: scale(1.05);
}
.lph-wrap[data-clickable="true"]:hover {
  transform: translateY(-1px);
}

/* Focus ring para navegación por teclado */
.lph-wrap[tabindex]:focus-visible {
  outline: 2px solid var(--c-accent, var(--lk-brand));
  outline-offset: 3px;
}

/* Reduced motion — respeta preferencia del usuario */
@media (prefers-reduced-motion: reduce) {
  .lph-halo,
  .lph-dot,
  .lph-img {
    animation: none !important;
    transition: none !important;
  }
}


/* ──────────────────────────────────────────────────────────────────────────
   S24D-2026-05-13 · Avatar reusable + halo radial-gradient (.lk-av-*)
   Promovido desde Reservas/SmartView. Usado por:
     - tabla Reservas (md = 28px)
     - LK.avPicker (lg = 32px por default)
     - SmartView bar (sm = 24px, via alias .sv-bar-av-halo)
   Regla absoluta: halo SOLO via radial-gradient en ::before. NUNCA border.
   ────────────────────────────────────────────────────────────────────────── */

.lk-av-wrap {
  position: relative;
  flex-shrink: 0;
  display: inline-block;
}

.lk-av {
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 500;
  overflow: hidden;
  position: relative;
  z-index: 2;
  line-height: 1;
  user-select: none;
}

.lk-av-img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 50%;
  display: block;
}

.lk-av-ini {
  line-height: 1;
  pointer-events: none;
  user-select: none;
}

/* ── Tamaños ──────────────────────────────────────────────────────────── */
.lk-av-sm,
.lk-av-wrap.lk-av-sm { width: 24px; height: 24px; }
.lk-av-sm .lk-av,
.lk-av-sm-inner       { width: 24px; height: 24px; font-size: calc(var(--font-base) * 0.692); }

.lk-av-md,
.lk-av-wrap.lk-av-md { width: 28px; height: 28px; }
.lk-av-md .lk-av,
.lk-av-md-inner       { width: 28px; height: 28px; font-size: calc(var(--font-base) * 0.769); }

.lk-av-lg,
.lk-av-wrap.lk-av-lg { width: 32px; height: 32px; }
.lk-av-lg .lk-av,
.lk-av-lg-inner       { width: 32px; height: 32px; font-size: calc(var(--font-base) * 0.846); }

/* ── Halo radial-gradient (NUNCA border solido) ──────────────────────── */
.lk-av-halo::before {
  content: '';
  position: absolute;
  border-radius: 50%;
  background: radial-gradient(circle, color-mix(in srgb, var(--lk-brand) 45%, transparent) 0%, color-mix(in srgb, var(--lk-brand) 0%, transparent) 65%);
  z-index: 1;
  pointer-events: none;
  transition: background .18s ease;
}

.lk-av-sm.lk-av-halo::before,
.lk-av-wrap.lk-av-sm.lk-av-halo::before { inset: -5px; }
.lk-av-md.lk-av-halo::before,
.lk-av-wrap.lk-av-md.lk-av-halo::before { inset: -6px; }
.lk-av-lg.lk-av-halo::before,
.lk-av-wrap.lk-av-lg.lk-av-halo::before { inset: -7px; }

/* Glow al hover (mas intenso) — opt-in con .lk-av-halo-glow en parent hoverable */
.lk-av-halo-glow:hover .lk-av-halo::before {
  background: radial-gradient(circle, color-mix(in srgb, var(--lk-brand) 65%, transparent) 0%, color-mix(in srgb, var(--lk-brand) 0%, transparent) 70%);
}

@media (prefers-reduced-motion: reduce) {
  .lk-av-halo::before { transition: none !important; }
}
/* /S24D-2026-05-13 */

/* ─────────────────────────────────────────────────────────────────────────────
   lk-avatar-card.css · la tarjeta al pasar el cursor sobre un avatar
   (encargo de Cristián, 16-ago-2026 · «que sea un recurso de todo el sistema»)

   La lógica y el marcado viven en core/lk-avatar-card.js (delegación única en
   `document`, carga perezosa). Esta hoja sólo dibuja el nodo que ese módulo
   mueve de avatar en avatar — mismo patrón que el tooltip canónico de arriba.

   z-index 9500: medido contra lo que ya declara este mismo árbol, no un número
   al azar — igual que el menú contextual (`.lkctx`, 9500 · lk-ctx.css) y por
   debajo del tooltip canónico (9600 · lk-tooltip.css, arriba en este fichero),
   que sigue ganando si algún día llegaran a coincidir sobre el mismo punto.

   Sólo tokens `--lk-*` que YA existen en lk-tokens.css (ese fichero no se
   toca): la misma familia visual que ya usan `.lph-dot` y el tooltip, así que
   esta tarjeta no inventa un vestido nuevo para el sistema. Clases con prefijo
   propio `lk-avcard-` para no chocar con nada existente. */
.lk-avcard {
  position: fixed;
  z-index: 9500;
  width: 264px;
  max-width: calc(100vw - 20px);
  padding: 11px 13px;
  box-sizing: border-box;
  background: var(--lk-bg-card);
  border: .5px solid var(--lk-border);
  border-radius: 13px;
  box-shadow: var(--lk-shadow-md);
  font-family: var(--lk-font-sans);
  /* No interactiva a propósito: es información de sólo lectura, no un panel
     con botones. `pointer-events:none` evita que el cursor «pise» la tarjeta
     al cruzar hacia otro elemento y dispare un mouseout falso sobre el avatar
     de abajo. */
  pointer-events: none;
  opacity: 0;
  transform: translateY(-4px);
  transition: opacity .12s ease, transform .12s ease;
}
.lk-avcard.lk-avcard-on { opacity: 1; transform: none; }
.lk-avcard.lk-avcard-abajo { transform: translateY(4px); }
.lk-avcard.lk-avcard-abajo.lk-avcard-on { transform: none; }

.lk-avcard-top { display: flex; align-items: center; gap: 10px; }

/* El wrapper propio de la foto: el mismo trato que `.avatar-btn` /
   `.lk-account-avatar` de más arriba en este fichero — `.avatar-photo` de
   adentro es `position:absolute;inset:0`, así que el ancestro posicionado
   tiene que ser ESTE, o la foto salta a ocupar la tarjeta entera. */
.lk-avcard-photo {
  /* SIN `overflow:hidden` (spec-CORE-DOT-PRESENCIA, 21-ago-2026): mismo trato
     que `.avatar-btn`/`.lk-account-avatar` más arriba en este fichero — es otro
     ancla de `.lph-dot` y por eso entra en el mismo censo. */
  position: relative; flex: 0 0 auto;
  width: 40px; height: 40px;
  border-radius: 50%;
  display: grid; place-items: center;
  background: var(--lk-bg-surface);
}
.lk-avcard-photo .avatar-letters {
  font-size: var(--lk-font-sm); font-weight: 600; color: var(--lk-text-secondary);
}

.lk-avcard-id { min-width: 0; }
/* ESCALA TIPOGRÁFICA A LA CHICA (spec-AVATAR-CARD-CONSTRUIR, 21-ago-2026):
   antes eran px clavados —17/15/14— que además no obedecían al mover la
   letra del sistema al 90/100/115/130%. Los tokens `--lk-font-xs/sm/md` ya
   viven en lk-tokens.css con la base en 13 y SÍ escalan con `--font-base`. */
.lk-avcard-name {
  font-size: var(--lk-font-md); font-weight: 700; color: var(--lk-text-primary);
  line-height: 1.25; overflow-wrap: anywhere;
}
.lk-avcard-role {
  font-size: var(--lk-font-xs); color: var(--lk-text-faint);
  line-height: 1.3; margin-top: 1px; overflow-wrap: anywhere;
}

.lk-avcard-sep { height: .5px; margin: 10px 0; background: var(--lk-border-soft); }

.lk-avcard-row {
  display: flex; align-items: center; justify-content: space-between;
  gap: 10px; font-size: var(--lk-font-xs); line-height: 1.4;
}
.lk-avcard-row + .lk-avcard-row { margin-top: 6px; }
.lk-avcard-label { color: var(--lk-text-faint); flex: none; }
.lk-avcard-value {
  display: inline-flex; align-items: center; gap: 6px;
  color: var(--lk-text-primary); text-align: right;
}
.lk-avcard-mono { font-family: var(--lk-font-mono); font-size: calc(var(--lk-font-xs) * .92); }

/* El punto de «Conexión»: MISMOS colores que `.lph-dot` (arriba, en la zona
   de AVATAR) para que sea la misma idea visual en toda la casa, pero SIN su
   `position:absolute` — ahí el dot vive anclado a la esquina de una foto; acá
   es un punto en línea dentro de una fila de texto, un contexto distinto.
   7px, no 8: mismo tamaño que `.lph-dot` desde el 21-ago, un solo punto en
   todo el sistema. */
.lk-avcard-dot { width: 7px; height: 7px; border-radius: 50%; flex: none; }
.lk-avcard-dot--on  { background: var(--lk-green); }
.lk-avcard-dot--off { background: var(--lk-red); }
.lk-avcard-dot--no  { background: var(--lk-red); }

.lk-avcard-relativo {
  margin-top: 2px;
  text-align: right;
  font-size: calc(var(--lk-font-xs) * .92);
  color: var(--lk-text-faint);
}

@media (prefers-reduced-motion: reduce) {
  .lk-avcard, .lk-avcard-dot--on { transition: none !important; animation: none !important; }
}

/* ══ Complementos del shell derivado (E4/F2) · spotlight (de luzokit) + chasis ══ */
/* El margen superior alinea el CENTRO del orbe con el centro de la cabecera de
   UL1 (74px de alto -> centro en 37; el orbe mide 18 -> 37-9 = 28). Antes eran
   11px y el orbe quedaba 4px mas arriba que la marca. 12-ago-2026. */
.ul0-logo { width:18px;height:18px;position:relative;margin:23px 0 15px;display:grid;place-items:center;
  overflow:visible;background:none;cursor:pointer; }
/* Orbe con órbitas: esfera + halo + respiración + chispas que orbitan */
.ul0-orb-halo { position:absolute; inset:-36%; border-radius:50%; pointer-events:none;
  background:radial-gradient(circle, color-mix(in srgb, var(--lk-brand) 50%, transparent), color-mix(in srgb, var(--lk-brand) 0%, transparent) 64%); filter:blur(7px); animation:ul0halo 5s ease-in-out infinite; }
.ul0-orb { position:absolute; inset:0; border-radius:50%; overflow:hidden; animation:ul0breathe 5.5s ease-in-out infinite;
  background:radial-gradient(circle at 36% 30%, #f3efff 0%, color-mix(in srgb, var(--lk-brand) 42%, white) 16%, var(--lk-brand) 46%, var(--lk-brand) 70%, color-mix(in srgb, var(--lk-brand) 78%, black) 100%);
  box-shadow: inset 0 1px 1px rgba(255,255,255,.6), inset 0 -3px 7px rgba(43,15,92,.6), 0 3px 12px -3px color-mix(in srgb, var(--lk-brand) 60%, transparent); }
.ul0-orb::after { content:""; position:absolute; top:14%; left:24%; width:32%; height:24%; border-radius:50%;
  background:radial-gradient(circle, rgba(255,255,255,.9), rgba(255,255,255,0) 70%); filter:blur(.6px); }
.ul0-orb-orbit { position:absolute; inset:-26%; border-radius:50%; pointer-events:none; animation:ul0spin 13s linear infinite; }
.ul0-spark { position:absolute; border-radius:50%; background:color-mix(in srgb, var(--lk-brand) 18%, white); box-shadow:0 0 3px 1px color-mix(in srgb, var(--lk-brand) 90%, transparent); }
.ul0-spark:nth-child(1) { top:0; left:50%; width:2px; height:2px; margin-left:-1px; }
.ul0-spark:nth-child(2) { top:72%; left:8%; width:1.5px; height:1.5px; opacity:.8; }
.ul0-spark:nth-child(3) { top:66%; left:90%; width:1.5px; height:1.5px; opacity:.62; }
@keyframes ul0breathe { 0%,100%{ transform:scale(1); filter:brightness(1);} 50%{ transform:scale(1.04); filter:brightness(1.1);} }
@keyframes ul0halo    { 0%,100%{ opacity:.38; transform:scale(1);} 50%{ opacity:.68; transform:scale(1.14);} }
@keyframes ul0spin    { to{ transform:rotate(360deg); } }
@media (prefers-reduced-motion: reduce){ .ul0-orb,.ul0-orb-halo,.ul0-orb-orbit{ animation:none !important; } }
.ul1-head { padding:14px 16px 6px;font-size:calc(var(--font-base) * 0.846);text-transform:uppercase;letter-spacing:.07em;color:var(--tx-dim);font-weight:500; }
.ul1-badge { margin-left:auto;font-size:calc(var(--font-base) * 0.692);font-weight:500;padding:2px 6px;border-radius:20px;background:var(--bg-hover);color:var(--tx-muted); }
.ul1-item.is-soon { opacity:.6; }
.tx-footer a, .footer-powered a { color:var(--tx-muted);text-decoration:none; }
.footer-powered a { color:var(--c-accent); }
.footer-powered { font-size:calc(var(--font-base) * 0.769); }
.footer-sep { color:var(--border-soft); margin:0 4px; }
.mod-empty { padding:24px;color:var(--tx-muted);font-size:calc(var(--font-base) * 1.0); }
.spotlight { position:relative;width:100%;max-width:520px;margin:0 auto; }
.spotlight-bar { display:flex;align-items:center;gap:9px;background:var(--lk-bg-card);border:.5px solid var(--border);border-radius:11px;padding:0 13px;height:34px;box-shadow:inset 0 .5px 0 rgba(255,255,255,.06),0 1px 3px rgba(0,0,0,.22);transition:border-color .18s var(--lk-ease-out,ease),box-shadow .18s var(--lk-ease-out,ease),background .18s var(--lk-ease-out,ease); }
.spotlight-bar:hover { border-color:color-mix(in srgb, var(--lk-brand) 30%, var(--border)); }
.spotlight-bar:focus-within { border-color:var(--lk-brand-border);box-shadow:0 0 0 3px color-mix(in srgb, var(--lk-brand) 18%, transparent),inset 0 .5px 0 rgba(255,255,255,.07); background:var(--lk-bg-card); }
.spotlight-ico { display:flex;color:var(--tx-muted);flex-shrink:0; }
.spotlight-ico svg { width:14px;height:14px; }
.spotlight-input { flex:1;border:none;background:transparent;font-size:calc(var(--font-base) * 0.962);color:var(--tx-base);outline:none;font-family:inherit; }
.spotlight-input::placeholder { color:var(--tx-muted); }
.spotlight-kbd { font-size:calc(var(--font-base) * 0.769);color:var(--tx-muted);background:var(--bg-hover);border:.5px solid var(--border-soft);border-radius:6px;padding:2px 7px;flex-shrink:0;font-family:var(--lk-font-mono,monospace); }

/* ══ Desk curado (E4/F4b) · overlays CENTRADOS (RA-06) + taskbar + dimmer ══ */
/* Contrato único de velo modal. Los módulos conservan su layout interior y
   estado de apertura, pero ninguno decide ya alcance, profundidad o material. */
:is(
  .lk-modal-ov, .cs-ov, .cc-velo,
  .p3-ed-overlay, .p3-pk-overlay, .p3-ev-overlay,
  .modal-ov, .cl-overlay, .cl-verif-ov, .rmd-ov,
  .cfg-us-ov, .cfg-ov, .sadm-ov, .sala-ov, .lk-dg-back,
  .lk-cita-frame .lkcf-backdrop
) {
  position: fixed !important;
  inset: 0 !important;
  z-index: var(--lk-z-modal, 850) !important;
  background: var(--lk-overlay, rgba(0,0,0,.52)) !important;
  -webkit-backdrop-filter: var(--lk-blur-sm, blur(3px)) !important;
  backdrop-filter: var(--lk-blur-sm, blur(3px)) !important;
}
#ldDimmer { position: fixed; inset: 0; background: var(--lk-overlay, rgba(0,0,0,.52)); opacity: 0; pointer-events: none; transition: opacity .25s ease; z-index: var(--lk-z-overlay, 800); -webkit-backdrop-filter: var(--lk-blur-sm, blur(3px)); backdrop-filter: var(--lk-blur-sm, blur(3px)); }
#ldDimmer.on { opacity: 1; pointer-events: auto; }
.ld-overlay { position: fixed; inset: 0; display: grid; place-items: center; padding: 20px; z-index: var(--lk-z-modal, 850); pointer-events: none; }
.ld-overlay.open { pointer-events: auto; }
.ld-ov-panel { width: min(92vw, 560px); max-height: min(86dvh, 860px); overflow: hidden; display: flex; flex-direction: column; min-height: 0; background: var(--bg-card); border: 1px solid var(--border);
  border-radius: 16px; box-shadow: var(--lk-shadow-lg); transform: translateY(8px) scale(.98); opacity: 0; transition: transform .2s var(--spring, ease), opacity .2s; }
.ld-overlay.open .ld-ov-panel { transform: none; opacity: 1; }
.ld-overlay--sm .ld-ov-panel { width: min(92vw, 420px); }
.ld-overlay--lg .ld-ov-panel { width: min(94vw, 820px); }
.ld-ov-head { display: flex; align-items: center; gap: 12px; padding: 14px 16px; border-bottom: 1px solid var(--border-soft); }
.ld-ov-title { flex: 1; font-weight: 500; color: var(--tx-base); font-size: var(--lk-font-lg); }
.ld-ov-acts { display: flex; gap: 4px; }
.ld-ov-btn { width: 30px; height: 30px; border: none; background: transparent; color: var(--tx-muted); border-radius: 8px; cursor: pointer; font-size: calc(var(--font-base) * 1.154); }
.ld-ov-btn:hover { background: var(--bg-hover); color: var(--tx-base); }
.ld-ov-body { padding: 16px; min-height: 0; overflow: auto; overscroll-behavior: contain; }
@media (max-width: 639.98px) {
  .ld-overlay { padding: 0; align-items: end; }
  .ld-ov-panel,.ld-overlay--sm .ld-ov-panel,.ld-overlay--lg .ld-ov-panel { width: 100%; max-height: 92dvh; border-radius: 18px 18px 0 0; }
  /* Desk no tiene footer propio: sólo su cuerpo recibe el espacio del gesto.
     No se aplica a otras hojas, cuyos pies ya incluyen su safe-area. */
  .ld-overlay[data-lk-surface] .ld-ov-body:last-child { padding-bottom: calc(16px + var(--lk-safe-bottom)); }
}
/* Pills del taskbar (tab minimizado) → definición ÚNICA en §14 "LEGACY TASKBAR TABS"
   (paridad MK-2). Se eliminó el duplicado #ldTaskbar/.ld-pill/.ld-pill-main/.ld-pill-close que
   colisionaba con esa sección y filtraba props (DESK-A dedup). El markup lo emite lk-shell/desk.js. */
[data-mode="vintage"] .ld-ov-panel { transform: none !important; opacity: 1; }

/* ══════════════════════════════════════════════════════════════════════════════
   Paridad chasis viejo (desktop pixel-perfect): reloj de dos líneas. Medidas
   transcritas de luzokit.css (pull 225531).
   ══════════════════════════════════════════════════════════════════════════════ */
.ul0-rail { position: relative; }                    /* ancla del wordmark absoluto */
.ul0-logo-full { position: absolute; left: 52px; top: 0; height: var(--top-h, 52px);
  display: flex; align-items: center; gap: 8px; padding-left: 14px; text-decoration: none;
  white-space: nowrap; z-index: 1; }
.logo-full-name { font-size: calc(var(--font-base) * 1.077); font-weight: 800; color: var(--tx-base); letter-spacing: -.03em; }
.logo-full-name b { font-weight: 900; }
.logo-full-suf  { font-weight: 400; opacity: .6; }
/* Aquí estaban `.logo-full-dev` (la píldora «DEV») y `.logo-full-ver` (la
   versión). Se fueron con su marcado: el «DEV» no tenía condición de entorno y
   se pintaba también en producción, y la versión era el literal fijo «v2.0.0»,
   sin ningún consumidor del gancho `js-app-version`. En su sitio va el logotipo
   del inquilino. */
.logo-full-sep { width: 1px; height: 15px; background: currentColor; opacity: .18; }
/* El color NO se declara: se hereda de `body` (`--tx-base`), y por eso el
   logotipo sale casi negro en `lightmode` y blanco en `darkmode`/`midnight` sin
   una sola regla por tema. Los rellenos del SVG son `currentColor`. */
/* MICROANIMACIONES · sutiles a propósito. La marca es lo primero que se ve al
   entrar, así que la entrada es un desvanecido con un ascenso de 6px y un punto
   de escala: se percibe como que «se asienta», no como que salta. El reposo dura
   520ms con una curva suave; más largo se siente lento, más corto se siente un
   parpadeo. El hover no mueve la marca de sitio —eso desalinearía lo que costó
   medir— sino que la aclara apenas y la levanta 1px.
   Quien no quiera movimiento no lo tiene: `prefers-reduced-motion` lo apaga. */
.logo-tenant { display: inline-flex; align-items: center; margin-top: 19px;
  animation: tl-entrada 520ms cubic-bezier(.16,.84,.44,1) both;
  transition: transform 220ms cubic-bezier(.16,.84,.44,1), filter 220ms ease; }
@keyframes tl-entrada {
  from { opacity: 0; transform: translateY(6px) scale(.985); }
  to   { opacity: 1; transform: none; }
}
.ul1-logo-mark:hover .logo-tenant { transform: translateY(-1px); filter: brightness(1.12); }
.ul1-logo-mark:active .logo-tenant { transform: translateY(0); filter: brightness(1); }
.ul1-logo-mark { cursor: pointer; text-decoration: none; -webkit-tap-highlight-color: transparent; }
.ul1-logo-mark:focus-visible { outline: 1.5px solid var(--lk-brand); outline-offset: 6px; border-radius: 8px; }
@media (prefers-reduced-motion: reduce) {
  .logo-tenant { animation: none; transition: none; }
  .ul1-logo-mark:hover .logo-tenant { transform: none; }
}
/* Los dos archivos del dueno de la marca: se muestra uno u otro segun el tema, y
   ninguno se recolorea. `lightmode` pide el de tonos claros; `darkmode` y
   `midnight` el de fondo oscuro. Por defecto se asume oscuro, que es el tema con
   el que arranca el CRM. */
.logo-tenant .tl-svg { height: 55px; width: auto; display: block; }
.logo-tenant .tl-claro { display: none; }
[data-theme="lightmode"] .logo-tenant .tl-claro { display: block; }
[data-theme="lightmode"] .logo-tenant .tl-oscuro { display: none; }
/* El signo `+`: tinte del color de texto, no color de marca. Al 70% reproduce
   exactamente el #4D4D4D del fichero original sobre blanco, y sobre los fondos
   oscuros da el mismo gris relativo en vez de desaparecer. */
.logo-tenant .tl-plus { opacity: .7; }
/* Alineacion MEDIDA contra la referencia del 13-ago 02:08, no estimada: alli el
   orbe del riel mide 22,5px y aqui 18, o sea la captura esta al 125%. Normalizado
   ese factor, la tinta del logotipo arranca a 62,8px del centro del orbe, que con
   el riel de 44px son 40 de sangria. Esta alineacion costo horas de rehacer: si
   alguien la toca, que sea con una medida, no a ojo. */
.ul1-logo-spacer { height: var(--top-h, 52px); flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  overflow: visible; }
/* reloj de dos líneas (fecha + hora con segundos) */
.top-clock { text-align: right; line-height: 1.15; }
.top-date  { font-size: calc(var(--font-base) * 0.808); color: var(--tx-muted); white-space: nowrap; margin: 0; }
.top-time  { font-size: calc(var(--font-base) * 0.923); font-weight: 500; color: var(--tx-base); letter-spacing: -.02em; margin: 0; }

/* ══════ Estado de error único (LK.dom.errorState) ══════ */
/* 12-ago-2026 · Cristian: «centraria la composicion tanto horizontal como vertical».
   Con `min-height:60vh` centraba dentro de 60vh y quedaba alta. Ahora ocupa el alto
   disponible del contenedor. */
.lz-err{min-height:100%;height:100%;display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;padding:40px 24px}
.lz-err-ico{margin-bottom:16px;animation:lzErrFloat 3.6s ease-in-out infinite}
.lz-err-code{font-size:calc(var(--font-base) * 0.885);color:var(--tx-dim,#5b6472);font-weight:500;letter-spacing:.14em;margin-bottom:9px}
/* `.lz-err-logo` la ponia el JS (lk-errorstate.js:118) y NO TENIA NI UNA REGLA — la
   tercera clase asi en esta misma pantalla. Por eso el wordmark iba pegado al titulo.
   El aire lo da este margen; el peso, el contraste entre `b` y `span`. */
.lz-err-logo{font-family:'Space Grotesk',ui-sans-serif,system-ui,sans-serif;font-size:calc(var(--font-base) * 1.0);line-height:1;letter-spacing:-.018em;color:var(--tx-muted);margin-bottom:18px}
.lz-err-logo b{font-weight:600;color:var(--tx-base)}
.lz-err-logo span{font-weight:400;margin-left:.08em}
.lz-err-title{font-size:calc(var(--font-base) * 1.308);font-weight:500;letter-spacing:-.02em;color:var(--tx-base)}
.lz-err-sub{font-size:calc(var(--font-base) * 1.0);color:var(--tx-muted);line-height:1.5;max-width:250px;margin:8px auto 0}
/* El boton RELLENO vuelve por peticion expresa de Cristian (12-ago-2026, «repondria
   el boton»). Sustituye a la version de contorno que se probo antes. */
.lz-err-btn{margin-top:22px;min-width:190px;display:inline-flex;align-items:center;justify-content:center;gap:8px;font-family:inherit;font-size:calc(var(--font-base) * 1.077);font-weight:500;color:#fff;background:var(--c-accent,var(--lk-brand));border:1px solid var(--c-accent,var(--lk-brand));border-radius:12px;padding:10px 18px;cursor:pointer;transition:.15s}
.lz-err-btn:hover{filter:brightness(1.12)}

/* `.lz-err-menor` se ponia en el JS (lk-errorstate.js:122) y NO TENIA NI UNA REGLA:
   el navegador la pintaba con su morado subrayado por omision. Es el patron de «la
   clase que nadie escribe». La accion secundaria es texto, no un enlace del sistema. */
.lz-err-menor{display:inline-block;margin-top:14px;color:var(--tx-muted);font-size:calc(var(--font-base) * 0.95);text-decoration:none;cursor:pointer;transition:color .15s}
.lz-err-menor:hover{color:var(--tx-base)}
.lz-err-menor:visited{color:var(--tx-muted)}

.lz-err-btn--ghost{color:var(--c-accent-soft,var(--lk-brand-soft));background:transparent}
.lz-err-btn--ghost:hover{background:var(--c-accent-soft,color-mix(in srgb, var(--lk-brand) 14%, transparent));filter:none}
.lz-err-btn svg{flex:none}
.lz-ph-body{fill:#141a24;stroke:var(--lk-brand);stroke-width:1.9}
.lz-ph-scr{fill:#0b0f16}
.lz-ph-isla{fill:#0b0f16}
.lz-ph-fa{stroke:var(--lk-brand-soft);stroke-width:2.4;stroke-linecap:round;stroke-linejoin:round;fill:none}
@keyframes lzErrFloat{0%,100%{transform:translateY(0) rotate(-3deg)}50%{transform:translateY(-6px) rotate(-3deg)}}
@media (prefers-reduced-motion:reduce){.lz-err-ico{animation:none}}

/* ══ PILLTAB ESTÁNDAR (design-system · base P360 .p3e-tab) ═══════════════════════
   UN solo formato de pilltab en todos los módulos con topbar. Normaliza las clases
   existentes SIN tocar markup. !important porque el CSS de módulo carga tras el core.
   No se toca ancho/posición del contenedor (cada topbar lo ubica a su manera). */
.lk-pilltab {
  display: grid !important; grid-auto-flow: column !important; grid-auto-columns: 1fr !important;
  height: 34px !important; padding: 0 !important; gap: 0 !important;
  border: .5px solid var(--lk-border) !important; border-radius: 8px !important;
  overflow: hidden !important; background: var(--lk-bg-card) !important;
  box-shadow: var(--lk-shadow-sm) !important;
}
.lk-pilltab__item {
  box-sizing: border-box !important; min-width: 0 !important; height: 33px !important;
  display: inline-flex !important; align-items: center !important; justify-content: center !important; gap: 7px !important;
  padding: 0 14px !important; border: 0 !important; border-radius: 0 !important;
  background: transparent !important; color: var(--lk-text-muted) !important;
  font: 500 var(--font-base, 13px)/1 var(--lk-font-sans, system-ui, sans-serif) !important;
  letter-spacing: 0 !important; white-space: nowrap !important; box-shadow: none !important; cursor: pointer;
  transition: background .15s var(--lk-ease, ease), color .15s var(--lk-ease, ease) !important;
}
.lk-pilltab__item + .lk-pilltab__item { border-left: .5px solid var(--lk-border) !important; }
.lk-pilltab__item:is(.is-active,.active,.sadm-on) {
  background: color-mix(in srgb, var(--c-accent, var(--lk-brand)) 15%, var(--lk-bg-card)) !important;
  color: var(--c-accent, var(--lk-brand)) !important; font-weight: 600 !important;
}
.lk-pilltab__item:hover:not(.is-active):not(.active):not(.sadm-on) {
  background: var(--lk-bg-hover) !important; color: var(--lk-text-primary) !important;
}
.lk-pilltab__item svg { width: 14px !important; height: 14px !important; flex: none !important; stroke-width: 1.8 !important; }

/* Botón compuesto canónico: icono + texto + divisor + chevron. */
.lk-compound { position: relative; display: inline-flex; align-items: center; flex: none; }
.lk-compound__button {
  box-sizing: border-box !important; height: 36px !important;
  display: inline-flex !important; align-items: center !important; gap: 8px !important;
  padding: 0 8px 0 14px !important; border: .5px solid var(--lk-border) !important;
  border-radius: 10px !important; background: var(--lk-bg-card) !important;
  color: var(--lk-text-secondary) !important; box-shadow: var(--lk-shadow-sm) !important;
  font: 500 var(--font-base, 13px)/1 var(--lk-font-sans, system-ui, sans-serif) !important;
  letter-spacing: 0 !important; white-space: nowrap !important; cursor: pointer;
  transition: background .15s, border-color .15s, color .15s, transform .12s !important;
}
.lk-compound__button:hover,.lk-compound.is-open .lk-compound__button {
  background: var(--lk-bg-hover) !important; border-color: var(--lk-brand-border) !important;
  color: var(--lk-text-primary) !important;
}
.lk-compound__button:active { transform: scale(.97) !important; }
.lk-compound__button > svg { width: 15px !important; height: 15px !important; flex: none !important; stroke-width: 1.8 !important; }
.lk-compound__divider { width: .5px !important; height: 18px !important; margin: 0 1px 0 3px !important; background: var(--lk-border) !important; flex: none !important; }
.lk-compound__chevron { display: inline-flex !important; align-items: center !important; color: var(--lk-text-faint) !important; transition: transform .25s !important; }
.lk-compound__chevron svg { width: 14px !important; height: 14px !important; stroke-width: 2 !important; }
.lk-compound.is-open .lk-compound__chevron { transform: rotate(180deg) !important; }
@media (max-width: 639.98px) {
  .lk-pilltab { grid-auto-columns: max-content !important; max-width: 100% !important; overflow-x: auto !important; }
  .lk-pilltab__item { padding: 0 11px !important; }
  .lk-pilltab__item > span { display: inline !important; }
  .lk-compound__button { width: 36px !important; padding: 0 !important; justify-content: center !important; }
  .lk-compound__button > span:not(.lk-compound__chevron) { display: none !important; }
  .lk-compound__divider { display: none !important; }
}

.p3e-tabs, .sadm-tabpill, .cc-canal-tabs, .ev-tabs {
  border: .5px solid var(--lk-border) !important; border-radius: 8px !important;
  overflow: hidden !important; background: var(--lk-bg-card) !important;
  padding: 0 !important; gap: 0 !important; box-shadow: var(--lk-shadow-sm, 0 1px 3px rgba(0,0,0,.3)) !important;
}
.p3e-tab, .sadm-tabpill button, .cc-canal-tab, .ev-tab {
  border: 0 !important; border-radius: 0 !important; background: transparent !important;
  color: var(--lk-text-muted) !important; font-weight: 500 !important;
  height: 34px !important; padding: 0 14px !important; box-shadow: none !important;
}
.p3e-tab + .p3e-tab, .sadm-tabpill button + button, .cc-canal-tab + .cc-canal-tab, .ev-tab + .ev-tab {
  border-left: .5px solid var(--lk-border) !important;
}
.p3e-tab.is-active, .sadm-tabpill button.sadm-on, .cc-canal-tab.active, .ev-tab.active {
  background: color-mix(in srgb, var(--c-accent, var(--lk-brand)) 15%, var(--lk-bg-card)) !important;
  color: var(--c-accent, var(--lk-brand)) !important; font-weight: 600 !important;
}
.p3e-tab:hover:not(.is-active), .sadm-tabpill button:hover:not(.sadm-on),
.cc-canal-tab:hover:not(.active), .ev-tab:hover:not(.active) {
  color: var(--lk-text-primary) !important; background: transparent !important;
}

/* ══ TOPBAR DE MÓDULO ESTÁNDAR (alto 56 · fondo card · borde .5px · padding 22 · tokens) ══
   Un solo formato de topbar en todos los módulos. Normaliza sin tocar markup (!important). */
.p3e-modbar, .lz-az-top, .rv2-topbar, .cc-topbar, .agw .topbar, .sadm-sa-top {
  height: 56px !important; min-height: 56px !important; box-sizing: border-box !important;
  padding-top: 0 !important; padding-bottom: 0 !important;
  padding-left: 22px !important; padding-right: 22px !important;
  background: var(--lk-bg-card) !important;
  border-bottom: .5px solid var(--lk-border) !important;
  align-items: center !important;
}
/* pilltab absoluto (P360/Salas): centrado vertical dentro de la topbar de 56 */
.p3e-tabs, .sadm-tabpill { top: 50% !important; transform: translate(-50%, -50%) !important; }

/* ══ RAIL DE MÓDULO → adopta la NORMA DEL SISTEMA (UL1 .ul1-item) ══ */
.lz-az-ni, .cc-rail-item { padding: 8px !important; border-radius: 8px !important; gap: 8px !important; font-size: 13px !important; color: var(--tx-muted) !important; }
.lz-az-ni:hover:not(.on), .cc-rail-item:hover:not(.on) { background: var(--bg-hover) !important; color: var(--tx-base) !important; }
.lz-az-ni.on, .cc-rail-item.on { background: var(--bg-active) !important; color: var(--c-accent-soft) !important; font-weight: 500 !important; }
/* chevron UL0: efecto de rotación acorde al colapso de UL1 */
#ul0ExpandBtn svg { transition: transform .28s cubic-bezier(.4,0,.2,1); }
html.ul-collapsed #ul0ExpandBtn svg { transform: rotate(180deg); }

/* consistencia de UI: pilltab y rail al MISMO font + tamaño */
.p3e-tab, .sadm-tabpill button, .cc-canal-tab, .ev-tab, .lz-az-ni, .cc-rail-item {
  font-family: var(--lk-font-sans, system-ui, sans-serif) !important;
  font-size: 13px !important;
}

/* ══ PILLTAB · Com Center toggle-group (Operación/Plantillas/Sistema) ══════════
   Era el pilltab REAL de la topbar de Com Center (no .cc-canal-tabs). Se suma a la
   norma para que use el mismo formato P360 que el resto. */
.cc-toggle-group {
  border: .5px solid var(--lk-border) !important; border-radius: 8px !important;
  overflow: hidden !important; background: var(--lk-bg-card) !important;
  padding: 0 !important; gap: 0 !important; box-shadow: var(--lk-shadow-sm, 0 1px 3px rgba(0,0,0,.3)) !important;
}
.cc-toggle-btn {
  border: 0 !important; border-radius: 0 !important; background: transparent !important;
  color: var(--lk-text-muted) !important; font-weight: 500 !important;
  height: 34px !important; padding: 0 14px !important; box-shadow: none !important;
  font-family: var(--lk-font-sans, system-ui, sans-serif) !important; font-size: 13px !important;
}
.cc-toggle-btn + .cc-toggle-btn { border-left: .5px solid var(--lk-border) !important; }
.cc-toggle-btn.active {
  background: color-mix(in srgb, var(--lk-brand) 15%, var(--lk-bg-card)) !important;
  color: var(--lk-brand) !important; font-weight: 600 !important; box-shadow: none !important;
}
.cc-toggle-btn:hover:not(.active) { color: var(--lk-text-primary) !important; background: transparent !important; }

/* ══ IDENTIDAD DE MÓDULO ESTÁNDAR · ícono desnudo en ACENTO + nombre como título ══
   "el mismo tipo de ícono del módulo con el color de énfasis, el nombre como título,
   y nada más". Ícono sin chip de fondo; versión oculta. Sin tocar markup. */
.cc-mod-icon, .agw .tb-brand .mi, .rv2-mod-icon, .sadm-sa-top-ic {
  background: transparent !important; border: 0 !important; border-radius: 0 !important;
  width: auto !important; height: auto !important; color: var(--lk-brand) !important;
  display: inline-flex !important; align-items: center !important; padding: 0 !important;
}
.cc-mod-icon svg, .agw .tb-brand .mi svg, .rv2-mod-icon svg, .sadm-sa-top-ic svg {
  width: 19px !important; height: 19px !important;
}
.cc-mod-name, .agw .tb-brand h1, .rv2-mod-name, .sadm-sa-top-t {
  font-family: var(--lk-font-sans, system-ui, sans-serif) !important;
  font-size: 15px !important; font-weight: 600 !important;
  color: var(--lk-text-primary) !important; letter-spacing: -.01em !important;
}
/* "y nada más": las píldoras de versión fuera del título */
.rv2-mod-ver, .sadm-sa-top-t .sadm-v { display: none !important; }

/* ══ BOTONES DE TOPBAR → formato P360 (.p3e-sv: borde .5px · radio 10 · sombra · hover acento) ══
   Mismo diseño/feel en toda topbar. Se conserva el alto propio de cada control para no
   romper clústeres (nav de fechas, buscador); se unifica borde/radio/fondo/color/hover. */
.agw .icb, .agw .hoy, .agw .btn-txt, .agw .tb-search-btn,
.cc-topbar .btn, .cc-topbar .btn-icon {
  border: .5px solid var(--lk-border) !important; border-radius: 10px !important;
  background: var(--lk-bg-card) !important; color: var(--lk-text-muted) !important;
  box-shadow: var(--lk-shadow-sm, 0 1px 3px rgba(0,0,0,.25)) !important;
  transition: background .18s, color .18s, border-color .18s, transform .1s !important;
}
.agw .icb:hover, .agw .hoy:hover, .agw .btn-txt:hover, .agw .tb-search-btn:hover,
.cc-topbar .btn:hover, .cc-topbar .btn-icon:hover {
  background: var(--lk-brand-muted) !important; color: var(--lk-brand) !important;
  border-color: transparent !important;
}
.agw .icb:active, .agw .hoy:active, .agw .btn-txt:active,
.cc-topbar .btn:active, .cc-topbar .btn-icon:active { transform: scale(.96) !important; }

/* ══ PILLTAB · tabs de IGUAL ANCHO ════════════════════════════════════════════
   Un segmentado se lee como control cuando sus celdas son iguales. Grid de columnas
   1fr = todas al mismo ancho (la más larga manda), texto centrado en cada celda. */
.p3e-tabs, .sadm-tabpill, .cc-canal-tabs, .ev-tabs, .cc-toggle-group {
  display: grid !important; grid-auto-flow: column !important; grid-auto-columns: 1fr !important;
}
.p3e-tab, .sadm-tabpill button, .cc-canal-tab, .ev-tab, .cc-toggle-btn {
  justify-content: center !important; text-align: center !important;
}

/* ══ .ld-pill (tabs minimizados) · leve énfasis de ACENTO en el activo ═════════
   El pill activo lleva un canto superior de acento (2px) + un tinte tenue de acento
   sobre la tarjeta. Sigue --lk-brand (nunca hardcode); mantiene opaco el contenido. */
.ld-pill.is-active {
  background: color-mix(in srgb, var(--lk-brand) 8%, var(--bg-card)) !important;
}
.ld-pill.is-active::before {
  box-shadow: inset 0 2px 0 0 var(--lk-brand), inset 0 0 0 .5px var(--lk-pill-bd-active) !important;
}

/* ══ FONDO DE MÓDULO CENTRALIZADO ═════════════════════════════════════════════
   El sistema tiene UN fondo: la luz de ambiente del shell (body/.tx-content). Los
   módulos-página NO deben repintar el cuerpo con --lk-bg-body plano (rompía la
   continuidad: Com Center/cfg salían negro-plano mientras Agenda/Sala/Autoriz dejan
   ver el ambiente). Se transparentan; las tarjetas conservan --lk-bg-card.
   (cita-frame NO entra: su lienzo opaco es intencional, es overlay flotante.) */
.cc-wrap, .cc-content, .cfg, .cfg-pane { background: transparent !important; }

/* ══ FONDO CENTRALIZADO · DEFINITIVO (todas las raíces de módulo) ══════════════
   Corrobora: casi todos los módulos repintaban el cuerpo (agenda/reservas/p360 con
   rgb(11,11,13); autorizaciones con rgb(30,30,30) = color de tarjeta → se veía distinto).
   El hijo directo del outlet ES la raíz del módulo (las tarjetas van más profundas).
   Transparentarlo centraliza el fondo en el ambiente del sistema (body) de una vez,
   presente y futuro, sin listar cada módulo. Más los rellenos-página internos. */
#moduleContent > * { background: transparent !important; }
.cc-content, .cfg-pane, .lz-az-shell, .lz-az-main { background: transparent !important; }

/* ══ RIELES DE MÓDULO → IDÉNTICOS A UL1 (autorizaciones + Com Center) ══════════
   Adoptan la norma del sistema: mismos panel/etiqueta-grupo/item/hover/activo/ícono/
   badge que .ul1-* del shell (lk-layout). !important porque el CSS de estos módulos
   se inyecta después del core. */
/* panel → .ul1-panel */
.lz-az-nav, .cc-rail {
  background: var(--bg-card) !important; border-right: 1px solid var(--border-soft) !important;
  padding: var(--space-2) !important; gap: 2px !important;
}
/* etiqueta de grupo → .ul1-head */
.lz-az-nav-pt, .cc-rail-eyebrow {
  padding: 14px 16px 6px !important; font-size: calc(var(--font-base) * 0.846) !important;
  text-transform: uppercase !important; letter-spacing: .07em !important;
  font-weight: 600 !important; color: var(--tx-muted) !important; display: block !important;
}
/* item → .ul1-item */
.lz-az-ni, .cc-rail-item {
  display: flex !important; align-items: center !important; gap: var(--space-2) !important;
  padding: 8px var(--space-2) !important; border-radius: var(--radius-md) !important;
  background: transparent !important; color: var(--tx-muted) !important;
  font-size: var(--font-md) !important; font-weight: 400 !important;
}
.lz-az-ni:hover:not(.on), .cc-rail-item:hover:not(.on) { background: var(--bg-hover) !important; color: var(--tx-base) !important; }
.lz-az-ni.on, .cc-rail-item.on { background: var(--bg-active) !important; color: var(--c-accent-soft) !important; font-weight: 500 !important; }
/* ícono → .ul1-icon (22 caja · 18 svg · opacity .75) */
.cc-rail-ic { width: 22px !important; height: 22px !important; opacity: .75 !important; }
.cc-rail-ic svg, .lz-az-ni > svg { width: 18px !important; height: 18px !important; stroke-width: 1.7 !important; opacity: .75 !important; }
/* label → .ul1-label */
.cc-rail-l, .lz-az-ni > span:not(.lz-az-ni-b) { flex: 1 !important; white-space: nowrap !important; overflow: hidden !important; text-overflow: ellipsis !important; }
/* badge de conteo → .ul1-badge */
.cc-rail-c, .lz-az-ni-b {
  margin-left: auto !important; font-family: inherit !important;
  font-size: calc(var(--font-base) * 0.692) !important; font-weight: 500 !important;
  padding: 2px 6px !important; border-radius: 20px !important; border: none !important;
  background: var(--bg-active) !important; color: var(--c-accent-soft) !important;
}

/* riel de módulo = MISMO vidrio que el UL1 del shell (chrome translúcido = surface-fill;
   NO es contenido, por eso sí lleva vidrio). Cierra la última diferencia con UL1. */
.lz-az-nav, .cc-rail {
  background: var(--lk-surface-fill, var(--bg-card)) !important;
  -webkit-backdrop-filter: var(--lk-surface-blur, none) !important;
  backdrop-filter: var(--lk-surface-blur, none) !important;
}

/* ══ KPI CARDS · TRATAMIENTO DEL SISTEMA (layout-agnóstico) ════════════════════
   Dos variantes válidas y NO excluyentes, según contexto: tarjetas individuales
   (.op-kpi) y tira grid-4 con divisores (.lz-az-kpi / .rv-kpis+.kpi-* / eventos).
   NO se fuerza layout ni tamaño (eso lo decide el contexto). Se unifica el TRATAMIENTO
   del valor: peso 500 (Operaciones estaba en 650), tracking y tabular-nums para que
   los números calcen. Los colores semánticos ya salen de --lk (red/amber/green/brand). */
.lz-az-kpi-v, .op-kpi-val, .kpi-val {
  font-weight: 500 !important; letter-spacing: -.01em !important;
  font-variant-numeric: tabular-nums !important;
}
/* etiqueta superior del KPI: mismo muted del sistema */
.lz-az-kpi-top, .op-kpi-top, .kpi-top { color: var(--lk-text-muted) !important; }

/* pilltab del topbar de Reservas → misma norma P360 (ya es flex-equal; se asegura
   centrado + fuente + tinte de activo idénticos al resto de pilltabs) */
.rv2-toggle-btn {
  justify-content: center !important; text-align: center !important;
  font-family: var(--lk-font-sans, system-ui, sans-serif) !important;
}
.rv2-toggle-btn.active {
  background: color-mix(in srgb, var(--lk-brand) 15%, var(--lk-bg-card)) !important;
  color: var(--lk-brand) !important; font-weight: 600 !important;
}

/* ══ TOPBAR DE MÓDULO = MISMO VIDRIO DEL CHASIS (.tx-top) ══════════════════════
   Antes forcé bg-card OPACO y pisó el vidrio del material → los topbar de módulo
   quedaban rgb(30,30,30) opaco mientras el chasis es surface-fill translúcido+blur.
   Ahora usan el mismo material (chrome, no contenido). Cierra el desajuste de color. */
.p3e-modbar, .lz-az-top, .rv2-topbar, .cc-topbar, .agw .topbar, .sadm-sa-top {
  background: var(--lk-surface-fill, var(--lk-bg-card)) !important;
  -webkit-backdrop-filter: var(--lk-surface-blur, none) !important;
  backdrop-filter: var(--lk-surface-blur, none) !important;
}

/* ── LAS DOS BARRAS PEGADAS USAN EL MATERIAL PEGADO, NO EL QUIETO ────────────
   `.p3e-modbar` y `.sadm-sa-top` son `position: sticky; top: 0` sobre contenedores
   que scrollean (`p3-escritorio.css:18`, `sala-admin.css:324`). Su fondo cambia en
   CADA cuadro mientras arrastras la lista, así que el desenfoque se rehace entero
   60 veces por segundo — a diferencia de un modal, que lo calcula una vez.
   Por eso consumen `--lk-surface-blur-fijo` y no `--lk-surface-blur`: son la costura
   que separa «superficie quieta» de «superficie pegada». HOY LOS DOS VALEN LO MISMO
   —30px, elegido por Cristián el 7-ago-2026 mirando el comparador— así que esto no
   cambia nada de lo que se ve. La costura se deja puesta igual: el día que haya que
   afinar el coste, ya está identificado quién es quién.
   Las otras CUATRO de la regla de arriba no son `sticky` —comprobado, cero reglas
   `position:sticky|fixed`— así que se quedan con el material quieto.
   PRIMERA VERSIÓN DE ESTO, Y ESTABA MAL: apagué el desenfoque con `none`. Apagar el
   material no es arreglar nada; era el hachazo. Cristián lo paró, y tiene razón: el
   veneno no es el vidrio, es el token que responde a dos preguntas y obliga a copiar
   el valor a mano en seis sitios. Eso es lo que queda por arreglar. */
.p3e-modbar, .sadm-sa-top {
  -webkit-backdrop-filter: var(--lk-surface-blur-fijo, var(--lk-surface-blur, none)) !important;
  backdrop-filter: var(--lk-surface-blur-fijo, var(--lk-surface-blur, none)) !important;
}

/* ══ BOTONES DE TOPBAR · DOS TIPOS P360, ALTURA UNIFORME 36 ════════════════════
   Referencia real P360: íconos DESNUDOS (.p3e-sbtn: transparente, sin borde/sombra)
   + acciones con texto en PÍLDORA con borde (.p3e-sv). Antes hice todo con borde y
   las alturas variaban (32/34/38). Se corrige a los dos tipos, todos a 36. */
/* ICONO SOLO → desnudo (como .p3e-sbtn) */
.agw .icb, .agw .tb-search-btn, .lz-az-ibtn, .cc-topbar .btn.btn-icon {
  width: 36px !important; height: 36px !important; border: 0 !important;
  background: transparent !important; box-shadow: none !important;
  border-radius: 10px !important; color: var(--lk-text-muted) !important;
}
.agw .icb:hover, .agw .tb-search-btn:hover, .lz-az-ibtn:hover, .cc-topbar .btn.btn-icon:hover {
  background: var(--lk-brand-muted) !important; color: var(--lk-brand) !important;
}
/* CON TEXTO → píldora con borde (como .p3e-sv) */
.agw .hoy, .agw .btn-txt, .lz-az-tbtn, .cc-topbar .btn:not(.btn-icon) {
  height: 36px !important; border: .5px solid var(--lk-border) !important;
  border-radius: 10px !important; background: var(--lk-bg-card) !important;
  box-shadow: var(--lk-shadow-sm, 0 1px 3px rgba(0,0,0,.25)) !important;
  color: var(--lk-text-muted) !important;
}
.agw .hoy:hover, .agw .btn-txt:hover, .lz-az-tbtn:hover, .cc-topbar .btn:not(.btn-icon):hover {
  background: var(--lk-brand-muted) !important; color: var(--lk-brand) !important; border-color: transparent !important;
}

/* Agenda: una sola métrica tipográfica para todos los controles de la topbar.
   Usa --font-base (no px fijo) para conservar el escalado de accesibilidad. */
.agw .topbar :is(button, .pill) {
  font-family: var(--lk-font-sans, system-ui, sans-serif) !important;
  font-size: var(--font-base, 13px) !important;
  font-weight: 500 !important;
  line-height: 1 !important;
  letter-spacing: 0 !important;
}
.agw .topbar .tb-search input {
  font-family: var(--lk-font-sans, system-ui, sans-serif) !important;
  font-size: var(--font-base, 13px) !important;
  font-weight: 400 !important;
  letter-spacing: 0 !important;
}

/* ══ MENÚS CONTEXTUALES · vidrio legible (unificación al look de Agenda) ═══════
   El usuario quiere los menús contextuales translúcidos PERO legibles (opacidad alta).
   Se aplica a los menús propios con clase dedicada; el core .lkctx ya lo trae en
   lk-ctx.css. (Autoriz usa un dropdown COMPARTIDO .lz-az-dd → se migrará a LK.ctx,
   no se restilea acá para no tocar sus desplegables de valor.) */
.rv-menu, .cc-menu {
  background: color-mix(in srgb, var(--lk-bg-card-solid, var(--lk-bg-card)) 85%, transparent) !important;
  -webkit-backdrop-filter: blur(24px) saturate(180%) !important;
  backdrop-filter: blur(24px) saturate(180%) !important;
}

/* OVERLAYS · oscurecimiento sin desenfoque.
   Los vidrios de navegación, menús y dock conservan su material; esta regla
   cubre exclusivamente capas modales que oscurecen la aplicación. */
.lk-cita-frame .lkcf-backdrop,
.lk-cita-frame .lkcf-ov,
.cc-overlay,
.cs-ov,
.cfg-ov,
.agv-ov,
.p3-ed-overlay,
.p3-pk-overlay,
.p3-ev-overlay,
.lk-dg-back,
.modal-ov,
.cl-overlay,
.rmd-ov,
.sala-ov,
.sadm-ov,
.lkh-guide,
#ldDimmer {
  -webkit-backdrop-filter: none !important;
  backdrop-filter: none !important;
}

/* Los temas oscuros usan un velo negro neutro: el overlay no hereda el
   matiz azul de las superficies midnight. */
[data-theme="darkmode"] .lk-cita-frame .lkcf-backdrop,
[data-theme="darkmode"] .lk-cita-frame .lkcf-ov,
[data-theme="darkmode"] .cc-overlay,
[data-theme="darkmode"] .cs-ov,
[data-theme="darkmode"] .cfg-ov,
[data-theme="darkmode"] .agv-ov,
[data-theme="darkmode"] .p3-ed-overlay,
[data-theme="darkmode"] .p3-pk-overlay,
[data-theme="darkmode"] .p3-ev-overlay,
[data-theme="darkmode"] .lk-dg-back,
[data-theme="darkmode"] .modal-ov,
[data-theme="darkmode"] .cl-overlay,
[data-theme="darkmode"] .rmd-ov,
[data-theme="darkmode"] .sala-ov,
[data-theme="darkmode"] .sadm-ov,
[data-theme="darkmode"] .lkh-guide {
  background: rgba(0, 0, 0, .72) !important;
}

[data-theme="midnight"] .lk-cita-frame .lkcf-backdrop,
[data-theme="midnight"] .lk-cita-frame .lkcf-ov,
[data-theme="midnight"] .cc-overlay,
[data-theme="midnight"] .cs-ov,
[data-theme="midnight"] .cfg-ov,
[data-theme="midnight"] .agv-ov,
[data-theme="midnight"] .p3-ed-overlay,
[data-theme="midnight"] .p3-pk-overlay,
[data-theme="midnight"] .p3-ev-overlay,
[data-theme="midnight"] .lk-dg-back,
[data-theme="midnight"] .modal-ov,
[data-theme="midnight"] .cl-overlay,
[data-theme="midnight"] .rmd-ov,
[data-theme="midnight"] .sala-ov,
[data-theme="midnight"] .sadm-ov,
[data-theme="midnight"] .lkh-guide {
  background: rgba(0, 0, 0, .78) !important;
}

/* Buscador canónico de topbar: compacto, autocolapsable y aislado al módulo. */
.lk-module-search {
  width: 36px !important;
  height: 36px !important;
  display: inline-flex !important;
  align-items: center;
  flex: 0 0 auto;
  overflow: hidden;
  border: .5px solid transparent;
  border-radius: 9px;
  background: transparent;
  transition: width .24s var(--lk-ease, ease), background .18s, border-color .18s, box-shadow .18s;
}
.lk-module-search.is-open,
.lk-module-search:focus-within {
  width: clamp(180px, 22vw, 300px) !important;
  background: var(--lk-bg-card);
  border-color: var(--lk-border);
  box-shadow: var(--lk-shadow-sm);
}
.lk-module-search input {
  width: 0 !important;
  min-width: 0;
  flex: 1;
  padding: 0;
  border: 0;
  outline: 0;
  opacity: 0;
  background: transparent;
  color: var(--lk-text-primary);
  font: 400 var(--font-base)/1 var(--lk-font-sans);
  transition: opacity .14s;
}
.lk-module-search.is-open input,
.lk-module-search:focus-within input {
  width: auto !important;
  padding-left: 11px;
  opacity: 1;
}
.lk-module-search__button {
  margin-left: auto !important;
  flex: 0 0 35px !important;
  border: 0 !important;
  background: transparent !important;
  color: var(--lk-text-muted) !important;
  box-shadow: none !important;
}
.lk-module-search__button:hover { color: var(--lk-brand) !important; background: var(--lk-bg-hover) !important; }
.lk-module-search__button svg { width: 16px; height: 16px; }
[data-lk-search-hidden] { display: none !important; }
@media (max-width: 639.98px) {
  .lk-module-search.is-open,
  .lk-module-search:focus-within { width: min(220px, 65vw) !important; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   CANON HEALTH MODULE BAR
   Semantic contract shared by every Salud module. These rules intentionally
   win over legacy module CSS so title, icon and controls cannot drift again.
   ═══════════════════════════════════════════════════════════════════════════ */
.lk-modulebar {
  box-sizing: border-box !important;
  width: 100% !important;
  height: 56px !important;
  min-height: 56px !important;
  padding: 0 20px !important;
  display: flex !important;
  align-items: center !important;
  gap: 12px !important;
  flex-wrap: nowrap !important;
  font-family: var(--lk-font-sans) !important;
  background: var(--lk-surface-fill, var(--lk-bg-card)) !important;
  -webkit-backdrop-filter: var(--lk-surface-blur, none) !important;
  backdrop-filter: var(--lk-surface-blur, none) !important;
  color: var(--lk-text-primary) !important;
  border: 0 !important;
  border-bottom: .5px solid var(--lk-border) !important;
  border-radius: 0 !important;
  box-shadow: var(--lk-specular, none) !important;
}
.lk-modulebar__identity {
  min-width: max-content !important;
  display: inline-flex !important;
  align-items: center !important;
  gap: 10px !important;
  flex: 0 0 auto !important;
}
.lk-modulebar__icon {
  box-sizing: border-box !important;
  width: 20px !important;
  height: 20px !important;
  min-width: 20px !important;
  padding: 0 !important;
  display: inline-flex !important;
  align-items: center !important;
  justify-content: center !important;
  color: var(--c-accent, var(--lk-brand)) !important;
  background: transparent !important;
  border: 0 !important;
  border-radius: 0 !important;
  box-shadow: none !important;
}
.lk-modulebar__icon svg {
  width: 20px !important;
  height: 20px !important;
  color: inherit !important;
  stroke: currentColor !important;
}
.lk-modulebar__title {
  margin: 0 !important;
  padding: 0 !important;
  font-family: var(--lk-font-sans) !important;
  font-size: calc(var(--font-base) * 1.154) !important;
  line-height: 1 !important;
  font-weight: 600 !important;
  letter-spacing: -.01em !important;
  color: var(--lk-text-primary) !important;
  white-space: nowrap !important;
}
.lk-modulebar__spacer { flex: 1 1 0 !important; min-width: 8px !important; }

/* ── VARIANTE `--centrado` · el medio va al CENTRO DE LA BARRA ───────────────
   Es OPT-IN: sin esta clase la barra sigue siendo flex exactamente como estaba,
   asi que los modulos que no la pidan no se enteran de que existe.

   PARA QUE SIRVE: con flex, el elemento del medio queda centrado en el HUECO
   LIBRE, no en la barra: si la identidad y las acciones no miden lo mismo, se
   ve descentrado. La otra salida —sacarlo del flujo con position:absolute— si
   centra exacto, pero entonces nadie le reserva sitio y con un titulo largo se
   MONTA encima. Fue lo que paso en Paciente 360.
   La rejilla `1fr auto 1fr` resuelve las dos cosas a la vez: las dos columnas
   laterales miden SIEMPRE lo mismo, asi que el medio cae en el centro real, y
   al estar en el flujo no puede pisarse con nada.

   CONTRATO: exige EXACTAMENTE TRES hijos —izquierda, centro, derecha—. Si un
   modulo tiene espaciadores (.lk-modulebar__spacer) sobran: la rejilla ya
   reparte. No poner esta clase con 4 o 5 hijos.                              */
.lk-modulebar--centrado {
  display: grid !important;
  grid-template-columns: 1fr auto 1fr !important;
  align-items: center !important;
}
/* `stretch` (el valor por omision) y NO `start`: con `start` el hijo se
   dimensiona por su CONTENIDO y puede desbordar su columna —medido: una
   identidad de 538px saliendose de una columna de 485 y metiendose en las
   pestanas—. Estirado a la columna + min-width:0, cede y recorta con elipsis,
   que es lo que debe pasar. El contenido sigue alineado a la izquierda porque
   el propio hijo es flex. */
.lk-modulebar--centrado > :first-child  { justify-self: stretch; min-width: 0; max-width: 100%; }
.lk-modulebar--centrado > :nth-child(2) { justify-self: center; }
.lk-modulebar--centrado > :last-child   { justify-self: end; min-width: 0; max-width: 100%; }
/* En movil la rejilla vuelve a dos columnas: el medio se pliega (lo decide el
   modulo) y no tiene sentido reservarle una columna vacia. */
@media (max-width: 639.98px) {
  .lk-modulebar--centrado { grid-template-columns: 1fr auto !important; }
}
/* ── BOTONES DEL TOPBAR · el canónico ────────────────────────────────────────
   Cristián, 12-ago-2026 (E050), textual: «los botones de búsqueda, tarifario y
   configuración de la topbar no deberían aparecer por RBAC, y no deberían tener
   esa apariencia horrible». La mitad RBAC ya estaba; ésta es la apariencia.
   Referencia: mockups/mockup-topbar-canonico.html §B.

   QUÉ FALTABA, y por qué se veía mal. Este bloque declaraba tipografía, alto,
   borde y radio — y nada más. No hay `button{}` de reinicio en ningún
   core/css/*.css, así que el navegador ponía lo suyo:
     · sin `background` → fondo NATIVO del <button> (ButtonFace). Medido en
       darkmode: rgb(107,107,107) contra una barra de rgb(15,15,17). No sigue
       ningún tema porque no es CSS, es el widget del SO asomando.
     · sin `display:flex` → el rótulo y el SVG no se centraban.
     · sin tamaño de SVG → el icono se estiraba al alto del botón (la lupa).
     · sin `cursor`, sin `:hover`, sin `:focus-visible`, sin `:disabled`.
   Estaba diagnosticado desde el 14-ago en honorarios.css, parcheado allí a
   `.hon-bar` porque «no se pidió tocar a los demás». Ya se pidió: sube a la
   raíz y el parche del módulo se borra.

   `!important` SÓLO en el reinicio estructural (lo que no puede derivar nunca).
   Color, fondo y estados van SIN él a propósito, para que las tres excepciones
   deliberadas que ya existen sigan pudiendo ganar por especificidad:
   `.lk-module-search__button`, `.vrf-topsearch .lk-top-icon` y el activo de
   Agenda (`.agw .prof-wrap.open .pill`).                                     */
.lk-top-action,
.lk-top-icon {
  box-sizing: border-box !important;
  height: 36px !important;
  min-height: 36px !important;
  font: inherit !important;
  font-family: var(--lk-font-sans) !important;
  font-size: var(--font-base) !important;
  line-height: 1 !important;
  font-weight: 500 !important;
  letter-spacing: 0 !important;
  display: inline-flex !important;
  align-items: center !important;
  justify-content: center !important;
  gap: 7px !important;
  position: relative;
  cursor: pointer;
  background: var(--lk-bg-card);
  color: var(--lk-text-secondary);
  transition: background .15s, border-color .15s, color .15s, transform .12s, box-shadow .15s;
}
.lk-top-action {
  padding: 0 14px !important;
  border: .5px solid var(--lk-border) !important;
  border-radius: 8px !important;
}
.lk-top-icon {
  width: 36px !important;
  min-width: 36px !important;
  padding: 0 !important;
  border: .5px solid var(--lk-border) !important;
  border-radius: 8px !important;
}
/* El SVG lo devuelve `S.icon()` sin width/height: si nadie se lo da, se estira
   al alto del botón. Los hermanos ya lo hacen (`.lk-pilltab__item svg` 14px,
   `.lk-compound__button > svg` 15px); esta familia era la única sin ello. */
.lk-top-action svg,
.lk-top-icon svg { width: 15px !important; height: 15px !important; stroke-width: 1.8; flex: none; }

.lk-top-action:hover:not(:disabled),
.lk-top-icon:hover:not(:disabled) {
  background: var(--lk-bg-hover);
  border-color: var(--lk-brand-border) !important;
  color: var(--lk-text-primary);
}
.lk-top-action:active:not(:disabled),
.lk-top-icon:active:not(:disabled) { transform: scale(.96); }
.lk-top-action:focus-visible,
.lk-top-icon:focus-visible { outline: none; box-shadow: var(--lk-ring-focus); }
.lk-top-action.is-active,
.lk-top-icon.is-active {
  background: var(--lk-bg-active);
  border-color: var(--lk-brand-border) !important;
  color: var(--c-accent, var(--lk-brand));
}
.lk-top-action:disabled,
.lk-top-icon:disabled { opacity: .5; cursor: default; }

/* Sólo-icono: en reposo deja de ser transparente — una superficie visible se
   lee como control; hasta hoy era invisible hasta que lo tocabas. */
.lk-top-icon { background: var(--lk-bg-hover); }
.lk-top-icon:hover:not(:disabled) { background: var(--lk-bg-active); }

/* Primaria — mismo patrón que `.cfg-btn.pri`. */
.lk-top-action--pri {
  background: var(--c-accent, var(--lk-brand));
  border-color: transparent !important;
  color: var(--lk-text-inverse);
}
.lk-top-action--pri:hover:not(:disabled) {
  background: var(--c-accent, var(--lk-brand));
  border-color: transparent !important;
  color: var(--lk-text-inverse);
  filter: brightness(1.08);
}
.lk-top-action--pri:disabled { background: var(--c-accent, var(--lk-brand)); opacity: .5; filter: none; }

/* Destructiva — hereda el tratamiento de `.cfg-btn.dang`. La clase `.danger`
   NO existe en este sistema: no la escribas. */
.lk-top-action--dang:hover:not(:disabled),
.lk-top-icon--dang:hover:not(:disabled) {
  background: var(--lk-red-soft);
  border-color: var(--lk-red) !important;
  color: var(--lk-red);
}
.lk-top-action--dang:focus-visible,
.lk-top-icon--dang:focus-visible { box-shadow: 0 0 0 3px color-mix(in srgb, var(--lk-red) 30%, transparent); }

/* El rótulo del sólo-icono: sale del `aria-label` que el botón YA lleva, sin
   JS y sin duplicar el texto. Resuelve el «cuadrado mudo». */
.lk-top-icon[aria-label]::after {
  content: attr(aria-label);
  position: absolute; top: calc(100% + 7px); left: 50%;
  transform: translateX(-50%) translateY(-2px);
  padding: 4px 8px; border-radius: 6px;
  background: var(--lk-text-primary); color: var(--lk-bg-card);
  font-size: calc(var(--font-base) * .77); font-weight: 500;
  white-space: nowrap; pointer-events: none; opacity: 0;
  box-shadow: var(--lk-shadow-md); z-index: 30;
  transition: opacity .12s, transform .12s;
}
.lk-top-icon:hover::after,
.lk-top-icon:focus-visible::after { opacity: 1; transform: translateX(-50%) translateY(0); }
/* Excepción: el botón que vive DENTRO del buscador no lleva rótulo flotante —
   el campo ya dice qué es, y su contenedor tiene `overflow:hidden`, así que el
   globo saldría recortado en vez de no salir. */
.lk-module-search__button::after { content: none !important; }
@media (prefers-reduced-motion: reduce) {
  .lk-top-action, .lk-top-icon, .lk-top-icon[aria-label]::after { transition: none; }
  .lk-top-action:active:not(:disabled), .lk-top-icon:active:not(:disabled) { transform: none; }
}

/* ── RANURAS DEL TOPBAR CANÓNICO ─────────────────────────────────────────────
   Referencia: mockups/mockup-topbar-canonico.html §2, aprobado.

   La barra (.lk-modulebar) y los botones ya estaban. Esto es lo que faltaba:
   las RANURAS. Son las seis piezas que el mockup declara y que hasta hoy no
   existían en ningún core/css/*.css — cada módulo se dibujaba la suya con
   clases propias, y por eso ninguna barra se parecía a la de al lado.

   El orden canónico de la barra, de izquierda a derecha:
     vuelta · identidad · contexto · [espaciador] · nav · filtro · buscar ·
     acciones · gestión · desborde

   POLÍTICA DE `!important`, igual que en los botones: sólo en lo ESTRUCTURAL
   (caja, medidas, disposición), que es lo que no puede volver a divergir. El
   color y los estados van sin él, para que un módulo con una razón escrita
   pueda seguir ganando por especificidad.                                    */

/* CONTEXTO — el dato que acompaña al título (rango de fechas, nombre del
   paciente, versión). Se recorta ANTES que el título: el título es la
   identidad del módulo y no se sacrifica. De ahí `min-width:0` + la elipsis
   en `.tx`, y `flex:none` en el distintivo, que es corto y no debe encogerse. */
.lk-modulebar__context {
  display: inline-flex !important;
  align-items: center !important;
  gap: 8px !important;
  min-width: 0 !important;
  overflow: hidden !important;
  white-space: nowrap !important;
  /* El `text-overflow` va también en el propio contenedor, no sólo en `.tx`:
     hay dos formas de contexto en el árbol —el que envuelve su texto en `.tx`
     (P360, con distintivo al lado) y el que lo lleva suelto (el rango de
     Agenda, que su JS reescribe con `textContent` y no admite un hijo)—. Sin
     esto la segunda forma recorta a hachazo, sin puntos suspensivos. */
  text-overflow: ellipsis !important;
  font-size: calc(var(--font-base) * .92);
  color: var(--lk-text-muted);
}
.lk-modulebar__context .tx { overflow: hidden !important; text-overflow: ellipsis !important; }
.lk-modulebar__context .badge {
  flex: none !important;
  padding: 2px 7px !important;
  border-radius: 999px !important;
  font-size: calc(var(--font-base) * .77);
  font-weight: 600;
  letter-spacing: .02em;
  background: var(--lk-bg-active);
  color: var(--c-accent, var(--lk-brand));
}

/* VUELTA — icono-sólo que antecede a la identidad. Hereda entero el
   tratamiento de `.lk-top-icon`; aquí sólo se le impide encoger.
   OJO: la ranura EXISTE, pero hoy no la usa nadie. En Paciente 360 la prueba
   `P360-NAV` prohíbe expresamente la flecha de vuelta (se vuelve reclicando la
   pestaña Pacientes), y el mockup deja escrito que si el canónico la reemplaza
   es decisión de Cristián, no tomada. No se cablea sin esa decisión.          */
.lk-modulebar__back { flex: none !important; }

/* BUSCAR — icono que se abre en campo inline. El patrón ya lo hacían Agenda y
   Honorarios cada uno por su cuenta; esto lo vuelve uno solo.
   El campo se anima con `width`+`opacity` y NO se oculta con `display:none`,
   para que el foco pueda entrar en él en el mismo cuadro en que se abre.

   UNA SOLA CAJA. Éste era el defecto de verdad: los tres módulos dibujan un
   recuadro en el ENVOLTORIO, y desde que `.lk-top-icon` tiene borde propio
   (commit anterior de esta misma rama) el botón dibujaba OTRO recuadro dentro.
   Medido en banco sobre Agenda. Aquí la regla es que la caja es del envoltorio,
   siempre, abierta o cerrada; el botón de dentro nunca dibuja la suya.        */
.lk-modulebar__search {
  box-sizing: border-box !important;
  height: 36px !important;
  display: inline-flex !important;
  align-items: center !important;
  overflow: hidden !important;
  border: .5px solid var(--lk-border) !important;
  border-radius: 8px !important;
  background: var(--lk-bg-card);
  transition: border-color .15s, background .15s, box-shadow .15s;
}
.lk-modulebar__search input {
  width: 0;
  padding: 0;
  opacity: 0;
  border: 0 !important;
  outline: none;
  background: transparent;
  color: var(--lk-text-primary);
  font: inherit !important;
  transition: width .18s, opacity .18s, padding .18s;
}
/* El botón de dentro pierde su caja — la caja ya es del envoltorio — y también
   el globo del rótulo: el propio campo dice lo que es, y el envoltorio tiene
   `overflow:hidden`, así que el globo saldría recortado en vez de no salir.   */
.lk-modulebar__search .lk-top-icon {
  width: 34px !important;
  min-width: 34px !important;
  height: 34px !important;
  border: 0 !important;
  border-radius: 7px !important;
  background: transparent !important;
}
.lk-modulebar__search .lk-top-icon::after { content: none !important; }
.lk-modulebar__search:focus-within { border-color: var(--lk-brand-border) !important; box-shadow: var(--lk-ring-focus); }
/* PUENTE DE MIGRACIÓN — el canónico llama `is-open` al estado abierto, pero los
   tres módulos que ya tenían buscador lo llaman cada uno a su manera: Agenda y
   Verificación `on`, Paciente 360 `is-on`. Aceptar los tres nombres convierte la
   adopción en UNA LÍNEA de marcado por módulo, sin tocar una sola línea de
   lógica — y tocar el JS de tres módulos vivos para renombrar una clase es todo
   riesgo y ningún beneficio. Los alias van SCOPADOS a `.lk-modulebar__search`,
   así que `.on` sólo significa algo dentro de una ranura que ya pidió el canon.
   Cuando los tres estén migrados, se borran los dos alias y queda `is-open`. */
.lk-modulebar__search.is-open,
.lk-modulebar__search.on,
.lk-modulebar__search.is-on { border-color: var(--lk-brand-border) !important; }
/* El ancho abierto va SIN `!important` a propósito: es lo único de la ranura
   que cada módulo tiene medido para su barra (Agenda 206px, P360 194, VRF 184)
   y no es lo que estaba roto. El canon da 170 por omisión y el módulo que tenga
   una razón medida sigue ganando por especificidad. Lo que el canon SÍ impone
   es la caja, que es lo que divergía. */
.lk-modulebar__search.is-open input,
.lk-modulebar__search.on input,
.lk-modulebar__search.is-on input { width: 170px; padding: 0 2px 0 12px; opacity: 1; }

/* DESBORDE — lo que no cabe se pliega en un menú PROPIO. Nunca un <select>
   nativo: la regla escrita de Cristián es que los desplegables son nuestros. */
.lk-modulebar__overflow { position: relative !important; flex: none !important; }
.lk-topmenu {
  position: absolute !important;
  top: calc(100% + 8px) !important;
  right: 0 !important;
  z-index: 40 !important;
  min-width: 200px !important;
  padding: 6px !important;
  display: none;
  border: .5px solid var(--lk-border) !important;
  border-radius: var(--lk-radius-md) !important;
  background: var(--lk-bg-card);
  box-shadow: var(--lk-shadow-md);
}
.lk-modulebar__overflow.is-open .lk-topmenu { display: block; }
.lk-topmenu button {
  box-sizing: border-box !important;
  width: 100% !important;
  padding: 8px 9px !important;
  display: flex !important;
  align-items: center !important;
  gap: 9px !important;
  text-align: left !important;
  border: 0 !important;
  border-radius: 6px !important;
  font: inherit !important;
  font-size: calc(var(--font-base) * .92) !important;
  cursor: pointer;
  background: transparent;
  color: var(--lk-text-secondary);
}
.lk-topmenu button:hover { background: var(--lk-bg-hover); color: var(--lk-text-primary); }
.lk-topmenu button:focus-visible { outline: none; box-shadow: var(--lk-ring-focus); }
.lk-topmenu button svg { width: 14px !important; height: 14px !important; stroke-width: 1.8; flex: none !important; }
.lk-topmenu .sep { height: .5px !important; margin: 5px 2px !important; background: var(--lk-border-soft); }

/* SEGUNDA FILA — la franja de filtros, sólo para el módulo que la use.
   Va en `--lk-bg-surface`, un escalón por debajo de la barra, para que se lea
   como subordinada a ella y no como una segunda barra. */
.lk-modulebar__filas {
  padding: 10px 20px !important;
  display: flex !important;
  align-items: center !important;
  gap: 8px !important;
  flex-wrap: wrap !important;
  background: var(--lk-bg-surface);
  border-bottom: .5px solid var(--lk-border);
}

/* RANURA SIN DECIDIR — el hueco declarado que todavía no es un botón vivo.
   Es producto, no andamio: hace VISIBLE que ahí falta una decisión, en vez de
   dejar un vacío que nadie recuerda. Hoy la piden Config y KPIs de Reservas. */
.lk-slot-vacia {
  box-sizing: border-box !important;
  height: 34px !important;
  padding: 0 12px !important;
  display: inline-flex !important;
  align-items: center !important;
  gap: 6px !important;
  border: 1px dashed var(--lk-border) !important;
  border-radius: 8px !important;
  font-size: calc(var(--font-base) * .85) !important;
  white-space: nowrap !important;
  color: var(--lk-text-faint);
}
/* Medido en banco: sin esto el SVG se estira al alto de la ranura y parte el
   rótulo en tres líneas. El tamaño NO puede depender de que quien la escriba
   se acuerde de poner width/height en el <svg>. */
.lk-slot-vacia svg { width: 13px !important; height: 13px !important; flex: none !important; }

@media (max-width: 760px) {
  .lk-modulebar {
    padding: 0 12px !important;
    gap: 8px !important;
    overflow-x: auto !important;
    overflow-y: hidden !important;
    scrollbar-width: none;
  }
  .lk-modulebar::-webkit-scrollbar { display: none; }
  /* `background:inherit` NO es decorativo: sin él la identidad pegajosa es
     transparente y el resto de la barra se ve pasar POR DEBAJO al desplazar. */
  .lk-modulebar__identity { position: sticky; left: 0; z-index: 2; background: inherit; }
  .lk-modulebar__filas { padding: 8px 12px !important; }
}

/* ══ BADGE DE MENSAJE RESPONSIVE · contrato canónico ═══════════════════════
   Una sola línea, fija sobre el borde superior REAL del dock. El contenido
   interno adopta las tres ranuras `__state · __text · __action`; la familia de
   color queda a cargo del módulo que emite el mensaje. */
@media (max-width: 639.98px) {
  .lk-responsive-message-badge {
    position: fixed; left: 22px; right: 22px;
    /* El dock nace en safe-area + 3px y mide --lk-dock-h. El badge queda
       físicamente 4px arriba de su borde superior y debe pintar DELANTE de
       él: con z-index menor el vidrio del dock lo recortaba visualmente. */
    bottom: calc(env(safe-area-inset-bottom, 8px) + 3px + var(--lk-dock-h, 58px) + 4px);
    z-index: calc(var(--lk-z-dock, 55) + 1);
    display: grid; grid-template-columns: auto minmax(0, 1fr) auto;
    align-items: center; gap: 8px; min-height: 38px;
    padding: 5px 6px 5px 9px; border: .5px solid var(--lk-border);
    border-radius: 999px; background: var(--lk-bg-card); box-shadow: var(--lk-shadow-md);
  }
  .lk-responsive-message-badge__text { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .lk-responsive-message-badge__action { white-space: nowrap; }
}


/* ── css/lk-ceremonia.css ── */
/* ══════════════════════════════════════════════════════════════════════════════
   core/css/lk-ceremonia.css · el molde COMPARTIDO de las ceremonias de identidad
   (clases .lkv-*). Antes vivía inyectado como texto desde `core/lk-llave.js::_css()`
   —así la ceremonia no entraba al paquete de tokens ni disparaba su gate de diseño
   por un cambio que era suyo—, y por eso el único lugar donde existía era montada
   la ceremonia: quien necesitaba el mismo aspecto en otra pantalla no tenía más
   remedio que copiar las clases a mano bajo otro prefijo.

   Mudado tal cual (spec CORE-LKV-HOJA, 21-ago-2026): ni una medida, ni un color,
   ni un nombre de clase cambia. Cualquier módulo que necesite este molde lo
   consume desde aquí — NO lo porta ni lo copia con otro prefijo.
   ══════════════════════════════════════════════════════════════════════════════ */
.lkv{width:100%;max-width:340px;background:var(--lk-bg-card);border:.5px solid var(--lk-border);
border-radius:18px;box-shadow:var(--lk-shadow-lg);padding:24px 22px;text-align:center}
/* El envoltorio bare sólo sostiene la tarjeta de ceremonia: si conserva el
   marco del modal genérico, se dibujan dos cajas concéntricas. */
.lk-modal-ov--llave .lk-modal-box{background:transparent;border:0;box-shadow:none;width:auto;overflow:visible}
.lkv-ic{width:52px;height:52px;border-radius:50%;display:grid;place-items:center;margin:0 auto 14px;
background:var(--lk-brand-muted);color:var(--lk-brand)}
.lkv-ic svg{width:26px;height:26px;stroke-width:2.2}
.lkv-t{font-size:calc(var(--font-base,13px) * 1.231);font-weight:500;letter-spacing:-.01em;color:var(--lk-text-primary)}
.lkv-s{font-size:var(--font-base,13px);color:var(--lk-text-muted);margin-top:6px;line-height:1.45}
.lkv-s b{color:var(--lk-text-primary);font-weight:500}
/* ── la voz de SUSCRIPCIÓN (mockup 6ed7a766) ──────────────────────────
   Tamaños en la misma escala que el resto del archivo (calc sobre
   --font-base), no en px fijos: si el usuario sube el tamaño de letra del
   sistema, la ceremonia crece con él. */
.lkv-eyebrow{font-size:calc(var(--font-base,13px) * .769);font-weight:700;letter-spacing:.13em;
text-transform:uppercase;color:var(--lk-brand);margin-bottom:7px}
.lkv-doc{text-align:left;background:var(--lk-bg-surface);border:.5px solid var(--lk-border-soft);
border-radius:11px;padding:11px 13px;margin-top:14px;display:grid;gap:6px}
.lkv-kv{display:flex;align-items:baseline;justify-content:space-between;gap:12px;
font-size:calc(var(--font-base,13px) * .923)}
.lkv-kv .k{color:var(--lk-text-faint);flex:0 0 auto}
/* el valor puede ser largo (nombre completo): parte, no desborda */
.lkv-kv .v{color:var(--lk-text-primary);font-weight:500;text-align:right;min-width:0;overflow-wrap:anywhere}
.lkv-kv .v.mono{font-family:var(--lk-font-mono,ui-monospace,Menlo,monospace);
font-size:calc(var(--font-base,13px) * .885)}
.lkv-firmante{display:flex;align-items:center;gap:9px;text-align:left;margin-top:12px;
padding-top:12px;border-top:.5px solid var(--lk-border-soft)}
.lkv-av{width:30px;height:30px;border-radius:50%;flex:0 0 auto;display:grid;place-items:center;
background:var(--lk-brand-muted);color:var(--lk-brand);font-weight:600;
font-size:calc(var(--font-base,13px) * .846)}
.lkv-firmante .who{min-width:0;line-height:1.3}
.lkv-firmante .who b{display:block;font-weight:600;color:var(--lk-text-primary);
font-size:calc(var(--font-base,13px) * .962)}
.lkv-firmante .who span{color:var(--lk-text-faint);font-size:calc(var(--font-base,13px) * .846)}
.lkv-legal{display:flex;gap:8px;text-align:left;margin-top:13px;line-height:1.45;
color:var(--lk-text-faint);font-size:calc(var(--font-base,13px) * .846)}
.lkv-legal svg{width:13px;height:13px;flex:0 0 auto;margin-top:1px;color:var(--lk-brand)}
/* factores · lado a lado (diseño aprobado) */
.lkv-factors{display:flex;gap:8px;margin:18px 0 6px}
.lkv-factor{flex:1;border:.5px solid var(--lk-border);border-radius:10px;padding:12px;cursor:pointer;
text-align:center;background:var(--lk-bg-card);color:var(--lk-text-primary);font-family:inherit;font-size:inherit;transition:all .15s}
.lkv-factor:hover{border-color:var(--lk-brand-border)}
.lkv-factor:focus-visible{outline:0;border-color:var(--lk-brand);box-shadow:var(--lk-ring-focus)}
.lkv-factor .fic{color:var(--lk-brand);display:inline-flex;margin-bottom:6px}
.lkv-factor .fic svg{width:20px;height:20px}
.lkv-factor .ft{font-size:calc(var(--font-base,13px) * .962);font-weight:600}
.lkv-factor .fd{font-size:calc(var(--font-base,13px) * .808);color:var(--lk-text-muted);margin-top:2px}
/* Sin shorthand `font`: con `inherit` como familia la declaracion es INVALIDA
   y el navegador la descarta ENTERA (peso y tamano incluidos). Se separa. */
.lkv-btn{width:100%;height:40px;padding:0 13px;border-radius:10px;border:.5px solid var(--lk-border);
background:transparent;color:var(--lk-text-muted);font-weight:500;
font-size:calc(var(--font-base,13px) * .962);font-family:inherit;
cursor:pointer;display:flex;align-items:center;justify-content:center;margin-top:16px}
.lkv-btn:hover{border-color:var(--lk-brand-border)}
/* casillero · 42x50 mono 20px, con guion 3+3 */
.lkv-pin{display:flex;gap:8px;justify-content:center;margin:18px 0 0}
.lkv-pin input{width:42px;height:50px;text-align:center;font-size:20px;font-family:var(--lk-font-mono,ui-monospace,Menlo,monospace);
border:.5px solid var(--lk-border);border-radius:10px;background:var(--lk-bg-surface);color:var(--lk-text-primary)}
.lkv-pin input:focus{outline:0;border-color:var(--lk-brand);box-shadow:var(--lk-ring-focus)}
/* el guion NO es una casilla: sin foco, sin selección, no cuenta como dígito */
.lkv-sep{width:9px;text-align:center;color:var(--lk-text-faint);font-size:16px;align-self:center;
-webkit-user-select:none;user-select:none;flex:0 0 auto}
.lkv-pin.err input{border-color:color-mix(in srgb,var(--lk-red) 45%,transparent)}
@keyframes lkv-sacude{10%,90%{transform:translateX(-2px)}20%,80%{transform:translateX(4px)}
30%,50%,70%{transform:translateX(-7px)}40%,60%{transform:translateX(7px)}}
.lkv-pin.err{animation:lkv-sacude .5s cubic-bezier(.36,.07,.19,.97) both}
@media(prefers-reduced-motion:reduce){.lkv-pin.err{animation:none}}
/* barra de estado · nace vacía, solo reserva alto */
.lkv-bar{margin-top:16px;height:30px;border-radius:8px;display:flex;align-items:center;justify-content:center;
gap:7px;font-size:calc(var(--font-base,13px) * .885);color:var(--lk-text-muted);background:transparent;
border:.5px solid transparent}
.lkv-bar svg{width:13px;height:13px;stroke-width:2}
.lkv-bar.err{color:var(--lk-red);background:var(--lk-red-soft);border-color:color-mix(in srgb,var(--lk-red) 30%,transparent)}
.lkv-bar.ok{color:var(--lk-green);background:var(--lk-green-soft);border-color:color-mix(in srgb,var(--lk-green) 30%,transparent)}
/* ── CONFIRMAR EL NOMBRE (mockup firma-nombre, autorizado por Cristián el
   20-ago-2026) ──────────────────────────────────────────────────────────
   El bloque del nombre NO es una fila rótulo/valor como `.lkv-kv`: se probó
   así y el nombre completo partía feo contra el rótulo. Va centrado y solo,
   porque lo que se aprueba es exactamente lo que se verá en el sello. */
.lkv-nom{text-align:center;background:var(--lk-bg-surface);border:.5px solid var(--lk-border-soft);
border-radius:11px;padding:16px 13px 14px;margin-top:15px}
.lkv-nom .nom{font-size:calc(var(--font-base,13px) * 1.154);font-weight:600;letter-spacing:.02em;
color:var(--lk-text-primary);line-height:1.3;overflow-wrap:anywhere}
.lkv-nom .run{margin-top:5px;color:var(--lk-text-faint);
font-family:var(--lk-font-mono,ui-monospace,Menlo,monospace);
font-size:calc(var(--font-base,13px) * .846)}
.lkv-nom .de{margin-top:9px;padding-top:9px;border-top:.5px solid var(--lk-border-soft);
color:var(--lk-text-faint);font-size:calc(var(--font-base,13px) * .808);line-height:1.4}
/* «Sí» y «No» usan la MISMA forma que PassKey/PIN: es el vocabulario que la
   ceremonia ya tiene para «elige una de dos». Sólo cambia el color del icono. */
.lkv-factor.si .fic{color:var(--lk-green)}
.lkv-factor.no .fic{color:var(--lk-amber)}
.lkv-ic.amb{background:var(--lk-amber-soft);color:var(--lk-amber)}
.lkv-ic.red{background:var(--lk-red-soft);color:var(--lk-red)}
.lkv-eyebrow.amb{color:var(--lk-amber)}
.lkv-eyebrow.red{color:var(--lk-red)}
/* La SALIDA: en un muro, decir a quién acudir importa más que la negativa.
   Ningún estado terminal sin llave. */
.lkv-salida{display:flex;gap:8px;text-align:left;margin-top:14px;padding:11px 12px;border-radius:10px;
line-height:1.45;background:var(--lk-bg-surface);border:.5px solid var(--lk-border-soft);
color:var(--lk-text-muted);font-size:calc(var(--font-base,13px) * .885)}
.lkv-salida svg{width:14px;height:14px;flex:0 0 auto;margin-top:2px}
/* El principal · clonado de modules/cfg/cfg.css:392-393. El énfasis sale de
   --c-accent, que es el alias POR TENANT, no del brand de LUZO. */
.lkv-btn.pri{background:var(--c-accent);border-color:transparent;color:var(--lk-text-inverse);font-weight:600}
.lkv-btn.pri:hover{filter:brightness(1.08);border-color:transparent}
/* El QR del traspaso al teléfono. Fondo BLANCO fijo y no un token: un lector
   de códigos necesita contraste real, y en tema oscuro un QR sobre superficie
   oscura no se lee. Es tinta sobre papel, no interfaz. */
.lkv-qr{margin-top:15px;padding:14px;border-radius:11px;background:#fff;
display:grid;place-items:center}
.lkv-qr svg{width:180px;height:180px;display:block}
.lkv-enlace{margin-top:10px;word-break:break-all;text-align:left;
font-family:var(--lk-font-mono,ui-monospace,Menlo,monospace);
font-size:calc(var(--font-base,13px) * .731);color:var(--lk-text-faint);line-height:1.4}


/* ── css/lk-emptystate.css ── */
/* ══════════════════════════════════════════════════════════════════════════════
   core/css/lk-emptystate.css · estilos del estado vacío único (LK.dom.emptyState).
   Archivo PROPIO (fuera de lk-components.css) para sobrevivir sobrescrituras
   concurrentes del server compartido.
   CLON 1:1 del estado vacío del CREADOR DE CITAS NUEVO (.rv-cal-empty de
   modules/reservas/create/css/rc.css): ícono círculo 52px con fondo del ACENTO
   DEL TENANT (--c-brand-muted), svg 24px, título 15/500, bajada 12, botón --c-brand.
   Sin sombra ni halo. Fallback a --lk-* por si el acento aún no llegó del boot.
   ══════════════════════════════════════════════════════════════════════════════ */
.lz-empty{ display:grid; place-content:center; justify-items:center; gap:4px;
  padding:40px 24px; text-align:center; }
.lz-empty-ico{ display:grid; place-items:center; width:52px; height:52px; margin-bottom:8px;
  border-radius:50%; background:var(--c-brand-muted, var(--lk-brand-muted));
  color:var(--c-brand, var(--lk-brand)); }
.lz-empty-ico svg{ width:24px; height:24px; }
.lz-empty-title{ font-size:15px; font-weight:500; color:var(--tx-base, var(--lk-text-primary)); }
.lz-empty-sub{ max-width:260px; font-size:12px; line-height:1.5; color:var(--tx-muted, var(--lk-text-muted)); }
.lz-empty-btn{ display:inline-flex; align-items:center; gap:7px; margin-top:12px; padding:8px 16px;
  border:none; border-radius:9px; background:var(--c-brand, var(--lk-brand)); color:#fff;
  font:inherit; font-size:12px; font-weight:500; cursor:pointer; transition:background .15s; }
.lz-empty-btn:hover{ background:var(--c-brand-hover, var(--c-brand, var(--lk-brand))); filter:brightness(1.04); }
.lz-empty-btn svg{ width:14px; height:14px; }


/* ── css/lk-callout.css ── */
/* ══════════════════════════════════════════════════════════════════════════════
   core/css/lk-callout.css · estilos del aviso EN LÍNEA único (LK.dom.callout).
   Hermano de lk-emptystate.css: archivo PROPIO (fuera de lk-components.css) para
   sobrevivir sobrescrituras concurrentes del server compartido.
   Mockup aprobado: mockups/mockup-agenda-avisos.html:75-89. Cristián, textual:
   «propuesta de avisos aprobada». Las medidas NO son inventadas: son las del
   aviso flotante del sistema (core/lk-toast.js:74-92) trasladadas al aviso en
   línea, para que los dos hablen igual — tarjeta --bg-card, borde de media
   línea, radio 12, y la severidad SÓLO en la pastilla (9px, mayúsculas,
   letter-spacing .05em). El cuadro nunca se tiñe entero y no lleva franja
   lateral de color (decisión de Cristián, feedback_no_laterales_color).
   Fallback a --lk-* por si el token corto aún no llegó del boot.
   ══════════════════════════════════════════════════════════════════════════════ */
.lz-callout{display:flex;align-items:flex-start;gap:10px;padding:11px 13px;border-radius:12px;
  background:var(--bg-card, var(--lk-bg-card));border:.5px solid var(--border, var(--lk-border))}
.lz-callout-badge{display:inline-flex;align-items:center;justify-content:center;flex:0 0 auto;
  font-size:9px;font-weight:500;text-transform:uppercase;letter-spacing:.05em;
  padding:3px 8px;border-radius:20px;white-space:nowrap;margin-top:1px}
.lz-callout--warn  .lz-callout-badge{background:var(--amber-soft, var(--lk-amber-soft));color:var(--amber, var(--lk-amber))}
.lz-callout--ok    .lz-callout-badge{background:var(--green-soft, var(--lk-green-soft));color:var(--green, var(--lk-green))}
.lz-callout--error .lz-callout-badge{background:var(--red-soft, var(--lk-red-soft));color:var(--red, var(--lk-red))}
.lz-callout--info  .lz-callout-badge{background:var(--blue-soft, var(--lk-blue-soft));color:var(--blue, var(--lk-blue))}
.lz-callout-body{flex:1 1 auto;min-width:0}
.lz-callout-title{font-size:12.5px;font-weight:500;color:var(--tx-base, var(--lk-text-primary));line-height:1.35}
.lz-callout-detail{font-size:11.5px;color:var(--tx-muted, var(--lk-text-muted));margin-top:2px;line-height:1.45}
.lz-callout-acts{margin-top:8px;display:inline-flex;gap:14px}
.lz-callout-act{font-size:11px;font-weight:500;color:var(--c-brand, var(--lk-brand));background:none;border:0;
  padding:0;cursor:pointer;font-family:inherit}


/* ── css/lk-focus.css ── */
/* ══════════════════════════════════════════════════════════════════════════════
 * lk-focus.css · EL MODO FOCUS, UNA SOLA HOJA (pareja de core/lk-focus.js)
 *
 * Antes estaba duplicada: `.agw.ag-focus` en modules/agenda/styles/agenda.css y
 * `.rv-root.rv-focus` en modules/reservas/styles/reservas.css, línea por línea
 * la misma receta. Orden textual de Cristián (02-sep-2026): «el modo focus debe
 * ser uno solo a nivel global y estar estandarizado».
 *
 * Aquí vive el MECANISMO —pantalla completa, lista blanca de lo que sobrevive,
 * contexto de apilamiento y velo—. Lo que sigue siendo de cada módulo es su
 * PROPIA MAQUETA dentro del focus: qué nodo es su cabecera (para la zona segura
 * de la PWA) y cómo reparte el alto su contenido. Eso no es el modo focus: es
 * el marcado del módulo, y se escribe con `.lk-focus` en su hoja.
 * ══════════════════════════════════════════════════════════════════════════════ */

/* `position:fixed;inset:0` da la pantalla completa. El JS pone/quita la clase
   de GOLPE — sin transición CSS de entrada (R1, agenda/CLAUDE.md: una pestaña
   en segundo plano congela la animación y el elemento se quedaría invisible
   para siempre). La microanimación de crecer/encoger la hace `lk-focus.js` con
   WAAPI, que es cancelable y no deja estado de reposo animado.
   `display:flex` + `min-height:0` en los hijos es lo que hace que el módulo
   LLENE la pantalla y no sólo la tape: con `fixed;inset:0` a secas el marco
   ocupa todo el alto pero el contenido se queda arriba con su alto natural y
   debajo queda un vacío muerto (16-ago-2026, Cristián: «no está bien centrado
   y posicionado»). */
/* `.lk-focus.lk-focus` NO ES UN DESCUIDO: es especificidad, y sin ella esto no
   funciona. El bundle del core (tokens.<hash>.css) se concatena ANTES que el
   CSS de cada módulo, así que a igualdad de peso gana el módulo. Y la raíz que
   entra en foco siempre trae ya su propia clase con una regla de una clase:
   `.agw{position:relative;display:flex;overflow:hidden}` (agenda.css) y
   `.rv-root{...}` (reservas.css). Con `.lk-focus` a secas —0,1,0, igual que
   ellas y ANTES en la hoja— `position:relative` le ganaba a `position:fixed` y
   el modo focus no llegaba a abrirse. Repetir la clase sube a 0,2,0 sin
   nombrar a ningún módulo: la pieza no puede conocer a sus consumidores.
   Las dos originales lo lograban por otro camino (`.agw.ag-focus`,
   `.rv-root.rv-focus`), que es justo el que no se puede tener con una clase
   compartida. */
.lk-focus.lk-focus{position:fixed;inset:0;z-index:700;display:flex;flex-direction:column;overflow:hidden}

/* LISTA BLANCA, no lista negra: se esconde lo que se marca, y lo que nadie
   marca sobrevive al foco — así los avisos permanentes
   (spec-AVISOS-TAXONOMIA-FOCUS, 21-ago-2026) siguen a la vista sin declarar
   nada. El botón de salida NUNCA lleva la marca: sin Esc en un teléfono sería
   un estado sin salida humana. */
.lk-focus.lk-focus [data-focus="fuera"]{display:none}

/* EL RIEL SE COMÍA LA HORA — causa real, encontrada el 20-ago-2026.
   NO era el z-index del propio marco (declara 700, el riel sólo 200): un
   z-index sólo compite DENTRO del mismo contexto de apilamiento, y
   `#moduleContent` —donde monta CUALQUIER módulo— declara
   `position:relative;z-index:1` (core/css/lk-layout.css:139). Eso ATRAPA al
   marco (aunque sea `position:fixed`) en un contexto que vale 1 frente al resto
   de la página, así que el 700 nunca llegaba a competir. Comprobado con
   `elementFromPoint(30,230)`: devolvía un botón del riel, encima del focus.
   La salida es subir el contexto que de verdad bloqueaba, y sólo mientras
   contiene el focus: reactivo, sin JS, se revierte solo al quitar la clase.
   700 iguala al marco y ya gana al riel (200) y a `.tx-top` (650). */
#moduleContent:has(.lk-focus){z-index:700}

/* ── EL VELO ────────────────────────────────────────────────────────────────
   AG-IND-12(a), decidida (spec-AGENDA-FOCUS-VELO, 20-ago-2026, palabras
   textuales de Cristián): «cubre todo, riel incluido. Nada de atrás compite ni
   se puede pulsar; se sale con Esc o con el botón de salir.»

   Va como PRIMER hijo del marco. Visible/oculto por `display`, nunca por
   `opacity` — R1: así jamás puede quedar en `opacity:0` con los punteros
   activos (20-ago: un overlay animado se clavó así e, invisible, se tragó los
   clics de toda la pantalla).

   Empieza donde acaba la barra del módulo, no en `inset:0`
   (spec-AGENDA-FOCUS-Y-HOVER, 23-ago-2026, textual: «no atenues la topbar»).
   El 56 va literal y con esta cita: NO sale de `--lk-layout-top-h` (52px), que
   es el token de la barra del CHASIS; la barra de MÓDULO es `.lk-modulebar` y
   mide 56px fijos con `!important` (core/css/lk-components.css). Los dos no
   casan y usar el token equivocado dejaría una franja de 4px.

   `z-index:-1` — CORRECCIÓN (02-sep-2026, hipótesis A del encargo, confirmada
   con una captura real de Chrome antes/después, no supuesta): "ser primer
   hijo" NO bastaba para pintar detrás. El velo es `position:fixed` con
   z-index:auto; por el orden de pintado de CSS2.1 §E, los descendientes
   POSICIONADOS con z-index:auto/0 pintan DESPUÉS que los NO posicionados,
   sin importar el orden del DOM — y `.grid-card` (agenda), `.rv-body`/
   `.rv-lista` (reservas) no declaran `position`. El velo pintaba ENCIMA del
   contenido, no detrás: eso era el oscurecimiento que reportó Cristián, no
   sólo el margen. `.lk-focus` ya es su propio contexto de apilado
   (`position:fixed;z-index:700`, arriba), así que -1 es seguro: no se escapa
   de él, sólo lo manda al fondo de ESE contexto — antes que cualquier
   descendiente no posicionado, que es lo que hacía falta. */
.lk-focus-velo{display:none}
.lk-focus.lk-focus .lk-focus-velo{
  display:block;position:fixed;top:56px;right:0;bottom:0;left:0;z-index:-1;
  background-color:var(--lk-overlay, rgba(0,0,0,.52));
  /* FRANJA DEL RIEL, no toda la pantalla (02-sep-2026, palabras textuales de
     Cristián sobre el resultado anterior: «oscureces las celdas??? … te pedi
     que resaltaras el contenido … no que lo hicieras invisible»). Con el
     apilamiento corregido arriba, el contenido de cada módulo YA pinta
     encima del velo — subir la opacidad general para tapar el riel ya no
     hacía falta ahí, y sólo empeoraba el margen (que sí queda expuesto,
     nunca lo tapa un `.grid-card`/`.rv-lista`). Se acota la capa extra a la
     columna del riel, con el mismo ancho que ya usa el chasis
     (`--lk-layout-rail-w`, core/css/lk-layout.css) en vez de un número
     inventado, y con un corte duro (sin degradado) porque no es un efecto
     visual: es una tapa. Dos capas MÁS ahí, sobre la de base = tres en total
     en esa franja, 1-(1-.52)³ ≈ .89 (la misma cuenta del 02-sep, sólo que ya
     no se paga en todo el velo); el resto queda en una sola capa, ~.52,
     que es «aire», no un marco. Medido con captura real: el ícono del riel
     sigue sin leerse, y el resto del contenido ya no se ve apagado.
     Ningún hexadecimal nuevo: mismo `--lk-overlay` repetido. */
  background-image:
    linear-gradient(to right,
      var(--lk-overlay, rgba(0,0,0,.52)) 0, var(--lk-overlay, rgba(0,0,0,.52)) var(--lk-layout-rail-w, 52px),
      transparent var(--lk-layout-rail-w, 52px), transparent 100%),
    linear-gradient(to right,
      var(--lk-overlay, rgba(0,0,0,.52)) 0, var(--lk-overlay, rgba(0,0,0,.52)) var(--lk-layout-rail-w, 52px),
      transparent var(--lk-layout-rail-w, 52px), transparent 100%);
}


/* ── css/lk-dropdown.css ── */
/* ═══════════════════════════════════════════════════════════════════════════
   lk-dropdown.css · MK-3 · primitiva de core: desplegable anclado a campo
   ───────────────────────────────────────────────────────────────────────────
   SOLO tokens --lk-*: los 3 temas se heredan de css/lk-tokens.css. Aquí NO se
   redefine ningún token.
   El velo (.lkdd-ov) es TRANSPARENTE a propósito: solo atrapa el clic de fuera.
   Un desplegable no es un modal; oscurecer detrás mentiría sobre su jerarquía.
   ═══════════════════════════════════════════════════════════════════════════ */

.lkdd-ov {
  position: fixed; inset: 0;
  z-index: calc(var(--lk-z-modal, 850) + 40);   /* por encima del frame de cita */
  background: transparent;
}

.lkdd {
  position: fixed;
  display: flex; flex-direction: column;
  max-height: min(60vh, 320px);
  padding: var(--lk-menu-pad);
  background: var(--lk-bg-card);
  border: var(--lk-menu-border) solid var(--lk-border);
  border-radius: var(--lk-menu-radius);
  box-shadow: var(--lk-shadow-lg, 0 24px 60px -12px rgba(0, 0, 0, .28));
  /* MEJORA 4 · NACE VISIBLE. La entrada anima SOLO el desplazamiento. Antes el
     fotograma 0% ponia opacity:0 y, con la linea de tiempo detenida -pestana en
     segundo plano, ahorro de energia, GPU ocupada-, el panel quedaba montado,
     clickeable e INVISIBLE. Mismo fallo que costo horas en el menu contextual
     y en los toasts. La opacidad no se anima nunca mas. */
  animation: lkdd-in .18s cubic-bezier(.32, .72, 0, 1);
}
@keyframes lkdd-in { from { transform: translateY(-6px); } to { transform: none; } }
@media (prefers-reduced-motion: reduce) { .lkdd { animation: none; } }

.lkdd * { box-sizing: border-box; }
.lkdd svg { fill: none; }

/* ── buscador ── */
.lkdd .lkdd-search {
  display: flex; align-items: center; gap: 8px;
  padding: 8px 9px; margin-bottom: 4px;
  background: var(--lk-bg-surface); border: .5px solid var(--lk-border);
  border-radius: 9px;
}
.lkdd .lkdd-search svg { width: 15px; height: 15px; flex-shrink: 0; color: var(--lk-text-faint); stroke: currentColor; }
.lkdd .lkdd-search input {
  flex: 1; min-width: 0; border: 0; background: transparent; outline: none;
  font: inherit; font-size: var(--lk-font-md, 13px); color: var(--lk-text-primary);
}

/* ── lista ── */
.lkdd .lkdd-list { overflow-y: auto; display: flex; flex-direction: column; gap: 2px; scrollbar-width: thin; }

/* Contrato pieza 2: item 9/10, radio 8, peso 500. `width:100%` con box-sizing
   heredado del bloque de arriba, asi que el hover mide el ANCHO INTERIOR del
   panel y nunca se desborda del relleno. */
.lkdd .lkdd-item {
  display: flex; align-items: center; gap: 10px; width: 100%;
  padding: var(--lk-menu-item-pad); border: 0; border-radius: var(--lk-menu-item-radius);
  background: transparent; color: var(--lk-text-primary);
  font: inherit; font-weight: 500; text-align: left; cursor: pointer;
  transition: background var(--lk-transition-fast, 120ms ease), color var(--lk-transition-fast, 120ms ease);
}
/* Hover con el color de ENFASIS, igual que el menu contextual: misma perilla,
   asi que los dos se mueven juntos. */
.lkdd .lkdd-item:hover { background: var(--lk-menu-hover-bg); color: var(--lk-menu-hover-fg); }
/* Destructivas: conservan su rojo tambien en el desplegable. */
.lkdd .lkdd-item.is-danger { color: var(--lk-red); }
.lkdd .lkdd-item.is-danger:hover { background: var(--lk-red-soft); color: var(--lk-red); }
.lkdd .lkdd-item:focus-visible { outline: 2px solid var(--lk-brand); outline-offset: -2px; }
.lkdd .lkdd-item.is-sel { background: var(--lk-bg-active); }
.lkdd .lkdd-item.is-dis { opacity: .45; cursor: default; }
.lkdd .lkdd-item.is-dis:hover { background: transparent; }

.lkdd .lkdd-ini {
  flex-shrink: 0; width: 28px; height: 28px; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--lk-brand-muted); color: var(--lk-brand-soft);
  font-size: var(--lk-font-xs, 11px); font-weight: 500;
}
.lkdd .lkdd-tx { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.lkdd .lkdd-lb { font-size: var(--lk-font-md, 13px); font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lkdd .lkdd-sub { font-size: var(--lk-font-xs, 11px); color: var(--lk-text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lkdd .lkdd-ck { flex-shrink: 0; display: flex; color: var(--lk-brand); }
.lkdd .lkdd-ck svg { width: 15px; height: 15px; stroke: currentColor; }

.lkdd .lkdd-empty {
  padding: 18px 12px; text-align: center;
  font-size: var(--lk-font-sm, 12px); color: var(--lk-text-muted);
}


/* ── MEJORA 5 · DOS VARIANTES, UNA SOLA PIEZA ───────────────────────────────
   No son dos componentes: es el mismo panel con un modificador.

   `selector`  · elige UN valor de una lista. Se ancla al ancho del disparador
                 para que la opcion elegida caiga justo sobre el campo, lleva
                 check a la derecha y admite filtro.
   `acciones`  · dispara COSAS distintas. Ancho propio segun su contenido, sin
                 check (no hay nada "elegido") e iconos a la izquierda.
   Sin modificador se comporta como `acciones`, que es el uso mayoritario.     */
.lkdd--selector { min-width: var(--lkdd-ancla, 212px); }
.lkdd--acciones { min-width: 212px; }
.lkdd--acciones .lkdd-ck { display: none; }

/* El check solo ocupa sitio cuando hay algo seleccionado; el hueco se reserva
   igual para que la fila no salte al elegir. */
.lkdd--selector .lkdd-item .lkdd-ck { visibility: hidden; }
.lkdd--selector .lkdd-item.is-sel .lkdd-ck { visibility: visible; }
.lkdd--selector .lkdd-item.is-sel { background: var(--lk-menu-active-bg); color: var(--lk-menu-active-fg); }


/* ── VARIANTE `--canto` · buscador sin recuadro, filas a ras de borde ─────────
   Decisión del dueño (01-ago-2026) tras comparar las dos caras lado a lado.
   La usa la FAMILIA DE CITA: creador, editor, visor y reagenda.

   Va como VARIANTE y no como cara global a propósito: `.lkdd` ya lo usa el
   menú de plantillas de Com Center, y su panel no tiene por qué moverse porque
   la familia de cita prefiera otra cara.

   Solo cambia el aspecto. El comportamiento —volteo si no cabe, filtro
   automático sobre 10 opciones, check de selección, teclado— es el mismo. */
.lkdd--canto { padding: 0; border-radius: 10px; overflow: hidden; }
.lkdd--canto .lkdd-search {
  margin: 0; padding: 9px 11px;
  border: 0; border-bottom: .5px solid var(--lk-border-soft); border-radius: 0;
  background: transparent;
}
.lkdd--canto .lkdd-list { border-top: 0; gap: 0; }
.lkdd--canto .lkdd-item { border-radius: 0; padding: 9px 11px; }


/* ── PIE DE ACCION (`cfg.cta`) · la salida cuando lo buscado no esta ──────────
   Va SEPARADO de la lista a proposito: no es una opcion mas, es "crear lo que
   no encontraste". Por eso lleva su propio canto superior y no se confunde con
   un resultado. Nace del creador de citas y sirve a cualquier buscador. */
.lkdd-cta {
  display: flex; align-items: center; gap: 10px; width: 100%;
  margin: 5px 0 0; padding: 9px 10px;
  border: 0; border-top: .5px solid var(--lk-border-soft);
  background: transparent; text-align: left; cursor: pointer; font: inherit;
  transition: background .14s ease;
}
.lkdd-cta:hover { background: var(--lk-bg-hover); }
.lkdd-cta:focus-visible { outline: 2px solid var(--lk-brand); outline-offset: -2px; }
/* SIN pastilla de color detras: el icono va suelto. La baldosa tenida competia
   con el propio texto de la accion y pesaba mas que ella. Se conserva la caja de
   30px para que el icono quede alineado con las iniciales de los resultados de
   arriba — quitarla desalinea la columna entera. */
.lkdd-cta-ic {
  flex: 0 0 auto; width: 30px; height: 30px;
  display: grid; place-items: center;
  color: var(--c-accent, var(--lk-brand));
}
.lkdd-cta-ic svg { width: 16px; height: 16px; }
.lkdd-cta-tx { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.lkdd-cta-t { font-size: calc(var(--font-base) * .962); font-weight: 500; color: var(--lk-text-primary); }
.lkdd-cta-s { font-size: calc(var(--font-base) * .846); color: var(--lk-text-muted); }
/* en la variante a canto el pie tambien llega al borde */
.lkdd--canto .lkdd-cta { margin: 0; padding: 9px 11px; }

/* ══ CARA DE TELÉFONO · LA HOJA ═══════════════════════════════════════════════
   Mockup `docs/disenos/mockup-selector-hoja.html`, APROBADO 16-ago-2026.
   La clase la pone `lk-dropdown.js` cuando `LK.viewport.isPhone()`; no hay
   `@media` nuevo aquí, así que no se inventa ningún corte (RESP-04) y el corte
   sigue decidiéndolo el chasis (RESP-03).

   Medidas tomadas de la hoja canónica `#shellSheet`
   (`core/css/lk-layout.css:251-266`), que es la aprobada el 4-ago: radio 18
   arriba, tirador de 38×4 con radio 3, y el colchón inferior con la safe-area.

   ⚠️ LO QUE **NO** SE COPIA DE `#shellSheet`, Y POR QUÉ:
   su `transform: translateY(101%)` en reposo. Esa hoja vive SIEMPRE montada y
   sólo conmuta una clase, así que puede permitirse reposar fuera de la pantalla.
   Ésta se CREA al abrirse, y una pieza que nace fuera y entra por animación
   queda invisible si la línea de tiempo está detenida —pestaña en segundo plano,
   ahorro de energía—: medido y pagado dos veces en este repo (el creador de
   citas entraba desde abajo y quedaba «arriba 737 en un alto de 737»; y el
   propio `lkdd-in` de más arriba lleva escrita la misma lección). Por eso el
   reposo es VISIBLE y la animación sólo MUEVE 14px, igual que se corrigió allí.

   Sin desenfoque propio: en teléfono el único con `backdrop-filter` es el dock. */
/* ⚠️ ESTO NO CONTRADICE LA CABECERA DE ESTE ARCHIVO, LA ACOTA.
   Arriba está escrito que `.lkdd-ov` es transparente a propósito, porque «un
   desplegable no es un modal; oscurecer detrás mentiría sobre su jerarquía». Esa
   decisión sigue intacta y vale para el panel anclado, que es lo que se ve de 640
   para arriba. Pero en teléfono esto YA NO es un desplegable anclado: es la hoja
   del sistema, ocupa el borde inferior a ancho completo y toma el foco de la
   pantalla. Todas las hojas del chasis van con velo (`#shellScrim`, negro al 42%),
   y una hoja SIN velo es la que mentiría — no se sabría qué queda vivo detrás ni
   que tocar fuera la cierra. */
.lkdd-ov--hoja { background: rgba(0, 0, 0, .42); }   /* el velo del chasis, #shellScrim */

.lkdd--hoja {
  left: 0; right: 0; bottom: 0; top: auto;
  width: auto; max-width: none;
  /* `dvh` y no `vh` · RESP-15: `vh` mide contra el viewport grande mientras la
     hoja está clavada al pequeño, así que con la barra del navegador a la vista
     la hoja se pasa de alto. */
  max-height: 74dvh;
  border: 0; border-top: .5px solid var(--lk-border-soft);
  border-radius: 18px 18px 0 0;
  padding: 8px 14px calc(24px + env(safe-area-inset-bottom, 0px));
  /* TRANSICIÓN, no `animation` · el JS añade `is-puesta` tras un reflow síncrono.
     Una animación en curso gana a los estilos en línea y dejaba el arrastre sin
     efecto durante sus primeros 260ms; y `LK.sheet` cuenta con esta `transition`
     para devolver la hoja a su sitio al soltar un arrastre corto. Reposo a 14px:
     visible aunque la transición no llegue a correr. */
  transform: translateY(14px);
  transition: transform var(--lk-dur-3, .26s) cubic-bezier(.32, .72, 0, 1);
  animation: none;
}
.lkdd--hoja.is-puesta { transform: none; }
@media (prefers-reduced-motion: reduce) { .lkdd--hoja { transition: none; } }

/* MATERIAL DE HOJA, NO DE MENÚ · `[data-mode="glass"] .lkdd` (lk-glass.css:75)
   le daba 62% de transparencia y `backdrop-filter`, y ese archivo va DESPUÉS en
   el bundle, así que ganaba: la hoja salía desenfocada justo bajo un comentario
   que prometía lo contrario. Se gana con especificidad (0,3,0 contra 0,2,0), no
   con `!important`. El dock sigue siendo el único con desenfoque en teléfono, y
   `#shellSheet` se sacó de esa familia el 4-ago por esta misma razón. */
[data-mode="glass"] .lkdd.lkdd--hoja,
[data-mode="tint"] .lkdd.lkdd--hoja,
.lkdd.lkdd--hoja {
  background: var(--lk-bg-card-solid, var(--lk-bg-card));
  -webkit-backdrop-filter: none; backdrop-filter: none;
  box-shadow: 0 -18px 44px rgba(0, 0, 0, .42);
}

/* El tirador, misma medida que #shellSheet .sheet-grab */
.lkdd--hoja::before {
  content: ''; display: block; flex: 0 0 auto;
  width: 38px; height: 4px; border-radius: 3px;
  background: var(--lk-border); margin: 2px auto 12px;
}

/* El rótulo · dice QUÉ se está eligiendo. En el panel anclado sobraba porque el
   campo quedaba justo debajo; en una hoja a pantalla completa, sin él no se sabe.
   Mismo tratamiento que `#shellSheet .sheet-title`. */
.lkdd--hoja .lkdd-hoja-t {
  font-size: var(--lk-font-sm, 12px); text-transform: uppercase; letter-spacing: .06em;
  color: var(--lk-text-muted); padding: 0 4px 8px;
}

/* El buscador respira y deja de ser una línea apretada de escritorio */
.lkdd--hoja .lkdd-search { padding: 10px 11px; margin-bottom: var(--lk-space-2, 8px); }
.lkdd--hoja .lkdd-search input { font-size: var(--lk-font-md, 13px); }

/* RESP-13 · el gesto no se escapa al documento mientras se arrastra la hoja */
.lkdd--hoja .lkdd-list { overscroll-behavior: contain; }

/* RESP-14 · blanco de toque. Aquí SÍ crece el alto de la fila: en una lista de
   nombres la fila ES el blanco, no hay un icono pequeño al que colgarle un
   pseudo-elemento, y 44px de fila no se leen como un botón grotesco. */
.lkdd--hoja .lkdd-item,
.lkdd--hoja .lkdd-cta { min-height: 44px; }


/* ── css/lk-datepicker.css ── */
/* core/css/lk-datepicker.css · MK-3 · hoja de LK.datepicker
   LUZOcrm V2 / TRANSED ONG

   Portada de `modules/agenda/styles/agenda.css:440-478`, donde el calendario
   vivía encerrado bajo el namespace `.agw` del módulo. Aquí pierde ese prefijo
   —es de la casa, no de Agenda— y conserva TODO lo demás: alturas, radios,
   tamaños y el mismo juego de estados. Ver la cabecera de `core/lk-datepicker.js`
   para la deuda declarada: Agenda sigue con su copia hasta que su hilo cierre.

   Lo ÚNICO que Agenda no necesitaba es el RANGO: allí se elige una semana, aquí
   un intervalo. Se resuelve con el mismo lenguaje de la casa —marca suave para
   el tramo, marca sólida en los dos extremos— sin inventar ningún color.
   Aprobado sobre `mockups/mockup-fecha-personalizada-25ago.html`. */

.lkdp { padding: 9px; border-radius: 10px; background: var(--lk-bg-surface); border: .5px solid var(--lk-border-soft) }

/* ── cabecera: ‹ 2026 Agosto › ─────────────────────────────────────────────── */
.lkdp-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 10px }
.lkdp-nav { width: 28px; height: 28px; border: 0; background: transparent; border-radius: 8px; display: grid; place-items: center; color: var(--lk-text-muted); cursor: pointer }
.lkdp-nav:hover { background: var(--lk-bg-hover) }
.lkdp-nav svg { width: 14px; height: 14px }
.lkdp-crumbs { display: flex; align-items: baseline; gap: 5px }
.lkdp-crumb { font: inherit; background: transparent; border: 0; cursor: pointer; border-radius: 6px; padding: 2px 5px; color: var(--lk-text-muted); font-size: calc(var(--font-base) * .92) }
.lkdp-crumb:hover { background: var(--lk-bg-hover); color: var(--lk-text-primary) }
.lkdp-crumb.is-nivel { color: var(--lk-text-primary); font-weight: 600; font-size: calc(var(--font-base) * 1.03) }

/* ── rejilla de días ───────────────────────────────────────────────────────── */
.lkdp-dow { display: grid; grid-template-columns: repeat(7, 1fr); margin-bottom: 2px }
.lkdp-dow span { text-align: center; font-size: calc(var(--font-base) * .70); text-transform: uppercase; letter-spacing: .04em; color: var(--lk-text-muted); padding: 2px 0 }
.lkdp-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px 0 }
.lkdp-dia {
  height: 32px; display: grid; place-items: center; border: 0; border-radius: 8px;
  font: inherit; font-size: calc(var(--font-base) * .87); color: var(--lk-text-primary);
  font-variant-numeric: tabular-nums; background: transparent; cursor: pointer;
}
.lkdp-dia:hover { background: var(--lk-bg-hover) }
.lkdp-dia:focus-visible { outline: 2px solid var(--lk-brand-border); outline-offset: -2px }
.lkdp-dia.is-otromes { color: var(--lk-text-muted); opacity: .55 }
.lkdp-dia.is-hoy { box-shadow: inset 0 0 0 1.5px var(--lk-brand) }
/* Fuera de min/max: se ve, pero no se puede elegir. Se muestra en vez de
   esconderse para que el mes no cambie de forma según el rango permitido. */
.lkdp-dia.is-fuera { color: var(--lk-text-faint); opacity: .4; cursor: default; pointer-events: none }

/* ── EL RANGO · lo único que no venía de Agenda ────────────────────────────── */
.lkdp-dia.en-rango { background: color-mix(in srgb, var(--lk-brand) 14%, transparent); border-radius: 0 }
.lkdp-dia.extremo { background: var(--lk-brand); color: var(--lk-on-brand, #fff); font-weight: 600 }
.lkdp-dia.extremo.ini { border-radius: 8px 0 0 8px }
.lkdp-dia.extremo.fin { border-radius: 0 8px 8px 0 }
.lkdp-dia.extremo.solo { border-radius: 8px }
/* El aro de «hoy» se apaga dentro del rango: sobre el relleno de marca no se
   distingue, y dos marcas peleando por la misma celda no dicen ninguna. */
.lkdp-dia.extremo.is-hoy { box-shadow: inset 0 0 0 1.5px var(--lk-bg-card), inset 0 0 0 3px var(--lk-brand) }

/* ── niveles mes y año ─────────────────────────────────────────────────────── */
.lkdp-meses, .lkdp-anios { display: grid; grid-template-columns: repeat(4, 1fr); gap: 5px }
.lkdp-celda {
  height: 46px; display: grid; place-items: center; border: 0; border-radius: 9px;
  font: inherit; font-size: calc(var(--font-base) * .88); color: var(--lk-text-primary);
  background: transparent; cursor: pointer; text-transform: capitalize;
}
.lkdp-celda:hover { background: var(--lk-bg-hover) }
.lkdp-celda:focus-visible { outline: 2px solid var(--lk-brand-border); outline-offset: -2px }
.lkdp-celda.is-hoy { box-shadow: inset 0 0 0 1.5px var(--lk-brand) }
.lkdp-celda.is-elegido { background: var(--lk-brand); color: var(--lk-on-brand, #fff); font-weight: 600 }
.lkdp-celda.is-elegido.is-hoy { box-shadow: inset 0 0 0 1.5px var(--lk-bg-card), inset 0 0 0 3px var(--lk-brand) }

/* ── pie: cuántos días abarca, y el atajo «Hoy» ────────────────────────────── */
.lkdp-foot { display: flex; justify-content: space-between; align-items: center; gap: 8px; margin-top: 9px; padding-top: 8px; border-top: .5px solid var(--lk-border-soft) }
.lkdp-rango-txt { font-size: calc(var(--font-base) * .83); color: var(--lk-text-muted); font-variant-numeric: tabular-nums; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap }
.lkdp-hoy-btn { font: inherit; font-size: calc(var(--font-base) * .83); font-weight: 600; color: var(--lk-brand); background: var(--lk-brand-muted); border: 0; border-radius: 7px; padding: 5px 11px; cursor: pointer; flex: none }
.lkdp-hoy-btn:hover { filter: brightness(1.06) }

/* ── variante flotante (LK.datepicker.abrir) ───────────────────────────────── */
.lkdp-flotante { z-index: var(--lk-z-modal, 850); width: 258px }
.lkdp-flotante .lkdp { background: var(--lk-bg-card); border-color: var(--lk-border); box-shadow: 0 18px 44px rgba(0, 0, 0, .34) }


/* ── css/lk-ctx.css ── */
/* ══════════════════════════════════════════════════════════════════════════════
   core/css/lk-ctx.css · MK-3 · menú contextual de acciones (LK.ctx)
   LUZOcrm V2 / TRANSED ONG

   Fisonomía heredada de la agenda — el gesto que ya gustaba: entrada con resorte
   desde la esquina apuntada, fila que se corre 2px al pasar, rótulo de sección en
   versalitas, acción destructiva en rojo solo al tocarla.

   El acento es una variable: por defecto la marca, pero cada módulo puede fijar
   el suyo sin tocar este archivo ni duplicar el componente:
       .agw { --lkctx-accent: var(--ag); --lkctx-accent-soft: var(--ag-muted); }
   ══════════════════════════════════════════════════════════════════════════════ */

.lkctx{
  --lkctx-accent:      var(--lk-brand);
  --lkctx-accent-soft: var(--lk-brand-muted);

  position: fixed;
  z-index: 9500;                      /* sobre modales (8000), bajo toasts (9990) */
  min-width: 200px;                   /* molde .rv-tbm (Reservas · referencia congelada) */
  max-width: 300px;
  padding: var(--lk-menu-pad);
  /* vidrio legible: translucido pero con opacidad alta para leer el texto (pedido usuario) */
  background: color-mix(in srgb, var(--lk-bg-card-solid, var(--lk-bg-card)) 85%, transparent);
  -webkit-backdrop-filter: blur(24px) saturate(180%);
  backdrop-filter: blur(24px) saturate(180%);
  border: var(--lk-menu-border) solid var(--lk-border);
  border-radius: var(--lk-menu-radius);
  box-shadow: var(--lk-shadow-md);
  font-family: var(--lk-font-sans);

  /* ★ VISIBLE Y USABLE DESDE QUE EXISTE. No se negocia.
     Antes el panel nacia con opacity:0 / pointer-events:none y solo se encendia al
     recibir .is-on, con una transicion de opacidad. Eso ataba QUE SE VEA a que la
     linea de tiempo de animaciones del navegador avance. Cuando no avanza -pestana
     en segundo plano, ahorro de energia, timeline detenida, GPU ocupada- la
     transicion queda detenida en tiempo 0 y CONGELA la opacidad en 0: el menu
     queda montado, con sus acciones, clickeable... e invisible. Medido en Chrome
     sobre el modulo real de P360. Era la causa de que el clic secundario pareciera
     no hacer nada, y el motivo por el que el consumidor forzaba estilos inline.
     Un menu que aparece cuando el usuario lo pide no puede depender de que haya
     cuadros de animacion disponibles. */
  opacity: 1;
  pointer-events: auto;
  transform-origin: top left;
  /* La entrada es adorno y toca SOLO el transform: si la linea de tiempo esta
     detenida, lo peor que pasa es que el panel se vea 4% mas chico y 4px arriba.
     Visible y usable igual. La opacidad no se anima nunca mas. */
  animation: lkctx-entra .18s cubic-bezier(.34,1.56,.64,1);
}
@keyframes lkctx-entra{
  from{ transform: scale(.96) translateY(-4px); }
  to  { transform: none; }
}
/* .is-on se conserva por compatibilidad con quien la consulte; ya no decide nada. */
.lkctx.is-on{
  opacity: 1;
  pointer-events: auto;
}

/* Encabezado: el contexto de lo que se apuntó ("miércoles · 11:00") */
.lkctx-title{
  padding: 6px 10px 8px;
  margin-bottom: 4px;
  border-bottom: 1px solid var(--lk-border-soft);
  font-size: var(--lk-font-sm);
  font-weight: 600;
  color: var(--lk-text-primary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Rótulo de sección */
.lkctx-head{
  padding: 5px 10px 3px;
  font-size: calc(var(--font-base) * 0.731);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .05em;
  color: var(--lk-text-faint);
}

.lkctx-sep{
  height: 1px;
  margin: 5px 8px;
  background: var(--lk-border);   /* paleta P360: separador visible, no fantasma */
}

/* Fila de acción */
.lkctx-it{
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 8px 10px;
  border-radius: 7px;
  font: 500 calc(var(--font-base) * 0.962)/1 var(--lk-font-sans);
  color: var(--lk-text-secondary);
  cursor: pointer;
  user-select: none;
  transition: background .12s ease, color .12s ease, transform .1s ease;
}
/* HOVER CON EL COLOR DE ENFASIS · decision del dueno (31-jul-2026).
   Nota de historia: el 30-jul se habia puesto NEUTRO al adoptar la paleta de
   P360, con el argumento de reservar el acento para lo activo. El dueno lo
   reviso en uso y pidio el acento; manda su ojo. Se lee de la perilla comun
   --lk-menu-hover-*, asi que cambia a la vez en menu contextual y desplegable.
   Las acciones destructivas NO entran: su regla va mas abajo y conserva el rojo. */
.lkctx-it:hover,
.lkctx-it:focus-visible{
  background: var(--lk-menu-hover-bg);
  color: var(--lk-menu-hover-fg);
  transform: translateX(2px);
}
.lkctx-it:focus-visible{
  outline: none;
  box-shadow: var(--lk-ring-focus);
}

.lkctx-ic{
  flex: 0 0 auto;
  width: 15px;
  height: 15px;
  display: grid;
  place-items: center;
  opacity: .85;
}
.lkctx-ic svg{ width: 15px; height: 15px; display: block; }

.lkctx-lb{
  flex: 1 1 auto;
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Atajo o dato al margen ("⌘K", "Pronto") — molde .rv-tbm-soon */
.lkctx-hint{
  flex: 0 0 auto;
  margin-left: auto;
  padding: 2px 7px;
  border: .5px solid var(--lk-border-soft);
  border-radius: 20px;
  background: var(--lk-bg-surface);
  font-size: calc(var(--font-base) * 0.731);
  font-weight: 600;
  letter-spacing: .04em;
  color: var(--lk-text-faint);
  font-variant-numeric: tabular-nums;
}

/* Accion destructiva: ROJA YA EN REPOSO (contrato pieza 1, paleta de P360).
   Antes era neutra y solo se tenia al pasar el raton, asi que la unica senal de
   "esto borra" aparecia cuando el puntero ya estaba encima. Se avisa antes. */
.lkctx-it.is-danger{
  color: var(--lk-red);
}
.lkctx-it.is-danger .lkctx-ic{
  color: var(--lk-red);
}
.lkctx-it.is-danger:hover,
.lkctx-it.is-danger:focus-visible{
  background: var(--lk-red-soft);
  color: var(--lk-red);
}

/* MEJORA 3 · MOTIVO DEL DESHABILITADO.
   Un item apagado sin explicacion deja al usuario adivinando si es un permiso,
   un estado del paciente o un fallo. La razon va DEBAJO del item, alineada con
   su etiqueta (34px = 10 de relleno + 15 de icono + 9 de hueco). */
.lkctx-why{
  padding: 0 10px 7px 34px;
  margin-top: -2px;
  /* SUELO DE 11px: --font-base es ajustable por el usuario (A- lo baja a 11.7px) y
     un factor puro dejaba el motivo en 9px. Medido: ilegible. */
  font-size: max(11px, calc(var(--font-base) * 0.85));
  line-height: 1.35;
  /* --lk-text-faint daba 2.5:1 sobre el panel, bajo el minimo AA de 4.5:1. El
     motivo es informacion, no decoracion: tiene que leerse. */
  color: var(--lk-text-muted);
}

.lkctx-it.is-disabled{
  color: var(--lk-text-faint);
  cursor: default;
  opacity: .6;
}
.lkctx-it.is-disabled:hover{
  background: transparent;
  color: var(--lk-text-faint);
  transform: none;
}

/* Estado activo (opción ya aplicada) */
.lkctx-it.is-checked .lkctx-ic{ color: var(--lkctx-accent); opacity: 1; }

@media (prefers-reduced-motion: reduce){
  /* Sin movimiento: se entra de golpe. La visibilidad NO depende de esto. */
  .lkctx{ animation: none; transform: none; }
  .lkctx.is-on{ transform: none; }
  .lkctx-it{ transition: none; }
  .lkctx-it:hover, .lkctx-it:focus-visible{ transform: none; }
}


/* ── css/lk-tooltip.css ── */
/* ══════════════════════════════════════════════════════════════════════════════
   core/css/lk-tooltip.css · Tooltip canónico · LUZOcrm
   ──────────────────────────────────────────────────────────────────────────────
   Encargo textual de Cristián (16-ago-2026): un tooltip ÚNICO para todo el CRM,
   moderno/elegante/sutil, con el color saliendo del tema. La lógica vive en
   core/lk-tooltip.js (delegación en `document`, un solo nodo movido de icono en
   icono); esta hoja sólo dibuja ese nodo compartido.

   Sólo tokens que YA existen en lk-tokens.css — ese fichero no se tocó, así que
   no hace falta el ACK de artefacto protegido. Superficie/borde/sombra son los
   mismos que usan el menú contextual (lk-ctx.css) y el pop de apariencia: el
   tooltip se siente de la misma familia visual, no una pieza aparte inventada.

   z-index 9600, medido contra lo que ya existe en el árbol (no un número al
   azar): por encima del menú contextual (`.lkctx`, 9500 — lk-ctx.css) y de la
   tarjeta de SmartView (`.sv-tt-portal`, 9000 — lk-sv.css): un tooltip tiene
   que verse SIEMPRE sobre lo que señala, sea lo que sea que haya debajo. Por
   debajo del overlay de Spotlight (9999 — lk-spotlight.css), que es modal y no
   debe quedar tapado por una etiqueta de paso.

   Sin arco/flecha apuntando al ancla: los sistemas modernos de referencia (el
   propio `.lkctx` de esta casa incluido) ya prescinden de ella — es un adorno
   menos, y "sutil" pide menos, no más.

   MOVIMIENTO: transición CSS normal con los tokens de lk-motion.css. No hace
   falta un bloque de prefers-reduced-motion propio aquí — esa hoja ya apaga
   TODA animación/transición del sistema con un selector `*` global, tanto para
   el ajuste del sistema operativo como para el interruptor manual de Apariencia
   (`html[data-motion="reduced"]`). Duplicarlo en cada componente nuevo es
   exactamente la sobreingeniería que la casa prohíbe.
   ══════════════════════════════════════════════════════════════════════════════ */

.lktt{
  position: fixed;
  z-index: 9600;
  max-width: 240px;
  padding: 5px 9px;

  /* 16-ago-2026 · Cristián: «pero con algo de glass para el modo glass». No hace
     falta un selector `[data-mode="glass"]` aquí: el sistema YA declara el material
     de una capa flotante en `lk-tokens.css` y lo define SÓLO dentro de ese modo
     (`--lk-fill-menu`, `--lk-surface-blur`). Consumiéndolos con caída, el vidrio
     aparece en glass y en los demás modos queda el sólido de siempre — una regla,
     los cinco modos, y si mañana se ajusta la transparencia del sistema este
     tooltip la sigue sin tocarlo. Es la perilla única que el propio fichero de
     tokens pide usar. */
  background: var(--lk-fill-menu, var(--lk-bg-card-solid, var(--lk-bg-card)));
  -webkit-backdrop-filter: var(--lk-surface-blur, none);
  backdrop-filter: var(--lk-surface-blur, none);
  color: var(--lk-text-primary);
  border: .5px solid var(--lk-border);
  border-radius: var(--lk-radius-sm);
  box-shadow: var(--lk-shadow-sm);

  font-family: var(--lk-font-sans);
  font-size: var(--lk-font-xs);
  font-weight: 500;
  line-height: 1.35;
  /* 16-ago-2026 · se quita `overflow:hidden` + `text-overflow:ellipsis`, y NO por
     gusto: el pico del globo es un pseudo-elemento que sobresale del cuerpo, y con
     `overflow:hidden` quedaba recortado justo en la parte que asoma — o sea, no se
     veía. Como el texto de un tooltip es el nombre de un módulo o de una función,
     lo correcto cuando no cabe es que envuelva en dos líneas dentro de sus 240 px,
     no que se corte con puntos suspensivos: un nombre truncado no identifica nada,
     que es lo único que este tooltip existe para hacer. */
  white-space: normal;
  overflow-wrap: anywhere;

  /* Oculto hasta que lk-tooltip.js añade .lktt-on. El nodo se monta en <body>
     SÓLO al mostrarse (y se desmonta al ocultarse) — nunca queda de fondo con
     opacity:0 esperando; ver lk-ctx.css para el porqué de esa distinción (una
     línea de tiempo de animación pausada podría congelar la opacidad en 0).
     Aquí el riesgo no aplica igual —sólo se muestra con la pestaña activa, tras
     un hover o un tab real— pero igual se monta bajo demanda, no queda vivo. */
  opacity: 0;
  transform: translateY(4px);
  transition: opacity var(--lk-dur-1) var(--lk-ease-out),
              transform var(--lk-dur-1) var(--lk-ease-out);
  pointer-events: none;   /* nunca intercepta el puntero: no compite con lo que señala */
}
/* Anclado debajo del icono (sin sitio arriba, ver lk-tooltip.js::_place):
   entra desde arriba en vez de desde abajo, mismo gesto, otro origen. */
.lktt.lktt-abajo{ transform: translateY(-4px); }
.lktt.lktt-on{
  opacity: 1;
  transform: translateY(0);
}

/* ══════════════════════════════════════════════════════════════════════════════
   EL PICO · opción B del mockup aprobado (`mockups/mockup-tooltip-globo.html`),
   elegida por Cristián: «B» sobre las cinco formas presentadas.

   Un cuadrado girado 45°, no un triángulo de bordes: así hereda el MISMO relleno
   y el MISMO borde que el cuerpo, incluido el vidrio del modo glass. Un triángulo
   hecho con `border-color` no puede llevar borde propio ni desenfoque, y en glass
   se habría visto como una cuña opaca pegada a un globo translúcido.

   Sólo se pintan DOS de sus cuatro lados —los que quedan hacia fuera al girar—:
   los otros dos caerían encima del cuerpo y dibujarían una costura.

   `--lktt-pico` la escribe `lk-tooltip.js::_place` con el centro real del icono,
   porque el globo se recorta contra el margen de la pantalla y un `50%` fijo
   apuntaría al vacío justo en los iconos del riel. Su caída al 50% es sólo por si
   alguien pinta un `.lktt` a mano sin pasar por el posicionador.
   ══════════════════════════════════════════════════════════════════════════════ */
.lktt::after{
  content: '';
  position: absolute;
  left: var(--lktt-pico, 50%);
  width: 8px; height: 8px;
  background: inherit;
  border-radius: 1.5px;
  transform: translateX(-50%) rotate(45deg);
  pointer-events: none;
}
/* Anclado ARRIBA del icono (el caso normal): el pico sale por abajo. */
.lktt::after{
  bottom: -4.5px;
  border-right: .5px solid var(--lk-border);
  border-bottom: .5px solid var(--lk-border);
}
/* Anclado DEBAJO: el pico sale por arriba y cambian los dos lados visibles. */
.lktt.lktt-abajo::after{
  bottom: auto; top: -4.5px;
  border-right: 0; border-bottom: 0;
  border-left: .5px solid var(--lk-border);
  border-top: .5px solid var(--lk-border);
}


/* ── css/lk-module.css ── */
/* ══════════════════════════════════════════════════════════════════════════════
   lk-module.css — MOLDE ESTÁNDAR DE MÓDULO · quietly modern (RESP-02)
   Lenguaje: Apple HIG (claridad · deferencia · profundidad). Un solo esqueleto que
   todos los módulos heredan → consistencia. Superficie continua sobre --bg-body;
   la jerarquía la cargan tipografía y espacio, no bandas ni divisores.
   El módulo vive DENTRO del shell: NO maneja safe-area (la maneja el chasis) y NO
   flota sobre el dock. Responde a SU ancho vía container-query (root .lkm), robusto
   al estado del rail. Alcance de diseño: móvil + tablet. Reservas/Operaciones
   (UI congelada) NO adoptan esto hasta descongelarse.
   ══════════════════════════════════════════════════════════════════════════════ */

.lkm {
  container-type: inline-size; container-name: lkmod;
  background: var(--bg-body); color: var(--tx-base);
  min-height: 100%;
  /* elevación en dos capas, por tema */
  --lkm-elev: 0 1px 2px rgba(15,23,42,.05), 0 8px 20px -10px rgba(15,23,42,.16);
}
[data-theme="darkmode"] .lkm, [data-theme="midnight"] .lkm {
  --lkm-elev: 0 1px 2px rgba(0,0,0,.5), 0 12px 26px -12px rgba(0,0,0,.6);
}
.lkm-page { padding: 12px 22px 30px; display: flex; flex-direction: column; gap: 14px; max-width: 720px; margin: 0 auto; }

/* ── Cabecera: large title estático + acción sólida (bar-button) ── */
.lkm-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; }
.lkm-titles { min-width: 0; }
.lkm-title { font-size: calc(var(--font-base) * 1.923); font-weight: 700; letter-spacing: -.02em; margin: 0; color: var(--tx-base); line-height: 1.1; }
.lkm-sub { font-size: calc(var(--font-base) * 0.962); color: var(--tx-muted); margin: 3px 0 0; }
.lkm-new {
  border: none; background: var(--c-accent); color: #fff; font: inherit; font-size: calc(var(--font-base) * 1.0); font-weight: 600;
  cursor: pointer; height: 34px; padding: 0 14px; border-radius: 11px; display: inline-flex; align-items: center; gap: 6px;
  flex-shrink: 0; margin-top: 2px; box-shadow: 0 4px 12px -3px var(--c-accent), 0 1px 2px rgba(0,0,0,.22);
  transition: transform .12s, box-shadow .14s, filter .14s;
}
.lkm-new:hover  { filter: brightness(1.06); box-shadow: 0 7px 18px -4px var(--c-accent), 0 1px 2px rgba(0,0,0,.22); }
.lkm-new:active { transform: translateY(1px); }
.lkm-new svg { width: 15px; height: 15px; }

/* ── Resumen cohesivo: UNA superficie con divisores finos (no cifras sueltas) ── */
.lkm-summary { background: var(--bg-card); border-radius: 15px; box-shadow: var(--lkm-elev); display: grid; grid-template-columns: repeat(3,1fr); overflow: hidden; }
.lkm-sm { padding: 13px 15px; display: flex; flex-direction: column; gap: 3px; position: relative; }
.lkm-sm + .lkm-sm::before { content: ""; position: absolute; left: 0; top: 12px; bottom: 12px; width: 1px; background: var(--border-soft); }
.lkm-sm-v { font-size: calc(var(--font-base) * 1.538); font-weight: 700; font-variant-numeric: tabular-nums; color: var(--tx-base); line-height: 1; }
.lkm-sm-k { font-size: calc(var(--font-base) * 0.885); color: var(--tx-muted); }

/* ── Segmentado iOS (pill group, seleccionado elevado) ── */
.lkm-seg { display: inline-flex; align-self: flex-start; background: var(--bg-surface); border: 1px solid var(--border-soft); border-radius: 10px; padding: 3px; gap: 2px; }
.lkm-sg { border: none; background: none; color: var(--tx-muted); font: inherit; font-size: calc(var(--font-base) * 1.0); font-weight: 500; padding: 6px 14px; border-radius: 8px; cursor: pointer; transition: color .13s, background .13s; }
.lkm-sg.on { background: var(--bg-card); color: var(--tx-base); box-shadow: 0 1px 3px rgba(0,0,0,.3); }

/* ── Encabezado de sección tenue (inset) ── */
.lkm-sec { font-size: calc(var(--font-base) * 0.885); color: var(--tx-muted); font-weight: 600; text-transform: uppercase; letter-spacing: .04em; padding: 2px 6px 0; }

/* ── Inset grouped list: UNA superficie + separadores finos inset ── */
.lkm-group { background: var(--bg-card); border-radius: 15px; box-shadow: var(--lkm-elev); overflow: hidden; }
.lkm-row { display: flex; align-items: center; gap: 13px; padding: 11px 15px; position: relative; transition: background .12s; }
.lkm-row:active { background: var(--bg-hover); }
.lkm-row + .lkm-row::before { content: ""; position: absolute; left: 60px; right: 0; top: 0; height: 1px; background: var(--border-soft); }
.lkm-rt { font-size: calc(var(--font-base) * 1.077); font-weight: 600; font-variant-numeric: tabular-nums; color: var(--tx-base); min-width: 40px; }
.lkm-rb { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.lkm-rn { font-size: calc(var(--font-base) * 1.077); font-weight: 500; color: var(--tx-base); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.lkm-rm { font-size: calc(var(--font-base) * 0.923); color: var(--tx-muted); display: flex; align-items: center; gap: 6px; }
.lkm-rd { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
.lkm-rd.ok   { background: var(--tx-green); }
.lkm-rd.warn { background: var(--tx-amber); }

/* ── Tablet (contenedor ≥640): inset grouped rinde mejor en ancho regular (HIG) ── */
@container lkmod (min-width: 640px) {
  .lkm-page { padding: 22px 36px 34px; gap: 16px; max-width: 700px; }
  .lkm-title { font-size: calc(var(--font-base) * 2.154); }
}


/* ── css/lk-home.css ── */
/* ============================================================
   lk-home.css — Home del orbe (NAV-MOVIL)
   Port nativo del mockup. Todo tras [data-bp="phone"].
   Marca-agnóstico vía color-mix sobre --accent.
   Fuente manuscrita: cursivas del sistema (Caveat self-host = deuda).
   ============================================================ */

/* ── Orbe ── */
.orb-btn { width:34px;height:34px;border-radius:50%;display:grid;place-items:center;position:relative;
  background:var(--bg-surface);border:.5px solid var(--border);cursor:pointer;transition:transform .15s,background .15s,box-shadow .18s; }
.orb-btn:active { transform:scale(.92); }
.orb-core { width:19px;height:19px;border-radius:50%;position:relative;overflow:hidden;
  background:radial-gradient(circle at 37% 30%, color-mix(in srgb,var(--accent) 45%,white), var(--accent) 55%, color-mix(in srgb,var(--accent) 65%,black));
  box-shadow:0 0 8px -1px color-mix(in srgb,var(--accent) 55%,transparent); }
.orb-core::before { content:"";position:absolute;inset:0;border-radius:50%;
  background:linear-gradient(115deg,transparent 43%,rgba(255,255,255,.22) 50%,transparent 57%);
  background-size:220% 220%;animation:orbGlint 5.5s ease-in-out infinite; }
@keyframes orbGlint { 0%,100%{background-position:160% 160%} 50%{background-position:-60% -60%} }
.tb-orb { display:none; }
[data-bp="phone"] .tb-orb { display:grid; }
/* 34px a la vista, 44 de blanco de toque por fuera (RESP-14): el disco no crece,
   se extiende el hit-test con un ::before invisible. */
.tb-orb::before { content:""; position:absolute; inset:-5px; }
[data-bp="phone"] .tb-orb::after { content:"";position:absolute;inset:-1px;border-radius:50%;
  border:1.5px solid var(--accent);animation:orbPing 2.6s cubic-bezier(0,0,.2,1) infinite;pointer-events:none; }
[data-bp="phone"].home-open .tb-orb::after { animation:none;opacity:0; }
@keyframes orbPing { 0%{transform:scale(1);opacity:.5} 70%,100%{transform:scale(1.9);opacity:0} }
.orb-btn.pressed { background:color-mix(in srgb,var(--accent) 16%,transparent);
  border-color:color-mix(in srgb,var(--accent) 50%,transparent);box-shadow:inset 0 2px 6px rgba(0,0,0,.5); }
.orb-btn.pressed .orb-core { transform:scale(.86);box-shadow:none;filter:brightness(.92); }

/* ── Panel Home ── */
.lk-home { display:none; }
[data-bp="phone"] .lk-home { display:flex;flex-direction:column;position:fixed;inset:0;z-index:700;
  padding:calc(46px + env(safe-area-inset-top,0px)) 18px calc(16px + env(safe-area-inset-bottom,0px));
  background:color-mix(in srgb,var(--bg-body) 92%,transparent);
  -webkit-backdrop-filter:blur(30px) saturate(1.4);backdrop-filter:blur(30px) saturate(1.4);
  opacity:0;pointer-events:none;transform:translateY(-10px) scale(.99);overflow:hidden;
  transition:opacity .28s ease,transform .28s cubic-bezier(.4,0,.2,1); }
[data-bp="phone"] .lk-home.open { opacity:1;pointer-events:auto;transform:none; }
[data-bp="phone"].home-open .tx-top,
[data-bp="phone"].home-open .bn-bar { visibility:hidden; }
[data-bp="phone"] .lk-home.closing { opacity:0;transform:translateY(12px) scale(.99); }
@media (prefers-reduced-motion:reduce) {
  [data-bp="phone"] .lk-home { transition:opacity .12s;transform:none; }
  .orb-core::before,[data-bp="phone"] .tb-orb::after,.lkh-guide-arrow path.draw { animation:none; }
}

.lkh-grab { position:absolute;top:8px;left:50%;transform:translateX(-50%);width:38px;height:4px;border-radius:3px;
  background:color-mix(in srgb,var(--tx-muted) 45%,transparent);cursor:grab; }
.lkh-head { flex:none;display:flex;align-items:flex-start;gap:10px; }
.lkh-greet { line-height:1.3; }
.lkh-hi { display:block;font-size:calc(var(--font-base) * 0.923);color:var(--tx-muted); }
.lkh-name { display:block;font-size:calc(var(--font-base) * 1.308);font-weight:500;letter-spacing:-.02em;color:var(--tx-base);margin-top:1px; }
.lkh-acts { margin-left:auto;display:flex;align-items:center;gap:9px; }

/* búsqueda */
.lkh-search { flex:none;margin-top:22px;display:flex;align-items:center;gap:10px;
  background:color-mix(in srgb,var(--bg-surface) 70%,transparent);border:1px solid var(--border);border-radius:14px;padding:0 8px 0 14px;height:48px; }
.lkh-search-ico { display:flex;color:var(--accent);flex:none; }
.lkh-search-ico svg { width:17px;height:17px; }
.lkh-search-input { flex:1;min-width:0;background:none;border:none;outline:none;color:var(--tx-base);font-family:inherit;font-size:calc(var(--font-base) * 1.154); }
.lkh-search-input::placeholder { color:var(--tx-dim); }
.lkh-search-input::-webkit-search-cancel-button,.lkh-search-input::-webkit-search-decoration { -webkit-appearance:none;display:none; }
.lkh-search-clr { flex:none;width:30px;height:30px;border-radius:8px;border:none;background:none;color:var(--tx-muted);cursor:pointer;display:grid;place-items:center;transform:rotate(90deg); }
.lkh-search-clr svg { width:16px;height:16px; }

/* cuerpo */
.lkh-body { flex:1;overflow-x:hidden;overflow-y:auto;overscroll-behavior:contain;-webkit-overflow-scrolling:touch;margin-top:12px; }
.lkh-body::-webkit-scrollbar { display:none; }
.lkh-cat { font-size:calc(var(--font-base) * 0.808);font-weight:500;letter-spacing:.07em;color:var(--tx-dim);padding:16px 4px 6px; display:flex; align-items:baseline; gap:8px }
.lkh-empty { padding:26px 8px;text-align:center;color:var(--tx-dim);font-size:calc(var(--font-base) * 1.0); }

/* fila minimal con bajada */
.lkh-r { display:flex;align-items:center;gap:14px;padding:12px 10px;cursor:pointer;position:relative;user-select:none;-webkit-user-select:none;border-radius:12px;transition:box-shadow .14s; }
.lkh-r + .lkh-r { border-top:1px solid color-mix(in srgb,var(--border) 55%,transparent); }
.lkh-r:active,.lkh-r:hover { box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--accent) 40%,transparent),inset 0 0 18px -7px color-mix(in srgb,var(--accent) 55%,transparent); }
.lkh-r:active,.lkh-r:hover { border-top-color:transparent; }
.lkh-r:active + .lkh-r,.lkh-r:hover + .lkh-r { border-top-color:transparent; }
.lkh-r-press { background:color-mix(in srgb,var(--accent) 12%,transparent);border-radius:12px; }
.lkh-r-ico { width:26px;height:26px;display:grid;place-items:center;color:var(--accent);flex:none; }
.lkh-r-ico svg { width:21px;height:21px; }
.lkh-r-txt { flex:1;min-width:0; }
.lkh-r-nm { font-size:calc(var(--font-base) * 1.154);font-weight:500;color:var(--tx-base); }
.lkh-r-desc { font-size:calc(var(--font-base) * 0.885);color:var(--tx-muted);margin-top:1px; }
.lkh-chev { margin-left:auto;color:var(--tx-dim);display:flex; }
.lkh-chev svg { width:16px;height:16px; }
.lkh-star { margin-left:auto;background:none;border:none;cursor:pointer;padding:6px;display:grid;place-items:center;flex:none; }
.lkh-star svg { width:19px;height:19px;fill:#fbbf24;stroke:#fbbf24; }
.lkh-star:active { transform:scale(.85); }

/* carrusel */
.lkh-rail { display:flex;overflow-x:auto;scroll-snap-type:x mandatory;overscroll-behavior-x:contain;-webkit-overflow-scrolling:touch; }
.lkh-rail::-webkit-scrollbar { display:none; }
.lkh-page { flex:0 0 100%;min-width:0;scroll-snap-align:start; }
.lkh-pgh { font-size:calc(var(--font-base) * 1.0);font-weight:500;letter-spacing:-.01em;color:var(--tx-base);padding:4px 4px 2px; }
.lkh-dots { display:flex;justify-content:center;gap:6px;padding:10px 0 2px; }
.lkh-dot { width:6px;height:6px;border-radius:50%;background:color-mix(in srgb,var(--tx-muted) 40%,transparent);transition:.2s; }
.lkh-dot.on { background:var(--accent);width:18px;border-radius:3px; }

/* sesión */
.lkh-sess { flex:none;margin-top:10px;padding-top:12px;border-top:1px solid var(--border);display:flex;gap:9px; }
.lkh-sbtn { flex:1;display:flex;align-items:center;justify-content:center;gap:7px;
  background:color-mix(in srgb,var(--bg-surface) 60%,transparent);border:1px solid var(--border);border-radius:12px;padding:12px;
  font-family:inherit;font-size:calc(var(--font-base) * 0.962);font-weight:500;color:var(--tx-muted);cursor:pointer; }
.lkh-sbtn:active { transform:scale(.97); }
.lkh-sbtn svg { width:15px;height:15px; }
.lkh-sbtn.danger { color:var(--tx-red); }

/* toast */
.lkh-toast { position:absolute;bottom:92px;left:50%;transform:translateX(-50%) translateY(10px);
  background:var(--bg-card);border:1px solid var(--border);border-radius:12px;padding:10px 16px;
  font-size:calc(var(--font-base) * 0.962);font-weight:500;color:var(--tx-base);z-index:210;opacity:0;pointer-events:none;transition:.2s; }
.lkh-toast.show { opacity:1;transform:translateX(-50%) translateY(0); }

/* ── guía a mano alzada ── */
.lkh-guide { position:absolute;inset:0;z-index:220;opacity:0;pointer-events:none;transition:opacity .3s;
  background:color-mix(in srgb,var(--bg-body) 90%,transparent);
  -webkit-backdrop-filter:blur(5px);backdrop-filter:blur(5px); }
.lkh-guide.open { opacity:1;pointer-events:auto; }
.lkh-guide-mount { position:absolute;background:var(--bg-card);
  box-shadow:0 0 0 1px color-mix(in srgb,var(--accent) 32%,transparent),0 0 30px 6px color-mix(in srgb,var(--accent) 42%,transparent);
  transition:top .32s cubic-bezier(.4,0,.2,1),left .32s cubic-bezier(.4,0,.2,1),width .32s,height .32s,border-radius .32s;z-index:2; }
#lkhGClone { position:absolute;inset:0;z-index:3;pointer-events:none; }
#lkhGClone > * { position:absolute!important;margin:0!important; }
.lkh-guide-arrow { position:absolute;inset:0;width:100%;height:100%;overflow:visible;pointer-events:none;z-index:4; }
.lkh-guide-arrow path { fill:none;stroke:color-mix(in srgb,var(--accent) 60%,white);stroke-width:2.6;stroke-linecap:round;stroke-linejoin:round;filter:drop-shadow(0 2px 5px rgba(0,0,0,.5)); }
.lkh-guide-arrow path.draw { stroke-dasharray:340;stroke-dashoffset:340;animation:lkhDraw .55s ease forwards; }
@keyframes lkhDraw { to { stroke-dashoffset:0; } }
.lkh-guide-hand { position:absolute;z-index:4;font-family:'Caveat','Bradley Hand','Noteworthy',cursive;font-weight:500;font-size:calc(var(--font-base) * 2.154);line-height:1.02;
  color:color-mix(in srgb,var(--accent) 12%,white);max-width:215px;text-shadow:0 2px 10px rgba(0,0,0,.75);
  transition:top .35s cubic-bezier(.34,1.3,.5,1),left .35s cubic-bezier(.34,1.3,.5,1);pointer-events:none; }
.lkh-guide-hand em { color:color-mix(in srgb,var(--accent) 45%,white);font-style:normal; }
.lkh-guide-hand::before { content:"";position:absolute;inset:-16px -22px;z-index:-1;
  background:radial-gradient(ellipse at center,color-mix(in srgb,var(--bg-body) 92%,transparent) 42%,transparent 80%);filter:blur(4px); }
.lkh-guide-foot { position:absolute;left:0;right:0;display:flex;align-items:center;justify-content:center;gap:16px;z-index:5;transition:top .3s,bottom .3s; }
.lkh-guide-step { font-family:'Caveat','Bradley Hand',cursive;font-size:calc(var(--font-base) * 1.385);color:var(--tx-muted); }
.lkh-guide-skip,.lkh-guide-next { font-family:inherit;font-size:calc(var(--font-base) * 1.0);font-weight:500;border-radius:11px;padding:9px 18px;cursor:pointer;
  border:1px solid color-mix(in srgb,var(--accent) 30%,transparent);background:color-mix(in srgb,var(--accent) 18%,transparent);color:color-mix(in srgb,var(--accent) 15%,white); }
.lkh-guide-skip { background:none;border-color:transparent;color:var(--tx-dim); }

/* ══ SP0d · búsqueda del Home ═════════════════════════════════════════════════
   Reglas nuevas en tokens CANÓNICOS (--lk-*). El resto de este archivo está
   escrito contra el bridge (--tx-*, --accent…), que se retira en T2-T4 del
   Doc 07: lo que nace ahora nace canónico, no se suma a la deuda.

   Nota: este archivo usa --accent, que NADIE sobre-escribe (brand.js:24-26 toca
   --c-accent). Por eso el Home no sigue la marca del tenant pese a que su
   cabecera dice "marca-agnóstico". Es la deuda D7 y es de Equipo A: se arregla
   con una línea en lk-tokens.css (--accent: var(--c-accent)), no desde aquí.
   ════════════════════════════════════════════════════════════════════════════ */

/* Contador por categoría: "3 de 9". Es el gancho de la paginación. */
.lkh-cat-n { margin-left:auto; font-weight:500; letter-spacing:0; text-transform:none;
  font-size:calc(var(--font-base) * 0.769); color:var(--lk-text-muted); }

/* Barra de estado. Ocupa el lugar de la sesión MIENTRAS se busca: un teléfono
   no tiene esc ni flechas, y buscando no se cierra sesión. */
.lkh-stat { flex:none; margin-top:10px; padding-top:11px; border-top:1px solid var(--lk-border);
  display:flex; align-items:center; gap:9px; min-height:44px;
  font-size:calc(var(--font-base) * 0.885); color:var(--lk-text-muted); }
.lkh-stat-n { color:var(--lk-text-primary); font-weight:500; }
.lkh-stat-s { margin-left:auto; display:flex; align-items:center; gap:6px; }
.lkh-stat-d { width:7px; height:7px; border-radius:50%; background:var(--lk-green); flex-shrink:0; }
.lk-home.lkh-searching .lkh-sess { display:none; }


/* ── css/lk-sv.css ── */
/* ═══════════════════════════════════════════════════════════════════════════════
   lk-sv.css · SmartView · estilos UI v3
   Tokenizado al sistema (--c-brand*, --lk-*) con fallbacks. Hereda light/dark/midnight
   por los tokens (que cambian con [data-theme]). Animación solo transform/opacity.
   ═══════════════════════════════════════════════════════════════════════════════ */

.sv-shell { position: relative; width: 100%; font-family: var(--lk-font-sans, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, system-ui, sans-serif); }

/* ── barra ─────────────────────────────────────────────────────────────────── */
.sv {
  position: relative; display: flex; align-items: center; gap: 11px;
  height: 54px; padding: 0 12px; overflow: visible;
  background: var(--lk-bg-card, #fff);
  border: .5px solid var(--lk-border, rgba(15,23,42,.10));
  border-radius: 13px;
  box-shadow: 0 1px 2px rgba(15,23,42,.04);
  transition: border-color .5s;
}
.sv .to-veil {
  position: absolute; inset: 0; border-radius: 13px; pointer-events: none; opacity: 0;
  background: radial-gradient(120% 140% at 100% 50%, var(--lk-red-soft, rgba(185,28,28,.10)), transparent 60%);
  transition: opacity .6s;
}
.sv-shell.sv-timeout .sv { border-color: var(--lk-red, #b91c1c); }
.sv-shell.sv-timeout .to-veil { opacity: 1; animation: sv-veil 3s ease-in-out infinite; }
@keyframes sv-veil { 0%,100% { opacity: .55; } 50% { opacity: .9; } }

.dvl { width: .5px; height: 26px; background: var(--lk-border-soft, rgba(15,23,42,.06)); flex: 0 0 auto; position: relative; z-index: 1; }

/* ── lead (estrella contorno + SmartView + chevron) ────────────────────────── */
.sv-lead { display: inline-flex; align-items: center; gap: 7px; flex: 0 0 auto; padding: 5px 8px; border-radius: 9px; cursor: pointer; transition: background .14s; position: relative; z-index: 2; }
.sv-lead:hover { background: var(--lk-bg-hover, #f8fafc); }
.sv-lead .ic { color: var(--c-brand, var(--lk-brand)); display: grid; place-items: center; }
.sv-lead .ic svg { width: 18px; height: 18px; }
.sv-lead .nm { font-size: calc(var(--font-base) * 0.923); font-weight: 500; color: var(--lk-text-primary, #0f172a); letter-spacing: -.01em; }
.sv-lead .nm b { color: var(--c-brand, var(--lk-brand)); font-weight: 500; }
.sv-lead .chev { width: 14px; height: 14px; color: var(--lk-text-muted, #94a3b8); transition: transform .35s cubic-bezier(.34,1.4,.64,1); display: grid; place-items: center; }
.sv-lead .chev svg { width: 14px; height: 14px; }
.sv-lead.open .chev { transform: rotate(180deg); color: var(--c-brand, var(--lk-brand)); }

/* ── KPIs ──────────────────────────────────────────────────────────────────── */
.sv-kpis { display: flex; align-items: center; gap: 11px; flex: 0 0 auto; position: relative; z-index: 1; }
.sv-kpi-host { display: flex; align-items: center; cursor: help; }
.sv-kpis .kpi { display: flex; flex-direction: column; justify-content: center; line-height: 1.12; }
.sv-kpis .kpi-lbl { font-size: calc(var(--font-base) * 0.692); color: var(--lk-text-muted, #94a3b8); text-transform: uppercase; letter-spacing: .06em; }
.sv-kpis .kpi-val { font-size: calc(var(--font-base) * 1.077); font-weight: 500; color: var(--lk-text-primary, #0f172a); font-variant-numeric: tabular-nums; }
.sv-loading { font-size: calc(var(--font-base) * 0.769); letter-spacing: .08em; color: var(--lk-text-muted, #94a3b8); text-transform: uppercase; }

/* ── sesión (tele + BARRA antes + cronómetro + timeout) ────────────────────── */
.sv-sess { display: flex; align-items: center; gap: 10px; flex: 0 0 auto; padding: 0 2px; position: relative; z-index: 1; border-radius: 9px; transition: background .3s; }
.sv-sess .tele { width: 30px; height: 30px; border-radius: 8px; background: var(--c-brand-muted, color-mix(in srgb, var(--lk-brand) 7%, transparent)); color: var(--c-brand, var(--lk-brand)); display: grid; place-items: center; flex-shrink: 0; cursor: pointer; transition: transform .2s, background .2s, color .2s; }
.sv-sess .tele:hover { transform: scale(1.06); background: var(--c-brand, var(--lk-brand)); color: #fff; }
.sv-sess .tele svg { width: 16px; height: 16px; }
.sv-sess .txt { display: flex; flex-direction: column; line-height: 1.1; cursor: help; }
.sv-sess .txt .l { font-size: calc(var(--font-base) * 0.692); text-transform: uppercase; letter-spacing: .06em; color: var(--lk-text-muted, #94a3b8); }
.sv-sess .txt .p { font-size: calc(var(--font-base) * 0.923); font-weight: 500; color: var(--lk-text-primary, #0f172a); }
.sv-sess .bar { position: relative; width: 150px; height: 8px; border-radius: 5px; background: var(--lk-bg-surface, #eef1f6); overflow: hidden; flex-shrink: 0; cursor: help; }
.sv-sess .bar .fill { position: absolute; left: 0; top: 0; height: 100%; border-radius: 5px; overflow: hidden; background: linear-gradient(90deg, var(--c-brand, var(--lk-brand)), var(--c-brand-lt, var(--lk-brand))); transition: width 1s linear, background .4s; }
.sv-sess .bar .fill::after { content: ''; position: absolute; inset: 0; background: linear-gradient(90deg, transparent, rgba(255,255,255,.4), transparent); transform: translateX(-100%); animation: sv-sheen 2.8s ease-in-out infinite; }
@keyframes sv-sheen { 0% { transform: translateX(-100%); } 55%,100% { transform: translateX(180%); } }
.sv-sess .bar .fill.amb { background: linear-gradient(90deg, var(--lk-amber, #b45309), #f59e0b); }
.sv-sess .bar .fill.red { background: linear-gradient(90deg, var(--lk-red, #b91c1c), #ef4444); }
.sv-sess .chrono { font-family: var(--lk-font-mono, 'SF Mono', ui-monospace, Menlo, monospace); font-size: calc(var(--font-base) * 1.462); font-weight: 500; color: var(--lk-text-primary, #0f172a); font-variant-numeric: tabular-nums; min-width: 64px; text-align: center; transition: color .3s; }
.sv-sess .chrono.amb { color: var(--lk-amber, #b45309); }
.sv-sess .chrono.red { color: var(--lk-red, #b91c1c); }
.sv-sess .to { display: none; align-items: center; gap: 6px; font-size: calc(var(--font-base) * 0.962); font-weight: 500; color: var(--lk-red, #b91c1c); }
.sv-sess .to svg { width: 15px; height: 15px; }
.sv-sess.timeout .chrono { display: none; }
.sv-sess.timeout .to { display: inline-flex; }

/* ── alertas · isla Dynamic Island de a una ────────────────────────────────── */
.sv-alerts { flex: 1; min-width: 0; display: flex; padding-left: 6px; border-left: .5px solid var(--lk-border-soft, rgba(15,23,42,.06)); position: relative; z-index: 1; }
.sv-alerts .island { flex: 1; height: 38px; display: flex; align-items: center; background: var(--lk-bg-surface, #f6f7fb); border: .5px solid var(--lk-border, rgba(15,23,42,.10)); border-radius: 14px; padding: 0 10px; overflow: hidden; box-shadow: 0 1px 2px rgba(15,23,42,.04); transition: box-shadow .3s; }
.sv-alerts.sv-flash .island { box-shadow: 0 0 0 2px var(--c-brand-muted, color-mix(in srgb, var(--lk-brand) 15%, transparent)), 0 1px 2px rgba(15,23,42,.04); }
.isl-slot { display: flex; align-items: center; gap: 9px; width: 100%; transition: transform .36s cubic-bezier(.34,1.4,.64,1), opacity .28s; cursor: pointer; }
.isl-slot.out { opacity: 0; transform: translateY(-8px) scale(.97); }
.isl-slot.in  { opacity: 0; transform: translateY(9px) scale(.97); }
.isl-bdg { width: 24px; height: 24px; border-radius: 7px; display: grid; place-items: center; flex-shrink: 0; }
.isl-bdg svg { width: 13px; height: 13px; }
.isl-bdg.b-grn, .isl-bdg.b-green { background: var(--lk-green-soft, rgba(21,128,61,.09)); color: var(--lk-green, #15803d); }
.isl-bdg.b-amb, .isl-bdg.b-amber { background: var(--lk-amber-soft, rgba(180,83,9,.10)); color: var(--lk-amber, #b45309); }
.isl-bdg.b-red { background: var(--lk-red-soft, rgba(185,28,28,.09)); color: var(--lk-red, #b91c1c); }
.isl-bdg.b-info { background: var(--lk-blue-soft, rgba(67,56,202,.08)); color: var(--lk-blue, #4338ca); }
.isl-tx { display: flex; flex-direction: column; min-width: 0; }
.isl-tag { font-size: calc(var(--font-base) * 0.654); text-transform: uppercase; letter-spacing: .05em; color: var(--lk-text-muted, #94a3b8); font-weight: 500; }
.isl-nm { font-size: calc(var(--font-base) * 0.923); color: var(--lk-text-secondary, #334155); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.isl-nm b { color: var(--lk-text-primary, #0f172a); font-weight: 500; }
.isl-cnt { min-width: 18px; height: 18px; padding: 0 5px; border-radius: 9px; font-size: calc(var(--font-base) * 0.769); font-weight: 500; display: grid; place-items: center; margin-left: auto; flex-shrink: 0; }
.isl-cnt.c-red { background: var(--lk-red-soft, rgba(185,28,28,.09)); color: var(--lk-red, #b91c1c); }
.isl-cnt.c-amb, .isl-cnt.c-amber { background: var(--lk-amber-soft, rgba(180,83,9,.10)); color: var(--lk-amber, #b45309); }
.isl-go { margin-left: auto; flex-shrink: 0; color: var(--c-brand, var(--lk-brand)); display: inline-flex; }
.isl-go svg { width: 14px; height: 14px; animation: sv-nudge 1.5s ease-in-out infinite; }
@keyframes sv-nudge { 0%,100% { transform: translateX(0); } 50% { transform: translateX(3px); } }
.isl-wait { width: 6px; height: 6px; border-radius: 50%; background: var(--lk-amber, #b45309); flex-shrink: 0; animation: sv-blink 1.4s infinite; }
@keyframes sv-blink { 0%,100% { opacity: 1; } 50% { opacity: .4; } }

/* ── sync dot ──────────────────────────────────────────────────────────────── */
.sv-sync { width: 8px; height: 8px; border-radius: 50%; flex: 0 0 auto; cursor: help; position: relative; z-index: 1; }
.sv-sync[data-state="on"]  { background: var(--lk-green, #15803d); animation: sv-pulse 2s infinite; }
.sv-sync[data-state="off"] { background: var(--lk-amber, #b45309); }
@keyframes sv-pulse { 0% { box-shadow: 0 0 0 0 rgba(21,128,61,.4); } 70% { box-shadow: 0 0 0 5px rgba(21,128,61,0); } 100% { box-shadow: 0 0 0 0 rgba(21,128,61,0); } }

/* ── detalle (dropdown volador) ────────────────────────────────────────────── */
.sv-detail {
  position: absolute; top: calc(100% + 10px); left: 0; width: 330px; z-index: 50;
  background: var(--lk-bg-card, #fff); border: .5px solid var(--lk-border, rgba(15,23,42,.10)); border-radius: 14px;
  box-shadow: 0 18px 44px -12px rgba(15,23,42,.22), 0 4px 12px rgba(15,23,42,.05); padding: 8px;
  transform-origin: top left;
}
.sv-detail[hidden] { display: none; }
.sv-shell:not(.sv-open) .sv-detail { opacity: 0; transform: translateY(-12px) scale(.96); pointer-events: none; }
.sv-shell.sv-open .sv-detail { opacity: 1; transform: translateY(0) scale(1); pointer-events: auto; transition: opacity .26s ease, transform .44s cubic-bezier(.34,1.4,.5,1); }
.sv-detail-h { padding: 7px 9px 9px; border-bottom: .5px solid var(--lk-border-soft, rgba(15,23,42,.06)); margin-bottom: 5px; }
.sv-detail-h .t { font-size: calc(var(--font-base) * 0.962); font-weight: 500; color: var(--lk-text-primary, #0f172a); display: flex; align-items: center; gap: 7px; }
.sv-detail-h .t svg { width: 14px; height: 14px; color: var(--c-brand, var(--lk-brand)); }
.sv-detail-h .s { font-size: calc(var(--font-base) * 0.846); color: var(--lk-text-muted, #94a3b8); margin-top: 3px; }
.sv-sechead { display: flex; align-items: center; justify-content: space-between; padding: 6px 9px; cursor: pointer; font-size: calc(var(--font-base) * 0.846); font-weight: 500; text-transform: uppercase; letter-spacing: .04em; color: var(--lk-text-muted, #94a3b8); }
.sv-sechead .sv-sec-chev svg { width: 14px; height: 14px; transition: transform .25s; }
.sv-sec.col .sv-sec-chev svg { transform: rotate(-90deg); }
.sv-sec.col .sv-secbody { display: none; }
.di-item { display: flex; align-items: center; gap: 11px; padding: 9px; border-radius: 9px; cursor: pointer; transition: background .13s; }
.di-item:hover { background: var(--lk-bg-hover, #f8fafc); }
.di-ic { width: 28px; height: 28px; border-radius: 8px; display: grid; place-items: center; flex-shrink: 0; }
.di-ic svg { width: 15px; height: 15px; }
.di-ic.v-info { background: var(--lk-blue-soft, rgba(67,56,202,.08)); color: var(--lk-blue, #4338ca); }
.di-ic.v-purple { background: var(--c-brand-muted, color-mix(in srgb, var(--lk-brand) 7%, transparent)); color: var(--c-brand, var(--lk-brand)); }
.di-ic.v-danger { background: var(--lk-red-soft, rgba(185,28,28,.09)); color: var(--lk-red, #b91c1c); }
.di-ic.v-warn { background: var(--lk-amber-soft, rgba(180,83,9,.10)); color: var(--lk-amber, #b45309); }
.di-ic.v-muted { background: var(--lk-bg-surface, #eef1f6); color: var(--lk-text-muted, #94a3b8); }
.di-tx { flex: 1; min-width: 0; }
.di-l { font-size: calc(var(--font-base) * 0.962); font-weight: 500; color: var(--lk-text-primary, #0f172a); }
.di-m { font-size: calc(var(--font-base) * 0.808); color: var(--lk-text-muted, #94a3b8); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; margin-top: 1px; }
.di-badge { min-width: 18px; height: 18px; padding: 0 5px; border-radius: 9px; font-size: calc(var(--font-base) * 0.769); font-weight: 500; display: grid; place-items: center; flex-shrink: 0; }
.di-badge.v-info { background: var(--lk-blue-soft, rgba(67,56,202,.08)); color: var(--lk-blue, #4338ca); }
.di-badge.v-danger { background: var(--lk-red-soft, rgba(185,28,28,.09)); color: var(--lk-red, #b91c1c); }
.di-badge.v-warn { background: var(--lk-amber-soft, rgba(180,83,9,.10)); color: var(--lk-amber, #b45309); }
.di-go { flex-shrink: 0; color: var(--lk-text-muted, #94a3b8); display: inline-flex; }
.di-go svg { width: 15px; height: 15px; }

/* ── tooltip (portal en body) ──────────────────────────────────────────────── */
.sv-tt-portal { position: fixed; z-index: 9000; opacity: 0; transform: translateY(4px); transition: opacity .16s, transform .2s; pointer-events: none; }
.sv-tt-portal.sv-tt-on { opacity: 1; transform: translateY(0); pointer-events: auto; }
.sv-tt { background: var(--lk-bg-card, #fff); border: .5px solid var(--lk-border, rgba(15,23,42,.10)); border-radius: 11px; box-shadow: 0 18px 44px -12px rgba(15,23,42,.22); padding: 10px 12px; min-width: 186px; max-width: 258px; }
.sv-tt-head { display: flex; justify-content: space-between; align-items: center; gap: 10px; }
.sv-tt-t { font-size: calc(var(--font-base) * 0.885); font-weight: 500; color: var(--lk-text-primary, #0f172a); }
.sv-tt-badge { font-size: calc(var(--font-base) * 0.731); color: var(--lk-text-muted, #94a3b8); font-weight: 500; }
.sv-tt-mini { display: flex; align-items: flex-end; gap: 2px; height: 24px; margin-top: 7px; }
.sv-tt-mini i { width: 5px; border-radius: 1.5px 1.5px 0 0; background: var(--c-brand, var(--lk-brand)); opacity: .45; }
.sv-tt-mini i.hot { opacity: 1; }
.sv-tt-row { display: flex; justify-content: space-between; gap: 16px; font-size: calc(var(--font-base) * 0.846); color: var(--lk-text-muted, #94a3b8); margin-top: 5px; }
.sv-tt-row .v { color: var(--lk-text-secondary, #334155); font-weight: 500; }
.sv-tt-tag { margin-top: 8px; font-size: calc(var(--font-base) * 0.769); font-weight: 500; padding: 3px 8px; border-radius: 6px; display: inline-block; }
.sv-tt-tag.brand { background: var(--c-brand-muted, color-mix(in srgb, var(--lk-brand) 7%, transparent)); color: var(--c-brand, var(--lk-brand)); }
.sv-tt-tag.red { background: var(--lk-red-soft, rgba(185,28,28,.09)); color: var(--lk-red, #b91c1c); }
.sv-tt-tag.amber { background: var(--lk-amber-soft, rgba(180,83,9,.10)); color: var(--lk-amber, #b45309); }
.sv-tt-tag.green { background: var(--lk-green-soft, rgba(21,128,61,.09)); color: var(--lk-green, #15803d); }
.sv-tt-dep { margin-top: 9px; padding-top: 8px; border-top: .5px solid var(--lk-border-soft, rgba(15,23,42,.06)); font-size: calc(var(--font-base) * 0.808); color: var(--c-brand, var(--lk-brand)); display: flex; align-items: center; gap: 5px; font-weight: 500; cursor: pointer; }
.sv-tt-dep:hover { opacity: .75; }
.sv-tt-dep svg { width: 12px; height: 12px; }


/* ── css/lk-spotlight.css ── */
/* ══════════════════════════════════════════════════════════════════════════════
 * lk-spotlight.css · SP0-Mojave · rediseño aprobado (roadmap D·A, 21-jul)
 * ------------------------------------------------------------------------------
 * Lenguaje de diseño Mojave sobre el chasis SP0b: material vibrancy, selección
 * con acento sólido macOS, tiles de ícono squircle, keycaps, tarjeta de cita con
 * separadores inset. Mismas clases sp3-* (el DOM del motor no cambia salvo los
 * keycaps de barra/footer en view.js). Tokens 100% canónicos --lk-*/--c-accent*
 * (SPOT-10, §6.1): cero bridge legacy (--tx-*/--bg-*/--border/--c-brand), cero
 * hex de color. Los tres temas (lightmode/darkmode/midnight) salen del sistema.
 *
 * Acento → --c-accent (NO --lk-brand): brand.js:24-26 lo sobre-escribe inline en
 * :root; es la costura de marca por tenant.
 *
 * ── RENDIMIENTO · no quemar GPU (requisito del dueño) ─────────────────────────
 *  1. El blur SOLO cubre el panel (≈380px), nunca el viewport. Antes el
 *     ::backdrop llevaba blur(8px) a pantalla completa — se elimina: es el
 *     costo GPU más alto y no hace falta con el material del panel.
 *  2. Cerrado = display:none (UA): el <dialog> NO pinta ni compone nada mientras
 *     el spotlight está cerrado (antes quedaba display:flex; opacity:0, una capa
 *     de composición viva y ociosa).
 *  3. Se anima SOLO transform/opacity, one-shot al abrir (compositor puro).
 *     Nunca se anima filter/blur (eso sí funde GPU).
 *  4. Degradación sin costo: @supports sin backdrop-filter, y
 *     prefers-reduced-transparency → material sólido opaco, idéntica lectura.
 *     will-change: ausente a propósito (una capa GPU persistente por panel).
 * ══════════════════════════════════════════════════════════════════════════════ */

/* ── Tokens de material del spotlight · namespaced --sp3-*, sin tocar el token
 *    file (territorio A). El material se deriva de --lk-bg-card por color-mix →
 *    tiñe con el tema solo; el brillo interior (sheen) sí va por tema. ─────────── */
:root {
  /* Superficies SÓLIDAS por token directo. NO usar color-mix() guardado en una
     custom property: varios navegadores fallan al sustituir un color-mix anidado
     en una var → el valor queda inválido y el fondo cae a transparente (el panel
     desaparecía). El color-mix directo en reglas (hover/acento) sí es seguro. */
  --sp3-field: var(--lk-bg-hover);
  --sp3-edge:  rgba(255,255,255,.62);
  --sp3-keyhi: rgba(255,255,255,.7);
}
[data-theme="darkmode"], [data-theme="midnight"] {
  --sp3-field: var(--lk-bg-hover);
  --sp3-edge:  rgba(255,255,255,.10);
  --sp3-keyhi: rgba(255,255,255,.14);
}

/* ── Overlay · <dialog> ──────────────────────────────────────────────────────── */
/* RESP-15 · el alto va en dvh, con vh como respaldo para el navegador que no la
   entienda (mismo par que usa lk-layout.css:6). Con 100vh la paleta quedaba
   cortada por debajo de la barra del navegador en iOS, y daba un salto al
   entrar y salir esa barra. El ancho sigue en vw: ahí no hay barra que entre. */
dialog.sp3-overlay { position:fixed; inset:0; margin:0; z-index:9999; width:100vw; max-width:100vw; padding:0; border:none; background:none; overflow:visible;
  height:100vh; height:100dvh; max-height:100vh; max-height:100dvh }
/* cerrado → display:none por UA (no lo forzamos a flex): cero pintura/GPU */
dialog.sp3-overlay[open] { display:flex; align-items:flex-start; justify-content:center; padding-top:min(14vh,110px); padding-top:min(14dvh,110px) }
/* ATENUADO oscuro (la "capa"). COLOR LITERAL, no var(): ::backdrop NO hereda
   custom properties de forma confiable entre navegadores — con var() la capa
   quedaba transparente. Es una capa translúcida sin filtro: cero costo GPU;
   el blur de viewport (lo caro) NO vuelve. */
dialog.sp3-overlay::backdrop { background:rgba(15,23,42,.46) }
:root[data-theme="darkmode"] dialog.sp3-overlay::backdrop,
:root[data-theme="midnight"] dialog.sp3-overlay::backdrop { background:rgba(0,0,0,.5) }

/* ── VIDRIO · la cortina se corre ───────────────────────────────────────────────
   Decision del dueno (31-jul-2026). Esta capa era la que impedia ver el vidrio: el
   panel ya pedia blur(30px) saturate(200%), pero por debajo habia una cortina al
   46/50% sobre TODA la app, asi que lo que el vidrio dejaba ver no era la pantalla
   sino la cortina. Medido: de la pantalla real llegaba ~15%; con la cortina al 22%
   y el relleno al 62% (ver FAMILIA 2b-bis en lk-glass.css) llega ~30%.
   SOLO en material vidrio: grafito, tinte, vintage y plano conservan su cortina.
   Y SOLO mientras el desenfoque esta activo — sin desenfoque una cortina clara deja
   la pantalla legible detras del panel, que es peor que la cortina oscura. Por eso
   los dos casos de movimiento reducido la devuelven, incluso mas cerrada. */
html[data-mode="glass"] dialog.sp3-overlay::backdrop { background:rgba(15,23,42,.22) }
html[data-mode="glass"][data-theme="darkmode"] dialog.sp3-overlay::backdrop,
html[data-mode="glass"][data-theme="midnight"] dialog.sp3-overlay::backdrop { background:rgba(0,0,0,.22) }
@media (prefers-reduced-motion: reduce) {
  html[data-mode="glass"] dialog.sp3-overlay::backdrop { background:rgba(15,23,42,.55) }
  html[data-mode="glass"][data-theme="darkmode"] dialog.sp3-overlay::backdrop,
  html[data-mode="glass"][data-theme="midnight"] dialog.sp3-overlay::backdrop { background:rgba(0,0,0,.55) }
}
html[data-motion="reduced"][data-mode="glass"] dialog.sp3-overlay::backdrop { background:rgba(15,23,42,.55) }
html[data-motion="reduced"][data-mode="glass"][data-theme="darkmode"] dialog.sp3-overlay::backdrop,
html[data-motion="reduced"][data-mode="glass"][data-theme="midnight"] dialog.sp3-overlay::backdrop { background:rgba(0,0,0,.55) }

/* ── Panel · material vibrancy ──────────────────────────────────────────────── */
/* Ancho protagónico (≈macOS Spotlight), no más chico que el disparador. */
.sp3-modal { width:min(620px, calc(100vw - 40px)); max-height:min(70vh,600px); max-height:min(70dvh,600px); display:flex; flex-direction:column; overflow:hidden;
  transform-origin:top center; background:var(--lk-bg-card);
  /* --lk-modal-radius vale 16px: mismo píxel de antes, ahora por token. */
  border:.5px solid var(--lk-border); border-radius:var(--lk-modal-radius, 16px);
  box-shadow:0 24px 70px rgba(0,0,0,.34), 0 3px 10px rgba(0,0,0,.16), inset 0 .5px 0 var(--sp3-edge) }
/* RESP-10 · duración y curva del vocabulario, no escritas a mano. Antes iba
   `.28s cubic-bezier(.22,.61,.36,1)`: dos valores que no existían en ninguna
   otra parte del producto, así que la paleta entraba con un gesto que no se
   reconocía. --lk-dur-3 (.26s) + --lk-ease-out es el gesto de «aparece». */
dialog.sp3-overlay[open] .sp3-modal { animation:sp3modin var(--lk-dur-3, .26s) var(--lk-ease-out, cubic-bezier(.22,1,.36,1)) both }
@keyframes sp3modin { from { opacity:0; transform:translateY(6px) scale(.994) } to { opacity:1; transform:none } }

/* Degradaciones sin costo GPU: material sólido opaco, misma lectura */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .sp3-modal { background:var(--lk-bg-card) }
}
@media (prefers-reduced-transparency: reduce) {
  .sp3-modal { background:var(--lk-bg-card); -webkit-backdrop-filter:none; backdrop-filter:none }
  dialog.sp3-overlay::backdrop { background:rgba(15,23,42,.55) }
}

/* ── Barra de búsqueda ──────────────────────────────────────────────────────── */
.sp3-bar { display:flex; align-items:center; gap:11px; padding:15px 17px; border-bottom:.5px solid color-mix(in srgb, var(--lk-border-soft) 60%, transparent) }
.sp3-bar svg { width:19px; height:19px; stroke:var(--lk-text-muted); stroke-width:1.9; fill:none; flex-shrink:0 }
.sp3-input { flex:1; border:none; outline:none; background:none; font-size:calc(var(--font-base) * 1.231); color:var(--lk-text-primary); font-family:inherit; letter-spacing:-.01em }
.sp3-input::placeholder { color:var(--lk-text-muted) }

/* keycaps ⌘K (barra) y navegación (footer) — mismo molde Mojave */
.sp3-kcombo { display:inline-flex; gap:5px; align-items:center; flex-shrink:0 }
.sp3-kcap { font-family:inherit; font-size:calc(var(--font-base) * 0.923); font-weight:500; line-height:1; color:var(--lk-text-secondary);
  min-width:22px; height:22px; padding:0 6px; display:inline-flex; align-items:center; justify-content:center; border-radius:7px;
  background:var(--sp3-field); border:.5px solid var(--lk-border-soft); box-shadow:0 1px 1.5px rgba(0,0,0,.10), inset 0 .5px 0 var(--sp3-keyhi) }
.sp3-kcap.sp3-cmd { font-size:calc(var(--font-base) * 1.0) }

/* ── Cuerpo · grupos y filas ────────────────────────────────────────────────── */
.sp3-body { flex:1; overflow-y:auto; padding:7px 0 6px; overscroll-behavior:contain }
.sp3-group { padding:1px 0 }
.sp3-group + .sp3-group { margin-top:3px; padding-top:5px; border-top:.5px solid color-mix(in srgb, var(--lk-border-soft) 45%, transparent) }
.sp3-gtitle { font-size:calc(var(--font-base) * 0.808); font-weight:500; text-transform:uppercase; letter-spacing:.06em; color:var(--lk-text-muted); padding:8px 18px 4px }

/* filas inset con selección de acento macOS */
.sp3-item { display:flex; align-items:center; gap:11px; margin:1px 8px; padding:8px 10px; cursor:pointer; border-radius:9px; font-size:calc(var(--font-base) * 1.038); color:var(--lk-text-primary); transition:background .18s ease, box-shadow .2s ease }
.sp3-item:not(.on):hover { background:color-mix(in srgb, var(--lk-text-primary) 7%, transparent) }
.sp3-item.on { background:color-mix(in srgb, var(--c-accent) 15%, transparent); color:var(--lk-text-primary); box-shadow:inset 0 0 0 .5px color-mix(in srgb, var(--c-accent) 38%, transparent) }

/* tile de ícono squircle con luz interior */
.sp3-ico { width:29px; height:29px; border-radius:9px; display:flex; align-items:center; justify-content:center; flex-shrink:0;
  background:linear-gradient(180deg, color-mix(in srgb, var(--lk-text-primary) 5%, transparent), color-mix(in srgb, var(--lk-text-primary) 11%, transparent));
  border:.5px solid var(--lk-border-soft); box-shadow:inset 0 .5px 0 var(--sp3-keyhi);
  /* RESP-10 · era `.22s cubic-bezier(.2,.9,.3,1)`, otra curva de nadie. */
  transition:transform var(--lk-dur-2, .18s) var(--lk-ease-out, cubic-bezier(.22,1,.36,1)) }
.sp3-item:hover .sp3-ico { transform:scale(1.05) }
.sp3-ico svg { width:15px; height:15px; stroke:var(--lk-text-secondary); stroke-width:1.8; fill:none }
.sp3-item.on .sp3-ico { background:color-mix(in srgb, var(--c-accent) 20%, transparent); border-color:transparent; box-shadow:none }
.sp3-item.on .sp3-ico svg { stroke:var(--c-accent) }

.sp3-info { flex:1; min-width:0; display:flex; flex-direction:column; gap:2px }
.sp3-label { font-size:calc(var(--font-base) * 1.038); line-height:1.2; overflow:hidden; text-overflow:ellipsis; white-space:nowrap }
.sp3-label mark { background:color-mix(in srgb, var(--c-accent) 16%, transparent); color:inherit; border-radius:2px; padding:0 1px }
.sp3-item.on mark { background:color-mix(in srgb, var(--c-accent) 24%, transparent); color:var(--lk-text-primary) }
.sp3-sub { font-size:calc(var(--font-base) * 0.885); line-height:1.2; color:var(--lk-text-muted); overflow:hidden; text-overflow:ellipsis; white-space:nowrap }
.sp3-item.on .sp3-sub { color:var(--lk-text-muted) }
/* ── SP6 · anclar (chincheta) ──────────────────────────────────────────────
   No ocupa sitio mientras no se pide: se revela SOLO con Shift mantenido, y el
   hueco se reserva de antemano para que la fila no salte al aparecer. */
.sp3-pin { flex-shrink:0; width:26px; height:26px; margin-left:2px; padding:0; border:0;
  border-radius:7px; background:transparent; color:var(--lk-text-faint); cursor:pointer;
  display:grid; place-items:center; opacity:0; pointer-events:none; transition:opacity .12s ease }
.sp3-pin-ic { display:grid; place-items:center }
.sp3-pin svg { width:14px; height:14px; stroke:currentColor; fill:none; stroke-width:1.8 }
/* Shift mantenido: aparecen todas. Las ya ancladas se ven siempre. */
.sp3-modal.sp3-anclando .sp3-pin,
.sp3-pin.on { opacity:1; pointer-events:auto }
.sp3-pin.on { color:var(--c-accent) }
.sp3-pin:hover { background:color-mix(in srgb, var(--lk-text-primary) 8%, transparent);
  color:var(--lk-text-primary) }
.sp3-pin.on:hover { color:var(--c-accent) }
.sp3-pin:focus-visible { outline:2px solid var(--c-accent); outline-offset:-2px; opacity:1; pointer-events:auto }
@media (prefers-reduced-motion: reduce) { .sp3-pin { transition:none } }

/* SP7 · mover de sitio lo anclado. Dos reglas, y son todo el costo en estilos:
   dentro del modo anclar la fila se puede tomar, y mientras viaja se atenua
   para que se lea que es ella la que se esta moviendo. Ningun color nuevo.
   La opacidad es .65 y no menos por medida, no por gusto: a .45 el texto de la
   fila arrastrada caia a 2.93:1 en lightmode (4.48 dark / 4.49 midnight), bajo
   el minimo AA de 4.5:1 que exige la revision del paquete. A .65 mide
   5.57 / 8.06 / 7.99. Bajarla vuelve a romper el contraste. */
.sp3-modal.sp3-anclando .sp3-item { cursor:grab }
.sp3-item.sp3-lift { opacity:.65; cursor:grabbing }

.sp3-tag { font-size:calc(var(--font-base) * 0.769); color:var(--lk-text-muted); background:var(--sp3-field); padding:2px 7px; border-radius:5px; flex-shrink:0 }
.sp3-tag.prox { color:var(--lk-amber); background:color-mix(in srgb, var(--lk-amber) 14%, transparent) }
.sp3-item.on .sp3-tag { background:var(--sp3-field); color:var(--lk-text-muted) }

.sp3-empty { padding:32px 16px; text-align:center; font-size:calc(var(--font-base) * 1.0); color:var(--lk-text-muted) }

/* ── Footer de navegación ───────────────────────────────────────────────────── */
.sp3-footer { display:flex; align-items:center; gap:16px; padding:9px 16px; border-top:.5px solid color-mix(in srgb, var(--lk-border-soft) 60%, transparent); font-size:calc(var(--font-base) * 0.846); color:var(--lk-text-muted) }
.sp3-fk { display:inline-flex; align-items:center; gap:6px }
.sp3-fsp { flex:1 }
.sp3-footer kbd, .sp3-footer .sp3-kcap { font-family:inherit; font-size:calc(var(--font-base) * 0.846); min-width:18px; height:18px; padding:0 4px; display:inline-flex; align-items:center; justify-content:center;
  border-radius:5px; background:var(--sp3-field); border:.5px solid var(--lk-border-soft); color:var(--lk-text-secondary); box-shadow:inset 0 .5px 0 var(--sp3-keyhi) }

/* ── Tarjeta de cita (fuente rica · SPOT-12) · grupo Mojave inset ────────────── */
.sp3-cita { margin:6px 12px 4px; border:.5px solid var(--lk-border); border-radius:12px; overflow:hidden; cursor:pointer; background:var(--sp3-field);
  transition:border-color .16s ease, box-shadow .22s ease }
.sp3-cita.on { border-color:color-mix(in srgb, var(--c-accent) 45%, var(--lk-border)); box-shadow:0 8px 26px -10px color-mix(in srgb, var(--c-accent) 30%, transparent) }
.sp3-chead { display:flex; align-items:center; gap:10px; padding:13px 15px }
.sp3-cico { width:30px; height:30px; border-radius:9px; display:flex; align-items:center; justify-content:center; flex-shrink:0;
  background:linear-gradient(180deg, color-mix(in srgb, var(--c-accent) 26%, transparent), color-mix(in srgb, var(--c-accent) 16%, transparent));
  border:.5px solid color-mix(in srgb, var(--c-accent) 30%, transparent); box-shadow:inset 0 .5px 0 rgba(255,255,255,.4) }
.sp3-cico svg { width:16px; height:16px; stroke:var(--c-accent); stroke-width:1.8; fill:none }
.sp3-cfolio { flex:1; font-family:ui-monospace,Menlo,Consolas,monospace; font-size:calc(var(--font-base) * 0.962); color:var(--lk-text-muted) }
.sp3-cest { display:inline-flex; align-items:center; gap:6px; font-size:calc(var(--font-base) * 0.846); padding:3px 10px; border-radius:20px; background:var(--sp3-field); color:var(--lk-text-primary); border:.5px solid var(--lk-border) }
.sp3-cdot { width:7px; height:7px; border-radius:50%; flex-shrink:0; background:var(--lk-green) }
.sp3-chero { display:flex; align-items:center; gap:14px; padding:4px 15px 16px }
.sp3-hicon { flex-shrink:0; display:flex }
.sp3-hicon svg { width:28px; height:28px; stroke-width:1.6; fill:none; stroke:currentColor }
.sp3-count { font-size:calc(var(--font-base) * 2.077); font-weight:500; line-height:1; letter-spacing:-.015em; color:var(--lk-text-primary); font-variant-numeric:tabular-nums }
.sp3-count small { font-size:calc(var(--font-base) * 1.0); font-weight:400; color:var(--lk-text-muted); margin-left:3px }
.sp3-htitle { font-size:calc(var(--font-base) * 1.308); font-weight:500; color:var(--lk-text-primary); line-height:1.1 }
.sp3-cwhen { font-size:calc(var(--font-base) * 0.923); color:var(--lk-text-muted); margin-top:5px }
.sp3-crows { border-top:.5px solid color-mix(in srgb, var(--lk-border-soft) 40%, transparent); padding:5px 0 7px }
.sp3-crow { display:flex; justify-content:space-between; gap:12px; padding:7px 15px; font-size:calc(var(--font-base) * 1.0); position:relative; transition:background .16s ease }
.sp3-crow:hover { background:color-mix(in srgb, var(--lk-text-primary) 3.5%, transparent) }
/* separadores inset: empiezan y terminan con margen, no borde a borde */
.sp3-crow + .sp3-crow::before { content:""; position:absolute; left:15px; right:15px; top:0; height:.5px; background:color-mix(in srgb, var(--lk-border-soft) 34%, transparent) }
.sp3-k { color:var(--lk-text-muted); flex-shrink:0 }
.sp3-v { color:var(--lk-text-primary); text-align:right; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap }
.sp3-v.mono { font-family:ui-monospace,Menlo,monospace; font-size:calc(var(--font-base) * 0.923) }

/* ── tarjeta de PACIENTE · identidad propia (mockup aprobado) ──────────────────
   Cuelga de `.sp3-pac`, que va JUNTO a `.sp3-cita` en la raíz. Así hereda el
   estado seleccionado, el foco y las bajadas de vintage, pero no le toca un
   píxel a la tarjeta de cita: el defecto era, precisamente, que compartían
   clases y el nombre del paciente terminaba en la ranura de un folio. */
.sp3-pac .sp3-chead { padding:14px 16px 12px }
.sp3-pac .sp3-pxid { flex:1; font-family:ui-monospace,Menlo,Consolas,monospace;
  font-size:calc(var(--font-base) * 0.885); color:var(--lk-text-muted); letter-spacing:.02em }
/* El nombre manda: es lo que se vino a buscar. */
.sp3-pac .sp3-pnom { font-size:calc(var(--font-base) * 1.462); font-weight:650;
  letter-spacing:-.015em; line-height:1.2; color:var(--lk-text-primary); padding:0 16px }
.sp3-pac .sp3-pmeta { font-size:calc(var(--font-base) * 0.923); color:var(--lk-text-muted);
  padding:4px 16px 14px }
/* Sin bloque de cita, la meta es lo último antes de las filas y necesita aire. */
.sp3-pac .sp3-pmeta:last-of-type { padding-bottom:14px }

/* Próxima cita · etiqueta + cuánto falta + el dato concreto. */
.sp3-pac .sp3-pcita { margin:0 16px 14px; padding:11px 13px; border-radius:10px;
  background:color-mix(in srgb, var(--c-accent) 10%, transparent);
  border:.5px solid color-mix(in srgb, var(--c-accent) 22%, transparent) }
.sp3-pac .sp3-pcita-top { display:flex; align-items:center; justify-content:space-between; gap:10px }
.sp3-pac .sp3-pcita-k { font-size:calc(var(--font-base) * 0.808); letter-spacing:.09em;
  text-transform:uppercase; font-weight:700; color:var(--lk-text-muted) }
.sp3-pac .sp3-pcita-chip { font-size:calc(var(--font-base) * 0.908); font-weight:600;
  color:var(--c-accent); white-space:nowrap; border-radius:20px; padding:2px 9px;
  font-variant-numeric:tabular-nums;
  background:color-mix(in srgb, var(--c-accent) 16%, transparent);
  border:.5px solid color-mix(in srgb, var(--c-accent) 30%, transparent) }
.sp3-pac .sp3-pcita-v { font-size:calc(var(--font-base) * 1.046); color:var(--lk-text-primary);
  margin-top:6px; line-height:1.35 }

/* Aire en las filas · sube el respiro sin tocar la tarjeta de cita. */
.sp3-pac .sp3-crows { padding:6px 0 8px }
.sp3-pac .sp3-crow { padding:9px 16px }
.sp3-pac .sp3-crow + .sp3-crow::before { left:16px; right:16px }
.sp3-pac .sp3-crow:nth-child(odd) { background:color-mix(in srgb, var(--lk-text-primary) 2.2%, transparent) }
/* El punto del consentimiento, ya dentro de una fila. */
.sp3-pac .sp3-pinline { display:inline-block; margin-right:6px; vertical-align:baseline }
.sp3-mask { font-family:ui-monospace,monospace; letter-spacing:1px; color:var(--lk-text-muted) }

/* bloque "nuevo folio" (reagendas) */
.sp3-cnf { display:flex; align-items:center; gap:10px; margin:2px 15px 12px; padding:10px 12px; border-radius:11px; background:color-mix(in srgb, var(--c-accent) 9%, transparent); border:.5px solid color-mix(in srgb, var(--c-accent) 28%, transparent) }
.sp3-nfic { color:var(--c-accent); display:flex; flex-shrink:0 }
.sp3-nfic svg { width:17px; height:17px; stroke-width:1.8; fill:none; stroke:currentColor }
.sp3-nflbl { font-size:calc(var(--font-base) * 0.808); color:var(--lk-text-muted) }
.sp3-nffolio { font-family:ui-monospace,Menlo,monospace; font-size:calc(var(--font-base) * 1.0); color:var(--c-accent); font-weight:500 }
.sp3-nfwhen { font-size:calc(var(--font-base) * 0.885); color:var(--lk-text-muted); margin-top:1px }

/* footer LUZOguard de la tarjeta (Ley 20.584) */
.sp3-cfoot { display:flex; align-items:center; gap:8px; padding:9px 15px; border-top:.5px solid color-mix(in srgb, var(--lk-border-soft) 40%, transparent); font-size:calc(var(--font-base) * 0.885); color:var(--lk-text-muted); background:color-mix(in srgb, var(--c-accent) 6%, transparent) }
.sp3-cfoot svg { width:14px; height:14px; stroke:var(--c-accent); stroke-width:1.7; fill:none; flex-shrink:0 }
.sp3-cfoot b { color:var(--lk-text-secondary); font-weight:500 }

/* ── Estados (nacen canónicos) ──────────────────────────────────────────────── */
.sp3-gerr { display:flex; align-items:center; gap:9px; padding:10px 16px; font-size:calc(var(--font-base) * 0.962); color:var(--lk-text-muted) }
.sp3-gerr svg { width:15px; height:15px; stroke-width:1.8; fill:none }
.sp3-gerr.net { color:var(--lk-amber) }
.sp3-gerr.srv { color:var(--lk-red) }
.sp3-retry { margin-left:auto; font-size:calc(var(--font-base) * 0.846); padding:2px 8px; border-radius:5px; border:.5px solid var(--lk-border);
             background:none; color:var(--lk-text-secondary); cursor:pointer; font-family:inherit }
.sp3-retry:hover { background:var(--sp3-field) }
.sp3-skel { padding:8px 16px; display:flex; align-items:center; gap:10px }
.sp3-sk { height:9px; border-radius:5px; background:var(--sp3-field); animation:sp3pulse 1.1s ease-in-out infinite }
@keyframes sp3pulse { 0%,100%{opacity:.45} 50%{opacity:.9} }

/* accesibilidad / motion */
@media (prefers-reduced-motion: reduce) {
  .sp3-sk { animation:none }
  dialog.sp3-overlay[open] .sp3-modal { animation:none }
  .sp3-item .sp3-ico, .sp3-item, .sp3-crow, .sp3-cita { transition:none }
}
.sp3-item:focus-visible, .sp3-cita:focus-visible { outline:2px solid var(--c-accent); outline-offset:-2px }

/* ══════════════════════════════════════════════════════════════════════════════
 * SP4 · pulido responsive + vintage + hit-targets + motion (cierra SPOT-15)
 * Solo CSS: el DOM del motor no cambia. Tokens canónicos; sombras/edges por rgba
 * (misma convención del archivo). Se anima solo transform (compositor puro).
 * ══════════════════════════════════════════════════════════════════════════════ */

/* ══════════════════════════════════════════════════════════════════════════════
 * CARA COMPACTA · hoja inferior (patrón iOS/Android)
 * ------------------------------------------------------------------------------
 * QUIÉN DECIDE (RESP-01/03/04). Este bloque colgaba de
 * `@media (max-width: 600px)` — un corte de VIEWPORT, inventado, que además
 * tomaba prestado el 600 del eje de CONTENEDOR. Medido antes de arreglarlo:
 *   · 601–639 px: el chasis ya era teléfono (corta en 640) y la paleta seguía
 *     saliendo como modal centrado de escritorio;
 *   · 640–1023 px (toda la tablet): `LK.viewport.isMobile()` decía «compacta» y
 *     la paleta montaba escritorio igual.
 * Ahora no hay ni una consulta de medios acá: `view.js::vestir()` pregunta a
 * `LK.viewport` y publica `data-cara` en el <dialog>. Un corte menos en el
 * árbol, y los dos que quedan son los del contrato.
 *
 * El corte fino teléfono/tablet DENTRO de la cara compacta sí es de este
 * archivo, y sale de `:root[data-bp]`, que el shell ya publica — no de un
 * `@media` nuevo.
 * ══════════════════════════════════════════════════════════════════════════════ */
dialog.sp3-overlay[data-cara="compacta"][open] { align-items:flex-end; justify-content:center; padding-top:0 }
dialog.sp3-overlay[data-cara="compacta"] .sp3-modal {
  position:relative;
  width:100vw; max-width:100vw;
  max-height:88vh; max-height:88dvh;                 /* RESP-15 */
  border-radius:20px 20px 0 0; border-bottom:none;
  box-shadow:0 -12px 40px rgba(0,0,0,.30), inset 0 .5px 0 var(--sp3-edge);
  padding-bottom:env(safe-area-inset-bottom, 0px);   /* PWA-06 */
  /* EL MODAL ES EL QUE SE DESPLAZA, no el cuerpo, y es a propósito: LK.sheet no
     arranca el arrastre «si la hoja está desplazada por dentro», y ese guardia
     mira `hoja.scrollTop`. Con el scroll en `.sp3-body` el modal marcaba cero
     para siempre y bajar el dedo sobre una lista ya recorrida habría cerrado la
     hoja. RESP-13 · overscroll-behavior:contain para que el gesto no se escape
     al documento. */
  overflow-y:auto; overflow-x:hidden; overscroll-behavior:contain;
}
dialog.sp3-overlay[data-cara="compacta"] .sp3-body { flex:0 0 auto; overflow:visible }

/* Manija de arrastre · elemento REAL (`.spm-grip`), no un ::before decorativo:
   así se puede tocar, medir y esconder por separado. Va pegada arriba junto con
   la barra para que buscar siga a mano con la lista recorrida. */
.spm-grip { position:sticky; top:0; z-index:3; display:flex; justify-content:center;
  padding:7px 0 3px; background:var(--lk-bg-card) }
.spm-handle { width:36px; height:4px; border-radius:99px; background:var(--lk-border) }
dialog.sp3-overlay[data-cara="compacta"] .sp3-bar { position:sticky; top:14px; z-index:3;
  background:var(--lk-bg-card); min-height:52px }

/* «Cancelar» reemplaza a los keycaps ⌘K: es la salida con el dedo. Blanco de
   toque por ÁREA (RESP-14), sin agrandar el texto. */
.spm-cancel { border:0; background:none; padding:0 2px; margin-left:4px; flex-shrink:0;
  font:inherit; font-size:calc(var(--font-base) * 1.0); color:var(--c-accent);
  cursor:pointer; position:relative }
.spm-cancel::before { content:""; position:absolute; inset:-13px -8px }
.spm-cancel:focus-visible { outline:2px solid var(--c-accent); outline-offset:2px; border-radius:6px }

/* Pie de la cara compacta · en reposo va VACÍO y desaparece; sólo sale el
   «Volver» de la hoja de acciones. Nada de keycaps: no hay teclado. */
dialog.sp3-overlay[data-cara="compacta"] .sp3-footer:empty { display:none }
dialog.sp3-overlay[data-cara="compacta"] .sp3-footer { padding:8px 12px calc(8px + env(safe-area-inset-bottom, 0px)) }
.spm-volver { flex:1; min-height:44px; border:.5px solid var(--lk-border); border-radius:11px;
  background:var(--sp3-field); color:var(--lk-text-primary); font:inherit;
  font-size:calc(var(--font-base) * 1.038); cursor:pointer }
.spm-volver:focus-visible { outline:2px solid var(--c-accent); outline-offset:-2px }

/* Blancos de toque y respiro de la lista, sólo en esta cara. */
dialog.sp3-overlay[data-cara="compacta"] .sp3-item { min-height:44px; padding:9px 12px; margin:1px 6px }
dialog.sp3-overlay[data-cara="compacta"] .sp3-crow { padding-top:9px; padding-bottom:9px }
dialog.sp3-overlay[data-cara="compacta"] .sp3-retry { min-height:40px }

/* ── El corte fino, por data-bp (RESP-02/04) ───────────────────────────────────
   En TABLET la cara compacta también se monta (isMobile() = teléfono Y tablet),
   pero una hoja a 1023 px de ancho no es una hoja: es una pared. Se le da el
   mismo ancho protagónico de la cara de escritorio, apoyada abajo. */
:root[data-bp="tablet"] dialog.sp3-overlay[data-cara="compacta"] .sp3-modal {
  width:min(620px, calc(100vw - 40px)); max-width:min(620px, calc(100vw - 40px));
  border-radius:20px 20px 0 0;
}

/* Entrada · el mismo recorrido de la hoja canónica del chasis. RESP-10: era
   `.34s cubic-bezier(.22,1,.36,1)`, que ES --lk-dur-4 + --lk-ease-out escritos
   a mano. Ahora se piden por nombre. */
dialog.sp3-overlay[data-cara="compacta"][open] .sp3-modal {
  animation:sp3sheetin var(--lk-dur-4, .34s) var(--lk-ease-out, cubic-bezier(.22,1,.36,1)) both }
@keyframes sp3sheetin { from { transform:translateY(100%) } to { transform:translateY(0) } }

/* ── Vintage (data-mode · SHELL-13): material PLANO ──────────────────────────── */
[data-mode="vintage"] .sp3-modal {
  box-shadow:none; border:.5px solid var(--lk-border);
  -webkit-backdrop-filter:none; backdrop-filter:none;
}
[data-mode="vintage"] .sp3-item.on,
[data-mode="vintage"] .sp3-cita.on,
[data-mode="vintage"] .sp3-cita { box-shadow:none }
[data-mode="vintage"] dialog.sp3-overlay[data-cara="compacta"] .sp3-modal { box-shadow:none }

/* ── Motion reducido: el sheet TAMPOCO se desliza (cierra SPOT-15) ───────────── */
/* Al final a propósito. OJO con la especificidad: la cara compacta re-declara la
 * animación con `[data-cara="compacta"][open]`, que pesa MÁS que `[open]` solo —
 * ir más tarde ya no basta, como bastaba cuando era un @media. Por eso acá se
 * apagan las dos por separado. Quitar la segunda línea devuelve el deslizamiento
 * a quien pidió que no se moviera nada. */
@media (prefers-reduced-motion: reduce) {
  dialog.sp3-overlay[open] .sp3-modal { animation:none }
  dialog.sp3-overlay[data-cara="compacta"][open] .sp3-modal { animation:none }
  .spm-grip { transition:none }
}


/* ── css/lk-material.css ── */
/* ══════════════════════════════════════════════════════════════════════════════
   core/css/lk-material.css · APLICACIÓN del eje material (data-mode)
   ──────────────────────────────────────────────────────────────────────────────
   POR QUÉ ESTE ARCHIVO EXISTE, Y POR QUÉ CARGA ÚLTIMO:

   lk-tokens.css DECLARA los valores del material (--lk-surface-fill, -blur,
   --lk-specular, --lk-ambient). Pero declarar no basta: cada superficie del
   sistema escribe su propio `background: var(--lk-bg-card)` opaco, y esos
   archivos (lk-layout, lk-components, los módulos) cargan DESPUÉS de tokens.
   Una regla de material escrita en tokens.css la pisa cualquiera de ellos.

   Por eso la aplicación vive acá y este archivo va ÚLTIMO en core.order.json:
   es el único punto donde el material puede ganarle al fondo opaco que cada
   superficie declara por su cuenta.

   REGLA DE ALCANCE — el desenfoque solo va donde NO hay scroll detrás:
     SÍ:  riel, panel, barras superiores, dock, hoja móvil, menús, modales.
     NO:  la grilla de agenda, listas, tablas, el contenido del módulo.
   `backdrop-filter` obliga al navegador a recomponer el fondo en cada cuadro;
   sobre algo que se desplaza es el peor caso de rendimiento que existe.

   En grafito y tint --lk-surface-blur vale `none` y --lk-surface-fill es el
   fondo opaco: estas mismas reglas quedan inertes sin necesidad de apagarlas.
   ══════════════════════════════════════════════════════════════════════════════ */


/* ── EL VIDRIO ALCANZA A TODA SUPERFICIE, SIN NOMBRARLAS ───────────────────
   Cada módulo escribe `background: var(--lk-bg-card)` en sus tarjetas. Listar
   una por una era perseguir nombres: aparece un módulo nuevo y queda opaco.

   En vez de eso se vuelve translúcido el PROPIO --lk-bg-card cuando el material
   es glass. Toda superficie que ya lo usaba obedece sola, sin tocar un archivo
   de módulo. --lk-bg-card-solid guarda el valor opaco para quien lo necesite
   (y para que el relleno de las barras no se transparente dos veces).

   Sin desenfoque: detrás de una tarjeta quieta solo está la luz de ambiente,
   que es estática. Translucidez sí, recomposición por cuadro no. */

:root,                        [data-theme="lightmode"] { --lk-bg-card-solid: #ffffff; }
[data-theme="darkmode"]                                { --lk-bg-card-solid: #1e1e1e; }
[data-theme="midnight"]                                { --lk-bg-card-solid: #141824; }
[data-theme="darkmode"][data-mode="tint"]              { --lk-bg-card-solid: #121215; }
[data-theme="midnight"][data-mode="tint"]              { --lk-bg-card-solid: #0d1017; }

[data-mode="glass"] {
  /* --lk-bg-card queda OPACO: el CONTENIDO (tarjetas, listas, tablas, KPIs, paneles
     y modales de módulo) NUNCA se transparenta — regla del usuario, y coincide con
     el "NO: listas/tablas/contenido" de este mismo encabezado. El vidrio se limita
     al CHROME y a las capas flotantes, que pintan con --lk-surface-fill (abajo). */
  --lk-bg-card:      var(--lk-bg-card-solid);
  --lk-surface-fill: color-mix(in srgb, var(--lk-bg-card-solid) 42%, transparent);
}

/* Lo que NO puede transparentarse: encima suele haber texto sobre texto. */
[data-mode="glass"] input,
[data-mode="glass"] select,
[data-mode="glass"] textarea,
[data-mode="glass"] .lk-modal-ov { --lk-bg-card: var(--lk-bg-card-solid); }

/* ── LUZ DE AMBIENTE VISIBLE ───────────────────────────────────────────────
   El area de contenido lleva la luz; los contenedores de modulo que pintan el
   fondo del cuerpo se vuelven transparentes para no taparla. Asi el fondo deja
   de ser negro muerto y el material glass tiene algo que filtrar detras. */
.tx-content{
  background-image: var(--lk-ambient, none);
  background-repeat: no-repeat;
}
/* contenedores raiz de modulo que hoy repintan el fondo del cuerpo → transparentes */
.tx-content > .cfg,
.tx-content > [class$="-root"],
.tx-content > [class$="-wrap"]{
  background: transparent;
}

/* P360 y Agenda no terminan en -root/-wrap. En Glass, sus fondos opacos quedaban
   detrás de la propia topbar y anulaban visualmente surface-fill + blur. */
[data-mode="glass"] .tx-content .p3:not(.p3-ohost),
[data-mode="glass"] .tx-content .agw {
  background: transparent;
}


/* ── CROMADO DEL SHELL ─────────────────────────────────────────────────────
   Riel, panel, barra superior, pie, dock y hoja móvil. Cuando el material es
   translúcido, por detrás asoma la luz de ambiente del body — que es lo que
   da la sensación de profundidad sin aclarar ninguna superficie. */

/* #shellSheet SALIÓ de esta familia el 4-ago-2026 (mockup 2118acd6, aprobado).
   Seguía al eje del material como el riel y el panel, así que fuera del modo
   vidrio quedaba sólida mientras el dock —que está pegado a ella y es vidrio
   siempre— seguía siendo translúcido. Su material lo define ahora una sola regla,
   en lk-layout.css, junto con las otras tres hojas del sistema. */
.ul0-rail,
.ul1-panel,
.tx-top,
.tx-footer {
  background: var(--lk-surface-fill, var(--lk-bg-card));
  -webkit-backdrop-filter: var(--lk-surface-blur, none);
  backdrop-filter: var(--lk-surface-blur, none);
  box-shadow: var(--lk-specular, none);
}

/* El dock ya lo hace en lk-layout.css (es su propia regla de posición);
   acá solo se le suma el canto iluminado para que no quede fuera del sistema. */
.bn-bar { box-shadow: var(--lk-shadow-lg), var(--lk-specular, none); }


/* ── BARRAS DE MÓDULO ──────────────────────────────────────────────────────
   Cada módulo se hizo la suya antes de que existiera el contrato de barra.
   Se listan por nombre en vez de inventar una clase común: renombrarlas es
   otra tarea (el contrato de barra), y hasta que ocurra esto las alcanza a
   todas sin tocar un solo archivo de módulo. */

.rv2-topbar,
.p3e-modbar,
.agw .topbar,
.cfg-sg-topbar {
  background: var(--lk-surface-fill, var(--lk-bg-card));
  -webkit-backdrop-filter: var(--lk-surface-blur, none);
  backdrop-filter: var(--lk-surface-blur, none);
  box-shadow: var(--lk-specular, none);
}


/* ── CAPAS FLOTANTES ───────────────────────────────────────────────────────
   Lo que flota SIEMPRE tiene contenido detrás: es donde el vidrio se nota y
   donde además tiene sentido, porque el desenfoque separa capa de contenido. */

.pop,
.lkctx,
.lk-modal-box,
.sp3-modal,
.spotlight-bar,
.lk-dropdown {
  background: var(--lk-surface-fill, var(--lk-bg-card));
  -webkit-backdrop-filter: var(--lk-surface-blur, none);
  backdrop-filter: var(--lk-surface-blur, none);
}
.pop, .lkctx, .lk-modal-box, .sp3-modal, .lk-dropdown {
  box-shadow: var(--lk-shadow-lg), var(--lk-specular, none);
}


/* ── VIDRIO SIN COSTO ──────────────────────────────────────────────────────
   Detrás de una superficie grande y quieta solo está la luz de ambiente, que
   es estática: basta bajarle la opacidad al relleno, sin desenfocar nada. Se
   ve como vidrio y no cuesta un cuadro, porque no hay nada que recomponer.
   Es lo que permite subir la sensación de vidrio sin subir la cuenta. */

/* (la lista de tarjetas por nombre se eliminó: --lk-bg-card ya las alcanza) */


/* ── ACCESIBILIDAD ─────────────────────────────────────────────────────────
   Reducir movimiento apaga el desenfoque en TODO, sea cual sea el material.
   No es preferencia estética: quien lo pide lo necesita. */

html[data-motion="reduced"] *,
html[data-motion="reduced"] *::before,
html[data-motion="reduced"] *::after {
  -webkit-backdrop-filter: none !important;
  backdrop-filter: none !important;
}
html[data-motion="reduced"] .ul0-rail,
html[data-motion="reduced"] .ul1-panel,
html[data-motion="reduced"] .tx-top,
html[data-motion="reduced"] .bn-bar,
html[data-motion="reduced"] #shellSheet,
html[data-motion="reduced"] .pop,
html[data-motion="reduced"] .lkctx,
html[data-motion="reduced"] .lk-modal-box {
  background: var(--lk-bg-card);
}

@media (prefers-reduced-motion: reduce) {
  .ul0-rail, .ul1-panel, .tx-top, .bn-bar, #shellSheet,
  .pop, .lkctx, .lk-modal-box, .sp3-modal, .spotlight-bar {
    -webkit-backdrop-filter: none !important;
    backdrop-filter: none !important;
    background: var(--lk-bg-card);
  }
}


/* ── FONDO ÚNICO CON LUZ · un solo lienzo para todo el responsive ──────────────
   La luz de ambiente vive en el body (lk-layout). Las capas intermedias del shell
   y los contenedores de módulo se vuelven transparentes para dejarla ver: así el
   fondo iluminado es el mismo y continuo en escritorio, tablet y teléfono.
   No toca tarjetas, barras ni dock — esos llevan su propio material. */
#lz-shell,
.tx-main,
.tx-content,
.tx-content > .cfg,
.tx-content > [class$="-root"],
.tx-content > [class$="-wrap"],
.tx-content > [class$="-shell"],
.tx-content > [class*="-app"]{
  background: transparent !important;
}
/* La luz también en el body a nivel más presente (capa base, detrás de todo) */
body{ background-image: var(--lk-ambient, none) !important; } /* iOS: sin attachment:fixed (franja negra safe-area en PWA) */


/* ── css/lk-glass.css ── */
/* ══════════════════════════════════════════════════════════════════════════════
   core/css/lk-glass.css · CAPA DE VIDRIO · LUZOcrm
   ──────────────────────────────────────────────────────────────────────────────
   El material `glass` como sistema, con el RENDIMIENTO como primera regla.

   LA LECCIÓN QUE COSTÓ: `backdrop-filter` es caro — el navegador recompone lo que
   hay detrás en CADA cuadro. Ponerlo en superficies PERMANENTES (riel, panel,
   barra, buscador) hace que cada clic, scroll o animación pague ese costo una y
   otra vez. La experiencia se degrada con el uso. Ese fue el error.

   LA ARQUITECTURA CORRECTA · dos familias:

     1. SUPERFICIES PERMANENTES (riel, panel, barra superior, buscador del hero):
        están FIJAS. Detrás solo tienen la luz de ambiente, que es estática — un
        desenfoque no cambiaría nada visible. Se hacen TRANSLÚCIDAS sin desenfoque:
        se ven de vidrio (dejan pasar la luz) y cuestan CERO por cuadro.

     2. SUPERFICIES EFÍMERAS (menús, modales, spotlight, dropdown) + DOCK móvil:
        aparecen brevemente o son únicas, y detrás SÍ pasa contenido real. Ahí el
        desenfoque aporta y su costo es puntual, no permanente. Llevan blur real.

   Resultado: el vidrio se ve en todo el sistema, pero el desenfoque continuo vive
   en una sola superficie a la vez (el modal/menú abierto), no en cinco fijas.

   Cuelga de `[data-mode="glass"]`; en grafito/tint no existe. Carga tras material.
   ══════════════════════════════════════════════════════════════════════════════ */

/* ── FAMILIA 1 · PERMANENTES · translúcidas SIN desenfoque (costo cero/cuadro) ──
   El relleno semi-opaco sobre la luz de ambiente da el efecto vidrio. El canto de
   luz arriba lo remata. Nada de backdrop-filter: son fijas, no hay qué desenfocar. */
[data-mode="glass"] .ul0-rail,
[data-mode="glass"] .ul1-panel,
[data-mode="glass"] .tx-top,
[data-mode="glass"] .lz-mod-topbar,
[data-mode="glass"] .spotlight-bar{
  background: var(--lk-surface-fill);
  box-shadow: var(--lk-specular);
}

/* Canto de luz en el borde superior de las barras horizontales */
/* ATENCION antes de meter aqui una barra o un panel: este selector
   ([data-mode] .clase = 0,2,0) le gana a la regla del propio componente (0,1,0)
   y le pisa el `position`. Si el componente usa `sticky` para quedarse arriba al
   hacer scroll, meterlo en esta lista se lo convierte en `relative` y deja de
   pegarse — solo en modo glass, y sin que nada lo delate leyendo su CSS. Es el
   mismo patron que mato al menu contextual el 30-jul-2026.
   Un ::before/::after de canto de luz NO necesita `relative`: `fixed` y `sticky`
   tambien son ancestros posicionados. */
[data-mode="glass"] .tx-top{ position: relative; }
[data-mode="glass"] .tx-top::after,
[data-mode="glass"] .lz-mod-topbar::after{
  content: "";
  position: absolute; inset: 0 0 auto 0; height: 1px;
  background: linear-gradient(90deg, transparent, rgba(255,255,255,.10) 25%,
    rgba(255,255,255,.10) 75%, transparent);
  pointer-events: none;
}

/* ── FAMILIA 2a · MENÚS · vidrio pleno, igual que el chasis ─────────────────────
   HISTORIA DE ESTA CIFRA (leer antes de volver a moverla):
   Estuvo en 88% —casi sólido— para que el texto de abajo no se mezclara con el del
   menú. El efecto colateral fue que el vidrio dejaba de percibirse: con solo un 12%
   de fondo asomando, un menú en glass se veía IDÉNTICO a uno en grafito. Verificado
   capturando el mismo menú en ambos materiales, uno tras otro.

   El 30-jul-2026 el dueño lo revisó sobre una comparativa de 88 / 62 / 42 y eligió
   42% —el mismo relleno que riel, panel y barra— ACEPTANDO EXPLÍCITAMENTE el riesgo
   de que, sobre una tabla densa, el texto de abajo asome. Es una decisión suya, no
   un descuido: no subir esta cifra sin preguntarle.

   Se mantiene el color OPACO como base (--lk-bg-card-solid), no --lk-bg-card, para
   no transparentar dos veces. */
[data-mode="glass"] .pop,
[data-mode="glass"] .lkctx,
[data-mode="glass"] .lkdd,
[data-mode="glass"] .lk-dropdown{
  background: color-mix(in srgb, var(--lk-bg-card-solid, var(--lk-bg-card)) 62%, transparent);
  -webkit-backdrop-filter: var(--lk-surface-blur);
  backdrop-filter: var(--lk-surface-blur);
  box-shadow: var(--lk-shadow-lg), var(--lk-specular);
}

/* ── FAMILIA 2a-bis · LOS MENÚS QUE VIVÍAN FUERA DEL SISTEMA ────────────────────
   AUDITORÍA DEL 30-jul-2026. La regla de arriba solo cubría .pop / .lkctx /
   .lk-dropdown / .rv-tbm, pero el sistema tiene MÁS superficies de menú y cada una
   traía su opacidad a mano. Medido en la app real, en glass + midnight:

     .lk-account-pop  (menú del avatar) ....  94%  · regla propia en lk-components
     .rv-tbm .rv-menu .cc-menu .agw .ctx ...  85%  · bloque !important de la
                                                     normalización del design system
     .lks-drop        (panel del selector) . 100%  · opaco entero

   Por eso bajar la cifra de la FAMILIA 2a no se notó: el dueño abría un menú y lo
   seguía viendo sólido, porque el que abría no era ninguno de los cuatro cubiertos.

   POR QUÉ `!important` ACÁ, que normalmente no se usa: el bloque de normalización
   `.agw .ctx, .rv-menu, .cc-menu` declara fondo y desenfoque CON
   `!important`. Contra `!important` no alcanza con tener más especificidad: hay
   que igualar la importancia y ganar por especificidad. De ahí el prefijo
   [data-mode="glass"] (una clase más) MÁS `!important`. Sin las dos cosas la regla
   no se aplica y el menú sigue sólido. Si algún día ese bloque deja de usar
   `!important`, acá se puede quitar también.

   FUERA a propósito: los CAMPOS de formulario (.lz-select y compañía). El sistema
   los mantiene opacos porque encima va texto sobre texto. */
[data-mode="glass"] .lk-account-pop,
[data-mode="glass"] .lks-drop,
[data-mode="glass"] .rv-menu,
[data-mode="glass"] .cc-menu,
/* Los que todavia NO estan migrados a las piezas del core siguen teniendo su
   propio JS, pero NO hay razon para que se vean opacos mientras tanto: entran
   aqui y toman la misma perilla de menu que el resto. */
[data-mode="glass"] .op-menu,
[data-mode="glass"] .sadm-dd-menu,
[data-mode="glass"] .p3e-pop,
[data-mode="glass"] .cv-menu,
[data-mode="glass"] .ctr-dd,
[data-mode="glass"] .rv-dd-menu,
[data-mode="glass"] .prof-menu,
[data-mode="glass"] .ag-compound-pop,
[data-mode="glass"] .sadm-compound-pop{
  background: var(--lk-fill-menu) !important;
  -webkit-backdrop-filter: var(--lk-surface-blur) !important;
  backdrop-filter: var(--lk-surface-blur) !important;
  box-shadow: var(--lk-shadow-lg), var(--lk-specular);
}

/* ── FAMILIA 2b · SUPERFICIES GRANDES EFÍMERAS + DOCK · translúcidas + blur ─────
   Modal, spotlight, hoja móvil y dock: grandes, con contenido detrás que vale la
   pena desenfocar. Aquí el vidrio translúcido sí se aprecia sin comerse la lectura. */
/* #shellSheet SALIÓ de esta familia el 4-ago-2026 (mockup 2118acd6, aprobado).
   Estaba clasificada como superficie efímera grande y por eso tomaba
   --lk-fill-modal (72%), mientras el riel, el panel y la barra superior iban al
   42%: la hoja se veía un escalón más opaca que el resto del chasis, que es lo
   que el mockup llamó "la misma hoja, cuatro veces, cada una distinta". Su
   material lo define ahora una sola regla, en lk-layout.css, junto con las otras
   tres hojas del sistema. */
[data-mode="glass"] .lk-modal-box,
[data-mode="glass"] .sp3-modal,
[data-mode="glass"] .bn-bar{
  background: var(--lk-fill-modal);
  -webkit-backdrop-filter: var(--lk-surface-blur);
  backdrop-filter: var(--lk-surface-blur);
  box-shadow: var(--lk-shadow-lg), var(--lk-specular);
}

/* ── FAMILIA 2b-bis · EL BUSCADOR, un escalon mas de vidrio ─────────────────────
   Decision del dueno (31-jul-2026), opcion "Intermedio" de una comparativa de tres
   niveles medida sobre el buscador real. El panel baja su relleno un escalon (72 ->
   62%, el mismo valor que ya usan los menus) y sube el desenfoque (30 -> 42px).
   VA APARTE de la FAMILIA 2b a proposito: si se cambiara el valor de arriba, el
   mismo salto se lo comerian tambien los modales, la hoja movil y el dock, que
   nadie pidio mover. La saturacion se deja en 200% (la del token compartido).
   El desenfoque sube JUNTO con el vidrio, no por gusto: al dejar pasar mas fondo,
   es lo unico que impide que el texto de la pantalla de atras se lea a traves.
   Los bloques de movimiento reducido que vienen mas abajo siguen ganando y dejan
   el panel solido, como hasta ahora. */
[data-mode="glass"] .sp3-modal{
  background: color-mix(in srgb, var(--lk-bg-card-solid, var(--lk-bg-card)) 62%, transparent);
  -webkit-backdrop-filter: blur(42px) saturate(200%);
  backdrop-filter: blur(42px) saturate(200%);
}

/* Canto en los flotantes con cabecera.
   ATENCION: aqui NO va .lkctx. El menu contextual se posiciona con position:fixed
   contra la pantalla, y este selector ([data-mode] .clase = especificidad 0,2,0) le
   ganaba a la del componente (.lkctx = 0,1,0) y se lo cambiaba a relative. Sin fixed,
   las coordenadas del puntero se aplicaban como desplazamiento en el flujo y el panel
   se dibujaba al final del documento, fuera de la pantalla: el menu existia, estaba
   completo y era operable, pero el usuario no veia nada al hacer clic secundario.
   Solo ocurria en modo glass, que es justamente el que usa el dueno.
   El relative no hacia falta: ::before se posiciona igual contra un padre fixed,
   porque fixed tambien es un ancestro posicionado. */
[data-mode="glass"] .lk-modal-box,
[data-mode="glass"] .pop{ position: relative; }
[data-mode="glass"] .lk-modal-box::before,
[data-mode="glass"] .lkctx::before,
[data-mode="glass"] .pop::before{
  content: "";
  position: absolute; inset: 0 0 auto 0; height: 1px;
  background: linear-gradient(90deg, transparent, rgba(255,255,255,.12) 20%,
    rgba(255,255,255,.12) 80%, transparent);
  pointer-events: none; z-index: 1;
}

/* ── SUPERFICIES DE CONTENIDO · vidrio sin desenfoque (gratis) ──────────────────
   Tarjetas y secciones: translúcidas sobre la luz, sin blur (scroll barato). */
[data-mode="glass"] .lk-card,
[data-mode="glass"] .lkm-sec,
[data-mode="glass"] .cfg-ap-card,
/* `.cfg-card` salió de aquí: el módulo cfg la retiró (no la emitía ninguna vista),
   así que este selector ya no alcanzaba a nada. `.cfg-sg-card` sigue viva. */
[data-mode="glass"] .cfg-sg-card{
  background: var(--lk-surface-fill);
  box-shadow: var(--lk-shadow-sm), var(--lk-specular);
}

/* Campos NO se transparentan (texto sobre texto). El buscador SÍ (va sobre la barra). */
[data-mode="glass"] input,
[data-mode="glass"] select,
[data-mode="glass"] textarea{
  background: var(--lk-bg-card-solid, var(--lk-bg-card));
}
[data-mode="glass"] .sp3-input,
[data-mode="glass"] .spotlight-input{ background: transparent !important; }

/* El velo del modal se mantiene opaco: separa el vidrio del fondo real */
[data-mode="glass"] .lk-modal-ov{ background: rgba(0,0,0,.5); }
/* velo de modal SIEMPRE sin desenfoque (regla del usuario), sea cual sea material/tema */
.lk-modal-ov{ -webkit-backdrop-filter:none !important; backdrop-filter:none !important; }

/* ── ACCESIBILIDAD · reducir movimiento apaga el desenfoque restante ────────────
   Cae a sólido legible; también es la salida para equipos muy lentos. */
@media (prefers-reduced-motion: reduce){
  [data-mode="glass"] .pop,
  [data-mode="glass"] .lkctx,
  [data-mode="glass"] .lkdd,
  [data-mode="glass"] .lk-dropdown,
  [data-mode="glass"] .lk-modal-box,
  [data-mode="glass"] .sp3-modal,
  [data-mode="glass"] #shellSheet,
  [data-mode="glass"] .bn-bar{
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
    background: var(--lk-bg-card-solid, var(--lk-bg-card));
  }
}
/* Los seis de la FAMILIA 2a-bis caen a solido igual que el resto cuando se pide
   reducir movimiento. Con !important porque su regla base lo lleva. */
@media (prefers-reduced-motion: reduce){
  [data-mode="glass"] .lk-account-pop,
  [data-mode="glass"] .lks-drop,
  [data-mode="glass"] .rv-menu,
  [data-mode="glass"] .cc-menu,
  }
html[data-motion="reduced"][data-mode="glass"] .lk-account-pop,
html[data-motion="reduced"][data-mode="glass"] .lks-drop,
html[data-motion="reduced"][data-mode="glass"] .rv-menu,
html[data-motion="reduced"][data-mode="glass"] .cc-menu,
html[data-motion="reduced"]html[data-motion="reduced"][data-mode="glass"] .pop,
html[data-motion="reduced"][data-mode="glass"] .lkctx,
html[data-motion="reduced"][data-mode="glass"] .lkdd,
html[data-motion="reduced"][data-mode="glass"] .lk-dropdown,
html[data-motion="reduced"][data-mode="glass"] .lk-modal-box,
html[data-motion="reduced"][data-mode="glass"] .sp3-modal,
html[data-motion="reduced"][data-mode="glass"] #shellSheet,
html[data-motion="reduced"][data-mode="glass"] .bn-bar{
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  background: var(--lk-bg-card-solid, var(--lk-bg-card));
}


/* ── DOCK · más vidrio que el resto (pieza flotante protagónica en móvil) ───────
   Más translúcido y más desenfoque: se ve el contenido difuminarse debajo al
   hacer scroll. Es una sola superficie, el costo es aceptable. */
[data-mode="glass"] .bn-bar{
  background:
    linear-gradient(180deg,
      color-mix(in srgb, var(--lk-bg-card-solid, var(--lk-bg-card)) 52%, transparent),
      color-mix(in srgb, var(--lk-bg-card-solid, var(--lk-bg-card)) 70%, transparent));
  /* 4-ago-2026 (mockup 2118acd6, aprobado): pasa de blur(40) saturate(180%) al
     desenfoque único del sistema, blur(30) saturate(200%), para que el dock se vea
     igual en los cinco modos. QUEDA DICHO que los 40/180 eran deliberados —lo
     explica el comentario de arriba— y que el dueño decidió unificar igual. Si
     alguna vez se echa de menos ese punto extra de vidrio, es acá. */
  -webkit-backdrop-filter: blur(30px) saturate(200%);
  backdrop-filter: blur(30px) saturate(200%);
  border: .5px solid rgba(255,255,255,.14);
  box-shadow:
    var(--lk-shadow-lg),
    inset 0 1px 0 rgba(255,255,255,.16),
    inset 0 -.5px 0 rgba(255,255,255,.05);
}


/* ── css/lk-motion.css ── */
/* ══════════════════════════════════════════════════════════════════════════════
   core/css/lk-motion.css · CAPA DE MOVIMIENTO · LUZOcrm
   ──────────────────────────────────────────────────────────────────────────────
   Sistema único de animación. Antes cada módulo declaraba sus propias curvas
   (--spring, --out, --ease) y transiciones sueltas; acá viven UNA vez y todo el
   sistema se mueve con el mismo pulso.

   REGLA DE RENDIMIENTO (no negociable): solo se animan `transform`, `opacity`,
   `box-shadow`, `filter` y `backdrop-filter` — propiedades que la GPU compone sin
   recalcular layout. Nunca se anima width/height/top/left/margin en interacción.

   REGLA DE SOBRIEDAD: el movimiento acompaña, no protagoniza. Entradas cortas
   (.18–.32s), micro-interacciones más cortas (.12–.16s), una sola curva por gesto.

   Carga DESPUÉS de lk-material.css. La última palabra en movimiento la tiene el
   bloque de accesibilidad al pie: prefers-reduced-motion apaga todo.
   ══════════════════════════════════════════════════════════════════════════════ */

:root{
  /* Curvas — un vocabulario chico y deliberado */
  --lk-ease-out:    cubic-bezier(.22, 1, .36, 1);      /* salida natural, desacelera */
  --lk-ease-inout:  cubic-bezier(.4, 0, .2, 1);        /* material estándar, simétrica */
  --lk-ease-spring: cubic-bezier(.34, 1.56, .64, 1);   /* rebote sutil, para lo que "aparece" */
  --lk-ease-snap:   cubic-bezier(.5, 0, .1, 1);        /* rápida y firme, para toggles */

  /* Duraciones */
  --lk-dur-1: .12s;   /* micro: hover, active */
  --lk-dur-2: .18s;   /* corta: estados, foco */
  --lk-dur-3: .26s;   /* media: entrada de tarjetas */
  --lk-dur-4: .34s;   /* larga: modales, paneles */
}

/* ── TRANSICIÓN BASE EN LO INTERACTIVO ─────────────────────────────────────
   Todo lo que responde al puntero comparte una transición suave por defecto.
   Los módulos que ya declaran la suya la sobrescriben sin conflicto. */
button, a, .lk-btn, .tbb, [role="button"], [data-set], [data-toggle],
.cfg-ap-card, .cfg-ap-tile, .cfg-ap-swb, .cfg-ap-fb, .cfg-sg-card,
.tile, .lk-card, .lkm-sec, .lkctx-it, .lk-pill, .lk-chip{
  transition:
    background-color var(--lk-dur-2) var(--lk-ease-out),
    border-color     var(--lk-dur-2) var(--lk-ease-out),
    color            var(--lk-dur-2) var(--lk-ease-out),
    box-shadow       var(--lk-dur-2) var(--lk-ease-out),
    transform        var(--lk-dur-1) var(--lk-ease-out);
}

/* Micro-respuesta al presionar: firme, no exagerada */
button:active, .lk-btn:active, .tbb:active, [role="button"]:active,
.cfg-ap-tile:active, .cfg-ap-swb:active{ transform: scale(.975); }

/* Tarjetas: se elevan un pelo al pasar el puntero (la sombra la da el material) */
.lk-card:hover, .cfg-ap-card:hover, .cfg-sg-card:hover{ transform: translateY(-2px); }

/* ── ENTRADAS · lo que aparece, aparece con intención ──────────────────────── */

@keyframes lk-fade-up{
  from{ opacity: 0; transform: translateY(8px); }
  to  { opacity: 1; transform: translateY(0); }
}
@keyframes lk-fade-in{
  from{ opacity: 0; }
  to  { opacity: 1; }
}
@keyframes lk-scale-in{
  from{ opacity: 0; transform: scale(.96); }
  to  { opacity: 1; transform: scale(1); }
}
@keyframes lk-pop-in{        /* con resorte, para menús anclados al cursor */
  0%  { opacity: 0; transform: scale(.92) translateY(-6px); }
  100%{ opacity: 1; transform: scale(1) translateY(0); }
}
@keyframes lk-shimmer{       /* skeletons de carga */
  0%  { background-position: -160% 0; }
  100%{ background-position: 160% 0; }
}

/* Vista de módulo al montar: sube suave. El shell añade .lk-enter al outlet. */
.lk-enter, .tx-content > .cfg, [data-view-enter]{
  animation: lk-fade-up var(--lk-dur-3) var(--lk-ease-out) both;
}

/* Superficies flotantes: aparecen desde su origen */
/* .lkctx NO lleva animación acá: la entrada ya la hace el propio componente con la
   transición de core/css/lk-ctx.css (mismo gesto de resorte, mismas propiedades).
   Tener las dos no era redundancia inofensiva: al declararse con fill-mode `both`, si
   la línea de tiempo de animaciones no avanza —pestaña en segundo plano, ahorro de
   energía, timeline pausada— el fotograma 0% (opacity:0) queda CONGELADO y, como una
   animación gana sobre una declaración normal, pisaba `.lkctx.is-on{opacity:1}`.
   Resultado medido en Chrome: el menú montado, con sus acciones, clickeable... e
   invisible. Era la causa de que el clic secundario "no hiciera nada". Sin animación,
   si la transición tampoco corre el menú simplemente aparece de golpe, que es el modo
   de fallar correcto. Los keyframes lk-pop-in se conservan por si otro los necesita. */
.pop, .lk-dropdown{ animation: lk-scale-in var(--lk-dur-2) var(--lk-ease-out) both; }
.lk-modal-box, .sp3-modal{ animation: lk-scale-in var(--lk-dur-4) var(--lk-ease-spring) both; }
.lk-modal-ov{ animation: lk-fade-in var(--lk-dur-2) var(--lk-ease-out) both; }

/* Tarjetas de una lista/grilla: entran escalonadas y sutiles.
   El escalón lo pone el módulo con --i; sin él, todas entran juntas (fallback 0). */
.lk-stagger > *{
  animation: lk-fade-up var(--lk-dur-3) var(--lk-ease-out) both;
  animation-delay: calc(var(--i, 0) * 40ms);
}

/* Acordeón: el cuerpo abre por grid-rows (0fr→1fr), técnica sin salto de layout */
.cfg-ap-body, .cfg-sg-body{
  transition: grid-template-rows var(--lk-dur-3) var(--lk-ease-inout);
}

/* Skeleton con brillo que recorre */
.lk-skeleton{
  background: linear-gradient(100deg,
    var(--lk-bg-surface) 30%,
    var(--lk-bg-hover) 50%,
    var(--lk-bg-surface) 70%);
  background-size: 220% 100%;
  animation: lk-shimmer 1.4s var(--lk-ease-inout) infinite;
}

/* Punto "en vivo" — respiración lenta, un solo latido a la vez */
@keyframes lk-pulse{ 0%,100%{ opacity: 1 } 50%{ opacity: .4 } }
.lk-pulse, .live-dot, .sync{ animation: lk-pulse 2.4s var(--lk-ease-inout) infinite; }

/* ── ACCESIBILIDAD · la última palabra ─────────────────────────────────────
   Quien pide reducir movimiento —por el sistema operativo o por la casilla de
   Apariencia— recibe TODO sin animación. No es opcional: es una necesidad. */
@media (prefers-reduced-motion: reduce){
  *, *::before, *::after{
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
}
html[data-motion="reduced"] *,
html[data-motion="reduced"] *::before,
html[data-motion="reduced"] *::after{
  animation-duration: .01ms !important;
  animation-iteration-count: 1 !important;
  transition-duration: .01ms !important;
}

/* ── PESTAÑA OCULTA · no gastar bateria animando lo que nadie mira ─────────
   El sistema tiene 65 reglas con `infinite` (pulsos "en vivo", skeletons).
   Sin esto siguen corriendo en segundo plano y el equipo compone cuadros de
   una pantalla que nadie ve. `paused` congela sin reiniciar: al volver, la
   animacion sigue donde estaba. Con la pestaña visible no cambia nada.
   Hermano de data-motion="reduced": misma tecnica, otro disparador. */
html[data-inactivo] *,
html[data-inactivo] *::before,
html[data-inactivo] *::after{
  animation-play-state: paused !important;
}

/* EXCEPCIÓN 1 · LAS ENTRADAS NO SE PAUSAN. NUNCA.
   Tercer incidente de la misma familia (Spotlight en blanco, agenda vacía, y el
   23-ago el calendario tapando el pie por 2 px). La causa es siempre la misma y
   conviene dejarla escrita porque es contraintuitiva:

     `animation-play-state: paused` congela el fotograma ACTUAL. Si la animación
     se crea —o se pausa— dentro de su duración activa, ese fotograma es el
     inicial, y ahí se queda. `animation-fill-mode` NO tiene nada que ver: el
     relleno sólo manda FUERA del intervalo activo, así que quitarle el `both`
     a una entrada no arregla absolutamente nada. Medido, no argumentado.

   Y ojo con `data-inactivo`: no es sólo la pestaña oculta. `core/lk-boot.js:44`
   lo pone tras 15 s SIN INTERACCIÓN con la pestaña A LA VISTA. O sea: el usuario
   está mirando el fotograma congelado.

   Una animación de ENTRADA es finita y dura décimas: no es la que gasta batería.
   Lo que gasta son los 65 `infinite` del sistema —pulsos, esqueletos, auroras—,
   y ésos siguen pausados exactamente igual que antes; esa decisión no se toca.

   Un módulo se apunta poniendo `lk-entrada` en la clase del elemento que anima
   su entrada. Es la adopción de una palabra y evita el cuarto incidente. */
html[data-inactivo] .lk-enter,
html[data-inactivo] .tx-content > .cfg,
html[data-inactivo] [data-view-enter],
html[data-inactivo] .lk-stagger > *,
html[data-inactivo] .pop,
html[data-inactivo] .lk-dropdown,
html[data-inactivo] .lk-modal-ov,
html[data-inactivo] .sp3-modal,
html[data-inactivo] .lk-entrada{
  animation-play-state: running !important;
}

/* EXCEPCIÓN 2 · un modal en PRIMER PLANO se está mirando aunque la pestaña esté
   marcada inactiva (ventana ocluida, App Nap, otro monitor). Sus animaciones de
   ENTRADA gatean la visibilidad (opacity 0→1 con fill:both): pausarlas deja el
   modal EN BLANCO —era el bug del Spotlight—. Se reanudan sólo dentro de un
   dialog abierto o una caja de modal; el resto (pulsos/skeletons de fondo)
   sigue pausado. Mayor especificidad que la regla de arriba, así que gana. */
html[data-inactivo] dialog[open],
html[data-inactivo] dialog[open] *,
html[data-inactivo] dialog[open] *::before,
html[data-inactivo] dialog[open] *::after,
html[data-inactivo] .lk-modal-box,
html[data-inactivo] .lk-modal-box *{
  animation-play-state: running !important;
}


/* ── css/lk-visor-doc.css ── */
/* ══════════════════════════════════════════════════════════════════════════════
   core/css/lk-visor-doc.css · VISOR DE DOCUMENTOS · LUZOkit 2.4
   LUZOcrm V2 / TRANSED ONG
   ───────────────────────────────────────────────────────────────────────────
   Namespace .lk-vd / .vd-*. Todo cuelga de `.lk-vd` para no filtrar al shell.

   El visor ocupa el ÁREA DE TRABAJO (`.tx-content`), no la ventana: el riel, el
   panel, la barra de cuenta y la búsqueda siguen en su sitio. Por eso se ancla
   con `absolute` sobre esa área, que ya es `position:relative; overflow:hidden`.

   ADAPTACIÓN. En el marco del visor no hay un solo ancho fijo: lienzo, barra y
   cajón se dimensionan en relativo. El ÚNICO ancho fijo es el del papel, y lo
   manda el servidor en `medida`. Los tres regímenes del cajón y las cuatro
   densidades de la barra los decide el JS mirando el ancho del CONTENEDOR —el
   panel lateral de la app se pliega y eso cambia el sitio sin tocar la ventana—
   y los publica como clases `is-cajon-*` / `is-barra-*`.

   Lo que manda el estándar visual vigente:
   · CERO bordes en el contenido. Las superficies se separan por FONDO y SOMBRA.
   · Radios grandes: 20 px las piezas mayores, 11 los botones, 99 los chips.
   · Botones planos: jerarquía por RELLENO y color, no por encierro.
     `:active` hunde con `scale(.975)`.
   · Foco por `box-shadow`, NUNCA `outline`.
   · Sólo tokens `--lk-*`, sin un color escrito a mano: el papel lo pinta el
     documento, no este archivo.
   ══════════════════════════════════════════════════════════════════════════════ */

.lk-vd {
  /* Centinela. El visor monta en línea lo que lo hace superficie (position/
     inset/z-index) para no depender de esta hoja; esta bandera es cómo el JS
     sabe que la hoja SÍ llegó y puede callarse. Si no la ve, avisa por consola. */
  --vd-hoja: 1;

  /* Puentes locales: el estándar los nombra pero lk-tokens.css todavía no los
     publica. Se declaran acá con el valor del estándar y ceden si se publican. */
  --vd-lift: var(--lk-lift, 0 8px 24px -14px rgba(15, 23, 42, .30));
  --vd-ring: var(--lk-ring, var(--lk-ring-focus, 0 0 0 3px color-mix(in srgb, var(--lk-brand) 22%, transparent)));
  --vd-spring: var(--lk-ease-spring, cubic-bezier(.34, 1.56, .64, 1));
  --vd-ease: var(--lk-ease-out, cubic-bezier(.22, 1, .36, 1));
  --vd-press: color-mix(in srgb, var(--lk-text-primary) 9%, transparent);
  --vd-barra: color-mix(in srgb, var(--lk-text-primary) 20%, transparent);
  --vd-barra-viva: color-mix(in srgb, var(--lk-text-primary) 36%, transparent);
  /* Tope, no ancho: el cajón nunca pasa de esto ni se come más del 38 % del sitio.
     Los mismos números viven en el JS, que es quien decide el régimen. */
  --vd-cajon-w: min(344px, 38%);

  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  background: var(--lk-bg-body);
  font-family: var(--lk-font-sans);
  color: var(--lk-text-primary);
  animation: vd-entra .26s var(--vd-ease) both;
}
/* Respaldo: si no existiera el área de trabajo, el JS monta sobre <body> y avisa. */
.lk-vd--suelto { position: fixed; z-index: 860; }

[data-theme="darkmode"] .lk-vd,
[data-theme="midnight"] .lk-vd {
  --vd-lift: var(--lk-lift, 0 10px 30px -14px rgba(0, 0, 0, .75));
  --vd-press: color-mix(in srgb, #ffffff 9%, transparent);
  --vd-barra: color-mix(in srgb, #ffffff 20%, transparent);
  --vd-barra-viva: color-mix(in srgb, #ffffff 34%, transparent);
}

/* ── LAS BARRAS DE DESPLAZAMIENTO ─────────────────────────────────────────────
   Las nativas son claras, anchas y del sistema: sobre una superficie oscura
   desentonan con todo y piden más atención que el propio documento. Acá se visten
   finas, con la PISTA transparente —no aportan color de fondo— y el pulgar apenas
   más claro que la superficie, saliendo sólo cuando el puntero está encima o algo
   tiene el foco dentro.

   Nota honesta sobre «que no robe ancho»: en motores WebKit una barra declarada
   con `::-webkit-scrollbar` OCUPA su ancho; la superposición de verdad sólo la
   daba `overflow: overlay`, que está retirado del estándar. Así que se baja a
   8 px y se vuelve invisible en reposo, que es lo más cerca que se llega sin
   dibujar barras a mano con JS. Firefox sí las superpone con `scrollbar-width`.

   La barra de DENTRO del documento no se puede vestir: el marco va con
   `sandbox=""` y su hoja de estilo es del servidor. Si algún día molesta, se
   arregla allá. */
.lk-vd .vd-lienzo,
.lk-vd .vd-cajon-b {
  scrollbar-width: thin;
  scrollbar-color: transparent transparent;
  transition: scrollbar-color .2s var(--vd-ease);
}
.lk-vd .vd-lienzo:hover, .lk-vd .vd-lienzo:focus-within,
.lk-vd .vd-cajon-b:hover, .lk-vd .vd-cajon-b:focus-within {
  scrollbar-color: var(--vd-barra) transparent;
}
.lk-vd .vd-lienzo::-webkit-scrollbar,
.lk-vd .vd-cajon-b::-webkit-scrollbar { width: 8px; height: 8px; }
.lk-vd .vd-lienzo::-webkit-scrollbar-track,
.lk-vd .vd-cajon-b::-webkit-scrollbar-track,
.lk-vd .vd-lienzo::-webkit-scrollbar-corner,
.lk-vd .vd-cajon-b::-webkit-scrollbar-corner { background: transparent; }
.lk-vd .vd-lienzo::-webkit-scrollbar-thumb,
.lk-vd .vd-cajon-b::-webkit-scrollbar-thumb {
  /* el borde transparente con recorte al contenido deja el pulgar fino y
     despegado del borde, sin dibujar una segunda pista */
  background-color: transparent;
  border: 2px solid transparent;
  background-clip: content-box;
  border-radius: 99px;
  transition: background-color .2s var(--vd-ease);
}
.lk-vd .vd-lienzo:hover::-webkit-scrollbar-thumb,
.lk-vd .vd-lienzo:focus-within::-webkit-scrollbar-thumb,
.lk-vd .vd-cajon-b:hover::-webkit-scrollbar-thumb,
.lk-vd .vd-cajon-b:focus-within::-webkit-scrollbar-thumb { background-color: var(--vd-barra); }
.lk-vd .vd-lienzo::-webkit-scrollbar-thumb:hover,
.lk-vd .vd-cajon-b::-webkit-scrollbar-thumb:hover { background-color: var(--vd-barra-viva); }

@keyframes vd-entra { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }

/* ── BARRA · una tarjeta que flota, no una cinta pegada ────────────────────── */
.lk-vd .vd-top {
  position: relative;
  flex: none;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  margin: 14px 14px 0;
  padding: 12px 16px;
  border-radius: 20px;
  background: var(--lk-bg-card);
  box-shadow: var(--vd-lift);
}
.lk-vd .vd-tx { min-width: 0; flex: 1 1 120px; display: flex; flex-direction: column; gap: 2px; }
.lk-vd .vd-t {
  margin: 0;
  font-size: calc(var(--lk-font-lg, 15px) * 1.15);
  font-weight: 600; letter-spacing: -.022em; line-height: 1.2;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.lk-vd .vd-s {
  margin: 0; font-size: var(--lk-font-sm, 12px); color: var(--lk-text-muted); line-height: 1.35;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.lk-vd .vd-s:empty { display: none; }

/* ── IDENTIDAD · «qué estoy mirando» · spec-VISOR-IMPLANTAR ──────────────────
   estado / folio / período / versión, en chips bajo el título. Sólo el estado
   se pinta con color — borrador ámbar, emitido verde, anulado rojo — el resto
   va neutro: si todo se pinta, nada destaca. `folio` sin valor NO se calla:
   dice «Sin folio», que es información y no un hueco. */
.lk-vd .vd-meta {
  display: flex; flex-wrap: wrap; align-items: center; gap: 5px;
  margin-top: 0; min-width: 0; flex: none;
}
.lk-vd .vd-chip {
  flex: none; display: inline-flex; align-items: center; gap: 5px;
  height: 21px; padding: 0 9px; border-radius: 99px;
  background: var(--lk-bg-surface); color: var(--lk-text-muted);
  font: 500 var(--lk-font-xs, 11px)/1 var(--lk-font-sans);
  letter-spacing: -.002em; white-space: nowrap;
}
.lk-vd .vd-chip--folio { font-family: var(--lk-font-mono); letter-spacing: 0; }
.lk-vd .vd-chip--est { font-weight: 600; }
.lk-vd .vd-chip--est::before { content: ""; width: 6px; height: 6px; border-radius: 99px; background: currentColor; flex: none; }
.lk-vd .vd-chip--est.es-borrador { background: var(--lk-amber-soft); color: var(--lk-amber); }
.lk-vd .vd-chip--est.es-emitido  { background: var(--lk-green-soft); color: var(--lk-green); }
.lk-vd .vd-chip--est.es-anulado  { background: var(--lk-red-soft);   color: var(--lk-red); }

.lk-vd .vd-sp { flex: 1 1 0; min-width: 0; }
/* El corte de fila sólo existe en el ancho mínimo. */
.lk-vd .vd-brk { display: none; }

/* ── PAGINACIÓN · deja de ser etiqueta y pasa a ser navegación ─────────────── */
.lk-vd .vd-pag {
  flex: none; display: inline-flex; align-items: center; gap: 2px;
  padding: 2px; border-radius: 99px; background: var(--lk-bg-surface);
}
.lk-vd .vd-pag[hidden] { display: none; }
.lk-vd .vd-pag button {
  width: 26px; height: 26px; display: grid; place-items: center;
  border: 0; border-radius: 99px; background: transparent; color: var(--lk-text-muted); cursor: pointer;
  transition: background .13s, color .13s, transform .1s var(--vd-spring);
}
.lk-vd .vd-pag button:hover { background: var(--lk-bg-hover); color: var(--lk-text-primary); }
.lk-vd .vd-pag button:active { transform: scale(.9); }
.lk-vd .vd-pag button:focus-visible { outline: none; box-shadow: var(--vd-ring); }
.lk-vd .vd-pag button[disabled] { opacity: .3; pointer-events: none; }
.lk-vd .vd-pag button svg { width: 14px; height: 14px; fill: none; stroke: currentColor; }
.lk-vd .vd-pag-n {
  min-width: 46px; padding: 0 4px; text-align: center;
  font: 600 var(--lk-font-sm, 12px)/1 var(--lk-font-sans);
  color: var(--lk-text-secondary); font-variant-numeric: tabular-nums; white-space: nowrap;
}

/* ── BOTONES · planos, sin encierro ───────────────────────────────────────── */
.lk-vd .vd-btn {
  flex: none;
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  height: 34px; padding: 0 14px;
  border: 0; border-radius: 11px;
  background: var(--lk-bg-surface); color: var(--lk-text-secondary);
  font: 500 var(--lk-font-sm, 12px)/1 var(--lk-font-sans);
  letter-spacing: -.004em; text-decoration: none; white-space: nowrap; cursor: pointer;
  transition: background .14s, color .14s, transform .1s var(--vd-spring);
}
.lk-vd .vd-btn:hover { background: var(--lk-bg-hover); color: var(--lk-text-primary); }
.lk-vd .vd-btn:active { background: var(--vd-press); transform: scale(.975); }
.lk-vd .vd-btn:focus-visible { outline: none; box-shadow: var(--vd-ring); }
.lk-vd .vd-btn svg { width: 15px; height: 15px; flex: none; fill: none; stroke: currentColor; }
.lk-vd .vd-btn--pri { background: var(--lk-brand); color: #fff; font-weight: 600; }
.lk-vd .vd-btn--pri:hover { background: color-mix(in srgb, var(--lk-brand) 86%, #ffffff); color: #fff; }
.lk-vd .vd-btn--pri:active { background: color-mix(in srgb, var(--lk-brand) 92%, #000000); }
.lk-vd .vd-btn--caj.is-on { background: var(--lk-brand-muted); color: var(--lk-brand); font-weight: 600; }
.lk-vd .vd-btn.is-off, .lk-vd .vd-btn[disabled] { opacity: .38; pointer-events: none; }
/* El botón de desbordamiento sólo aparece cuando de verdad hay algo desbordado. */
.lk-vd .vd-btn--mas { width: 34px; padding: 0; display: none; }

/* ── SEGMENTADO de zoom ───────────────────────────────────────────────────── */
.lk-vd .vd-seg {
  flex: none; display: inline-flex; gap: 2px; padding: 2px;
  border-radius: 12px; background: var(--lk-bg-surface);
}
.lk-vd .vd-seg button {
  height: 26px; padding: 0 8px; border: 0; border-radius: 10px; background: none;
  color: var(--lk-text-muted); font: 500 var(--lk-font-xs, 11px)/1 var(--lk-font-sans); cursor: pointer;
  transition: background .14s, color .14s, transform .1s var(--vd-spring);
}
.lk-vd .vd-seg button:hover { color: var(--lk-text-primary); }
.lk-vd .vd-seg button:active { transform: scale(.975); }
.lk-vd .vd-seg button:focus-visible { outline: none; box-shadow: var(--vd-ring); }
.lk-vd .vd-seg button.is-on { background: var(--lk-brand-muted); color: var(--lk-brand); font-weight: 600; }
.lk-vd .vd-seg button[disabled] { opacity: .4; pointer-events: none; }

/* ── MENÚ de desbordamiento ───────────────────────────────────────────────── */
.lk-vd .vd-menu {
  position: absolute; right: 12px; top: calc(100% + 6px); z-index: 6;
  min-width: 214px; max-width: min(280px, calc(100vw - 24px));
  display: none; flex-direction: column; gap: 2px; padding: 6px;
  border-radius: 16px; background: var(--lk-bg-card); box-shadow: var(--vd-lift);
  animation: vd-menu-in .18s var(--vd-ease) both;
}
.lk-vd.is-menu .vd-menu { display: flex; }
@keyframes vd-menu-in { from { opacity: 0; transform: translateY(-6px); } to { opacity: 1; transform: none; } }
.lk-vd .vd-menu-i {
  display: flex; align-items: center; gap: 10px; width: 100%; height: 36px; padding: 0 11px;
  border: 0; border-radius: 10px; background: transparent; color: var(--lk-text-secondary);
  font: 500 var(--lk-font-sm, 12px)/1 var(--lk-font-sans); text-align: left; text-decoration: none;
  cursor: pointer; transition: background .13s, color .13s;
}
.lk-vd .vd-menu-i:hover { background: var(--lk-bg-hover); color: var(--lk-text-primary); }
.lk-vd .vd-menu-i:focus-visible { outline: none; box-shadow: var(--vd-ring); }
.lk-vd .vd-menu-i.is-on { background: var(--lk-brand-muted); color: var(--lk-brand); font-weight: 600; }
.lk-vd .vd-menu-i.is-off, .lk-vd .vd-menu-i[disabled] { opacity: .38; pointer-events: none; }
.lk-vd .vd-menu-i svg { width: 15px; height: 15px; flex: none; fill: none; stroke: currentColor; }

/* ── CUERPO · lienzo + cajón ──────────────────────────────────────────────── */
.lk-vd .vd-cuerpo { position: relative; flex: 1; min-height: 0; display: flex; }

/* `flex-wrap: wrap` NO es decoración, y es el arreglo 4 del 11-ago-2026 ──────────
   El lienzo tiene DOS hijos: el papel y `.vd-min-nota`, la nota del ancho mínimo.
   Sin envolver, los dos comparten renglón. La nota pide `flex: 0 0 100%`, o sea el
   ancho entero del lienzo, así que la línea medía el doble de lo que cabía; y como el
   lienzo centra su contenido, la mitad sobrante se repartía a los dos lados. Medido a
   390 px: el papel escalado mide 366 y el lienzo se desplazaba 183 px a la derecha —
   con otros 183 fuera del alcance por la izquierda. Ése era «el papel se sale y obliga
   a rodar a la derecha»: no era la escala, que ya estaba bien (k=0.449), era la nota
   empujando desde el costado.

   `align-content: flex-start` va con el `wrap`: sin él las dos líneas se reparten el
   alto sobrante y el papel deja de estar arriba. */
.lk-vd .vd-lienzo {
  flex: 1 1 auto; min-width: 0; min-height: 0;
  overflow: auto; padding: 28px;
  display: flex; flex-wrap: wrap; justify-content: center;
  align-items: flex-start; align-content: flex-start;
  overscroll-behavior: contain;
}

/* ── LA HOJA NO PINTA NADA ────────────────────────────────────────────────────
   Es sólo la caja que encuadra y escala. El papel lo pinta el DOCUMENTO: cada
   carilla trae su blanco y su sombra en su propia hoja de estilo, que es donde
   corresponde — un documento sabe de qué color es su papel.

   Pintar aquí un blanco de fondo era lo que convertía el hueco entre carillas en
   una banda ajena: la superficie de la app, una franja del ancho del documento y
   las hojas, tres colores en pantalla. Sin ese fondo, el hueco deja ver el lienzo
   del visor y las hojas quedan FLOTANDO sobre la superficie de la app.

   Y no se añade borde, ni halo, ni sombra propia para «separar» el papel del
   fondo: el blanco contrasta de sobra contra la superficie oscura, y dibujarle un
   marco alrededor sería exactamente lo contrario del estándar. */
.lk-vd .vd-hoja {
  flex: none; position: relative; overflow: hidden;
  background: transparent;
}
/* Un `iframe` pinta un blanco opaco por omisión aunque su documento sea
   transparente: sin esto, el fondo del lienzo no se vería nunca por detrás. */
.lk-vd .vd-marco { display: block; border: 0; transform-origin: top left; background: transparent; }
/* De a una página: la hoja mide UNA carilla y el marco se desplaza dentro. Es lo
   único que se puede hacer sin abrir el sandbox, y alcanza: el alto de página
   sale de `medida`. */
.lk-vd .vd-hoja.is-pagina .vd-marco { position: absolute; left: 0; top: 0; }
/* Sin medida utilizable el documento ocupa el lienzo y se desplaza dentro de sí. */
.lk-vd .vd-hoja.is-libre { width: min(100%, 1100px); height: auto; align-self: stretch; }
.lk-vd .vd-hoja.is-libre .vd-marco { width: 100%; height: 100%; transform: none; }
/* La transición del papel se enciende SÓLO durante el gesto del cajón: dejarla
   puesta haría que arrastrar el borde de la ventana se sintiera con retardo. */
.lk-vd.is-animando .vd-hoja { transition: width .24s var(--vd-ease), height .24s var(--vd-ease); }
.lk-vd.is-animando .vd-marco { transition: transform .24s var(--vd-ease); }

/* La nota honesta del ancho mínimo: a 360 px un facsímil A4 no se lee, y decirlo
   con la salida al lado es mejor que fingir que sí. */
.lk-vd .vd-min-nota {
  display: none; flex: 0 0 100%; margin: 14px 0 0; text-align: center;
  font-size: var(--lk-font-sm, 12px); line-height: 1.5; color: var(--lk-text-muted);
}

/* ── ESTADOS del lienzo ───────────────────────────────────────────────────── */
.lk-vd .vd-estado {
  margin: auto; display: flex; align-items: center; gap: 11px;
  padding: 16px 20px; border-radius: 16px;
  background: var(--lk-bg-card); box-shadow: var(--vd-lift);
  font-size: var(--lk-font-md, 13px); color: var(--lk-text-muted);
}
.lk-vd .vd-estado.is-err { color: var(--lk-red); background: var(--lk-red-soft); box-shadow: none; }
/* Esto SÍ está cargando, así que sí late. El reposo, que espera una decisión y
   no una respuesta, no lleva latido ninguno. */
.lk-vd .vd-lat {
  width: 9px; height: 9px; flex: none; border-radius: 50%;
  background: var(--lk-brand); animation: vd-lat 1.1s ease-in-out infinite;
}
@keyframes vd-lat { 0%, 100% { opacity: .35; transform: scale(.85); } 50% { opacity: 1; transform: scale(1); } }
.lk-vd .vd-reposo { margin: 0 auto; width: 100%; max-width: 820px; }

/* ── CAJÓN · tres regímenes, decididos por el ancho del CONTENEDOR ─────────── */
.lk-vd .vd-cajon {
  flex: none; display: flex; flex-direction: column;
  width: var(--vd-cajon-w);
  margin: 14px 14px 14px 0;
  border-radius: 20px; background: var(--lk-bg-card); box-shadow: var(--vd-lift);
  overflow: hidden;
}
.lk-vd:not(.is-cajon) .vd-cajon { display: none; }

/* 1 · AL LADO mientras quede sitio para el papel. */
.lk-vd.is-cajon-lado .vd-cajon { position: relative; }

/* 2 · ENCIMA cuando exprimir el documento lo dejaría demasiado angosto: 794 px
       reducidos a 300 no están mostrados, están escondidos, y el cajón se cierra. */
.lk-vd.is-cajon-encima .vd-cajon {
  position: absolute; right: 0; top: 0; bottom: 0; z-index: 2;
  width: min(344px, calc(100% - 28px));
  animation: vd-caj .24s var(--vd-ease) both;
}

/* 3 · A TODO EL ANCHO en teléfono: repartir 360 px entre dos cosas no es repartir. */
.lk-vd.is-cajon-lleno .vd-cajon {
  position: absolute; inset: 0; z-index: 2;
  width: auto; margin: 8px; border-radius: 18px;
  animation: vd-caj-sube .24s var(--vd-ease) both;
}
@keyframes vd-caj { from { opacity: 0; transform: translateX(18px); } to { opacity: 1; transform: none; } }
@keyframes vd-caj-sube { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: none; } }

.lk-vd .vd-cajon-h { flex: none; display: flex; align-items: center; gap: 10px; padding: 15px 16px 11px; }
.lk-vd .vd-cajon-h b { flex: 1; font-size: calc(var(--lk-font-md, 13px) * 1.08); font-weight: 600; letter-spacing: -.015em; }
.lk-vd .vd-cajon-x {
  width: 30px; height: 30px; flex: none; display: grid; place-items: center;
  border: 0; border-radius: 10px; background: transparent; color: var(--lk-text-muted); cursor: pointer;
  transition: background .14s, color .14s, transform .1s var(--vd-spring);
}
.lk-vd .vd-cajon-x:hover { background: var(--lk-bg-hover); color: var(--lk-text-primary); }
.lk-vd .vd-cajon-x:active { transform: scale(.9); }
.lk-vd .vd-cajon-x:focus-visible { outline: none; box-shadow: var(--vd-ring); }
.lk-vd .vd-cajon-x svg { width: 15px; height: 15px; fill: none; stroke: currentColor; }
.lk-vd .vd-cajon-b { flex: 1; min-height: 0; overflow-y: auto; padding: 0 16px 20px; }

/* Responsive: el visor es una hoja de trabajo, no un modal encogido. El
   documento conserva su scroll propio y el cajón de firmas sube como hoja
   sobre el dock, sin dejar una segunda columna ilegible. */
@media (max-width: 639.98px) {
  .lk-vd,
  .lk-vd.lk-vd--suelto { position: fixed!important; inset: 0!important; z-index: var(--lk-z-surface, 950)!important; width: 100vw; height: 100dvh; border-radius: 0; }
  .lk-vd .vd-top { margin: 0; padding: 9px 10px; border-radius: 0; gap: 6px; flex-wrap: nowrap; overflow: hidden; }
  .lk-vd .vd-tx { flex: 1 1 auto; min-width: 0; }
  .lk-vd .vd-t { font-size: 15px; }
  .lk-vd .vd-s,.lk-vd .vd-sp,.lk-vd .vd-brk,.lk-vd .vd-seg { display: none; }
  .lk-vd .vd-meta { display: flex; flex: none; }
  .lk-vd .vd-meta .vd-chip--folio,.lk-vd .vd-meta .vd-chip--per,.lk-vd .vd-meta .vd-chip--ver { display: none; }
  .lk-vd .vd-pag { order: 2; margin-left: auto; }
  .lk-vd .vd-pag-n { min-width: 34px; }
  .lk-vd .vd-btn--vol,.lk-vd .vd-btn--caj { width: 34px; padding: 0; }
  .lk-vd .vd-btn--vol span,.lk-vd .vd-btn--caj span { display: none; }
  .lk-vd .vd-btn--imp,.lk-vd .vd-btn--pest,.lk-vd .vd-top > [data-vd-accion] { display: none!important; }
  .lk-vd .vd-btn--mas { display: grid; order: 9; }
  .lk-vd .vd-menu { z-index: 30; pointer-events: auto; }
  .lk-vd .vd-min-nota { display: none!important; }
  .lk-vd .vd-cuerpo { min-height: 0; }
  .lk-vd .vd-lienzo { padding: 12px; overflow: auto; justify-content: center; }
  .lk-vd.is-cajon-lleno .vd-cajon,
  .lk-vd.is-cajon-encima .vd-cajon { inset: auto 0 0; width: 100%; height: min(78dvh, 620px); max-height: 78dvh; margin: 0; border-radius: 18px 18px 0 0; box-shadow: 0 -14px 38px rgba(0,0,0,.28); }
  .lk-vd.is-cajon-lleno .vd-cajon::before,
  .lk-vd.is-cajon-encima .vd-cajon::before { content: ''; display: block; width: 38px; height: 4px; margin: 9px auto 3px; border-radius: 99px; background: var(--lk-border); flex: none; }
  .lk-vd .vd-cajon-h { padding: 10px 16px; }
  .lk-vd .vd-cajon-b { padding: 0 16px calc(20px + env(safe-area-inset-bottom, 0px)); }
}

/* ══════════════════════════════════════════════════════════════════════════════
   DENSIDADES DE LA BARRA
   Diez controles no caben en un ancho chico. La degradación va quitando por
   orden de prescindencia y agrupando en el menú, pero VOLVER y COMPONER
   sobreviven a todo: son salir y configurar.
   ══════════════════════════════════════════════════════════════════════════════ */

/* media · los secundarios pierden el rótulo y se quedan en íconos */
.lk-vd.is-barra-media .vd-btn--imp span,
.lk-vd.is-barra-media .vd-btn--pest span { display: none; }
.lk-vd.is-barra-media .vd-btn--imp,
.lk-vd.is-barra-media .vd-btn--pest { width: 34px; padding: 0; }

/* compacta · imprimir, las acciones del llamador y la pestaña se van al menú */
.lk-vd.is-barra-compacta .vd-s { display: none; }
.lk-vd.is-barra-compacta .vd-meta { gap: 4px; }
.lk-vd.is-barra-compacta .vd-chip--per { display: none; }
.lk-vd.is-barra-compacta .vd-top > .vd-btn--imp,
.lk-vd.is-barra-compacta .vd-top > .vd-btn--pest,
.lk-vd.is-barra-compacta .vd-top > [data-vd-accion] { display: none; }
.lk-vd.is-barra-compacta .vd-btn--mas { display: inline-flex; }
.lk-vd.is-barra-compacta .vd-btn--caj span { display: none; }
.lk-vd.is-barra-compacta .vd-btn--caj { width: 34px; padding: 0; }

/* mínima (teléfono) · la barra pasa a DOS filas en vez de esconder lo que hace
   falta para leer. Arriba: volver, título y el menú. Abajo: paginación, componer
   y —promovida a acción principal— abrir en pestaña, que a este ancho es la
   superficie buena de verdad. El zoom se va al menú: con el documento de a una
   página ajustada al ancho, acercar deja de ser el gesto principal. */
.lk-vd.is-barra-min .vd-top { gap: 8px; padding: 10px 12px; border-radius: 16px; margin: 8px 8px 0; }
.lk-vd.is-barra-min .vd-s { display: none; }
.lk-vd.is-barra-min .vd-t { font-size: var(--lk-font-lg, 15px); }
.lk-vd.is-barra-min .vd-meta { gap: 4px; }
.lk-vd.is-barra-min .vd-chip--per,
.lk-vd.is-barra-min .vd-chip--ver { display: none; }
.lk-vd.is-barra-min .vd-brk { display: block; flex: 0 0 100%; height: 0; order: 4; }
.lk-vd.is-barra-min .vd-btn--vol { order: 1; width: auto; padding: 0 12px; }
.lk-vd.is-barra-min .vd-tx { order: 2; }
.lk-vd.is-barra-min .vd-sp { display: none; }
.lk-vd.is-barra-min .vd-btn--mas { display: inline-flex; order: 3; margin-left: auto; }
.lk-vd.is-barra-min .vd-pag { order: 5; }
.lk-vd.is-barra-min .vd-btn--caj { display: none; }
.lk-vd.is-barra-min .vd-btn--caj span { display: none; }
.lk-vd.is-barra-min .vd-btn--pest {
  order: 7; flex: 1 1 auto; width: auto; padding: 0 14px;
  background: var(--lk-brand); color: #fff; font-weight: 600;
}
.lk-vd.is-barra-min .vd-btn--pest span { display: inline; }
.lk-vd.is-barra-min .vd-btn--pest:hover { background: color-mix(in srgb, var(--lk-brand) 86%, #ffffff); color: #fff; }
.lk-vd.is-barra-min .vd-seg,
.lk-vd.is-barra-min .vd-top > .vd-btn--imp,
.lk-vd.is-barra-min .vd-top > [data-vd-accion] { display: none; }
.lk-vd.is-barra-min .vd-lienzo { padding: 12px; }
.lk-vd.is-barra-min .vd-min-nota { display: block; }
/* La pestaña ya está en la barra y promovida: repetirla en el menú sobra. */
.lk-vd.is-barra-min .vd-menu > .vd-menu-i[data-vd-pestana] { display: none; }

/* ── IMPRESIÓN DE CORTESÍA ────────────────────────────────────────────────────
   El botón «Imprimir» abre el documento en su propia ventana para que valga su
   `@page`. Pero alguien puede pulsar Ctrl+P con el visor abierto: sin estas
   reglas saldría impreso el CRM entero. Va por `visibility` y no por `display`
   porque el visor cuelga de `.tx-content`, muy adentro del árbol: esconder «todo
   menos uno» por display exigiría conocer cada nivel intermedio. */
@media print {
  body * { visibility: hidden !important; }
  .lk-vd, .lk-vd * { visibility: visible !important; }
  .lk-vd {
    position: fixed !important; inset: 0 !important; z-index: 99999 !important;
    background: #fff; animation: none;
  }
  .lk-vd .vd-top, .lk-vd .vd-cajon, .lk-vd .vd-min-nota { display: none !important; }
  .lk-vd .vd-cuerpo { display: block; }
  .lk-vd .vd-lienzo { overflow: visible; padding: 0; display: block; }
  /* En papel no hay «de a una página»: sale el documento entero. */
  .lk-vd .vd-hoja { width: auto !important; height: auto !important; overflow: visible; }
  .lk-vd .vd-hoja.is-pagina .vd-marco { position: static !important; }
  .lk-vd .vd-marco { transform: none !important; width: 100% !important; top: 0 !important; }
}

@media (prefers-reduced-motion: reduce) {
  .lk-vd, .lk-vd .vd-cajon, .lk-vd .vd-lat, .lk-vd .vd-menu { animation: none !important; }
  .lk-vd *, .lk-vd *::before, .lk-vd *::after { transition: none !important; }
}

/* ══════════════════════════════════════════════════════════════════════════════
   PANEL DE FIRMAS · namespace propio `fp-`, alojado en `.vd-cajon-b`.
   spec-PANEL-FIRMAS-IMPLANTAR · mockup aprobado `mockups/mockup-panel-firmas.html`.

   Reusa `.fp` como panel nuevo con namespace nuevo: reusar clases que otro panel
   CONSULTA cruza los selectores. Las de puro estilo del sistema (`--lk-*`) sí se
   comparten. Apple-like acá es QUITAR: jerarquía por tamaño y peso, separadores
   finos, cero sombras duras, cero laterales de color, cero franjas rellenas.

   La cadena de confianza que dibuja este bloque es la de HOY, con dos huecos
   reales (autoridad certificadora y raíz no existen todavía): la PKI real es
   spec-FEI-PKI-REAL, obra aparte, y este archivo no dibuja su forma futura.
   ══════════════════════════════════════════════════════════════════════════════ */
.lk-vd .fp { font: var(--lk-font-md, 13px)/1.5 var(--lk-font-sans); color: var(--lk-text-primary); }

/* ── LA FRANJA DE ALCANCE · siempre visible, nunca dentro de lo colapsable ──── */
.lk-vd .fp-alcance {
  margin: 0 0 12px; padding: 9px 2px 12px;
  border-bottom: .5px solid var(--lk-border-soft);
  color: var(--lk-text-muted); font-size: var(--lk-font-xs, 11px); line-height: 1.5;
}

/* ── NIVEL 1 · CERRADO · el veredicto de un vistazo ─────────────────────────── */
.lk-vd .fp-vered {
  width: 100%; display: flex; align-items: flex-start; gap: 11px; text-align: left;
  padding: 12px 2px 14px; border: 0; background: transparent; color: inherit;
  font: inherit; cursor: pointer; border-radius: var(--lk-radius-md, 8px);
}
.lk-vd .fp-vered:focus-visible { outline: none; box-shadow: var(--vd-ring); }
.lk-vd .fp-glifo {
  flex: none; width: 22px; height: 22px; margin-top: 1px; display: grid; place-items: center;
  border-radius: 99px; color: var(--lk-green);
  background: color-mix(in srgb, currentColor 14%, transparent);
}
.lk-vd .fp-glifo svg { width: 13px; height: 13px; fill: none; stroke: currentColor; stroke-width: 2; }
.lk-vd .fp-glifo[data-tono="aviso"] { color: var(--lk-amber); }
.lk-vd .fp-glifo[data-tono="malo"] { color: var(--lk-red); }
.lk-vd .fp-vered-tx { flex: 1; min-width: 0; }
/* 16-ago-2026 · Cristián, textual: «hace mas pequeña esta tambien, se ve demasiado
   grande y chillona». Antes iba en `calc(lg*1.06)` — más grande que el propio
   título del visor (`.vd-t`, ver más arriba). Baja a `--lk-font-md`, EL MISMO
   escalón que ya usa `.fp-fir-tx b` unas líneas más abajo para el nombre de cada
   firmante: no se inventa un tamaño nuevo, se reutiliza el que este panel ya
   tiene para un encabezado de su propio nivel. */
.lk-vd .fp-vered-tx b {
  display: block; font-size: var(--lk-font-md, 13px); font-weight: 600;
  letter-spacing: -.015em; line-height: 1.3;
}
.lk-vd .fp-vered-tx span { display: block; color: var(--lk-text-secondary); font-size: var(--lk-font-sm, 12px); margin-top: 2px; }
.lk-vd .fp-chev { flex: none; margin-top: 4px; color: var(--lk-text-faint, var(--lk-text-muted)); transition: transform var(--lk-dur-3) var(--vd-ease); }
.lk-vd .fp-chev svg { width: 14px; height: 14px; fill: none; stroke: currentColor; stroke-width: 1.8; display: block; }
.lk-vd .fp.is-abierto > .fp-vered .fp-chev { transform: rotate(180deg); }

.lk-vd .fp-chk { margin: 0; padding: 0 0 4px; list-style: none; border-top: .5px solid var(--lk-border-soft); }
.lk-vd .fp-chk li { display: flex; gap: 8px; align-items: flex-start; padding: 7px 2px; color: var(--lk-text-secondary); font-size: var(--lk-font-sm, 12px); }
.lk-vd .fp-chk li + li { border-top: .5px solid var(--lk-border-soft); }
.lk-vd .fp-chk i { flex: none; margin-top: 3px; width: 12px; height: 12px; color: var(--lk-green); }
.lk-vd .fp-chk i svg { width: 12px; height: 12px; fill: none; stroke: currentColor; stroke-width: 2; display: block; }
.lk-vd .fp-chk li[data-tono="hueco"] i { color: var(--lk-amber); }
.lk-vd .fp-chk li[data-tono="malo"] i { color: var(--lk-red); }
.lk-vd .fp-chk li[data-tono="hueco"], .lk-vd .fp-chk li[data-tono="malo"] { color: var(--lk-text-primary); }
.lk-vd .fp-chk em { display: block; color: var(--lk-text-muted); font-style: normal; font-size: var(--lk-font-xs, 11px); margin-top: 1px; }

.lk-vd .fp-cuerpo { display: none; }
.lk-vd .fp.is-abierto .fp-cuerpo { display: block; animation: fp-entra var(--lk-dur-3) var(--vd-ease) both; }
@keyframes fp-entra { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }

/* ── NIVEL 2 · POR FIRMANTE ─────────────────────────────────────────────────── */
.lk-vd .fp-tit { margin: 16px 0 0; padding: 0 2px 6px; color: var(--lk-text-faint, var(--lk-text-muted)); font-size: var(--lk-font-xs, 11px); font-weight: 500; letter-spacing: .01em; }
.lk-vd .fp-fir { border-top: .5px solid var(--lk-border-soft); }
.lk-vd .fp-fir-h { width: 100%; display: flex; align-items: center; gap: 9px; text-align: left; padding: 11px 2px; border: 0; background: transparent; color: inherit; font: inherit; cursor: pointer; }
.lk-vd .fp-fir-h:focus-visible { outline: none; box-shadow: var(--vd-ring); border-radius: var(--lk-radius-md, 8px); }
/* El hueco del avatar del firmante. Existe por lo que explica el comentario de
   `lk-visor-doc.js` al pintarlo: `.avatar-photo` es `position:absolute; inset:0`
   y sin un ancestro posicionado a su medida la foto se iba fuera de sus 26px.
   `position:relative` la devuelve encima de las iniciales, y de paso le da a la
   tarjeta de presencia un halo propio al que anclarse, en vez de la fila entera.
   Mismas medidas que `.fp-ini` para no mover ni un píxel de lo aprobado. */
.lk-vd .fp-av { position: relative; flex: none; width: 26px; height: 26px; }
.lk-vd .fp-ini { flex: none; width: 26px; height: 26px; border-radius: 99px; display: grid; place-items: center; background: var(--lk-bg-hover); color: var(--lk-text-secondary); font-size: var(--lk-font-xs, 11px); font-weight: 600; letter-spacing: .01em; }
.lk-vd .fp-fir-tx { flex: 1; min-width: 0; }
.lk-vd .fp-fir-tx b { display: block; font-size: var(--lk-font-md, 13px); font-weight: 600; letter-spacing: -.01em; }
.lk-vd .fp-fir-tx span { display: block; color: var(--lk-text-muted); font-size: var(--lk-font-xs, 11px); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lk-vd .fp-fir-b { display: none; padding: 0 2px 14px; }
.lk-vd .fp-fir.is-abierto .fp-fir-b { display: block; }
.lk-vd .fp-fir.is-abierto .fp-fir-h .fp-chev { transform: rotate(180deg); }

.lk-vd .fp-fila { position: relative; padding: 8px 0; border-top: .5px solid var(--lk-border-soft); }
.lk-vd .fp-fila:first-child { border-top: 0; }
.lk-vd .fp-k { display: block; color: var(--lk-text-muted); font-size: var(--lk-font-xs, 11px); }
.lk-vd .fp-v { display: block; color: var(--lk-text-primary); font-size: var(--lk-font-sm, 12px); overflow-wrap: anywhere; }
.lk-vd .fp-v.mono { font-family: var(--lk-font-mono); font-size: calc(var(--lk-font-xs, 11px) * 1.04); letter-spacing: .01em; }
.lk-vd .fp-sub { display: block; color: var(--lk-text-faint, var(--lk-text-muted)); font-size: var(--lk-font-xs, 11px); margin-top: 2px; }

.lk-vd .fp-fila[data-hueco] .fp-v { color: var(--lk-text-muted); font-style: italic; }
.lk-vd .fp-fila[data-hueco] .fp-k::after {
  content: "sin dato"; margin-left: 7px; padding: 1px 6px; border-radius: 99px;
  border: .5px solid var(--lk-border); font-style: normal; font-size: calc(var(--lk-font-xs, 11px) * .92);
  color: var(--lk-text-faint, var(--lk-text-muted)); vertical-align: 1px;
}

.lk-vd .fp-cp {
  display: inline-flex; align-items: baseline; gap: 6px; max-width: 100%;
  border: 0; background: transparent; padding: 1px 5px 1px 0; margin-left: -1px;
  border-radius: var(--lk-radius-sm, 4px); color: inherit; font: inherit; cursor: pointer; text-align: left;
  position: relative; transition: background var(--lk-dur-2) var(--vd-ease);
}
.lk-vd .fp-cp:hover { background: var(--lk-bg-hover); }
.lk-vd .fp-cp:focus-visible { outline: none; box-shadow: var(--vd-ring); }
.lk-vd .fp-cp::before { content: ""; position: absolute; inset: -8px -6px; }
.lk-vd .fp-cp svg { flex: none; width: 11px; height: 11px; fill: none; stroke: currentColor; stroke-width: 1.7; color: var(--lk-text-faint, var(--lk-text-muted)); align-self: center; }
.lk-vd .fp-cp:hover svg { color: var(--lk-text-secondary); }
.lk-vd .fp-cp.is-ok svg { color: var(--lk-green); }
.lk-vd .fp-cp .fp-ok { position: absolute; top: 8px; right: 0; white-space: nowrap; color: var(--lk-green); font-size: var(--lk-font-xs, 11px); opacity: 0; pointer-events: none; transition: opacity var(--lk-dur-2) var(--vd-ease); }
.lk-vd .fp-cp.is-ok .fp-ok { opacity: 1; }

.lk-vd .fp-esl { margin: 10px 0 2px; padding: 10px 0 2px; border-top: .5px solid var(--lk-border-soft); }
.lk-vd .fp-esl-r { display: grid; grid-template-columns: 14px 1fr; gap: 0 10px; align-items: start; }
.lk-vd .fp-esl-p { grid-column: 1; position: relative; display: flex; justify-content: center; padding-top: 5px; }
.lk-vd .fp-esl-p b { width: 7px; height: 7px; border-radius: 99px; background: var(--lk-text-faint, var(--lk-text-muted)); box-shadow: 0 0 0 3px color-mix(in srgb, var(--lk-text-faint, var(--lk-text-muted)) 18%, transparent); }
.lk-vd .fp-esl-r + .fp-esl-r .fp-esl-p::before { content: ""; position: absolute; left: 50%; top: -14px; height: 19px; width: 1px; background: var(--lk-border); transform: translateX(-.5px); }
.lk-vd .fp-esl-r[data-yo] .fp-esl-p b { background: var(--lk-brand); box-shadow: 0 0 0 3px var(--lk-brand-muted); }
.lk-vd .fp-esl-t { grid-column: 2; padding-bottom: 12px; min-width: 0; }
.lk-vd .fp-esl-r:last-child .fp-esl-t { padding-bottom: 2px; }
.lk-vd .fp-esl-t small { display: block; color: var(--lk-text-faint, var(--lk-text-muted)); font-size: var(--lk-font-xs, 11px); }
.lk-vd .fp-esl-r[data-yo] .fp-esl-t small { color: var(--lk-text-secondary); }

/* ── NIVEL 3 · EL CERTIFICADO · plegado DENTRO del firmante ─────────────────── */
.lk-vd .fp-cert { margin-top: 8px; border-top: .5px solid var(--lk-border-soft); }
.lk-vd .fp-cert-h { width: 100%; display: flex; align-items: center; gap: 8px; text-align: left; padding: 10px 2px; border: 0; background: transparent; color: var(--lk-text-secondary); font: inherit; font-size: var(--lk-font-sm, 12px); cursor: pointer; }
.lk-vd .fp-cert-h:hover { color: var(--lk-text-primary); }
.lk-vd .fp-cert-h:focus-visible { outline: none; box-shadow: var(--vd-ring); border-radius: var(--lk-radius-md, 8px); }
.lk-vd .fp-cert-h b { flex: 1; font-weight: 500; }
.lk-vd .fp-cert-b { display: none; padding: 0 0 8px; }
.lk-vd .fp-cert.is-abierto .fp-cert-b { display: block; }
.lk-vd .fp-cert.is-abierto .fp-cert-h .fp-chev { transform: rotate(180deg); }

.lk-vd .fp-cad { margin: 10px 0 0; padding-top: 10px; border-top: .5px solid var(--lk-border-soft); }
.lk-vd .fp-cad-r { display: grid; grid-template-columns: 16px 1fr; gap: 0 10px; }
.lk-vd .fp-cad-p { position: relative; display: flex; justify-content: center; padding-top: 4px; }
.lk-vd .fp-cad-p i { width: 9px; height: 9px; border-radius: 99px; border: 1.5px solid currentColor; color: var(--lk-green); background: currentColor; }
.lk-vd .fp-cad-r[data-est="hueco"] .fp-cad-p i { background: transparent; color: var(--lk-amber); border-style: dashed; }
.lk-vd .fp-cad-r[data-est="malo"] .fp-cad-p i { background: transparent; color: var(--lk-red); }
.lk-vd .fp-cad-r + .fp-cad-r .fp-cad-p::before { content: ""; position: absolute; left: 50%; top: -16px; height: 20px; width: 1px; background: var(--lk-border); transform: translateX(-.5px); }
.lk-vd .fp-cad-r[data-est="hueco"] + .fp-cad-r .fp-cad-p::before,
.lk-vd .fp-cad-r[data-est="hueco"] .fp-cad-p::before { background: repeating-linear-gradient(180deg, var(--lk-border) 0 2px, transparent 2px 5px); }
.lk-vd .fp-cad-t { min-width: 0; padding-bottom: 13px; }
.lk-vd .fp-cad-r:last-child .fp-cad-t { padding-bottom: 2px; }
.lk-vd .fp-cad-t b { display: block; font-size: var(--lk-font-sm, 12px); font-weight: 600; letter-spacing: -.01em; }
.lk-vd .fp-cad-t b.vacio { font-weight: 500; font-style: italic; color: var(--lk-text-muted); }
.lk-vd .fp-cad-t small { display: block; color: var(--lk-text-faint, var(--lk-text-muted)); font-size: var(--lk-font-xs, 11px); }
.lk-vd .fp-cad-t span { display: block; color: var(--lk-text-muted); font-size: var(--lk-font-xs, 11px); margin-top: 2px; }

/* ── EL PIE DEL PANEL · la comprobación independiente ───────────────────────── */
.lk-vd .fp-pie { margin-top: 14px; padding-top: 12px; border-top: .5px solid var(--lk-border-soft); }
.lk-vd .fp-a { display: inline-flex; align-items: center; gap: 7px; color: var(--lk-brand); text-decoration: none; font-size: var(--lk-font-sm, 12px); padding: 5px 0; position: relative; }
.lk-vd .fp-a::before { content: ""; position: absolute; inset: -9px -8px; }
.lk-vd .fp-a:hover { text-decoration: underline; }
.lk-vd .fp-a:focus-visible { outline: none; box-shadow: var(--vd-ring); border-radius: var(--lk-radius-sm, 4px); }
.lk-vd .fp-a svg { width: 13px; height: 13px; fill: none; stroke: currentColor; stroke-width: 1.7; }
.lk-vd .fp-pie p { margin: 5px 0 0; color: var(--lk-text-faint, var(--lk-text-muted)); font-size: var(--lk-font-xs, 11px); max-width: 46ch; }

/* ── BORRADOR · sin panel. Se dice que aún no hay nada que verificar. ────────── */
.lk-vd .fp-nada { padding: 26px 6px; text-align: center; color: var(--lk-text-muted); }
.lk-vd .fp-nada i { display: block; margin: 0 auto 10px; width: 30px; height: 30px; color: var(--lk-text-faint, var(--lk-text-muted)); }
.lk-vd .fp-nada i svg { width: 30px; height: 30px; fill: none; stroke: currentColor; stroke-width: 1.3; }
.lk-vd .fp-nada b { display: block; color: var(--lk-text-primary); font-size: var(--lk-font-md, 13px); font-weight: 600; }
.lk-vd .fp-nada p { margin: 5px auto 0; font-size: var(--lk-font-sm, 12px); max-width: 34ch; }

/* ── FIRMA QUE FALTA · media caja vacía, dicha ──────────────────────────────── */
.lk-vd .fp-falta { display: flex; gap: 9px; align-items: flex-start; padding: 11px 2px; border-top: .5px solid var(--lk-border-soft); color: var(--lk-text-muted); }
.lk-vd .fp-falta i { flex: none; width: 26px; height: 26px; border-radius: 99px; display: grid; place-items: center; border: 1px dashed var(--lk-border); color: var(--lk-text-faint, var(--lk-text-muted)); }
.lk-vd .fp-falta i svg { width: 13px; height: 13px; fill: none; stroke: currentColor; stroke-width: 1.7; }
.lk-vd .fp-falta b { display: block; color: var(--lk-text-secondary); font-size: var(--lk-font-md, 13px); font-weight: 500; }
.lk-vd .fp-falta span { display: block; font-size: var(--lk-font-xs, 11px); margin-top: 1px; }

@media (prefers-reduced-motion: reduce) {
  .lk-vd .fp-cuerpo, .lk-vd .fp-chev, .lk-vd .fp-cp .fp-ok { animation: none !important; transition: none !important; }
}
