/* global React */
const { useState, useEffect, useRef, useCallback } = React;

// =====================================================================
// CAN PETITA — Gamification & interactive components
// All registered on window.CP_GAME so components.jsx can import them.
// =====================================================================

// -------------- shared helpers --------------
const _safe = (obj, path, fallback) => {
  try {
    return path.split('.').reduce((a, k) => (a == null ? a : a[k]), obj) ?? fallback;
  } catch (_) { return fallback; }
};

const _todayKey = () => {
  const d = new Date();
  return `${d.getFullYear()}-${String(d.getMonth()+1).padStart(2,'0')}-${String(d.getDate()).padStart(2,'0')}`;
};

// Tiny string hash → 6-char base36 code (deterministic, no library)
const _hashCode = (str) => {
  let h = 5381;
  for (let i = 0; i < str.length; i++) h = ((h << 5) + h) + str.charCodeAt(i);
  return Math.abs(h).toString(36).slice(0, 6).toUpperCase().padEnd(6, 'X');
};

// Smooth scroll helper, respecting browser scroll-behavior
const _scrollTo = (id) => {
  const el = document.querySelector(id);
  if (el) el.scrollIntoView({ behavior: 'smooth', block: 'start' });
};

// CSS-only confetti burst — appends N small spans with random trajectories
const _confettiBurst = (host, count = 22) => {
  if (!host) return;
  const root = document.createElement('div');
  root.className = 'cp-confetti';
  for (let i = 0; i < count; i++) {
    const p = document.createElement('span');
    const angle = (Math.PI * 2 * i) / count + (Math.random() - 0.5);
    const dist = 80 + Math.random() * 120;
    p.style.setProperty('--tx', Math.cos(angle) * dist + 'px');
    p.style.setProperty('--ty', Math.sin(angle) * dist + 'px');
    p.style.setProperty('--rot', (Math.random() * 540 - 270) + 'deg');
    p.style.setProperty('--delay', (Math.random() * 0.15) + 's');
    p.style.background = i % 3 === 0
      ? '#c9a86a'
      : i % 3 === 1 ? '#e6c98a' : '#3a8a72';
    root.appendChild(p);
  }
  host.appendChild(root);
  setTimeout(() => root.remove(), 1800);
};

// =====================================================================
// Brand quiz icons (no emojis) — 64x64 line-art on currentColor
// =====================================================================
const _svgProps = {
  viewBox: '0 0 64 64', width: 36, height: 36,
  fill: 'none', stroke: 'currentColor', strokeWidth: 1.5,
  strokeLinecap: 'round', strokeLinejoin: 'round',
  'aria-hidden': true
};
const CP_QUIZ_ICONS = {
  sunrise: () => (
    <svg {..._svgProps}>
      <circle cx="32" cy="38" r="10"/>
      <path d="M14 48h36" />
      <path d="M10 54h44" opacity="0.55"/>
      <path d="M32 18v6M18 24l4 4M46 24l-4 4M12 38h4M48 38h4" opacity="0.85"/>
      <path d="M22 38a10 10 0 0 1 20 0" opacity="0.5"/>
    </svg>
  ),
  croissant: () => (
    <svg {..._svgProps}>
      <path d="M14 38c2-12 12-22 24-22s20 10 22 22c-6 6-16 8-22 8s-16-2-24-8z"/>
      <path d="M22 36c2-7 6-12 10-12s8 5 10 12" opacity="0.75"/>
      <path d="M28 30c1-3 4-5 6-5M34 30c1-3 4-5 6-5" opacity="0.55"/>
      <path d="M14 38c4 4 10 6 18 6s14-2 18-6" opacity="0.4"/>
    </svg>
  ),
  'plate-cutlery': () => (
    <svg {..._svgProps}>
      <circle cx="32" cy="34" r="18"/>
      <circle cx="32" cy="34" r="13" opacity="0.55"/>
      <path d="M14 10v10a3 3 0 0 0 3 3v8M17 10v10M20 10v13a3 3 0 0 1-3 0" opacity="0.85"/>
      <path d="M50 10c-3 4-4 9-4 14h4z"/>
      <path d="M48 24v8" opacity="0.85"/>
    </svg>
  ),
  afternoon: () => (
    <svg {..._svgProps}>
      <path d="M10 48h44"/>
      <path d="M6 54h52" opacity="0.5"/>
      <circle cx="32" cy="40" r="9"/>
      <path d="M22 40h20" opacity="0.6"/>
      <path d="M16 30l4 4M48 30l-4 4M32 24v6" opacity="0.7"/>
      <path d="M12 44c4-2 8-2 12 0M40 44c4-2 8-2 12 0" opacity="0.4"/>
    </svg>
  ),
  feather: () => (
    <svg {..._svgProps}>
      <path d="M14 50c10-2 22-10 30-22 4-6 4-12 2-16-4-2-10-2-16 2-12 8-20 20-22 30z"/>
      <path d="M14 50l28-28" opacity="0.7"/>
      <path d="M22 36c4-1 8-1 10 1M28 30c4-1 8-1 10 1M34 24c4-1 8-1 10 1" opacity="0.5"/>
    </svg>
  ),
  'fork-knife': () => (
    <svg {..._svgProps}>
      <path d="M20 8v18a4 4 0 0 0 4 4v24"/>
      <path d="M24 8v14M28 8v18a4 4 0 0 1-4 4" opacity="0.85"/>
      <path d="M44 8c-3 4-4 10-4 16h4z"/>
      <path d="M40 24v30" opacity="0.85"/>
    </svg>
  ),
  flame: () => (
    <svg {..._svgProps}>
      <path d="M32 8c-2 8 8 12 6 22-1 6-6 10-6 14"/>
      <path d="M32 56c-10 0-16-6-16-16 0-8 6-12 8-18 1 6 4 8 6 8s4-4 4-10c6 4 14 12 14 22 0 8-6 14-16 14z"/>
      <path d="M28 50c-4-2-6-6-6-10 0-4 2-6 4-8" opacity="0.55"/>
    </svg>
  ),
  'hungry-face': () => (
    <svg {..._svgProps}>
      <circle cx="32" cy="34" r="18"/>
      <path d="M22 28l4 2M42 28l-4 2" opacity="0.85"/>
      <path d="M22 42c4 4 16 4 20 0c-2-2-6-3-10-3s-8 1-10 3z"/>
      <path d="M26 44h12" opacity="0.6"/>
      <path d="M14 12c2 2 0 4 0 6M22 8c2 2 0 4 0 6M50 12c-2 2 0 4 0 6M42 8c-2 2 0 4 0 6" opacity="0.7"/>
    </svg>
  ),
  honey: () => (
    <svg {..._svgProps}>
      <path d="M16 22h32l-2 28a4 4 0 0 1-4 4H22a4 4 0 0 1-4-4z"/>
      <path d="M14 22h36"/>
      <path d="M22 14h20l2 8H20z" opacity="0.85"/>
      <path d="M28 8c2 2 0 4 0 6M36 8c2 2 0 4 0 6" opacity="0.55"/>
      <path d="M26 36c2-2 4-2 6 0s4 2 6 0" opacity="0.6"/>
      <path d="M30 44c1-1 3-1 4 0" opacity="0.5"/>
    </svg>
  ),
  pancakes: () => (
    <svg {..._svgProps}>
      <ellipse cx="32" cy="42" rx="20" ry="5"/>
      <path d="M12 42v4c0 3 9 5 20 5s20-2 20-5v-4"/>
      <ellipse cx="32" cy="36" rx="18" ry="4" opacity="0.75"/>
      <ellipse cx="32" cy="30" rx="16" ry="4" opacity="0.55"/>
      <path d="M22 22c2-3 8-4 10-2c1-1 4-2 6 0c2 2 0 4-2 4s-4-2-2-4" opacity="0.7"/>
      <path d="M28 30c2-1 6-1 8 0" opacity="0.4"/>
    </svg>
  ),
  cheese: () => (
    <svg {..._svgProps}>
      <path d="M10 42l36-22 8 8v18a4 4 0 0 1-4 4H14a4 4 0 0 1-4-4z"/>
      <path d="M10 42h44"/>
      <path d="M46 20l8 8h-8z" opacity="0.55"/>
      <circle cx="22" cy="44" r="2" opacity="0.7"/>
      <circle cx="34" cy="40" r="2.5" opacity="0.7"/>
      <circle cx="44" cy="46" r="1.8" opacity="0.7"/>
      <circle cx="28" cy="50" r="1.4" opacity="0.55"/>
    </svg>
  ),
  chili: () => (
    <svg {..._svgProps}>
      <path d="M22 12c4 0 6 2 8 4s4 4 8 4c-2 14-12 30-22 34-6-2-10-6-10-12 0-12 8-30 16-30z"/>
      <path d="M30 16c2-2 6-4 8-2c-2 4-4 6-8 6" opacity="0.85"/>
      <path d="M14 50c2-12 8-22 14-28" opacity="0.5"/>
      <path d="M44 14c2 0 4 2 4 4M50 18c2 0 4 2 4 4" opacity="0.6"/>
    </svg>
  ),
  shield: () => (
    <svg {..._svgProps}>
      <path d="M32 8c-6 4-12 6-18 6 0 18 4 30 18 42 14-12 18-24 18-42-6 0-12-2-18-6z"/>
      <path d="M32 18v28" opacity="0.55"/>
      <path d="M22 26h20" opacity="0.55"/>
      <path d="M32 14c-4 3-9 4-14 4 0 14 3 24 14 34" opacity="0.4"/>
    </svg>
  ),
  handshake: () => (
    <svg {..._svgProps}>
      <path d="M6 30l10-6 8 4 12-4 10 4 12-4v14l-12 6-10-4-12 4-8-4-10 6z"/>
      <path d="M24 28l8 4 8-4" opacity="0.85"/>
      <path d="M16 28v8M48 28v8" opacity="0.55"/>
      <path d="M28 36l4 2 4-2" opacity="0.6"/>
      <path d="M10 36c2 4 4 6 8 6M54 36c-2 4-4 6-8 6" opacity="0.5"/>
    </svg>
  ),
  eyes: () => (
    <svg {..._svgProps}>
      <path d="M4 32c4-8 12-12 20-12s16 4 20 12c-4 8-12 12-20 12S8 40 4 32z"/>
      <circle cx="20" cy="32" r="6"/>
      <circle cx="20" cy="32" r="2.5" fill="currentColor" stroke="none"/>
      <path d="M40 32c4-8 12-12 20-12" opacity="0.6"/>
      <path d="M44 32c4 8 12 12 20 12" opacity="0.6"/>
      <circle cx="50" cy="32" r="5" opacity="0.85"/>
      <circle cx="50" cy="32" r="2" fill="currentColor" stroke="none"/>
      <path d="M14 22l2-2M22 20l1-3M48 22l-2-2M54 22l2-3" opacity="0.55"/>
    </svg>
  ),
  rocket: () => (
    <svg {..._svgProps}>
      <path d="M32 6c8 6 14 16 14 28v12H18V34c0-12 6-22 14-28z"/>
      <circle cx="32" cy="26" r="4"/>
      <path d="M18 38l-8 6 4 4 6-4M46 38l8 6-4 4-6-4" opacity="0.85"/>
      <path d="M26 46h12l-2 8h-8z"/>
      <path d="M28 54l-2 4M36 54l2 4M32 56v4" opacity="0.7"/>
    </svg>
  ),
  meditation: () => (
    <svg {..._svgProps}>
      <circle cx="32" cy="16" r="6"/>
      <path d="M16 50c2-8 8-14 16-14s14 6 16 14"/>
      <path d="M22 44c2-2 8 0 10 2s8 0 10-2" opacity="0.7"/>
      <path d="M14 50h36"/>
      <path d="M26 30c-2 2-4 2-6 4M38 30c2 2 4 2 6 4" opacity="0.55"/>
      <path d="M26 12c-2-2 0-4 2-4M38 12c2-2 0-4-2-4" opacity="0.5"/>
    </svg>
  ),
  'two-hearts': () => (
    <svg {..._svgProps}>
      <path d="M22 42c-8-6-12-12-12-18 0-4 4-8 8-8 3 0 5 2 6 4 1-2 3-4 6-4 4 0 8 4 8 8 0 6-4 12-12 18z"/>
      <path d="M48 50c-6-5-10-10-10-15 0-3 3-7 7-7 2 0 4 2 5 3 1-1 3-3 5-3 4 0 7 4 7 7 0 5-4 10-10 15z" opacity="0.85"/>
      <path d="M16 22c0-2 2-4 4-4" opacity="0.55"/>
      <path d="M42 36c0-2 2-3 4-3" opacity="0.55"/>
    </svg>
  ),
  friends: () => (
    <svg {..._svgProps}>
      <circle cx="16" cy="20" r="5"/>
      <circle cx="32" cy="16" r="6"/>
      <circle cx="48" cy="20" r="5"/>
      <path d="M6 50c1-8 5-14 10-14s9 6 10 14"/>
      <path d="M22 52c2-10 5-16 10-16s8 6 10 16"/>
      <path d="M38 50c1-8 5-14 10-14s9 6 10 14"/>
      <path d="M22 24c0-2 0-4-2-4M42 24c0-2 0-4 2-4" opacity="0.5"/>
    </svg>
  ),
  family: () => (
    <svg {..._svgProps}>
      <circle cx="16" cy="18" r="5"/>
      <path d="M8 44c1-8 4-12 8-12s7 4 8 12"/>
      <circle cx="46" cy="18" r="5"/>
      <path d="M38 44c1-8 4-12 8-12s7 4 8 12"/>
      <circle cx="32" cy="32" r="4"/>
      <path d="M26 52c0-6 2-10 6-10s6 4 6 10"/>
      <path d="M16 23v-2M46 23v-2" opacity="0.5"/>
      <path d="M16 44h-8M46 44h8M32 52h-6M32 52h6" opacity="0.4"/>
    </svg>
  ),
  coffee: () => (
    <svg {..._svgProps}>
      <path d="M14 24h32l-2 22a6 6 0 0 1-6 6H22a6 6 0 0 1-6-6z"/>
      <path d="M44 28c5 0 8 3 8 7s-3 7-8 7"/>
      <path d="M14 24h32" opacity="0.85"/>
      <path d="M22 14c2 2 0 4 0 6M30 12c2 2 0 4 0 6M38 14c2 2 0 4 0 6" opacity="0.7"/>
      <path d="M22 38c2 1 6 1 8 0" opacity="0.55"/>
    </svg>
  ),
  'cold-drink': () => (
    <svg {..._svgProps}>
      <path d="M18 20h28l-2 32a4 4 0 0 1-4 4H24a4 4 0 0 1-4-4z"/>
      <path d="M16 20h32" opacity="0.85"/>
      <path d="M40 8v44" opacity="0.85"/>
      <path d="M40 8l4-2" opacity="0.7"/>
      <circle cx="26" cy="32" r="2" opacity="0.6"/>
      <circle cx="32" cy="40" r="1.5" opacity="0.6"/>
      <circle cx="36" cy="34" r="1.4" opacity="0.55"/>
      <path d="M22 26h12" opacity="0.4"/>
    </svg>
  ),
  'beer-wine': () => (
    <svg {..._svgProps}>
      <path d="M22 12h20l-2 18a8 8 0 0 1-16 0z"/>
      <path d="M32 38v14"/>
      <path d="M24 54h16" opacity="0.85"/>
      <path d="M22 12h20" opacity="0.85"/>
      <path d="M26 18c2 2 4 2 6 0s4 2 6 0" opacity="0.55"/>
      <path d="M26 26c2-2 4 0 6-2" opacity="0.5"/>
    </svg>
  ),
  'water-drop': () => (
    <svg {..._svgProps}>
      <path d="M32 6c-10 12-16 22-16 30a16 16 0 0 0 32 0c0-8-6-18-16-30z"/>
      <path d="M22 38c0 6 4 10 8 10" opacity="0.6"/>
      <path d="M28 22c-3 4-6 8-6 12" opacity="0.4"/>
      <circle cx="36" cy="34" r="1.4" opacity="0.55"/>
    </svg>
  ),
  meat: () => (
    <svg {..._svgProps}>
      <path d="M14 38c-4-4-4-12 0-16s12-4 16 0 6 6 12 6c4 0 8 4 8 8s-4 8-8 8c-6 0-8 2-12 6s-12 4-16 0-4-12 0-12z"/>
      <circle cx="22" cy="32" r="4"/>
      <path d="M50 26l4-4M52 32l4 0" opacity="0.7"/>
      <path d="M22 32l-2 4" opacity="0.55"/>
    </svg>
  ),
  fish: () => (
    <svg {..._svgProps}>
      <path d="M50 24c0-4-4-6-8-6s-12 2-18 8-12 6-16 6c0 4 4 6 8 6 8 0 14 6 22 6 6 0 12-4 12-10v-10z"/>
      <path d="M50 32l8-4v8z"/>
      <circle cx="44" cy="30" r="1.6" fill="currentColor" stroke="none"/>
      <path d="M30 30c4 0 6 2 6 4M22 32c2 0 4 2 4 4" opacity="0.5"/>
      <path d="M14 24c2 0 4-1 4-3" opacity="0.55"/>
    </svg>
  ),
  salad: () => (
    <svg {..._svgProps}>
      <path d="M10 32h44l-4 18a4 4 0 0 1-4 4H18a4 4 0 0 1-4-4z"/>
      <path d="M10 32h44" opacity="0.85"/>
      <path d="M18 24c0-6 6-10 12-10s10 2 12 6" opacity="0.7"/>
      <path d="M28 16c-2 0-4 2-4 6M40 18c0-3 3-5 6-3" opacity="0.55"/>
      <circle cx="22" cy="40" r="2" opacity="0.7"/>
      <circle cx="32" cy="44" r="2.5" opacity="0.7"/>
      <circle cx="42" cy="40" r="2" opacity="0.7"/>
      <path d="M16 24c2-2 6-2 8 0" opacity="0.4"/>
    </svg>
  ),
  sprout: () => (
    <svg {..._svgProps}>
      <path d="M32 56V30"/>
      <path d="M16 50h32" opacity="0.85"/>
      <path d="M32 30c-8 0-14-4-14-12 8 0 14 4 14 12z"/>
      <path d="M32 30c8 0 14-4 14-12-8 0-14 4-14 12z" opacity="0.85"/>
      <path d="M32 22c-2 0-4-2-4-4M32 22c2 0 4-2 4-4" opacity="0.55"/>
      <path d="M22 50c2-2 6-2 10 0s8 2 10 0" opacity="0.4"/>
    </svg>
  ),
  leaf: () => (
    <svg {..._svgProps}>
      <path d="M50 10c-4 0-22 2-30 14s-6 24-2 28c4 4 16 4 28-4S52 22 50 10z"/>
      <path d="M18 52L48 18" opacity="0.7"/>
      <path d="M28 36c2-2 6-2 8 0M22 42c2-2 6-2 8 0M34 30c2-2 6-2 8 0" opacity="0.5"/>
    </svg>
  ),
  bolt: () => (
    <svg {..._svgProps}>
      <path d="M34 4L14 34h12l-4 26 22-32H32z"/>
      <path d="M22 36c2-2 4-2 6 0" opacity="0.5"/>
      <path d="M34 8l-2 4M40 14l-2 4" opacity="0.6"/>
      <path d="M28 50l2-4" opacity="0.55"/>
    </svg>
  ),
  party: () => (
    <svg {..._svgProps}>
      <path d="M10 54L28 18l18 18z"/>
      <path d="M14 50l30 0" opacity="0.55"/>
      <path d="M40 8l4 2-2 4M50 16l4 0-2 4M52 28l4 2-2 4" opacity="0.85"/>
      <circle cx="48" cy="10" r="1.5" fill="currentColor" stroke="none"/>
      <circle cx="56" cy="22" r="1.5" fill="currentColor" stroke="none"/>
      <circle cx="42" cy="22" r="1.5" fill="currentColor" stroke="none"/>
      <circle cx="20" cy="38" r="1.6" fill="currentColor" stroke="none" opacity="0.7"/>
      <circle cx="30" cy="32" r="1.6" fill="currentColor" stroke="none" opacity="0.7"/>
      <circle cx="34" cy="44" r="1.6" fill="currentColor" stroke="none" opacity="0.7"/>
    </svg>
  ),
  sparkles: () => (
    <svg {..._svgProps}>
      <path d="M32 6l3 12 12 3-12 3-3 12-3-12-12-3 12-3z"/>
      <path d="M50 36l1.5 6 6 1.5-6 1.5-1.5 6-1.5-6-6-1.5 6-1.5z" opacity="0.85"/>
      <path d="M14 42l1 4 4 1-4 1-1 4-1-4-4-1 4-1z" opacity="0.7"/>
    </svg>
  ),
  sandwich: () => (
    <svg {..._svgProps}>
      <path d="M10 18h44v6c0 2-2 4-4 4H14c-2 0-4-2-4-4z"/>
      <path d="M14 28h36l-2 6H16z" opacity="0.85"/>
      <path d="M12 34h40v8c0 2-2 4-4 4H16c-2 0-4-2-4-4z"/>
      <path d="M18 28c2-2 6-2 8 0M30 28c2-2 6-2 8 0M42 28c2-2 4-2 6 0" opacity="0.5"/>
      <path d="M14 22h36" opacity="0.5"/>
    </svg>
  ),
  avocado: () => (
    <svg {..._svgProps}>
      <path d="M32 6c-10 0-18 10-18 24s8 28 18 28 18-14 18-28S42 6 32 6z"/>
      <path d="M32 14c-6 0-12 8-12 18s6 22 12 22 12-12 12-22S38 14 32 14z" opacity="0.5"/>
      <ellipse cx="32" cy="36" rx="6" ry="8"/>
      <path d="M30 32c0-2 2-4 4-3" opacity="0.55"/>
    </svg>
  ),
  'fried-egg': () => (
    <svg {..._svgProps}>
      <path d="M16 28c0-8 4-14 12-14 6 0 8 4 14 4 6 0 10 4 10 10 0 4-2 8-6 10 0 8-6 14-14 14s-14-4-16-12c-4-2-6-6-6-10 0-2 2-2 6-2z"/>
      <circle cx="32" cy="32" r="8"/>
      <circle cx="32" cy="32" r="4" fill="currentColor" stroke="none" opacity="0.7"/>
      <path d="M30 30c1-1 2-1 3 0" opacity="0.4"/>
    </svg>
  ),
  shrimp: () => (
    <svg {..._svgProps}>
      <path d="M50 18c4 0 8 4 8 10 0 12-12 24-26 24-10 0-18-6-18-14 0-2 2-4 4-4 4 0 6 4 10 4 6 0 6-6 14-12 4-3 6-8 8-8z"/>
      <path d="M50 18c-2 4-2 8-2 12" opacity="0.6"/>
      <circle cx="48" cy="22" r="1.5" fill="currentColor" stroke="none"/>
      <path d="M22 38c4 2 8 2 14 0" opacity="0.55"/>
      <path d="M28 32c2 1 6 1 8 0" opacity="0.4"/>
      <path d="M14 40l-4-2M16 44l-4 0" opacity="0.6"/>
    </svg>
  ),
  octopus: () => (
    <svg {..._svgProps}>
      <path d="M16 26c0-10 6-16 16-16s16 6 16 16v8H16z"/>
      <path d="M16 34c-2 4-4 6-6 6 0 4 4 6 6 4M22 34c-1 6-3 10-5 14M30 34c-1 8-3 14-3 18M38 34c1 6 3 10 5 14M44 34c1 4 3 6 5 4 0 4-4 4-6 2M48 34c2 4 4 6 6 6 0 4-4 6-6 4" opacity="0.85"/>
      <circle cx="26" cy="22" r="1.5" fill="currentColor" stroke="none"/>
      <circle cx="38" cy="22" r="1.5" fill="currentColor" stroke="none"/>
      <path d="M28 28c2 1 6 1 8 0" opacity="0.55"/>
    </svg>
  ),
  steak: () => (
    <svg {..._svgProps}>
      <path d="M10 32c0-12 8-22 22-22s22 10 22 22-8 20-22 20S10 44 10 32z"/>
      <path d="M16 32c0-10 6-16 16-16s16 6 16 16-6 14-16 14S16 42 16 32z" opacity="0.55"/>
      <path d="M22 22l16 16M28 18l16 16M22 30l12 12M30 18l14 14" opacity="0.7"/>
    </svg>
  ),
  'cake-slice': () => (
    <svg {..._svgProps}>
      <path d="M14 30h36v22a2 2 0 0 1-2 2H16a2 2 0 0 1-2-2z"/>
      <path d="M14 30c4-2 12-2 18-2s14 0 18 2" opacity="0.85"/>
      <path d="M14 38c4-2 12-2 18-2s14 0 18 2" opacity="0.5"/>
      <path d="M22 30v-8M32 30v-10M42 30v-8" opacity="0.7"/>
      <path d="M22 22c0-2 2-2 2 0M32 20c0-2 2-2 2 0M42 22c0-2 2-2 2 0" opacity="0.85"/>
      <circle cx="22" cy="20" r="1.5" fill="currentColor" stroke="none" opacity="0.7"/>
      <circle cx="32" cy="18" r="1.5" fill="currentColor" stroke="none" opacity="0.7"/>
      <circle cx="42" cy="20" r="1.5" fill="currentColor" stroke="none" opacity="0.7"/>
    </svg>
  )
};

// =====================================================================
// 1. <DishQuiz /> — "El Test Can Petita" (8 preguntas, perfil real)
// =====================================================================
function DishQuiz({ t, lang }) {
  // -------- Hardcoded ES fallback (i18n entries are not required) --------
  const FALLBACK = {
    eyebrow: '✦  El Test Can Petita',
    title: 'El test que te dice exactamente qué pedir',
    sub: '8 preguntas honestas. Un menú a tu medida: plato, bebida y dulce — pensado para esta hora del día y este humor.',
    start: 'Empezar el test',
    again: 'Repetir test',
    reserveCta: 'Reservar mesa con esto',
    returningPrefix: 'La última vez salisteis',
    returningSuffix: '¿Volvemos a probar?',
    progressLabel: (a, b) => `${a} de ${b}`,
    resultEyebrow: 'Vuestro perfil',
    sectionMain: 'Para comer',
    sectionDrink: 'Para beber',
    sectionSweet: 'Para terminar',
    qs: [
      {
        q: '¿A qué hora estás pensando en pasarte por Can Petita?',
        opts: [
          { icon: 'sunrise', l: 'Bien temprano', d: 'Antes de las 10h, café y algo ligero.' },
          { icon: 'croissant', l: 'A media mañana', d: 'Entre 10h y 12h, con calma.' },
          { icon: 'plate-cutlery', l: 'A mediodía', d: 'Hora punta, comida en condiciones.' },
          { icon: 'afternoon', l: 'A media tarde', d: 'Picar algo sin agobios.' }
        ]
      },
      {
        q: '¿Cómo vienes de hambre?',
        opts: [
          { icon: 'feather', l: 'Solo pica-pica', d: 'Una cosita y listo.' },
          { icon: 'fork-knife', l: 'Hambre normal', d: 'Lo que toca, sin pasarme.' },
          { icon: 'flame', l: 'Bastante hambre', d: 'Vengo con ganas.' },
          { icon: 'hungry-face', l: 'Muerto de hambre', d: 'No he comido en horas.' }
        ]
      },
      {
        q: 'Sin pensarlo: ¿dulce o salado?',
        opts: [
          { icon: 'honey', l: 'Dulce siempre', d: 'Mermelada, miel, fruta…' },
          { icon: 'pancakes', l: 'Más bien dulce', d: 'Suave, con un toque dulce.' },
          { icon: 'cheese', l: 'Más bien salado', d: 'Queso, embutido, tomate.' },
          { icon: 'chili', l: 'Salado y con chispa', d: 'Bravo, intenso, con sabor.' }
        ]
      },
      {
        q: '¿Carta clásica o algo que no hayas probado nunca?',
        opts: [
          { icon: 'shield', l: 'Lo de toda la vida', d: 'Tortilla, jamón, café con leche.' },
          { icon: 'handshake', l: 'Algo familiar', d: 'Conocido pero con un giro.' },
          { icon: 'eyes', l: 'Curioso, dame ideas', d: 'Sorpréndeme un poco.' },
          { icon: 'rocket', l: 'A por algo nuevo', d: 'Quiero probar algo distinto.' }
        ]
      },
      {
        q: '¿Vienes solo, en pareja o con cuadrilla?',
        opts: [
          { icon: 'meditation', l: 'Solo, mi rato', d: 'Mesa para uno, sin prisa.' },
          { icon: 'two-hearts', l: 'En pareja', d: 'Algo bonito para los dos.' },
          { icon: 'friends', l: 'Con amigos', d: 'Para compartir y reírnos.' },
          { icon: 'family', l: 'Con la familia', d: 'Mesa grande, niños incluidos.' }
        ]
      },
      {
        q: '¿Qué te apetece beber?',
        opts: [
          { icon: 'coffee', l: 'Algo caliente', d: 'Café, té, chocolate.' },
          { icon: 'cold-drink', l: 'Algo frío y suave', d: 'Zumo, batido, smoothie.' },
          { icon: 'beer-wine', l: 'Una cerveza o vino', d: 'Caña, copa, vermut.' },
          { icon: 'water-drop', l: 'Refresco o agua', d: 'Sin alcohol, ligerito.' }
        ]
      },
      {
        q: '¿Algo que evitar en la mesa?',
        opts: [
          { icon: 'meat', l: 'Carne o pescado, todo vale', d: 'Sin restricciones.' },
          { icon: 'fish', l: 'Mejor pescado', d: 'Más mar que carne.' },
          { icon: 'salad', l: 'Sin carne, gracias', d: 'Veggie o pescado.' },
          { icon: 'sprout', l: '100% vegetal', d: 'Vegano si puede ser.' }
        ]
      },
      {
        q: 'Y de humor… ¿cómo vienes hoy?',
        opts: [
          { icon: 'leaf', l: 'Tranquilo', d: 'Vengo a desconectar.' },
          { icon: 'bolt', l: 'Con energía', d: 'Listo para el día.' },
          { icon: 'party', l: 'Para celebrar', d: 'Hoy me lo merezco.' },
          { icon: 'sparkles', l: 'Saludable', d: 'Cuidándome un poco.' }
        ]
      }
    ],
    profiles: {
      morning_savory: {
        icon: 'sandwich',
        name: 'Esmorzar de pueblo',
        desc: 'Te encanta empezar el día como manda la tradición catalana: pan, embutido, café fuerte y conversación. Sin prisas, sin tonterías.'
      },
      morning_sweet: {
        icon: 'honey',
        name: 'Despertar dulce',
        desc: 'Eres de los que se despiertan con ganas de algo dulce y reconfortante. Tostada con miel, café con leche y el día se ve mejor.'
      },
      brunch_healthy: {
        icon: 'avocado',
        name: 'Brunch sano y luminoso',
        desc: 'A media mañana sin prisa, con cosas frescas, color en el plato y un smoothie al lado. Cuidarse también es disfrutar.'
      },
      brunch_indulgent: {
        icon: 'fried-egg',
        name: 'Brunch de capricho',
        desc: 'Si vas a desayunar tarde, que sea con todo: huevo poché, bacon, aguacate y un café decente. La vida es corta.'
      },
      tapas_classic: {
        icon: 'shrimp',
        name: 'Tapas de toda la vida',
        desc: 'Sois de mesa larga, de bravas con alioli, de croquetas calientes y de pedir “una más, va”. Compartir es vuestro idioma.'
      },
      tapas_adventurous: {
        icon: 'octopus',
        name: 'Picoteo curioso',
        desc: 'Os gusta el picoteo, sí, pero con un puntito distinto: pulpo, tequeños, mejillón tigre. La carta entera si hace falta.'
      },
      main_meat: {
        icon: 'steak',
        name: 'Plato fuerte de carnívoro',
        desc: 'Tienes hambre y lo sabes. Brasa, hierro, jugo. Un buen plato principal con su guarnición y todos contentos.'
      },
      main_fish: {
        icon: 'fish',
        name: 'Sabor de Costa Brava',
        desc: 'Pescado fresco del día, brasa suave y sabor de mar. Lo que se come en los pueblos de la costa, sin pretensiones.'
      },
      vegan_fresh: {
        icon: 'sprout',
        name: 'Verde y mediterráneo',
        desc: 'Buscas cosas frescas, vegetales, sin renunciar al sabor. Burrata, ensaladas, hamburguesa vegana, aguacate por todas partes.'
      },
      dessert_lover: {
        icon: 'cake-slice',
        name: 'Final feliz',
        desc: 'Para ti la comida empieza por el postre. Cheesecake, coulant, xuixo a la brasa. Un café y eres la persona más feliz del mundo.'
      }
    }
  };

  const G = _safe(t, 'game', {});
  // Try i18n qsV2 if present, else fallback
  const Q  = (i, key) => _safe(G, `qsV2.${i}.${key}`, FALLBACK.qs[i][key]);
  const QO = (i, j, key) => _safe(G, `qsV2.${i}.opts.${j}.${key}`, FALLBACK.qs[i].opts[j][key]);

  // -------- Menu lookup helpers (auto-localized via CP_TRANSLATIONS) --------
  const menu = (typeof window !== 'undefined' && window.CP_TRANSLATIONS && window.CP_TRANSLATIONS[lang]) || {};
  const breakfastItems = _safe(menu, 'breakfast.items', {});
  const lunchItems     = _safe(menu, 'lunch.items', {});

  // findItem(category, predicate) → first non-optional item matching name fragment
  const findIn = (cat, frag) => {
    const arr = breakfastItems[cat] || lunchItems[cat] || [];
    const f = frag.toLowerCase();
    return arr.find(it => !it.opt && (it.n || '').toLowerCase().includes(f)) || null;
  };
  const truncate = (s, n = 80) => {
    if (!s) return '';
    return s.length > n ? s.slice(0, n - 1).trimEnd() + '…' : s;
  };

  // -------- Recommendation table: profile → curated dish set --------
  // Each entry returns { mains: [{cat, frag} x3], drink: {cat,frag}, sweet: {cat,frag}|null }
  const RECIPES = {
    morning_savory: {
      mains: [
        { cat: 'Delicia entre panes', frag: 'capricho ibérico' },
        { cat: 'Delicia entre panes', frag: 'misterio catalán' },
        { cat: 'Viaje planchado', frag: 'aventura ibérica' }
      ],
      drink: { cat: 'Momentos cafeinados', frag: 'cortado' },
      sweet: null
    },
    morning_sweet: {
      mains: [
        { cat: 'Capricho matutino', frag: 'sinfonía de cacahuete' },
        { cat: 'Gloria firmada Can Petita', frag: 'caricia mañanera' },
        { cat: 'Capricho matutino', frag: 'fiesta del yogur' }
      ],
      drink: { cat: 'La hora del té', frag: 'chai latte' },
      sweet: null
    },
    brunch_healthy: {
      mains: [
        { cat: 'Capricho matutino', frag: 'esplendor mangotero' },
        { cat: 'Gloria firmada Can Petita', frag: 'aguacate vital' },
        { cat: 'Gloria firmada Can Petita', frag: 'horizonte mediterráneo' }
      ],
      drink: { cat: 'Sueños licuados', frag: 'raíz tropical' },
      sweet: { cat: 'Capricho matutino', frag: 'fiesta del yogur' }
    },
    brunch_indulgent: {
      mains: [
        { cat: 'Gloria firmada Can Petita', frag: 'aurora salmónida' },
        { cat: 'Viaje planchado', frag: 'australiano' },
        { cat: 'Gloria firmada Can Petita', frag: 'poché australiano' }
      ],
      drink: { cat: 'Momentos cafeinados', frag: 'iced latte' },
      sweet: { cat: 'Para los más golosos', frag: 'cremoso encanto' }
    },
    tapas_classic: {
      mains: [
        { cat: 'Destellos para compartir', frag: 'bravas' },
        { cat: 'Destellos para compartir', frag: 'tortilla' },
        { cat: 'Destellos para compartir', frag: 'croquetitas' }
      ],
      drink: { cat: 'Brinda con ganas', frag: 'caña' },
      sweet: { cat: 'Para los más golosos', frag: 'cheesecake' }
    },
    tapas_adventurous: {
      mains: [
        { cat: 'Destellos para compartir', frag: 'delirio de pulpo' },
        { cat: 'Destellos para compartir', frag: 'teque' },
        { cat: 'Destellos para compartir', frag: 'mejillón tigre' }
      ],
      drink: { cat: 'Brinda con ganas', frag: 'vermut' },
      sweet: { cat: 'Para los más golosos', frag: 'nutty' }
    },
    main_meat: {
      mains: [
        { cat: 'Corazones gastronómicos', frag: 'entrecot' },
        { cat: 'Corazones gastronómicos', frag: 'secreto bien guardado' },
        { cat: 'Corazones gastronómicos', frag: 'maxi burger' }
      ],
      drink: { cat: 'Brinda con ganas', frag: 'copa de vino' },
      sweet: { cat: 'Para los más golosos', frag: 'corazón fundente' }
    },
    main_fish: {
      mains: [
        { cat: 'Corazones gastronómicos', frag: 'sepia brava' },
        { cat: 'Corazones gastronómicos', frag: 'bacalao' },
        { cat: 'Destellos para compartir', frag: 'tallarinas' }
      ],
      drink: { cat: 'Brinda con ganas', frag: 'estrella' },
      sweet: { cat: 'Para los más golosos', frag: 'tarta tatín' }
    },
    vegan_fresh: {
      mains: [
        { cat: 'Corazones gastronómicos', frag: 'pura vida' },
        { cat: 'Delicias del huerto', frag: 'dulce encanto de mango' },
        { cat: 'Delicias del huerto', frag: 'burrata' }
      ],
      drink: { cat: 'Sueños licuados', frag: 'explosión' },
      sweet: { cat: 'Para los más golosos', frag: 'arcofrutal' }
    },
    dessert_lover: {
      mains: [
        { cat: 'Para los más golosos', frag: 'cheesecake' },
        { cat: 'Para los más golosos', frag: 'cremoso encanto' },
        { cat: 'Para los más golosos', frag: 'corazón fundente' }
      ],
      drink: { cat: 'La hora del té', frag: 'chocolate' },
      sweet: { cat: 'Para los más golosos', frag: 'nube de trufas' }
    }
  };

  // -------- Scoring weights: 8 questions, 4 options, each option adds 1-3 pts to 1-3 keys --------
  // q0 horario | q1 hambre | q2 dulce/salado | q3 clásico/atrevido
  // q4 solo/compartir | q5 bebida | q6 dieta | q7 humor
  const WEIGHTS = [
    // q0 — horario
    [
      { morning_savory: 3, morning_sweet: 2 },                                  // bien temprano
      { brunch_healthy: 2, brunch_indulgent: 2, morning_sweet: 1 },             // media mañana
      { tapas_classic: 2, main_meat: 2, main_fish: 2 },                         // mediodía
      { tapas_adventurous: 2, dessert_lover: 1, vegan_fresh: 1 }                // media tarde
    ],
    // q1 — hambre
    [
      { morning_sweet: 1, dessert_lover: 1, vegan_fresh: 1 },                   // pica-pica
      { brunch_healthy: 1, tapas_classic: 1, morning_savory: 1 },               // normal
      { brunch_indulgent: 2, tapas_adventurous: 1, main_fish: 1 },              // bastante
      { main_meat: 3, brunch_indulgent: 1 }                                     // muerto
    ],
    // q2 — dulce vs salado
    [
      { morning_sweet: 3, dessert_lover: 2 },                                   // dulce siempre
      { morning_sweet: 1, brunch_healthy: 1, brunch_indulgent: 1, dessert_lover: 1 }, // más bien dulce
      { morning_savory: 2, tapas_classic: 1, main_fish: 1, vegan_fresh: 1 },    // más bien salado
      { tapas_classic: 2, tapas_adventurous: 2, main_meat: 1 }                  // salado con chispa
    ],
    // q3 — clásico vs atrevido
    [
      { morning_savory: 2, tapas_classic: 2, main_meat: 1 },                    // de toda la vida
      { brunch_indulgent: 1, tapas_classic: 1, main_fish: 1, dessert_lover: 1 },// familiar
      { brunch_healthy: 1, tapas_adventurous: 2, vegan_fresh: 1 },              // curioso
      { tapas_adventurous: 2, vegan_fresh: 2, main_fish: 1 }                    // a por algo nuevo
    ],
    // q4 — solo/compartir
    [
      { morning_savory: 1, morning_sweet: 1, brunch_healthy: 1 },               // solo
      { brunch_indulgent: 2, main_fish: 1, dessert_lover: 1 },                  // pareja
      { tapas_classic: 3, tapas_adventurous: 2 },                               // amigos
      { tapas_classic: 2, main_meat: 2, dessert_lover: 1 }                      // familia
    ],
    // q5 — bebida
    [
      { morning_savory: 2, morning_sweet: 2, dessert_lover: 1 },                // caliente
      { brunch_healthy: 2, vegan_fresh: 2, brunch_indulgent: 1 },               // frío suave
      { tapas_classic: 2, tapas_adventurous: 2, main_meat: 1, main_fish: 1 },   // cerveza/vino
      { brunch_healthy: 1, vegan_fresh: 1, dessert_lover: 1 }                   // refresco/agua
    ],
    // q6 — dieta
    [
      { main_meat: 2, tapas_classic: 1, brunch_indulgent: 1 },                  // todo vale
      { main_fish: 3, brunch_healthy: 1 },                                      // mejor pescado
      { vegan_fresh: 2, brunch_healthy: 2, main_fish: 1 },                      // sin carne
      { vegan_fresh: 3 }                                                        // vegano
    ],
    // q7 — humor
    [
      { morning_savory: 1, morning_sweet: 1, brunch_healthy: 1 },               // tranquilo
      { brunch_indulgent: 1, tapas_adventurous: 1, main_meat: 1 },              // energía
      { brunch_indulgent: 2, main_meat: 1, dessert_lover: 2, tapas_classic: 1 },// celebrar
      { brunch_healthy: 2, vegan_fresh: 2, main_fish: 1 }                       // saludable
    ]
  ];

  const PROFILE_KEYS = [
    'morning_savory', 'morning_sweet',
    'brunch_healthy', 'brunch_indulgent',
    'tapas_classic', 'tapas_adventurous',
    'main_meat', 'main_fish',
    'vegan_fresh', 'dessert_lover'
  ];

  const computeScores = (ans) => {
    const score = {};
    PROFILE_KEYS.forEach(k => { score[k] = 0; });
    ans.forEach((opt, qi) => {
      const w = WEIGHTS[qi]?.[opt] || {};
      Object.keys(w).forEach(k => { if (k in score) score[k] += w[k]; });
    });
    return score;
  };

  // Pick a brand icon based on the recommendation's character.
  const inferProfileIcon = (rec) => {
    const m = rec && rec.main;
    const diet = m && m.tags && m.tags.dietary || {};
    if (diet.isVegan) return 'sprout';
    if (diet.hasFish) return 'fish';
    if (rec.sectionPick === 'breakfast') {
      const sweet = m && m.tags && (m.tags.sweet || 0) >= 3;
      return sweet ? 'honey' : (diet.hasMeat ? 'sandwich' : 'fried-egg');
    }
    if (diet.hasMeat) return 'steak';
    return 'salad';
  };

  // Map a dish entity from the engine (with .n / .desc / .price) to the legacy
  // shape the UI expects (.n / .d / .p) so the JSX stays untouched.
  const toLegacyDish = (d) => {
    if (!d) return null;
    return { n: d.n, d: d.desc, p: d.price };
  };

  // Map a profile key to a legacy fallback profile used as last resort if the
  // engine global hasn't loaded yet.
  const legacyProfileForKey = (top) => FALLBACK.profiles[top] || FALLBACK.profiles.tapas_classic;

  const buildResult = (ans) => {
    const eng = (typeof window !== 'undefined') && window.CP_QUIZ_ENGINE;

    // Engine path (new): uses tagged dish catalog + dietary filters.
    if (eng && typeof eng.recommend === 'function') {
      const r = eng.recommend(ans);
      const mainsRaw = [r.main, ...((r.alternativeMains) || [])].filter(Boolean);
      const mains = mainsRaw.map(toLegacyDish).filter(Boolean);
      const icon = inferProfileIcon(r);
      return {
        key: r.sectionPick + '_' + (r.filterApplied || 'open'),
        secondKey: null,
        profile: {
          icon,
          name: r.profileLabel || 'Tu plato',
          desc: r.profileSub || ''
        },
        secondProfile: null,
        mains,
        drink: toLegacyDish(r.drink),
        sweet: toLegacyDish(r.dessert),
        reasonLines: r.reasonLines || [],
        filterApplied: r.filterApplied || null,
        sectionPick: r.sectionPick
      };
    }

    // Legacy path: hardcoded WEIGHTS + RECIPES (used only if engine missing).
    const score = computeScores(ans);
    const sorted = PROFILE_KEYS.slice().sort((a, b) => score[b] - score[a]);
    const top = sorted[0];
    const second = sorted[1];
    const closeSecond = (score[top] - score[second]) <= 1 ? second : null;
    const recipe = RECIPES[top] || RECIPES.tapas_classic;
    const profile = legacyProfileForKey(top);
    const mains = recipe.mains.map(r => findIn(r.cat, r.frag)).filter(Boolean);
    const drink = recipe.drink ? findIn(recipe.drink.cat, recipe.drink.frag) : null;
    const sweet = recipe.sweet ? findIn(recipe.sweet.cat, recipe.sweet.frag) : null;
    return {
      key: top,
      secondKey: closeSecond,
      profile,
      secondProfile: closeSecond ? legacyProfileForKey(closeSecond) : null,
      mains, drink, sweet,
      reasonLines: [],
      filterApplied: null,
      sectionPick: null,
      score
    };
  };

  // -------- React state --------
  const TOTAL_Q = 8;
  const [step, setStep] = useState(-1); // -1 intro · 0..7 questions · 8 result
  const [answers, setAnswers] = useState([]);
  const [result, setResult] = useState(null);
  const [previous, setPrevious] = useState(null);
  const cardRef = useRef(null);

  useEffect(() => {
    try {
      const stored = JSON.parse(localStorage.getItem('cp_quiz_result_v2') || 'null');
      if (stored && stored.key && FALLBACK.profiles[stored.key]) {
        setPrevious({ key: stored.key, profile: FALLBACK.profiles[stored.key] });
      }
    } catch (_) {}
  }, []);

  const pick = (j) => {
    const next = [...answers, j];
    setAnswers(next);
    if (next.length === TOTAL_Q) {
      const r = buildResult(next);
      setResult(r);
      setStep(TOTAL_Q);
      try {
        localStorage.setItem('cp_quiz_result_v2', JSON.stringify({
          key: r.key, name: r.profile?.name, at: Date.now()
        }));
      } catch (_) {}
      setTimeout(() => _confettiBurst(cardRef.current), 90);
    } else {
      setStep(step + 1);
    }
  };

  const back = () => {
    if (step <= 0) return;
    setAnswers(answers.slice(0, -1));
    setStep(step - 1);
  };

  const restart = () => {
    setAnswers([]); setResult(null); setStep(-1);
  };

  const startFromPrevious = () => { restart(); setStep(0); };

  // Progress: (step+1) / (TOTAL_Q+1) — covers intro→q1…q8→result
  const denom = TOTAL_Q + 1;
  const progressNum = step < 0 ? 0 : Math.min(denom, step + 1);
  const progressPct = (progressNum / denom) * 100;

  return (
    <section className="cp-quiz-section" id="dish-quiz">
      <div className="section-inner">
        <div className="cp-quiz-card cp-quiz-card-v2" ref={cardRef}>
          <span className="eyebrow">{ _safe(G, 'eyebrowV2', FALLBACK.eyebrow) }</span>
          <h2 className="cp-quiz-title">{ _safe(G, 'titleV2', FALLBACK.title) }</h2>
          <p className="cp-quiz-sub">{ _safe(G, 'subV2', FALLBACK.sub) }</p>

          {step >= 0 && step < TOTAL_Q && (
            <div className="cp-quiz-progress">
              <div className="cp-quiz-progress-bar" style={{ width: `${progressPct}%` }}/>
              <span className="cp-quiz-progress-label">{step + 1} / {TOTAL_Q}</span>
            </div>
          )}

          {step === -1 && (
            <div className="cp-quiz-intro">
              {previous && (() => {
                const PrevIcon = CP_QUIZ_ICONS[previous.profile.icon] || (() => null);
                return (
                  <div className="cp-quiz-returning">
                    {FALLBACK.returningPrefix}{' '}
                    <b className="gold cp-quiz-inline-icon"><PrevIcon/> {previous.profile.name}</b>.{' '}
                    {FALLBACK.returningSuffix}
                  </div>
                );
              })()}
              <button className="cp-btn-gold" onClick={() => setStep(0)}>
                { previous ? FALLBACK.again : FALLBACK.start } →
              </button>
              <p className="cp-quiz-meta">8 preguntas · 1 minuto · te recomendamos plato + bebida + postre.</p>
            </div>
          )}

          {step >= 0 && step < TOTAL_Q && (
            <div className="cp-quiz-q cp-quiz-q-v2" key={step}>
              <h3>{ Q(step, 'q') }</h3>
              <div className="cp-quiz-opts cp-quiz-opts-v2">
                {[0,1,2,3].map(j => {
                  const Icon = CP_QUIZ_ICONS[QO(step, j, 'icon')] || (() => null);
                  return (
                    <button key={j} className="cp-quiz-opt cp-quiz-opt-v2" onClick={() => pick(j)}>
                      <span className="cp-quiz-opt-emoji"><Icon/></span>
                      <span className="cp-quiz-opt-text">
                        <b>{ QO(step, j, 'l') }</b>
                        <span className="cp-quiz-opt-desc">{ QO(step, j, 'd') }</span>
                      </span>
                    </button>
                  );
                })}
              </div>
              {step > 0 && (
                <button className="cp-quiz-back" onClick={back}>← Atrás</button>
              )}
            </div>
          )}

          {step === TOTAL_Q && result && (() => {
            const ProfileIcon = CP_QUIZ_ICONS[result.profile.icon] || (() => null);
            const SecondIcon = result.secondProfile
              ? (CP_QUIZ_ICONS[result.secondProfile.icon] || (() => null))
              : null;
            return (
            <div className="cp-quiz-result cp-quiz-result-v2">
              <div className="cp-quiz-profile-head">
                <span className="cp-quiz-profile-emoji"><ProfileIcon/></span>
                <div>
                  <span className="eyebrow">{FALLBACK.resultEyebrow}</span>
                  <h3 className="gold">{result.profile.name}</h3>
                  {result.secondProfile && SecondIcon && (
                    <p className="cp-quiz-secondary">
                      …con un toque de <b className="cp-quiz-inline-icon"><SecondIcon/> {result.secondProfile.name}</b>.
                    </p>
                  )}
                </div>
              </div>
              <p className="cp-quiz-profile-desc">{result.profile.desc}</p>

              {result.filterApplied === 'vegan' && (
                <div className="cp-quiz-filter-chip"><b>100% vegano</b> · solo platos sin productos animales.</div>
              )}
              {result.filterApplied === 'noMeat' && (
                <div className="cp-quiz-filter-chip"><b>Sin carne</b> · pescado, veggie y vegano.</div>
              )}
              {result.filterApplied === 'preferFish' && (
                <div className="cp-quiz-filter-chip"><b>Mejor pescado</b> · priorizamos opciones del mar.</div>
              )}

              {result.reasonLines && result.reasonLines.length > 0 && (
                <div className="cp-quiz-reasons">
                  {result.reasonLines.map((line, i) => (
                    <p key={`r${i}`} className="cp-quiz-reason-line">{line}</p>
                  ))}
                </div>
              )}

              {result.mains.length > 0 && (
                <div className="cp-quiz-rec-block">
                  <span className="cp-quiz-rec-label">{FALLBACK.sectionMain}</span>
                  <ul className="cp-quiz-rec-list">
                    {result.mains.map((it, i) => (
                      <li key={`m${i}`} className="cp-quiz-rec-item">
                        <div className="cp-quiz-rec-text">
                          <b>{it.n}</b>
                          <span>{truncate(it.d, 80)}</span>
                        </div>
                        <span className="cp-quiz-rec-price">{it.p}€</span>
                      </li>
                    ))}
                  </ul>
                </div>
              )}

              {result.drink && (
                <div className="cp-quiz-rec-block">
                  <span className="cp-quiz-rec-label">{FALLBACK.sectionDrink}</span>
                  <ul className="cp-quiz-rec-list">
                    <li className="cp-quiz-rec-item">
                      <div className="cp-quiz-rec-text">
                        <b>{result.drink.n}</b>
                        <span>{truncate(result.drink.d, 80)}</span>
                      </div>
                      <span className="cp-quiz-rec-price">{result.drink.p}€</span>
                    </li>
                  </ul>
                </div>
              )}

              {result.sweet && (
                <div className="cp-quiz-rec-block">
                  <span className="cp-quiz-rec-label">{FALLBACK.sectionSweet}</span>
                  <ul className="cp-quiz-rec-list">
                    <li className="cp-quiz-rec-item">
                      <div className="cp-quiz-rec-text">
                        <b>{result.sweet.n}</b>
                        <span>{truncate(result.sweet.d, 80)}</span>
                      </div>
                      <span className="cp-quiz-rec-price">{result.sweet.p}€</span>
                    </li>
                  </ul>
                </div>
              )}

              <div className="cp-quiz-result-ctas">
                <button className="cp-btn-gold" onClick={() => { _scrollTo('#reserve'); }}>
                  { FALLBACK.reserveCta } →
                </button>
                <button className="cp-btn-ghost" onClick={restart}>
                  { FALLBACK.again }
                </button>
              </div>
            </div>
            );
          })()}
        </div>
      </div>
    </section>
  );
}

// =====================================================================
// 2. <SpinWheel /> — Daily lucky wheel, 1 spin / device / day
// =====================================================================
function SpinWheel({ t }) {
  const FALLBACK = {
    eyebrow: '✦  La rueda del día',
    title: 'Una sorpresa al día',
    sub: 'Gira la rueda — un premio por dispositivo cada día.',
    spin: 'Girar',
    spinning: 'Girando…',
    showCode: 'Enseña este código en mesa',
    comeBack: 'Vuelve mañana para otra tirada',
    segments: [
      '10% off postre',
      'Café cortesía',
      'Mejor mesa terraza',
      'Sorbete cortesía',
      'Vermut bienvenida',
      'Suerte mañana ✨'
    ]
  };
  const G = _safe(t, 'game', {});
  const segments = _safe(G, 'wheel.segments', FALLBACK.segments);
  const eyebrow = _safe(G, 'wheel.eyebrow', FALLBACK.eyebrow);
  const title = _safe(G, 'wheel.title', FALLBACK.title);
  const sub = _safe(G, 'wheel.sub', FALLBACK.sub);
  const spinLabel = _safe(G, 'wheel.spin', FALLBACK.spin);
  const spinningLabel = _safe(G, 'wheel.spinning', FALLBACK.spinning);
  const showCode = _safe(G, 'wheel.showCode', FALLBACK.showCode);
  const comeBack = _safe(G, 'wheel.comeBack', FALLBACK.comeBack);

  const [angle, setAngle] = useState(0);
  const [spinning, setSpinning] = useState(false);
  const [winner, setWinner] = useState(null); // { idx, label, code }
  const todayStorageKey = `cp_wheel_${_todayKey()}`;

  useEffect(() => {
    try {
      const stored = JSON.parse(localStorage.getItem(todayStorageKey) || 'null');
      if (stored && typeof stored.idx === 'number') {
        setWinner({ idx: stored.idx, label: segments[stored.idx], code: stored.code });
        // Pre-set angle so the wheel is visually parked at the prize
        const segDeg = 360 / segments.length;
        setAngle(360 * 5 - (stored.idx * segDeg + segDeg / 2));
      }
    } catch (_) {}
  }, []); // eslint-disable-line

  const spin = () => {
    if (spinning || winner) return;
    const segDeg = 360 / segments.length;
    const idx = Math.floor(Math.random() * segments.length);
    const turns = 5 + Math.random() * 1.5;
    // Wheel rotates clockwise; arrow points up at top. Park midpoint of segment under arrow.
    const finalAngle = 360 * turns - (idx * segDeg + segDeg / 2);
    setSpinning(true);
    setAngle(finalAngle);
    const code = 'CP-' + _hashCode(`${_todayKey()}|${idx}|${segments[idx]}`);
    window.setTimeout(() => {
      setSpinning(false);
      setWinner({ idx, label: segments[idx], code });
      try {
        localStorage.setItem(todayStorageKey, JSON.stringify({ idx, code, at: Date.now() }));
      } catch (_) {}
    }, 4400);
  };

  // Build SVG segments
  const R = 140;
  const cx = 160, cy = 160;
  const segDeg = 360 / segments.length;

  const segPath = (i) => {
    const start = (i * segDeg - 90) * Math.PI / 180;
    const end = ((i + 1) * segDeg - 90) * Math.PI / 180;
    const x1 = cx + R * Math.cos(start), y1 = cy + R * Math.sin(start);
    const x2 = cx + R * Math.cos(end),   y2 = cy + R * Math.sin(end);
    return `M ${cx} ${cy} L ${x1} ${y1} A ${R} ${R} 0 0 1 ${x2} ${y2} Z`;
  };
  const labelPos = (i) => {
    const a = ((i + 0.5) * segDeg - 90) * Math.PI / 180;
    const r = R * 0.62;
    return { x: cx + r * Math.cos(a), y: cy + r * Math.sin(a), rot: i * segDeg + segDeg / 2 };
  };

  return (
    <section className="cp-wheel-section">
      <div className="section-inner">
        <div className="cp-wheel-card">
          <span className="eyebrow">{eyebrow}</span>
          <h2 className="cp-wheel-title">{title}</h2>
          <p className="cp-wheel-sub">{sub}</p>

          <div className="cp-wheel-stage">
            <div className="cp-wheel-pointer" aria-hidden="true">▼</div>
            <svg className="cp-wheel-svg" viewBox="0 0 320 320">
              <defs>
                <radialGradient id="cp-wheel-shine" cx="50%" cy="40%" r="60%">
                  <stop offset="0%" stopColor="rgba(255,255,255,0.18)"/>
                  <stop offset="100%" stopColor="rgba(255,255,255,0)"/>
                </radialGradient>
              </defs>
              <g
                className="cp-wheel-rotor"
                style={{
                  transform: `rotate(${angle}deg)`,
                  transformOrigin: `${cx}px ${cy}px`,
                  transition: spinning
                    ? 'transform 4.2s cubic-bezier(.17,.67,.18,1)'
                    : 'transform 0s'
                }}
              >
                {segments.map((seg, i) => (
                  <g key={i}>
                    <path d={segPath(i)} fill={i % 2 === 0 ? '#1f5d4c' : '#c9a86a'} stroke="#0c2620" strokeWidth="1.5"/>
                  </g>
                ))}
                {/* labels */}
                {segments.map((seg, i) => {
                  const p = labelPos(i);
                  return (
                    <text
                      key={`l${i}`}
                      x={p.x} y={p.y}
                      transform={`rotate(${p.rot}, ${p.x}, ${p.y})`}
                      textAnchor="middle"
                      dominantBaseline="middle"
                      fill={i % 2 === 0 ? '#f4ede0' : '#0c2620'}
                      fontFamily="Inter, sans-serif"
                      fontSize="10.5"
                      fontWeight="600"
                      style={{ letterSpacing: '0.04em' }}
                    >
                      {seg.length > 18 ? seg.slice(0, 17) + '…' : seg}
                    </text>
                  );
                })}
                <circle cx={cx} cy={cy} r={R} fill="url(#cp-wheel-shine)" pointerEvents="none"/>
              </g>
              {/* hub */}
              <circle cx={cx} cy={cy} r="22" fill="#0c2620" stroke="#c9a86a" strokeWidth="2"/>
              <circle cx={cx} cy={cy} r="6" fill="#e6c98a"/>
            </svg>

            <button
              className={`cp-wheel-btn ${spinning ? 'spinning' : ''}`}
              onClick={spin}
              disabled={spinning || !!winner}
              aria-label={spinLabel}
            >
              {winner ? '✓' : (spinning ? spinningLabel : spinLabel)}
            </button>
          </div>

          {winner && (
            <div className="cp-wheel-winner">
              <div className="cp-wheel-prize-name">{winner.label}</div>
              <div className="cp-wheel-code-label">{showCode}</div>
              <div className="cp-wheel-code">{winner.code}</div>
              <div className="cp-wheel-comeback">{comeBack}</div>
            </div>
          )}
        </div>
      </div>
    </section>
  );
}

// =====================================================================
// 3. <LoyaltyTracker /> — 5-stamp digital sello
// =====================================================================
// ----- Cookie helpers (60-day persistence) -----
function _setCookie(name, value, days) {
  try {
    const exp = new Date(Date.now() + days * 24 * 60 * 60 * 1000).toUTCString();
    document.cookie = `${name}=${encodeURIComponent(value)}; expires=${exp}; path=/; SameSite=Lax`;
  } catch (_) {}
}
function _getCookie(name) {
  try {
    const m = document.cookie.match(new RegExp('(?:^|; )' + name.replace(/[.$?*|{}()[\]\\/+^]/g, '\\$&') + '=([^;]*)'));
    return m ? decodeURIComponent(m[1]) : null;
  } catch (_) { return null; }
}
function _delCookie(name) {
  try { document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/`; } catch (_) {}
}

// ----- Daily-rotating code (deterministic, same on landing & admin) -----
// Generates a 4-character code derived from the date. Both Paco's admin and
// the customer's loyalty form compute the same code for the same calendar day,
// without any server round-trip. Customer must obtain it AT the restaurant.
const CP_LOYALTY_SECRET = 'paco-2026-can-petita-sello';
function cpDayCode(d) {
  const x = d || new Date();
  const ymd = x.getFullYear() + '-' + String(x.getMonth()+1).padStart(2,'0') + '-' + String(x.getDate()).padStart(2,'0');
  const seed = ymd + '|' + CP_LOYALTY_SECRET;
  // simple hash
  let h = 5381;
  for (let i = 0; i < seed.length; i++) h = ((h << 5) + h) + seed.charCodeAt(i);
  const alphabet = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789';  // omit I,O,0,1
  let out = '';
  let n = (h >>> 0);
  for (let i = 0; i < 4; i++) { out += alphabet[n % alphabet.length]; n = Math.floor(n / alphabet.length); }
  return out;
}
if (typeof window !== 'undefined') window.CP_DAY_CODE = cpDayCode;

function LoyaltyTracker({ t }) {
  const FALLBACK = {
    eyebrow: '✦  Tu tarjeta de visitas',
    title: 'Cinco visitas, un postre por la casa',
    sub: 'Para sumar un sello tienes que pasar de verdad por Can Petita. Pídele a Paco el código del día y mételo aquí.',
    placeholder: 'CÓDIGO DE 4 LETRAS',
    submit: 'Sellar',
    askPaco: 'Pídele a Paco el código del día — cambia cada mañana.',
    invalid: 'Ese código no es el de hoy. Asegúrate de estar en el restaurante.',
    alreadyToday: 'Ya tienes el sello de hoy ✓ — vuelve mañana.',
    success: '¡Sello añadido! ✓',
    rewardTitle: '¡Lacre abierto!',
    rewardDesc: 'Enseña este código en tu próxima visita — postre por la casa.',
    rewardCode: 'Tu premio',
    reset: 'Reiniciar tarjeta',
    helper: 'Mismo navegador, 60 días. Si limpias cookies, contamos desde cero.'
  };
  const G = _safe(t, 'game', {});
  const eyebrow = _safe(G, 'loyalty.eyebrow', FALLBACK.eyebrow);
  const title = _safe(G, 'loyalty.title', FALLBACK.title);
  const sub = _safe(G, 'loyalty.sub', FALLBACK.sub);
  const placeholder = _safe(G, 'loyalty.placeholder', FALLBACK.placeholder);
  const submitLbl = _safe(G, 'loyalty.submit', FALLBACK.submit);
  const askPaco = _safe(G, 'loyalty.askPaco', FALLBACK.askPaco);
  const invalidLbl = _safe(G, 'loyalty.invalid', FALLBACK.invalid);
  const alreadyTodayLbl = _safe(G, 'loyalty.alreadyToday', FALLBACK.alreadyToday);
  const successLbl = _safe(G, 'loyalty.success', FALLBACK.success);
  const rewardTitle = _safe(G, 'loyalty.rewardTitle', FALLBACK.rewardTitle);
  const rewardDesc = _safe(G, 'loyalty.rewardDesc', FALLBACK.rewardDesc);
  const rewardCodeLabel = _safe(G, 'loyalty.rewardCode', FALLBACK.rewardCode);
  const resetLabel = _safe(G, 'loyalty.reset', FALLBACK.reset);
  const helper = _safe(G, 'loyalty.helper', FALLBACK.helper);

  const COOKIE_NAME = 'cp_visits_v3';
  const COOKIE_DAYS = 60;

  const readVisits = () => {
    const raw = _getCookie(COOKIE_NAME);
    if (!raw) return [];
    try { const a = JSON.parse(raw); return Array.isArray(a) ? a : []; } catch (_) { return []; }
  };
  const writeVisits = (arr) => _setCookie(COOKIE_NAME, JSON.stringify(arr), COOKIE_DAYS);

  const [visits, setVisits] = useState(readVisits);
  const [code, setCode] = useState('');
  const [feedback, setFeedback] = useState(null); // { kind: 'ok'|'err', msg }
  const [justAdded, setJustAdded] = useState(false);

  const todayCode = cpDayCode();
  const todayKey = (() => { const d = new Date(); return d.getFullYear() + '-' + (d.getMonth()+1) + '-' + d.getDate(); })();

  const stampedToday = visits.some(v => v.day === todayKey);

  const trySubmit = (e) => {
    e && e.preventDefault();
    const entered = (code || '').toUpperCase().replace(/[^A-Z0-9]/g, '');
    if (entered.length !== 4) {
      setFeedback({ kind: 'err', msg: invalidLbl });
      return;
    }
    if (entered !== todayCode) {
      setFeedback({ kind: 'err', msg: invalidLbl });
      return;
    }
    if (stampedToday) {
      setFeedback({ kind: 'err', msg: alreadyTodayLbl });
      return;
    }
    const next = [...visits, { day: todayKey, ts: Date.now() }];
    writeVisits(next);
    setVisits(next);
    setCode('');
    setFeedback({ kind: 'ok', msg: successLbl });
    setJustAdded(true);
    setTimeout(() => setJustAdded(false), 2200);
  };

  const reset = () => {
    setVisits([]);
    _delCookie(COOKIE_NAME);
    setFeedback(null);
  };

  const filled = Math.min(5, visits.length);
  const completed = filled >= 5;
  const rewardCode = completed ? 'CP-' + _hashCode(`reward|${visits.slice(-5).map(v => v.day).join('|')}`) : null;

  return (
    <section className="cp-loyalty-section">
      <div className="section-inner">
        <div className="cp-loyalty-card">
          <span className="eyebrow">{eyebrow}</span>
          <h2 className="cp-loyalty-title">{title}</h2>
          <p className="cp-loyalty-sub">{sub}</p>

          <div className="cp-loyalty-stamps" role="list">
            {[0,1,2,3,4].map(i => (
              <div
                key={i}
                role="listitem"
                className={`cp-stamp ${i < filled ? 'filled' : ''} ${i === filled - 1 && justAdded ? 'just-filled' : ''}`}
                aria-label={`Sello ${i+1} ${i < filled ? 'conseguido' : 'pendiente'}`}
              >
                <svg viewBox="0 0 60 60" width="100%" height="100%">
                  <circle cx="30" cy="30" r="26" className="cp-stamp-ring"/>
                  <text x="30" y="36" textAnchor="middle" className="cp-stamp-num">{i+1}</text>
                </svg>
              </div>
            ))}
          </div>

          {!completed && (
            <form className="cp-loyalty-form" onSubmit={trySubmit}>
              <div className="cp-loyalty-input-wrap">
                <input
                  type="text"
                  inputMode="text"
                  autoComplete="off"
                  spellCheck={false}
                  maxLength={4}
                  value={code}
                  onChange={e => { setCode(e.target.value.toUpperCase().replace(/[^A-Z0-9]/g, '').slice(0,4)); setFeedback(null); }}
                  placeholder={placeholder}
                  className="cp-loyalty-input"
                  disabled={stampedToday}
                />
                <button type="submit" className="cp-btn-gold" disabled={stampedToday || code.length !== 4}>
                  {stampedToday ? '✓' : submitLbl}
                </button>
              </div>
              {feedback && (
                <div className={`cp-loyalty-note ${feedback.kind === 'ok' ? 'cp-loyalty-ok' : 'cp-loyalty-err'}`}>{feedback.msg}</div>
              )}
              {!feedback && stampedToday && (
                <div className="cp-loyalty-note cp-loyalty-ok">{alreadyTodayLbl}</div>
              )}
              <div className="cp-loyalty-helper">📍 {askPaco}</div>
              <div className="cp-loyalty-helper" style={{ opacity: 0.65 }}>🍪 {helper}</div>
            </form>
          )}

          {completed && (
            <div className="cp-loyalty-reward">
              <div className="cp-wax-seal">
                <div className="cp-wax-seal-broken">✦</div>
                <div className="cp-wax-ribbon"/>
              </div>
              <h3 className="gold">{rewardTitle}</h3>
              <p>{rewardDesc}</p>
              <div className="cp-loyalty-code-wrap">
                <span className="cp-loyalty-code-label">{rewardCodeLabel}</span>
                <span className="cp-loyalty-code">{rewardCode}</span>
              </div>
              <button className="cp-btn-ghost" onClick={reset} style={{ marginTop: 14 }}>{resetLabel}</button>
            </div>
          )}
        </div>
      </div>
    </section>
  );
}

// =====================================================================
// 4. <EasterEggHunt /> — 5 hidden stars, unlock secret menu
// =====================================================================
function EasterEggHunt() {
  const [found, setFound] = useState(() => {
    try {
      const stored = JSON.parse(localStorage.getItem('cp_eggs') || '[]');
      return Array.isArray(stored) ? stored : [];
    } catch (_) { return []; }
  });
  const [showModal, setShowModal] = useState(false);
  const [shouldOpenOnComplete, setShouldOpenOnComplete] = useState(true);

  // 5 strategic positions across the page (% of viewport / page selectors).
  // Stars are positioned absolutely on document.body so they show wherever the user is scrolled.
  const SPOTS = [
    { id: 'e1', selector: '#story',     pos: { top: '8%', right: '4%' } },
    { id: 'e2', selector: '#breakfast', pos: { top: '12%', left: '3%' } },
    { id: 'e3', selector: '#lunch',     pos: { bottom: '10%', right: '6%' } },
    { id: 'e4', selector: '#gallery',   pos: { top: '45%', left: '2%' } },
    { id: 'e5', selector: '#visit',     pos: { bottom: '14%', left: '4%' } }
  ];

  // Mount each star inside the targeted section so it scrolls with the page.
  useEffect(() => {
    const mounted = [];
    const removeFns = [];

    const tryMount = () => {
      SPOTS.forEach(spot => {
        if (document.getElementById(`cp-egg-${spot.id}`)) return;
        const host = document.querySelector(spot.selector);
        if (!host) return;
        // Make sure the host can contain absolutely-positioned children
        const cs = window.getComputedStyle(host);
        if (cs.position === 'static') host.style.position = 'relative';

        const el = document.createElement('button');
        el.type = 'button';
        el.id = `cp-egg-${spot.id}`;
        el.className = 'cp-egg' + (found.includes(spot.id) ? ' found' : '');
        el.setAttribute('aria-label', 'Estrella escondida');
        el.innerHTML = '★';
        Object.entries(spot.pos).forEach(([k, v]) => { el.style[k] = v; });
        const handler = (ev) => {
          ev.preventDefault();
          ev.stopPropagation();
          if (el.classList.contains('found')) return;
          el.classList.add('found', 'cp-egg-burst');
          setFound(prev => {
            if (prev.includes(spot.id)) return prev;
            const next = [...prev, spot.id];
            try { localStorage.setItem('cp_eggs', JSON.stringify(next)); } catch (_) {}
            return next;
          });
        };
        el.addEventListener('click', handler);
        host.appendChild(el);
        mounted.push(el);
        removeFns.push(() => el.removeEventListener('click', handler));
      });
    };

    // Try right away and again after Babel-rendered components mount
    tryMount();
    const id1 = setTimeout(tryMount, 400);
    const id2 = setTimeout(tryMount, 1200);

    return () => {
      clearTimeout(id1); clearTimeout(id2);
      removeFns.forEach(f => f());
      mounted.forEach(el => el.remove());
    };
  }, []); // mount once

  // Sync visual "found" class on existing stars when state changes
  useEffect(() => {
    SPOTS.forEach(spot => {
      const el = document.getElementById(`cp-egg-${spot.id}`);
      if (el && found.includes(spot.id)) el.classList.add('found');
    });
    if (found.length === 5 && shouldOpenOnComplete) {
      setShowModal(true);
      setShouldOpenOnComplete(false);
    }
  }, [found, shouldOpenOnComplete]);

  const reset = () => {
    try { localStorage.removeItem('cp_eggs'); } catch (_) {}
    SPOTS.forEach(spot => {
      const el = document.getElementById(`cp-egg-${spot.id}`);
      if (el) el.classList.remove('found');
    });
    setFound([]);
    setShouldOpenOnComplete(true);
  };

  return (
    <>
      <div className="cp-egg-counter" title={`Estrellas encontradas: ${found.length}/5`}>
        ✦ {found.length}/5
        {found.length === 5 && (
          <button className="cp-egg-reopen" onClick={() => setShowModal(true)}>ver carta</button>
        )}
      </div>

      {showModal && (
        <div className="cp-egg-modal-backdrop" onClick={() => setShowModal(false)}>
          <div className="cp-egg-modal" onClick={e => e.stopPropagation()}>
            <button className="cp-modal-close" onClick={() => setShowModal(false)} aria-label="Cerrar">✕</button>
            <span className="eyebrow">✦  Carta secreta del chef</span>
            <h3 className="gold cp-egg-modal-title">Risotto de bogavante de la casa</h3>
            <p className="cp-egg-modal-sub">Sólo bajo encargo · 48 h de antelación</p>
            <p className="cp-egg-modal-desc">
              Arroz cremoso de bogavante fresco de la lonja, fumet reducido del día, ralladura de
              limón de Calonge y un toque final de mantequilla noisette. Para mesas que vienen a celebrar.
            </p>
            <div className="cp-egg-modal-actions">
              <button className="cp-btn-gold" onClick={() => { setShowModal(false); _scrollTo('#reserve'); }}>
                Reservar y encargarlo →
              </button>
              <button className="cp-btn-ghost" onClick={reset}>Esconder de nuevo</button>
            </div>
          </div>
        </div>
      )}
    </>
  );
}

// =====================================================================
// 5. <StatsCounter /> — animated big numbers on scroll
// =====================================================================
function StatsCounter() {
  const STATS = [
    { value: 4.9,    suffix: '★',   label: 'valoración media',   decimals: 1 },
    { value: 157,    prefix: '+',   label: 'reseñas en Google',  decimals: 0 },
    { value: 50000,  prefix: '+',   label: 'sonrisas servidas',  decimals: 0 },
    { value: 6,      prefix: '+',   label: 'años cocinando',     decimals: 0 }
  ];
  const ref = useRef(null);
  const [animated, setAnimated] = useState(false);
  const [values, setValues] = useState(STATS.map(() => 0));

  useEffect(() => {
    if (!ref.current) return;
    const io = new IntersectionObserver((entries) => {
      entries.forEach(e => {
        if (e.isIntersecting && !animated) {
          setAnimated(true);
          const start = performance.now();
          const dur = 1600;
          const tick = (now) => {
            const t = Math.min(1, (now - start) / dur);
            const eased = 1 - Math.pow(1 - t, 4); // easeOutQuart
            setValues(STATS.map(s => s.value * eased));
            if (t < 1) requestAnimationFrame(tick);
          };
          requestAnimationFrame(tick);
        }
      });
    }, { threshold: 0.3 });
    io.observe(ref.current);
    return () => io.disconnect();
  }, [animated]);

  const fmt = (v, s) => {
    if (s.decimals > 0) return v.toFixed(s.decimals);
    if (s.value >= 1000) return Math.round(v).toLocaleString('es-ES');
    return Math.round(v).toString();
  };

  return (
    <section className="cp-stats-section" ref={ref}>
      <div className="section-inner">
        <div className="cp-stats-grid">
          {STATS.map((s, i) => (
            <div key={i} className="cp-stat">
              <div className="cp-stat-num">
                {s.prefix && <span className="cp-stat-prefix">{s.prefix}</span>}
                <span>{fmt(values[i], s)}</span>
                {s.suffix && <span className="cp-stat-suffix">{s.suffix}</span>}
              </div>
              <div className="cp-stat-label">{s.label}</div>
            </div>
          ))}
        </div>
      </div>
    </section>
  );
}

// =====================================================================
// 6. <FloatingReserveCTA /> — sticky conversion button
// =====================================================================
function FloatingReserveCTA({ t }) {
  const [show, setShow] = useState(false);
  const FALLBACK = 'Reservar';
  const label = _safe(t, 'game.floatingReserve', _safe(t, 'nav.reserve', FALLBACK));

  useEffect(() => {
    const heroH = () => {
      const hero = document.querySelector('.hero, #top');
      return hero ? hero.getBoundingClientRect().height * 0.9 : 600;
    };
    const reserveEl = () => document.querySelector('#reserve');

    const check = () => {
      const past = window.scrollY > heroH();
      const r = reserveEl();
      let inReserve = false;
      if (r) {
        const rect = r.getBoundingClientRect();
        inReserve = rect.top < window.innerHeight * 0.5 && rect.bottom > window.innerHeight * 0.3;
      }
      const visible = past && !inReserve;
      setShow(visible);
      // Tell other fixed pieces (egg counter, speaker) to lift up on mobile
      try { document.body.classList.toggle('cp-cta-up', visible); } catch (_) {}
    };

    check();
    window.addEventListener('scroll', check, { passive: true });
    window.addEventListener('resize', check);
    return () => {
      window.removeEventListener('scroll', check);
      window.removeEventListener('resize', check);
    };
  }, []);

  return (
    <button
      className={`cp-floating-reserve ${show ? 'visible' : ''}`}
      onClick={(e) => { e.preventDefault(); _scrollTo('#reserve'); }}
      aria-label={label}
    >
      <span>{label}</span>
      <span className="cp-floating-arrow">→</span>
    </button>
  );
}

// =====================================================================
// 7. <AmbientToggle /> — synthesized warm pink-noise ambient loop
// =====================================================================
function AmbientToggle() {
  const [on, setOn] = useState(false);
  const ctxRef = useRef(null);
  const gainRef = useRef(null);
  const sourceRef = useRef(null);

  // Restore preference but never auto-play
  useEffect(() => {
    try {
      const pref = localStorage.getItem('cp_ambient');
      // We do not auto-start — user must tap. We just remember the icon state.
      if (pref === 'on') {
        // Do nothing; require gesture.
      }
    } catch (_) {}
    return () => {
      try { sourceRef.current?.stop(); } catch (_) {}
      try { ctxRef.current?.close(); } catch (_) {}
    };
  }, []);

  const toggle = async () => {
    if (!on) {
      try {
        const Ctx = window.AudioContext || window.webkitAudioContext;
        if (!Ctx) return;
        const ctx = new Ctx();
        ctxRef.current = ctx;

        // 4 seconds of warm pink-noise loop (Voss-McCartney-inspired soft pink)
        const sr = ctx.sampleRate;
        const buf = ctx.createBuffer(1, sr * 4, sr);
        const data = buf.getChannelData(0);
        let b0 = 0, b1 = 0, b2 = 0, b3 = 0, b4 = 0, b5 = 0, b6 = 0;
        for (let i = 0; i < data.length; i++) {
          const w = Math.random() * 2 - 1;
          b0 = 0.99886 * b0 + w * 0.0555179;
          b1 = 0.99332 * b1 + w * 0.0750759;
          b2 = 0.96900 * b2 + w * 0.1538520;
          b3 = 0.86650 * b3 + w * 0.3104856;
          b4 = 0.55000 * b4 + w * 0.5329522;
          b5 = -0.7616 * b5 - w * 0.0168980;
          let pink = b0 + b1 + b2 + b3 + b4 + b5 + b6 + w * 0.5362;
          b6 = w * 0.115926;
          // Soft envelope to imitate "room hum"
          pink *= 0.11;
          // Apply slight low-frequency wobble (plates, distant chatter feel)
          const wobble = 1 + Math.sin(i / sr * Math.PI * 2 * 0.4) * 0.08;
          data[i] = pink * wobble;
        }
        const src = ctx.createBufferSource();
        src.buffer = buf;
        src.loop = true;

        // Low-pass to take the harshness off
        const lp = ctx.createBiquadFilter();
        lp.type = 'lowpass';
        lp.frequency.value = 1100;
        lp.Q.value = 0.7;

        const gain = ctx.createGain();
        gain.gain.value = 0;
        gainRef.current = gain;

        src.connect(lp).connect(gain).connect(ctx.destination);
        src.start();
        sourceRef.current = src;

        // Soft fade-in
        const t = ctx.currentTime;
        gain.gain.setValueAtTime(0, t);
        gain.gain.linearRampToValueAtTime(0.05, t + 1.2);

        setOn(true);
        try { localStorage.setItem('cp_ambient', 'on'); } catch (_) {}
      } catch (_) {
        setOn(false);
      }
    } else {
      try {
        const ctx = ctxRef.current;
        const gain = gainRef.current;
        if (gain && ctx) {
          const t = ctx.currentTime;
          gain.gain.cancelScheduledValues(t);
          gain.gain.setValueAtTime(gain.gain.value, t);
          gain.gain.linearRampToValueAtTime(0.0001, t + 0.4);
        }
        setTimeout(() => {
          try { sourceRef.current?.stop(); } catch (_) {}
          try { ctxRef.current?.close(); } catch (_) {}
          sourceRef.current = null;
          ctxRef.current = null;
          gainRef.current = null;
        }, 500);
      } catch (_) {}
      setOn(false);
      try { localStorage.setItem('cp_ambient', 'off'); } catch (_) {}
    }
  };

  return (
    <button
      type="button"
      className={`cp-ambient-toggle ${on ? 'on' : 'off'}`}
      onClick={toggle}
      aria-label={on ? 'Apagar sonido ambiente' : 'Encender sonido ambiente'}
      aria-pressed={on}
    >
      {on ? (
        <svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round">
          <path d="M4 9v6h4l5 4V5L8 9H4z"/>
          <path d="M16 8c1.5 1 1.5 7 0 8"/>
          <path d="M19 5c3 2.5 3 11.5 0 14"/>
        </svg>
      ) : (
        <svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round">
          <path d="M4 9v6h4l5 4V5L8 9H4z"/>
          <line x1="16" y1="9" x2="22" y2="15"/>
          <line x1="22" y1="9" x2="16" y2="15"/>
        </svg>
      )}
    </button>
  );
}

// =====================================================================
// 8. <PhotoLightbox /> — premium fullscreen gallery viewer
// =====================================================================
function PhotoLightbox({ photos, index, onClose }) {
  const [i, setI] = useState(typeof index === 'number' ? index : 0);
  const [animKey, setAnimKey] = useState(0);
  const touchStart = useRef(null);

  const total = photos?.length || 0;
  const next = useCallback(() => {
    setI(prev => (prev + 1) % total);
    setAnimKey(k => k + 1);
  }, [total]);
  const prev = useCallback(() => {
    setI(prev => (prev - 1 + total) % total);
    setAnimKey(k => k + 1);
  }, [total]);

  useEffect(() => { setI(typeof index === 'number' ? index : 0); }, [index]);

  useEffect(() => {
    const onKey = (e) => {
      if (e.key === 'Escape') onClose && onClose();
      else if (e.key === 'ArrowRight') next();
      else if (e.key === 'ArrowLeft') prev();
    };
    document.addEventListener('keydown', onKey);
    // Prevent body scroll while open
    const prevOverflow = document.body.style.overflow;
    document.body.style.overflow = 'hidden';
    return () => {
      document.removeEventListener('keydown', onKey);
      document.body.style.overflow = prevOverflow;
    };
  }, [next, prev, onClose]);

  if (!photos || total === 0) return null;
  const cur = photos[i] || {};

  const onTouchStart = (e) => {
    touchStart.current = e.touches[0]?.clientX ?? null;
  };
  const onTouchEnd = (e) => {
    if (touchStart.current == null) return;
    const dx = (e.changedTouches[0]?.clientX ?? 0) - touchStart.current;
    if (Math.abs(dx) > 40) (dx < 0 ? next() : prev());
    touchStart.current = null;
  };

  return (
    <div className="cp-lightbox" onClick={onClose} onTouchStart={onTouchStart} onTouchEnd={onTouchEnd}>
      <button className="cp-lightbox-close" onClick={onClose} aria-label="Cerrar">✕</button>
      <button className="cp-lightbox-arrow prev" onClick={(e) => { e.stopPropagation(); prev(); }} aria-label="Anterior">‹</button>
      <button className="cp-lightbox-arrow next" onClick={(e) => { e.stopPropagation(); next(); }} aria-label="Siguiente">›</button>
      <figure className="cp-lightbox-figure" onClick={e => e.stopPropagation()}>
        <img
          key={animKey}
          src={cur.src}
          alt={cur.alt || cur.caption || ''}
          className="cp-lightbox-img"
        />
        {(cur.caption || cur.credit) && (
          <figcaption className="cp-lightbox-cap">
            {cur.caption && <span>{cur.caption}</span>}
            {cur.credit && <span className="cp-lightbox-credit">  ·  {cur.credit}</span>}
          </figcaption>
        )}
      </figure>
      <div className="cp-lightbox-thumbs" onClick={e => e.stopPropagation()}>
        {photos.map((p, idx) => (
          <button
            key={idx}
            className={`cp-lightbox-thumb ${idx === i ? 'active' : ''}`}
            onClick={() => { setI(idx); setAnimKey(k => k + 1); }}
            aria-label={`Foto ${idx+1}`}
          >
            <img src={p.src} alt="" loading="lazy"/>
          </button>
        ))}
      </div>
      <div className="cp-lightbox-count">{i+1} / {total}</div>
    </div>
  );
}

// =====================================================================
// Styles — single injected block
// =====================================================================
if (typeof document !== 'undefined' && !document.getElementById('cp-game-styles')) {
  const s = document.createElement('style');
  s.id = 'cp-game-styles';
  s.textContent = `
/* ========== shared palette refs (mirrors styles.css) ========== */
.cp-quiz-section, .cp-wheel-section, .cp-loyalty-section, .cp-stats-section {
  padding: clamp(60px, 8vw, 110px) 0;
  background: var(--ink, #0c2620);
  color: var(--cream, #f4ede0);
}

/* ========== buttons (scoped, won't clobber site .btn) ========== */
.cp-btn-gold, .cp-btn-ghost {
  display: inline-flex; align-items: center; justify-content: center; gap: 10px;
  border: 1px solid #c9a86a;
  font-family: "Inter", system-ui, sans-serif;
  font-size: 12px; letter-spacing: 0.18em; text-transform: uppercase;
  font-weight: 600;
  padding: 16px 28px; border-radius: 999px;
  cursor: pointer;
  transition: all .35s cubic-bezier(.2,.7,.2,1);
}
.cp-btn-gold {
  background: linear-gradient(180deg, #e6c98a 0%, #c9a86a 100%);
  color: #0c2620;
  box-shadow: 0 6px 30px rgba(201,168,106,.18);
}
.cp-btn-gold:hover { transform: translateY(-2px); box-shadow: 0 14px 40px rgba(201,168,106,.32); }
.cp-btn-ghost {
  background: transparent;
  color: #c9a86a;
}
.cp-btn-ghost:hover { background: rgba(201,168,106,.08); color: #e6c98a; }

/* ========== confetti (CSS-only) ========== */
.cp-confetti {
  position: absolute; inset: 0; pointer-events: none; overflow: visible;
  z-index: 5;
}
.cp-confetti span {
  position: absolute; top: 50%; left: 50%;
  width: 6px; height: 10px; border-radius: 1px;
  transform: translate(-50%,-50%);
  animation: cp-confetti-fly 1.4s cubic-bezier(.22,.6,.36,1) forwards;
  animation-delay: var(--delay, 0s);
}
@keyframes cp-confetti-fly {
  0%   { transform: translate(-50%,-50%) rotate(0); opacity: 1; }
  100% { transform: translate(calc(-50% + var(--tx)), calc(-50% + var(--ty))) rotate(var(--rot)); opacity: 0; }
}

/* ========== 1. DishQuiz ========== */
.cp-quiz-section { padding-left: 16px !important; padding-right: 16px !important; }
@media (min-width: 600px) { .cp-quiz-section { padding-left: clamp(20px, 4vw, 64px) !important; padding-right: clamp(20px, 4vw, 64px) !important; } }
.cp-quiz-card {
  position: relative;
  max-width: 760px; margin: 0 auto;
  padding: clamp(20px, 4vw, 52px);
  background: linear-gradient(180deg, rgba(20,59,48,.85), rgba(12,38,32,.95));
  border-radius: 14px;
  border: 1px solid rgba(201,168,106,.32);
  box-shadow: 0 20px 60px rgba(0,0,0,.32), inset 0 1px 0 rgba(230,201,138,.12);
  overflow: hidden;
  box-sizing: border-box;
}
@media (max-width: 600px) {
  .cp-quiz-card { padding: 22px 18px; border-radius: 12px; }
  .cp-quiz-title { font-size: 24px !important; }
}
.cp-quiz-card::before {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background:
    radial-gradient(800px 200px at 50% -10%, rgba(230,201,138,.10), transparent 60%);
}
.cp-quiz-title {
  font-family: var(--ff-display); font-weight: 500;
  font-size: clamp(28px, 4vw, 42px); line-height: 1.05;
  color: #f4ede0; margin-top: 16px;
}
.cp-quiz-sub { color: rgba(244,237,224,.65); font-size: 15px; margin-top: 10px; }

.cp-quiz-progress {
  position: relative; height: 4px;
  background: rgba(244,237,224,.08); border-radius: 2px;
  margin: 28px 0 24px;
}
.cp-quiz-progress-bar {
  position: absolute; top: 0; left: 0; height: 100%;
  background: linear-gradient(90deg, #c9a86a, #e6c98a);
  border-radius: 2px;
  transition: width .5s cubic-bezier(.2,.7,.2,1);
}
.cp-quiz-progress-label {
  position: absolute; right: 0; top: 12px;
  font-size: 11px; letter-spacing: .2em; color: rgba(244,237,224,.5);
}

.cp-quiz-intro { display: flex; flex-direction: column; align-items: flex-start; gap: 22px; margin-top: 24px; }
.cp-quiz-returning {
  font-size: 14px; color: rgba(244,237,224,.78);
  background: rgba(201,168,106,.08); padding: 14px 18px; border-radius: 12px;
  border: 1px solid rgba(201,168,106,.2);
}

.cp-quiz-q { animation: cp-fade-up .5s cubic-bezier(.2,.7,.2,1) both; }
.cp-quiz-q h3 {
  font-family: var(--ff-display); font-weight: 500;
  font-size: clamp(22px, 3vw, 30px); color: #f4ede0; margin-bottom: 22px;
}
.cp-quiz-opts { display: grid; gap: 12px; }
@media (min-width: 600px) { .cp-quiz-opts { grid-template-columns: 1fr 1fr; } }
.cp-quiz-opt {
  display: flex; align-items: center; gap: 14px;
  padding: 18px 22px; text-align: left;
  background: rgba(244,237,224,.04);
  border: 1px solid rgba(201,168,106,.22);
  border-radius: 12px;
  color: #f4ede0; font-family: var(--ff-body); font-size: 15px;
  cursor: pointer; transition: all .25s cubic-bezier(.2,.7,.2,1);
}
.cp-quiz-opt:hover {
  background: rgba(201,168,106,.10);
  border-color: rgba(201,168,106,.55);
  transform: translateX(4px);
}
.cp-quiz-opt-mark {
  width: 28px; height: 28px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  background: rgba(201,168,106,.15); color: #e6c98a;
  font-size: 12px; font-weight: 700;
  border: 1px solid rgba(201,168,106,.4);
  flex-shrink: 0;
}

.cp-quiz-result { animation: cp-fade-up .6s cubic-bezier(.2,.7,.2,1) both; margin-top: 24px; }
.cp-quiz-result-photo {
  position: relative; aspect-ratio: 16/10; border-radius: 14px; overflow: hidden;
  border: 1px solid rgba(201,168,106,.4);
  box-shadow: 0 18px 50px rgba(0,0,0,.4);
}
.cp-quiz-result-photo img { width: 100%; height: 100%; object-fit: cover; transform: scale(1); transition: transform 4s ease; }
.cp-quiz-result-photo:hover img { transform: scale(1.05); }
.cp-quiz-medal {
  position: absolute; top: 14px; right: 14px;
  background: linear-gradient(180deg, #e6c98a, #c9a86a);
  color: #0c2620; width: 32px; height: 32px;
  border-radius: 50%; display: inline-flex; align-items: center; justify-content: center;
  font-weight: 700; box-shadow: 0 4px 14px rgba(201,168,106,.4);
}
.cp-quiz-result-body { margin-top: 22px; }
.cp-quiz-result-body h3 {
  font-family: var(--ff-display); font-size: clamp(26px, 3.4vw, 36px);
  margin: 8px 0 12px;
}
.cp-quiz-result-body p { color: rgba(244,237,224,.78); font-size: 15px; line-height: 1.6; }
.cp-quiz-result-ctas { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 22px; }

/* ========== 1.b DishQuiz v2 — extras ========== */
.cp-quiz-card-v2 { max-width: 820px; }
.cp-quiz-meta {
  font-size: 12px; letter-spacing: .12em; text-transform: uppercase;
  color: rgba(244,237,224,.45); margin-top: 0;
}
.cp-quiz-opts-v2 { gap: 14px; }
.cp-quiz-opt-v2 {
  align-items: flex-start; gap: 16px; padding: 16px 18px; min-height: 72px;
}
.cp-quiz-opt-emoji {
  flex-shrink: 0;
  width: 44px; height: 44px;
  display: inline-flex; align-items: center; justify-content: center;
  background: rgba(201,168,106,.10);
  border: 1px solid rgba(201,168,106,.28);
  border-radius: 10px;
  color: #e6c98a;
  transition: all .3s cubic-bezier(.2,.7,.2,1);
}
.cp-quiz-opt-emoji svg {
  width: 28px; height: 28px;
  display: block;
}
.cp-quiz-opt-v2:hover .cp-quiz-opt-emoji {
  background: rgba(201,168,106,.18);
  border-color: rgba(201,168,106,.55);
  color: #f0dfb5;
}
.cp-quiz-opt-text {
  display: flex; flex-direction: column; gap: 4px; line-height: 1.3;
}
.cp-quiz-opt-text b { color: #f4ede0; font-weight: 600; font-size: 15px; }
.cp-quiz-opt-desc {
  color: rgba(244,237,224,.55); font-size: 13px; font-weight: 400;
}
.cp-quiz-back {
  margin-top: 18px;
  background: transparent; border: none;
  color: rgba(244,237,224,.5); font-size: 12px;
  letter-spacing: .15em; text-transform: uppercase; cursor: pointer;
  padding: 6px 0;
  transition: color .25s;
}
.cp-quiz-back:hover { color: #e6c98a; }

/* Result v2 */
.cp-quiz-result-v2 .cp-quiz-profile-head {
  display: flex; align-items: flex-start; gap: 18px;
  padding-bottom: 18px;
  border-bottom: 1px solid rgba(201,168,106,.18);
}
.cp-quiz-profile-emoji {
  flex-shrink: 0;
  display: inline-flex; align-items: center; justify-content: center;
  width: 78px; height: 78px;
  background: linear-gradient(180deg, rgba(230,201,138,.22), rgba(201,168,106,.06));
  border: 1px solid rgba(201,168,106,.45);
  border-radius: 16px;
  box-shadow: 0 6px 22px rgba(201,168,106,.18), inset 0 1px 0 rgba(240,223,181,.18);
  color: #f0dfb5;
}
.cp-quiz-profile-emoji svg {
  width: 48px; height: 48px;
  display: block;
}
.cp-quiz-inline-icon {
  display: inline-flex; align-items: center; gap: 6px;
  vertical-align: middle;
}
.cp-quiz-inline-icon svg {
  width: 20px; height: 20px;
  display: inline-block;
  color: #e6c98a;
}
.cp-quiz-result-v2 .cp-quiz-profile-head h3 {
  font-family: var(--ff-display); font-size: clamp(24px, 3.2vw, 32px);
  margin: 6px 0 4px; line-height: 1.1;
}
.cp-quiz-secondary {
  font-size: 13px; color: rgba(244,237,224,.6);
  margin: 4px 0 0; font-style: italic;
}
.cp-quiz-secondary b { color: #e6c98a; font-style: normal; }
.cp-quiz-profile-desc {
  margin: 18px 0 6px;
  color: rgba(244,237,224,.78);
  font-size: 15px; line-height: 1.65;
}

.cp-quiz-filter-chip {
  display: inline-block;
  margin: 12px 0 4px;
  padding: 6px 14px;
  font-size: 12px;
  letter-spacing: 0.04em;
  background: rgba(109, 191, 163, 0.10);
  border: 1px solid rgba(109, 191, 163, 0.36);
  color: #b8e0cf;
  border-radius: 999px;
}
.cp-quiz-filter-chip b { color: #d4f0e2; font-weight: 600; }

.cp-quiz-reasons {
  margin-top: 14px;
  padding: 14px 16px;
  background: rgba(201, 168, 106, 0.05);
  border-left: 2px solid rgba(201, 168, 106, 0.4);
  border-radius: 0 8px 8px 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.cp-quiz-reason-line {
  margin: 0;
  color: rgba(244, 237, 224, 0.78);
  font-size: 14px;
  line-height: 1.55;
  font-style: italic;
}
.cp-quiz-reason-line:last-child { color: rgba(244, 237, 224, 0.65); }

.cp-quiz-rec-block { margin-top: 22px; }
.cp-quiz-rec-label {
  display: inline-block;
  font-size: 11px; letter-spacing: .25em; text-transform: uppercase;
  color: #c9a86a;
  padding: 4px 10px;
  background: rgba(201,168,106,.10);
  border: 1px solid rgba(201,168,106,.25);
  border-radius: 999px;
  margin-bottom: 10px;
}
.cp-quiz-rec-list {
  list-style: none; padding: 0; margin: 0;
  display: flex; flex-direction: column; gap: 8px;
}
.cp-quiz-rec-item {
  display: flex; align-items: center; gap: 14px;
  padding: 14px 16px;
  background: rgba(244,237,224,.04);
  border: 1px solid rgba(201,168,106,.18);
  border-radius: 12px;
  transition: all .3s cubic-bezier(.2,.7,.2,1);
}
.cp-quiz-rec-item:hover {
  background: rgba(201,168,106,.08);
  border-color: rgba(201,168,106,.4);
  transform: translateX(3px);
}
.cp-quiz-rec-text {
  display: flex; flex-direction: column; gap: 4px;
  flex: 1; min-width: 0;
}
.cp-quiz-rec-text b {
  color: #f4ede0; font-weight: 600; font-size: 14.5px;
}
.cp-quiz-rec-text span {
  color: rgba(244,237,224,.6); font-size: 13px; line-height: 1.45;
}
.cp-quiz-rec-price {
  flex-shrink: 0;
  font-family: var(--ff-display); font-weight: 600;
  font-size: 17px; color: #e6c98a;
  padding-left: 12px;
  border-left: 1px solid rgba(201,168,106,.22);
  align-self: stretch;
  display: flex; align-items: center;
}

/* ========== 2. SpinWheel ========== */
.cp-wheel-card {
  max-width: 540px; margin: 0 auto; text-align: center;
  padding: clamp(24px, 5vw, 48px);
  background: linear-gradient(180deg, rgba(20,59,48,.85), rgba(12,38,32,.95));
  border-radius: 18px;
  border: 1px solid rgba(201,168,106,.32);
  box-shadow: 0 20px 60px rgba(0,0,0,.32);
}
.cp-wheel-title {
  font-family: var(--ff-display); font-weight: 500;
  font-size: clamp(28px, 4vw, 40px); color: #f4ede0; margin-top: 14px;
}
.cp-wheel-sub { color: rgba(244,237,224,.65); font-size: 14px; margin-top: 8px; }

.cp-wheel-stage {
  position: relative; margin: 28px auto 8px;
  width: min(100%, 360px); aspect-ratio: 1; padding: 18px 18px 0;
}
.cp-wheel-svg { width: 100%; height: 100%; display: block;
  filter: drop-shadow(0 12px 30px rgba(0,0,0,.45));
}
.cp-wheel-pointer {
  position: absolute; top: -4px; left: 50%;
  transform: translateX(-50%);
  color: #e6c98a; font-size: 26px; line-height: 1;
  text-shadow: 0 2px 6px rgba(0,0,0,.55);
  z-index: 3;
}
.cp-wheel-btn {
  position: absolute; left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  width: 64px; height: 64px; border-radius: 50%;
  background: linear-gradient(180deg, #e6c98a, #c9a86a);
  color: #0c2620;
  border: 2px solid #0c2620;
  font-weight: 700; font-size: 11px; letter-spacing: .15em; text-transform: uppercase;
  cursor: pointer;
  box-shadow: 0 6px 18px rgba(0,0,0,.35), inset 0 1px 0 rgba(255,255,255,.4);
  transition: transform .25s, box-shadow .25s;
  z-index: 2;
}
.cp-wheel-btn:not(:disabled):hover {
  animation: cp-pulse-gold 1.6s ease-in-out infinite;
}
.cp-wheel-btn:disabled { cursor: default; opacity: .92; }
.cp-wheel-btn.spinning { animation: cp-pulse-gold 1.4s ease-in-out infinite; }
@keyframes cp-pulse-gold {
  0%, 100% { box-shadow: 0 6px 18px rgba(0,0,0,.35), inset 0 1px 0 rgba(255,255,255,.4), 0 0 0 0 rgba(230,201,138,.5); }
  50%      { box-shadow: 0 6px 18px rgba(0,0,0,.35), inset 0 1px 0 rgba(255,255,255,.4), 0 0 0 14px rgba(230,201,138,0); }
}

.cp-wheel-winner {
  margin-top: 24px; padding: 22px;
  background: rgba(201,168,106,.08);
  border-radius: 12px;
  border: 1px solid rgba(201,168,106,.32);
  animation: cp-fade-up .6s cubic-bezier(.2,.7,.2,1) both;
}
.cp-wheel-prize-name {
  font-family: var(--ff-display); font-size: 24px; color: #f4ede0;
}
.cp-wheel-code-label {
  display: block; margin-top: 12px;
  font-size: 11px; letter-spacing: .25em; text-transform: uppercase;
  color: rgba(201,168,106,.85);
}
.cp-wheel-code {
  display: inline-block; margin-top: 6px;
  font-family: "Courier New", monospace;
  font-size: 22px; letter-spacing: .25em; font-weight: 700;
  color: #e6c98a;
  padding: 10px 18px; border: 1px dashed rgba(201,168,106,.55);
  border-radius: 8px;
  background: rgba(12,38,32,.6);
}
.cp-wheel-comeback {
  margin-top: 14px; font-size: 13px; color: rgba(244,237,224,.55);
}

/* ========== 3. LoyaltyTracker ========== */
.cp-loyalty-card {
  max-width: 680px; margin: 0 auto; text-align: center;
  padding: clamp(28px, 5vw, 52px);
  background: linear-gradient(180deg, rgba(20,59,48,.85), rgba(12,38,32,.95));
  border-radius: 18px;
  border: 1px solid rgba(201,168,106,.32);
  box-shadow: 0 20px 60px rgba(0,0,0,.32);
}
.cp-loyalty-title {
  font-family: var(--ff-display); font-weight: 500;
  font-size: clamp(26px, 3.6vw, 36px); color: #f4ede0; margin-top: 14px;
}
.cp-loyalty-sub { color: rgba(244,237,224,.65); font-size: 14px; margin-top: 8px; }

.cp-loyalty-stamps {
  display: flex; gap: clamp(10px, 2vw, 22px); justify-content: center;
  margin: 36px 0;
}
.cp-stamp {
  width: clamp(48px, 11vw, 70px); height: clamp(48px, 11vw, 70px);
  position: relative; transition: transform .35s cubic-bezier(.2,.7,.2,1);
}
.cp-stamp .cp-stamp-ring {
  fill: rgba(244,237,224,.04);
  stroke: rgba(201,168,106,.4);
  stroke-width: 1.5;
  stroke-dasharray: 2 3;
  transition: all .35s;
}
.cp-stamp .cp-stamp-num {
  font-family: var(--ff-display); font-size: 22px; font-weight: 500;
  fill: rgba(244,237,224,.35);
  transition: fill .35s;
}
.cp-stamp.filled .cp-stamp-ring {
  fill: rgba(201,168,106,.18);
  stroke: #c9a86a; stroke-dasharray: none;
  filter: drop-shadow(0 0 8px rgba(230,201,138,.35));
}
.cp-stamp.filled .cp-stamp-num { fill: #e6c98a; }
.cp-stamp.just-filled { animation: cp-stamp-pop .55s cubic-bezier(.34,1.56,.64,1); }
@keyframes cp-stamp-pop {
  0%   { transform: scale(.6); }
  50%  { transform: scale(1.18); }
  100% { transform: scale(1); }
}

.cp-loyalty-actions { display: flex; flex-direction: column; align-items: center; gap: 10px; }
.cp-loyalty-note { font-size: 12px; color: rgba(201,168,106,.7); font-style: italic; }

.cp-loyalty-form {
  display: flex; flex-direction: column; align-items: center;
  gap: 12px; margin-top: 18px;
}
.cp-loyalty-input-wrap {
  display: flex; gap: 8px;
  width: 100%; max-width: 380px;
}
.cp-loyalty-input {
  flex: 1;
  background: rgba(0,0,0,.3);
  border: 1px solid rgba(201,168,106,.35);
  color: #f4ede0;
  padding: 14px 18px;
  border-radius: 999px;
  font-family: 'Inter', sans-serif;
  font-size: 18px;
  letter-spacing: 0.4em;
  text-align: center;
  text-transform: uppercase;
  font-weight: 600;
  transition: border-color .25s, background .25s;
}
.cp-loyalty-input:focus {
  outline: none;
  border-color: #c9a86a;
  background: rgba(0,0,0,.45);
}
.cp-loyalty-input:disabled { opacity: 0.5; cursor: not-allowed; }
.cp-loyalty-input::placeholder { color: rgba(244,237,224,.35); letter-spacing: 0.2em; font-weight: 400; }
.cp-loyalty-input-wrap .cp-btn-gold {
  border-radius: 999px;
  padding: 12px 24px;
  white-space: nowrap;
}
.cp-loyalty-input-wrap .cp-btn-gold:disabled { opacity: 0.5; cursor: not-allowed; transform: none; }
.cp-loyalty-helper {
  font-size: 12px;
  color: rgba(244,237,224,.6);
  margin-top: 6px;
  text-align: center;
  max-width: 460px;
  line-height: 1.5;
}
.cp-loyalty-ok  { color: #88dcc1; font-style: normal; font-weight: 600; }
.cp-loyalty-err { color: #f0a988; font-style: normal; font-weight: 600; }

.cp-loyalty-reward { animation: cp-fade-up .6s cubic-bezier(.2,.7,.2,1) both; }
.cp-loyalty-reward h3 { font-family: var(--ff-display); font-size: 28px; margin: 14px 0 8px; }
.cp-loyalty-reward p { color: rgba(244,237,224,.78); }

.cp-wax-seal {
  position: relative; width: 96px; height: 96px; margin: 0 auto 18px;
  border-radius: 50%;
  background: radial-gradient(circle at 35% 35%, #e6c98a, #c9a86a 50%, #8a6c3e 100%);
  box-shadow: 0 14px 30px rgba(0,0,0,.4), inset 0 -3px 8px rgba(0,0,0,.3);
  animation: cp-seal-break .9s cubic-bezier(.34,1.56,.64,1) both;
}
.cp-wax-seal-broken {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  font-family: var(--ff-display); font-size: 36px; color: #0c2620;
  text-shadow: 0 1px 0 rgba(255,255,255,.3);
}
.cp-wax-ribbon {
  position: absolute; left: 50%; bottom: -22px;
  width: 4px; height: 38px;
  background: linear-gradient(180deg, #e6c98a, #c9a86a);
  transform: translateX(-50%);
  border-radius: 2px;
  animation: cp-ribbon-grow .6s .5s cubic-bezier(.2,.7,.2,1) both;
  box-shadow: 0 4px 12px rgba(201,168,106,.3);
}
@keyframes cp-seal-break {
  0%   { transform: scale(.4) rotate(-25deg); opacity: 0; }
  100% { transform: scale(1)   rotate(0);     opacity: 1; }
}
@keyframes cp-ribbon-grow {
  0%   { transform: translateX(-50%) scaleY(0); transform-origin: top; }
  100% { transform: translateX(-50%) scaleY(1); }
}

.cp-loyalty-code-wrap {
  display: inline-flex; flex-direction: column; gap: 6px;
  margin-top: 18px;
}
.cp-loyalty-code-label {
  font-size: 11px; letter-spacing: .25em; text-transform: uppercase;
  color: rgba(201,168,106,.85);
}
.cp-loyalty-code {
  font-family: "Courier New", monospace;
  font-size: 22px; letter-spacing: .25em; font-weight: 700;
  color: #e6c98a;
  padding: 10px 18px; border: 1px dashed rgba(201,168,106,.55);
  border-radius: 8px;
  background: rgba(12,38,32,.6);
}

/* ========== 4. EasterEggHunt ========== */
.cp-egg {
  position: absolute;
  width: 28px; height: 28px;
  background: transparent; border: none;
  color: #c9a86a;
  font-size: 18px; line-height: 1;
  cursor: pointer;
  z-index: 50;
  opacity: .35;
  filter: drop-shadow(0 0 4px rgba(230,201,138,.45));
  transition: transform .3s, opacity .3s;
  animation: cp-egg-pulse 3.6s ease-in-out infinite;
}
.cp-egg:hover { opacity: 1; transform: scale(1.4); }
.cp-egg.found {
  color: #e6c98a; opacity: 1;
  animation: none;
  filter: drop-shadow(0 0 10px rgba(230,201,138,.95));
}
@keyframes cp-egg-pulse {
  0%, 100% { opacity: .25; }
  50%      { opacity: .55; }
}
.cp-egg-burst::after {
  content: ""; position: absolute; inset: -10px;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(230,201,138,.7), transparent 60%);
  animation: cp-egg-spark .6s ease-out forwards;
  pointer-events: none;
}
@keyframes cp-egg-spark {
  0%   { transform: scale(.4); opacity: 1; }
  100% { transform: scale(2.4); opacity: 0; }
}

.cp-egg-counter {
  position: fixed; bottom: 20px; left: 70px;
  z-index: 80;
  background: rgba(12,38,32,.85);
  backdrop-filter: blur(8px);
  border: 1px solid rgba(201,168,106,.4);
  color: #e6c98a;
  padding: 8px 14px; border-radius: 999px;
  font-size: 12px; letter-spacing: .15em; font-weight: 600;
  display: inline-flex; align-items: center; gap: 10px;
}
@media (max-width: 600px) {
  .cp-egg-counter { bottom: 14px; left: 64px; padding: 6px 12px; font-size: 11px; }
}
.cp-egg-reopen {
  background: transparent; border: none; cursor: pointer;
  color: #c9a86a; font-size: 11px; text-transform: uppercase; letter-spacing: .15em;
  text-decoration: underline; padding: 0;
}

.cp-egg-modal-backdrop {
  position: fixed; inset: 0; z-index: 9000;
  background: rgba(20,59,48,.85);
  backdrop-filter: blur(6px);
  display: flex; align-items: center; justify-content: center; padding: 20px;
  animation: cp-fade-in .35s ease both;
}
.cp-egg-modal {
  position: relative;
  max-width: 520px; width: 100%;
  background: linear-gradient(180deg, #143b30, #0c2620);
  border: 1px solid rgba(201,168,106,.4);
  border-radius: 18px;
  padding: 36px 32px;
  box-shadow: 0 30px 80px rgba(0,0,0,.6);
  animation: cp-modal-in .45s cubic-bezier(.34,1.56,.64,1) both;
}
.cp-modal-close {
  position: absolute; top: 14px; right: 14px;
  background: transparent; border: none; cursor: pointer;
  color: rgba(244,237,224,.6); font-size: 18px; padding: 6px 10px;
  border-radius: 50%;
}
.cp-modal-close:hover { color: #e6c98a; background: rgba(244,237,224,.06); }
.cp-egg-modal-title { font-family: var(--ff-display); font-size: 28px; margin: 14px 0 6px; }
.cp-egg-modal-sub { font-size: 12px; letter-spacing: .15em; text-transform: uppercase; color: rgba(201,168,106,.85); margin-bottom: 14px; }
.cp-egg-modal-desc { color: rgba(244,237,224,.78); line-height: 1.65; }
.cp-egg-modal-actions { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 22px; }
@keyframes cp-fade-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes cp-modal-in {
  from { opacity: 0; transform: scale(.9) translateY(20px); }
  to   { opacity: 1; transform: scale(1) translateY(0); }
}

/* ========== 5. StatsCounter ========== */
.cp-stats-section { padding: clamp(48px, 6vw, 84px) 0; background: var(--jade-deep, #143b30); }
.cp-stats-grid {
  display: grid; gap: 26px;
  grid-template-columns: repeat(2, 1fr);
}
@media (min-width: 720px) { .cp-stats-grid { grid-template-columns: repeat(4, 1fr); } }
.cp-stat { text-align: center; padding: 12px; }
.cp-stat-num {
  font-family: var(--ff-display); font-weight: 500;
  font-size: clamp(40px, 6vw, 64px); line-height: 1;
  color: #e6c98a;
  display: inline-flex; align-items: baseline; gap: 4px;
}
.cp-stat-prefix, .cp-stat-suffix { font-size: 0.7em; }
.cp-stat-suffix { color: #c9a86a; margin-left: 4px; }
.cp-stat-label {
  margin-top: 12px;
  font-size: 12px; letter-spacing: .2em; text-transform: uppercase;
  color: rgba(244,237,224,.6);
}

/* ========== 6. FloatingReserveCTA ========== */
.cp-floating-reserve {
  position: fixed; right: 24px; bottom: 24px;
  z-index: 70;
  background: linear-gradient(180deg, #e6c98a, #c9a86a);
  color: #0c2620;
  border: none;
  padding: 16px 26px;
  border-radius: 999px;
  font-family: "Inter", sans-serif;
  font-size: 13px; letter-spacing: .18em; text-transform: uppercase; font-weight: 700;
  cursor: pointer;
  box-shadow: 0 14px 40px rgba(0,0,0,.45), 0 4px 14px rgba(201,168,106,.35);
  display: inline-flex; align-items: center; gap: 12px;
  opacity: 0; pointer-events: none;
  transform: translateY(80px) scale(.9);
  transition: opacity .45s cubic-bezier(.34,1.56,.64,1),
              transform .45s cubic-bezier(.34,1.56,.64,1);
}
.cp-floating-reserve.visible {
  opacity: 1; pointer-events: auto;
  transform: translateY(0) scale(1);
}
.cp-floating-reserve:hover { transform: translateY(-3px) scale(1.04); }
.cp-floating-arrow { transition: transform .3s; }
.cp-floating-reserve:hover .cp-floating-arrow { transform: translateX(4px); }

@media (max-width: 600px) {
  .cp-floating-reserve {
    right: 12px; left: 12px; bottom: 12px;
    justify-content: center;
    padding: 16px 22px;
    font-size: 12px;
  }
}
/* When the floating reserve appears, lift the egg counter + speaker above it */
.cp-floating-reserve.visible ~ .cp-egg-counter,
.cp-floating-reserve.visible ~ .cp-ambient-toggle {
  /* siblings — but they're not actual siblings; rely on JS-set body class fallback */
}
@media (max-width: 600px) {
  body.cp-cta-up .cp-egg-counter   { bottom: 78px !important; }
  body.cp-cta-up .cp-ambient-toggle { bottom: 78px !important; }
}

/* ========== 7. AmbientToggle ========== */
.cp-ambient-toggle {
  position: fixed; top: 18px; right: 18px;
  z-index: 9100;
  width: 40px; height: 40px;
  background: rgba(12,38,32,.7);
  backdrop-filter: blur(8px);
  border: 1px solid rgba(201,168,106,.32);
  color: #c9a86a;
  border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  cursor: pointer;
  transition: all .3s cubic-bezier(.2,.7,.2,1);
}
.cp-ambient-toggle:hover { color: #e6c98a; border-color: rgba(201,168,106,.6); transform: scale(1.08); }
.cp-ambient-toggle.on {
  color: #e6c98a;
  box-shadow: 0 0 0 0 rgba(230,201,138,.5);
  animation: cp-amb-pulse 2.4s ease-in-out infinite;
}
@keyframes cp-amb-pulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(230,201,138,.4); }
  50%      { box-shadow: 0 0 0 8px rgba(230,201,138,0); }
}

/* On small screens move the speaker to bottom-left to avoid the burger menu */
@media (max-width: 1080px) {
  .cp-ambient-toggle { top: auto; bottom: 18px; left: 18px; right: auto; width: 36px; height: 36px; }
}

/* ========== 8. PhotoLightbox ========== */
.cp-lightbox {
  position: fixed; inset: 0; z-index: 9500;
  background: rgba(20,59,48,.92);
  backdrop-filter: blur(8px);
  display: flex; align-items: center; justify-content: center;
  animation: cp-fade-in .25s ease both;
  padding: 80px 20px 140px;
}
.cp-lightbox-figure {
  position: relative;
  max-width: min(1200px, 100%);
  max-height: 100%;
  display: flex; flex-direction: column; align-items: center;
}
.cp-lightbox-img {
  max-width: 100%;
  max-height: 70vh;
  border-radius: 8px;
  box-shadow: 0 30px 80px rgba(0,0,0,.55);
  animation: cp-lightbox-zoom .4s cubic-bezier(.2,.7,.2,1) both;
  object-fit: contain;
}
@keyframes cp-lightbox-zoom {
  from { opacity: 0; transform: scale(.96); }
  to   { opacity: 1; transform: scale(1); }
}
.cp-lightbox-cap {
  margin-top: 14px;
  color: rgba(244,237,224,.85);
  font-family: var(--ff-display); font-size: 18px; font-style: italic;
  text-align: center;
  max-width: 720px;
}
.cp-lightbox-credit { color: rgba(201,168,106,.75); font-size: 13px; font-style: normal; }

.cp-lightbox-close {
  position: absolute; top: 18px; right: 18px;
  background: rgba(12,38,32,.7);
  border: 1px solid rgba(201,168,106,.4);
  color: #e6c98a;
  width: 40px; height: 40px; border-radius: 50%;
  font-size: 18px; cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
}
.cp-lightbox-close:hover { background: rgba(201,168,106,.18); }

.cp-lightbox-arrow {
  position: absolute; top: 50%; transform: translateY(-50%);
  width: 52px; height: 52px;
  background: rgba(12,38,32,.7);
  border: 1px solid rgba(201,168,106,.4);
  color: #e6c98a;
  font-size: 30px; line-height: 1;
  border-radius: 50%;
  cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  transition: background .25s;
}
.cp-lightbox-arrow:hover { background: rgba(201,168,106,.18); }
.cp-lightbox-arrow.prev { left: 18px; }
.cp-lightbox-arrow.next { right: 18px; }

.cp-lightbox-thumbs {
  position: absolute; left: 0; right: 0; bottom: 18px;
  display: flex; gap: 8px; justify-content: center; overflow-x: auto;
  padding: 0 18px;
  scrollbar-width: thin;
}
.cp-lightbox-thumb {
  flex-shrink: 0;
  width: 64px; height: 48px;
  border-radius: 4px; overflow: hidden;
  border: 1px solid rgba(201,168,106,.25);
  background: transparent; cursor: pointer; padding: 0;
  opacity: .55; transition: all .25s;
}
.cp-lightbox-thumb img { width: 100%; height: 100%; object-fit: cover; }
.cp-lightbox-thumb:hover { opacity: 1; }
.cp-lightbox-thumb.active { opacity: 1; border-color: #e6c98a; box-shadow: 0 4px 14px rgba(201,168,106,.4); }

.cp-lightbox-count {
  position: absolute; top: 24px; left: 24px;
  font-family: "Courier New", monospace;
  color: rgba(244,237,224,.65);
  font-size: 12px; letter-spacing: .2em;
}

@media (max-width: 600px) {
  .cp-lightbox { padding: 60px 8px 110px; }
  .cp-lightbox-arrow { width: 42px; height: 42px; font-size: 24px; }
  .cp-lightbox-arrow.prev { left: 6px; }
  .cp-lightbox-arrow.next { right: 6px; }
  .cp-lightbox-thumb { width: 50px; height: 38px; }
}

/* ========== shared keyframes ========== */
@keyframes cp-fade-up {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* Reduced-motion override */
@media (prefers-reduced-motion: reduce) {
  .cp-egg, .cp-ambient-toggle.on, .cp-wheel-btn:hover, .cp-wheel-btn.spinning {
    animation: none !important;
  }
  .cp-quiz-q, .cp-quiz-result, .cp-wheel-winner, .cp-loyalty-reward,
  .cp-egg-modal-backdrop, .cp-egg-modal, .cp-lightbox-img {
    animation: none !important;
  }
}
`;
  document.head.appendChild(s);
}

// =====================================================================
// Register
// =====================================================================
window.CP_GAME = {
  DishQuiz, SpinWheel, LoyaltyTracker, EasterEggHunt, StatsCounter,
  FloatingReserveCTA, AmbientToggle, PhotoLightbox
};
