/* ============================================================
   MUFAH SOLUTIONS — MOVIMIENTO Y CURSOR
   Un solo lugar para los tiempos, las curvas y el cursor del
   sitio, el cotizador y los demos. Los tres cargan ESTE archivo:
   el sitio y el cotizador directo, los demos por su lista
   (showroom/comun.lista). Si algo se mueve distinto en una de
   las tres piezas, el error está aquí y se arregla aquí.

   Las reglas son las del kit, bloque 07:
     GEOMÉTRICO  todo va en ejes de 45° y 90°, como el isotipo
     SERENO      sin rebotes; entra, se asienta y se queda
     BREVE       nada de interfaz pasa de 400 ms

   NO SE ESCRIBEN NÚMEROS AQUÍ. Los tiempos y las curvas salen de
   los tokens del kit (--dur-micro, --dur-ui, --dur-entrada,
   --curva-ui, --curva-entrada). El bloque de abajo lo copia
   herramientas/kit.js; si el kit cambia, se corre ese comando.
   ============================================================ */

/* KIT:INICIO · copiado por herramientas/kit.js de MUFAH-BRAND-KIT/10-WEB/MUFAH-TOKENS-WEB.css. No se edita a mano. */
:root {
  /* ── Color de marca ── */
  --mufah-navy: #0C2340;
  --mufah-azul: #2E6FD8;
  --mufah-celeste: #BFD9FF;
  --mufah-gris: #6B7686;
  --mufah-niebla: #F2F3F5;
  /* ── Escalas de UI ── */
  --navy-50: #F0F2F4;
  --navy-100: #DDE0E4;
  --navy-200: #BBC1CA;
  --navy-300: #929CA9;
  --navy-400: #556579;
  --navy-500: #0C2340;
  --navy-600: #0A1D36;
  --navy-700: #08182D;
  --navy-800: #061323;
  --navy-900: #050D18;
  --navy-950: #03080F;
  --azul-50: #F2F6FD;
  --azul-100: #E2EBFA;
  --azul-200: #C4D7F4;
  --azul-300: #A1BEED;
  --azul-400: #6D9AE4;
  --azul-500: #2E6FD8;
  --azul-600: #275DB5;
  --azul-700: #204E97;
  --azul-800: #193C75;
  --azul-900: #112A52;
  --azul-950: #0B1B34;
  --gris-50: #F6F7F8;
  --gris-100: #EAECEE;
  --gris-200: #D6D9DD;
  --gris-300: #BCC1C9;
  --gris-400: #979FAA;
  --gris-500: #6B7686;
  --gris-600: #5A6371;
  --gris-700: #4B535E;
  --gris-800: #3A4048;
  --gris-900: #292D33;
  --gris-950: #1A1C20;
  /* ── Funcionales ── */
  --fn-exito: #2E7D5B;
  --fn-error: #B4443C;
  --fn-advertencia: #C08A2E;
  --fn-informacion: #2E6FD8;
  /* ── Tipografía ── */
  --tipo-titulos: 'Archivo', Helvetica, Arial, sans-serif;
  --tipo-datos: 'DM Mono', ui-monospace, monospace;
  /* ── Espaciado (base 4) ── */
  --esp-1: 4px;
  --esp-2: 8px;
  --esp-3: 16px;
  --esp-4: 24px;
  --esp-5: 40px;
  --esp-6: 64px;
  /* ── Radios ── */
  --radio-s: 6px;
  --radio-m: 10px;
  --radio-l: 14px;
  --radio-completo: 9999px;
  /* ── Sombras ── */
  --sombra-card: 0 10px 28px rgba(12,35,64,0.10);
  --sombra-flotante: 0 16px 36px rgba(12,35,64,0.16);
  /* ── Movimiento ── */
  --curva-ui: cubic-bezier(0.2, 0, 0, 1);
  --curva-entrada: cubic-bezier(0.16, 1, 0.3, 1);
  --dur-micro: 150ms;
  --dur-ui: 250ms;
  --dur-entrada: 400ms;
}
/* KIT:FIN */

/* Dos ritmos que el kit define en su bloque 07 (el cargador) y que no
   vienen en el archivo de tokens. Se escriben aquí UNA vez:
     «El nodo azul gira 90° cada 600 ms con una pausa de 200 ms.»
   La media vuelta del rombo de la portada va a esa misma velocidad. */
:root {
  --dur-giro: 600ms;     /* un cuarto de vuelta */
  --dur-pausa: 200ms;    /* la pausa entre giros del cargador */
  --dur-intro-paso: 300ms;   /* cada tramo de la intro del logo: tres tramos, 900 ms */
}


/* ============================================================
   CURSOR
   El cursor es el rombo azul del isotipo. Sus estados salen de
   las tres piezas del logo:
     reposo       el rombo solo
     clicable     se completa el isotipo alrededor del rombo
     arrastrable  los picos se abren a los lados
     carga        picos apagados, rombo a medio giro

   Es una imagen que pinta el propio sistema, igual que la flecha
   de siempre: por eso no se retrasa ni se traba. Cada regla
   termina con el cursor normal de respaldo (auto, pointer, grab):
   si la imagen no carga, el visitante ve el de siempre. Nunca se
   esconde el cursor.

   Solo con ratón. En pantallas táctiles esto no existe, y se
   apaga también cuando la persona pidió más contraste: ahí manda
   el cursor grande de su sistema.

   Los dibujos los hace herramientas/kit.js a partir del isotipo
   del kit (assets/cursor/). Cada uno va dos veces: tamaño normal
   y al doble, para pantallas retina.

   Las reglas llevan !important a propósito: el cursor se decide
   aquí y en ningún otro lado.
   ============================================================ */
@media (hover: hover) and (pointer: fine) and (not (forced-colors: active)) and (not (prefers-contrast: more)) {
  html {
    cursor: url(../assets/cursor/cursor-reposo.png) 16 16, auto !important;
    cursor: image-set(url(../assets/cursor/cursor-reposo.png) 1x, url(../assets/cursor/cursor-reposo-2x.png) 2x) 16 16, auto !important;
  }

  /* Lo que se puede tocar */
  :is(a[href], button, summary, select, label[for], label:has(input), [role="button"], [role="option"], [role="radio"], [role="tab"],
      input:is([type="button"], [type="submit"], [type="checkbox"], [type="radio"]), [data-cursor="clic"]) {
    cursor: url(../assets/cursor/cursor-clic.png) 16 16, pointer !important;
    cursor: image-set(url(../assets/cursor/cursor-clic.png) 1x, url(../assets/cursor/cursor-clic-2x.png) 2x) 16 16, pointer !important;
  }

  /* Lo que se arrastra de lado a lado */
  :is([data-cursor="arrastra"], [role="slider"], input[type="range"]) {
    cursor: url(../assets/cursor/cursor-arrastra.png) 16 16, grab !important;
    cursor: image-set(url(../assets/cursor/cursor-arrastra.png) 1x, url(../assets/cursor/cursor-arrastra-2x.png) 2x) 16 16, grab !important;
  }
  :is([data-cursor="arrastra"], [role="slider"], input[type="range"]):active {
    cursor: url(../assets/cursor/cursor-arrastrando.png) 16 16, grabbing !important;
    cursor: image-set(url(../assets/cursor/cursor-arrastrando.png) 1x, url(../assets/cursor/cursor-arrastrando-2x.png) 2x) 16 16, grabbing !important;
  }

  /* Mientras algo carga. El giro no va en el cursor: va en la página. */
  html[data-cursor="carga"], html[data-cursor="carga"] *, [data-cursor="carga"][data-cursor], [aria-busy="true"][aria-busy] {
    cursor: url(../assets/cursor/cursor-carga.png) 16 16, progress !important;
    cursor: image-set(url(../assets/cursor/cursor-carga.png) 1x, url(../assets/cursor/cursor-carga-2x.png) 2x) 16 16, progress !important;
  }

  /* Donde se escribe vuelve el cursor de texto del sistema */
  :is(input:not([type="button"], [type="submit"], [type="checkbox"], [type="radio"], [type="range"], [type="file"]),
      textarea, [contenteditable]:not([contenteditable="false"]), [data-cursor="texto"]) {
    cursor: text !important;
  }

  /* Lo apagado dice que está apagado. El selector va doble para que le gane
     a la regla de «lo que se puede tocar»: un botón apagado es las dos cosas. */
  :is(:disabled, [aria-disabled="true"]):is(:disabled, [aria-disabled="true"]) { cursor: not-allowed !important; }
}


/* ============================================================
   FOCO
   El anillo del kit: 3 px, separado 2 px. Celeste sobre fondos
   oscuros y azul sobre claros, porque el celeste sobre Niebla no
   se ve (contraste 1.3). Una sección clara lo declara con
   data-tono="claro" y todo lo que lleva dentro cambia de anillo.
   ============================================================ */
:root { --foco: var(--mufah-celeste); }
[data-tono="claro"] { --foco: var(--mufah-azul); }
[data-tono="oscuro"] { --foco: var(--mufah-celeste); }
:focus-visible { outline: 3px solid var(--foco); outline-offset: 2px; }


/* ============================================================
   EL CORTE A 45°
   La firma del rombo en imágenes y videos: la esquina de arriba
   a la derecha, cortada. Donde el navegador ya sabe hacerlo
   (corner-shape) el corte es de verdad y el anillo de foco lo
   sigue. Donde no, se recorta la pieza.

   OJO: el recorte de respaldo se come el anillo de foco, así que
   .corte va en la imagen o en el video, NUNCA en el enlace o el
   botón que lo envuelve.
   ============================================================ */
.corte { --corte: clamp(18px, 3vw, 34px); }
@supports (corner-shape: bevel) {
  .corte { border-top-right-radius: var(--corte); corner-shape: bevel; }
}
@supports not (corner-shape: bevel) {
  .corte { clip-path: polygon(0 0, calc(100% - var(--corte)) 0, 100% var(--corte), 100% 100%, 0 100%); }
}


/* ============================================================
   CARGADOR
   El del kit, tal cual: el isotipo apagado y el rombo azul que da
   un cuarto de vuelta, descansa y da otro. Es lo único del sitio
   que gira solo, y solo mientras algo carga.

     <svg class="cargador" viewBox="0 0 200 200" role="img" aria-label="Cargando">
       <path class="cargador__picos" d="…los dos picos del isotipo…"/>
       <path class="cargador__nodo" d="…el rombo…"/>
     </svg>

   movimiento.js lo arma con MUFAH_MOV.cargador().
   ============================================================ */
.cargador { width: 56px; height: 56px; display: inline-block; color: var(--mufah-navy); }
[data-tono="oscuro"] .cargador, .cargador--claro { color: #fff; }
.cargador__picos { fill: currentColor; opacity: .18; }
.cargador__nodo { fill: var(--mufah-azul); transform-box: view-box; transform-origin: 50% 50%; }
@media (prefers-reduced-motion: no-preference) {
  .cargador__nodo { animation: cargador-giro calc(var(--dur-giro) + var(--dur-pausa)) var(--curva-ui) infinite; }
  @keyframes cargador-giro { 0%, 25% { transform: rotate(0deg); } 100% { transform: rotate(90deg); } }
}


/* ============================================================
   UN MOMENTO PROTAGONISTA POR VISTA
   Todo el contenido está a la vista desde el primer cuadro. Cada
   página puede marcar UNA pieza con data-protagonista; esa pieza
   se descubre una sola vez con un corte a 45°, en el tiempo de
   entrada del kit. Nada más se mueve al llegar.

   Solo existe si movimiento.js cargó (pone .mov en <html>) y si
   la persona no pidió menos movimiento. Si el guion falla, la
   pieza simplemente está ahí.
   ============================================================ */
@media (prefers-reduced-motion: no-preference) {
  .mov [data-protagonista] { animation: descubre var(--dur-entrada) var(--curva-entrada) backwards; }
  @keyframes descubre {
    from { clip-path: polygon(0 0, 0 0, 0 0); }
    to   { clip-path: polygon(0 0, 220% 0, 0 220%); }
  }
  /* La que está más abajo espera a que se vea: movimiento.js le pone .visto.
     Se esconde con opacidad y no con el recorte: para el navegador una pieza
     recortada a cero nunca «entra en pantalla» y no avisaría. */
  .mov [data-protagonista="al-ver"]:not(.visto) { animation: none; opacity: 0; }
}


/* ============================================================
   CAMBIO DE PÁGINA
   Entre una página y otra —también hacia el cotizador y los
   demos, que viven en el mismo dominio— la página nueva se
   descubre con una cortinilla a 45° desde la esquina de arriba,
   en el tiempo de entrada del kit. La barra no se mueve: lleva
   nombre propio (barra) y por eso se queda en su lugar, y el
   rombo de «estás aquí» viaja de un enlace al otro.

   Donde el navegador no lo sabe hacer, el cambio es el de
   siempre: instantáneo. Con «reducir movimiento», solo un
   fundido corto y nada se desplaza.

   Los cambios DENTRO de una página (filtros, fichas, pantallas
   del cotizador) van por MUFAH_MOV.transicion(): mientras duran,
   <html> lleva data-vt y aquí reciben un fundido breve en vez de
   la cortinilla.

   Cada página repite esta primera regla en línea, en su <head>:
   el navegador decide si hace la cortinilla al empezar a leer el
   cuerpo, y esta hoja puede llegar después. Aquí queda para las
   páginas que no la lleven.
   ============================================================ */
@view-transition { navigation: auto; }
[data-vt-barra] { view-transition-name: barra; }

::view-transition-old(root), ::view-transition-new(root) { mix-blend-mode: normal; }

@media (prefers-reduced-motion: no-preference) {
  html:not([data-vt])::view-transition-old(root) { animation: vt-atenua var(--dur-entrada) var(--curva-ui) both; }
  html:not([data-vt])::view-transition-new(root) { animation: vt-cortinilla var(--dur-entrada) var(--curva-ui) both; }
  @keyframes vt-cortinilla {
    from { clip-path: polygon(0 0, 0 0, 0 0); }
    to   { clip-path: polygon(0 0, 250vmax 0, 0 250vmax); }
  }
  @keyframes vt-atenua { to { opacity: 0.45; } }

  html[data-vt]::view-transition-old(root), html[data-vt]::view-transition-new(root) { animation-duration: var(--dur-ui); animation-timing-function: var(--curva-ui); }
  ::view-transition-group(*) { animation-duration: var(--dur-ui); animation-timing-function: var(--curva-ui); }
}
@media (prefers-reduced-motion: reduce) {
  ::view-transition-group(*) { animation: none; }
  ::view-transition-old(*), ::view-transition-new(*) { animation-duration: var(--dur-micro); }
}


/* ============================================================
   RENGLONES
   Los titulares se reparten solos para no dejar una palabra
   colgando; los párrafos evitan la última línea de una palabra.
   ============================================================ */
:where(h1, h2, h3) { text-wrap: balance; }
:where(p, li, figcaption) { text-wrap: pretty; }


/* ============================================================
   LUZ · el filo de luz que recorre el contorno
   La animación de las fichas de antes, con dos formas de hacerla:
   .luz        para tarjetas en rejilla: un disco con el filo gira
               DETRÁS del cuerpo opaco (solo transform: lo mueve la
               tarjeta gráfica). El cuerpo va en un hijo (.luz > *).
   .luz-borde  para una pieza suelta (el chat, la tarjeta del
               cotizador): el filo gira sobre el propio borde.
   En escritorio el filo va siempre encendido, bajito, y sube al
   pasar; en pantalla táctil no existe. Con «reducir movimiento»
   queda un filo fijo.
   ============================================================ */
@property --giro-luz { syntax: '<angle>'; initial-value: 0deg; inherits: false; }
.luz { position: relative; isolation: isolate; overflow: hidden; border-radius: var(--radio-l); padding: 1.5px; }
.luz > * { position: relative; z-index: 1; border-radius: calc(var(--radio-l) - 1.5px); }
.luz::before {
  content: ''; position: absolute; left: 50%; top: 50%; width: 200%; aspect-ratio: 1; translate: -50% -50%;
  background: conic-gradient(from 0deg, transparent 0 44%, var(--mufah-azul) 52%, var(--mufah-celeste) 56%, var(--mufah-azul) 60%, transparent 68% 100%);
  opacity: 0; transition: opacity var(--dur-ui) var(--curva-ui);
}
.luz-borde { position: relative; }
.luz-borde::before {
  content: ''; position: absolute; inset: -1.5px; border-radius: inherit; pointer-events: none; padding: 1.5px;
  background: conic-gradient(from var(--giro-luz), transparent 0deg 150deg, var(--mufah-azul) 190deg, var(--mufah-celeste) 205deg, var(--mufah-azul) 220deg, transparent 260deg 360deg);
  /* Solo se pinta el aro de 1.5 px: la máscara recorta el centro, así no hay que mandarlo
     detrás de la pieza (ahí el fondo de la sección lo tapaba) */
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0); -webkit-mask-composite: xor;
  mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0); mask-composite: exclude;
  opacity: 0; transition: opacity var(--dur-ui) var(--curva-ui);
}
@media (hover: hover) {
  .luz::before, .luz-borde::before { opacity: .55; }
  .luz:hover::before, .luz:focus-within::before, .luz-borde:hover::before, .luz-borde:focus-within::before, .luz--fuerte::before { opacity: 1; }
}
@media (hover: hover) and (prefers-reduced-motion: no-preference) {
  .luz::before { animation: luz-gira 7s linear infinite; }
  .luz-borde::before { animation: luz-borde-gira 7s linear infinite; }
  @keyframes luz-gira { to { rotate: 360deg; } }
  @keyframes luz-borde-gira { to { --giro-luz: 360deg; } }
}
@media (hover: none) { .luz::before, .luz-borde::before { display: none; } }


/* ============================================================
   APARICIONES AL LLEGAR
   Las piezas con data-revela entran cuando llegan a la pantalla:
   16 px hacia arriba y opacidad, en el tiempo de entrada del kit,
   una sola vez. Van escalonadas con --orden. Solo existen si el
   guion cargó (.mov) y sin «reducir movimiento»; si no, todo está
   a la vista desde el principio.
   ============================================================ */
@media (prefers-reduced-motion: no-preference) {
  .mov [data-revela] { transition: opacity var(--dur-entrada) var(--curva-entrada), translate var(--dur-entrada) var(--curva-entrada); transition-delay: calc(var(--orden, 0) * 70ms); }
  .mov [data-revela]:not(.visto) { opacity: 0; translate: 0 16px; }
}
