/* ==========================================================================
   BASE — tokens, typographie, primitives partagées
   ========================================================================== */

:root {
    /* Couleurs — 1 seul accent. Les neutres tirent légèrement vers le chaud :
       c'est ce qui distingue le site d'un noir-et-blanc générique. */
    --ink: #14110f;
    --ink-soft: #221d1a;
    --paper: #faf8f5;
    --card: #ffffff;
    --accent: #c8102e;
    --accent-dark: #a10d25;

    --grey-100: #f1ede8;
    --grey-200: #e2dcd4;
    --grey-300: #c9c1b7;
    --grey-500: #7d766e;
    --grey-600: #57514b;

    /* Typographie */
    --font: "DM Sans", sans-serif;
    --font-mono: "DM Mono", ui-monospace, monospace;

    --step-eyebrow: 0.72rem;
    --step-small: 0.86rem;
    --step-body: clamp(1rem, 0.96rem + 0.2vw, 1.09rem);
    --step-lead: clamp(1.08rem, 1rem + 0.42vw, 1.32rem);
    --step-h3: clamp(1.28rem, 1.1rem + 0.85vw, 1.72rem);
    --step-h2: clamp(1.85rem, 1.4rem + 2.1vw, 3.1rem);
    --step-h1: clamp(2.5rem, 1.5rem + 4.6vw, 5.4rem);

    /* Rythme */
    --gutter: 1.35rem;
    --measure: 68ch;
    --radius: 4px;
    --radius-lg: 10px;

    --header-h: 68px;
    --ease: cubic-bezier(0.22, 0.61, 0.36, 1);
    --ease-out: cubic-bezier(0.76, 0, 0.24, 1);
}

@media (min-width: 900px) {
    :root {
        --gutter: 2.75rem;
        --header-h: 82px;
    }
}

/* Téléphone en paysage : le header rendrait 18 % de la hauteur inutilisable. */
@media (max-width: 900px) and (max-height: 620px) {
    :root {
        --header-h: 56px;
    }
}

html,
body {
    background: var(--paper);
}

body {
    font-family: var(--font);
    font-size: var(--step-body);
    font-weight: 400;
    line-height: 1.62;
    color: var(--ink);
    -webkit-font-smoothing: antialiased;
    overflow-x: hidden;
}

/* Page figée derrière le menu ou la visionneuse. La position fixe est le seul
   verrou que respecte iOS Safari ; `top` est posé en JS pour ne pas perdre la
   position de défilement. */
body.is-locked {
    position: fixed;
    left: 0;
    right: 0;
    width: 100%;
    overflow: hidden;
}

/* --- Annotation technique -------------------------------------------------- */

.mono {
    font-family: var(--font-mono);
    font-size: 0.78rem;
    font-weight: 400;
    letter-spacing: 0.02em;
    text-transform: lowercase;
}

/* --- Titres ------------------------------------------------------------- */

h1,
h2,
h3,
h4 {
    font-weight: 700;
    line-height: 1.08;
    letter-spacing: -0.025em;
    text-wrap: balance;
}

h3,
h4 {
    line-height: 1.25;
    letter-spacing: -0.015em;
}

strong {
    font-weight: 700;
}

/* --- Layout ------------------------------------------------------------- */

.container {
    width: 100%;
    max-width: 1240px;
    margin-inline: auto;
    padding-inline: var(--gutter);
}

.container--narrow {
    max-width: 880px;
}

.section {
    padding-block: clamp(4rem, 2rem + 9vw, 8.5rem);
}

.section--tight {
    padding-block: clamp(3rem, 1.8rem + 6vw, 5.5rem);
}

/* Sur téléphone, la formule ci-dessus produisait 134px de vide entre chaque
   section — près d'un sixième d'écran, dix fois dans la page. */
@media (max-width: 600px) {
    .section {
        padding-block: 3.2rem;
    }

    .section--tight {
        padding-block: 2.6rem;
    }
}

.section--ink {
    background: var(--ink);
    color: var(--paper);
}

/* Alternance de fonds : évite le mur de blanc d'une page à sections identiques */
.section--tint {
    background: var(--grey-100);
}

.section--edge {
    border-top: 1px solid var(--grey-200);
}

.rule {
    height: 1px;
    background: var(--grey-200);
    border: 0;
    margin: 0;
}

/* --- Label de section ---------------------------------------------------- */

.section-label {
    display: flex;
    align-items: center;
    gap: 1rem;
    margin-bottom: 1.6rem;
}

.section-label span {
    font-family: var(--font-mono);
    font-size: 0.78rem;
    font-weight: 500;
    letter-spacing: 0.02em;
    text-transform: lowercase;
    color: var(--accent);
    white-space: nowrap;
}

.section-label::after {
    content: "";
    flex: 1;
    height: 1px;
    background: var(--grey-200);
}

.section--ink .section-label::after {
    background: rgba(255, 255, 255, 0.16);
}

.section-heading {
    font-size: var(--step-h2);
    max-width: 20ch;
}

.section-intro {
    font-size: var(--step-lead);
    color: var(--grey-600);
    max-width: 56ch;
    margin-top: 1.4rem;
}

/* La mesure courte de 20ch met en valeur les titres sur grand écran ; sur
   téléphone elle bride la colonne et provoque des coupures orphelines. */
@media (max-width: 600px) {
    .section-heading {
        max-width: none;
    }
}

.section--ink .section-intro {
    color: rgba(255, 255, 255, 0.68);
}

/* --- Boutons ------------------------------------------------------------- */

.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.6rem;
    padding: 0.95rem 1.6rem;
    font-size: 0.94rem;
    font-weight: 700;
    letter-spacing: -0.01em;
    border-radius: var(--radius);
    border: 1px solid transparent;
    transition: transform 0.25s var(--ease), background-color 0.25s var(--ease),
        color 0.25s var(--ease), border-color 0.25s var(--ease), box-shadow 0.25s var(--ease);
}

.btn svg {
    flex-shrink: 0;
}

.btn--accent {
    background: var(--accent);
    color: var(--paper);
}

.btn--accent:hover {
    background: var(--accent-dark);
    transform: translateY(-2px);
    box-shadow: 0 10px 24px -12px rgba(200, 16, 46, 0.75);
}

.btn--ink {
    background: var(--ink);
    color: var(--paper);
}

.btn--ink:hover {
    transform: translateY(-2px);
    box-shadow: 0 10px 24px -14px rgba(0, 0, 0, 0.7);
}

.btn--ghost {
    border-color: var(--grey-300);
    color: var(--ink);
}

.btn--ghost:hover {
    border-color: var(--ink);
    transform: translateY(-2px);
}

.btn--light {
    background: rgba(255, 255, 255, 0.1);
    border-color: rgba(255, 255, 255, 0.28);
    color: var(--paper);
    backdrop-filter: blur(8px);
}

.btn--light:hover {
    background: var(--paper);
    color: var(--ink);
    transform: translateY(-2px);
}

/* --- Lien texte animé ---------------------------------------------------- */

.link {
    position: relative;
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    font-weight: 700;
    color: var(--accent);
}

.link::after {
    content: "";
    position: absolute;
    left: 0;
    bottom: -3px;
    width: 100%;
    height: 1.5px;
    background: currentColor;
    transform: scaleX(0);
    transform-origin: left center;
    transition: transform 0.3s var(--ease);
}

.link:hover::after {
    transform: scaleX(1);
}

/* --- Accessibilité ------------------------------------------------------- */

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

.section--ink :focus-visible,
.hero :focus-visible {
    outline-color: var(--paper);
}

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

.skip-link {
    position: absolute;
    top: -100px;
    left: var(--gutter);
    z-index: 200;
    padding: 0.75rem 1.1rem;
    background: var(--ink);
    color: var(--paper);
    font-weight: 700;
    border-radius: var(--radius);
    transition: top 0.2s var(--ease);
}

.skip-link:focus {
    top: 0.75rem;
}

/* --- Reveal au scroll ---------------------------------------------------- */

/* Discret par choix : le geste marqué du site est le rideau qui découvre les
   photos, pas l'entrée des blocs de texte.

   IMPORTANT — tout ce qui masque du contenu est conditionné à `.js-anim`, une
   classe posée sur <html> par un script inline en tête de page. Sans JS (script
   bloqué, module en erreur, crawler qui n'exécute rien), aucune règle d'opacité
   ne s'applique et la page reste intégralement lisible. L'animation est un
   bonus, jamais un prérequis à l'affichage. */
.js-anim .reveal {
    opacity: 0;
    transform: translateY(12px);
    transition: opacity 0.55s var(--ease), transform 0.55s var(--ease);
}

.js-anim .reveal.is-visible {
    opacity: 1;
    transform: none;
}

.js-anim .reveal[data-delay="1"] {
    transition-delay: 0.09s;
}

.js-anim .reveal[data-delay="2"] {
    transition-delay: 0.18s;
}

.js-anim .reveal[data-delay="3"] {
    transition-delay: 0.27s;
}

.js-anim .reveal[data-delay="4"] {
    transition-delay: 0.36s;
}

/* Trait rouge qui se déploie sous les titres de section à leur apparition */
.section-heading {
    position: relative;
    padding-bottom: 1.15rem;
}

.section-heading::after {
    content: "";
    position: absolute;
    left: 0;
    bottom: 0;
    width: 76px;
    height: 3px;
    background: var(--accent);
    transform-origin: left center;
}

/* Le trait n'est replié qu'en présence de JS, sinon il reste déployé. */
.js-anim .section-heading::after {
    transform: scaleX(0);
    transition: transform 0.85s var(--ease) 0.2s;
}

.js-anim .section-heading.is-visible::after,
.js-anim .is-visible .section-heading::after {
    transform: scaleX(1);
}

@media (prefers-reduced-motion: reduce) {

    .js-anim .reveal {
        opacity: 1;
        transform: none;
    }

    .js-anim .section-heading::after {
        transform: scaleX(1);
        transition: none;
    }
}

/* --- Médias -------------------------------------------------------------- */

/* Les photos sont servies en WebP via <picture>, avec repli JPG/PNG sur l'<img>.
   `display: contents` fait disparaître la boîte du <picture> de la mise en page :
   l'<img> reste l'enfant direct de son conteneur, exactement comme avant
   l'ajout du <picture>.

   Ce n'est pas cosmétique. Sans cette règle, le <picture> devient un élément
   de flux à part entière — dans le hero, qui est en `display: flex`, il se
   retrouve dimensionné à zéro (son unique enfant est en position absolue) et
   l'image de fond ne s'affiche plus du tout. */
picture {
    display: contents;
}

/* Par défaut une photo n'est JAMAIS rognée : elle garde son ratio d'origine.
   Le recadrage est un choix explicite, via `.media--crop`. */
.media {
    position: relative;
    display: block;
    overflow: hidden;
    border-radius: var(--radius-lg);
    background: var(--grey-100);
}

.media img {
    display: block;
    width: 100%;
    height: auto;
    filter: saturate(0.82) contrast(1.02);
    transform: translate3d(0, 0, 0) scale(1);
    transition: transform 1.1s var(--ease-out), filter 0.6s var(--ease);
}

/* --- Rideau de révélation ------------------------------------------------- */

/* La photo est masquée par un aplat rouge qui se retire quand le bloc entre
   dans l'écran, pendant que l'image se dézoome. */
.js-anim .reveal-media::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: 4;
    background: var(--accent);
    transform: scaleX(1);
    transform-origin: left center;
    transition: transform 0.9s var(--ease-out);
}

.js-anim .reveal-media img {
    transform: translate3d(0, 0, 0) scale(1.14);
}

.js-anim .reveal-media.is-visible::before {
    transform: scaleX(0);
    transform-origin: right center;
}

.js-anim .reveal-media.is-visible img {
    transform: translate3d(0, 0, 0) scale(1);
}

@media (prefers-reduced-motion: reduce) {

    .js-anim .reveal-media::before {
        display: none;
    }

    .js-anim .reveal-media img,
    .media img {
        transform: none;
        transition: none;
    }
}

/* Recadrage volontaire, pour les grilles où la hauteur doit être régulière */
.media--crop {
    aspect-ratio: var(--ratio, 16 / 9);
}

.media--crop img {
    height: 100%;
    object-fit: cover;
}

/* Repli visuel si un fichier photo est absent : bloc sombre discret,
   jamais une icône d'image cassée. */
.media.is-missing {
    background: linear-gradient(150deg, var(--ink-soft), #2c2c30);
    aspect-ratio: var(--ratio, 16 / 9);
}

.media.is-missing img {
    visibility: hidden;
}

/* --- Photo cliquable ------------------------------------------------------ */

.zoom {
    position: relative;
    display: block;
    width: 100%;
    cursor: zoom-in;
}

.zoom .media::after {
    content: "";
    position: absolute;
    inset: 0;
    z-index: 1;
    background: rgba(20, 17, 15, 0);
    transition: background-color 0.4s var(--ease);
}

/* Équerres d'accent aux coins, façon repère de plan technique */
.zoom::before,
.zoom::after {
    content: "";
    position: absolute;
    z-index: 3;
    width: 18px;
    height: 18px;
    border: 0 solid var(--accent);
    opacity: 0;
    transition: opacity 0.35s var(--ease), transform 0.35s var(--ease);
    pointer-events: none;
}

.zoom::before {
    top: 10px;
    left: 10px;
    border-top-width: 2px;
    border-left-width: 2px;
    border-top-left-radius: 4px;
    transform: translate(6px, 6px);
}

.zoom::after {
    bottom: 10px;
    right: 10px;
    border-bottom-width: 2px;
    border-right-width: 2px;
    border-bottom-right-radius: 4px;
    transform: translate(-6px, -6px);
}

@media (hover: hover) {

    .zoom:hover .media img,
    .zoom:focus-visible .media img {
        transform: translate3d(0, 0, 0) scale(1.04);
        filter: saturate(1.06) contrast(1);
    }

    .zoom:hover .media::after,
    .zoom:focus-visible .media::after {
        background: rgba(20, 17, 15, 0.14);
    }

    .zoom:hover::before,
    .zoom:hover::after,
    .zoom:focus-visible::before,
    .zoom:focus-visible::after {
        opacity: 1;
        transform: translate(0, 0);
    }
}

.zoom-hint {
    position: absolute;
    right: 0.85rem;
    bottom: 0.85rem;
    z-index: 2;
    display: flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.42rem 0.7rem;
    border-radius: 100px;
    background: rgba(250, 248, 245, 0.94);
    color: var(--ink);
    font-size: 0.7rem;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    opacity: 0;
    transform: translateY(6px);
    transition: opacity 0.3s var(--ease), transform 0.3s var(--ease);
}

.zoom:hover .zoom-hint,
.zoom:focus-visible .zoom-hint {
    opacity: 1;
    transform: none;
}

/* --- Dérive au scroll ------------------------------------------------------ */

/* Le décalage est calculé en JS et injecté dans --shift. Il porte sur le bloc
   entier, jamais sur l'image : aucune photo n'est rognée par le mouvement. */
[data-parallax] {
    transform: translate3d(0, var(--shift, 0px), 0);
    will-change: transform;
}

figure {
    margin: 0;
}

/* --- Colonne épinglée ------------------------------------------------------ */

/* Le titre reste en place à gauche pendant que le contenu défile à droite. */
.pinned {
    display: grid;
    gap: 2.4rem;
}

.pinned-head .section-heading {
    max-width: 16ch;
}

.pinned-head .section-intro {
    font-size: var(--step-body);
    max-width: 40ch;
}

/* Les grilles reprennent leur souffle dans la colonne de droite, plus étroite */
.pinned-body > :first-child {
    margin-top: 0;
}

@media (min-width: 1000px) {

    .pinned {
        grid-template-columns: 1fr 1.55fr;
        gap: 4rem;
        align-items: start;
    }

    .pinned-head {
        position: sticky;
        top: calc(var(--header-h) + 2.4rem);
        align-self: start;
    }

    .pinned-body .process {
        grid-template-columns: repeat(2, 1fr);
        gap: 2rem 2.2rem;
    }

    .pinned-body .works {
        columns: 2;
    }
}
