.portfolio {
    background: #f5f5f5;
}

.portfolio__hero {
    min-height: 100vh;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: start;
    background: #0D0D0D;
    color: #f5f5f5;
    padding: 0 6%;
    text-align: center;
}

/* Forme/typographie communes : .hero-title (tokens.css). */
.portfolio__title {
    position: relative;
    margin-bottom: 0.3em;
    --hero-title-max: 132px;
    --hero-title-vw: 10vw;
}

/*
 * Balayage flou -> net au défilement : même mécanisme que le bloc "Titre -
 * Apparition nette/floue" (blocks/title-reveal), réimplémenté ici en CSS
 * pur car ce hero appartient à un template PHP classique, pas à un bloc
 * Gutenberg. Déclenché par assets/js/hero-title-reveal.js.
 */
.portfolio__title-blur,
.portfolio__title-sharp {
    display: block;
}

.portfolio__title-blur {
    filter: blur(28px);
    opacity: 0.28;
}

@property --portfolio-title-reveal {
    syntax: '<percentage>';
    inherits: false;
    initial-value: 0%;
}

.portfolio__title-sharp {
    position: absolute;
    inset: 0;
    --portfolio-title-reveal: -10%;
    -webkit-mask-image: linear-gradient(to right, black 0%, black var(--portfolio-title-reveal), transparent calc(var(--portfolio-title-reveal) + 10%));
    mask-image: linear-gradient(to right, black 0%, black var(--portfolio-title-reveal), transparent calc(var(--portfolio-title-reveal) + 10%));
    -webkit-mask-repeat: no-repeat;
    mask-repeat: no-repeat;
}

/* Texte du calque net via attr(data-text) plutôt qu'un vrai texte dupliqué
   dans le DOM : évite un H1 "vu en double" par les outils qui lisent le
   textContent sans respecter aria-hidden. */
.portfolio__title-sharp::before {
    content: attr(data-text);
}

.hero-reveal.is-visible .portfolio__title-blur {
    opacity: 0;
    transition: opacity 500ms ease 600ms;
}

.hero-reveal.is-visible .portfolio__title-sharp {
    --portfolio-title-reveal: 100%;
    transition: --portfolio-title-reveal 2800ms cubic-bezier(0.22, 1, 0.36, 1) 600ms;
}

@media (prefers-reduced-motion: reduce) {
    .portfolio__title-blur {
        opacity: 0;
    }

    .portfolio__title-sharp {
        -webkit-mask-image: none;
        mask-image: none;
    }
}

/* Forme/typographie communes : .hero-subtitle (tokens.css). */
.portfolio__subtitle {
    /* Fondu léger seul (pas de balayage directionnel comme le titre). */
    opacity: 0;
    filter: blur(6px);
    transform: translateY(12px);
    transition: opacity 900ms ease 600ms, filter 900ms ease 600ms, transform 900ms ease 600ms;
}

.hero-reveal.is-visible .portfolio__subtitle {
    opacity: 1;
    filter: blur(0);
    transform: translateY(0);
}

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

/* Layout/forme communs : .hero-filters (tokens.css). */
.portfolio__filters {
    margin: 0 auto var(--chirripo-space-xl, 3rem);
    /* Démarre une fois le fondu du descriptif terminé (600ms + 900ms). */
    opacity: 0;
    transform: translateY(16px);
    transition: opacity 700ms ease 1500ms, transform 700ms ease 1500ms;
}

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

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

/* Forme/couleur/hover/.is-active communs : .hero-filter (tokens.css). */

/*
 * La galerie remonte sur la zone noire du hero (la première card chevauche
 * la transition) : marge négative plutôt qu'un simple empilement.
 */
.portfolio__grid {
    position: relative;
    z-index: 1;
    margin: auto 0;
    padding: 0 6%;
    background-color: #f5f5f5;
    transition: opacity 0.2s ease;
}

/* Le temps du fetch AJAX déclenché par un changement de filtre secteur (portfolio.js). */
.portfolio__grid.is-loading {
    opacity: 0.4;
}

.portfolio__full,
.portfolio__asymmetric,
.portfolio__pair {
    margin-bottom: var(--chirripo-space-md, 1.5rem);
}

.portfolio__full .client-card__link {
    aspect-ratio: 16 / 10;
}

/* La toute première card remonte encore davantage sur le hero. Comme un
   décalage relatif (top) ne libère pas d'espace en dessous, on referme
   cet espace en remontant d'autant la rangée asymétrique qui suit. */
.portfolio__full:first-child {
    position: relative;
    top: -15rem;
}

/* Ciblé uniquement sur la ligne asymétrique qui suit la 1ère card (pas
   toutes), sans quoi les cycles suivants (7e client et +) remonteraient
   aussi de 10rem. */
.portfolio__full:first-child+.portfolio__asymmetric {
    margin-top: -14rem;
}

.portfolio__pair {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: var(--chirripo-space-md, 1.5rem);
}

.portfolio__pair .client-card__link {
    aspect-ratio: 16 / 10;
}

/* Ligne asymétrique : grande carte à gauche (quasi carrée), 2 cards
   empilées à droite — même mécanique que le bloc "Grille de projets". */
.portfolio__asymmetric {
    display: grid;
    gap: var(--chirripo-space-md, 1.5rem);
    /* minmax(0, Nfr), pas Nfr seul (colonnes ET lignes) : sinon la piste
       dont le contenu a le plus grand min-content (titre, image)
       revendique tout l'espace et écrase l'autre piste à 0 — même piège
       que sur la grille "Projets" de l'accueil. Touchait aussi les lignes
       ici (pas seulement les colonnes) : selon les cartes chargées via
       "Voir plus", top/bottom pouvaient écraser la carte "large" à plat. */
    grid-template-columns: minmax(0, 3fr) minmax(0, 2fr);
    grid-template-rows: minmax(0, 1fr) minmax(0, 1fr);
    grid-template-areas:
        "large top"
        "large bottom";
}

.portfolio__asymmetric-large {
    grid-area: large;
}

.portfolio__asymmetric-top {
    grid-area: top;
}

.portfolio__asymmetric-bottom {
    grid-area: bottom;
}

.portfolio__asymmetric-top .client-card__link,
.portfolio__asymmetric-bottom .client-card__link {
    aspect-ratio: 16 / 10;
}

/* La grande carte n'a pas son propre ratio : elle se cale sur la hauteur
   cumulée des 2 cards empilées à droite (voir Projets-Home pour la même
   technique et son explication détaillée). */
.portfolio__asymmetric-large .client-card {
    height: 100%;
}

.portfolio__asymmetric-large .client-card__link {
    height: 100%;
    aspect-ratio: auto;
}

@media (max-width: 768px) {

    /* minmax(0, 1fr), pas 1fr seul, même à une seule colonne : sans ça, la
       piste s'étire pour accueillir le contenu le plus large de ses enfants
       (ex. la ligne d'étiquettes nowrap de .client-card__tags), ce qui
       élargit la colonne — et l'image qui la remplit à 100% — au-delà du
       viewport (même piège que la grille "Projets" de l'accueil). */
    .portfolio__pair {
        grid-template-columns: minmax(0, 1fr);
    }

    .portfolio__asymmetric {
        grid-template-columns: minmax(0, 1fr);
        grid-template-rows: none;
        grid-template-areas:
            "large"
            "top"
            "bottom";
    }

    .portfolio__asymmetric-large .client-card__link {
        height: auto;
        aspect-ratio: 16 / 10;
    }
}

@media (max-width: 600px) {


    .portfolio__pair {
        gap: 40px;
    }

    /* Même remontée que la règle desktop ci-dessus (-10rem), réduite pour
       ne pas trop chevaucher le hero sur un écran plus court (encore
       réduite ici, était -5rem, pour le même espacement filtres/1ère card). */
    .portfolio__full:first-child {
        top: -7rem;
    }

    .portfolio__full:first-child+.portfolio__asymmetric {
        margin-top: -7rem;
    }

    .portfolio__hero {
        min-height: 66vh;
        padding-bottom: 0;
    }

    .portfolio__filters {
        margin-top: 3rem;
        margin-bottom: 1rem;
    }
}

.portfolio__empty {
    text-align: center;
    color: var(--chirripo-color-text-muted, #6a6a6a);
    padding: var(--chirripo-space-xl, 6rem) 0;
}

.portfolio__load-more {
    text-align: center;
    padding: 3% 0 10%;
    background: #f5f5f5;
    font-family: var(--chirripo-font-body, sans-serif);
    font-size: 16px;
    font-weight: 400;
    text-transform: uppercase;
}

/* Forme/couleur/hover/:disabled communs : .btn-pill (tokens.css). Contexte
   toujours clair ici (template PHP classique, pas de .has-bg-*) : le hover
   par défaut de .btn-pill (fond noir/texte clair) s'applique déjà tel
   quel, sans réglage local. */