/* ============================================================
   TRELUC — estilos base
   Solo vive aquí lo que Tailwind no debe resolver:
   variables de tema, escalas tipográficas fluidas, estados
   iniciales de animación y los fallbacks sin-JS / reduced-motion.
   Todo lo demás se estiliza con utilidades en el HTML.
   ============================================================ */

:root {
  --blanco:       #FFFFFF;
  --gris-1:       #FAFAFA;
  --gris-2:       #F5F5F7;
  --tinta:        #0A0A0A;
  --humo:         #6E6E73;
  --borde:        rgba(0, 0, 0, 0.06);
  --acento:       #0071E3;
}

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

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

/* `clip` no rompe position:sticky (a diferencia de `hidden`). */
html, body { overflow-x: clip; }
@supports not (overflow: clip) {
  body { overflow-x: hidden; }
}

body {
  margin: 0;
  background: var(--blanco);
  color: var(--tinta);
  font-family: -apple-system, BlinkMacSystemFont, "SF Pro Display", "Inter", system-ui, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  font-synthesis-weight: none;
}

::selection { background: var(--tinta); color: var(--blanco); }

/* Foco visible y consistente en todo lo interactivo (AA). */
:focus-visible {
  outline: 2px solid var(--acento);
  outline-offset: 3px;
  border-radius: 4px;
}

/* ---------- Escalas tipográficas fluidas ---------- */
.t-hero {
  font-size: clamp(2.75rem, 8vw, 7rem);
  line-height: 0.98;
  letter-spacing: -0.04em;
}
.t-seccion {
  font-size: clamp(2rem, 5vw, 4rem);
  line-height: 1.04;
  letter-spacing: -0.03em;
}
.t-frase {
  font-size: clamp(1.5rem, 3.6vw, 3rem);
  line-height: 1.22;
  letter-spacing: -0.025em;
}
.t-metrica {
  font-size: clamp(2.5rem, 6vw, 5rem);
  line-height: 1;
  letter-spacing: -0.045em;
  font-variant-numeric: tabular-nums;
}
.t-wordmark {
  font-size: 25.8vw;   /* "TRELUC" mide ~3.75 em de ancho: esto lo lleva a sangre */
  line-height: 0.78;
  letter-spacing: -0.05em;
  margin-left: -0.02em; /* compensa el hueco lateral de la T */
}

/* ============================================================
   ESTADOS INICIALES DE ANIMACIÓN
   Se aplican por CSS para que no haya destello de contenido
   antes de que anime.js tome el control. Cada clase se
   corresponde con un bloque comentado de main.js.
   ============================================================ */

.reveal        { opacity: 0; }                                   /* fade simple */
.reveal-y      { opacity: 0; transform: translateY(40px); }       /* fade + subida */
.reveal-blur   { opacity: 0; transform: translateY(60px); filter: blur(10px); }
.proyecto-anim { opacity: 0; }                                   /* capa animada de cada proyecto */
.hero-titulo   { opacity: 0; }                                   /* se revela tras el split */
.frase         { opacity: 0.14; }                                /* manifiesto: apagado hasta el scroll */
.paso-panel    { opacity: 0; }                                   /* pasos del proceso */
#wordmark      { transform: translateX(-102%); }                 /* entra de izquierda a derecha */
.marcadores    { opacity: 0; }                                   /* hasta que anime.js las sitúa */

/* will-change solo en lo que realmente se anima */
.reveal, .reveal-y, .reveal-blur, .proyecto-anim, .paso-panel,
#hero-contenido, #wordmark, .foto-parallax, .marcador { will-change: transform; }

/* ============================================================
   FALLBACKS
   .no-js        → JS deshabilitado del todo
   .sin-animacion→ el módulo no arrancó en 2.5s (CDN caído) o
                   el usuario pidió reducir movimiento
   ============================================================ */
.no-js .reveal,        .sin-animacion .reveal,
.no-js .reveal-y,      .sin-animacion .reveal-y,
.no-js .reveal-blur,   .sin-animacion .reveal-blur,
.no-js .proyecto-anim, .sin-animacion .proyecto-anim,
.no-js .hero-titulo,   .sin-animacion .hero-titulo,
.no-js .frase,         .sin-animacion .frase,
.no-js .paso-panel,    .sin-animacion .paso-panel,
.no-js #wordmark,      .sin-animacion #wordmark,
.no-js .foto-parallax, .sin-animacion .foto-parallax {
  opacity: 1 !important;
  transform: none !important;
  filter: none !important;
}

/* Sin animación las barras no tienen recorrido que seguir: se retiran y
   quedan solo las curvas punteadas, que ya funcionan como textura. */
.no-js .marcadores,
.sin-animacion .marcadores { display: none; }
@media (prefers-reduced-motion: reduce) {
  .marcadores { display: none; }
}

/* Con movimiento reducido los pasos se apilan y se leen todos. */
.sin-animacion .paso-panel {
  position: relative !important;
  inset: auto !important;
  margin-bottom: 3rem;
}
.sin-animacion #proceso-track,
.sin-animacion #plataforma-track { height: auto !important; }
.sin-animacion #proceso-sticky,
.sin-animacion #plataforma-sticky {
  position: static !important;
  height: auto !important;
  padding-block: 5rem;
}

/* El respeto a reduced-motion también vive en CSS, por si el JS
   se cae antes de poder desactivar nada. */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .reveal, .reveal-y, .reveal-blur, .proyecto-anim,
  .hero-titulo, .frase, .paso-panel, #wordmark, .foto-parallax {
    opacity: 1 !important;
    transform: none !important;
    filter: none !important;
  }
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    transition-duration: 0.001ms !important;
  }
}

/* ============================================================
   FORMULARIO — etiquetas flotantes y subrayado animado
   ============================================================ */
.campo input,
.campo select,
.campo textarea {
  appearance: none;
  background: transparent;
  border: 0;
  border-radius: 0;
  width: 100%;
  padding: 1.75rem 0 0.75rem;
  font: inherit;
  color: var(--tinta);
  outline: none;
}
.campo textarea { resize: none; }

.campo label {
  position: absolute;
  left: 0;
  top: 1.5rem;
  color: var(--humo);
  pointer-events: none;
  transform-origin: left top;
  transition: transform 0.35s cubic-bezier(0.22, 1, 0.36, 1),
              color 0.35s cubic-bezier(0.22, 1, 0.36, 1);
}
/* Sube la etiqueta cuando el campo tiene foco o contenido.
   :placeholder-shown cubre input/textarea; el select usa
   la clase .tiene-valor que pone el JS. */
.campo input:focus + label,
.campo input:not(:placeholder-shown) + label,
.campo textarea:focus + label,
.campo textarea:not(:placeholder-shown) + label,
.campo select:focus + label,
.campo.tiene-valor label {
  transform: translateY(-1.45rem) scale(0.78);
  color: var(--humo);
}
.campo input:focus + label,
.campo textarea:focus + label,
.campo select:focus + label { color: var(--acento); }

/* Línea inferior: gris fija + línea de acento que crece al foco */
.campo .linea      { position: absolute; left: 0; right: 0; bottom: 0; height: 1px; background: rgba(0,0,0,0.12); }
.campo .linea-foco { position: absolute; left: 0; right: 0; bottom: 0; height: 1px; background: var(--acento);
                     transform: scaleX(0); transform-origin: left; transition: transform 0.45s cubic-bezier(0.22,1,0.36,1); }
.campo input:focus    ~ .linea-foco,
.campo select:focus   ~ .linea-foco,
.campo textarea:focus ~ .linea-foco { transform: scaleX(1); }

.campo.error .linea      { background: #D7263D; }
.campo.error label       { color: #D7263D; }
.campo .mensaje-error    { color: #D7263D; font-size: 0.8125rem; margin-top: 0.5rem; display: none; }
.campo.error .mensaje-error { display: block; }

/* Flecha del select dibujada en CSS (sin iconos externos) */
.campo.select-campo::after {
  content: "";
  position: absolute;
  right: 2px;
  bottom: 1.15rem;
  width: 8px; height: 8px;
  border-right: 1.5px solid var(--humo);
  border-bottom: 1.5px solid var(--humo);
  transform: rotate(45deg);
  pointer-events: none;
}

/* Check SVG del estado de éxito: se dibuja con stroke-dashoffset */
#check-path {
  stroke-dasharray: 48;
  stroke-dashoffset: 48;
}
.sin-animacion #check-path,
.no-js #check-path { stroke-dashoffset: 0; }

/* Indicador de scroll del hero */
@keyframes hilo-scroll {
  0%   { transform: scaleY(0); transform-origin: top; }
  45%  { transform: scaleY(1); transform-origin: top; }
  55%  { transform: scaleY(1); transform-origin: bottom; }
  100% { transform: scaleY(0); transform-origin: bottom; }
}
.hilo-scroll { animation: hilo-scroll 2.4s cubic-bezier(0.5, 0, 0.5, 1) infinite; }

/* Oculta la barra de scroll horizontal del riel de filtros */
.sin-barra { scrollbar-width: none; -ms-overflow-style: none; }
.sin-barra::-webkit-scrollbar { display: none; }

/* Palabras del manifiesto: inline-block para que acepten transform.
   La clase la aplica text.splitText() de anime.js. */
.palabra { display: inline-block; will-change: transform, opacity; }

/* Líneas del hero partidas por text.splitText(): la máscara la pone el
   wrapper `clip`; esto solo garantiza que la línea acepte transform. */
.hero-titulo .linea-hero { display: block; }


/* ============================================================
   IMÁGENES
   Cada foto vive dentro de un .marco que ya reserva su espacio.
   Si el archivo aún no está en img/, main.js le pone .sin-archivo
   y queda a la vista el marco gris con las iniciales: la maqueta
   no se mueve y no aparece ningún icono roto.
   ============================================================ */
.marco {
  position: relative;
  overflow: hidden;
  background: var(--gris-2);
}
.marco-vacio {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: clamp(2rem, 5vw, 3.5rem);
  font-weight: 600;
  letter-spacing: -0.03em;
  color: rgba(0, 0, 0, 0.08);
  user-select: none;
}
.foto {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.foto.sin-archivo { display: none; }

/* Marco sobre fondo oscuro: el gris claro daría un fogonazo mientras la
   foto carga o si el archivo falta. */
.marco-oscuro { background: rgba(255, 255, 255, 0.06); }
.marco-oscuro .marco-vacio { color: rgba(255, 255, 255, 0.12); }

/* La foto de la franja es más alta que su marco para que el parallax
   (±8%) nunca descubra un borde. */
.foto-parallax { top: -12%; height: 124%; }

/* Encuadre: cuando el sujeto no está centrado, el recorte automático de
   object-fit lo dejaría fuera en las pantallas estrechas. */
.foto-derecha { object-position: 58% 50%; }


/* ============================================================
   NAVBAR SOBRE LA IMAGEN
   El hero es una foto oscura: mientras la barra está encima,
   va transparente y en blanco. main.js le quita .sobre-imagen
   al salir del hero y recupera el cristal blanco.
   ============================================================ */
#navbar { background: rgba(255, 255, 255, 0.7); backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px); }
#navbar.sobre-imagen { background: transparent; backdrop-filter: none; -webkit-backdrop-filter: none; color: #fff; }
#navbar.sobre-imagen a { color: rgba(255, 255, 255, 0.78); }
#navbar.sobre-imagen a:hover { color: #fff; }
#navbar.sobre-imagen .logo-treluc,
#navbar.sobre-imagen .cta-nav { color: #fff; }
#navbar.sobre-imagen .cta-nav { background: rgba(255, 255, 255, 0.14); border: 1px solid rgba(255, 255, 255, 0.35); }
#navbar.sobre-imagen .cta-nav:hover { background: rgba(255, 255, 255, 0.22); }
#navbar.sobre-imagen .barra-menu { background: #fff; }

/* ============================================================
   SECCIÓN PLATAFORMA — ilustración isométrica
   ============================================================ */
#isometria .reticula path { stroke: rgba(255, 255, 255, 0.10); stroke-width: 1; fill: none; }
#isometria .rutas path    { stroke: rgba(255, 255, 255, 0.28); stroke-width: 1; fill: none;
                            stroke-dasharray: 2 6; stroke-linecap: round; }
#isometria .v-techo { fill: rgba(255,255,255,0.05); stroke: rgba(255,255,255,0.45); stroke-width: 1.2; }
#isometria .v-lado  { fill: rgba(255,255,255,0.02); stroke: rgba(255,255,255,0.22); stroke-width: 1; }
#isometria .volumen { transition: opacity 0.6s cubic-bezier(0.22,1,0.36,1); }
#isometria .volumen.apagado { opacity: 0.5; }
#isometria .volumen.activo .v-techo { stroke: var(--acento); fill: rgba(0,113,227,0.14); }
#isometria .rombo { fill: var(--acento); }
#isometria .origen .v-techo { stroke: rgba(0,113,227,0.75); fill: rgba(0,113,227,0.12); }
#isometria .origen .v-lado  { stroke: rgba(0,113,227,0.35); }

/* El giro es del grupo entero, alrededor de su propio centro. Sin
   transform-box:fill-box, un <g> de SVG rota respecto al origen del
   viewBox y se va de cuadro. */
#malla { transform-box: fill-box; transform-origin: 50% 50%; }

/* Items de la lista de plataforma */
.item-plataforma { border-left: 1px solid rgba(255,255,255,0.14); transition: border-color 0.5s cubic-bezier(0.22,1,0.36,1); }
.item-plataforma[aria-selected="true"] { border-left-color: var(--acento); }
.item-plataforma .desc { display: grid; grid-template-rows: 0fr; opacity: 0;
                         transition: grid-template-rows 0.55s cubic-bezier(0.22,1,0.36,1), opacity 0.4s; }
.item-plataforma .desc > * { overflow: hidden; min-height: 0; }
.item-plataforma[aria-selected="true"] .desc { grid-template-rows: 1fr; opacity: 1; }
.item-plataforma .titulo { color: rgba(255,255,255,0.45); transition: color 0.45s cubic-bezier(0.22,1,0.36,1); }
.item-plataforma[aria-selected="true"] .titulo { color: #fff; }
