/* utilities.css — media queries transverses, états de chargement/erreur
   d'image. Chargé en dernier : ces règles (surtout les media queries)
   doivent pouvoir passer devant celles des fichiers précédents. */

@media (max-width:800px) {
    .nav-toggle {
        display: inline-block
    }

    .main-nav {
        display: none
    }

    .product {
        flex-direction: column;
        gap: 16px;
        align-items: stretch
    }

    /* max-width (600px, posé en style inline) gardé même ici — sans ça, la
       colonne description s'étirait sur toute la largeur du produit empilé,
       trop large et moins lisible sur un écran moyen. Centrée (margin:auto)
       pour ne pas coller à gauche une fois plus étroite que sa colonne
       (width:100%) juste en dessous. */
    .product .meta {
        width: 100%;
        margin-left: auto;
        margin-right: auto;
        padding-left: 0 !important
    }

    .product-left,
    .product-right,
    .product-main {
        width: 100%;
        display: flex;
        padding: 0
    }

    .product-main .viewer {
        height: 360px
    }
}

@media (max-width:600px) {
    .page-header h1 {
        font-size: 28px;
    }

    /* La largeur de colonne fixe des prints (posée en style inline par
       catégorie, voir PRINT_CATEGORIES/renderPrints dans
       js/pages/prints.js) peut dépasser la largeur d'écran disponible sur
       mobile — jusqu'à 360px pour "Landscape", plus encore pour "Wide".
       `!important` nécessaire pour passer devant le style inline (rien
       d'autre ne le peut) : une seule colonne fluide (100% du conteneur) en
       dessous de 600px, le ratio de chaque image (posé séparément, pas
       touché ici) continue de s'appliquer à cette largeur réduite. */
    .prints-grid {
        grid-template-columns: 1fr !important;
    }
}

/* État de chargement initial (fetch de assets/*.json) --------------------- */
.loading-message {
    text-align: center;
    color: var(--muted);
    padding: 80px 0;
}

/* Image manquante (fichier supprimé/déplacé après coup, entrée du CMS
   pointant vers un chemin qui n'existe plus...) : la source est remplacée
   par un SVG vide/transparent (voir onImageError, js/images.js) — ce fond
   gris est donc ce qui reste visible, même teinte que le reste du site
   pendant un chargement (--placeholder-bg), pas un gris distinct dédié à
   l'erreur. */
.img-missing {
    background: var(--placeholder-bg);
}

/* Image pas encore chargée (requête /.netlify/images en cours, surtout avec
   loading="lazy") : tant qu'elle n'a pas de pixels à afficher, le navigateur
   affiche par défaut le texte alt — qui hérite du style de lien (bleu
   souligné) quand l'image est dans un <a> (grilles, panier, produits
   associés). On le rend invisible ; l'espace est déjà réservé ailleurs
   (aspect-ratio ou width/height fixes), donc aucun saut de mise en page. */
img {
    color: transparent;
    text-decoration: none;
}

/* Fond gris clair pendant le chargement — .card .thumb, .related-card img et
   .cart-line-thumb img en ont déjà un ; il manquait à la grille prints. */
.prints-grid img {
    background: var(--placeholder-bg);
}

/* Fondu d'apparition des images de galerie (originals + prints), même
   principe que .home-hero-bg : invisible tant que non chargée, la classe
   "loaded" est ajoutée par onImageLoad (js/images.js, posé en attribut
   `onload` inline sur chaque <img>) une fois le chargement terminé — y
   compris pour une image déjà en cache, dont le "load" se déclenche dès
   l'insertion dans le DOM. Espace déjà réservé (aspect-ratio), donc aucun
   saut de mise en page pendant le fondu. */
.fade-img {
    opacity: 0;
    transition: opacity .35s ease;
}

.fade-img.loaded {
    opacity: 1;
}

/* .disabled-img (print épuisé, grisé à 50%) doit garder son opacité réduite
   une fois chargée — sans ce override, .fade-img.loaded (plus spécifique
   que .disabled-img seul) la repasserait à 100%. */
.fade-img.loaded.disabled-img {
    opacity: 0.5;
}
