/* ==========================================================================
   PAGE PORTFOLIO : VIGNETTES "COMING SOON" QUI COMBLENT LES TROUS DE LA GRILLE (desktop >= 1200 px, 24 oct. 2026 ; + TABLETTE 768 - 1199 px, 27 oct. 2026)
   --------------------------------------------------------------------------
   Quand un filtre laisse la derniere ligne incomplete, ou une grille plus courte que la fenetre, js/portfolio-coming-soon.js ajoute des vignettes
   "COMING SOON" a la suite des vraies vignettes (meme largeur : 25 %, meme format : 666 / 456). Elles ne sont PAS des .thumb : aucun script de
   la grille (filtres, rollover, glitch des legendes, ordre des projets) ne les voit. Un petit glitch passe dessus de temps en temps, au hasard.
   FOND (24 oct., v101) : noir DELAVE (centre #2e2e2e, ~82 % de noir) avec un degrade RADIAL vers des coins tres sombres (#050505) : de la profondeur,
   pas de filet entre les vignettes. TEXTE : exactement la structure de la legende d'une vraie vignette au survol (css/skin.css + css/style.css :
   .thumbInfo) -- nom en Roboto gras 24,15 px, interligne 21 px, espacement 1 px ; dessous, le "secteur" en Doto 17 px gras, 12 px plus bas.
   Ici : nom = COMING SOON, secteur = AI.
   Tablette (768 - 1199 px) : meme principe, grille a 2 colonnes (v130). Mobile (< 768 px) : aucune vignette, aucun changement.
   REGLAGES : taille du texte (--soon-size), trame (le ::after), glitch (CONFIG dans js/portfolio-coming-soon.js).
   POUR TOUT RETIRER : supprimer les lignes <link> et <script> de portfolio-coming-soon dans portfolio.html et EN/portfolio.html.
   ========================================================================== */
@media only screen and (min-width: 768px) {
	#grid .thumb-soon {
		--soon-center: #2e2e2e;           /* centre : noir delave (~82 % de noir) */
		--soon-edge: #050505;             /* coins : ombre forte */
		position: relative;
		flex: 0 0 25%;
		width: 25%;
		aspect-ratio: 666 / 456;          /* meme format que .thumb (css/style.css) */
		margin: 0;
		overflow: hidden;
		box-sizing: border-box;
		background: #000;
		background: radial-gradient(ellipse at 50% 50%, var(--soon-center) 0%, #1c1c1c 45%, var(--soon-edge) 100%);
		display: flex;
		align-items: center;
		justify-content: center;
		opacity: 0;
		transition: opacity .5s ease;
		cursor: default;
		user-select: none;
		-webkit-user-select: none;
	}
	#grid .thumb-soon.soon-in { opacity: 1; }
	/* NOIR UNI A 44 % EN FUSION "PRODUIT" (24 oct., v111) sur TOUTES les tuiles COMING SOON (images et tuiles texte) : elles sont ainsi plus sombres que les vraies vignettes, ce qui
	   les distingue au premier coup d'oeil. Remplace le degrade d'ombre radial des versions v108 a v110 (supprime). Le voile du survol (le .rollover-wrapper, plus tard dans le DOM a
	   z-index egal, passe devant), la legende et la trame restent au-dessus / nets. Reglage : --soon-dark (0 = rien, 1 = noir complet). */
	#grid .thumb-soon {
		--soon-dark: 0;
		isolation: isolate;               /* le multiply se fait sur l'image de la tuile, pas sur le reste de la page */
	}
	#grid .thumb-soon::before {
		content: "";
		position: absolute;
		inset: 0;
		z-index: 1;
		pointer-events: none;
		background: rgba(0, 0, 0, var(--soon-dark));
		mix-blend-mode: multiply;
	}
	/* meme trame (scanlines) que les vraies vignettes (css/glitch-tv.css), en clair sur fond sombre */
	#grid .thumb-soon::after {
		content: "";
		position: absolute;
		inset: 0;
		z-index: 2;
		pointer-events: none;
		background: repeating-linear-gradient(to bottom, rgba(255, 255, 255, 0.05) 0px, rgba(255, 255, 255, 0.05) 1px, transparent 1px, transparent 3px);
	}
	/* LEGENDE : meme structure et memes valeurs que .thumbInfo des vraies vignettes (css/skin.css l.107, css/style.css l.1002-1003) */
	#grid .thumb-soon .soon-info {
		position: relative;
		z-index: 1;
		width: 100%;
		text-align: center;
		color: #fff;
		font-family: "Roboto", sans-serif;
		font-size: 24.15px;
		line-height: 21px;
		letter-spacing: 1px;
		font-weight: bold;
	}
	#grid .thumb-soon .soon-info .soon-name {      /* nom : c'est lui (et lui seul) qui glitche, comme le nom de la marque sur les vraies vignettes */
		display: inline;                          /* inline (et non inline-block) : l'ecart nom / secteur est alors EXACTEMENT celui d'une vraie legende (36 px) */
		position: relative;
		isolation: isolate;                       /* les calques de glitch passent DERRIERE le texte blanc */
		font: inherit;
		letter-spacing: inherit;
		white-space: nowrap;
	}
	#grid .thumb-soon .soon-info .soon-sector {    /* secteur : Doto 17 px gras, 12 px sous le nom (comme "Beauty", "AI"...) */
		display: block;
		margin-top: 12px;
		font: 800 18px 'Doto', sans-serif;   /* (29 oct.) 18 px, extra-gras (800) ; avant : 20 px, 22 px, puis 700 17px. Doto est une police variable 100 - 900 : 900 = noir encore plus epais */
		font-style: normal;
		letter-spacing: .2em;   /* (29 oct.) interlettrage aere : .2em = 3,6 px a 18 px (avant : normal, lettres collees) */
		word-spacing: -.3em;    /* (29 oct.) l'interlettrage s'ajoute aussi autour de l'espace NO / SIGNAL (≈ .4em de trop) : on le resserre ; plus petit (ex. -.4em) = mots plus proches, plus grand (ex. -.2em) = plus ecartes. Herite par les calques du glitch */
		padding-left: .2em;     /* compense l'espace ajoute apres la derniere lettre : le texte reste centre */
		text-align: center;
	}
	/* VARIANTES D'EFFET SUR LES TUILES-IMAGES COMING SOON (24 oct., v114) -- celles de la planche d'effets, REPARTIES AU HASARD par js/portfolio-coming-soon.js (CONFIG.variants)
	   pour les juger en situation, sur la vraie page :
	     R = REFERENCE : voile noir 44 % seul, aucun effet ;
	     A = DUOTONE NEON : image en noir et blanc teintee rose -> violet -> cyan, le degrade glisse lentement ;
	     B = HOLOGRAMME : reflet irise + eclat blanc qui balaie (option choisie en v113 ; hors du tirage pour l'instant) ;
	     D = SCANNER : teinte bleu nuit, grille, reperes aux 4 coins, ligne cyan qui balaie.
	   Classe .soon-fx-R / -A / -B / -D sur la tuile. Ordre des calques : image -> calques d'effet (z 0) -> VOILE NOIR 44 % (::before) -> voile du survol + legende -> trame (::after).
	   LEGER : calques <i> animes en CSS sur "transform" seulement ; en pause hors ecran (.soon-paused) ; figes si "reduire les animations".
	   PASTILLE (R / A / B / D) en haut a gauche : pour reperer la variante pendant les essais -- CONFIG.showLabels = false dans le JS pour la retirer. */
	#grid .thumb-soon .soon-tag {
		position: absolute;
		left: 8px;
		top: 8px;
		z-index: 7;
		min-width: 20px;
		height: 20px;
		padding: 0 6px;
		border-radius: 4px;
		background: rgba(0, 0, 0, 0.78);
		color: #fff;
		font: 700 11px/20px 'Roboto', sans-serif;
		letter-spacing: .5px;
		text-align: center;
		pointer-events: none;
	}
	#grid .thumb-soon .soon-fx { position: absolute; pointer-events: none; }
	#grid .thumb-soon.soon-paused .soon-fx,
	#grid .thumb-soon.soon-paused .crt-tvlight { animation-play-state: paused; }

	/* --- A : DUOTONE NEON, RADIAL ET FIXE (v115 : c'est la variante retenue ; plus de glissement) ---
	   Image en noir et blanc, teintee (fusion "color") par des taches de couleur RADIALES qui se melangent : rose, cyan, violet, bleu. js/portfolio-coming-soon.js place les 4
	   couleurs sur des coins differents et legerement decales pour CHAQUE tuile (--> pas deux tuiles identiques, rendu moins "code"). AUCUNE ANIMATION, aucun calque en mouvement. */
	#grid .thumb-soon.soon-fx-A a img { filter: grayscale(1) contrast(1.2) brightness(1.08); transition: filter .45s ease; }
	/* AU SURVOL (v120) : les taches de couleur disparaissent (fondu) et l'image retrouve sa couleur D'ORIGINE (plus de noir et blanc) : on a un premier apercu de la tonalite
	   graphique et chromatique du projet. Valable pour l'image ET pour son double de zoom (.animationImage). Au depart de la souris, la teinte revient en fondu. */
	#grid .thumb-soon.soon-fx-A:hover a img { filter: none; }
	#grid .thumb-soon.soon-fx-A:hover .soon-duo { opacity: 0; }
	#grid .thumb-soon.soon-fx-A:hover .soon-wash { opacity: 0; }
	/* VOILE BLANC (v123) : pose sur l'image en noir et blanc, SOUS les taches de couleur : il l'eclaircit un peu (--soon-wash : 0,15 = 15 % de blanc ; 0 = aucun).
	   Ordre : image N&B -> voile blanc -> taches de couleur (9 %) -> voile du survol + legende. Disparait au survol, avec les taches (fondu). */
	#grid .thumb-soon .soon-wash {
		inset: 0; z-index: 0;
		background: rgba(255, 255, 255, var(--soon-wash, 0.11));
		transition: opacity .45s ease;
	}
	#grid .thumb-soon .soon-duo {
		inset: 0; z-index: 0;
		transition: opacity .45s ease;
		mix-blend-mode: color; opacity: var(--soon-tint, 0.09);   /* v123 : 0,09 = taches de couleur a 9 % (par-dessus le voile blanc) ; 0 = pur noir et blanc ; 0,11 (v122), 0,2, 0,33, 0,5 = anciennes valeurs */
		background: #5a2fd0;              /* fond violet : aucune zone sans teinte ; le JS le remplace par les 4 taches radiales + ce fond */
	}

	/* --- B : HOLOGRAMME / FOIL --- */
	#grid .thumb-soon.soon-fx-B a img { filter: saturate(var(--soon-desat, 0.4)) contrast(1.12) brightness(0.95); }
	#grid .thumb-soon .soon-foil {
		left: -50%; top: -50%; width: 200%; height: 200%; z-index: 0;
		mix-blend-mode: color-dodge; opacity: var(--soon-foil-opacity, 0.4);
		background: repeating-linear-gradient(115deg, #ff6ad5 0%, #ffd86a 4%, #a6ff8a 8%, #6ae6ff 12%, #a37aff 16%, #ff6ad5 20%);
		will-change: transform;
		animation: soon-foil-move var(--soon-foil-speed, 8s) ease-in-out infinite alternate;
		animation-delay: var(--fx-delay, 0s);
	}
	#grid .thumb-soon .soon-spec {
		inset: 0; z-index: 0;
		mix-blend-mode: overlay; transform: translate3d(-120%, 0, 0);
		background: linear-gradient(105deg, transparent 38%, rgba(255, 255, 255, 0.85) 50%, transparent 62%);
		will-change: transform;
		animation: soon-spec-sweep var(--soon-spec-every, 5.5s) cubic-bezier(0.5, 0, 0.3, 1) infinite;
		animation-delay: var(--fx-delay2, 0s);
	}
	@keyframes soon-foil-move { from { transform: translate3d(-12%, -6%, 0); } to { transform: translate3d(12%, 6%, 0); } }
	@keyframes soon-spec-sweep { 0% { transform: translate3d(-120%, 0, 0); } 55%, 100% { transform: translate3d(120%, 0, 0); } }

	/* --- D : SCANNER / HUD --- */
	#grid .thumb-soon.soon-fx-D a img { filter: grayscale(1) contrast(1.15) brightness(0.9); }
	#grid .thumb-soon .soon-tint { inset: 0; z-index: 0; mix-blend-mode: color; background: linear-gradient(180deg, #0f5a86 0%, #06202f 100%); opacity: 0.95; }
	#grid .thumb-soon .soon-gridl {
		inset: 0; z-index: 0;
		background:
			linear-gradient(rgba(0, 255, 255, 0.11) 1px, transparent 1px) 0 0 / 30px 30px,
			linear-gradient(90deg, rgba(0, 255, 255, 0.11) 1px, transparent 1px) 0 0 / 30px 30px;
	}
	#grid .thumb-soon .soon-brk {
		inset: 14px; z-index: 0; --c: rgba(255, 255, 255, 0.9); --t: 1.5px; --l: 22px;
		background:
			linear-gradient(var(--c), var(--c)) 0 0 / var(--l) var(--t) no-repeat, linear-gradient(var(--c), var(--c)) 0 0 / var(--t) var(--l) no-repeat,
			linear-gradient(var(--c), var(--c)) 100% 0 / var(--l) var(--t) no-repeat, linear-gradient(var(--c), var(--c)) 100% 0 / var(--t) var(--l) no-repeat,
			linear-gradient(var(--c), var(--c)) 0 100% / var(--l) var(--t) no-repeat, linear-gradient(var(--c), var(--c)) 0 100% / var(--t) var(--l) no-repeat,
			linear-gradient(var(--c), var(--c)) 100% 100% / var(--l) var(--t) no-repeat, linear-gradient(var(--c), var(--c)) 100% 100% / var(--t) var(--l) no-repeat;
	}
	#grid .thumb-soon .soon-scan {
		inset: 0; z-index: 0; transform: translate3d(0, -100%, 0);
		background: linear-gradient(to bottom, rgba(0, 255, 255, 0) 0%, rgba(0, 255, 255, 0) 70%, rgba(0, 255, 255, 0.30) 97%, #b9fdff 99%, #b9fdff 100%);
		will-change: transform;
		animation: soon-scan 3.6s linear infinite;
		animation-delay: var(--fx-delay, 0s);
	}
	@keyframes soon-scan { 0% { transform: translate3d(0, -100%, 0); } 82%, 100% { transform: translate3d(0, 0, 0); } }

	@media (prefers-reduced-motion: reduce) {
		#grid .thumb-soon .soon-fx { animation: none; }
		#grid .thumb-soon .soon-spec, #grid .thumb-soon .soon-scan { display: none; }
	}

	/* TUILE AVEC UNE IMAGE (CONFIG.images dans js/portfolio-coming-soon.js) : c'est une VRAIE vignette (.thumb, structure <a><img></a>), donc le voile noir, le zoom,
	   la legende au survol, le glitch du nom et la trame viennent des regles / scripts habituels de la grille (css/style.css, css/skin.css, css/glitch-tv.css).
	   Ici seulement : pas de centrage flex, pas de lien (curseur normal), image en "cover" au cas ou son format differe de 666 / 456. */
	#grid .thumb-soon.soon-has-img {
		display: block;
		background: #000;
		opacity: 1;
		cursor: default;
		margin: 0;
	}
	#grid .thumb-soon.soon-has-img:not(.soon-in) { opacity: 0; }
	#grid .thumb-soon.soon-has-img a { cursor: default; }
	#grid .thumb-soon.soon-has-img a > img:not(.animationImage) {
		width: 100%;
		height: 100%;
		object-fit: cover;
	}
	#grid .thumb-soon .soon-layer {
		position: absolute;
		left: 0; top: 0; right: 0; bottom: 0;
		z-index: -1;
		pointer-events: none;
		opacity: 0;
		white-space: nowrap;
		font: inherit;
		line-height: normal;              /* meme boite que le texte inline du nom : sinon les franges de glitch montent de ~3 px */
		letter-spacing: inherit;
		will-change: transform, opacity;
	}
}
/* TABLETTE (768 - 1199 px, 27 oct. 2026) : la grille y a 2 colonnes (vignettes a 50 %, cf. css/udt_media_queries.css) : la tuile COMING SOON fait donc 50 %
   de large (meme format 666 / 456 que les vraies vignettes) et comble le trou de la derniere ligne comme sur desktop. */
@media only screen and (min-width: 768px) and (max-width: 1199px) {
	#grid .thumb-soon { flex: 0 0 50%; width: 50%; }
}
/* v134 / v135 : LA TUILE TEXTE N'A PLUS QU'UNE LIGNE, "Coming Soon" (ancienne police Doto 17 px, discrete), BLANC A 22 % (--soon-txt : .22), glitch au maximum (js/portfolio-coming-soon.js).
   v135 : voile noir du fond = 15 % + 11 % = 26 %. v136 : +30 % = 56 %. v137 : 66 % (--soon-dark : .66). v139 : texte a 15 % (--soon-txt : .15). Valable sur
   tablette ET desktop, tous les filtres. (Les regles .soon-sector ci-dessous ne servent plus : il n'y a plus de ligne "secteur".)
   TABLETTE + DESKTOP (>= 768 px ; tablette en v131, desktop en v132) : TUILE TEXTE "AI / Coming Soon" PLUS DISCRETE + GLITCH SUR LES DEUX LIGNES
   - FOND : voile noir a 15 % (--soon-dark : .15) par-dessus le degrade, en fusion "produit" (::before, deja prevu plus haut) : le degrade est moins present.
   - TEXTE : a 22 % d'opacite (--soon-txt : .22). Pendant un glitch, le texte "flashe" brievement plus fort
     (valeur posee par js/portfolio-coming-soon.js sur la variable --soon-txt de la ligne concernee), puis revient a 21 %.
   - Le secteur ("Coming Soon") devient un contexte d'empilement comme le nom : ses calques de glitch (rose / cyan / vert / jaune) passent derriere le texte.
   Ne concerne QUE les tuiles texte (les tuiles-images gardent leur rendu). Mobile (<= 767 px) : pas de tuile.
   REGLAGES : --soon-dark et --soon-txt juste ci-dessous. POUR RETIRER : supprimer ce bloc. */
@media only screen and (min-width: 768px) {
	#grid .thumb-soon:not(.soon-has-img) { --soon-dark: .66; }   /* v148 : retour a l'ORIGINAL : voile noir 66 % (v145 - v147 : .33) */
	/* v148 : RETOUR A L'ORIGINAL pour le fond des tuiles : degrade radial sombre (centre #2e2e2e -> #1c1c1c a 45 % -> coins --soon-edge #050505), comme avant les effets.
	   (v145 - v147 : fond uni #2e2e2e sans ombre ; v144 : degrade adouci ; pour les retrouver : voir LISEZMOI.) */
	#grid .thumb-soon:not(.soon-has-img) {
		background: radial-gradient(ellipse at 50% 50%, var(--soon-center) 0%, #1c1c1c 45%, var(--soon-edge) 100%);
	}   /* v137 : 66 % (v136 : .56 ; v135 : .26 ; v131 : .15) */
	#grid .thumb-soon:not(.soon-has-img) .soon-name,
	#grid .thumb-soon:not(.soon-has-img) .soon-sector { color: rgba(255, 255, 255, var(--soon-txt, .15)); }   /* v139 : 15 % (v134 - v138 : 22 %) */
	#grid .thumb-soon:not(.soon-has-img) .soon-sector { position: relative; isolation: isolate; }
	#grid .thumb-soon:not(.soon-has-img) .soon-sector .soon-layer { line-height: inherit; padding-left: .2em; }   /* (29 oct.) meme decalage que le texte (interlettrage .2em) : les franges de glitch restent alignees */
	/* v135 : ligne unique -> plus de marge de 12 px au-dessus (centrage exact) ; meme chose pour la legende "Coming Soon" au survol des tuiles-images */
	#grid .thumb-soon:not(.soon-has-img) .soon-info .soon-sector { margin-top: 0; }
	#grid .thumb-soon.soon-has-img .thumbInfo span span { margin-top: 0; }
}
/* MOBILE (<= 767 px) : aucune tuile, aucun changement. */
@media only screen and (max-width: 767px) {
	#grid .thumb-soon { display: none !important; }
}

/* ==========================================================================
   PAGE PORTFOLIO : FOND NOIR DERRIERE LES VIGNETTES (24 oct. 2026, v129 : DESKTOP + TABLETTE + MOBILE, exception demandee)
   --------------------------------------------------------------------------
   Le fond de la page (body : creme #fbfbfa + motif de petits points) apparaissait derriere les vignettes pendant les transitions d'animation d'un filtre a l'autre (vignettes qui
   partent / arrivent, tuiles COMING SOON qui apparaissent en fondu) : un flash clair, tres visible. Il est maintenant NOIR uni, comme le bandeau, la barre de filtres et le footer : les
   transitions se voient beaucoup moins. Le fond du body se propage a toute la fenetre (y compris le "rebond" sous le footer). Scope strict : body.portfolio-page (FR + EN).
   v128 : desktop seulement ; v129 : EXCEPTIONNELLEMENT aussi tablette et mobile (la regle n'est plus dans un @media).
   POUR REVENIR EN ARRIERE : supprimer ce bloc (ou le remettre dans @media only screen and (min-width: 1200px) pour desktop seul).
   ========================================================================== */
body.portfolio-page {
	background-color: #000 !important;
	background-image: none !important;
}

/* ==========================================================================
   EFFET "VIEUX TELEVISEUR ALLUME" (27 oct. 2026 : essai v140 - v141, VALIDE en v142 ; desktop + tablette)
   --------------------------------------------------------------------------
   Pose par js/portfolio-coming-soon.js (CONFIG.crt) sur certaines tuiles COMING SOON du filtre AI : B trame fine, C neige legere, F monochrome FROID (bleu / blanc / gris ; v141, avant : ambre) et leurs combinaisons B+F, C+F, B+C+F
   (A phosphore, D verre bombe, E barre de roulement : abandonnes et retires). Les calques <i class="crt-layer crt-*"> sont places AVANT le texte (le texte reste devant) et au-dessus du voile noir.
   La trame de base de la tuile (::after) est masquee sur les tuiles a effet pour voir chaque effet tel quel. Petite lettre en haut a gauche : .soon-crt-tag.
   v142 : effet final = B (trame fine) + toute petite neige legere + bords sombres, sur toutes les tuiles texte (v143 : bords /3,7, neige et trame plus visibles) (crtDefault dans le JS).
   POUR TOUT RETIRER : supprimer ce bloc (et mettre crtDefault: null dans le JS).
   ========================================================================== */
@media only screen and (min-width: 768px) {
	#grid .thumb-soon.soon-crt::after { display: none; }
	#grid .thumb-soon .crt-layer { position: absolute; inset: 0; z-index: 1; pointer-events: none; }
	/* v146 : TRAME CONTINUE D'UNE TUILE A L'AUTRE. Avant, chaque tuile redemarrait sa trame depuis son propre haut ; comme la hauteur d'une tuile n'est pas un multiple de 3 px, la trame
	   etait decalee a la jonction entre deux rangees (ligne double ou trou qui "clignotait" en derivant). Maintenant : motif de 3 px non repete (linear-gradient + background-size), cale par le JS
	   sur des multiples de 3 px de la PAGE (--sl-y, js/portfolio-coming-soon.js : alignScan) et derive par PAS d'1 px (steps(3), net, pas de gris intermediaires), toutes les tuiles sur la meme horloge. */
	#grid .thumb-soon .crt-sl { background-image: linear-gradient(to bottom, rgba(255, 255, 255, .11) 0, rgba(255, 255, 255, .11) 1px, transparent 1px, transparent 3px); background-size: 100% 3px; background-position: 0 var(--sl-y, 0px); }   /* .11 (v143, avant .07) */
	#grid .thumb-soon .crt-sl.crt-soft { opacity: .6; }
	#grid .thumb-soon .crt-sl.crt-drift { animation: crt-dr 2.4s steps(3) infinite; }   /* derive de 3 px en 3 pas d'1 px (v146 ; v143 : 2,4 s) */
	/* v142 : TOUTE PETITE NEIGE tres legere (opacite .045 au lieu de .10 pour l'essai C), grain plus fin (tuile de bruit reduite a 100 px), saut un peu plus lent : on sent que
	   l'ecran est vivant sans le remarquer au premier coup d'oeil. Plus visible : monter l'opacite (.07 - .10) ; plus discret : .03. */
	#grid .thumb-soon .crt-snow.crt-lite { opacity: .10; background-size: 100px 100px; animation: crt-sn .35s steps(1) infinite; }   /* v143 : .10 (avant .045) et saut toutes les .35 s (avant .42) */
	/* v149 : RECTANGLE NOIR a 33 % par-dessus le fond (variante 'ORIG' du JS), a la place de la neige de la v148 (retiree : petits bugs visuels). Il s'ajoute au voile noir a 66 %
	   (--soon-dark) : assombrissement total ~77 % (1 - 0,34 x 0,67). Plus sombre : monter .33 ; plus clair : le baisser. */
	#grid .thumb-soon .crt-black { background: rgba(0, 0, 0, .33); }
	/* v150 : PHOTO DE VIEILLE TELE "NO SIGNAL" a 15 % sur le fond de toutes les tuiles sans photo (toujours la meme : images/portfolio/vignetteNOSIGNAL.webp, chemin relatif a ce fichier CSS :
	   ../images/ -> marche pour les pages FR et EN). EFFET "IMAGE VIEILLIE" : noir et blanc a moitie + sepia + contraste legerement releve + assombrie (brightness .75) + legerement floue, en fusion "ecran" (screen : la photo
	   n'eclaire que le fond, elle ne l'assombrit jamais) ; un FANTOME decale de 9 px (double image d'une mauvaise reception analogique) a 7 %. Aucune animation. Si le fichier est absent :
	   rien ne s'affiche (pas d'image cassee). Reglages : opacity (.15 demande), filter, translateX du fantome ; autre fusion : mix-blend-mode: difference ou overlay. */
	/* v151 : IMAGE ANCIENNE (une par tuile, vignetteNOSIGNAL01 ... 08, posee en style en ligne par le JS) : sous le cadre. Effet "image vieillie" : sepia 70 %, noir et blanc a moitie, contraste
	   releve, assombrie, legerement floue, a 30 % d'opacite. .crt-bezel = le meme cadre de tele en fusion "produit" (multiply) a 60 % : le contour noir du cadre assombrit les bords de l'image,
	   l'interieur clair du cadre la laisse intacte -> on voit l'image "dans" l'ecran. Le cadre lumineux a 15 % (.crt-photo, v150) reste par-dessus, inchange. Reglages : opacity de .crt-pic
	   (.30) et de .crt-bezel (.60) ; filter de .crt-pic. */
	#grid .thumb-soon .crt-pic { background-size: cover; background-position: center; background-repeat: no-repeat; opacity: .30; filter: sepia(.7) grayscale(.5) contrast(1.35) brightness(.8) blur(.6px); }
	#grid .thumb-soon .crt-bezel { background: url("../images/portfolio/vignetteNOSIGNAL.webp") center / cover no-repeat; mix-blend-mode: multiply; opacity: .6; }
	#grid .thumb-soon .crt-photo { background: url("../images/portfolio/vignetteNOSIGNAL.webp") center / cover no-repeat; opacity: .15; filter: grayscale(.4) sepia(.6) contrast(1.2) brightness(.75) blur(.5px); mix-blend-mode: screen; }
	#grid .thumb-soon .crt-ghost { background: url("../images/portfolio/vignetteNOSIGNAL.webp") center / cover no-repeat; opacity: .07; filter: grayscale(1) contrast(1.1) brightness(.8) blur(1px); mix-blend-mode: screen; transform: translateX(9px); }
	#grid .thumb-soon .crt-snow { background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='160' height='160'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 .9 0'/></filter><rect width='100%' height='100%' filter='url(%23n)'/></svg>"); opacity: .10; animation: crt-sn .5s steps(1) infinite; }
	#grid .thumb-soon .soon-crt-tag { position: absolute; left: 8px; top: 8px; z-index: 7; min-width: 20px; height: 20px; padding: 0 7px; white-space: nowrap; border-radius: 4px; background: rgba(255, 255, 255, .85); color: #000; font: 700 12px/20px 'Roboto', sans-serif; font-style: normal; text-align: center; pointer-events: none; }
}
@keyframes crt-dr { from { background-position-y: var(--sl-y, 0px); } to { background-position-y: calc(var(--sl-y, 0px) + var(--sl-p, 3px)); } }
@keyframes crt-fl { 0%, 100% { opacity: 1; } 45% { opacity: .78; } 50% { opacity: .92; } 70% { opacity: .8; } }
@keyframes crt-rb { from { transform: translateY(-110%); } to { transform: translateY(340%); } }
@keyframes crt-sn { 0% { background-position: 0 0; } 20% { background-position: -37px 21px; } 40% { background-position: 19px -43px; } 60% { background-position: -61px -12px; } 80% { background-position: 33px 50px; } }
@media (prefers-reduced-motion: reduce) { #grid .thumb-soon .crt-layer { animation: none !important; } }

/* ==========================================================================
   SERIE DE 8 VARIANTES DU FOND "VIEUX TELEVISEUR" A ESSAYER SUR LE FILTRE AI (27 oct. 2026, v147 -- TEMPORAIRE, desktop + tablette)
   --------------------------------------------------------------------------
   Pose par js/portfolio-coming-soon.js (CONFIG.crt.ai) : O original / R reference (dernier effet) / A plus present / B bleu froid / C halo phosphore / D barre de roulement /
   E trame 2 px / F masque RVB. Chaque variante = le dernier effet (R) + une modification. La lettre est en haut a gauche (.soon-crt-tag).
   POUR TOUT RETIRER : supprimer ce bloc (et mettre crt: {} dans le JS).
   ========================================================================== */
@media only screen and (min-width: 768px) {
	#grid .thumb-soon.soon-fx-O:not(.soon-has-img) { --soon-dark: .66; background: radial-gradient(ellipse at 50% 50%, var(--soon-center) 0%, #1c1c1c 45%, var(--soon-edge) 100%); }
	#grid .thumb-soon .crt-sl.crt-strong { background-image: linear-gradient(to bottom, rgba(255, 255, 255, .17) 0, rgba(255, 255, 255, .17) 1px, transparent 1px, transparent 3px); animation-duration: 1.6s; }
	#grid .thumb-soon .crt-snow.crt-strong { opacity: .17; animation-duration: .28s; }
	#grid .thumb-soon .crt-cool { background: rgba(140, 168, 210, .11); mix-blend-mode: screen; }
	#grid .thumb-soon .crt-coolglow { background: radial-gradient(ellipse at 50% 50%, rgba(220, 232, 250, .13) 0%, rgba(220, 232, 250, 0) 70%); animation: crt-fl 7s ease-in-out infinite; }
	#grid .thumb-soon .crt-halo { background: radial-gradient(ellipse at 50% 50%, rgba(255, 246, 225, .08) 0%, rgba(255, 246, 225, 0) 70%); animation: crt-fl 5s ease-in-out infinite; }
	#grid .thumb-soon .crt-roll { height: 30%; bottom: auto; background: linear-gradient(to bottom, rgba(255, 255, 255, 0), rgba(255, 255, 255, .06), rgba(255, 255, 255, 0)); animation: crt-rb 6s linear infinite; }
	#grid .thumb-soon .crt-slfine { background-image: linear-gradient(to bottom, rgba(255, 255, 255, .09) 0, rgba(255, 255, 255, .09) 1px, transparent 1px, transparent 2px); background-size: 100% 2px; background-position: 0 var(--sl-y, 0px); --sl-p: 2px; }
	#grid .thumb-soon .crt-slfine.crt-drift { animation: crt-dr 1.6s steps(2) infinite; }
	#grid .thumb-soon .crt-rgb { background: repeating-linear-gradient(90deg, rgba(255, 0, 0, .05) 0, rgba(255, 0, 0, .05) 1px, rgba(0, 255, 0, .05) 1px, rgba(0, 255, 0, .05) 2px, rgba(0, 0, 255, .05) 2px, rgba(0, 0, 255, .05) 3px); }
}

/* ==========================================================================
   IMAGES ANCIENNES "FOIREES" (27 oct. 2026, v152) : elles doivent a peine se reconnaitre -- contrastes durs, incrustations (fusions), aplats de couleur, grain. Desktop + tablette.
   --------------------------------------------------------------------------
   6 traitements (JS : CONFIG.picFx, ou ?picfx=A..F dans l'adresse ; ?picfx=ALL = les six cote a cote sur le filtre AI) :
     A seuil dur          : noir et blanc, flou puis contraste x9 = taches noires / blanches (photocopie de photocopie)
     B photocopie cramee  : sepia + noir et blanc, contraste x6, fusion "difference" + grain
     C (DEFAUT) bandes pleines : seuil dur + trois bandes de couleur pleines (cyan, magenta, blanc) en fusion "difference" (position differente selon la tuile : --bs) + grain
     D decalage RVB       : trois copies rouge / vert / bleu decalees de 12 px, contraste fort (desalignement analogique)
     E pixels morts       : tres flou + contraste, grille de blocs de 6 px + grain
     F negatif brule      : inverse + teinte tournee + contraste, fusion "difference" + grain
   Le GRAIN est FIXE (aucune animation : pas de scintillement). Cadre "NO SIGNAL" 15 %, contour et fantome (v150 - v151) inchanges par-dessus.
   REGLAGES : opacity / filter de chaque .crt-fxX ; .crt-grain (opacity .22) ; .crt-bands (couleurs, positions).
   ========================================================================== */
@media only screen and (min-width: 768px) {
	#grid .thumb-soon .crt-pic.crt-fxA { opacity: .26; filter: grayscale(1) blur(3px) contrast(9) brightness(.85); }
	#grid .thumb-soon .crt-pic.crt-fxB { opacity: .30; filter: sepia(1) saturate(0) blur(2px) contrast(7) brightness(1.1); mix-blend-mode: difference; }
	#grid .thumb-soon .crt-pic.crt-fxC { opacity: .28; filter: grayscale(1) blur(2.8px) contrast(9) brightness(.9); mix-blend-mode: screen; }
	#grid .thumb-soon .crt-pic.crt-fxD { opacity: .30; background-blend-mode: multiply; mix-blend-mode: screen; filter: blur(2px) contrast(2.6) brightness(.95); }
	#grid .thumb-soon .crt-pic.crt-fxD.crt-r { background-color: #f00; transform: translateX(-12px); }
	#grid .thumb-soon .crt-pic.crt-fxD.crt-g { background-color: #0f0; }
	#grid .thumb-soon .crt-pic.crt-fxD.crt-b { background-color: #00f; transform: translateX(12px); }
	#grid .thumb-soon .crt-pic.crt-fxE { opacity: .34; filter: grayscale(1) blur(6px) contrast(4) brightness(1.1); }
	#grid .thumb-soon .crt-pic.crt-fxF { opacity: .30; filter: invert(1) blur(2.5px) contrast(4) saturate(2.5) hue-rotate(160deg) brightness(.9); mix-blend-mode: difference; }
	#grid .thumb-soon .crt-bands { mix-blend-mode: difference; background-repeat: no-repeat; background-size: 100% 100%, 60% 100%, 100% 100%; background-position: 0 0, calc(var(--bs, 0) * 13%) 0, 0 0;
		background-image:
			linear-gradient(to bottom, transparent calc(10% + var(--bs, 0) * 20%), rgba(0, 230, 255, .4) calc(10% + var(--bs, 0) * 20%), rgba(0, 230, 255, .4) calc(16% + var(--bs, 0) * 20%), transparent calc(16% + var(--bs, 0) * 20%)),
			linear-gradient(to bottom, transparent calc(85% - var(--bs, 0) * 17%), rgba(255, 0, 150, .38) calc(85% - var(--bs, 0) * 17%), rgba(255, 0, 150, .38) calc(88% - var(--bs, 0) * 17%), transparent calc(88% - var(--bs, 0) * 17%)),
			linear-gradient(to bottom, transparent calc(38% + var(--bs, 0) * 9%), rgba(255, 255, 255, .42) calc(38% + var(--bs, 0) * 9%), rgba(255, 255, 255, .42) calc(40% + var(--bs, 0) * 9%), transparent calc(40% + var(--bs, 0) * 9%)); }
	#grid .thumb-soon .crt-deadgrid { background-image: linear-gradient(to right, rgba(0, 0, 0, .85) 1px, transparent 1px), linear-gradient(to bottom, rgba(0, 0, 0, .85) 1px, transparent 1px); background-size: 6px 6px; }
	#grid .thumb-soon .crt-grain { background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='160' height='160'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 .9 0'/></filter><rect width='100%' height='100%' filter='url(%23n)'/></svg>"); background-size: 120px 120px; opacity: .22; mix-blend-mode: overlay; }
}

/* ==========================================================================
   VIEILLES BOBINES DE FILM BRULEES PAR LA LUMIERE (27 oct. 2026, v153) : traitements G, H, I des images anciennes. Desktop + tablette. Tout est FIXE (aucune animation).
   --------------------------------------------------------------------------
   Pas de seuil dur ici : l'image est DELAVEE (sepia, contraste bas, surexposee, legerement floue) puis MANGEE par des brulures de lumiere (halos orange / jaune / blanc en fusion "ecran",
   comme une pellicule voilee), avec poussieres, rayures et grain. La position des brulures change selon la tuile (--bs : 4 dispositions).
     G (DEFAUT) brulure orange : grosse brulure orange / blanche qui entre par un bord + petit eclat oppose + bord de pellicule voile + poussieres + grain
     H surexposee            : grand halo blanc-jaune, image tres delavee
     I pellicule rayee       : brulures brunes aux coins, rayures verticales, ligne de cadre horizontale sombre, poussieres + grain
   ESSAI : ?picfx=G / H / I dans l'adresse, ou ?picfx=FILM (les trois cote a cote sur le filtre AI). REGLAGES : opacity / filter des .crt-fxG / H / I ; couleurs et opacites de .crt-burn*.
   ========================================================================== */
@media only screen and (min-width: 768px) {
	#grid .thumb-soon .crt-pic.crt-fxG { opacity: .34; filter: sepia(1) saturate(1.1) contrast(.9) brightness(1.2) blur(1.4px); mix-blend-mode: screen; }
	#grid .thumb-soon .crt-pic.crt-fxH { opacity: .38; filter: sepia(.8) saturate(.9) contrast(.7) brightness(1.55) blur(1.8px); mix-blend-mode: screen; }
	#grid .thumb-soon .crt-pic.crt-fxI { opacity: .32; filter: sepia(1) contrast(1.1) brightness(1) blur(1.2px); mix-blend-mode: screen; }
	#grid .thumb-soon .crt-burn { mix-blend-mode: screen; opacity: .62; background-repeat: no-repeat;
		background-image:
			radial-gradient(ellipse 55% 85% at calc(-8% + var(--bs, 0) * 36%) calc(25% + var(--bs, 0) * 18%), rgba(255, 255, 230, .95) 0, rgba(255, 190, 70, .8) 14%, rgba(255, 90, 10, .55) 34%, rgba(150, 20, 0, .25) 56%, transparent 74%),
			radial-gradient(ellipse 30% 40% at calc(92% - var(--bs, 0) * 22%) calc(80% - var(--bs, 0) * 20%), rgba(255, 230, 150, .8) 0, rgba(255, 120, 30, .45) 40%, transparent 78%),
			linear-gradient(90deg, transparent 90%, rgba(255, 210, 120, .35) 96%, rgba(255, 255, 255, .7) 100%); }
	#grid .thumb-soon .crt-burn2 { mix-blend-mode: screen; opacity: .65;
		background-image:
			radial-gradient(circle at calc(30% + var(--bs, 0) * 15%) 40%, rgba(255, 255, 255, .9) 0, rgba(255, 240, 200, .6) 18%, rgba(255, 170, 80, .3) 38%, transparent 62%),
			linear-gradient(to bottom, rgba(255, 220, 120, .45) 0, transparent 22%); }
	#grid .thumb-soon .crt-burn3 { mix-blend-mode: screen; opacity: .7;
		background-image:
			radial-gradient(ellipse at calc(100% - var(--bs, 0) * 14%) 0%, rgba(255, 150, 40, .7) 0, rgba(190, 60, 10, .5) 30%, transparent 62%),
			radial-gradient(ellipse at calc(var(--bs, 0) * 12%) 100%, rgba(255, 120, 20, .55) 0, rgba(120, 30, 0, .4) 30%, transparent 55%); }
	#grid .thumb-soon .crt-dust { background-repeat: no-repeat;
		background-image:
			radial-gradient(circle at 12% 22%, rgba(255,255,255,.55) 0, rgba(255,255,255,.55) 1.3px, transparent 2.0px),
			radial-gradient(circle at 31% 68%, rgba(255,255,255,.5) 0, rgba(255,255,255,.5) 1.0px, transparent 1.7px),
			radial-gradient(circle at 47% 15%, rgba(0,0,0,.55) 0, rgba(0,0,0,.55) 1.6px, transparent 2.3px),
			radial-gradient(circle at 58% 81%, rgba(255,255,255,.45) 0, rgba(255,255,255,.45) 1.2px, transparent 1.9px),
			radial-gradient(circle at 73% 34%, rgba(0,0,0,.5) 0, rgba(0,0,0,.5) 1.4px, transparent 2.0999999999999996px),
			radial-gradient(circle at 86% 57%, rgba(255,255,255,.55) 0, rgba(255,255,255,.55) 1.0px, transparent 1.7px),
			radial-gradient(circle at 92% 12%, rgba(255,255,255,.4) 0, rgba(255,255,255,.4) 1.8px, transparent 2.5px),
			radial-gradient(circle at 8% 84%, rgba(0,0,0,.5) 0, rgba(0,0,0,.5) 1.5px, transparent 2.2px),
			radial-gradient(circle at 64% 48%, rgba(255,255,255,.6) 0, rgba(255,255,255,.6) 0.9px, transparent 1.6px),
			radial-gradient(circle at 22% 45%, rgba(255,255,255,.4) 0, rgba(255,255,255,.4) 1.1px, transparent 1.8px),
			radial-gradient(circle at 39% 90%, rgba(0,0,0,.45) 0, rgba(0,0,0,.45) 1.7px, transparent 2.4px),
			radial-gradient(circle at 79% 76%, rgba(255,255,255,.5) 0, rgba(255,255,255,.5) 1.1px, transparent 1.8px),
			radial-gradient(circle at 52% 36%, rgba(255,240,200,.28) 0, rgba(255,240,200,.28) 2.2px, transparent 2.9000000000000004px),
			radial-gradient(circle at 17% 8%, rgba(0,0,0,.5) 0, rgba(0,0,0,.5) 1.2px, transparent 1.9px); }
	#grid .thumb-soon .crt-scratch { background-repeat: no-repeat; background-size: 100% 78%, 100% 55%, 100% 66%; background-position: 0 calc(var(--bs, 0) * 7%), 0 calc(40% - var(--bs, 0) * 6%), 0 calc(20% + var(--bs, 0) * 5%);
		background-image:
			linear-gradient(90deg, transparent calc(8% + var(--bs, 0) * 17%), rgba(255, 255, 255, .30) calc(8% + var(--bs, 0) * 17%), rgba(255, 255, 255, .30) calc(8% + var(--bs, 0) * 17% + 1px), transparent calc(8% + var(--bs, 0) * 17% + 1px)),
			linear-gradient(90deg, transparent calc(61% - var(--bs, 0) * 9%), rgba(255, 245, 220, .22) calc(61% - var(--bs, 0) * 9%), rgba(255, 245, 220, .22) calc(61% - var(--bs, 0) * 9% + 1px), transparent calc(61% - var(--bs, 0) * 9% + 1px)),
			linear-gradient(90deg, transparent calc(83% + var(--bs, 0) * 3%), rgba(0, 0, 0, .35) calc(83% + var(--bs, 0) * 3%), rgba(0, 0, 0, .35) calc(83% + var(--bs, 0) * 3% + 2px), transparent calc(83% + var(--bs, 0) * 3% + 2px)); }
	#grid .thumb-soon .crt-fline { background-image: linear-gradient(to bottom, transparent calc(60% - var(--bs, 0) * 12%), rgba(0, 0, 0, .5) calc(60% - var(--bs, 0) * 12%), rgba(0, 0, 0, .5) calc(62.5% - var(--bs, 0) * 12%), transparent calc(62.5% - var(--bs, 0) * 12%)); }
}

/* ==========================================================================
   IMAGE SPECTRALE ET SUBLIMINALE (27 oct. 2026, v154) : traitements J, K, L des images anciennes. Desktop + tablette.
   --------------------------------------------------------------------------
     J SPECTRALE    : l'image est une APPARITION froide (blanc / bleu / vert pale), tres floue, qui RESPIRE lentement (7 - 11 s, opacite de ~0 a .34) + un ECHO decale (double exposition) qui
                      apparait avec retard. Presque rien n'est visible a un instant donne.
     K SUBLIMINALE  : l'image est presque invisible (opacite .03) ; toutes les 22 - 35 s (rythme different par tuile), elle SURGIT deux fois en ~0,3 s (flashs de ~70 ms, jusqu'a .5) puis disparait.
     L (DEFAUT)     : J + K ensemble.
   Les rythmes sont poses tuile par tuile par le JS (--sd, --sdl, --sf, --sfl) : jamais deux tuiles en phase. Grain fixe. Cadre "NO SIGNAL" par-dessus, inchange.
   "Reduire les animations" (reglage du visiteur) : plus d'animation, apparition fixe tres discrete. ESSAI : ?picfx=J / K / L, ou ?picfx=SPECTRE (J, K, L cote a cote sur le filtre AI).
   REGLAGES : opacites dans les @keyframes spec-breathe / spec-echo / sub-flash ; filter de .crt-fxJ / .crt-fxK ; periodes : JS (applyPic).
   ========================================================================== */
@media only screen and (min-width: 768px) {
	#grid .thumb-soon .crt-pic.crt-fxJ { opacity: .02; filter: grayscale(1) sepia(1) hue-rotate(170deg) saturate(.8) brightness(1.7) contrast(.75) blur(3px); mix-blend-mode: screen; animation: spec-breathe var(--sd, 9s) ease-in-out var(--sdl, 0s) infinite; }
	#grid .thumb-soon .crt-pic.crt-echo { filter: grayscale(1) sepia(1) hue-rotate(170deg) saturate(.8) brightness(1.7) contrast(.75) blur(7px); transform: translate(-12px, 7px) scale(1.05); animation: spec-echo calc(var(--sd, 9s) * 1.3) ease-in-out calc(var(--sdl, 0s) - 2s) infinite; }
	#grid .thumb-soon .crt-pic.crt-fxK { opacity: .03; filter: grayscale(.6) sepia(.5) contrast(1.3) brightness(1.3) blur(1.2px); mix-blend-mode: screen; animation: sub-flash var(--sf, 28s) linear var(--sfl, 0s) infinite; }
}
@keyframes spec-breathe { 0%, 100% { opacity: .02; } 50% { opacity: .34; } }
@keyframes spec-echo { 0%, 100% { opacity: 0; } 55% { opacity: .2; } }
@keyframes sub-flash { 0%, 95.8%, 100% { opacity: .03; } 96% { opacity: .5; } 96.3% { opacity: .03; } 96.7% { opacity: .42; } 97% { opacity: .03; } }
@media (prefers-reduced-motion: reduce) { #grid .thumb-soon .crt-pic.crt-fxJ, #grid .thumb-soon .crt-pic.crt-echo, #grid .thumb-soon .crt-pic.crt-fxK { animation: none; opacity: .12; } }

/* ==========================================================================
   CADRE "NO SIGNAL" AU PREMIER PLAN + IMAGE EXTREMEMENT SOMBRE ET DELAVEE (27 oct. 2026, v155). Desktop + tablette.
   --------------------------------------------------------------------------
   - CADRE (.crt-bezel) : images/portfolio/vignetteNOSIGNAL.webp passe au PREMIER PLAN (derniere couche, au-dessus de l'image, de la trame fixe et du grain ; le texte "No Signal" reste devant) en fusion
     "produit" (multiply) a 100 % : le BLANC de l'ecran devient INVISIBLE, le NOIR du contour reste VISIBLE et net. Le fichier est passe en noir et blanc et durci (grayscale + contraste 1,8 +
     luminosite 1,15) : l'ecran clair (et son halo cyan) est pousse a blanc pur -> aucun voile, aucune teinte sur l'image ; le contour est un noir franc. Remplace le cadre lumineux a 15 %
     (.crt-photo) et son fantome (.crt-ghost), retires des couches.
   - IMAGE (traitement M, DEFAUT) : derriere le cadre, EXTREMEMENT SOMBRE et TOTALEMENT DELAVEE : desaturee, contraste ecrase a 30 % (tout devient gris moyen), assombrie de moitie, legerement floue,
     55 % d'opacite. On ne distingue presque plus que des masses de gris tres sombre. ESSAI : ?picfx=M ; les autres traitements (A - L) passent aussi derriere le cadre.
   REGLAGES : .crt-fxM (filter : contrast .3 = delave ; brightness .55 = sombre ; opacity .55) ; .crt-bezel (filter : contrast / brightness pour un noir plus ou moins franc ; opacity < 1 pour un contour plus doux).
   ========================================================================== */
@media only screen and (min-width: 768px) {
	#grid .thumb-soon .crt-bezel { opacity: 1; mix-blend-mode: multiply; filter: grayscale(1) contrast(1.8) brightness(1.15); }
	#grid .thumb-soon .crt-pic.crt-fxM { opacity: .55; filter: grayscale(.9) sepia(.3) contrast(.3) brightness(.55) blur(.6px); }
}

/* ==========================================================================
   CADRE ADOUCI + IMAGE "EXTINCTION D'UNE VIEILLE TELE", FIGEE (27 oct. 2026, v156). Desktop + tablette.
   --------------------------------------------------------------------------
   - CADRE (.crt-bezel) : le noir etait trop profond. Il est ADOUCI : contraste du fichier abaisse (.75) et luminosite relevee (1.3) -> le noir du contour passe d'environ 4 % a ~20 % de gris
     (un noir de tube, plus un trou), le blanc de l'ecran reste a blanc pur donc INVISIBLE en multiply. Reglage : .crt-bezel { filter : contrast (plus bas = noir plus clair) / brightness }.
   - IMAGE (traitement N, DEFAUT) : le moment ou l'on eteint une vieille tele, FIGE : l'image est delavee (contraste ecrase a 55 %), lumineuse (x1,8) au centre, floue (2,8 px), et SE DISSOUT
     VERS LES BORDS (masque radial) : on devine encore l'image, mais presque plus : elle part dans un flash. AUCUN grain, aucune poussiere, aucun glitch ajoute : seulement l'image et son contraste.
     O : variante ou l'image commence a s'ecraser verticalement (echelle 55 %), plus lumineuse (x2,4). ESSAI : ?picfx=N / O.
   - REGLAGES (.crt-fxN) : opacity (.42), filter (contrast .55 = delave ; brightness 1.8 = flash), blur, et le masque radial (taille du flash).
   ========================================================================== */
@media only screen and (min-width: 768px) {
	#grid .thumb-soon .crt-bezel { filter: grayscale(1) contrast(.75) brightness(1.3); }
	#grid .thumb-soon .crt-pic.crt-fxN { opacity: .42; filter: grayscale(1) contrast(.55) brightness(1.8) blur(2.8px); mix-blend-mode: screen; -webkit-mask-image: radial-gradient(ellipse 62% 70% at 50% 50%, #000 0%, rgba(0, 0, 0, .55) 55%, transparent 100%); mask-image: radial-gradient(ellipse 62% 70% at 50% 50%, #000 0%, rgba(0, 0, 0, .55) 55%, transparent 100%); }
	#grid .thumb-soon .crt-pic.crt-fxO { opacity: .6; filter: grayscale(1) contrast(.5) brightness(2.4) blur(2.5px); mix-blend-mode: screen; transform: scaleY(.55); -webkit-mask-image: radial-gradient(ellipse 66% 70% at 50% 50%, #000 0%, rgba(0, 0, 0, .55) 55%, transparent 100%); mask-image: radial-gradient(ellipse 66% 70% at 50% 50%, #000 0%, rgba(0, 0, 0, .55) 55%, transparent 100%); }
}

/* ==========================================================================
   IMAGE SURCONTRASTEE + PETITE NEIGE LEGERE (27 oct. 2026, v157). Desktop + tablette.
   --------------------------------------------------------------------------
   - IMAGE (traitement P, DEFAUT) = le traitement N (extinction de vieille tele : noir et blanc, floue, qui se dissout vers les bords) mais SURCONTRASTEE : contraste x8 (avant .55) -> on ne garde que des
     taches blanches et noires dures ; luminosite ramenee a 1 (avant 1,8) pour que le seuil blanc / noir reste equilibre ; et a UN TIERS DE L'OPACITE (.14 au lieu de .42).
   - PETITE NEIGE LEGERE par-dessus l'image (sous le cadre) : grain fin de vieux televiseur, opacite .07, saut toutes les .5 s (plus calme que celle de la v148 : .08 / .35 s).
     Toutes les neiges des tuiles changent a la meme seconde (horloge commune) pour que ca ressemble a UN ecran et non a huit.
   - REGLAGES : .crt-fxP { opacity (.14), filter (contrast 8 = durete) } ; .crt-snow.crt-light { opacity .07 ; duree .5 s }. Plus visible : opacity .20 ; plus dur : contrast 14.
   ========================================================================== */
@media only screen and (min-width: 768px) {
	#grid .thumb-soon .crt-pic.crt-fxP { opacity: .14; filter: grayscale(1) blur(1.5px) contrast(8) brightness(1); mix-blend-mode: screen; -webkit-mask-image: radial-gradient(ellipse 62% 70% at 50% 50%, #000 0%, rgba(0, 0, 0, .55) 55%, transparent 100%); mask-image: radial-gradient(ellipse 62% 70% at 50% 50%, #000 0%, rgba(0, 0, 0, .55) 55%, transparent 100%); }
	#grid .thumb-soon .crt-snow.crt-light { opacity: .07; animation-duration: .5s; }
}

/* ==========================================================================
   FIN DU CLIGNOTEMENT BLANC / NOIR + IMAGES A 10 % (27 oct. 2026, v158). Desktop + tablette.
   --------------------------------------------------------------------------
   SYMPTOME (capture Safari 17:12) : chaque vignette alternait entre deux etats, un NOIR (le bon) et un BLANC (la 8e tuile de la capture est entierement blanche : on y voit l'ecran blanc du cadre).
   CAUSE : le cadre "NO SIGNAL" etait pose en fusion "produit" (mix-blend-mode: multiply, v155) pour que son blanc soit invisible. Safari abandonne parfois ce mode de fusion sur une couche
   quand un calque voisin s'anime (la neige) : le cadre s'affiche alors tel quel, blanc compris, puis revient. L'etat blanc = la fusion qui saute.
   CORRECTIF : PLUS AUCUNE FUSION dans la pile des tuiles. Le cadre est maintenant un PNG TRANSPARENT (fabrique a partir de ton fichier vignetteNOSIGNAL.webp, integre dans ce CSS : 10 Ko) :
   le blanc de l'ecran est transparent (donc invisible), le noir du contour est un noir semi-transparent (le meme noir adouci que la v156 : ~84 % au plus). Meme rendu, sans fusion -> plus de blanc.
   Le voile noir de la tuile (::before) passe aussi de "multiply" a un noir transparent ordinaire (rendu identique). Le fichier images/portfolio/vignetteNOSIGNAL.webp n'est donc plus charge ;
   si tu changes ce cadre, dis-le-moi : je regenere le PNG integre.
   IMAGES : opacite .14 -> .10 (si elles devaient etre a 100 %, elles sont a 10 %), et fusion "ecran" retiree (sans effet visible sur un fond sombre).
   REGLAGES : .crt-bezel { opacity : .8 pour un contour plus doux } ; .crt-fxP { opacity .10 }.
   ========================================================================== */
@media only screen and (min-width: 768px) {
	#grid .thumb-soon::before { mix-blend-mode: normal; background: rgba(0, 0, 0, var(--soon-dark)); }
	#grid .thumb-soon .crt-bezel { background: url("data:image/png;base64,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") center / cover no-repeat; mix-blend-mode: normal; filter: none; opacity: 1; }
	#grid .thumb-soon .crt-pic.crt-fxP { opacity: var(--picop, .03); mix-blend-mode: normal; }   /* (29 oct.) images de fond a 3 % (avant : 4 %, 6 %, 5 %, 10 % en essai) (avant : 2,5 %). v164 : images a 2,5 % (entre 2 et 3 %) (v163 : 5 % ; v161 : 1 % ; v160 : 5 % ; v159 : 100 % pour juger ; v158 : .10). Essai sans modifier le code : ?picop=10 (10 %), ?picop=100... dans l'adresse. */
}

/* ==========================================================================
   LOGO PAUL LEON EN FILIGRANE (27 oct. 2026, v162). Desktop + tablette.
   --------------------------------------------------------------------------
   Le logo qui sert de bouton retour a l'index (images/logopaulleon_OFF.svg, le meme fichier que le haut de page ; chemin relatif a ce CSS : ../images/ -> marche pour FR et EN) est pose en
   BLANC a 3 % d'opacite, EN PLEIN MILIEU de chaque tuile "No Signal" : au-dessus de l'image et de la neige, SOUS le cadre. Blanc pur garanti : filtre brightness(0) invert(1) (quelle que soit la
   couleur du SVG : le fichier OFF est un gris tres clair). Hauteur = 56 % de celle de la tuile, centre exact. Fichier absent : rien ne s'affiche.
   REGLAGES : .crt-logo { opacity .03 ; background-size : auto 56% = taille } ; pour la version ON : remplacer logopaulleon_OFF.svg par logopaulleon_ON.svg. POUR RETIRER : enlever 'logo' de PIC_FX.P (JS).
   ========================================================================== */
@media only screen and (min-width: 768px) {
	#grid .thumb-soon .crt-logo { background: url("../images/logopaulleon_OFF.svg") center / auto 56% no-repeat; opacity: var(--logoop, .03); filter: brightness(0) invert(1); mix-blend-mode: normal; }   /* (29 oct.) logo PAUL LEON a 3 % (avant : 4 %, 6 %, 5 %). v168 : retour au logo BLANC (v167 : noir, annule) ; v163 : 2 % (v162 : 3 %) */
}

/* ==========================================================================
   GLITCH ALEATOIRE DU LOGO PAUL LEON (27 oct. 2026, v165). Desktop + tablette.
   --------------------------------------------------------------------------
   Quatre copies du logo, chacune d'une couleur du glitch du site (rose #ff00a8 / cyan #00ffff / vert fluo #c0ff01 / jaune #ffff00), decoupees en bandes horizontales et decalees par
   js/portfolio-coming-soon.js (logoBurst) : le logo est utilise comme MASQUE (la forme du SVG), la couleur vient du fond du calque. Invisibles au repos (opacity 0) ; pendant un glitch, 11 %
   d'opacite (CONFIG.logoGlitch.opacity). Le logo de base (.crt-logo) reste a 2 %. Pas de mode de fusion (cf. v158). Meme chemin que .crt-logo.
   REGLAGES : CONFIG.logoGlitch dans le JS (opacity, pause = delai moyen par tuile, minGap, frames, offset en px) ; couleurs ci-dessous. ESSAI RAPIDE : ?logoglitch=fast.
   ========================================================================== */
@media only screen and (min-width: 768px) {
	#grid .thumb-soon .crt-lg { opacity: 0; mix-blend-mode: normal; -webkit-mask: url("../images/logopaulleon_OFF.svg") center / auto 56% no-repeat; mask: url("../images/logopaulleon_OFF.svg") center / auto 56% no-repeat; }
	#grid .thumb-soon .crt-lgA { background: #ff00a8; }
	#grid .thumb-soon .crt-lgB { background: #00ffff; }
	#grid .thumb-soon .crt-lgC { background: #c0ff01; }
	#grid .thumb-soon .crt-lgD { background: #ffff00; }
}

/* ==========================================================================
   GLITCH DU LOGO SANS MASQUE, DANS LA BOUCLE DU TEXTE (27 oct. 2026, v169). Desktop + tablette.
   --------------------------------------------------------------------------
   v165 colorait les copies du logo avec un MASQUE CSS (mask-image sur le SVG) : un masque charge depuis un fichier local (file://) est refuse par plusieurs navigateurs -> le glitch pouvait ne pas
   s'afficher du tout (c'est ce qu'on a constate : "je ne le vois pas"). Maintenant : DEUX calques seulement, le logo en BLANC (brightness(0) invert(1)) avec deux franges colorees en OMBRES PORTEES
   (drop-shadow, qui suit la forme du logo) : calque A rose / cyan, calque B vert fluo / jaune, decales de 6 px. js/portfolio-coming-soon.js les decoupe en bandes, les decale et les montre a 100 %
   pendant un glitch de la tuile (meme moment que le "No Signal"). Invisibles au repos. Aucun mode de fusion, aucun masque.
   ========================================================================== */
@media only screen and (min-width: 768px) {
	#grid .thumb-soon .crt-lg { opacity: 0; mix-blend-mode: normal; -webkit-mask: none; mask: none; background: url("../images/logopaulleon_OFF.svg") center / auto 56% no-repeat; }
	#grid .thumb-soon .crt-lgA { filter: brightness(0) invert(1) drop-shadow(6px 0 0 #ff00a8) drop-shadow(-6px 0 0 #00ffff); }
	#grid .thumb-soon .crt-lgB { filter: brightness(0) invert(1) drop-shadow(-4px 0 0 #c0ff01) drop-shadow(4px 0 0 #ffff00); }
}

/* ==========================================================================
   GLITCH DES IMAGES D'ARRIERE-PLAN (27 oct. 2026, v173 -- ESSAI). Desktop + tablette.
   --------------------------------------------------------------------------
   Calque .crt-ig = copie de l'image de la tuile (meme fichier que .crt-pic, pose par le JS), invisible au repos ; pendant une rafale (js : imgBurst) il montre 1 a 3 bandes de l'image decalees
   horizontalement, a 3 % d'opacite (CONFIG.imgGlitch.opacity). Noir et blanc dur (contraste x6) comme le traitement P. Aucun mode de fusion, aucun masque.
   ========================================================================== */
@media only screen and (min-width: 768px) {
	#grid .thumb-soon .crt-ig { opacity: 0; mix-blend-mode: normal; background-size: cover; background-position: center; background-repeat: no-repeat; filter: grayscale(1) contrast(6) brightness(1.1); }
}

/* ==========================================================================
   NO SIGNAL EN MAJUSCULES + LUEUR BLEUTEE DE TELE QUI VACILLE (29 oct. 2026). Desktop + tablette.
   --------------------------------------------------------------------------
   - Le texte de la tuile est affiche en MAJUSCULES (le JS envoie deja "NO SIGNAL" ; text-transform en filet de securite, et les calques du glitch heritent).
   - .crt-tvlight : calque pose par le JS (PIC_FX.P, 'tvlight') au-dessus de l'image et de la neige, SOUS le logo-glitch, le cadre et le texte. Une lueur bleue froide, large et douce, centree
     un peu au-dessus du milieu (comme la lumiere d'un ecran qui eclaire une piece), dont l'opacite vacille de facon irreguliere. Duree (10 - 17 s, vacillement lent et doux) et phase tirees au hasard par tuile dans le JS.
     Aucun mode de fusion (cf. v158), animation sur "opacity" seulement ; en pause hors ecran (.soon-paused) ; figee et douce si "reduire les animations".
   REGLAGES : --tvl (intensite, .33 = defaut = 33 % du premier reglage ; ESSAI : ?tvlight=100 = plein) ; couleurs du degrade ; keyframes tvlightFlicker (amplitude du vacillement).
   POUR RETIRER : enlever 'tvlight' de PIC_FX.P dans le JS.
   ========================================================================== */
@media only screen and (min-width: 768px) {
	#grid .thumb-soon .soon-sector { text-transform: uppercase; }
	#grid .thumb-soon .crt-tvlight {
		mix-blend-mode: normal;
		background:
			radial-gradient(ellipse 62% 58% at 50% 42%, rgba(120, 185, 255, calc(.42 * var(--tvl, .33))) 0%, rgba(70, 130, 255, calc(.22 * var(--tvl, .33))) 38%, rgba(40, 90, 230, calc(.08 * var(--tvl, .33))) 66%, rgba(40, 90, 230, 0) 100%),
			radial-gradient(ellipse 100% 100% at 50% 50%, rgba(30, 70, 200, calc(.07 * var(--tvl, .33))) 0%, rgba(30, 70, 200, 0) 80%);
		opacity: .6;
		animation: tvlightFlickerA 13s ease-in-out infinite;   /* nom, duree et phase REMPLACES par tuile dans le JS */
		will-change: opacity;
	}

	@keyframes tvlightFlickerA {
		0% { opacity: .70; }
		12% { opacity: .95; }
		25% { opacity: .55; }
		38% { opacity: .85; }
		50% { opacity: .62; }
		62% { opacity: 1; }
		75% { opacity: .58; }
		88% { opacity: .82; }
		100% { opacity: .70; }
	}
	@keyframes tvlightFlickerB {
		0% { opacity: .60; }
		12% { opacity: .82; }
		25% { opacity: 1; }
		38% { opacity: .66; }
		50% { opacity: .50; }
		62% { opacity: .78; }
		75% { opacity: .92; }
		88% { opacity: .56; }
		100% { opacity: .60; }
	}
	@keyframes tvlightFlickerC {
		0% { opacity: .85; }
		12% { opacity: .58; }
		25% { opacity: .74; }
		38% { opacity: 1; }
		50% { opacity: .64; }
		62% { opacity: .52; }
		75% { opacity: .90; }
		88% { opacity: .70; }
		100% { opacity: .85; }
	}
}
@media (prefers-reduced-motion: reduce) { #grid .thumb-soon .crt-tvlight { animation: none !important; opacity: .55; } }
