/* ╔══════════════════════════════════════════════════════════════════════════╗
   ║  DS · Sistema de diseño de Ducoudray & Asociados                          ║
   ║                                                                            ║
   ║  Capa final: se carga DESPUÉS de erp.css, erp-ui.css, brand.css y app.css. ║
   ║  Aquí viven (a) la escala de tokens completa, (b) el tema oscuro derivado   ║
   ║  de esos tokens y (c) los componentes que el rediseño añade.               ║
   ║                                                                            ║
   ║  Regla de la casa: **ningún componente nuevo escribe un color literal**.    ║
   ║  Todo sale de un token. Es lo que permite que el tema oscuro y el color     ║
   ║  corporativo por empresa se cambien en un sitio y no en doscientos.        ║
   ╚══════════════════════════════════════════════════════════════════════════╝ */

/* ══════════════════════════════════════════════════════════════════════════
   1) TOKENS · la escala completa
   erp-ui.css ya define la paleta base (--erp-primary, estados, neutros).
   Aquí se completa con lo que faltaba para poder dejar de improvisar:
   espaciado, tipografía, elevación, motion y capas z.
   ══════════════════════════════════════════════════════════════════════════ */
:root {
    /* ── Espaciado (escala de 4) ───────────────────────────────────────── */
    --sp-1: 4px;   --sp-2: 8px;   --sp-3: 12px;  --sp-4: 16px;
    --sp-5: 20px;  --sp-6: 24px;  --sp-8: 32px;  --sp-10: 40px;
    --sp-12: 48px; --sp-16: 64px;

    /* ── Tipografía ────────────────────────────────────────────────────── */
    --fs-xs: 11.5px; --fs-sm: 12.5px; --fs-md: 13.5px;
    --fs-lg: 15px;   --fs-xl: 18px;   --fs-2xl: 22px; --fs-3xl: 28px;
    --lh-tight: 1.25; --lh-normal: 1.5;
    --fw-medium: 500; --fw-semibold: 600; --fw-bold: 700;

    /* ── Elevación ─────────────────────────────────────────────────────── */
    --el-0: none;
    --el-1: 0 1px 2px rgba(16,32,48,.05), 0 1px 3px rgba(16,32,48,.05);
    --el-2: 0 2px 4px rgba(16,32,48,.05), 0 4px 12px rgba(16,32,48,.07);
    --el-3: 0 4px 8px rgba(16,32,48,.06), 0 12px 32px rgba(16,32,48,.10);
    --el-4: 0 8px 16px rgba(16,32,48,.08), 0 24px 56px rgba(16,32,48,.14);

    /* ── Movimiento ────────────────────────────────────────────────────── */
    --mo-fast: 120ms; --mo-base: 180ms; --mo-slow: 260ms;
    --mo-ease: cubic-bezier(.4, 0, .2, 1);

    /* ── Capas ─────────────────────────────────────────────────────────── */
    --z-sticky: 20; --z-drawer: 1045; --z-modal: 1050;
    --z-palette: 1080; --z-toast: 1090;

    /* ── Superficies derivadas (las usan los componentes nuevos) ────────── */
    --su-page:     var(--erp-bg);
    --su-card:     var(--erp-surface);
    --su-sunken:   #EDF1F5;   /* fondos hundidos: kanban, code, zona de drop */
    --su-hover:    rgba(16,32,48,.035);
    --su-active:   rgba(var(--erp-primary-rgb), .08);
    --su-overlay:  rgba(16,26,38,.48);
    --li-border:   var(--erp-border);
    --li-strong:   var(--erp-border-2);
    --tx-title:    var(--erp-ink);
    --tx-body:     var(--erp-ink-2);
    --tx-muted:    var(--erp-muted);
    --tx-faint:    var(--erp-faint);
}

/* ══════════════════════════════════════════════════════════════════════════
   2) TEMA OSCURO · sólo se redefinen tokens
   El tema no repinta componente por componente: cambia la escala y todo lo
   que consume tokens se entera solo. Lo que queda abajo son los parches para
   ArchitectUI, que sí trae colores literales en su CSS y no los podemos tocar.
   ══════════════════════════════════════════════════════════════════════════ */
[data-theme="dark"] {
    --erp-bg:        #0F151C;
    --erp-surface:   #161E27;
    --erp-border:    #26313D;
    --erp-border-2:  #35424F;
    --erp-ink:       #E7EDF3;
    --erp-ink-2:     #C6D1DC;
    --erp-muted:     #8C9AA8;
    --erp-faint:     #6B7885;

    --su-sunken:  #111922;
    --su-hover:   rgba(255,255,255,.045);
    --su-active:  rgba(var(--erp-primary-rgb), .20);
    --su-overlay: rgba(0,0,0,.62);

    /* ⚠ Los ocho derivados de arriba **hay que repetirlos aquí**, y no es
       redundancia: es la única forma de que cambien.

       En la sección 1 se declaran en `:root` en función de la paleta base
       —`--su-card: var(--erp-surface)`—, y este bloque redefine `--erp-surface`
       en `[data-theme="dark"]`, que va en el `<body>`. La sustitución de una
       custom property se resuelve **donde se declara**, no donde se usa: el
       valor de `--su-card` se calcula una sola vez, en `:root`, con el blanco
       todavía vigente, y ese blanco es el que hereda hacia abajo.

       El resultado era un tema oscuro con el fondo negro y **todas las
       tarjetas, tablas, modales y desplegables en blanco**, con su texto
       oscuro encima ilegible —incluidos los parches de más abajo, que piden
       `var(--su-card)` creyendo que ya es oscuro—. Los cuatro de arriba
       (`--su-sunken`, `--su-hover`, `--su-active`, `--su-overlay`) llevan valor
       propio y por eso eran los únicos que funcionaban.

       Se escriben en literal a propósito: apuntarlos otra vez a `var(--erp-*)`
       aquí sí valdría —el bloque ya está en el ámbito oscuro—, pero deja el
       mismo pie para que alguien los mueva de vuelta a `:root` y reviva el
       fallo sin enterarse. */
    --su-page:   #0F151C;
    --su-card:   #161E27;
    --li-border: #26313D;
    --li-strong: #35424F;
    --tx-title:  #E7EDF3;
    --tx-body:   #C6D1DC;
    --tx-muted:  #8C9AA8;
    --tx-faint:  #6B7885;

    /* Los tintes suaves de estado tienen que oscurecerse o el badge queda
       como una mancha luminosa sobre fondo negro. */
    --erp-primary-soft: rgba(var(--erp-primary-rgb), .18);
    --erp-success-soft: rgba(30,158,90,.18);
    --erp-warning-soft: rgba(199,126,6,.20);
    --erp-danger-soft:  rgba(214,69,80,.18);
    --erp-info-soft:    rgba(46,124,214,.18);
    --erp-purple-soft:  rgba(122,90,236,.18);

    --el-1: 0 1px 2px rgba(0,0,0,.28);
    --el-2: 0 2px 6px rgba(0,0,0,.34);
    --el-3: 0 8px 24px rgba(0,0,0,.42);
    --el-4: 0 16px 48px rgba(0,0,0,.52);

    color-scheme: dark;
}

/* Parches para lo que ArchitectUI pinta con color literal. */
[data-theme="dark"] body,
[data-theme="dark"] .app-main__outer,
[data-theme="dark"] .app-main__inner { background: var(--erp-bg); color: var(--tx-body); }
[data-theme="dark"] .card,
[data-theme="dark"] .main-card,
[data-theme="dark"] .app-header,
[data-theme="dark"] .app-sidebar,
[data-theme="dark"] .dropdown-menu,
[data-theme="dark"] .modal-content,
[data-theme="dark"] .list-group-item,
[data-theme="dark"] .popover { background: var(--su-card) !important; color: var(--tx-body); border-color: var(--li-border); }
[data-theme="dark"] .card-header,
[data-theme="dark"] .modal-header,
[data-theme="dark"] .modal-footer { background: transparent !important; border-color: var(--li-border); color: var(--tx-title); }
[data-theme="dark"] .table { color: var(--tx-body); }
[data-theme="dark"] .table thead th { color: var(--tx-muted); border-color: var(--li-border); }
[data-theme="dark"] .table td, [data-theme="dark"] .table th { border-color: var(--li-border); }
[data-theme="dark"] .table-striped tbody tr:nth-of-type(odd) { background: rgba(255,255,255,.022); }
[data-theme="dark"] .table-hover tbody tr:hover { background: var(--su-hover); }
[data-theme="dark"] .form-control,
[data-theme="dark"] .custom-select,
[data-theme="dark"] .custom-file-label,
[data-theme="dark"] .input-group-text { background: var(--su-sunken); border-color: var(--li-strong); color: var(--tx-body); }
[data-theme="dark"] .form-control::placeholder { color: var(--tx-faint); }
[data-theme="dark"] .text-muted { color: var(--tx-muted) !important; }
[data-theme="dark"] .dropdown-item { color: var(--tx-body); }
[data-theme="dark"] .dropdown-item:hover,
[data-theme="dark"] .dropdown-item:focus { background: var(--su-hover); color: var(--tx-title); }
[data-theme="dark"] .dropdown-divider,
[data-theme="dark"] hr { border-color: var(--li-border); }
[data-theme="dark"] .close { color: var(--tx-body); text-shadow: none; }
[data-theme="dark"] .bg-light,
[data-theme="dark"] .alert-light { background: var(--su-sunken) !important; color: var(--tx-body); }
[data-theme="dark"] .btn-light { background: var(--su-sunken); border-color: var(--li-strong); color: var(--tx-body); }
[data-theme="dark"] .btn-light:hover { background: var(--li-border); color: var(--tx-title); }
[data-theme="dark"] .page-link { background: var(--su-card); border-color: var(--li-border); color: var(--tx-body); }
[data-theme="dark"] .progress { background: var(--su-sunken); }
[data-theme="dark"] .app-page-title { background: transparent; }
[data-theme="dark"] .vertical-nav-menu li a { color: var(--tx-body); }
[data-theme="dark"] .erp-skeleton { background: linear-gradient(90deg, #1A222C 25%, #222C38 37%, #1A222C 63%); background-size: 400% 100%; }
[data-theme="dark"] .select2-container--bootstrap4 .select2-selection,
[data-theme="dark"] .select2-dropdown,
[data-theme="dark"] .select2-search__field,
[data-theme="dark"] .flatpickr-calendar,
[data-theme="dark"] .flatpickr-months,
[data-theme="dark"] .flatpickr-weekdays { background: var(--su-card) !important; border-color: var(--li-strong) !important; color: var(--tx-body) !important; }
[data-theme="dark"] .flatpickr-day { color: var(--tx-body); }
[data-theme="dark"] .flatpickr-day.flatpickr-disabled { color: var(--tx-faint); }
[data-theme="dark"] .swal2-popup { background: var(--su-card) !important; color: var(--tx-body) !important; }

/* ══════════════════════════════════════════════════════════════════════════
   3) ICONOS · Lucide como única familia
   El `<i>` de fuente icónica se cambió por un `<svg><use></use></svg>`.
   Se dimensiona en `em` para que herede el tamaño del texto que acompaña,
   que es como se comportaba la fuente y evita repasar cada llamada.
   ══════════════════════════════════════════════════════════════════════════ */
.erp-i {
    width: 1.08em;
    height: 1.08em;
    vertical-align: -.18em;
    flex: 0 0 auto;
    stroke-width: 2;
    /* El icono no intercepta el clic: el botón que lo contiene sí. */
    pointer-events: none;
}
/* A partir de cierto tamaño un trazo de 2 sobre 24 se ve tosco. */
.erp-i[style*="width:32"], .erp-i[style*="width:44"],
.erp-i[style*="width:56"], .erp-i[style*="width:72"] { stroke-width: 1.6; }

/* Separación automática cuando el icono precede a texto dentro de un botón:
   antes se ponía `mr-2` a mano y unas veces sí y otras no. */
.btn .erp-i:not(:only-child):first-child { margin-right: .45em; }
.btn .erp-i { vertical-align: -.2em; }
.btn-sm .erp-i, .btn-xs .erp-i { width: 1em; height: 1em; }

/* Contenedores de icono del sistema anterior: fijaban `font-size` sobre el
   `<i>`; ahora hay que fijar caja. */
.page-title-icon .erp-i  { width: 24px; height: 24px; }
.erp-stat__icon .erp-i   { width: 22px; height: 22px; }
.erp-section-ic .erp-i   { width: 17px; height: 17px; }
.erp-empty__icon .erp-i  { width: 30px; height: 30px; }
.erp-row-actions .btn .erp-i { width: 15px; height: 15px; margin: 0; }
.erp-sort .erp-i { width: 12px; height: 12px; opacity: .4; margin-left: 3px; }
.erp-sort.is-active .erp-i { opacity: 1; color: var(--erp-primary); }
.erp-breadcrumbs .breadcrumb-item:first-child a .erp-i { color: var(--erp-primary); width: 14px; height: 14px; }
.erp-avatar .erp-i { width: 46%; height: 46%; vertical-align: middle; }
.dropdown-item .erp-i { width: 15px; height: 15px; margin-right: .55em; vertical-align: -.2em; }
.alert .erp-i { vertical-align: -.2em; }
.badge .erp-i { width: 1em; height: 1em; vertical-align: -.15em; }

/* ══════════════════════════════════════════════════════════════════════════
   4) PESTAÑAS · páginas de detalle (§13)
   Una ficha de empresa con doce bloques apilados obliga a recorrer la página
   entera para saber qué hay. Con pestañas, cada plano se pide cuando se busca.
   ══════════════════════════════════════════════════════════════════════════ */
.ds-tabs {
    display: flex;
    gap: 2px;
    border-bottom: 1px solid var(--li-border);
    margin: 0 0 var(--sp-5);
    overflow-x: auto;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
}
.ds-tabs::-webkit-scrollbar { display: none; }
.ds-tabs__link {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-2);
    padding: 10px 14px;
    font-size: var(--fs-md);
    font-weight: var(--fw-semibold);
    color: var(--tx-muted);
    white-space: nowrap;
    border-bottom: 2px solid transparent;
    border-radius: var(--erp-radius-sm) var(--erp-radius-sm) 0 0;
    transition: color var(--mo-fast) var(--mo-ease), background var(--mo-fast) var(--mo-ease);
}
.ds-tabs__link:hover { color: var(--tx-title); background: var(--su-hover); text-decoration: none; }
.ds-tabs__link.is-active { color: var(--erp-primary); border-bottom-color: var(--erp-primary); }
.ds-tabs__link .erp-i { width: 15px; height: 15px; }
.ds-tabs__count {
    font-size: var(--fs-xs);
    font-weight: var(--fw-bold);
    padding: 1px 6px;
    border-radius: 999px;
    background: var(--su-sunken);
    color: var(--tx-muted);
}
.ds-tabs__link.is-active .ds-tabs__count { background: var(--erp-primary-soft); color: var(--erp-primary); }

/* ══════════════════════════════════════════════════════════════════════════
   5) LÍNEA DE TIEMPO / ACTIVIDAD (§18)
   Quién, qué, cuándo — en una columna que se lee de un vistazo.
   ══════════════════════════════════════════════════════════════════════════ */
.ds-timeline { position: relative; padding-left: 30px; margin: 0; list-style: none; }
.ds-timeline::before {
    content: ""; position: absolute; left: 11px; top: 6px; bottom: 6px;
    width: 2px; background: var(--li-border);
}
.ds-timeline__item { position: relative; padding: 0 0 var(--sp-5); }
.ds-timeline__item:last-child { padding-bottom: 0; }
.ds-timeline__dot {
    position: absolute; left: -30px; top: 1px;
    width: 24px; height: 24px; border-radius: 50%;
    display: flex; align-items: center; justify-content: center;
    background: var(--su-card); border: 2px solid var(--li-border);
    color: var(--tx-muted);
}
.ds-timeline__dot .erp-i { width: 12px; height: 12px; }
.ds-timeline__item.is-success .ds-timeline__dot { border-color: var(--erp-success); color: var(--erp-success); background: var(--erp-success-soft); }
.ds-timeline__item.is-danger  .ds-timeline__dot { border-color: var(--erp-danger);  color: var(--erp-danger);  background: var(--erp-danger-soft); }
.ds-timeline__item.is-warning .ds-timeline__dot { border-color: var(--erp-warning); color: var(--erp-warning); background: var(--erp-warning-soft); }
.ds-timeline__item.is-info    .ds-timeline__dot { border-color: var(--erp-info);    color: var(--erp-info);    background: var(--erp-info-soft); }
.ds-timeline__head { display: flex; align-items: baseline; gap: var(--sp-2); flex-wrap: wrap; }
.ds-timeline__who  { font-weight: var(--fw-semibold); color: var(--tx-title); font-size: var(--fs-md); }
.ds-timeline__when { font-size: var(--fs-xs); color: var(--tx-faint); margin-left: auto; white-space: nowrap; }
.ds-timeline__what { font-size: var(--fs-sm); color: var(--tx-body); margin-top: 2px; }
.ds-timeline__note {
    margin-top: var(--sp-2); padding: var(--sp-2) var(--sp-3);
    background: var(--su-sunken); border-radius: var(--erp-radius-sm);
    font-size: var(--fs-sm); color: var(--tx-body);
    border-left: 2px solid var(--li-strong);
}

/* ══════════════════════════════════════════════════════════════════════════
   6) MENÚ DE ACCIONES POR FILA (kebab)
   Cuatro botones por fila multiplicados por veinticinco filas son cien
   objetivos de clic compitiendo. Se dejan a la vista los dos frecuentes y el
   resto pasa al menú.
   ══════════════════════════════════════════════════════════════════════════ */
.ds-kebab > .btn {
    width: 30px; height: 30px; padding: 0;
    display: inline-flex; align-items: center; justify-content: center;
    color: var(--tx-muted); border-radius: var(--erp-radius-sm);
}
.ds-kebab > .btn:hover { background: var(--su-hover); color: var(--tx-title); }
.ds-kebab .dropdown-menu { min-width: 190px; padding: 5px; border-radius: var(--erp-radius); box-shadow: var(--el-3); border: 1px solid var(--li-border); }
.ds-kebab .dropdown-item { border-radius: var(--erp-radius-sm); padding: 7px 10px; font-size: var(--fs-md); }
.ds-kebab .dropdown-item.text-danger:hover { background: var(--erp-danger-soft); }

/* ══════════════════════════════════════════════════════════════════════════
   7) SUBIDA DE ARCHIVOS · arrastrar y soltar (§17)
   ══════════════════════════════════════════════════════════════════════════ */
.ds-drop {
    position: relative;
    border: 1.5px dashed var(--li-strong);
    border-radius: var(--erp-radius);
    background: var(--su-sunken);
    padding: var(--sp-6);
    text-align: center;
    transition: border-color var(--mo-base) var(--mo-ease), background var(--mo-base) var(--mo-ease);
}
.ds-drop.is-over { border-color: var(--erp-primary); background: var(--erp-primary-soft); }
.ds-drop__icon { color: var(--erp-primary); margin-bottom: var(--sp-2); }
.ds-drop__icon .erp-i { width: 32px; height: 32px; }
.ds-drop__title { font-weight: var(--fw-semibold); color: var(--tx-title); font-size: var(--fs-lg); }
.ds-drop__hint  { font-size: var(--fs-sm); color: var(--tx-muted); margin-top: 2px; }
.ds-drop input[type="file"] {
    position: absolute; inset: 0; width: 100%; height: 100%;
    opacity: 0; cursor: pointer;
}
.ds-drop input[type="file"]:focus-visible + .ds-drop__body { outline: 2px solid var(--erp-primary); outline-offset: 3px; }

/* Lista de archivos elegidos / ya subidos */
.ds-files { display: grid; gap: var(--sp-2); margin-top: var(--sp-3); }
.ds-file {
    display: flex; align-items: center; gap: var(--sp-3);
    padding: var(--sp-2) var(--sp-3);
    border: 1px solid var(--li-border); border-radius: var(--erp-radius-sm);
    background: var(--su-card);
}
.ds-file__thumb {
    width: 38px; height: 38px; flex: none;
    border-radius: var(--erp-radius-sm);
    display: flex; align-items: center; justify-content: center;
    background: var(--su-sunken); color: var(--tx-muted); overflow: hidden;
}
.ds-file__thumb img { width: 100%; height: 100%; object-fit: cover; }
.ds-file__thumb .erp-i { width: 18px; height: 18px; }
.ds-file__name { font-size: var(--fs-md); font-weight: var(--fw-medium); color: var(--tx-title); word-break: break-word; }
.ds-file__meta { font-size: var(--fs-xs); color: var(--tx-muted); }
.ds-file__body { min-width: 0; flex: 1; }
/* Tinte del icono según el tipo: leer la extensión antes que el nombre. */
.ds-file__thumb.is-pdf   { color: var(--erp-danger);  background: var(--erp-danger-soft); }
.ds-file__thumb.is-sheet { color: var(--erp-success); background: var(--erp-success-soft); }
.ds-file__thumb.is-doc   { color: var(--erp-info);    background: var(--erp-info-soft); }
.ds-file__thumb.is-image { color: var(--erp-purple);  background: var(--erp-purple-soft); }

/* ══════════════════════════════════════════════════════════════════════════
   8) ANILLO DE PROGRESO
   ══════════════════════════════════════════════════════════════════════════ */
.ds-ring { display: inline-flex; align-items: center; justify-content: center; position: relative; }
.ds-ring svg { transform: rotate(-90deg); display: block; }
.ds-ring__track { stroke: var(--su-sunken); }
.ds-ring__bar { stroke: var(--erp-primary); transition: stroke-dashoffset var(--mo-slow) var(--mo-ease); }
.ds-ring.is-success .ds-ring__bar { stroke: var(--erp-success); }
.ds-ring.is-warning .ds-ring__bar { stroke: var(--erp-warning); }
.ds-ring.is-danger  .ds-ring__bar { stroke: var(--erp-danger); }
.ds-ring__label {
    position: absolute; inset: 0;
    display: flex; align-items: center; justify-content: center;
    font-size: var(--fs-sm); font-weight: var(--fw-bold); color: var(--tx-title);
}

/* ══════════════════════════════════════════════════════════════════════════
   9) FICHAS DE FILTRO ACTIVO
   Un filtro que no se ve puesto es la causa número uno del «faltan datos».
   ══════════════════════════════════════════════════════════════════════════ */
.ds-chips { display: flex; flex-wrap: wrap; gap: var(--sp-2); align-items: center; }
.ds-chip {
    display: inline-flex; align-items: center; gap: 6px;
    padding: 3px 6px 3px 10px;
    border-radius: 999px;
    background: var(--erp-primary-soft);
    color: var(--erp-primary);
    font-size: var(--fs-xs); font-weight: var(--fw-semibold);
    max-width: 260px;
}
.ds-chip__x {
    display: inline-flex; align-items: center; justify-content: center;
    width: 16px; height: 16px; border-radius: 50%;
    background: rgba(var(--erp-primary-rgb), .18);
    color: inherit; flex: none;
}
.ds-chip__x:hover { background: var(--erp-primary); color: #fff; text-decoration: none; }
.ds-chip__x .erp-i { width: 10px; height: 10px; }
.ds-chip__label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ══════════════════════════════════════════════════════════════════════════
   10) GRUPO DE AVATARES
   ══════════════════════════════════════════════════════════════════════════ */
.ds-avatars { display: inline-flex; align-items: center; }
.ds-avatars .erp-avatar { border: 2px solid var(--su-card); margin-left: -8px; }
.ds-avatars .erp-avatar:first-child { margin-left: 0; }
.ds-avatars__more {
    display: inline-flex; align-items: center; justify-content: center;
    min-width: 32px; height: 32px; padding: 0 6px; margin-left: -8px;
    border-radius: 999px; border: 2px solid var(--su-card);
    background: var(--su-sunken); color: var(--tx-muted);
    font-size: var(--fs-xs); font-weight: var(--fw-bold);
}

/* ══════════════════════════════════════════════════════════════════════════
   11) ESTADOS · color + icono + texto (§11 · nunca sólo color)
   ══════════════════════════════════════════════════════════════════════════ */
.ds-state { display: inline-flex; align-items: center; gap: 5px; font-weight: var(--fw-semibold); font-size: var(--fs-xs); }
.ds-state .erp-i { width: 13px; height: 13px; }

/* ══════════════════════════════════════════════════════════════════════════
   12) ESQUELETOS DE CARGA (§21)
   ══════════════════════════════════════════════════════════════════════════ */
.ds-sk { background: linear-gradient(90deg, var(--su-sunken) 25%, var(--su-card) 37%, var(--su-sunken) 63%);
    background-size: 400% 100%; animation: ds-shimmer 1.4s ease infinite;
    border-radius: var(--erp-radius-sm); height: 13px; }
.ds-sk + .ds-sk { margin-top: var(--sp-2); }
.ds-sk--title { height: 20px; width: 42%; }
.ds-sk--line  { width: 100%; }
.ds-sk--short { width: 60%; }
.ds-sk--card  { height: 88px; border-radius: var(--erp-radius-lg); }
.ds-sk--avatar{ width: 34px; height: 34px; border-radius: 50%; }
@keyframes ds-shimmer { 0% { background-position: 100% 50%; } 100% { background-position: 0 50%; } }
@media (prefers-reduced-motion: reduce) { .ds-sk { animation: none; } }

/* ══════════════════════════════════════════════════════════════════════════
   13) ACCESIBILIDAD · foco visible en todo lo interactivo (§29)
   ArchitectUI quita el contorno en varios sitios. Se restituye: sin foco
   visible, el teclado se vuelve inutilizable.
   ══════════════════════════════════════════════════════════════════════════ */
a:focus-visible, button:focus-visible, [tabindex]:focus-visible,
.btn:focus-visible, .form-control:focus-visible, .custom-select:focus-visible,
.ds-tabs__link:focus-visible, .dropdown-item:focus-visible {
    outline: 2px solid var(--erp-primary);
    outline-offset: 2px;
    box-shadow: none;
}
[data-theme="dark"] a:focus-visible, [data-theme="dark"] button:focus-visible,
[data-theme="dark"] .btn:focus-visible { outline-color: #7FB5B5; }

/* Sólo para lector de pantalla */
.ds-sr {
    position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0;
}
/* Salto al contenido: primer tabulador de la página */
.ds-skip {
    position: absolute; left: -9999px; top: 0; z-index: var(--z-toast);
    background: var(--erp-primary); color: #fff;
    padding: 10px 16px; border-radius: 0 0 var(--erp-radius) 0;
    font-weight: var(--fw-semibold);
}
.ds-skip:focus { left: 0; color: #fff; text-decoration: none; }

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

/* ══════════════════════════════════════════════════════════════════════════
   14) PALETA DE COMANDOS (§25) · Ctrl/⌘ + K
   Lanzador y buscador en el mismo sitio. Se monta sobre la página, no navega.
   ══════════════════════════════════════════════════════════════════════════ */
.ds-palette { position: fixed; inset: 0; z-index: var(--z-palette); display: flex; justify-content: center; }
.ds-palette[hidden] { display: none; }
.ds-palette__backdrop { position: absolute; inset: 0; background: var(--su-overlay); backdrop-filter: blur(2px); }
.ds-palette__panel {
    position: relative;
    width: min(660px, calc(100vw - 32px));
    margin-top: min(12vh, 110px);
    max-height: min(70vh, 620px);
    display: flex; flex-direction: column;
    background: var(--su-card);
    border: 1px solid var(--li-border);
    border-radius: var(--erp-radius-lg);
    box-shadow: var(--el-4);
    overflow: hidden;
    animation: ds-pop var(--mo-base) var(--mo-ease);
}
@keyframes ds-pop { from { opacity: 0; transform: translateY(-8px) scale(.99); } to { opacity: 1; transform: none; } }

.ds-palette__search { display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-4); border-bottom: 1px solid var(--li-border); }
.ds-palette__searchic { width: 19px; height: 19px; color: var(--tx-muted); flex: none; }
.ds-palette__input {
    flex: 1; border: 0; background: transparent; outline: none;
    font-size: var(--fs-lg); color: var(--tx-title); min-width: 0;
}
.ds-palette__input::placeholder { color: var(--tx-faint); }
.ds-palette__input::-webkit-search-cancel-button { display: none; }
.ds-palette__esc {
    border: 1px solid var(--li-border); background: var(--su-sunken); color: var(--tx-muted);
    border-radius: var(--erp-radius-sm); padding: 3px 8px; font-size: var(--fs-xs); font-weight: var(--fw-semibold);
}
.ds-palette__esc:hover { color: var(--tx-title); border-color: var(--li-strong); }

.ds-palette__list { overflow-y: auto; padding: var(--sp-2); flex: 1; overscroll-behavior: contain; }
.ds-palette__group {
    display: flex; align-items: center; gap: var(--sp-2);
    padding: var(--sp-3) var(--sp-3) var(--sp-1);
    font-size: var(--fs-xs); font-weight: var(--fw-bold);
    text-transform: uppercase; letter-spacing: .05em; color: var(--tx-faint);
}
.ds-palette__more { font-weight: var(--fw-medium); text-transform: none; letter-spacing: 0; }
.ds-palette__item {
    display: flex; align-items: center; gap: var(--sp-3);
    padding: 8px 10px; border-radius: var(--erp-radius-sm);
    color: var(--tx-body); text-decoration: none;
}
.ds-palette__item:hover, .ds-palette__item.is-active { background: var(--su-active); color: var(--tx-title); text-decoration: none; }
.ds-palette__ic {
    width: 30px; height: 30px; flex: none; border-radius: var(--erp-radius-sm);
    display: flex; align-items: center; justify-content: center;
    background: var(--su-sunken); color: var(--tx-muted);
}
.ds-palette__ic .erp-i { width: 16px; height: 16px; }
.ds-palette__item.is-active .ds-palette__ic { background: var(--erp-primary); color: #fff; }
.ds-palette__body { min-width: 0; flex: 1; }
.ds-palette__label { display: block; font-size: var(--fs-md); font-weight: var(--fw-semibold); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ds-palette__sub { display: block; font-size: var(--fs-xs); color: var(--tx-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ds-palette__hint { width: 14px; height: 14px; color: var(--tx-faint); opacity: 0; flex: none; }
.ds-palette__item.is-active .ds-palette__hint { opacity: 1; }
.ds-palette__vacio { text-align: center; padding: var(--sp-10) var(--sp-4); color: var(--tx-muted); }
.ds-palette__vacio p { margin: var(--sp-3) 0 2px; color: var(--tx-body); font-size: var(--fs-md); }
.ds-palette__vacio small { font-size: var(--fs-xs); }
.ds-palette__cargando { padding: var(--sp-4); }
.ds-palette__foot {
    display: flex; align-items: center; gap: var(--sp-4);
    padding: 8px var(--sp-4); border-top: 1px solid var(--li-border);
    background: var(--su-sunken); font-size: var(--fs-xs); color: var(--tx-muted);
}
.ds-palette__foot kbd {
    background: var(--su-card); border: 1px solid var(--li-border); border-bottom-width: 2px;
    border-radius: 4px; padding: 1px 5px; margin-right: 2px;
    font-family: inherit; font-size: 10.5px; color: var(--tx-body);
}
@media (max-width: 575.98px) {
    .ds-palette__panel { margin-top: 0; width: 100vw; max-height: 100vh; height: 100%; border-radius: 0; border: 0; }
    .ds-palette__foot span { display: none; }
    .ds-palette__foot a { margin-left: 0 !important; }
}

/* ══════════════════════════════════════════════════════════════════════════
   15) DISPARADOR DE BÚSQUEDA DEL HEADER
   Una caja que parece caja: el buscador anterior estaba comentado y no había
   ninguna pista de que se pudiera buscar.
   ══════════════════════════════════════════════════════════════════════════ */
.ds-search-trigger {
    display: flex; align-items: center; gap: var(--sp-2);
    width: min(340px, 42vw);
    padding: 7px var(--sp-3);
    border: 1px solid var(--li-border); border-radius: var(--erp-radius);
    background: var(--su-sunken); color: var(--tx-muted);
    font-size: var(--fs-md); text-align: left;
    transition: border-color var(--mo-fast) var(--mo-ease), background var(--mo-fast) var(--mo-ease);
}
.ds-search-trigger:hover { border-color: var(--li-strong); background: var(--su-card); color: var(--tx-body); text-decoration: none; }
.ds-search-trigger .erp-i { width: 15px; height: 15px; flex: none; }
.ds-search-trigger__text { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ds-search-trigger__kbd {
    display: inline-flex; gap: 2px; flex: none;
    font-size: 10.5px; font-weight: var(--fw-semibold); color: var(--tx-faint);
}
.ds-search-trigger__kbd span {
    background: var(--su-card); border: 1px solid var(--li-border);
    border-radius: 4px; padding: 0 4px; line-height: 16px;
}
@media (max-width: 991.98px) {
    .ds-search-trigger { width: auto; padding: 7px 9px; }
    .ds-search-trigger__text, .ds-search-trigger__kbd { display: none; }
}

/* ══════════════════════════════════════════════════════════════════════════
   16) (libre)
   Aquí vivía un menú lateral con grupos plegables y filtro. Se retiró a
   petición: el sidebar vuelve a ser la lista plana de siempre, que se pinta
   en `layouts/partials/sidebar.blade.php`. Lo único que queda de aquello es
   el dimensionado del icono, en la sección 3, y el color por módulo, que
   está en la sección 15 de erp-ui.css.
   ══════════════════════════════════════════════════════════════════════════ */

/* ══════════════════════════════════════════════════════════════════════════
   17) SELECTOR DE VISTA (lista / tablero / calendario · §15)
   ══════════════════════════════════════════════════════════════════════════ */
.ds-viewswitch {
    display: inline-flex; padding: 3px; gap: 2px;
    background: var(--su-sunken); border: 1px solid var(--li-border);
    border-radius: var(--erp-radius);
}
.ds-viewswitch__btn {
    display: inline-flex; align-items: center; gap: 6px;
    padding: 6px 12px; border-radius: var(--erp-radius-sm);
    font-size: var(--fs-md); font-weight: var(--fw-semibold); color: var(--tx-muted);
}
.ds-viewswitch__btn:hover { color: var(--tx-title); text-decoration: none; }
.ds-viewswitch__btn.is-active { background: var(--su-card); color: var(--erp-primary); box-shadow: var(--el-1); }
.ds-viewswitch__btn .erp-i { width: 15px; height: 15px; }
@media (max-width: 575.98px) { .ds-viewswitch__btn span { display: none; } .ds-viewswitch__btn { padding: 6px 10px; } }

/* ══════════════════════════════════════════════════════════════════════════
   18) TABLERO KANBAN (§15)
   Siete columnas no caben en una pantalla sin dejar las tarjetas ilegibles,
   así que el tablero desplaza en horizontal y cada columna desplaza dentro.
   ══════════════════════════════════════════════════════════════════════════ */
.ds-board {
    display: flex; gap: var(--sp-3);
    overflow-x: auto; padding-bottom: var(--sp-3);
    scroll-snap-type: x proximity;
}
.ds-board__col {
    flex: 0 0 288px; max-width: 288px;
    display: flex; flex-direction: column;
    background: var(--su-sunken);
    border: 1px solid var(--li-border);
    border-radius: var(--erp-radius-lg);
    max-height: 74vh;
    scroll-snap-align: start;
}
.ds-board__head {
    display: flex; align-items: center; gap: var(--sp-2);
    padding: var(--sp-3) var(--sp-3) var(--sp-2);
    border-bottom: 1px solid var(--li-border);
}
.ds-board__dot { width: 8px; height: 8px; border-radius: 50%; flex: none; }
.ds-board__title { margin: 0; font-size: var(--fs-md); font-weight: var(--fw-bold); color: var(--tx-title); }
.ds-board__count {
    margin-left: auto; min-width: 22px; padding: 1px 7px; text-align: center;
    background: var(--su-card); border: 1px solid var(--li-border);
    border-radius: 999px; font-size: var(--fs-xs); font-weight: var(--fw-bold); color: var(--tx-muted);
}
.ds-board__body { padding: var(--sp-2); overflow-y: auto; flex: 1; display: grid; gap: var(--sp-2); align-content: start; }
.ds-board__empty { text-align: center; color: var(--tx-faint); font-size: var(--fs-sm); padding: var(--sp-6) 0; margin: 0; }

/* ── Tarjeta ────────────────────────────────────────────────────────────── */
.ds-card {
    display: block; padding: var(--sp-3);
    background: var(--su-card); border: 1px solid var(--li-border);
    border-radius: var(--erp-radius); color: var(--tx-body);
    transition: border-color var(--mo-fast) var(--mo-ease), box-shadow var(--mo-fast) var(--mo-ease), transform var(--mo-fast) var(--mo-ease);
}
.ds-card:hover { border-color: var(--erp-primary); box-shadow: var(--el-2); text-decoration: none; transform: translateY(-1px); }
.ds-card__top { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2); margin-bottom: 6px; }
.ds-card__code { font-size: var(--fs-xs); font-weight: var(--fw-bold); color: var(--tx-faint); letter-spacing: .02em; }
.ds-card__title { margin: 0 0 5px; font-size: var(--fs-md); font-weight: var(--fw-semibold); color: var(--tx-title); line-height: var(--lh-tight); }
.ds-card__meta { margin: 0 0 var(--sp-2); font-size: var(--fs-xs); color: var(--tx-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ds-card__bar { height: 4px; border-radius: 999px; background: var(--su-sunken); overflow: hidden; margin-bottom: var(--sp-2); }
.ds-card__bar span { display: block; height: 100%; background: var(--erp-primary); border-radius: 999px; }
.ds-card__foot { display: flex; align-items: center; gap: var(--sp-2); font-size: var(--fs-xs); color: var(--tx-muted); }
.ds-card__pct { font-weight: var(--fw-bold); color: var(--tx-body); }
.ds-card__due { margin-left: auto; display: inline-flex; align-items: center; gap: 3px; white-space: nowrap; }
.ds-card__due.is-late { color: var(--erp-danger); font-weight: var(--fw-bold); }
.ds-card__due.is-soon { color: var(--erp-warning); font-weight: var(--fw-semibold); }
.ds-card__clip { display: inline-flex; align-items: center; gap: 2px; }

/* ══════════════════════════════════════════════════════════════════════════
   19) CALENDARIO (§15)
   ══════════════════════════════════════════════════════════════════════════ */
.ds-monthnav { display: inline-flex; align-items: center; gap: var(--sp-2); }
.ds-monthnav__btn {
    width: 32px; height: 32px; display: inline-flex; align-items: center; justify-content: center;
    border: 1px solid var(--li-border); border-radius: var(--erp-radius-sm);
    background: var(--su-card); color: var(--tx-muted);
}
.ds-monthnav__btn:hover { color: var(--erp-primary); border-color: var(--erp-primary); text-decoration: none; }
.ds-monthnav__label { font-weight: var(--fw-bold); color: var(--tx-title); min-width: 138px; text-align: center; font-size: var(--fs-lg); }
.ds-monthnav__today { font-size: var(--fs-sm); font-weight: var(--fw-semibold); color: var(--erp-primary); }

.ds-cal__names, .ds-cal__grid { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); }
.ds-cal__names {
    border-bottom: 1px solid var(--li-border);
    font-size: var(--fs-xs); font-weight: var(--fw-bold); color: var(--tx-muted);
    text-transform: uppercase; letter-spacing: .04em;
}
.ds-cal__names span { padding: var(--sp-2); text-align: center; }
.ds-cal__day {
    min-height: 112px; padding: 6px;
    border-right: 1px solid var(--li-border); border-bottom: 1px solid var(--li-border);
    display: flex; flex-direction: column; gap: 3px;
}
.ds-cal__day:nth-child(7n) { border-right: 0; }
.ds-cal__day.is-out { background: var(--su-sunken); }
.ds-cal__day.is-out .ds-cal__num { color: var(--tx-faint); }
.ds-cal__day.is-today { background: var(--erp-primary-soft); }
.ds-cal__day.is-today .ds-cal__num span:first-child {
    background: var(--erp-primary); color: #fff; border-radius: 999px;
    width: 22px; height: 22px; display: inline-flex; align-items: center; justify-content: center;
}
.ds-cal__num { display: flex; align-items: center; justify-content: space-between; font-size: var(--fs-sm); font-weight: var(--fw-semibold); color: var(--tx-body); }
.ds-cal__badge {
    min-width: 18px; padding: 0 5px; border-radius: 999px; text-align: center;
    background: var(--su-sunken); color: var(--tx-muted); font-size: 10px; font-weight: var(--fw-bold);
}
.ds-cal__badge.is-late { background: var(--erp-danger-soft); color: var(--erp-danger); }
.ds-cal__items { display: grid; gap: 2px; min-width: 0; }
.ds-cal__item {
    display: flex; align-items: center; gap: 4px;
    padding: 2px 5px; border-radius: 4px;
    font-size: 11px; color: var(--tx-body); background: var(--su-sunken);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ds-cal__item:hover { background: var(--su-active); color: var(--tx-title); text-decoration: none; }
.ds-cal__dot { width: 6px; height: 6px; border-radius: 50%; flex: none; background: var(--tx-faint); }
.ds-cal__item.is-success .ds-cal__dot { background: var(--erp-success); }
.ds-cal__item.is-danger  .ds-cal__dot { background: var(--erp-danger); }
.ds-cal__item.is-warning .ds-cal__dot { background: var(--erp-warning); }
.ds-cal__item.is-info    .ds-cal__dot { background: var(--erp-info); }
.ds-cal__more { font-size: 10.5px; font-weight: var(--fw-semibold); color: var(--erp-primary); padding-left: 5px; }

/* En móvil la rejilla de siete columnas deja celdas de 45 px: ilegible.
   Se pasa a una lista de días, que es como se consulta desde el teléfono. */
@media (max-width: 767.98px) {
    .ds-cal__names { display: none; }
    .ds-cal__grid { grid-template-columns: 1fr; }
    .ds-cal__day { min-height: 0; border-right: 0; flex-direction: row; align-items: flex-start; gap: var(--sp-3); padding: var(--sp-2) var(--sp-3); }
    .ds-cal__day.is-out { display: none; }
    .ds-cal__num { flex: 0 0 46px; }
    .ds-cal__items { flex: 1; }
    .ds-cal__item { font-size: var(--fs-sm); padding: 5px 8px; }
}

/* ══════════════════════════════════════════════════════════════════════════
   20) CABECERA DEL PANEL (§06)
   Saludo contextual + acciones de creación. Sustituye al encabezado de módulo
   en los paneles: allí el título repetía lo que el menú ya decía.
   ══════════════════════════════════════════════════════════════════════════ */
.ds-greet {
    display: flex; align-items: flex-start; gap: var(--sp-4);
    flex-wrap: wrap; margin-bottom: var(--sp-6);
}
.ds-greet__text { flex: 1; min-width: 240px; }
.ds-greet__title { margin: 0; font-size: var(--fs-2xl); font-weight: var(--fw-bold); color: var(--tx-title); line-height: var(--lh-tight); }
.ds-greet__sub {
    margin: 5px 0 0; display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
    font-size: var(--fs-md); color: var(--tx-muted);
}
.ds-greet__actions { flex: none; }
@media (max-width: 575.98px) {
    .ds-greet { margin-bottom: var(--sp-4); }
    .ds-greet__title { font-size: var(--fs-xl); }
    .ds-greet__actions { width: 100%; }
    .ds-greet__actions .dropdown, .ds-greet__actions .btn { width: 100%; }
}

/* ══════════════════════════════════════════════════════════════════════════
   21) RESPONSIVE (§23) · lo que faltaba
   La experiencia del colaborador en el teléfono es la prioritaria: es quien
   sube evidencia desde donde está pasando el trabajo.
   ══════════════════════════════════════════════════════════════════════════ */
@media (max-width: 767.98px) {
    /* Objetivos táctiles: 24 px de alto no se aciertan con el pulgar. */
    .btn { min-height: 38px; }
    .btn-sm { min-height: 32px; }
    .vertical-nav-menu li a { padding-top: 10px; padding-bottom: 10px; }
    .erp-row-actions .btn { min-width: 36px; min-height: 36px; }

    /* Las acciones del encabezado, a lo ancho y apiladas. */
    .app-page-title .page-title-actions { display: flex; flex-wrap: wrap; gap: var(--sp-2); width: 100%; margin-top: var(--sp-3); }
    .app-page-title .page-title-actions > * { flex: 1 1 auto; }
    .app-page-title .page-title-wrapper { flex-direction: column; align-items: flex-start; }

    /* La barra de filtros: un campo por línea en vez de cuatro apretados. */
    .erp-toolbar > [class*="col-"] { flex: 0 0 100%; max-width: 100%; }

    /* El tablero pasa a una columna por pantalla, con arrastre horizontal. */
    .ds-board__col { flex: 0 0 86vw; max-width: 86vw; max-height: none; }

    /* Tablas anchas: se desplazan dentro de su caja, nunca empujan la página. */
    .table-responsive { -webkit-overflow-scrolling: touch; }
}

/* Ninguna tabla ni bloque ancho puede desplazar la página entera en horizontal:
   es el defecto responsive más común y el más molesto de usar. */
body { overflow-x: hidden; }
.table-responsive, .ds-board, .ds-tabs { max-width: 100%; }

/* ══════════════════════════════════════════════════════════════════════════
   22) IMPRESIÓN
   Un reporte que se manda a imprimir con el menú y los botones dentro no vale
   como respaldo ante el cliente.
   ══════════════════════════════════════════════════════════════════════════ */
@media print {
    .app-sidebar, .app-header, .app-footer, .ds-palette, .ds-viewswitch,
    .page-title-actions, .erp-toolbar, .erp-row-actions, .ds-kebab,
    .pagination { display: none !important; }
    .app-main__outer { margin-left: 0 !important; }
    .card, .main-card { box-shadow: none !important; border: 1px solid #ccc !important; break-inside: avoid; }
    a[href]::after { content: ""; }   /* la URL detrás de cada enlace es ruido */
}

/* ══════════════════════════════════════════════════════════════════════════
   23) CABECERA DE ENTIDAD (§13)
   Identidad de la ficha: logo, nombre, datos que identifican y estado. Es lo
   que evita tener que bajar media pantalla para saber de quién es la cuenta.
   ══════════════════════════════════════════════════════════════════════════ */
.ds-entity {
    display: flex; align-items: flex-start; gap: var(--sp-4);
    padding: var(--sp-4);
    background: var(--su-card); border: 1px solid var(--li-border);
    border-radius: var(--erp-radius-lg); box-shadow: var(--el-1);
    margin-bottom: var(--sp-4); flex-wrap: wrap;
}
.ds-entity__logo {
    width: 56px; height: 56px; flex: none;
    display: flex; align-items: center; justify-content: center;
    border-radius: var(--erp-radius); overflow: hidden;
    background: var(--erp-warning-soft); color: var(--erp-a-amber);
}
.ds-entity__logo img { width: 100%; height: 100%; object-fit: contain; }
.ds-entity__logo .erp-i { width: 26px; height: 26px; }
.ds-entity__body { flex: 1; min-width: 200px; }
.ds-entity__name { margin: 0; font-size: var(--fs-2xl); font-weight: var(--fw-bold); color: var(--tx-title); line-height: var(--lh-tight); }
.ds-entity__meta {
    margin: 6px 0 0; display: flex; flex-wrap: wrap; gap: var(--sp-1) var(--sp-4);
    font-size: var(--fs-sm); color: var(--tx-muted);
}
.ds-entity__meta span { display: inline-flex; align-items: center; gap: 4px; }
.ds-entity__side { display: flex; flex-direction: column; align-items: flex-end; gap: var(--sp-3); }
.ds-entity__actions { display: flex; flex-wrap: wrap; gap: var(--sp-2); justify-content: flex-end; }

@media (max-width: 767.98px) {
    .ds-entity__side { width: 100%; align-items: stretch; }
    .ds-entity__actions { justify-content: stretch; }
    .ds-entity__actions > * { flex: 1 1 auto; }
    .ds-entity__name { font-size: var(--fs-xl); }
}

/* ══════════════════════════════════════════════════════════════════════════
   24) MAPA ESTRATÉGICO (§07)
   El árbol de objetivos. La sangría dice la dependencia y el anillo dice el
   avance: los dos de un vistazo, que es como se lee un mapa en un consejo.
   ══════════════════════════════════════════════════════════════════════════ */
.ds-obj {
    display: flex; align-items: stretch; gap: var(--sp-2);
    margin-bottom: var(--sp-2);
}
.ds-obj__main {
    flex: 1; min-width: 0;
    display: flex; align-items: center; gap: var(--sp-3);
    padding: var(--sp-3);
    background: var(--su-card); border: 1px solid var(--li-border);
    border-radius: var(--erp-radius); color: var(--tx-body);
    transition: border-color var(--mo-fast) var(--mo-ease), box-shadow var(--mo-fast) var(--mo-ease);
}
.ds-obj__main:hover { border-color: var(--erp-primary); box-shadow: var(--el-1); text-decoration: none; }
.ds-obj__ring { flex: none; }
.ds-obj__body { flex: 1; min-width: 0; }
.ds-obj__name {
    display: block; font-weight: var(--fw-semibold); color: var(--tx-title);
    font-size: var(--fs-md); line-height: var(--lh-tight);
}
.ds-obj__meta { display: block; font-size: var(--fs-xs); color: var(--tx-muted); margin-top: 2px; }
.ds-obj__side { display: flex; align-items: center; gap: 6px; flex: none; flex-wrap: wrap; justify-content: flex-end; }
.ds-obj__tag {
    display: inline-flex; align-items: center; gap: 3px;
    padding: 2px 7px; border-radius: 999px;
    background: var(--su-sunken); color: var(--tx-muted);
    font-size: var(--fs-xs); font-weight: var(--fw-semibold);
}
.ds-obj__tag.is-warn { background: var(--erp-warning-soft); color: var(--erp-warning); }
.ds-obj__add {
    flex: none; width: 34px;
    display: flex; align-items: center; justify-content: center;
    border: 1px dashed var(--li-strong); border-radius: var(--erp-radius);
    color: var(--tx-faint);
}
.ds-obj__add:hover { border-color: var(--erp-primary); color: var(--erp-primary); background: var(--erp-primary-soft); text-decoration: none; }
/* Un objetivo descartado se conserva pero no compite por la atención. */
.ds-obj.is-dropped .ds-obj__main { opacity: .55; }
.ds-obj.is-dropped .ds-obj__name { text-decoration: line-through; }

@media (max-width: 767.98px) {
    .ds-obj { margin-left: 0 !important; }   /* la sangría no cabe en el móvil */
    .ds-obj__main { flex-wrap: wrap; }
    .ds-obj__side { width: 100%; justify-content: flex-start; }
}

/* ── Elección de perspectiva ────────────────────────────────────────────── */
.ds-persp { display: grid; gap: var(--sp-2); grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); }
.ds-persp__opt { margin: 0; cursor: pointer; }
.ds-persp__opt input { position: absolute; opacity: 0; width: 0; height: 0; }
.ds-persp__box {
    display: block; height: 100%;
    padding: var(--sp-3);
    border: 1.5px solid var(--li-border); border-radius: var(--erp-radius);
    background: var(--su-card);
    transition: border-color var(--mo-fast) var(--mo-ease), background var(--mo-fast) var(--mo-ease);
}
.ds-persp__opt:hover .ds-persp__box { border-color: var(--li-strong); }
.ds-persp__opt input:checked + .ds-persp__box { border-color: var(--erp-primary); background: var(--erp-primary-soft); }
.ds-persp__opt input:focus-visible + .ds-persp__box { outline: 2px solid var(--erp-primary); outline-offset: 2px; }
.ds-persp__ic { display: block; margin-bottom: 6px; }
.ds-persp__ic .erp-i { width: 20px; height: 20px; }
.ds-persp__name { display: block; font-weight: var(--fw-semibold); color: var(--tx-title); font-size: var(--fs-md); }
.ds-persp__q { display: block; font-size: var(--fs-xs); color: var(--tx-muted); margin-top: 3px; }

/* ══════════════════════════════════════════════════════════════════════════
   25) PROYECTO: FASES E HITOS (§08)
   La fase de la ruta crítica se distingue del resto: es la única cuyo retraso
   mueve la fecha de entrega, y si se ve igual que las demás se acaba corriendo
   detrás del retraso que no importa.
   ══════════════════════════════════════════════════════════════════════════ */
.ds-phase {
    border: 1px solid var(--li-border); border-radius: var(--erp-radius);
    padding: var(--sp-3); margin-bottom: var(--sp-3); background: var(--su-card);
}
.ds-phase.is-critical { border-color: var(--erp-warning); box-shadow: inset 3px 0 0 var(--erp-warning); }
.ds-phase__head { display: flex; align-items: center; gap: var(--sp-3); }
.ds-phase__pos {
    width: 26px; height: 26px; flex: none; border-radius: 50%;
    display: flex; align-items: center; justify-content: center;
    background: var(--su-sunken); color: var(--tx-muted);
    font-size: var(--fs-xs); font-weight: var(--fw-bold);
}
.ds-phase.is-critical .ds-phase__pos { background: var(--erp-warning-soft); color: var(--erp-warning); }
.ds-phase__tag {
    display: inline-flex; align-items: center; gap: 4px;
    padding: 1px 7px; border-radius: 999px;
    background: var(--erp-warning-soft); color: var(--erp-warning);
    font-size: var(--fs-xs); font-weight: var(--fw-bold);
}
.ds-phase__tasks { margin-top: var(--sp-3); display: grid; gap: 2px; }
.ds-phase__task {
    display: flex; align-items: center; gap: var(--sp-2);
    padding: 5px 8px; border-radius: var(--erp-radius-sm);
    font-size: var(--fs-sm); color: var(--tx-body);
}
.ds-phase__task:hover { background: var(--su-hover); color: var(--tx-title); text-decoration: none; }
.ds-phase__foot { display: flex; align-items: center; margin-top: var(--sp-2); padding-top: var(--sp-2); border-top: 1px solid var(--li-border); }

/* ── Hitos ──────────────────────────────────────────────────────────────── */
.ds-mile { padding: var(--sp-3) 0; border-bottom: 1px solid var(--li-border); }
.ds-mile:last-of-type { border-bottom: 0; }
/* El hito que compromete la entrega al cliente no se pierde entre los veinte
   internos: lleva su propia marca. */
.ds-mile.is-key { border-left: 2px solid var(--erp-danger); padding-left: var(--sp-3); margin-left: calc(var(--sp-3) * -1); }

/* ══════════════════════════════════════════════════════════════════════════
   26) MATRIZ 9-BOX (§20)
   Se lee de arriba abajo (alto desempeño primero) y de izquierda a derecha
   (alto potencial primero), que es como se mira en una sesión de comité.
   ══════════════════════════════════════════════════════════════════════════ */
.ds-ninebox {
    display: grid; gap: var(--sp-2);
    grid-template-columns: repeat(3, minmax(0, 1fr));
}
.ds-ninebox__cell {
    border: 1px solid var(--li-border); border-radius: var(--erp-radius);
    padding: var(--sp-3); background: var(--su-card);
    min-height: 148px; display: flex; flex-direction: column;
}
.ds-ninebox__cell.is-success { border-top: 3px solid var(--erp-success); }
.ds-ninebox__cell.is-info    { border-top: 3px solid var(--erp-info); }
.ds-ninebox__cell.is-warning { border-top: 3px solid var(--erp-warning); }
.ds-ninebox__cell.is-danger  { border-top: 3px solid var(--erp-danger); }
.ds-ninebox__cell.is-secondary { border-top: 3px solid var(--li-strong); }
.ds-ninebox__head { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2); }
.ds-ninebox__count {
    min-width: 22px; padding: 1px 7px; text-align: center; border-radius: 999px;
    background: var(--su-sunken); color: var(--tx-muted);
    font-size: var(--fs-xs); font-weight: var(--fw-bold);
}
/* La acción va en la casilla y no en un pie de página: es para lo que sirve
   la matriz, y en una sesión nadie baja a leer la leyenda. */
.ds-ninebox__action { font-size: var(--fs-xs); color: var(--tx-muted); margin: 4px 0 var(--sp-2); }
.ds-ninebox__people { display: grid; gap: 3px; margin-top: auto; }
.ds-ninebox__person {
    display: flex; align-items: center; gap: 6px;
    font-size: var(--fs-xs); color: var(--tx-body);
}
.ds-ninebox__axes {
    display: flex; justify-content: space-between; flex-wrap: wrap; gap: var(--sp-3);
    margin-top: var(--sp-2); font-size: var(--fs-xs); color: var(--tx-faint);
}
.ds-ninebox__axes span { display: inline-flex; align-items: center; gap: 4px; }

@media (max-width: 767.98px) {
    /* Tres columnas de 100 px no se leen: en el móvil la matriz pasa a una
       columna y se recorre en el orden del comité. */
    .ds-ninebox { grid-template-columns: 1fr; }
    .ds-ninebox__cell { min-height: 0; }
}

/* ══════════════════════════════════════════════════════════════════════════
   27) ESCALA DE 1 A 5
   Para las encuestas cortas (transferencia al puesto). Botones y no un
   desplegable: en una pregunta de cinco opciones, verlas todas a la vez es lo
   que hace que se conteste en un minuto.
   ══════════════════════════════════════════════════════════════════════════ */
.ds-scale { display: grid; gap: var(--sp-2); grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); }
.ds-scale__opt { margin: 0; cursor: pointer; }
.ds-scale__opt input { position: absolute; opacity: 0; width: 0; height: 0; }
.ds-scale__box {
    display: flex; flex-direction: column; gap: 4px; height: 100%;
    padding: var(--sp-3); text-align: center;
    border: 1.5px solid var(--li-border); border-radius: var(--erp-radius);
    background: var(--su-card); color: var(--tx-body);
    transition: border-color var(--mo-fast) var(--mo-ease), background var(--mo-fast) var(--mo-ease);
}
.ds-scale__box b { font-size: var(--fs-xl); color: var(--tx-title); }
.ds-scale__box span { font-size: var(--fs-xs); color: var(--tx-muted); }
.ds-scale__opt:hover .ds-scale__box { border-color: var(--li-strong); }
.ds-scale__opt input:checked + .ds-scale__box { border-color: var(--erp-primary); background: var(--erp-primary-soft); }
.ds-scale__opt input:checked + .ds-scale__box b { color: var(--erp-primary); }
.ds-scale__opt input:focus-visible + .ds-scale__box { outline: 2px solid var(--erp-primary); outline-offset: 2px; }

/* ══════════════════════════════════════════════════════════════════════════
   28) PANEL: BANDA PRINCIPAL Y TABLERO DE RIESGO (§13)
   El panel era un muro de contadores. Un contador dice cuánto hay; no dice si
   sube o baja, ni qué hay que mirar hoy. Esta capa añade las tres piezas que
   convierten la pantalla en una lectura: la banda con la cifra que manda y su
   dirección, la minigráfica de tendencia y la lista ordenada por riesgo.
   ══════════════════════════════════════════════════════════════════════════ */

/* ── Banda principal ────────────────────────────────────────────────── */
.ds-hero {
    position: relative; overflow: hidden;
    display: grid; gap: var(--sp-5);
    grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
    padding: var(--sp-6);
    margin-bottom: var(--sp-5);
    border: 1px solid var(--li-border);
    border-radius: var(--erp-radius-lg, 14px);
    background: var(--su-card);
}
/* El acento vive en una capa propia y no en el fondo: así el degradado no
   arrastra el color del texto cuando cambia el tema. */
.ds-hero::before {
    content: ""; position: absolute; inset: 0; pointer-events: none;
    background:
        radial-gradient(120% 140% at 100% 0%, var(--erp-primary-soft) 0%, transparent 58%),
        radial-gradient(90% 120% at 0% 100%, var(--erp-info-soft) 0%, transparent 55%);
    opacity: .85;
}
.ds-hero > * { position: relative; }

.ds-hero__lead { display: flex; flex-direction: column; gap: var(--sp-3); min-width: 0; }
.ds-hero__eyebrow {
    display: inline-flex; align-items: center; gap: 6px;
    font-size: var(--fs-xs); font-weight: var(--fw-semibold);
    letter-spacing: .06em; text-transform: uppercase; color: var(--tx-muted);
}
.ds-hero__figure { display: flex; align-items: baseline; gap: var(--sp-3); flex-wrap: wrap; }
.ds-hero__value {
    font-size: clamp(2.25rem, 5vw, 3.25rem); font-weight: var(--fw-bold);
    line-height: 1; color: var(--tx-title); font-variant-numeric: tabular-nums;
}
.ds-hero__delta {
    display: inline-flex; align-items: center; gap: 4px;
    padding: 3px 9px; border-radius: 999px;
    font-size: var(--fs-sm); font-weight: var(--fw-semibold);
    background: var(--su-sunken, rgba(0,0,0,.04)); color: var(--tx-muted);
}
.ds-hero__delta.is-up   { background: var(--erp-success-soft); color: var(--erp-a-green); }
.ds-hero__delta.is-down { background: var(--erp-danger-soft);  color: var(--erp-a-red); }
.ds-hero__note { margin: 0; font-size: var(--fs-md); color: var(--tx-muted); max-width: 46ch; }

.ds-hero__spark { color: var(--erp-primary); }
.ds-hero__spark .ds-spark { width: 100%; height: 46px; }

/* Las tres cifras de apoyo. Van en el mismo bloque y no en tarjetas sueltas:
   son la misma historia contada con tres números, no tres historias. */
.ds-hero__side { display: grid; gap: var(--sp-3); align-content: center; }
.ds-hero__row {
    display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3);
    padding: var(--sp-3) var(--sp-4);
    border: 1px solid var(--li-border); border-radius: var(--erp-radius);
    background: var(--su-card); text-decoration: none; color: inherit;
    transition: border-color var(--mo-fast) var(--mo-ease), transform var(--mo-fast) var(--mo-ease);
}
a.ds-hero__row:hover { border-color: var(--li-strong); transform: translateY(-1px); text-decoration: none; color: inherit; }
.ds-hero__row-label { display: flex; align-items: center; gap: 8px; font-size: var(--fs-sm); color: var(--tx-muted); min-width: 0; }
.ds-hero__row-value { font-size: var(--fs-xl); font-weight: var(--fw-bold); color: var(--tx-title); font-variant-numeric: tabular-nums; }
.ds-hero__row-value.is-alert { color: var(--erp-a-red); }
.ds-hero__row-value.is-warn  { color: var(--erp-a-amber); }

@media (max-width: 991.98px) {
    .ds-hero { grid-template-columns: 1fr; padding: var(--sp-5); }
}

/* ── Minigráfica ────────────────────────────────────────────────────── */
.ds-spark { display: block; overflow: visible; }
.ds-spark--teal   { color: var(--erp-a-teal); }
.ds-spark--green  { color: var(--erp-a-green); }
.ds-spark--red    { color: var(--erp-a-red); }
.ds-spark--amber  { color: var(--erp-a-amber); }
.ds-spark--blue   { color: var(--erp-a-blue); }
.ds-spark--slate  { color: var(--tx-muted); }

/* ── Tablero de riesgo ──────────────────────────────────────────────── */
.ds-risk { display: flex; flex-direction: column; }
.ds-risk__item {
    display: grid; gap: var(--sp-1) var(--sp-3);
    grid-template-columns: 4px minmax(0, 1fr) auto;
    align-items: center;
    padding: var(--sp-3) var(--sp-4);
    border-bottom: 1px solid var(--li-border);
    text-decoration: none; color: inherit;
    transition: background var(--mo-fast) var(--mo-ease);
}
.ds-risk__item:last-child { border-bottom: 0; }
.ds-risk__item:hover { background: var(--su-hover, rgba(0,0,0,.02)); text-decoration: none; color: inherit; }
/* La barra de color no decora: dice en qué escalón de riesgo cae la fila, y es
   lo que permite recorrer la lista sin leer los números. */
.ds-risk__flag { align-self: stretch; border-radius: 999px; background: var(--li-border); }
.ds-risk__item.is-high .ds-risk__flag { background: var(--erp-a-red); }
.ds-risk__item.is-mid  .ds-risk__flag { background: var(--erp-a-amber); }
.ds-risk__item.is-low  .ds-risk__flag { background: var(--erp-a-green); }
.ds-risk__name { font-weight: var(--fw-semibold); color: var(--tx-title); }
.ds-risk__why { display: flex; flex-wrap: wrap; gap: 6px 12px; font-size: var(--fs-xs); color: var(--tx-muted); margin-top: 2px; }
.ds-risk__why span { display: inline-flex; align-items: center; gap: 4px; }
.ds-risk__rate { text-align: right; font-weight: var(--fw-bold); font-variant-numeric: tabular-nums; color: var(--tx-title); }

/* ── Lista de «qué mirar hoy» ───────────────────────────────────────── */
.ds-focus__item {
    display: grid; grid-template-columns: auto minmax(0, 1fr); gap: var(--sp-3);
    padding: var(--sp-3) var(--sp-4);
    border-bottom: 1px solid var(--li-border);
}
.ds-focus__item:last-child { border-bottom: 0; }
.ds-focus__dot { width: 9px; height: 9px; border-radius: 999px; margin-top: 6px; background: var(--tx-muted); }
.ds-focus__item.sev-critical .ds-focus__dot { background: var(--erp-a-red); }
.ds-focus__item.sev-high     .ds-focus__dot { background: var(--erp-a-amber); }
.ds-focus__item.sev-medium   .ds-focus__dot { background: var(--erp-a-blue); }
.ds-focus__title { font-weight: var(--fw-semibold); color: var(--tx-title); }
.ds-focus__where { font-size: var(--fs-xs); color: var(--tx-muted); }
.ds-focus__why { font-size: var(--fs-sm); color: var(--tx-muted); margin: 4px 0 0; }

/* ── 29 · Salud de la plataforma ──────────────────────────────────────
   El panel del superadministrador dejó de contar y pasó a diagnosticar. La
   banda cambia de color según lo peor que haya encontrado: un panel verde con
   un fallo dentro es exactamente el adorno que este panel viene a sustituir.
   ------------------------------------------------------------------------ */
.ds-health.is-fail { border-color: var(--erp-a-red); }
.ds-health.is-warn { border-color: var(--erp-a-amber); }
.ds-health.is-fail::before {
    background: radial-gradient(120% 140% at 100% 0%, var(--erp-danger-soft) 0%, transparent 58%);
}
.ds-health.is-warn::before {
    background: radial-gradient(120% 140% at 100% 0%, var(--erp-warning-soft) 0%, transparent 58%);
}
.ds-health.is-ok::before {
    background: radial-gradient(120% 140% at 100% 0%, var(--erp-success-soft) 0%, transparent 58%);
}
/* «6/8» y no «75 %»: el porcentaje esconde de cuántas cosas se habla, y aquí
   ocho chequeos con dos rotos es una frase, no una proporción. */
.ds-health__of { font-size: .45em; font-weight: var(--fw-semibold); color: var(--tx-muted); }

/* ── Lista de chequeos ─────────────────────────────────────────────── */
.ds-checks { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-3); }
.ds-check {
    display: grid; grid-template-columns: auto minmax(0, 1fr); gap: var(--sp-3);
    padding: var(--sp-3) var(--sp-4);
    border: 1px solid var(--li-border); border-left-width: 3px;
    border-radius: var(--erp-radius);
    background: var(--su-card);
}
.ds-check--ok      { border-left-color: var(--erp-a-green); }
.ds-check--warn    { border-left-color: var(--erp-a-amber); }
.ds-check--fail    { border-left-color: var(--erp-a-red); }
.ds-check--unknown { border-left-color: var(--li-strong); }

.ds-check__dot {
    display: inline-flex; align-items: center; justify-content: center;
    width: 28px; height: 28px; border-radius: 999px; flex: none;
    background: var(--su-sunken, rgba(0,0,0,.04)); color: var(--tx-muted);
}
.ds-check--ok   .ds-check__dot { background: var(--erp-success-soft); color: var(--erp-a-green); }
.ds-check--warn .ds-check__dot { background: var(--erp-warning-soft); color: var(--erp-a-amber); }
.ds-check--fail .ds-check__dot { background: var(--erp-danger-soft);  color: var(--erp-a-red); }

.ds-check__body { min-width: 0; }
.ds-check__head {
    display: flex; align-items: center; justify-content: space-between;
    gap: var(--sp-3); flex-wrap: wrap; margin-bottom: 4px;
}
.ds-check__label { font-weight: var(--fw-semibold); color: var(--tx-title); }
.ds-check__detail { margin: 0; font-size: var(--fs-sm); color: var(--tx-muted); }
/* La acción siguiente se distingue del diagnóstico: un semáforo en rojo sin
   qué hacer sólo produce ansiedad, y si se lee igual que el resto se pierde. */
.ds-check__action {
    display: flex; align-items: center; gap: 6px;
    margin: 6px 0 0; font-size: var(--fs-sm); font-weight: var(--fw-semibold);
    color: var(--tx-title);
}
.ds-check__link { display: inline-block; margin-top: 4px; font-size: var(--fs-xs); }

/* ── Origen de los intentos fallidos ───────────────────────────────── */
.ds-ips { display: grid; gap: 6px; }
.ds-ips__row {
    display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3);
    padding: 6px 10px; border-radius: var(--erp-radius);
    background: var(--su-sunken, rgba(0,0,0,.04));
}
.ds-ips__row code { font-size: var(--fs-sm); color: var(--tx-title); background: none; padding: 0; }
