/* ============================================================
   Khiustin — Opción B · "Flow": brutalista B&N, grotesca pesada
   ============================================================ */

/* Fuentes alojadas en la propia web (antes Google Fonts). Licencia SIL OFL 1.1:
   assets/fonts/OFL-*.txt. Inter es variable: un archivo cubre 400–700. */
@font-face { font-family: 'Archivo Black'; font-style: normal; font-weight: 400; font-display: swap;
  src: url(../assets/fonts/archivo-black-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF; }
@font-face { font-family: 'Archivo Black'; font-style: normal; font-weight: 400; font-display: swap;
  src: url(../assets/fonts/archivo-black-latin.woff2) format('woff2');
  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; }
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 400 700; font-display: swap;
  src: url(../assets/fonts/inter-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF; }
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 400 700; font-display: swap;
  src: url(../assets/fonts/inter-latin.woff2) format('woff2');
  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; }

:root {
  --bg:    #FFFFFF;
  --ink:   #0A0A0A;
  --soft:  #6E6E6E;
  --line:  rgba(10,10,10,0.14);
  --dark:  #0E0E0E;

  --disp: "Archivo Black", system-ui, sans-serif;
  --sans: "Inter", system-ui, sans-serif;

  --ink-rgb: 10,10,10;            /* --ink en rgb, para aplicarlo con alpha */
  --white: #fff;
  --white-rgb: 255,255,255;
  --black: #000;
  --grafito: #1a1a1a;             /* gris casi negro: sección "Sobre mí", barra del footer */
  --placeholder: linear-gradient(135deg, #3a3a3a, #0d0d0d);   /* fondo mientras carga una imagen */

  --r-sm: 4px;                    /* esquinas de imágenes y tarjetas */
  --r-pill: 999px;                /* botones y etiquetas en píldora */

  --pad: clamp(1rem, 3vw, 2.6rem);
  /* Retícula común: 12 columnas con la misma carrilera en la portada (.pgrid)
     y en los casos de estudio (caso.css) */
  --grid12: repeat(12, minmax(0, 1fr));
  --gut: clamp(1rem, 2.4vw, 2.6rem);
  --ease: cubic-bezier(0.16, 1, 0.3, 1);
}

* { margin: 0; padding: 0; box-sizing: border-box; }
/* <picture> solo elige formato (AVIF con WebP de respaldo): no genera caja, la
   <img> de dentro se maqueta como si fuera hija directa del contenedor */
picture { display: contents; }
/* overflow-x: clip (no "hidden") en html Y body. Razones: (a) `hidden` solo en body
   no impide el paneo lateral en varios navegadores móviles —de ahí el scroll
   horizontal en móvil/tablet—; (b) `clip` NO crea contenedor de scroll, así que a
   diferencia de `hidden` no rompe el `position: sticky` del scroll horizontal de
   proyectos3 ni el anclaje de los elementos fijos. */
html { -webkit-font-smoothing: antialiased; scroll-behavior: smooth; overflow-x: clip; }
body { background: var(--bg); color: var(--ink); font-family: var(--sans); line-height: 1.32; overflow-x: clip; }
img { max-width: 100%; display: block; }
a { color: inherit; text-decoration: none; }
em { font-style: italic; }
sup { font-size: 0.28em; vertical-align: super; font-family: var(--sans); font-weight: 500; }
::selection { background: var(--ink); color: var(--bg); }

.reveal { opacity: 0; transform: translateY(26px); transition: opacity .9s var(--ease), transform .9s var(--ease); }
.reveal.is-in { opacity: 1; transform: none; }

.ulink { display: inline-block; font-weight: 500; border-bottom: 1.5px solid var(--ink); padding-bottom: 2px; transition: opacity .3s; }
.ulink:hover { opacity: .55; }
.ulink--big { font-family: var(--sans); font-size: clamp(1.6rem, 4vw, 3rem); font-weight: 600; letter-spacing: -0.02em; }

/* ---------- Preloader ---------- */
.pre {
  position: fixed; inset: 0; z-index: 1000; background: var(--ink); color: var(--bg);
  display: flex; align-items: center; justify-content: center;
  transition: transform 1.3s var(--ease); transition-delay: 0s;   /* repliegue más lento: el panel del loader desaparece despacio */
}
.pre.is-done { transform: translateY(-101%); }
.pre__mark { font-family: var(--disp); font-size: clamp(2.5rem, 12vw, 9rem); letter-spacing: -.02em; }
.pre__count { position: absolute; right: var(--pad); bottom: var(--pad); font-family: var(--disp); font-size: clamp(2rem,7vw,5rem); opacity: .45; }

/* ---------- Nav ---------- */
.nav {
  position: fixed; top: 0; left: 0; width: 100%; z-index: 500;
  display: flex; align-items: flex-start; justify-content: space-between;
  padding: clamp(.9rem,2vw,1.5rem) var(--pad); gap: 1rem;
  font-size: .95rem; font-weight: 500;
  mix-blend-mode: difference; color: var(--white);
}
.nav__tag { font-weight: 600; letter-spacing: -.02em; font-size: 36px; line-height: 1; }
.nav__links { display: flex; gap: .55rem; align-items: center; }
.nav__links span { opacity: .55; }
.nav__links a:hover { opacity: .55; }

/* Tagline (rol) ↔ nombre: al hacer scroll >150px la tagline hace fadeOut y entra el
   nombre. Ambos ocupan el MISMO hueco (nombre en absolute sobre el rol). El header ya
   es position:fixed, así que permanece arriba durante todo el scroll. */
.nav__tag { position: relative; }
.nav__role { display: inline-block; }
.nav__role, .nav__name { transition: opacity .4s var(--ease), transform .4s var(--ease); }
.nav__name { position: absolute; left: 0; top: 0; white-space: nowrap; opacity: 0; transform: translateY(7px); pointer-events: none; }
.nav.is-scrolled .nav__role { opacity: 0; transform: translateY(-7px); pointer-events: none; }
.nav.is-scrolled .nav__name { opacity: 1; transform: none; pointer-events: auto; }

/* ============================================================
   HERO
   ============================================================ */
.hero { position: relative; min-height: 100svh; overflow: hidden; isolation: isolate; background: var(--bg); }

/* TRES FILAS de marquesina (opcion-c):
   · Fila 2 (centro): derecha→izquierda, alternando delante/detrás de la foto.
   · Filas 1 y 3: izquierda→derecha (scaleX -1 en la fila + en los glifos para que
     sean legibles) y TODAS por detrás de la foto (la scaleX crea su contexto de
     apilamiento en z-index 1 < foto z2). Desfasadas entre sí. */
.hero__mq { position: absolute; inset: 4% 0 20% 0; display: flex; flex-direction: column;
  justify-content: center; gap: clamp(.1rem, .6vh, .6rem); overflow: hidden; }
.mqrow { display: grid; align-content: center; }
.mqrow--rev { transform: scaleX(-1); z-index: 1; }
.mqrow--rev .mqtrack span { transform: scaleX(-1); }

.mqtrack {
  grid-area: 1 / 1; display: flex; align-items: center; width: max-content; white-space: nowrap;
  will-change: transform; transform: translateX(105vw);
  /* Tamaño responsivo por ANCHO y por ALTO: en pantallas bajas se reduce para no
     montarse con la tagline / el enunciado (3 filas caben en el alto disponible).
     Va en el track para que el dot herede el mismo em. */
  font-size: clamp(2.5rem, min(21vw, calc((100vh - 260px) / 2.7)), 18rem);
}
.mqtrack span {
  display: block; font-family: var(--disp);
  line-height: .9; letter-spacing: -0.035em;
  padding-right: calc(.18em + 23px);
}
/* Separador tipo "dot" entre palabras DISTINTAS (filas 1 y 3). En esas filas el
   espacio lo da el dot + sus márgenes, no el padding. */
.mqdot { flex: 0 0 auto; width: .13em; height: .13em; border-radius: 50%; background: currentColor; margin: 0 .17em; }
.mqrow--rev .mqtrack span { padding-right: 0; }
/* Espacio interno de las frases (p.ej. "DISEÑO WEB") igualado al hueco del dot
   (0.17em, como entre KHIUSTIN y KHIUSTIN): el espacio real medía 0.298em. */
.mqrow--rev .mqtrack span { word-spacing: -0.128em; }
.mqtrack--back { z-index: 1; }
.mqtrack--front { z-index: 3; }
/* Fila 2 (nombre) con dots: cada dot va en la MISMA capa que la palabra que le
   precede (delante/detrás). Por eso se ocultan por PAREJAS palabra+dot (4 hijos =
   2 delante + 2 detrás), no palabra suelta. */
.mqrow[data-row="2"] .mqtrack--back  > :nth-child(4n+1),
.mqrow[data-row="2"] .mqtrack--back  > :nth-child(4n+2) { visibility: hidden; }
.mqrow[data-row="2"] .mqtrack--front > :nth-child(4n+3),
.mqrow[data-row="2"] .mqtrack--front > :nth-child(4n)   { visibility: hidden; }
/* En el nombre, palabras más próximas (el dot ya de por sí separa mucho) */
.mqrow[data-row="2"] .mqtrack span { padding-right: 0; }
.mqrow[data-row="2"] .mqdot { margin: 0 .17em; }
.v-c .mqtrack span { opacity: .9; }

/* Velocidad ~IGUAL entre filas pero ACELERADA respecto a antes (≈231 / 249 / 266px/s)
   y CONSTANTE (entrada a juego con el bucle → sin acelerones). El DESFASE viene de:
   (a) anchos de pista distintos → bucles de distinta duración → nunca se sincronizan, y
   (b) una diferencia de velocidad MÁS marcada entre las filas 1 y 3 (mismo sentido),
   porque se veían demasiado alineadas. Duraciones = distancia / velocidad (calibrado a
   1920px): entrada = 105vw/V (=2016/V), bucle(50%) = anchoSegmento/V.
   Anchos de segmento: fila1≈8208 · fila2≈6400 · fila3≈7700px.
   ARRANQUE A 105vw (no 100vw): en las filas invertidas (scaleX -1) el borde de la pista
   caía justo en x=0 y, con el ancho del scrollbar, asomaba "la L de Drupal" antes de
   entrar; 105vw da margen y nada se ve antes de tiempo.
   ENTRADA ESCALONADA (delays 0.1 → 0.25 → 0.4s, orden fila 1 → 2 → 3): cascada CORTA
   para que los textos aparezcan pronto, con la foto al ~50% de opacidad (el desfase
   fuerte ya lo aporta la diferencia de velocidad). + fundido mqfade 0→1 por pista
   (0.5s): garantiza que nada se vea antes de entrar (opacidad 0 retenida durante el
   delay). El fundido va en .mqtrack (NO en .hero__mq ni .mqrow) para no romper el
   delante/detrás de la foto. */
body.loaded .mqrow[data-row="1"] .mqtrack { animation: mqenter 8.71s linear .1s both, mqscroll 35.49s linear 8.81s infinite, mqfade .5s linear .1s both; }  /* V≈231px/s · entra 1ª */
body.loaded .mqrow[data-row="2"] .mqtrack { animation: mqenter 8.11s linear .25s both, mqscroll 25.76s linear 8.36s infinite, mqfade .5s linear .25s both; }  /* V≈249px/s · entra 2ª */
body.loaded .mqrow[data-row="3"] .mqtrack { animation: mqenter 7.59s linear .4s both, mqscroll 28.98s linear 7.99s infinite, mqfade .5s linear .4s both; }  /* V≈266px/s · entra 3ª */
@keyframes mqenter  { from { transform: translateX(105vw); } to { transform: translateX(0); } }
@keyframes mqscroll { from { transform: translateX(0); } to { transform: translateX(-50%); } }
@keyframes mqfade   { from { opacity: 0; } to { opacity: 1; } }

/* Entrada: se dispara con body.loaded, que la JS añade CUANDO el loader ya se ha
   ido. fadeIn + slideUp; la tagline entra palabra a palabra (secuencial).
   La marquesina NO lleva opacidad (evita crear stacking context que rompa el
   z-index detrás/delante de la foto); se revela sola al retirarse el loader. */
.nav__role > span, .nav__links, .hero__statement { opacity: 0; }
/* La foto NO arranca en opacidad 0: queda pintada debajo del preloader desde el
   primer momento (es el elemento más grande de la portada y así cuenta como
   pintado enseguida para el LCP). La destapa el propio telón del preloader y al
   entrar solo se asienta con un leve zoom (propiedad scale, que no choca con
   los transform del layout móvil). */
.nav__role > span { display: inline-block; margin-right: .5em; }

body.loaded .nav__role > span:nth-child(1) { animation: fadeUp .6s var(--ease) 0s    both; }
body.loaded .nav__role > span:nth-child(2) { animation: fadeUp .6s var(--ease) .12s  both; }
body.loaded .nav__role > span:nth-child(3) { animation: fadeUp .6s var(--ease) .24s  both; }
body.loaded .nav__links      { animation: fadeUp .6s var(--ease) .36s both; }
body.loaded .hero__statement { animation: fadeUp .65s var(--ease) .44s both; }
body.loaded .hero__photo     { animation: photoIn 1.4s var(--ease) both; }
@keyframes fadeUp { from { opacity: 0; transform: translateY(24px); } to { opacity: 1; transform: none; } }
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
@keyframes photoIn { from { scale: 1.04; } to { scale: 1; } }

.hero__photo {
  position: absolute; right: clamp(1rem, 3vw, 4rem); bottom: 0; z-index: 2;
  height: min(92vh, 96vw); width: auto;
}

.hero__statement {
  position: absolute; left: var(--pad); bottom: clamp(1.5rem, 4vh, 3rem); z-index: 4;
  font-family: var(--sans); font-weight: 400;
  font-size: clamp(1.4rem, 2.4vw, 40px); line-height: 1.12; letter-spacing: -0.02em;
  max-width: min(760px, 46vw);
}

/* Marcas gigantes (servicios / misión / footer) */
.svc__word, .mission__mark span, .foot__mark span {
  font-family: var(--disp); letter-spacing: -0.035em; display: block; white-space: nowrap;
}

/* ============================================================
   STATEMENT
   ============================================================ */
.stmt { min-height: 100svh; display: flex; align-items: center;
  padding: clamp(3rem,8vh,6rem) var(--pad);
  background: var(--grafito); color: var(--bg); }      /* sección oscura: gris muy oscuro (tono de la marquesina), texto blanco */
.stmt ::selection { background: var(--white); color: var(--grafito); }
.stmt .ulink { border-color: var(--bg); }
.stmt__big {
  font-family: var(--sans); font-weight: 400;
  font-size: clamp(1.9rem, 5vw, 5rem); line-height: 1.12; letter-spacing: -0.02em;
}
/* Entrada del statement: fadeIn + slideIn con recorrido AMPLIO (120px) y LENTO (1.6s),
   para que el desplazamiento se note bien junto al fundido de opacidad. Se REPITE
   cada vez que la sección entra en pantalla: un observer dedicado (opcion-c.js)
   añade/quita .is-visible al entrar/salir.
   La transición vive SOLO en .is-visible → la ENTRADA anima; al salir se quita la
   clase y el reset al estado oculto es instantáneo y fuera de pantalla (sin salto). */
.stmt__big { opacity: 0; transform: translateY(120px); }
.stmt__big.is-visible { opacity: 1; transform: none;
  transition: opacity 1.9s cubic-bezier(0.33, 1, 0.68, 1), transform 1.9s cubic-bezier(0.33, 1, 0.68, 1); }  /* easeOutCubic: entra más suave y sostenida */
.stmt__big em { color: var(--soft); font-style: normal; }

/* ============================================================
   FOOTER
   ============================================================ */
.foot { background: var(--ink); color: var(--bg); padding: clamp(2.5rem,5vw,4rem) var(--pad) clamp(1.5rem,3vw,2rem); }
.foot ::selection { background: var(--white); color: var(--ink); }
.foot__mark { overflow: hidden; line-height: .8; flex: 1; min-width: 0; }
.foot__mark span { font-size: clamp(3.5rem, 20vw, 20rem); }
.foot .ulink { border-color: var(--bg); }
.foot__cols { display: grid; grid-template-columns: repeat(3, 1fr); gap: 2rem;
  padding: clamp(2.5rem,5vw,4rem) 0; }
.fcol { display: flex; flex-direction: column; gap: .35rem; }
.fcol a, .fcol__big { font-family: var(--sans); font-size: clamp(1.5rem,2.6vw,2.4rem); font-weight: 500; letter-spacing: -0.02em; }
.fcol a { transition: opacity .3s; } .fcol a:hover { opacity: .55; }
.foot__bar { display: flex; justify-content: space-between; flex-wrap: wrap; gap: 1rem;
  border-top: 1px solid rgba(var(--white-rgb), .18); padding-top: 1.4rem; font-size: .85rem; color: rgba(var(--white-rgb), .7); }
.foot__bar a:hover { color: var(--white); }

/* ============================================================
   Responsive
   ============================================================ */
/* En desktop MUY GRANDE la marquesina queda algo alta respecto a la foto: se baja
   ~50px moviendo la caja por inset (top +50 / bottom -50, misma altura). NO se usa
   transform: crearía un stacking context que rompería el delante/detrás de la foto. */
@media (min-width: 1600px) {
  .hero__mq { inset: calc(4% + 50px) 0 calc(20% - 50px) 0; }
  .stmt__big { font-size: clamp(5rem, 5.8vw, 7.5rem); }   /* statement aún más grande en monitores muy grandes */
}

@media (max-width: 860px) {
  .nav__links { display: none; }
  .nav__tag { font-size: 22px; }
  .hero__photo { left: 50%; right: auto; transform: translateX(-50%); height: min(86vh, 132vw); opacity: 1; }
  .hero::after { content: ""; position: absolute; inset: auto 0 0 0; height: 52%; z-index: 3;
    background: linear-gradient(to top, var(--bg) 44%, rgba(var(--white-rgb), 0)); pointer-events: none; }
  .mqtrack span { font-size: clamp(3.2rem, 30vw, 9rem); }
  .hero__statement { font-size: clamp(1.3rem, 5vw, 2rem); max-width: 88%; bottom: clamp(1.5rem,4vh,3rem); }
  .foot__cols { grid-template-columns: 1fr; gap: 2.5rem; }
}
/* "Reducir movimiento" activado: versión SUAVE, no estática. Fuera todo lo que
   desplaza, escala o barre (marquesina, parallax, deslizamientos, telón); se
   conservan los fundidos de opacidad con su mismo escalonado, para que la web
   siga viva sin mover cosas por la pantalla. Cada hoja ajusta sus propias
   entradas en su bloque prefers-reduced-motion. */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  /* Curva suave de entrada y salida en vez de la de arranque brusco (que, sin el
     desplazamiento, hacía que los fundidos parecieran saltos: en 150 ms ya iban
     por el 60%). Y fundidos de entrada algo más largos, para que se perciban. */
  :root { --ease: cubic-bezier(.4, 0, .2, 1); }
  body.loaded .nav__role > span, body.loaded .nav__links, body.loaded .hero__statement { animation-duration: 1s !important; }
  /* Las mismas animaciones de entrada, sin recorrido: solo fundido */
  @keyframes fadeUp  { from { opacity: 0; } to { opacity: 1; } }
  @keyframes photoIn { from { opacity: 1; } to { opacity: 1; } }   /* la foto no se mueve (y sigue pintada desde el inicio, por el LCP) */
  .reveal { transform: none; transition: opacity 1.2s var(--ease); }
  /* Preloader: el contador y el nombre se mantienen; el telón se funde en vez de subir */
  .pre { transition: opacity .9s var(--ease), visibility 0s .9s; }
  .pre.is-done { transform: none; opacity: 0; visibility: hidden; }
  /* Marquesina: quieta, solo aparece con un fundido */
  body.loaded .mqrow .mqtrack { animation: mqfade .9s linear .1s both !important; transform: none !important; }
  /* Statement: fundido sin el recorrido de 120px */
  .stmt__big { transform: none !important; }
}
