<!doctype html>
<html lang="fr">

<head>
  <script>
 (function () {
 try {
 var pref = localStorage.getItem('cookie-consent');
 if (pref === 'denied') {
 window['ga-disable-G-PBLFFTB4GZ'] = true;
 }
 } catch (e) { /* ignore */ }
 })();
 </script>
 <script async src="https://www.googletagmanager.com/gtag/js?id=G-PBLFFTB4GZ"></script>
 <script>
 window.dataLayer = window.dataLayer || [];
 function gtag() { dataLayer.push(arguments); }
 gtag('js', new Date());

 gtag('config', 'G-PBLFFTB4GZ');
 </script>
 <meta charset="utf-8">
 <meta name="viewport" content="width=device-width, initial-scale=1">
 <meta name="robots" content="index,follow">
 <meta name="robots" content="max-image-preview:large">
 <meta name="theme-color" content="#ff5757">
 <title> Tatouage unique et personnalisé à Grenoble  - Studio Pixel</title>
  <link rel="canonical" href="https://lestudiopixel.com/">
 <meta name="description" content="Studio Pixel, salon de tatouage priv&eacute; &agrave; Grenoble: cr&eacute;ations sur mesure, artistes r&eacute;sidents, guests et rendez-vous personnalis&eacute;s.">
  <link rel="icon" href="/images/pixel-logo-square-32x32.webp" type="image/webp">
  
    <meta property="og:title" content="Tatouage unique et personnalis&eacute; &agrave; Grenoble - Studio Pixel">
 <meta property="og:description" content="Studio Pixel, salon de tatouage priv&eacute; &agrave; Grenoble: cr&eacute;ations sur mesure, artistes r&eacute;sidents, guests et rendez-vous personnalis&eacute;s.">
 <meta property="og:image" content="https://lestudiopixel.com/images/hero-dessin.webp">
 <meta property="og:image:width" content="1200">
 <meta property="og:image:height" content="675">
 <meta property="og:url" content="https://lestudiopixel.com/">
 <meta property="og:type" content="website">
 <meta name="twitter:card" content="summary_large_image">
 <meta name="twitter:title" content="Tatouage unique et personnalis&eacute; &agrave; Grenoble - Studio Pixel">
 <meta name="twitter:description" content="Studio Pixel, salon de tatouage priv&eacute; &agrave; Grenoble: cr&eacute;ations sur mesure, artistes r&eacute;sidents, guests et rendez-vous personnalis&eacute;s.">
 <meta name="twitter:image" content="https://lestudiopixel.com/images/hero-dessin.webp">
    <link rel="preload" as="image" href="/images/hero-dessin.webp" type="image/webp" fetchpriority="high">
 <link rel="preload" as="image" href="/images/hero-dessin-mobile.webp" type="image/webp" media="(max-width: 768px)">
 <style>
 .wrap.hero {
 background-image: url('/images/hero-dessin.webp');
 }

 @media (max-width: 767px) {
 .wrap.hero {
 background-image: url('/images/hero-dessin-mobile.webp');
 background-position: center;
 }
 }
 </style>
  <link href="/src/css/home-light.css?v251021" rel="stylesheet" />

 <!-- navigation styling moved to /src/css/home-light.css -->


 <script>
 // Public API base for dynamic refresh when served from static domain
 // Recommended for dynamic PHP API: https://api.lestudiopixel.com
 // (If you set a value that already ends with /api, code below will not add it again.)
 window.API_BASE = "https://api.lestudiopixel.com";
 </script>
 <script src="/assets/v2/acquisition-attribution.js"></script>
 <script src="/assets/v2/math-captcha.js"></script>
  <script type="application/ld+json">
 {
 "@context": "https://schema.org",
 "@type": "WebSite",
 "name": "Studio Pixel Tatouage Grenoble",
 "url": "https://lestudiopixel.com"
 }
 </script>
 <script type="application/ld+json">
 {
 "@context": "https://schema.org",
 "@type": "WebPage",
 "name": " Tatouage unique et personnalisé à Grenoble ",
 "url": "https://lestudiopixel.com/"
 }
 </script>
  <script type="application/ld+json">
 {
 "@context": "https://schema.org",
 "@type": "TattooParlor",
 "name": "Studio Pixel",
 "url": "https://lestudiopixel.com/",
 "logo": "https://lestudiopixel.com/images/studiopixel-logo-vecto.svg",
 "image": "https://lestudiopixel.com/images/contact.webp",
 "address": {
 "@type": "PostalAddress",
 "streetAddress": "126 rue de Stalingrad",
 "addressLocality": "Grenoble",
 "postalCode": "38100",
 "addressCountry": "FR"
 },
 "contactPoint": {
 "@type": "ContactPoint",
 "contactType": "customer service",
 "email": "hello@lestudiopixel.com"
 }
 }
 </script>

 <script>
 // Ensure getJSON is available early for pages that call it before footer scripts
 if (!window.getJSON) {
 window.getJSON = function (url, ms) {
 ms = ms || 5000;
 return new Promise(function (res) {
 var c = new AbortController();
 var t = setTimeout(function () { c.abort(); }, ms);
 fetch(url, { signal: c.signal, credentials: 'omit' })
 .then(function (r) { return r.json(); })
 .then(function (j) { clearTimeout(t); res(j); })
 .catch(function () { res(null); });
 });
 };
 }
 </script>
</head>

<body class="is-home">
 <header class="site-header">
 <div class="wrap header-bar">
 <a class="brand" href="/" aria-label="Accueil">
 <img class="brand-logo" src="/images/pixel-logo-serre.svg" alt="Studio Pixel" width="140" height="28">
 </a>
 <button class="nav-toggle" aria-controls="mainnav" aria-expanded="false" aria-label="Menu">☰</button>
 <nav id="mainnav" class="main-nav" aria-label="Navigation principale">
 <button class="nav-close" type="button" aria-label="Fermer">×</button>
 <a class="nav-link" href="/artistes/">Artistes</a>
 <a class="nav-link" href="/posts/">Actu</a>
 <a class="nav-link" href="/flashs/">Flashs</a>
 <a class="nav-link" href="/tattoos/">Tattoos</a>
 <a class="nav-link" href="/guests/">Guests</a>
 <a class="nav-link" href="/soins/">Soins</a>
 <a class="nav-link" href="/faq/">FAQ</a>
 <a class="nav-link" href="/cowork/">Cowork</a>
 <a class="btn btn--nav" href="/rdv/" rel="nofollow">Rendez-vous</a>
 </nav>
 </div>
 </header>

 

 
 <header class="wrap hero" aria-labelledby="home-hero-title" data-updated-at="0" id="home-hero">
 <div class="hero-content">
 <h1 id="home-hero-title">Tatouages sur‑mesure, r&eacute;alis&eacute;s avec soin &agrave; Grenoble</h1>
 <p class="hero-sub">Des pi&egrave;ces uniques, pens&eacute;es pour toi par notre &eacute;quipe d&rsquo;artistes.</p>
 <div class="cta-row hero-ctas">
  <a id="hero-cta1" class="btn btn--ghost-inv" href="/artistes/"
 aria-label="Nos artistes">Nos artistes</a>
   <a id="hero-cta2" class="btn btn--ghost" href="/rdv/" aria-label="Prendre rendez-vous">Prendre rendez-vous</a>
  </div>
 </div>
 <style>
 /* Hero loading state: hide content until data is ready or timeout */
 html.hero-loading .hero {
 opacity: 0;
 visibility: hidden;
 transition: opacity 0.3s ease;
 }
 </style>
 <script>
 (function () {
 // Add loading class immediately
 document.documentElement.classList.add('hero-loading');

 // Function to reveal hero
 function revealHero() {
 document.documentElement.classList.remove('hero-loading');
 }

 // Timeout fallback (show placeholder if too long)
 const timeoutId = setTimeout(revealHero, 2000);

 // Check for dynamic updates
 const hero = document.getElementById('home-hero');
 if (!hero) { revealHero(); return; }

 const localTime = parseInt(hero.getAttribute('data-updated-at') || '0', 10);
 const apiBase = window.API_BASE || 'https://api.lestudiopixel.com';
 const url = apiBase.replace(/\/$/, '') + '/settings.json';

 fetch(url)
 .then(r => r.json())
 .then(data => {
 if (!data || !data.hero) { revealHero(); return; }
 const remoteTime = parseInt(data.updated_at || '0', 10);

 if (remoteTime > localTime) {
 console.log('Updating hero from remote settings...');
 const h = data.hero;

 // Update Text
 if (h.title) document.getElementById('home-hero-title').textContent = h.title;
 if (h.subtitle) document.querySelector('.hero-sub').textContent = h.subtitle;

 // Update CTAs
 const cta1 = document.getElementById('hero-cta1');
 if (cta1 && h.cta1_text) { cta1.textContent = h.cta1_text; cta1.setAttribute('aria-label', h.cta1_text); }
 if (cta1 && h.cta1_link) cta1.href = h.cta1_link;

 const cta2 = document.getElementById('hero-cta2');
 if (cta2 && h.cta2_text) { cta2.textContent = h.cta2_text; cta2.setAttribute('aria-label', h.cta2_text); }
 if (cta2 && h.cta2_link) cta2.href = h.cta2_link;

 // Update Images (Background)
 if (h.image_desktop || h.image_mobile) {
 const style = document.createElement('style');
 let css = '';
 if (h.image_desktop) css += `.wrap.hero { background-image: url('${h.image_desktop}') !important; }`;
 if (h.image_mobile) css += `@media (max-width: 767px) { .wrap.hero { background-image: url('${h.image_mobile}') !important; background-position: center !important; } }`;
 style.textContent = css;
 document.head.appendChild(style);
 }
 }
 // Clear timeout and reveal
 clearTimeout(timeoutId);
 revealHero();
 })
 .catch(e => {
 console.warn('Failed to check remote settings:', e);
 clearTimeout(timeoutId);
 revealHero();
 });
 })();
 </script>
 </header>

 <!-- Hidden blog shell to render a classical blog page via JS when needed -->
 <style>
 /* Simplified blog hero (no loading overlays) */
 #blog-hero {
 height: 100svh;
 min-height: 100svh;
 overflow: hidden;
 }
 </style>
 <div id="blog-shell" style="display:none;">
 <!-- Optional hero; JS can add background-image and set title/date -->
 <header class="wrap hero post-hero" id="blog-hero" aria-labelledby="post-title">
 <div class="hero-content">
 <h1 id="post-title">Article</h1>
 <p class="hero-sub" id="post-date"></p>
 </div>
 </header>
 <!-- Main content area -->
 <div class="wrap content-wrap" id="blog-content-wrap">
 <article class="section" aria-labelledby="post-title">
 <div class="section content" id="post-body"></div>
 </article>
 </div>
 <!-- End blog shell -->
 <noscript>
 <div class="wrap content-wrap">
 <p class="muted">Activez JavaScript pour charger l’article.</p>
 </div>
 </noscript>
 </div>

 <!-- Single global wrapper for page content (keeps header/footer wraps separate) -->
 <div class="wrap content-wrap">

 <!-- simplified about block (placed after hero) -->
 <div class="body markup about-grid" dir="auto">
 <div class="about-media" aria-hidden="true"></div>
 <div class="about-text">
 <h2 id="about-title">Le Studio Pixel est un collectif grenoblois, créé en 2018 et constitué d’artistes
 tatoueur·euses.</h2>
 <p>Initié par <a href="/artistes#artist-arthak">Arthak</a> & <a href="/artistes#artist-ptitoc">Ptitoc</a>, le
 collectif s’est ensuite agrandi avec <a href="/artistes#artist-flyean">Flyean</a>, <a
 href="/artistes#artist-max-graire">Max Graire</a> et <a href="/artistes#artist-yoyo">Yoyo</a> (pour ne citer
 qu'eux !).</p>
 <p>Studio de tatouage privé, uniquement sur rendez‑vous. Nous privilégions des échanges respectueux et adaptés à
 chaque personne. Les styles vont de la pop culture flashy au noir fin, en passant par le semi‑réalisme floral —
 <em>aussi diversifié qu’éclectique</em>.
 </p>
 <p>Découvre l’équipe complète sur <a href="/artistes/">la page Artistes</a>.</p>
 </div>
 </div>

 
 <section class="category-nav" aria-labelledby="category-nav-title">
 <div class="wrap">
 <div class="category-nav__head">
 <h2 id="category-nav-title">Explorer par styles</h2>
 <p class="category-nav__desc">Choisis une catégorie pour parcourir nos galeries.</p>
 </div>
 <div class="category-pills" id="category-pills" role="list">
  <a class="category-pill" role="listitem" href="/galerie/categorie/animalier/">Animalier</a>
  <a class="category-pill" role="listitem" href="/galerie/categorie/challenge-du-mardi/">Challenge du mardi</a>
  <a class="category-pill" role="listitem" href="/galerie/categorie/cicatrise/">Cicatris&eacute;</a>
  <a class="category-pill" role="listitem" href="/galerie/categorie/cover/">Cover</a>
  <a class="category-pill" role="listitem" href="/galerie/categorie/dotwork/">Dotwork</a>
  <a class="category-pill" role="listitem" href="/galerie/categorie/fineline/">Fineline</a>
  <a class="category-pill" role="listitem" href="/galerie/categorie/floral/">Floral</a>
  <a class="category-pill" role="listitem" href="/galerie/categorie/fun/">Fun</a>
  <a class="category-pill" role="listitem" href="/galerie/categorie/guest/">Guest</a>
  <a class="category-pill" role="listitem" href="/galerie/categorie/halloween/">Halloween</a>
  <a class="category-pill" role="listitem" href="/galerie/categorie/micro-realisme/">Micro-r&eacute;alisme</a>
  <a class="category-pill" role="listitem" href="/galerie/categorie/neo-traditionnel/">N&eacute;o-Traditionnel</a>
  <a class="category-pill" role="listitem" href="/galerie/categorie/neotribal/">N&eacute;otribal</a>
  <a class="category-pill" role="listitem" href="/galerie/categorie/old-school/">Old school</a>
  <a class="category-pill" role="listitem" href="/galerie/categorie/onirique/">Onirique</a>
  <a class="category-pill" role="listitem" href="/galerie/categorie/organique/">Organique</a>
  <a class="category-pill" role="listitem" href="/galerie/categorie/ornemental/">Ornemental</a>
  <a class="category-pill" role="listitem" href="/galerie/categorie/pop-culture/">Pop Culture</a>
  <a class="category-pill" role="listitem" href="/galerie/categorie/reparateur/">R&eacute;parateur</a>
  <a class="category-pill" role="listitem" href="/galerie/categorie/scribbling/">Scribbling</a>
  <a class="category-pill" role="listitem" href="/galerie/categorie/typographie/">Typographie</a>
  </div>
 </div>
 </section>

 <!-- close content wrap to allow full-bleed howto section -->
 </div>

 <!-- Dossiers (blog) carousel -->
<section class="section" id="dossiers" aria-labelledby="dossiers-title">
 <div class="wrap" style="padding-left: 0%; padding-right: 0%;padding-top:50px;padding-bottom:50px;">
 <h2 id="dossiers-title" class="section-title" >Ça se passe au studio</h2>
 <style>
 #dossiers {
 color: var(--text);
 }
 /* Mobile-first: vertical stack, each card with 20px left offset */
 #dossiers-row{display:flex;gap:12px;overflow-x:auto;padding:8px 2px 6px;scroll-snap-type:x mandatory;-webkit-overflow-scrolling:touch;scrollbar-width:none;-ms-overflow-style:none}
 
 #dossiers-row::-webkit-scrollbar{display:none}
 .dossier-card{margin-left:20px;margin-right:20px;max-width:70vw;opacity:.7;transition:opacity .25s ease, transform .25s ease;scroll-snap-align:center;background:var(--card);color:var(--text);display:flex;flex-direction:column;gap:8px;text-decoration:none;border-radius:10px;overflow:hidden;box-shadow:0 4px 20px rgba(0,0,0,.15);border:1px solid rgba(0,0,0,0.05)}
 .dossier-card.is-active{opacity:1;transform:scale(1.01)}
 .dossier-card img{width:100%;height:auto;aspect-ratio:16/9;object-fit:cover;display:block}
 .dossier-card .box{padding:12px 14px;display:flex;flex-direction:column;gap:6px}
 .dossier-card .date{font-size:12px;color:var(--muted)}
 .dossier-card h3{margin:0;font-size:18px;line-height:1.25;color:var(--text);}
 .dossier-card p{margin:0;color:var(--muted);font-size:14px; }
 .dossier-card:hover{ text-decoration: none; }
 .dossier-card:focus-visible{ text-decoration: none; }
 @media (prefers-color-scheme: dark){
 .dossier-card{box-shadow:0 10px 28px rgba(0,0,0,0.45);border-color:rgba(255,255,255,0.08)}
 .dossier-card .date{color:rgba(255,255,255,0.72)}
 .dossier-card p{color:rgba(255,255,255,0.85)}
 }
 
 @media (max-width: 1023px){
 #dossiers-title {
 margin-top: 0;
 margin-bottom: 25px;
 text-align: left !important;
 padding-left: 20px
 }
 }

 /* Desktop: classic 4-column grid */
 @media (min-width: 1024px){
 #dossiers-row{display:grid;grid-template-columns:1fr;gap:16px;overflow:visible;padding:0;scrollbar-width:none;-ms-overflow-style:none}
 
 #dossiers-row{grid-template-columns:repeat(4, minmax(0,1fr));gap:20px}
 .dossier-card{margin-left:0}
 }
 </style>
 <div class="dossiers-row" id="dossiers-row" role="list" aria-live="polite">
 <!-- cards inserted by JS -->
 </div>
 </div>
</section>

 <script>
 (function(){
 var row = document.getElementById('dossiers-row'); if (!row) return;
 function card(it){
 var a = document.createElement('a');
 a.className = 'card dossier-card';
 a.setAttribute('role','listitem');
 a.href = '/post/' + (it.slug||'');
 a.style.flex = '0 0 auto';
 var imgUrl = String(it.thumb_url||it.image_url||'');
 if (imgUrl) {
 var img = document.createElement('img');
 img.loading = 'lazy'; img.decoding='async'; img.alt='';
 img.src = imgUrl;
 img.onerror = function () {
 if (!img.dataset.retried) {      
 img.dataset.retried = true;
 try {
 const p = new URL(imgUrl, window.location.href).pathname;
 img.src = 'https://v2.lestudiopixel.com' + p;
 console.log(img.src);
 } catch (e) {
 img.src = 'https://v2.lestudiopixel.com' + imgUrl;
 console.log(img.src);
 }
 } else {
 console.warn('Impossible de charger l’image après deux essais :', img.src);
 }
 };
 a.appendChild(img);
 }
 var box = document.createElement('div'); box.className='box';
 var d = document.createElement('div'); d.className='muted date'; d.textContent = it.date || ''; box.appendChild(d);
 var h = document.createElement('h3'); h.textContent = it.title || it.slug || ''; box.appendChild(h);
 if (it.excerpt){ var p = document.createElement('p'); p.textContent = it.excerpt; box.appendChild(p); }
 a.appendChild(box);
 return a;
 }
 function sortFeaturedThenDate(items){
 var a = (items||[]).slice(0);
 a.sort(function(x,y){
 var fx = !!(x && x.featured), fy = !!(y && y.featured);
 // Ensure featured posts come first
 if (fx !== fy) return fx ? -1 : 1; // featured first
 var dx = String(x.date||''); var dy = String(y.date||'');
 return dy.localeCompare(dx);
 });
 return a;
 }
 var remote = (window.API_BASE || 'https://api.lestudiopixel.com').replace(/\/$/, '') + '/blog/posts-manifest?limit=4';

   var local = remote;
 
 getJSON(remote, 4500).then(function(j){ return (j&&j.items&&j.items.length)?j:getJSON(local, 4500); }).then(function(j){
 // If we are on a post page, exclude the current post from the list
 function currentPostSlug(){
 try {
 var p = String(window.location && window.location.pathname || '');
 var m = p.match(/\/post\/([a-z0-9-]+)\/?$/);
 return m ? m[1] : null;
 } catch(e) { return null; }
 }
 var items = (j&&j.items)||[];
 var cur = currentPostSlug();
 if (cur) {
 items = items.filter(function(it){ return String(it && it.slug || '') !== cur; });
 }
 var ordered = sortFeaturedThenDate(items).slice(0,4);
 if (!ordered.length) { row.innerHTML = '<p class="muted" style="color:#fff;opacity:.9">Aucun article pour le moment.</p>'; return; }
 var frag = document.createDocumentFragment();
 ordered.forEach(function(it){ frag.appendChild(card(it)); });
 row.appendChild(frag);
 // Active card highlight with snap effect
 try{
 var opts = { root: row, threshold: 0.6 };
 var io = new IntersectionObserver(function(entries){
 entries.forEach(function(en){ var el=en.target; if (en.isIntersecting){ el.classList.add('is-active'); } else { el.classList.remove('is-active'); } });
 }, opts);
 Array.prototype.forEach.call(row.querySelectorAll('.dossier-card'), function(el){ io.observe(el); });
 }catch(e){ /* ignore */ }
 }).catch(function(){ row.innerHTML = '<p class="muted" style="color:#fff;opacity:.9">Impossible de charger les dossiers.</p>'; });
 })();
 </script>

 <section class="section howto" aria-labelledby="howto-title">
 <div class="wrap">
 <h2 id="howto-title" class="section-title howto-title">Se faire tatouer en 3 étapes</h2>
 <div class="howto-steps">
 <article class="howto-step">
 <!-- icon: contact (from contact.svg) -->
 <svg class="howto-icon" width="48" height="48" viewBox="0 0 24 24" fill="none" role="img" aria-hidden="true">
 <path
 d="M4 18L9 12M20 18L15 12M3 8L10.225 12.8166C10.8665 13.2443 11.1872 13.4582 11.5339 13.5412C11.8403 13.6147 12.1597 13.6147 12.4661 13.5412C12.8128 13.4582 13.1335 13.2443 13.775 12.8166L21 8M6.2 19H17.8C18.9201 19 19.4802 19 19.908 18.782C20.2843 18.5903 20.5903 18.2843 20.782 17.908C21 17.4802 21 16.9201 21 15.8V8.2C21 7.0799 21 6.51984 20.782 6.09202C20.5903 5.71569 20.2843 5.40973 19.908 5.21799C19.4802 5 18.9201 5 17.8 5H6.2C5.0799 5 4.51984 5 4.09202 5.21799C3.71569 5.40973 3.40973 5.71569 3.21799 6.09202C3 6.51984 3 7.07989 3 8.2V15.8C3 16.9201 3 17.4802 3.21799 17.908C3.40973 18.2843 3.71569 18.5903 4.09202 18.782C4.51984 19 5.07989 19 6.2 19Z"
 stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
 </svg>
 <strong class="howto-step-title">1 — Prendre contact</strong>
 <p class="howto-step-desc">Explique ton projet par email ou au studio. On discute style, taille et emplacement.
 </p>
 <a class="btn howto-cta btn--ghost" href="/artistes/" aria-label="Prendre rendez-vous">Trouve ton artiste</a>
 </article>
 <article class="howto-step">
 <!-- icon: draw/pencil (from draw.svg) -->
 <svg class="howto-icon" width="48" height="48" viewBox="0 0 24 24" fill="none" role="img" aria-hidden="true">
 <path
 d="M9.65661 17L6.99975 17L6.99975 14M6.10235 14.8974L17.4107 3.58902C18.1918 2.80797 19.4581 2.80797 20.2392 3.58902C21.0202 4.37007 21.0202 5.6364 20.2392 6.41745L8.764 17.8926C8.22794 18.4287 7.95992 18.6967 7.6632 18.9271C7.39965 19.1318 7.11947 19.3142 6.8256 19.4723C6.49475 19.6503 6.14115 19.7868 5.43395 20.0599L3 20.9998L3.78312 18.6501C4.05039 17.8483 4.18403 17.4473 4.3699 17.0729C4.53497 16.7404 4.73054 16.424 4.95409 16.1276C5.20582 15.7939 5.50466 15.4951 6.10235 14.8974Z"
 stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
 </svg>
 <strong class="howto-step-title">2 — On prépare le dessin</strong>
 <p class="howto-step-desc">Après avoir fixé la date, ton artiste te prépare un dessin quelques jours avant.</p>
 <a class="btn howto-cta btn--ghost" href="/rdv/" aria-label="Demander une consultation">Demander une
 consultation</a>
 </article>
 <article class="howto-step">
 <!-- icon: soins (from soins.svg) -->
 <svg class="howto-icon" width="48" height="48" viewBox="0 0 24 24" fill="none" role="img" aria-hidden="true">
 <path fill-rule="evenodd" clip-rule="evenodd"
 d="M12 6.00019C10.2006 3.90317 7.19377 3.2551 4.93923 5.17534C2.68468 7.09558 2.36727 10.3061 4.13778 12.5772C5.60984 14.4654 10.0648 18.4479 11.5249 19.7369C11.6882 19.8811 11.7699 19.9532 11.8652 19.9815C11.9483 20.0062 12.0393 20.0062 12.1225 19.9815C12.2178 19.9532 12.2994 19.8811 12.4628 19.7369C13.9229 18.4479 18.3778 14.4654 19.8499 12.5772C21.6204 10.3061 21.3417 7.07538 19.0484 5.17534C16.7551 3.2753 13.7994 3.90317 12 6.00019Z"
 stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
 </svg>
 <strong class="howto-step-title">3 — Session & soins</strong>
 <p class="howto-step-desc">Séance de tatouage suivie des conseils de soins pour une bonne cicatrisation.</p>
 <a class="btn howto-cta btn--ghost" href="/soins/" aria-label="Voir les soins après-tatouage">Voir nos
 conseils</a>
 </article>
 </div>
 </div>
 </section>

 <!-- reopen content wrap for the rest of the page content -->
 <div class="wrap content-wrap">

 <section class="section reviews" aria-labelledby="reviews-title">
 <h2 id="reviews-title" class="section-title">Iels parlent de nous</h2>

 <div class="reviews-grid">
 <article class="review" aria-labelledby="rev-claire">
 <img class="avatar" src="https://v2.lestudiopixel.com/assets/v2/avis/claire.webp" alt="Portrait de Claire">
 <div class="meta">
 <div class="who" id="rev-claire">
 <span>Claire</span>
 <time class="when" datetime="2025-06">Juin 2025</time>
 </div>
 <div class="stars" aria-hidden="true">
 <!-- five filled stars -->
 <svg>
 <use href="#icon-star"></use>
 </svg>
 <svg>
 <use href="#icon-star"></use>
 </svg>
 <svg>
 <use href="#icon-star"></use>
 </svg>
 <svg>
 <use href="#icon-star"></use>
 </svg>
 <svg>
 <use href="#icon-star"></use>
 </svg>
 </div>
 <p>Si vous cherchez un tatoueur pro, bienveillant et avec un style bien à lui vous pouvez y aller les yeux
 fermés !</p>
 </div>

 </article>

 <article class="review" aria-labelledby="rev-deborah">
 <img class="avatar" src="https://v2.lestudiopixel.com/assets/v2/avis/deborah.webp" alt="Portrait de Déborah">
 <div class="meta">
 <div class="who" id="rev-deborah">
 <span>Déborah</span>
 <time class="when" datetime="2024-12">Décembre 2024</time>
 </div>
 <div class="stars" aria-hidden="true">
 <svg>
 <use href="#icon-star"></use>
 </svg>
 <svg>
 <use href="#icon-star"></use>
 </svg>
 <svg>
 <use href="#icon-star"></use>
 </svg>
 <svg>
 <use href="#icon-star"></use>
 </svg>
 <svg>
 <use href="#icon-star"></use>
 </svg>
 </div>
 <p>Un tatoueur à l'écoute avec beaucoup d'humour. J'ai beaucoup de retours très positifs sur la finesse du
 trait.</p>
 </div>

 </article>

 <article class="review" aria-labelledby="rev-laura">
 <img class="avatar" src="https://v2.lestudiopixel.com/assets/v2/avis/laura.webp" alt="Portrait de Laura">
 <div class="meta">
 <div class="who" id="rev-laura">
 <span>Laura</span>
 <time class="when" datetime="2025-09">Septembre 2025</time>
 </div>
 <div class="stars" aria-hidden="true">
 <svg>
 <use href="#icon-star"></use>
 </svg>
 <svg>
 <use href="#icon-star"></use>
 </svg>
 <svg>
 <use href="#icon-star"></use>
 </svg>
 <svg>
 <use href="#icon-star"></use>
 </svg>
 <svg>
 <use href="#icon-star"></use>
 </svg>
 </div>
 <p>Une super expérience pour mon premier tatouage. J'ai été prise en charge par Nitro qui est accueillant,
 sympathique et prévenant. Les règles d'hygiène sont respectées. Le travail a été rapide et réussi, sans être
 trop douloureux. Merci pour tout !</p>
 </div>

 </article>

 <article class="review" aria-labelledby="rev-geoffrey">
 <img class="avatar" src="https://v2.lestudiopixel.com/assets/v2/avis/geoffrey.webp" alt="Portrait de Geoffrey">
 <div class="meta">
 <div class="who" id="rev-geoffrey">
 <span>Geoffrey</span>
 <time class="when" datetime="2025-04">Avril 2025</time>
 </div>
 <div class="stars" aria-hidden="true">
 <svg>
 <use href="#icon-star"></use>
 </svg>
 <svg>
 <use href="#icon-star"></use>
 </svg>
 <svg>
 <use href="#icon-star"></use>
 </svg>
 <svg>
 <use href="#icon-star"></use>
 </svg>
 <svg>
 <use href="#icon-star"></use>
 </svg>
 </div>
 <p>Un shop super accueillant, avec une équipe de zinzins tous très doués et des guests de folie! Longue vie au
 studio Pixel!</p>
 </div>

 </article>
 </div>

 <!-- Reviews footer: link to Google and summary -->
 <div class="reviews-footer" style="margin-top:1rem;">
 <a class="btn btn--sm" href="/avis" rel="nofollow noopener" target="_blank"
 aria-label="Voir nos avis sur Google Maps">
 Voir nos avis sur Google
 </a>
 <div class="reviews-note" style="display:inline-block;margin-left:.75rem;color:var(--muted);font-size:.95rem;">
 204 avis <div class="stars" aria-hidden="true">
 <svg>
 <use href="#icon-star"></use>
 </svg>
 <svg>
 <use href="#icon-star"></use>
 </svg>
 <svg>
 <use href="#icon-star"></use>
 </svg>
 <svg>
 <use href="#icon-star"></use>
 </svg>
 <svg>
 <use href="#icon-star"></use>
 </svg>
 </div>
 </div>
 </div>
 </section>

 <section class="section" id="guests">
 <h2>Guests</h2>
 <div class="grid" id="guests-grid" aria-live="polite"></div>
 <script>
 (function () {
 function slugify(input) {
 var raw = (input || '').toString().trim();
 var s = raw.toLowerCase();
 // Try to fix common mojibake (e.g., "LÃ©lÃ©" -> "Lélé")
 try {
 var fixed = decodeURIComponent(escape(raw));
 if (fixed && fixed !== raw) { s = fixed.toLowerCase(); }
 } catch (e) { /* ignore */ }
 if (s && typeof s.normalize === 'function') {
 s = s.normalize('NFKD').replace(/[\u0300-\u036f]+/g, '');
 }
 s = s.replace(/œ/g, 'oe').replace(/æ/g, 'ae').replace(/ß/g, 'ss');
 s = s.replace(/[\u2019\u2018']/g, '');
 s = s.replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '').replace(/-+/g, '-');
 return s;
 }
 const PLACEHOLDER_CARD = {
 placeholder: true,
 name: 'Venir en guest ?',
 date: 'T\'as du talent ? Je trouve aussi !',
 link: '/cowork',
 img: '/v2/home/placeholder.webp'
 };

 function within7Days(d) {
 if (!d) return true;
 const ts = Date.parse(d + 'T00:00:00');
 if (isNaN(ts)) return true;
 return (Date.now() - ts) <= 7 * 24 * 3600 * 1000;
 }

 function formatDateRange(dateStart, dateFin) {
 if (!dateStart) return '';
 const months = ['janvier','février','mars','avril','mai','juin','juillet','août','septembre','octobre','novembre','décembre'];
 const start = new Date(dateStart + 'T00:00:00');
 if (isNaN(start)) return '';
 const sd = start.getDate(), sm = start.getMonth(), sy = start.getFullYear();
 if (!dateFin) return sd + ' ' + months[sm] + ' ' + sy;
 const end = new Date(dateFin + 'T00:00:00');
 if (isNaN(end)) return sd + ' ' + months[sm] + ' ' + sy;
 const ed = end.getDate(), em = end.getMonth(), ey = end.getFullYear();
 if (sm === em && sy === ey) return sd + '-' + ed + ' ' + months[sm] + ' ' + sy;
 if (sy === ey) return sd + ' ' + months[sm] + ' - ' + ed + ' ' + months[em] + ' ' + sy;
 return sd + ' ' + months[sm] + ' ' + sy + ' - ' + ed + ' ' + months[em] + ' ' + ey;
 }

 function clonePlaceholder() {
 return Object.assign({}, PLACEHOLDER_CARD);
 }

 function cellUnits(cls) {
 if (!cls) return 1;
 if (cls.includes('guest-card--full')) return 6;
 const columns = cls.includes('guest-card--span-2') ? 2 : 1;
 const rows = cls.includes('guest-card--span-row-2') ? 2 : 1;
 return columns * rows;
 }

 function planCards(items) {
 const total = items.length;
 if (!total) {
 return {
 cards: [clonePlaceholder()],
 classes: ['guest-card--full guest-card--feature']
 };
 }

 const classes = new Array(total).fill('');
 if (total === 1) {
 classes[0] = 'guest-card--full guest-card--feature';
 } else if (total === 2) {
 classes[0] = 'guest-card--span-2 guest-card--feature';
 } else if (total === 3) {
 classes[0] = 'guest-card--span-2 guest-card--span-row-2 guest-card--feature';
 } else if (total === 4) {
 classes[0] = 'guest-card--span-2 guest-card--feature';
 classes[1] = 'guest-card--span-2';
 } else if (total >= 5) {
 classes[0] = 'guest-card--span-2 guest-card--span-row-2 guest-card--feature';
 }

 const cards = items.slice(0);
 const occupied = classes.reduce((sum, cls) => sum + cellUnits(cls), 0);
 const gap = (3 - (occupied % 3)) % 3;
 if (gap > 0) {
 cards.push(clonePlaceholder());
 classes.push(gap === 2 ? 'guest-card--span-2' : '');
 }
 return { cards, classes };
 }

 function createGuestCard(data, extraClasses) {
 const card = document.createElement('a');
 card.className = 'card guest-card';
 if (extraClasses) {
 extraClasses.split(' ').filter(Boolean).forEach(cls => card.classList.add(cls));
 }

 if (data.placeholder) {
 card.classList.add('guest-card--placeholder');
 const inner = document.createElement('div');
 inner.className = 'guest-card__placeholder';
 const title = document.createElement('strong');
 title.textContent = data.name || 'Venir en guest ?';
 const message = document.createElement('p');
 message.textContent = data.date || 'Contacte-nous pour rejoindre la programmation.';
 const action = document.createElement('a');
 action.className = 'btn btn--ghost';
 action.href = data.link || '/cowork';
 action.rel = 'nofollow';
 action.textContent = 'Proposer un guest';
 inner.append(title, message, action);
 card.appendChild(inner);
 card.dataset.placeholder = '1';
 return card;
 }

 const href = data.link || '#';
 card.tabIndex = 0;
 const cardSlug = slugify(data.slug || data.name || data.id || '');
 card.href = '/artist/' + cardSlug;
 card.dataset.name = data.name || '';
 card.dataset.image = data.img || '/v2/home/placeholder.webp';
 card.dataset.date = data.date || '';
 card.dataset.description = data.description || '';
 card.dataset.link = href;
 const counts = data._photoCounts || { tattoo: 0, flash: 0 };
 const queryName = encodeURIComponent(data.name || '');
 const autoFlashLink = counts.flash > 0 ? `/flashs?artist=${queryName}` : '';
 const autoTattooLink = counts.tattoo > 0 ? `/tattoos?artist=${queryName}` : '';
 const explicitFlash = data.flash_link || '';
 const explicitTattoo = data.tattoo_link || '';
 card.dataset.flashLink = explicitFlash || autoFlashLink;
 card.dataset.tattooLink = explicitTattoo || autoTattooLink;
 card.dataset.instagram = data.instagram || data.social || '';
 card.dataset.slug = cardSlug;

 const media = document.createElement('div');
 media.className = 'guest-card__media';
 // media is decorative and non-interactive; the whole card is the link

 const img = document.createElement('img');
 img.loading = 'lazy';
 img.decoding = 'async';
 img.src = card.dataset.image;
 img.alt = data.name || '';
 img.width = 800;
 img.height = 800;
 media.appendChild(img);
 card.appendChild(media);

 const meta = document.createElement('div');
 meta.className = 'guest-card__meta';
 const heading = document.createElement('h3');
 heading.textContent = data.name || '';
 meta.appendChild(heading);
 if (data.date) {
 const info = document.createElement('p');
 info.textContent = data.date;
 meta.appendChild(info);
 }
 card.appendChild(meta);
 return card;
 }

 const photosPromise = window.__photosPromise ||= getJSON('https://api.lestudiopixel.com/photos-list?action=list&limit=8&offset=0&type=tattoos', 4000);

 Promise.all([
 getJSON('https://api.lestudiopixel.com/guests', 4000),
 photosPromise,
 ]).then(([guestsData, photosData]) => {
 const list = Array.isArray(guestsData) ? guestsData : (guestsData && guestsData.guests) || [];
 const photoItems = (photosData && Array.isArray(photosData.items)) ? photosData.items : [];

 const photoCounts = {};
 photoItems.forEach(item => {
 const artistName = (item && item.artist) ? String(item.artist).trim() : '';
 if (!artistName) { return; }
 if (!photoCounts[artistName]) {
 photoCounts[artistName] = { tattoo: 0, flash: 0 };
 }
 const type = (item && item.type) ? String(item.type).toLowerCase() : '';
 if (type.includes('flash')) {
 photoCounts[artistName].flash += 1;
 } else {
 photoCounts[artistName].tattoo += 1;
 }
 });

 const items = list.filter(g => within7Days(g.date_start));
 // Derive human-readable date from date_start/date_fin
 items.forEach(g => { g.date = formatDateRange(g.date_start, g.date_fin); });
 const grid = document.getElementById('guests-grid');
 if (!grid) return;
 grid.innerHTML = '';
 const { cards, classes } = planCards(items);
 const frag = document.createDocumentFragment();
 cards.forEach((guest, index) => {
 const extra = classes[index] || '';
 const counts = photoCounts[guest.name || ''] || { tattoo: 0, flash: 0 };
 const card = createGuestCard({ ...guest, _photoCounts: counts }, extra);
 frag.appendChild(card);
 });
 grid.appendChild(frag);
 setupGuestModal(grid.querySelectorAll('.guest-card'));
 });

 function setupGuestModal(cardList) {
 const modal = document.getElementById('guest-modal');
 if (!modal) { return; }
 // Disable popup: keep default navigation to the artist page
 Array.prototype.forEach.call(cardList, function (card) {
 if (card.dataset && card.dataset.slug) {
 card.href = '/artist/' + encodeURIComponent(card.dataset.slug);
 }
 });
 return;
 const imageEl = document.getElementById('guest-modal-image');
 const nameEl = document.getElementById('guest-modal-name');
 const dateEl = document.getElementById('guest-modal-date');
 const descWrap = document.getElementById('guest-modal-description-wrap');
 const descEl = document.getElementById('guest-modal-description');
 const actionsWrap = document.getElementById('guest-modal-actions');
 const closeBtn = modal.querySelector('.artist-modal__close');
 const backdrop = modal.querySelector('.artist-modal__backdrop');

 if (!imageEl || !nameEl || !dateEl || !descWrap || !descEl || !actionsWrap || !closeBtn || !backdrop) {
 return;
 }

 let previousFocus = null;

 function openModal(card) {
 if (!card || card.dataset.placeholder) { return; }
 previousFocus = document.activeElement;
 const name = card.dataset.name || '';
 const image = card.dataset.image || '/v2/home/placeholder.webp';
 const date = card.dataset.date || '';
 const description = (card.dataset.description || '').replace(/\r\n|\r|\n/g, '\n').trim();
 const href = card.dataset.link || '';
 const flashHref = card.dataset.flashLink || '';
 const tattooHref = card.dataset.tattooLink || '';
 const instagramHref = card.dataset.instagram || '';
 const slug = slugify(card.dataset.slug || name || '');

 // Reset any transform/opacity from a previous swipe-close and scroll position
 const dialogEl = modal.querySelector('.artist-modal__dialog');
 if (dialogEl) {
 dialogEl.style.transform = '';
 dialogEl.style.opacity = '';
 dialogEl.style.transition = '';
 dialogEl.style.willChange = '';
 }
 modal.scrollTop = 0;

 nameEl.textContent = name;
 imageEl.src = image;
 imageEl.alt = name ? 'Visuel de ' + name : '';

 if (date) {
 dateEl.textContent = date;
 dateEl.removeAttribute('hidden');
 } else {
 dateEl.textContent = '';
 dateEl.setAttribute('hidden', 'hidden');
 }

 if (description) {
 descEl.textContent = description;
 descWrap.removeAttribute('hidden');
 descEl.removeAttribute('hidden');
 } else {
 descEl.textContent = '';
 descWrap.setAttribute('hidden', 'hidden');
 descEl.setAttribute('hidden', 'hidden');
 }

 actionsWrap.innerHTML = '';

 if (flashHref) {
 const flashLink = document.createElement('a');
 flashLink.className = 'btn';
 flashLink.href = flashHref;
 flashLink.textContent = 'Flashs';
 actionsWrap.appendChild(flashLink);
 }

 if (tattooHref) {
 const tattooLink = document.createElement('a');
 tattooLink.className = 'btn btn--ghost';
 tattooLink.href = tattooHref;
 tattooLink.textContent = 'Tattoos';
 actionsWrap.appendChild(tattooLink);
 }

 if (instagramHref) {
 const instaLink = document.createElement('a');
 instaLink.className = 'artist-modal__instagram';
 instaLink.href = instagramHref;
 instaLink.target = '_blank';
 instaLink.rel = 'noopener';
 instaLink.setAttribute('aria-label', 'Profil Instagram');
 instaLink.innerHTML = '<svg width="24" height="24" viewBox="0 0 24 24" role="img" aria-hidden="true" focusable="false"><path fill="currentColor" d="M12 2.2c3.2 0 3.6 0 4.9.1 1.2.1 1.8.2 2.2.4.6.2 1 .5 1.4.9.4.4.7.9.9 1.4.1.4.3 1 .4 2.2.1 1.3.1 1.7.1 4.9s0 3.6-.1 4.9c-.1 1.2-.2 1.8-.4 2.2-.2.6-.5 1-.9 1.4-.4.4-.9.7-1.4.9-.4.1-1 .3-2.2.4-1.3.1-1.7.1-4.9.1s-3.6 0-4.9-.1c-1.2-.1-1.8-.2-2.2-.4-.6-.2-1-.5-1.4-.9-.4-.4-.7-.9-.9-1.4-.1-.4-.3-1-.4-2.2C2.2 15.6 2.2 15.2 2.2 12s0-3.6.1-4.9c.1-1.2.2-1.8.4-2.2.2-.6.5-1 .9-1.4.4-.4.9-.7 1.4-.9.4-.1 1-.3 2.2-.4C8.4 2.2 8.8 2.2 12 2.2m0-2.2C8.7 0 8.3 0 7 0 5.7.1 4.9.3 4.2.6c-.8.3-1.5.7-2.2 1.4C1.3 2.7.9 3.4.6 4.2.3 4.9.1 5.7 0 7c0 1.3 0 1.7 0 5s0 3.7.1 5c.1 1.3.3 2.1.6 2.8.3.8.7 1.5 1.4 2.2.7.7 1.4 1.1 2.2 1.4.7.3 1.5.5 2.8.6 1.3.1 1.7.1 5 .1s3.7 0 5-.1c1.3-.1 2.1-.3 2.8-.6.8-.3 1.5-.7 2.2-1.4.7-.7 1.1-1.4 1.4-2.2.3-.7.5-1.5.6-2.8.1-1.3.1-1.7.1-5s0-3.7-.1-5c-.1-1.3-.3-2.1-.6-2.8-.3-.8-.7-1.5-1.4-2.2-.7-.7-1.4-1.1-2.2-1.4-.7-.3-1.5-.5-2.8-.6C15.7 0 15.3 0 12 0Z"/><path fill="currentColor" d="M12 5.8A6.2 6.2 0 0 0 5.8 12 6.2 6.2 0 0 0 12 18.2 6.2 6.2 0 0 0 18.2 12 6.2 6.2 0 0 0 12 5.8m0 10.3A4.1 4.1 0 0 1 7.9 12 4.1 4.1 0 0 1 12 7.9 4.1 4.1 0 0 1 16.1 12 4.1 4.1 0 0 1 12 16.1Zm7.9-11.7a1.4 1.4 0 1 1-2.7 0 1.4 1.4 0 0 1 2.7 0Z"/></svg>';
 actionsWrap.appendChild(instaLink);
 }

 if (!actionsWrap.children.length) {
 actionsWrap.setAttribute('hidden', 'hidden');
 } else {
 actionsWrap.removeAttribute('hidden');
 }

 modal.removeAttribute('hidden');
 modal.setAttribute('aria-hidden', 'false');
 modal.classList.add('is-open');
 document.body.classList.add('modal-open');
 closeBtn.focus();

 // Reflect SEO URL in address bar without navigation
 if (history && history.replaceState && slug) {
 history.replaceState(null, '', '/artist/' + encodeURIComponent(slug));
 }
 }

 function closeModal() {
 if (modal.hasAttribute('hidden')) { return; }
 modal.setAttribute('hidden', 'hidden');
 modal.setAttribute('aria-hidden', 'true');
 modal.classList.remove('is-open');
 document.body.classList.remove('modal-open');
 // Ensure dialog visual state is reset for next open
 const dialogEl = modal.querySelector('.artist-modal__dialog');
 if (dialogEl) {
 dialogEl.style.transform = '';
 dialogEl.style.opacity = '';
 dialogEl.style.transition = '';
 dialogEl.style.willChange = '';
 }
 modal.scrollTop = 0;
 if (previousFocus && typeof previousFocus.focus === 'function') {
 previousFocus.focus();
 }
 previousFocus = null;

 // Restore homepage section anchor for UX
 if (history && history.replaceState) {
 history.replaceState(null, '', '/#guests');
 }
 }

 Array.prototype.forEach.call(cardList, function (card) {
 if (card.dataset.placeholder) { return; }
 card.addEventListener('click', function (event) { event.preventDefault(); openModal(card); });
 card.addEventListener('keydown', function (event) {
 if (event.key === 'Enter' || event.key === ' ') {
 event.preventDefault();
 openModal(card);
 }
 });
 });

 closeBtn.addEventListener('click', closeModal);
 backdrop.addEventListener('click', closeModal);
 // Swipe down to close (mobile gesture)
 (function enableSwipeToClose() {
 const dialog = modal.querySelector('.artist-modal__dialog');
 if (!dialog) return;
 let startY = null, currentY = 0, dragging = false, startedAtTop = false;
 const THRESHOLD = 120;
 function onStart(e) {
 if (!e.touches || e.touches.length !== 1) return;
 startY = e.touches[0].clientY;
 currentY = startY;
 startedAtTop = (modal.scrollTop || 0) <= 0;
 dragging = false;
 dialog.style.willChange = 'transform, opacity';
 dialog.style.transition = 'none';
 }
 function onMove(e) {
 if (startY === null) return;
 currentY = e.touches ? e.touches[0].clientY : currentY;
 const dy = currentY - startY;
 if (dy > 0 && startedAtTop) {
 dragging = true;
 e.preventDefault();
 dialog.style.transform = 'translateY(' + dy + 'px)';
 dialog.style.opacity = String(Math.max(0.5, 1 - dy / 300));
 }
 }
 function onEnd() {
 if (startY === null) return;
 const dy = currentY - startY;
 dialog.style.transition = 'transform .2s ease, opacity .2s ease';
 if (dragging && dy > THRESHOLD) {
 dialog.style.transform = 'translateY(100vh)';
 dialog.style.opacity = '0';
 setTimeout(closeModal, 150);
 } else {
 dialog.style.transform = '';
 dialog.style.opacity = '';
 setTimeout(function () { dialog.style.transition = ''; dialog.style.willChange = ''; }, 200);
 }
 startY = null; currentY = 0; dragging = false; startedAtTop = false;
 }
 modal.addEventListener('touchstart', onStart, { passive: true });
 modal.addEventListener('touchmove', onMove, { passive: false });
 modal.addEventListener('touchend', onEnd, { passive: true });
 modal.addEventListener('touchcancel', onEnd, { passive: true });
 })();
 document.addEventListener('keydown', function (event) {
 if (event.key === 'Escape') { closeModal(); }
 });
 }


 try {
 function autoLinkBlogUrls(root) {
 if (!root || !document.createTreeWalker) return;
 var skip = { A: 1, CODE: 1, PRE: 1, SCRIPT: 1, STYLE: 1, IFRAME: 1 };
 var walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT, {
 acceptNode: function (node) {
 var parent = node.parentElement;
 if (!parent || skip[parent.tagName]) return NodeFilter.FILTER_REJECT;
 return /(?:https?:\/\/|www\.)\S+/i.test(node.nodeValue || '') ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT;
 }
 });
 var nodes = [];
 while (walker.nextNode()) nodes.push(walker.currentNode);
 nodes.forEach(function (node) {
 var text = node.nodeValue || '';
 var re = /\b((?:https?:\/\/|www\.)[^\s<>()]+[^\s<>().,;:!?])/ig;
 var frag = document.createDocumentFragment();
 var last = 0;
 var match;
 while ((match = re.exec(text))) {
 frag.appendChild(document.createTextNode(text.slice(last, match.index)));
 var label = match[1];
 var link = document.createElement('a');
 link.href = /^www\./i.test(label) ? 'https://' + label : label;
 link.textContent = label;
 frag.appendChild(link);
 last = match.index + label.length;
 }
 frag.appendChild(document.createTextNode(text.slice(last)));
 node.parentNode.replaceChild(frag, node);
 });
 }
 var qs = new URLSearchParams(window.location.search);
 // Isolate slug from /post/:slug
 var parts = (window.location.pathname || '/').split('/').filter(Boolean);
 if (parts.length < 2 || parts[0] !== 'post') return;
 var slug = parts[1];
 // Before fetching, suppress the default home hero background to avoid blink
 var API = (window.API_BASE || 'https://api.lestudiopixel.com').replace(/\/$/, '');
 var url = API + '/blog/post-meta/' + slug;
 console.log('[home-post-loader] fetch', url);
 fetch(url, { credentials: 'omit' }).then(function (r) { return r.ok ? r.json() : null; }).then(function (j) {
 if (!j || !j.ok) { console.warn('[home-post-loader] invalid response'); return; }
 // Show blog shell and hide home sections
 var shell = document.getElementById('blog-shell');
 if (!shell) return;
 shell.style.display = 'block';
 try { document.body.classList.add('is-home'); } catch (e) { }
 document.querySelectorAll('header.wrap.hero, .wrap.content-wrap, section.section').forEach(function (el) {
 if (!el.closest('#blog-shell') && el.id !== 'blog-shell') el.style.display = 'none';
 });
 // Title and date
 if (j.title) { var cleanTitle = String(j.title).trim(); var t = document.getElementById('post-title'); if (t) t.textContent = cleanTitle; document.title = cleanTitle + ' - Studio Pixel'; }
 if (j.date_text) { var d = document.getElementById('post-date'); if (d) d.textContent = j.date_text; }
 // Hero background image with v2 fallback
 var heroSrc = j.image_url || '';
 var blogHero = document.getElementById('blog-hero');
 if (blogHero) {
 if (heroSrc) {
 // Set primary hero background
 blogHero.style.backgroundImage = 'url("' + heroSrc + '")';
 // Fallback to v2.lestudiopixel.com if the image 404s/missing
 try {
 var probe = new Image();
 var triedFallback = false;
 probe.onerror = function () {
 if (triedFallback) return;
 triedFallback = true;
 try {
 var u = null;
 try { u = new URL(heroSrc, window.location.href); } catch (e) { }
 var host = u ? (u.hostname || '') : '';
 var path = u ? (u.pathname || '') : (heroSrc.startsWith('/') ? heroSrc : ('/' + heroSrc));
 if (!/v2\.lestudiopixel\.com$/i.test(host)) {
 var fb = 'https://v2.lestudiopixel.com' + path;
 blogHero.style.backgroundImage = 'url("' + fb + '")';
 console.log('[home-post-loader] hero fallback ->', fb);
 }
 } catch (e) { /* ignore */ }
 };
 probe.src = heroSrc;
 } catch (e) { /* ignore */ }
 }
 }
 // Content body into #post-body
 var bodyEl = document.getElementById('post-body');
 if (typeof j.content === 'string' && bodyEl) {
 bodyEl.innerHTML = j.content;
 autoLinkBlogUrls(bodyEl);
 }
 console.log('[home-post-loader] rendered post into home');
 }).catch(function (e) { console.error('[home-post-loader] error', e); });
 } catch (e) { console.error('[home-post-loader] fatal', e); }

 })();
 </script>
 </section>

 <div id="guest-modal" class="artist-modal" hidden aria-hidden="true" role="dialog" aria-modal="true"
 aria-labelledby="guest-modal-name">
 <div class="artist-modal__backdrop" data-close="1"></div>
 <div class="artist-modal__dialog" role="document">
 <button type="button" class="artist-modal__close" aria-label="Fermer">
 <svg viewBox="0 0 24 24" aria-hidden="true" focusable="false">
 <line x1="5" y1="5" x2="19" y2="19" />
 <line x1="19" y1="5" x2="5" y2="19" />
 </svg>
 </button>
 <div class="artist-modal__content">
 <div class="artist-modal__media">
 <img id="guest-modal-image" src="" alt="" width="640" height="640" loading="lazy">
 </div>
 <div class="artist-modal__details">
 <div class="artist-modal__title">
 <h3 id="guest-modal-name"></h3>
 <span id="guest-modal-date" class="muted" hidden></span>
 </div>
 <div id="guest-modal-description-wrap" class="artist-modal__scroll" hidden>
 <p id="guest-modal-description" class="artist-modal__description"></p>
 </div>
 <div class="artist-modal__actions" id="guest-modal-actions"></div>
 </div>
 </div>
 </div>
 </div>

 <section class="section" id="gallery">
 <h2>Derniers tattoos</h2>
 <div class="grid" id="tattoos-grid"></div>
 <div class="cta-row">
 <a class="btn btn--ghost-inv" href="/flashs/">Projets disponibles</a>
 <a class="btn btn--ghost" href="/tattoos/">Nos réalisations</a>
 </div>
 <script>
 (function () {
 (window.__photosPromise ||= getJSON('https://api.lestudiopixel.com/photos-list?action=list&limit=8&offset=0&type=tattoos', 4000)).then(data => {
 const items = (data && Array.isArray(data.items)) ? data.items : [];
 const tattoos = items.filter(i => /^(tattoo|tattoos|tattooed)$/i.test(i.type || ''));
 const grid = document.getElementById('tattoos-grid'); if (!grid) return;
 const pick = tattoos.slice(0, 8);
 const frag = document.createDocumentFragment();
 pick.forEach(ph => {
 const card = document.createElement('article'); card.className = 'card';
 const link = document.createElement('a'); link.href = '/tattoos?artist=' + encodeURIComponent(ph.artist || '');
 const src = String(ph.image || '');
 const absoluteSrc = src.startsWith('http://') || src.startsWith('https://') ? src : `https://api.lestudiopixel.com/` + src.replace(/^\/+/, '').replace(/^api\//, '');
 const img = document.createElement('img'); img.loading = 'lazy'; img.decoding = 'async'; img.src = absoluteSrc; img.alt = (ph.artist || '') + ' tattoo'; img.width = 800; img.height = 800;
 link.appendChild(img); card.appendChild(link); frag.appendChild(card);
 });
 grid.appendChild(frag);
 });
 })();
 </script>
 </section>

 <svg width="0" height="0" style="display: none;">
 <symbol id="icon-star" viewBox="0 0 24 24">
 <path d="M12 .587l3.668 7.431L23 9.75l-5.5 5.362L18.335 24 12 20.091 5.665 24l.835-8.888L1 9.75l7.332-1.732z" />
 </symbol>
 </svg>
 </div>

  
 <div class="wrap">
 <div class="site-banner-slot" data-banner-container>
 </div>

<style>
 .site-banner-slot:empty{display:none}
 .site-banner{--site-banner-bg:#ff5757;--site-banner-fg:#111;--site-banner-cta-bg:rgba(255,255,255,.94);--site-banner-cta-fg:#111;--site-banner-cta-hover-bg:#fff;--site-banner-cta-hover-fg:#111;margin:22px auto 0;border-radius:10px;background:var(--site-banner-bg);color:var(--site-banner-fg);box-shadow:0 18px 44px rgba(0,0,0,.14)}
 .site-banner--warning{--site-banner-bg:#facc15}
 .site-banner--success{--site-banner-bg:#22c55e}
 .site-banner--info{--site-banner-bg:#38bdf8}
 .site-banner--dark{--site-banner-bg:#111827;--site-banner-fg:#fff}
 .site-banner--custom{--site-banner-fg:#fff}
 .site-banner__content{display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:center;gap:28px;padding:26px 34px;text-align:left}
 .site-banner__copy{display:flex;min-width:0;flex-direction:column;gap:6px}
 .site-banner__title{font-size:clamp(22px,2.1vw,34px);font-weight:900;line-height:1.08;letter-spacing:0}
 .site-banner__message{max-width:72ch;font-size:clamp(15px,1.1vw,18px);font-weight:650;line-height:1.45;opacity:.9}
 .site-banner__message p{margin:0}
 .site-banner__cta{display:inline-flex;align-items:center;justify-content:center;min-height:48px;border-radius:8px;background:var(--site-banner-cta-bg);color:var(--site-banner-cta-fg);padding:12px 22px;font-size:clamp(16px,1.25vw,20px);font-weight:900;text-decoration:none;white-space:nowrap;box-shadow:0 8px 18px rgba(0,0,0,.14)}
 .site-banner__cta:hover{text-decoration:none;background:var(--site-banner-cta-hover-bg);color:var(--site-banner-cta-hover-fg);transform:translateY(-1px)}
 @media (prefers-color-scheme:dark){.site-banner{--site-banner-fg:#fff;--site-banner-cta-bg:rgba(255,255,255,.14);--site-banner-cta-fg:#fff;--site-banner-cta-hover-bg:rgba(255,255,255,.22);--site-banner-cta-hover-fg:#fff;box-shadow:0 18px 44px rgba(0,0,0,.38)}.site-banner--warning,.site-banner--success,.site-banner--info{--site-banner-fg:#111;--site-banner-cta-bg:rgba(0,0,0,.78);--site-banner-cta-fg:#fff;--site-banner-cta-hover-bg:#000;--site-banner-cta-hover-fg:#fff}.site-banner--dark{--site-banner-bg:#f3f4f6;--site-banner-fg:#111;--site-banner-cta-bg:#111827;--site-banner-cta-fg:#fff;--site-banner-cta-hover-bg:#000;--site-banner-cta-hover-fg:#fff}}
 @media (min-width:900px){.site-banner{max-width:980px}.site-banner__content{min-height:128px}}
 @media (max-width:640px){.site-banner{margin-top:14px;border-radius:8px}.site-banner__content{display:flex;flex-direction:column;align-items:stretch;gap:16px;padding:22px 18px;text-align:center}.site-banner__message{max-width:none}.site-banner__cta{width:100%}}
 </style>
<script>
 (function () {
 var container = document.querySelector('[data-banner-container]');
 if (!container || !window.fetch) return;
 var isLocal = /^(localhost|127\.0\.0\.1|0\.0\.0\.0)$/i.test(location.hostname);
 var url = isLocal ? '/admin/api/banners.php' : 'https://admin.lestudiopixel.com/api/banners.php';
 var cacheKey = 'lsp_banner_cache_v2';
 function escapeHtml(value) {
 return String(value || '').replace(/[&<>"']/g, function (c) {
 return ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#039;' })[c];
 });
 }
 function render(banner) {
 if (!banner) {
 container.innerHTML = '';
 return;
 }
 var color = escapeHtml(banner.color || 'primary');
 var style = color === 'custom' && banner.custom_color ? ' style="--site-banner-bg:' + escapeHtml(banner.custom_color) + '"' : '';
 var title = banner.title ? '<div class="site-banner__title">' + escapeHtml(banner.title) + '</div>' : '';
 var message = banner.message ? '<div class="site-banner__message">' + banner.message + '</div>' : '';
 var cta = banner.cta_text && banner.cta_url
 ? '<a class="site-banner__cta" href="' + escapeHtml(banner.cta_url) + '">' + escapeHtml(banner.cta_text) + '</a>'
 : '';
 container.innerHTML = '<div class="site-banner site-banner--' + color + '"' + style + '><div class="site-banner__content"><div class="site-banner__copy">' + title + message + '</div>' + cta + '</div></div>';
 }
 try {
 var cached = JSON.parse(localStorage.getItem(cacheKey) || 'null');
 if (cached && cached.expires_at > Date.now()) {
 render(cached.banner);
 return;
 }
 } catch (e) {}
 fetch(url, { credentials: 'omit', headers: { 'Accept': 'application/json' } })
 .then(function (response) { return response.ok ? response.json() : null; })
 .then(function (payload) {
 var banner = payload && payload.ok ? payload.banner : payload;
 try { localStorage.setItem(cacheKey, JSON.stringify({ banner: banner || null, expires_at: Date.now() + 60000 })); } catch (e) {}
 render(banner || null);
 })
 .catch(function () {});
 })();
 </script>
 </div>

 <footer class="wrap foot">
 <h2 class="sr">Newsletter</h2>
 
 <form class="newsletter" action="https://api.lestudiopixel.com/mailchimp/subscribe" method="post" novalidate data-lead-newsletter>
 <input type="hidden" name="u" value="5cffe10b65bbcc4acad6c7e63">
 <input type="hidden" name="id" value="8c9c686547">
 <input type="hidden" name="source" value="newsletter_footer">
 <input type="hidden" name="form" value="newsletter_footer">
 <label for="newsletter-email" style="position:absolute;left:-9999px">Email</label>
 <input class="newsletter-input" id="newsletter-email" name="EMAIL" type="email" placeholder="Votre email" required
 inputmode="email" autocomplete="email">
 <button class="btn" type="submit">S'abonner</button>
 <small class="muted" data-newsletter-status>1 email/semaine max. Désinscription à tout moment.</small>
 </form>
 <div class="address">Studio Pixel • 126 rue de Stalingrad, 38100 Grenoble</div>

 <!-- small footer links -->
 <div style="margin-top:6px;text-align:center;">
 <a href="/mentions/" class="muted">Mentions légales</a>
 <span class="muted"> · </span>
 <a href="/programme-piercing/" class="muted">Formation piercing</a>
 <span class="muted"> · </span>
 <a href="https://www.instagram.com/studiopixel.tattoo/" class="muted" target="_blank" rel="noopener">Nous suivre
 sur Instagram</a>
 <span class="muted"> · </span>
 <a href="#cookies" class="muted" data-cookie-settings>Gérer les cookies</a>
 </div>
 </footer>

 <div class="cookie-banner" id="cookie-banner" role="region" aria-label="Préférences cookies" tabindex="-1" hidden>
 <div class="cookie-banner__text">
 <strong>Cookies</strong>
 <p class="cookie-banner__desc">On utilise des cookies de mesure d’audience. Tu peux accepter ou refuser, et changer d’avis à tout moment.</p>
 </div>
 <div class="cookie-banner__actions">
 <button type="button" class="btn btn--ghost cookie-banner__btn" data-cookie-deny>Tout refuser</button>
 <button type="button" class="btn cookie-banner__btn" data-cookie-accept>Tout accepter</button>
 </div>
 </div>

 <script>
 // Small helper to fetch JSON without blocking, with timeout
 function getJSON(url, ms = 5000) { return new Promise((res) => { const c = new AbortController(); const t = setTimeout(() => c.abort(), ms); fetch(url, { signal: c.signal, credentials: 'omit' }).then(r => r.json()).then(j => { clearTimeout(t); res(j) }).catch(() => res(null)) }) }

 (function () {
 document.addEventListener('submit', function (event) {
 var form = event.target && event.target.closest ? event.target.closest('[data-lead-newsletter]') : null;
 if (!form) return;
 event.preventDefault();
 var status = form.querySelector('[data-newsletter-status]');
 var email = form.querySelector('input[type="email"]');
 if (!email || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(String(email.value || '').trim())) {
 if (status) status.textContent = 'Indique une adresse email valide.';
 if (email) email.focus();
 return;
 }
 if (status) status.textContent = 'Inscription en cours...';
 var data = new FormData(form);
 data.set('email', String(email.value || '').trim());
 data.set('current_url', location.href);
 if (window.MathCaptcha) {
 MathCaptcha.appendToFormData(data);
 }
 fetch(form.action, {
 method: 'POST',
 headers: { 'Accept': 'application/json' },
 body: data
 }).then(function (response) {
 return response.json().catch(function () { return {}; }).then(function (payload) {
 // 429: rate limited, show captcha
 if (response.status === 429 && payload.captcha_required && window.MathCaptcha) {
 if (status) status.textContent = '';
 MathCaptcha.ensureContainer(form);
 MathCaptcha.handleResponse(payload, form.action);
 return;
 }
 if (!response.ok || !payload.ok) throw new Error(payload.error || 'Erreur inscription');
 if (status) status.textContent = 'Inscription confirmée.';
 form.reset();
 });
 }).catch(function () {
 if (status) status.textContent = 'Inscription impossible pour le moment.';
 });
 });
 })();

 // Mobile nav toggle
 (function () {
 var btn = document.querySelector('.nav-toggle');
 var nav = document.getElementById('mainnav');
 var closeBtn = document.querySelector('.nav-close');
 var backdrop = null;
 if (!btn || !nav) return;
 // Add swipe-to-left-to-close behavior on the open side panel
 function enableSwipeToClose() {
 var startX = 0, currentX = 0, dragging = false, maxDrag = 0;
 function onStart(e) {
 if (nav.getAttribute('data-open') !== '1') return;
 var t = (e.touches && e.touches[0]) || e;
 startX = t.clientX;
 currentX = startX;
 dragging = true;
 maxDrag = nav.clientWidth; // 70vw
 nav.style.transition = 'none';
 }
 function onMove(e) {
 if (!dragging) return;
 var t = (e.touches && e.touches[0]) || e;
 currentX = t.clientX;
 var dx = currentX - startX; // left swipe => negative dx
 // Clamp translate between 0 and -maxDrag
 var tx = Math.max(-maxDrag, Math.min(0, dx));
 // If moving mostly horizontally, prevent vertical scroll
 if (Math.abs(dx) > 10) { try { e.preventDefault(); } catch (_) { } }
 nav.style.transform = 'translateX(' + tx + 'px)';
 }
 function onEnd() {
 if (!dragging) return;
 dragging = false;
 var dx = currentX - startX;
 nav.style.transition = '';
 // Close if swiped left beyond 80px or >35% of panel width
 if (dx < -80 || Math.abs(dx) > maxDrag * 0.35) {
 nav.style.transform = '';
 toggle(false);
 } else {
 // snap back open
 nav.style.transform = 'translateX(0)';
 setTimeout(function () { nav.style.transform = ''; }, 250);
 }
 }
 // Touch listeners
 nav.addEventListener('touchstart', onStart, { passive: false });
 nav.addEventListener('touchmove', onMove, { passive: false });
 nav.addEventListener('touchend', onEnd, { passive: true });
 nav.addEventListener('touchcancel', onEnd, { passive: true });
 }
 function ensureBackdrop() {
 if (!backdrop) {
 backdrop = document.createElement('div');
 backdrop.className = 'nav-backdrop';
 }
 if (!backdrop.parentNode) {
 document.body.appendChild(backdrop);
 }
 return backdrop;
 }
 function onBackdropClick() { toggle(false); }
 function toggle(open) {
 var isOpen = open != null ? !!open : nav.getAttribute('data-open') !== '1';
 nav.setAttribute('data-open', isOpen ? '1' : '0');
 btn.setAttribute('aria-expanded', isOpen ? 'true' : 'false');
 document.documentElement.classList.toggle('mobile-nav-open', isOpen);
 if (isOpen) {
 try { closeBtn && closeBtn.focus(); } catch (e) { }
 var b = ensureBackdrop();
 b.addEventListener('click', onBackdropClick, { once: false });
 b.style.display = 'block';
 // reset potential drag offset when opening
 nav.style.transform = 'translateX(0)';
 } else {
 if (backdrop) {
 backdrop.style.display = 'none';
 backdrop.removeEventListener('click', onBackdropClick);
 if (backdrop.parentNode) backdrop.parentNode.removeChild(backdrop);
 backdrop = null;
 }
 nav.style.transform = '';
 }
 }
 btn.addEventListener('click', function () { toggle(); });
 if (closeBtn) closeBtn.addEventListener('click', function () { toggle(false); });
 nav.addEventListener('click', function (e) {
 var t = e.target;
 if (t && (t.classList.contains('nav-link') || t.classList.contains('btn'))) {
 toggle(false);
 }
 });
 var mainNav = document.querySelector('.main-nav');
 if (mainNav) {
 mainNav.addEventListener('scroll', function () {
 if (this.scrollTop + this.clientHeight >= this.scrollHeight) {
 this.dataset.open = '0';
 btn.setAttribute('aria-expanded', 'false');
 document.documentElement.classList.remove('mobile-nav-open');
 }
 });
 }
 // Initialize swipe handling once
 enableSwipeToClose();
 })();

 // Cookie consent banner (accept/refuse + reopen from footer link)
 (function () {
 var KEY = 'cookie-consent';
 var banner = document.getElementById('cookie-banner');
 if (!banner) return;
 var btnAccept = banner.querySelector('[data-cookie-accept]');
 var btnDeny = banner.querySelector('[data-cookie-deny]');
 var manageLinks = document.querySelectorAll('[data-cookie-settings]');

 function applyAnalyticsPreference(val) {
 var disable = val === 'denied';
 window['ga-disable-G-PBLFFTB4GZ'] = disable;
 }
 function save(val) {
 try { localStorage.setItem(KEY, val); } catch (e) { /* ignore */ }
 applyAnalyticsPreference(val);
 }
 function hide() {
 banner.hidden = true;
 banner.setAttribute('aria-hidden', 'true');
 document.documentElement.classList.remove('cookie-banner-open');
 }
 function show() {
 banner.hidden = false;
 banner.setAttribute('aria-hidden', 'false');
 document.documentElement.classList.add('cookie-banner-open');
 try { banner.focus({ preventScroll: true }); } catch (e) { /* ignore */ }
 }
 function onAccept() { save('accepted'); hide(); }
 function onDeny() { save('denied'); hide(); }

 if (btnAccept) btnAccept.addEventListener('click', onAccept);
 if (btnDeny) btnDeny.addEventListener('click', onDeny);
 manageLinks.forEach(function (lnk) {
 lnk.addEventListener('click', function (e) {
 e.preventDefault();
 show();
 });
 });

 // Auto-add manage link if missing in older static pages
 if (!manageLinks.length) {
 var footerLinks = document.querySelector('.foot div');
 if (footerLinks) {
 var sep = document.createElement('span');
 sep.className = 'muted';
 sep.textContent = ' · ';
 var link = document.createElement('a');
 link.href = '#cookies';
 link.className = 'muted';
 link.setAttribute('data-cookie-settings', '1');
 link.textContent = 'Gérer les cookies';
 footerLinks.appendChild(sep);
 footerLinks.appendChild(link);
 link.addEventListener('click', function (e) { e.preventDefault(); show(); });
 }
 }

 var pref = null;
 try { pref = localStorage.getItem(KEY); } catch (e) { /* ignore */ }
 if (pref === 'accepted' || pref === 'denied') {
 applyAnalyticsPreference(pref);
 } else {
 show();
 }
 })();
 </script>
<script>(function(){function c(){var b=a.contentDocument||a.contentWindow.document;if(b){var d=b.createElement('script');d.innerHTML="window.__CF$cv$params={r:'a05c70f6dca44434',t:'MTc4MDQ2NjA0Ng=='};var a=document.createElement('script');a.src='/cdn-cgi/challenge-platform/scripts/jsd/main.js';document.getElementsByTagName('head')[0].appendChild(a);";b.getElementsByTagName('head')[0].appendChild(d)}}if(document.body){var a=document.createElement('iframe');a.height=1;a.width=1;a.style.position='absolute';a.style.top=0;a.style.left=0;a.style.border='none';a.style.visibility='hidden';document.body.appendChild(a);if('loading'!==document.readyState)c();else if(window.addEventListener)document.addEventListener('DOMContentLoaded',c);else{var e=document.onreadystatechange||function(){};document.onreadystatechange=function(b){e(b);'loading'!==document.readyState&&(document.onreadystatechange=e,c())}}}})();</script></body>

</html>
