/* =============================================================================
   Modulo: carosello dei case study.

   Stessa struttura a due layout degli altri moduli-scena: il default è statico —
   le card una sotto l'altra, leggibili e cliccabili — e il layout animato sta
   dentro `@media (scripting: enabled) and (prefers-reduced-motion: no-preference)`.

   Il JavaScript scrive **due numeri**: `--cards-x`, di quanto è scorsa la fila,
   e `--cta-o`, quanto è comparso il pulsante. Nient'altro. La corsa totale la
   misura dal DOM, perché dipende da quante card ci sono e da quanto sono larghe:
   è l'unica cosa che il CSS non può sapere da solo.
   ========================================================================== */

.case-carousel {
    /* --- Valori guidati dal JS ----------------------------------------------
       I default sono il fotogramma zero: fila ferma all'inizio, pulsante non
       ancora comparso. */
    --cards-x: 0px;
    --cta-o: 0;

    /* Quanto scroll vale un passo di scena. Mezza schermata e non una intera
       perché i passi qui sono tanti: uno per card più due per il pulsante. Nel
       Make lo scorrimento orizzontale è circa il doppio più veloce di così —
       1464px di corsa in 119vh — ma su un movimento scrubbato quel ritmo è
       nervoso. Questo è il valore da toccare se la corsa sembra lenta. */
    --step-length: 50vh;

    /* --- Geometrie ----------------------------------------------------------
       Contenitore 1448 su un frame 1512, card 838 e 594, distanziatore 16.
       838 + 16 + 594 fa esattamente 1448: **una coppia larga+stretta riempie il
       contenitore**, ed è quello che dà il ritmo alla fila. Le due frazioni sotto
       sono 838 e 594 su 1432, cioè sulla larghezza al netto del distanziatore.

       ⚠ Nel file di design le card sono invece **tutte larghe 838** (nodo 649:2392,
       a x=32, 886, 1740, 2594), e la seconda risulta tagliata dal bordo destro
       dello schermo. L'alternanza qui è una scelta esplicita del 26 agosto, che si
       discosta dal design e torna al ritmo del Make. Se un domani si torna
       all'uniforme, cambiano insieme: queste due frazioni, la larghezza della
       pista qui sotto, `$travel_steps` nel PHP e `travelSteps` nel JS — perché
       senza la coppia che riempie il contenitore la corsa comincia una card prima. */
    --track-width: 95.77%;
    --card-gap: 1rem;
    --card-wide: 0.5852;
    --card-narrow: 0.4148;

    /* 520 su un frame alto 982. Le due card hanno proporzioni diverse — 1,61 e
       1,14 — quindi è l'altezza a essere comune, non l'aspect-ratio. */
    --card-height: clamp(20rem, 52.95vh, 34rem);

    position: relative;
    color: var(--color-scene-text);
}

/* -----------------------------------------------------------------------------
   Layout statico: nessun JavaScript, movimento ridotto, o viewport stretto.
   -------------------------------------------------------------------------- */

.case-carousel__viewport {
    padding-block: var(--space-section);
}

.case-carousel__scene {
    position: relative;
    display: grid;
    gap: var(--space-2xl);
    justify-items: center;
    width: 100%;
    max-width: var(--container-max);
    margin-inline: auto;
    padding-inline: var(--gutter);
}

/* Nel design è un **titolo di sezione in display**: 72px su 64 di interlinea,
   peso 900, maiuscolo, centrato, col riempimento sfumato (nodo 649:2391). Nel
   Make era un paragrafo a 40px in tondo. La classe `.display-gradient` la mette
   il PHP. */
.case-carousel__intro {
    /* Niente `margin` qui: lo possiede `.display-gradient` (base.css), che ci mette
       un negativo per compensare il proprio padding. Un `margin: 0` in questa regola
       lo azzererebbe — stessa specificita', ma il CSS del modulo carica dopo — e
       l'accento delle maiuscole tornerebbe tagliato. Il reset di base.css lo azzera
       gia' per tutti. */
    font-size: var(--text-display);
    line-height: var(--leading-display);
    font-weight: var(--weight-black);
    text-transform: uppercase;
    text-align: center;
    font-feature-settings: "lnum", "pnum";
}

.case-carousel__track {
    width: 100%;
}

.case-carousel__row {
    display: grid;
    gap: var(--card-gap);
    list-style: none;
    margin: 0;
    padding: 0;
}

/* La card è tutta un link. `display: grid` con la riga centrale che si allarga
   tiene i tag in alto e il blocco di testo in basso, senza posizionamenti. */
.case-carousel__card {
    display: grid;
    position: relative;
    grid-template-rows: auto 1fr auto;
    height: var(--card-height);
    overflow: hidden;
    border-radius: var(--radius-l);
    color: inherit;
    text-decoration: none;
    isolation: isolate;
}

.case-carousel__media {
    position: absolute;
    inset: 0;
    z-index: -1;
    background-color: #000;
}

.case-carousel__poster,
.case-carousel__video {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: center;
}

/* Il filmato sta sopra il poster e resta trasparente finché non parte: così il
   passaggio è una dissolvenza e non uno sfarfallio, e senza JavaScript resta
   semplicemente il poster. */
.case-carousel__video {
    opacity: 0;
    transition: opacity var(--duration-base) var(--ease-out);
}

/* Senza immagine di poster il filmato **è** il poster: resta visibile invece di
   aspettare `is-playing`, e quel che si vede fermo è il primo fotogramma, che il
   markup chiede col frammento `#t=0.1`.

   Sta qui sotto e non sopra apposta: stessa specificità di `.case-carousel__video`,
   quindi vince per ordine di sorgente. Spostandola più in alto smetterebbe di
   funzionare senza un errore. */
.case-carousel__video--poster {
    opacity: 1;
}

.case-carousel__card.is-playing .case-carousel__video {
    opacity: 1;
}

/* La sfumatura del Make: nera al 60% in basso, trasparente a metà card. Serve a
   tenere leggibili titolo e dati sopra qualunque immagine. */
.case-carousel__veil {
    position: absolute;
    inset: 0;
    background-image: linear-gradient(
        to top,
        rgb(0 0 0 / 0.6) 11.25%,
        rgb(0 0 0 / 0) 50%
    );
}

.case-carousel__tags {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3xs);
    padding: var(--space-2xs);
}

/* label-sm a 10px del design: 10 su 16, peso 600, tracking 8%, maiuscolo, su una
   pastiglia nera al 32% con angoli a 16px. L'80% di opacità è quello del design:
   sul tag, non sul suo fondo. */
.case-carousel__tag {
    padding: var(--space-2xs) var(--space-xs);
    border-radius: var(--radius-m);
    background-color: rgb(0 0 0 / 0.32);
    font-size: var(--text-label-s);
    line-height: var(--leading-label-s);
    font-weight: var(--weight-semibold);
    letter-spacing: var(--tracking-label-s);
    text-transform: uppercase;
    opacity: 0.8;
}

.case-carousel__body {
    display: grid;
    grid-row: 3;
    gap: var(--space-2xs);
    padding: var(--space-m);
}

/* title-upper-md: 40 su 40, peso 900, maiuscolo, nessun tracking. Nel Make era
   48px con tracking negativo.

   Il filetto sotto è l'unico bordo del design: rgba(255,255,255,.2), con 4px di
   respiro sopra e sotto. */
.case-carousel__title {
    padding-block: var(--space-3xs);
    border-block-end: 1px solid var(--color-border);
    font-size: var(--text-title);
    line-height: var(--leading-solid);
    font-weight: var(--weight-black);
    text-transform: uppercase;
    font-feature-settings: "lnum", "pnum";
}

/* Nel design i primi due campi stanno vicini a 32px e la data è spinta al bordo
   opposto. Con l'ultimo campo a `margin-inline-start: auto` viene esattamente
   così, senza un contenitore in più nel markup.

   `:not(:first-child)` serve al caso di un campo solo: senza, quell'unico campo
   verrebbe spinto a destra invece di restare a sinistra col titolo. */
.case-carousel__meta {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-s) var(--space-l);
}

.case-carousel__field {
    display: grid;

    &:last-child:not(:first-child) {
        margin-inline-start: auto;
        text-align: end;
    }
}

.case-carousel__label {
    font-size: var(--text-label-s);
    line-height: var(--leading-label-s);
    font-weight: var(--weight-semibold);
    letter-spacing: var(--tracking-label-s);
    text-transform: uppercase;
    opacity: 0.8;
}

/* body-xs: 16 su 24, peso 500, tracking 1%. Nel Make era 24px al peso 600. */
.case-carousel__value {
    font-size: var(--text-body-s);
    line-height: var(--leading-body-s);
    font-weight: var(--weight-medium);
    letter-spacing: var(--tracking-body-s);
    font-feature-settings: "lnum", "pnum";
}

/* Il pulsante è `.button--outline` di base.css — il `cta-l-white` del design, con
   il riempimento bianco che cresce dal basso all'hover. Stava qui, perché questo
   era l'unico modulo ad averlo; è salito in base.css quando è diventato chiaro
   che nel file di design **di pulsanti ce n'è uno solo**, e quindi non è un caso
   particolare del carosello. Con lui sono salite la curva e la durata, e se n'è
   andato lo `<span>` dell'etichetta: là il riempimento sta a `z-index: -1` dentro
   un contesto isolato, quindi passa dietro al testo senza che il testo debba
   essere avvolto in qualcosa.

   Qui resta soltanto **dove sta e come compare**. */

/* -----------------------------------------------------------------------------
   Layout animato.
   -------------------------------------------------------------------------- */

/* soglia scene: 901px — vedi base.css → "Passaggio fra scene" */
@media (scripting: enabled) and (prefers-reduced-motion: no-preference) and (min-width: 901px) {

    /* La schermata in pin, un passo per card da far scorrere, due per il
       pulsante, più i due tratti del passaggio fra scene. Il conto dei passi è
       lo stesso che fa il JS, ed è l'unica cosa che i due file sanno entrambi.
       `--travel-steps` arriva dal PHP: è `card - 2`, perché una coppia
       larga+stretta riempie già il contenitore e non ha niente da scorrere. */
    .case-carousel {
        height: calc(
            100vh
            + var(--scene-enter, 0px)
            + (var(--travel-steps, 0) + 2) * var(--step-length)
            + var(--scene-hold, 0px)
        );
    }

    .case-carousel__viewport {
        position: sticky;
        inset-block-start: 0;
        height: 100vh;
        padding-block: 0;
        overflow: hidden;
    }

    /* La scena riempie lo schermo e centra il proprio contenuto: titolo, pista e
       pulsante impilati.

       Una colonna sola, larga quanto la pista, e non tre elementi larghi quanto
       la scena: è quello che allinea il pulsante al bordo **destro della pista**
       invece che a quello dello schermo. Nel Make sono lo stesso bordo perché il
       pulsante sta nella stessa colonna delle card; separarli si vedrebbe.

       La colonna al 95,77% lascia 32px per lato su un frame da 1512, che sono
       esattamente i 32px di margine del design: il margine non va aggiunto, c'è
       già. Regge perché una coppia larga+stretta riempie la colonna esatta e la
       fila non sporge — con le card tutte uguali non sarebbe così, e la pista
       dovrebbe arrivare al bordo dello schermo.

       Il padding in alto senza quello in basso serve ai 28px di scarto del Make,
       che ha 160px sopra e 104px sotto attorno a un blocco centrato: con
       `align-content: center` un padding solo in testa sposta il contenuto della
       propria metà. Col `row-gap` del design il conto torna da sé: titolo 128,
       gap 64, pista 520 fanno 712 — l'altezza esatta del frame 649:2390 — e
       centrati nei 926 che restano dei 982 danno 163 sopra e 107 sotto. */
    .case-carousel__scene {
        display: grid;
        grid-template-columns: var(--track-width);
        justify-content: center;
        align-content: center;

        /* ⚠ Serve, e non è ridondante: il layout statico ha `justify-items:
           center` per impilare le card al centro, e qui quel centro farebbe danni
           — pista e titolo si dimensionerebbero al contenuto invece di riempire
           la colonna, e le larghezze delle card verrebbero sbagliate in silenzio,
           perché il conto è giusto su una pista sbagliata. Il pulsante conserva
           il proprio `justify-self: end`. */
        justify-items: stretch;

        height: 100%;
        max-width: none;

        /* 64px fra titolo e pista: nel design il titolo sta a y=0 alto 128 e la
           pista a y=192 (nodo 649:2390). È lo stesso valore che il Make mette fra
           pista e pulsante, quindi lo `row-gap` copre entrambi gli stacchi e il
           pulsante non ha bisogno di un margine proprio. */
        row-gap: var(--space-2xl);
        padding-block-start: 5.7vh;
        padding-inline: 0;
    }

    .case-carousel__track {
        width: 100%;
        margin-inline: 0;
        overflow: hidden;
    }

    /* La fila. Si trasla, non si scrolla: il movimento è guidato dallo scroll
       verticale, e uno scroll orizzontale vero risponderebbe anche al trackpad
       creando due sorgenti di movimento in disaccordo. */
    .case-carousel__row {
        display: flex;
        gap: var(--card-gap);
        translate: calc(var(--cards-x) * -1) 0;
        will-change: translate;
    }

    /* Le due larghezze, calcolate sulla pista al netto del distanziatore: una
       coppia larga+stretta la riempie esattamente. */
    .case-carousel__item {
        flex: 0 0 auto;
    }

    .case-carousel__item--wide {
        width: calc((100% - var(--card-gap)) * var(--card-wide));
    }

    .case-carousel__item--narrow {
        width: calc((100% - var(--card-gap)) * var(--card-narrow));
    }

    /* Il pulsante compare alla fine, allineato al bordo destro della pista — che
       è anche il margine di pagina, perché la colonna al 95,77% lascia 32px per
       lato. Perciò non serve un margine proprio.

       Il pulsante nel frame del design non c'è — la sezione è titolo e card e
       basta — perché compare a fine scorrimento e il frame è il primo fotogramma.
       Resta un campo ACF opzionale: se l'editor non lo compila, non esiste.

       Fra pista e pulsante il Make mette 64px, che sono esattamente lo `row-gap`
       della scena: nessun margine da aggiungere. Ne aveva uno finché il gap era
       24px, e serviva solo a colmare la differenza. */
    .case-carousel__cta {
        justify-self: end;
        width: max-content;

        /* Il pulsante compare **scoprendosi dal basso**, non in dissolvenza.
           Non è una preferenza: una dissolvenza di bianco su fondo scuro passa
           necessariamente per il grigio, perché ridurre l'opacità del bianco *è*
           fare del grigio. Non esiste un valore intermedio che sia bianco, e
           accorciare la finestra non basta — resta un tratto di scroll in cui il
           pulsante è visibilmente grigio invece che bianco come nel design.

           Con un ritaglio ogni pixel visibile è a colore pieno: il pulsante non
           è mai un po' trasparente, è solo un po' scoperto. Ed è la stessa
           direzione del riempimento all'hover, quindi il modulo ha un movimento
           solo invece di due.

           `inset(X 0 0 0)` ritaglia dall'alto: portando X da 100% a 0 la parte
           visibile cresce da sotto in su. */
        clip-path: inset(calc((1 - var(--cta-o)) * 100%) 0 0 0);
    }

    /* Finché il pulsante non è comparso del tutto non è interattivo, e l'attributo
       lo mette il JS — vedi il commento lì, che spiega perché la soglia è 1 e non
       zero. Questa regola è solo la ridondanza per i browser che leggono `inert`
       senza implementarlo. */
    .case-carousel__cta[inert] {
        pointer-events: none;
    }
}
