/* ==========================================================================
   CONCEPT: "LA PROIEZIONE"
   Il sito è strutturato come la visione di un film: atti numerati,
   timecode, e il portfolio come schermo acceso (foglio chiaro) nel buio
   della sala (body sempre dark). Il nome appare solo nei titoli di coda.
   ==========================================================================

   0. FONT (Variable, self-hosted — zero richieste esterne)
   Chillax: display (Fontshare, asse wght 200–700) — geometrico e rotondo.
   NOTA LICENZA: Chillax non è ridistribuibile. Scaricalo gratis da
   https://www.fontshare.com/fonts/chillax → nello zip trovi
   Fonts/WEB/fonts/Chillax-Variable.woff2 → copialo in assets/fonts/
   rinominandolo "chillax-variable.woff2". Finché il file manca, il sito
   ripiega su Chillax-Medium (statico, già presente): stesso disegno, un
   peso solo.
   ========================================================================== */
@font-face {
    font-family: 'Chillax Variable';
    src: url('../assets/fonts/chillax-variable.woff2') format('woff2-variations');
    font-weight: 200 700;
    font-display: swap;
}

/* Ripiego di Chillax. Il nome della famiglia diceva "Archivo" ma il file
   caricato e' Chillax-Medium: il ripiego era Chillax stesso, con
   un'etichetta sbagliata. Peggio, era dichiarato come variabile
   (woff2-variations, wght 100-900, con asse di larghezza): a un file
   statico il browser credeva di poter chiedere qualsiasi peso, e per il
   700 dei titoli finiva per fabbricare un finto grassetto ingrossando i
   contorni. Qui il nome dice la verita' e il formato e' quello giusto.
   L'intervallo 200-700 su un file statico non e' un errore: e' il modo di
   dire al browser "questo file copre tutti i pesi, non inventarne altri",
   cosi' il 700 rende come un Medium invece che come un finto grassetto.
   Se un giorno metti in assets/fonts/ un vero Archivo variabile, cambia
   solo l'url e rimetti format('woff2-variations'). */
/* --- Anaktoria: solo per il monogramma del footer ------------------------
   Due sorgenti nello stesso src, in ordine di preferenza: il browser prende
   la prima che sa leggere. Cosi' il sito funziona SUBITO con il solo .otf, e
   il giorno che aggiungi il .woff2 passa a quello senza toccare il CSS.

   font-weight: 200 700 su un file che ha un peso solo non e' un errore. E'
   il modo di dire al browser "questo file copre tutti i pesi": il
   .footer-mark chiede il 700, e senza questa riga il browser fabbricherebbe
   un finto grassetto ingrossando i contorni — su un serif di questo tipo si
   vede parecchio. Con la riga, il 700 rende come il disegno originale. */
@font-face {
    font-family: 'Anaktoria';
    src: url('../assets/fonts/anaktoria.woff2') format('woff2'),
         url('../assets/fonts/Anaktoria.otf') format('opentype');
    font-weight: 200 700;
    font-style: normal;
    font-display: swap;
}

@font-face {
    font-family: 'Chillax Fallback';
    src: url('../assets/fonts/Chillax-Medium.woff2') format('woff2');
    font-weight: 200 700;
    font-display: swap;
}

@font-face {
    font-family: 'Instrument Sans Variable';
    src: url('../assets/fonts/instrument-sans-variable.woff2') format('woff2-variations');
    font-weight: 400 700;
    font-display: swap;
}

/* ==========================================================================
   1. DESIGN SYSTEM
   ========================================================================== */
:root {
    --dark: #191919;
    --light: #f5f5f5;
    --ink: #191919;
    --muted: #8E8E93;

    --accent-purple: #a88fbb;
    --accent-orange: #d85633;
    --accent-cyan: #5d737e;

    /* Pastelli per le pillole del portfolio (una per tipologia) */
    --pill-lime:   #D8F5A2;
    --pill-lilac:  #E5D4FF;
    --pill-pink:   #FFD6EE;
    --pill-blue:   #CDE8FF;
    --pill-peach:  #FFE3C2;
    --pill-mint:   #C9F0E4;

    /* Maglia di colore del monogramma nel footer. Presa dalla palette del
       sito e non da una tavolozza al neon: su fondo scuro i pastelli
       brillano gia', e l'arancio fa da unico picco di contrasto. */
    --mesh-1: #a88fbb;   /* viola   */
    --mesh-2: #CDE8FF;   /* blu     */
    --mesh-3: #FFD6EE;   /* rosa    */
    --mesh-4: #d85633;   /* arancio */
    --mesh-5: #C9F0E4;   /* menta   */

    --font-display: 'Chillax Variable', 'Chillax Fallback', Impact, sans-serif;
    /* Font del solo monogramma nel footer. Separato da
       --font-display di proposito: il resto del sito resta Chillax. */
    --font-mark: 'Anaktoria', Georgia, 'Times New Roman', serif;
    --font-body: 'Instrument Sans Variable', -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;

    --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
    --ease-soft: cubic-bezier(0.25, 1, 0.5, 1);

    /* --- RITMO VERTICALE DELLA HOME ------------------------------------
       Un token per ogni GIUNZIONE tra due atti. Regola: lo stacco lo porta
       sempre la sezione che ARRIVA (padding-top / margin-top), mai
       entrambe. Prima erano due padding sommati su ogni giunzione, ed era
       questo — non il valore singolo — a raddoppiare i vuoti.
       Per ritoccare una distanza si cambia UN numero, qui. */
    --gap-hdr-01:  calc(clamp(70px,  10vh, 120px) + 20px); /* +20px hero */  /* header  -> Atto 01 Sinossi  */
    --gap-01-02:   clamp(96px,  18vh, 190px);  /* Sinossi -> Atto 02 Skills   */
    --gap-02-03:   clamp(28px, 3.5vh,  56px);  /* Skills  -> Atto 03 Works    */
    --gap-03-04:   clamp(110px, 20vh, 220px);  /* Works   -> Atto 04 Contatti */

    /* --- RITMO VERTICALE DELLE PAGINE INTERNE ---------------------------
       Stessa logica: un token per giunzione, lo stacco lo porta chi arriva. */
    --gap-page-top:    clamp(88px, 11vh, 130px);  /* header  -> primo blocco  */
    --gap-about-media: clamp(20px, 2.5vh, 34px);  /* titolo  -> foto          */
    --gap-about-blocks: clamp(48px, 6vh,  88px);  /* bio -> ticker -> diario  */

    /* Larghezza del contenitore sui monitor grandi. A 1800px vale
       esattamente 1280px, quindi la soglia non produce nessuno scatto. */
    --wide-container: clamp(1280px, 82vw, 1780px);
}

/* ==========================================================================
   2. RESET E BASE
   ========================================================================== */
*, *::before, *::after {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
}

body {
    font-family: var(--font-body);
    background-color: var(--dark); /* la sala resta buia: il tema non cambia mai */
    color: #FFFFFF;
    overflow-x: hidden;   /* ripiego per i browser piu' vecchi */
    overflow-x: clip;     /* non crea un contenitore di scorrimento:
                             `hidden` in alcuni browser disattiva
                             position:sticky, da cui dipende il
                             footer a sipario */
    -webkit-font-smoothing: antialiased;
}

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

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

.visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
}

/* CSS richiesto da Lenis */
html.lenis, html.lenis body { height: auto; }
.lenis:not(.lenis-autoToggle).lenis-stopped { overflow: clip; }
.lenis.lenis-smooth iframe { pointer-events: none; }

.container {
    width: 90%;
    max-width: 1280px;
    margin: 0 auto;
}

/* Timecode: elemento ricorrente che scandisce la sequenza */
.timecode {
    font-size: 0.78rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 2px;
    opacity: 0.55;
    font-variant-numeric: tabular-nums;
}

/* ==========================================================================
   3. ACT HEADER — l'intestazione che dà ritmo e sequenza a ogni sezione
   La linea si "disegna" quando entra in viewport.
   ========================================================================== */
.act-header {
    display: flex;
    align-items: center;
    gap: 20px;
    margin-bottom: clamp(48px, 7vh, 80px);
}

.act-num,
.act-name {
    font-size: 0.8rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 2.5px;
    white-space: nowrap;
}

.act-num { color: var(--accent-orange); }

/* RIMOSSO: .act-rule (la linea che si disegnava nell'act-header).
   Non esiste in nessuna delle tre pagine ne' viene creata dal JS. */

/* Nelle pagine attuali gli <span> dell'act-header sono vuoti: nessun
   numero, nessun nome. L'intestazione non disegna nulla ma il suo
   margin-bottom (fino a 80px) continua a occupare spazio, e quel vuoto
   viene letto come "distanza sbagliata" in cima a ogni sezione.
   Qui sparisce solo quando e' davvero vuota: se un domani riempi le
   etichette, la regola smette di applicarsi da sola e l'header torna. */
.act-header:has(> .act-num:empty):has(> .act-name:empty) {
    display: none;
}

/* ==========================================================================
   4. REVEAL ALLO SCROLL
   ========================================================================== */
.scroll-reveal {
    opacity: 0;
    transform: translateY(40px);
    transition: opacity 1s var(--ease-out), transform 1s var(--ease-out);
    transition-delay: var(--reveal-delay, 0s);
}

.scroll-reveal.is-visible {
    opacity: 1;
    transform: translateY(0);
}

/* ==========================================================================
   5. HEADER NAVIGATION
   Sopra la hero: barra piena trasparente. Oltre la hero (body.header-compact)
   logo e bottoni si riuniscono al centro in una capsula arrotondata (20px).
   ========================================================================== */
.main-header {
    position: fixed;
    top: 0;
    left: 50%;
    transform: translateX(-50%);
    width: 100%;
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 24px 5%;
    z-index: 100;
    border-radius: 40px;
    border: 1px solid transparent;
    background-color: transparent;
    transition:
        width 0.6s var(--ease-out),
        top 0.6s var(--ease-out),
        padding 0.6s var(--ease-out),
        background-color 0.5s ease,
        border-color 0.5s ease,
        box-shadow 0.5s ease;
}

body.header-compact .main-header {
    top: 14px;
    width: min(480px, 92%);
    padding: 10px 16px;
    background-color: rgba(25, 25, 25, 0.82);
    -webkit-backdrop-filter: blur(14px);
    backdrop-filter: blur(14px);
    border-color: rgba(255, 255, 255, 0.1);
    box-shadow: 0 16px 40px rgba(0, 0, 0, 0.45);
}

.logo {
    display: block;
    transition: transform 0.6s var(--ease-out);
}

.logo img {
    height: 68px;
    width: auto;
    display: block;
}

body.header-compact .logo img { height: 56px; }

.nav-links {
    display: flex;
    gap: 32px;
    align-items: center;
    transition: gap 0.6s var(--ease-out);
}

body.header-compact .nav-links { gap: 22px; }

.nav-link {
    color: #FFFFFF;
    text-decoration: none;
    font-size: 0.9rem;
    font-weight: 600;
    transition: opacity 0.3s ease, color 0.35s ease;
}

.nav-link:hover { opacity: 0.6; }

.nav-btn {
    background-color: #FFFFFF;
    color: var(--dark);
    padding: 10px 20px;
    border-radius: 30px;
    font-weight: 700;
    transition: background-color 0.35s ease, color 0.35s ease, transform 0.3s var(--ease-soft);
}

body.header-compact .nav-btn { padding: 8px 16px; }

.nav-btn:hover { opacity: 1; transform: scale(1.05); }

/* Sul foglio chiaro la capsula scura garantisce già il contrasto;
   l'inversione testo serve solo se l'header non è ancora compatto. */
body.on-light:not(.header-compact) .nav-link { color: var(--ink); }

body.on-light:not(.header-compact) .nav-btn {
    background-color: var(--ink);
    color: var(--light);
}

/* ==========================================================================
   6. HERO — ATTO 00, TITOLI DI TESTA
   Foto full-viewport con parallax, titolo a zig-zag con reveal orchestrato.
   ========================================================================== */
.hero {
    position: relative;
    min-height: 100vh;
    min-height: 100dvh;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    overflow: hidden;
    padding: 0;
}

.hero-media {
    position: absolute;
    inset: 0;
    z-index: 1;
}

.hero-media img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    /* leggero over-scale: il parallax JS non scopre mai i bordi */
    transform: scale(1.12);
    will-change: transform;
}

.hero-scrim {
    position: absolute;
    inset: 0;
    background: linear-gradient(180deg,
        rgba(25, 25, 25, 0.55) 0%,
        rgba(25, 25, 25, 0.15) 38%,
        rgba(25, 25, 25, 0.35) 68%,
        rgba(25, 25, 25, 0.92) 100%);
    z-index: 2;
}

.hero-content {
    position: relative;
    z-index: 3;
    padding-top: 18vh;
    will-change: opacity;
}

.hero-eyebrow {
    font-size: 0.85rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 2.5px;
    color: var(--accent-orange);
    margin: 0 0 4vh 5%;
    opacity: 0;
    animation: fadeIn 1s ease 1.1s forwards;
}

/* Titolo a zig-zag: pieno / contorno / pieno.
   Ogni riga esce dal proprio "sipario" (clip) in sequenza. */
.hero-title {
    font-family: var(--font-display);
    font-weight: 700;
    text-transform: uppercase;
    font-size: clamp(4.5rem, 15.5vw, 15rem);
    line-height: 0.86;
    letter-spacing: -0.015em;
    display: flex;
    flex-direction: column;
    padding: 0 4%;
    user-select: none;
}

/* RIMOSSI: .hero-line, .line-1/2/3 e @keyframes lineUp — il titolo hero a
   tre righe con il "sipario". Sostituito dal FIX 13 (round 03), che ne ha
   fatto un paragrafo ancorato in basso a sinistra. */

@keyframes fadeIn {
    to { opacity: 1; }
}

.hero-footer {
    position: relative;
    z-index: 3;
    will-change: opacity;
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: 32px;
    padding: 0 5% 5vh 5%;
    opacity: 0;
    animation: fadeIn 1s ease 1.3s forwards;
}


.scroll-cue {
    color: #FFFFFF;
    text-decoration: none;
    font-size: 0.85rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 2px;
    white-space: nowrap;
}

.scroll-cue span {
    display: inline-block;
    animation: bounce 2s ease-in-out infinite;
}

@keyframes bounce {
    0%, 100% { transform: translateY(0); }
    50%      { transform: translateY(6px); }
}

@media (max-width: 768px) {
    .hero-footer {
        flex-direction: column;
        align-items: flex-start;
        gap: 20px;
    }
}

/* ==========================================================================
   7. MARQUEE — pellicola di competenze (loop infinito CSS)
   ========================================================================== */
.marquee {
    margin: clamp(70px, 10vh, 130px) 0;
    border-top: 1px solid rgba(255, 255, 255, 0.1);
    border-bottom: 1px solid rgba(255, 255, 255, 0.1);
    overflow: hidden;
    padding: 26px 0;
}

.marquee-track {
    display: flex;
    align-items: center;
    gap: 56px;
    width: max-content;
    animation: marqueeScroll 30s linear infinite;
}

.marquee-track span {
    font-family: var(--font-display);
    font-weight: 650;
    font-size: 1.15rem;
    text-transform: uppercase;
    letter-spacing: 1.5px;
    color: rgba(255, 255, 255, 0.8);
    white-space: nowrap;
}

/* Alternanza pieno/contorno: richiama il titolo hero */
.marquee-track .outline {
    color: transparent;
    -webkit-text-stroke: 1px rgba(255, 255, 255, 0.5);
}

@keyframes marqueeScroll {
    from { transform: translateX(0); }
    to   { transform: translateX(-50%); }
}

.marquee:hover .marquee-track { animation-play-state: paused; }

/* ==========================================================================
   8. ATTO 01 — SINOSSI (manifesto editoriale con immagini inline)
   ========================================================================== */
/* padding-bottom a zero: lo stacco verso l'Atto 02 lo porta .skills-section.
   Il valore in alto era gia' stato dimezzato nel vecchio round 03: ora sta
   qui, alla fonte, e la duplicazione in coda al file e' stata rimossa. */
.about-section {
    padding-top: var(--gap-hdr-01);
    padding-bottom: 0;
}

.manifesto {
    font-family: var(--font-display);
    font-weight: 500;
    font-size: clamp(1.7rem, 3.6vw, 3.4rem);
    line-height: 1.35;
    letter-spacing: -0.01em;
    max-width: 1100px;
}

/* --- Corpo della sinossi (Atto 01, solo home) ------------------------
   Era clamp(1.7rem, 3.6vw, 3.4rem). Qui scende di circa il 14%%.
   Scritto su .about-section e non su .manifesto perche' la stessa
   classe la usa la bio dell'about, che ha il suo corpo e resta ferma.
   Per ritoccare: e' il 3.1vw a comandare fra i 550 e i 1000px di
   larghezza, il tetto di 2.95rem da li' in su. */
.about-section .manifesto {
    font-size: clamp(1.5rem, 3.1vw, 2.95rem);
}

.manifesto > span {
    display: inline;
}

.manifesto em {
    font-style: normal;
    color: var(--accent-purple);
}

.manifesto .accent {
    color: var(--accent-orange);
}

/* Chip d'immagine inline: anticipano i progetti dentro il testo */
.inline-chip {
    display: inline-block;
    width: 2.2em;
    height: 1.15em;
    object-fit: cover;
    border-radius: 100px;
    vertical-align: -0.18em;
    margin: 0 0.1em;
    transition: transform 0.4s var(--ease-soft);
}

.inline-chip:hover { transform: scale(2.2) rotate(-3deg); }

/* ==========================================================================
   9. ATTO 02 — SKILLS (scrollytelling)
   La track è alta 320vh (340vh su mobile): lo stage resta sticky mentre si scorre, e il
   progresso dello scroll accende le parole in sequenza e cambia l'immagine.
   ========================================================================== */
.skills-section {
    padding-top: var(--gap-01-02);
    padding-bottom: 0; /* lo stacco verso l'Atto 03 lo porta .portfolio-section */
}

.skills-track {
    height: 320vh; /* più è alta, più la sequenza è lenta */
    position: relative;
}

.skills-stage {
    position: sticky;
    top: 0;
    height: 100vh;
    height: 100svh;
    display: flex;
    align-items: center;
    overflow: hidden;
}

.skills-stage .act-header {
    position: absolute;
    top: clamp(28px, 6vh, 64px);
    left: 0;
    right: 0;
    margin-bottom: 0;
}

.skills-stage .container {
    position: relative;
    height: 100%;
    display: flex;
    align-items: center;
}

.skills-layout {
    width: 100%;
    display: grid;
    grid-template-columns: 0.75fr 1.25fr;
    gap: clamp(40px, 6vw, 100px);
    align-items: center;
}

/* --- Le quattro parole: spente in grigio, accese in accento, una alla volta --- */
.skill-words {
    display: flex;
    flex-direction: column;
    gap: 0.3em;
    position: relative;
    z-index: 2; /* le parole giganti passano sopra la foto: è voluto */
    will-change: transform;
}

/* Il ritratto: proporzioni verticali, cornice unica.
   max-width con min(vw, vh): sui portatili bassi comanda l'altezza, sui
   monitor grandi la larghezza, e non sfonda mai lo stage sticky.
   Questa e' l'UNICA regola che dimensiona la cornice: i tre override in
   coda al file (round 01 e round finale) sono stati rimossi. */
.skill-frame {
    position: relative;
    z-index: 1;
    width: 100%;
    max-width: clamp(200px, min(19vw, 34vh), 500px);
    justify-self: start;
    aspect-ratio: 7 / 10;
    will-change: transform;
}

.skill-word {
    font-family: var(--font-display);
    text-transform: uppercase;
    white-space: nowrap;
    will-change: opacity;
    font-weight: 650;
    font-size: clamp(6rem, 9.5vw, 9.4rem);
    text-align: right;
    line-height: 1;
    letter-spacing: -0.02em;
    color: #3D3D3D;
    transition: color 0.6s ease, transform 0.6s var(--ease-soft);
    transform-origin: right center;
}

.skill-word.is-lit {
    color: var(--accent-orange);
    transform: translateX(0.12em);
}

.skill-float {
    position: relative;
    width: 100%;
    height: 100%;
    border-radius: 24px;
    overflow: hidden;
    box-shadow: 0 30px 90px rgba(0, 0, 0, 0.6);
    animation: gentleFloat 7s ease-in-out infinite;
}

/* Oscillazione di riposo: sobria ma percepibile */
@keyframes gentleFloat {
    0%, 100% { transform: translateY(0) rotate(0deg); }
    50%      { transform: translateY(-12px) rotate(0.72deg); }
}

.skill-img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    opacity: 0;
    transform: scale(1.05);
    transition: opacity 0.6s ease, transform 1.1s var(--ease-soft);
}

.skill-img.is-active {
    opacity: 1;
    transform: scale(1);
}

@media (max-width: 991px) {
    .skills-track { height: 340vh; }
    .skills-layout {
        grid-template-columns: 1fr;
        gap: 40px;
    }
    .skill-frame {
        justify-self: center;
        max-width: min(48vw, 24vh);
    }
    .skill-word { font-size: clamp(4.6rem, 19vw, 8.5rem); }
}

/* --- SCHERMI GRANDI (27" e oltre) ----------------------------------------
   Da 1800px in su il tappo di 1280px del .container non e' piu' una misura
   di leggibilita': e' solo una gabbia. La colonna del ritratto si ferma a
   442px e la cornice, per quanto la si allarghi, non ha spazio dove
   crescere. Qui il contenitore dell'Atto 02 — e SOLO quello — viene
   sganciato con una larghezza fluida, e i tetti di cornice e parole salgono
   di conseguenza.

   La soglia e' 1800px per non toccare i portatili: un MacBook Pro 16"
   riporta 1728px CSS e resta esattamente com'e' adesso.

   Il tetto in vh e' la briglia vera: la cornice e' 7/10, quindi 46vw di
   larghezza diventano 66vh di altezza. Oltre si scontrerebbe con
   l'act-header in alto e con il parallax del mouse (±64px). */
@media (min-width: 1800px) {

    .skills-stage .container {
        max-width: var(--wide-container);
    }

    .skill-frame {
        max-width: min(26vw, 46vh);
    }

    /* Le parole seguono, altrimenti il ritratto le schiaccia e l'equilibrio
       della scena si ribalta. Il termine in vh non e' un dettaglio: sono
       quattro righe impilate, e su un monitor largo ma basso 8vw le
       porterebbe a sfondare il bordo inferiore durante la deriva. Con
       min(vw, vh) il blocco resta sempre alto circa 61vh. */
    .skill-word {
        font-size: clamp(9.4rem, min(8vw, 15vh), 13rem);
    }
}

/* ==========================================================================
   10. ATTO 03 — SCENE PRINCIPALI
   Il foglio chiaro: lo schermo acceso nel buio della sala.
   Niente gradiente: un taglio netto, con angoli arrotondati.
   ========================================================================== */
/* Il foglio e' a filo dei bordi (margini laterali 0): assorbe il vecchio
   FIX 3 del round 01, che qui non serve piu'. */
.portfolio-section {
    background-color: var(--light);
    color: var(--ink);
    border-radius: clamp(28px, 4vw, 56px);
    margin: var(--gap-02-03) 0 0 0;
    padding: clamp(100px, 14vh, 160px) 0 clamp(120px, 16vh, 180px) 0;
}

.act-header-light .act-num { color: var(--accent-orange); } /* arancio: contrasto pieno su chiaro */

.portfolio-intro {
    margin-bottom: clamp(72px, 10vh, 120px);
    max-width: 680px;
}

.section-title {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: clamp(2.4rem, 5vw, 4.2rem);
    line-height: 1.02;
    letter-spacing: -0.02em;
    margin-bottom: 28px;
}

.section-desc {
    font-size: 1.2rem;
    line-height: 1.6;
    color: #55555A;
}

/* Griglia asimmetrica 12 colonne, card frameless editoriali */
.portfolio-grid {
    display: grid;
    grid-template-columns: repeat(12, 1fr);
    gap: clamp(90px, 13vh, 150px) 56px;
}

/* RIMOSSI: .col-span-* e .card-offset — la griglia a 12 colonne con gli
   scarti verticali alternati, sostituita dal FIX 6 (righe flex a coppie). */
@media (max-width: 991px) {
    .portfolio-grid { gap: 72px 0; }
}

.portfolio-card {
    background: none;
    border: none;
}

.card-img-wrapper {
    position: relative;
    width: 100%;
    aspect-ratio: 16 / 10;
    overflow: hidden;
    border-radius: 18px;
    background-color: #E4E2DC;
    margin-bottom: 22px;
}

.card-img-wrapper img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: transform 0.8s var(--ease-soft);
}

.portfolio-card:hover .card-img-wrapper img { transform: scale(1.05); }

.card-meta {
    display: flex;
    align-items: center;
    gap: 14px;
    margin-bottom: 12px;
}

.card-index {
    font-size: 0.8rem;
    font-weight: 700;
    letter-spacing: 1.5px;
    color: #9A9892;
    font-variant-numeric: tabular-nums;
}

.card-tag {
    font-size: 0.72rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 1px;
    padding: 6px 13px;
    border-radius: 30px;
    color: var(--ink);
    background-color: #E9E7E1; /* fallback */
}

/* Un pastello per ogni tipologia di attivita' */
.tag-guerrilla  { background-color: var(--pill-lime); }
.tag-tiktok     { background-color: var(--pill-lilac); }
.tag-virtual    { background-color: var(--pill-blue); }
.tag-audio      { background-color: var(--pill-peach); }
.tag-web        { background-color: var(--pill-mint); }
.tag-community  { background-color: var(--pill-pink); }

.card-title {
    font-family: var(--font-display);
    font-weight: 650;
    font-size: 1.6rem;
    letter-spacing: -0.01em;
    margin-bottom: 10px;
}

.card-text {
    font-size: 1rem;
    line-height: 1.6;
    color: #55555A;
    max-width: 52ch;
}

/* ==========================================================================
   11. ATTO 04 — TITOLI DI CODA (contatti + nome finale)
   ========================================================================== */
.contact-section {
    padding: var(--gap-03-04) 0 0 0;
}

.contact-card {
    background-color: #202020;
    border: 1px solid rgba(255, 255, 255, 0.08);
    color: #FFFFFF;
    border-radius: 32px;
    padding: 80px 60px;
    text-align: center;
    max-width: 1000px;
    margin: 0 auto;
}

@media (max-width: 768px) {
    .contact-card { padding: 48px 24px; }
}

.section-tag-alt {
    display: inline-block;
    padding: 6px 12px;
    background-color: rgba(255, 255, 255, 0.05);
    border: 1px solid rgba(255, 255, 255, 0.1);
    color: var(--accent-orange);
    font-size: 0.8rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 1px;
    border-radius: 4px;
    margin-bottom: 32px;
}

.contact-title {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: clamp(2rem, 4vw, 3.5rem);
    letter-spacing: -0.015em;
    margin-bottom: 48px;
}

.mad-libs-container {
    max-width: 800px;
    margin: 0 auto;
}

.mad-libs-text {
    font-size: clamp(1.3rem, 2.5vw, 2rem);
    line-height: 1.7;
    font-weight: 500;
    color: #A1A1AA;
    margin-bottom: 48px;
    text-align: left;
}

.select-wrapper {
    display: inline-block;
    position: relative;
    border-bottom: 2px dashed var(--accent-orange);
    padding: 0 4px;
}

.select-wrapper select {
    appearance: none;
    -webkit-appearance: none;
    background: transparent;
    border: none;
    font-family: inherit;
    font-size: inherit;
    font-weight: 700;
    color: #FFFFFF;
    cursor: pointer;
    padding-right: 16px;
}

.select-wrapper select option { color: var(--ink); }

.select-wrapper::after {
    content: '▾';
    font-size: 0.6em;
    position: absolute;
    right: 2px;
    bottom: 0.5em;
    color: var(--accent-orange);
    pointer-events: none;
}

.btn-pastel {
    background-color: var(--accent-orange);
    color: #FFFFFF;
    border: none;
    padding: 20px 48px;
    border-radius: 40px;
    font-family: inherit;
    font-size: 1.1rem;
    font-weight: 700;
    cursor: pointer;
    transition: transform 0.3s var(--ease-soft), box-shadow 0.3s var(--ease-soft);
}

.btn-pastel:hover {
    transform: translateY(-4px);
    box-shadow: 0 15px 30px rgba(216, 86, 51, 0.35);
}

/* Il nome appare solo qui, gigante, come firma di regia */
.end-credits {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 18px;
    padding: clamp(100px, 16vh, 180px) 4% clamp(60px, 8vh, 100px) 4%;
    text-align: center;
}

.credits-role {
    font-size: 0.8rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 3px;
    color: var(--muted);
}

.credits-name {
    font-family: var(--font-display);
    font-weight: 700;
    text-transform: uppercase;
    font-size: clamp(3rem, 11vw, 11rem);
    line-height: 0.95;
    letter-spacing: -0.015em;
    color: transparent;
    -webkit-text-stroke: 2px rgba(255, 255, 255, 0.85);
    white-space: nowrap;
    transition: color 0.6s var(--ease-soft);
}

.credits-name:hover { color: var(--accent-orange); -webkit-text-stroke: 2px transparent; }

/* ==========================================================================
   12. FOOTER
   ========================================================================== */
.main-footer {
    padding: 40px 0 48px 0;
    border-top: 1px solid rgba(255, 255, 255, 0.08);
}

.footer-grid {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 24px;
}

@media (max-width: 680px) {
    .footer-grid {
        flex-direction: column;
        text-align: center;
    }
}

.copyright {
    font-size: 0.9rem;
    opacity: 0.6;
}

.footer-socials {
    display: flex;
    gap: 24px;
}

.social-link {
    color: inherit;
    text-decoration: none;
    font-size: 0.9rem;
    font-weight: 600;
    transition: opacity 0.3s;
}

.social-link:hover { opacity: 0.7; }

/* ==========================================================================
   13. REDUCED MOTION
   (Lenis e parallax si disattivano via JS; qui si azzera il resto)
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
    }
    .scroll-reveal { opacity: 1; transform: none; }
    .hero-eyebrow, .hero-footer { opacity: 1; animation: none; }
    .marquee-track { animation: none; }
    .hero-media img { transform: none; }
}

/* ==========================================================================
   14. PAGINE PORTFOLIO (portfolio01.html ... portfolio06.html)
   I contenitori fanno da cornice: proporzioni fisse, foto centrata con
   object-fit cover, eccedenze nascoste, bordi arrotondati. Così le foto
   non vanno ridimensionate al millimetro.
   ========================================================================== */
.project-main {
    padding-top: clamp(120px, 16vh, 170px);
}

.project-block {
    perspective: 1000px; /* profondità per l'inclinazione 3D delle cornici */
}

/* La cornice */
.project-media {
    position: relative;
    width: 100%;
    border-radius: clamp(18px, 2vw, 28px);
    overflow: hidden;
    background-color: #222222;
    transition: transform 0.6s var(--ease-soft);
    will-change: transform;
    transform-style: preserve-3d;
}

.project-media img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;      /* centra e taglia le eccedenze */
    object-position: center;
    transition: transform 0.8s var(--ease-soft);
}

/* RIMOSSI: .tilt e .shine — zoom e riflesso sulle foto di progetto. Il FIX 8
   (round 03) li aveva gia' tolti dal markup; restava solo il CSS. */

/* Le proporzioni delle cornici stanno nella sezione 15: erano dichiarate
   qui e riscritte la' con altri valori, quindi queste tre righe non hanno
   mai avuto effetto. */

/* Ritmo verticale della pagina */
.project-hero,
.project-wide,
.project-grid-2,
.project-brief,
.project-nav {
    margin-bottom: clamp(48px, 7vh, 90px);
}

.project-grid-2 {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: clamp(24px, 3.5vw, 56px);
}

@media (max-width: 768px) {
    .project-grid-2 { grid-template-columns: 1fr; gap: 32px; }
}

/* --- Barra info arancione --- */
.project-brief {
    background-color: var(--accent-orange);
    color: var(--dark);
    border-radius: 20px;
    padding: clamp(22px, 3vw, 34px) clamp(22px, 3vw, 38px);
    display: grid;
    grid-template-columns: 1.15fr 0.85fr;
    gap: clamp(32px, 6vw, 90px);
    align-items: start;
}

@media (max-width: 768px) {
    .project-brief { grid-template-columns: 1fr; gap: 28px; }
}

.brief-label {
    display: block;
    font-size: 0.7rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 1.5px;
    margin-bottom: 12px;
    opacity: 0.75;
}

.brief-overview p {
    font-size: 0.98rem;
    line-height: 1.5;
    font-weight: 500;
}

.brief-meta {
    display: flex;
    flex-direction: column;
}

.brief-row {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 24px;
    padding: 10px 0;
    border-bottom: 1px solid rgba(25, 25, 25, 0.35);
}

.brief-row dt {
    font-size: 0.72rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 1px;
    opacity: 0.75;
}

.brief-row dd {
    margin: 0;
    font-size: 0.95rem;
    font-weight: 700;
}

/* --- Navigazione tra le scene --- */
.project-nav {
    display: flex;
    justify-content: space-between;
    gap: 24px;
    padding-top: 12px;
}

.project-nav-link {
    font-family: var(--font-display);
    font-weight: 650;
    font-size: clamp(1.1rem, 2vw, 1.5rem);
    color: #FFFFFF;
    text-decoration: none;
    transition: color 0.3s ease, transform 0.3s var(--ease-soft);
}

.project-nav-link:hover {
    color: var(--accent-orange);
    transform: translateX(4px);
}

.project-nav-link:first-child:hover { transform: translateX(-4px); }

/* --- Reveal bidirezionale: entra con fade+risalita, esce con fade --- */
.reveal-io {
    opacity: 0;
    transform: translateY(50px) scale(0.985);
    transition: opacity 0.9s var(--ease-out), transform 0.9s var(--ease-out);
}

.reveal-io.in-view {
    opacity: 1;
    transform: translateY(0) scale(1);
}

/* --- Card della home cliccabili verso le pagine progetto --- */
.card-link {
    display: block;
    color: inherit;
    text-decoration: none;
}

@media (prefers-reduced-motion: reduce) {
    .reveal-io { opacity: 1; transform: none; }
}

/* ==========================================================================
   15. PAGINA PROGETTO — LAYOUT DI RIFERIMENTO "TABASQUE"
   Hero con parallax a finestra (la cornice copre progressivamente la foto,
   pilotato da main.js §8), titolo grande + tagline, scheda Year/Client/
   Services a righe, overview in stile manifesto. Proporzioni come nel
   riferimento: hero e full-width 3:2, coppie verticali 4:5.
   Selettori usati solo nelle pagine progetto: la home non è toccata.
   ========================================================================== */

/* --- Proporzioni delle cornici (unica sede: la sezione 14 dichiarava altri
   valori, tutti scavalcati da qui e quindi rimossi) --------------------- */
.project-hero .project-media   { aspect-ratio: 16 / 9; }
.project-wide .project-media   { aspect-ratio: 3 / 2; }
.project-grid-2 .project-media { aspect-ratio: 4 / 5; }

/* --- Parallax a due strati ------------------------------------------------
   Il parallax non deve per forza vivere DENTRO la foto. Qui sono due
   movimenti sommati, e solo uno dei due costa immagine:

   1) LA CORNICE VA ALLA DERIVA (--hero-deriva). L'intero riquadro, foto
      compresa, resta indietro rispetto allo scroll di qualche pixel. E' il
      movimento che si legge come profondita', e non taglia nulla: la foto
      dentro sta ferma e intera. Da sola questa riga basterebbe.
      La deriva e' solo verso il basso: sopra la foto c'e' sempre un titolo
      a pochi pixel, sotto c'e' un margine largo.

   2) LA FOTO SCORRE NELLA CORNICE (--hero-sovrascala). Questo e' il
      parallax classico ed e' l'unico che costa: per scorrere, l'immagine
      deve essere piu' alta della cornice, e per riempire un box piu' alto
      viene ingrandita — l'eccedenza esce di LATO, non sopra e sotto.

   Il valore di partenza e' 106%: si perde il 2,8% per lato, cioe' 54px su
   una foto da 1920. Se i testi nelle tue immagini stanno a piu' del 3% dal
   bordo (~60px su 1920) non ne esce niente. Se li tieni piu' a filo,
   scendi a 104%; se vuoi la garanzia assoluta metti 100% e resta solo la
   deriva della cornice, che e' comunque un parallax vero.

   Entrambi usano le proprieta' indipendenti `translate` e `scale` invece
   di `transform`: cosi' si sommano da soli al transform che .reveal-io usa
   per l'entrata e allo zoom dell'hover, senza cancellarli. */
.parallax-window,
.about-figure {
    --hero-sovrascala: 106%;
    --hero-deriva: 40px;   /* di quanto la cornice scende, in tutta la corsa */
    translate: 0 var(--hero-drift, 0px);
    will-change: translate;
}

.parallax-window img,
.about-figure img {
    display: block;
    height: var(--hero-sovrascala);
    transform: translateY(var(--hero-pan, 0%));
    will-change: transform;
}

.parallax-window img {
    bottom: auto;
    transition: none;
}

/* --- Titolo e tagline --- */
.project-header {
    margin-bottom: clamp(36px, 5vh, 60px);
}

.project-title {
    font-family: var(--font-display);
    font-weight: 500;
    text-transform: uppercase;
    font-size: clamp(3rem, 9vw, 8rem);
    line-height: 0.92;
    letter-spacing: -0.02em;
}

.project-subtitle {
    margin-top: 20px;
    font-size: clamp(1.15rem, 2.2vw, 1.8rem);
    font-weight: 300;
    color: rgba(255, 255, 255, 0.65);
}

/* --- Scheda info a righe (Year / Client / Services) --- */
.project-meta {
    max-width: 560px;
    margin-bottom: clamp(36px, 5vh, 60px);
}

.meta-row {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 18px;
    padding: 14px 0;
    border-bottom: 1px solid rgba(255, 255, 255, 0.12);
}

.meta-row:first-child { border-top: 1px solid rgba(255, 255, 255, 0.12); }

.meta-row dt {
    font-size: 0.72rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 1.5px;
    opacity: 0.6;
}

.meta-row dd {
    margin: 0;
    font-size: 0.95rem;
    font-weight: 500;
    text-align: right;
}

/* --- Overview: eco del manifesto della home --- */
.project-overview {
    font-family: var(--font-display);
    font-weight: 500;
    font-size: clamp(1.5rem, 3vw, 2.6rem);
    line-height: 1.15;
    letter-spacing: -0.01em;
    max-width: 1000px;
    margin-bottom: clamp(64px, 9vh, 110px);
}

/* Su reduced-motion il JS non muove niente: senza scorrimento la
   sovrascala sarebbe solo un ritaglio gratuito, quindi torna a 100% e la
   deriva della cornice si azzera. */
@media (prefers-reduced-motion: reduce) {
    .parallax-window,
    .about-figure {
        --hero-sovrascala: 100%;
        --hero-deriva: 0px;
    }
}

/* ==========================================================================
   16. PAGINA ABOUT — DIETRO LE QUINTE
   Extra 01: foto a sinistra (angoli curvi come le foto progetto, tilt +
   shine) e "About me" a destra. Fade in/out allo scroll via .reveal-io.
   Extra 02: diario di visione — 4 card placeholder per il feed Letterboxd,
   da popolare via fetch (letterboxd-proxy.php, integrazione futura).
   Selettori usati solo in about.html: il resto del sito non è toccato.
   ========================================================================== */

.about-hero-section {
    margin-bottom: var(--gap-about-blocks);
}


/* RIMOSSI: .about-hero, .about-photo, .about-title, .about-text.
   Erano il vecchio impianto a due colonne (foto a sinistra, testo a
   destra), sostituito dalla testata a tutta larghezza della sezione 22.
   Nessuna di queste classi esiste piu' in about.html. */

/* ==========================================================================
   DIARIO DI VISIONE (card Letterboxd)
   ========================================================================== */
.lb-section {
    margin-bottom: var(--gap-about-blocks);
}

.lb-intro {
    margin-bottom: clamp(32px, 4.5vh, 56px);
    max-width: 80%;
}

/* section-title nasce per il foglio chiaro: qui si adatta al buio */
.lb-title-main { color: #FFFFFF; font-weight: 600; }

.lb-grid {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: clamp(20px, 2.5vw, 32px);
}

@media (max-width: 991px) { .lb-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 560px) { .lb-grid { grid-template-columns: 1fr; } }

.lb-card {
    background-color: #202020;
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 18px;
    overflow: hidden;
    transition: transform 0.4s var(--ease-soft), border-color 0.4s ease;
}

.lb-card:hover {
    transform: translateY(-6px);
    border-color: rgba(255, 255, 255, 0.2);
}

/* Locandina: proporzioni poster cinema (2:3). Il placeholder mostra
   un'etichetta; con il feed vero qui entrerà <img> a tutta cornice. */
.lb-poster {
    aspect-ratio: 2 / 3;
    background: linear-gradient(160deg, #2A2A2A 0%, #1E1E1E 100%);
    display: flex;
    align-items: center;
    justify-content: center;
}

.lb-poster span {
    font-size: 0.72rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 2px;
    opacity: 0.35;
}

.lb-poster img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.lb-body {
    padding: 18px 18px 20px 18px;
}

.lb-title {
    font-family: var(--font-display);
    font-weight: 650;
    font-size: 1.1rem;
    letter-spacing: -0.01em;
    margin-bottom: 8px;
}

.lb-rating {
    color: var(--accent-orange);
    font-size: 0.9rem;
    letter-spacing: 2px;
    margin-bottom: 10px;
}

.lb-more {
    margin-top: clamp(36px, 5vh, 56px);
    text-align: right;
}

/* ==========================================================================
   17. CORREZIONI INDEX — round 01
   Regole in coda: vincono per ordine di cascata, le sezioni originali
   restano leggibili e intatte.
   ========================================================================== */

/* --- FIX 1 — La hero entra esatta nel viewport ----------------------------
   Il problema non era l'unità (dvh/svh) ma il fatto che min-height è un
   PAVIMENTO, non un soffitto: il contenuto interno (padding 18vh + tre
   righe di titolo a 15.5vw + footer) su schermi bassi e larghi superava
   l'altezza dello schermo e la sezione cresceva. Qui l'altezza diventa
   esatta e il titolo scala anche sull'ALTEZZA, non solo sulla larghezza. */
.hero {
    min-height: 0;
    height: 100vh;
    height: 100svh; /* svh = viewport minimo: mai coperto dalle barre mobile */
}

.hero-title {
    /* min(vw, vh): sui portatili bassi comanda l'altezza, sui 27" la
       larghezza, e il tetto di 15rem resta quello di prima */
    font-size: clamp(3.2rem, min(15.5vw, 22vh), 15rem);
}

.hero-content {
    padding-top: clamp(60px, 13vh, 160px);
}

/* --- FIX 2 — Il ritratto dell'Atto 02 scala con lo schermo ----------------
   RIMOSSO: superato dal round finale e ora scritto una volta sola nella
   sezione 9, dove la cornice viene dimensionata. */

/* --- FIX 3 — Il foglio bianco a filo dei bordi ---------------------------
   RIMOSSO: assorbito nella regola .portfolio-section della sezione 10. */

/* --- FIX 4 — Menu a tendina custom ----------------------------------------
   La tendina nativa è disegnata dal sistema operativo: bella su macOS,
   anni '90 su Windows, e non accetta CSS. Qui il <select> resta nel DOM
   (invisibile) e continua a essere la fonte del valore per initMadLibs:
   se il JS non parte, la tendina nativa torna a funzionare da sola.
   Sopra ci disegniamo un pannello nostro, uguale su ogni sistema. */

/* Il select nativo si nasconde solo quando il JS ha costruito la tendina */
.cs-native {
    position: absolute;
    width: 1px;
    height: 1px;
    opacity: 0;
    pointer-events: none;
}

/* Il "bottone": è la parola nella frase, eredita corpo e peso */
.cs-trigger {
    appearance: none;
    background: transparent;
    border: none;
    padding: 0 16px 0 0;
    font: inherit;
    font-weight: 700;
    color: #FFFFFF;
    cursor: pointer;
    line-height: inherit;
    text-align: left;
}

.select-wrapper.is-open::after { transform: rotate(180deg); }
.select-wrapper::after { transition: transform 0.25s var(--ease-soft); }

/* Il pannello: corpo del testo FISSO, slegato dalla frase gigante.
   Era questo il problema su Mac, dove le voci risultavano enormi. */
.cs-list {
    position: absolute;
    top: calc(100% + 12px);
    left: 0;
    z-index: 40;
    min-width: 100%;
    width: max-content;
    max-width: min(340px, 78vw);
    margin: 0;
    padding: 6px;
    list-style: none;
    text-align: left;
    background-color: #1A1A1A;
    border: 1px solid rgba(255, 255, 255, 0.12);
    border-radius: 14px;
    box-shadow: 0 24px 60px rgba(0, 0, 0, 0.55);
    font-family: var(--font-body, inherit);
    font-size: clamp(0.9rem, 1.05vw, 1.05rem);
    font-weight: 500;
    line-height: 1.4;
    max-height: min(320px, 50vh);
    overflow-y: auto;
    transform-origin: top left;
    animation: csIn 0.22s var(--ease-out) both;
}

/* Se la tendina uscirebbe dallo schermo, il JS la ancora a destra */
.cs-list.cs-flip { left: auto; right: 0; transform-origin: top right; }

.cs-list[hidden] { display: none; }

@keyframes csIn {
    from { opacity: 0; transform: translateY(-6px) scale(0.98); }
    to   { opacity: 1; transform: translateY(0) scale(1); }
}

.cs-option {
    padding: 10px 14px;
    border-radius: 9px;
    color: #D4D4D8;
    cursor: pointer;
    transition: background-color 0.18s ease, color 0.18s ease;
}

.cs-option:hover,
.cs-option:focus,
.cs-option:focus-visible {
    background-color: rgba(255, 255, 255, 0.07);
    color: #FFFFFF;
    outline: none;
}

.cs-option.is-selected {
    color: var(--accent-orange);
    font-weight: 700;
}

/* Pallino sulla voce attiva: si capisce al volo cosa è selezionato */
.cs-option.is-selected::before {
    content: '';
    display: inline-block;
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background-color: var(--accent-orange);
    margin-right: 9px;
    vertical-align: middle;
}

@media (prefers-reduced-motion: reduce) {
    .cs-list { animation: none; }
    .select-wrapper::after { transition: none; }
}

/* ==========================================================================
   18. CORREZIONI INDEX — round 02 (Atto 03)
   ========================================================================== */

/* --- FIX 5 — Angoli arrotondati anche a margine zero ---------------------
   RIMOSSO: era identico al border-radius gia' scritto nella sezione 10. */

/* --- FIX 6 — Griglia regolare a coppie con ingrandimento reciproco --------
   La griglia a 12 colonne con span diversi e offset verticali dava
   l'effetto "disordine" segnalato dalla cliente. Ora ogni riga e' una
   coppia di card identiche; il ritmo non e' piu' nella misura fissa ma
   nel movimento: al passaggio del mouse la card cresce e la gemella si
   stringe. I testi stanno dentro la card, quindi seguono la colonna da
   soli e restano sempre allineati alla loro foto.

   Perche' flex-grow e non le colonne della griglia: flex-grow e' animabile
   ovunque e in modo fluido, e ogni riga e' indipendente dalle altre.
   ------------------------------------------------------------------------ */
.portfolio-grid {
    display: flex;
    flex-direction: column;
    gap: clamp(70px, 10vh, 120px);
}

.pf-row {
    display: flex;
    align-items: flex-start;
    gap: clamp(28px, 3.5vw, 56px);
}

.pf-row .portfolio-card {
    flex: 1 1 0;
    min-width: 0; /* senza questo il flex non lascia stringere il testo */
    /* opacity e transform vanno ripetute: questa regola vince su
       .scroll-reveal e la scorciatoia transition azzererebbe le sue */
    transition: flex-grow 0.75s var(--ease-soft),
                opacity 1s var(--ease-out),
                transform 1s var(--ease-out);
    transition-delay: var(--reveal-delay, 0s);
}

/* Il ritardo dello stagger vale per l'entrata, non per l'hover:
   a card gia' visibile la tendina di flex-grow deve partire subito */
.pf-row .portfolio-card.is-visible { transition-delay: 0s; }

/* Quando una card della riga e' sotto il mouse, l'altra arretra... */
.pf-row:has(.portfolio-card:hover) .portfolio-card { flex-grow: 0.74; }
/* ...e quella puntata prende lo spazio liberato */
.pf-row .portfolio-card:hover { flex-grow: 1.26; }

/* La cornice ha altezza FISSA: cambia solo la larghezza, cosi' la pagina
   sotto non salta mai. La foto si scopre di lato invece di gonfiarsi. */
.pf-row .card-img-wrapper {
    aspect-ratio: auto;
    height: clamp(240px, 26vw, 420px);
}

/* Lo zoom interno resta, appena accennato: sommato all'allargamento
   sarebbe troppo */
.pf-row .portfolio-card:hover .card-img-wrapper img { transform: scale(1.03); }

/* Altezza minima del testo: la card stretta manda a capo una riga in piu',
   riservare lo spazio evita che il contenuto sotto sobbalzi */
.pf-row .card-text {
    min-height: calc(4 * 1.6em);
    margin-bottom: 0;
}

/* Sotto i 992px si torna a una colonna: l'hover non esiste sul touch,
   e la cornice riprende le sue proporzioni naturali */
@media (max-width: 991px) {
    .pf-row {
        flex-direction: column;
        gap: clamp(56px, 8vh, 90px);
    }
    .pf-row .portfolio-card,
    .pf-row:has(.portfolio-card:hover) .portfolio-card,
    .pf-row .portfolio-card:hover { flex-grow: 1; }
    .pf-row .card-img-wrapper { aspect-ratio: 16 / 10; height: auto; }
    .pf-row .card-text { min-height: 0; }
}

/* Su dispositivi senza mouse l'effetto non si attiva mai: niente stati
   appiccicati dopo il tap */
@media (hover: none) {
    .pf-row:has(.portfolio-card:hover) .portfolio-card,
    .pf-row .portfolio-card:hover { flex-grow: 1; }
}

@media (prefers-reduced-motion: reduce) {
    .pf-row .portfolio-card { transition: none; }
}

/* ==========================================================================
   19. PAGINA PROGETTO — TESTATA EDITORIALE (round 03)
   Cliente e titolo condividono lo stesso corpo tipografico e si
   distinguono solo per colore: bianco il cliente, arancio il lavoro.
   Sotto, due colonne: info a sinistra, descrizione a destra, allineata
   al centro del blocco info. Sovrascrive per ordine la sezione 15.
   ========================================================================== */

/* Corpo condiviso da etichette, valori e descrizione: un solo numero
   da toccare se la cliente li vuole più grandi o più piccoli */
:root { --project-info-size: clamp(0.95rem, 1.15vw, 1.15rem); }

.project-intro {
    margin-bottom: clamp(70px, 11vh, 130px);
}

/* --- Blocco tipografico: cliente + titolo --- */
.project-lockup {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: clamp(2.6rem, 7.4vw, 6.4rem);
    line-height: 1.02;
    letter-spacing: -0.025em;
    margin-bottom: clamp(60px, 11vh, 150px);
}

.project-client,
.project-title {
    font: inherit;
    margin: 0;
    text-transform: none;
    letter-spacing: inherit;
}

.project-client { color: #FFFFFF; }
.project-title  { color: var(--accent-orange); }

/* --- Due colonne: info a sinistra, descrizione a destra --- */
.project-details {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: clamp(36px, 6vw, 110px);
    align-items: center; /* la descrizione si centra sulle info */
}

/* Le info: niente più righe separate da bordi, solo etichetta + valore */
.project-meta {
    max-width: none;
    margin: 0;
}

.meta-row {
    display: grid;
    grid-template-columns: minmax(88px, 128px) 1fr;
    gap: 16px;
    align-items: baseline;
    padding: 0 0 14px 0;
    border: none;
}

.meta-row:first-child { border-top: none; }
.meta-row:last-child  { padding-bottom: 0; }

.meta-row dt {
    font-size: var(--project-info-size);
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: 1.5px;
    color: rgba(255, 255, 255, 0.42);
    opacity: 1;
}

.meta-row dd {
    margin: 0;
    font-size: var(--project-info-size);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    color: #FFFFFF;
    text-align: left;
}

/* --- La descrizione: font del sito, stesso corpo delle info --- */
.project-overview {
    font-family: var(--font-body);
    font-weight: 400;
    font-size: var(--project-info-size);
    line-height: 1.75;
    letter-spacing: 0;
    color: #FFFFFF;
    max-width: 58ch;
    margin: 0;
}

@media (max-width: 860px) {
    .project-details {
        grid-template-columns: 1fr;
        gap: 36px;
        align-items: start;
    }
    .project-overview { max-width: none; }
}

/* --- FIX 8 — Niente zoom né riflesso sulle foto di progetto ---------------
   Le classi .tilt e gli <span class="shine"> sono stati tolti dal markup:
   initTiltEffect non trova più nulla ed esce da solo. Qui neutralizzo
   anche la transizione rimasta sulla cornice, così le foto stanno ferme. */
.project-page .project-media,
.project-page .project-media img {
    transition: none;
}
.project-overview { font-size: clamp(1.15rem, 1.7vw, 1.5rem); }

/* ==========================================================================
   20. PAGINA PROGETTO — ritocchi alla testata
   ========================================================================== */

/* --- FIX 9 — Cliente e titolo piu' leggeri -------------------------------
   Chillax e' un font variabile con asse 200-700: il peso non salta di
   scatto tra i tagli, si sceglie il valore esatto. A questo corpo il 700
   diventa un muro; 450 tiene la presenza e lascia respirare le lettere.
   Il titolo eredita da qui, quindi basta questa riga per entrambi. */
.project-lockup { font-weight: 450; }

/* --- FIX 10 — Descrizione piu' compatta ----------------------------------
   1.75 e' un'interlinea da testo lungo; su quattro o cinque righe
   affiancate a un blocco di info sfilacciava il paragrafo. */
.project-overview { line-height: 1.45; }

/* ==========================================================================
   21. TRANSIZIONE TRA LE PAGINE (View Transitions API)
   La pagina nuova entra salendo dal basso, come una diapositiva che si
   infila davanti alla precedente; la vecchia arretra di un soffio invece
   di sparire, cosi' il movimento ha profondita' invece di essere un taglio.

   Non serve toccare nessun link: il browser intercetta da solo ogni
   navigazione verso una pagina dello stesso sito, purche' entrambe
   dichiarino questa regola. Vivendo nel foglio di stile condiviso, la
   dichiarano tutte automaticamente — anche le portfolio02...06 che
   nasceranno domani.

   Supporto: Chrome/Edge 126+, Safari 18.2+. Firefox non c'e' ancora.
   Dove manca, il link funziona esattamente come prima: nessun errore,
   nessuna attesa, solo il cambio pagina secco di sempre.
   ========================================================================== */

/* L'opt-in sta dentro prefers-reduced-motion: chi ha chiesto meno
   animazioni al sistema operativo non entra proprio nel meccanismo. */
@media (prefers-reduced-motion: no-preference) {
    @view-transition { navigation: auto; }
}

/* --- La pagina che entra: sale dal basso --- */
::view-transition-new(root) {
    animation: vtPageIn 0.99s cubic-bezier(0.16, 1, 0.3, 1) both;
    /* il browser userebbe plus-lighter per la dissolvenza incrociata:
       qui le pagine si sovrappongono davvero, quindi serve normale */
    mix-blend-mode: normal;
}

/* --- La pagina che esce: resta sotto e indietreggia --- */
::view-transition-old(root) {
    animation: vtPageOut 0.99s cubic-bezier(0.16, 1, 0.3, 1) both;
    mix-blend-mode: normal;
}

@keyframes vtPageIn {
    from { transform: translateY(100%); }
    to   { transform: translateY(0); }
}

@keyframes vtPageOut {
    from { transform: scale(1);    opacity: 1; }
    to   { transform: scale(0.94); opacity: 0.5; }
}

/* ==========================================================================
   22. PAGINA ABOUT — TESTATA (round 02)
   Titolo gigante a tutta larghezza + foto a tutta larghezza.
   Sostituisce per ordine il vecchio impianto a due colonne della sez. 16.
   ========================================================================== */

.about-headline {
    font-family: var(--font-display);
    font-weight: 700;
    color: #FFFFFF;
    white-space: nowrap;
    width: max-content;   /* serve a initFitText per misurare il testo vero */
    line-height: 0.9;
    letter-spacing: -0.035em;
    margin: 0 0 var(--gap-about-media) auto;
    /* Corpo di riserva: se il JS non gira ci va comunque molto vicino.
       Con il JS attivo questo valore viene sostituito da quello esatto. */
    font-size: clamp(2.4rem, 13vw, 11.6rem);
}

/* --- La foto a tutta larghezza --- */
.about-figure {
    position: relative;
    width: 100%;
    aspect-ratio: 16 / 9;
    border-radius: clamp(18px, 2vw, 28px);
    overflow: hidden;
    background-color: #222222;
    margin: 0 0 var(--gap-about-media) 0;
}

/* Lo zoom dell'hover usa `scale`, proprieta' a se stante: si somma al
   translateY del parallax invece di sovrascriverlo, e puo' avere la sua
   transizione mentre il movimento di scroll resta immediato. */
.about-figure img {
    width: 100%;
    object-fit: cover;
    object-position: center;
    transition: scale 0.9s var(--ease-soft);
}

.about-figure:hover img { scale: 1.045; }

@media (max-width: 700px) {
    .about-figure { aspect-ratio: 4 / 3; }
}

/* Sul touch l'hover resterebbe appiccicato dopo il tap */
@media (hover: none) {
    .about-figure:hover img { scale: 1; }
}

@media (prefers-reduced-motion: reduce) {
    .about-figure img { transition: none; }
    .about-figure:hover img { scale: 1; }
}

/* --- Il testo sotto la foto --- */
.about-copy {
    max-width: 62ch;
}

.about-copy p {
    font-size: clamp(1.05rem, 1.4vw, 1.25rem);
    line-height: 1.7;
    color: #A1A1AA;
    margin: 0;
}

.about-copy p + p { margin-top: 1.2em; }

/* ==========================================================================
   23. DIARIO DI VISIONE — stato di caricamento e dati reali
   Le card nascono vuote e pulsano finche' il proxy non risponde: meglio di
   un buco che si riempie di colpo, e meglio di uno spinner che non dice
   nulla. Se il feed non arriva, spariscono del tutto invece di restare
   li' con dei segnaposto che sembrano un errore.
   ========================================================================== */

.lb-link {
    display: block;
    color: inherit;
    text-decoration: none;
}

.lb-grid[hidden],
.lb-card[hidden] { display: none; }

/* --- Scheletro pulsante durante il caricamento --- */
.lb-card.is-loading .lb-poster,
.lb-card.is-loading .lb-title,
.lb-card.is-loading .lb-rating,
.lb-card.is-loading .lb-date {
    background-image: linear-gradient(100deg,
        rgba(255, 255, 255, 0.03) 30%,
        rgba(255, 255, 255, 0.09) 50%,
        rgba(255, 255, 255, 0.03) 70%);
    background-size: 250% 100%;
    animation: lbShimmer 1.6s ease-in-out infinite;
    color: transparent;
}

.lb-card.is-loading .lb-title  { height: 1.15em; border-radius: 5px; }
.lb-card.is-loading .lb-rating { height: 0.85em; width: 62%; border-radius: 5px; }
.lb-card.is-loading .lb-date   { height: 0.75em; width: 45%; border-radius: 5px; }
.lb-card.is-loading .lb-poster-fallback { opacity: 0; }
.lb-card.is-loading { pointer-events: none; }

@keyframes lbShimmer {
    from { background-position: 150% 0; }
    to   { background-position: -50% 0; }
}

@media (prefers-reduced-motion: reduce) {
    .lb-card.is-loading .lb-poster,
    .lb-card.is-loading .lb-title,
    .lb-card.is-loading .lb-rating,
    .lb-card.is-loading .lb-date { animation: none; }
}

/* --- Locandina vera --- */
.lb-poster img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

/* --- Quando il feed non risponde --- */
.lb-fallback {
    color: #71717A;
    font-size: 0.95rem;
}

/* ==========================================================================
   24. CORREZIONI INDEX — round 03
   ========================================================================== */

/* Gap unico per l'Atto 03 su schermi stretti: righe e colonne devono
   respirare uguale, per questo vive in una variabile sola */
:root { --pf-gap-mobile: clamp(56px, 8vh, 90px); }


/* --- FIX 13 — Il titolo hero diventa un paragrafo in basso a sinistra ----
   Il blocco esce dal flusso e si ancora all'angolo: e' l'unico modo per
   avere davvero 50px dal fondo e 50px dal bordo qualunque sia l'altezza
   del testo. Restando in flusso, i 50px sarebbero misurati dal footer,
   non dal bordo della finestra. */
.hero { justify-content: flex-end; }

.hero-content {
    position: absolute;
    left: 100px;
    right: 0;
    bottom: 100px;
    padding-top: 0;
}

/* L'occhiello e' vuoto ma il suo margine spingerebbe comunque il titolo */
.hero-eyebrow:empty { display: none; }

.hero-title {
    font-family: var(--font-display);
    font-weight: 400;          /* Chillax regular */
    text-transform: none;
    font-size: clamp(3.35rem, 2.4vw, 2.3rem);
    line-height: 1.2;
    letter-spacing: -0.01em;
    display: block;
    padding: 0;
    max-width: min(760px, 62vw);
    color: #FFFFFF;
    opacity: 0;
    animation: heroTitleIn 1.1s var(--ease-out) 0.25s forwards;
}

@keyframes heroTitleIn {
    from { opacity: 0; transform: translateY(22px); }
    to   { opacity: 1; transform: translateY(0); }
}

/* Lo "Scroll ↓" si allinea alla base del titolo, sul lato opposto */
.hero-footer {
    justify-content: flex-end;
    padding: 0 5% 50px 5%;
}


/* --- FIX 14 — Meta' dello spazio sopra la Sinossi ------------------------
   RIMOSSO: il valore vive ora in --gap-hdr-01 (sezione 1) ed e' applicato
   direttamente da .about-section nella sezione 8. */


/* --- FIX 15 — Atto 02 su schermi stretti ---------------------------------
   Tre problemi insieme: le parole a 19vw uscivano dallo schermo (in
   maiuscolo "Production" e "Creativity" chiedono circa 6,2 volte il
   corpo, molto piu' della larghezza disponibile), il ritratto sembrava
   appeso perche' le parole gli scorrevano addosso, e la deriva verticale
   pensata per il desktop su 390px porta il blocco fuori campo.
   ------------------------------------------------------------------------ */
@media (max-width: 991px) {

    .skills-layout {
        grid-template-columns: 1fr;
        justify-items: center;
        gap: clamp(22px, 3.5vh, 38px);
        /* spazio per l'act-header, che qui e' in posizione assoluta */
        padding-top: clamp(36px, 6vh, 64px);
    }

    /* (il centraggio e la misura del ritratto stanno ora nella sezione 9) */

    /* La deriva verticale la scrive il JS come stile inline: per fermarla
       da qui serve !important, non c'e' altro modo di scavalcarlo */
    .skill-words {
        transform: none !important;
        align-items: center;
        gap: 0.2em;
        width: 100%;
    }

    /* min(vw, vh): sui telefoni comanda la larghezza, sui tablet
       sdraiati l'altezza, e le quattro parole ci stanno sempre tutte */
    .skill-word {
        font-size: clamp(1.8rem, min(11vw, 9vh), 5.4rem);
        text-align: center;
        transform-origin: center;
        letter-spacing: -0.01em;
    }

    /* Lo scarto laterale della parola accesa, al centro, sembrerebbe
       un errore di allineamento: meglio un ingrandimento appena visibile */
    .skill-word.is-lit { transform: scale(1.04); }
}


/* --- FIX 16 — Atto 03 su mobile: passo regolare tra le foto --------------
   In colonna singola c'erano due distanze diverse che si alternavano: lo
   spazio dentro la coppia (8vh) e quello tra una coppia e l'altra (10vh).
   Da qui in giu' e' una misura sola. */
@media (max-width: 991px) {
    .portfolio-grid { gap: var(--pf-gap-mobile); }
    .pf-row         { gap: var(--pf-gap-mobile); }

    /* Anche il testo entra nel conto: una didascalia di tre righe e una di
       quattro cambierebbero la distanza tra le foto. Riservando lo spazio,
       il passo resta identico per tutte. */
    .pf-row .card-text { min-height: calc(4 * 1.6em); }
}


/* --- Hero su schermi stretti ---------------------------------------------
   A 50px dal bordo il titolo mangerebbe mezzo telefono, e lo "Scroll"
   in colonna finirebbe sotto al testo: qui restano affiancati. */
@media (max-width: 768px) {
    .hero-content {
        left: 24px;
        right: 24px;
        bottom: 84px;
    }

    .hero-title {
        max-width: none;
        font-size: clamp(1.2rem, 5.4vw, 1.75rem);
    }

    .hero-footer {
        flex-direction: row;
        align-items: flex-end;
        justify-content: flex-end;
        padding: 0 24px 30px 24px;
    }
}

@media (prefers-reduced-motion: reduce) {
    .hero-title { opacity: 1; animation: none; }
}

/* ==========================================================================
   25. MODIFICHE BATCH 04
   ========================================================================== */

/* --- (4) Bio About con lo stile della Sinossi ----------------------------
   .manifesto porta gia' font display, corpo fluido e interlinea giusti.
   Qui tolgo solo il limite di larghezza pensato per il testo con le chip
   inline: la bio e' piu' corta e sta bene un filo piu' stretta. */
.manifesto-bio {
    max-width: 60ch;
    color: #EDEDED;
}
.about-copy { max-width: none; }


/* --- (3) HEADER: hamburger su mobile -------------------------------------
   Il bottone non esiste sul desktop: da 861px in su restano i link testuali
   di sempre. Sotto, i link si nascondono e compare l'hamburger a destra.
   Quando l'header diventa compatto (oltre la hero) la capsula si stringe e
   porta logo + hamburger vicini al centro, esattamente come i link prima. */
.nav-toggle {
    display: none; /* acceso solo nel media query mobile */
    position: relative;
    width: 44px;
    height: 44px;
    padding: 0;
    border: none;
    background: transparent;
    cursor: pointer;
    z-index: 101;
    flex: 0 0 auto;
}

.nav-toggle-bar {
    position: absolute;
    left: 50%;
    width: 24px;
    height: 2px;
    background-color: #FFFFFF;
    border-radius: 2px;
    transform: translateX(-50%);
    transition: transform 0.35s var(--ease-out), opacity 0.25s ease, background-color 0.35s ease;
}

.nav-toggle-bar:nth-child(1) { top: 17px; }
.nav-toggle-bar:nth-child(2) { top: 25px; }

/* Aperto: le due barre diventano una X */
.nav-toggle[aria-expanded="true"] .nav-toggle-bar:nth-child(1) {
    top: 21px;
    transform: translateX(-50%) rotate(45deg);
}
.nav-toggle[aria-expanded="true"] .nav-toggle-bar:nth-child(2) {
    top: 21px;
    transform: translateX(-50%) rotate(-45deg);
}

/* Sul foglio chiaro (prima che l'header sia compatto) le barre si scuriscono */
body.on-light:not(.header-compact) .nav-toggle-bar { background-color: var(--ink); }

@media (max-width: 860px) {
    /* Header sopra la hero: logo a sinistra, hamburger a destra */
    .main-header { padding: 16px 5%; }

    .nav-toggle { display: block; }

    /* I link escono dal flusso e diventano un pannello a tendina, chiuso di
       default. Niente piu' fila di testo sull'header. */
    .nav-links {
        position: fixed;
        top: 0;
        right: 0;
        width: min(320px, 82vw);
        height: 100vh;
        height: 100dvh;
        flex-direction: column;
        justify-content: center;
        align-items: flex-start;
        gap: 28px;
        padding: 0 40px;
        background-color: rgba(20, 20, 20, 0.97);
        -webkit-backdrop-filter: blur(20px);
        backdrop-filter: blur(20px);
        transform: translateX(100%);
        transition: transform 0.45s var(--ease-out);
        z-index: 100;
    }

    body.nav-open .nav-links { transform: translateX(0); }

    .nav-link { font-size: 1.4rem; color: #FFFFFF; }
    .nav-btn { padding: 12px 26px; font-size: 1.1rem; }

    /* Nel pannello aperto i link sono sempre su fondo scuro: l'inversione
       del foglio chiaro non deve intromettersi */
    body.on-light .nav-links .nav-link { color: #FFFFFF; }
    body.on-light .nav-links .nav-btn { background-color: #FFFFFF; color: var(--dark); }

    /* Header compatto oltre la hero: la capsula si stringe e porta logo e
       hamburger insieme verso il centro, come faceva con i link. */
    body.header-compact .main-header {
        width: min(340px, 90%);
        justify-content: center;
        gap: 28px;
        padding: 8px 20px;
    }
    body.header-compact .logo { order: 1; }
    body.header-compact .nav-toggle { order: 2; }

    /* Il velo scuro dietro il pannello */
    .nav-scrim {
        position: fixed;
        inset: 0;
        background: rgba(0, 0, 0, 0.5);
        opacity: 0;
        visibility: hidden;
        transition: opacity 0.4s ease, visibility 0.4s ease;
        z-index: 99;
    }
    body.nav-open .nav-scrim { opacity: 1; visibility: visible; }

    /* Con il pannello aperto la pagina sotto non scorre */
    body.nav-open { overflow: hidden; }
}

@media (prefers-reduced-motion: reduce) {
    .nav-links, .nav-toggle-bar, .nav-scrim { transition: none; }
}


/* --- (5) PAGINA PORTFOLIO su mobile: passo uniforme tra le foto ----------
   In colonna singola convivevano due distanze: il gap DENTRO la coppia
   (.project-grid-2, 32px) e il margine TRA le righe (.project-*, fino a
   90px). Da qui in giu' e' un valore solo, come nella home. */
@media (max-width: 768px) {
    .project-hero,
    .project-wide,
    .project-grid-2,
    .project-brief,
    .project-intro,
    .project-nav {
        margin-bottom: clamp(28px, 4.5vh, 40px);
    }

    .project-grid-2 { gap: clamp(28px, 4.5vh, 40px); }
}

/* ==========================================================================
   26. FIX MENU MOBILE — pannello ancorato al viewport
   Il pannello .nav-links viene spostato dal JS fuori da .main-header, come
   figlio diretto del <body> (classe .nav-detached). Da fuori dall'header
   non subisce piu' il containing block creato dal backdrop-filter compact,
   quindi position:fixed torna relativo al viewport e translateX(100%) lo
   nasconde davvero. Queste regole valgono a QUALSIASI larghezza per il
   pannello staccato; l'hamburger resta gestito dalla sezione 25.
   ========================================================================== */

/* Il pannello staccato: nascosto di default, ovunque */
body .nav-links.nav-detached {
    position: fixed;
    top: 0;
    right: 0;
    left: auto;
    width: min(320px, 82vw);
    height: 100vh;
    height: 100dvh;
    flex-direction: column;
    justify-content: center;
    align-items: flex-start;
    gap: 28px;
    padding: 0 40px;
    margin: 0;
    background-color: rgba(20, 20, 20, 0.97);
    -webkit-backdrop-filter: blur(20px);
    backdrop-filter: blur(20px);
    transform: translateX(101%); /* 101%: un filo oltre, mai una fessura */
    transition: transform 0.45s var(--ease-out);
    z-index: 200;              /* sopra l'header (100) e sopra il velo */
    display: flex;
}

body.nav-open .nav-links.nav-detached { transform: translateX(0); }

/* Le voci nel pannello staccato, a ogni larghezza */
.nav-links.nav-detached .nav-link {
    color: #FFFFFF;
    font-size: 1.4rem;
    opacity: 1;
}
.nav-links.nav-detached .nav-btn {
    background-color: #FFFFFF;
    color: var(--dark);
    padding: 12px 26px;
    font-size: 1.1rem;
}

/* Il velo, anch'esso spostato nel body */
.nav-scrim {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.5);
    opacity: 0;
    visibility: hidden;
    transition: opacity 0.4s ease, visibility 0.4s ease;
    z-index: 150;              /* tra header e pannello */
}
body.nav-open .nav-scrim { opacity: 1; visibility: visible; }
body.nav-open { overflow: hidden; }

/* Da 861px in su il menu mobile non esiste: pannello e velo spariti,
   l'hamburger e' gia' display:none dalla sezione 25, e i link tornano
   la fila orizzontale di sempre DENTRO l'header. Ma il pannello ora e'
   staccato nel body: se non lo rimettessimo in riga, i link sparirebbero
   dal desktop. Quindi sopra 861px lo "riattacco" visivamente. */
@media (min-width: 861px) {
    body .nav-links.nav-detached {
        position: static;
        width: auto;
        height: auto;
        flex-direction: row;
        align-items: center;
        justify-content: flex-end;
        gap: 32px;
        padding: 0;
        background: transparent;
        -webkit-backdrop-filter: none;
        backdrop-filter: none;
        transform: none;
        z-index: auto;
    }
    .nav-links.nav-detached .nav-link { font-size: 0.9rem; }
    .nav-links.nav-detached .nav-btn {
        padding: 10px 20px;
        font-size: inherit;
    }
    .nav-scrim { display: none; }
}


/* ==========================================================================
   26. BIO ABOUT — un capoverso alla volta, parola per parola
   La bio non e' una colonna che si riempie scorrendo: e' una track alta con
   dentro uno stage sticky. I capoversi stanno tutti nella stessa cella di
   griglia, sovrapposti, e se ne vede uno per volta. Stesso impianto di
   .skills-track / .skills-stage (sezione 9).

   Lo stato "invisibile" e' legato a .is-split e .is-stage, classi che mette
   il JS: senza JS la bio resta una normale colonna di testo leggibile.
   ========================================================================== */

/* --- Ripiego senza JS: colonna centrata, tutto visibile ------------------ */
.about-copy.bio-reveal {
    max-width: 60ch;
    margin-inline: auto;
    text-align: center;
}

/* Corpo del testo: +20% rispetto a clamp(1.05rem, 1.4vw, 1.25rem) della
   sezione 22. Il selettore ha due classi, quindi vince su .about-copy p, e
   valendo anche in discendenza copre i capoversi dentro lo stage. */
.about-copy.bio-reveal p {
    font-size: clamp(1.575rem, 2.1vw, 1.875rem);
    text-wrap: balance; /* righe di lunghezza simile: centrato rende meglio */
}

.about-copy.bio-reveal p + p {
    margin-top: 1.9em;
}

/* --- Con JS: la track ---------------------------------------------------
   L'altezza decide il ritmo. --bio-passi (capoversi + anticipo) e
   --bio-passo (quanto scroll ciascuno) arrivano dal JS: piu' alto
   --bio-passo, piu' lenta la sequenza. */
.about-copy.is-stage {
    position: relative;
    max-width: none;
    margin-inline: 0;
    height: calc(var(--bio-passi, 5) * var(--bio-passo, 110vh));
}

.bio-stage {
    position: sticky;
    top: 0;
    height: 100vh;
    height: 100svh;
    display: grid;
    place-items: center;
}

/* Tutti i capoversi nella stessa cella: si sovrappongono invece di
   incolonnarsi, cosi' il cambio avviene nello stesso punto dello schermo. */
.about-copy.is-stage .bio-stage p {
    grid-area: 1 / 1;
    margin: 0;
    width: 100%;
    max-width: 60ch;
}

/* --- Le parole ----------------------------------------------------------
   inline-block serve a far funzionare translateY su un elemento di testo.
   Gli spazi fra una parola e l'altra restano nodi di testo veri, quindi
   a capo, selezione e copia-incolla si comportano come sempre.

   Entrata e uscita non sono simmetriche, ed e' voluto: si entra a onda,
   parola per parola (il ritardo --d lo calcola il JS), si esce tutti
   insieme e in fretta, per lasciare il campo libero al capoverso dopo. */
.about-copy.is-split .w {
    display: inline-block;
    opacity: 0;
    transform: translateY(0.28em);
    transition:
        opacity 0.34s var(--ease-out),
        transform 0.34s var(--ease-out);
    transition-delay: 0ms;
}

.about-copy.is-split p.is-visible .w {
    opacity: 1;
    transform: translateY(0);
    transition-duration: 0.85s;
    transition-delay: var(--d, 0ms);
}

/* --- Ritmo verticale della pagina ---------------------------------------
   I margini vivono ora alle loro regole d'origine (sezioni 16 e 22), scritti
   con i token della sezione 1: qui restano solo le cose che non hanno una
   sede naturale altrove. Tutto sotto .about-page, perche' .project-main e
   .marquee li condividono anche le pagine progetto. */
.about-page .project-main {
    padding-top: var(--gap-page-top);
}

.about-page .marquee {
    margin: var(--gap-about-blocks) 0;
}

/* --- Corpo della bio ----------------------------------------------------
   Era clamp(1.575rem, 2.1vw, 1.875rem): il tetto di 30px veniva raggiunto
   gia' a 1430px, quindi da li' in su il testo NON cresceva piu' — su un 27"
   restava identico a un portatile, ed e' questo che lo faceva sembrare
   piccolo. Il termine in vh e' la briglia: la bio vive dentro uno stage
   sticky alto 100vh, e su un monitor largo ma basso il solo vw porterebbe
   il capoverso piu' lungo a non entrarci. */
.about-copy.bio-reveal p {
    font-size: clamp(1.6rem, min(2.4vw, 4.4vh), 3.4rem);
}

/* --- SCHERMI GRANDI (27" e oltre) ---------------------------------------
   Stesso ragionamento dell'Atto 02: sopra i 1800px il tappo di 1280px del
   .container non e' leggibilita', e' una gabbia. Il titolo "About Letizia"
   e' dimensionato dal JS sulla larghezza del contenitore, quindi si
   ingrandisce da solo appena il contenitore respira. */
@media (min-width: 1800px) {
    .about-page .container { max-width: var(--wide-container); }
}

/* Su reduced-motion il JS non costruisce ne' track ne' stage: la bio resta
   una colonna di testo ferma. Questa e' solo una rete di sicurezza se la
   preferenza cambia a pagina gia' aperta. */
@media (prefers-reduced-motion: reduce) {
    .about-copy.is-split .w {
        opacity: 1;
        transform: none;
        transition: none;
    }
}


/* ==========================================================================
   27. MARQUEE — loop senza salto e colori alternati
   Ritocca la sezione 7 senza modificarla. Tutto e' sotto .is-seamless,
   classe che mette initMarqueeLoop (main.js §13): senza JS il ticker resta
   quello di prima.

   a) LO SPAZIO STA SULLE PAROLE, NON FRA LE PAROLE
      Con N span e un gap, gli spazi sono N-1: meta' larghezza non coincide
      mai con una copia intera, e a ogni giro il track scatta indietro di
      mezzo gap. Con margin-right gli spazi sono N e i conti tornano:

          larghezza = S(2 cicli) + 2C x 56px
          -50%      = S(1 ciclo) + C  x 56px   <- una copia esatta

      Ne segue anche che la distanza fra l'ultima parola e la prima e'
      identica a tutte le altre.

   b) LE DUE COPIE E I COLORI LI FA IL JS
      Nell'HTML basta l'elenco delle parole, senza classi e senza
      duplicati: ci pensa initMarqueeLoop. Il colore segue .alt, che il JS
      mette alle posizioni pari.
   ========================================================================== */

.about-page .marquee-track.is-seamless {
    gap: 0;
}

.about-page .marquee-track.is-seamless span {
    margin-right: 56px;
}

.about-page .marquee-track.is-seamless .alt {
    color: #d85633;
    -webkit-text-stroke: 0;
}

/* ==========================================================================
   28. ATTO 02 — ritratto piu' grande
   RIMOSSO: i valori (clamp 200-500px desktop, min(48vw,24vh) sotto i 992px)
   sono stati portati alla fonte, nella sezione 9. Nessun cambio visivo.
   ========================================================================== */

/* ==========================================================================
   29. TITOLI DI CODA — FOOTER A SIPARIO
   Il footer non scorre con la pagina: sta fermo, incollato al fondo del
   viewport, e il <main> gli passa sopra come un sipario che si alza.
   Tre pezzi indipendenti: (a) l'impianto a sipario, (b) il monogramma con
   il gradiente animato, (c) la comparsa dei contenuti guidata dallo scroll.
   ========================================================================== */

/* --- (a) L'IMPIANTO A SIPARIO --------------------------------------------
   Meccanica: il footer e' l'ULTIMO elemento del <body>, fuori dal <main>.
   Con bottom:0 resta incollato al fondo del viewport fin dall'inizio, ma il
   <main> ha uno sfondo pieno e z-index piu' alto, quindi lo nasconde. Negli
   ultimi pixel di scroll il bordo inferiore del <main> risale e scopre il
   footer dall'alto verso il basso, mentre il footer non si muove di un
   pixel. La rivelazione dura esattamente quanto l'altezza del footer.

   Il footer NON deve mai essere piu' alto del viewport: con bottom:0 la
   parte eccedente finirebbe sopra il bordo superiore e resterebbe tagliata.
   Da qui il tetto a 100svh (svh, non vh: su mobile tiene conto della barra
   del browser) e il ritorno a flusso normale sugli schermi bassi. */
main {
    position: relative;
    z-index: 2;
    background-color: var(--dark);
}

.site-footer {
    position: relative;
    z-index: 1;
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    gap: clamp(32px, 6vh, 72px);
    /* Non 100svh: con solo monogramma e riga di chiusura, un footer alto
       quanto lo schermo lascia mezzo viewport di vuoto sopra il testo e
       sembra un errore invece che respiro. Questa altezza e' anche la
       durata della rivelazione: il sipario dura esattamente questi pixel. */
    min-height: min(72svh, 640px);
    padding: clamp(60px, 10vh, 120px) clamp(20px, 4vw, 64px) clamp(28px, 4vh, 48px);
    overflow: hidden;
}

/* Il sipario si attiva solo dove c'e' spazio per reggerlo. Sotto questa
   soglia il footer torna un blocco normale in coda alla pagina: nessuna
   sovrapposizione, nessun contenuto tagliato. */
@media (min-width: 700px) and (min-height: 560px) {
    .site-footer {
        position: sticky;
        bottom: 0;
    }
}

.footer-inner {
    width: 100%;
    display: flex;
    flex-direction: column;
    gap: clamp(32px, 6vh, 72px);
}

/* --- (b) IL MONOGRAMMA: GRADIENTE A MAGLIA ANIMATO -----------------------
   Il testo fa da maschera: background-clip:text ritaglia il gradiente sulla
   forma delle lettere e color:transparent toglie il riempimento.

   Il gradiente non e' uno solo. Quattro radiali sfalsati creano le "pozze"
   di colore (la maglia) e una lineare sotto fa da legante: e' questo che
   da' l'effetto liquido invece della solita sciarpa arcobaleno diagonale.
   background-size al 300% da' all'animazione il margine per spostarsi;
   sotto il 200% il movimento si vede come uno scatto invece che come uno
   scorrimento.

   La lima del sito entra nella palette di proposito: senza, il footer
   sembrerebbe incollato da un altro progetto. */
.footer-mark {
    font-family: var(--font-mark, var(--font-display));
    font-weight: 700;
    text-transform: lowercase;
    letter-spacing: -0.033em;
    line-height: 0.85;
    /* --- Spazio per le lettere che escono dalla riga --------------------
       Con background-clip:text il gradiente viene dipinto solo dentro il
       PADDING BOX, poi ritagliato sulla forma delle lettere. Un glifo che
       sporge da quel riquadro non ha sfondo su cui disegnarsi e appare
       mozzato: non e' overflow, e' che li' non c'e' niente da ritagliare.
       Misurato su questo testo: l'inchiostro sborda di 0,134em sopra
       (le aste di l, t, i) e 0,063em sotto (le discendenti di g e z), e
       Anaktoria, da serif storico, scende ancora piu' giu'.

       Il padding qui e' in em di proposito: cresce col corpo, e il corpo
       lo decide initFitText a seconda dello schermo. In px si romperebbe
       a ogni cambio di larghezza.

       I margini negativi riprendono quasi tutto lo spazio aggiunto: il
       riquadro dipinto diventa piu' alto senza che la composizione si
       allarghi. */
    /* Lo 0.05em ai lati non e' un margine estetico, e' l'ultima
       lettera che rientra nel riquadro dipinto. letter-spacing e'
       negativo e viene applicato ANCHE dopo l'ultimo carattere:
       la scatola di testo finisce cosi' 0,035em prima di dove
       finisce la "o", e con background-clip:text quel pezzo di
       glifo resta senza sfondo su cui disegnarsi.
       0,05em > 0,035em, quindi nessuna lettera puo' cadere fuori
       qualunque font si usi. Il testo rientra di una decina di
       pixel su laptop e di tre su mobile: si perde questo, invece
       di una fetta di lettera. */
    padding: 0.24em 0.05em 0.22em;
    margin: -0.18em 0 -0.16em;
    white-space: nowrap;
    /* width:max-content lo rende largo quanto il testo, quindi da
       solo si appoggia a sinistra: align-self lo centra nella
       colonna, text-align vale se un giorno il testo non riempie. */
    align-self: center;
    text-align: center;
    width: max-content;
    /* niente max-width qui: bloccherebbe offsetWidth al valore del
       contenitore e initFitText misurerebbe sempre "gia' giusto",
       lasciando il testo a sbordare sotto il ritaglio */

    /* Corpo di ripiego: il valore vero lo calcola initFitText misurando il
       testo, cosi' il monogramma tocca i bordi su qualunque schermo. */
    font-size: clamp(2.4rem, 11vw, 16rem);

    /* Ogni var() ha il suo colore di scorta dopo la virgola. Non e'
       pignoleria: in CSS basta UNA variabile non definita perche' l'intera
       dichiarazione background-image diventi invalida e il testo resti
       trasparente sul nulla. Con la scorta, al massimo sbaglia un colore. */
    background-image:
        radial-gradient(58% 120% at 10% 25%, var(--mesh-1, #a88fbb) 0%, transparent 62%),
        radial-gradient(52% 115% at 38% 88%, var(--mesh-2, #CDE8FF) 0%, transparent 64%),
        radial-gradient(55% 120% at 68% 12%, var(--mesh-3, #FFD6EE) 0%, transparent 62%),
        radial-gradient(62% 130% at 92% 78%, var(--mesh-4, #d85633) 0%, transparent 58%),
        linear-gradient(100deg,
            var(--mesh-1, #a88fbb)  0%,
            var(--mesh-2, #CDE8FF) 26%,
            var(--mesh-5, #C9F0E4) 48%,
            var(--mesh-3, #FFD6EE) 72%,
            var(--mesh-4, #d85633) 100%);
    background-size: 300% 300%;
    background-position: 0% 50%;
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
    animation: meshDrift 5.6s ease-in-out infinite alternate;
    will-change: background-position;
}

@keyframes meshDrift {
    from { background-position: 0% 50%; }
    to   { background-position: 100% 50%; }
}

/* --- La riga in fondo: legale a sinistra, crediti al centro, social a destra
   1fr auto 1fr e' l'unico modo perche' il blocco centrale sia centrato
   rispetto alla PAGINA e non rispetto allo spazio che avanza fra i due
   laterali, che hanno larghezze diverse. */
.footer-bar {
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    align-items: center;
    gap: clamp(16px, 3vw, 48px);
    padding-top: clamp(20px, 3vh, 36px);
    border-top: 1px solid rgba(255, 255, 255, 0.12);
    font-size: clamp(0.78rem, 0.95vw, 0.95rem);
    letter-spacing: 0.02em;
}

.footer-legal  { justify-self: start; }
.footer-social { justify-self: end; }

.footer-legal,
.footer-social {
    display: flex;
    gap: clamp(14px, 2vw, 32px);
}

.footer-credits {
    justify-self: center;
    text-align: center;
    margin: 0;
    display: flex;
    gap: 0.6em;
    color: #A1A1AA;
    white-space: nowrap;
}

.footer-link {
    color: #A1A1AA;
    text-decoration: none;
    white-space: nowrap;
    /* translate resta libero per l'effetto magnetico del JS: qui si usa
       solo scale, che e' una proprieta' a se' e non lo sovrascrive. */
    transition: color 0.3s var(--ease-soft), scale 0.3s var(--ease-soft);
}

.footer-link:hover {
    color: var(--accent);
    scale: 1.06;
}

/* --- (c) COMPARSA GUIDATA DALLO SCROLL -----------------------------------
   Il JS scrive un solo numero, --rivela, da 0 (footer ancora coperto) a 1
   (footer scoperto del tutto). Tutto il resto e' calcolato qui: ogni
   elemento legge lo stesso numero ma con partenza e velocita' diverse, ed
   e' proprio lo sfasamento a produrre la parallasse.

   Le regole valgono solo con .js-rivela, che il JS aggiunge da se': senza
   JS il footer resta semplicemente visibile invece di sparire. */
.js-rivela .footer-mark,
.js-rivela .footer-bar > * {
    will-change: opacity, transform;
}

.js-rivela .footer-mark {
    opacity: clamp(0, calc((var(--rivela, 1) - 0.04) * 2.4), 1);
    transform:
        translateY(calc((1 - var(--rivela, 1)) * 56px))
        scale(calc(0.94 + var(--rivela, 1) * 0.06));
}

/* Le tre colonne entrano piu' tardi del monogramma e a velocita' diverse */
.js-rivela .footer-legal {
    opacity: clamp(0, calc((var(--rivela, 1) - 0.42) * 2.6), 1);
    transform: translateY(calc((1 - var(--rivela, 1)) * 34px));
}

.js-rivela .footer-credits {
    opacity: clamp(0, calc((var(--rivela, 1) - 0.50) * 2.6), 1);
    transform: translateY(calc((1 - var(--rivela, 1)) * 26px));
}

.js-rivela .footer-social {
    opacity: clamp(0, calc((var(--rivela, 1) - 0.58) * 2.6), 1);
    transform: translateY(calc((1 - var(--rivela, 1)) * 42px));
}

/* --- Schermi stretti: una colonna, niente sipario ------------------------ */
@media (max-width: 699px) {
    .footer-bar {
        grid-template-columns: 1fr;
        justify-items: center;
        gap: 18px;
        text-align: center;
    }
    .footer-legal,
    .footer-social,
    .footer-credits { justify-self: center; }
    .footer-credits { flex-wrap: wrap; justify-content: center; }
}

@media (prefers-reduced-motion: reduce) {
    .footer-mark {
        animation: none;
        background-position: 50% 50%;
    }
    .js-rivela .footer-mark,
    .js-rivela .footer-legal,
    .js-rivela .footer-credits,
    .js-rivela .footer-social {
        opacity: 1;
        transform: none;
    }
    .footer-link:hover { scale: 1; }
}


/* ==========================================================================
   30. SOCIAL NEL MENU MOBILE
   Due voci in fondo al pannello a tendina, sotto i tre link di pagina.
   Icone in SVG scritte nel markup: niente file da caricare, niente libreria
   di icone, e `stroke: currentColor` le fa seguire il colore del testo.
   ========================================================================== */

/* Di base non esistono: sull'header desktop i link sono una riga sola e
   due voci con icona non c'entrano niente. Compaiono solo sotto gli 860px,
   cioe' esattamente dove .nav-links diventa il pannello a tendina. */
.nav-social { display: none; }

@media (max-width: 860px) {
    .nav-social {
        display: flex;
        flex-direction: column;
        align-items: flex-start;
        gap: 18px;
        width: 100%;
        margin-top: 10px;
        padding-top: 26px;
        border-top: 1px solid rgba(255, 255, 255, 0.14);
    }

    .nav-social-link {
        display: flex;
        align-items: center;
        gap: 12px;
        color: #FFFFFF;
        text-decoration: none;
        font-size: 1rem;
        letter-spacing: 0.01em;
        opacity: 0.72;
        /* translate e non transform: resta libero se un domani serve altro */
        transition: opacity 0.3s var(--ease-soft), translate 0.3s var(--ease-soft);
    }

    .nav-social-link:hover,
    .nav-social-link:focus-visible {
        opacity: 1;
        translate: 3px 0;
    }

    .nav-social-link svg {
        width: 22px;
        height: 22px;
        flex: 0 0 auto;
    }

    /* Nel pannello il fondo e' sempre scuro: l'inversione del foglio chiaro
       non deve intromettersi, come gia' fanno .nav-link e .nav-btn */
    body.on-light .nav-links .nav-social-link { color: #FFFFFF; }
}

@media (prefers-reduced-motion: reduce) {
    .nav-social-link { transition: none; }
    .nav-social-link:hover { translate: 0 0; }
}
