/* ============================================================
   Javier García — portfolio personal
   Referencia de estructura y movimiento: michaelpumo.com

   Todo lo que se anima parte de un estado inicial que SOLO se
   aplica bajo `html.js`. Sin JavaScript la página se ve entera
   y quieta, que es como debe degradar.

   1.  Tokens
   2.  Reset y base
   3.  Tipografía
   4.  Utilidades de maquetación
   5.  Hero
   6.  Píldora de disponibilidad
   7.  Botones
   8.  Entrada escalonada
   9.  Texto que se ilumina al scrollear
   10. Secciones
   11. Filas del CV
   12. Rejilla de trabajos
   13. Contacto y pie
   14. Revelado de bloques
   15. Movimiento reducido
   16. Responsive
   ============================================================ */

/* --- 1. Tokens ------------------------------------------- */
:root{
  --bg:        #0d0d0e;
  --bg-alt:    #08080a;
  --panel:     #131315;
  --text:      #f2f1ef;
  --muted:     #8e8e8c;
  --faint:     #67676a;
  --line:      rgba(255,255,255,.08);
  --accent:    #57d98a;

  --sans: "Switzer", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
          "Helvetica Neue", Arial, sans-serif;

  --pad:   clamp(1.75rem, 5vw, 4.25rem);
  --round: 999px;

  /* Curva de salida larga: entra rápido y se posa. Es la que da la
     sensación de "peso" en las entradas. */
  --ease-salida: cubic-bezier(.16, 1, .3, 1);
  --ease-suave:  cubic-bezier(.4, 0, .2, 1);
}

/* --- 2. Reset y base ------------------------------------- */
*,*::before,*::after{ box-sizing:border-box; }

html{ -webkit-text-size-adjust:100%; }

body{
  margin:0;
  background:var(--bg);
  color:var(--text);
  font-family:var(--sans);
  font-size:1rem;
  line-height:1.6;
  font-weight:400;
  -webkit-font-smoothing:antialiased;
  -moz-osx-font-smoothing:grayscale;
}

h1,h2,h3,p,ul{ margin:0; }
ul{ padding:0; list-style:none; }
img{ display:block; max-width:100%; }
a{ color:inherit; }

::selection{ background:var(--text); color:var(--bg); }

/* Barra de scroll discreta, a juego con el fondo */
::-webkit-scrollbar{ width:10px; }
::-webkit-scrollbar-track{ background:var(--bg); }
::-webkit-scrollbar-thumb{
  background:#2a2a2d; border-radius:99px;
  border:3px solid var(--bg);
}
::-webkit-scrollbar-thumb:hover{ background:#3a3a3e; }

/* Enlaces de texto: el subrayado se aviva al pasar */
.prose a, .hero__foot a, .contact a{
  text-decoration:underline;
  text-decoration-thickness:1px;
  text-underline-offset:3px;
  text-decoration-color:rgba(255,255,255,.26);
  transition:text-decoration-color .25s var(--ease-suave),
             color .25s var(--ease-suave);
}
.prose a:hover, .hero__foot a:hover, .contact a:hover{
  text-decoration-color:currentColor;
  color:#fff;
}

:focus-visible{
  outline:2px solid var(--accent);
  outline-offset:3px;
  border-radius:2px;
}

.skip{
  position:absolute; left:-9999px;
  top:.75rem; padding:.6rem 1rem;
  background:var(--text); color:var(--bg);
  border-radius:6px; font-size:.875rem; z-index:50;
}
.skip:focus{ left:.75rem; }

/* --- 3. Tipografía --------------------------------------- */
/* Lo que la saca de lo genérico no es la fuente: es el peso 300 en
   tamaños grandes, el interletrado negativo, el interlineado corto
   y una medida de línea estrecha. */
.titular{
  max-width:19ch;
  font-size:clamp(2.25rem, 4.4vw, 4rem);
  font-weight:300;
  line-height:1.08;
  letter-spacing:-.022em;
  text-wrap:pretty;
}

.grande{
  max-width:24ch;
  margin-bottom:clamp(2rem, 5vh, 3.25rem);
  font-size:clamp(1.6rem, 3.4vw, 3.25rem);
  font-weight:300;
  line-height:1.125;
  letter-spacing:-.022em;
  text-wrap:pretty;
}

.lede{
  max-width:38ch;
  font-size:clamp(.95rem, .6vw + .8rem, 1.0625rem);
  line-height:1.55;
  color:var(--muted);
}

.prose p{
  max-width:58ch;
  font-size:clamp(1rem, .45vw + .9rem, 1.0625rem);
  line-height:1.7;
  color:#c6c6c4;
}
.prose p + p{ margin-top:1.35rem; }

/* --- 4. Utilidades de maquetación ------------------------ */
.wrap{
  width:100%;
  max-width:1120px;
  margin-inline:auto;
  padding-inline:var(--pad);
}

/* --- 5. Hero --------------------------------------------- */
.hero{
  display:grid;
  grid-template-columns:1fr 1fr;
  min-height:100vh;
  min-height:100svh;
  background:var(--panel);
  overflow:hidden;          /* la imagen entra desde fuera */
}

.hero__panel{
  display:flex;
  padding:var(--pad);
  background:var(--bg);
}

/* Columna completa: la píldora arriba, el pie abajo, el bloque
   central flotando entre los dos `margin:auto`. */
.hero__inner{
  display:flex;
  flex-direction:column;
  width:100%;
  max-width:32rem;
  min-height:calc(100svh - (var(--pad) * 2));
  margin-inline:auto;
}

/* Dos `margin-top:auto` (aqui y en el pie) reparten el hueco sobrante:
   la pildora queda arriba, el pie abajo y este grupo centrado. */
.hero .titular{ margin-top:auto; }

.hero__bloque{
  margin-top:clamp(1.75rem, 4vh, 2.75rem);
}

.hero__portrait{
  position:relative;
  background:#1b1b1d;
  overflow:hidden;
}
/* Absoluta a propósito: en el flujo, el alto intrínseco de la imagen
   estira la fila del grid y el hero deja de medir una pantalla. */
.hero__portrait img{
  position:absolute;
  inset:0;
  width:100%;
  height:100%;
  object-fit:cover;
  object-position:center 8%;    /* deja aire sobre la cabeza; por encima de ~14% se corta */
}

.hero__foot{
  margin-top:auto;
  padding-top:clamp(2.5rem, 8vh, 5rem);
  font-size:.8125rem;
  line-height:1.75;
  color:var(--faint);
}
.hero__foot-alt{ margin-top:.35rem; }

/* --- 6. Marca ------------------------------------------- */
/* Ancla la parte alta del panel igual que hacia la pildora, pero sin
   pedir nada: solo dice quien firma esto. */
.marca{
  align-self:flex-start;
  font-size:.6875rem;
  font-weight:500;
  letter-spacing:.15em;
  text-transform:uppercase;
  color:var(--muted);
}

/* --- 7. Botones ------------------------------------------ */
.btn{
  align-self:flex-start;
  display:inline-block;
  margin-top:1.85rem;
  padding:.8rem 1.65rem;
  border:1px solid transparent;
  border-radius:var(--round);
  background:rgba(255,255,255,.075);
  color:var(--text);
  font-size:.9375rem;
  text-decoration:none;
  transition:background .3s var(--ease-suave),
             transform .3s var(--ease-salida);
}
.btn:hover{ background:rgba(255,255,255,.135); transform:translateY(-2px); }
.btn:active{ transform:translateY(0); }

.btn--ghost{
  margin-top:2.25rem;
  background:transparent;
  border-color:var(--line);
}
.btn--ghost:hover{ background:rgba(255,255,255,.05); }

/* --- 8. Entrada escalonada -------------------------------- */
/* La imagen entra deslizando desde la derecha; los bloques de texto
   suben un poco mientras aparecen. El JS reparte los retardos. */
.js .hero__portrait img{
  transform:translateX(101%);
}
.js .hero.entrando .hero__portrait img{
  transform:translateX(0);
  transition:transform 1.15s var(--ease-salida);
}

.js [data-entra]{
  opacity:0;
  transform:translateY(12px);
}
.js .hero.entrando [data-entra]{
  opacity:1;
  transform:none;
  transition:opacity .85s var(--ease-suave),
             transform .85s var(--ease-salida);
  transition-delay:var(--retardo, 0ms);
}

/* --- 9. Texto que se ilumina al scrollear ----------------- */
/* Cada letra va en su propio span. El JS sube la opacidad de 0.5 a 1
   siguiendo el scroll, de la primera letra a la última. */
.js [data-letras] .l{
  opacity:.5;
  transition:opacity .35s linear;
}
/* En el titular del hero la entrada es por tiempo, no por scroll:
   ahí el barrido lo marca un retardo por letra. */
.js .hero [data-letras] .l{
  transition:opacity .5s var(--ease-suave);
}
/* Las ligadas al scroll no llevan transicion: si la llevan, el brillo
   va por detras del dedo y se nota. */
.js [data-brillo] .l{ transition:none; }
.w{ display:inline-block; }   /* evita que una palabra se parta */

/* --- 10. Secciones --------------------------------------- */
.section{
  padding-block:clamp(5rem, 15vh, 9.5rem);
  border-top:1px solid var(--line);
}
.section--alt{ background:var(--bg-alt); }
.section--end{ padding-bottom:clamp(6rem, 16vh, 11rem); }

.eyebrow{
  margin-bottom:clamp(2rem, 5vh, 3.25rem);
  font-size:.6875rem;
  font-weight:500;
  letter-spacing:.16em;
  text-transform:uppercase;
  color:var(--faint);
}

.section__note{
  max-width:58ch;
  margin-bottom:clamp(2.25rem, 5vh, 3.25rem);
  color:var(--muted);
}

.signature{
  margin-top:2.25rem;
  font-size:1.0625rem;
  color:var(--muted);
}

.titular--cierre{
  max-width:16ch;
  margin-bottom:1.5rem;
}

/* --- 11. Filas del CV ------------------------------------ */
.rows{ border-top:1px solid var(--line); }

.row{
  display:grid;
  grid-template-columns:10rem 1fr;
  gap:clamp(1rem, 3vw, 2.5rem);
  padding-block:clamp(1.6rem, 3.5vh, 2.4rem);
  border-bottom:1px solid var(--line);
  transition:opacity .45s var(--ease-suave),
             border-color .45s var(--ease-suave);
}

.row__date{
  padding-top:.2rem;
  font-size:.75rem;
  letter-spacing:.09em;
  text-transform:uppercase;
  color:var(--faint);
  transition:color .45s var(--ease-suave);
}

.row__body{
  transition:transform .5s var(--ease-salida);
}

.row__body h3{
  margin-bottom:.4rem;
  font-size:1.0625rem;
  font-weight:500;
  letter-spacing:-.005em;
}
.row__body p{
  max-width:52ch;
  color:var(--muted);
}

/* --- La fila viva -----------------------------------------
   Con raton manda el puntero: se apaga toda la lista menos la fila
   señalada. Sin raton (movil) manda el scroll, y de eso se encarga
   main.js poniendo .modo-scroll y .is-activa.

   El `:not()` no es decorativo: sin el, `.reveal.is-in{opacity:1}` de
   mas abajo empata en especificidad y gana por orden, dejando la lista
   sin atenuar. */
.row__date{ transition:color .45s var(--ease-suave); }

@media (hover:hover) and (pointer:fine){
  .js .rows:hover .row:not(:hover){ opacity:.38; }
  .js .rows .row:hover{ border-bottom-color:rgba(255,255,255,.3); }
  .js .rows .row:hover .row__date{ color:#c9c9c7; }
  .js .rows .row:hover .row__body{ transform:translateX(6px); }
}

.js .rows.modo-scroll .row:not(.is-activa){ opacity:.38; }
.js .rows.modo-scroll .row.is-activa{ border-bottom-color:rgba(255,255,255,.3); }
.js .rows.modo-scroll .row.is-activa .row__date{ color:#c9c9c7; }
.js .rows.modo-scroll .row.is-activa .row__body{ transform:translateX(6px); }

/* --- 12. Rejilla de trabajos ----------------------------- */
.grid{
  display:grid;
  grid-template-columns:repeat(auto-fill, minmax(230px, 1fr));
  gap:clamp(.75rem, 1.4vw, 1.15rem);
}

.tile{
  margin:0;
  aspect-ratio:4 / 5;
  overflow:hidden;
  border-radius:3px;
  background:#18181a;
}
.tile img{
  width:100%; height:100%;
  object-fit:cover;
  transition:transform .8s var(--ease-salida);
}
.tile:hover img{ transform:scale(1.04); }

/* Las webs se enseñan apaisadas, como se ven en pantalla. Con una sola
   pieza no hace falta rejilla: basta con no dejar que crezca tanto que
   se coma la seccion. */
.webs{ max-width:820px; }

.web{ margin:0; }

.web__marco{
  position:relative;
  display:block;
  aspect-ratio:16 / 10;
  overflow:hidden;
  border:1px solid var(--line);
  border-radius:5px;
  background:#131315;
  transition:border-color .35s var(--ease-suave),
             transform .5s var(--ease-salida);
}
a.web__marco:hover{
  border-color:rgba(255,255,255,.22);
  transform:translateY(-3px);
}

/* El iframe se dibuja a tamaño de escritorio y se reduce por escala,
   para que la maqueta que se ve sea la de escritorio y no la de móvil.
   El factor lo calcula main.js según el ancho real del marco. */
.web__marco iframe{
  position:absolute;
  top:0; left:0;
  width:1440px;
  height:900px;
  border:0;
  transform-origin:top left;
  transform:scale(var(--escala, .3));
  pointer-events:none;   /* el clic es del enlace, no del iframe */
}


.web figcaption{
  margin-top:.85rem;
  font-size:.8125rem;
  color:var(--faint);
}

/* --- 13. Contacto y pie ---------------------------------- */
.contact{
  display:flex;
  flex-wrap:wrap;
  gap:.6rem 2rem;
  margin-top:2.25rem;
  font-size:1.0625rem;
}

.foot{
  padding-block:2.25rem;
  border-top:1px solid var(--line);
  font-size:.8125rem;
  color:var(--faint);
}

/* --- 14. Revelado de bloques ----------------------------- */
.js .reveal{
  opacity:0;
  transform:translateY(16px);
  transition:opacity .8s var(--ease-suave),
             transform .8s var(--ease-salida);
}
.js .reveal.is-in{ opacity:1; transform:none; }

/* --- 15. Movimiento reducido ----------------------------- */
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{
    animation-duration:.01ms !important;
    animation-iteration-count:1 !important;
    transition-duration:.01ms !important;
  }
  .js .reveal,
  .js [data-entra]{ opacity:1 !important; transform:none !important; }
  .js [data-letras] .l{ opacity:1 !important; }
  .js .rows .row{ opacity:1 !important; }
  .js .rows .row__body{ transform:none !important; }
  .js .hero__portrait img{ transform:none !important; }
}

/* --- 16. Responsive -------------------------------------- */
/* Por debajo de 900px el split se apila: el retrato arriba, el texto
   debajo. El barbero va a abrir esto en el móvil. */
@media (max-width:900px){
  .hero{
    grid-template-columns:1fr;
    min-height:0;
  }
  /* Apilada y a todo el ancho, con poca altura la foto se recorta a una
     franja y solo se ve la cara. Se fija la proporcion para que no pase. */
  .hero__portrait{
    order:-1;
    height:auto;
    aspect-ratio:5 / 4;
  }
  /* Apilado, deslizar en horizontal no tiene sentido: entra en vertical */
  .js .hero__portrait img{ transform:translateY(-8%); }
  .js .hero.entrando .hero__portrait img{
    transform:translateY(0);
    transition:transform 1.1s var(--ease-salida);
  }
  .hero__panel{ padding-block:clamp(2.5rem, 8vh, 4rem); }
  .hero__inner{ max-width:none; min-height:0; }
  .hero__foot{ margin-top:2.75rem; padding-top:0; }
  .titular{ max-width:none; }
  .grande{ max-width:none; }
}

@media (max-width:560px){
  /* En movil si compensa que ocupe alto: es lo primero que se ve. */
  .hero__portrait{
    aspect-ratio:auto;
    height:52vh;
    min-height:300px;
  }
  .row{ grid-template-columns:1fr; gap:.5rem; }
  .grid{ grid-template-columns:repeat(2, 1fr); }
  .contact{ gap:.5rem 1.25rem; font-size:1rem; }
}
