/* ==========================================================================
   UB Logistics · Theme 2026
   Paleta: #9D2035 rojo · #373737 tinta · grises · blanco.
   El material de marca es monocromo: el rojo es el único color.
   ========================================================================== */

:root {
    --ubl-red:       #9D2035;
    --ubl-red-rgb:   157, 32, 53;
    --ubl-red-dark:  #7E1A2B;
    --ubl-ink:       #373737;
    --ubl-black:     #111111;
    --ubl-gray:      #8A8A93;
    --ubl-gray-50:   #FAFAFA;
    --ubl-gray-100:  #F2F2F2;
    --ubl-gray-200:  #E7E7E7;
    --ubl-gray-300:  #CFCFCF;
    --ubl-white:     #FFFFFF;

    --ubl-font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
    --ubl-font-display: 'DM Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;

    --ubl-nav-h: 80px;
    --ubl-topbar-h: 10px;   /* 3% de una lámina 16:9 del deck, llevado a web */

    /* Ritmo vertical del sitio en un solo lugar. */
    --ubl-section-y: clamp(3rem, 6vw, 5.5rem);
    --ubl-section-y-sm: clamp(2.5rem, 4vw, 3.5rem);

    /* Curva de salida: arranca rapido y frena largo. Es la que da la
       sensacion de peso; con `ease` las entradas se leian como un fundido. */
    --ubl-ease: cubic-bezier(.16, 1, .3, 1);
}

/* Las anclas del menú caen bajo un header fijo: scroll-padding-top en html lo
   resuelve para el click, el deep-link al cargar y el botón atrás por igual.
   Es lo que hace scrollIntoView() innecesario en JS. */
html {
    scroll-behavior: smooth;
    scroll-padding-top: calc(var(--ubl-nav-h) + var(--ubl-topbar-h) + 16px);
}
@media (prefers-reduced-motion: reduce) {
    html { scroll-behavior: auto; }
}

body {
    font-family: var(--ubl-font-sans);
    color: var(--ubl-ink);
    background: var(--ubl-white);
    -webkit-font-smoothing: antialiased;
}
body.ubl-solid-nav { padding-top: calc(var(--ubl-nav-h) + var(--ubl-topbar-h)); }

h1, h2, h3, h4 {
    font-family: var(--ubl-font-display);
    font-weight: 700;
    letter-spacing: -0.02em;
    color: var(--ubl-ink);
}

/* El deck va en blanco y negro con el rojo como único color. */
body.ubl-mono .ubl-hero.has-image::before { filter: grayscale(1); }

/* ===== Botones ===== */

.ubl-btn {
    display: inline-flex;
    align-items: center;
    gap: .5rem;
    padding: .8rem 1.6rem;
    border-radius: 999px;
    border: 2px solid transparent;
    font-family: var(--ubl-font-display);
    font-weight: 700;
    font-size: .92rem;
    text-decoration: none;
    transition: background .18s ease, color .18s ease, transform .18s ease;
}
.ubl-btn--primary { background: var(--ubl-red); color: #fff; }
.ubl-btn--primary:hover { background: var(--ubl-red-dark); color: #fff; transform: translateY(-2px); }
.ubl-btn--ghost { border-color: currentColor; color: var(--ubl-ink); }
.ubl-btn:focus-visible { outline: 3px solid color-mix(in srgb, var(--ubl-red) 45%, transparent); outline-offset: 3px; }

/* ===== Header ===== */

.ubl-skip { position: absolute; z-index: 1100; }

.ubl-header {
    position: fixed;
    inset: var(--ubl-topbar-h) 0 auto 0;
    z-index: 1030;
    height: var(--ubl-nav-h);
    display: flex;
    align-items: center;
    background: var(--ubl-white);
    border-bottom: 1px solid var(--ubl-gray-200);
    transition: background .2s ease, box-shadow .2s ease, border-color .2s ease;
}
/* En la home arranca transparente encima del hero y se solidifica al scrollear. */
body.ubl-over-hero .ubl-header {
    background: transparent;
    border-bottom-color: transparent;
}
body.ubl-over-hero .ubl-header.is-scrolled {
    background: var(--ubl-white);
    border-bottom-color: var(--ubl-gray-200);
    box-shadow: 0 1px 0 rgba(0, 0, 0, .08);
}
.ubl-navbar { width: 100%; padding: 0; }

.ubl-brand__img { display: block; height: 54px; width: auto; }
/* Sobre el hero el logo rojo no contrasta. El filtro lo pasa a blanco sin pedir
   una segunda imagen; el footer sí usa el PNG blanco porque ahí es permanente. */
body.ubl-over-hero .ubl-header:not(.is-scrolled) .ubl-brand__img { filter: brightness(0) invert(1); }

.ubl-nav-link,
.ubl-nav .nav-link {
    position: relative;
    font-size: .86rem;
    font-weight: 600;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--ubl-ink);
    padding: .5rem .9rem;
    transition: color .25s ease;
}
/* El ítem activo se marca con un filete propio en vez de text-decoration: el
   subrayado del navegador se pega a las descendentes y corta los acentos. */
.ubl-nav .nav-link::after {
    content: '';
    position: absolute;
    left: .9rem;
    right: .9rem;
    bottom: .15rem;
    height: 2px;
    background: currentColor;
    transform: scaleX(0);
    transform-origin: left;
    transition: transform .35s var(--ubl-ease);
}
.ubl-nav .nav-link:hover::after,
.ubl-nav .nav-link.active::after { transform: scaleX(1); }
.ubl-nav .nav-link:hover,
.ubl-nav .nav-link.active { color: var(--ubl-red); }
body.ubl-over-hero .ubl-header:not(.is-scrolled) .ubl-nav .nav-link { color: #fff; }
body.ubl-over-hero .ubl-header:not(.is-scrolled) .ubl-nav .nav-link:hover,
body.ubl-over-hero .ubl-header:not(.is-scrolled) .ubl-nav .nav-link.active { color: #fff; }

.ubl-lang__toggle {
    display: inline-flex;
    align-items: center;
    gap: .4rem;
    padding: .38rem .8rem;
    border: 1px solid var(--ubl-gray-200);
    border-radius: 999px;
    background: transparent;
    font-family: var(--ubl-font-display);
    font-size: .78rem;
    font-weight: 700;
    letter-spacing: .06em;
    color: var(--ubl-ink);
    transition: background-color .25s ease, border-color .25s ease, color .25s ease;
}
.ubl-lang__toggle:hover { border-color: var(--ubl-red); color: var(--ubl-red); }
.ubl-lang__toggle:focus-visible { outline: 2px solid var(--ubl-red); outline-offset: 2px; }

/* El menú se configura con las variables del propio dropdown de Bootstrap en
   vez de sobrescribir sus reglas: menos especificidad y nada que romper si
   cambia de versión. */
.ubl-lang__menu {
    --bs-dropdown-min-width: 11rem;
    --bs-dropdown-spacer: 1.1rem;
    --bs-dropdown-border-radius: 2px;
    --bs-dropdown-border-color: var(--ubl-gray-200);
    --bs-dropdown-font-size: .88rem;
    --bs-dropdown-link-active-bg: var(--ubl-red);
    --bs-dropdown-link-hover-bg: var(--ubl-gray-100);
    box-shadow: 0 18px 40px rgba(0, 0, 0, .12);
}
.ubl-lang__menu .dropdown-item { display: flex; align-items: center; gap: .6rem; padding: .55rem 1rem; }
.ubl-lang__code {
    min-width: 1.7rem;
    font-size: .68rem;
    font-weight: 700;
    letter-spacing: .1em;
    color: var(--ubl-gray);
}
.ubl-lang__menu .dropdown-item.active .ubl-lang__code { color: rgba(255, 255, 255, .7); }

/* Sobre el hero el header es transparente: el botón se invierte para leerse. */
body.ubl-over-hero .ubl-header:not(.is-scrolled) .ubl-lang__toggle { color: #fff; border-color: rgba(255,255,255,.45); }
body.ubl-over-hero .ubl-header:not(.is-scrolled) .ubl-lang__toggle:hover { background: #fff; color: var(--ubl-red); border-color: #fff; }

@media (max-width: 991.98px) {
    .ubl-navbar .navbar-collapse {
        background: var(--ubl-white);
        margin: 0 -1rem;
        padding: 1rem;
        border-top: 1px solid var(--ubl-gray-200);
    }
    body.ubl-over-hero .ubl-header:not(.is-scrolled) .navbar-collapse .nav-link { color: var(--ubl-ink); }
    body.ubl-over-hero .ubl-header:not(.is-scrolled) .navbar-collapse .ubl-lang__toggle { color: var(--ubl-ink); border-color: var(--ubl-gray-200); }
}

/* ===== Secciones ===== */

.ubl-section { padding: var(--ubl-section-y) 0; }
.ubl-hero + .ubl-kpis + .ubl-section,
.ubl-hero + .ubl-section { padding-top: var(--ubl-section-y-sm); }
.ubl-section--gray { background: var(--ubl-gray-50); }
.ubl-section--dark { background: var(--ubl-ink); color: #fff; }
.ubl-section--dark h1, .ubl-section--dark h2, .ubl-section--dark h3 { color: #fff; }

.ubl-eyebrow {
    display: block;
    font-size: .74rem;
    font-weight: 600;
    letter-spacing: .22em;
    text-transform: uppercase;
    color: var(--ubl-red);
    margin-bottom: .75rem;
}
.ubl-section__head { max-width: 62ch; margin-bottom: clamp(2rem, 4vw, 3rem); }
.ubl-section__title { font-size: clamp(1.9rem, 3.6vw, 3rem); line-height: 1.12; margin: 0 0 1rem; }
.ubl-section__lead { font-size: clamp(1rem, 1.3vw, 1.15rem); line-height: 1.7; color: var(--ubl-gray); margin: 0; }
.ubl-section--dark .ubl-section__lead { color: rgba(255,255,255,.75); }
.ubl-empty { color: var(--ubl-gray); font-style: italic; }

/* ===== Hero ===== */

.ubl-hero {
    position: relative;
    display: flex;
    align-items: flex-end;
    min-height: clamp(520px, 78vh, 760px);
    padding: calc(var(--ubl-nav-h) + var(--ubl-topbar-h) + 3rem) 0 clamp(3rem, 6vw, 5rem);
    background: var(--ubl-ink);
    color: #fff;
    overflow: hidden;
}
.ubl-hero.has-image::before {
    content: "";
    position: absolute;
    inset: 0;
    background-image: var(--ubl-hero-img);
    background-size: cover;
    background-position: center;
}
.ubl-hero::after {
    content: "";
    position: absolute;
    inset: 0;
    background: linear-gradient(180deg, rgba(17,17,17,.45) 0%, rgba(17,17,17,.75) 100%);
}
.ubl-hero .container { position: relative; z-index: 1; }
/* El ancho se mide en rem y no en ch: el título usa la display a ~4rem, así que
   34ch de esa fuente dejaba una columna angosta que partía el titular palabra
   por palabra. */
.ubl-hero__body { max-width: min(46rem, 100%); }
.ubl-hero__title {
    color: #fff;
    font-size: clamp(2.4rem, 5.5vw, 4.2rem);
    line-height: 1.05;
    margin: 0 0 1.25rem;
}
.ubl-hero__lead {
    font-size: clamp(1.02rem, 1.4vw, 1.2rem);
    line-height: 1.7;
    color: rgba(255,255,255,.85);
    margin: 0 0 1.75rem;
    max-width: 52ch;
}

/* ===== KPIs ===== */

/* En el material de marca el rojo es acento sobre blanco, nunca un bloque a
   todo ancho: como franja llena se leía marrón y se comía el hero. */
.ubl-kpis { padding: clamp(2rem, 4vw, 3rem) 0; border-bottom: 1px solid var(--ubl-gray-200); }
.ubl-kpis__grid { display: grid; grid-template-columns: repeat(4, 1fr); }
.ubl-kpi { text-align: center; padding: 0 1rem; border-left: 1px solid var(--ubl-gray-200); }
.ubl-kpi:first-child { border-left: 0; }
.ubl-kpi__value {
    display: block;
    font-family: var(--ubl-font-display);
    font-size: clamp(2rem, 4vw, 3.1rem);
    font-weight: 500;
    letter-spacing: -.03em;
    font-variant-numeric: tabular-nums;
    color: var(--ubl-red);
}
.ubl-kpi__label {
    display: block;
    font-size: .7rem;
    letter-spacing: .18em;
    text-transform: uppercase;
    color: var(--ubl-gray);
    margin-top: .4rem;
}
@media (max-width: 767.98px) {
    .ubl-kpis__grid { grid-template-columns: repeat(2, 1fr); gap: 1.5rem 0; }
    .ubl-kpi:nth-child(odd) { border-left: 0; }
}

/* ===== ADN ===== */

.ubl-adn { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 1.5rem; }
.ubl-adn__item {
    position: relative;
    padding: 1.75rem 1.5rem;
    background: var(--ubl-gray-50);
    border-top: 3px solid var(--ubl-red);
    transition: transform .4s var(--ubl-ease), box-shadow .4s var(--ubl-ease), background-color .3s ease;
}
/* El filete se dibuja sobre el borde superior que la tarjeta ya trae, en vez de
   abajo como en servicios: es el mismo gesto, en el lado que le corresponde. */
.ubl-adn__item::after {
    content: '';
    position: absolute;
    left: 0;
    top: -3px;
    height: 3px;
    width: 100%;
    background: var(--ubl-red-dark);
    transform: scaleX(0);
    transform-origin: left;
    transition: transform .45s var(--ubl-ease);
}
.ubl-adn__item:hover,
.ubl-adn__item:focus-within {
    transform: translateY(-8px);
    background: #fff;
    box-shadow: 0 22px 45px rgba(0, 0, 0, .10);
}
.ubl-adn__item:hover::after,
.ubl-adn__item:focus-within::after { transform: scaleX(1); }
.ubl-adn__icon {
    display: block;
    font-size: 1.6rem;
    color: var(--ubl-red);
    margin-bottom: .75rem;
    transition: transform .4s var(--ubl-ease);
}
.ubl-adn__item:hover .ubl-adn__icon { transform: translateY(-3px) scale(1.12); }
.ubl-adn__title { font-size: 1.05rem; margin: 0 0 .5rem; }
.ubl-adn__text { font-size: .93rem; line-height: 1.65; color: var(--ubl-gray); margin: 0; }

/* ===== Servicios ===== */

.ubl-services { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 1.75rem; }
.ubl-service {
    position: relative;
    background: #fff;
    border: 1px solid var(--ubl-gray-200);
    padding: 2rem 1.75rem;
    transition: transform .4s var(--ubl-ease), box-shadow .4s var(--ubl-ease), border-color .3s ease;
}
/* La regla roja se dibuja de izquierda a derecha al entrar el puntero: es el
   mismo gesto del filete rojo del deck, no un color nuevo. */
.ubl-service::after {
    content: '';
    position: absolute;
    left: 0;
    bottom: -1px;
    height: 3px;
    width: 100%;
    background: var(--ubl-red);
    transform: scaleX(0);
    transform-origin: left;
    transition: transform .45s var(--ubl-ease);
}
.ubl-service:hover,
.ubl-service:focus-within {
    transform: translateY(-8px);
    box-shadow: 0 22px 45px rgba(0, 0, 0, .10);
    border-color: var(--ubl-gray-100);
}
.ubl-service:hover::after,
.ubl-service:focus-within::after { transform: scaleX(1); }
.ubl-service__icon {
    display: block;
    font-size: 2rem;
    color: var(--ubl-red);
    margin-bottom: 1rem;
    transition: transform .4s var(--ubl-ease);
}
.ubl-service:hover .ubl-service__icon { transform: translateY(-3px) scale(1.12); }
.ubl-service__title { font-size: 1.25rem; margin: 0 0 .65rem; }
.ubl-service__text { color: var(--ubl-gray); line-height: 1.7; margin: 0 0 1.25rem; }
.ubl-chips { list-style: none; display: flex; flex-wrap: wrap; gap: .4rem; padding: 0; margin: 0; }
.ubl-chip {
    padding: .3rem .75rem;
    border-radius: 999px;
    background: var(--ubl-gray-100);
    color: var(--ubl-ink);
    font-size: .74rem;
    font-weight: 600;
    letter-spacing: .02em;
    transition: background-color .35s ease, color .35s ease;
}
.ubl-service:hover .ubl-chip {
    background: rgba(var(--ubl-red-rgb), .09);
    color: var(--ubl-red);
}

/* El botón solo aparece cuando el script pudo hacerse cargo del panel; sin JS
   los atributos quedan visibles y un botón muerto sobraría. */
.ubl-service__toggle { display: none; }
.ubl-service__toggle.is-enhanced {
    display: inline-flex;
    align-items: center;
    gap: .45rem;
    margin-top: 1.25rem;
    padding: 0;
    border: 0;
    background: none;
    font-family: var(--ubl-font-display);
    font-size: .78rem;
    font-weight: 700;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--ubl-red);
    cursor: pointer;
    transition: gap .3s var(--ubl-ease);
}
.ubl-service__toggle.is-enhanced:hover { gap: .8rem; }
.ubl-service__toggle .bi { transition: transform .35s var(--ubl-ease); }
.ubl-service__toggle[aria-expanded="true"] .bi { transform: rotate(180deg); }
.ubl-service__toggle:focus-visible { outline: 2px solid var(--ubl-red); outline-offset: 3px; }

/* El panel se muestra u oculta con `display` y la entrada la hace una animación
   sobre la lista. Animar la altura del contenedor obliga a que la transición
   llegue a destino para que el contenido exista; así, si el navegador
   estrangula las animaciones, los atributos igual quedan a la vista. */
.ubl-service__toggle.is-enhanced ~ .ubl-service__more { display: none; margin-top: 1rem; }
.ubl-service__toggle.is-enhanced ~ .ubl-service__more.is-open { display: block; }
.ubl-service__more.is-open .ubl-service__highlights { animation: ubl-more-in .45s var(--ubl-ease) both; }
@keyframes ubl-more-in { from { opacity: 0; transform: translateY(-8px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) {
    .ubl-service__more.is-open .ubl-service__highlights { animation: none; }
}
.ubl-service__highlights {
    list-style: none;
    padding: 0;
    margin: 0;
    display: grid;
    gap: .7rem;
}
.ubl-service__highlights li {
    position: relative;
    padding-left: 1.1rem;
    font-size: .88rem;
    line-height: 1.6;
    color: var(--ubl-gray);
}
.ubl-service__highlights li::before {
    content: '';
    position: absolute;
    left: 0;
    top: .55em;
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--ubl-red);
}

/* ===== Cobertura · mapa ===== */

.ubl-coverage__layout { display: grid; gap: clamp(1.75rem, 4vw, 3rem); }
/* Los pines van en una capa hermana sobre el mapa, con la misma caja. */
.ubl-coverage__stage { position: relative; width: 100%; max-width: 1100px; margin: 0 auto; aspect-ratio: 1994 / 1350; }
.ubl-coverage__map { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: contain; }
.ubl-coverage__pins { position: absolute; inset: 0; }

/* El marcador ya está dibujado en el mapa: el botón solo aporta la zona
   sensible y un halo. Si además pintara un pin propio quedarían dos. */
.ubl-pin {
    position: absolute;
    transform: translate(-50%, -50%);
    display: grid;
    place-items: center;
    width: 8%;
    aspect-ratio: 1;
    padding: 0;
    border: 0;
    background: none;
    cursor: pointer;
    z-index: 2;
}
.ubl-pin__ring {
    width: 100%;
    height: 100%;
    border-radius: 50%;
    background: rgba(var(--ubl-red-rgb), .16);
    opacity: 0;
    transform: scale(.4);
    transition: opacity .3s ease, transform .4s var(--ubl-ease);
}
.ubl-pin:hover .ubl-pin__ring,
.ubl-pin:focus-visible .ubl-pin__ring,
.ubl-pin.is-active .ubl-pin__ring {
    opacity: 1;
    transform: scale(1);
    box-shadow: 0 0 0 2px rgba(var(--ubl-red-rgb), .35);
}
.ubl-pin:focus-visible { outline: 3px solid color-mix(in srgb, var(--ubl-red) 55%, transparent); outline-offset: 4px; border-radius: 50%; }

.ubl-warehouses {
    list-style: none;
    padding: 0;
    margin: 0 0 1.5rem;
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
    gap: 0 clamp(1.5rem, 3vw, 2.5rem);
}
.ubl-warehouse {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: 1rem;
    padding: 1.15rem 0;
    border-top: 1px solid var(--ubl-gray-200);
    cursor: default;
    transition: opacity .25s ease, border-color .25s ease;
    opacity: .55;
}
.ubl-warehouse.is-active { opacity: 1; border-top-color: var(--ubl-red); }
.ubl-warehouse__num {
    font-family: var(--ubl-font-display);
    font-size: .8rem;
    font-weight: 700;
    color: var(--ubl-red);
    letter-spacing: .08em;
    padding-top: .15rem;
}
.ubl-warehouse__name { font-size: 1.15rem; margin: 0 0 .15rem; }
.ubl-warehouse__place { font-size: .84rem; color: var(--ubl-gray); margin: 0 0 .4rem; letter-spacing: .04em; text-transform: uppercase; }
.ubl-warehouse__detail { font-size: .92rem; color: var(--ubl-gray); line-height: 1.6; margin: 0; }
.ubl-coverage__ports {
    display: flex;
    gap: .6rem;
    align-items: flex-start;
    font-size: .9rem;
    line-height: 1.6;
    color: var(--ubl-ink);
    border-left: 3px solid var(--ubl-red);
    padding: .25rem 0 .25rem 1rem;
    margin: 0;
}
.ubl-coverage__ports i { color: var(--ubl-red); }

@media (max-width: 767.98px) {
    /* Apiladas, la fila de arriba de cada ficha hace de separador. */
    .ubl-warehouse + .ubl-warehouse { border-top: 1px solid var(--ubl-gray-200); }
}

/* ===== Ley 30-24 · anillo EOL ===== */

/* La diagonal es el recurso de composición del deck. Acá entra como un lavado
   rojo muy bajo detrás de la sección: da profundidad sin meter un color nuevo
   ni otro bloque oscuro (el contacto ya venía inmediatamente después). */
.ubl-eol { position: relative; overflow: hidden; }
.ubl-eol::before {
    content: '';
    position: absolute;
    top: -20%;
    right: -14%;
    width: 60%;
    height: 140%;
    background: linear-gradient(135deg, rgba(var(--ubl-red-rgb), .07), rgba(var(--ubl-red-rgb), 0) 62%);
    transform: skewX(-12deg);
    pointer-events: none;
}
.ubl-eol > .container { position: relative; }

.ubl-eol__intro { max-width: 56ch; margin-bottom: clamp(2rem, 4vw, 3.5rem); }

.ubl-eol__wheel {
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    align-items: center;
    gap: clamp(1.5rem, 3vw, 3rem);
}
.ubl-eol__col { display: flex; flex-direction: column; justify-content: space-between; gap: clamp(1.75rem, 3vw, 3rem); }

.ubl-eol__item { cursor: default; transition: transform .35s var(--ubl-ease); }
.ubl-eol__item--left { text-align: right; }
.ubl-eol__item--right { text-align: left; }
.ubl-eol__item-title {
    font-size: clamp(1rem, 1.25vw, 1.2rem);
    margin: 0 0 .5rem;
    transition: color .3s ease;
}
.ubl-eol__item-text {
    color: var(--ubl-gray);
    font-size: .93rem;
    line-height: 1.65;
    margin: 0;
    max-width: 34ch;
    transition: color .3s ease;
}
.ubl-eol__item--left .ubl-eol__item-text { margin-left: auto; }

/* Pareja resaltada: el JS marca a la vez la porción y su bloque de texto, así
   que da igual por cuál de los dos entre el puntero. */
.ubl-eol__item.is-active .ubl-eol__item-title { color: var(--ubl-red); }
.ubl-eol__item.is-active .ubl-eol__item-text { color: var(--ubl-ink); }
.ubl-eol__item--left.is-active { transform: translateX(-6px); }
.ubl-eol__item--right.is-active { transform: translateX(6px); }

.ubl-eol__donut {
    position: relative;
    width: clamp(280px, 32vw, 440px);
    aspect-ratio: 1;
    flex: none;
}
.ubl-eol__svg { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }

/* Rojo y negro alternados, como en la lámina. Con un número impar de ítems la
   alternancia se corta en la última porción; es el único caso y se prefiere
   eso a repintar el anillo entero. */
.ubl-eol__slice {
    fill: var(--ubl-ink);
    cursor: pointer;
    transform-origin: center;
    transition: transform .4s var(--ubl-ease), fill .3s ease, filter .3s ease;
}
.ubl-eol__slice:nth-of-type(odd) { fill: var(--ubl-red); }
.ubl-eol__slice.is-active {
    transform: translate(calc(var(--ubl-dx) * 1px), calc(var(--ubl-dy) * 1px));
    filter: drop-shadow(0 6px 16px rgba(0, 0, 0, .28));
}
.ubl-eol__slice.is-active { fill: var(--ubl-black); }
.ubl-eol__slice:nth-of-type(odd).is-active { fill: var(--ubl-red-dark); }

.ubl-eol__hub-bg { fill: var(--ubl-red); }

/* Los iconos van en HTML encima del SVG: bootstrap-icons es una fuente y no
   entra en un <svg> sin foreignObject. El translate replica el del hover de su
   porción para que salgan juntos. */
.ubl-eol__ico {
    position: absolute;
    transform: translate(-50%, -50%);
    color: #fff;
    font-size: clamp(1.1rem, 2.4vw, 1.75rem);
    line-height: 1;
    pointer-events: none;
    transition: transform .4s var(--ubl-ease);
}
.ubl-eol__ico.is-active {
    transform: translate(-50%, -50%) translate(calc(var(--ubl-dx) * 1%), calc(var(--ubl-dy) * 1%)) scale(1.12);
}

.ubl-eol__hub {
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    width: 40%;
    text-align: center;
    font-family: var(--ubl-font-display);
    font-size: clamp(.72rem, 1.1vw, .95rem);
    font-weight: 700;
    letter-spacing: .08em;
    color: #fff;
    pointer-events: none;
}

@media (prefers-reduced-motion: reduce) {
    .ubl-eol__slice, .ubl-eol__ico, .ubl-eol__item { transition: none; }
    .ubl-eol__slice.is-active, .ubl-eol__ico.is-active, .ubl-eol__item.is-active { transform: none; }
    .ubl-eol__ico.is-active { transform: translate(-50%, -50%); }
}

/* Debajo de 992px las columnas laterales no caben al lado del anillo: el
   gráfico pasa arriba y los seis textos bajan a una sola columna. Como todos
   están visibles siempre, no se pierde nada al reordenar. */
@media (max-width: 991.98px) {
    .ubl-eol__wheel { grid-template-columns: 1fr; justify-items: center; }
    .ubl-eol__donut { order: -1; width: min(82vw, 380px); }
    .ubl-eol__col { width: 100%; }
    .ubl-eol__item--left, .ubl-eol__item--right { text-align: left; }
    .ubl-eol__item--left .ubl-eol__item-text { margin-left: 0; }
    .ubl-eol__item-text { max-width: none; }
    .ubl-eol__item--left.is-active, .ubl-eol__item--right.is-active { transform: translateX(4px); }
}

/* ===== Clientes y certificaciones ===== */

.ubl-logos { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 2rem 2.5rem; align-items: center; }
.ubl-certs {
    display: grid;
    grid-template-columns: 1.4fr .6fr;
    gap: clamp(1.5rem, 4vw, 3.5rem);
    align-items: center;
    margin-top: clamp(2.5rem, 5vw, 4rem);
    padding-top: clamp(2rem, 4vw, 3rem);
    border-top: 1px solid var(--ubl-gray-200);
}
.ubl-certs__title { font-size: clamp(1.4rem, 2.4vw, 2rem); margin: 0 0 1rem; }
.ubl-certs__text { color: var(--ubl-gray); line-height: 1.75; margin: 0 0 .85rem; max-width: 62ch; }
.ubl-certs__text:last-child { margin-bottom: 0; }
.ubl-certs__list { display: flex; flex-wrap: wrap; gap: clamp(1.25rem, 2.5vw, 2rem); align-items: center; }
/* Los sellos traen su propia bajada de texto (BASC, "Operador Económico
   Autorizado"): por debajo de ~100px dejan de leerse. */
.ubl-certs__logo { max-height: 104px; max-width: 170px; width: auto; height: auto; }
/* Sello de respaldo mientras no haya logo cargado en el panel. */
.ubl-certs__seal {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 5.5rem;
    padding: .9rem 1.3rem;
    border: 2px solid var(--ubl-red);
    border-radius: 999px;
    font-family: var(--ubl-font-display);
    font-size: 1rem;
    font-weight: 700;
    letter-spacing: .12em;
    color: var(--ubl-red);
}
@media (max-width: 767.98px) {
    .ubl-certs { grid-template-columns: 1fr; }
}
.ubl-logos__item { display: flex; align-items: center; justify-content: center; }
.ubl-logos__item img { max-width: 100%; max-height: 54px; width: auto; filter: grayscale(1); opacity: .75; transition: filter .2s ease, opacity .2s ease; }
.ubl-logos__item img:hover { filter: none; opacity: 1; }

/* ===== Contacto ===== */

.ubl-contact-data { margin: 2rem 0 0; }
.ubl-contact-data dt { font-size: .72rem; letter-spacing: .18em; text-transform: uppercase; color: var(--ubl-red); margin-top: 1.25rem; }
.ubl-contact-data dd { margin: .25rem 0 0; color: var(--ubl-ink); }

/* El formulario lo arma el módulo Forms con clases de Bootstrap; el tema no
   toca ese markup, solo lo reviste desde acá. Por eso todo cuelga de .ubl-form,
   que es la clase que el partial recibe como `extra_class`. */
.ubl-form {
    background: #fff;
    border: 1px solid var(--ubl-gray-200);
    border-top: 3px solid var(--ubl-red);
    padding: clamp(1.5rem, 3vw, 2.25rem);
    box-shadow: 0 24px 60px rgba(0, 0, 0, .06);
}
.ubl-form .form-label {
    font-family: var(--ubl-font-display);
    font-size: .7rem;
    font-weight: 700;
    letter-spacing: .14em;
    text-transform: uppercase;
    color: var(--ubl-gray);
    margin-bottom: .4rem;
}
.ubl-form .form-label .text-danger { color: var(--ubl-red) !important; }
.ubl-form .form-control,
.ubl-form .form-select {
    border-radius: 2px;
    border: 1px solid var(--ubl-gray-200);
    background: var(--ubl-gray-50);
    padding: .75rem .9rem;
    font-size: .95rem;
    color: var(--ubl-ink);
    transition: background-color .25s ease, border-color .25s ease, box-shadow .25s ease;
}
.ubl-form .form-control::placeholder { color: var(--ubl-gray-300); }
.ubl-form .form-control:focus,
.ubl-form .form-select:focus {
    background: #fff;
    border-color: var(--ubl-red);
    box-shadow: 0 0 0 3px rgba(var(--ubl-red-rgb), .12);
}
.ubl-form textarea.form-control { min-height: 8rem; resize: vertical; }

/* El botón lo emite el módulo como .btn-primary: se reviste con las propias
   variables de Bootstrap para que quede igual al .ubl-btn--primary del tema. */
.ubl-form .btn-primary {
    --bs-btn-bg: var(--ubl-red);
    --bs-btn-border-color: var(--ubl-red);
    --bs-btn-hover-bg: var(--ubl-red-dark);
    --bs-btn-hover-border-color: var(--ubl-red-dark);
    --bs-btn-active-bg: var(--ubl-red-dark);
    --bs-btn-active-border-color: var(--ubl-red-dark);
    --bs-btn-disabled-bg: var(--ubl-gray-300);
    --bs-btn-disabled-border-color: var(--ubl-gray-300);
    --bs-btn-focus-shadow-rgb: var(--ubl-red-rgb);
    --bs-btn-border-radius: 999px;
    --bs-btn-padding-x: 1.7rem;
    --bs-btn-padding-y: .8rem;
    --bs-btn-font-family: var(--ubl-font-display);
    --bs-btn-font-size: .92rem;
    --bs-btn-font-weight: 700;
    transition: transform .25s var(--ubl-ease);
}
.ubl-form .btn-primary:hover { transform: translateY(-2px); }
.ubl-form .alert { border-radius: 2px; }
.ubl-form .form-errors:empty { display: none; }

/* ===== Páginas sueltas y errores ===== */

.ubl-page-hero { background: var(--ubl-ink); color: #fff; padding: calc(var(--ubl-nav-h) + 2rem) 0 2.5rem; }
.ubl-page-hero__title { color: #fff; font-size: clamp(1.9rem, 4vw, 3rem); margin: 0; }
.ubl-prose { max-width: 70ch; line-height: 1.8; }
.ubl-notfound { text-align: center; }

/* ===== Footer ===== */

.ubl-footer { background: var(--ubl-black); color: rgba(255,255,255,.75); padding: clamp(2.5rem, 5vw, 4rem) 0 1.5rem; }
.ubl-footer__logo { display: block; height: 42px; width: auto; }
.ubl-footer__tagline { margin: .75rem 0 1rem; font-size: .92rem; line-height: 1.6; }
.ubl-footer__title { font-size: .72rem; letter-spacing: .18em; text-transform: uppercase; color: #fff; margin: 0 0 .5rem; }
.ubl-footer__text { font-size: .92rem; line-height: 1.6; margin: 0; }
.ubl-footer__link { color: var(--ubl-red); font-size: .9rem; text-decoration: none; }
.ubl-footer__social { display: flex; gap: .75rem; font-size: 1.15rem; }
.ubl-footer__social a { color: rgba(255,255,255,.7); }
.ubl-footer__social a:hover { color: #fff; }
.ubl-footer__menu { list-style: none; display: flex; flex-wrap: wrap; gap: 1.25rem; padding: 0; margin: 2rem 0 0; }
.ubl-footer__menu a { color: rgba(255,255,255,.7); font-size: .88rem; text-decoration: none; }
.ubl-footer__bottom {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    margin-top: 2rem;
    padding-top: 1.25rem;
    border-top: 1px solid rgba(255, 255, 255, .12);
}
.ubl-footer__copy { margin: 0; font-size: .82rem; }

/* El selector se repite en el footer, que es oscuro: se invierte el botón. */
.ubl-footer .ubl-lang__toggle { color: rgba(255, 255, 255, .85); border-color: rgba(255, 255, 255, .25); }
.ubl-footer .ubl-lang__toggle:hover { background: #fff; color: var(--ubl-red); border-color: #fff; }

/* ===== Motion ===== */

/* El estado oculto se aplica SOLO si el JS confirmó que puede animar (clase en
   <html>). Si el script falla o el observer nunca dispara, el contenido se ve
   igual: antes dependía de JS para ser visible, que es al revés de lo que conviene. */
/* El estado oculto se declara sobre `:not(.is-visible)` y el visible no declara
   transform en absoluto. Si el visible lo fijara en `none`, esa regla le ganaría
   por especificidad al `:hover` de cada tarjeta y la elevación nunca ocurriría
   (pasaba en servicios y en el ADN). Así, una vez revelado, el elemento vuelve
   a su transform por defecto y cada componente manda sobre el suyo. */
.ubl-js .ubl-reveal {
    transition: opacity .8s var(--ubl-ease), transform .8s var(--ubl-ease);
    transition-delay: var(--reveal-delay, 0ms);
}
.ubl-js .ubl-reveal:not(.is-visible) {
    opacity: 0;
    transform: translateY(44px) scale(.97);
}

/* Variantes direccionales: cada bloque entra desde el lado que ocupa en la
   grilla, así el movimiento acompaña la lectura en vez de cruzarla. */
.ubl-js .ubl-reveal--left:not(.is-visible) { transform: translateX(-52px); }
.ubl-js .ubl-reveal--right:not(.is-visible) { transform: translateX(52px); }

@media (prefers-reduced-motion: reduce) {
    .ubl-reveal { opacity: 1; transform: none; transition: none; }
    .ubl-btn, .ubl-pin, .ubl-service, .ubl-adn__item, .ubl-lang__toggle { transition: none; }
    .ubl-service:hover, .ubl-adn__item:hover, .ubl-form .btn-primary:hover { transform: none; }
}

/* ===== Navbar toggler ===== */

/* El icono de hamburguesa de Bootstrap es oscuro: sobre el hero, con el header
   transparente, quedaba invisible. */
.ubl-navbar .navbar-toggler { border-color: rgba(0, 0, 0, .18); padding: .35rem .5rem; }
.ubl-navbar .navbar-toggler:focus { box-shadow: 0 0 0 .2rem color-mix(in srgb, var(--ubl-red) 28%, transparent); }
body.ubl-over-hero .ubl-header:not(.is-scrolled) .navbar-toggler { border-color: rgba(255, 255, 255, .55); }
body.ubl-over-hero .ubl-header:not(.is-scrolled) .navbar-toggler-icon { filter: invert(1) brightness(2); }

/* ===== Marco del deck ===== */

/* Barra roja superior: en el PDF cruza las 13 láminas. En una web de scroll
   continuo repetirla por sección se vería raro, así que va una sola vez arriba. */
.ubl-topbar {
    position: fixed;
    inset: 0 0 auto 0;
    z-index: 1040;
    height: var(--ubl-topbar-h);
    background: var(--ubl-red);
}

/* Con sesión abierta el CMS inyecta su barra de administración fija arriba. Su
   middleware empuja los headers de una lista de clases que no incluye las de
   este tema, y tampoco podría: son dos elementos fijos apilados. Se resuelve
   acá, que es donde se sabe el orden. */
body.cms-has-admin-bar .ubl-topbar { top: var(--cms-admin-bar-height, 46px); }
body.cms-has-admin-bar .ubl-header { top: calc(var(--cms-admin-bar-height, 46px) + var(--ubl-topbar-h)); }
body.cms-has-admin-bar.ubl-solid-nav {
    padding-top: calc(var(--cms-admin-bar-height, 46px) + var(--ubl-nav-h) + var(--ubl-topbar-h)) !important;
}

/* Etiqueta numerada arriba a la derecha, como el "02 QUIÉNES SOMOS" del deck. */
.ubl-seclabel {
    text-align: right;
    font-family: var(--ubl-font-display);
    font-size: .78rem;
    letter-spacing: .12em;
    text-transform: uppercase;
    color: var(--ubl-gray);
    margin: 0 0 clamp(1.5rem, 3vw, 2.5rem);
}
.ubl-seclabel strong { color: var(--ubl-ink); font-weight: 700; }
.ubl-section--gray .ubl-seclabel strong { color: var(--ubl-ink); }

/* Pie de lámina: logo tenue + línea punteada. Va una vez, antes del footer. */
.ubl-deckfoot {
    display: flex;
    align-items: center;
    gap: 1.25rem;
    padding: 1.5rem 0 0;
    border-top: 2px dotted var(--ubl-gray-300);
    margin-top: clamp(2rem, 5vw, 4rem);
}
.ubl-deckfoot__logo { height: 30px; width: auto; opacity: .3; }
