/* Portfolio de Adrián Picazo
   ---------------------------------------------------------------------------
   Todas las medidas salen de docs/figma-spec.md, medido por API contra los nodos
   2:66 (escritorio, 1512×1204) y 9:167 (móvil, 402×2140).

   Criterio responsive: a la anchura exacta del diseño el resultado es idéntico a
   Figma; fuera de ella el grid escala por aspect-ratio y las posiciones
   horizontales van en %, mientras alturas de barra y tipografía se mantienen
   dentro de un rango legible.
   --------------------------------------------------------------------------- */

@font-face {
  font-family: 'Inter';
  src: url('assets/fonts/inter-latin-var.woff2') format('woff2-variations');
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

:root {
  --design-w: 1512;

  --color-bg: #ffffff;
  --color-ink: #000000;          /* el nombre, el rol y el pie
                                    (el boceto usaba #202020) */
  --color-para: #909090;         /* solo la intro */
  --color-ink-strong: #000000;   /* footer y título de la barra */
  --color-muted: #b0b0b0;        /* subtítulo de la barra */
  --color-card-bg: #f4f4f4;      /* fondo de card mientras no hay media */

  --edge: 16px;                  /* margen lateral del header (Figma: x=16) */
  --edge-tight: 12px;            /* margen del footer y de la barra (Figma: x=12) */

  --masthead-h: 51px;
  --intro-block-h: 56px;
  --intro-offset: 16px;          /* del inicio del bloque al top del texto */
  --grid-top-gap: 40px;          /* aire entre la intro y la primera fila */
  --footer-h: 85px;
  --footer-text-top: 19px;

  --bar-h: 36px;
  --bar-pad: 12px;

  /* 12px y 10px exactos a 1512px de ancho, con suelo y techo para el resto */
  --type-ui: clamp(11px, 0.79365vw, 14px);
  --type-small: clamp(10px, 0.66138vw, 12px);

  --bar-duration: 600ms;
  --bar-ease: cubic-bezier(0.16, 1, 0.3, 1);

  --loader-size: 12px;
  --loader-spin: 1400ms;   /* dos vueltas completas */
  --buffer-size: 8px;      /* el mismo cuadrado, en pequeño, sobre un vídeo que carga */
  --buffer-blur: 14px;
}

*,
*::before,
*::after { box-sizing: border-box; }

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

body {
  margin: 0;
  background: var(--color-bg);
  color: var(--color-ink);
  font-family: 'Inter', system-ui, sans-serif;
  overflow-x: hidden;
}

body.is-locked { overflow: hidden; }

img,
video { display: block; max-width: 100%; }

.skip-link { position: absolute; left: -9999px; }
.skip-link:focus {
  left: var(--edge);
  top: 8px;
  z-index: 10;
  background: var(--color-bg);
  padding: 8px 12px;
}

/* ---------- Cabecera ---------- */

.masthead {
  position: relative;
  height: var(--masthead-h);
  font-size: var(--type-ui);
  line-height: 15px;
}

.masthead__name,
.masthead__role {
  position: absolute;
  white-space: nowrap;
}

.masthead__name {
  top: 24px;
  left: var(--edge);
  text-transform: uppercase;
}

/* El rol comparte tamaño y color con la intro. Al bajar de 12px a 10px se
   recentra ópticamente sobre la línea del nombre: 24 + (15-12)/2. Es el mismo
   cálculo que usa el boceto móvil (nombre en 20, rol en 21.5). */
.masthead__role {
  top: 25.5px;
  font-size: var(--type-small);
  line-height: 12px;
}

.masthead__role { right: var(--edge); }

/* ---------- Intro ---------- */

.intro {
  height: var(--intro-block-h);
  margin: 0;
  padding: var(--intro-offset) 0 0 var(--edge);
  color: var(--color-para);
  font-size: var(--type-small);
  line-height: 12px;
}

/* ---------- Grid ----------
   Dos columnas a sangre en escritorio, sin gaps: las cards se tocan (Figma las
   coloca en x=0 y x=756 de 1512). */

.grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0;
  margin: var(--grid-top-gap) 0 0;
  padding: 0;
  list-style: none;
  container-type: inline-size;   /* el alto de las cards se calcula sobre su ancho (cqw) */
}

/* ---------- Card ---------- */

.card { margin: 0; }

.card__frame {
  position: relative;
  overflow: hidden;              /* la barra se esconde fuera de este marco */
  aspect-ratio: 756 / 486;       /* a 1512px de ancho da los 486px de Figma */
  background: var(--color-card-bg);
}

/* Alto redondeado a píxel entero. Con el aspect-ratio a secas, a anchos como 1280
   o 390 el alto sale fraccionario (411,42px, 471,48px) y el navegador redondea por
   separado el recorte de cada card y la capa del vídeo: entre dos filas quedaba
   una línea de 1px del fondo blanco. Los navegadores sin round() se quedan con
   el aspect-ratio. Las piezas con `ratio` propio (projects.js) no se tocan. */
@supports (height: round(down, 1px, 1px)) {
  .card__frame:not([style*="aspect-ratio"]) {
    aspect-ratio: auto;
    height: round(50cqw * 486 / 756, 1px);
  }
}

.card__media {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.card__media--placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
  color: #8a8a8a;
  font-size: 10px;
  letter-spacing: 0.08em;
}

/* La barra blanca.
   Se anima SOLO transform: va en GPU y no provoca relayout. */
.card__bar {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  display: flex;
  align-items: center;
  gap: 6px;                      /* Figma: 12+52 = 64, el siguiente rótulo en 70 */
  height: var(--bar-h);
  padding: 0 var(--bar-pad);
  background: #ffffff;
  font-size: 10px;
  font-weight: 500;
  line-height: 12px;
  font-family: 'Inter', system-ui, sans-serif;
  text-transform: uppercase;      /* los rótulos se escriben como sea en projects.js */
  transform: translateY(100%);
  transition: transform var(--bar-duration) var(--bar-ease);
  will-change: transform;
}

.card__title {
  color: var(--color-ink-strong);
  font-weight: 400;              /* la primera palabra, en regular */
}
.card__subtitle { color: var(--color-muted); }

/* Escritorio: sube con el ratón encima y baja, con la misma curva, al salir */
@media (hover: hover) and (pointer: fine) {
  .card__frame:hover .card__bar,
  .card:focus-within .card__bar { transform: translateY(0); }
  .card { cursor: pointer; }
}

/* Pieza ancha: la fila entera. Su alto lo da el `ratio` de projects.js. */
.card--wide { grid-column: 1 / -1; }

/* Sin lightbox: el cursor no promete un clic. */
.card--static,
.card--static .card__frame { cursor: default; }

/* Táctil: la sube y la baja el toque, vía clase desde main.js */
.card.is-open .card__bar { transform: translateY(0); }

/* ---------- Pantalla de carga ----------
   Un cuadrado que da dos vueltas con la misma curva que la barra del hover:
   sale disparado y frena en seco. En cuanto para, main.js retira el nodo de
   golpe, sin desvanecido. */

.loader {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--color-bg);
}

.loader__square {
  width: var(--loader-size);
  height: var(--loader-size);
  background: var(--color-ink-strong);
  animation: loader-spin var(--loader-spin) var(--bar-ease) forwards;
}

/* Si al acabar las dos vueltas los vídeos aún no corren, sigue girando igual. */
.loader__square.is-waiting {
  animation: loader-spin var(--loader-spin) var(--bar-ease) infinite;
}

@keyframes loader-spin {
  from { transform: rotate(0deg); }
  to   { transform: rotate(720deg); }
}

/* Al parar el cuadrado, el velo se va de golpe: sin desvanecido. */

/* Mientras carga no se hace scroll por detrás del velo */
body.is-loading { overflow: hidden; }

/* ---------- Vídeo cargando ----------
   Mientras un vídeo no corre, su primer frame se desenfoca y en el centro gira
   el cuadrado del loader de entrada, en pequeño y en bucle, con la misma curva:
   sale disparado, frena y descansa, así que se lee como algo vivo y no como un
   spinner de sistema. El frame, además de desenfocado, se oscurece un poco: así
   el cuadrado blanco se lee igual sobre un cielo que sobre una sombra. El
   desenfoque escala un pelo el vídeo para que el halo no deje bordes claros;
   el marco lo recorta. */

.card__media,
.lightbox__media {
  transition:
    filter var(--bar-duration) var(--bar-ease),
    transform var(--bar-duration) var(--bar-ease);
}

.is-buffering > .card__media,
.is-buffering > .lightbox__media {
  filter: blur(var(--buffer-blur)) brightness(0.8);
  transform: scale(1.06);
}

.buffer {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
  opacity: 0;
  transition: opacity 300ms ease;
}

.is-buffering > .buffer { opacity: 1; }

.buffer__square {
  width: var(--buffer-size);
  height: var(--buffer-size);
  background: #ffffff;
  animation: buffer-spin var(--loader-spin) var(--bar-ease) infinite;
}

@keyframes buffer-spin {
  to { transform: rotate(360deg); }
}

@keyframes buffer-pulse {
  50% { opacity: 0.25; }
}

/* ---------- Lightbox ---------- */

.lightbox {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 5vmin;
  background: rgba(0, 0, 0, 0.92);
}

.lightbox[hidden] { display: none; }

.lightbox:focus { outline: none; }

.lightbox__stage {
  position: relative;            /* ancla el indicador de carga */
  overflow: hidden;              /* recorta el halo del desenfoque */
  max-width: 100%;
  max-height: 100%;
}

.lightbox__media {
  max-width: 100%;
  max-height: 90vh;
  width: auto;
  height: auto;
  object-fit: contain;
}

.lightbox__close {
  position: absolute;
  top: 2vmin;
  right: 2vmin;
  width: 28px;
  height: 28px;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
}

/* El foco del sistema pinta un anillo azul que no pega con nada: se sustituye
   por uno propio, fino, y solo cuando la navegación es por teclado. */
.lightbox__close:focus { outline: none; }

.lightbox__close:focus-visible {
  outline: 1px solid rgba(255, 255, 255, 0.6);
  outline-offset: 6px;
}

.lightbox__close svg {
  width: 100%;
  height: 100%;
  stroke: #ffffff;
  stroke-width: 0.75;      /* trazo fino: la X es una línea, no un glifo */
  stroke-linecap: square;
  fill: none;
  vector-effect: non-scaling-stroke;
}

/* ---------- Cursor a medida ----------
   Un punto negro de 10px que sustituye al puntero del sistema, y que se vuelve
   blanco sobre lo que se puede pulsar.

   La clase la pone main.js, así que si el JS no llega a ejecutarse el puntero
   normal sigue ahí y la página no se queda sin cursor. */

.cursor { display: none; }

html.has-custom-cursor,
html.has-custom-cursor * { cursor: none !important; }

html.has-custom-cursor .cursor {
  display: block;
  position: fixed;
  top: 0;
  left: 0;
  z-index: 9999;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--color-ink-strong);
  pointer-events: none;
  transform: translate3d(-100px, -100px, 0);
  transition: background-color 150ms ease, border-color 150ms ease;
}

/* Blanco liso, sin contorno: sobre fondo blanco se pierde, y así se ha pedido. */
html.has-custom-cursor .cursor.is-interactive { background: #ffffff; }

html.has-custom-cursor .cursor.is-outside { opacity: 0; }

/* ---------- Pie ---------- */

.colophon {
  position: relative;
  height: var(--footer-h);
  color: var(--color-ink-strong);
  font-size: var(--type-small);
  line-height: 12px;
}

.colophon__contact,
.colophon__top {
  position: absolute;
  top: var(--footer-text-top);
  white-space: nowrap;
}

.colophon__contact {
  left: var(--edge-tight);
  color: inherit;                /* nada de azul de enlace visitado */
  text-decoration: none;
  cursor: pointer;
}

.colophon__top {
  right: var(--edge-tight);
  color: inherit;
  text-decoration: none;
}

/* ---------- Móvil (Figma: 402 × 2140) ---------- */

@media (max-width: 767px) {
  :root {
    --masthead-h: 47px;
    --intro-block-h: 24px;
    --intro-offset: 0px;
    --edge: 12px;
    --type-ui: 12px;             /* el rango de anchuras es estrecho: px fijos */
    --type-small: 10px;
  }

  .masthead__name { top: 20px; }

  .masthead__role { top: 21.5px; }

  .grid { grid-template-columns: 1fr; }

  .card__frame { aspect-ratio: 402 / 486; }

  @supports (height: round(down, 1px, 1px)) {
    .card__frame:not([style*="aspect-ratio"]) { height: round(100cqw * 486 / 402, 1px); }
  }

}

/* ---------- Accesibilidad ---------- */

@media (prefers-reduced-motion: reduce) {
  .loader { display: none; }

  /* Sin giro, pero tampoco un cuadrado quieto, que parecería colgado: un pulso lento. */
  .buffer__square {
    animation: buffer-pulse 1600ms ease-in-out infinite !important;
  }

  * {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}
