// screens.jsx — All screens for La Roue Fleur de Sel
// Each screen accepts { width, height, mobile, onNavigate, prize, spinning, started }
// and renders the contents to fit the artboard. Footer is shared.

// Lien direct pour laisser un avis Google sur la fiche du restaurant (lien de partage Google).
const GOOGLE_REVIEW_URL = 'https://g.page/r/CUhEiqjErhTuEBE/review';

// Helpers pour l'horodatage / numero de participation affiches en bas des ecrans Win et Lose.
// Permet au serveur de verifier la date du gain (anti-screenshot recycle) et de tracer dans l'admin.
const MONTHS_FR = ['janvier', 'février', 'mars', 'avril', 'mai', 'juin', 'juillet', 'août', 'septembre', 'octobre', 'novembre', 'décembre'];
function formatPlayedAt(ms) {
  const d = new Date(ms);
  const dd = d.getDate();
  const mm = MONTHS_FR[d.getMonth()];
  const yy = d.getFullYear();
  const hh = String(d.getHours()).padStart(2, '0');
  const mn = String(d.getMinutes()).padStart(2, '0');
  return `Joué le ${dd} ${mm} ${yy} à ${hh}h${mn}`;
}
function getParticipationNo() {
  const n = window.FDSBackend?.getStats?.()?.participations || 1;
  return `FDS-${String(n).padStart(4, '0')}`;
}

const COLORS = {
  // Palette alignee sur l'identite visuelle du restaurant client (fleurdesel-lgc.com)
  bg: '#FAF6F0',        // background du site (HSL 38 15% 97%)
  surface: '#FFFFFF',
  ink: '#2F231A',       // foreground (HSL 25 30% 15%) marron tres fonce
  ink2: '#6B5A48',      // muted-foreground (HSL 25 15% 45%)
  gold: '#C9954A',      // accent dore conserve pour le visuel casino/bistrot
  goldDark: '#5C4422',  // primary du site (HSL 35 45% 25%) warm-brown
  cream: '#F5EDD9',     // cream du site (HSL 42 40% 95%)
  border: '#E0D7C5',    // border (HSL 35 15% 88%)
  // Conserves pour les illustrations du jeu (icones secteurs roue)
  peach: '#F5C9B5',
  sky: '#C5D6DC',
  sage: '#B8C8B0',
  greyBlue: '#9CABB7',
};

// ─────────────── Shared bits ───────────────

function CityCrest({ size = 28, color = '#3a3a3a' }) {
  // Original geometric crest placeholder (NOT a real municipal logo)
  return (
    <svg width={size} height={size * 1.1} viewBox="0 0 40 44" style={{ display: 'block' }}>
      {/* tiny crown */}
      <path d={`M8 10 L8 6 L11 8 L14 4 L17 8 L20 4 L23 8 L26 4 L29 8 L32 6 L32 10 Z`}
        fill={color} />
      {/* shield */}
      <path d="M6 12 L34 12 L34 26 C34 34 27 40 20 42 C13 40 6 34 6 26 Z"
        fill="none" stroke={color} strokeWidth="2" />
      {/* shield interior cross + dots */}
      <line x1="20" y1="13" x2="20" y2="40" stroke={color} strokeWidth="1.4" />
      <line x1="7" y1="24" x2="33" y2="24" stroke={color} strokeWidth="1.4" />
      <circle cx="13.5" cy="18" r="1.6" fill={color} />
      <circle cx="26.5" cy="18" r="1.6" fill={color} />
      <circle cx="13.5" cy="31" r="1.6" fill={color} />
      <circle cx="26.5" cy="31" r="1.6" fill={color} />
    </svg>
  );
}

function CityWordmark({ scale = 1, color = '#3a3a3a' }) {
  return (
    <div style={{
      display: 'flex', alignItems: 'center', gap: 8 * scale,
    }}>
      <CityCrest size={28 * scale} color={color} />
      <div style={{
        fontFamily: 'Inter, sans-serif',
        fontWeight: 800,
        fontSize: 11 * scale,
        lineHeight: 1.05,
        letterSpacing: '-0.01em',
        color,
        textTransform: 'uppercase',
      }}>
        <div style={{ fontWeight: 500 }}>La</div>
        <div>Garenne—</div>
        <div>Colombes</div>
      </div>
    </div>
  );
}

// Icone couverts (fourchette + couteau) facon "carte de restaurant".
function MenuIcon({ size = 15, color = 'currentColor' }) {
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="none"
      stroke={color} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"
      style={{ display: 'block' }}>
      <path d="M3 2v7c0 1.1.9 2 2 2h0a2 2 0 0 0 2-2V2" />
      <path d="M7 2v20" />
      <path d="M21 15V2a5 5 0 0 0-5 5v6c0 1.1.9 2 2 2h3Zm0 0v7" />
    </svg>
  );
}

// Banniere de marque affichee en haut de toute l'app (live).
// Reprend le wordmark du site fleurdesel-lgc.com : "FLEUR DE SEL" en Futura,
// couleur primary (brun) et majuscules (cf. .font-futura.text-primary.uppercase).
function TopBanner() {
  const futura = '"Futura", "Century Gothic", "Avenir Next", sans-serif';
  return (
    <div style={{
      position: 'sticky', top: 0, zIndex: 60,
      width: '100%', boxSizing: 'border-box',
      display: 'flex', alignItems: 'center', justifyContent: 'space-between',
      gap: 10, padding: '11px 18px',
      background: 'rgba(250,246,240,0.97)', // fond creme du site (--background)
      borderBottom: `1px solid ${COLORS.border}`,
      boxShadow: '0 1px 10px rgba(92,68,34,0.07)',
      backdropFilter: 'saturate(1.1) blur(6px)',
      WebkitBackdropFilter: 'saturate(1.1) blur(6px)',
    }}>
      <span style={{
        fontFamily: futura,
        fontWeight: 500, fontSize: 24, lineHeight: 1,
        color: COLORS.goldDark, // primary brun #5C4422
        textTransform: 'uppercase', letterSpacing: '0.04em',
        whiteSpace: 'nowrap',
      }}>Fleur de Sel</span>
      <div style={{ display: 'inline-flex', alignItems: 'center', gap: 8, flexShrink: 0 }}>
        {/* Le menu (carte du resto) — onglet externe, style secondaire (contour). */}
        <a
          href="https://fleurdesel-lgc.com/#menu"
          target="_blank"
          rel="noopener noreferrer"
          style={{
            display: 'inline-flex', alignItems: 'center', gap: 6,
            fontFamily: futura, fontSize: 11, fontWeight: 600,
            textTransform: 'uppercase', letterSpacing: '0.08em',
            color: '#3A2A16', textDecoration: 'none', whiteSpace: 'nowrap',
            padding: '7px 12px', borderRadius: 999,
            background: 'transparent', border: `1px solid ${COLORS.border}`,
          }}
        >
          <MenuIcon size={14} color="#3A2A16" />
          Le menu
        </a>
        {/* Jouer — ramène au jeu depuis n'importe quel écran (retour facile après
            un détour par l'avis Google, la carte, le règlement…). Style primaire. */}
        <button
          onClick={() => {
            // Page admin = document séparé (/admin/) : on revient au jeu par une
            // vraie navigation. Sinon (site du jeu), on quitte une éventuelle
            // sous-route (#reglement…) et on bascule sur la roue via l'event.
            if (window.FDS_ADMIN_PAGE) { window.location.href = '/'; return; }
            if (window.location.hash) window.location.hash = '';
            window.dispatchEvent(new CustomEvent('fds:goto-game'));
          }}
          style={{
            display: 'inline-flex', alignItems: 'center', gap: 6,
            fontFamily: futura, fontSize: 11, fontWeight: 700,
            textTransform: 'uppercase', letterSpacing: '0.08em',
            color: '#3A2A16', cursor: 'pointer', whiteSpace: 'nowrap',
            padding: '7px 13px', borderRadius: 999, border: 'none',
            background: 'linear-gradient(135deg, #EFC139, #E8CF8A)', // gradient gold du site
            boxShadow: '0 2px 8px rgba(201,149,74,0.4)',
          }}
        >
          🎡 Jouer
        </button>
      </div>
    </div>
  );
}

function Footer({ mobile, onNavigate }) {
  const linkStyle = {
    textDecoration: 'underline',
    textUnderlineOffset: 2,
    color: COLORS.ink2,
    background: 'none',
    border: 'none',
    padding: 0,
    font: 'inherit',
    cursor: 'pointer',
  };
  const go = (path) => (e) => {
    e.preventDefault();
    if (onNavigate) onNavigate(path);
  };
  return (
    <div style={{
      borderTop: `1px solid ${COLORS.border}`,
      padding: mobile ? '14px 20px' : '16px 48px',
      fontFamily: 'Inter, sans-serif',
      fontSize: mobile ? 11 : 12,
      color: COLORS.ink2,
      background: COLORS.bg,
      display: 'flex',
      flexDirection: 'column',
      alignItems: 'center',
      gap: 4,
      lineHeight: 1.5,
      textAlign: 'center',
    }}>
      <div style={{ display: 'flex', flexWrap: 'wrap', gap: mobile ? 6 : 12, alignItems: 'center', justifyContent: 'center' }}>
        <span>Restaurant Fleur de Sel</span>
        <span style={{ opacity: 0.5 }}>·</span>
        <span>La Garenne-Colombes</span>
        <span style={{ opacity: 0.5 }}>·</span>
        <button style={linkStyle} onClick={go('reglement')}>Règlement</button>
        <span style={{ opacity: 0.5 }}>·</span>
        <span style={{ textDecoration: 'underline', textUnderlineOffset: 2 }}>Mentions légales</span>
        <span style={{ opacity: 0.5 }}>·</span>
        <span style={{ textDecoration: 'underline', textUnderlineOffset: 2 }}>Données personnelles</span>
      </div>
      <div style={{ fontSize: mobile ? 10 : 11, opacity: 0.85 }}>
        Jeu sans obligation d'achat. Une participation par personne et par jour.
      </div>
    </div>
  );
}

function GoldButton({ children, onClick, fullWidth, disabled, size = 'md', style = {} }) {
  const sizes = {
    sm: { fs: 18, px: 28, py: 12, r: 10 },
    md: { fs: 24, px: 40, py: 16, r: 12 },
    lg: { fs: 28, px: 48, py: 20, r: 12 },
  }[size];
  const [hover, setHover] = React.useState(false);
  return (
    <button
      onClick={onClick}
      disabled={disabled}
      onMouseEnter={() => setHover(true)}
      onMouseLeave={() => setHover(false)}
      style={{
        fontFamily: '"Lobster", cursive',
        fontSize: sizes.fs,
        background: COLORS.goldDark, // deeper for AAA contrast
        color: COLORS.bg,
        border: 'none',
        padding: `${sizes.py}px ${sizes.px}px`,
        borderRadius: sizes.r,
        cursor: disabled ? 'not-allowed' : 'pointer',
        opacity: disabled ? 0.4 : 1,
        width: fullWidth ? '100%' : 'auto',
        transform: hover && !disabled ? 'translateY(-2px)' : 'translateY(0)',
        boxShadow: hover && !disabled
          ? '0 8px 22px rgba(45,53,64,0.14)'
          : '0 4px 12px rgba(45,53,64,0.06)',
        transition: 'transform 180ms ease-out, box-shadow 180ms ease-out, opacity 200ms',
        letterSpacing: '0.01em',
        outlineOffset: 3,
        ...style,
      }}
      onFocus={(e) => e.currentTarget.style.outline = `2px solid ${COLORS.gold}`}
      onBlur={(e) => e.currentTarget.style.outline = 'none'}
    >
      <span style={{
        display: 'inline-block',
        transition: 'transform 180ms ease-out',
        transform: hover && !disabled ? 'translateX(0)' : 'translateX(0)',
      }}>
        {children}
      </span>
    </button>
  );
}

// ─────────────── Animations ───────────────
const fadeUpKF = `
@keyframes fdsFadeUp { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: translateY(0); } }
@keyframes fdsFadeDown { from { opacity: 0; transform: translateY(-10px); } to { opacity: 1; transform: translateY(0); } }
@keyframes fdsScaleBounce { 0% { opacity: 0; transform: scale(0.6); } 60% { transform: scale(1.08); opacity: 1; } 100% { transform: scale(1); } }
@keyframes fdsConfettiFall { 0% { transform: translateY(-20px) rotate(0deg); opacity: 1; } 100% { transform: translateY(110vh) rotate(720deg); opacity: 0.85; } }
@keyframes fdsFadeIn { from { opacity: 0; } to { opacity: 1; } }
@keyframes fdsKenBurns { 0% { transform: scale(1.08) translateY(0); } 50% { transform: scale(1.14) translateY(-8px); } 100% { transform: scale(1.08) translateY(0); } }
@keyframes fdsCityFloat { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-6px); } }
@keyframes fdsTitleRise { 0% { opacity: 0; transform: translateY(24px) rotate(-1.5deg); letter-spacing: 0.04em; } 100% { opacity: 1; transform: translateY(0) rotate(0deg); letter-spacing: 0.005em; } }
@keyframes fdsPillPop { 0% { opacity: 0; transform: translateY(8px) scale(0.92); } 60% { opacity: 1; transform: translateY(0) scale(1.04); } 100% { transform: translateY(0) scale(1); } }
@keyframes fdsShimmer { 0% { background-position: -200% 0; } 100% { background-position: 200% 0; } }
@keyframes fdsArrowNudge { 0%, 100% { transform: translateX(0); } 50% { transform: translateX(5px); } }
@keyframes fdsCloudDrift { 0% { transform: translateX(-10px); } 100% { transform: translateX(10px); } }
@keyframes fdsWheelWobble { 0% { transform: rotate(-19deg); } 50% { transform: rotate(2deg); } 100% { transform: rotate(-19deg); } }
@keyframes fdsComicPop { 0%, 100% { transform: scale(0.78); } 30% { transform: scale(1.18); } 60% { transform: scale(0.92); } }
@keyframes fdsCabaretBlink { 0%, 100% { filter: drop-shadow(0 0 4px #FFE070) drop-shadow(0 0 10px #FFD23F); } 50% { filter: drop-shadow(0 0 8px #FFFFFF) drop-shadow(0 0 18px #FFB800); } }
@keyframes fdsCabaretSparkle { 0%, 100% { opacity: 0; transform: scale(0.6) rotate(0deg); } 30% { opacity: 1; transform: scale(1.2) rotate(120deg); } 60% { opacity: 0.7; transform: scale(0.9) rotate(220deg); } }
.fds-fadeup { animation: fdsFadeUp 600ms ease-out both; }
@keyframes fdsScreenEnter {
  from { opacity: 0; transform: translateY(8px) scale(0.985); filter: blur(3px); }
  to   { opacity: 1; transform: translateY(0)   scale(1);     filter: blur(0); }
}

/* Cabaret yellow shimmering text — wheel hero + subtitles */
@keyframes fdsCabaretFlicker {
  0%, 100% { filter: drop-shadow(0 0 4px #FFE070) drop-shadow(0 0 10px #FFD23F); }
  50%      { filter: drop-shadow(0 0 8px #FFFFFF) drop-shadow(0 0 18px #FFB800); }
}
.fds-cabaret-text {
  font-family: 'Lobster', cursive;
  color: transparent;
  background: linear-gradient(
    to bottom,
    #FFF6B0 0%,
    #FFD23F 35%,
    #FFB800 60%,
    #C9954A 100%
  );
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
  animation: fdsCabaretFlicker 1.4s ease-in-out infinite;
  text-shadow: 0 1px 0 rgba(0,0,0,0.4);
  letter-spacing: 0.01em;
  display: inline-block;
}

/* Casino Art-Déco gold-metallic title — used on the Jeu Concours card */
.fds-casino-title {
  font-family: 'Cinzel', 'Playfair Display', serif !important;
  font-weight: 700 !important;
  text-transform: uppercase;
  letter-spacing: 0.18em !important;
  font-size: 22px !important;
  line-height: 1.1;
  color: transparent !important;
  background: linear-gradient(
    to bottom,
    #f5e27a 0%,
    #c8960c 22%,
    #ffd700 48%,
    #c8960c 72%,
    #8a6500 100%
  );
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
  filter: drop-shadow(0 1px 2px rgba(0,0,0,0.5)) drop-shadow(0 0 0.5px rgba(255,215,0,0.4));
  text-shadow: none;
  display: inline-block;
}
`;
function injectKF() {
  if (document.getElementById('fds-kf')) return;
  const s = document.createElement('style');
  s.id = 'fds-kf';
  s.textContent = fadeUpKF;
  document.head.appendChild(s);
}

// ─────────────── Confetti ───────────────
function Confetti() {
  const pieces = React.useMemo(() => {
    const arr = [];
    const colors = [COLORS.gold, COLORS.peach, COLORS.sage, COLORS.sky, COLORS.cream];
    for (let i = 0; i < 60; i++) {
      arr.push({
        id: i,
        left: Math.random() * 100,
        delay: Math.random() * 4,
        duration: 4 + Math.random() * 3,
        size: 6 + Math.random() * 8,
        color: colors[i % colors.length],
        rot: Math.random() * 360,
      });
    }
    return arr;
  }, []);
  return (
    <div style={{
      position: 'absolute', inset: 0, pointerEvents: 'none',
      overflow: 'hidden', opacity: 0.85, zIndex: 5,
    }}>
      {pieces.map(p => (
        <div key={p.id} style={{
          position: 'absolute',
          top: -20,
          left: `${p.left}%`,
          width: p.size,
          height: p.size * 0.4,
          background: p.color,
          borderRadius: 1,
          transform: `rotate(${p.rot}deg)`,
          animation: `fdsConfettiFall ${p.duration}s linear ${p.delay}s infinite`,
        }} />
      ))}
    </div>
  );
}

// ─────────────── Screen Shell ───────────────
// Back arrow — 44×44 round button, top-left, returns to home/landing.
function BackArrow({ onClick, mobile = true }) {
  if (!onClick) return null;
  return (
    <button
      onClick={onClick}
      aria-label="Retour à l'accueil"
      style={{
        position: 'absolute',
        top: mobile ? 12 : 18,
        left: mobile ? 12 : 18,
        width: 44, height: 44,
        borderRadius: 22, border: 'none',
        background: 'rgba(255,255,255,0.85)',
        backdropFilter: 'blur(8px)',
        WebkitBackdropFilter: 'blur(8px)',
        cursor: 'pointer',
        zIndex: 20,
        display: 'flex', alignItems: 'center', justifyContent: 'center',
        boxShadow: '0 2px 6px rgba(0,0,0,0.1)',
        padding: 0,
      }}
    >
      <svg width="22" height="22" viewBox="0 0 24 24" fill="none"
        stroke={COLORS.ink} strokeWidth="2.4"
        strokeLinecap="round" strokeLinejoin="round">
        <path d="M15 18 L9 12 L15 6" />
      </svg>
    </button>
  );
}

function ScreenShell({ width, height, mobile, children, contentStyle = {}, onNavigate, onBack }) {
  React.useEffect(() => { injectKF(); }, []);
  // En mode design-canvas (IOSDevice avec dimensions fixes), on respecte width/height.
  // En mode live (Phone passe-plat), on prend 100% du parent.
  const inDesign = typeof window !== 'undefined'
    && (window.location.hash === '#design' || window.location.hash === '#canvas');
  return (
    <div style={{
      width: inDesign ? width : '100%',
      height: inDesign ? height : 'auto',
      minHeight: inDesign ? undefined : '100dvh',
      background: COLORS.bg,
      display: 'flex', flexDirection: 'column',
      fontFamily: 'Inter, sans-serif',
      color: COLORS.ink,
      overflow: 'hidden',
      position: 'relative',
    }}>
      <div style={{ flex: 1, display: 'flex', flexDirection: 'column', overflow: 'hidden', position: 'relative', ...contentStyle }}>
        <BackArrow onClick={onBack} mobile={mobile} />
        {children}
      </div>
      <Footer mobile={mobile} onNavigate={onNavigate} />
    </div>
  );
}

// Top mini-bar (used on form & errors): tiny clocher + La Garenne wordmark
function TopBar({ mobile }) {
  return (
    <div style={{
      display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 14,
      padding: mobile ? '14px 16px' : '20px 32px',
      borderBottom: `1px solid ${COLORS.border}`,
      background: COLORS.bg,
    }}>
      {/* tiny clocher */}
      <svg width={mobile ? 22 : 28} height={mobile ? 30 : 38} viewBox="0 0 28 38">
        <line x1="14" y1="0" x2="14" y2="6" stroke={COLORS.greyBlue} strokeWidth="1" />
        <path d="M4 14 L14 4 L24 14 Z" fill={COLORS.greyBlue} />
        <rect x="6" y="14" width="16" height="20" fill={COLORS.surface} stroke={COLORS.greyBlue} strokeWidth="1" />
        <circle cx="14" cy="22" r="3" fill="none" stroke={COLORS.greyBlue} strokeWidth="1" />
        <line x1="14" y1="22" x2="14" y2="20" stroke={COLORS.greyBlue} strokeWidth="0.8" />
        <line x1="14" y1="22" x2="15.5" y2="22" stroke={COLORS.greyBlue} strokeWidth="0.8" />
      </svg>
      <div style={{ width: 1, height: mobile ? 24 : 32, background: COLORS.border }} />
      <CityWordmark scale={mobile ? 0.85 : 1} color={COLORS.ink} />
    </div>
  );
}

// ─────────────── CtaCard — bloc CTA standardisé (titre / baseline / bouton) ───────────────
function CtaCard({ eyebrow, title, baseline, ctaLabel, onClick, accent, ctaPrimary, animDelay = 0, footnote, theme }) {
  const [hover, setHover] = React.useState(false);
  const isCabaret = theme === 'cabaret';
  const isReviews = theme === 'reviews';
  // White-on-dark only for cabaret (dark bg). Reviews uses dark ink on light bg.
  const onDarkText = isCabaret;

  const cardStyle = isCabaret
    ? {
        backgroundImage: 'linear-gradient(rgba(0,0,0,0.55), rgba(0,0,0,0.78)), url(assets/casino-gambling-1.gif)',
        backgroundSize: 'cover',
        backgroundPosition: 'center center',
        border: '4px solid #C9954A',
        boxShadow: hover
          ? '0 8px 28px rgba(0,0,0,0.45), 0 0 18px rgba(255,215,0,0.55), inset 0 0 0 1px #FFE88A, inset 0 0 14px rgba(0,0,0,0.45)'
          : '0 4px 18px rgba(0,0,0,0.35), 0 0 10px rgba(255,215,0,0.35), inset 0 0 0 1px #FFE88A, inset 0 0 14px rgba(0,0,0,0.45)',
      }
    : isReviews
    ? {
        // Plain white background at 50% opacity, no image.
        backgroundColor: 'rgba(255,255,255,0.5)',
        border: `1px solid ${COLORS.border}`,
        cursor: onClick ? 'pointer' : 'default',
        boxShadow: hover
          ? '0 8px 22px rgba(45,53,64,0.10)'
          : '0 3px 12px rgba(45,53,64,0.05)',
      }
    : {
        background: COLORS.surface,
        border: `1px solid ${COLORS.border}`,
        boxShadow: hover ? '0 8px 22px rgba(45,53,64,0.10)' : '0 3px 12px rgba(45,53,64,0.05)',
      };

  // If there's no CTA label, the whole card itself becomes the click target.
  const cardOnClick = !ctaLabel ? onClick : undefined;

  return (
    <div
      onClick={cardOnClick}
      role={cardOnClick ? 'button' : undefined}
      tabIndex={cardOnClick ? 0 : undefined}
      onKeyDown={cardOnClick ? (e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); cardOnClick(); } } : undefined}
      style={{
        display: 'flex', flexDirection: 'column',
        gap: 10, textAlign: 'center', alignItems: 'center',
        padding: '18px 18px 16px',
        borderRadius: 14,
        transition: 'box-shadow 200ms ease, transform 200ms ease',
        transform: hover ? 'translateY(-2px)' : 'translateY(0)',
        animation: `fdsFadeUp 600ms ease-out ${animDelay}ms both`,
        minHeight: 200,
        height: '100%',
        width: '100%',
        boxSizing: 'border-box',
        ...cardStyle,
      }}
      onMouseEnter={() => setHover(true)}
      onMouseLeave={() => setHover(false)}
    >
      <div style={{
        display: 'inline-flex', alignItems: 'center', gap: 6,
        fontSize: 11, letterSpacing: '0.14em', textTransform: 'uppercase',
        color: onDarkText ? '#FFFFFF' : accent, fontWeight: 600,
        textShadow: onDarkText ? '0 1px 2px rgba(0,0,0,0.4)' : 'none',
      }}>{eyebrow}</div>

      {title && (
        <div style={{
          fontFamily: '"Lobster", cursive',
          fontSize: 26, lineHeight: 1.05,
          color: onDarkText ? '#FFFFFF' : COLORS.ink,
        }}>{title}</div>
      )}

      {baseline && (
        <p style={{
          fontSize: 14, lineHeight: 1.5, margin: 0,
          maxWidth: 280, flex: 1,
          color: onDarkText ? '#FFFFFF' : COLORS.ink2,
          textShadow: onDarkText ? '0 1px 2px rgba(0,0,0,0.5)' : 'none',
          fontWeight: onDarkText ? 500 : 400,
          display: 'flex',
          alignItems: 'center',
          justifyContent: 'center',
          textAlign: 'center',
        }}>{baseline}</p>
      )}

      {ctaLabel && <button
        onClick={onClick}
        style={{
          marginTop: 4,
          display: 'inline-flex', alignItems: 'center', justifyContent: 'center', gap: 8,
          width: '100%',
          padding: '12px 20px',
          borderRadius: 10,
          fontFamily: '"Lobster", cursive', fontSize: 18,
          cursor: 'pointer',
          border: isReviews ? 'none' : (ctaPrimary ? 'none' : `1.5px solid ${accent}`),
          background: isReviews
            ? COLORS.goldDark
            : ctaPrimary
              ? `linear-gradient(180deg, ${COLORS.gold} 0%, ${COLORS.goldDark} 100%)`
              : COLORS.surface,
          color: isReviews ? '#fff' : (ctaPrimary ? '#fff' : accent),
          boxShadow: isReviews
            ? '0 4px 12px rgba(164,115,57,0.4)'
            : ctaPrimary
              ? '0 4px 12px rgba(184,140,42,0.35)'
              : '0 2px 8px rgba(45,53,64,0.05)',
          transition: 'transform 160ms ease, box-shadow 160ms ease',
        }}
      >
        {ctaLabel}
        <span style={{
          display: 'inline-block',
          animation: 'fdsArrowNudge 1.6s ease-in-out infinite',
        }}>→</span>
      </button>}

      {footnote && (
        <p style={{
          fontSize: 12, lineHeight: 1.5, margin: '4px 0 0',
          maxWidth: 280,
          color: isCabaret ? 'rgba(255,236,200,0.88)' : COLORS.ink2,
          textShadow: isCabaret ? '0 1px 2px rgba(0,0,0,0.7)' : 'none',
        }}>{footnote}</p>
      )}
    </div>
  );
}

// Petit logo Google (G multicolore).
function GoogleG({ size = 16 }) {
  return (
    <svg width={size} height={size} viewBox="0 0 48 48" style={{ display: 'block' }}>
      <path fill="#4285F4" d="M43.611 20.083h-1.611v-.083H24v8h11.303c-1.649 4.657-6.08 8-11.303 8-6.627 0-12-5.373-12-12s5.373-12 12-12c3.059 0 5.842 1.154 7.961 3.039l5.657-5.657C34.046 6.053 29.268 4 24 4 12.955 4 4 12.955 4 24s8.955 20 20 20 20-8.955 20-20c0-1.341-.138-2.65-.389-3.917z"/>
      <path fill="#34A853" d="M6.306 14.691l6.571 4.819C14.655 15.108 18.961 12 24 12c3.059 0 5.842 1.154 7.961 3.039l5.657-5.657C34.046 6.053 29.268 4 24 4 16.318 4 9.656 8.337 6.306 14.691z"/>
      <path fill="#FBBC05" d="M24 44c5.166 0 9.86-1.977 13.409-5.192l-6.19-5.238C29.211 35.091 26.715 36 24 36c-5.202 0-9.619-3.317-11.283-7.946l-6.522 5.025C9.505 39.556 16.227 44 24 44z"/>
      <path fill="#EA4335" d="M43.611 20.083H42V20H24v8h11.303c-.792 2.237-2.231 4.166-4.087 5.571.001-.001.002-.001.003-.002l6.19 5.238C36.971 39.205 44 34 44 24c0-1.341-.138-2.65-.389-3.917z"/>
    </svg>
  );
}

// Etoile pleine doree.
function Star({ size = 18, color = '#FBB400' }) {
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" fill={color} style={{ display: 'block' }}>
      <path d="M12 2.5l2.92 5.92 6.53.95-4.72 4.6 1.11 6.51L12 17.9l-5.84 3.08 1.11-6.51-4.72-4.6 6.53-.95z"/>
    </svg>
  );
}

// Card "Avis Google" moderne : verre depoli + degrade doux, halo dore,
// chip Google, 5 etoiles, social proof, bouton pill. Toute la card est cliquable.
function ReviewCard({ onClick, animDelay = 0 }) {
  const [hover, setHover] = React.useState(false);
  const open = (e) => { if (e) e.stopPropagation(); if (onClick) onClick(); };
  return (
    <div
      onClick={open}
      role="button"
      tabIndex={0}
      onKeyDown={(e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); open(); } }}
      onMouseEnter={() => setHover(true)}
      onMouseLeave={() => setHover(false)}
      style={{
        position: 'relative', overflow: 'hidden',
        display: 'flex', flexDirection: 'column', alignItems: 'center',
        justifyContent: 'center', textAlign: 'center', gap: 13,
        padding: '24px 20px',
        borderRadius: 20,
        width: '100%', height: '100%', minHeight: 200, boxSizing: 'border-box',
        background: 'linear-gradient(155deg, #FFFFFF 0%, #FBF5E9 100%)',
        border: '1px solid rgba(201,149,74,0.28)',
        boxShadow: hover ? '0 16px 36px rgba(92,68,34,0.16)' : '0 6px 18px rgba(92,68,34,0.08)',
        transform: hover ? 'translateY(-3px)' : 'translateY(0)',
        transition: 'transform 240ms cubic-bezier(0.16,1,0.3,1), box-shadow 240ms ease',
        animation: `fdsFadeUp 600ms ease-out ${animDelay}ms both`,
        cursor: 'pointer',
      }}
    >
      {/* halo dore decoratif */}
      <div style={{
        position: 'absolute', top: -50, right: -50, width: 140, height: 140,
        borderRadius: '50%', pointerEvents: 'none',
        background: 'radial-gradient(circle, rgba(239,193,57,0.25), transparent 70%)',
      }} />

      {/* chip Google */}
      <div style={{
        display: 'inline-flex', alignItems: 'center', gap: 10,
        padding: '9px 18px 9px 14px', borderRadius: 999,
        background: '#fff', border: '1px solid #ECECEC',
        boxShadow: '0 2px 6px rgba(0,0,0,0.08)',
      }}>
        <GoogleG size={24} />
        <span style={{ fontFamily: 'Inter, sans-serif', fontSize: 17, fontWeight: 700, color: '#5f6368', letterSpacing: '0.01em' }}>
          Avis Google
        </span>
      </div>

      {/* etoiles + social proof */}
      <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 7 }}>
        <div style={{ display: 'flex', gap: 4 }}>
          {[0, 1, 2, 3, 4].map(i => <Star key={i} size={21} />)}
        </div>
        <div style={{ fontFamily: 'Inter, sans-serif', fontSize: 12.5, lineHeight: 1.4, color: COLORS.ink2, maxWidth: 240 }}>
          Vous avez passé un bon moment ? Votre avis est notre plus belle récompense.
        </div>
      </div>

      {/* bouton pill moderne */}
      <button
        onClick={open}
        style={{
          marginTop: 2,
          display: 'inline-flex', alignItems: 'center', justifyContent: 'center', gap: 8,
          width: '100%', padding: '13px 20px',
          borderRadius: 999, border: 'none', cursor: 'pointer',
          fontFamily: 'Inter, sans-serif', fontSize: 14.5, fontWeight: 700, letterSpacing: '0.01em',
          color: '#fff',
          background: `linear-gradient(135deg, ${COLORS.gold} 0%, ${COLORS.goldDark} 100%)`,
          boxShadow: '0 6px 16px rgba(164,115,57,0.38)',
        }}
      >
        <Star size={16} color="#fff" />
        Laisser un avis
      </button>
    </div>
  );
}

// ─────────────── 1) LANDING ───────────────
function LandingScreen({ width, height, mobile, onStart, onNavigate, prizes }) {
  // Build prize pills from backend prizes (3 lots) + the catch-all désolés count.
  const p = prizes || (window.FDSBackend ? window.FDSBackend.getPrizes() : null);
  const PRIZES = p ? [
    { label: p.entree.label,   count: String(p.entree.stock),   kind: 'plate' },
    { label: p.cafe.label,     count: String(p.cafe.stock),     kind: 'mug' },
    { label: p.digestif.label, count: String(p.digestif.stock), kind: 'glass' },
    { label: 'Désolés',        count: '∞',                       kind: 'cross' },
  ] : [
    { label: 'Repas pour 2', count: '1',   kind: 'plate' },
    { label: 'Café',         count: '100', kind: 'mug' },
    { label: 'Digestif',     count: '100', kind: 'glass' },
    { label: 'Désolés',      count: '∞',   kind: 'cross' },
  ];
  return (
    <ScreenShell width={width} height={height} mobile={mobile} onNavigate={onNavigate}>
      <div style={{ position: 'relative', flex: 1, overflow: 'hidden', display: 'flex', flexDirection: 'column' }}>
        {/* Cabaret/bistrot backdrop -- meme image que la WheelScreen, voile clair pour le landing */}
        <div style={{
          position: 'absolute', inset: 0, overflow: 'hidden',
          background: '#2A1810', // marron sombre fallback
        }}>
          {/* hero illustration cabaret with ken-burns subtle */}
          <div style={{
            position: 'absolute', inset: 0,
            backgroundImage: 'url(assets/wheel-stage-bg.png)',
            backgroundSize: 'cover',
            backgroundPosition: 'center 30%',
            backgroundRepeat: 'no-repeat',
            animation: 'fdsKenBurns 22s ease-in-out infinite',
          }} />
          {/* voile creme pour le haut (lisibilite titre + cards), s'estompe vers le bas pour reveler le cabaret */}
          <div style={{
            position: 'absolute', inset: 0,
            background: 'linear-gradient(180deg, rgba(250,246,240,0.92) 0%, rgba(250,246,240,0.78) 35%, rgba(250,246,240,0.35) 65%, rgba(42,24,16,0.10) 100%)',
          }} />
        </div>

        {/* Top-aligned content — title 50px from the top */}
        <div style={{
          position: 'relative', zIndex: 2, flex: 1,
          display: 'flex', flexDirection: 'column',
          alignItems: 'center', justifyContent: 'flex-start',
          padding: '80px 24px 28px',
          textAlign: 'center', gap: 16,
        }}>
          {/* (lien "Voir le menu" retire : deja present dans le header TopBanner) */}

          {/* DEUX CARDS + titre intercale entre les deux (cards a hauteur egale via 1fr) */}
          <div style={{
            display: 'grid', gap: 12,
            gridTemplateRows: '1fr auto 1fr',
            width: '100%',
            marginTop: 4,
            flex: 1,
            alignSelf: 'stretch',
          }}>
            <ReviewCard
              animDelay={900}
              onClick={() => {
                window.open(GOOGLE_REVIEW_URL, '_blank', 'noopener,noreferrer');
                window.dispatchEvent(new CustomEvent('fds:review-clicked'));
              }}
            />
            <h1 style={{
              fontFamily: '"Lobster", cursive',
              fontSize: 32, lineHeight: 1.05, margin: '2px 0', color: COLORS.ink,
              textAlign: 'center',
              animation: 'fdsTitleRise 900ms cubic-bezier(0.22, 1, 0.36, 1) 1000ms both',
              textShadow: '0 1px 0 rgba(255,255,255,0.6)',
            }}>
              Tentez votre chance
            </h1>
            <CtaCard
              theme="cabaret"
              eyebrow={<span className="fds-casino-title">Jeu Concours</span>}
              baseline="Un dîner pour deux, un café, un digestif. La fortune est entre vos mains — tournez la roue."
              ctaLabel="Tente ta chance"
              accent={COLORS.goldDark}
              ctaPrimary
              onClick={onStart}
              animDelay={1100}
            />
          </div>
        </div>
      </div>
    </ScreenShell>
  );
}

// ─────────────── 2) FORMULAIRE ───────────────
function FormScreen({ width, height, mobile, onSubmit, onNavigate }) {
  const [name, setName] = React.useState('');
  const [email, setEmail] = React.useState('');
  const [rgpd, setRgpd] = React.useState(false);
  const [touched, setTouched] = React.useState({ name: false, email: false });
  const emailValid = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
  const valid = name.trim().length >= 2 && emailValid && rgpd;

  const inputBase = {
    width: '100%',
    boxSizing: 'border-box',
    padding: mobile ? '14px 14px' : '16px 16px',
    border: `1px solid ${COLORS.border}`,
    borderRadius: 8,
    fontFamily: 'Inter, sans-serif',
    fontSize: mobile ? 15 : 16,
    color: COLORS.ink,
    background: COLORS.surface,
    outline: 'none',
    transition: 'border-color 160ms ease',
  };

  return (
    <ScreenShell width={width} height={height} mobile={mobile} onNavigate={onNavigate} onBack={onBack}>
      <TopBar mobile={mobile} />
      <div style={{
        flex: 1, display: 'flex', alignItems: 'center', justifyContent: 'center',
        padding: mobile ? '24px 16px' : '48px 32px',
        overflow: 'auto',
      }}>
        <div style={{
          width: '100%', maxWidth: 480,
          background: COLORS.surface,
          border: `1px solid ${COLORS.border}`,
          borderRadius: 12,
          padding: mobile ? 28 : 48,
          boxShadow: '0 4px 12px rgba(45,53,64,0.06)',
        }}>
          <h2 style={{
            fontFamily: '"Lobster", cursive',
            fontSize: mobile ? 30 : 36,
            lineHeight: 1.1, margin: 0, color: COLORS.ink,
          }}>
            Avant de faire tourner la roue…
          </h2>
          <p style={{ fontSize: mobile ? 14 : 16, lineHeight: 1.6, color: COLORS.ink2, marginTop: 12, marginBottom: 28 }}>
            Juste votre prénom et votre email. Promis, on n'en fait pas tout un plat.
          </p>

          <label style={{ display: 'block', fontSize: 13, color: COLORS.ink2, marginBottom: 6 }}>Votre prénom</label>
          <input
            value={name}
            onChange={(e) => setName(e.target.value)}
            onBlur={() => setTouched(t => ({ ...t, name: true }))}
            placeholder="Camille"
            style={{
              ...inputBase,
              borderColor: name && touched.name && name.trim().length < 2 ? '#C97C57' : COLORS.border,
            }}
            onFocus={(e) => e.currentTarget.style.borderColor = COLORS.gold}
          />

          <div style={{ height: 18 }} />

          <label style={{ display: 'block', fontSize: 13, color: COLORS.ink2, marginBottom: 6 }}>Votre email</label>
          <input
            type="email"
            value={email}
            onChange={(e) => setEmail(e.target.value)}
            onBlur={() => setTouched(t => ({ ...t, email: true }))}
            placeholder="vous@exemple.com"
            style={{
              ...inputBase,
              borderColor: email && touched.email && !emailValid ? '#C97C57' : COLORS.border,
            }}
            onFocus={(e) => e.currentTarget.style.borderColor = COLORS.gold}
          />
          <div style={{ fontSize: 13, color: COLORS.ink2, marginTop: 8, lineHeight: 1.5 }}>
            Pour identifier votre participation. Aucun message commercial ne vous sera envoyé.
          </div>

          <div style={{ height: 24 }} />

          <label style={{
            display: 'flex', gap: 12, alignItems: 'flex-start', cursor: 'pointer',
            fontSize: mobile ? 13 : 14, lineHeight: 1.6, color: COLORS.ink,
          }}>
            <span style={{
              flexShrink: 0,
              width: 22, height: 22,
              borderRadius: 5,
              border: `1.5px solid ${rgpd ? COLORS.gold : COLORS.greyBlue}`,
              background: rgpd ? COLORS.cream : COLORS.surface,
              display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
              transition: 'all 140ms ease',
              marginTop: 1,
            }}>
              {rgpd && (
                <svg width="14" height="14" viewBox="0 0 14 14"><path d="M2 7 L6 11 L12 3" stroke={COLORS.goldDark} strokeWidth="2" fill="none" strokeLinecap="round" strokeLinejoin="round" /></svg>
              )}
            </span>
            <input type="checkbox" checked={rgpd} onChange={(e) => setRgpd(e.target.checked)}
              style={{ position: 'absolute', opacity: 0, pointerEvents: 'none' }} />
            <span>
              J'ai lu et j'accepte le <a href="#" target="_blank" rel="noopener" style={{ color: COLORS.ink, textDecoration: 'underline', textUnderlineOffset: 2 }}>règlement du jeu</a> et la conservation de mes données pour les besoins du tirage (3 ans maximum).
            </span>
          </label>

          <div style={{ height: 28 }} />

          <GoldButton size="md" fullWidth disabled={!valid} onClick={() => valid && onSubmit({ name, email })}>
            C'est parti !
          </GoldButton>
          <div style={{ textAlign: 'center', marginTop: 14 }}>
            <a href="#" style={{ fontSize: 13, color: COLORS.ink2, textDecoration: 'underline', textUnderlineOffset: 2 }}>
              Voir le règlement complet
            </a>
          </div>
        </div>
      </div>
    </ScreenShell>
  );
}

// ─────────────── 3) WHEEL ───────────────
// Static fallback layout (also used as the visual template for sector colors).
// Index 0 starts at top (-90°) and rotates clockwise.
// Losing sectors all show the same "GAME OVER" sign.
const LOSE_ICONS = ['game-over', 'game-over', 'game-over', 'game-over'];
const WHEEL_FALLBACK = [
  { id: 'cafe',   label: '', color: COLORS.gold,  icon: 'mug',       win: 'cafe' },
  { id: 'lose1',  label: '', color: COLORS.cream, icon: 'game-over', win: null },
  { id: 'dig',    label: '', color: COLORS.peach, icon: 'glass',     win: 'digestif' },
  { id: 'lose2',  label: '', color: COLORS.sky,   icon: 'game-over', win: null },
  { id: 'cafe2',  label: '', color: COLORS.gold,  icon: 'mug',       win: 'cafe' },
  { id: 'lose3',  label: '', color: COLORS.cream, icon: 'game-over', win: null },
  { id: 'entree', label: '', color: COLORS.peach, icon: 'plate',     win: 'entree' },
  { id: 'lose4',  label: '', color: COLORS.sky,   icon: 'game-over', win: null },
];

// Win sectors use coloured PNG icons (named after the prize key).
//   cafe     → cafe.png   (latte cup)
//   digestif → drink.png  (lemonade glass)
//   entree   → diner.png  (fork + knife with heart)
const WIN_SLOT_PALETTE = [
  { color: COLORS.gold,  iconByKey: { cafe: 'cafe', digestif: 'drink', entree: 'diner' } },
  { color: COLORS.peach, iconByKey: { cafe: 'cafe', digestif: 'drink', entree: 'diner' } },
  { color: COLORS.gold,  iconByKey: { cafe: 'cafe', digestif: 'drink', entree: 'diner' } },
  { color: COLORS.peach, iconByKey: { cafe: 'cafe', digestif: 'drink', entree: 'diner' } },
];
const LOSE_SLOT_COLORS = [COLORS.cream, COLORS.sky, COLORS.cream, COLORS.sky];

// Build the 8-sector array from current prize labels + wheelMapping.
function buildWheelSectors(prizes, mapping) {
  if (!prizes || !mapping) return WHEEL_FALLBACK;
  const winIdx = [0, 2, 4, 6];
  const loseIdx = [1, 3, 5, 7];
  const sectors = new Array(8);
  // Short label for the wheel face (e.g. "Café", not "Café offert")
  const shortLabel = (full) => {
    if (!full) return '';
    // take the first word (or first two if very short)
    const first = full.split(/\s+/)[0];
    return first.length <= 3 && full.split(/\s+/).length > 1
      ? full.split(/\s+/).slice(0, 2).join(' ')
      : first;
  };
  winIdx.forEach((idx, i) => {
    const key = mapping[idx];
    sectors[idx] = {
      id: `win-${idx}`,
      label: '',
      color: WIN_SLOT_PALETTE[i].color,
      icon: WIN_SLOT_PALETTE[i].iconByKey[key] || 'mug',
      win: key,
    };
  });
  loseIdx.forEach((idx, i) => {
    sectors[idx] = {
      id: `lose-${idx}`,
      label: '',
      color: LOSE_SLOT_COLORS[i],
      icon: LOSE_ICONS[i],
      win: null,
    };
  });
  return sectors;
}

// Default export still named WHEEL_SECTORS for backward compat with app.jsx;
// it lazily reads from backend on each access.
const WHEEL_SECTORS = new Proxy([], {
  get(_, prop) {
    const prizes = window.FDSBackend?.getPrizes();
    const mapping = window.FDSBackend?.getWheelMapping();
    const arr = buildWheelSectors(prizes, mapping);
    if (prop === 'length') return arr.length;
    if (prop === 'map' || prop === 'forEach' || prop === 'filter' || prop === 'find' || prop === 'findIndex' || prop === 'slice' || prop === Symbol.iterator) {
      return arr[prop].bind(arr);
    }
    return arr[prop];
  }
});

// Single static roulette.png centerpiece — clickable to spin.
function WheelCenterpiece({ onClick, mobile, disabled }) {
  const size = mobile ? 110 : 132;
  return (
    <button
      onClick={onClick}
      disabled={disabled}
      aria-label="Lancer la roue"
      style={{
        position: 'absolute', top: '50%', left: '50%',
        transform: 'translate(-50%, -50%)',
        width: size, height: size,
        borderRadius: '50%',
        background: 'transparent',
        border: 'none',
        cursor: disabled ? 'not-allowed' : 'pointer',
        zIndex: 3,
        padding: 0, overflow: 'visible',
        opacity: disabled ? 0.5 : 1,
        filter: 'drop-shadow(0 4px 12px rgba(45,53,64,0.25))',
      }}
    >
      <img
        src="assets/roulette.png"
        alt=""
        style={{ width: '100%', height: '100%', objectFit: 'contain', display: 'block' }}
      />
    </button>
  );
}

function SectorIcon({ kind, size = 22, color }) {
  const s = size;
  if (kind === 'mug') {
    return <svg width={s} height={s} viewBox="0 0 24 24"><path d="M5 8 H17 V16 a3 3 0 0 1 -3 3 H8 a3 3 0 0 1 -3 -3 Z" fill="none" stroke={color} strokeWidth="1.6"/><path d="M17 10 h2 a2 2 0 0 1 0 4 h-2" fill="none" stroke={color} strokeWidth="1.6"/><path d="M9 4 c0 2 -1 2 -1 4 M12 4 c0 2 -1 2 -1 4" stroke={color} strokeWidth="1.4" fill="none" strokeLinecap="round"/></svg>;
  }
  if (kind === 'glass') {
    return <svg width={s} height={s} viewBox="0 0 24 24"><path d="M5 4 H19 L13 13 V19 H16 M11 19 H8 M11 19 V13 L5 4" fill="none" stroke={color} strokeWidth="1.6" strokeLinejoin="round"/></svg>;
  }
  if (kind === 'plate') {
    return <svg width={s} height={s} viewBox="0 0 24 24"><circle cx="12" cy="12" r="9" fill="none" stroke={color} strokeWidth="1.6"/><circle cx="12" cy="12" r="5" fill="none" stroke={color} strokeWidth="1.4"/></svg>;
  }
  // cross
  return <svg width={s} height={s} viewBox="0 0 24 24"><circle cx="12" cy="12" r="9" fill="none" stroke={color} strokeWidth="1.4" opacity="0.5"/><line x1="6" y1="6" x2="18" y2="18" stroke={color} strokeWidth="1.6" strokeLinecap="round"/></svg>;
}

function WheelSVG({ size, rotation, spinning }) {
  const r = size / 2;
  const cx = r, cy = r;
  const n = WHEEL_SECTORS.length;
  const slice = (2 * Math.PI) / n;
  // Build path for each sector
  const paths = WHEEL_SECTORS.map((sec, i) => {
    const a0 = -Math.PI / 2 + i * slice;
    const a1 = a0 + slice;
    const x0 = cx + r * Math.cos(a0), y0 = cy + r * Math.sin(a0);
    const x1 = cx + r * Math.cos(a1), y1 = cy + r * Math.sin(a1);
    const d = `M${cx},${cy} L${x0},${y0} A${r},${r} 0 0 1 ${x1},${y1} Z`;
    // label position
    const am = (a0 + a1) / 2;
    const lr = r * 0.66;
    const lx = cx + lr * Math.cos(am);
    const ly = cy + lr * Math.sin(am);
    const angleDeg = (am * 180) / Math.PI + 90;
    return { d, sec, lx, ly, angleDeg, i };
  });
  return (
    <svg width={size} height={size} viewBox={`0 0 ${size} ${size}`}
      style={{
        transform: `rotate(${rotation}deg)`,
        transition: spinning ? `transform 4200ms cubic-bezier(0.17, 0.67, 0.22, 1)` : 'none',
        display: 'block',
        filter: 'drop-shadow(0 6px 18px rgba(45,53,64,0.10))',
      }}>
      <defs>
        {/* Shimmering gold gradient — animated by translating the stops. */}
        <linearGradient id="fds-shimmer" x1="0%" y1="0%" x2="100%" y2="0%" gradientUnits="userSpaceOnUse">
          <stop offset="0%"   stopColor="#7A4F1A" />
          <stop offset="35%"  stopColor="#E2B85A" />
          <stop offset="50%"  stopColor="#FFF3C8" />
          <stop offset="65%"  stopColor="#E2B85A" />
          <stop offset="100%" stopColor="#7A4F1A" />
          <animate attributeName="x1" values="-100%;0%;100%;-100%" dur="3.4s" repeatCount="indefinite" />
          <animate attributeName="x2" values="0%;100%;200%;0%"     dur="3.4s" repeatCount="indefinite" />
        </linearGradient>
        {/* Sparkle stroke — thin warm gold outline behind text for legibility. */}
        <filter id="fds-textglow" x="-30%" y="-30%" width="160%" height="160%">
          <feGaussianBlur stdDeviation="1.2" result="b" />
          <feMerge><feMergeNode in="b" /><feMergeNode in="SourceGraphic" /></feMerge>
        </filter>
      </defs>
      {/* outer ring */}
      <circle cx={cx} cy={cy} r={r - 1} fill={COLORS.bg} stroke={COLORS.border} strokeWidth="2" />
      {paths.map(({ d, sec, lx, ly, angleDeg, i }) => {
        // Faces (round-clipped portrait) — kept for back-compat, unused for now
        const isFace = sec.icon === 'lolo' || sec.icon === 'manu';
        // Flat PNG icons (no round clip) for prize/lose sectors
        const isPngIcon = sec.icon === 'cafe' || sec.icon === 'drink'
          || sec.icon === 'diner' || sec.icon === 'game-over';
        // For face sectors, push label *under* the avatar; for prize sectors keep
        // the original layout (icon above, label below).
        const iconYOffset = isFace ? -32 : -28;
        const labelY = isFace ? 32 : 6;
        return (
          <g key={i}>
            <path d={d} fill={sec.color} stroke={COLORS.surface} strokeWidth="2" />
            <g transform={`translate(${lx} ${ly}) rotate(${angleDeg})`}>
              <g transform={`translate(-12 ${iconYOffset})`}>
                {isFace ? (
                  <g transform="translate(-12 -12)">
                    <circle cx="24" cy="24" r="26" fill={COLORS.surface} stroke="#A47339" strokeWidth="1.4" />
                    <clipPath id={`fds-clip-${i}`}>
                      <circle cx="24" cy="24" r="24" />
                    </clipPath>
                    <image
                      href={`assets/${sec.icon}.png`}
                      x="0" y="-4" width="48" height="56"
                      preserveAspectRatio="xMidYMid slice"
                      clipPath={`url(#fds-clip-${i})`}
                    />
                  </g>
                ) : isPngIcon ? (
                  <image
                    href={`assets/${sec.icon}.png`}
                    x="-6" y="-12" width="36" height="36"
                    preserveAspectRatio="xMidYMid meet"
                  />
                ) : (
                  <SectorIcon kind={sec.icon} size={24} color={COLORS.ink} />
                )}
              </g>
              {/* Sector label — only rendered if non-empty */}
              {sec.label ? (
                <text
                  y={labelY} textAnchor="middle"
                  fontFamily='"Lobster", cursive'
                  fontSize={isFace ? 16 : 17}
                  fontWeight={400}
                  stroke="#000000" strokeWidth="0.7"
                  fill="#FFFFFF"
                  style={{ paintOrder: 'stroke' }}
                >{sec.label}</text>
              ) : null}
            </g>
          </g>
        );
      })}
      {/* inner ring decoration */}
      <circle cx={cx} cy={cy} r={r * 0.18} fill={COLORS.bg} stroke="#A47339" strokeWidth="1.5" />
    </svg>
  );
}

function WheelScreen({ width, height, mobile, spinState, onSpin, soundOn, onToggleSound, onNavigate, sectors, onBack }) {
  // spinState: { phase: 'idle'|'spinning'|'done', rotation: number }
  const wheelMax = mobile ? Math.min(width - 40, height * 0.55) : Math.min(height * 0.7, 460);
  // Re-render when admin edits prizes / regenerates the mapping.
  const [, force] = React.useReducer(x => x + 1, 0);
  React.useEffect(() => {
    if (!window.FDSBackend) return;
    return window.FDSBackend.subscribe(() => force());
  }, []);
  const subtitle = spinState.phase === 'spinning'
    ? <span className="fds-cabaret-text" style={{ fontSize: 26, animation: 'fdsCabaretFlicker 1.2s ease-in-out infinite, fdsFadeIn 300ms ease-out' }}>Et la roue tourne…</span>
    : <span style={{
        fontSize: 15, fontFamily: 'Inter, sans-serif', fontWeight: 500,
        color: 'rgba(255,255,255,0.95)',
        textShadow: '0 1px 3px rgba(0,0,0,0.85), 0 0 8px rgba(0,0,0,0.55)',
        letterSpacing: '0.005em',
      }}>Cliquez sur le bouton au centre pour lancer la roue.</span>;

  return (
    <ScreenShell
      width={width} height={height} mobile={mobile} onBack={onBack}
      contentStyle={{
        backgroundImage: 'linear-gradient(rgba(0,0,0,0.45), rgba(0,0,0,0.65)), url(assets/wheel-stage-bg.png)',
        backgroundSize: 'cover',
        backgroundPosition: 'center center',
        backgroundRepeat: 'no-repeat',
      }}
    >
      {/* sound toggle top right -- pill blanc semi-transparent pour rester visible sur fond cabaret sombre */}
      <button
        onClick={onToggleSound}
        aria-label={soundOn ? 'Couper le son' : 'Activer le son'}
        style={{
          position: 'absolute', top: mobile ? 14 : 20, right: mobile ? 14 : 24,
          width: 38, height: 38, borderRadius: 19,
          border: '1px solid rgba(255,255,255,0.25)',
          background: 'rgba(0,0,0,0.35)',
          backdropFilter: 'blur(6px)',
          WebkitBackdropFilter: 'blur(6px)',
          cursor: 'pointer',
          color: 'rgba(255,255,255,0.95)', zIndex: 10,
          display: 'flex', alignItems: 'center', justifyContent: 'center',
          boxShadow: '0 2px 8px rgba(0,0,0,0.25)',
        }}>
        {soundOn ? (
          <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><path d="M11 5L6 9H2v6h4l5 4V5z"/><path d="M19.07 4.93a10 10 0 0 1 0 14.14M15.54 8.46a5 5 0 0 1 0 7.07"/></svg>
        ) : (
          <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><path d="M11 5L6 9H2v6h4l5 4V5z"/><line x1="22" y1="9" x2="16" y2="15"/><line x1="16" y1="9" x2="22" y2="15"/></svg>
        )}
      </button>

      <div style={{
        flex: 1, display: 'flex', flexDirection: 'column',
        alignItems: 'center', justifyContent: 'center',
        padding: mobile ? '20px 16px' : '32px 32px',
        gap: mobile ? 14 : 22,
      }}>
        {/* Bloc titre+subtitle pose sur un voile noir doux pour assurer le contraste
            par-dessus le fond cabaret rouge (les ampoules dorees creaient des zones
            claires qui faisaient blanchir le titre gradient gold + le subtitle). */}
        <div style={{
          textAlign: 'center',
          padding: '14px 22px 16px',
          borderRadius: 16,
          background: 'radial-gradient(ellipse at center, rgba(0,0,0,0.55) 0%, rgba(0,0,0,0.35) 65%, rgba(0,0,0,0) 100%)',
          maxWidth: 360,
        }}>
          <h2 className="fds-cabaret-text" style={{
            fontSize: mobile ? 34 : 42,
            margin: 0, lineHeight: 1.1,
            filter: 'drop-shadow(0 2px 4px rgba(0,0,0,0.8)) drop-shadow(0 0 12px rgba(0,0,0,0.45))',
          }}>À vous de jouer !</h2>
          <div style={{ marginTop: 10, minHeight: 22 }}>{subtitle}</div>
        </div>

        <div style={{ position: 'relative', width: wheelMax, height: wheelMax }}>
          {/* pointer */}
          <div style={{
            position: 'absolute',
            top: -8, left: '50%', transform: 'translateX(-50%)',
            width: 0, height: 0,
            borderLeft: '14px solid transparent',
            borderRight: '14px solid transparent',
            borderTop: `22px solid ${COLORS.goldDark}`,
            zIndex: 4,
            filter: 'drop-shadow(0 2px 4px rgba(45,53,64,0.15))',
          }} />
          <WheelSVG size={wheelMax} rotation={spinState.rotation} spinning={spinState.phase === 'spinning'} />
          {/* Animated centerpiece — replaces the old "GO !" button */}
          {spinState.phase !== 'spinning' && (
            <WheelCenterpiece
              onClick={onSpin}
              mobile={mobile}
              disabled={spinState.phase === 'done'}
            />
          )}
        </div>

        <div style={{
          fontSize: 11, color: 'rgba(255,255,255,0.95)', textAlign: 'center',
          padding: '6px 14px', borderRadius: 999,
          background: 'rgba(0,0,0,0.45)',
          border: '1px solid rgba(255,255,255,0.12)',
          backdropFilter: 'blur(6px)',
          WebkitBackdropFilter: 'blur(6px)',
          letterSpacing: '0.02em',
          fontWeight: 500,
        }}>
          8 secteurs · 4 lots possibles · 4 cases perdantes
        </div>
      </div>
    </ScreenShell>
  );
}

// ─────────────── 4) WIN ───────────────
const PRIZE_COPY = {
  cafe: {
    name: 'Un café offert',
    body: "Présentez cet écran à votre serveur pour profiter de votre café offert. Et bonne fin de repas !",
  },
  digestif: {
    name: 'Un digestif offert',
    body: "Présentez cet écran à votre serveur pour profiter de votre digestif. Le moment idéal pour prolonger un peu le plaisir.",
  },
  entree: {
    name: 'Une entrée offerte la prochaine fois',
    body: "Demandez votre bon au serveur, conservez-le précieusement. Il vous attendra à votre prochaine visite — au plaisir de vous revoir !",
  },
};

function WinScreen({ width, height, mobile, prize = 'cafe', onClose, onNavigate, prizes, onBack }) {
  const copy = PRIZE_COPY[prize];
  const p = prizes || (window.FDSBackend ? window.FDSBackend.getPrizes() : null);
  const dynamicName = p?.[prize]?.label || copy.name;
  // Horodatage + n° de participation captures une fois au mount (anti-screenshot recycle + tracabilite serveur).
  const [playedAt] = React.useState(() => Date.now());
  const [partNo] = React.useState(() => getParticipationNo());
  return (
    <ScreenShell width={width} height={height} mobile={mobile} onNavigate={onNavigate} onBack={onBack}>
      <Confetti />
      <div style={{
        flex: 1, display: 'flex', flexDirection: 'column',
        alignItems: 'center', justifyContent: 'center',
        padding: mobile ? '32px 20px' : '48px 32px',
        textAlign: 'center', position: 'relative', zIndex: 1,
      }}>
        <div style={{ maxWidth: 540, width: '100%', display: 'flex', flexDirection: 'column', alignItems: 'center', gap: mobile ? 22 : 28 }}>
          <h1 style={{
            fontFamily: '"Lobster", cursive',
            fontSize: mobile ? 42 : 64, lineHeight: 1, margin: 0,
            color: COLORS.ink,
            animation: 'fdsScaleBounce 600ms cubic-bezier(0.34, 1.56, 0.64, 1) 300ms both',
          }}>
            Félicitations !
          </h1>

          <div style={{
            background: COLORS.surface,
            border: `1px solid ${COLORS.gold}`,
            borderRadius: 12,
            padding: mobile ? '20px 24px' : '24px 32px',
            width: '100%',
            boxSizing: 'border-box',
            animation: 'fdsFadeUp 500ms ease-out 800ms both',
            boxShadow: '0 4px 12px rgba(45,53,64,0.06)',
          }}>
            <div style={{ fontSize: 13, color: COLORS.ink2, letterSpacing: '0.04em', textTransform: 'uppercase' }}>Vous remportez</div>
            <div style={{ fontFamily: 'Inter, sans-serif', fontWeight: 500, fontSize: mobile ? 22 : 28, color: COLORS.ink, marginTop: 8, lineHeight: 1.25 }}>
              {dynamicName}
            </div>
          </div>

          <p style={{
            fontSize: mobile ? 14 : 16, lineHeight: 1.7, color: COLORS.ink, margin: 0, maxWidth: 460,
            animation: 'fdsFadeUp 500ms ease-out 950ms both',
          }}>
            {copy.body}
          </p>

          {/* Lolo video — réaction du chef */}
          <div style={{
            width: '100%', maxWidth: 320,
            display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 10,
            animation: 'fdsFadeUp 600ms ease-out 1200ms both',
          }}>
            <div style={{
              width: '100%',
              borderRadius: 14, overflow: 'hidden',
              border: `1px solid ${COLORS.border}`,
              background: '#1a1a1a',
              boxShadow: '0 6px 18px rgba(45,53,64,0.10)',
              position: 'relative',
              display: 'flex', alignItems: 'center', justifyContent: 'center',
            }}>
              <video
                src="assets/lolo_light.mp4"
                autoPlay
                muted
                loop
                playsInline
                style={{ width: '100%', height: 'auto', display: 'block' }}
              />
              <div style={{
                position: 'absolute', top: 10, left: 10,
                background: 'rgba(45,53,64,0.78)', color: COLORS.bg,
                fontSize: 10, fontWeight: 600, letterSpacing: '0.08em',
                textTransform: 'uppercase',
                padding: '4px 8px', borderRadius: 4,
                backdropFilter: 'blur(4px)',
              }}>En direct du chef</div>
            </div>
            <p style={{
              fontFamily: '"Lobster", cursive',
              fontSize: 20, color: COLORS.goldDark,
              margin: 0, lineHeight: 1.2, textAlign: 'center',
            }}>
              Lolo est tellement content que vous ayez gagné !
            </p>
          </div>

          <div style={{ animation: 'fdsFadeUp 500ms ease-out 1400ms both' }}>
            <GoldButton size="md" onClick={onClose}>Merci, à très vite !</GoldButton>
          </div>

          {/* SECTION AVIS GOOGLE -- totalement separee, optionnelle, sans contrepartie.
              Conformite : "Riwil rewards spinning the wheel - not the review itself."
              Le lot a deja ete attribue. L'avis est une demarche volontaire. */}
          <div style={{
            width: '100%',
            marginTop: mobile ? 8 : 12,
            padding: mobile ? '16px 18px' : '20px 24px',
            background: COLORS.cream,
            border: `1px solid ${COLORS.border}`,
            borderRadius: 14,
            boxSizing: 'border-box',
            display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 10,
            animation: 'fdsFadeUp 500ms ease-out 1600ms both',
            textAlign: 'center',
          }}>
            <div style={{
              fontSize: 11, letterSpacing: '0.12em', textTransform: 'uppercase',
              color: COLORS.goldDark, fontWeight: 600,
            }}>
              ⭐ Pour aller plus loin
            </div>
            <div style={{
              fontFamily: 'Inter, sans-serif', fontWeight: 600,
              fontSize: 16, color: COLORS.ink, lineHeight: 1.35,
            }}>
              Vous avez aimé votre expérience ?
            </div>
            <div style={{
              fontSize: 13, color: COLORS.ink2, lineHeight: 1.55, maxWidth: 320,
            }}>
              Un avis Google nous fait toujours énormément plaisir et nous aide à rester ouverts. C'est totalement facultatif — votre lot vous est attribué quoi qu'il arrive.
            </div>
            <a
              href={GOOGLE_REVIEW_URL}
              target="_blank"
              rel="noopener noreferrer"
              onClick={() => window.dispatchEvent(new CustomEvent('fds:review-clicked'))}
              style={{
                display: 'inline-flex', alignItems: 'center', justifyContent: 'center', gap: 8,
                marginTop: 4,
                padding: '12px 22px',
                borderRadius: 10,
                background: '#FFFFFF',
                color: COLORS.ink,
                border: `1.5px solid ${COLORS.gold}`,
                fontFamily: 'Inter, sans-serif',
                fontSize: 14, fontWeight: 600,
                textDecoration: 'none',
                cursor: 'pointer',
                boxShadow: '0 2px 8px rgba(45,53,64,0.05)',
                transition: 'transform 160ms ease, box-shadow 160ms ease',
              }}
              onMouseEnter={(e) => { e.currentTarget.style.transform = 'translateY(-1px)'; e.currentTarget.style.boxShadow = '0 4px 14px rgba(45,53,64,0.10)'; }}
              onMouseLeave={(e) => { e.currentTarget.style.transform = 'translateY(0)'; e.currentTarget.style.boxShadow = '0 2px 8px rgba(45,53,64,0.05)'; }}
            >
              <svg width="18" height="18" viewBox="0 0 24 24"><path fill="#4285F4" d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z"/><path fill="#34A853" d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z"/><path fill="#FBBC05" d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z"/><path fill="#EA4335" d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z"/></svg>
              Laisser un avis Google
            </a>
          </div>

          <div style={{ fontSize: 12, color: COLORS.ink2, marginTop: 8, animation: 'fdsFadeIn 500ms ease-out 1750ms both', fontWeight: 500 }}>
            {formatPlayedAt(playedAt)} · Participation n° {partNo}
          </div>

          <div style={{ fontSize: 11, color: COLORS.ink2, marginTop: 0, opacity: 0.85, animation: 'fdsFadeIn 500ms ease-out 1800ms both', maxWidth: 320, lineHeight: 1.5 }}>
            Jeu sans obligation d'achat. Le lot attribué est indépendant et inconditionnel : il vous est offert que vous laissiez un avis ou non, et quelle que soit la note de cet avis.
          </div>
        </div>
      </div>
    </ScreenShell>
  );
}

// ─────────────── 5) LOSE ───────────────
function LoseScreen({ width, height, mobile, onClose, onNavigate, onBack }) {
  // Capture l'horodatage et le n° une seule fois au mount du screen pour qu'ils restent
  // stables meme si le user laisse l'ecran ouvert plusieurs minutes.
  const [playedAt] = React.useState(() => Date.now());
  const [partNo] = React.useState(() => getParticipationNo());
  return (
    <ScreenShell width={width} height={height} mobile={mobile} onNavigate={onNavigate} onBack={onBack}>
      <div style={{
        flex: 1, display: 'flex', flexDirection: 'column',
        alignItems: 'center', justifyContent: 'center',
        padding: mobile ? '28px 20px' : '40px 32px',
        textAlign: 'center',
      }}>
        <div style={{ maxWidth: 540, display: 'flex', flexDirection: 'column', alignItems: 'center', gap: mobile ? 18 : 22 }}>
          {/* Désolé GIF */}
          <div style={{
            width: mobile ? 220 : 280, height: mobile ? 220 : 280,
            borderRadius: 12, overflow: 'hidden',
            background: COLORS.surface,
            border: `1px solid ${COLORS.border}`,
            animation: 'fdsFadeUp 500ms ease-out 100ms both',
          }}>
            <img
              src="https://media1.giphy.com/media/8dV1zQbek0JJC/giphy.gif"
              alt="Désolé"
              style={{ width: '100%', height: '100%', objectFit: 'cover', display: 'block' }}
            />
          </div>

          <h1 style={{
            fontFamily: '"Lobster", cursive',
            fontSize: mobile ? 36 : 52, lineHeight: 1, margin: 0,
            color: COLORS.ink,
            animation: 'fdsFadeUp 500ms ease-out 250ms both',
          }}>Désolé… perdu !</h1>

          <p style={{
            fontSize: mobile ? 16 : 18, fontStyle: 'italic',
            color: COLORS.ink, lineHeight: 1.6, margin: 0, maxWidth: 460,
            animation: 'fdsFadeUp 500ms ease-out 400ms both',
          }}>
            Mais ne regardez pas le serveur ou la serveuse de travers — il (ou elle) n'y est vraiment pour rien.
          </p>

          <p style={{
            fontSize: 15, lineHeight: 1.7, color: COLORS.ink2, margin: 0, maxWidth: 460,
            animation: 'fdsFadeUp 500ms ease-out 550ms both',
          }}>
            La fortune tourne, comme dit l'autre. À votre prochaine visite, vous aurez à nouveau votre chance.
          </p>

          <div style={{ animation: 'fdsFadeUp 500ms ease-out 700ms both' }}>
            <GoldButton size="md" onClick={onClose}>À la prochaine !</GoldButton>
          </div>

          <div style={{ fontSize: 12, color: COLORS.ink2, animation: 'fdsFadeIn 500ms ease-out 850ms both' }}>
            {formatPlayedAt(playedAt)} · Participation n° {partNo}
          </div>
        </div>
      </div>
    </ScreenShell>
  );
}

// ─────────────── ERROR Screens ───────────────
function ErrorOrnament({ kind }) {
  // tiny geometric ornament — never an SVG illustration
  return (
    <div style={{
      width: 56, height: 56, borderRadius: '50%',
      border: `1px solid ${COLORS.border}`,
      background: COLORS.surface,
      display: 'flex', alignItems: 'center', justifyContent: 'center',
    }}>
      {kind === 'A' && (
        <svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke={COLORS.greyBlue} strokeWidth="1.6"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2" strokeLinecap="round"/></svg>
      )}
      {kind === 'B' && (
        <svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke={COLORS.greyBlue} strokeWidth="1.6"><rect x="4" y="6" width="16" height="14" rx="2"/><line x1="4" y1="10" x2="20" y2="10"/><line x1="9" y1="3" x2="9" y2="7"/><line x1="15" y1="3" x2="15" y2="7"/></svg>
      )}
      {kind === 'C' && (
        <svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke={COLORS.greyBlue} strokeWidth="1.6" strokeLinecap="round"><path d="M12 4l9 16H3z"/><line x1="12" y1="11" x2="12" y2="14"/><circle cx="12" cy="17" r="0.8" fill={COLORS.greyBlue}/></svg>
      )}
    </div>
  );
}

// ─────────────── 4 BIS) SECOND CHANCE QUIZ ───────────────
// Shown after a lose so the player has a chance to re-spin if they answer right.
const SECOND_CHANCE_QUIZ = [
  {
    image: 'assets/lolo_ntm.png',
    question: 'De quel film est tirée cette image ?',
    options: [
      { label: "L'Amour",  correct: false },
      { label: 'La Haine', correct: true  },
    ],
  },
  {
    image: 'assets/manu_banane.png',
    question: 'Notre chef a pris la place de qui ?',
    options: [
      { label: 'Johnny Hallyday', correct: false },
      { label: 'Eddie Mitchell',  correct: true  },
    ],
  },
  {
    image: 'assets/loloBond.png',
    question: 'De quel film est tirée cette affiche ?',
    options: [
      { label: 'LoloBond',   correct: true  },
      { label: 'JohnnyBond', correct: false },
    ],
  },
];

function SecondChanceScreen({ width, height, mobile, quizIdx = 0, onCorrect, onWrong, onNavigate, onBack }) {
  const q = SECOND_CHANCE_QUIZ[quizIdx] || SECOND_CHANCE_QUIZ[0];
  const [picked, setPicked] = React.useState(null);

  const choose = (idx) => {
    if (picked !== null) return;
    setPicked(idx);
    const isCorrect = q.options[idx].correct;
    setTimeout(() => {
      if (isCorrect) onCorrect && onCorrect();
      else onWrong && onWrong();
    }, 1100);
  };

  return (
    <ScreenShell width={width} height={height} mobile={mobile} onBack={onBack} onNavigate={onNavigate}>
      <div style={{
        flex: 1, display: 'flex', flexDirection: 'column',
        alignItems: 'center', justifyContent: 'center',
        padding: '48px 22px 28px',
        textAlign: 'center', gap: 14,
      }}>
        <div style={{
          fontSize: 11, letterSpacing: '0.16em', textTransform: 'uppercase',
          color: COLORS.goldDark, fontWeight: 700,
        }}>
          Seconde chance
        </div>
        <h2 style={{
          fontFamily: '"Lobster", cursive',
          fontSize: 26, lineHeight: 1.1, margin: 0, color: COLORS.ink,
        }}>
          Réponds bien et la roue<br />repart pour un tour
        </h2>

        <div style={{
          width: '100%', maxWidth: 280, marginTop: 4,
          borderRadius: 12, overflow: 'hidden',
          background: COLORS.surface,
          border: `1px solid ${COLORS.border}`,
          boxShadow: '0 4px 14px rgba(45,53,64,0.10)',
        }}>
          <img
            src={q.image} alt=""
            style={{ width: '100%', height: 370, objectFit: 'cover', display: 'block' }}
          />
        </div>

        <p style={{
          margin: 0, fontSize: 15, lineHeight: 1.4, color: COLORS.ink,
          fontWeight: 500, maxWidth: 320,
        }}>{q.question}</p>

        <div style={{ display: 'flex', flexDirection: 'column', gap: 10, width: '100%', maxWidth: 280 }}>
          {q.options.map((opt, i) => {
            const isPicked = picked === i;
            const showResult = picked !== null;
            const isCorrect = opt.correct;
            let bg = COLORS.surface, fg = COLORS.ink, border = `1.5px solid ${COLORS.goldDark}`;
            if (showResult) {
              if (isCorrect) { bg = '#2a8a4a'; fg = '#fff'; border = '1.5px solid #2a8a4a'; }
              else if (isPicked) { bg = '#C04848'; fg = '#fff'; border = '1.5px solid #C04848'; }
              else { bg = '#F1ECE0'; fg = COLORS.ink2; border = `1.5px solid ${COLORS.border}`; }
            }
            return (
              <button
                key={i}
                onClick={() => choose(i)}
                disabled={picked !== null}
                style={{
                  padding: '14px 18px', borderRadius: 10,
                  border, background: bg, color: fg,
                  fontFamily: '"Lobster", cursive', fontSize: 18,
                  cursor: picked === null ? 'pointer' : 'default',
                  transition: 'background 200ms ease, color 200ms ease',
                  width: '100%',
                }}
              >{opt.label}</button>
            );
          })}
        </div>
      </div>
    </ScreenShell>
  );
}

function ErrorScreen({ width, height, mobile, kind = 'A', onAction, cooldownMs = 0, onNavigate, onBack }) {
  const [remaining, setRemaining] = React.useState(cooldownMs);
  React.useEffect(() => {
    if (kind !== 'A' || cooldownMs <= 0) return;
    setRemaining(cooldownMs);
    const start = Date.now();
    const id = setInterval(() => {
      const r = Math.max(0, cooldownMs - (Date.now() - start));
      setRemaining(r);
      if (r <= 0) clearInterval(id);
    }, 250);
    return () => clearInterval(id);
  }, [kind, cooldownMs]);

  const fmt = (ms) => {
    const s = Math.ceil(ms / 1000);
    if (s < 60) return `${s}s`;
    const m = Math.floor(s / 60), ss = s % 60;
    return `${m}m ${ss.toString().padStart(2, '0')}s`;
  };

  const data = {
    A: {
      title: 'Du calme, du calme…',
      body: "Vous avez déjà tenté votre chance. Repassez-nous voir demain — on garde un secteur de la roue rien que pour vous.",
      cta: 'À tout à l\'heure !',
      micro: cooldownMs > 0
        ? (remaining > 0 ? `Prochaine tentative dans ${fmt(remaining)}` : 'Vous pouvez rejouer maintenant')
        : 'Votre prochaine tentative possible : demain à partir de midi',
      titleSize: 40,
    },
    B: {
      title: 'Vous arrivez juste après la dernière danse…',
      body: "Tous les lots du mois ont trouvé preneur — un grand merci à vous tous qui jouez ! La roue se remettra à tourner dès le 1er du mois prochain.",
      cta: 'Je reviendrai !',
      micro: 'Prochaine remise en jeu : 1er mai 2026',
      titleSize: 40,
    },
    C: {
      title: 'Aïe, un grain de sel dans l\'engrenage…',
      body: "Quelque chose s'est cassé de notre côté. Réessayez dans un instant, ou prévenez votre serveur.",
      cta: 'Réessayer',
      micro: '',
      titleSize: 36,
    },
  }[kind];

  return (
    <ScreenShell width={width} height={height} mobile={mobile} onNavigate={onNavigate} onBack={onBack}>
      <TopBar mobile={mobile} />
      <div style={{
        flex: 1, display: 'flex', flexDirection: 'column',
        alignItems: 'center', justifyContent: 'center',
        padding: mobile ? '28px 20px' : '48px 32px',
        textAlign: 'center',
      }}>
        <div style={{ maxWidth: 520, display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 22 }}>
          <ErrorOrnament kind={kind} />
          <h1 style={{
            fontFamily: '"Lobster", cursive',
            fontSize: mobile ? Math.round(data.titleSize * 0.75) : data.titleSize,
            lineHeight: 1.1, margin: 0, color: COLORS.ink,
          }}>{data.title}</h1>
          <p style={{
            fontSize: mobile ? 15 : (kind === 'C' ? 14 : 16),
            lineHeight: 1.7, color: COLORS.ink, margin: 0,
          }}>{data.body}</p>
          <GoldButton size="sm" onClick={onAction}>{data.cta}</GoldButton>
          {data.micro && <div style={{ fontSize: 12, color: COLORS.ink2 }}>{data.micro}</div>}
        </div>
      </div>
    </ScreenShell>
  );
}

// ─────────────── 6) RÈGLEMENT ───────────────
function ReglementScreen({ width, height, mobile, onBack, onNavigate, prizes }) {
  const p = prizes || (window.FDSBackend ? window.FDSBackend.getPrizes() : null);
  const lots = p ? [
    { key: 'cafe',     ...p.cafe     },
    { key: 'digestif', ...p.digestif },
    { key: 'entree',   ...p.entree   },
  ] : [];

  return (
    <ScreenShell width={width} height={height} mobile={mobile} onNavigate={onNavigate} onBack={onBack}>
      <TopBar mobile={mobile} />
      <div style={{
        flex: 1, overflow: 'auto',
        padding: mobile ? '20px 18px 28px' : '32px 48px 40px',
      }}>
        <button onClick={onBack} style={{
          background: 'none', border: 'none', padding: 0, cursor: 'pointer',
          color: COLORS.ink2, fontSize: 12, marginBottom: 14,
          textDecoration: 'underline', textUnderlineOffset: 2,
          fontFamily: 'inherit',
        }}>← Retour</button>
        <h1 style={{
          fontFamily: '"Lobster", cursive', fontSize: mobile ? 32 : 42,
          margin: 0, color: COLORS.ink, lineHeight: 1.1,
        }}>Règlement du jeu</h1>
        <div style={{ fontSize: 11, letterSpacing: '0.14em', textTransform: 'uppercase', color: COLORS.ink2, marginTop: 8 }}>
          La Roue Fleur de Sel
        </div>

        <Section title="Article 1 — Organisateur">
          <p>Le présent jeu est organisé par le restaurant <strong>Fleur de Sel</strong>, La Garenne-Colombes, sans obligation d'achat.</p>
        </Section>

        <Section title="Article 2 — Participation">
          <p>Une participation par personne et par jour. Chaque appareil ne peut tenter sa chance qu'une fois toutes les 24 heures.</p>
        </Section>

        <Section title="Article 3 — Lots à gagner">
          <p>Les lots mis en jeu pour la période en cours sont les suivants&nbsp;:</p>
          <ul style={{ paddingLeft: 18, marginTop: 8, marginBottom: 0 }}>
            {lots.map(l => (
              <li key={l.key} style={{ marginBottom: 6 }}>
                <strong>{l.label}</strong> — {l.stock} lot{l.stock > 1 ? 's' : ''} disponible{l.stock > 1 ? 's' : ''}.
              </li>
            ))}
          </ul>
          <p style={{ marginTop: 12 }}>Les lots sont attribués dans la limite des stocks disponibles, par tirage aléatoire à chaque tour de roue.</p>
        </Section>

        <Section title="Article 4 — Tirage et désignation des gagnants">
          <p>Le résultat de chaque tour est déterminé par un algorithme aléatoire pondéré selon le stock restant. La répartition des lots sur les secteurs de la roue est elle-même tirée au sort en début de période et à chaque réinitialisation.</p>
        </Section>

        <Section title="Article 5 — Remise des lots">
          <p>Les lots sont à retirer sur place auprès du personnel du restaurant, sur présentation de l'écran de gain.</p>
        </Section>

        <Section title="Article 6 — Indépendance du jeu et des avis Google">
          <p><strong>Le tirage de la roue est totalement indépendant et inconditionnel.</strong> Le lot gagné est attribué au participant <strong>quelle que soit la note ou le contenu de l'avis Google laissé</strong>, et même si aucun avis n'est laissé.</p>
          <p>La possibilité de déposer un avis sur Google, proposée à l'issue du jeu, constitue une <strong>démarche volontaire et facultative</strong> du participant. Aucune contrepartie n'est attachée au dépôt d'un avis, ni à la note attribuée à celui-ci.</p>
          <p>Cette mécanique respecte les Conditions d'utilisation de Google relatives aux avis (interdiction d'inciter à laisser des avis positifs en échange d'une contrepartie) ainsi que la position de la CNIL et de la DGCCRF sur les loteries promotionnelles sans obligation d'achat.</p>
        </Section>

        <Section title="Article 7 — Données personnelles">
          <p>Aucune donnée personnelle n'est collectée à des fins commerciales. L'identifiant d'appareil (empreinte locale du navigateur) est conservé en <code>localStorage</code> uniquement pour limiter une participation par appareil et par jour. Aucune donnée n'est transmise à un tiers.</p>
        </Section>
      </div>
    </ScreenShell>
  );
}

function Section({ title, children }) {
  return (
    <div style={{ marginTop: 22 }}>
      <h2 style={{
        fontFamily: 'Inter, sans-serif', fontWeight: 600,
        fontSize: 14, color: COLORS.ink,
        margin: 0, marginBottom: 6,
      }}>{title}</h2>
      <div style={{ fontSize: 13, lineHeight: 1.65, color: COLORS.ink }}>{children}</div>
    </div>
  );
}

Object.assign(window, {
  COLORS,
  LandingScreen,
  FormScreen,
  WheelScreen,
  WinScreen,
  LoseScreen,
  ErrorScreen,
  ReglementScreen,
  SecondChanceScreen,
  SECOND_CHANCE_QUIZ,
  WHEEL_SECTORS,
  buildWheelSectors,
});
