/* ============================================================
   Flying Fries — fiche produit, presentation « modern »
   Chargee sur TOUTES les fiches produit : `products.layout` a ete supprimee le
   2026-08-13, il n'y a plus de presentation legacy a preserver.

   ⚠️ LE HTML EST LE MEME A TOUTES LES LARGEURS, et le fichier se lit en trois
   zones dans cet ordre :
     1. LE SOMBRE — les couleurs, sans condition de largeur. C'est le theme.
     2. PETIT ECRAN — le peu qui ne peut pas etre commun.
     3. BUREAU — la mise en page : grille, barres fixes, diaporama, cinema.

   Le telephone change de COULEURS, pas de FORME : il garde exactement
   l'empilement qu'il avait. Une page sombre au bureau et claire sur mobile
   aurait fait deux produits differents pour un seul add-on.

   ⚠️ POURQUOI L'ENCART NE PEUT PAS DEPENDRE DE L'IMAGE
   Mesure du 2026-08-12 sur les 12 heroes du Gabriel, 9 zones : les zones hautes
   sont claires sur 7 a 9 images sur 12, et meme le bandeau bas — le plus sombre
   et le plus uniforme — est clair sur une image sur douze. Aucune zone n'est
   universellement sure : Lord Frites compose ses cadrages differemment d'une
   photo a l'autre, volontairement.
   Donc verre depoli TEINTE portant son propre contraste, plus un voile uniforme.
   Le flou seul ne suffit pas : un ciel clair sous du texte blanc reste illisible
   meme floute. Recette a valider sur `hero-06`, la pire du lot.
   ============================================================ */

.product-layout--modern {
    /* Le gris neutre du voile. Sombre sans etre noir : un noir pur ecraserait
       les ombres des photos, deja travaillees a la prise de vue. */
    --veil-dark: #14161a;
    /* Force du voile. LE curseur a bouger pour arbitrer entre lisibilite et
       respect de l'image — tout le reste en decoule. */
    --veil-strength: 0.62;

    --glass-bg: rgba(18, 20, 24, 0.58);
    --glass-border: rgba(255, 255, 255, 0.12);
    --glass-blur: 18px;

    /* Hauteurs des deux barres fixes du HAUT. Deux valeurs et non une somme :
       la barre meta se cale sous la barre titre, il faut donc connaitre la
       hauteur de cette derniere separement.

       EN HAUT et non en bas — corrige le 2026-08-12 apres essai. Sur tout le
       site les titres sont en haut ; les poser en bas cassait la coherence et
       « faisait bizarre ». Et c'est en haut que les yeux vont naturellement. */
    /* `height` EXACTE et non `min-height` : la barre meta se positionne a un
       decalage calcule depuis cette valeur. Avec un `min-height`, la barre titre
       pouvait grandir sans que le decalage suive — et venait grignoter le
       sous-titre. Constate le 2026-08-12.
       104 px = titre 42 px (interligne 1.05) + sous-titre + rembourrage, avec de
       l'air. Le titre le plus long du catalogue tient sur une ligne. */
    --bar-title-h: 104px;
    --bar-meta-h: 44px;
    --bar-gap: 22px;

    /* Largeur utile. `.page-content` plafonne a 960 px pour tout le site, ce qui
       donnait une colonne etroite au milieu d'une photo plein cadre — le defaut
       que Lord Frites a nomme « blocs poses par-ci par-la ». */
    --band-max: 1560px;
    --band-pad: 40px;

    /* ⚠️ LES ENCRES SOMBRES, EN PERMANENCE — et sans condition de theme.
       Une fiche produit est sombre par identite : elle ne suit pas le choix
       clair/sombre du visiteur, elle n'a meme pas de bouton pour le proposer.
       Les tokens d'encre de `tokens.css` basculent sur `data-theme`, ce qui ne
       lui sert a rien : en theme clair elle recevrait le bleu et le vert de
       marque sur sa barre sombre — 4,46:1 et 3,49:1, sous le seuil.
       C'est le meme geste que les ilots clairs de l'en-tete, en sens inverse. */
    --ff-blue-ink:  #579FF4;
    --ff-green-ink: #73A793;
    --ff-red-ink:   #D9867E;
}

/* ⚠️ TOUT ELEMENT RESERVE AU BUREAU DOIT ETRE AJOUTE ICI.
   Ses autres regles vivent dans le `min-width` du bas ; sans ce garde
   inconditionnel, l'element s'affiche NU dans le flux en petit ecran — bouton
   popcorn brut, ou logo Flying Fries a sa taille naturelle de 500 px.
   La regle a deja ete oubliee une fois, le 2026-08-12, sur `.cinema-brand`
   ajoute apres coup. Un element dont TOUT le style est conditionnel a besoin
   d'un `display: none` qui, lui, ne l'est pas.

   `.hero-stage` n'y figure PLUS depuis le 2026-08-13 : la scene porte le fond a
   toutes les largeurs. Ce sont ses DIAPOSITIVES qui restent au bureau — sur un
   telephone il ne reste que le voile, un degrade CSS qui ne coute pas un octet
   de reseau. */
.hero-slide,
.pop-toggle,
.cinema-brand,
.catalog-tab {
    display: none;
}

/* ═══════════════════════════════════════════════════════════
   1. LE SOMBRE — A TOUTES LES LARGEURS

   Le theme de la fiche produit, et un theme n'a pas de point de rupture : ce
   qui suit vaut sur un telephone comme sur un 27 pouces. Tout ce qui touche a
   la MISE EN PAGE vit dans les deux blocs de largeur, plus bas.

   Beaucoup de ces regles reparent la meme chose. Le site entier est dessine
   pour un fond clair, donc `--ff-text` (#252525) et `--ff-text-muted` (#6b6b6b)
   sont partout — et les deux s'effacent sur du sombre.
   ═══════════════════════════════════════════════════════════ */

/* ⚠️ DECISION ARRETEE le 2026-08-12 par Lord Frites : le fond ATC ne figure PAS
   sur la fiche produit. Ce n'est plus une piste a essayer.

   Il reste le tissu conjonctif de tout le reste du site. Ici la scene occupe le
   meme calque, et l'idee de le faire revenir entre les sections supposait des
   bandes opaques alternees — ce n'est pas cette page. Deux textures en
   concurrence, c'en est une de trop. */
.product-layout--modern .ff-bg-atc {
    display: none;
}

/* Sur <html> AUTANT que sur <body> : base.css rend le body transparent des
   qu'un fond ATC existe dans le DOM — il y est toujours, on ne fait que le
   masquer. Sans la regle sur <html>, le blanc reviendrait sous la scene. */
.product-layout--modern,
html:has(body.product-layout--modern) {
    background-color: var(--veil-dark);
}

/* ─── La scene ────────────────────────────────
   `fixed` : le fond ne defile pas, le contenu passe dessus.
   Si la barre d'URL d'un telephone decale le viewport et decouvre une bande, la
   couleur posee sur <html> ci-dessus prend le relais — c'est le gris du point
   sombre du voile, donc il n'y a rien a voir. */
.hero-stage {
    display: block;
    position: fixed;
    inset: 0;
    z-index: -1;
    overflow: hidden;
    pointer-events: none;
    background: var(--veil-dark);
}

/* Voile uniforme par construction, du gris neutre a la couleur du produit :
   chaque appareil a la sienne, donc le voile porte l'identite sans repeindre la
   photo.
   En petit ecran il est SEUL — aucune diapositive n'est chargee. C'est trait
   pour trait le fond que rend deja au bureau une fiche sans hero, et Lord Frites
   l'a valide comme tel le 2026-08-13. */
.hero-veil {
    position: absolute;
    inset: 0;
    background: linear-gradient(150deg,
        color-mix(in srgb, var(--product-color, #6b6b6b) 6%,  var(--veil-dark)) 0%,
        color-mix(in srgb, var(--product-color, #6b6b6b) 46%, var(--veil-dark)) 100%);
    opacity: var(--veil-strength);
    transition: opacity 0.7s ease;
}

/* ─── Le texte ────────────────────────────────
   Blanc pur pour les titres, blanc casse (#e8e5de) pour le corps : sur de
   grandes surfaces, un blanc pur fatigue. */
.product-layout--modern .product-title {
    color: #ffffff;
}
.product-layout--modern .product-tagline {
    color: #cfcbc2;
}
/* Le conteneur AUTANT que ses paragraphes : `.product-description-body` porte
   son propre `--ff-text-muted`, dont heriterait tout ce que le body editor
   n'enveloppe pas dans un `<p>`. */
.product-layout--modern .product-description-body,
.product-layout--modern .product-description p,
.product-layout--modern .product-description li,
.product-layout--modern .product-features li {
    color: #e8e5de;
}
/* `b` autant que `strong` : le body editor produit du `<b>`, et product.css ne
   colore que `strong`. Sans cette ligne, un passage en gras retombe sur
   `--ff-text` — sombre sur sombre. */
.product-layout--modern .product-description-body strong,
.product-layout--modern .product-description-body b {
    color: #ffffff;
}
.product-layout--modern .product-description h2,
.product-layout--modern .product-description h3,
.product-layout--modern .product-features h2,
.product-layout--modern .product-videos h2 {
    color: #ffffff;
}
.product-layout--modern .product-description a {
    color: color-mix(in srgb, var(--product-color, #6b6b6b) 45%, #ffffff);
}

/* Citations et encarts posent un fond a 4-6 % d'opacite ET un texte en
   `--ff-text` : trois fiches en contiennent (Scrapyard, Quasar, Hind), elles y
   seraient sombres sur sombre. Ici l'encart se lit comme un renfoncement.
   Le filet dore reste INTACT — c'est la signature visuelle d'une citation, et un
   `border-color` global l'aurait efface pour reparer un probleme qui n'est pas
   la sienne. */
.product-layout--modern .product-description-body blockquote,
.product-layout--modern .product-description-body .callout {
    background: rgba(255, 255, 255, 0.06);
    color: #e8e5de;
}

/* ─── Barre d'infos ───────────────────────────
   ⚠️ ILOT SOMBRE, EN PERMANENCE — tranche par Lord Frites le 2026-08-14.
   `.version-chip` et `.info-btn` lisent `--ff-bg` et `--ff-text`, donc ils
   SUIVAIENT le theme du visiteur : pastilles blanches en clair, sombres en
   sombre, sur une barre qui, elle, ne change jamais. Lord Frites les prefere
   sombres — c'est plus coherent avec une page sombre par nature — et surtout
   elles ne doivent pas dependre d'un reglage qui ne s'applique pas ici.

   Les tokens sont redeclares sur la BARRE et non sur le `<body>` : au niveau du
   body ils repeindraient aussi les popups, qui sont volontairement CLAIRS.
   Meme technique que les ilots clairs de l'en-tete, a l'echelle d'un bloc.

   `.compat-status` garde sa couleur d'etat — vert, bleu, or ou rouge : c'est le
   signal utile, et le mot seul ne le porte pas. */
.product-layout--modern .product-info-bar {
    --ff-bg:         #1c1c20;
    --ff-bg-warm:    #18181b;
    --ff-text:       #f0ede5;
    --ff-text-muted: #9a978d;
    --ff-border:     #3a3a40;
}
.product-layout--modern .info-date {
    color: #b9b5ac;
}
.product-layout--modern .compat-badge {
    color: #d3cfc6;
}

/* ⚠️ LE SURVOL SUIT LA PASTILLE, ET LA PASTILLE EST SOMBRE.
   Ce survol a ete blanc casse tant que les pastilles l'etaient. Depuis qu'elles
   sont un ilot sombre (cf. ci-dessus), ce fond quasi blanc posait du texte clair
   sur du blanc : le libelle disparaissait sous le curseur.
   Constate par Lord Frites le 2026-08-14, apres l'avoir deja ete le 2026-08-12
   dans l'autre sens — c'est la troisieme fois que ce survol se fait rattraper
   par la couleur de ce qu'il recouvre. Il est desormais derive de la MEME valeur
   que la pastille (`#1c1c20`), donc les deux ne peuvent plus divergier.

   ⚠️ `:not(.info-btn--videos)` : le bouton Videos est rouge a fond plein, un
   survol pris ailleurs l'ecraserait. Constate le 2026-08-13.
   Un `:not()` et non un reordonnancement : les deux regles ont la MEME
   specificite, seule leur position dans le fichier les separe. Une intention
   declaree ne peut pas etre cassee par un futur deplacement de bloc. */
.product-layout--modern .version-chip:hover,
.product-layout--modern .info-btn:not(.info-btn--videos):hover {
    background: color-mix(in srgb, var(--ff-gold) 22%, #1c1c20);
    border-color: var(--ff-gold);
}

/* ─── Le bloc « Requires » ────────────────────
   Tout le bloc herite de couleurs pensees pour un fond clair : le libelle et
   l'icone en `--ff-text-muted`, le NOM de la dependance en `--ff-text` — donc
   illisible hors survol. Signale par Lord Frites le 2026-08-12.
   Le nom est le plus clair des trois : c'est lui qu'on doit pouvoir lire, et
   c'est un lien. Le soulignement passe en blanc translucide pour qu'il se lise
   comme cliquable avant meme le survol, qui garde son or. */
.product-layout--modern .product-requires,
.product-layout--modern .product-requires-label,
.product-layout--modern .product-requires-icon,
.product-layout--modern .product-requires-sep {
    color: #b9b5ac;
}
.product-layout--modern .product-requires-item {
    color: #f0ede6;
    border-bottom-color: rgba(255, 255, 255, 0.28);
}
.product-layout--modern .product-requires-item:hover {
    color: var(--ff-gold);
    border-bottom-color: var(--ff-gold);
}

/* ─── Le prix ─────────────────────────────────
   Le montant porte `--accent`, pose en ligne : bleu #0F76EF pour un payware,
   vert #247657 pour un freeware. Les deux sont trop sombres sur du sombre.
   `color-mix` vers le blanc les eclaircit SANS toucher a la teinte — le bleu
   reste bleu, le vert reste vert, et une seule regle couvre les deux. */
.product-layout--modern .product-price {
    color: #e8e5de;
}
.product-layout--modern .product-price strong {
    color: color-mix(in srgb, var(--accent) 50%, #ffffff);
}

/* ─── La mosaique ─────────────────────────────
   Le lisere clair venait du FOND (`--ff-bg-warm`, #faf9f6) qui affleure sur les
   bords, et non d'une bordure — celle de base est transparente. Sur un fond
   sombre, cet ourlet presque blanc detachait chaque vignette comme un
   timbre-poste. Un gris sombre les repose sur la page.
   Le survol garde son or : c'est l'affordance, pas de la decoration. */
.product-layout--modern .gallery-mosaic-item {
    background: #1b1e23;
    border-color: #383d45;
    box-shadow: none;
}

/* Le lien « 32 photos — view all » vit sous la galerie, donc a meme le fond et
   non sur du verre : l'or y perd trop de contraste. Blanc, avec l'ombre portee
   du titre pour tenir sur une image claire comme sur une image sombre. L'or
   reste au survol, ou il redevient un signal et non une couleur de repos. */
.product-layout--modern .product-gallery .read-more-text {
    color: #ffffff;
    text-shadow: 0 1px 3px rgba(0, 0, 0, 0.55);
}
.product-layout--modern .product-gallery .view-all-btn:hover .read-more-text {
    color: var(--ff-gold);
}
/* Le filet d'origine est un DEGRADE qui s'efface vers l'exterieur, inverse sur
   le dernier. Un aplat blanc aurait supprime ce fondu : on garde la meme forme,
   seule la couleur change.
   Les DEUX filets, celui de la galerie et celui du « read more » de la
   description : `--ff-border` (#e5e2dc) est presque blanc, et deux traits de
   clarte differente a quelques centaines de pixels l'un de l'autre se
   remarquent. */
.product-layout--modern .read-more-line {
    background: linear-gradient(to right, transparent, rgba(255, 255, 255, 0.34));
}
.product-layout--modern .read-more-line:last-child {
    background: linear-gradient(to left, transparent, rgba(255, 255, 255, 0.34));
}

/* ─── L'en-tete ───────────────────────────────
   Dessine pour un fond clair, il se retrouve sur la scene. Il a deja une
   transition sur `backdrop-filter`, donc il etait prevu pour.

   ⚠️ NE PAS ELARGIR `.header-inner` ICI.
   Essaye le 2026-08-12 pour aligner le logo sur le titre : refuse par Lord
   Frites, et il a raison. Les icones du menu doivent rester exactement au meme
   endroit d'une page a l'autre — on ne doit jamais avoir a chercher un bouton de
   navigation qui s'est deplace. L'alignement du logo avec le titre est un detail
   esthetique ; la stabilite de la navigation n'en est pas un.

   ⚠️ `topbar_menu.js` choisit le logo blanc ou sombre a partir de la classe
   `has-dark-header`. Le jour ou l'une des deux conditions change, l'autre doit
   suivre — sinon on obtient un logo sombre sur un en-tete sombre. */
.product-layout--modern .header {
    background: rgba(18, 20, 24, 0.55);
    backdrop-filter: blur(14px);
    -webkit-backdrop-filter: blur(14px);
    border-bottom-color: rgba(255, 255, 255, 0.1);
}
.product-layout--modern .header-social svg,
.product-layout--modern .header-account svg {
    fill: #ffffff;
}
/* Le compte connecte garde son or : information d'etat, pas decor. */
.product-layout--modern .header-account.is-signed-in svg {
    fill: var(--ff-gold);
}
.product-layout--modern .header-hamburger span {
    background: #ffffff;
}
.product-layout--modern .header-separator {
    background: rgba(255, 255, 255, 0.22);
}
.product-layout--modern .header-social:hover,
.product-layout--modern .header-hamburger:hover {
    background: rgba(255, 255, 255, 0.1);
}

/* Le nom recopie dans l'en-tete au defilement — en petit ecran seulement, cf. la
   zone bureau. Ses deux lignes heritent de `--ff-text` et `--ff-text-muted` :
   sans ceci, un titre invisible apparaitrait au defilement. */
.product-layout--modern .header-page-title-main {
    color: #ffffff;
}
.product-layout--modern .header-page-title-sub {
    color: #cfcbc2;
}

/* `fries.png` est monochrome et sombre : sur un fond sombre il disparait.
   `invert(1)` l'eclaircit, exactement comme sur la home et la page catalogue —
   meme recette, aucun second fichier a maintenir.
   En CSS et non dans la definition de la frite : la teinte depend de la
   presentation, et un style en ligne ne saurait pas s'adapter. */
.product-layout--modern .hidden-fry {
    filter: invert(1);
}


/* ═══════════════════════════════════════════════════════════
   2. PETIT ECRAN — ce qui ne peut pas etre commun

   Trois blocs seulement, et tous pour la meme raison : leur fond CLAIR est
   ecrit dans product.css pour la presentation empilee, qui n'existe QU'ICI. Au
   bureau la barre d'infos est une bande fixe, les onglets n'existent pas, et la
   bande de videos est partie dans un popup.
   ═══════════════════════════════════════════════════════════ */

@media (max-width: 768px) {

    /* Le PHP emet huit vignettes, mais ici la mosaique s'empile : huit forcent a
       defiler longuement avant d'atteindre la suite. On en masque trois.
       Les images masquees portent `loading="lazy"` : un navigateur ne telecharge
       pas une image en `display: none` hors du viewport. */
    .gallery-mosaic-item:nth-child(n+6) {
        display: none;
    }

    /* ⚠️ ET LA CASE TRAILER NOMMEMENT, sans compter sur le selecteur ci-dessus.
       Elle est emise en DERNIER pour tomber au-dela du cinquieme enfant et
       disparaitre avec les autres — ce qui suppose au moins cinq photos. Les
       quatre fiches qui ont un trailer en ont vingt-deux au minimum, mais rien
       ne le garantit de la prochaine ; avec trois photos, la case reapparait.
       Et elle ouvrirait un lecteur dont AUCUN style n'existe en petit ecran :
       l'iframe s'y ecraserait a sa hauteur par defaut. */
    .mosaic-trailer {
        display: none;
    }

    /* Une carte, et non la bande fixe du bureau : l'empilement est conserve tel
       quel, seules les couleurs changent. */
    .product-layout--modern .product-info-bar {
        background: rgba(12, 14, 17, 0.55);
        border-color: rgba(255, 255, 255, 0.1);
        box-shadow: none;
        backdrop-filter: blur(14px);
        -webkit-backdrop-filter: blur(14px);
    }

    /* Les onglets Key features / Videos collent sous l'en-tete : leur fond doit
       rester franchement opaque, sinon le contenu qui defile dessous se lit au
       travers. */
    .product-layout--modern .product-tabs {
        background: rgba(20, 22, 26, 0.92);
    }
    .product-layout--modern .product-tab {
        border-color: rgba(255, 255, 255, 0.16);
        color: #b9b5ac;
    }
    .product-layout--modern .product-tab:hover:not(.active) {
        border-color: rgba(255, 255, 255, 0.34);
    }

    /* La bande de videos reste dans la page en petit ecran — c'est le bouton
       rouge de la barre meta qui n'existe qu'au bureau. Ses liens sont ecrits
       pour un fond clair : texte en `--ff-text`, donc invisible, et survol en
       `--ff-bg-warm`, donc blanc sur blanc. */
    .product-layout--modern .video-link {
        color: #e8e5de;
    }
    .product-layout--modern .video-link:hover {
        background: rgba(255, 255, 255, 0.08);
        border-color: rgba(255, 255, 255, 0.16);
    }

    /* ─── Les badges de compatibilite ─────────────
       `.compat-status` — le mot « Fully compatible », « Partly compatible »,
       « Not compatible » — est masque ici pour tenir dans la largeur. La couleur
       devient donc le SEUL signal, et un fond a 5 % d'opacite ne le porte pas.

       ⚠️ DEUX COULEURS ET DEUX SEULEMENT, tranche par Lord Frites le
       2026-08-13 : vert = ca marche, rouge = non. Le bleu du FS2024 et l'or du
       « partly » ne veulent rien dire pour qui ne connait pas le code — « les
       gens vont se demander a quoi ca correspond, et ils ne vont pas
       comprendre ». Au bureau ils RESTENT, et c'est deliberé : le mot complet
       est affiche a cote, la couleur n'a donc pas a porter le sens toute seule
       et peut se permettre d'etre nuancee.

       Le vert est la valeur par defaut et le rouge la seule exception : a
       specificite egale c'est l'ordre du fichier qui tranche, donc `.compat-nc`
       vient apres. Deux declarations couvrent les quatre degres, et un FS2026
       n'en demandera aucune. */
    .compat-badge { --compat-tint: var(--ff-green); }
    .compat-nc    { --compat-tint: var(--ff-red); }

    /* ⚠️ Le blanc du texte n'est pas cosmetique : `--ff-green` (#247657) est
       trop sombre pour du sombre. `color-mix` vers le blanc l'eclaircit SANS
       toucher a la teinte, exactement la recette deja utilisee pour le prix.
       Trois chiffres a bouger si le signal reste trop faible, ou devient trop
       fort.

       `display: block` et non le `flex` d'origine : le libelle est un simple
       nœud de texte, sans element a lui. Dans un conteneur flex il devient un
       element anonyme, et la propagation d'un `text-decoration` jusque-la n'est
       pas quelque chose sur quoi je parierais. En bloc, la barre du rouge
       s'applique sans discussion. Le `flex` ne servait qu'a espacer le libelle
       du mot d'etat — lequel est masque ici. */
    .product-layout--modern .compat-badge {
        display: block;
        background: color-mix(in srgb, var(--compat-tint) 15%, transparent);
        border-color: color-mix(in srgb, var(--compat-tint) 50%, transparent);
        color: color-mix(in srgb, var(--compat-tint) 50%, #ffffff);
    }

    /* Le texte barre dit « nope » sans un mot — idee de Lord Frites. */
    .product-layout--modern .compat-nc {
        text-decoration: line-through;
    }

    /* « Partly compatible » reste VERT : l'add-on fonctionne, et le dire en
       rouge serait faux. Son contour passe en tirets — meme vocabulaire de
       trait que la barre du rouge, et aucune couleur de plus a decoder. Une
       ligne a retirer si c'est un signal de trop. */
    .product-layout--modern .compat-partial {
        border-style: dashed;
    }
}


/* ═══════════════════════════════════════════════════════════
   3. BUREAU — LA MISE EN PAGE

   Sous 769 px, aucune de ces regles ne s'applique : la fiche garde son
   empilement d'origine. Decision de Lord Frites, et plus juste qu'une
   adaptation — un diaporama plein cadre derriere du verre depoli, sur un ecran
   de telephone, ne laisse de place ni a l'image ni au texte. Le JS ne demarre
   pas non plus sous ce seuil, donc pas une image n'est telechargee.
   769 px et non 860 : point de rupture dominant du site (12 usages).
   ═══════════════════════════════════════════════════════════ */

@media (min-width: 769px) {

    /* ⚠️ AUCUN titre recopie dans l'en-tete AU BUREAU : la barre de titre est
       fixe juste dessous, on lirait le nom deux fois a quelques pixels d'ecart.

       La regle vit ICI, et non dans un test cote JS comme jusqu'au 2026-08-13 :
       c'est la LARGEUR qui commande, et la largeur est du ressort du CSS.
       En petit ecran la barre defile avec la page, l'en-tete reprend donc son
       role — exactement comme sur toutes les autres pages du site. */
    .product-layout--modern .header-page-title {
        display: none;
    }

    /* ─────────────────────────────────────────────
       SCENE — le diaporama plein cadre
       ───────────────────────────────────────────── */

    .hero-slide {
        display: block;
        position: absolute;
        inset: 0;
        width: 100%;
        height: 100%;
        object-fit: cover;
        /* `center` et non un point d'interet par image : le sujet se deplace
           d'une photo a l'autre, aucun reglage unique ne conviendrait. */
        object-position: center;
        opacity: 0;
        transition: opacity 1.4s ease-in-out;
    }
    .hero-slide.is-active {
        opacity: 1;
    }

    /* ─────────────────────────────────────────────
       RYTHME DE LA PAGE

       ⚠️ REGLE D'OR, retablie le 2026-08-12 : les screenshots doivent etre
       accessibles SANS DEFILER. La presentation legacy la respectait, la premiere
       maquette moderne s'en etait tres loin ecartee — elle ouvrait sur un ecran
       entierement vide.

       D'ou deux consequences : plus d'ecran vide, et la GALERIE monte a cote de
       la description. Ce n'est pas un arbitrage esthetique, c'est la contrainte
       qui commande la grille.

       Le diaporama n'a pas besoin d'un ecran pour lui seul : « il est appreciable
       aussi, meme s'il est juste suggere en fond derriere les blocs ».
       ───────────────────────────────────────────── */

    .product-layout--modern .page-wrapper {
        /* Place pour l'en-tete fixe plus les deux barres fixes. */
        padding-top: calc(var(--ff-header-height) + var(--bar-title-h)
                          + var(--bar-meta-h) + var(--bar-gap));
        padding-bottom: 40px;
    }

    .product-layout--modern .page-content {
        max-width: var(--band-max);
        padding-inline: var(--band-pad);

        /* Grille EXPLICITE et non un placement automatique : dans le DOM la
           galerie precede les features et les videos. Nommer les lignes est ce
           qui permet de reordonner sans toucher au HTML.

           Description un peu plus etroite que la galerie : 0.9fr donne ~665 px,
           soit ~81 caracteres — dans la zone lisible — et laisse le reste aux
           vignettes, qui sont ce qu'on vient voir. */
        display: grid;
        grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr);
        column-gap: 26px;
        row-gap: 26px;
        align-items: start;
    }

    /* ─── Rangee 1 : About | Galerie ──────────────
       La galerie monte ici au nom de la regle d'or. Effet de bord heureux : le
       dilemme du « Read more » se dissout. Une description tronquee a cote d'une
       galerie haute n'est plus un demi-bloc vide a remplir — c'est l'accroche, et
       la suite se demande. Le bouton garde donc sa raison d'etre. */

    .product-layout--modern .product-description {
        grid-column: 1;
        grid-row: 1;
    }

    /* `display: contents` dissout le conteneur pour que ses deux enfants
       deviennent des elements de grille a part entiere — sans cela features et
       videos resteraient solidaires dans une seule cellule. */
    .product-layout--modern .product-bottom {
        display: contents;
    }

    /* ─── Rangee 2 : Key features, pleine largeur ─
       DEUX sous-colonnes et non trois : les features font 70 caracteres de
       moyenne, 158 au maximum. Sur trois colonnes de ~490 px elles passeraient
       presque toutes a deux lignes ; sur deux colonnes de ~740 px la moyenne
       tient sur une ligne. 24 features donnent alors 12 rangees. */
    .product-layout--modern .product-features {
        grid-column: 1 / -1;
        grid-row: 2;
    }
    .product-layout--modern .product-features ul {
        columns: 2;
        column-gap: 40px;
    }
    .product-layout--modern .product-features li {
        break-inside: avoid;
    }

    /* ─── Bande 2 : la galerie, sans verre ───────
       C'est elle qui donne le rythme. Si toutes les bandes sont du verre, on a
       seulement remplace six rectangles etroits par quatre plus larges. Il faut
       au moins un moment ou l'image parle seule. */
    /* Trois rangees au lieu de deux : la grande vignette occupe la colonne 1 sur
       deux rangees, quatre suivent en colonnes 2-3, et trois paysages completent
       la rangee 3 — huit visibles d'un coup d'oeil. Le placement automatique
       suffit, l'ordre du DOM tombe juste.
       140 px de haut : a ~250 px de large, c'est le 16:9 de tes captures. */
    .product-layout--modern .gallery-mosaic {
        grid-template-rows: 140px 140px 140px;
    }

    /* ─── La case trailer ─────────────────────────
       Placee EXPLICITEMENT en rangee 1, colonne 2 — juste a droite du grand
       screenshot, la ou l'oeil arrive apres lui. Elle est emise en DERNIER dans
       le DOM pour que le mobile ne la voie pas ; c'est cette regle, et elle
       seule, qui lui donne sa position visuelle.

       Les petites cases font ~250x140, soit du 16:9 exact — le ratio d'une
       vignette YouTube. La grande case, presque carree (1,05), aurait rogne la
       video ou l'aurait cernee de bandes. */
    .product-layout--modern .mosaic-trailer {
        grid-area: 1 / 2;
        padding: 0;
        cursor: pointer;
        overflow: hidden;
    }
    .product-layout--modern .mosaic-trailer img {
        width: 100%;
        height: 100%;
        object-fit: cover;
        display: block;
    }

    /* Le triangle. Blanc avec une ombre portee, comme le nom de l'appareil : une
       vignette YouTube peut etre claire ou sombre, l'ombre le rend lisible sur
       les deux. Il grandit au survol — la seule animation de la mosaique, parce
       que c'est la seule case ou il se passe autre chose qu'un agrandissement. */
    .product-layout--modern .mosaic-play {
        position: absolute;
        inset: 0;
        display: grid;
        place-items: center;
        color: #ffffff;
        filter: drop-shadow(0 1px 3px rgba(0, 0, 0, 0.6))
                drop-shadow(0 2px 16px rgba(0, 0, 0, 0.5));
        transition: transform 0.25s ease;
        pointer-events: none;
    }
    .product-layout--modern .mosaic-trailer:hover .mosaic-play {
        transform: scale(1.12);
    }

    /* Pas de libelle sur la case : les vignettes de Lord Frites sont composees
       AVEC leur titre en grand. Un bandeau par-dessus ferait doublon et
       recouvrirait le bas de son artwork. Le triangle dit « video », le titre est
       dans l'image, et l'en-tete du popup le redonne.
       Retire le 2026-08-13 apres l'avoir vu a l'ecran. */

    /* ─── Le bouton Videos et son popup ───────────
       La bande de videos quitte le defilement : elle etait le pave que Lord
       Frites rejetait. Tout part dans un popup, atteint par un bouton de la
       barre meta — la ou vivent deja Resources et Related. */
    /* Le rouge de la charte (`--ff-red`, #C0392B) legerement assombri vers le
       gris du voile, et non le #FF0000 de YouTube : brique plutot que flashy, et
       aucune couleur a inventer. Le bouton se distingue de ses voisins blancs
       sans crier plus fort qu'eux.
       Le triangle est en `currentColor` dans le SVG, il suit donc le blanc. */
    .product-layout--modern .info-btn--videos {
        display: flex;
        background: color-mix(in srgb, var(--ff-red) 84%, var(--veil-dark));
        border-color: color-mix(in srgb, var(--ff-red) 92%, var(--veil-dark));
        color: #ffffff;
    }
    /* Sans cette regle, le survol partage repeindrait le bouton en or translucide
       et effacerait le rouge. */
    .product-layout--modern .info-btn--videos:hover {
        background: var(--ff-red);
        border-color: var(--ff-gold);
        color: #ffffff;
    }
    .product-layout--modern .product-videos {
        display: none;
    }

    /* ⚠️ Le panneau ne defile plus LUI-MEME : seul son corps le fait.
       `.popup-panel` porte `max-height: 80vh` + `overflow-y: auto`, donc l'en-tete
       partait avec le defilement — et avec lui le bouton de fermeture, sur un
       popup de 14 videos. Le motif flex en colonne est celui qu'utilise deja
       `.admin-popup` : en-tete et onglets figes, corps seul scrollable. */
    .popup-panel.popup-videos {
        width: min(1020px, 92vw);
        max-width: none;
        max-height: 84vh;
        display: flex;
        flex-direction: column;
        overflow: hidden;
    }
    .popup-videos .popup-header,
    .popup-videos .videos-tabs {
        flex-shrink: 0;
    }
    .popup-videos .popup-body {
        flex: 1 1 auto;
        overflow-y: auto;
        min-height: 0;
    }

    /* Onglets : le langage de ceux de `/resources` — souligne dore, majuscules,
       teinte discrete au repos. Rien a inventer, et la coherence est gratuite. */
    .videos-tabs {
        display: flex;
        gap: 0;
        padding: 0 24px;
        border-bottom: 2px solid var(--ff-border);
        /* ⚠️ LES DEUX AXES, EXPLICITEMENT.
           En CSS, des qu'un axe cesse d'etre `visible`, l'autre passe de `visible`
           a `auto` tout seul. `overflow-x: auto` seul creait donc un ascenseur
           VERTICAL que personne n'avait demande, declenche par le
           `margin-bottom: -2px` des onglets qui depasse de deux pixels.
           Constate par Lord Frites le 2026-08-13. */
        overflow-x: auto;
        overflow-y: hidden;
    }
    .videos-tab {
        display: flex;
        align-items: center;
        gap: 7px;
        padding: 11px 18px;
        background: transparent;
        border: none;
        border-bottom: 3px solid transparent;
        margin-bottom: -2px;
        cursor: pointer;
        font-family: 'Futura', 'Trebuchet MS', sans-serif;
        font-size: 12px;
        text-transform: uppercase;
        letter-spacing: 0.8px;
        white-space: nowrap;
        color: var(--ff-text-muted);
        transition: all var(--ff-transition-fast);
    }
    .videos-tab.active {
        border-bottom-color: var(--ff-gold);
        color: var(--ff-gold);
        font-weight: 700;
    }
    .videos-tab:hover:not(.active) {
        color: var(--ff-text);
    }
    .videos-tab-count {
        font-size: 10px;
        font-weight: 700;
        padding: 1px 6px;
        border-radius: 999px;
        background: var(--ff-bg-warm);
        color: var(--ff-text-muted);
    }
    .videos-tab.active .videos-tab-count {
        background: color-mix(in srgb, var(--ff-gold) 14%, #ffffff);
        color: var(--ff-gold);
    }

    .videos-panel {
        display: none;
    }
    .videos-panel.active {
        display: block;
    }

    /* 150 px de minimum et non 180 : Lord Frites les voulait plus petites, et
       cinq a six par rangee se parcourent mieux que trois. */
    .videos-grid {
        display: grid;
        grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
        gap: 12px;
    }

    /* ⚠️ Carte CLAIRE et non sombre. Le panneau de popup est en `--ff-bg`, donc
       blanc, meme sur une fiche moderne. Un fond sombre y faisait une ile, et le
       titre en `--ff-text` devenait sombre sur sombre — la « bande noire » que
       Lord Frites a vue sous chaque image le 2026-08-13. */
    .videos-card {
        position: relative;
        display: block;
        padding: 0;
        border: 1px solid var(--ff-border);
        border-radius: var(--ff-radius-md);
        background: var(--ff-bg);
        overflow: hidden;
        cursor: pointer;
        text-align: left;
        transition: border-color var(--ff-transition-fast), transform 0.2s ease,
                    box-shadow var(--ff-transition-fast);
    }
    .videos-card:hover {
        border-color: var(--ff-gold);
        transform: translateY(-2px);
        box-shadow: 0 6px 18px rgba(0, 0, 0, 0.12);
    }
    .videos-card img {
        display: block;
        width: 100%;
        aspect-ratio: 16 / 9;
        object-fit: cover;
    }
    .videos-card-play {
        position: absolute;
        top: 0;
        left: 0;
        right: 0;
        aspect-ratio: 16 / 9;
        display: grid;
        place-items: center;
        color: #ffffff;
        filter: drop-shadow(0 1px 3px rgba(0, 0, 0, 0.6));
        pointer-events: none;
        transition: transform 0.2s ease;
    }
    .videos-card:hover .videos-card-play {
        transform: scale(1.14);
    }
    .videos-card-title {
        display: block;
        padding: 7px 9px 8px;
        font-size: 11px;
        font-weight: 600;
        color: var(--ff-text);
        line-height: 1.35;
    }

    /* Repli pour une URL dont on ne sait pas lire l'identifiant : un lien nu
       plutot qu'une vignette cassee. */
    .videos-card--plain {
        padding: 10px 12px;
        color: var(--ff-text);
        text-decoration: none;
        font-size: 12px;
        font-weight: 600;
    }

    /* Retour vers la liste. Discret : c'est une commande de navigation, pas une
       action principale. Meme famille visuelle que `.info-btn`. */
    .popup-back {
        display: inline-flex;
        align-items: center;
        gap: 6px;
        padding: 5px 12px;
        margin-right: 14px;
        border: 1px solid var(--ff-border);
        border-radius: var(--ff-radius-md);
        background: var(--ff-bg);
        color: var(--ff-text-muted);
        font-size: 11px;
        font-weight: 600;
        text-transform: uppercase;
        letter-spacing: 0.6px;
        cursor: pointer;
        transition: all var(--ff-transition-fast);
    }
    .popup-back:hover {
        border-color: var(--ff-gold);
        color: var(--ff-gold);
    }
    /* `[hidden]` seul ne suffit pas face au `display: inline-flex` ci-dessus :
       une declaration d'affichage explicite l'emporte sur le style par defaut de
       l'attribut. */
    .popup-back[hidden] {
        display: none;
    }

    /* ─── Le popup de lecture ─────────────────────
       Large, parce que c'est tout l'objet du clic : on quitte une case de 250 px
       pour voir la video en grand. */
    .popup-panel.popup-video {
        width: min(1100px, 92vw);
        max-width: none;
    }
    .video-frame {
        position: relative;
        width: 100%;
        /* `aspect-ratio` plutot que le vieux calage par `padding-bottom` : le
           navigateur reserve la place avant que l'iframe existe, donc aucun saut
           de mise en page a l'ouverture. */
        aspect-ratio: 16 / 9;
        background: #000000;
        border-radius: var(--ff-radius-md);
        overflow: hidden;
    }
    .video-frame iframe {
        position: absolute;
        inset: 0;
        width: 100%;
        height: 100%;
        border: 0;
    }

    .product-layout--modern .product-gallery {
        grid-column: 2;
        grid-row: 1;
        background: none;
        border: none;
        backdrop-filter: none;
        -webkit-backdrop-filter: none;
        padding: 0;
    }

    /* La bande de videos n'existe plus en presentation moderne : tout est parti
       dans le popup, atteint par le bouton rouge de la barre meta. Son placement
       en grille, son verre depoli et la couleur de son titre ont donc ete
       SUPPRIMES le 2026-08-13, et non seulement neutralises.

       Ils portaient un `display: grid` qui, ecrit plus bas dans le fichier que
       mon `display: none` et de meme specificite, le battait — la bande restait
       affichee. Garder des regles mortes pour se battre contre une autre regle est
       exactement la situation a ne pas laisser derriere soi. La seule declaration
       qui subsiste est celle qui masque, ligne ~315. */

    /* ─── Verre depoli ───────────────────────────
       Sur les bandes de lecture seulement. La galerie en est exclue, les barres
       fixes ont leur propre traitement. */
    .product-layout--modern .product-description,
    .product-layout--modern .product-features {
        background: var(--glass-bg);
        border: 1px solid var(--glass-border);
        border-radius: var(--ff-radius-lg);
        backdrop-filter: blur(var(--glass-blur)) saturate(1.1);
        -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(1.1);
        padding: 26px 30px;
        /* Repli si `backdrop-filter` n'est pas honore : le fond semi-opaque
           suffit seul a la lisibilite. C'est exactement pourquoi elle ne repose
           pas sur le flou. */
        color: #e8e5de;
    }

    /* ─────────────────────────────────────────────
       LES DEUX BARRES FIXES DU HAUT — identite, achat, reference

       En haut, sous l'en-tete. Sur tout le site les titres sont en haut : les
       poser en bas cassait la coherence, et c'est en haut que les yeux vont.

       `fixed` et non `sticky`, pour deux raisons. La barre doit etre visible des
       le chargement, sans avoir a defiler jusqu'a elle — c'est exactement ce que
       fait `fixed`. Et une position `sticky` sur un element de GRILLE ne colle
       qu'a l'interieur de sa propre rangee : le titre decrocherait des la bande
       suivante.

       Elles resolvent trois choses d'un coup : l'action d'achat ne defile plus,
       le titre reste visible, et le bug de scroll du mode cinema disparait — il
       n'y a plus rien a faire defiler pour voir le titre.

       `left/right: 0` et non `100vw` : la barre d'ascenseur n'est pas comptee,
       donc aucun debordement horizontal.

       Le rembourrage lateral centre le contenu sur `--band-max` sans conteneur
       interieur — il n'y en a pas dans le HTML partage, et en ajouter un serait
       modifier le gabarit.
       ───────────────────────────────────────────── */

    .product-layout--modern .product-hero,
    .product-layout--modern .product-info-bar {
        position: fixed;
        left: 0;
        right: 0;
        z-index: 20;
        margin: 0;
        border-radius: 0;
        padding-inline: max(var(--band-pad), calc((100% - var(--band-max)) / 2 + var(--band-pad)));
        backdrop-filter: blur(20px) saturate(1.15);
        -webkit-backdrop-filter: blur(20px) saturate(1.15);
    }

    .product-layout--modern .product-hero {
        top: var(--ff-header-height);
        height: var(--bar-title-h);
        display: flex;
        align-items: center;
        justify-content: space-between;
        /* `nowrap` explicite : la regle legacy est en `wrap`, et
           `.product-requires` y porte `flex-basis: 100%` pour passer seul sur sa
           ligne. Dans une barre a hauteur FIXE, ce retour a la ligne deborderait
           sur la barre meta. Le `flex: 0 1 auto` pose plus bas neutralise la
           base, celui-ci interdit le retour a la ligne quoi qu'il arrive. */
        flex-wrap: nowrap;
        gap: 30px;
        padding-block: 12px;
        background: rgba(16, 18, 22, 0.72);
    }

    /* Rangee basse, plus discrete : version, date, compatibilite, acces aux
       popups. C'est de la reference, pas de l'achat — d'ou un contraste moindre. */
    .product-layout--modern .product-info-bar {
        top: calc(var(--ff-header-height) + var(--bar-title-h));
        height: var(--bar-meta-h);
        background: rgba(12, 14, 17, 0.82);
        /* La regle legacy porte un `border: 1px solid` ET un `box-shadow` de
           carte. Surcharger seulement `border-bottom` laissait les trois autres
           cotes et l'ombre visibles sur une barre pleine largeur — la bordure que
           Lord Frites a vue le 2026-08-12. */
        border: none;
        box-shadow: none;
        border-bottom: 1px solid rgba(255, 255, 255, 0.07);
        padding-block: 0;
    }

    /* La hauteur de la barre est FIXE : le titre et le sous-titre y sont cales
       au pixel, marges comprises. Leurs couleurs, elles, sont communes a toutes
       les largeurs et vivent dans la premiere zone du fichier. */
    .product-layout--modern .product-title {
        margin: 0;
        line-height: 1.05;
    }
    .product-layout--modern .product-tagline {
        margin: 2px 0 0;
    }
    .product-layout--modern .product-hero-text {
        min-width: 0;
    }
    /* ─── Le bloc « Requires » dans la barre ──────
       `.product-requires` est un FRERE de `.product-cta`, pas son enfant — voulu,
       parce que le CTA ne s'affiche que pour un produit disponible et vendu
       quelque part, alors qu'une dependance doit se lire dans tous les cas.

       Dans une barre a hauteur FIXE, il faut donc trois precautions :
       l'ordonner avant le bouton (on lit la condition avant d'agir), le laisser
       se comprimer plutot que deborder sur la barre meta, et le tenir sur une
       ligne.

       Cas realiste : une ou deux dependances, et la regle produit interdit toute
       dependance sur un payware — seul du freeware peut en porter. Si un jour
       c'est serre malgre tout, la place suivante est la barre meta, qui a de la
       largeur libre. */
    .product-layout--modern .product-hero-text {
        order: 1;
        flex: 1 1 auto;
    }
    .product-layout--modern .product-requires {
        order: 2;
        flex: 0 1 auto;
        min-width: 0;
        margin: 0;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
    }
    /* La regle legacy est en `flex-direction: column` : bouton au-dessus, prix
       en dessous. Dans une barre de hauteur fixe, cela remontait le bouton et
       poussait le prix hors du cadre. En rangee, les deux sont centres. */
    .product-layout--modern .product-cta {
        order: 3;
        flex-shrink: 0;
        display: flex;
        flex-direction: row;
        align-items: center;
        gap: 18px;
    }
    /* Dans une barre a hauteur fixe, un prix qui se replierait sur deux lignes
       deborderait. Sa couleur est commune a toutes les largeurs. */
    .product-layout--modern .product-price {
        white-space: nowrap;
    }

    /* ─────────────────────────────────────────────
       RETOUR AU CATALOGUE — l'onglet du bord gauche

       Cale sur le bord et VERTICALEMENT CENTRE, non pose a une hauteur fixe :
       il est en `fixed`, donc il ne defile pas, et le centre est le seul point
       qui ne heurte ni les deux barres du haut ni le bouton popcorn en bas a
       droite, quelle que soit la hauteur de la fenetre.

       ~32 px de large : il tient dans les 40 px de `--band-pad`, la gouttiere
       qui separe deja le contenu du bord. Il ne recouvre donc rien, meme sur une
       fenetre etroite ou la bande de contenu touche presque les bords.

       Le CHEVRON n'est pas pivote — il pointe a gauche, la ou l'on va. Seul le
       libelle passe en ecriture verticale et se lit de bas en haut, montant vers
       lui. Faire tourner les deux aurait donne une fleche pointant vers le bas
       pour dire « en arriere ».
       ───────────────────────────────────────────── */

    .catalog-tab {
        display: flex;
        position: fixed;
        left: 0;
        top: 50%;
        transform: translateY(-50%);
        z-index: 25;
        flex-direction: column;
        align-items: center;
        gap: 10px;
        padding: 20px 8px;
        border: 1px solid var(--glass-border);
        border-left: none;
        border-radius: 0 var(--ff-radius-lg) var(--ff-radius-lg) 0;
        background: rgba(18, 20, 24, 0.62);
        backdrop-filter: blur(14px) saturate(1.1);
        -webkit-backdrop-filter: blur(14px) saturate(1.1);
        color: #e8e5de;
        text-decoration: none;
        cursor: pointer;
        /* ⚠️ `opacity` et `visibility` sont DANS cette liste, et non ajoutees a
           celle du mode cinema plus bas. Cette derniere pose `transition:` en
           entier et, ecrite apres, elle effacerait le survol de cet onglet. */
        transition: background var(--ff-transition-fast),
                    color var(--ff-transition-fast),
                    border-color var(--ff-transition-fast),
                    padding-right var(--ff-transition-fast),
                    opacity 0.55s ease,
                    visibility 0.55s;
    }

    .catalog-tab span {
        /* `vertical-rl` seul se lirait de HAUT en bas ; la rotation le remet
           dans le sens attendu d'un onglet de bord gauche. */
        writing-mode: vertical-rl;
        transform: rotate(180deg);
        font-family: 'Futura', 'Trebuchet MS', sans-serif;
        font-size: 11px;
        font-weight: 700;
        text-transform: uppercase;
        letter-spacing: 1.6px;
        white-space: nowrap;
    }

    /* Il s'avance de quelques pixels au survol plutot que de changer de taille :
       un onglet ancre a un bord se tire, il ne grandit pas. Le rembourrage
       plutot qu'un `translateX` — la surface cliquable suit le mouvement au lieu
       de glisser sous le curseur. */
    .catalog-tab:hover {
        background: rgba(24, 27, 32, 0.82);
        border-color: var(--ff-gold);
        color: var(--ff-gold);
        padding-right: 13px;
    }
    .catalog-tab:focus-visible {
        outline: 2px solid var(--ff-gold);
        outline-offset: 2px;
    }

    /* ─────────────────────────────────────────────
       MODE CINEMA — la soupape

       Sans elle on serait tenu de rendre les encarts tres transparents pour ne
       pas cacher les photos, donc illisibles sur les images claires. Avec elle
       ils peuvent etre franchement opaques : qui veut l'image nue a un geste
       pour l'obtenir.

       Le NOM SEUL reste, sans le bouton d'achat. Le mode cinema est un moment de
       contemplation ; un bouton d'achat dedans, c'est un vendeur qui s'invite, et
       la sortie est a un clic. Reversible en retirant `.product-cta` de la liste
       ci-dessous.
       ───────────────────────────────────────────── */

    .pop-toggle {
        display: grid;
        position: fixed;
        right: 20px;
        bottom: 20px;
        z-index: 30;
        width: 46px;
        height: 46px;
        place-items: center;
        border: 1px solid var(--glass-border);
        border-radius: 50%;
        background: rgba(18, 20, 24, 0.6);
        backdrop-filter: blur(12px);
        -webkit-backdrop-filter: blur(12px);
        color: #f3f1ec;
        font-size: 20px;
        line-height: 1;
        cursor: pointer;
        transition: transform 0.25s ease, background 0.25s ease;
    }
    .pop-toggle:hover {
        transform: scale(1.08);
        background: rgba(18, 20, 24, 0.78);
    }
    .pop-toggle:focus-visible {
        outline: 2px solid #ffffff;
        outline-offset: 3px;
    }
    /* `visibility` en plus de l'opacite : un lien invisible mais focusable au
       clavier serait un piege. */
    .product-layout--modern.is-cinema .header,
    .product-layout--modern.is-cinema .footer,
    .product-layout--modern.is-cinema .product-info-bar,
    .product-layout--modern.is-cinema .product-description,
    .product-layout--modern.is-cinema .product-features,
    .product-layout--modern.is-cinema .product-gallery,
    .product-layout--modern.is-cinema .product-requires,
    .product-layout--modern.is-cinema .hidden-fry,
    /* L'onglet de retour part avec le reste : le mode cinema ne laisse que
       l'appareil et son nom. */
    .product-layout--modern.is-cinema .catalog-tab,
    /* ✔ TRANCHE le 2026-08-12 apres essai : le bouton d'achat RESTE en mode
       cinema, seul le prix disparait.

       Mon hypothese etait qu'un bouton d'achat dans un moment de contemplation
       ferait vendeur qui s'invite. Lord Frites a essaye et conclu l'inverse : tout
       se passe sur UNE ligne vers le haut de l'image, donc 98 % de la photo reste
       libre, et le bouton prolonge le titre au lieu de le concurrencer. Il ajoute
       — non sans raison — qu'une belle image plein ecran est justement le moment
       ou un achat se decide.

       Le prix, lui, reste masque : « It's in your account » dans une capture
       d'ecran est du bruit. */
    .product-layout--modern.is-cinema .product-price {
        opacity: 0;
        visibility: hidden;
    }

    .product-layout--modern .header,
    .product-layout--modern .footer,
    .product-layout--modern .product-info-bar,
    .product-layout--modern .product-description,
    .product-layout--modern .product-features,
    .product-layout--modern .product-gallery,
    .product-layout--modern .product-cta,
    .product-layout--modern .product-price,
    .product-layout--modern .product-requires,
    .product-layout--modern .hidden-fry {
        transition: opacity 0.55s ease, visibility 0.55s;
    }

    /* ─── Le carre de marque ──────────────────────
       Absent hors mode cinema : la marque est deja dans l'en-tete, la repeter
       serait redondant. Il n'apparait que lorsque l'en-tete s'efface — donc
       exactement quand une capture d'ecran perdrait toute trace de l'auteur.

       Carre de la meme hauteur que le bloc titre + sous-titre, pour que les trois
       elements se lisent comme une seule signature. */
    .cinema-brand {
        display: none;
        order: 0;
        flex-shrink: 0;
        place-items: center;
    }

    /* ⚠️ `box-shadow` ne conviendrait PAS : il suit la boite de l'element, pas le
       canal alpha du PNG — on obtiendrait un rectangle d'ombre autour d'un logo
       decoupe. `filter: drop-shadow()` suit la transparence, c'est l'outil fait
       pour ca.

       DEUX ombres et non une : la barre de titre est en HAUT de l'image, et la
       mesure du 2026-08-12 dit que c'est la zone la plus claire (147 a 167 de
       luminance, claire sur 7 a 9 images sur 12). Un logo blanc n'y tient pas
       avec une seule ombre douce. La premiere, serree, dessine le contour ; la
       seconde, large, donne la profondeur — et reprend exactement celle du nom de
       l'appareil, pour que les deux se lisent comme une meme signature. */
    .cinema-brand img {
        width: auto;
        height: 56px;
        display: block;
        filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.55))
                drop-shadow(0 2px 24px rgba(0, 0, 0, 0.6));
    }
    .product-layout--modern.is-cinema .cinema-brand {
        display: grid;
    }
    /* L'espacement du dock est genereux (30 px) : trop pour coller le carre au
       titre dont il doit paraitre solidaire. */
    .product-layout--modern.is-cinema .product-hero {
        gap: 16px;
    }

    /* L'en-tete s'effacant, le titre remonte prendre sa place et se depouille de
       son encart : plus rien entre lui et l'image. */
    .product-layout--modern.is-cinema .product-hero {
        background: transparent;
        backdrop-filter: none;
        -webkit-backdrop-filter: none;
        top: 24px;
        transition: background 0.55s ease, top 0.55s ease;
    }
    .product-layout--modern.is-cinema .product-title {
        text-shadow: 0 2px 24px rgba(0, 0, 0, 0.6);
    }

    .product-layout--modern.is-cinema .hero-veil {
        opacity: 0;
    }

    .product-layout--modern.is-cinema {
        overflow: hidden;
    }

    /* Mouvement automatique = besoin d'un renoncement. */
    @media (prefers-reduced-motion: reduce) {
        .hero-slide,
        .hero-veil {
            transition: none;
        }
    }
}
