/* ==========================================================================
   base.css — Reset, tipografía base y accesibilidad
   --------------------------------------------------------------------------
   Depende de tokens.css. Cargar siempre después.
   ========================================================================== */

/* ------------------------------------------------------------------ */
/* 1. Reset                                                            */
/* ------------------------------------------------------------------ */

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

html {
  -webkit-text-size-adjust: 100%;
  /* El original no usa smooth scroll global (verificado en su CSS y JS).
     Se activa solo aquí, para el ancla #projects, que es la única del sitio. */
  scroll-behavior: smooth;
}

body,
h1,
h2,
h3,
h4,
h5,
h6,
p,
figure,
blockquote,
dl,
dd {
  margin: 0;
}

ul[role="list"],
ol[role="list"] {
  list-style: none;
  margin: 0;
  padding: 0;
}

h1,
h2,
h3,
h4,
h5,
h6 {
  font-size: inherit;
  font-weight: inherit;
  text-wrap: balance;
}

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

img {
  height: auto;
}

input,
button,
textarea,
select {
  font: inherit;
  color: inherit;
}

button {
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
}

a {
  color: inherit;
  text-decoration: none;
}

/* ------------------------------------------------------------------ */
/* 2. Tipografía base                                                  */
/* ------------------------------------------------------------------ */

/* Raleway e Inter se cargan desde Google Fonts en el <head> de cada página:

   <link rel="preconnect" href="https://fonts.googleapis.com">
   <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
   <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Raleway:wght@600;700&display=swap">

   Solo los pesos que usa el diseño. Ver docs/DISENO.md §1. */

body {
  background-color: var(--color-bg);
  color: var(--color-text);
  font-family: var(--font-body);
  font-size: var(--fs-body-sm);
  font-weight: var(--fw-regular);
  line-height: var(--lh-relaxed);
  letter-spacing: var(--ls-micro);
  /* El nav va pegado al borde superior (y=0 en el Figma); el gutter de 12px
     es solo lateral e inferior. Cada bloque blanco añade sus 12px de arriba. */
  padding: 0 var(--page-gutter) var(--page-gutter);
  min-height: 100vh;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/* ------------------------------------------------------------------ */
/* 3. Roles tipográficos                                               */
/* ------------------------------------------------------------------ */

/* Cada regla corresponde a una fila de la tabla de docs/DISENO.md §3.
   Son clases, no selectores de elemento: el mismo tamaño aparece en
   etiquetas distintas según la página. */

.t-404 {
  font-family: var(--font-heading);
  font-weight: var(--fw-semibold);
  font-size: var(--fs-404);
  line-height: var(--lh-404);
  letter-spacing: var(--ls-tight);
}

.t-hero {
  font-family: var(--font-heading);
  font-weight: var(--fw-semibold);
  font-size: var(--fs-hero);
  line-height: var(--lh-tight);
  letter-spacing: var(--ls-tight);
}

.t-title {
  font-family: var(--font-heading);
  font-weight: var(--fw-semibold);
  font-size: var(--fs-title);
  line-height: var(--lh-tight);
  letter-spacing: var(--ls-tight);
}

/* Solo en páginas de proyecto: "Other Projects" es 72px, no 64px.
   Incoherencia del Figma, replicada a propósito. */
.t-h2-lg {
  font-family: var(--font-heading);
  font-weight: var(--fw-semibold);
  font-size: var(--fs-h2-lg);
  line-height: var(--lh-tight);
  letter-spacing: var(--ls-tighter);
}

.t-h2 {
  font-family: var(--font-heading);
  font-weight: var(--fw-semibold);
  font-size: var(--fs-h2);
  line-height: var(--lh-tight);
  letter-spacing: var(--ls-tighter);
}

/* h2 dentro de página de proyecto. Sin tracking, a diferencia del resto. */
.t-h2-sm {
  font-family: var(--font-heading);
  font-weight: var(--fw-semibold);
  font-size: var(--fs-h2-sm);
  line-height: var(--lh-heading);
  letter-spacing: var(--ls-none);
}

.t-statement {
  font-family: var(--font-body);
  font-weight: var(--fw-medium);
  font-size: var(--fs-statement);
  line-height: var(--lh-heading);
  letter-spacing: var(--ls-statement);
}

.t-h3 {
  font-family: var(--font-heading);
  font-weight: var(--fw-semibold);
  font-size: var(--fs-h3);
  line-height: var(--lh-heading);
  letter-spacing: var(--ls-tight);
}

.t-lead {
  font-family: var(--font-body);
  font-weight: var(--fw-medium);
  font-size: var(--fs-lead);
  line-height: var(--lh-snug);
  letter-spacing: var(--ls-lead);
}

.t-card-title {
  font-family: var(--font-body);
  font-weight: var(--fw-semibold);
  font-size: var(--fs-h4);
  line-height: var(--lh-tight);
  letter-spacing: var(--ls-card);
}

.t-meta {
  font-family: var(--font-heading);
  font-weight: var(--fw-semibold);
  font-size: var(--fs-meta);
  line-height: var(--lh-heading);
  letter-spacing: var(--ls-none);
}

.t-body {
  font-family: var(--font-body);
  font-weight: var(--fw-regular);
  font-size: var(--fs-body);
  line-height: var(--lh-loose);
  letter-spacing: var(--ls-micro);
}

.t-body-sm {
  font-family: var(--font-body);
  font-weight: var(--fw-regular);
  font-size: var(--fs-body-sm);
  line-height: var(--lh-relaxed);
  letter-spacing: var(--ls-micro);
}

/* Eyebrow: `/// Portfolio ///` */
.t-eyebrow {
  font-family: var(--font-body);
  font-weight: var(--fw-medium);
  font-size: var(--fs-body-sm);
  line-height: var(--lh-heading);
  letter-spacing: var(--ls-micro);
  color: var(--color-text-muted);
}

.t-muted {
  color: var(--color-text-muted);
}

/* ------------------------------------------------------------------ */
/* 4. Contenedores                                                     */
/* ------------------------------------------------------------------ */

/* El Figma sitúa el contenido en 1200px REALES dentro de un lienzo de 1440.
   Si el max-width fuera 1200 con padding dentro, el contenido quedaría en 1160.
   Por eso el tope suma el padding: 1200 + 20 + 20 = 1240. */
.container {
  width: 100%;
  max-width: calc(var(--container-max) + var(--container-padding) * 2);
  margin-inline: auto;
  padding-inline: var(--container-padding);
}

/* ------------------------------------------------------------------ */
/* 5. Accesibilidad                                                    */
/* ------------------------------------------------------------------ */

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

/* Sin :focus-visible el foco de teclado se pierde sobre fondo oscuro. */
.footer :focus-visible,
.on-dark :focus-visible {
  outline-color: var(--color-white);
}

.visually-hidden:not(:focus):not(:active) {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.skip-link {
  position: absolute;
  top: var(--space-2);
  left: var(--space-2);
  z-index: var(--z-skip-link);
  padding: var(--space-2) var(--space-4);
  background-color: var(--color-text);
  color: var(--color-text-invert);
  border-radius: var(--radius-btn);
  font-family: var(--font-heading);
  font-weight: var(--fw-bold);
  font-size: var(--fs-body);
}

.skip-link:not(:focus):not(:active) {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* Compensa el header al saltar a un ancla. El header no es sticky en el
   original (verificado), pero el margen evita que el título quede pegado. */
[id] {
  scroll-margin-top: var(--space-10);
}

/* ------------------------------------------------------------------ */
/* 6. Estados iniciales de animación                                   */
/* ------------------------------------------------------------------ */

/* Contrato de la Fase 4, con la lógica INVERTIDA respecto al original.

   El contenido es visible por defecto. Estas dos clases las añade
   js/animations.js, y solo DESPUÉS de confirmar que GSAP está cargado y que
   va a animar de verdad. La cabecera no oculta nada.

   Lo que se gana: si el JS no llega a ejecutarse —sin conexión, CDN caído,
   la página abierta con file:// y los módulos bloqueados por CORS— no hay
   nada que destapar, porque nunca se ocultó. El original hacía lo contrario
   (`html.w-mod-js:not(.w-mod-ix3)`) y dejaba el sitio en blanco.

   Lo que se paga: entre el primer pintado y la ejecución del módulo puede
   verse un parpadeo. Es el intercambio correcto: un parpadeo breve es mejor
   que una página vacía.

   Son clases distintas de `js-enabled` a propósito. `js-enabled` significa
   "hay JavaScript", de ella depende el menú móvil, y por eso no puede
   usarse para ocultar contenido. */

.js-anim [data-animate="slide-in"] {
  opacity: 0;
  transform: translateY(var(--slide-in-offset));
  filter: blur(var(--slide-in-blur));
  will-change: transform, opacity, filter;
}

/* SplitText es la única animación con dependencia externa (un plugin, no
   solo GSAP core). Se invierte la lógica del original: el h1 es visible por
   defecto y solo se oculta cuando js/animations.js ha confirmado que GSAP
   Y SplitText cargaron. Si el CDN cae, el título aparece sin animar en vez
   de quedarse invisible. */
.js-split-ready [data-animate="split-chars"] {
  visibility: hidden;
}

/* ------------------------------------------------------------------ */
/* 7. prefers-reduced-motion                                           */
/* ------------------------------------------------------------------ */

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }

  /* Anula los estados iniciales: el contenido se ve de entrada, sin
     desplazamiento ni blur. El blur es la excepción a la regla de "solo
     transform y opacity" y aquí se desactiva por completo. */
  .js-anim [data-animate="slide-in"] {
    opacity: 1;
    transform: none;
    filter: none;
    will-change: auto;
  }

  .js-split-ready [data-animate="split-chars"] {
    visibility: visible;
  }
}
