/* interaccion.css — capa de estados y tokens v2 de la flota (homogeneización visual, 15-oct-2026).

   FUENTE ÚNICA: services/_shared-ui/static/interaccion.css. Se copia tal cual a las 14 apps con
   tema claro/oscuro (NO al MES, mes-espejo, catalogo, cocheras ni scentcanvas) y se enlaza
   DESPUÉS de tema.css y ANTES de <app>-claro.css, así gana por ORDEN contra la Capa A, polish.css
   y el CSS de cada app a igual especificidad, y el claro de cada app la sigue pisando.

   Revisión adversarial de la cascada (opus, 15-oct 12:00) aplicada: isla de logistics y Litepicker,
   pill-toggle de la isla, radio de foco = radio de reposo, disabled sin tocar grillas, /ventas del CRM,
   tinte de fila en claro, press sin deshabilitados, movimiento reducido completo.
   Decisiones del dueño (15-oct-2026, láminas D1-D3 sobre páginas reales):
     D1-B superficies: la tarjeta queda POR ENCIMA de la página (antes era un pozo más oscuro).
     D2-C campos: borde de reposo visible (>= 3:1) y foco pegado (borde dorado + 1 px del mismo
          color, sin anillo separado).
     D3-B radios: control 8 · tarjeta 12 · pill 999. La isla de filtros conserva los suyos.

   RONDA 2 (15-oct-2026 tarde, láminas D5-D13 sobre páginas reales; §4 a §11):
     D5-C  tarjeta sólida por encima de la página en las 14 (sin vidrio, blur, halo ni degradé en el hero).
     D6-D  dorado plano en primario / «Actualizar» / solapas / barras de progreso; solapa activa de los
           gráficos en tinte con contorno; primario con relieve.
     D7-A  ítem activo del sidebar COMO HOY. EXCEPCIÓN DEL DUEÑO sobre D6 y D13: ni se aplana ni se tiñe
           ni pasa a «tecla blanca» (ver §5 y §11).
     D8-C  toda cifra en Inter tabular; mono sólo en códigos, kbd, grillas editables y planillas de mrp.
     D9-B  misma piel de header (fondo = página, hairline como sombra, título 600) + logo centrado.
     D10-C un solo lenguaje de tabla.   D11-C un solo molde de pastilla de estado.
     D12-C ritmo 24/24/32, lateral 32, techo 24 (con exclusiones).   D13-C claro con papel con jerarquía.
   Lo que va en la hoja de cada app (no acá): el +16 px de max-width de deposito/design/lims (D12), la
   excepción de cashflow del logo (<1440 px, a la izquierda) y el logo nuevo de mrp/logistics/etoro (D9).

   Reglas de la capa:
     · Todo cuelga de @media screen: la impresión y los PDF quedan exactamente como estaban.
     · No toca caja, salvo por decisión del dueño: §10 (D12) fija padding y margin de .content y de
       las tarjetas; la UI4 Capa 2 (5-nov) el relleno de .pill-toggle (§2, D7-C) y el alto de los botones
       (§26, D6-C). El resto (D5-D11, D13) no mueve el layout: líneas como sombra inset, colores y
       familia tipográfica, nunca width/height/gap/font-size/line-height.
     · Sólo se transicionan color, background-color, border-color, box-shadow, opacity y transform.
     · Sin !important. El anillo cian !important de polish.css:84-90 se apaga redefiniendo la
       variable que lee (--accent-live) EN el campo enfocado.
     · Los hover van bajo (hover: hover) and (pointer: fine): nada queda pegado en táctil.
   Contrastes (WCAG, oscuro, sobre página #0f0f11 · tarjeta #18181b · soft #1d1d21 · elev #212125
   · elev-2 #29292e): --fg-faint #8f8f8f = 5,92 · 5,48 · 5,20 · 4,96 · 4,48; --field-border
   #74747c = 4,13 · 3,82 · 3,63 · 3,46 · 3,12; acento #F2A900 = 9,53 · 8,82 · 8,36 · 7,98 · 7,20.
   Claro: --field-border #8a857a = 3,31 sobre el papel #f4f3ef y 3,67 sobre blanco.

   FORMA EXPANDIDA (30-oct-2026, U4). Esta fuente ES la antigua copia de cashflow: las reglas de la ronda 2
   (desde §4) cuyo último selector era un `:is(...)` están escritas con un selector por alternativa.
   Mismo significado y MISMA especificidad (si una alternativa pesaba menos que la más pesada de la
   lista, un `:not(.__)` o `:not(__)` de relleno le devuelve el peso: ninguna clase ni etiqueta se llama
   así). Blink indexa cada regla por su último selector simple y NO mira adentro de `:is()`: esas reglas
   se probaban contra los ~10.000 elementos de /dia en cada recálculo de estilo, y cada acción de fila
   (que reemplaza todo el `.content`) lo paga completo. Con la CPU a 4× el recálculo de /dia bajó de 511
   a 352 ms y «Posponer» de 1,31 a 0,98 s. Los estilos computados de las pantallas de cashflow, en
   oscuro y claro, quedaron idénticos a los de la versión con `:is()`.
   REGLA PARA LO NUEVO: un selector por alternativa (sin `:is()` largos sobre muchos elementos),
   `:not(.__)` de relleno si hace falta especificidad, todo dentro de @media screen, sin !important. */

@media screen {

/* ── §0 Tokens v2 ────────────────────────────────────────────────────────────────────
   Oscuro en :root (0,1,0); el claro lo fija tema.css con :root[data-tema="claro"] (0,2,0),
   que gana por especificidad. Todo token de superficie de acá tiene su par claro en tema.css. */
:root {
    /* motion: --dur-base 150 / --dur-slow 200 / --dur-tab 200 viven en tokens.css (UI4 S01: un valor,
       un nombre). Sin rebote: la fuente ya no tiene spring; estos dos alias quedan SÓLO para las copias
       podadas que todavía lo nombran (components.css de cashflow, polish.css de mrp). */
    --ease-spring: var(--ease-out);
    --dur-spring: var(--dur-base);

    /* superficies D1-B: página más oscura, tarjeta un paso más clara */
    --bg: #0f0f11;              /* papel y MES: #000 (base.css) */
    --bg-soft: #1d1d21;         /* papel: #111 */
    --bg-card: #18181b;         /* papel: #0a0a0a */
    --cockpit-surface: #18181b;
    --surface-elev: #212125;
    --surface-elev-2: #29292e;  /* encima, sólo --fg y --fg-muted (F1-16) */
    /* hairlines: con la tarjeta más clara, #1f1f1f quedaba en 1,07:1 y las tablas/chips perdían
       sus divisores. #28282d = 1,21:1 sobre la tarjeta (lo que tenían antes sobre el pozo, 1,2:1). */
    --border: #28282d;

    /* texto tenue legible (AA) sobre todas las superficies; antes #7d7d7d (3,5 a 4,6:1) */
    --fg-faint: #8f8f8f;

    /* rojo de error: con las superficies D1-B, #ef4444 quedaba en 4,46 sobre --bg-soft (etiqueta
       «Rechazado» de LIMS). #f05252 = 5,50 página · 5,09 tarjeta · 4,83 soft · 4,61 elev. Un solo rojo:
       --color-danger (#e05252) pasa a ser el mismo. El claro sigue con #b42318 (tema.css). */
    --err: #f05252;
    --color-danger: var(--err);

    /* acento: los pares que sólo existían en claro (tema.css:118-119) */
    --accent-fill: var(--accent);
    --accent-ink: var(--accent);

    /* foco: un solo color en toda la flota (el cian queda sólo para lo «en vivo») */
    --focus-color: var(--accent);
    --focus-ring: 2px solid var(--focus-color);

    /* campos (D2-C): cada app lo aplica en SU regla de campo */
    --field-border: #74747c;
    --field-border-hover: #9a9aa2;
    --focus-field-shadow: 0 0 0 1px var(--focus-color);

    /* hover, filas y elevación */
    --hover-tint: color-mix(in srgb, var(--fg) 7%, transparent);
    --row-hover: color-mix(in srgb, var(--accent) 6%, transparent);
    --shadow-1: inset 0 1px 0 rgba(255, 255, 255, 0.04);
    --shadow-2: 0 6px 16px -4px rgb(var(--sombra-rgb) / 0.5);
    --shadow-3: var(--shadow-pop);
    --disabled-opacity: 0.5;

    /* radios D3-B (la isla de filtros los fija aparte, más abajo). tokens.css conserva 6/8: los leen
       el MES, la isla y el papel. */
    --radius-btn: 8px;
    --radius-card: 12px;

    /* alturas de control: 32 el chico, 36 el normal en escritorio, 44 con el dedo (§17 y §26, D6-C) */
    --control-h-sm: 32px;
    --control-h-md: 36px;
    --control-h-touch: 44px;

    /* D1-C: el texto del botón de peligro sale de --err (aclarado como el texto de las pastillas, §9);
       en claro, la tinta --err. */
    --peligro-fg: color-mix(in srgb, var(--err) 78%, #ffffff);
}
:root[data-tema="claro"] {
    /* una sola tinta de sombra en claro, sepia (S02): la leen tema.css y esta capa (tokens.css: negro) */
    --sombra-rgb: 60 40 0;
    --field-border: #8a857a;
    --field-border-hover: #5f5b51;
    --row-hover: color-mix(in srgb, var(--accent-fill) 10%, transparent);
    /* D13-C: neutros y sombras sepia (hover, tarjeta en reposo y en hover) y el papel hondo del sidebar */
    --hover-tint: rgb(var(--sombra-rgb) / 0.05);
    --shadow-1: 0 1px 2px rgb(var(--sombra-rgb) / 0.07), 0 1px 0 rgb(var(--sombra-rgb) / 0.03);
    --shadow-2: 0 1px 2px rgb(var(--sombra-rgb) / 0.06), 0 8px 20px -10px rgb(var(--sombra-rgb) / 0.24);
    --bg-rail: #e7e4dc;   /* RIEL-C (dueño, 16-oct 09:08): un paso más hondo que --bg-soft #ecebe5, así el ítem activo (como hoy) se recorta */
    --peligro-fg: var(--err);
}

/* La isla de filtros (tarjeta sticky: Período · Filtros · pills, y sus popovers) queda IDÉNTICA:
   conserva los radios que tenía antes de esta capa. */
:is(.fb, .fb-popover, .fb-dim, .filter-island, .toolbar-seccion, .isla-filtros, .cp-isla,
    .isla, .litepicker) {
    --radius-btn: 6px;
    --radius-card: 8px;
}

/* ── §1 Estados ────────────────────────────────────────────────────────────────────── */

/* 1.1 Transición única de lo accionable. Reemplaza el spring de polish.css:61-73,
       components.css:723-730 y la copia de cashflow/logistics components.css:95-101. */
.btn, .btn--primary, .btn--ghost, .btn--secondary, .btn--danger,
button.refresh, .cmd-palette-trigger, button[data-magnetic],
.pill, .chip, .tabs__item, .tema-toggle, .sidebar-salir__btn,
[role="tab"]:where(:not(.fb *, .isla-filtros *, .toolbar-seccion *, .cp-isla *)),
button[aria-pressed]:where(:not(.fb *, .isla-filtros *, .toolbar-seccion *, .cp-isla *)) {
    transition: color var(--dur-base) var(--ease),
                background-color var(--dur-base) var(--ease),
                border-color var(--dur-base) var(--ease),
                box-shadow var(--dur-base) var(--ease),
                opacity var(--dur-base) var(--ease),
                transform var(--dur-base) var(--ease-out);
}
/* campos: selector de elemento (0,0,1); si la app ya declara su transition, gana la suya */
:where(input, select, textarea):where(:not(.fb *, .fb-popover *, .isla-filtros *, .toolbar-seccion *, .cp-isla *)) {
    transition: border-color var(--dur-base) var(--ease),
                box-shadow var(--dur-base) var(--ease),
                background-color var(--dur-base) var(--ease);
}
/* tarjetas: sólo color y sombra (sin el scale de polish.css:52-58) */
.card, .kpi-card, .chart-card {
    transition: border-color var(--dur-base) var(--ease),
                box-shadow var(--dur-base) var(--ease),
                background-color var(--dur-base) var(--ease),
                transform var(--dur-base) var(--ease-out);
}

/* 1.2 Press: corto (100 ms) y suelta en 150 ms. Sólo controles: nunca filas ni campos. */
.btn:active, .pill:active, .chip:active, .tabs__item:active,
button.refresh:active, .cmd-palette-trigger:active, [role="tab"]:active, button[aria-pressed]:active {
    transition-duration: var(--dur-fast);
}
:is(.btn, button.refresh, .cmd-palette-trigger):active:not(:disabled, [aria-disabled="true"], .is-disabled) {
    transform: scale(0.97);
}

/* 1.3 Hover (sólo puntero fino) */
@media (hover: hover) and (pointer: fine) {
    /* ghost compartido: el mismo sentido en los dos temas (hacia el texto) */
    .btn.is-ghost:hover, .btn--ghost:hover {
        background-color: var(--hover-tint);
        color: var(--fg);
    }
    /* default para chips/solapas que no tienen hover propio (0,0,0: cualquier regla de la app gana) */
    :where(.chip, .tabs__item, [role="tab"], button[aria-pressed]):where(:hover:not(:disabled, [aria-disabled="true"], [aria-selected="true"], [aria-pressed="true"])) {
        background-color: var(--hover-tint);
    }
    /* tarjetas ACCIONABLES: un paso de borde + sombra corta. Las de lectura no reaccionan. */
    a.card:hover, .card.is-interactive:hover, a.kpi-card:hover, .card[role="link"]:hover {
        border-color: var(--border-hover);
        box-shadow: var(--shadow-2);
    }
    /* filas de tabla: tinte como background-image para no pisar el fondo propio de la celda
       (tintes por tipo, celdas sticky opacas). Sin transición: se usan cientos de veces por día.
       D10: el mismo tinte en todas las tablas de la flota (antes sólo .tbl y .tbl-base). */
    :is(.tbl, .tbl-base, .tabla, .lista-tabla, .plan-tabla, .tabla-simple, .grilla, .vx-tabla, .dp-table) > tbody > tr:hover > :is(td, th) {
        background-image: linear-gradient(var(--row-hover), var(--row-hover));
    }
    /* claro: tema.css:299 `:root[data-tema="claro"] .tbl tr:hover td { background: … }` (0,4,2) borra la imagen;
       el `html` suma uno para ganarle también a logistics-claro.css (`.tabla tbody tr:hover td`, 0,4,3) */
    html:root[data-tema="claro"] :is(.tbl, .tbl-base, .tabla, .lista-tabla, .plan-tabla, .tabla-simple, .grilla, .vx-tabla, .dp-table) > tbody > tr:hover > :is(td, th) {
        background-image: linear-gradient(var(--row-hover), var(--row-hover));
    }
}
/* KPI de lectura: sin el scale de polish.css:52-58 / components.css:717-721 */
.kpi-card:hover { transform: none; }

/* 1.4 Foco de teclado — un solo color.
   (a) Todo campo enfocado: el outline !important de polish.css:84-90 lee --accent-live; acá se
       vuelve dorado, así ningún campo queda con el cian. Campos sin borde (buscador de la isla,
       grillas editables) conservan ese anillo como único indicador. (0,1,0) */
:where(input, select, textarea):focus-visible {
    --accent-live: var(--focus-color);
}
/* (a2) Radio de reposo por defecto (0,0,0): sólo lo toman los campos SIN regla propia (UA, radio 0),
       así el radio de foco de (b) coincide con el de reposo. */
:where(input:not([type="checkbox"], [type="radio"], [type="range"], [type="file"], [type="color"],
                 [type="hidden"], [type="submit"], [type="button"], [type="reset"], [type="image"]),
       select, textarea):where(:not(.grilla-editable *, .fb *, .isla-filtros *, .toolbar-seccion *, .cp-isla *)) {
    border-radius: var(--radius-btn);
}
/* (b) D2-C en los campos CON borde: borde dorado + 1 px pegado, sin anillo separado (el outline
       queda transparente: no ocupa lugar y Windows lo pinta en modo de alto contraste). Las esquinas
       vuelven a su radio (components.css:741 y polish.css:89 forzaban `border-radius: inherit`).
       Especificidad (0,1,1) y después de polish: gana a `input:focus-visible` de polish.css; las
       reglas de foco propias de cada app (>= (0,2,0)) siguen ganando y se ajustan app por app. */
input:where(:not([type="checkbox"], [type="radio"], [type="range"], [type="file"], [type="color"],
               [type="hidden"], [type="submit"], [type="button"], [type="reset"], [type="image"],
               .pill-search__input, [data-fb-custom-input], .grilla-editable *, .fb *,
               .isla-filtros *, .toolbar-seccion *, .cp-isla *)):focus-visible,
select:where(:not(.grilla-editable *, .fb *, .isla-filtros *, .toolbar-seccion *, .cp-isla *)):focus-visible,
textarea:where(:not(.grilla-editable *, .fb *, .isla-filtros *, .toolbar-seccion *, .cp-isla *)):focus-visible {
    --accent-live: transparent;
    border-color: var(--focus-color);
    box-shadow: var(--focus-field-shadow);
    border-radius: var(--radius-btn);
}

/* (c) el buscador píldora de la isla LIMS: polish.css:89 lo cuadraba al enfocar (999 -> 0) */
.isla-filtros__busqueda input:focus-visible { border-radius: var(--radius-pill); }

/* 1.5 Deshabilitado: legible, sin hover, cursor claro. NO se quita el pointer-events:none de
       components.css:319 (es lo único que frena el clic en un <a class="btn" aria-disabled>). */
:where(input, select, textarea):where(:disabled):where(:not(.grilla-editable *)) {
    opacity: var(--disabled-opacity);
    cursor: not-allowed;
}
:where(.chip, .pill, [role="tab"], button[aria-pressed]):where(:disabled, [aria-disabled="true"]) {
    opacity: var(--disabled-opacity);
    cursor: not-allowed;
}

/* 1.6 Cargando (aria-busy, ya lo ponen mrp, crm y cashflow): barrido tenue de fondo, sin cambiar
       ancho ni texto. button.refresh tiene el suyo. */
.btn[aria-busy="true"]:not(.refresh) {
    cursor: progress;
    position: relative;
    overflow: hidden;
}
/* el barrido es una capa que se TRASLADA (transform: lo compone la GPU, no repinta cada cuadro) */
.btn[aria-busy="true"]:not(.refresh)::after {
    content: "";
    position: absolute;
    inset: 0;
    background-image: linear-gradient(100deg, transparent 30%,
                      color-mix(in srgb, currentColor 16%, transparent) 50%, transparent 70%);
    pointer-events: none;
    animation: ia-ocupado 1.1s linear infinite;
}
@keyframes ia-ocupado { from { transform: translateX(-100%); } to { transform: translateX(100%); } }

/* 1.7 Error: el mismo rojo en el borde; el mensaje lo pone cada app (no se toca el DOM). */
:is(input, select, textarea)[aria-invalid="true"] {
    border-color: var(--err);
}
:is(input, select, textarea)[aria-invalid="true"]:focus-visible {
    box-shadow: 0 0 0 1px var(--err);
}

/* 1.8 Nombre de la app en el sidebar sin texto con gradiente (chrome.css:30-34 y su copia por
       app). Dorado plano: en claro es la tinta #855900. El degradé claro de tema.css se borró (S05). */
.sidebar .brand .accent {
    background: none;
    -webkit-text-fill-color: currentColor;
    color: var(--accent);
}

/* ── §2 Forma (D3-B) ──────────────────────────────────────────────────────────────────
   polish.css:188, 342-353 fijaba radios literales (tarjetas 16, botones 12, pills 14) que
   contradecían los tokens. Acá vuelven a los tokens. Lo de la isla de filtros (.fb-*,
   .vistas-save__btn, .filtro-chip-activo) NO está en esta lista: queda como estaba. */
.card, .kpi-card, .chart-card, .chart-card--premium, .feed-alertas, .resumen-list, .sync-card,
.modal-panel, .placeholder {
    border-radius: var(--radius-card);
}
.btn, .toggle-link {
    border-radius: var(--radius-btn);
}
.pill-toggle:where(:not(:is(.fb, .toolbar-seccion, .isla-filtros, .cp-isla, .filter-island) *)),
.pill-toggle:where(:not(:is(.fb, .toolbar-seccion, .isla-filtros, .cp-isla, .filter-island) *)) .pill {
    border-radius: var(--radius-pill);
}
/* D7-C (UI4 Capa 2): el riel de las solapas de gráfico a la grilla de 2 px (polish/chrome dicen 3 px, que
   con el alto de 32 dejaba la pastilla de 26 un px corrida). La isla queda como está. */
.pill-toggle:where(:not(:is(.fb, .toolbar-seccion, .isla-filtros, .cp-isla, .filter-island) *)) {
    padding: 2px;
}


/* crm /ventas: ventas.css se carga DESPUÉS de la capa (crm base.html:188-194) con literales 16/14/11. */
.page-ventas:not(.page-ventas *) :is(.card, .kpi-card, .chart-card, .chart-card--premium, .sync-card, .modal-panel) {
    border-radius: var(--radius-card);
}
.page-ventas .pill-toggle:where(:not(:is(.fb, .toolbar-seccion, .isla-filtros, .cp-isla, .filter-island) *)),
.page-ventas .pill-toggle:where(:not(:is(.fb, .toolbar-seccion, .isla-filtros, .cp-isla, .filter-island) *)) .pill {
    border-radius: var(--radius-pill);
}

/* ── §3 Movimiento reducido: sin transform ni barrido (motion.css:14-23 ya lleva las duraciones
       a ~0); el foco y los cambios de color siguen. ─────────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
    :is(.btn, button.refresh, .cmd-palette-trigger):active:not(:disabled, [aria-disabled="true"], .is-disabled),
    .btn--primary:active, .pill:active, button[data-magnetic]:active { transform: none; }
    .data-card:hover, .kpi-card:hover, .card:hover { transform: none; }
    .btn[aria-busy="true"]:not(.refresh) { opacity: 0.75; }
    .btn[aria-busy="true"]:not(.refresh)::after { animation: none; display: none; }
}


/* ══════════════════════════════════════════════════════════════════════════════════════
   RONDA 2 (15-oct-2026 tarde) — decisiones del dueño D5 a D13, una sección por decisión.
   Especificidad: el claro va con `html:root[data-tema="claro"]` (0,2,1) porque <app>-claro.css
   carga DESPUÉS de esta capa; tema.css carga antes y se le gana por orden. Sin !important.
   ══════════════════════════════════════════════════════════════════════════════════════ */

/* ── §4 Tarjeta sólida por encima de la página (D5-C) ─────────────────────────────────────
   Decisión del dueño: en las 14 apps la tarjeta es sólida y queda POR ENCIMA de la página (D1-B de
   verdad): sin vidrio, sin blur, sin halo y sin degradé dorado en el hero. La red de fondo (reports,
   meetings, wapp) sigue, pero sólo se ve ENTRE tarjetas.
   NO cambia: botones ghost e inputs (--border-elev y --shadow-glass-card NO se redefinen: los leen
   .btn.is-ghost, los campos y el modal); la KPI .kpi-card--accent de crm conserva su borde dorado y
   .kpi-alerta el de peligro; .area-card (border-top de 3 px con el color del área); la isla de filtros.
   Un solo bloque sirve a los dos temas: la sombra sale de --shadow-1/--shadow-2 (sepia en claro, §0).
   --glass-bg no se toca: sólo lo lee el bottom-nav del CRM (las tarjetas no lo usan). */
:root {
    --card-glass: var(--bg-card);          /* en claro --bg-card es #fff: no hace falta un par */
    --card-glass-content: var(--bg-card);
    --card-glass-blur: none;
    --ambient-accent: none;                /* el halo existía para que el vidrio «refracte» */
}
/* tema.css fija --ambient-accent también en `body` (0,2,1): sin esto la herencia desde html no llega */
html:root[data-tema="claro"], html:root[data-tema="claro"] body { --ambient-accent: none; }
/* Borde y sombra DIRECTOS en la tarjeta, en reposo. Con puntero fino el :hover queda afuera de esta regla
   (:not(:hover)) para no pisar el borde de las tarjetas accionables ni los hover propios de cada app;
   en táctil (sin hover real) el :hover queda PEGADO después de un toque, así que ahí la regla de reposo
   no lo excluye y la tarjeta vuelve al reposo: nada queda marcado. (0,3,2)
   Borde con significado, que NO se pisa: .kpi-alerta, .kpi-card--accent y [class*="kpi-card--"] (menos
   los de ancho .kpi-card--span-*), .card--accent (crm /ventas), el semáforo .kpi-card.is-ok/.is-warn/
   .is-err/.is-danger/.is-neutro (briefing). El :where() de las variantes suma 0: la regla sigue en (0,3,2).
   Todas llevan la sombra de reposo, también .kpi-alerta y .kpi-card--accent: con la sombra vieja en reposo y
   --shadow-1 en el hover de §12 la KPI «saltaba» al pasar el puntero (se medía en crm /). */
@media (hover: hover) and (pointer: fine) {
    html body .card:not(.kpi-alerta, .kpi-card--accent):not(:hover):where(:not(:has(.tbl-scroll))),
    html body .kpi-card:not(.kpi-alerta, .kpi-card--accent):not(:hover):where(:not(:has(.tbl-scroll))),
    html body .sync-card:not(.kpi-alerta, .kpi-card--accent):not(:hover):where(:not(:has(.tbl-scroll))),
    html body .chart-card:not(.kpi-alerta, .kpi-card--accent):not(:hover):where(:not(:has(.tbl-scroll))),
    html body .chart-card--premium:not(.kpi-alerta, .kpi-card--accent):not(:hover):where(:not(:has(.tbl-scroll))),
    html body .section-block:not(.kpi-alerta, .kpi-card--accent):not(:hover):where(:not(:has(.tbl-scroll))),
    html body .cockpit-hero__card:not(.kpi-alerta, .kpi-card--accent):not(:hover):where(:not(:has(.tbl-scroll))),
    html body .data-panel:not(.kpi-alerta, .kpi-card--accent):not(:hover):where(:not(:has(.tbl-scroll))) {
        box-shadow: var(--shadow-1);
    }
    html body .kpi-alerta.card:not(:hover),
    html body .kpi-alerta.kpi-card:not(:hover),
    html body .kpi-card--accent.card:not(:hover),
    html body .kpi-card--accent.kpi-card:not(:hover) {
        box-shadow: var(--shadow-1);
    }
    html body .card:not(.kpi-alerta, .kpi-card--accent):not(:hover):where(:not(
                  :has(.tbl-scroll), [class*="kpi-card--"]:not([class*="kpi-card--span"]), .card--accent,
                  .kpi-card:is(.is-ok, .is-warn, .is-err, .is-danger, .is-neutro))),
    html body .kpi-card:not(.kpi-alerta, .kpi-card--accent):not(:hover):where(:not(
                  :has(.tbl-scroll), [class*="kpi-card--"]:not([class*="kpi-card--span"]), .card--accent,
                  .kpi-card:is(.is-ok, .is-warn, .is-err, .is-danger, .is-neutro))),
    html body .sync-card:not(.kpi-alerta, .kpi-card--accent):not(:hover):where(:not(
                  :has(.tbl-scroll), [class*="kpi-card--"]:not([class*="kpi-card--span"]), .card--accent,
                  .kpi-card:is(.is-ok, .is-warn, .is-err, .is-danger, .is-neutro))),
    html body .chart-card:not(.kpi-alerta, .kpi-card--accent):not(:hover):where(:not(
                  :has(.tbl-scroll), [class*="kpi-card--"]:not([class*="kpi-card--span"]), .card--accent,
                  .kpi-card:is(.is-ok, .is-warn, .is-err, .is-danger, .is-neutro))),
    html body .chart-card--premium:not(.kpi-alerta, .kpi-card--accent):not(:hover):where(:not(
                  :has(.tbl-scroll), [class*="kpi-card--"]:not([class*="kpi-card--span"]), .card--accent,
                  .kpi-card:is(.is-ok, .is-warn, .is-err, .is-danger, .is-neutro))),
    html body .section-block:not(.kpi-alerta, .kpi-card--accent):not(:hover):where(:not(
                  :has(.tbl-scroll), [class*="kpi-card--"]:not([class*="kpi-card--span"]), .card--accent,
                  .kpi-card:is(.is-ok, .is-warn, .is-err, .is-danger, .is-neutro))),
    html body .cockpit-hero__card:not(.kpi-alerta, .kpi-card--accent):not(:hover):where(:not(
                  :has(.tbl-scroll), [class*="kpi-card--"]:not([class*="kpi-card--span"]), .card--accent,
                  .kpi-card:is(.is-ok, .is-warn, .is-err, .is-danger, .is-neutro))),
    html body .data-panel:not(.kpi-alerta, .kpi-card--accent):not(:hover):where(:not(
                  :has(.tbl-scroll), [class*="kpi-card--"]:not([class*="kpi-card--span"]), .card--accent,
                  .kpi-card:is(.is-ok, .is-warn, .is-err, .is-danger, .is-neutro))) {
        border-color: var(--border);
    }
    /* hover: sombra corta en todas; el borde pasa a --border-hover (sin esto volvería al --border-elev
       de polish.css y la tarjeta «saltaría» a un hairline blanco). Alerta, acento y semáforo conservan su borde. */
    html body .card:hover:where(:not(:has(.tbl-scroll))),
    html body .kpi-card:hover:where(:not(:has(.tbl-scroll))),
    html body .sync-card:hover:where(:not(:has(.tbl-scroll))),
    html body .chart-card:hover:where(:not(:has(.tbl-scroll))),
    html body .chart-card--premium:hover:where(:not(:has(.tbl-scroll))),
    html body .section-block:hover:where(:not(:has(.tbl-scroll))),
    html body .cockpit-hero__card:hover:where(:not(:has(.tbl-scroll))),
    html body .data-panel:hover:where(:not(:has(.tbl-scroll))) {
        box-shadow: var(--shadow-2);
    }
    html body .card:not(.kpi-alerta, .kpi-card--accent):hover:where(:not(
                  :has(.tbl-scroll), [class*="kpi-card--"]:not([class*="kpi-card--span"]), .card--accent,
                  .kpi-card:is(.is-ok, .is-warn, .is-err, .is-danger, .is-neutro))),
    html body .kpi-card:not(.kpi-alerta, .kpi-card--accent):hover:where(:not(
                  :has(.tbl-scroll), [class*="kpi-card--"]:not([class*="kpi-card--span"]), .card--accent,
                  .kpi-card:is(.is-ok, .is-warn, .is-err, .is-danger, .is-neutro))),
    html body .sync-card:not(.kpi-alerta, .kpi-card--accent):hover:where(:not(
                  :has(.tbl-scroll), [class*="kpi-card--"]:not([class*="kpi-card--span"]), .card--accent,
                  .kpi-card:is(.is-ok, .is-warn, .is-err, .is-danger, .is-neutro))),
    html body .chart-card:not(.kpi-alerta, .kpi-card--accent):hover:where(:not(
                  :has(.tbl-scroll), [class*="kpi-card--"]:not([class*="kpi-card--span"]), .card--accent,
                  .kpi-card:is(.is-ok, .is-warn, .is-err, .is-danger, .is-neutro))),
    html body .chart-card--premium:not(.kpi-alerta, .kpi-card--accent):hover:where(:not(
                  :has(.tbl-scroll), [class*="kpi-card--"]:not([class*="kpi-card--span"]), .card--accent,
                  .kpi-card:is(.is-ok, .is-warn, .is-err, .is-danger, .is-neutro))),
    html body .section-block:not(.kpi-alerta, .kpi-card--accent):hover:where(:not(
                  :has(.tbl-scroll), [class*="kpi-card--"]:not([class*="kpi-card--span"]), .card--accent,
                  .kpi-card:is(.is-ok, .is-warn, .is-err, .is-danger, .is-neutro))),
    html body .cockpit-hero__card:not(.kpi-alerta, .kpi-card--accent):hover:where(:not(
                  :has(.tbl-scroll), [class*="kpi-card--"]:not([class*="kpi-card--span"]), .card--accent,
                  .kpi-card:is(.is-ok, .is-warn, .is-err, .is-danger, .is-neutro))),
    html body .data-panel:not(.kpi-alerta, .kpi-card--accent):hover:where(:not(
                  :has(.tbl-scroll), [class*="kpi-card--"]:not([class*="kpi-card--span"]), .card--accent,
                  .kpi-card:is(.is-ok, .is-warn, .is-err, .is-danger, .is-neutro))) {
        border-color: var(--border-hover);
    }
}
@media not ((hover: hover) and (pointer: fine)) {
    html body .card:not(.kpi-alerta, .kpi-card--accent):where(:not(:has(.tbl-scroll))),
    html body .kpi-card:not(.kpi-alerta, .kpi-card--accent):where(:not(:has(.tbl-scroll))),
    html body .sync-card:not(.kpi-alerta, .kpi-card--accent):where(:not(:has(.tbl-scroll))),
    html body .chart-card:not(.kpi-alerta, .kpi-card--accent):where(:not(:has(.tbl-scroll))),
    html body .chart-card--premium:not(.kpi-alerta, .kpi-card--accent):where(:not(:has(.tbl-scroll))),
    html body .section-block:not(.kpi-alerta, .kpi-card--accent):where(:not(:has(.tbl-scroll))),
    html body .cockpit-hero__card:not(.kpi-alerta, .kpi-card--accent):where(:not(:has(.tbl-scroll))),
    html body .data-panel:not(.kpi-alerta, .kpi-card--accent):where(:not(:has(.tbl-scroll))) {
        box-shadow: var(--shadow-1);
    }
    html body .kpi-alerta.card,
    html body .kpi-alerta.kpi-card,
    html body .kpi-card--accent.card,
    html body .kpi-card--accent.kpi-card {
        box-shadow: var(--shadow-1);
    }
    html body .card:not(.kpi-alerta, .kpi-card--accent):where(:not(
                  :has(.tbl-scroll), [class*="kpi-card--"]:not([class*="kpi-card--span"]), .card--accent,
                  .kpi-card:is(.is-ok, .is-warn, .is-err, .is-danger, .is-neutro))),
    html body .kpi-card:not(.kpi-alerta, .kpi-card--accent):where(:not(
                  :has(.tbl-scroll), [class*="kpi-card--"]:not([class*="kpi-card--span"]), .card--accent,
                  .kpi-card:is(.is-ok, .is-warn, .is-err, .is-danger, .is-neutro))),
    html body .sync-card:not(.kpi-alerta, .kpi-card--accent):where(:not(
                  :has(.tbl-scroll), [class*="kpi-card--"]:not([class*="kpi-card--span"]), .card--accent,
                  .kpi-card:is(.is-ok, .is-warn, .is-err, .is-danger, .is-neutro))),
    html body .chart-card:not(.kpi-alerta, .kpi-card--accent):where(:not(
                  :has(.tbl-scroll), [class*="kpi-card--"]:not([class*="kpi-card--span"]), .card--accent,
                  .kpi-card:is(.is-ok, .is-warn, .is-err, .is-danger, .is-neutro))),
    html body .chart-card--premium:not(.kpi-alerta, .kpi-card--accent):where(:not(
                  :has(.tbl-scroll), [class*="kpi-card--"]:not([class*="kpi-card--span"]), .card--accent,
                  .kpi-card:is(.is-ok, .is-warn, .is-err, .is-danger, .is-neutro))),
    html body .section-block:not(.kpi-alerta, .kpi-card--accent):where(:not(
                  :has(.tbl-scroll), [class*="kpi-card--"]:not([class*="kpi-card--span"]), .card--accent,
                  .kpi-card:is(.is-ok, .is-warn, .is-err, .is-danger, .is-neutro))),
    html body .cockpit-hero__card:not(.kpi-alerta, .kpi-card--accent):where(:not(
                  :has(.tbl-scroll), [class*="kpi-card--"]:not([class*="kpi-card--span"]), .card--accent,
                  .kpi-card:is(.is-ok, .is-warn, .is-err, .is-danger, .is-neutro))),
    html body .data-panel:not(.kpi-alerta, .kpi-card--accent):where(:not(
                  :has(.tbl-scroll), [class*="kpi-card--"]:not([class*="kpi-card--span"]), .card--accent,
                  .kpi-card:is(.is-ok, .is-warn, .is-err, .is-danger, .is-neutro))) {
        border-color: var(--border);
    }
}
/* hero de reports/meetings/crm: sólido, sin el anillo de luz ni el degradé dorado de su ::before */
body .cockpit-hero__card { background: var(--bg-card); }
body .cockpit-hero__card::before { display: none; }

/* ── §5 Dorado de acción (D6-D) y sidebar (D7-A) ──────────────────────────────────────────
   D6-D: el relleno dorado queda PLANO en el primario, «Actualizar», las solapas activas de los
   gráficos y las barras de progreso; la solapa activa pasa a tinte 16 % + contorno + texto dorado
   (tinta en claro); el primario gana relieve (filo de luz arriba y contorno un tono más oscuro) y
   pierde el resplandor dorado. Todo sale del token --accent-grad, que ahora vale el dorado plano.
   EXCEPCIÓN DEL DUEÑO (D7-A): el ÍTEM ACTIVO DEL SIDEBAR queda COMO HOY en los dos temas, con su barra
   de degradé y resplandor y su fondo: .sidebar re-declara el degradé EXACTO de hoy (oscuro: base.css,
   claro: tema.css), así que ni se aplana ni se tiñe. Tampoco cambia la isla de filtros.
   Barras de progreso en claro: el dorado plano #F2A900 da 1,8:1 sobre el papel; usan la tinta
   #855900 (5,1 a 6,1:1). */
:root { --accent-grad: var(--accent); }
/* tema.css fija --accent-grad también en `body` (0,2,1): se le gana con (0,2,2) */
html:root[data-tema="claro"], html:root[data-tema="claro"] body { --accent-grad: var(--accent-fill); }
.sidebar,
.fb,
.fb-popover,
.fb-dim,
.filter-island,
.toolbar-seccion,
.isla-filtros,
.cp-isla,
.isla,
.litepicker {
    --accent-grad: linear-gradient(135deg, #FFCC00 0%, #F2391C 100%);
}
html:root[data-tema="claro"] .sidebar,
html:root[data-tema="claro"] .fb,
html:root[data-tema="claro"] .fb-popover,
html:root[data-tema="claro"] .fb-dim,
html:root[data-tema="claro"] .filter-island,
html:root[data-tema="claro"] .toolbar-seccion,
html:root[data-tema="claro"] .isla-filtros,
html:root[data-tema="claro"] .cp-isla,
html:root[data-tema="claro"] .isla,
html:root[data-tema="claro"] .litepicker {
    --accent-grad: linear-gradient(135deg, #f2a900 0%, #e8590c 100%);
}
html:root[data-tema="claro"] .ld-emb-barra,
html:root[data-tema="claro"] .progress__bar,
html:root[data-tema="claro"] .sow-bar__fill {
    background: var(--accent);
}
/* primario y «Actualizar»: plano con relieve (la isla conserva el suyo) */
body .btn.is-primary:where(:not(:is(.fb, .fb-popover, .fb-dim, .filter-island, .toolbar-seccion, .isla-filtros, .cp-isla, .isla, .litepicker) *)),
body .btn--primary:where(:not(:is(.fb, .fb-popover, .fb-dim, .filter-island, .toolbar-seccion, .isla-filtros, .cp-isla, .isla, .litepicker) *)):not(.__),
body .header button.refresh {
    background: var(--accent-fill);
    border-color: transparent;
    color: var(--on-accent);
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.30),
                0 0 0 1px color-mix(in srgb, var(--accent-fill) 72%, #000);
}
@media (hover: hover) and (pointer: fine) {
    /* 12 % más oscuro, sin filtro. El segundo selector le gana a tema.css:398 (hover del primario en claro) */
    body .btn.is-primary:where(:not(:is(.fb, .fb-popover, .fb-dim, .filter-island, .toolbar-seccion, .isla-filtros, .cp-isla, .isla, .litepicker) *)):hover,
    body .btn--primary:where(:not(:is(.fb, .fb-popover, .fb-dim, .filter-island, .toolbar-seccion, .isla-filtros, .cp-isla, .isla, .litepicker) *)):hover:not(.__),
    html:root[data-tema="claro"] body .btn.is-primary:where(:not(:is(.fb, .fb-popover, .fb-dim, .filter-island, .toolbar-seccion, .isla-filtros, .cp-isla, .isla, .litepicker) *)):hover,
    html:root[data-tema="claro"] body .btn--primary:where(:not(:is(.fb, .fb-popover, .fb-dim, .filter-island, .toolbar-seccion, .isla-filtros, .cp-isla, .isla, .litepicker) *)):hover:not(.__),
    body .header button.refresh:hover {
        background: color-mix(in srgb, var(--accent-fill) 88%, #000);
        filter: none;
    }
    /* sin el levantado de 1 px de chrome.css:270, pero el press (§1.2) se conserva: por eso :not(:active) */
    body .btn.is-primary:where(:not(:is(.fb, .fb-popover, .fb-dim, .filter-island, .toolbar-seccion, .isla-filtros, .cp-isla, .isla, .litepicker) *)):hover:not(:active),
    body .btn--primary:where(:not(:is(.fb, .fb-popover, .fb-dim, .filter-island, .toolbar-seccion, .isla-filtros, .cp-isla, .isla, .litepicker) *)):hover:not(:active):not(.__),
    body .header button.refresh:hover:not(:active) {
        transform: none;
    }
}
/* solapa activa de los gráficos: tinte + contorno. :root x3 = (0,6,1) gana a tema.css:386
   (.pill--secondary.pill--active en claro, 0,6,0) y a chrome.css:541, así primarias y secundarias de
   una misma barra quedan iguales. Contorno >= 3:1: 60 % en oscuro (3,9-4,0:1), 90 % de la tinta en
   claro (3,9-5,0:1). */
:root:root:root body .pill-toggle:where(:not(:is(.fb, .toolbar-seccion, .isla-filtros, .cp-isla, .filter-island) *)) .pill.pill--active {
    background: color-mix(in srgb, var(--accent-fill) 16%, transparent);
    color: var(--accent);
    border-color: transparent;
    box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent-fill) 60%, transparent);
    font-weight: 600;
}
html:root[data-tema="claro"]:root:root body .pill-toggle:where(:not(:is(.fb, .toolbar-seccion, .isla-filtros, .cp-isla, .filter-island) *)) .pill.pill--active {
    box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent) 90%, transparent);
}
@media (hover: hover) and (pointer: fine) {
    :root:root:root body .pill-toggle:where(:not(:is(.fb, .toolbar-seccion, .isla-filtros, .cp-isla, .filter-island) *)) .pill.pill--active:hover {
        background: color-mix(in srgb, var(--accent-fill) 22%, transparent);
        filter: none;
    }
}

/* ── §6 Cifras en Inter tabular (D8-C) ────────────────────────────────────────────────────
   Decisión del dueño: TODA cifra en Inter tabular (KPI, importes, cantidades, porcentajes y totales
   de tabla). La mono queda SÓLO para códigos (.mono, td.mono, code, «DMF03»), kbd, los campos de las
   grillas editables (cashflow /lineas) y las planillas de mrp (.plan-tabla: en Inter una celda de
   «meses» se recorta, medido). Hoy polish.css y cada app fuerzan .num/.numeric a mono.
   Declarado y sin arreglo: en crm /clientes un nombre largo («DISTRIBUIDORA MDH BAHIA S.R.L») pasa a
   2 líneas (+20 px) al ensancharse la columna numérica; un min-width no entra sin desbordar. */
body .kpi-card__valor:not(.__),
body .kpi-card__value:not(.__),
body .kpi-hero__valor:not(.__),
body .kpi-hero__value:not(.__),
body .cockpit-hero__value:not(.__),
body .data-card__valor:not(.__),
body .card .value {
    font-family: var(--font-sans);
    font-weight: 600;
    letter-spacing: -0.02em;
    font-variant-numeric: tabular-nums;
}
body .numeric:where(:not(.plan-tabla *, :is(.grilla-editable, .sueldos-grilla) :is(input, select, textarea))):not(.__):not(__),
body .num:where(:not(.plan-tabla *, :is(.grilla-editable, .sueldos-grilla) :is(input, select, textarea))):not(.__):not(__),
body .total-col:where(:not(.plan-tabla *, :is(.grilla-editable, .sueldos-grilla) :is(input, select, textarea))):not(.__):not(__),
body .total-mes:where(:not(.plan-tabla *, :is(.grilla-editable, .sueldos-grilla) :is(input, select, textarea))):not(.__):not(__),
body .total-mes-col:where(:not(.plan-tabla *, :is(.grilla-editable, .sueldos-grilla) :is(input, select, textarea))):not(.__):not(__),
body .fila-total-horas:where(:not(.plan-tabla *, :is(.grilla-editable, .sueldos-grilla) :is(input, select, textarea))):not(.__):not(__),
body .fila-total-equipo:where(:not(.plan-tabla *, :is(.grilla-editable, .sueldos-grilla) :is(input, select, textarea))):not(.__):not(__),
body .dia-hs-total:where(:not(.plan-tabla *, :is(.grilla-editable, .sueldos-grilla) :is(input, select, textarea))):not(.__):not(__),
body .tbl td.num:where(:not(.plan-tabla *, :is(.grilla-editable, .sueldos-grilla) :is(input, select, textarea))),
body th.numeric:where(:not(.plan-tabla *, :is(.grilla-editable, .sueldos-grilla) :is(input, select, textarea))):not(.__),
body td.numeric:where(:not(.plan-tabla *, :is(.grilla-editable, .sueldos-grilla) :is(input, select, textarea))):not(.__),
body .tag .numeric:where(:not(.plan-tabla *, :is(.grilla-editable, .sueldos-grilla) :is(input, select, textarea))):not(__),
body .cockpit-hero__delta:where(:not(.plan-tabla *, :is(.grilla-editable, .sueldos-grilla) :is(input, select, textarea))):not(.__):not(__),
body .data-card__delta:where(:not(.plan-tabla *, :is(.grilla-editable, .sueldos-grilla) :is(input, select, textarea))):not(.__):not(__),
body .kpi-card__delta:where(:not(.plan-tabla *, :is(.grilla-editable, .sueldos-grilla) :is(input, select, textarea))):not(.__):not(__),
body .kpi-hero__delta:where(:not(.plan-tabla *, :is(.grilla-editable, .sueldos-grilla) :is(input, select, textarea))):not(.__):not(__),
body .alerta__valor:where(:not(.plan-tabla *, :is(.grilla-editable, .sueldos-grilla) :is(input, select, textarea))):not(.__):not(__),
body .impacto-valor:where(:not(.plan-tabla *, :is(.grilla-editable, .sueldos-grilla) :is(input, select, textarea))):not(.__):not(__),
body .breadcrumb-chip__valor:where(:not(.plan-tabla *, :is(.grilla-editable, .sueldos-grilla) :is(input, select, textarea))):not(.__):not(__),
body [data-tween]:where(:not(.plan-tabla *, :is(.grilla-editable, .sueldos-grilla) :is(input, select, textarea))):not(.__):not(__),
body [data-kpi]:where(:not(.plan-tabla *, :is(.grilla-editable, .sueldos-grilla) :is(input, select, textarea))):not(.__):not(__),
body .wapp-volumen__num:where(:not(.plan-tabla *, :is(.grilla-editable, .sueldos-grilla) :is(input, select, textarea))):not(.__):not(__),
body .wapp-volumen__lim:where(:not(.plan-tabla *, :is(.grilla-editable, .sueldos-grilla) :is(input, select, textarea))):not(.__):not(__),
body .cell-ventana:where(:not(.plan-tabla *, :is(.grilla-editable, .sueldos-grilla) :is(input, select, textarea))):not(.__):not(__),
body .tb-time:where(:not(.plan-tabla *, :is(.grilla-editable, .sueldos-grilla) :is(input, select, textarea))):not(.__):not(__) {
    font-family: var(--font-sans);
    letter-spacing: 0;
    font-variant-numeric: tabular-nums;
}
/* .proxima-hero__num (meetings, «#30») queda en mono A PROPÓSITO: es un código de reunión, no una cifra. */
/* el código bajo el nombre (crm /clientes «DMF03») es un código, no una cifra: sigue en mono */
html body .clientes-sub.numeric {
    font-family: var(--font-mono);
}

/* ── §7 Header: una sola piel + logo centrado (D9-B) ──────────────────────────────────────
   Decisión del dueño: misma piel en las 14 (hoy hay 7 fondos, dos translúcidos): fondo = la página,
   hairline inferior dibujado como sombra de 1 px (el borde queda transparente: no suma caja) y título
   en 600 con -0,022 em (hoy 600/650/700). NO cambia alturas ni tamaños. En claro el header queda sobre
   el papel de la página (D13); el segundo selector le gana a tema.css y a los <app>-claro.css
   (mrp-claro.css:129 pinta .header). */
body .header,
html:root[data-tema="claro"] body .header {
    background: var(--bg);
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
    border-bottom-color: transparent;
    box-shadow: 0 1px 0 var(--border);
}
body .header h1 {
    font-weight: 600;
    letter-spacing: -0.022em;
}
/* Logo centrado (pedido del dueño, 15-oct 17:24): el enlace .header-brand pasa al centro del header en
   las apps que tienen logo. Sin DOM nuevo: absoluto dentro del header (sticky = posicionado); la imagen
   conserva su transform propio (el colapso por scroll escala la <img>, no el enlace). Excluye
   .header:has(.header__actions): reports ya lo centra con su grilla. mrp lo oculta a propósito; logistics
   y etoro no lo tienen. Sólo desde 1280 px: debajo, el logo queda en el flujo (a la izquierda, como hoy);
   centrado entre 1025 y ~1215 px tapaba el «Buscar ⌘K» de meetings, el buscador rápido de design y los
   títulos de lims. Las excepciones por app (cashflow, logistics, lims) van en su hoja. */
@media (min-width: 1280px) {
    body .header:not(:has(.header__actions)) > .header-brand {
        position: absolute;
        left: 50%;
        top: 50%;
        transform: translate(-50%, -50%);
        margin: 0;
        z-index: 1;
    }
}

/* ── §8 Un solo lenguaje de tabla (D10-C) ─────────────────────────────────────────────────
   Decisión del dueño: cabecera con el MISMO fondo opaco en toda la flota (--bg-soft; hoy hay 3 recetas)
   y una línea inferior más firme que los divisores; divisores de fila un 30 % más tenues; la última fila
   sin línea contra el borde de la tarjeta; la fila de totales en 600 con filete superior. Las líneas van
   como sombra inset o color de borde existente: no suman caja. El hover de fila está en §1.3.
   El total de cashflow /lineas no es tfoot ni tr.total: esta regla no lo alcanza (declarado).
   costeador /lista conserva su cebra. El segundo selector de la cabecera (claro) le gana a las
   sombras de cabecera sticky de costeador-claro / mrp-claro y al fondo de logistics-claro (sólo
   fondo y sombra: ver abajo). */
:is(.tbl, .tbl-base, .tabla, .lista-tabla, .plan-tabla, .tabla-simple, .grilla, .vx-tabla, .dp-table) > thead > tr > th {
    font-weight: 500;
    letter-spacing: 0;
    text-transform: none;
    color: var(--fg-muted);
    background-color: var(--bg-soft);
    box-shadow: inset 0 -1px 0 color-mix(in srgb, var(--fg) 16%, var(--bg-soft));
}
/* claro: SÓLO fondo y sombra llevan el peso extra (0,3,4) que necesitan para ganarle a mrp-claro /
   costeador-claro / logistics-claro. Tipografía y color quedan en la regla base (0,1,3), así los estados
   de cada app (columna ordenada, total del mes, th.num, feriado) ganan igual en los dos temas. */
html:root[data-tema="claro"] :is(.tbl, .tbl-base, .tabla, .lista-tabla, .plan-tabla, .tabla-simple, .grilla, .vx-tabla, .dp-table) > thead > tr > th {
    background-color: var(--bg-soft);
    box-shadow: inset 0 -1px 0 color-mix(in srgb, var(--fg) 16%, var(--bg-soft));
}
:is(.tbl, .tbl-base, .tabla, .lista-tabla, .tabla-simple, .grilla, .vx-tabla, .dp-table) > tbody > tr > td,
:is(.tbl, .tbl-base, .tabla, .lista-tabla, .tabla-simple, .grilla, .vx-tabla, .dp-table) > tbody > tr > th {
    border-bottom-color: color-mix(in srgb, var(--border) 70%, transparent);
}
:is(.tbl, .tbl-base, .tabla, .tabla-simple, .grilla, .vx-tabla, .dp-table) > tbody > tr:last-child > td,
:is(.tbl, .tbl-base, .tabla, .tabla-simple, .grilla, .vx-tabla, .dp-table) > tbody > tr:last-child > th {
    border-bottom-color: transparent;
}
:is(.tbl, .tbl-base, .tabla, .lista-tabla, .tabla-simple, .grilla, .vx-tabla, .dp-table) :is(tfoot tr, tr.total, tr.fila-total, tr.subtotal) > td,
:is(.tbl, .tbl-base, .tabla, .lista-tabla, .tabla-simple, .grilla, .vx-tabla, .dp-table) :is(tfoot tr, tr.total, tr.fila-total, tr.subtotal) > th {
    font-weight: 600;
    color: var(--fg);
    box-shadow: inset 0 1px 0 color-mix(in srgb, var(--fg) 16%, var(--bg-card));
}

/* ── §9 Un solo molde de pastilla de estado (D11-C) ───────────────────────────────────────
   Decisión del dueño: tinte 12 % + contorno 35 % (sombra inset: no suma caja) + texto del color
   semántico en 500 y en oración (sin versalitas forzadas); los neutros, planos y sin contorno. Cubre
   .tag, .badge y los chips de estado de logistics (pedido, viaje, flete, turno). Texto: en oscuro el
   semántico se aclara un 22 % hacia el blanco (puros daban 4,2-4,6:1; así 5,2-6,0:1); en claro va la
   tinta oscura de cada semántico (4,6-6,5:1). (El dorado puro y su 85 % con negro en claro se fueron con
   D2-C: ya no hay pastilla de estado dorada.)
   Las categorías de reports (.badge-<estado> de stock) conservan su matiz dentro del molde.
   :root:root = (0,4,1): gana a `.tag.is-ok` (components, 0,2,0) y a `:root[data-tema="claro"] .badge.ok`
   (tema.css y reports/meetings/wapp-claro, 0,4,0). NO entra: .ab-estado de mrp (planilla densa). */
.tag,
.badge,
.estado:where(:not(select, input, textarea, button)) { --estado-c: var(--fg-muted); }
.tag--ok:not(.__),
.tag.is-ok,
.badge.ok,
.badge-normal:not(.__),
.pill--enviado:not(.__),
.estado-listo:not(.__) { --estado-c: var(--ok); }
.tag--warn:not(.__),
.tag.is-warn,
.tag.is-actualizar,
.badge.warn,
.badge-atencion:not(.__),
.pill--enviando:not(.__) { --estado-c: var(--warn); }
.tag--err:not(.__),
.tag.is-danger,
.badge.err,
.badge-quebrado:not(.__),
.pill--fallido:not(.__),
.estado-error:not(.__) { --estado-c: var(--err); }
/* D2-C (UI4 Capa 2, 5-nov-2026): en curso / pendiente / procesando y lo que era dorado («accent») van en el
   AZUL informativo, como .tag.is-info y .tag--info (S13). El dorado queda para acciones y marca; atención
   sigue ámbar. Hasta el 5-nov .tag--accent, .is-accent, .pill--pendiente, .estado-procesando y el «alta»
   del feed eran dorados. En PAPEL nada cambia (esta hoja es de pantalla). */
.tag.is-info,
.tag--info:not(.__),
.tag--accent:not(.__),
.tag.is-accent,
.feed-alertas__badge--alta:not(.__),
.pill--pendiente:not(.__),
.estado-procesando:not(.__) { --estado-c: var(--info); }
/* D2-C: lo normal sin tinte. En una lista larga el estado normal o terminal va neutro y sólo la excepción
   lleva color: el «ok» del macro dentro de una celda (lims «Aprobado» en las 50 filas de /consultas) y
   cualquier pastilla marcada como normal (`tag(..., normal=True)` → .tag--normal). (0,2,1) y (0,3,0):
   ganan a .tag--ok:not(.__) (0,2,0). */
td .tag.tag--ok,
.tag.tag--normal:not(.__) { --estado-c: var(--fg-muted); }
.pill--cancelado { --estado-c: var(--fg-muted); }
.tag--live { --estado-c: var(--accent-live); }
.badge-critico { --estado-c: #e87a00; }
.badge-exceso { --estado-c: var(--info); }
.badge-obsoleto { --estado-c: #7a6f9c; }
html:root[data-tema="claro"] .badge-critico { --estado-c: #8e4c10; }
html:root[data-tema="claro"] .badge-obsoleto { --estado-c: #65529e; }
:root:root body .tag,
:root:root body .badge,
:root:root body .estado:where(:not(select, input, textarea, button)),
:root:root body .pill--enviado,
:root:root body .pill--enviando,
:root:root body .pill--fallido,
:root:root body .pill--pendiente,
:root:root body .pill--cancelado {
    --estado-fg: color-mix(in srgb, var(--estado-c) 78%, #ffffff);
}
html:root[data-tema="claro"]:root body .tag,
html:root[data-tema="claro"]:root body .badge,
html:root[data-tema="claro"]:root body .estado:where(:not(select, input, textarea, button)),
html:root[data-tema="claro"]:root body .pill--enviado,
html:root[data-tema="claro"]:root body .pill--enviando,
html:root[data-tema="claro"]:root body .pill--fallido,
html:root[data-tema="claro"]:root body .pill--pendiente,
html:root[data-tema="claro"]:root body .pill--cancelado {
    --estado-fg: var(--estado-c);
}
/* El molde NO entra a la isla de filtros (la leyenda de reports /compras vive dentro de .toolbar-seccion y
   debe quedar como hoy): el :where() de cada selector suma 0, la especificidad no cambia. Wapp (.pill--*
   de la cola) y meetings (.estado-*) no son .tag/.badge pero son la misma pastilla; .pill-toggle (solapas
   de los gráficos) no está en la lista. */
:root:root body .tag.tag:where(:not(.fb *, .fb-popover *, .toolbar-seccion *, .isla-filtros *, .cp-isla *, .filter-island *, .isla *)),
:root:root body .badge.badge:where(:not(.fb *, .fb-popover *, .toolbar-seccion *, .isla-filtros *, .cp-isla *, .filter-island *, .isla *)),
:root:root body .estado:where(:not(select, input, textarea, button)).estado:where(:not(select, input, textarea, button)):where(:not(.fb *, .fb-popover *, .toolbar-seccion *, .isla-filtros *, .cp-isla *, .filter-island *, .isla *, .pill-toggle *)),
:root:root body .pill--enviado.pill--enviado:where(:not(.fb *, .fb-popover *, .toolbar-seccion *, .isla-filtros *, .cp-isla *, .filter-island *, .isla *, .pill-toggle *)),
:root:root body .pill--enviando.pill--enviando:where(:not(.fb *, .fb-popover *, .toolbar-seccion *, .isla-filtros *, .cp-isla *, .filter-island *, .isla *, .pill-toggle *)),
:root:root body .pill--fallido.pill--fallido:where(:not(.fb *, .fb-popover *, .toolbar-seccion *, .isla-filtros *, .cp-isla *, .filter-island *, .isla *, .pill-toggle *)),
:root:root body .pill--pendiente.pill--pendiente:where(:not(.fb *, .fb-popover *, .toolbar-seccion *, .isla-filtros *, .cp-isla *, .filter-island *, .isla *, .pill-toggle *)),
:root:root body .pill--cancelado.pill--cancelado:where(:not(.fb *, .fb-popover *, .toolbar-seccion *, .isla-filtros *, .cp-isla *, .filter-island *, .isla *, .pill-toggle *)) {
    color: var(--estado-fg);
    background: color-mix(in srgb, var(--estado-c) 12%, transparent);
    border-color: transparent;
    box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--estado-c) 35%, transparent);
    font-weight: 500;
    text-transform: none;
    letter-spacing: 0;
}
:root:root body .tag--neutral:where(:not(.fb *, .fb-popover *, .toolbar-seccion *, .isla-filtros *, .cp-isla *, .filter-island *, .isla *, .pill-toggle *)):not(.__):not(.__),
:root:root body .tag.is-muted:where(:not(.fb *, .fb-popover *, .toolbar-seccion *, .isla-filtros *, .cp-isla *, .filter-island *, .isla *, .pill-toggle *)):not(.__),
:root:root body .badge.muted:where(:not(.fb *, .fb-popover *, .toolbar-seccion *, .isla-filtros *, .cp-isla *, .filter-island *, .isla *, .pill-toggle *)):not(.__),
:root:root body .badge-sin_movimiento:where(:not(.fb *, .fb-popover *, .toolbar-seccion *, .isla-filtros *, .cp-isla *, .filter-island *, .isla *, .pill-toggle *)):not(.__):not(.__),
:root:root body .ldl-chip--tipo:where(:not(.fb *, .fb-popover *, .toolbar-seccion *, .isla-filtros *, .cp-isla *, .filter-island *, .isla *, .pill-toggle *)):not(.__):not(.__),
:root:root body .badge:not(.ok, .warn, .err, [class*="badge-"]):where(:not(.fb *, .fb-popover *, .toolbar-seccion *, .isla-filtros *, .cp-isla *, .filter-island *, .isla *, .pill-toggle *)):not(.__),
:root:root body .tag:not([class*="tag--"]):not([class*="is-"]):where(:not(.fb *, .fb-popover *, .toolbar-seccion *, .isla-filtros *, .cp-isla *, .filter-island *, .isla *, .pill-toggle *)),
:root:root body .pill--cancelado:where(:not(.fb *, .fb-popover *, .toolbar-seccion *, .isla-filtros *, .cp-isla *, .filter-island *, .isla *, .pill-toggle *)):not(.__):not(.__),
:root:root body .estado:not(.estado-listo, .estado-error, .estado-procesando):where(:not(select, input, textarea, button)):where(:not(.fb *, .fb-popover *, .toolbar-seccion *, .isla-filtros *, .cp-isla *, .filter-island *, .isla *, .pill-toggle *)):not(.__) {
    color: var(--fg-muted);
    background: var(--bg-soft);
    border-color: transparent;
    box-shadow: none;
}
/* D11-C completo (UI4 S11): la CAJA del molde, no sólo el color. 11 px / 500 / sin interletra / línea 16 /
   2 × 8 y SIN borde (el contorno ya es la sombra inset): 20 px de alto en toda la flota. Misma especificidad
   que el molde (:root:root). La variante grande (cabecera de columna del kanban del CRM) es .tag.is-lg:
   12 px y 4 × 10 (24 px). NO entran .ab-estado (mrp, planilla densa) ni .hoy-senal (crm). */
:root:root body .tag.tag:where(:not(.fb *, .fb-popover *, .toolbar-seccion *, .isla-filtros *, .cp-isla *, .filter-island *, .isla *)),
:root:root body .badge.badge:where(:not(.fb *, .fb-popover *, .toolbar-seccion *, .isla-filtros *, .cp-isla *, .filter-island *, .isla *)),
:root:root body .estado:where(:not(select, input, textarea, button)).estado:where(:not(select, input, textarea, button)):where(:not(.fb *, .fb-popover *, .toolbar-seccion *, .isla-filtros *, .cp-isla *, .filter-island *, .isla *, .pill-toggle *)),
:root:root body .pill--enviado.pill--enviado:where(:not(.fb *, .fb-popover *, .toolbar-seccion *, .isla-filtros *, .cp-isla *, .filter-island *, .isla *, .pill-toggle *)),
:root:root body .pill--enviando.pill--enviando:where(:not(.fb *, .fb-popover *, .toolbar-seccion *, .isla-filtros *, .cp-isla *, .filter-island *, .isla *, .pill-toggle *)),
:root:root body .pill--fallido.pill--fallido:where(:not(.fb *, .fb-popover *, .toolbar-seccion *, .isla-filtros *, .cp-isla *, .filter-island *, .isla *, .pill-toggle *)),
:root:root body .pill--pendiente.pill--pendiente:where(:not(.fb *, .fb-popover *, .toolbar-seccion *, .isla-filtros *, .cp-isla *, .filter-island *, .isla *, .pill-toggle *)),
:root:root body .pill--cancelado.pill--cancelado:where(:not(.fb *, .fb-popover *, .toolbar-seccion *, .isla-filtros *, .cp-isla *, .filter-island *, .isla *, .pill-toggle *)) {
    font-size: var(--text-xs);
    line-height: 16px;
    padding: 2px 8px;
    border-width: 0;
}
:root:root body .tag.tag.is-lg:where(:not(.fb *, .fb-popover *, .toolbar-seccion *, .isla-filtros *, .cp-isla *, .filter-island *, .isla *)) {
    font-size: var(--text-12);
    padding: 4px 10px;
}
/* chips de logistics: ya llevan su color en --c; sólo se unifica el molde */
body .chip[class*="chip--est-"],
body .chip[class*="chip--via-"],
body .chip[class*="chip--ff-"],
body .chip[class*="chip--tur-"],
body .chip.chip--ok,
body .chip.chip--warn,
body .chip.chip--err,
body .chip.chip--info,
body .chip.chip--neutro,
body .chip.chip--naranja,
body .chip.chip--teal,
body .chip.chip--violeta {
    font-weight: 500;
    background: color-mix(in srgb, var(--c, var(--st-gris)) 12%, transparent);
    /* contorno inset (S11): el borde no suma caja; misma caja que el molde */
    border-color: transparent;
    border-width: 0;
    box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--c, var(--st-gris)) 35%, transparent);
    font-size: var(--text-xs);
    letter-spacing: 0;
    line-height: 16px;
    padding: 2px 8px;
}
/* rrhh .dchip: la misma caja (su color y su contorno los pone rrhh.css; el contorno pasa a inset). El
   tamaño táctil (15 px en rrhh.css) se respeta: la letra del molde sólo con puntero fino. */
body .dchip:not(.__):not(.__) {
    font-weight: 500;
    letter-spacing: 0;
    line-height: 16px;
    padding: 2px 8px;
    border-width: 0;
    box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--warn) 35%, transparent);
}
@media not (pointer: coarse) {
    body .dchip:not(.__):not(.__) { font-size: var(--text-xs); }
}
/* cashflow .marca: ya era la caja del molde salvo la interletra */
body .marca:not(.__) { letter-spacing: 0; }

/* ── §10 Ritmo 24 / 24 / 32 (D12-C) ───────────────────────────────────────────────────────
   Decisión del dueño: tarjetas de contenido y KPI a 24 en TODAS (hoy 16/20/22/24 según la app), bloques
   hermanos a 24, sección a 32 (sin cambio), lateral 32 y techo 24. Sólo ≥ 1025 px.
   NO entra: logistics /hoy y la COLA de /pedidos (.page-hoy, .page-pedidos--cola: la ficha
   de pedido, que lleva el mismo body.page-pedidos, SÍ recibe D12), crm /hoy y el kanban (#kanban),
   costeador /lista (.page-lista), ni las tarjetas que envuelven una tabla (> table, > .tbl-wrap,
   > .tabla-wrap). El +16 px de max-width de deposito, design y lims va en la hoja de cada app
   (deposito.css:205, design.css:222, lims.css:283): sin él la columna Artículo del historial se parte.
   (0,1,1): igual que `body .content > * + *` de design/deposito/cashflow/logistics/lims; gana por
   orden (esas hojas cargan antes) y m-hoy.css:384 (page-informe, 0,2,1) sigue ganando.
   El margen entre bloques es UNA regla sobre el receptor (`.content > :where(:not(…))`), SIN combinador de
   hermanos, SIN :has() y SIN atributos en el ancla: medido en mrp /compras (766 filas, 18.000 nodos), el `A ~ B`
   anterior invalidaba a todos los hermanos siguientes ante CUALQUIER cambio de [hidden] o de clase (~3,5× el
   recálculo al filtrar con el buscador), y un :has() en la cadena de una regla de subject universal recalculaba
   la planilla entera en cada inserción en .content. Todo va en :where() (suma 0). Por eso:
     · «tiene un bloque anterior» se escribe :nth-child(1 of :not(<invisibles>)): el primer hijo que se ve queda sin
       margen, y un primer hijo que no se ve (script, link, style, template, svg de sprite, h1.sr-only, centinela
       vacío de 1 px, [hidden]) NO cuenta como «bloque anterior»: el techo queda en 24 y no en 48;
     · los SUPERPUESTOS no reciben margen (dialog, .modal, [popover], [role=dialog], los modales fijos
       con inset:0): el margen los corría 24 px, dejaba una franja sin velo y descentraba los <dialog>;
     · la isla de filtros y sus centinelas (.toolbar-seccion, .fb, .isla-filtros, .filter-island,
       .cp-isla, .filtros-sentinel) tampoco: la isla queda donde estaba, sin saltos al pegarse;
     · los toasts y modales fijos ([class*="modal"], [class*="toast"]) tampoco: no son bloques del flujo;
     · la «sección a 32» (.section-title, details.sync-card) conserva el margen propio de su app;
     · el kanban de crm (.kanban-nav, .kanban-board) y logistics /hoy y crm /hoy (.page-hoy) y costeador /lista
       (.page-lista) conservan el suyo. La COLA de /pedidos de logistics ya tiene 24 entre bloques (medido), así que
       la regla no la mueve; sus paddings siguen excluidos por .page-pedidos--cola más abajo;
     · los bloques pegados por diseño siguen pegados: etoro .runs-terminal-body y el .paginador conservan el margen
       de su app, y las parejas barra de tabla + tabla (.tbl-toolbar/.compras-acciones), título de sección +
       barra, eyebrow/título/subtítulo (meetings, etoro) y la ceja de crm /clientes/<id> con su fila de KPI
       (.eyebrow + .kpi-row) se ponen en 0 con reglas de receptor CLASEADO (un receptor universal con
       combinador volvería a recalcular la planilla al insertar);
     · conservan el margen de su app: la fila de chips de la ficha de cliente de crm (.cliente-tags, −8 px bajo
       la cabecera), la cabecera de etoro /ticker (.ticker-header, 8 px bajo su ceja) y la hoja de los
       informes (.informe-hoja: el documento y su lugar en la página quedan como hoy).
   El «1 de» lleva SÓLO rasgos estáticos (etiquetas y clases fijas): con [hidden], [popover], [role] o [class*=]
   adentro, cada cambio de hidden o de clase en CUALQUIER elemento (las filas de una planilla al filtrar) hacía
   recalcular a todos sus hermanos. Esos rasgos siguen excluyendo al receptor (eso sólo recalcula al propio).
   Medido el 16-oct a las 05:15, con la máquina sin carga, en mrp /compras (766 filas): 7 teclas en el buscador
   ~250 ms de recálculo en producción, ~475 con la capa (~630 con el «1 de» dinámico); ocultar media tabla 110 · 210
   (330). Costo conocido: insertar un hijo AL PRINCIPIO de .content cuesta ~90 ms por vez (el «1 de» cambia de
   dueño), y ninguna app lo hace (ni JS ni HTMX); insertar al final es barato. */
/* E4 (30-oct, F3): las excepciones van por CLASE del <body> y no por :has() — `body:has(#kanban)` y
   `.page-pedidos:has(.pedidos-cola)` hacían re-evaluar el selector ante cada cambio del DOM (la isla de filtros y la
   ficha del CRM lo pagaban en cada tecla). El tablero del CRM pone `page-kanban` y la cola de logistics
   `page-pedidos--cola` en su <body>. En las apps que no tienen ninguno de los dos, la regla es la misma. */
@media (min-width: 1025px) {
    body:where(:not(.page-hoy, .page-pedidos--cola, .page-lista, .page-kanban)) .kpi-card:where(:not(:has(> table, > .tbl-wrap, > .tabla-wrap))),
    body:where(:not(.page-hoy, .page-pedidos--cola, .page-lista, .page-kanban)) .card:where(:not(:has(> table, > .tbl-wrap, > .tabla-wrap))) {
        padding: var(--space-4);
    }
    body:where(:not(.page-hoy, .page-pedidos--cola, .page-lista, .page-kanban)) .content {
        padding-left: var(--space-5);
        padding-right: var(--space-5);
        padding-top: var(--space-4);
    }
    body:where(:not(.page-hoy, .page-lista)) .content >
    :where(:not(:nth-child(1 of :not(script, link, style, template, datalist, noscript, svg, .sr-only, dialog, .modal, .filtros-sentinel)),
                script, link, style, template, datalist, noscript, svg, [hidden], .sr-only,
                    dialog, .modal, [popover], [role="dialog"], [role="alertdialog"], [class*="modal"], [class*="toast"],
                    .filtros-sentinel, div[aria-hidden="true"]:empty,
                .toolbar-seccion, .fb, .isla-filtros, .filter-island, .cp-isla,
                .runs-terminal-body, .paginador, .section-title, details.sync-card,
                .kanban-nav, .kanban-board,
                .cliente-tags, .ticker-header, .informe-hoja)) {
        margin-top: var(--space-4);
    }
    /* pegados: barra de tabla + tabla, título de sección + barra, eyebrow/título/subtítulo → 0 */
    body:where(:not(.page-hoy, .page-lista)) .content > :is(.tbl-toolbar, .compras-acciones) + .tbl-wrap,
    body:where(:not(.page-hoy, .page-lista)) .content > :is(.tbl-toolbar, .compras-acciones) + .tbl-fade-wrap,
    body:where(:not(.page-hoy, .page-lista)) .content > :is(.tbl-toolbar, .compras-acciones) + .tabla-wrap,
    body:where(:not(.page-hoy, .page-lista)) .content > .section-title + .tbl-toolbar,
    body:where(:not(.page-hoy, .page-lista)) .content > :is(.page-eyebrow, .page-title, .page-subtitle) + .page-title,
    body:where(:not(.page-hoy, .page-lista)) .content > :is(.page-eyebrow, .page-title, .page-subtitle) + .page-subtitle,
    body:where(:not(.page-hoy, .page-lista)) .content > .eyebrow + .kpi-row {
        margin-top: 0;
    }
}

/* ── §11 Tema claro: papel con jerarquía (D13-C) ──────────────────────────────────────────
   Decisión del dueño: en claro el sidebar baja a un papel más hondo (#e7e4dc, --bg-rail en §0; RIEL-C) que la
   página, el header queda sobre el papel de la página con hairline (§7), las tarjetas siguen blancas
   (lo más claro de la pantalla; borde y sombra sepia en §4 y §0) y reports/meetings pierden el crema
   dorado de fondo (--ambient-accent, §4).
   EXCEPCIÓN DEL DUEÑO: el ítem activo del sidebar NO pasa a «tecla blanca»: queda como hoy (sidebar.css:
   degradé lateral sobre --bg-soft, barra y badge); sólo cambia el papel del sidebar alrededor. Sólo se
   toca el hover de los ítems NO activos, que con el riel nuevo (#eeece5) igualaba a --bg-soft (#ecebe5).
   NO se redefinen --border-elev, --shadow-glass-card ni --glass-bg (los leen ghost, campos, modal y el
   bottom-nav del CRM). Para la hoja de crm: crm-claro.css:49 le pone un degradé al sidebar. */
html:root[data-tema="claro"] body .sidebar { background: var(--bg-rail); }
html:root[data-tema="claro"] body .sidebar nav a:not(.active):hover { background: var(--hover-tint); }
html:root[data-tema="claro"] body .feed-alertas,
html:root[data-tema="claro"] body .resumen-list { border-color: var(--border); }

/* ══════════════════════════════════════════════════════════════════════════════════════
   RONDA 2 · ARREGLOS DE FLOTA (15-oct-2026 17:24, aprobados: «Accesibilidad y bugs CSS» y «Pulido CSS
   restante»). A14, A15, A17, A18, A19. Mismo criterio que §4-§11: @media screen, sin !important, sin
   transiciones de caja; la isla de filtros, el ítem activo del sidebar y los documentos (.informe-hoja,
   impresión) no se tocan.
   ══════════════════════════════════════════════════════════════════════════════════════ */

/* ── §12 KPI de lectura sin hover de botón (A14) ──────────────────────────────────────────
   Las KPI que NO llevan a ningún lado no reaccionan al puntero: ni borde, ni sombra, ni translate, ni
   scale (components.css:717 / polish.css:53 les ponían scale, borde teñido y fondo; §4 les sumaba
   sombra y borde). Las accionables (a.kpi-card, [role=link], con href, .is-interactive, o dentro de un
   enlace) tienen UN gesto: borde --border-hover + --shadow-2. Esta sección corrige el choque con la
   regla de hover de tarjetas de §4 para las KPI no clickeables (las accionables conservan lo de §4).
   Accionable = a, [role=link], [href], [onclick], [data-href], [tabindex], .is-interactive o hija de un
   enlace/.kpi-card-link. Las variantes con color propio (--accent, .kpi-alerta, kpi-card--*) conservan su
   borde y fondo: sólo pierden el movimiento y la sombra de hover. (0,4,2): gana a §4 y a los -claro. */
html:root body .kpi-card:not(a, [role="link"], [href], [onclick], [data-href], [tabindex], .is-interactive,
                             .kpi-alerta, .kpi-card--accent, [class*="kpi-card--"], .is-ok, .is-warn, .is-err, .is-danger, .is-neutro,
                             :is(a, [role="link"], .kpi-card-link) *):hover {
    transform: none;
    border-color: var(--border);
    box-shadow: var(--shadow-1);
    background-color: var(--bg-card);
}
html:root body .kpi-card.kpi-alerta:not(a, [role="link"], [href],
                             [onclick], [data-href], [tabindex], .is-interactive,
                             :is(a, [role="link"], .kpi-card-link) *):hover,
html:root body .kpi-card.kpi-card--accent:not(a, [role="link"], [href],
                             [onclick], [data-href], [tabindex], .is-interactive,
                             :is(a, [role="link"], .kpi-card-link) *):hover,
html:root body .kpi-card[class*="kpi-card--"]:not(a, [role="link"], [href],
                             [onclick], [data-href], [tabindex], .is-interactive,
                             :is(a, [role="link"], .kpi-card-link) *):hover,
html:root body .kpi-card.is-ok:not(a, [role="link"], [href],
                             [onclick], [data-href], [tabindex], .is-interactive,
                             :is(a, [role="link"], .kpi-card-link) *):hover,
html:root body .kpi-card.is-warn:not(a, [role="link"], [href],
                             [onclick], [data-href], [tabindex], .is-interactive,
                             :is(a, [role="link"], .kpi-card-link) *):hover,
html:root body .kpi-card.is-err:not(a, [role="link"], [href],
                             [onclick], [data-href], [tabindex], .is-interactive,
                             :is(a, [role="link"], .kpi-card-link) *):hover,
html:root body .kpi-card.is-danger:not(a, [role="link"], [href],
                             [onclick], [data-href], [tabindex], .is-interactive,
                             :is(a, [role="link"], .kpi-card-link) *):hover,
html:root body .kpi-card.is-neutro:not(a, [role="link"], [href],
                             [onclick], [data-href], [tabindex], .is-interactive,
                             :is(a, [role="link"], .kpi-card-link) *):hover {
    transform: none;
    box-shadow: var(--shadow-1);
}
html:root body .data-card:not(a, [role="link"], [href], [onclick], [data-href], [tabindex], .is-interactive,
                              :is(a, [role="link"], .kpi-card-link) *):hover,
html:root body .cockpit-hero__card:not(a, [role="link"], [href], [onclick], [data-href], [tabindex], .is-interactive,
                              :is(a, [role="link"], .kpi-card-link) *):hover {
    transform: none;
    border-color: var(--border);
    box-shadow: var(--shadow-1);
}
@media (hover: hover) and (pointer: fine) {
    html:root body :is(a.kpi-card, .kpi-card[role="link"], .kpi-card[href], .kpi-card.is-interactive,
                       .kpi-card-link .kpi-card, a.data-card, .data-card[role="link"], .data-card[href]):hover,
    html:root body .kpi-card-link:hover .kpi-card {
        transform: none;
        border-color: var(--border-hover);
        box-shadow: var(--shadow-2);
        background-color: var(--bg-card);
    }
}

/* ── §13 Sin pulsos infinitos ni resplandores (A15) ───────────────────────────────────────
   Los puntos «en vivo» y de estado pulsan 3 veces y quedan quietos (animation-iteration-count: 3) y
   pierden el halo de color: el punto ya dice «vivo» por su color. Los de sincronización (ok/warn/err)
   cambian el glow por un anillo plano de 2 px teñido al 25 %. .glow-border y .marquee, que existen en la
   capa compartida y nadie usa, quedan apagados como red de seguridad. Movimiento reducido: quietos del
   todo. Alcance: .live-dot, .sincro-dot(--live), .tag--live .tag__dot, .badge-en-curso__icon,
   .motion-pulse y .conn-strip__dot (crm). NO toca los spinners (mrp-spin, cost-spin: trabajo en curso). */
:root:root body .live-dot:not(.__),
:root:root body .sincro-dot--live:not(.__),
:root:root body .sincro-dot:not(.__),
:root:root body .tag--live .tag__dot {
    box-shadow: none;
}
:root:root body .sincro-ok .sincro-dot { box-shadow: 0 0 0 2px color-mix(in srgb, var(--ok) 25%, transparent); }
:root:root body .sincro-warn .sincro-dot { box-shadow: 0 0 0 2px color-mix(in srgb, var(--warn) 25%, transparent); }
:root:root body .sincro-err .sincro-dot { box-shadow: 0 0 0 2px color-mix(in srgb, var(--err) 25%, transparent); }
:root:root body .live-dot,
:root:root body .sincro-dot--live,
:root:root body .badge-en-curso__icon,
:root:root body .motion-pulse,
:root:root body .conn-strip__dot {
    animation-iteration-count: 3;
}
:root:root body :is(.conn-strip--degraded, .conn-strip--offline) .conn-strip__dot {
    animation-iteration-count: 3;
}
.glow-border::before,
.glow-border:hover::before { animation: none; opacity: 0; }
.marquee__track { animation: none; transform: none; }
@media (prefers-reduced-motion: reduce) {
    :root:root body .live-dot,
    :root:root body .sincro-dot--live,
    :root:root body .badge-en-curso__icon,
    :root:root body .motion-pulse,
    :root:root body .conn-strip__dot {
        animation: none;
    }
    :root:root body :is(.conn-strip--degraded, .conn-strip--offline) .conn-strip__dot { animation: none; }
}

/* ── §14 Pantalla de acceso de flota (A17) ────────────────────────────────────────────────
   Las 8 (cashflow, crm, deposito, design, lims, logistics, mrp, wapp) con la MISMA tarjeta: 380 de
   ancho, superficie sólida --bg-card con borde hairline, sombra --shadow-2 y padding 32/24; mismo botón
   de Google (44 de alto, radio de control, borde de campo, --bg-soft; blanco de logistics sale). El pie
   pasa de --fg-faint (#8f8f8f sobre #29292e = 4,48:1) a --fg-muted; lo mismo el resumen del acceso
   alternativo y el aviso «no configurado» de crm/lims (idéntico problema). wapp es un formulario de
   token, sin botón de Google: sólo comparte ancho, superficie y sombra. crm y lims llevan su CSS en un
   <style> de la página, que carga DESPUÉS de esta capa: se les gana por especificidad (0,4,2), no por
   orden. cashflow/logistics/mrp/design/deposito: `.acceso-card.glass-elev` (0,2,0) también queda abajo.
   Se apaga el pseudo-borde de luz de .glass-elev (display:none en ::before). */
html:root:root body .acceso-card.acceso-card,
html:root:root body .login-card.login-card {
    width: 100%;
    max-width: 380px;
    box-sizing: border-box;
    padding: var(--space-5) var(--space-4);
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: var(--radius-card);
    box-shadow: var(--shadow-2);
}
html body .acceso-card.glass-elev::before { display: none; }
html:root body .login-shell { max-width: 380px; }
html:root body .acceso-card__pie:not(__),
html:root body .acceso-sep:not(__),
html:root body .acceso-alt > summary { color: var(--fg-muted); }
html:root body .acceso-alt > summary:hover { color: var(--fg); }
html:root body .acceso-google {
    min-height: 44px;
    gap: var(--space-2);
    padding: 0 var(--space-3);
    border: 1px solid var(--field-border);
    border-radius: var(--radius-btn);
    background: var(--bg-soft);
    color: var(--fg);
    font-size: var(--text-sm);
    font-weight: 600;
    box-shadow: none;
}
html:root[data-tema="claro"] body .acceso-google {
    background: var(--bg-card);
    border-color: var(--field-border);
}
@media (hover: hover) and (pointer: fine) {
    html:root body .acceso-google:hover {
        background: var(--hover-tint);
        border-color: var(--field-border-hover);
        color: var(--fg);
    }
    html:root[data-tema="claro"] body .acceso-google:hover {
        background: var(--bg-soft);
        border-color: var(--field-border-hover);
    }
}

/* ── §15 Estado vacío canónico (A18) ──────────────────────────────────────────────────────
   Contorno punteado visible (18 % del texto), título 15/600 --fg, cuerpo 13 --fg-muted, y min-height 120
   dentro de una tarjeta (la base trae 200 pensados para una página entera). Cubre .empty-state (macro
   _empty_state: __title y __mensaje son el título; __body y __hint, el cuerpo) y .vacio (logistics,
   cashflow, deposito, design).
   EXCLUIDOS: las variantes --inline y --info del macro (mrp las usa a propósito sin marco ni alto);
   los vacíos de logistics /hoy y /pedidos (.page-hoy / .page-pedidos: m-hoy.css y m-pedidos.css calculan
   alturas); todo lo que viva en una celda de tabla (td/th; las celdas .empty de mrp incluidas). Esta
   sección corrige un choque con lo propio de deposito y design (deposito.css:321, design.css:340 sacan
   el marco del vacío dentro de .card): A18 pide el contorno visible también ahí. */
body .empty-state:not(.empty-state--inline, .empty-state--info):not(:is(td, th, .page-hoy, .page-pedidos) *),
body .vacio:not(td, th, tr):not(:is(td, th, .page-hoy, .page-pedidos) *) {
    border: 1px dashed color-mix(in srgb, var(--fg) 18%, transparent);
    border-radius: var(--radius-card);
}
body .card .empty-state:not(.empty-state--inline, .empty-state--info):not(:is(td, th, .page-hoy, .page-pedidos) *),
body :is(.card, .section-block, .data-panel, .chart-card) .vacio:not(td, th, tr):not(:is(td, th, .page-hoy, .page-pedidos) *) {
    border: 1px dashed color-mix(in srgb, var(--fg) 18%, transparent);
    min-height: 120px;
    box-sizing: border-box;
}
body :is(.card, .section-block, .data-panel, .chart-card) .vacio:not(td, th, tr):not(:is(td, th, .page-hoy, .page-pedidos) *) {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
}
body .empty-state:not(.empty-state--inline, .empty-state--info) .empty-state__title,
body .empty-state:not(.empty-state--inline, .empty-state--info) .empty-state__mensaje,
body .vacio:not(:is(.page-hoy, .page-pedidos) *) .vacio__titulo {
    font-size: var(--text-15);
    font-weight: 600;
    color: var(--fg);
}
body .empty-state:not(.empty-state--inline, .empty-state--info) .empty-state__body,
body .empty-state:not(.empty-state--inline, .empty-state--info) .empty-state__hint,
body .vacio:not(:is(.page-hoy, .page-pedidos) *) .vacio__sub:not(__),
body .vacio:not(:is(.page-hoy, .page-pedidos) *) .vacio__msg:not(__),
body .vacio:not(:is(.page-hoy, .page-pedidos) *) p:not(.vacio__titulo) {
    font-size: var(--text-sm);
    color: var(--fg-muted);
}

/* ── §16 Prosa (A19) ──────────────────────────────────────────────────────────────────────
   Títulos con text-wrap-style: balance (se acabaron las viudas de una palabra), descripciones con pretty;
   .page-description sin cursiva, en --fg-muted (era --fg-faint) y a 72 caracteres como máximo. Los
   documentos (.informe-hoja) quedan como están. */
/* Longhands (text-wrap-style), NO el atajo `text-wrap`: el atajo también fija text-wrap-mode:wrap y
   pisaba el `white-space: nowrap` + elipsis de los títulos del header (.header h1) y de los paneles
   de cada app en toda la flota. Con el longhand el nowrap de la app sigue mandando y el balance sólo
   actúa donde el título ya podía partirse. .sr-only queda afuera (su nowrap es parte del recorte). */
body :is(h1, h2, .page-title):not(.informe-hoja *, .sr-only) { text-wrap-style: balance; }
body .page-description:not(.informe-hoja *, .sr-only),
body .page-subtitle:not(.informe-hoja *, .sr-only),
body .empty-state__body:not(.informe-hoja *, .sr-only),
body .empty-state__hint:not(.informe-hoja *, .sr-only),
body .acceso-card__sub:not(.informe-hoja *, .sr-only) {
    text-wrap-style: pretty;
}
body .page-description {
    font-style: normal;
    color: var(--fg-muted);
    max-width: 72ch;
}


/* ════════════════════════════════════════════════════════════════════════════════════════
   OLA UI3 (30-oct-2026): §17 a §24. Estilo expandido, todo en @media screen, sin !important. La isla de
   filtros (.fb*, .isla, .isla-filtros, .toolbar-seccion, .cp-isla, Litepicker) y el MES (esta hoja no le
   llega) quedan afuera. Impresión y PDF idénticos.
   ════════════════════════════════════════════════════════════════════════════════════════ */

/* ── §17 Táctil: sin demora ni destello gris, y piso de 44 px por TIPO de puntero (A1, D17) ─────────
   (pointer: coarse) = el dedo, no el ancho: una tablet apaisada de 1280 px también lo es. :where() deja
   la especificidad en la del elemento: lo que tiene gestos propios (Sortable de mrp, mapa de zonas del
   CRM) lo pisa con cualquier regla. Sin la isla ni Litepicker (.litepicker *). */
@media (pointer: coarse) {
    a:where(:not(.fb *, .fb-popover *, .toolbar-seccion *, .isla-filtros *, .cp-isla *, .filter-island *, .isla *, .litepicker *)),
    button:where(:not(.fb *, .fb-popover *, .toolbar-seccion *, .isla-filtros *, .cp-isla *, .filter-island *, .isla *, .litepicker *)),
    [role="button"]:where(:not(.fb *, .fb-popover *, .toolbar-seccion *, .isla-filtros *, .cp-isla *, .filter-island *, .isla *, .litepicker *)),
    [role="tab"]:where(:not(.fb *, .fb-popover *, .toolbar-seccion *, .isla-filtros *, .cp-isla *, .filter-island *, .isla *, .litepicker *)),
    summary:where(:not(.fb *, .fb-popover *, .toolbar-seccion *, .isla-filtros *, .cp-isla *, .filter-island *, .isla *, .litepicker *)),
    label:where(:not(.fb *, .fb-popover *, .toolbar-seccion *, .isla-filtros *, .cp-isla *, .filter-island *, .isla *, .litepicker *)),
    select:where(:not(.fb *, .fb-popover *, .toolbar-seccion *, .isla-filtros *, .cp-isla *, .filter-island *, .isla *, .litepicker *)),
    .btn:where(:not(.fb *, .fb-popover *, .toolbar-seccion *, .isla-filtros *, .cp-isla *, .filter-island *, .isla *, .litepicker *)),
    .pill:where(:not(.fb *, .fb-popover *, .toolbar-seccion *, .isla-filtros *, .cp-isla *, .filter-island *, .isla *, .litepicker *)),
    .chip:where(:not(.fb *, .fb-popover *, .toolbar-seccion *, .isla-filtros *, .cp-isla *, .filter-island *, .isla *, .litepicker *)) {
        touch-action: manipulation;
    }
    /* El destello gris sólo se quita donde hay :active propio (línea ~170); links, summary y filas
       conservan el del navegador como único feedback táctil. */
    button:where(:not(.fb *, .fb-popover *, .toolbar-seccion *, .isla-filtros *, .cp-isla *, .filter-island *, .isla *, .litepicker *)),
    .btn:where(:not(.fb *, .fb-popover *, .toolbar-seccion *, .isla-filtros *, .cp-isla *, .filter-island *, .isla *, .litepicker *)),
    .pill:where(:not(.fb *, .fb-popover *, .toolbar-seccion *, .isla-filtros *, .cp-isla *, .filter-island *, .isla *, .litepicker *)),
    .chip:where(:not(.fb *, .fb-popover *, .toolbar-seccion *, .isla-filtros *, .cp-isla *, .filter-island *, .isla *, .litepicker *)),
    [role="tab"]:where(:not(.fb *, .fb-popover *, .toolbar-seccion *, .isla-filtros *, .cp-isla *, .filter-island *, .isla *, .litepicker *)) {
        -webkit-tap-highlight-color: transparent;
    }
    /* D17: el CRM baja sus 36/40 a 44 en SUS hojas; acá el piso común. (0,2,0) gana a .btn.is-sm de components. */
    .btn:where(:not(.fb *, .fb-popover *, .toolbar-seccion *, .isla-filtros *, .cp-isla *, .filter-island *, .isla *, .litepicker *)),
    .btn.is-sm:where(:not(.fb *, .fb-popover *, .toolbar-seccion *, .isla-filtros *, .cp-isla *, .filter-island *, .isla *, .litepicker *)),
    .chip:where(:not(.fb *, .fb-popover *, .toolbar-seccion *, .isla-filtros *, .cp-isla *, .filter-island *, .isla *, .litepicker *)),
    .tabs__item:where(:not(.fb *, .fb-popover *, .toolbar-seccion *, .isla-filtros *, .cp-isla *, .filter-island *, .isla *, .litepicker *)),
    [role="tab"]:where(:not(.fb *, .fb-popover *, .toolbar-seccion *, .isla-filtros *, .cp-isla *, .filter-island *, .isla *, .litepicker *)) {
        min-height: 44px;
    }
}

/* ── §18 Capas: scroll que no se encadena (M2), velo sin blur (M3) y salida animada (M4) ─────────
   M2: la lista de selectores es cerrada a propósito (NO [class*="menu"]: atrapa .sidebar-menu). La isla
   (.fb-popover, .fb-list) queda como está. */
dialog,
[popover],
.sidebar.drawer-open,
.cmd-palette__results,
.header-controls-pop,
.modal-body,
.dialogo__cuerpo,
.atajos-modal__card,
.des-dialogo,
.nov-ac__menu,
.kanban-sheet,
.ldl-menu {
    overscroll-behavior: contain;
}
/* M3: velo parejo en toda la flota, sin blur (tablets). */
dialog::backdrop {
    background: rgb(0 0 0 / 0.6);
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
}
/* M4: los <dialog> y [popover] SALEN animados. `display` y `overlay` con allow-discrete mantienen el
   elemento en la capa superior hasta terminar el fundido; @starting-style fija el punto de partida de la
   entrada. Entra en --dur-slow (regla [open]) y sale en --dur-base (regla base): la salida es más
   corta. Sin blur. Quedan AFUERA el cajón .panel-archivo de design y .td (Tu día), con animación propia, y las hojas del CRM que ya salen por JS (is-cerrando) y lo que lleva
   x-transition de Alpine. El `animation: fade-up` de components.css (dialog[open]) se anula acá: con
   las dos cosas juntas la animación pisaba la transición. */
dialog:not(.ldl-hoja, .ld-hoja, .ldf, .ldf-hoja, .kpanel, .agc-ficha, .panel-archivo, .td, [x-transition], [x-transition\:enter], [x-transition\:leave]) {
    opacity: 0;
    translate: 0 8px;
    transition: opacity var(--dur-base) var(--ease-out),
                translate var(--dur-base) var(--ease-out),
                display var(--dur-base) allow-discrete,
                overlay var(--dur-base) allow-discrete;
}
dialog[open]:not(.ldl-hoja, .ld-hoja, .ldf, .ldf-hoja, .kpanel, .agc-ficha, .panel-archivo, .td, [x-transition], [x-transition\:enter], [x-transition\:leave]) {
    opacity: 1;
    translate: 0 0;
    animation: none;
    transition: opacity var(--dur-slow) var(--ease-out),
                translate var(--dur-slow) var(--ease-out),
                display var(--dur-slow) allow-discrete,
                overlay var(--dur-slow) allow-discrete;
}
@starting-style {
    dialog[open]:not(.ldl-hoja, .ld-hoja, .ldf, .ldf-hoja, .kpanel, .agc-ficha, .panel-archivo, .td, [x-transition], [x-transition\:enter], [x-transition\:leave]) {
        opacity: 0;
        translate: 0 8px;
    }
}
dialog:not(.ldl-hoja, .ld-hoja, .ldf, .ldf-hoja, .kpanel, .agc-ficha, .panel-archivo, .td, [x-transition], [x-transition\:enter], [x-transition\:leave])::backdrop {
    opacity: 0;
    transition: opacity var(--dur-base) var(--ease-out),
                display var(--dur-base) allow-discrete,
                overlay var(--dur-base) allow-discrete;
}
dialog[open]:not(.ldl-hoja, .ld-hoja, .ldf, .ldf-hoja, .kpanel, .agc-ficha, .panel-archivo, .td, [x-transition], [x-transition\:enter], [x-transition\:leave])::backdrop {
    opacity: 1;
    transition: opacity var(--dur-slow) var(--ease-out),
                display var(--dur-slow) allow-discrete,
                overlay var(--dur-slow) allow-discrete;
}
@starting-style {
    dialog[open]:not(.ldl-hoja, .ld-hoja, .ldf, .ldf-hoja, .kpanel, .agc-ficha, .panel-archivo, .td, [x-transition], [x-transition\:enter], [x-transition\:leave])::backdrop {
        opacity: 0;
    }
}
@supports selector(:popover-open) {
    [popover]:not([x-transition], [x-transition\:enter], [x-transition\:leave]) {
        opacity: 0;
        translate: 0 8px;
        transition: opacity var(--dur-base) var(--ease-out),
                    translate var(--dur-base) var(--ease-out),
                    display var(--dur-base) allow-discrete,
                    overlay var(--dur-base) allow-discrete;
    }
    [popover]:popover-open:not([x-transition], [x-transition\:enter], [x-transition\:leave]) {
        opacity: 1;
        translate: 0 0;
        transition: opacity var(--dur-slow) var(--ease-out),
                    translate var(--dur-slow) var(--ease-out),
                    display var(--dur-slow) allow-discrete,
                    overlay var(--dur-slow) allow-discrete;
    }
    @starting-style {
        [popover]:popover-open:not([x-transition], [x-transition\:enter], [x-transition\:leave]) {
            opacity: 0;
            translate: 0 8px;
        }
    }
}
/* el popover del ⚙ del header: antes keyframe de entrada y display:none de golpe al salir. Mismas
   duraciones (150 sale / 200 entra) y nace desde la esquina del botón. Sin overlay: no vive en la capa
   superior. */
.header-controls-pop {
    opacity: 0;
    translate: 0 -4px;
    transform-origin: top right;
    animation: none;
    transition: opacity var(--dur-base) var(--ease-out),
                translate var(--dur-base) var(--ease-out),
                display var(--dur-base) allow-discrete;
}
.header-controls-pop--abierto {
    opacity: 1;
    translate: 0 0;
    transition: opacity var(--dur-slow) var(--ease-out),
                translate var(--dur-slow) var(--ease-out),
                display var(--dur-slow) allow-discrete;
}
@starting-style {
    .header-controls-pop--abierto {
        opacity: 0;
        translate: 0 -4px;
    }
}
@media (prefers-reduced-motion: reduce) {
    dialog:not(.ldl-hoja, .ld-hoja, .ldf, .ldf-hoja, .kpanel, .agc-ficha),
    [popover],
    .header-controls-pop {
        translate: none;
    }
}

/* ── §19 Detalle de oficio (A4, D1, D2, D3, D20) ───────────────────────────────────────────────── */
/* A4: `color-scheme: dark` no alcanza para las <option>: varios UA las pintan con su default claro. */
select option,
select optgroup {
    background-color: var(--bg-elev, var(--surface-elev));
    color: var(--fg);
}
/* D1: títulos balanceados también en h3, tarjetas, diálogos y vacíos; texto corrido de las tarjetas en
   pretty. Longhands (ver §16). */
body h3:not(.informe-hoja *, .sr-only),
body .section-title:not(.informe-hoja *, .sr-only),
body .empty-state__title:not(.informe-hoja *, .sr-only),
body .vacio__titulo:not(.informe-hoja *, .sr-only),
body .data-panel__title:not(.informe-hoja *, .sr-only),
body .banner__title:not(.informe-hoja *, .sr-only),
body dialog h2:not(.informe-hoja *, .sr-only),
body dialog h3:not(.informe-hoja *, .sr-only),
body .kanban-card__title:not(.informe-hoja *, .sr-only),
body .bus-card__tit:not(.informe-hoja *, .sr-only) {
    text-wrap-style: balance;
}
body .card p:not(.informe-hoja *),
body .section-block p:not(.informe-hoja *),
body .panel p:not(.informe-hoja *),
body .data-panel p:not(.informe-hoja *),
body .chart-card p:not(.informe-hoja *),
body .chart-subtitle:not(.informe-hoja *) {
    text-wrap-style: pretty;
}
/* D2: el título de una columna numérica va a la derecha, sobre sus cifras. */
body .tbl th.num,
body .tbl-base th.num,
body .tabla th.num,
body .lista-tabla th.num,
body .plan-tabla th.num,
body .tabla-simple th.num {
    text-align: right;
}
/* D3: padding óptico, 2 px menos del lado del ícono. Quedan afuera .is-sm (ya van justos) y los
   botones sólo-ícono (sin texto el 12/14 los desparejaría). */
.btn:not(.is-sm, .btn--icon, .btn-icon, .is-icon, .btn--square):has(> :is(svg, .btn__icon):first-child) {
    padding-inline-start: 12px;
}
.btn:not(.is-sm, .btn--icon, .btn-icon, .is-icon, .btn--square):has(> :is(svg, .btn__icon):last-child:not(:first-child)) {
    padding-inline-end: 12px;
}
/* D20: las fotos se recortan con un contorno neutro de 1 px al 10 % (no el borde teñido de la paleta). */
:root { --image-outline: rgb(255 255 255 / 0.1); }
:root[data-tema="claro"] { --image-outline: rgb(0 0 0 / 0.1); }
.bus-card__img,
.ficha-cab__img,
.sug__mini,
.comprimido__mini,
.remito-imagen img,
.tur-adjunto__img,
.des-foto img {
    outline: 1px solid var(--image-outline);
    outline-offset: -1px;
    border-color: transparent;
}

/* ── §20 Sombras en vez de bordes en las TARJETAS (D23 = Q5 C, los dos temas) ─────────────────────
   Decisión del dueño: la tarjeta pierde el borde de 1 px y lo dibuja una sombra de 0 0 0 1px (claro: más
   dos sombras sepia cortas). Se CONSERVA `border: 1px solid transparent` (forced-colors lo repinta). NO
   cambian: campos, divisores, celdas, tablas ni la isla. Quedan con su borde con sentido las mismas que
   en §4 (.kpi-alerta, .kpi-card--accent, .card--accent, kpi-card--*, semáforo).
   Cómo: en la tarjeta se REDEFINEN --shadow-1 y --shadow-2 (nadie fuera de esta hoja los lee: components,
   polish y las hojas de app no los usan), así reposo, hover de tarjeta accionable y las KPI de lectura de
   §12 toman el anillo sin repetir cada regla de §4/§12; el hover sube el anillo y suma la sombra corta
   de siempre. El borde va transparente en TODO estado: el (0,5,2) le gana a §4 (0,3,2) y a §12 (0,4,2). */
:root {
    --card-sombra-1: 0 0 0 1px rgb(255 255 255 / 0.08);
    --card-sombra-2: 0 0 0 1px rgb(255 255 255 / 0.14), 0 6px 16px -4px rgb(var(--sombra-rgb) / 0.5);
}
:root[data-tema="claro"] {
    --card-sombra-1: 0 0 0 1px rgb(var(--sombra-rgb) / 0.08), 0 1px 2px -1px rgb(var(--sombra-rgb) / 0.08), 0 2px 4px 0 rgb(var(--sombra-rgb) / 0.05);
    --card-sombra-2: 0 0 0 1px rgb(var(--sombra-rgb) / 0.14), 0 1px 2px rgb(var(--sombra-rgb) / 0.06), 0 8px 20px -10px rgb(var(--sombra-rgb) / 0.24);
}
html:root:root body .card:not(.kpi-alerta, .kpi-card--accent, .card--accent, [class*="kpi-card--"]:not([class*="kpi-card--span"]), .kpi-card:is(.is-ok, .is-warn, .is-err, .is-danger, .is-neutro), .fb, .fb-popover, .toolbar-seccion, .isla-filtros, .cp-isla, .filter-island, .isla):where(:not(.fb *, .fb-popover *, .toolbar-seccion *, .isla-filtros *, .cp-isla *, .filter-island *, .isla *, .fb, .fb-popover, .toolbar-seccion, .isla-filtros, .cp-isla, .filter-island, .isla)),
html:root:root body .kpi-card:not(.kpi-alerta, .kpi-card--accent, .card--accent, [class*="kpi-card--"]:not([class*="kpi-card--span"]), .kpi-card:is(.is-ok, .is-warn, .is-err, .is-danger, .is-neutro), .fb, .fb-popover, .toolbar-seccion, .isla-filtros, .cp-isla, .filter-island, .isla):where(:not(.fb *, .fb-popover *, .toolbar-seccion *, .isla-filtros *, .cp-isla *, .filter-island *, .isla *, .fb, .fb-popover, .toolbar-seccion, .isla-filtros, .cp-isla, .filter-island, .isla)),
html:root:root body .sync-card:not(.kpi-alerta, .kpi-card--accent, .card--accent, [class*="kpi-card--"]:not([class*="kpi-card--span"]), .kpi-card:is(.is-ok, .is-warn, .is-err, .is-danger, .is-neutro), .fb, .fb-popover, .toolbar-seccion, .isla-filtros, .cp-isla, .filter-island, .isla):where(:not(.fb *, .fb-popover *, .toolbar-seccion *, .isla-filtros *, .cp-isla *, .filter-island *, .isla *, .fb, .fb-popover, .toolbar-seccion, .isla-filtros, .cp-isla, .filter-island, .isla)),
html:root:root body .chart-card:not(.kpi-alerta, .kpi-card--accent, .card--accent, [class*="kpi-card--"]:not([class*="kpi-card--span"]), .kpi-card:is(.is-ok, .is-warn, .is-err, .is-danger, .is-neutro), .fb, .fb-popover, .toolbar-seccion, .isla-filtros, .cp-isla, .filter-island, .isla):where(:not(.fb *, .fb-popover *, .toolbar-seccion *, .isla-filtros *, .cp-isla *, .filter-island *, .isla *, .fb, .fb-popover, .toolbar-seccion, .isla-filtros, .cp-isla, .filter-island, .isla)),
html:root:root body .chart-card--premium:not(.kpi-alerta, .kpi-card--accent, .card--accent, [class*="kpi-card--"]:not([class*="kpi-card--span"]), .kpi-card:is(.is-ok, .is-warn, .is-err, .is-danger, .is-neutro), .fb, .fb-popover, .toolbar-seccion, .isla-filtros, .cp-isla, .filter-island, .isla):where(:not(.fb *, .fb-popover *, .toolbar-seccion *, .isla-filtros *, .cp-isla *, .filter-island *, .isla *, .fb, .fb-popover, .toolbar-seccion, .isla-filtros, .cp-isla, .filter-island, .isla)),
html:root:root body .section-block:not(.kpi-alerta, .kpi-card--accent, .card--accent, [class*="kpi-card--"]:not([class*="kpi-card--span"]), .kpi-card:is(.is-ok, .is-warn, .is-err, .is-danger, .is-neutro), .fb, .fb-popover, .toolbar-seccion, .isla-filtros, .cp-isla, .filter-island, .isla):where(:not(.fb *, .fb-popover *, .toolbar-seccion *, .isla-filtros *, .cp-isla *, .filter-island *, .isla *, .fb, .fb-popover, .toolbar-seccion, .isla-filtros, .cp-isla, .filter-island, .isla)),
html:root:root body .cockpit-hero__card:not(.kpi-alerta, .kpi-card--accent, .card--accent, [class*="kpi-card--"]:not([class*="kpi-card--span"]), .kpi-card:is(.is-ok, .is-warn, .is-err, .is-danger, .is-neutro), .fb, .fb-popover, .toolbar-seccion, .isla-filtros, .cp-isla, .filter-island, .isla):where(:not(.fb *, .fb-popover *, .toolbar-seccion *, .isla-filtros *, .cp-isla *, .filter-island *, .isla *, .fb, .fb-popover, .toolbar-seccion, .isla-filtros, .cp-isla, .filter-island, .isla)),
html:root:root body .data-panel:not(.kpi-alerta, .kpi-card--accent, .card--accent, [class*="kpi-card--"]:not([class*="kpi-card--span"]), .kpi-card:is(.is-ok, .is-warn, .is-err, .is-danger, .is-neutro), .fb, .fb-popover, .toolbar-seccion, .isla-filtros, .cp-isla, .filter-island, .isla):where(:not(.fb *, .fb-popover *, .toolbar-seccion *, .isla-filtros *, .cp-isla *, .filter-island *, .isla *, .fb, .fb-popover, .toolbar-seccion, .isla-filtros, .cp-isla, .filter-island, .isla)) {
    --shadow-1: var(--card-sombra-1);
    --shadow-2: var(--card-sombra-2);
    border-color: transparent;
}
/* las tarjetas con tabla no llevaban sombra en §4: acá reciben el anillo (sin él quedarían sin contorno) */
html:root:root body .card:has(.tbl-scroll):not(.kpi-alerta, .kpi-card--accent, .card--accent, [class*="kpi-card--"]:not([class*="kpi-card--span"]), .kpi-card:is(.is-ok, .is-warn, .is-err, .is-danger, .is-neutro), .fb, .fb-popover, .toolbar-seccion, .isla-filtros, .cp-isla, .filter-island, .isla):where(:not(.fb *, .fb-popover *, .toolbar-seccion *, .isla-filtros *, .cp-isla *, .filter-island *, .isla *, .fb, .fb-popover, .toolbar-seccion, .isla-filtros, .cp-isla, .filter-island, .isla)),
html:root:root body .kpi-card:has(.tbl-scroll):not(.kpi-alerta, .kpi-card--accent, .card--accent, [class*="kpi-card--"]:not([class*="kpi-card--span"]), .kpi-card:is(.is-ok, .is-warn, .is-err, .is-danger, .is-neutro), .fb, .fb-popover, .toolbar-seccion, .isla-filtros, .cp-isla, .filter-island, .isla):where(:not(.fb *, .fb-popover *, .toolbar-seccion *, .isla-filtros *, .cp-isla *, .filter-island *, .isla *, .fb, .fb-popover, .toolbar-seccion, .isla-filtros, .cp-isla, .filter-island, .isla)),
html:root:root body .sync-card:has(.tbl-scroll):not(.kpi-alerta, .kpi-card--accent, .card--accent, [class*="kpi-card--"]:not([class*="kpi-card--span"]), .kpi-card:is(.is-ok, .is-warn, .is-err, .is-danger, .is-neutro), .fb, .fb-popover, .toolbar-seccion, .isla-filtros, .cp-isla, .filter-island, .isla):where(:not(.fb *, .fb-popover *, .toolbar-seccion *, .isla-filtros *, .cp-isla *, .filter-island *, .isla *, .fb, .fb-popover, .toolbar-seccion, .isla-filtros, .cp-isla, .filter-island, .isla)),
html:root:root body .chart-card:has(.tbl-scroll):not(.kpi-alerta, .kpi-card--accent, .card--accent, [class*="kpi-card--"]:not([class*="kpi-card--span"]), .kpi-card:is(.is-ok, .is-warn, .is-err, .is-danger, .is-neutro), .fb, .fb-popover, .toolbar-seccion, .isla-filtros, .cp-isla, .filter-island, .isla):where(:not(.fb *, .fb-popover *, .toolbar-seccion *, .isla-filtros *, .cp-isla *, .filter-island *, .isla *, .fb, .fb-popover, .toolbar-seccion, .isla-filtros, .cp-isla, .filter-island, .isla)),
html:root:root body .chart-card--premium:has(.tbl-scroll):not(.kpi-alerta, .kpi-card--accent, .card--accent, [class*="kpi-card--"]:not([class*="kpi-card--span"]), .kpi-card:is(.is-ok, .is-warn, .is-err, .is-danger, .is-neutro), .fb, .fb-popover, .toolbar-seccion, .isla-filtros, .cp-isla, .filter-island, .isla):where(:not(.fb *, .fb-popover *, .toolbar-seccion *, .isla-filtros *, .cp-isla *, .filter-island *, .isla *, .fb, .fb-popover, .toolbar-seccion, .isla-filtros, .cp-isla, .filter-island, .isla)),
html:root:root body .section-block:has(.tbl-scroll):not(.kpi-alerta, .kpi-card--accent, .card--accent, [class*="kpi-card--"]:not([class*="kpi-card--span"]), .kpi-card:is(.is-ok, .is-warn, .is-err, .is-danger, .is-neutro), .fb, .fb-popover, .toolbar-seccion, .isla-filtros, .cp-isla, .filter-island, .isla):where(:not(.fb *, .fb-popover *, .toolbar-seccion *, .isla-filtros *, .cp-isla *, .filter-island *, .isla *, .fb, .fb-popover, .toolbar-seccion, .isla-filtros, .cp-isla, .filter-island, .isla)),
html:root:root body .cockpit-hero__card:has(.tbl-scroll):not(.kpi-alerta, .kpi-card--accent, .card--accent, [class*="kpi-card--"]:not([class*="kpi-card--span"]), .kpi-card:is(.is-ok, .is-warn, .is-err, .is-danger, .is-neutro), .fb, .fb-popover, .toolbar-seccion, .isla-filtros, .cp-isla, .filter-island, .isla):where(:not(.fb *, .fb-popover *, .toolbar-seccion *, .isla-filtros *, .cp-isla *, .filter-island *, .isla *, .fb, .fb-popover, .toolbar-seccion, .isla-filtros, .cp-isla, .filter-island, .isla)),
html:root:root body .data-panel:has(.tbl-scroll):not(.kpi-alerta, .kpi-card--accent, .card--accent, [class*="kpi-card--"]:not([class*="kpi-card--span"]), .kpi-card:is(.is-ok, .is-warn, .is-err, .is-danger, .is-neutro), .fb, .fb-popover, .toolbar-seccion, .isla-filtros, .cp-isla, .filter-island, .isla):where(:not(.fb *, .fb-popover *, .toolbar-seccion *, .isla-filtros *, .cp-isla *, .filter-island *, .isla *, .fb, .fb-popover, .toolbar-seccion, .isla-filtros, .cp-isla, .filter-island, .isla)) {
    box-shadow: var(--card-sombra-1);
}

/* ── §21 Marcas tipográficas «de IA» (H3 = Q4 D, parte CSS) ────────────────────────────────────────
   Rótulos de KPI y de tarjeta, y cabeceras de tabla (§8), en oración: sin mayúsculas forzadas ni tracking.
   Pastillas sin punto (queda el de «en vivo») y wordmark del sidebar de UN color (el .accent hereda el
   color del texto: sin degradé). La isla, la impresión y el MES quedan afuera. */
body .kpi-card__label,
body .kpi-hero__label,
body .card .label {
    text-transform: none;
    letter-spacing: 0;
}
body .tag--with-dot:not(.tag--live) .tag__dot,
body .tag:not(.tag--live) > .tag__dot {
    display: none;
}
html:root:root body .sidebar .brand .accent {
    background: none;
    -webkit-text-fill-color: currentColor;
    color: inherit;
}

/* ── §22 Cabeceras: título del header en un solo tamaño y de tarjeta en un molde (C6, C7) ───────────
   C6: sólo desde 1025 px. Abajo, mobile.css de briefing/costeador/meetings/vox lo baja a propósito.
   El 30 px + scale por scroll de chrome.css:225 sigue: lo que cambia es el tamaño de partida. */
@media (min-width: 1025px) {
    html:root body .header h1 {
        font-size: var(--text-xl);
        /* app.js calcula --header-title-scale para 30 px (1 -> 0,5). Se reescala para ir de 22 a 15 px:
           1 - (1 - s) * 0,6364, con 0,6364 = (1 - 15/22) / 0,5. */
        transform: scale(calc(1 - (1 - var(--header-title-scale, 1)) * 0.6364));
    }
}
/* C7: la cabecera de tarjeta, con cualquier nombre, en 15/600. Los eyebrows no se tocan. */
body .section-title,
body .placa__titulo,
body .ih-bloque__titulo,
body .franja__titulo,
body .aju-titulo,
body .hoy-titulo,
body .sync-card__title {
    font-size: var(--text-15);
    font-weight: 600;
}
/* C7: el molde de pastilla (§9) también para chip, sello, mp-pill, kpi-chip, semáforo y etiqueta:
   misma tipografía (500, oración, sin tracking). Color y fondo los trae cada una. */
body .sello:where(:not(.fb *, .fb-popover *, .toolbar-seccion *, .isla-filtros *, .cp-isla *, .filter-island *, .isla *, .pill-toggle *)),
body .mp-pill:where(:not(.fb *, .fb-popover *, .toolbar-seccion *, .isla-filtros *, .cp-isla *, .filter-island *, .isla *, .pill-toggle *)),
body .kpi-chip:where(:not(.fb *, .fb-popover *, .toolbar-seccion *, .isla-filtros *, .cp-isla *, .filter-island *, .isla *, .pill-toggle *)),
body .semaforo:where(:not(.fb *, .fb-popover *, .toolbar-seccion *, .isla-filtros *, .cp-isla *, .filter-island *, .isla *, .pill-toggle *)),
body .etiqueta:where(:not(.fb *, .fb-popover *, .toolbar-seccion *, .isla-filtros *, .cp-isla *, .filter-island *, .isla *, .pill-toggle *)) {
    font-weight: 500;
    text-transform: none;
    letter-spacing: 0;
}

/* ── §23 Trazo de íconos según el peso del texto vecino (D24 = Q6 C) ────────────────────────────────
   El sprite ya pinta sin escalar el trazo (vector-effect="non-scaling-stroke" en cada forma) y .icon fija
   1,5 px (components.css): 1,5 px renderizados junto a texto de 400-500, a cualquier tamaño. Los SVG EN LÍNEA
   con .icon no traen el atributo: se lo da esta regla, así dibujan igual que los del sprite (hoy, a 16 px
   desde un viewBox de 24, su 1,5 se ve de ~1 px). Junto a títulos (600-700), 2 px. */
body .icon path:not(.__),
body .icon line:not(.__),
body .icon polyline:not(.__),
body .icon polygon:not(.__),
body .icon circle:not(.__),
body .icon rect:not(.__),
body .icon ellipse:not(.__) {
    vector-effect: non-scaling-stroke;
}
body h1 .icon:not(.__),
body h2 .icon:not(.__),
body h3 .icon:not(.__),
body .page-title .icon:not(.__),
body .section-title .icon:not(.__),
body .data-panel__title .icon:not(.__) {
    stroke-width: 2;
}

/* ── §24 UI4 (4-nov-2026): placeholder legible y botón sólo-ícono ────────────────────────────────
   S08: el placeholder sin regla propia era el gris del navegador (#757575, 3,6:1 sobre --bg-soft); ahora
   --fg-faint (5,2:1 sobre soft en oscuro, 5,25 en claro). (0,0,2): cualquier ::placeholder de una app gana.
   La isla de filtros queda como está. */
input:where(:not(.fb *, .fb-popover *, .toolbar-seccion *, .isla-filtros *, .cp-isla *, .filter-island *, .isla *, .litepicker *))::placeholder,
textarea:where(:not(.fb *, .fb-popover *, .toolbar-seccion *, .isla-filtros *, .cp-isla *, .filter-island *, .isla *, .litepicker *))::placeholder {
    color: var(--fg-faint);
    opacity: 1;
}
/* S12: el botón sólo-ícono es cuadrado (36 en escritorio, 44 con el dedo): ancho = alto, sin relleno. Se
   adopta app por app poniendo `.is-cuadrado` (y aria-label) en el .btn.
   Clase NUEVA a propósito: `.is-icon` ya está puesta en botones vivos (cashflow .lineas-baja, crm .ldl-wa) como marca
   del padding óptico D3; reusarla los agrandaría (0,2,0 > 0,1,0) sin su ola. :where() no sirve: perdería contra .btn. */
.btn.is-cuadrado {
    width: var(--control-h-md);
    min-width: var(--control-h-md);
    min-height: var(--control-h-md);
    padding: 0;
    gap: 0;
}
@media (pointer: coarse) {
    .btn.is-cuadrado {
        width: var(--control-h-touch);
        min-width: var(--control-h-touch);
        min-height: var(--control-h-touch);
    }
}

/* ════════════════════════════════════════════════════════════════════════════════════════
   UI4 CAPA 2 (5-nov-2026, decisiones del dueño D1-C, D6-C): §25 y §26. Mismas reglas que la ola UI3:
   todo en @media screen, sin !important, la isla de filtros afuera. El papel no lo ve.
   ════════════════════════════════════════════════════════════════════════════════════════ */

/* ── §25 Confirmar: el color dice la consecuencia (D1-C) ────────────────────────────────────────────
   Un solo diálogo en la flota (confirmar.js + _confirm.html + confirmar.css): foco en «Cancelar», el botón
   dice verbo + objeto y su tono sale de la consecuencia. Estas dos variantes valen para cualquier .btn:
     .btn.is-danger  ROJO sólo para borrar o destruir. Sale de --err en los dos temas (antes un rosa suelto
                     #fca5a5 y rgba(239,68,68,…) en components.css, que quedan para el papel): tinte 8 %,
                     contorno 32 %, texto --peligro-fg (§0: 78 % de --err hacia el blanco; claro: --err).
     .btn.is-neutro  NEUTRO FUERTE (texto sobre fondo): reabrir, re-someter, deshacer, dar de baja ⇄
                     reactivar. Más peso que un secundario, sin el rojo de lo que no vuelve.
   (0,2,0) después de components/tema: gana por orden a .btn.is-danger de components.css; en claro, una regla
   (0,3,0) le gana al #a32018 de tema.css, que queda sólo para la isla. La isla de filtros queda como está. */
.btn.is-danger:where(:not(.fb *, .fb-popover *, .toolbar-seccion *, .isla-filtros *, .cp-isla *, .filter-island *, .isla *, .litepicker *)) {
    background: color-mix(in srgb, var(--err) 8%, transparent);
    border-color: color-mix(in srgb, var(--err) 32%, transparent);
    color: var(--peligro-fg);
    box-shadow: none;
}
.btn.is-neutro:where(:not(.fb *, .fb-popover *, .toolbar-seccion *, .isla-filtros *, .cp-isla *, .filter-island *, .isla *, .litepicker *)) {
    background: var(--fg);
    border-color: var(--fg);
    color: var(--bg);
    font-weight: 600;
}
/* claro: tema.css pone su #a32018 con (0,3,0); acá el mismo peso, después, desde --err. */
:root[data-tema="claro"] .btn.is-danger:where(:not(.fb *, .fb-popover *, .toolbar-seccion *, .isla-filtros *, .cp-isla *, .filter-island *, .isla *, .litepicker *)) {
    color: var(--peligro-fg);
}
@media (hover: hover) and (pointer: fine) {
    .btn.is-danger:where(:not(.fb *, .fb-popover *, .toolbar-seccion *, .isla-filtros *, .cp-isla *, .filter-island *, .isla *, .litepicker *)):hover {
        background: color-mix(in srgb, var(--err) 16%, transparent);
        border-color: color-mix(in srgb, var(--err) 45%, transparent);
        color: var(--peligro-fg);
    }
    :root[data-tema="claro"] .btn.is-danger:where(:not(.fb *, .fb-popover *, .toolbar-seccion *, .isla-filtros *, .cp-isla *, .filter-island *, .isla *, .litepicker *)):hover {
        color: var(--peligro-fg);
    }
    .btn.is-neutro:where(:not(.fb *, .fb-popover *, .toolbar-seccion *, .isla-filtros *, .cp-isla *, .filter-island *, .isla *, .litepicker *)):hover {
        background: color-mix(in srgb, var(--fg) 86%, var(--bg));
        border-color: color-mix(in srgb, var(--fg) 86%, var(--bg));
        color: var(--bg);
    }
}

/* ── §26 Alto de los botones (D6-C) ──────────────────────────────────────────────────────────────────
   El chico se lee (12 px, 32 de alto) y el normal mide 36 en escritorio; con el dedo sigue el piso de 44 de
   §17 y en ≤ 1024 px el de components.css (44 / 36). Antes el mismo botón medía 28-44 según la app.
   :where() deja la especificidad en la de .btn (0,1,0) / .btn.is-sm (0,2,0), y esta hoja carga DESPUÉS del
   CSS de cada app: le gana a components y a TODA regla de una app de igual o menor especificidad que declare
   min-height/padding (una sola clase: `.x { padding: 10px }` sobre un .btn PIERDE; para el chico, `.x .btn`
   también). Sólo gana la de la app que sea MÁS específica o que cargue DESPUÉS (las hojas de {% block head %},
   p. ej. leads-*.css del CRM): los 44 del CRM —D6-C: el CRM queda en 44—, los 28 de la franja de confirmar de
   cashflow, `body.page-x .y .btn`. Quedan afuera:
     · la isla de filtros y Litepicker (no se mueve: tampoco crece la barra que la contiene por esta regla);
     · los botones de FILA: todo .btn dentro de una celda (td) y la excepción con nombre `.btn.is-fila`
       para filas que no son <td> (la planilla de cashflow, D8: filas parejas);
     · los sólo-ícono (.is-icon, .is-cuadrado, .btn--icon, .btn-icon, .btn--square), .is-subtle y .is-lg;
     · los de VARIOS RENGLONES, con nombre: `.btn--decision` (design, panel de la ficha: <b>+<small> en
       columna con su relleno de 10 px; el padding 0 de acá los pegaba al borde). */
.btn.is-sm:where(:not(.fb *, .fb-popover *, .toolbar-seccion *, .isla-filtros *, .cp-isla *, .filter-island *, .isla *, .litepicker *)) {
    font-size: var(--text-12);
}
@media (min-width: 1025px) and (pointer: fine) {
    .btn.is-sm:where(:not(.fb *, .fb-popover *, .toolbar-seccion *, .isla-filtros *, .cp-isla *, .filter-island *, .isla *, .litepicker *, td *)) {
        min-height: var(--control-h-sm);
    }
    .btn:where(:not(.is-sm, .is-lg, .is-subtle, .is-icon, .is-cuadrado, .is-fila, .btn--icon, .btn-icon, .btn--square, .btn--decision)):where(:not(.fb *, .fb-popover *, .toolbar-seccion *, .isla-filtros *, .cp-isla *, .filter-island *, .isla *, .litepicker *, td *)) {
        min-height: var(--control-h-md);
        padding-top: 0;
        padding-bottom: 0;
    }
}

} /* @media screen */
