@import url(reset.css);

:root {

/* COLORES =============================== */
    --color-black: #000000;
    --color-white: #ffffff;
    --color-grey: #918f8b;


/* TIPOGRAFIA ============================ */
    --font-h1: 'Syne', sans-serif;
    --font-h2: 'Syne', sans-serif;
    --font-h3: 'Syne', sans-serif;
    --font-p: 'Karla', sans-serif;
    --font-nav: 'Syne', sans-serif;


    /* TAMAÑOS =========================== */
    --font-size-h1: 170px;
    --font-size-h2: 35px;
    --font-size-h3: 25px;
    --font-size-p: 16px;
    --font-size-nav: 16px;

    /* MEDIDAS RESPONSIVE ================ */
    --width-phone: 360px;
    --width-tablet: 768px;
    --width-desktop: 1200px;

}

html {
    box-sizing: border-box;
    /* El snap lo gestiona el plugin Lenis Snap (script.js), no el CSS */
}

/* CSS recomendado por Lenis (smooth scroll por JS) */
html.lenis,
html.lenis body {
    height: auto;
}

.lenis.lenis-smooth {
    scroll-behavior: auto !important;
}

.lenis.lenis-stopped {
    overflow: hidden;
}

::selection {
    background: var(--color-grey);
}

* {
    margin: 0;
    padding: 0;
    /* cursor: none; */
}

.syne-typo {
    font-family: "Syne", sans-serif;
    font-optical-sizing: auto;
    font-weight: 600;
    font-style: normal;
}


/* HEADER ================================================== */
#header {
    position: fixed;           /* siempre visible al hacer scroll */
    top: 0;
    left: 0;
    right: 0;
    z-index: 100;             /* por encima de todo el contenido */
}

.header-container {
    margin: 20px 40px 40px 40px;
    display: flex;
    flex-direction: row;
}

.logo {
    align-items: left;
}

.logo img {
    width: 50px;
    height: 45px;
}

.menu {
    margin-right: 0;
    margin-left: auto;
    display: flex;
    align-items: center;
    list-style: none;
    padding: 0;
    gap: 20px;

    font-family: var(--font-nav);
    font-weight: bolder;
}

.menu-id {
    align-self: center;
}

/* Menú negro por defecto (legible sobre secciones claras). Al pasar por una
   sección de fondo oscuro, JS añade .on-dark al header y pasa a blanco. */
.menu-id a,
.dark-mode {
    text-decoration: none;
    color: var(--color-black);
    transition: color 0.3s ease;
}

#header.on-dark .menu-id a,
#header.on-dark .dark-mode {
    color: var(--color-white);
}

/* Subrayado animado al pasar el ratón (crece desde la izquierda).
   Solo en dispositivos con puntero real, para no afectar al menú móvil. */
@media (hover: hover) {
    .menu-id a,
    .dark-mode {
        position: relative;
    }

    .menu-id a::after,
    .dark-mode::after {
        content: "";
        position: absolute;
        left: 0;
        bottom: -3px;
        width: 100%;
        height: 2px;
        background: currentColor;   /* sigue el color del texto (se adapta) */
        transform: scaleX(0);
        transform-origin: left;
        transition: transform 0.35s var(--ease-out-expo);
    }

    .menu-id a:hover::after,
    .dark-mode:hover::after {
        transform: scaleX(1);
    }
}

/* HERO ==================================================== */

/* Contenedor que abarca hero + about: dentro de él vive el retrato sticky,
   por eso el retrato puede quedarse fijo durante el hero y soltarse en about. */
.pin-hero {
    position: relative;
}

/* Retrato pinneado: ocupa una pantalla y se queda fijo (sticky) arriba.
   Como su contenedor mide 2 pantallas (hero + about), permanece fijo durante
   todo el hero y empieza a subir justo cuando entra la sección about. */
.hero-portrait {
    position: sticky;
    top: 0;
    height: 100vh;
    display: grid;
    place-items: center;        /* centra las imágenes apiladas */
    z-index: 10;                 /* detrás del título del hero y del about */
}

/* Todas las imágenes ocupan la misma celda -> quedan apiladas para el fundido */
.hero-portrait img {
    grid-area: 1 / 1;
    width: 400px;
    opacity: 0;
    transition: opacity 1s ease;
}

.hero-portrait img.is-active {
    opacity: 1;
}

#hero {
    position: relative;
    z-index: 11;                /* por encima del retrato (z-index: 10) */
    margin-top: -100vh;         /* solapa el hueco del retrato sticky */

    display: flex;
    height: 100vh;
    align-items: center;
    justify-content: center;
    pointer-events: none;       /* deja pasar el ratón salvo en el título */
}

#hero .title {
    pointer-events: auto;
}

.title {
    position: absolute;
    bottom: 200px;
    /* Margen derecho fluido: escala con el ancho hasta un máximo de 300px.
       Al escalar junto al tamaño del h1 (también en vw), el nombre nunca
       se corta ni salta de línea en tamaños intermedios. */
    right: clamp(20px, 22vw, 300px);

    display: flex;
    flex-direction: column;
    align-items: flex-end;
    text-align: right;
}

.title h1 {
    font-family: var(--font-h1);
    /* Tamaño fluido: escala con el ancho (hasta el máximo de 170px de
       escritorio) y nunca hace wrap, así "Joan G" queda siempre en una línea */
    font-size: clamp(64px, 13vw, var(--font-size-h1));
    font-weight: bolder;
    white-space: nowrap;
}

.title p {
    font-family: var(--font-p);
    font-size: var(--font-size-p);
}

/* ABOUT ================================================== */

#about {
    position: relative;
    z-index: 2;                          /* sube por delante del retrato sticky */
    background-color: var(--color-white);/* tapa el retrato al desplazarse */
    display: flex;

    height: 100vh;

    /* Marca la línea de tiempo de la cortina de #work: su rango "exit" (cuando
       #about se va por arriba, 100vh de scroll) es el que barre los paneles. */
    view-timeline-name: --wipe;
    view-timeline-axis: block;
}

.description {
    width: 30vw;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: flex-start;

    padding-left: 8vw;
}

.description h2 {
    font-size: var(--font-size-h2);
    font-family: var(--font-h2);
    font-weight: bolder;
}

.description p {
    font-size: var(--font-size-p);
    font-family: var(--font-p);
}

/* WORK ====================================================== */

#work {
    position: relative;
    background-color: var(--color-black);
    color: var(--color-white);
    padding: 12vh 8vw;
}

.projects {
    display: flex;
    flex-direction: row;
    justify-content: center;
    align-items: flex-start;
    gap: 6vw;
}

.work-col {
    display: flex;
    flex-direction: column;
    gap: 12vh;
    width: 34vw;
}

/* Segunda columna */
.work-col--offset {
    margin-top: 24vh;
}

.project {
    position: relative;
    display: flex;
    flex-direction: row;

    gap: 20px;
}

/* Una sola clase invierte el orden: imagen primero, texto despues */
.project--reverse {
    flex-direction: row-reverse;
}

.project-info {
    position: relative;
    display: flex;
    flex-direction: column;

    justify-content: space-between;
}

.project-num {
    font-family: var(--font-nav);
    font-size: var(--font-size-h3);
    color: var(--color-grey);
    margin-bottom: 10px;
}

.thumb {
    width: 100%;
    background-color: var(--color-grey);
    background-size: cover;
    background-position: center;
    overflow: hidden;
}

.thumb--landscape {
    aspect-ratio: 16 / 10;
}

.thumb--portrait {
    aspect-ratio: 3 / 4;
}

.project figcaption {
    margin-top: 14px;
    font-family: var(--font-h2);
    font-weight: bolder;
    font-size: var(--font-size-h2);
    line-height: 1.1;
}

/* GAME ==================================================== */
#game {
    min-height: 100vh;
    padding: 60px 20px;
    background-color: var(--color-white);
    color: var(--color-black);

    position: relative;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    text-align: center;
    gap: 16px;
}

#game h2{
    font-family: var(--font-h2);
    font-size: var(--font-size-h2);
    font-weight: bolder;
    color: var(--color-black);
}

#game p{
    font-family: var(--font-p);
    font-size: var(--font-size-p);
    color: var(--color-black);
}

#dot-game {
    width: min(660px, 90vw);
    height: auto;
    aspect-ratio: 1 / 1;
    touch-action: none;
}

/* Puntos numerados */
#dot-game .dot circle {
    fill: var(--color-black);
    cursor: pointer;
}

#dot-game .dot text {
    fill: var(--color-black);
    font-family: var(--font-h3);
    font-size: var(--font-size-h3);
    font-weight: bolder; 
    text-anchor: start;          /* el número arranca al lado del punto */
    dominant-baseline: middle;
    pointer-events: none;
}

/* Líneas dibujadas y cara del gato */
#dot-game .lines line,
#dot-game .temp-line {
    stroke: var(--color-black);
    stroke-width: 5;
    stroke-linecap: round;
}

#dot-game .cat-face {
    stroke: var(--color-black);
    stroke-width: 3;
    fill: none;
}

/* Gato de fondo como guía tenue para trazar encima */
#dot-game .cat-guide {
    opacity: 0.3;
    pointer-events: none;   /* no interfiere con el arrastre de los puntos */
}

/* Cronómetro */
.game-timer {
    font-family: var(--font-h2);
    font-size: var(--font-size-h2);
    font-weight: bolder;
    font-variant-numeric: tabular-nums;   /* los dígitos no "bailan" al contar */
    color: var(--color-black);
}

/* Botón reset */
.game-reset {
    font-family: var(--font-nav);
    font-weight: bolder;
    font-size: var(--font-size-nav);
    padding: 10px 24px;
    border: 2px solid var(--color-black);
    background: var(--color-white);
    color: var(--color-black);
    border-radius: 999px;
    cursor: pointer;
}

.game-reset:hover {
    background: var(--color-black);
    color: var(--color-white);
}

/* Ranking de tiempos */
.ranking {
    width: min(360px, 90vw);
    text-align: left;
}

.ranking h3 {
    font-family: var(--font-h3);
    font-size: var(--font-size-h3);
    font-weight: bolder;
    margin-bottom: 8px;
    text-align: center;
}

.ranking-list {
    list-style: none;
    padding: 0;
    margin: 0;
}

.ranking-list li {
    display: flex;
    justify-content: space-between;
    gap: 12px;
    font-family: var(--font-p);
    font-size: var(--font-size-p);
    padding: 6px 4px;
    border-bottom: 1px solid var(--color-grey);
}

.ranking-list li .rank-pos {
    width: 1.6em;
    color: var(--color-grey);
}

.ranking-list li .rank-name {
    flex: 1;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.ranking-list li .rank-time {
    font-variant-numeric: tabular-nums;
    font-weight: bolder;
}

/* Resalta la partida recién guardada */
.ranking-list li.is-new {
    color: var(--color-black);
    font-weight: bolder;
}

/* CONTACT ================================================= */
#contact {
    position: relative;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    height: 100vh;
    background-color: var(--color-white);
    color: var(--color-black);
    text-align: center;
}

.contact-details p {
    font-family: var(--font-p);
    font-size: var(--font-size-p);
    color: var(--color-black);
    margin-bottom: 20px;
}

.contact-details h3 {
    font-family: var(--font-h1);
    font-weight: bolder;
    font-size: clamp(32px, 6vw, 90px);
    line-height: 1;
}

/* ANIMACIONES DE TEXTO (estilo bettr) ===================== */
/* Solo hero, about y contact. El texto se parte en líneas por JS;
   cada línea vive dentro de una máscara (overflow oculto) y su
   contenido sube desde abajo con un easing expo. NO afecta a
   #work ni a #game.                                              */

:root {
    /* expo out: arranque rápido y freno muy suave, como en bettr */
    --ease-out-expo: cubic-bezier(0.16, 1, 0.3, 1);
}

/* Anti-parpadeo: si el JS de motion está activo, oculta los textos objetivo
   SOLO mientras aún no están preparados (:not(.reveal-el)). En cuanto el JS
   les añade .reveal-el, esta regla deja de aplicar y recuperan opacity:1 por
   defecto, sin conflictos de especificidad. La máscara por línea sigue
   ocultando el texto hasta que entra en viewport (.is-in). */
.js-motion #hero .title h1:not(.reveal-el),
.js-motion #hero .title p:not(.reveal-el),
.js-motion #about .description h2:not(.reveal-el),
.js-motion #about .description p:not(.reveal-el),
.js-motion #contact .contact-details p:not(.reveal-el),
.js-motion #contact .contact-details h3:not(.reveal-el) {
    opacity: 0;
}

/* Cada línea es una ventana que recorta lo que sobresale */
.reveal-line {
    display: block;
    overflow: hidden;
    /* holgura inferior para no recortar colas de letras (g, y, j) */
    padding-bottom: 0.08em;
    margin-bottom: -0.08em;
}

/* El contenido de la línea empieza escondido debajo de la máscara */
.reveal-el .reveal-line__inner {
    display: block;
    transform: translateY(115%);
    transition: transform 1s var(--ease-out-expo);
    transition-delay: inherit;   /* el retardo escalonado lo pone JS por línea */
    will-change: transform;
}

/* Al entrar en viewport, sube a su sitio */
.reveal-el.is-in .reveal-line__inner {
    transform: translateY(0);
}

/* Al re-partir el texto en un resize ya revelado, evita re-animar */
.reveal-el.no-anim .reveal-line__inner {
    transition: none;
}

/* Accesibilidad: sin movimiento si el usuario lo pide */
@media (prefers-reduced-motion: reduce) {
    .reveal-el .reveal-line__inner {
        transform: none !important;
        transition: none !important;
    }
}

/* NAV MÓVIL (menú hamburguesa) ============================ */

/* Botón hamburguesa: oculto en escritorio, dos líneas que forman una X */
.nav-toggle {
    display: none;
    position: relative;
    width: 34px;
    height: 22px;
    margin-left: auto;         /* empuja el botón a la derecha del header */
    padding: 0;
    border: 0;
    background: none;
    cursor: pointer;
    z-index: 110;              /* por encima del overlay del menú */
}

.nav-toggle__line {
    position: absolute;
    left: 0;
    right: 0;
    height: 2px;
    background: var(--color-black);
    transition: transform 0.45s var(--ease-out-expo),
                background-color 0.3s ease;
}

.nav-toggle__line:nth-child(1) { top: 4px; }
.nav-toggle__line:nth-child(2) { bottom: 4px; }

/* Al abrir: las dos líneas se cruzan en el centro formando una X */
.nav-toggle.is-active .nav-toggle__line:nth-child(1) {
    transform: translateY(6px) rotate(45deg);
}
.nav-toggle.is-active .nav-toggle__line:nth-child(2) {
    transform: translateY(-6px) rotate(-45deg);
}

/* La hamburguesa hereda el color adaptativo del header (blanco sobre #work),
   salvo cuando está abierta: entonces la X va en negro sobre el overlay blanco */
#header.on-dark .nav-toggle:not(.is-active) .nav-toggle__line {
    background: var(--color-white);
}
.nav-toggle.is-active .nav-toggle__line {
    background: var(--color-black);
}

@media (max-width: 768px) {
    /* En móvil se muestra la hamburguesa y se oculta el menú en línea */
    .nav-toggle { display: block; }

    /* El menú se convierte en un overlay blanco a pantalla completa */
    .menu {
        position: fixed;
        inset: 0;
        margin: 0;
        flex-direction: column;
        justify-content: center;
        align-items: flex-start;
        gap: 0;
        padding: 0 8vw;
        background: var(--color-white);
        z-index: 105;

        /* Cerrado: cortina recogida arriba y sin interacción */
        clip-path: inset(0 0 100% 0);
        pointer-events: none;
        transition: clip-path 0.8s var(--ease-out-expo);
    }

    /* Abierto: la cortina baja y cubre toda la pantalla */
    .menu.is-open {
        clip-path: inset(0 0 0 0);
        pointer-events: auto;
    }

    /* Cada item es grande y su texto vive dentro de una máscara */
    .menu-id,
    .dark-mode {
        width: 100%;
        overflow: hidden;
        padding: 0.06em 0;
    }

    .menu-id a,
    .dark-mode span {
        display: block;
        font-family: var(--font-h1);
        font-size: clamp(44px, 15vw, 110px);
        font-weight: bolder;
        line-height: 1.02;
        color: var(--color-black);              /* siempre negro sobre el overlay */
        transform: translateY(120%);            /* escondido bajo la máscara */
        transition: transform 0.8s var(--ease-out-expo);
    }

    /* Fuerza el negro aunque el header esté en modo .on-dark */
    #header .menu.is-open .menu-id a,
    #header .menu.is-open .dark-mode span {
        color: var(--color-black);
    }

    /* Revelado de texto escalonado al abrir (sube desde la máscara) */
    .menu.is-open .menu-id a,
    .menu.is-open .dark-mode span {
        transform: translateY(0);
    }
    .menu.is-open > *:nth-child(1) a,
    .menu.is-open > *:nth-child(1) span { transition-delay: 0.12s; }
    .menu.is-open > *:nth-child(2) a,
    .menu.is-open > *:nth-child(2) span { transition-delay: 0.20s; }
    .menu.is-open > *:nth-child(3) a,
    .menu.is-open > *:nth-child(3) span { transition-delay: 0.28s; }
}

/* TRANSICIÓN A #work: cortina de rectángulos (barrido vertical) ===========
   La cortina es un overlay a pantalla completa (position: fixed) POR ENCIMA de
   todo, no una sección propia. La animación es CSS puro ("scroll-driven"): el
   barrido se ata al scroll de #about mediante una view-timeline (--wipe). Cuando
   #about se va por arriba y entra #work, los paneles barren la pantalla.
   No hace falta JavaScript. */

/* La línea de tiempo la marca el scroll de #about (ver su regla en la sección
   ABOUT). timeline-scope sube el nombre --wipe hasta <body> para que la cortina,
   que vive en otra rama del DOM, pueda referenciarlo. */
body { timeline-scope: --wipe; }

.section-wipe {
    position: fixed;
    inset: 0;
    z-index: 200;              /* por encima de TODO (incluida la cabecera z-100) mientras dura la transición */
    pointer-events: none;
    overflow: hidden;
}

.wipe-panel {
    position: absolute;
    inset: 0;
    transform: translateY(100%);   /* estado base: fuera, justo debajo del viewport */
    will-change: transform;
}

.wipe-panel--black { background: var(--color-black); z-index: 1; }
.wipe-panel--white {
    background: var(--color-white);
    z-index: 2;
    display: flex;
    align-items: center;
    justify-content: center;
}

/* Título de sección que viaja con la cortina blanca */
.wipe-title {
    font-family: var(--font-h2);
    font-weight: bolder;
    font-size: clamp(48px, 12vw, 100px);
    line-height: 1;
    color: var(--color-black);
}

/* Coreografía en 4 tiempos, atada al scroll. El rango "exit" abarca los 100vh en
   que #about se va por arriba y #work ocupa el viewport: 0% = #about llena la
   pantalla (cortina aún oculta) y 100% = #about ya fuera (#work descubierto). */
@supports (animation-timeline: view()) {
    .wipe-panel--black,
    .wipe-panel--white {
        animation: linear both;
        animation-timeline: --wipe;
        animation-range: exit 0% exit 100%;
    }
    .wipe-panel--black { animation-name: wipe-black; }
    .wipe-panel--white { animation-name: wipe-white; }
}

/* 1) sube el negro  2) sube el blanco  3) sale el negro  4) sale el blanco */
@keyframes wipe-black {
    0%   { transform: translateY(100%); }
    25%  { transform: translateY(0); }
    50%  { transform: translateY(0); }
    75%  { transform: translateY(-100%); }
    100% { transform: translateY(-100%); }
}
@keyframes wipe-white {
    0%   { transform: translateY(100%); }
    25%  { transform: translateY(100%); }
    50%  { transform: translateY(0); }
    75%  { transform: translateY(0); }
    100% { transform: translateY(-100%); }
}

/* Sin movimiento si el usuario lo pide: la cortina no se muestra */
@media (prefers-reduced-motion: reduce) {
    .section-wipe { display: none; }
}
