/* ── Tipografía de marca: Schibsted Grotesk ─────────────────────────────────
   La MISMA fuente y el MISMO binario que la landing (vinali-landing) y que el
   marketplace: un solo .woff2 variable 400-900 del subconjunto latino, 46 KB.
   sha256 e3b56e90510a84ac0ed465b822e112983eaf58e37436bf769681c31f77b1f3a7 —
   si alguna de las tres copias deja de coincidir, esa superficie se ve distinta.

   Va aquí y no en el <head> porque app.css es el ÚNICO archivo que comparten el
   panel web y la app MAUI (BrincolinasControlApp.csproj enlaza ..\wwwroot\css\**
   y ..\wwwroot\fonts\**). Declararlo en los dos index.html obligaría a mantener
   dos copias a mano, y esos dos archivos ya se habían desincronizado antes.
   Efecto secundario: la app MAUI, que NUNCA cargó una fuente web —se veía en
   Helvetica del sistema—, pasa a tener la tipografía de marca, y offline.

   Se sirve desde /fonts, nunca desde fonts.googleapis.com: así vale la CSP con
   `font-src 'self'` y desaparecen dos preconnect y una hoja externa del arranque.
   Mismo patrón que el @font-face de Twemoji en phone-field.css.

   font-display:swap, no `optional`: esto es una SPA, no hay segunda navegación
   de documento, así que con `optional` una primera carga lenta dejaría al usuario
   la sesión ENTERA en la fuente de respaldo. El FOUT real es ~cero: la primera
   pintura es el splash .ic-boot y 46 KB precargados llegan mucho antes de que el
   runtime WASM dibuje el primer texto de interfaz.

   El unicode-range es el mismo subconjunto `latin` que Google servía para Inter,
   así que los glifos que ya caían al stack del sistema (→, ≤, ✓, ⋮, emoji) siguen
   cayendo igual. Ampliarlo no serviría: el archivo no trae esos glifos. */
@font-face {
    font-family: "Schibsted Grotesk";
    src: url("../fonts/schibsted-grotesk-latin-var.v1.woff2") format("woff2");
    font-weight: 400 900;
    font-style: normal;
    font-display: swap;
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
        U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,
        U+FEFF, U+FFFD;
}

html, body {
    font-family: var(--ic-font);
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    margin: 0;
    min-height: 100%;
    background-color: var(--ic-bg);
    color: var(--ic-text);
    /* Scrollbar tokenizada (flota claro/oscuro) */
    scrollbar-color: var(--ic-scrollbar-thumb) var(--ic-scrollbar-track);
    scrollbar-width: thin;
}

* {
    scrollbar-color: var(--ic-scrollbar-thumb) var(--ic-scrollbar-track);
}

::-webkit-scrollbar {
    width: 8px;
    height: 8px;
}

::-webkit-scrollbar-track {
    background: var(--ic-scrollbar-track);
}

::-webkit-scrollbar-thumb {
    background: var(--ic-scrollbar-thumb);
    border-radius: 6px;
    border: 2px solid transparent;
    background-clip: padding-box;
}

::-webkit-scrollbar-thumb:hover {
    background: var(--ic-scrollbar-thumb-hover);
    border: 2px solid transparent;
    background-clip: padding-box;
}

::-webkit-scrollbar-corner {
    background: var(--ic-bg);
}

/* Pantalla de arranque (antes de Blazor WASM) */
#app {
    min-height: 100vh;
    min-height: 100dvh;
}

.ic-boot {
    position: relative;
    min-height: 100vh;
    min-height: 100dvh;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: max(24px, env(safe-area-inset-top)) max(24px, env(safe-area-inset-right)) max(24px, env(safe-area-inset-bottom)) max(24px, env(safe-area-inset-left));
    box-sizing: border-box;
    background: radial-gradient(ellipse 120% 70% at 50% -10%, rgba(85, 99, 224, 0.20), transparent 60%),
                var(--ic-bg);
}

.ic-boot__pattern {
    position: absolute;
    inset: 0;
    background-image: radial-gradient(rgba(148, 163, 184, 0.10) 1px, transparent 1px);
    background-size: 22px 22px;
    pointer-events: none;
    mask-image: radial-gradient(ellipse 70% 55% at 50% 42%, black 15%, transparent 100%);
    -webkit-mask-image: radial-gradient(ellipse 70% 55% at 50% 42%, black 15%, transparent 100%);
}

.ic-boot__content {
    position: relative;
    z-index: 1;
    text-align: center;
    max-width: 320px;
}

/* Logo + halo. El halo es un ::before del contenedor para no meter otro <div>. */
.ic-boot__markwrap {
    position: relative;
    width: 96px;
    height: 96px;
    margin: 0 auto 1.625rem;
}

.ic-boot__markwrap::before {
    content: "";
    position: absolute;
    inset: -14px;
    border-radius: 32px;
    border: 1px solid var(--ic-brand-ring);
    animation: ic-boot-pulse 2.6s ease-in-out infinite;
}

.ic-boot__mark {
    display: block;
    width: 96px;
    height: 96px;
    border-radius: 24px;
    object-fit: contain;
    box-shadow: 0 18px 44px rgba(85, 99, 224, 0.32);
    animation: ic-boot-float 4s ease-in-out infinite;
}

.ic-boot__title {
    margin: 0;
    font-size: 2rem;
    font-weight: 800;
    letter-spacing: -0.045em;
    line-height: 1;
    color: var(--ic-text);
}

.ic-boot__tagline {
    margin: 0.5rem 0 0;
    font-size: 0.8125rem;
    font-weight: 500;
    letter-spacing: 0.02em;
    color: var(--ic-text-tertiary);
}

/* Barra indeterminada: sustituye al anillo giratorio. Un spinner dice "esperando";
   una barra que avanza dice "cargando", que es lo cierto durante el boot de WASM. */
.ic-boot__bar {
    width: 180px;
    height: 3px;
    margin: 2.375rem auto 0;
    border-radius: 99px;
    background: var(--ic-border);
    overflow: hidden;
}

.ic-boot__bar span {
    display: block;
    width: 34%;
    height: 100%;
    border-radius: 99px;
    background: var(--ic-brand-gradient);
    animation: ic-boot-bar 1.5s cubic-bezier(.65, .05, .36, 1) infinite;
}

.ic-boot__hint {
    margin: 1rem 0 0;
    min-height: 1.2em;
    font-size: 0.8125rem;
    font-weight: 500;
    line-height: 1.45;
    color: var(--ic-text-tertiary);
}

/* Build desplegado. index.html lo rellena desde <meta name="ic-build"> y lo deja
   oculto en local (donde el meta sigue siendo el placeholder __IC_BUILD__). */
.ic-boot__version {
    position: absolute;
    left: 0;
    right: 0;
    bottom: max(26px, env(safe-area-inset-bottom));
    text-align: center;
    font-size: 0.6875rem;
    font-weight: 600;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--ic-text-tertiary);
    opacity: 0.6;
}

@keyframes ic-boot-bar {
    0%   { transform: translateX(-100%); }
    100% { transform: translateX(320%); }
}

@keyframes ic-boot-pulse {
    0%, 100% { transform: scale(1);    opacity: 0.55; }
    50%      { transform: scale(1.14); opacity: 0.12; }
}

@keyframes ic-boot-float {
    0%, 100% { transform: translateY(0); }
    50%      { transform: translateY(-6px); }
}

@media (prefers-reduced-motion: reduce) {
    /* El logo deja de flotar y el halo de latir; la barra sigue avanzando (más lenta),
       porque es la única señal de que el arranque no se murió. */
    .ic-boot__mark,
    .ic-boot__markwrap::before {
        animation: none;
    }

    .ic-boot__bar span {
        animation-duration: 3s;
    }

    /* Drawer: sin scroll suave ni fades si el usuario pide menos movimiento. */
    .mud-drawer.ic-drawer .ic-nav-body {
        scroll-behavior: auto !important;
    }

    .mud-drawer.ic-drawer * {
        transition-duration: 0.01ms !important;
    }
}

/* ── Estado "atorado" (a los 30 s en la PWA, 20 s en MAUI) ──
   El script añade .ic-boot--stuck: el logo encoge, se paran las animaciones y
   desaparece la barra, porque a esas alturas ya no está "avanzando" nada. */
.ic-boot--stuck .ic-boot__markwrap,
.ic-boot--stuck .ic-boot__mark {
    width: 72px;
    height: 72px;
    animation: none;
}

.ic-boot--stuck .ic-boot__markwrap::before {
    display: none;
}

.ic-boot--stuck .ic-boot__mark {
    border-radius: 18px;
    opacity: 0.85;
}

.ic-boot--stuck .ic-boot__bar,
.ic-boot--stuck .ic-boot__tagline {
    display: none;
}

.ic-boot--stuck .ic-boot__markwrap {
    margin-bottom: 1.25rem;
}

/* En el estado atorado el problema manda: "Esto está tardando" toma el sitio y el
   peso del título, y la marca se retira. Dejar "Vinali" grande y el aviso pequeño
   invierte la jerarquía justo cuando el usuario necesita leer qué hacer. */
.ic-boot--stuck .ic-boot__title {
    display: none;
}

.ic-boot--stuck .ic-boot__hint {
    margin-top: 0;
    font-size: 1.5rem;
    font-weight: 800;
    letter-spacing: -0.04em;
    line-height: 1.15;
    color: var(--ic-text);
}

.ic-boot__stuck {
    margin-top: 0.625rem;
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 0.625rem;
}

.ic-boot__stuck-text {
    margin: 0 auto 1.75rem;
    max-width: 280px;
    font-size: 0.9375rem;
    line-height: 1.5;
    color: var(--ic-text-tertiary);
    text-wrap: pretty;
}

.ic-boot__retry-btn {
    appearance: none;
    height: var(--ic-touch-min);
    border: 0;
    border-radius: 12px;
    font-family: inherit;
    font-size: 0.9375rem;
    font-weight: 600;
    cursor: pointer;
    background: var(--ic-primary);
    color: #fff;
    box-shadow: 0 6px 18px var(--ic-brand-ring);
}

.ic-boot__retry-btn:active {
    opacity: 0.92;
    transform: scale(0.98);
}

.ic-boot__retry-btn--secondary {
    background: transparent;
    color: var(--ic-muted);
    border: 1px solid var(--ic-border);
    box-shadow: none;
}

/* Tema claro: el degradado de fondo, el punteado y el halo están calibrados para
   fondo oscuro; sobre el gris agrupado claro desaparecen. Se suben los alphas, no los tonos. */
html[data-theme="light"] .ic-boot {
    background: radial-gradient(ellipse 120% 70% at 50% -10%, rgba(85, 99, 224, 0.14), transparent 60%),
                var(--ic-bg);
}

html[data-theme="light"] .ic-boot__pattern {
    background-image: radial-gradient(rgba(71, 85, 105, 0.20) 1px, transparent 1px);
}

html[data-theme="light"] .ic-boot__markwrap::before {
    border-color: rgba(85, 99, 224, 0.55);
}

html[data-theme="light"] .ic-boot__mark {
    box-shadow: 0 18px 44px rgba(85, 99, 224, 0.22);
}

/* ── Variables del sistema de diseño (dark) ── */
:root {
    /* Familia base de TODA la app. Va en este :root y no en uno propio: los tests
       de paleta leen "el primer bloque :root" como el tema oscuro, así que un
       :root adelantado les deja la paleta vacía. Antes el mismo "stack de Inter"
       vivía escrito de CINCO formas distintas (aquí con Helvetica Neue, en
       auth-shared/crm como 'Inter',sans-serif, en _substrate-mock con system-ui,
       en mapa.css con otro, y en dos `font:` con -apple-system DELANTE de Inter,
       o sea que esos dos ni siquiera eran Inter). Cinco respaldos = cinco
       resultados distintos mientras carga la fuente.
       No lleva variante clara: la tipografía no cambia con el tema.
       OJO: la familia de los componentes de MudBlazor NO sale de aquí, sale del
       tema en C# (MainLayout.razor y SimplePublicLayout.razor). Si cambias una,
       cambia la otra: hay un test que falla si se separan. */
    --ic-font: "Schibsted Grotesk", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
        "Helvetica Neue", Arial, "Noto Sans", sans-serif;
    --ic-bg:           #000000;
    --ic-surface:      #1C1C1E;
    --ic-surface-2:    #2C2C2E;
    /* Componentes RGB (sin alpha) de los fondos, para superficies TRANSLÚCIDAS que usan alpha
       variable: rgba(var(--ic-surface-rgb), 0.92). En oscuro = valores originales (cero regresión);
       el tema claro los voltea en html[data-theme="light"]. */
    --ic-surface-rgb:   28, 28, 30;
    --ic-surface-2-rgb: 44, 44, 46;
    --ic-bg-rgb:        0, 0, 0;
    --ic-border:       rgba(84, 84, 88, 0.65);
    --ic-primary:      #5563E0;

    /* Texto sobre el relleno de marca. Existía disperso como #fff literal en varias
       hojas; aquí es un token para que las hojas blindadas contra hex puedan usarlo.
       OJO al medir: blanco sobre --ic-primary da 4.94:1 en LOS DOS TEMAS, porque desde
       2026-09-23 el relleno es el mismo hex en ambos: #5563E0, el --primary literal de la
       landing y del logo v7. Eso cumple AA en texto normal, que es nuevo: el azul de iOS
       daba 4.7/3.65 y el índigo aclarado de antes 4.9/3.49, y en oscuro ninguno pasaba de
       texto grande. No volver a aclararlo en oscuro «para que resalte»: eso es justo lo
       que costaba el punto de contraste. */
    --ic-on-primary:   #FFFFFF;

    --ic-primary-dim:  rgba(85, 99, 224, 0.15);
    --ic-text:         #FFFFFF;
    /* Texto secundario/terciario: una sola fuente de verdad = la paleta MudBlazor (PaletteDark en
       MainLayout.razor). El fallback hex protege antes de que Mud hidrate. Subir el contraste se hace
       en C# y cae en cascada a estos tokens, a --rq-* y a todo el CSS que ya usa var(--ic-*).
       Estos valores (alto contraste) son el default oscuro; el tema claro los redefine en
       html[data-theme="light"]. */
    --ic-muted:         var(--mud-palette-text-secondary, #AEAEB2);
    --ic-text-tertiary: var(--mud-palette-action-default, #98989D);
    --ic-icon-muted:    var(--mud-palette-action-default, #98989D);
    --ic-radius-sm:    8px;
    --ic-radius-md:    12px;
    --ic-radius-lg:    16px;
    --ic-shadow:       0 4px 24px rgba(0, 0, 0, 0.4);
    --ic-shadow-sm:    0 1px 4px rgba(0, 0, 0, 0.3);
    /* Hacia ARRIBA: la usan las barras pegajosas al pie de los diálogos de producto.
       No es --ic-shadow con el signo cambiado: una barra que flota sobre contenido que
       se desliza por debajo necesita menos desenfoque y menos alfa, o el borde superior
       se lee como una segunda línea por encima del border-top que ya lleva. */
    --ic-shadow-up:    0 -2px 12px rgba(0, 0, 0, 0.18);

    /* ── Escala de espaciado ────────────────────────────────────────────────
       Base 4px para coincidir con las utilidades de MudBlazor (mb-3 = 12px,
       mb-4 = 16px) y no pelearse con ellas. Regla de proximidad: el espacio
       DENTRO de un grupo debe ser <= al espacio ALREDEDOR (p. ej. padding de
       tarjeta space-3 con gutter space-4). */
    --ic-space-1: 4px;
    --ic-space-2: 8px;
    --ic-space-3: 12px;
    --ic-space-4: 16px;
    --ic-space-5: 20px;
    --ic-space-6: 24px;
    --ic-space-8: 32px;

    /* ── Escala tipográfica ─────────────────────────────────────────────────
       El rem base es el del navegador (16px): no se declara font-size en
       html/body. Usar estos tokens en vez de literales nuevos. */
    --ic-text-xs:   0.75rem;    /* 12px — badges/metadatos (piso absoluto) */
    --ic-text-sm:   0.875rem;   /* 14px — secundario en tarjetas */
    --ic-text-md:   0.9375rem;  /* 15px — cuerpo legible (piso senior-friendly) */
    --ic-text-base: 1rem;       /* 16px */
    --ic-text-lg:   1.0625rem;  /* 17px — títulos de tarjeta/barra */
    --ic-text-xl:   1.25rem;    /* 20px — título de página */
    --ic-text-2xl:  1.5rem;     /* 24px — números destacados */

    /* ── Mínimo táctil ──────────────────────────────────────────────────────
       48px, no 44: la app se usa con guantes de carga y a pleno sol. El
       contrato de mocks (wwwroot/css/_substrate-mock.css) ya declaraba este
       token, así que un mock dibujado con él calzaba en el banco y no en la
       app, donde sólo existía el alias --dr-touch-min. Ahora el nombre del
       contrato es el que manda y --dr-touch-min hereda de él. */
    --ic-touch-min: 48px;

    /* ── Grosor del hairline ─────────────────────────────────────────────────
       El separador del calendario y del menú inferior. 1px en pantallas 1x; en
       2x y 3x baja a medio píxel físico entero (al final de esta hoja), que es
       exactamente lo que hace iOS con 1/scale. Un 0.5px fijo desaparecería en
       un Android de densidad 1 y en escritorio. */
    --ic-hairline-w: 1px;

    /* ── Radio de la tarjeta del calendario ─────────────────────────────────
       14px y no --ic-radius-md (12): iOS redondea más lo que va suelto sobre un
       fondo agrupado. Lo lee calendario-dia.css y el override de más abajo. */
    --cal-card-radius: 14px;

    /* ── Lienzo de firma ────────────────────────────────────────────────────
       Blanco en los DOS temas, a propósito: la firma se captura como trazo
       oscuro sobre blanco, así que sobre el fondo del tema oscuro sería un
       rectángulo negro. No es un color de marca, es el papel. */
    --ic-canvas-firma: #FFFFFF;

    /* ── Superficies y señales de las pantallas de producto ─────────────────
       Nacieron en el listado (wwwroot/css/productos-lista.css) y viven aquí desde
       que la ficha (wwwroot/css/detalle-producto.css) consume las mismas: un token
       que sirve a dos pantallas no es local a ninguna, y dejarlo en la hoja de una
       hacía que la otra dependiera de que ésa se hubiera cargado. Conservan el
       prefijo --pl- de su origen. */
    /* Superficie de control (buscador, chips inactivos, pie de tarjeta, hoja).
       El mock la dibujaba #16242A: un escalón ENTRE --ic-bg y --ic-surface que
       el sistema no tiene, porque --ic-surface-2 va en el sentido contrario
       (más claro que la tarjeta). En oscuro se reconstruye mezclando; en claro
       el escalón correcto sí existe y es --ic-surface-2. */
    --pl-control: color-mix(in srgb, var(--ic-surface) 62%, var(--ic-bg));
    --pl-control-hover: color-mix(in srgb, var(--ic-surface) 34%, var(--ic-bg));

    /* Hover del relleno de acento (#A7B0FF en el mock). Mezclar contra el TEXTO
       y no contra blanco hace que aclare en oscuro y oscurezca en claro solo. */
    --pl-accent-hover: color-mix(in srgb, var(--lc-accent) 85%, var(--ic-text));

    /* Fondo del hueco de foto y color de su icono. */
    --pl-photo-bg: color-mix(in srgb, var(--ic-text) 7%, transparent);
    --pl-photo-ico: color-mix(in srgb, var(--ic-text-tertiary) 55%, transparent);

    /* Velo de la pastilla de unidades. IGUAL EN LOS DOS TEMAS a propósito: va
       encima de la foto del producto, no de la superficie de la app, así que
       voltearlo con el tema la dejaría ilegible sobre fotos claras. Mismo
       criterio que ya llevaban los chips de ProductoCard. */
    --pl-photo-scrim: rgba(2, 6, 23, 0.78);
    --pl-photo-scrim-line: color-mix(in srgb, var(--ic-muted) 22%, transparent);

    /* Línea suave (separadores dentro de la hoja). */
    --pl-hairline: color-mix(in srgb, var(--ic-border) 60%, transparent);

    /* Tinta oscura de las etiquetas sobre la foto. Fija en los dos temas, como su
       relleno: si volteara con el tema, en claro quedaría texto claro sobre un
       relleno claro. */
    --pl-on-tag: rgb(0, 0, 0);
    --pl-on-scrim: rgb(242, 247, 251);

    /* El acento de la etiqueta «Paquete» NO usa --lc-accent-rgb porque ése SÍ se
       voltea en tema claro (es el único --lc-*-rgb que lo hace), y el índigo
       oscuro de claro con tinta oscura encima se quedaba en 4.28:1. Los demás
       -rgb no voltean, así que fijarlo aquí además los deja a todos coherentes:
       una etiqueta sobre una foto no debe cambiar con el tema de la app. */
    --pl-tag-accent-rgb: 85, 99, 224;

    /* ── Canalón de las pantallas de detalle ────────────────────────────────
       El margen lateral del contenido en /rentas/{id}, /registrar-entrega,
       /productos/{id} y /asignar-renta. Va en :root y no en cada hoja porque
       el encabezado a sangre lo LEE para desbordarlo (PageHeader.razor.css):
       si las dos mitades no salen del mismo número, el encabezado acaba
       corrido respecto a las tarjetas, que es como se descubrió. No lo
       consume ningún MudContainer por su cuenta: hace falta .ic-page-gutter. */
    --ic-page-gutter: var(--ic-space-3);

    /* ── Contrato de página: canalón y ancho del contenido ──────────────────
       ÚNICO sitio donde se decide cuánto respira el contenido de una página
       contra los filos y hasta dónde se estira en una pantalla ancha. Lo
       consume .ic-content-wrap (más abajo en esta misma hoja), que es el
       MudContainer del layout, y .ic-viewport-page para las inmersivas. Van en
       app.css y no en MainLayout.razor.css porque ese archivo es CSS scoped y
       el MudContainer no lleva su atributo [b-…]: allí no aplicarían.
       Ninguna página declara max-width ni padding lateral por su cuenta: el
       ancho se elige por MODO (normal / --angosto / --denso), no por medida.

       Antes esto no existía y el canalón salía de tres sitios que no se
       hablaban: el gutter por omisión de MudBlazor (16/24px), un !important
       de móvil en el layout (8px) y lo que cada página se pusiera encima
       —incluidos 13 MudContainer anidados que lo sumaban dos veces—.

       REVERTIR LA PASADA ENTERA = 16px/24px aquí y 1920px en --ic-content-max.
       No hay que tocar ninguna página.

       OJO: NO es --ic-page-gutter, que es el canalón INTERIOR de las pantallas
       de detalle y de las barras del catálogo (catalogo-global.css lo lee en
       once sitios, PageHeader.razor.css lo desborda). Coinciden en móvil y
       difieren en escritorio a propósito. */
    --ic-page-pad-x:          var(--ic-space-3);   /* 12px — teléfono */
    --ic-content-max:         1600px;              /* normal: listados, tableros */
    --ic-content-max-angosto: 1100px;              /* lectura y formularios */

    /* ── PageHeader (sistema estandarizado de barras superiores de página) ──
       Consumidas por Components/PageHeader.razor.css. Cambiar aquí afecta
       a TODAS las páginas migradas; los valores cubren la variante List
       (estilo Calendario/Rentas) y Detail (estilo DetalleRenta). */
    --ic-page-header-row-h:             56px;
    --ic-page-header-padding-x:         12px;
    --ic-page-header-padding-y:         8px;
    --ic-page-header-bg:                rgba(28, 28, 30, 0.92);
    --ic-page-header-border:            var(--ic-border);
    --ic-page-header-shadow:            0 1px 0 0 rgba(255, 255, 255, 0.04);
    --ic-page-header-blur:              saturate(1.08) blur(12px);
    --ic-page-header-z:                 30;     /* List sticky: bajo todo lo flotante */
    --ic-page-header-z-detail:          1240;   /* < AppBar 1300, < Popover 1250, > BottomNav 1200 */
    --ic-page-header-touch-min:         44px;   /* móvil */
    --ic-page-header-touch-min-desktop: 48px;
    --ic-page-header-title-size:        1.0625rem;
    --ic-page-header-title-weight:      600;
    --ic-page-header-subtitle-size:     0.75rem;
    /* Detail no reserva hueco: es sticky y ocupa su sitio en el flujo, así que
       el ritmo lo da su propio margin-bottom. Hubo tokens de reserva mientras
       fue fixed y no había forma de que cuadraran en todas las páginas, porque
       el espacio por encima del ancla cambia con el margen de cada contenedor. */

    /* Altura real del AppBar (incluye padding/bordes). 64px = estándar moderno (M3 small
       top app bar); la zona-logo del drawer usa la misma var para la línea continua. */
    --ic-appbar-height: 64px;
    /* Mismos valores que MudDrawer en MainLayout (MiniWidth / Width). */
    --ic-drawer-mini-width: 72px;
    --ic-drawer-width: 280px;
    /* El hueco que el CONTENIDO reserva para el rail. En modo app no hay rail —el menú es un
       overlay temporal y el contenido llega al borde—, así que este token vale 0 allí.
       Los offsets de barras fijas leen ESTE, no --ic-drawer-mini-width, que describe el
       parámetro MiniWidth del MudDrawer y vale 72 en los dos modos. Lo redeclara
       html[data-chrome="app"] más abajo.

       ── Por qué el escritorio se escribe html:not([data-chrome="app"]) y no
          html[data-chrome="escritorio"] ──
       Porque así el escritorio es lo que sale cuando NO hay atributo, que es la misma caída
       segura que ic-chrome.js y ChromeModoService eligen si el interop falla. Importa para el
       banco: sus 28 páginas cargan esta hoja sin arrancar Blazor, y con un selector positivo
       se quedarían en un tercer estado —ni rail ni barra inferior— que no existe en producción
       y que haría mentir a la comparación. */
    --ic-chrome-rail-w: var(--ic-drawer-mini-width);

    /* ── Área segura inferior ── El inset crudo, tokenizado, y la mordida deliberada.
       En un iPhone el inset vale 34pt. Respetarlo entero dejaba la barra a 34pt del borde y el
       conjunto en 106pt, más alto que un tab bar nativo de iOS (83pt). Se le muerden 10pt y
       quedan 24, que es lo que necesita el gesto de inicio del sistema (~20pt) para no robarse
       los arrastres que empiezan sobre un tab. La esquina redondeada NO es la restricción: con
       radio ~55pt, a 30pt del borde se come 6pt de ancho y los iconos van centrados en tabs de
       ~80px, así que nunca los alcanza.
       El suelo NO es 24px: un dispositivo sin indicador de inicio (iPhone con botón, iPad,
       Android donde el WebView ya excluye la barra del sistema) reporta inset 0 y reservaría
       24px de nada. El 24 es el RESULTADO en iPhone (34 − 10). El suelo son 8px, y está para
       que en esos dispositivos la etiqueta no acabe a 4px del bisel.
       env(safe-area-inset-bottom) entra al sistema en UN SOLO SITIO, la declaración de
       --ic-bottom-nav-height (más abajo, en el bloque ≤1024px). El padding de la barra NO
       repite la fórmula: se deriva por RESTA de los dos tokens. Así no pueden divergir por
       construcción, y el banco puede falsificar la geometría del iPhone sobreescribiendo
       --ic-bottom-nav-height (una var() dentro de una custom property se sustituye donde se
       DECLARA, así que un override de --ic-safe-bottom en un descendiente no llegaría). */
    --ic-safe-bottom: env(safe-area-inset-bottom, 0px);
    --ic-nav-safe-bite: 10px;
    --ic-safe-pad-floor: 8px;

    /* ── BottomNav (móvil) ── Single source of truth para que cualquier página/FAB/spacer
       calcule offsets respecto al nav sin hardcodear la altura ni el área segura.
       En desktop = 0 (el BottomNav está oculto). En mobile se redefine más abajo con la
       altura real + el área segura mordida.
       60px y no 72: el tab más alto mide 59px = 8 de padding + 32 de cápsula + 2 de gap + 13 de
       etiqueta (11px con line-height:1 + 2 de padding) + 4 de padding. Los 13px que sobraban
       caían DEBAJO de las etiquetas, porque la barra alinea a flex-start para que el botón
       central pueda sobresalir; eso era la mitad de lo que se veía como «barra alta» en el
       iPhone. El +1 hasta 60 es el filete de arriba: la barra es border-box, así que el
       border-top cabalga dentro de la altura y el token debe cubrirlo (mejor pasarse medio
       píxel que quedarse corto, que es lo que taparía contenido).
       El tramo tablet vuelve a 73 más abajo, donde el tab sí mide 72. */
    --ic-bottom-nav-height: 0px;
    --ic-bottom-nav-content-height: 60px;
    /* Separación estándar de un FAB respecto al nav (o al bottom de la viewport en desktop). */
    --ic-fab-bottom-offset: 16px;
    --ic-z-drawer-overlay: 6000;
    --ic-z-dialog: 6100;
    --ic-z-snackbar: 6200;
    --ic-z-tooltip: 6300;
    /* Calendario: paneles full-bleed con relieve suave (sin márgenes laterales) */
    --ic-cal-panel-bg:    #1C1C1E;
    --ic-cal-panel-shine: rgba(255, 255, 255, 0.045);
    --ic-cal-empty-glow: rgba(85, 99, 224, 0.14);
    /* Banda translúcida de los headers/strip del calendario (consumida por calendario-nuevo.css) */
    --calendar-header-bg: rgba(var(--ic-surface-rgb), 0.92);
    /* ── Chrome unificado (drawer + appbar) ──
       UNA superficie idéntica para el rail y la barra superior: mismo fondo translúcido y
       mismo blur (el del calendario/PageHeader). La línea continua a y=64px es UN SOLO borde
       de 1px con --ic-chrome-border en cada mitad (border-bottom de la zona-logo +
       border-bottom del appbar), dentro de una banda de --ic-appbar-height en ambas.
       Nada de sombras encima: una segunda línea en solo una mitad rompe la continuidad. */
    --ic-chrome-bg-rgb:   0, 0, 0;                          /* #000000: negro puro, como iOS */
    --ic-chrome-bg:       rgba(var(--ic-chrome-bg-rgb), 0.90);
    --ic-chrome-blur:     saturate(1.08) blur(12px);
    --ic-chrome-border:   rgba(255, 255, 255, 0.10);
    /* Fondo de la barra inferior. En oscuro, el MISMO negro del lienzo: una franja gris
       #1C1C1E de lado a lado era la única caja de la pantalla (el encabezado de arriba va
       directo sobre el negro). En claro sigue siendo
       el mismo blanco que el lienzo (ver el bloque claro). También recorta el aro del FAB central, que
       tiene que casar con la barra para que el círculo parezca salir de ella. */
    --ic-bottom-nav-bg:   rgb(var(--ic-chrome-bg-rgb));
    /* ÚNICO lugar con hex de marca: avatar, mark del drawer y FAB lo referencian.
       En claro los DOS extremos son hex literales de la landing (--primary-h → --primary);
       en oscuro va del primario a su tono claro histórico, porque #4453D4 sobre negro
       apaga el FAB. */
    --ic-brand-gradient:  linear-gradient(135deg, #5563E0 0%, #8B97FF 100%);
    --ic-brand-ring:      rgba(85, 99, 224, 0.35);

    /* Navegación lateral */
    --ic-drawer-bg:         var(--ic-chrome-bg);
    --ic-drawer-surface:    rgba(255, 255, 255, 0.04);
    --ic-drawer-border:     rgba(255, 255, 255, 0.18);
    --ic-nav-accent:        #A6B2FF;
    --ic-nav-accent-dim:    rgba(85, 99, 224, 0.22);
    --ic-nav-accent-glow:   rgba(85, 99, 224, 0.45);
    --ic-nav-active-bg:     rgba(85, 99, 224, 0.14);
    --ic-nav-active-border: rgba(166, 178, 255, 0.22);

    /* ── Tokens semánticos de superficie (default oscuro) ──
       Floten entre claro/oscuro; el tema claro los redefine en html[data-theme="light"].
       Reemplazan hex/glass oscuros antes hardcodeados (AppBar, "glass" del drawer, scrollbar). */
    --ic-appbar-bg:           var(--ic-chrome-bg);
    --ic-appbar-border:       var(--ic-chrome-border);
    /* Banda superior del drawer (marca + negocio): el chrome corre continuo detrás;
       la separación la da solo el border-bottom de 1px. */
    --ic-drawer-toolbar-bg:   transparent;
    --ic-glass-surface:       rgba(255, 255, 255, 0.04);
    --ic-glass-surface-hover: rgba(255, 255, 255, 0.07);
    --ic-glass-border:        rgba(255, 255, 255, 0.09);
    --ic-glass-border-soft:   rgba(255, 255, 255, 0.06);
    --ic-scrollbar-track:     rgba(0, 0, 0, 0.95);
    --ic-scrollbar-thumb:     rgba(85, 99, 224, 0.28);
    --ic-scrollbar-thumb-hover: rgba(166, 178, 255, 0.45);

    /* ── Tokens theme-aware de elevación e interacción (pase de pulido UI) ──
       Los valores dark = las constantes hardcodeadas que reemplazan en sus reglas, así el
       modo oscuro queda intacto; el tema claro las corrige en html[data-theme="light"]. */
    --ic-chrome-shadow:        0 2px 12px rgba(0, 0, 0, 0.45);
    --ic-chrome-shadow-hover:  0 4px 16px rgba(0, 0, 0, 0.55);
    --ic-interactive-hover:    rgba(255, 255, 255, 0.07);
    --ic-interactive-active:   rgba(255, 255, 255, 0.13);
    --ic-fab-border:           rgba(255, 255, 255, 0.14);
    --ic-border-strong:        var(--ic-border);
    /* Visual circular del empty-state del calendario */
    --ic-cal-empty-bg:         linear-gradient(145deg, rgba(139, 151, 255, 0.18), rgba(85, 99, 224, 0.08));
    --ic-cal-empty-border:     rgba(166, 178, 255, 0.28);
    --ic-cal-empty-shadow:     0 12px 40px rgba(0, 0, 0, 0.45), inset 0 1px 0 0 rgba(255, 255, 255, 0.06);
    --ic-cal-empty-icon:       #A6B2FF;

    /* Colores semanticos de estado — NO modificar, tienen significado operativo */
    --estado-agendada:        #9E9E9E;
    --estado-asignado:        #2196F3;
    --estado-en-curso-entrega:#FF9800;
    --estado-en-curso-recogida:#795548;
    --estado-entregada:       #4CAF50;
    --estado-recogida:        #7B1FA2;
    --estado-cancelada:       #F44336;

    /* Paleta de eventos del calendario (chips/dots/filtros/tarjetas). Los estados
       "parciales" no llevan token propio: usan el token del estado pleno con
       tratamiento suave.

       Criterio (rediseño 2026-08): color de sistema POR TEMA, no el mismo hex en los
       dos. En oscuro son claros; en claro, profundos. Eso es lo que hace que el texto
       en color pleno sobre 22% de su propio tinte —el chip de la vista mes— dé ≥4,5:1
       en AMBOS temas. Los once están declarados en los dos temas: antes cinco heredaban
       del oscuro y salían sucios sobre blanco.

       Desde 2026-09-22 los tonos salen de la paleta de sistema de iOS (cyan, indigo,
       orange, brown, green, purple, pink, blue…) movidos en luminosidad hasta pasar el
       4,5:1 sobre su tinte al 22%: en oscuro sobre #1C1C1E, en claro sobre blanco.

       El ROJO está reservado a --cal-now y --cal-hoy-fill. Ningún estado es rojo:
       "cancelada" es rosa carmín y se apoya en doble señal (atenuada + tachada).
       El 2026-09-23, al volver la marca al índigo de la landing (#5563E0), «asignada para
       recolectar» se movió de #9B9AEF/#4E4CD4 a #B495FE/#672ABC: estaba a 4,7° de matiz del
       acento en claro y a 6,7° en oscuro, o sea era el mismo color que el chrome de la app.
       Ahora está a 19-24°. Se movió el ESTADO y no la marca porque la marca es el hex literal
       de la landing y del logo. El destino no es arbitrario: estos once tonos forman una rampa
       de matiz que sigue el flujo de la renta (entrega 212° → 251° → recolección 296° → 314°
       → 331°), así que el estado se desplazó DENTRO de su rampa, no fuera. */
    --cal-ev-agendada:          #A3A3A7;
    --cal-ev-asig-entrega:      #40C8E0;
    --cal-ev-asig-recoleccion:  #B495FE;
    --cal-ev-encurso-entrega:   #FF9F0A;
    --cal-ev-encurso-recogida:  #B99F7F;
    --cal-ev-entregada:         #30D158;
    --cal-ev-recogida:          #CF82F5;
    --cal-ev-cancelada:         #FF728E;
    --cal-ev-default:           #C9B896;
    --cal-ev-emp-asig-entrega:  #4CA5FF;
    --cal-ev-emp-asig-recogida: #EB74DF;
    /* Tinte de fin de semana en la vista de mes: SUBE hacia la superficie, no baja a gris */
    --cal-weekend-bg: rgba(255, 255, 255, 0.05);

    /* El rojo del tiempo. Un solo rojo, dos usos, dos valores por contraste:
       --cal-now      = línea y punto de "ahora" (elemento fino: pide luminancia)
       --cal-hoy-fill = relleno del círculo de "hoy" (lleva texto encima: pide ser
                        más profundo; 4,76:1 contra blanco — el #E0342B anterior
                        daba 4,47 y se quedaba por debajo del piso)
       Unifica los tres rojos que había sueltos (#F44336 día, #ea4335 3 días y agenda,
       #FF453A mes). */
    --cal-now:      #FF453A;
    --cal-hoy-fill: #DC2B21;
    --cal-on-now:   #FFFFFF;

    /* Material de separación del calendario: la línea fina sustituye a la caja.
       Más tinta que antes (8/6%) porque el separador de iOS pesa más y, a medio píxel
       en pantallas 2x, una línea al 8% desaparecía. */
    --cal-hairline:      color-mix(in srgb, var(--ic-text) 12%, transparent);
    --cal-hairline-soft: color-mix(in srgb, var(--ic-text) 8%, transparent);
    /* Base sobre la que se mezcla el tinte --ev de las tarjetas de renta. En oscuro es la
       superficie gris; en claro es BLANCO y no la superficie (que ahí es gris): el tinte sobre
       gris salía apagado, sobre blanco queda limpio. */
    --cal-card-base: var(--ic-surface);
    /* Relleno de los controles del calendario («‹ mes», acciones del encabezado, «Hoy» + lente,
       buscar/checklist/+). Token propio para poder aclararlos SIN tocar tarjetas ni listados,
       que siguen en --ic-surface. En oscuro coincide con la superficie. */
    --cal-control-bg: var(--ic-surface);

    /* Material «vidrio» de los controles flotantes del calendario (2026-09-23, como la barra de
       Calendario en iOS 26): «‹ mes», acciones, «Hoy» + lente, buscar/ruta/+. Fondo translúcido
       con desenfoque, anillo de medio píxel, brillo en el canto superior y una sombra suave. Es
       la ÚNICA excepción al «sin blur ni sombra» del rediseño 2026-08: vale para estos controles,
       nunca para las tarjetas. En oscuro parte de la superficie, no del negro: un negro
       translúcido sobre #000 no se distingue. Medido en _bench/mock-botones-ios-dia.html. */
    --cal-glass-bg:     color-mix(in srgb, var(--ic-surface) 72%, transparent);
    --cal-glass-edge:   color-mix(in srgb, var(--ic-text) 14%, transparent);
    --cal-glass-ring:   color-mix(in srgb, var(--ic-text) 12%, transparent);
    --cal-glass-shadow: 0 4px 16px rgba(0, 0, 0, 0.35), 0 1px 3px rgba(0, 0, 0, 0.3);
    --cal-glass-blur:   blur(20px) saturate(180%);
    --cal-glass-press:  color-mix(in srgb, var(--ic-text) 10%, transparent);
    --cal-glass-on:     color-mix(in srgb, var(--ic-text) 16%, transparent);  /* pulgar de la lente */

    /* Modo selección de ruta y avisos. Salen de tokens: antes eran índigo/ámbar crudos
       (#6366f1, #4338ca, #c7d2fe, #F59E0B, #D97706) que no volteaban con el tema. */
    --cal-ruta-sel:  var(--lc-accent);
    --cal-ruta-paso: var(--lc-accent);   /* paso YA guardado */
    --cal-ruta-pick: var(--lc-warn);     /* posición que se está eligiendo */
    --cal-urgente:   var(--lc-warn);     /* anillo de renta urgente: ÁMBAR, el rojo es del reloj */

    /* El pin del mapa. Dos tokens y no dos hex, pero con dueños distintos:

       --map-pin-stroke es el aro que separa la gota del SUELO, y el suelo no voltea: la base de
       teselas es clara en los dos temas (ver --map-teselas-bg abajo). Siguió a --ic-surface
       hasta el 2026-09-22 y eso hacía que el MISMO pin tuviera contorno de 13,7:1 contra las
       teselas en oscuro y de 1,24:1 en claro — pesado en un tema, inexistente en el otro. Fijo
       en blanco, con el drop-shadow separándolo, que es lo que hacen Apple Maps y Google Maps.

       --map-pin-ink es la tinta que va DENTRO de un disco de color, y ésa sí voltea, porque el
       disco voltea con ella: los --cal-ev-* son claros en oscuro (tinta negra encima) y
       profundos en claro (tinta casi blanca). */
    --map-pin-stroke: #FFFFFF;
    --map-pin-ink:    var(--ic-bg);

    /* El papel BAJO las teselas: lo que se ve por los huecos mientras cargan y al arrastrar.
       Fijo y declarado UNA vez —no se redeclara en html[data-theme="light"]— porque la base del
       mapa es clara en los dos temas (leaflet-map.js, _BASE_OSCURA_ACTIVA). Con un token que
       volteara, en tema oscuro cada arrastre dejaba bandas negras entre teselas, en el teléfono y
       con datos móviles. El tono es el gris papel de la base ArcGIS, para que el hueco no se note.
       Si se reactiva la base oscura, esto tiene que volver a voltear. */
    --map-teselas-bg: #EAE6E1;

    /* Tinta que va ENCIMA de las teselas: el chip del trayecto, el botón de encuadre y el velo de
       «toca para mover» del selector de dirección. Fijos y sin espejo en claro por el mismo motivo
       que el papel: el mapa es claro en los dos temas, así que un fondo que siguiera al tema
       desaparecería sobre las teselas en uno de los dos. No confundir con --map-pin-ink, que sí
       voltea porque el disco que lo contiene voltea con él.
       El valor era rgba(15,23,42,…) —el azul-pizarra de la paleta vieja— y se quedó ahí al pasar
       a los grises de sistema: el mecanismo era correcto, el tono no. En negro neutro el blanco
       encima sube de 13,2:1 a 17,1:1 y el chip contra las teselas de 10,6 a 13,8. */
    --map-chip-bg:     rgba(0, 0, 0, 0.88);
    --map-chip-ink:    #FFFFFF;
    --map-chip-border: rgba(255, 255, 255, 0.16);
    --map-chip-link:   #A6B2FF;
    --map-chip-shadow: rgba(0, 0, 0, 0.28);
    --map-scrim:       rgba(0, 0, 0, 0.28);
}

/* Escalón de escritorio del canalón de página. 24px es EXACTAMENTE lo que
   MudBlazor ya daba desde 600px, así que las páginas que no se metían con su
   contenedor no se mueven ni un píxel: lo que este bloque hace es dejar de
   depender de una hoja de terceros para un número del sistema. El corte es
   600px, el mismo de MudBlazor, para que la migración no introduzca un tercer
   punto de quiebre. */
@media (min-width: 600px) {
    :root { --ic-page-pad-x: var(--ic-space-6); }   /* 24px */
}

/* ═══ TEMA CLARO ═══
   Activado por el atributo data-theme="light" en <html> (lo pone ic-theme.js antes de pintar y el
   toggle icSetTheme). Redefine TODOS los tokens --ic-* a valores claros y ESPEJA las --mud-palette-*
   con los MISMOS hex que PaletteLight (C#) para que no haya parpadeo entre el pintado por CSS y la
   hidratación de MudBlazor. html[data-theme="light"] (0,0,1,1) gana a :root (0,0,1,0), mismo elemento.
   Los --estado-* NO se redefinen (significado operativo invariante).

   Las sombras y los velos de este bloque iban en rgba(15,23,42,…) —negro con tinte azul-pizarra
   de la paleta vieja— y se quedaron ahí al pasar a los grises de sistema. Desde 2026-09-22 son
   negro neutro: sobre el gris agrupado #F2F2F7 el tinte frío se notaba, y ahora el chrome del
   mapa consume estos mismos tokens. */
html[data-theme="light"] {
    /* Desde 2026-09-23, espejo del oscuro: allá el lienzo es negro y las tarjetas, píldoras y
       grupos flotantes van en gris (#1C1C1E / #2C2C2E); aquí el lienzo es BLANCO —el mismo de la
       barra inferior— y esas superficies van en el gris agrupado de iOS (#F2F2F7), con el escalón
       anidado sigue en #ECECF1. Antes era al revés: lienzo gris y tarjetas blancas.
       El escalón NO baja a systemGray5 (#E5E5EA), que era el espejo exacto de #2C2C2E: ahí los
       chips --lc-* al 18% caen a 4.27:1 y lista-cards.css los calibró contra la superficie más
       oscura del tema. Con #ECECF1 siguen en 4.52; la pista se distingue por su borde de 1px.
       Medido en _bench/mock-claro-blanco.html: la tarjeta contra el lienzo da el mismo 1.12:1 que
       antes (la marca el borde de 1px, 1.7:1) y --ic-muted sobre la tarjeta da 8.1:1. */
    --ic-bg:            #FFFFFF;
    --ic-surface:       #F2F2F7;
    --ic-surface-2:     #ECECF1;
    /* Ver «Superficies y señales de las pantallas de producto» en :root. */
    --pl-control: var(--ic-surface-2);
    --pl-control-hover: color-mix(in srgb, var(--ic-surface-2) 70%, var(--ic-text));
    --ic-surface-rgb:   242, 242, 247;
    --ic-surface-2-rgb: 236, 236, 241;
    --ic-bg-rgb:        255, 255, 255;
    --calendar-header-bg: rgba(255, 255, 255, 0.92);
    --ic-border:        rgba(60, 60, 67, 0.29);
    --ic-primary:       #5563E0;
    --ic-on-primary:    #FFFFFF;
    --ic-primary-dim:   rgba(85, 99, 224, 0.10);
    --ic-text:          #000000;
    --ic-muted:         #48484E;
    --ic-text-tertiary: #6A6A70;
    --ic-icon-muted:    #6A6A70;
    --ic-shadow:        0 4px 24px rgba(0, 0, 0, 0.10);
    --ic-shadow-sm:     0 1px 4px rgba(0, 0, 0, 0.08);
    --ic-shadow-up:     0 -2px 12px rgba(0, 0, 0, 0.08);

    --ic-page-header-bg:            rgba(255, 255, 255, 0.92);
    --ic-page-header-shadow:        0 1px 0 0 rgba(60, 60, 67, 0.08);

    --ic-cal-panel-bg:    #FFFFFF;
    --ic-cal-panel-shine: rgba(60, 60, 67, 0.03);
    --ic-cal-empty-glow:  rgba(85, 99, 224, 0.10);

    /* Chrome unificado en claro: blanco, como el lienzo. Dentro del calendario el lienzo sale
       de --ic-chrome-bg-rgb, así que la vista día queda blanca con las píldoras y los grupos
       flotantes en gris encima: el mismo reparto que el negro con gris del oscuro. */
    --ic-chrome-bg-rgb:   255, 255, 255;
    --ic-chrome-bg:       rgba(255, 255, 255, 0.92);
    --ic-chrome-border:   rgba(60, 60, 67, 0.29);
    /* Blanco fijo y no var(--ic-surface), que ahora es gris: barra y lienzo son el mismo blanco. */
    --ic-bottom-nav-bg:   #FFFFFF;
    --ic-brand-gradient:  linear-gradient(135deg, #4453D4 0%, #5563E0 100%);
    --ic-brand-ring:      rgba(85, 99, 224, 0.28);

    --ic-drawer-bg:       var(--ic-chrome-bg);
    --ic-drawer-surface:  rgba(60, 60, 67, 0.04);
    --ic-drawer-border:   rgba(60, 60, 67, 0.12);
    --ic-nav-accent:        #4453D4;
    --ic-nav-accent-dim:    rgba(85, 99, 224, 0.16);
    --ic-nav-accent-glow:   rgba(85, 99, 224, 0.30);
    --ic-nav-active-bg:     rgba(85, 99, 224, 0.12);
    --ic-nav-active-border: rgba(85, 99, 224, 0.28);

    /* Tokens semánticos de superficie (ver Fase 3) en su variante clara */
    --ic-appbar-bg:           var(--ic-chrome-bg);
    --ic-appbar-border:       var(--ic-chrome-border);
    /* Banda superior del drawer: el chrome corre continuo (separación = borde de 1px). */
    --ic-drawer-toolbar-bg:   transparent;
    --ic-glass-surface:       rgba(0, 0, 0, 0.04);
    --ic-glass-surface-hover: rgba(0, 0, 0, 0.06);
    --ic-glass-border:        rgba(0, 0, 0, 0.10);
    --ic-glass-border-soft:   rgba(0, 0, 0, 0.07);
    --ic-scrollbar-track:     rgba(60, 60, 67, 0.06);
    --ic-scrollbar-thumb:     rgba(85, 99, 224, 0.35);
    --ic-scrollbar-thumb-hover: rgba(85, 99, 224, 0.55);

    /* Elevación e interacción en claro: sombras suaves (no negro duro), washes oscuros
       sutiles para hover/press visibles sobre blanco, y empty-state del calendario legible. */
    --ic-chrome-shadow:        0 2px 10px rgba(0, 0, 0, 0.10);
    --ic-chrome-shadow-hover:  0 6px 18px rgba(0, 0, 0, 0.14);
    --ic-interactive-hover:    rgba(0, 0, 0, 0.05);
    --ic-interactive-active:   rgba(0, 0, 0, 0.09);
    --ic-fab-border:           var(--ic-border);
    --ic-border-strong:        rgba(60, 60, 67, 0.36);
    --ic-cal-empty-bg:         linear-gradient(145deg, rgba(68, 83, 212, 0.12), rgba(85, 99, 224, 0.05));
    --ic-cal-empty-border:     rgba(85, 99, 224, 0.22);
    --ic-cal-empty-shadow:     0 8px 24px rgba(0, 0, 0, 0.10), inset 0 1px 0 0 rgba(255, 255, 255, 0.6);
    --ic-cal-empty-icon:       #4453D4;

    /* Paleta de eventos del calendario en claro. LOS ONCE, no solo algunos: antes cinco
       heredaban el valor oscuro y salían lavados sobre blanco cuando se usan como tinte. */
    --cal-ev-agendada:          #606065;
    --cal-ev-asig-entrega:      #1D6977;
    --cal-ev-asig-recoleccion:  #672ABC;
    --cal-ev-encurso-entrega:   #8C5200;
    --cal-ev-encurso-recogida:  #725D42;
    --cal-ev-entregada:         #1D6E31;
    --cal-ev-recogida:          #8E25C3;
    --cal-ev-cancelada:         #B70023;
    --cal-ev-default:           #6C5E42;
    --cal-ev-emp-asig-entrega:  #005BBF;
    --cal-ev-emp-asig-recogida: #A12295;
    /* Velo del fin de semana en claro. Era un velo BLANCO al 60%, que sólo se veía porque el
       lienzo era gris (#F4F6FB); con el calendario en blanco desaparecía y sábado y domingo
       dejaban de distinguirse en la vista Mes. Ahora es un velo oscuro casi imperceptible. */
    --cal-weekend-bg:           rgba(0, 0, 0, 0.03);

    /* El rojo del tiempo en claro: la línea lleva el rojo de sistema de iOS (elemento fino);
       el relleno de «hoy» es más profundo porque lleva texto encima (4,76:1). */
    --cal-now:      #FF3B30;
    --cal-hoy-fill: #DC2B21;

    /* La línea fina pesa más sobre blanco que sobre el fondo oscuro; con el texto en negro
       puro, el 24% equivale al separador de iOS (rgba(60,60,67,.29)). */
    --cal-hairline:      color-mix(in srgb, var(--ic-text) 24%, transparent);
    --cal-hairline-soft: color-mix(in srgb, var(--ic-text) 16%, transparent);
    --cal-card-base: #FFFFFF;
    /* Un escalón más claro que --ic-surface (#F2F2F7): sobre el lienzo blanco el botón lo marca
       su hairline (1.67:1), y el riel del conmutador de lente gana contraste contra su marco
       (1.06 → 1.10). Medido en _bench/mock-botones-calendario.html. */
    --cal-control-bg: #F7F7F9;

    /* Vidrio en claro: parte del blanco y el brillo del canto es blanco casi opaco. */
    --cal-glass-bg:     color-mix(in srgb, #FFFFFF 72%, transparent);
    --cal-glass-edge:   color-mix(in srgb, #FFFFFF 85%, transparent);
    --cal-glass-ring:   color-mix(in srgb, var(--ic-text) 10%, transparent);
    --cal-glass-shadow: 0 4px 16px rgba(0, 0, 0, 0.08), 0 1px 3px rgba(0, 0, 0, 0.06);
    --cal-glass-press:  color-mix(in srgb, var(--ic-text) 8%, transparent);
    --cal-glass-on:     color-mix(in srgb, var(--ic-text) 10%, transparent);

    /* Espejo de PaletteLight (mismos hex) → evita el flash pre-hidratación de MudBlazor */
    --mud-palette-text-primary:   #000000;
    --mud-palette-text-secondary: #48484E;
    --mud-palette-action-default: #6A6A70;
    --mud-palette-drawer-text:    #1C1C1E;
    --mud-palette-drawer-icon:    #6A6A70;
    --mud-palette-lines-default:  rgba(60, 60, 67, 0.29);
    --mud-palette-lines-inputs:   rgba(60, 60, 67, 0.40);
    --mud-palette-divider:        rgba(60, 60, 67, 0.22);
    --mud-palette-background:     #FFFFFF;
    --mud-palette-background-gray: #ECECF1;
    --mud-palette-appbar-background: #FFFFFF;
    --mud-palette-drawer-background: #FFFFFF;
    --mud-palette-surface:        #FFFFFF;
}

/* Chip café para el estado "En curso — recolección".
   MudChip no expone un Color "café", así que aplicamos esta clase para forzar la paleta. */
.mud-chip.estado-encurso-recogida-chip.mud-chip-filled {
    background-color: var(--estado-en-curso-recogida) !important;
    color: #ffffff !important;
    border-color: var(--estado-en-curso-recogida) !important;
}

.mud-chip.estado-encurso-recogida-chip.mud-chip-outlined {
    background-color: transparent !important;
    color: var(--estado-en-curso-recogida) !important;
    border-color: var(--estado-en-curso-recogida) !important;
}

/* Cuando el chip outlined está seleccionado (filtro activo), se rellena en café */
.mud-chip.estado-encurso-recogida-chip.mud-chip-outlined.mud-clickable.mud-chip-selected,
.mud-chip.estado-encurso-recogida-chip.mud-chip-outlined[aria-pressed="true"] {
    background-color: var(--estado-en-curso-recogida) !important;
    color: #ffffff !important;
    border-color: var(--estado-en-curso-recogida) !important;
}

/* ═══ Legibilidad: púrpura como texto ═══
   MudText Color="Secondary" emite .mud-secondary-text → color púrpura (--mud-palette-secondary)
   con !important. Como TEXTO sobre fondo oscuro tiene contraste pobre y se pierde bajo el sol.
   Esta regla reasigna SOLO la tipografía (.mud-typography) al gris secundario legible; gana por
   especificidad (2 clases) + !important. NO afecta botones, chips ni iconos (que NO llevan
   .mud-typography), así que el púrpura sigue disponible como acento donde tiene sentido. */
.mud-typography.mud-secondary-text {
    color: var(--ic-muted) !important;
}

/* ═══ Drawer lateral (estilos globales) ═══
   MudDrawer concatena Class="ic-drawer" en el MISMO elemento que tiene .mud-drawer.
   Un selector descendiente .ic-drawer .mud-drawer nunca coincide → el glass no se veía en producción. */
.mud-drawer.ic-drawer {
    background: var(--ic-chrome-bg) !important;
    backdrop-filter: var(--ic-chrome-blur) !important;
    -webkit-backdrop-filter: var(--ic-chrome-blur) !important;
    border-right: 1px solid var(--ic-chrome-border) !important;
    box-shadow: none !important;
}

/* Táctil: blur del drawer + recomposición del Chrome Android suelen causar parpadeos al scroll */
@media (hover: none) and (pointer: coarse) {
    .mud-drawer.ic-drawer {
        backdrop-filter: none !important;
        -webkit-backdrop-filter: none !important;
        background: rgba(var(--ic-chrome-bg-rgb), 0.99) !important;
    }
}

/* ── Desktop con cursor: fluidez del expand-on-hover del rail mini ──
   Acotado a (hover:hover)+(pointer:fine): NO aplica en MAUI/táctil (sin expand-on-hover).
   Promueve el panel a su propia capa de composición para que, al animar MudBlazor el `width`,
   el repintado quede aislado y no fuerce repintar el contenido de la página por debajo (overlay).
   will-change:width NO crea containing block (a diferencia de transform), así que no rompe
   position:fixed de los hijos.
   NOTA: aquí NO se apaga el blur durante la transición (lo hacía la clase ic-drawer--animating):
   sustituir el glass por un fondo sólido provocaba un parpadeo —el fondo se aclaraba y volvía— al
   abrir el menú. Tampoco se hace fade del texto colapsado: mantenerlo en flujo con ancho 0
   descentraba el icono (el gap/margen seguía ocupando), por eso el colapsado usa display:none. */
@media (hover: hover) and (pointer: fine) {
    .mud-drawer.ic-drawer.mud-drawer-mini.mud-drawer-fixed {
        will-change: width;
    }
}

/* ── Modo app: el drawer es temporal y MudBlazor pinta un scrim ──
   Bug: con Variant="Mini" el panel se queda en z-index var(--mud-zindex-drawer) (1100),
   pero el scrim `.mud-overlay-drawer` va a calc(var(--mud-zindex-appbar) + 1) (1301). El scrim
   queda ENCIMA del panel y captura todos los toques → "se abre el menú y no se puede tocar nada".
   (Los drawers Responsive sí suben el panel a appbar+2; los Mini no.) Lo replicamos aquí para que
   el panel quede sobre su propio scrim. Solo en modo app: en escritorio es rail sin scrim. */
html[data-chrome="app"] .mud-drawer.ic-drawer {
    z-index: calc(var(--mud-zindex-appbar) + 2) !important; /* 1302 > scrim 1301 */
}

/* ── El scrim del menú en modo app ──
   MudBlazor sólo enciende su overlay (`display:block`) para variantes con un breakpoint con
   NOMBRE —`-xs`, `-sm`, `-md`…— o para `temporary`. Con Breakpoint.None emite
   `mud-drawer-overlay-none`, para el que no escribe ninguna regla, así que el scrim nace en el
   DOM con `display:none` de la regla base: el menú se abría y no había forma de cerrarlo
   tocando fuera. Medido en el navegador el 2026-09-22 a 1180px.
   Se enciende el overlay de MudBlazor en vez de pintar uno propio porque ESE ya trae el
   @onclick que cierra el drawer; un div nuestro tendría que repetir ese cableado.
   El z-index no se toca: 1301 del scrim contra 6000 del panel (regla de más abajo), que es
   justo el orden que el drawer necesita para quedar sobre su propio scrim. */
html[data-chrome="app"] .mud-overlay.mud-drawer-overlay.mud-drawer-overlay--open.mud-drawer-overlay-none {
    display: block;
}

/* Escritorio: rail a altura completa (ClipMode.Never) */
html:not([data-chrome="app"]) .mud-drawer.ic-drawer.mud-drawer-mini.mud-drawer-fixed {
    top: 0 !important;
    height: 100vh !important;
    height: 100dvh !important;
    max-height: 100vh !important;
    max-height: 100dvh !important;
}

/*
 * Modo superposición (sin pin): mismo hueco horizontal que el contenido (solo rail 72px).
 * La barra superior NO cambia de tamaño al expandir el menú; el drawer se dibuja encima (z-index).
 * Stack desktop: AppBar/contenido/popovers de pagina < drawer.
 * .mud-main-content crea su propio stacking context para que ningún fixed/sticky de página escape sobre el menú.
 */
html:not([data-chrome="app"]) .mud-layout.ic-layout--sidebar-overlay .mud-appbar.ic-appbar {
    margin-left: var(--ic-drawer-mini-width) !important;
    width: calc(100% - var(--ic-drawer-mini-width)) !important;
    max-width: calc(100% - var(--ic-drawer-mini-width)) !important;
    left: 0 !important;
    right: auto !important;
    box-sizing: border-box !important;
    z-index: 1230 !important;
}

html:not([data-chrome="app"]) .mud-layout.ic-layout--sidebar-overlay .mud-drawer.ic-drawer.mud-drawer-mini {
    z-index: var(--ic-z-drawer-overlay) !important;
}

/* Chrome flotante: en reposo el rail no lleva sombra (el borde hairline define);
   al expandirse SOBRE el contenido (overlay) gana la elevación del chrome del calendario. */
html:not([data-chrome="app"]) .mud-layout.ic-layout--sidebar-overlay .mud-drawer.ic-drawer.mud-drawer-mini:not(.mud-drawer--closed) {
    box-shadow: var(--ic-chrome-shadow) !important;
}

html:not([data-chrome="app"]) .mud-layout.ic-layout--sidebar-overlay .mud-main-content {
    margin-left: var(--ic-drawer-mini-width) !important;
    width: calc(100% - var(--ic-drawer-mini-width)) !important;
    max-width: calc(100% - var(--ic-drawer-mini-width)) !important;
    position: relative !important;
    z-index: 0 !important;
    isolation: isolate;
}

html:not([data-chrome="app"]) .mud-layout.ic-layout--sidebar-overlay .mud-appbar.ic-appbar,
html:not([data-chrome="app"]) .mud-layout.ic-layout--sidebar-overlay .mud-main-content.ic-main {
    transition: margin-left 0s linear, width 0s linear, max-width 0s linear !important;
}

/*
 * Diálogos (portal): por encima del rail (6000) y centrados en el área de contenido,
 * no en el viewport completo. Fullscreen sigue a pantalla entera.
 */
html:not([data-chrome="app"]) .mud-overlay.mud-overlay-dialog {
    z-index: var(--ic-z-dialog) !important;
}

html:not([data-chrome="app"]) .mud-dialog-container {
    z-index: calc(var(--ic-z-dialog) + 1) !important;
    left: var(--ic-drawer-mini-width) !important;
    width: calc(100% - var(--ic-drawer-mini-width)) !important;
    max-width: calc(100% - var(--ic-drawer-mini-width)) !important;
    box-sizing: border-box !important;
}

html:not([data-chrome="app"]) .mud-dialog-container:has(.mud-dialog-fullscreen) {
    left: 0 !important;
    width: 100% !important;
    max-width: 100% !important;
}

/* ── Escritorio (única banda con barra superior): toolbar estable junto al drawer ── */
html:not([data-chrome="app"]) .mud-layout .mud-appbar.ic-appbar .mud-toolbar {
    max-width: 100%;
    min-width: 0;
    gap: 6px;
}

html:not([data-chrome="app"]) .mud-layout .mud-appbar.ic-appbar .ic-appbar__title {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* AppBar alineado al contenido: NO forzar left/width aquí.
   MudBlazor ya aplica margin-left + width al .mud-appbar vía
   .mud-drawer-open-mini-*-left.mud-drawer-left-clipped-never (ClipMode.Never).
   Añadir left/width propios duplicaba el desplazamiento (doble hueco a la izquierda). */

/* Barra superior del drawer: marca + negocio (único control para cambiar de negocio).
   Visible en todo ancho; el drawer la oculta off-canvas cuando está cerrado en móvil. */
.ic-drawer-toolbar {
    display: flex;
    flex-shrink: 0;
    align-items: center;
    justify-content: space-between;
    /* Altura EXACTA del AppBar para que ambos border-bottom queden a la misma y (alineados). */
    height: var(--ic-appbar-height);
    min-height: var(--ic-appbar-height);
    padding: 0 12px;
    /* Mismo color que el border-bottom del appbar → línea horizontal continua a y=64px. */
    border-bottom: 1px solid var(--ic-chrome-border);
    box-sizing: border-box;
    overflow: hidden;
    background: var(--ic-drawer-toolbar-bg);
}

/* ════════════ Modo app: drawer = columna fija de pantalla completa ════════════
   La barra superior está oculta y el drawer es un overlay. Lo clavamos al viewport y dejamos
   que SOLO .ic-nav-body scrollee, para que el menú se detenga en el último ítem ("Instalar App")
   justo encima del pie. Encabezado y pie con la misma altura que las barras de página
   (--ic-page-header-row-h, 56px) y el BottomNav (--ic-bottom-nav-height, 72px). */
/* (#3) Drawer y contenedores clavados al viewport; el drawer NO scrollea. Usar !important
   sobre .ic-drawer (clase nuestra, SIEMPRE presente) gana a la regla "temporary" de
   MudBlazor (height:100%; overflow-y:auto, sin !important) sin depender de .mud-drawer-mini
   —que MudBlazor puede quitar bajo el breakpoint. Antes la regla dependía de esa clase y
   el drawer quedaba como segundo scroller: se podía pasar de largo el último ítem. */
html[data-chrome="app"] .mud-drawer.ic-drawer {
    /* position:fixed FORZADO: MudBlazor solo pone position:fixed si la clase
       .mud-drawer-fixed está presente; bajo el breakpoint (overlay temporary) la
       quita y cae a `.mud-drawer:not(.mud-drawer-fixed){position:absolute}`. Un drawer
       ABSOLUTO scrollea junto con la página (cuyo contenido detrás puede ser alto),
       arrastrando el menú y el pie fuera de vista —ESE era el "se puede scrolear de
       más". Fijándolo al viewport, el drawer queda quieto y solo .ic-nav-body scrollea. */
    position: fixed !important;
    top: 0 !important;
    height: 100vh !important;
    height: 100dvh !important;
    max-height: 100vh !important;
    max-height: 100dvh !important;
    overflow: hidden !important;
}

html[data-chrome="app"] .mud-drawer.ic-drawer .mud-drawer-content {
    height: 100% !important;
    max-height: 100% !important;
    overflow: hidden !important;
}

/* El contenedor interno llena el drawer y fija el pie abajo (en escritorio se deja al
   contenido para no dejar hueco en el rail). Prefijo .mud-layout para ganar a la base. */
html[data-chrome="app"] .mud-layout .mud-drawer.ic-drawer .ic-drawer__inner {
    flex: 1 1 auto !important;
    height: 100% !important;
    max-height: 100% !important;
    overflow: hidden !important;
}

/* El cuerpo del menú es el ÚNICO scroller: llena el espacio entre encabezado y pie y
   scrollea internamente; overscroll-behavior contiene el rebote. */
html[data-chrome="app"] .mud-layout .mud-drawer.ic-drawer .ic-nav-body {
    flex: 1 1 auto !important;
    min-height: 0 !important;
    overflow-y: auto !important;
    overscroll-behavior: contain !important;
}

/* (#1) Encabezado de negocio: banda de 56px (igual que las barras de página) + safe-area
   arriba para despejar el notch. Fondo y borde TRANSPARENTES: detrás de la tarjeta
   redondeada no debe verse una banda rectangular —la tarjeta es el único elemento visual. */
html[data-chrome="app"] .ic-drawer-toolbar {
    height: calc(var(--ic-page-header-row-h) + env(safe-area-inset-top, 0px));
    min-height: calc(var(--ic-page-header-row-h) + env(safe-area-inset-top, 0px));
    padding-top: env(safe-area-inset-top, 0px);
    padding-bottom: 0;
    overflow: visible;
    background: transparent !important;
    border-bottom: none !important;        /* override del border-bottom inline del .razor */
}

/* (#1) La tarjeta de marca cabe exacta en la banda de 56px (logo 36 + 2×6 + gap holgado). */
html[data-chrome="app"] .mud-drawer.ic-drawer .ic-drawer-toolbar .ic-brand {
    padding-top: 6px !important;
    padding-bottom: 6px !important;
}

/* (#2) Pie de usuario: banda de 72px (igual que el BottomNav) + safe-area abajo; tarjeta
   centrada. Prefijo .mud-layout para ganar a la base del pie (declarada después). */
html[data-chrome="app"] .mud-layout .mud-drawer.ic-drawer .ic-drawer__foot {
    height: auto !important;
    min-height: var(--ic-bottom-nav-height) !important;
    /* Espeja la barra con la MISMA resta, no con un env() propio: con dos expresiones, en un
       dispositivo sin indicador de inicio el pie medía la banda con 0 de padding y la barra
       con el suelo de 8, y la tarjeta de usuario se centraba contra otra altura. */
    padding: 0 12px calc(var(--ic-bottom-nav-height) - var(--ic-bottom-nav-content-height)) !important;
    box-sizing: border-box !important;
    display: flex !important;
    flex-direction: column !important;
    align-items: stretch !important;
    justify-content: center !important;
    border-top: 1px solid var(--ic-glass-border-soft) !important;
}

/* Botón de tema: aquí SÍ, porque es justo donde la barra superior no existe. */
html[data-chrome="app"] .mud-drawer.ic-drawer .ic-theme {
    display: flex !important;
}

/* Mínimo táctil de la casa: 48px, no los 44 del escritorio. */
html[data-chrome="app"] .mud-drawer.ic-drawer .ic-nav__item {
    min-height: var(--ic-touch-min) !important;
}

/* Ancho del overlay: 300px como techo (el rango habitual de un menú lateral en teléfono es
   280-320) y, en pantallas angostas, siempre deja al menos 72px de página visible —el ancho
   del rail— para que el toque fuera del menú lo cierre sin apuntar. 360: 288 · 390+: 300.
   Antes era min(360px, 86vw): en un teléfono de 440 se comía 360px y la página detrás casi
   desaparecía. El nombre del negocio cabe: .ic-brand__name recorta a 2 renglones. */
html[data-chrome="app"] .mud-drawer.ic-drawer.mud-drawer-mini {
    width: min(300px, calc(100vw - 72px)) !important;
}

/* ── Cabecera de marca del drawer (.ic-brand): negocio + logo/iniciales ──
   Tarjeta transparente que solo gana relieve si es clicable (multi-negocio). */
.mud-drawer.ic-drawer .ic-brand {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    min-width: 0;
    padding: 8px;
    border-radius: 12px;
    border: 1px solid transparent;
    background: transparent;
    cursor: default;
    color: inherit;
    text-decoration: none;
    box-sizing: border-box;
}

.mud-drawer.ic-drawer .ic-brand--clickable {
    cursor: pointer;
    transition: background 0.2s ease, border-color 0.2s ease;
}

.mud-drawer.ic-drawer .ic-brand--clickable:hover {
    background: var(--ic-interactive-hover);
    border-color: var(--ic-glass-border-soft);
}

.mud-drawer.ic-drawer .ic-brand--clickable:focus-visible {
    outline: none;
    box-shadow: inset 0 0 0 2px var(--ic-nav-accent-glow);
}

/* Sin marco: el logo se muestra completo, a su proporción natural. El alto queda fijo
   en 36px (presupuesto de la banda del toolbar: 64px escritorio / 56px móvil) y el ancho
   crece con el logo hasta max-width, en vez de encajarlo en un cuadro de 36px.
   min-width sostiene el tile de iniciales (.ic-brand__mark), que sí es cuadrado.
   max-width 96px: medido en el panel de 280px deja 101px a .ic-brand__name, por encima
   de los 81px que mide "Brincolinas" (la palabra más ancha) — con 120px el nombre se
   partía a media palabra. */
.mud-drawer.ic-drawer .ic-brand__logo {
    height: 36px;
    width: auto;
    min-width: 36px;
    max-width: 96px;
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: center;
}

.mud-drawer.ic-drawer .ic-brand__logo img {
    height: 100%;
    width: auto;
    max-width: 100%;
    object-fit: contain;
}

.mud-drawer.ic-drawer .ic-brand__mark {
    width: 100%;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 0.8125rem;
    font-weight: 700;
    letter-spacing: 0.02em;
    color: #fff;
    background: var(--ic-brand-gradient);
    border-radius: 10px;
    box-shadow: 0 0 0 2px var(--ic-brand-ring);
}

.mud-drawer.ic-drawer .ic-brand__name {
    flex: 1 1 0;
    min-width: 0;
    font-size: var(--ic-text-md);
    font-weight: 600;
    letter-spacing: -0.01em;
    color: var(--ic-text);
    line-height: 1.25;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.mud-drawer.ic-drawer .ic-brand__switch {
    flex-shrink: 0;
    color: var(--ic-icon-muted);
}

.mud-drawer.ic-drawer .ic-brand--clickable:hover .ic-brand__switch {
    color: var(--ic-text);
}

/* Rail colapsado: solo el logo, centrado */
.mud-drawer.ic-drawer.mud-drawer-mini.mud-drawer--closed .ic-drawer-toolbar {
    justify-content: center;
    padding-left: 6px;
    padding-right: 6px;
}

.mud-drawer.ic-drawer.mud-drawer-mini.mud-drawer--closed .ic-brand {
    justify-content: center;
    padding: 8px 0;
}

.mud-drawer.ic-drawer.mud-drawer-mini.mud-drawer--closed .ic-brand__name,
.mud-drawer.ic-drawer.mud-drawer-mini.mud-drawer--closed .ic-brand__switch {
    display: none;
}

/* El rail mide 72px (MiniWidth) y el toolbar deja 6px/lado: el logo, ya sin ancho fijo,
   se acota aquí para que un logo apaisado no desborde la columna. */
.mud-drawer.ic-drawer.mud-drawer-mini.mud-drawer--closed .ic-brand__logo {
    max-width: 48px;
}

/* Contenedor del drawer: columna para que el pie quede abajo y no se rompa el flex */
.mud-drawer.ic-drawer .mud-drawer-content {
    display: flex !important;
    flex-direction: column !important;
    flex: 1 1 auto !important;
    min-height: 0 !important;
    min-width: 0 !important;
    width: 100% !important;
    max-width: 100% !important;
    overflow: hidden !important;
    box-sizing: border-box !important;
}

.mud-drawer.ic-drawer .ic-drawer__inner {
    display: flex !important;
    flex-direction: column !important;
    /* No crecer a todo el alto del drawer: evita hueco + scroll vacío entre menú y pie */
    flex: 0 1 auto !important;
    align-self: stretch !important;
    height: auto !important;
    max-height: 100% !important;
    min-height: 0 !important;
    min-width: 0 !important;
    width: 100% !important;
    max-width: 100% !important;
    justify-content: flex-start !important;
    overflow: hidden !important;
    box-sizing: border-box !important;
}

.mud-drawer.ic-drawer .ic-nav-body {
    flex: 0 1 auto !important;
    min-height: 0 !important;
    min-width: 0 !important;
    overflow-y: auto !important;
    overflow-x: hidden !important;
    padding: 10px 12px 12px !important;
    box-sizing: border-box !important;
    -webkit-overflow-scrolling: touch;
    /* ── Fluidez del scroll (ambas plataformas) ──
       overscroll-behavior: antes solo en @media ≤1024px; global evita arrastrar el panel/scroll-chain.
       contain layout paint: aísla los repintados al box del scroller (NO usar size/strict: romperían
       el cálculo de alto flex que sostiene este menú). transform translateZ(0): capa de composición
       propia → al desplazar, el scroll no obliga a re-evaluar el backdrop-filter del panel de detrás
       (causa raíz del jank de scroll sobre glass en desktop). En el scroller, no en el drawer, para
       no crear containing block que rompa position:fixed. scrollbar-gutter: sin salto al aparecer la
       barra. */
    overscroll-behavior: contain !important;
    scrollbar-gutter: stable;
    contain: layout paint;
    transform: translateZ(0);
    scroll-behavior: smooth;
}

/* Modo app: sin rail fijo; el menú solo aparece al abrir desde "Más" (overlay) */
html[data-chrome="app"] .mud-drawer.ic-drawer.mud-drawer-mini {
    /* Debe quedar por encima del AppBar en móvil al abrirse como overlay */
    z-index: var(--ic-z-drawer-overlay) !important;
}

html[data-chrome="app"] .mud-drawer.ic-drawer.mud-drawer-mini.mud-drawer--closed {
    transform: translateX(-100%) !important;
}

/* Evita desplazamientos laterales del AppBar por clases automáticas del drawer */
html[data-chrome="app"] .mud-layout .mud-appbar.ic-appbar {
    margin-left: 0 !important;
    margin-right: 0 !important;
    left: 0 !important;
    right: 0 !important;
    width: 100% !important;
}

html[data-chrome="app"] .mud-layout .mud-main-content {
    margin-left: 0 !important;
    margin-right: 0 !important;
}

/* Modo app a partir de 600px (tablet, y el teléfono en horizontal): áreas táctiles del menú.
   Absorbió el bloque «iPad landscape» que vivía suelto con (min-width:960px) and (hover:none):
   ese rango ES modo app desde ic-chrome.js, y estos 48px se comen aquellos 46. */
@media (min-width: 600px) {
    html[data-chrome="app"] .mud-drawer.ic-drawer .ic-nav__item {
        min-height: 48px !important;
        font-size: 0.9rem !important;
    }

    html[data-chrome="app"] .mud-drawer.ic-drawer .ic-nav__glabel {
        font-size: 0.675rem;
    }

    /* AppBar con botones táctiles más cómodos */
    html[data-chrome="app"] .mud-appbar.ic-appbar .mud-icon-button {
        min-width: 42px !important;
        width: 42px !important;
        height: 42px !important;
    }
}

/* ════════════════════════ Menú lateral: las filas ════════════════════════
   Las filas dejaron de ser MudNavLink y son anclas propias (.ic-nav__item). Por eso aquí ya no
   hace falta ni un !important: no hay chrome de MudBlazor que neutralizar. La fila activa la
   decide ChromeNav en C#, no el componente.
   La píldora completa ES la señal de activo: nada de barra lateral ::before. */
.mud-drawer.ic-drawer .ic-nav__group {
    margin-bottom: 6px;
}

.mud-drawer.ic-drawer .ic-nav__glabel {
    font-size: 0.6875rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--ic-text-tertiary);
    padding: 18px 12px 6px;
    box-sizing: border-box;
}

.mud-drawer.ic-drawer .ic-nav__group:first-child .ic-nav__glabel {
    padding-top: 12px;
}

.mud-drawer.ic-drawer .ic-nav__item {
    position: relative;
    display: flex;
    align-items: center;
    gap: 12px;
    min-height: 44px;
    margin: 2px 0;
    padding: 0 12px;
    border-radius: var(--ic-radius-md);
    text-decoration: none;
    font-size: var(--ic-text-md);
    font-weight: 500;
    color: var(--ic-muted);
    transition: background .2s ease, color .2s ease;
}

.mud-drawer.ic-drawer .ic-nav__item .mud-icon-root {
    flex: 0 0 auto;
    width: 22px;
    height: 22px;
    font-size: 22px;
    color: var(--ic-icon-muted);
    transition: color .2s ease;
}

.mud-drawer.ic-drawer .ic-nav__tx {
    min-width: 0;
    flex: 1 1 auto;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.mud-drawer.ic-drawer .ic-nav__item:hover {
    background: var(--ic-interactive-hover);
    color: var(--ic-text);
}

.mud-drawer.ic-drawer .ic-nav__item:hover .mud-icon-root {
    color: var(--ic-text);
}

.mud-drawer.ic-drawer .ic-nav__item:active {
    background: var(--ic-interactive-active);
}

.mud-drawer.ic-drawer .ic-nav__item:focus-visible {
    outline: none;
    box-shadow: inset 0 0 0 2px var(--ic-nav-accent-glow);
}

.mud-drawer.ic-drawer .ic-nav__item--activo,
.mud-drawer.ic-drawer .ic-nav__item--activo:hover {
    background: var(--ic-nav-active-bg);
    color: var(--ic-nav-accent);
    font-weight: 600;
}

.mud-drawer.ic-drawer .ic-nav__item--activo .mud-icon-root {
    color: var(--ic-nav-accent);
}

/* ── Contador de la fila (hoy solo Lavado): dos niveles, los dos se conservan ── */
.mud-drawer.ic-drawer .ic-nav__count {
    flex: 0 0 auto;
    min-width: 20px;
    height: 20px;
    padding: 0 6px;
    border-radius: 999px;
    display: grid;
    place-items: center;
    font-size: 0.6875rem;
    font-weight: 700;
    letter-spacing: 0;
    line-height: 1;
    background: var(--ic-glass-surface);
    color: var(--ic-muted);
}

.mud-drawer.ic-drawer .ic-nav__count--urg {
    background: color-mix(in srgb, var(--lc-err, var(--mud-palette-error)) 22%, transparent);
    color: var(--lc-err, var(--mud-palette-error));
}

/* En el rail el número no cabe: queda un punto del mismo color. Se enciende con el colapsado. */
.mud-drawer.ic-drawer .ic-nav__dot {
    display: none;
    position: absolute;
    top: 6px;
    right: 6px;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--ic-muted);
    box-shadow: 0 0 0 2px rgba(var(--ic-chrome-bg-rgb), 0.9);
}

.mud-drawer.ic-drawer .ic-nav__dot--urg {
    background: var(--lc-err, var(--mud-palette-error));
}

/* ── Bloqueado por plan ──
   Conserva el icono de su módulo y su texto: sigue siendo reconocible. Lo que pierde es el color,
   un escalón por debajo del resto, así que se lee "todavía no" y no "roto". Antes el icono se
   cambiaba por un candado y la entrada era indistinguible de una fila cualquiera. */
.mud-drawer.ic-drawer .ic-nav__item--plan,
.mud-drawer.ic-drawer .ic-nav__item--plan .mud-icon-root {
    color: var(--ic-text-tertiary);
}

.mud-drawer.ic-drawer .ic-nav__lock {
    flex: 0 0 auto;
    display: inline-flex;
}

.mud-drawer.ic-drawer .ic-nav__lock .mud-icon-root {
    width: 16px;
    height: 16px;
    font-size: 16px;
}

/* La oferta aparece cuando la buscas y no grita cuando no. */
.mud-drawer.ic-drawer .ic-nav__upsell {
    display: none;
    flex: 0 0 auto;
    height: 20px;
    padding: 0 8px;
    border-radius: 999px;
    align-items: center;
    background: var(--ic-nav-accent-dim);
    color: var(--ic-nav-accent);
    font-size: 0.6875rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

.mud-drawer.ic-drawer .ic-nav__item--plan:hover {
    background: color-mix(in srgb, var(--ic-nav-accent) 10%, transparent);
    color: var(--ic-text);
}

.mud-drawer.ic-drawer .ic-nav__item--plan:hover .mud-icon-root {
    color: var(--ic-nav-accent);
}

.mud-drawer.ic-drawer .ic-nav__item--plan:hover .ic-nav__lock {
    display: none;
}

.mud-drawer.ic-drawer .ic-nav__item--plan:hover .ic-nav__upsell {
    display: inline-flex;
}

/* ════════════════════════ Rail colapsado (72px) ════════════════════════
   72 − 24 de canalón (.ic-nav-body) − 4 de margen = 44 de celda. */
.mud-drawer.ic-drawer.mud-drawer-mini.mud-drawer--closed .ic-nav__tx,
.mud-drawer.ic-drawer.mud-drawer-mini.mud-drawer--closed .ic-nav__count,
.mud-drawer.ic-drawer.mud-drawer-mini.mud-drawer--closed .ic-nav__lock,
.mud-drawer.ic-drawer.mud-drawer-mini.mud-drawer--closed .ic-nav__upsell,
.mud-drawer.ic-drawer.mud-drawer-mini.mud-drawer--closed .ic-nav__glabel,
.mud-drawer.ic-drawer.mud-drawer-mini.mud-drawer--closed .ic-legal,
.mud-drawer.ic-drawer.mud-drawer-mini.mud-drawer--closed .ic-user__bd,
.mud-drawer.ic-drawer.mud-drawer-mini.mud-drawer--closed .ic-user__chev {
    display: none;
}

/* El texto sale del flujo con display:none y NO con ancho 0: en un flex, un hijo invisible que
   sigue en flujo deja su gap y descentra el icono. Ya pasó una vez. */
.mud-drawer.ic-drawer.mud-drawer-mini.mud-drawer--closed .ic-nav__item {
    width: 44px;
    min-width: 44px;
    height: 44px;
    min-height: 44px;
    padding: 0;
    margin-left: auto;
    margin-right: auto;
    justify-content: center;
}

.mud-drawer.ic-drawer.mud-drawer-mini.mud-drawer--closed .ic-nav__dot {
    display: block;
}

/* Sin etiqueta de grupo el rail necesita otra separación: una línea entre grupos. */
.mud-drawer.ic-drawer.mud-drawer-mini.mud-drawer--closed .ic-nav__group + .ic-nav__group {
    border-top: 1px solid var(--ic-glass-border-soft);
    margin-top: 8px;
    padding-top: 8px;
}

.mud-drawer.ic-drawer.mud-drawer-mini.mud-drawer--closed .ic-user {
    flex-direction: column;
    gap: 2px;
}

.mud-drawer.ic-drawer.mud-drawer-mini.mud-drawer--closed .ic-user__card,
.mud-drawer.ic-drawer.mud-drawer-mini.mud-drawer--closed .ic-user__salir {
    flex: 0 0 auto;
    width: 44px;
    min-height: 44px;
    height: 44px;
    padding: 0;
    justify-content: center;
}

.mud-drawer.ic-drawer.mud-drawer-mini.mud-drawer--closed .ic-drawer__foot {
    padding-left: 6px;
    padding-right: 6px;
}

/* ════════════════════════ Pie del menú ════════════════════════
   Antes apilaba tres cosas heterogéneas sin jerarquía (tema, legales, usuario). Ahora es una fila
   de usuario —tarjeta + salir— con los legales encima y el tema, que sigue siendo solo de móvil,
   arriba de todo. El botón de salir existe porque hasta este pase el panel NO tenía ningún
   "Cerrar sesión" alcanzable en ningún ancho. */
.mud-drawer.ic-drawer .ic-drawer__foot {
    flex: 0 0 auto;
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding: 8px 10px max(10px, env(safe-area-inset-bottom, 10px));
    border-top: 1px solid var(--ic-glass-border-soft);
    box-sizing: border-box;
    width: 100%;
    max-width: 100%;
    min-width: 0;
    overflow: visible;
}

/* Tema: en escritorio se cambia desde la barra superior; aquí solo cuando esa barra no existe. */
.mud-drawer.ic-drawer .ic-theme {
    display: none;
    align-items: center;
    gap: 10px;
    width: 100%;
    padding: 10px 12px;
    box-sizing: border-box;
    border-radius: var(--ic-radius-md);
    border: 1px solid var(--ic-glass-border-soft);
    background: var(--ic-glass-surface);
    color: var(--ic-muted);
    font-family: inherit;
    font-size: 0.8125rem;
    font-weight: 600;
    text-align: left;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    touch-action: manipulation;
    transition: background .2s ease;
}

.mud-drawer.ic-drawer .ic-theme .mud-icon-root {
    width: 20px;
    height: 20px;
    font-size: 20px;
    color: var(--ic-icon-muted);
}

.mud-drawer.ic-drawer .ic-theme:active {
    background: var(--ic-glass-surface-hover);
}

.mud-drawer.ic-drawer .ic-legal {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 12px;
    padding: 0 8px;
}

.mud-drawer.ic-drawer .ic-legal a {
    font-size: 0.6875rem;
    color: var(--ic-text-tertiary);
    text-decoration: none;
}

.mud-drawer.ic-drawer .ic-legal a:hover {
    color: var(--ic-muted);
    text-decoration: underline;
}

.mud-drawer.ic-drawer .ic-user {
    display: flex;
    align-items: center;
    gap: 4px;
    min-width: 0;
}

.mud-drawer.ic-drawer .ic-user__card {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    align-items: center;
    gap: 10px;
    min-height: var(--ic-touch-min);
    padding: 0 8px;
    box-sizing: border-box;
    border-radius: var(--ic-radius-md);
    text-decoration: none;
}

.mud-drawer.ic-drawer .ic-user__card:hover {
    background: var(--ic-interactive-hover);
}

.mud-drawer.ic-drawer .ic-user__card:focus-visible {
    outline: none;
    box-shadow: inset 0 0 0 2px var(--ic-nav-accent-glow);
}

.mud-drawer.ic-drawer .ic-user__bd {
    display: flex;
    flex-direction: column;
    min-width: 0;
    flex: 1 1 auto;
}

.mud-drawer.ic-drawer .ic-user__nm {
    display: block;
    font-size: var(--ic-text-md);
    font-weight: 600;
    color: var(--ic-text);
    line-height: 1.2;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.mud-drawer.ic-drawer .ic-user__rl {
    display: block;
    font-size: var(--ic-text-xs);
    color: var(--ic-text-tertiary);
    line-height: 1.3;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.mud-drawer.ic-drawer .ic-user__chev {
    flex: 0 0 auto;
    color: var(--ic-icon-muted);
}

.mud-drawer.ic-drawer .ic-user__salir {
    flex: 0 0 auto;
    width: var(--ic-touch-min);
    height: var(--ic-touch-min);
    display: grid;
    place-items: center;
    border: 0;
    border-radius: var(--ic-radius-md);
    background: transparent;
    color: var(--ic-icon-muted);
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    transition: background .2s ease, color .2s ease;
}

.mud-drawer.ic-drawer .ic-user__salir:hover {
    background: color-mix(in srgb, var(--lc-err, var(--mud-palette-error)) 12%, transparent);
    color: var(--lc-err, var(--mud-palette-error));
}

/* ── El avatar, compartido por el pie del menú y la barra superior ──
   Un solo sitio: es la misma persona y tiene que verse igual en las dos superficies. */
.ic-avatar {
    flex: 0 0 auto;
    width: 32px;
    height: 32px;
    border-radius: 50%;
    display: grid;
    place-items: center;
    overflow: hidden;
    background: var(--ic-brand-gradient);
    /* Blanco deliberado: va sobre el relleno de marca, que no cambia con el tema. */
    color: #FFFFFF;
    font-size: var(--ic-text-xs);
    font-weight: 700;
    letter-spacing: 0;
    line-height: 1;
}

.ic-avatar img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

.ic-avatar--36 {
    width: 36px;
    height: 36px;
    font-size: 0.8125rem;
}
/* ════════════════════════ Barra inferior (≤1024px) ════════════════════════
   Vivía en un <style> dentro de BottomNav.razor, contra la regla de la casa: ese bloque no tiene
   scope y el banco no podía reproducir el componente. Ahora es chrome y vive con el chrome.

   La barra es la ÚNICA superficie opaca del conjunto (--ic-bottom-nav-bg, no --ic-chrome-bg): va
   bajo el pulgar y sobre el contenido que scrollea, y el cristal ahí se lee sucio. */
.bottom-nav {
    display: none;
}

html[data-chrome="app"] .bottom-nav {
    display: flex;
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    z-index: 1200;
    /* Fuente única: todos los spacers, FABs y barras de acción de la app leen
       var(--ic-bottom-nav-height) (contenido + área segura mordida). min-height y no height: el
       contenido no se comprime cuando el dispositivo añade el área de la home indicator. */
    min-height: var(--ic-bottom-nav-height);
    /* Las pestañas se alinean ARRIBA para que el botón central pueda sobresalir sin estirar
       a sus vecinas; antes era stretch y el círculo empujaba la fila. */
    align-items: flex-start;
    box-sizing: border-box;
    /* Abajo, la diferencia entre los dos tokens: exactamente el área segura mordida que
       --ic-bottom-nav-height ya reservó. Las dos var() se resuelven AQUÍ, en el elemento, no
       en :root, y por eso el banco puede falsificar las dos y obtener este padding solo.
       A los lados, el inset lateral, que faltaba: en horizontal safe-area-inset-left/right
       valen 59pt del lado de la isla y la barra es left:0/right:0, así que los tabs de los
       extremos se metían bajo el recorte y bajo la curva de la esquina. */
    padding: 0 env(safe-area-inset-right, 0px)
               calc(var(--ic-bottom-nav-height) - var(--ic-bottom-nav-content-height))
               env(safe-area-inset-left, 0px);
    background: var(--ic-bottom-nav-bg);
    /* Sin línea superior, en los dos temas: barra y lienzo son del mismo color y la barra se
       lee por sus iconos y por el botón central que sobresale. Hubo una versión a lo iOS (la
       línea sólo con contenido detrás, 2026-09-23) y se retiró el mismo día: al usarla, la
       línea que aparecía y desaparecía con el scroll estorbaba más de lo que separaba.
       Transparente y no borrada: el medio píxel sigue midiendo y ningún spacer se mueve. */
    border-top: var(--ic-hairline-w) solid transparent;
}

.bottom-nav__tab {
    flex: 1 1 0;
    /* Sin esto el hijo con nowrap impide encoger y el truncado de la etiqueta no llega a actuar. */
    min-width: 0;
    min-height: var(--ic-touch-min);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: flex-start;
    gap: 2px;
    /* 4 abajo y no 6: los otros 2 viven ahora en .bottom-nav__lb, que los necesita para su
       descendente (ver allí). El alto del tab no cambia: sigue siendo 59px. */
    padding: 8px 4px 4px;
    border: 0;
    background: transparent;
    color: var(--ic-icon-muted);
    font-family: inherit;
    font-size: 0.6875rem;
    font-weight: 500;
    letter-spacing: 0;
    text-decoration: none;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    touch-action: manipulation;
    transition: color .15s ease;
}

.bottom-nav__tab:active {
    opacity: .7;
}

/* Cápsula del icono: el indicador de estado del sistema (M3). */
.bottom-nav__cap {
    position: relative;
    width: 64px;
    height: 32px;
    display: grid;
    place-items: center;
    border-radius: 16px;
    transition: background .2s ease;
}

.bottom-nav__tab .mud-icon-root {
    width: 24px;
    height: 24px;
    font-size: 24px;
}

.bottom-nav__tab:hover .bottom-nav__cap {
    background: var(--ic-interactive-hover);
}

.bottom-nav__tab--activo {
    color: var(--ic-nav-accent);
}

.bottom-nav__tab--activo .bottom-nav__cap {
    background: var(--ic-nav-active-bg);
}

.bottom-nav__lb {
    max-width: 100%;
    /* line-height:1 aprieta la caja de línea a 11px, pero la caja del texto de Schibsted mide
       1,2344em (ascent 2000 + descent 528 sobre 2048 unidades, con USE_TYPO_METRICS): sobresale
       ~1,3px por lado. Como esta etiqueta lleva overflow:hidden para el truncado, el recorte cae
       en su caja de padding y la cola de la «y» de «Hoy» —la única etiqueta con descendente— se
       afeitaba. Estos 2px son los que se le quitaron al padding del tab: el alto es el mismo. */
    line-height: 1;
    padding-bottom: 2px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Contador. Elemento propio en vez de MudBadge: el componente obligaba a un envoltorio extra y a
   empujar su burbuja con un transform, y aun así no se podía colocar contra la cápsula. */
.bottom-nav__badge {
    position: absolute;
    top: -2px;
    right: 8px;
    min-width: 18px;
    height: 18px;
    padding: 0 5px;
    box-sizing: border-box;
    border-radius: 999px;
    display: grid;
    place-items: center;
    background: var(--lc-err, var(--mud-palette-error));
    /* Sobre el relleno rojo pleno, el texto toma el color de la barra: legible en los dos temas
       sin declarar un blanco. */
    color: var(--ic-surface);
    font-size: 0.6875rem;
    font-weight: 700;
    line-height: 1;
    letter-spacing: 0;
}

/* ── Botón central (Calendario) ──
   Círculo elevado que sobresale de la barra. La etiqueta va FUERA del círculo pero DENTRO del
   botón: en el mock cuelga del envoltorio, y ahí dejaría de ser tocable. */
.bottom-nav__tab--centro {
    padding-top: 0;
    color: var(--ic-nav-accent);
    overflow: visible;
}

.bottom-nav__fab {
    width: 56px;
    height: 56px;
    margin-top: -22px;
    border-radius: 50%;
    display: grid;
    place-items: center;
    /* Color plano: sin degradado ni resplandor. Sobre la barra negra el halo se leía como un
       foco encendido. El aro del estado activo sí se conserva, plano (regla de abajo).
       --ic-primary es el mismo #5563E0 en los dos temas, y el blanco del icono da 6.1:1 encima. */
    background: var(--ic-primary);
    border: 3px solid var(--ic-bottom-nav-bg);
    transition: transform .15s ease;
}

.bottom-nav__fab .mud-icon-root {
    width: 26px;
    height: 26px;
    font-size: 26px;
    /* Blanco deliberado: va sobre el relleno de marca, que no cambia con el tema. */
    color: #FFFFFF;
}

.bottom-nav__tab--centro .bottom-nav__lb {
    margin-top: 2px;
    font-weight: 600;
}

.bottom-nav__tab--centro:active .bottom-nav__fab {
    transform: scale(.94);
}

/* El aro del tab activo: vuelve (2026-09-23) pero SIN el resplandor que lo acompañaba. Es un
   anillo plano de 4px, separado del círculo por el aro de 3px del color de la barra, así que se
   lee como un contorno y no como una luz. */
.bottom-nav__tab--centro.bottom-nav__tab--activo .bottom-nav__fab {
    box-shadow: 0 0 0 4px var(--ic-brand-ring);
}

@media (min-width: 600px) {
    /* Aquí la cápsula pasa a 72×36, el padding a 10/6 y la etiqueta a 12px. El tab más alto es
       el CENTRAL y mide 72 = 10 + 36 (FAB 62 − 26 de margen) + 4 de gap + 2 de margen + 14 de
       etiqueta + 6. Los 10 de arriba no deberían estar —la línea 1956 le pone padding-top:0 al
       tab central— pero el `padding: 10px 6px 6px` de este bloque tiene la MISMA especificidad
       (0,1,0) y va después en el archivo, así que se lo devuelve. Ese defecto de cascada es de
       antes y se deja anotado: arreglarlo bajaría la banda a 70 y mezcla dos decisiones.
       Este bloque agrandaba el tab SIN subir el token, así que la barra crecía por encima de la
       altura que anunciaba y los spacers se quedaban cortos.
       Y no es «sólo tablet»: un iPhone en horizontal mide 874px de ancho y cae aquí. */
    html[data-chrome="app"] {
        --ic-bottom-nav-content-height: 73px;
    }

    html[data-chrome="app"] .bottom-nav__tab {
        gap: 4px;
        padding: 10px 6px 6px;
        font-size: 0.75rem;
    }

    html[data-chrome="app"] .bottom-nav__cap {
        width: 72px;
        height: 36px;
        border-radius: 18px;
    }

    html[data-chrome="app"] .bottom-nav__fab {
        width: 62px;
        height: 62px;
        margin-top: -26px;
    }
}

/* AppBar: chrome unificado con el drawer — MISMA superficie (fondo, blur, línea).
   La banda mide 64px EXACTOS con el borde dentro, igual que .ic-drawer-toolbar: height +
   box-sizing (no basta min-height, que dejaba el borde a y=65 empujado por el .mud-toolbar)
   y box-shadow:none (el hairline pintaba una SEGUNDA línea a y=65→66 que el drawer nunca
   tuvo → escalón visible en la unión rail↔barra). La línea la dibuja solo el border-bottom. */
.mud-appbar.ic-appbar {
    background-color: var(--ic-appbar-bg) !important;
    backdrop-filter: var(--ic-chrome-blur) !important;
    -webkit-backdrop-filter: var(--ic-chrome-blur) !important;
    border-bottom: 1px solid var(--ic-appbar-border) !important;
    box-shadow: none !important;
    height: var(--ic-appbar-height) !important;
    min-height: var(--ic-appbar-height) !important;
    box-sizing: border-box !important;
    padding-left: 20px !important;
    padding-right: 12px !important;
}

/* Simetría con el drawer: en táctil el blur se apaga (anti-parpadeo en WebView Android).
   El appbar solo existe ≥1025px, pero tablets landscape con touch pueden alcanzarlo. */
@media (hover: none) and (pointer: coarse) {
    .mud-appbar.ic-appbar {
        backdrop-filter: none !important;
        -webkit-backdrop-filter: none !important;
        background-color: rgba(var(--ic-chrome-bg-rgb), 0.99) !important;
    }
}

/* Cluster derecho del AppBar: un único contenedor flex con gap parejo.
   Reemplaza los márgenes ad-hoc por-elemento (chip, campana) por un ritmo de 10px. */
.mud-appbar.ic-appbar .ic-appbar__spacer {
    flex: 1 1 auto;
}

.mud-appbar.ic-appbar .ic-appbar__cluster {
    display: flex;
    align-items: center;
    gap: 10px;
    overflow: visible;
}

/* Píldora del plan SaaS: la vía de upsell. Es un <a> real, no un chip con OnClick. */
.mud-appbar.ic-appbar .ic-plan {
    display: inline-flex;
    align-items: center;
    height: 28px;
    padding: 0 12px;
    border-radius: 999px;
    background: var(--ic-primary-dim);
    border: 1px solid var(--ic-nav-active-border);
    color: var(--ic-nav-accent);
    font-size: var(--ic-text-xs);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    text-decoration: none;
    white-space: nowrap;
}

.mud-appbar.ic-appbar .ic-plan:hover {
    background: var(--ic-nav-active-bg);
}

/* Botones del grupo derecho: 40×40, radio 10, wash del sistema al hover. */
.mud-appbar.ic-appbar .ic-iconbtn,
.mud-appbar.ic-appbar .ic-appbar__cluster .mud-icon-button {
    position: relative;
    display: inline-grid;
    place-items: center;
    width: 40px;
    height: 40px;
    min-width: 40px;
    padding: 0;
    border: 0;
    border-radius: 10px;
    background: transparent;
    color: var(--ic-icon-muted);
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}

.mud-appbar.ic-appbar .ic-iconbtn:hover,
.mud-appbar.ic-appbar .ic-appbar__cluster .mud-icon-button:hover {
    background: var(--ic-interactive-hover);
    color: var(--ic-text);
}

/* Activador del menú de usuario: mismo hueco que un botón de icono, con el avatar dentro. */
.mud-appbar.ic-appbar .ic-userbtn {
    display: inline-grid;
    place-items: center;
    width: 40px;
    height: 40px;
    border-radius: 10px;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}

.mud-appbar.ic-appbar .ic-userbtn:hover {
    background: var(--ic-interactive-hover);
}

.mud-appbar.ic-appbar .ic-userbtn:focus-visible {
    outline: none;
    box-shadow: inset 0 0 0 2px var(--ic-nav-accent-glow);
}

/* ── Menú del avatar (popover) ──
   Misma superficie que el resto del chrome: si fuese una tarjeta opaca se leería como otra cosa. */
.ic-usermenu-popover .mud-list.ic-usermenu,
.mud-popover.ic-usermenu-popover {
    background: var(--ic-chrome-bg);
    backdrop-filter: var(--ic-chrome-blur);
    -webkit-backdrop-filter: var(--ic-chrome-blur);
    border: 1px solid var(--ic-glass-border);
    border-radius: var(--ic-radius-md);
    box-shadow: var(--ic-chrome-shadow);
}

.ic-usermenu-popover .mud-list.ic-usermenu {
    min-width: 240px;
    padding: 8px;
}

.ic-usermenu-popover .ic-usermenu__head {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 8px 12px;
    min-width: 0;
}

.ic-usermenu-popover .ic-usermenu__id {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

.ic-usermenu-popover .ic-usermenu__nm {
    font-size: var(--ic-text-md);
    font-weight: 600;
    color: var(--ic-text);
    line-height: 1.2;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.ic-usermenu-popover .ic-usermenu__rl {
    font-size: var(--ic-text-xs);
    color: var(--ic-text-tertiary);
    line-height: 1.3;
}

.ic-usermenu-popover .mud-list-item {
    min-height: var(--ic-touch-min);
    border-radius: var(--ic-radius-sm);
    color: var(--ic-muted);
    font-size: var(--ic-text-md);
    font-weight: 500;
}

.ic-usermenu-popover .mud-list-item:hover {
    background: var(--ic-interactive-hover);
    color: var(--ic-text);
}

.ic-usermenu-popover .mud-list-item .mud-icon-root {
    color: var(--ic-icon-muted);
}

.ic-usermenu-popover .ic-usermenu__sep {
    margin: 4px 8px;
    border-color: var(--ic-glass-border-soft);
}

/* Destructivo: el mismo rojo que el botón de salir del pie del menú. */
.ic-usermenu-popover .ic-usermenu__salir,
.ic-usermenu-popover .ic-usermenu__salir .mud-icon-root {
    color: var(--lc-err, var(--mud-palette-error));
}

.ic-usermenu-popover .ic-usermenu__salir {
    font-weight: 600;
}

.ic-usermenu-popover .ic-usermenu__salir:hover {
    background: color-mix(in srgb, var(--lc-err, var(--mud-palette-error)) 12%, transparent);
    color: var(--lc-err, var(--mud-palette-error));
}
/* MudBlazor le da al .mud-toolbar un height propio (--mud-internal-toolbar-height: 64px a
   ≥600px) que un min-height NO anula: ese alto sumaba con el borde del appbar y lo dejaba en
   65px. Aquí se descuenta el borde para que la caja de contenido mida 63px, el mismo reparto
   que en el drawer (.ic-brand de 52px dentro de los 63px útiles de .ic-drawer-toolbar). */
.mud-appbar.ic-appbar .mud-toolbar {
    height: calc(var(--ic-appbar-height) - 1px) !important;
    min-height: 0 !important;
    padding-left: 0 !important;
    padding-right: 0 !important;
}

/*
 * MudBadge (Origin TopRight + Overlap) sitúa el contador hacia arriba del icono.
 * Si el AppBar o el toolbar tienen overflow:hidden (por defecto en algunos temas),
 * el círculo/pill rojo queda recortado en el borde superior.
 */
.mud-appbar.ic-appbar,
.mud-appbar.ic-appbar .mud-toolbar {
    overflow: visible !important;
}

/* Ocultar la barra superior en modo app (móvil y tablet: ver ic-chrome.js). */
html[data-chrome="app"] .mud-layout.ic-layout-mobile-no-appbar {
    --ic-appbar-height: 0px;
}

html[data-chrome="app"] .mud-layout.ic-layout-mobile-no-appbar .mud-appbar.ic-appbar {
    display: none !important;
}

/* El BottomNav solo se renderiza en modo app (móvil y tablet). En ese modo,
   cualquier elemento que necesite acomodar el nav (spacers, FABs, action bars, scroll
   containers con altura calculada) debe leer var(--ic-bottom-nav-height) y obtendrá
   la altura efectiva (contenido + la mordida del área segura).
   ESTE es el único env(safe-area-inset-bottom) del chrome inferior: el padding de la barra
   se deriva restando los dos tokens, así que no hay una segunda copia de la fórmula que se
   pueda editar a medias. Si alguien vuelve a escribir env() en el padding, el token miente
   en cuanto la mordida cambie y los ~25 consumidores quedan flotando sobre un hueco vacío.
   Mordida de 10pt sobre los 34 del iPhone → 24, por encima de los ~20pt que se lleva el
   gesto de inicio. En horizontal el inset es 21 → 11. Sin indicador de inicio → el suelo. */
html[data-chrome="app"] {
    /* Sin rail: el menú es un overlay temporal y el contenido llega al borde. */
    --ic-chrome-rail-w: 0px;
    --ic-bottom-nav-height: calc(var(--ic-bottom-nav-content-height)
                                 + max(var(--ic-safe-pad-floor),
                                       calc(var(--ic-safe-bottom) - var(--ic-nav-safe-bite))));
}

/* Helper genérico: cualquier FAB o botón flotante que deba quedar justo encima del nav.
   En desktop el nav está oculto → la variable es 0px → el FAB se ancla a la base + offset. */
.ic-fab-above-nav {
    bottom: calc(var(--ic-bottom-nav-height) + var(--ic-fab-bottom-offset)) !important;
}

/* Campana + badge: toolbar móvil + safe area; el pill no debe quedar fuera del viewport a la derecha */
@media (max-width: 959px) {
    .mud-appbar.ic-appbar {
        padding-right: max(18px, calc(14px + env(safe-area-inset-right, 0px))) !important;
    }

    .mud-appbar.ic-appbar .ic-header-notif-menu {
        flex: 0 0 auto !important;
        width: auto !important;
        max-width: max-content !important;
        align-self: center;
        margin-right: 2px;
    }

    .mud-appbar.ic-appbar .ic-header-notif-menu .mud-menu-activator {
        display: inline-flex !important;
        width: auto !important;
        flex: 0 0 auto !important;
    }

    .mud-appbar.ic-appbar .ic-header-notif-menu .mud-badge-root {
        width: fit-content !important;
        max-width: 44px !important;
        display: inline-block !important;
    }

    /* Refuerzo global (BadgeClass en el componente): translate además del padding */
    .mud-appbar.ic-appbar .ic-header-notif-menu .mud-badge.ic-notif-appbar-badge {
        transform: translate3d(-10px, 5px, 0) !important;
    }
}

.mud-appbar.ic-appbar .ic-appbar__title {
    font-weight: 600 !important;
    font-size: var(--ic-text-base) !important;
    letter-spacing: -0.01em !important;
    color: var(--ic-text) !important;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: min(340px, 36vw);
    line-height: 1.3 !important;
}

@media (max-width: 599px) {
    .mud-appbar.ic-appbar .ic-appbar__title {
        max-width: 120px;
        font-size: 0.875rem !important;
    }
}

/* Contenido principal: fondo continuo (evita destellos al hacer scroll) */
.mud-main-content.ic-main {
    background-color: var(--ic-bg) !important;
    /*
      Offset superior estable: compensa AppBar fijo sin generar saltos.
    */
    margin-top: 0 !important;
    /* +12px: “aire” consistente debajo del AppBar (evita que el título quede pegado). */
    padding-top: calc(var(--ic-appbar-height) + env(safe-area-inset-top, 0px) + 12px) !important;
    box-sizing: border-box;
    /* Las barras a sangre (PageHeader Detail, .re-sticky-confirm) usan 100vw, que
       incluye el ancho de la scrollbar: en un navegador de escritorio estrechado
       eso asomaría medio scrollbar por cada lado. `clip` lo recorta SIN crear
       contenedor de scroll, así que —a diferencia de `hidden`— no rompe el
       position:sticky de esas mismas barras. */
    overflow-x: clip;
}

/* Latido de los esqueletos de carga. Vive aquí y no en la hoja de cada página
   porque lo usan varias —/rentas/{id}, /registrar-entrega, /productos/{id}— y
   además desde estilos en línea, que no cargan ninguna hoja de página. */
@keyframes ic-pulse {
    0%, 100% { opacity: 1; }
    50%      { opacity: .55; }
}

/* Canalón compartido de las pantallas de detalle. Se pone en el MudContainer de
   la página y sustituye al gutter por defecto de MudBlazor (16px), que dejaba
   /registrar-entrega y /productos/{id} 4px más estrechas por lado que
   /rentas/{id} — lo bastante para notarse al saltar de una a otra.
   El !important es para ganarle a las utilidades de gutter de MudBlazor, que
   vienen con la suya en el propio .mud-container. */
.ic-page-gutter {
    padding-left: var(--ic-page-gutter) !important;
    padding-right: var(--ic-page-gutter) !important;
}

/* ─────────────── Contrato de página ───────────────
   Este nodo (el MudContainer del layout) es el ÚNICO que decide el canalón
   lateral y el ancho del contenido. Los valores salen de --ic-page-pad-x /
   --ic-content-max (:root, arriba); aquí sólo se consumen.

   Los !important le ganan a .mud-container--gutters y .mud-container-maxwidth-*,
   que MudBlazor pone en ESTE MISMO nodo: sin ellos la hoja de terceros y la
   nuestra empatan en especificidad y decide el orden de carga, que no
   controlamos. El layout además pide Gutters="false" y MaxWidth.False, así que
   en el caso normal MudBlazor ya no emite ninguna de las dos clases.

   max() con la safe-area: en horizontal (teléfono acostado) el notch se come
   el canalón; el max lo respeta sin encoger el caso vertical. */
.ic-content-wrap:not(.ic-content-wrap--calendario-bleed):not(.ic-content-wrap--immersive-bleed) {
    /* El offset vertical principal ya lo aplica .mud-main-content.ic-main (app.css). */
    padding-top: 0.5rem !important;
    padding-bottom: 1rem !important;
    padding-left:  max(var(--ic-page-pad-x), env(safe-area-inset-left, 0px)) !important;
    padding-right: max(var(--ic-page-pad-x), env(safe-area-inset-right, 0px)) !important;
    max-width: var(--ic-content-max) !important;
}

@media (max-width: 599px) {
    .ic-content-wrap:not(.ic-content-wrap--calendario-bleed):not(.ic-content-wrap--immersive-bleed) {
        padding-top: 0.75rem !important;
        padding-bottom: 0.75rem !important;
    }
}

/* Los modos NO redeclaran max-width ni padding: redefinen el TOKEN en el propio
   nodo, y la regla de arriba lo resuelve. Es a propósito. La regla base lleva dos
   :not() para no pisar los bleeds, y cada :not() suma la especificidad de su
   argumento: son (0,3,0) contra los (0,2,0) de un `.mud-container.ic-content-wrap--x`,
   así que un modo que declarase `max-width` PERDERÍA — pasó, y el síntoma es que
   /finanzas medía 1600 en vez de 1100. Una custom property no compite por
   especificidad con la propiedad que la consume: se resuelve en el elemento donde
   se declara, y aquí siempre gana a la de :root. */

/* ANGOSTO: lectura y formularios (Finanzas, Centro de lavado, Configuración…).
   Sustituye a los max-width a mano que cada hoja llevaba —1100px en .fin-resumen,
   760px en .cl-page—, que es de donde venía que dos pantallas hermanas no calzaran. */
.ic-content-wrap--angosto {
    --ic-content-max: var(--ic-content-max-angosto);
}

/* DENSO: parrillas de tarjetas (/productos y compañía). Sin tope, porque la
   rejilla ya reparte por columnas; y en teléfono el canalón mínimo, donde con dos
   columnas cada 8px recuperados son 4px por tarjeta. */
.ic-content-wrap--denso {
    --ic-content-max: none;
}

@media (max-width: 599px) {
    .ic-content-wrap--denso { --ic-page-pad-x: var(--ic-space-2); }
}

/* DETALLE (/rentas/{id}, /registrar-entrega/{id}, /productos/{id},
   /asignar-renta/{id}): la página pone su propio canalón con .ic-page-gutter
   —12px, el mismo que su encabezado a sangre desborda— y quiere el ancho completo
   para no encogerse respecto al listado del que se abre. */
.ic-content-wrap--detalle {
    --ic-content-max: none;
    --ic-page-pad-x: 0px;
}

/* Encabezado plano (PageHeader --plano, hoy sólo /rentas/{id}): sin el gutter
   extra. Los +12px son "aire" para que un título no quede pegado al AppBar, pero
   ese encabezado va a sangre y pegado por diseño: ahí el aire se lee como una
   franja vacía sobre la barra. Mismo criterio que --calendario e --immersive. */
.mud-main-content.ic-main:has(.ic-ph--plano) {
    padding-top: calc(var(--ic-appbar-height) + env(safe-area-inset-top, 0px)) !important;
}

/* Calendario: no usar el gutter extra (evita la franja vacía). */
.mud-main-content.ic-main.ic-main--calendario {
    /* El calendario gestiona su alto internamente; aquí solo reservamos el AppBar (sin +12px extra). */
    padding-top: calc(var(--ic-appbar-height) + env(safe-area-inset-top, 0px)) !important;
    /*
      En /calendario el scroll vertical debe vivir DENTRO del calendario (vistas),
      no en la página, para que:
      - menú + filtros queden fijos arriba
      - barra de selección múltiple quede fija abajo
      - vista mes se estire al alto visible
    */
    height: 100vh;
    height: 100dvh;
    overflow: hidden !important;
    min-height: 0;
    /* Clave: acotar altura a hijos para permitir scroll interno */
    display: flex;
    flex-direction: column;
}

/* Páginas inmersivas (notificaciones, rentas, asignaciones, etc.): cabecera fija, scroll en el cuerpo. */
.mud-main-content.ic-main.ic-main--immersive {
    padding-top: calc(var(--ic-appbar-height) + env(safe-area-inset-top, 0px)) !important;
    height: 100vh;
    height: 100dvh;
    overflow: hidden !important;
    min-height: 0;
    display: flex;
    flex-direction: column;
}

@media (max-width: 599px) {
    .mud-main-content.ic-main {
        margin-top: 0 !important;
        padding-top: calc(var(--ic-appbar-height) + env(safe-area-inset-top, 0px) + 12px) !important;
    }

    /* Repetido dentro del media query a propósito: la regla de arriba vuelve a
       imponer los +12px con !important y, a igual especificidad, gana la última.
       Sin esto el hueco sobre el encabezado plano sólo desaparecía en escritorio.

       Aquí vale para CUALQUIER variante Detail, no sólo la plana: por debajo de
       960px el componente lleva su barra a 100vw (PageHeader.razor.css), así que
       en móvil todas van a sangre y el "aire" se lee como una franja vacía sobre
       el chrome. En escritorio no aplica: allí el encabezado vuelve a ser tarjeta
       flotante y sin ese hueco tocaría el AppBar mientras no haya scroll. */
    .mud-main-content.ic-main:has(.ic-ph--detail) {
        padding-top: calc(var(--ic-appbar-height) + env(safe-area-inset-top, 0px)) !important;
    }

    .mud-main-content.ic-main.ic-main--calendario {
        padding-top: calc(var(--ic-appbar-height) + env(safe-area-inset-top, 0px)) !important;
        height: 100vh;
        height: 100dvh;
        overflow: hidden !important;
        min-height: 0;
        display: flex;
        flex-direction: column;
    }

    .mud-main-content.ic-main.ic-main--immersive {
        padding-top: calc(var(--ic-appbar-height) + env(safe-area-inset-top, 0px)) !important;
        height: 100vh;
        height: 100dvh;
        overflow: hidden !important;
        min-height: 0;
        display: flex;
        flex-direction: column;
    }
}

/* /calendario: el wrapper del contenido debe poder estirarse */
.mud-main-content.ic-main.ic-main--calendario > .mud-container.ic-content-wrap--calendario-bleed {
    flex: 1 1 0%;
    min-height: 0;
    display: flex;
    flex-direction: column;
}

.mud-main-content.ic-main.ic-main--immersive > .mud-container.ic-content-wrap--immersive-bleed {
    flex: 1 1 0%;
    min-height: 0;
    display: flex;
    flex-direction: column;
}

/* Shell reutilizable: columna con cabecera fija y cuerpo con scroll (páginas inmersivas). */
.ic-viewport-page {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-height: 0;
    height: 100%;
    max-height: 100%;
    overflow: hidden;
    box-sizing: border-box;
    /* Mismo canalón que el resto del panel. El bleed de estas páginas es
       VERTICAL —100dvh, cabecera fija y scroll en el cuerpo—; en horizontal no
       había razón para que /rentas respirara 8px y /finanzas 24. Si el cambio
       no convence, revertir es volver estas dos líneas a 0.5rem: nada más
       depende de ellas. */
    padding-left:  max(var(--ic-page-pad-x), env(safe-area-inset-left, 0px));
    padding-right: max(var(--ic-page-pad-x), env(safe-area-inset-right, 0px));
}

.ic-viewport-page__header {
    flex-shrink: 0;
}

.ic-viewport-page__body {
    flex: 1 1 0%;
    min-width: 0;
    min-height: 0;
    overflow-y: auto;
    overflow-x: hidden;
    -webkit-overflow-scrolling: touch;
    padding-bottom: max(12px, env(safe-area-inset-bottom, 0px));
}

/* Sesión no iniciada: main ocupa el viewport completo para login/registro/selección de negocio */
.mud-main-content.ic-main-public {
    min-height: 100vh;
    min-height: 100dvh;
    display: flex;
    flex-direction: column;
    padding: 0 !important;
    margin: 0 !important;
    box-sizing: border-box;
}

.mud-layout {
    background-color: var(--ic-bg);
}

/* MudCard nace con Elevation="1" y arrastra una sombra Material de tres capas que no
   está escrita en ningún CSS del repo: las tarjetas que el diseño quiere planas la
   llevaban igual, y por eso un mock de tarjeta plana nunca calzaba. Que la app la
   quiere apagada ya estaba dicho a gritos —25 de los 28 MudCard del proyecto pasan
   Elevation="0" a mano—; esto lo vuelve el comportamiento por defecto en vez de una
   sorpresa invisible. Las elevaciones 2+ siguen intactas para quien las pida aposta. */
.mud-card.mud-elevation-1 {
    box-shadow: none;
}

/* ── Spacer del bottom nav en móvil para no tapar contenido ──
   Antes era height:72px fijo, lo que en iPhones con notch dejaba el último contenido
   parcialmente tapado por la home indicator. Ahora usa var(--ic-bottom-nav-height)
   que incluye el safe-area-inset-bottom automáticamente. */
.bottom-nav-spacer {
    display: none;
}
html[data-chrome="app"] .bottom-nav-spacer {
    display: block;
    height: var(--ic-bottom-nav-height);
}

/* /calendario y páginas inmersivas: sin spacer — el panel ya resta bottom nav en su alto */
html[data-chrome="app"] .bottom-nav-spacer.bottom-nav-spacer--calendario {
    display: none !important;
    height: 0 !important;
    min-height: 0 !important;
}

/* ── Enlace base ── */
a, .btn-link {
    color: var(--ic-primary);
}

/* ── Utilidades de scroll ── */
.scroll-x {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
}
.scroll-x::-webkit-scrollbar { display: none; }

/* ── Chip de estado: asegurar contraste en dark ── */
.mud-chip.mud-chip-color-default.mud-chip-selected {
    background-color: var(--estado-agendada) !important;
    color: white !important;
}
.mud-chip.mud-chip-color-primary.mud-chip-selected {
    background-color: var(--estado-asignado) !important;
    color: white !important;
}
.mud-chip.mud-chip-color-warning.mud-chip-selected {
    background-color: var(--estado-en-curso-entrega) !important;
    color: white !important;
}
.mud-chip.mud-chip-color-success.mud-chip-selected {
    background-color: var(--estado-entregada) !important;
    color: white !important;
}
.mud-chip.mud-chip-color-secondary.mud-chip-selected {
    background-color: var(--estado-recogida) !important;
    color: white !important;
}
.mud-chip.mud-chip-color-error.mud-chip-selected {
    background-color: var(--estado-cancelada) !important;
    color: white !important;
}

/* ── Filtro scroll horizontal (chips de estado) ── */
.filters-scroll-container {
    display: flex;
    flex-direction: row;
    align-items: center;
    overflow-x: auto;
    overflow-y: hidden;
    white-space: nowrap;
    padding-bottom: 4px;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    min-width: 0;
}
.filters-scroll-container::-webkit-scrollbar { display: none; }

/*
 * Mud 7.14+: .mud-chip-container { display: contents } — los chips participan en el layout de .mud-chipset.
 * Sin fila explícita el chipset puede apilar en columna (p. ej. móvil). Forzar fila + nowrap para scroll horizontal.
 */
.filters-scroll-container .mud-chipset {
    display: flex !important;
    flex-direction: row !important;
    flex-wrap: nowrap !important;
    align-items: center;
    width: max-content;
    min-width: min-content;
}

/* Calendario: barra de subcabecera — misma fila aunque Mud aplique columna en otra regla */
.calendar-sub-header .filters-scroll-container {
    display: flex !important;
    flex-direction: row !important;
    align-items: center !important;
    overflow-x: auto;
    overflow-y: hidden;
    min-width: 0;
}

.calendar-sub-header .filters-scroll-container .mud-chipset {
    display: flex !important;
    flex-direction: row !important;
    flex-wrap: nowrap !important;
    align-items: center !important;
    width: max-content !important;
    min-width: min-content !important;
}

/* ── Calendario: vistas ocupan el panel flexible (scroll interno, no página) ── */
.ic-cal-vista-root {
    flex: 1 1 0%;
    min-height: 0;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    height: 100%;
}

.ic-cal-vista-empty {
    flex: 1 1 0%;
    min-height: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-align: center;
    padding-top: clamp(1.75rem, 8vh, 3.25rem) !important;
    padding-bottom: clamp(2rem, 10vh, 4rem) !important;
    padding-left: max(1.25rem, env(safe-area-inset-left, 0px)) !important;
    padding-right: max(1.25rem, env(safe-area-inset-right, 0px)) !important;
    background: transparent;
    border: none !important;
    box-shadow: none !important;
}

.ic-cal-empty-visual {
    width: 4.25rem;
    height: 4.25rem;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    margin-bottom: 1.125rem;
    flex-shrink: 0;
    background: var(--ic-cal-empty-bg);
    border: 1px solid var(--ic-cal-empty-border);
    box-shadow: var(--ic-cal-empty-shadow);
}

.ic-cal-empty-visual .mud-icon-root {
    font-size: 1.625rem !important;
    color: var(--ic-cal-empty-icon) !important;
}

.ic-cal-vista-empty .ic-cal-empty-title,
.ic-cal-vista-empty .mud-typography-h6 {
    font-weight: 600 !important;
    letter-spacing: -0.02em;
    line-height: 1.4 !important;
    max-width: 18rem;
    margin: 0 auto !important;
    color: var(--ic-muted) !important;
}

/* Separación suave entre filtros y el cuerpo del calendario */
.calendario-layout-root .ic-cal-vista-root,
.calendario-layout-modal-host .ic-cal-vista-root {
    border-top: 1px solid var(--ic-border);
}

/* ── Calendario: un solo tono de fondo, el mismo del chrome ────────────────────
   El calendario tenía TRES tonos a la vez: el lienzo (--ic-bg: #F4F6FB claro / #101A1E
   oscuro), los paneles de semana/3 días/agenda (--ic-cal-panel-bg) y, al lado, un drawer
   pintado con --ic-chrome-bg. En claro eso se leía como un gris azulado pegado a un menú
   blanco. Aquí se redefine el token SOBRE el contenedor del calendario: como las custom
   properties se resuelven en el elemento, la regla `.mud-main-content.ic-main` de arriba y
   los ~15 selectores de las hojas de LazyPages que consumen var(--ic-bg) toman el nuevo
   valor sin tocar ni una de sus declaraciones. Incluido el recorte del contador de filtros
   (`inset 0 0 0 2px var(--ic-bg)` en calendario-nuevo.css), que así sigue casando solo.

   Se usa la BASE OPACA del chrome (rgb(var(--ic-chrome-bg-rgb))) y no --ic-chrome-bg, que
   es rgba(...,.92) + blur: el drawer es translúcido porque flota sobre el contenido; un
   lienzo translúcido dejaría ver lo que pasa por debajo al hacer scroll. Al derivar del
   token, voltea solo con data-theme y cubre los dos temas (blanco / #0C1418).

   Ámbito deliberadamente local: --ic-bg es el lienzo de las 125+ páginas del panel, y
   volverlo blanco en :root dejaría sin contraste a las tarjetas .lc-* de todo el producto.
   Los diálogos y menús de MudBlazor viven en el popover provider, a nivel de <body>, fuera
   de estos contenedores: NO heredan el override y conservan su fondo propio. */
.ic-main--calendario,
.calendario-layout-root,
.calendario-layout-modal-host {
    --ic-bg:           rgb(var(--ic-chrome-bg-rgb));
    --ic-bg-rgb:       var(--ic-chrome-bg-rgb);
    --ic-cal-panel-bg: rgb(var(--ic-chrome-bg-rgb));
}

/* Panel de contenido (semana / 3 días): superficie ligeramente elevada, sin bordes redondeados tipo tarjeta flotante */
.calendario-layout-root .week-container,
.calendario-layout-root .three-day-container,
.calendario-layout-modal-host .week-container,
.calendario-layout-modal-host .three-day-container {
    background-color: var(--ic-cal-panel-bg) !important;
    background-image: linear-gradient(180deg, var(--ic-cal-panel-shine) 0%, transparent 36%);
    box-shadow: inset 0 1px 0 0 rgba(255, 255, 255, 0.05) !important;
    border: none !important;
}

/* Vista día: el timeline comparte tono con la franja de días de arriba (--ic-bg), sin
   brillo ni inset que marquen un escalón — un solo bloque continuo bajo las tarjetas. */
.calendario-layout-root .timeline-container,
.calendario-layout-modal-host .timeline-container {
    background-color: var(--ic-bg) !important;
    background-image: none;
    box-shadow: none !important;
    border: none !important;
}

.calendario-layout-root .agenda-container,
.calendario-layout-modal-host .agenda-container {
    flex: 1 1 0%;
    min-height: 0;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    background-color: var(--ic-cal-panel-bg);
    background-image: linear-gradient(180deg, var(--ic-cal-panel-shine) 0%, transparent 36%);
    box-shadow: inset 0 1px 0 0 rgba(255, 255, 255, 0.05);
}

/* Tarjetas de evento en timeline. Rediseño 2026-08: la separación la dan el borde
   izquierdo de 4px del color del estado y el tinte al 8%; NO hay borde perimetral.

   Aquí antes vivía `border: 1px solid var(--ic-glass-border) !important`, y ese
   !important pisaba el `border-left: 4px solid <color>` que VistaDia mandaba por style
   inline (en la cascada, un !important de autor gana a una declaración inline normal).
   Resultado medido: el borde de color NUNCA se pintó; la tarjeta se distinguía solo por
   el tinte. Por eso el borde se declara ahora en la hoja de cada vista, sin !important,
   y este bloque se queda únicamente con lo que sigue siendo suyo.

   `box-shadow` deja de ser !important a propósito: el anillo de urgente y el halo del
   modo selección de ruta son box-shadow y no podían ganarle. */
.calendario-layout-root .event-card,
.calendario-layout-modal-host .event-card {
    border-radius: var(--cal-card-radius) !important;
    box-shadow: none;
    transition: transform 0.15s ease, box-shadow 0.18s ease;
}

.calendario-layout-root .event-card:hover,
.calendario-layout-modal-host .event-card:hover {
    /* Lift suave al pasar el cursor (solo escritorio). Token theme-aware: en claro es una
       sombra tenue (rgba 15,23,42,.10), no el negro duro que se veía pesado. */
    box-shadow: var(--ic-shadow, 0 4px 20px rgba(0, 0, 0, 0.45));
}

/* La densidad de la vista día (padding y gap por clase dia-cal-density-*) vivía aquí con
   seis reglas !important porque había que neutralizar el padding de MudCardContent y el
   gap de MudStack. La tarjeta ya no usa componentes Mud: es div + clases propias, y la
   densidad se resuelve en calendario-dia.css sin un solo !important. */

@media (max-width: 599px) {
    .ic-cal-empty-visual {
        width: 3.75rem;
        height: 3.75rem;
    }
    .ic-cal-empty-visual .mud-icon-root {
        font-size: 1.5rem !important;
    }
}

/* ── Blazor error UI ── */
#blazor-error-ui {
    background: var(--ic-surface);
    border-top: 1px solid var(--ic-border);
    bottom: 0;
    display: none !important;
    left: 0;
    padding: 0.6rem 1.25rem 0.7rem 1.25rem;
    position: fixed;
    width: 100%;
    z-index: 9999;
    color: var(--ic-text);
}
#blazor-error-ui .dismiss {
    cursor: pointer;
    position: absolute;
    right: 0.75rem;
    top: 0.5rem;
}

.blazor-error-boundary {
    background: #2d1515;
    padding: 1rem 1rem 1rem 3.7rem;
    color: #fca5a5;
    border-radius: var(--ic-radius-md);
}
.blazor-error-boundary::after {
    content: "Ha ocurrido un error.";
}

/*
 * Popover de MudMenu = 1200 por defecto, igual que .bottom-nav (1200).
 * En móvil el nav queda encima en el orden del DOM y roba los toques.
 * Refuerzo con variable CSS por si el tema tarda en aplicarse (WASM).
 */
:root {
    --mud-zindex-popover: 1250;
}

/*
 * /mapa: Leaflet usa paneles internos altos (p. ej. controles ~1000) y compositing en WebKit;
 * el popover del menú de vista puede quedar debajo y los toques van al mapa (en /calendario no pasa).
 */
.mud-popover-provider .ic-mapa-vista-mudmenu-popover,
.ic-mapa-vista-mudmenu-popover {
    z-index: 5000 !important;
}

/* Resaltar renta al volver del detalle (scrollToCalendarioRenta) */
.cal-renta-highlight {
    outline: 2px solid var(--lc-accent);
    outline-offset: 3px;
    border-radius: 10px;
    transition: outline 0.15s ease;
}

/* ══════════════════════════════════════════════════════════
   Sistema de diseño mobile-first — DetalleRenta / Checklist
   ═════════════════════════════════════════════════════════ */

:root {
    --dr-action-bar-h:  68px;
    /* Alto reservado bajo el scroll en PC (padding barra + botón ~48px + bordes) */
    --dr-action-bar-spacer-desktop: 88px;
    /* Alias histórico del token del contrato. Lo consumen renta-form.css y
       .dr-touch-target; se mantiene para no tocar a sus consumidores. */
    --dr-touch-min:     var(--ic-touch-min);
    /* Alias histórico: hereda la altura efectiva del BottomNav definida arriba en :root
       (incluye safe-area en mobile, 0 en desktop). Mantiene compatibilidad con renta-form.css
       y demás consumidores existentes sin tener que sustituirlos a mano. */
    --dr-bn-h:          var(--ic-bottom-nav-height);
    /* Aquí vivía --dr-thumb-bottom, que sumaba env(safe-area-inset-bottom) a --dr-bn-h (donde ya
       venía incluido) y no tenía NI UN consumidor en todo el repo. Borrado en vez de corregido. */
}

/* ── Touch targets ── */
.dr-touch-target {
    min-width:  var(--dr-touch-min) !important;
    min-height: var(--dr-touch-min) !important;
}

/* ── Barra de acciones sticky (encima del BottomNav) ── */
.dr-action-bar {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    /* 8 + 52 + 8 = 68px de alto real, la medida del mock (.dr-actions). */
    padding: var(--ic-space-2) var(--ic-space-3) max(var(--ic-space-2), env(safe-area-inset-bottom, 8px));
    background: rgba(var(--ic-bg-rgb), 0.97);
    backdrop-filter: blur(12px);
    -webkit-backdrop-filter: blur(12px);
    border-top: 1px solid var(--ic-border, rgba(148,163,184,0.12));
    /* Por encima del bottom-nav (z-index 1200) para que los CTAs sean pulsables en móvil */
    z-index: 1280;
    /* Columna: arriba la franja de equipo (opcional), abajo la fila de botones. */
    display: flex;
    flex-direction: column;
    gap: 8px;
    box-sizing: border-box;
}

/* La fila de botones conserva el layout que la barra tenía antes, así que
   .dr-action-bar__btn { flex:1 } y --main { flex:2 } siguen valiendo sin cambios. */
.dr-action-bar__row {
    display: flex;
    gap: var(--ic-space-2);
    width: 100%;
}

/* ── Franja de equipo dentro de la barra ── */
.dr-action-bar__crew {
    display: flex;
    align-items: center;
    gap: var(--ic-space-2);
    width: 100%;
    min-height: var(--dr-crew-strip-h, 50px);
    padding-bottom: var(--ic-space-2);
    border-bottom: 1px solid var(--ic-border);
    box-sizing: border-box;
}

/* SVG en línea (ver comentario en el .razor): tamaño real, no métrica de icon-font. */
.dr-action-bar__crew-icon {
    width: 17px;
    height: 17px;
    fill: var(--lc-accent);
    flex-shrink: 0;
    display: block;
}

.dr-action-bar__crew-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--lc-ok);
    flex-shrink: 0;
}

.dr-action-bar__crew-info {
    display: flex;
    flex-direction: column;
    gap: 1px;
    flex: 1;
    min-width: 0;
}

/* Una sola línea con elipsis en las dos: hace la altura de la franja
   determinista, que es de lo que depende la reserva del spacer. */
.dr-action-bar__crew-names {
    font-size: var(--ic-text-sm);
    font-weight: 700;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.dr-action-bar__crew-sub {
    font-size: var(--ic-text-xs);
    color: var(--ic-text-tertiary);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.dr-action-bar__crew-sub--ruta {
    color: var(--lc-ok);
    font-weight: 600;
}

/* Igual que el botón "Ir" de la franja del encabezado: se pinta a 36px y el
   hit-slop lo lleva a área tappable de 48px sin engordar la barra.
   El radio, el tamaño y el peso los pone .dr-btn--sm; los !important que había
   aquí existían para ganarle a MudButton, y desde que la barra usa botones
   propios sólo servían para desviarla del mock (radio 10 y 12.5px). */
.dr-action-bar__crew-btn {
    flex-shrink: 0;
    position: relative;
}

.dr-action-bar__crew-btn::after {
    content: "";
    position: absolute;
    inset: -6px;
}

html[data-chrome="app"] .dr-action-bar {
    /* Cuando esta barra existe, la nav inferior se oculta (regla :has más abajo),
       así que el CTA baja a ras del fondo (zona del pulgar, sin choque con el FAB). */
    bottom: 0;
}

/* PC: barra solo sobre el contenido; rail mini 72px o drawer expandido 280px (clase en MudLayout).
   El left sale de --ic-chrome-rail-w, que vale 0 en modo app: por eso este bloque sigue siendo
   una media query de ancho y aun así es correcto en un tablet de 1180px. */
@media (min-width: 960px) {
    .dr-action-bar {
        left: var(--ic-chrome-rail-w, 72px);
        right: 0;
        bottom: 0;
        z-index: 1235;
        transition: left 0.2s ease;
    }

}

/* ── Modo tarea inmersiva (campo) ──────────────────────────────────
   Al mostrarse una barra de acciones fija —DetalleRenta (.dr-action-bar,
   solo cuando hay un CTA real: iniciar/registrar entrega·recolección, asignar,
   reagendar) o el cierre de RegistrarEntrega (.re-sticky-confirm)— se OCULTA la
   nav inferior. Da foco a la tarea "en el momento" y evita que el botón central
   elevado (Calendario) tape el CTA. La salida sigue siendo el "volver" fijo del
   PageHeader arriba. El resto de DetalleRenta (sin CTA) conserva la nav normal.
   Mismo criterio para los formularios de renta (.edit-renta-bottombar, que usan
   tanto "Nueva renta" como "Modificar renta"): su barra ya vive en bottom:0 por
   encima de la nav, así que dejarlas apiladas duplicaba barras y comía pantalla.
   El panel ya usa :has() en varios lugares (soporte OK, incl. WebView MAUI).

   Aplica a TODAS las formas de la barra, incluida la informativa (--info): en
   esta pantalla el pie es el pie, y dos barras apiladas se comen el alto —que es
   lo escaso en móvil— además de dejar dos filas de controles compitiendo. La
   salida sigue siendo el «volver» fijo del encabezado, que es sticky.

   El cuarto marcador es la FICHA DEL PIN del mapa (`.mapa2-ficha-host`), y entra
   aquí por lo mismo: desde que se toca un pin la ficha ES la tarea, y la nav de
   abajo sólo sería una fila de botones sobre una hoja que ya no habla de ellos.
   Es el comportamiento de Google Maps en el móvil. La salida es su propia X, que
   vive en la cabecera y nunca se recorta.

   No hace falta marcador de altura: ese nodo SÓLO está en el DOM mientras la
   ficha está abierta, así que su presencia ya es la señal. Y no hace falta acotar
   por ancho: esta barra sólo existe por debajo de 1024px. La fila del calendario
   sí necesita acotarse, y por eso su regla vive en `calendario-nuevo.css`.

   Se esconde y NO se tapa con z-index a propósito: la fila del calendario (1100)
   y esta barra (1200) van por encima de la ficha (1040), y taparlas fue un bug
   de producción que dejó al usuario sin salida del mapa.

   OJO al usar este patrón: `display:none` NO pone `--ic-bottom-nav-height` a
   cero. Lo que cuelgue de ese token seguirá flotando sobre el hueco vacío, y por
   eso la ficha se ancla con `--mapa2-ficha-suelo` propio (ver `mapa.css`). */
.mud-layout:has(.dr-action-bar) .bottom-nav,
.mud-layout:has(.re-sticky-confirm) .bottom-nav,
.mud-layout:has(.edit-renta-bottombar) .bottom-nav,
.mud-layout:has(.mapa2-ficha-host) .bottom-nav {
    display: none !important;
}

.mud-layout:has(.dr-action-bar) .bottom-nav-spacer,
.mud-layout:has(.re-sticky-confirm) .bottom-nav-spacer,
.mud-layout:has(.edit-renta-bottombar) .bottom-nav-spacer,
.mud-layout:has(.mapa2-ficha-host) .bottom-nav-spacer {
    display: none !important;
    height: 0 !important;
    min-height: 0 !important;
}

/* .dr-action-bar__btn y --main vivían aquí para domar a MudButton dentro de la
   barra. Desde que la barra usa botones .dr-btn propios, su medida la pone
   detalle-renta.css (.dr-action-bar__row .dr-btn) y estas reglas se quedaron sin
   markup que las llevara. Se retiran para que no vuelvan a pelearse con ella. */

/* Etiquetas largas por defecto; en pantallas muy estrechas se muestran las cortas (barra fija DetalleRenta). */
.dr-action-bar__label-short {
    display: none;
}

@media (max-width: 599.98px) {
    .dr-action-bar__label-long {
        display: none !important;
    }

    .dr-action-bar__label-short {
        display: inline !important;
    }

    .dr-action-bar__btn {
        font-size: 0.8125rem !important;
        padding-left: 10px !important;
        padding-right: 10px !important;
    }

    .dr-action-bar__btn .mud-button-icon-start {
        margin-inline-end: 4px !important;
    }
}

/* El #id y el nombre del cliente van en UNA fila, alineados por línea base, como
   en el diseño. PageHeader los apila en columna por defecto; el override vive aquí
   y no en PageHeader.razor.css porque ese archivo es scoped y esto es propio de
   esta pantalla. app.css se carga después del bundle scoped, así que gana. */
.dr-page-container .ic-ph__center {
    flex-direction: row;
    align-items: baseline;
    gap: 7px;
}

.dr-page-container .ic-ph__id-inline {
    flex-shrink: 0;
    font-size: 0.8125rem;
    font-weight: 700;
}

/* Micro-etiqueta de sección DENTRO de una tarjeta (p. ej. "Datos generales").
   Distinta del título de tarjeta (.dr-section-label), que va en caja normal:
   el diseño usa versalitas solo para las etiquetas auxiliares. */
.dr-microlabel {
    display: block;
    font-size: 0.7rem;
    font-weight: 800;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--ic-muted, #94A3B8);
    margin: 0;
}

/* Fila del encabezado a 56px, la medida del mock: el botón de volver mide 48 y
   el padding lo completa. El override va sobre .dr-page-container y no sobre
   :root porque el token --ic-page-header-padding-y lo comparten el resto de
   pantallas Detail (/productos/{id}, /ventas/{id}, /solicitudes/{id}), que no
   cambian. El resto del canalón de esta página vive en detalle-renta.css. */
.dr-page-container {
    --ic-page-header-padding-y: 4px;
}

/* ── Franja de campo bajo el encabezado ──
   Se mudó a wwwroot/css/detalle-renta.css como .dr-strip*, con el nombre que
   usa el mock, para que el banco de /_bench compare las mismas clases que
   corre la app. Su único consumidor era DetalleRenta.razor. */

.dr-ir-btn {
    flex-shrink: 0;
    border-radius: 11px !important;
    font-weight: 700 !important;
    padding-inline: 13px !important;
}

/* ── Los dos hitos, lado a lado ──
   .dr-summary-row es una rejilla "ranura de icono + celda"; esta fila no lleva icono
   (los dos hitos ya se explican solos), así que anula la primera columna. Sin esto los
   hitos caían dentro de los 32px del hueco del icono. */
.dr-summary-row--hitos {
    grid-template-columns: 1fr !important;
}

.dr-hitos {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 10px;
    width: 100%;
    min-width: 0;
}

.dr-hito {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

.dr-hito__label {
    font-size: 0.6875rem;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--ic-muted, #94A3B8);
}

/* El hito abierto es el que se busca con la vista; el otro es contexto.
   --lc-accent y no --ic-primary: el acento del diseño era el de --lc-accent,
   un escalón por debajo de --ic-primary, y esa relación se conserva. */
.dr-hito__label--entrega {
    color: var(--lc-accent);
}

.dr-hito__valor {
    font-size: 0.9375rem;
    font-weight: 800;
    line-height: 1.25;
}

.dr-hito__abs {
    font-size: 0.75rem;
    color: var(--ic-muted, #94A3B8);
}

/* ── Avisos de la parte alta (notas del equipo, lavado) ────────────────────────
   Caja translúcida con borde en vez de bloque de color sólido: a ancho completo y
   relleno, el color gritaba por encima del contenido y dejaba el texto —que es lo
   que hay que leer— sobre fondo saturado. */
.dr-aviso {
    display: flex;
    gap: 11px;
    padding: 12px 13px;
    border-radius: 12px;
    border: 1px solid;
    box-sizing: border-box;
}

.dr-aviso__icon {
    flex-shrink: 0;
    font-size: 1.1875rem !important;
    margin-top: 1px;
}

.dr-aviso__body {
    display: flex;
    flex-direction: column;
    gap: 3px;
    min-width: 0;
}

.dr-aviso__title {
    font-size: 0.8125rem;
    font-weight: 800;
    line-height: 1.3;
}

.dr-aviso__text {
    font-size: 0.875rem;
    line-height: 1.45;
    white-space: pre-wrap;
    word-break: break-word;
    color: var(--ic-text);
}

.dr-aviso__cta {
    align-self: flex-start;
    margin-top: 2px;
}

.dr-aviso--urgente {
    background: rgba(var(--lc-err-rgb), 0.11);
    border-color: rgba(var(--lc-err-rgb), 0.32);
}

.dr-aviso--urgente .dr-aviso__icon,
.dr-aviso--urgente .dr-aviso__title { color: var(--lc-err); }

.dr-aviso--info,
.dr-aviso--lavado {
    background: rgba(var(--lc-warn-rgb), 0.10);
    border-color: rgba(var(--lc-warn-rgb), 0.30);
}

.dr-aviso--info .dr-aviso__icon,
.dr-aviso--info .dr-aviso__title,
.dr-aviso--lavado .dr-aviso__icon,
.dr-aviso--lavado .dr-aviso__title { color: var(--lc-warn); }

/* ── Tarjeta de Productos ──────────────────────────────────────────────────────
   Es lo primero que se lee en la página: quien carga la camioneta necesita el
   inventario antes que los datos administrativos. */
.dr-prod-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 10px;
    width: 100%;
    min-width: 0;
}

/* Total y saldo en la misma línea base: la cifra manda, lo que falta la acompaña. */
.dr-pago-cifras {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 10px;
}

/* Los dos documentos, en la tarjeta de pagos. */
.dr-docs {
    display: flex;
    gap: 8px;
    margin-top: 8px;
}

.dr-docs__btn {
    flex: 1;
    min-width: 0 !important;
    height: 42px;
    border-radius: 11px !important;
    font-size: 0.8125rem !important;
    font-weight: 700 !important;
    color: var(--ic-muted) !important;
    border-color: var(--ic-border) !important;
    /* MudButton mete 15px de padding por lado más su min-width de 64: sin esto
       "Nota de remisión" partía en dos renglones. */
    padding-inline: 8px !important;
    white-space: nowrap;
}

/* El botón de pago va en verde TENUE, no sólido: es la acción de una tarjeta,
   no la acción principal de la pantalla —esa vive en la barra fija—. En verde
   pleno competía con "Registrar entrega" y ganaba por color, no por jerarquía. */
.dr-btn-pago {
    height: 46px;
    border-radius: 11px !important;
    background: rgba(var(--lc-ok-rgb), 0.14) !important;
    color: var(--lc-ok) !important;
    box-shadow: none !important;
    font-size: 0.9375rem !important;
    font-weight: 700 !important;
}

/* Cuando la fila solo lleva el sello de confianza y no una etiqueta, el hueco
   reservado para el texto sobra. */
.dr-summary-label--solo-sello:empty {
    display: none;
}

/* Chrome de las tarjetas del detalle de renta. Vivía como un selector `.mud-card`
   pelado en el <style> inline de la página —sin scope y con !important—, así que
   restilaba también las MudCard de los diálogos que la propia página abre. Y al no
   estar en una hoja, /_bench no podía reproducir la tarjeta para compararla con el
   mock. Acotado a .dr-page-container: se arregla la fuga y el banco la ve. */
.dr-page-container .mud-card {
    background: var(--ic-surface, #1C1C1E);
    border: 1px solid var(--ic-border, rgba(148, 163, 184, 0.1));
    border-radius: 13px;
}

.dr-prod-head__sum {
    font-size: 0.78rem;
    font-weight: 700;
    color: var(--ic-muted, #94A3B8);
    white-space: nowrap;
    flex-shrink: 0;
}

/* La cabecera se separa de las filas con una línea, y el cuerpo pierde su
   relleno para que cada fila llegue a los bordes de la tarjeta: así los
   separadores entre productos cruzan de lado a lado, como en el diseño. */
#dr-productos-card .mud-card-header {
    padding: 13px 15px !important;
    border-bottom: 1px solid rgba(148, 163, 184, 0.10);
}

#dr-productos-card .mud-card-content,
#dr-productos-card .mud-card-content:last-child {
    padding: 0 !important;
}

/* El botón al Centro de lavado sí necesita su aire, ya que el cuerpo no lo pone. */
.dr-prod-lavado-cta {
    margin: 8px 15px 12px;
}

/* Filas separadas por una línea dentro de la tarjeta, no tarjetas flotantes con
   sombra y margen: el diseño trata Productos como UNA tarjeta con filas, y las
   MudPaper elevadas leían como tres tarjetas sueltas metidas en una cuarta. */
.dr-prod-row {
    padding: 12px 15px;
    cursor: pointer;
    border-bottom: 1px solid rgba(148, 163, 184, 0.08);
}

.dr-prod-row:last-child {
    border-bottom: 0;
}

.dr-prod-row:hover {
    background: rgba(255, 255, 255, 0.02);
}

.dr-prod-row__body {
    display: flex;
    align-items: center;
    gap: 11px;
    min-width: 0;
}

.dr-prod-row__media {
    width: 48px;
    height: 48px;
    flex: 0 0 48px;
    border-radius: 10px;
    object-fit: cover;
}

.dr-prod-row__info {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 3px;
    flex: 1;
    min-width: 0;
}

.dr-prod-row__name {
    font-size: 0.9375rem;
    font-weight: 700;
    line-height: 1.3;
    min-width: 0;
    overflow-wrap: anywhere;
}

.dr-prod-row__meta {
    font-size: 0.8125rem;
    color: var(--ic-muted, #94A3B8);
    line-height: 1.35;
}

/* El importe manda en su columna y no compite con el nombre: se apila la moneda
   debajo en vez de alargar la línea, que era lo que empujaba el "c/u" a dos renglones. */
.dr-prod-row__price {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    line-height: 1.15;
    font-size: 0.9375rem;
    font-weight: 800;
    white-space: nowrap;
    flex-shrink: 0;
    color: var(--lc-ok);
}

/* La moneda acompaña al importe sin competir con él. */
.dr-prod-row__moneda {
    font-size: 0.72rem;
    font-weight: 600;
    opacity: 0.7;
}

.dr-prod-row__chips {
    display: flex;
    flex-wrap: wrap;
    gap: 5px;
}

.dr-prod-chip {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    font-size: 0.72rem;
    font-weight: 600;
    padding: 1px 8px 1px 3px;
    border-radius: 999px;
    border: 1px solid var(--mud-palette-divider);
}

/* El color de fondo y el alfa del borde son DATO (vienen del swatch del producto),
   así que esos dos siguen inline; el resto de la forma vive aquí. */
.dr-prod-chip__dot {
    width: 15px;
    height: 15px;
    border-radius: 50%;
    flex-shrink: 0;
    border: 1px solid transparent;
}

.dr-prod-chip--horario {
    padding: 1px 9px;
    color: var(--lc-info);
    border-color: rgba(var(--lc-info-rgb), 0.35);
}

/* Aviso de lavado dentro de la línea del producto que lo necesita. */
.dr-prod-row__lavado {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    font-size: 0.75rem;
    font-weight: 700;
    color: var(--lc-warn);
    line-height: 1.3;
}

.dr-prod-row__lavado-icon {
    font-size: 0.875rem !important;
    flex-shrink: 0;
}


/* ── Barra de progreso mini ── */
.dr-progress-mini {
    height: 6px;
    background: rgba(148,163,184,0.12);
    border-radius: 3px;
    overflow: hidden;
    width: 100%;
}

.dr-progress-mini__fill {
    height: 100%;
    border-radius: 3px;
    transition: width 0.35s ease;
}

/* ── Section label (cabeceras de sección nivel 2) ── */
/* Título de tarjeta en caja normal y color de texto: es un TÍTULO, no una etiqueta
   auxiliar. En versalitas grises competía con el contenido y hacía que "PRODUCTOS"
   pesara visualmente lo mismo que el nombre del producto. Las versalitas se reservan
   para las sub-etiquetas de dentro de la tarjeta (.dr-summary-label, .dr-hito__label). */
.dr-section-label {
    font-size: 0.9375rem;
    font-weight: 700;
    letter-spacing: -0.01em;
    color: var(--ic-text);
    margin: 0;
    display: block;
}

/* ── Totales «Llevar en vehículo» (ChecklistRutaResumen): lista vertical ── */
.cruta-totales-pills {
    display: flex;
    flex-direction: column;
    flex-wrap: nowrap;
    gap: 8px;
    padding: 8px 0 4px;
}

.cruta-totales-pill {
    display: flex;
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    width: 100%;
    box-sizing: border-box;
    padding: 8px 12px;
    border-radius: 12px;
    background: var(--ic-primary-dim);
    border: 1px solid var(--ic-nav-active-border);
    font-size: 0.8125rem;
    font-weight: 700;
}

.cruta-totales-pill__name {
    color: var(--ic-text, #E2E8F0);
    flex: 1;
    min-width: 0;
    white-space: normal;
    word-break: break-word;
    line-height: 1.35;
}

.cruta-totales-pill__qty {
    color: var(--ic-primary, #5563E0);
    font-variant-numeric: tabular-nums;
    flex-shrink: 0;
}

.cruta-totales-pills--opcional {
    gap: 6px;
    padding-top: 0;
}

.cruta-totales-pill--opcional {
    background: rgba(148, 163, 184, 0.08);
    border-color: rgba(148, 163, 184, 0.22);
    font-weight: 600;
}

.cruta-totales-pills--opcional .cruta-totales-pill__qty {
    color: var(--mud-palette-secondary, #94a3b8);
}

/*
  Detalle producto (/productos/{id}): cards MudPaper/MudList.
  Debe vivir en CSS global: el CSS aislado del .razor no aplica a la raíz de componentes hijos (MudPaper).
*/

/* ════════════════════════════════════════════════════════════════════════════
   Tarjetas de estadística de página (.gasto-stat-card / .gasto-section-card)

   FUENTE ÚNICA. Estas reglas vivían copiadas a mano en cuatro <style> globales
   dentro de Gastos, Cancelaciones, AlertasStock y Mantenimiento — con valores
   distintos (padding 14 vs 12, pill 36 vs 34) que se pisaban entre sí según el
   orden de render, así que la misma tarjeta cambiaba de tamaño según por qué
   página hubieras pasado antes. El nombre conserva el prefijo "gasto-" porque
   ahí nació; el patrón es de toda la app.
   ════════════════════════════════════════════════════════════════════════════ */
.dash-icon-pill {
    width: 36px;
    height: 36px;
    border-radius: 10px;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
}

.gasto-stat-card {
    background: var(--ic-surface, #1C1C1E);
    border: 1px solid var(--ic-border, rgba(148, 163, 184, 0.1));
    border-radius: 14px;
    padding: 14px;
    margin-bottom: 16px;
    height: calc(100% - 16px);
    box-sizing: border-box;
}

.gasto-stat-card__top { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; }
.gasto-stat-card__label { font-size: 0.75rem; color: var(--ic-muted); font-weight: 500; }
.gasto-stat-card__value { font-size: 1.375rem; font-weight: 700; letter-spacing: -0.02em; line-height: 1.2; }
.gasto-stat-card__sub { font-size: 0.6875rem; color: var(--ic-muted); margin-top: 2px; }

.gasto-section-card {
    background: var(--ic-surface, #1C1C1E) !important;
    border: 1px solid var(--ic-border, rgba(148, 163, 184, 0.1)) !important;
    border-radius: 14px !important;
    margin-bottom: 0;
}

.gasto-section-card__header {
    border-bottom: 1px solid var(--ic-border, rgba(148, 163, 184, 0.08));
    padding-bottom: 12px !important;
}

/* El bloque .dp-* (tarjeta, stats, placeholder y lista de la ficha de producto) se borró
   el 2026-08-19: su única consumidora era /productos/{id}, que pasó a wwwroot/css/detalle-producto.css.
   Llevaba !important en TODAS sus propiedades, así que cualquier superficie nueva de esa
   pantalla tenía que subir especificidad encima en vez de declarar su fondo y su radio.
   Se comprobó con grep que ningún .razor las usaba ya: eran exclusivas de esa ficha. Las
   .dr-* de aquí abajo son del detalle de RENTA, otro bloque, y siguen vivas. */

/* ── Summary Strip (DetalleRenta): grid simétrico + filas con icono | contenido | acciones ── */
.dr-summary-strip {
    margin: 0;
    overflow: hidden;
}

/* Cada fila: icono + contenido. Las acciones van inline dentro del contenido
   (antes había una 3ª columna fija de 104px que desperdiciaba espacio). */
.dr-summary-row {
    display: grid;
    grid-template-columns: 32px minmax(0, 1fr);
    gap: 12px 14px;
    align-items: start;
    padding: 14px 16px;
    border-bottom: 1px solid rgba(148, 163, 184, 0.09);
    box-sizing: border-box;
}

.dr-summary-strip > .dr-summary-row:last-child {
    border-bottom: none;
}

.dr-summary-icon-slot {
    display: flex;
    align-items: flex-start;
    justify-content: center;
    padding-top: 2px;
}

.dr-summary-icon-slot .mud-icon-root {
    font-size: 1.125rem !important;
    opacity: 0.55;
}

.dr-summary-cell {
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-width: 0;
}

.dr-summary-label {
    font-size: 0.75rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--ic-muted, #94A3B8);
    line-height: 1.2;
}

.dr-summary-value {
    font-size: 1rem;
    font-weight: 600;
    color: var(--ic-text, #E2E8F0);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.dr-summary-value--rel {
    white-space: normal;
    line-height: 1.4;
    font-weight: 600;
}

.dr-summary-value--multiline {
    white-space: normal;
    word-break: break-word;
    line-height: 1.4;
    font-weight: 500;
}

.dr-summary-value--phone {
    font-weight: 700;
    letter-spacing: 0.02em;
}

.dr-summary-absolute {
    display: block;
    margin-top: 2px;
    font-size: 0.8125rem;
    font-weight: 500;
    color: var(--ic-muted, #94A3B8);
    line-height: 1.35;
}

.dr-summary-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: flex-end;
    gap: 4px;
    min-width: 104px;
    min-height: 40px;
}

.dr-summary-actions--top {
    align-items: flex-start;
    padding-top: 2px;
}

.dr-summary-pago-estado {
    font-size: 0.875rem;   /* acompaña al total, no compite con él */
    font-weight: 700;
    line-height: 1.3;
    text-align: right;
    white-space: nowrap;
    flex-shrink: 0;
}

/* Ámbar, no rojo: un saldo pendiente es lo normal en una renta con anticipo, no un
   error. En rojo contradecía a la franja del encabezado, que ya lo pinta en ámbar. */
.dr-summary-pago-estado--pendiente {
    color: var(--lc-warn);
}

.dr-summary-pago-estado--ok {
    color: var(--mud-palette-success, #4ade80);
}

.dr-progress-mini--summary {
    margin-top: 6px;
}

/* Apilado en todos los anchos: separadores horizontales entre filas y nada más.
   Antes, en escritorio, esto era una matriz 2×2 posicionada por :nth-child. Se
   retiró al pasar el Resumen a media anchura dentro de .dr-detalle-grid: en dos
   columnas de ~50% ya no cabía, y el posicionamiento por nth-child era frágil de
   origen porque las filas de horarios, hitos y contactos son condicionales —qué
   contenido caía en qué cuadrante dependía del dato, no del diseño. */
.dr-summary-strip {
    display: block;
}

.dr-summary-row {
    border-right: none !important;
    border-top: none !important;
}

/* El hueco bajo el scroll para la barra fija ya no se reserva con un div
   espaciador: lo pone .dr-body como padding-bottom (ver detalle-renta.css,
   .dr-body--pie*). El espaciador era un hijo más de la columna flex del cuerpo,
   así que su alto se sumaba al gap que lo separaba del chat y al padding inferior
   del propio cuerpo — tres fuentes para una sola medida, y 35px de aire de más. */
.dr-page-container {
    --dr-crew-strip-h: 50px;
}

.dr-detail-panels,
.dr-notas-panels {
    border-radius: 12px;
    overflow: hidden;
}

/* Título de los paneles de Entrega/Recogida: informativo en plegado (etiqueta +
   quién va + chip de estado), en una sola línea con elipsis en los nombres. */
.dr-asig-panel__title {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    min-width: 0;
}

.dr-asig-panel__title-label {
    font-size: 1rem;
    font-weight: 600;
    flex-shrink: 0;
}

.dr-asig-panel__title-names {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: 0.8125rem;
    color: var(--ic-muted, #94A3B8);
}

.dr-asig-panel__title .mud-chip {
    flex-shrink: 0;
}

/*
 * Dense=true aplica .mud-expand-panel-dense con padding-bottom:0 (mayor especificidad que un solo .mud-expand-panel-content).
 * Hay que igualar la cadena de selectores para recuperar aire inferior.
 */
.dr-detail-panels .mud-expand-panel .mud-expand-panel-content.mud-expand-panel-dense,
.dr-notas-panels .mud-expand-panel .mud-expand-panel-content.mud-expand-panel-dense {
    padding-bottom: 1.25rem;
}

/* Historial de pagos — mismo layout para cada movimiento */
.dr-pagos-historial .mud-expand-panel-content {
    padding-top: 0.25rem;
}

.dr-pago-item {
    border: 1px solid var(--mud-palette-lines-default);
    border-radius: 10px;
    padding: 12px 14px;
}

.dr-pago-item__header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 10px;
}

.dr-pago-item__chip-wrap {
    flex: 1;
    min-width: 0;
}

.dr-pago-item__chip-wrap .mud-chip {
    max-width: 100%;
}

.dr-pago-item__chip-wrap .mud-chip-content {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.dr-pago-item__monto {
    font-size: 1.0625rem;
    font-weight: 700;
    line-height: 1.35;
    white-space: nowrap;
    /* Sin tabular-nums: en Schibsted Grotesk la coma tabular se lleva un avance de
       dígito completo y "$1,250" se lee "$1 , 250" (+27% de ancho). Inter no lo hacía.
       Se conserva solo donde hay columna de dígitos SIN separador de miles.
       Ver docs/design-substrate.md → «La familia: Schibsted Grotesk». */
    flex-shrink: 0;
    text-align: right;
    color: var(--mud-palette-text-primary);
}

.dr-pago-item__rows {
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.dr-pago-item__row {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 12px;
    font-size: 0.8125rem;
    line-height: 1.35;
}

.dr-pago-item__label {
    color: var(--mud-palette-text-secondary);
    flex-shrink: 0;
    font-weight: 500;
}

.dr-pago-item__value {
    font-weight: 600;
    text-align: right;
    color: var(--mud-palette-text-primary);
    word-break: break-word;
}

.dr-pago-item__value--muted {
    font-weight: 500;
    color: var(--mud-palette-text-secondary);
}

.dr-pago-item__notas {
    margin-top: 8px;
    padding-top: 8px;
    border-top: 1px dashed var(--mud-palette-lines-default);
    font-size: 0.8125rem;
    font-style: italic;
    color: var(--mud-palette-text-secondary);
    line-height: 1.35;
}

/* Ruta y notas: barra compacta */
.dr-ruta-bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    width: 100%;
    flex-wrap: wrap;
    gap: 4px;
}

.dr-ruta-bar__nav {
    display: flex;
    align-items: center;
    gap: 0;
}

/* ── Colores semánticos — valores numéricos destacados ── */
.dr-val--success { color: var(--mud-palette-success); font-weight: 700; }
.dr-val--warn    { color: var(--mud-palette-warning); font-weight: 700; }
.dr-val--error   { color: var(--mud-palette-error);   font-weight: 700; }

/* Borde izquierdo de estado en cards de asignación */
.dr-card--entrega {
    border-left: 3px solid var(--mud-palette-primary) !important;
}
.dr-card--recogida {
    border-left: 3px solid var(--mud-palette-secondary) !important;
}
.dr-card--finalizado {
    border-left: 3px solid var(--mud-palette-success) !important;
}

/* ── RegistrarEntrega: barra de confirmación ──
   Espejo del encabezado Detail: misma superficie, mismo borde, mismo radio y
   mismo padding de fila, sin sombra. Antes era una banda de esquinas rectas
   soldada al borde inferior, el lenguaje que el encabezado ya abandonó. */
.re-sticky-confirm {
    position: sticky;
    /* La nav inferior se oculta en esta pantalla (regla :has), así que la barra
       flota sobre el borde del dispositivo; el indicador de inicio de iOS
       necesita su despeje. */
    bottom: max(8px, env(safe-area-inset-bottom, 8px));
    z-index: 90;
    background: var(--ic-page-header-bg);
    backdrop-filter: var(--ic-page-header-blur);
    -webkit-backdrop-filter: var(--ic-page-header-blur);
    border: 1px solid var(--ic-page-header-border);
    border-radius: var(--ic-radius-lg, 16px);
    padding: var(--ic-page-header-padding-y) var(--ic-page-header-padding-x);
    margin-top: 12px;
}

/* A sangre en móvil, en espejo del encabezado: mismo truco calc(50% - 50vw)
   para salir del gutter, borde y radio solo del lado que da al contenido, y
   pegada al borde inferior respetando el indicador de inicio de iOS. */
html[data-chrome="app"] .re-sticky-confirm {
    width: 100vw;
    margin: 12px calc(50% - 50vw) 0;
    bottom: 0;
    border-width: 1px 0 0;
    border-radius: var(--ic-radius-lg, 16px) var(--ic-radius-lg, 16px) 0 0;
    padding-bottom: max(var(--ic-page-header-padding-y), env(safe-area-inset-bottom, 0px));
}

html:not([data-chrome="app"]) .re-sticky-confirm {
    position: static;
}

/* Táctil (Chrome Android / MIUI): blur en barras fijas/sticky + URL bar que se oculta → recomposición y parpadeo */
@media (hover: none) and (pointer: coarse) {
    .dr-action-bar {
        backdrop-filter: none !important;
        -webkit-backdrop-filter: none !important;
        background: rgba(var(--ic-bg-rgb), 0.99) !important;
    }

    /* Superficie, no color de página: desde que es tarjeta debe leerse como tal. */
    .re-sticky-confirm {
        backdrop-filter: none !important;
        -webkit-backdrop-filter: none !important;
        background: rgba(var(--ic-surface-rgb), 0.99) !important;
    }

    /* Calendario/Mapa: mismo motivo (blur en barras sticky → parpadeo al scroll en Android WebView,
       incluido el host nativo MAUI). Estos headers son globales (compartidos calendario+mapa). */
    .calendar-header {
        backdrop-filter: none !important;
        -webkit-backdrop-filter: none !important;
        background-color: rgba(var(--ic-surface-rgb), 0.99) !important;
    }

    .calendar-sub-header {
        backdrop-filter: none !important;
        -webkit-backdrop-filter: none !important;
        background-color: rgba(var(--ic-surface-rgb), 0.99) !important;
    }
}

/* ════════════════════════════════════════════════════════════════════════
   ESTILOS COMPARTIDOS: header y popup de filtros (calendario + mapa)
   Estos selectores los usan /calendario y /mapa para que ambas páginas
   tengan top bar y popover de filtros visualmente idénticos.
   Originalmente en LazyPages/wwwroot/css/calendario-nuevo.css; promovidos
   aquí para uso global y evitar duplicación.
   ════════════════════════════════════════════════════════════════════════ */

.calendar-header {
    background-color: var(--calendar-header-bg) !important;
    border-bottom: 1px solid var(--ic-border, var(--mud-palette-lines-default));
    flex-shrink: 0;
    backdrop-filter: saturate(1.08) blur(12px);
    -webkit-backdrop-filter: saturate(1.08) blur(12px);
    box-shadow: 0 1px 0 0 rgba(255, 255, 255, 0.04);
}

.calendar-sub-header {
    background-color: rgba(var(--ic-surface-rgb), 0.94);
    border-bottom: 1px solid var(--ic-border, var(--mud-palette-lines-default));
    flex-shrink: 0;
    backdrop-filter: saturate(1.06) blur(10px);
    -webkit-backdrop-filter: saturate(1.06) blur(10px);
}

.width-100 { width: 100%; }

.header-title {
    font-size: 1.0625rem;
    font-weight: 600 !important;
    letter-spacing: -0.01em;
}

.cal-btn-back-mes {
    font-size: 1.0625rem !important;
    font-weight: 600 !important;
    letter-spacing: -0.01em !important;
    text-transform: none !important;
    padding: 0 4px 0 0 !important;
}

.cal-btn-back-mes .mud-icon-root {
    font-size: 1.25rem !important;
}

html[data-chrome="app"] .calendar-header .mud-icon-button,
html[data-chrome="app"] .calendar-header .mud-button-base {
    min-width: 44px !important;
    min-height: 44px !important;
}

@media (max-width: 600px) {
    .header-title { font-size: 0.9375rem !important; }
}

/* ── Popup de filtros (MudMenu activator + ChildContent) ── */
.cal-filter-popup {
    min-width: 220px;
    max-width: 290px;
    padding: 4px 0;
}

.cal-filter-popup-title {
    font-size: 0.6875rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.07em;
    color: var(--mud-palette-text-secondary);
    padding: 6px 16px 8px;
    line-height: 1;
}

.cal-filter-item {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 9px 16px;
    cursor: pointer;
    transition: background-color 0.12s ease;
    -webkit-tap-highlight-color: transparent;
    user-select: none;
}

@media (hover: hover) and (pointer: fine) {
    .cal-filter-item:hover {
        background-color: var(--ic-glass-surface-hover);
    }
}

.cal-filter-item:active {
    background-color: var(--ic-glass-surface-hover);
}

.cal-filter-dot {
    width: 10px;
    height: 10px;
    border-radius: 50%;
    flex-shrink: 0;
}

.cal-filter-label {
    flex: 1;
    font-size: 0.875rem;
    color: var(--mud-palette-text-primary);
    line-height: 1.3;
}

.cal-filter-check {
    color: var(--mud-palette-primary) !important;
    font-size: 1rem !important;
    flex-shrink: 0;
}

.cal-filter-popup-divider {
    height: 1px;
    background-color: var(--ic-border, var(--mud-palette-lines-default));
    margin: 4px 0;
}

.cal-filter-switch-row {
    padding: 6px 16px 4px;
}

/* ── Tour v2 (tour-engine.js) ──
   driver.js sigue dibujando el overlay+halo recortado pero su popover queda
   oculto. El contenido visible vive en TourBottomSheet.razor. */
/* Ocultamos el popover de driver.js sin display:none — driver.js v1 calcula
   posiciones leyendo el bounding rect del popover; si está display:none, sus
   dimensiones son 0 y moveNext() puede atascarse al re-posicionar. Con
   visibility+opacity+pointer-events seguimos invisibles e inertes, pero el
   nodo conserva tamaño y driver.js puede avanzar entre pasos sin errores. */
.ic-tour-popover-hidden,
.driver-popover.ic-tour-popover-hidden {
    visibility: hidden !important;
    pointer-events: none !important;
    opacity: 0 !important;
    /* Se queda en pantalla pero detrás de todo, sin recibir clicks ni foco. */
    z-index: -1 !important;
}

/* Neutralizamos el bloqueo de clicks que driver.js aplica con su overlay y
   con `body { pointer-events: none }`. Con allowClose:false ya no
   necesitamos que el overlay capture clicks fuera del highlight; los clicks
   que pasan a través caen sobre el TourBottomSheet (que tiene su propio
   pointer-events:auto y vive bajo <body> con z-index 100001) o sobre el
   contenido de la página, lo cual es aceptable porque el tour no se cierra. */
.driver-overlay,
#driver-page-overlay,
.driver-stage,
#driver-stage {
    pointer-events: none !important;
}

html.driver-active,
body.driver-active,
html,
body {
    pointer-events: auto !important;
}

/* Cinturón y tirantes: clicks SIEMPRE llegan al sheet y a todo lo de dentro. */
.ic-tour-sheet,
.ic-tour-sheet * {
    pointer-events: auto !important;
}


/* ── Banner: nueva versión disponible (Service Worker waiting) ── */
.ic-sw-update {
    position: fixed;
    left: 12px;
    right: 12px;
    bottom: max(12px, env(safe-area-inset-bottom, 0px));
    z-index: 2147483600;
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 10px 14px;
    background: var(--ic-surface);
    color: var(--ic-text);
    border-radius: 12px;
    box-shadow: var(--ic-shadow);
    font: 14px/1.3 var(--ic-font, 'Schibsted Grotesk', system-ui, sans-serif);
    animation: ic-sw-update-in 220ms ease-out;
}

@media (min-width: 720px) {
    .ic-sw-update {
        left: auto;
        right: 16px;
        bottom: 16px;
        max-width: 420px;
    }
}

.ic-sw-update__text {
    flex: 1;
    min-width: 0;
}

.ic-sw-update__btn {
    border: 0;
    border-radius: 8px;
    padding: 8px 12px;
    font-weight: 600;
    font-size: 13px;
    cursor: pointer;
    background: transparent;
    color: var(--ic-text);
    transition: background-color 120ms ease;
}

.ic-sw-update__btn:hover {
    background: var(--ic-glass-surface-hover);
}

.ic-sw-update__btn--primary {
    background: #6E59E0;
    color: #fff;
}

.ic-sw-update__btn--primary:hover {
    background: #7e6be8;
}

@keyframes ic-sw-update-in {
    from { opacity: 0; transform: translateY(8px); }
    to   { opacity: 1; transform: translateY(0); }
}

/* ── Aviso de actualización BLOQUEANTE (versión vieja / stale) ──
   Cuando el usuario lleva días en una versión vieja (assets en caché), un toast
   chico se ignora. Este modal centrado con scrim es imposible de no ver e incluye
   la instrucción de respaldo (cerrar y reabrir) para el caso PWA iOS. */
.ic-sw-modal {
    position: fixed;
    inset: 0;
    z-index: 2147483600;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 24px;
    background: rgba(0, 0, 0, 0.6);
    animation: ic-sw-update-in 200ms ease-out;
}

.ic-sw-modal__card {
    width: 100%;
    max-width: 380px;
    background: var(--ic-surface);
    color: var(--ic-text);
    border: 1px solid var(--ic-border);
    border-radius: 18px;
    box-shadow: var(--ic-shadow);
    padding: 24px 22px calc(22px + env(safe-area-inset-bottom, 0px));
    text-align: center;
}

.ic-sw-modal__icon {
    width: 56px;
    height: 56px;
    margin: 0 auto 12px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 16px;
    background: rgba(110, 89, 224, 0.16);
    color: #6E59E0;
    font-size: 28px;
    font-weight: 700;
}

.ic-sw-modal__title {
    font-size: 1.375rem;
    font-weight: 800;
    margin-bottom: 8px;
    color: var(--ic-text);
}

.ic-sw-modal__text {
    font-size: 1.0625rem;
    line-height: 1.4;
    color: var(--ic-muted);
    margin: 0 0 20px;
}

.ic-sw-modal__btn {
    width: 100%;
    min-height: 52px;
    border: 0;
    border-radius: 12px;
    background: #6E59E0;
    color: #fff;
    font-size: 1.0625rem;
    font-weight: 700;
    cursor: pointer;
    transition: background-color 120ms ease;
}

.ic-sw-modal__btn:hover { background: #7e6be8; }
.ic-sw-modal__btn:disabled { opacity: 0.7; cursor: default; }

.ic-sw-modal__hint {
    font-size: 0.875rem;
    line-height: 1.35;
    color: var(--ic-text-tertiary, var(--ic-muted));
    margin: 14px 0 0;
}

/* ── MudDialog: safe-area-inset + sin transform residual ───────────────────
   1) safe-area: en iPhone con home indicator (sin botón físico), los botones
      del footer del dialog pueden quedar debajo del área segura.
   2) animation-fill-mode: MudBlazor anima .mud-dialog con fill-mode `both`, así
      que el transform:scale(1) del último frame queda aplicado para siempre tras
      abrir (100ms). Un transform !== none, aunque sea la identidad, convierte al
      diálogo en containing block de sus descendientes position:fixed/absolute —
      rompe cualquier MudDatePicker/MudTimePicker PickerVariant.Dialog anidado
      adentro: su overlay se ancla a la caja del diálogo padre en vez del
      viewport. `none` no cambia el fade/scale de apertura (MudBlazor no usa
      animation-delay en ningún lado, así que "backwards" nunca aplicaba) y sólo
      evita que el transform sobreviva al final. Seguro para todas las posiciones
      de diálogo: existe un único @keyframes mud-open-dialog-center y termina en
      scale(1) = identidad; las variantes de posición usan flex/offsets. */
.mud-dialog-container .mud-dialog {
    padding-bottom: env(safe-area-inset-bottom, 0px);
    animation-fill-mode: none;
}

/* ── Overlay anidado dentro de un diálogo: scrim opaco ──────────────────────
   MudPicker.razor arma la variante Dialog como <MudOverlay DarkBackground
   Class="mud-overlay-dialog"><MudPaper>...</MudPaper></MudOverlay>, sin portal
   (MudOverlay sólo se porta a un provider si RenderOutsideOfSection, y eso es
   falso en cuanto el overlay trae ChildContent). Se queda anidado dentro del
   propio .mud-dialog padre. Su scrim usa el alpha pensado para un overlay de
   nivel raíz —OverlayDark 0.6/0.4, MainLayout.razor:993/1031— que deja ver el
   fondo A PROPÓSITO cuando detrás sólo hay la página. Anidado dentro de OTRO
   diálogo, lo que se alcanza a ver detrás es el título/las acciones de ESE
   diálogo (p. ej. "Guardar y otro" de GastoRapidoSheet) asomando a través del
   scrim, semitransparente pero legible.

   Va --ic-bg (fondo de PÁGINA), no --ic-surface: --ic-surface es idéntico a
   --mud-palette-surface en los dos temas, y el papel del picker es un MudPaper
   pintado con esa misma variable — el picker quedaría exactamente del color de
   su propio scrim y perdería el borde. --ic-bg es más recesivo que el papel en
   ambos temas, así que el scrim tapa y el picker sigue flotando.

   .mud-overlay-dark en el selector es deliberado: sin él esto empata en
   especificidad (0,3,0) con la regla de MudBlazor y ganaría sólo por orden de
   carga del <head>. Cubre también .arm-dt-overlay (AsignacionRutaMasivaDialog),
   el único MudOverlay propio del panel que vive dentro de un diálogo. */
.mud-dialog .mud-overlay-dialog .mud-overlay-scrim.mud-overlay-dark,
.mud-dialog .arm-dt-overlay .mud-overlay-scrim.mud-overlay-dark {
    background-color: var(--ic-bg);
}
/* En claro --ic-bg ya es blanco, igual que el papel del picker: el velo lo dejaría sin borde.
   Ahí lo recesivo es el gris, así que el velo va en --ic-surface (#F2F2F7) y el picker blanco
   sigue flotando. Mismo reparto que en oscuro, invertido. */
html[data-theme="light"] .mud-dialog .mud-overlay-dialog .mud-overlay-scrim.mud-overlay-dark,
html[data-theme="light"] .mud-dialog .arm-dt-overlay .mud-overlay-scrim.mud-overlay-dark {
    background-color: var(--ic-surface);
}

@media (max-width: 600px) {
    .mud-dialog-container .mud-dialog-actions,
    .mud-dialog-container .mud-dialog-content {
        padding-bottom: max(8px, env(safe-area-inset-bottom));
    }
}

/* ── Touch tap delay 300ms ─────────────────────────────────────────────────
   En iOS Safari (incluso versiones recientes) los browsers reservan ~300ms
   tras un tap por si el usuario hace doble-tap-to-zoom. touch-action:manipulation
   le dice al browser "este elemento no hace doble-tap-to-zoom, dispara click ya".
   Se aplica solo a elementos interactivos para no romper gestos en contenedores. */
.mud-button-base,
.mud-icon-button,
.mud-fab,
.mud-list-item-clickable,
.mud-card-actions button,
.mud-toggle-iconbutton,
.mud-nav-link,
.mud-chip-clickable,
button[type="button"],
button[type="submit"],
.auth-btn-google,
.auth-btn-facebook,
.auth-btn-cancel,
.auth-btn-primary-sm,
.auth-link-btn,
.auth-text-link,
.sn-negocio-card,
.sn-logout-btn,
.sn-logout-full-btn,
.sn-register-negocio-btn,
.sn-retry-btn {
    touch-action: manipulation;
}

/* ── El número tecleable de un contador (CantidadEditable) ────────────────────
   Sólo el reset. El aspecto lo pone la clase que le pasa cada pantalla
   (.cg-step__valor, .rq-qty-val, .rq-prodcard__stepval): este bloque existe
   para que esa clase mande igual sobre un <button> y sobre un <input>, que
   traen tipografía, relleno y fondo propios del navegador.

   Va en app.css y no en una hoja nueva a propósito: el componente vive en el
   RCL y sus tres consumidores están repartidos entre dos proyectos, así que
   una hoja aparte habría que registrarla en los tres index.html —y las hojas
   de _content/* se sirven immutable, que es justo lo que las deja rancias. */

.ic-cantedit,
.ic-cantedit__input {
    font: inherit;
    color: inherit;
    background: none;
    border: 0;
    border-radius: var(--ic-radius-sm, 8px);
    padding: 0;
    margin: 0;
    text-align: center;
    /* EL MISMO ancho en el botón y en el input, y por eso reservado desde antes
       de abrirlo: medido en el banco, un input dimensionado por su cuenta hacía
       crecer la fila unos 25px al tocar la cifra, y los +/− se movían justo bajo
       el dedo que iba a pulsarlos. El min-width de la clase de la pantalla sigue
       actuando de piso, y --ic-cantedit-w deja subirlo donde caben más dígitos. */
    width: var(--ic-cantedit-w, 3.5ch);
    box-sizing: content-box;
    /* Sin esto el número cambia de ancho al pasar de 9 a 10 y la fila entera se
       mueve mientras el dedo sigue en el botón de al lado. */
    font-variant-numeric: tabular-nums;
}

/* Lo interactivo va aparte de la métrica: la cifra de una fila que NO se puede
   teclear (pieza bloqueada, línea ya entregada) se pinta como <span> y necesita
   el mismo ancho que las demás, o las filas de una misma lista no alinean. */
.ic-cantedit--boton {
    cursor: pointer;
    /* Estirarse en alto y NO en ancho: los tres contadores son flex con un hueco
       angosto para la cifra (.rq-product-row__controls deja 2px de gap), y un
       objetivo táctil más ancho que ese hueco le robaría toques al +/− de al
       lado. Así el botón cubre el alto entero de su contenedor, que es el mismo
       que ya tienen sus vecinos. */
    align-self: stretch;
}

.ic-cantedit--boton:hover { color: var(--ic-primary); }

.ic-cantedit__input {
    /* El ancho va arriba, compartido con el botón. Aquí sólo lo que el UA impone
       de más sobre un <input>. */
    appearance: none;
    -webkit-appearance: none;
    background: none;
    /* Subrayado en vez de recuadro: el hueco es angosto y un borde completo
       desalineaba la cifra respecto de los +/− de al lado. */
    border-bottom: 1.5px solid var(--ic-primary);
    border-radius: 0;
    outline: none;
    -webkit-tap-highlight-color: transparent;
}

.ic-cantedit--boton:focus-visible {
    outline: 2px solid var(--ic-primary);
    outline-offset: 2px;
}

/* ── Acceso sin resolver ────────────────────────────────────────────────────
   Lo pinta AvisoAccesoSinResolver cuando no se pudo averiguar el rol en el negocio. Tokens, nunca
   hex: esta pantalla la ve el repartidor en la calle, y con mala señal es de las pocas que verá. */
.acceso-sin-resolver {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 12px;
    text-align: center;
    padding: 32px 24px;
    min-height: 240px;
    color: var(--ic-text);
}

.acceso-sin-resolver__icono { color: var(--ic-muted); }

.acceso-sin-resolver__texto {
    margin: 0;
    max-width: 34ch;
    color: var(--ic-muted);
    line-height: 1.45;
}

/* El hairline baja a medio píxel físico donde hay densidad para dibujarlo (ver
   --ic-hairline-w en :root). Va al final a propósito: es una redefinición del
   token, no una regla, y no compite con nada. */
@media (min-resolution: 2dppx) {
    :root { --ic-hairline-w: 0.5px; }
}
