<?php
if(!function_exists('mois_an')){function mois_an($date){if(!$date)return '';$ts=strtotime($date);if(!$ts)return '';$m=[1=>'janvier','fevrier','mars','avril','mai','juin','juillet','aout','septembre','octobre','novembre','decembre'];$m[2]='f'.chr(0xC3).chr(0xA9).'vrier';$m[8]='ao'.chr(0xC3).chr(0xBB).'t';$m[12]='d'.chr(0xC3).chr(0xA9).'cembre';return $m[(int)date('n',$ts)].' '.date('Y',$ts);}}

// ============================================================
// template.php — gabarit unique du site public.
// Toute page définit ses variables puis appelle render_page().
// Modifier ce fichier = modifier l'ossature de TOUT le site.
//
// Usage type dans une page :
//   require_once 'inc/template.php';
//   page_title('Titre'); page_desc('...'); page_active('temoignages');
//   ob_start();  ... HTML du contenu ...  $contenu = ob_get_clean();
//   render_page($contenu);
// ============================================================
require_once __DIR__ . '/config.php';
require_once __DIR__ . '/data.php';
require_once __DIR__ . '/auth.php';
require_once __DIR__ . '/zones.php';
require_once __DIR__ . '/galeries.php';
require_once __DIR__ . '/sections.php';

// Démarrage de session AVANT tout HTML (évite "session_name() ... headers
// already been sent"). On ne démarre la session QUE si le cookie admin est
// présent : les visiteurs anonymes ne reçoivent ni session ni cookie, ce qui
// laisse le HTML public pleinement cacheable par LiteSpeed.
if (!headers_sent()
    && session_status() !== PHP_SESSION_ACTIVE
    && !empty($_COOKIE['tuina_admin'])) {
    auth_start();
}



$GLOBALS['_pg'] = [
    'title'  => SITE_NAME,
    'desc'   => '',
    'active' => '',       // clé du menu actif
    'og_image' => '',
    'body_class' => '',
    'head_extra' => '',
];

function page_title(string $t): void { $GLOBALS['_pg']['title'] = $t; }
function page_desc(string $d): void  { $GLOBALS['_pg']['desc'] = $d; }
function page_active(string $a): void{ $GLOBALS['_pg']['active'] = $a; }
function page_og_image(string $u): void { $GLOBALS['_pg']['og_image'] = $u; }
function page_canonical(string $u): void { $GLOBALS['_pg']['canonical'] = $u; }

/**
 * Fil d'Ariane réutilisable : HTML visible + Schema.org BreadcrumbList.
 * $items : tableau d'étapes [['Accueil','/'], ['Articles','/articles.php'], ['Titre', null]]
 *          (le dernier élément, sans URL, est la page courante).
 * "Accueil" est ajouté automatiquement s'il n'est pas en premier.
 */
function fil_ariane(array $items): string {
    // garantir Accueil en tête (sauf s'il y est déjà)
    $premierEstAccueil = !empty($items) && ($items[0][1] ?? '') === '/';
    if (!$premierEstAccueil) {
        array_unshift($items, ['Accueil', '/']);
    }
    $html = '<nav class="breadcrumb" aria-label="Fil d\'Ariane">';
    $ld = [];
    $pos = 1;
    $last = count($items) - 1;
    foreach ($items as $i => $it) {
        $label = $it[0];
        $url   = $it[1] ?? null;
        if ($i > 0) $html .= ' <span>›</span> ';
        if ($url && $i !== $last) {
            $html .= '<a href="' . e($url) . '">' . e($label) . '</a>';
        } else {
            $html .= '<span class="bc-cur">' . e($label) . '</span>';
        }
        $ld[] = [
            '@type' => 'ListItem',
            'position' => $pos++,
            'name' => $label,
            'item' => (function($u){ $u = $u ?: ($_SERVER['REQUEST_URI'] ?? '/'); return preg_match('#^https?://#', $u) ? $u : SITE_URL . $u; })($url),
        ];
    }
    $html .= '</nav>';
    $schema = json_encode([
        '@context' => 'https://schema.org',
        '@type' => 'BreadcrumbList',
        'itemListElement' => $ld,
    ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
    $html .= '<script type="application/ld+json">' . $schema . '</script>';
    return $html;
}
function page_body_class(string $c): void { $GLOBALS['_pg']['body_class'] = $c; }
function page_head(string $h): void { $GLOBALS['_pg']['head_extra'] .= $h; }

// Zone image ronde en fondu, en haut à droite d'un hero de page.
// $cle : identifiant unique de la zone (ex: 'hero.contact')
function hero_image($cle): void {
    echo '<div class="hero-img-wrap">';
    zone_image($cle, '1/1', '', 'ronde hero-img');
    echo '</div>';
}

// Le menu, défini une seule fois ici
function site_menu(): array {
    return [
        'left' => [
            ['Le Tuina', '/le-tuina.php', 'le-tuina'],
            ['Les soins', '/les-soins.php', 'les-soins'],
            ['Le praticien', '/le-praticien.php', 'le-praticien'],
            ['Témoignages', '/temoignages/', 'temoignages'],
        ],
        'right' => [
            ['Formations', '/formations.php', 'formations'],
            ['Articles', '/articles.php', 'articles'],
            ['Liens', '/liens.php', 'liens'],
            ['Contact', '/contact.php', 'contact'],
        ],
    ];
}

function render_header(): void {
    $pg = $GLOBALS['_pg'];
    $menu = site_menu();
    $mk = function($items){
        $out='';
        foreach($items as $it){
            $cls = ($GLOBALS['_pg']['active']===$it[2]) ? ' class="lk active"' : ' class="lk"';
            $out .= '<li><a'.$cls.' href="'.$it[1].'">'.e($it[0]).'</a></li>';
        }
        return $out;
    };
    ?>
<div class="topbar">
  <div class="w">
    <div class="l">Cabinet de Caen · Du lundi au vendredi sur rendez-vous</div>
    <div class="r">
      <a href="https://www.facebook.com/herald.loygue" target="_blank" rel="noopener" class="tb-fb" aria-label="Facebook Hérald Loygue">
        <svg viewBox="0 0 24 24" width="15" height="15" fill="currentColor"><path d="M22 12c0-5.52-4.48-10-10-10S2 6.48 2 12c0 4.99 3.66 9.13 8.44 9.88v-6.99H7.9V12h2.54V9.8c0-2.5 1.49-3.89 3.78-3.89 1.09 0 2.24.2 2.24.2v2.46h-1.26c-1.24 0-1.63.77-1.63 1.56V12h2.78l-.44 2.89h-2.34v6.99C18.34 21.13 22 16.99 22 12z"/></svg>
      </a>
      <a href="tel:0231966262">02.31.96.62.62</a>
    </div>
  </div>
</div>
<header class="site">
  <nav class="nav">
    <ul class="l"><?= $mk($menu['left']) ?></ul>
    <a class="logo-square" href="/index.php" aria-label="Accueil — <?= e(SITE_NAME) ?>">
      <img src="/assets/logo.png" alt="<?= e(SITE_NAME) ?>"><span class="logo-nom">tuinaloygue</span>
    </a>
    <ul class="r"><?= $mk($menu['right']) ?></ul>
    <button class="burger" aria-label="Ouvrir le menu" aria-expanded="false">&#9776;</button>
  </nav>
  <!-- Menu mobile unique (combine les deux menus) -->
  <div class="mobile-menu">
    <ul><?= $mk(array_merge($menu['left'],$menu['right'])) ?></ul>
  </div>
</header>
<?php
}

function render_footer(): void {
    ?>
<footer class="site">
  <div class="fin">
    <div>
      <h4>Tuina&nbsp;Loygue</h4>
      <p style="color:#b9b3a6;max-width:34ch">Établissement de soins Tuina — médecine manuelle traditionnelle chinoise. Soins, formations et stages à Caen, en Normandie.</p>
    </div>
    <div>
      <div class="col-t">Découvrir</div>
      <ul>
        <li><a href="/le-tuina.php">Le Tuina</a></li>
        <li><a href="/les-soins.php">Les soins</a></li>
        <li><a href="/le-praticien.php">Le praticien</a></li>
        <li><a href="/temoignages/">Témoignages</a></li>
      </ul>
    </div>
    <div>
      <div class="col-t">Cabinet</div>
      <ul>
        <li>Caen, Normandie</li>
        <li><a href="tel:0231966262">02.31.96.62.62</a></li>
        <li>Du lundi au vendredi</li>
        <li><a href="/contact.php">Prendre rendez-vous</a></li>
      </ul>
    </div>
  </div>
  <div class="affil">
    <span class="affil-t">Membre & affiliations</span>
    <div class="affil-logos">
    <a href="https://www.ufpmtc.fr/" target="_blank" rel="noopener" class="affil-logo"><img src="/assets/logos/ufpmtc.png" alt="UFPMTC"><span>Membre de l'UFPMTC</span></a>
    <a href="https://www.medinat.fr/" target="_blank" rel="noopener" class="affil-logo"><span class="affil-medinat">MEDINAT</span><span>Assuré — groupe Alians</span></a>
    </div>
  </div>
  <div class="fb">© <?= date('Y') ?> Tuina Loygue — Tous droits réservés · <a href="/mentions-legales.php" style="color:inherit">Mentions légales</a> · <a href="/deontologie.php" style="color:inherit">Déontologie</a> · <a href="/rgpd.php" style="color:inherit">Confidentialité</a></div>
</footer>
<?php
}

// Rendu complet de la page
function render_page(string $contenu): void {
    $pg = $GLOBALS['_pg'];
    $title = $pg['title'] === SITE_NAME ? SITE_NAME : $pg['title'].' — '.SITE_NAME;
    ?><!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="icon" href="/assets/favicon.ico" sizes="any">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/favicon-16.png">
<link rel="apple-touch-icon" href="/assets/apple-touch-icon.png">
<?php
  // Empêche l'indexation tant qu'on n'est pas sur le domaine de production.
  // En prod (tuinaloygue.fr / www.tuinaloygue.fr) la balise disparaît seule.
  $host = strtolower($_SERVER['HTTP_HOST'] ?? '');
  $hostsProd = ['tuinaloygue.fr', 'www.tuinaloygue.fr'];
  if (!in_array($host, $hostsProd, true)):
?><meta name="robots" content="noindex, nofollow">
<?php endif; ?>
<title><?= e($title) ?></title>
<?php if($pg['desc']): ?><meta name="description" content="<?= e($pg['desc']) ?>"><?php endif; ?>
<?php
  $canon = $pg['canonical'] ?? (SITE_URL . strtok($_SERVER['REQUEST_URI'] ?? '/', '?'));
?><link rel="canonical" href="<?= e($canon) ?>">
<meta property="og:title" content="<?= e($title) ?>">
<?php if($pg['desc']): ?><meta property="og:description" content="<?= e($pg['desc']) ?>"><?php endif; ?>
<meta property="og:type" content="website">
<meta property="og:site_name" content="<?= e(SITE_NAME) ?>">
<meta property="og:locale" content="fr_FR">
<meta property="og:url" content="<?= e($canon) ?>">
<meta property="og:image" content="<?= e($pg['og_image'] ?: (SITE_URL.'/assets/logo.png')) ?>">
<meta name="twitter:card" content="summary">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="preload" as="style" href="https://fonts.googleapis.com/css2?family=Cormorant+Garamond:ital,wght@0,400;0,500;1,400&family=Marcellus&family=Manrope:wght@300;400;500&family=Ma+Shan+Zheng&display=swap">
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Cormorant+Garamond:ital,wght@0,400;0,500;1,400&family=Marcellus&family=Manrope:wght@300;400;500&family=Ma+Shan+Zheng&display=swap" media="print" onload="this.media='all'">
<noscript><link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Cormorant+Garamond:ital,wght@0,400;0,500;1,400&family=Marcellus&family=Manrope:wght@300;400;500&family=Ma+Shan+Zheng&display=swap"></noscript>
<link rel="stylesheet" href="/assets/style.css?v=<?= @filemtime(__DIR__.'/../assets/style.css') ?>">
<?php
  $orgSchema = [
    '@context' => 'https://schema.org',
    '@type' => 'MedicalBusiness',
    '@id' => SITE_URL . '/#cabinet',
    'name' => 'Tuina Loygue',
    'description' => "Établissement de soins Tuina — médecine manuelle traditionnelle chinoise. Soins, formations et stages à Caen, en Normandie.",
    'url' => SITE_URL . '/',
    'logo' => SITE_URL . '/assets/logo.png',
    'image' => SITE_URL . '/assets/logo.png',
    'telephone' => '+33231966262',
    'medicineSystem' => 'Traditional Chinese Medicine',
    'address' => [
      '@type' => 'PostalAddress',
      'streetAddress' => '12 rue Laplace',
      'addressLocality' => 'Caen',
      'addressRegion' => 'Normandie',
      'postalCode' => '14000',
      'addressCountry' => 'FR',
    ],
    'geo' => [
      '@type' => 'GeoCoordinates',
      'latitude' => 49.1785913,
      'longitude' => -0.3547057,
    ],
    'hasMap' => 'https://www.google.com/maps/search/?api=1&query=49.1785913,-0.3547057',
    'areaServed' => 'Caen, Normandie',
    'priceRange' => '€€',
    'openingHoursSpecification' => [
      '@type' => 'OpeningHoursSpecification',
      'dayOfWeek' => ['Monday','Tuesday','Wednesday','Thursday','Friday'],
      'opens' => '07:00',
      'closes' => '17:00',
    ],
    'sameAs' => ['https://www.facebook.com/herald.loygue'],
  ];
  echo '<script type="application/ld+json">' . json_encode($orgSchema, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . '</script>' . "\n";
?>
<?= $pg['head_extra'] ?>
<!-- Google tag (gtag.js) GA4 -->
 <script async src="https://www.googletagmanager.com/gtag/js?id=G-DCMDBXQC8Y"></script>
 <script>
   window.dataLayer = window.dataLayer || [];
   function gtag(){dataLayer.push(arguments);}
   gtag('js', new Date());
   gtag('config', 'G-DCMDBXQC8Y');
 </script>
</head>
<body<?= $pg['body_class'] ? ' class="'.e($pg['body_class']).'"' : '' ?>>
<?php render_header(); ?>
<?= appliquer_shortcodes_galerie($contenu) ?>
<?php $__hote = $GLOBALS['_pg']['active'] ?? ''; if ($__hote !== '') { rendre_sections($__hote); } ?>
<script>/*sl-nav-init*/(function(){document.querySelectorAll(".sl-nav").forEach(function(b){b.addEventListener("click",function(){var t=document.getElementById(b.getAttribute("data-t"));if(!t)return;var step=t.querySelector(".sl-item");var d=step?step.getBoundingClientRect().width+16:300;t.scrollBy({left:b.classList.contains("sl-prev")?-d:d,behavior:"smooth"});});});})();</script>
<?php render_footer(); ?>
<?php textes_auto_runtime(); ?>
<?php admin_bar(); ?>
<div class="cookie-banner" id="cookieBanner" role="dialog" aria-live="polite" aria-label="Information cookies" hidden>
  <p>Ce site utilise uniquement des cookies techniques nécessaires à son fonctionnement, sans aucun traçage publicitaire. <a href="/rgpd.php">En savoir plus</a>.</p>
  <button type="button" class="btn btn-blue" id="cookieOk">J'ai compris</button>
</div>
<script>
(function(){
  try{
    var key='tuina_cookie_ok';
    if(localStorage.getItem(key)!=='1'){
      var bn=document.getElementById('cookieBanner');
      if(bn){
        bn.hidden=false;
        var ok=document.getElementById('cookieOk');
        if(ok) ok.addEventListener('click',function(){ try{localStorage.setItem(key,'1');}catch(e){} bn.hidden=true; });
      }
    }
  }catch(e){}
})();
</script>
<script>
(function(){
  var b=document.querySelector('.burger');
  var h=document.querySelector('header.site');
  if(b&&h){
    b.addEventListener('click',function(){
      h.classList.toggle('menu-open');
      b.setAttribute('aria-expanded', h.classList.contains('menu-open')?'true':'false');
    });
    // referme le menu quand on clique un lien du panneau mobile
    h.querySelectorAll('.mobile-menu a').forEach(function(a){
      a.addEventListener('click',function(){ h.classList.remove('menu-open'); b.setAttribute('aria-expanded','false'); });
    });
  }
  // au scroll : replier le logo (mobile) — ne garder que le hamburger
  if(h){
    var onScroll=function(){
      if(window.scrollY>60){ h.classList.add('scrolled'); }
      else{ h.classList.remove('scrolled'); }
    };
    window.addEventListener('scroll',onScroll,{passive:true});
    onScroll();
  }
})();
</script>
<style>
.gal-link{display:block;cursor:zoom-in}
.glb-zoomable{cursor:zoom-in}
#galLightbox{position:fixed;inset:0;z-index:9999;display:none;align-items:center;justify-content:center;background:rgba(15,18,20,.92);padding:2rem;opacity:0;transition:opacity .25s ease}
#galLightbox.open{display:flex;opacity:1}
#galLightbox img{max-width:92vw;max-height:82vh;width:auto;height:auto;border-radius:6px;box-shadow:0 18px 60px rgba(0,0,0,.5);transform:scale(.97);transition:transform .25s ease}
#galLightbox.open img{transform:scale(1)}
#galLightbox .glb-cap{position:absolute;bottom:1.2rem;left:0;right:0;text-align:center;color:#f3efe8;font-family:'Manrope',sans-serif;font-size:.95rem;padding:0 1rem}
#galLightbox .glb-btn{position:absolute;background:none;border:0;color:#f3efe8;font-size:2.4rem;line-height:1;cursor:pointer;padding:.4rem .9rem;opacity:.8;transition:opacity .2s}
#galLightbox .glb-btn:hover{opacity:1}
#galLightbox .glb-close{top:1rem;right:1.2rem;font-size:2rem}
#galLightbox .glb-prev{left:.5rem;top:50%;transform:translateY(-50%)}
#galLightbox .glb-next{right:.5rem;top:50%;transform:translateY(-50%)}
@media(max-width:640px){#galLightbox .glb-prev,#galLightbox .glb-next{font-size:1.8rem}}
</style>
<div id="galLightbox" role="dialog" aria-modal="true" aria-label="Image agrandie">
  <button type="button" class="glb-btn glb-close" aria-label="Fermer">&times;</button>
  <button type="button" class="glb-btn glb-prev" aria-label="Precedent">&lsaquo;</button>
  <img src="" alt="">
  <button type="button" class="glb-btn glb-next" aria-label="Suivant">&rsaquo;</button>
  <div class="glb-cap"></div>
</div>
<script>/*gal-lightbox*/(function(){
  var box=document.getElementById('galLightbox');
  if(!box) return;
  var img=box.querySelector('img'), cap=box.querySelector('.glb-cap');
  var links=[], idx=0;
  function show(i){
    if(i<0)i=links.length-1; if(i>=links.length)i=0; idx=i;
    var a=links[idx];
    img.src=a.getAttribute('href'); img.alt=a.getAttribute('data-cap')||'';
    var c=a.getAttribute('data-cap')||''; cap.textContent=c; cap.style.display=c?'block':'none';
  }
  function openLb(group,i){links=group;show(i);box.classList.add('open');document.body.style.overflow='hidden';}
  function closeLb(){box.classList.remove('open');document.body.style.overflow='';img.src='';}
  document.addEventListener('click',function(e){
    var a=e.target.closest&&e.target.closest('.gal-link');
    if(!a) return;
    e.preventDefault();
    var zone=a.closest('.gal-zone,.sl-zone')||document;
    var group=Array.prototype.slice.call(zone.querySelectorAll('.gal-link'));
    openLb(group, group.indexOf(a));
  });
  box.querySelector('.glb-close').addEventListener('click',closeLb);
  box.querySelector('.glb-prev').addEventListener('click',function(){show(idx-1);});
  box.querySelector('.glb-next').addEventListener('click',function(){show(idx+1);});
  box.addEventListener('click',function(e){if(e.target===box)closeLb();});
  document.addEventListener('keydown',function(e){
    if(!box.classList.contains('open'))return;
    if(e.key==='Escape')closeLb();
    else if(e.key==='ArrowLeft')show(idx-1);
    else if(e.key==='ArrowRight')show(idx+1);
  });
})();</script>
</body>
</html>
<?php
}
