// theme.jsx — design tokens, sensation taxonomy, shared atoms, audio + persistence
// Aesthetic: dark navy field, holographic teal "energy body". Calm-but-cinematic.

const MT_COLORS = {
  bg:       '#04090f',
  bg2:      '#071420',
  veil:     'rgba(4,9,15,0.72)',
  ink:      '#EAF7F4',
  inkDim:   'rgba(206,233,230,0.66)',
  inkFaint: 'rgba(206,233,230,0.36)',
  inkGhost: 'rgba(206,233,230,0.16)',
  teal:     '#36E8D2',
  tealSoft: 'rgba(54,232,210,0.14)',
  tealLine: 'rgba(54,232,210,0.26)',
  blue:     '#56B4FF',
  panel:    'rgba(15,38,46,0.55)',
  panelHi:  'rgba(22,52,62,0.78)',
  stroke:   'rgba(120,210,205,0.16)',
};

// tradition / practice-phase colors — each lineage & phase reads distinctly
const MT_TRAD = {
  vipassana: { hue: '#36E8D2', label: 'Vipassanā', soft: 'rgba(54,232,210,0.12)' },
  anapana:   { hue: '#56B4FF', label: 'Ānāpāna',   soft: 'rgba(86,180,255,0.12)' },
  metta:     { hue: '#FF9EC4', label: 'Mettā',     soft: 'rgba(255,158,196,0.12)' },
  noting:    { hue: '#B49CFF', label: 'Noting',    soft: 'rgba(180,156,255,0.12)' },
  bhakti:    { hue: '#FFB24D', label: 'Bhakti',    soft: 'rgba(255,178,77,0.12)' },
};

// the three high-level paths
const MT_PATHS = {
  insight: { label: 'Insight', hue: '#36E8D2', sub: 'Vipassanā · observe & purify',
    blurb: 'Watch sensations objectively. Impurities dissolve through equanimous self-observation.' },
  bhakti:  { label: 'Bhakti', hue: '#FFB24D', sub: 'Naam · devotion & surrender',
    blurb: 'Fill the mind with the divine Name. The ego is pushed out as the heart fills with God.' },
  hybrid:  { label: 'Hybrid', hue: '#C9A0FF', sub: 'Naam-scan · the Name in every cell',
    blurb: 'Sweep the body like Vipassanā — but place the Name on each part, filling every cell with naama.' },
  relax:   { label: 'Relax', hue: '#7CC4FF', sub: '61-point · Himalayan yoga nidra',
    blurb: 'Attention travels through 61 fixed points across the body — Swami Rama\u2019s practice. Lie down, follow each point, and let it soften.' },
};

// devotional Names (naam) for Bhakti & Hybrid
const MT_DEITIES = {
  vitthala: { label: 'Vitthala', chant: 'Vitthala', phrase: 'Vitthala… Vitthala…', hue: '#FFB24D', tradition: 'Varkari · Tukaram' },
  radha:    { label: 'Radha',    chant: 'Radhe',    phrase: 'Radhe… Radhe…',       hue: '#FF9EC4', tradition: 'Bhakti · Krishna' },
  ram:      { label: 'Ram',      chant: 'Ram',      phrase: 'Ram… Ram…',           hue: '#FFD27C', tradition: 'Naam · Tulsidas' },
  om:       { label: 'Om',       chant: 'Om',       phrase: 'Om… Om…',             hue: '#9CD6FF', tradition: 'Pranava · the primordial' },
};

// The somatic vocabulary — Goenka/Dipa Ma sensation qualities + a pleasant one (equanimity).
const MT_SENSATIONS = [
  { id: 'tingling', label: 'Tingling',  hue: '#3CE6FF', note: 'subtle vibration' },
  { id: 'heat',     label: 'Heat',      hue: '#FFB24D', note: 'warmth, burning' },
  { id: 'tension',  label: 'Tension',   hue: '#FF5C7A', note: 'tightness, grip' },
  { id: 'pressure', label: 'Pressure',  hue: '#A98CFF', note: 'heaviness, weight' },
  { id: 'pulsing',  label: 'Pulsing',   hue: '#4FE6A0', note: 'throbbing, beat' },
  { id: 'tremor',   label: 'Tremor',    hue: '#5BA8FF', note: 'flutter, energy' },
  { id: 'numb',     label: 'Numbness',  hue: '#8FA6C0', note: 'dullness, blank' },
  { id: 'ease',     label: 'Ease',      hue: '#7CF0DC', note: 'open, flowing' },
];
const MT_SENS_MAP = Object.fromEntries(MT_SENSATIONS.map(s => [s.id, s]));

// Emotional tone — the "body keeps the score" bridge from sensation to feeling.
const MT_EMOTIONS = ['Calm', 'Restless', 'Fear', 'Grief', 'Anger', 'Joy', 'Heavy', 'Bright'];

const MT_INTENSITY = ['subtle', 'clear', 'strong']; // 0,1,2

// Region display names
const MT_REGION_LABEL = {
  head: 'Crown & face', throat: 'Throat', chest: 'Chest / heart', abdomen: 'Solar plexus',
  pelvis: 'Belly & hips', armL: 'Left arm', armR: 'Right arm', forearmL: 'Left forearm',
  forearmR: 'Right forearm', handL: 'Left hand', handR: 'Right hand',
  thighL: 'Left thigh', thighR: 'Right thigh', calfL: 'Left calf', calfR: 'Right calf',
  footL: 'Left foot', footR: 'Right foot',
};

// ── tiny icon set (simple strokes only) ───────────────────────────
function MTIcon({ name, size = 22, color = 'currentColor', sw = 1.7 }) {
  const p = { fill: 'none', stroke: color, strokeWidth: sw, strokeLinecap: 'round', strokeLinejoin: 'round' };
  const paths = {
    play:  <path d="M7 5l12 7-12 7z" fill={color} stroke="none" />,
    pause: <g {...p}><line x1="8" y1="5" x2="8" y2="19"/><line x1="16" y1="5" x2="16" y2="19"/></g>,
    plus:  <g {...p}><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></g>,
    check: <polyline {...p} points="4,12 10,18 20,6"/>,
    close: <g {...p}><line x1="6" y1="6" x2="18" y2="18"/><line x1="18" y1="6" x2="6" y2="18"/></g>,
    chevR: <polyline {...p} points="9,5 16,12 9,19"/>,
    chevL: <polyline {...p} points="15,5 8,12 15,19"/>,
    sound: <g {...p}><path d="M4 9v6h4l5 4V5L8 9z"/><path d="M16 9a4 4 0 010 6"/><path d="M18.5 6.5a8 8 0 010 11"/></g>,
    mute:  <g {...p}><path d="M4 9v6h4l5 4V5L8 9z"/><line x1="22" y1="9" x2="16" y2="15"/><line x1="16" y1="9" x2="22" y2="15"/></g>,
    today: <g {...p}><rect x="4" y="5" width="16" height="16" rx="3"/><line x1="4" y1="9.5" x2="20" y2="9.5"/><line x1="8" y1="3" x2="8" y2="6"/><line x1="16" y1="3" x2="16" y2="6"/></g>,
    atlas: <g {...p}><circle cx="12" cy="6.5" r="2.6"/><path d="M12 9.3v5M7 13c2 1.5 8 1.5 10 0M8.5 21l3.5-6 3.5 6"/></g>,
    book:  <g {...p}><path d="M5 5.5A2 2 0 017 4h11v15H7a2 2 0 00-2 1.5z"/><line x1="9" y1="8" x2="15" y2="8"/><line x1="9" y1="11.5" x2="14" y2="11.5"/></g>,
    flame: <path {...p} d="M12 3c1 3 4 4 4 8a4 4 0 01-8 0c0-1.5.8-2.5 1.5-3 .2 1 .8 1.5 1.3 1.7C10.5 8 10 6 12 3z"/>,
    timer: <g {...p}><circle cx="12" cy="13" r="8"/><line x1="12" y1="13" x2="12" y2="8.5"/><line x1="9.5" y1="2.5" x2="14.5" y2="2.5"/></g>,
    spark: <g {...p}><path d="M12 4v4M12 16v4M4 12h4M16 12h4"/><path d="M6.5 6.5l2.5 2.5M15 15l2.5 2.5M17.5 6.5L15 9M9 15l-2.5 2.5"/></g>,
    arc:   <path {...p} d="M5 16a7 7 0 0114 0"/>,
    leaf:  <path {...p} d="M5 19c0-8 6-13 14-14C18 12 13 18 5 19zM5 19c3-4 6-6 9-7"/>,
    eye:   <g {...p}><path d="M2.5 12S6 5.5 12 5.5 21.5 12 21.5 12 18 18.5 12 18.5 2.5 12 2.5 12z"/><circle cx="12" cy="12" r="3"/></g>,
    quotes:<g {...p}><path d="M9 7c-2.5 1-4 3.2-4 6 0 1.7 1.1 3 2.6 3S10 14.8 10 13.3 9 11 7.7 11c-.4 0-.8.1-1 .2C6.9 9.6 7.9 8.3 9.5 7.6zM18 7c-2.5 1-4 3.2-4 6 0 1.7 1.1 3 2.6 3S19 14.8 19 13.3 18 11 16.7 11c-.4 0-.8.1-1 .2.2-1.6 1.2-2.9 2.8-3.6z"/></g>,
    lotus: <g {...p}><path d="M12 4c-1.6 1.8-2.4 3.8-2.4 5.8 0 1 .2 2 .8 3M12 4c1.6 1.8 2.4 3.8 2.4 5.8 0 1-.2 2-.8 3"/><path d="M5.5 9.5c-.4 2.2.3 4 1.8 5.4.8.8 1.8 1.3 2.9 1.6M18.5 9.5c.4 2.2-.3 4-1.8 5.4-.8.8-1.8 1.3-2.9 1.6"/><path d="M3 14c.4 2.4 2.2 4 4.6 4.6 1.5.4 3 .4 4.4.4s2.9 0 4.4-.4C18.8 18 20.6 16.4 21 14"/></g>,
    person:<g {...p}><circle cx="12" cy="6" r="2.4"/><path d="M12 9c-2 0-3.4 1.4-3.8 3.4M12 9c2 0 3.4 1.4 3.8 3.4M5 18c1-3 3.8-4.4 7-4.4S18 15 19 18M5 18h14"/></g>,
    tray:  <g {...p}><path d="M4 13l2.2-7a2 2 0 011.9-1.4h7.8a2 2 0 011.9 1.4L20 13"/><path d="M4 13v5a2 2 0 002 2h12a2 2 0 002-2v-5M4 13h4l1.5 2.5h5L16 13h4"/></g>,
    gear:  <g {...p}><circle cx="12" cy="12" r="3.2"/><path d="M12 3.5v2.2M12 18.3v2.2M3.5 12h2.2M18.3 12h2.2M5.8 5.8l1.6 1.6M16.6 16.6l1.6 1.6M18.2 5.8l-1.6 1.6M7.4 16.6l-1.6 1.6"/></g>,
  };
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" style={{ display: 'block', flexShrink: 0 }}>
      {paths[name] || null}
    </svg>
  );
}

// ── shared atoms ──────────────────────────────────────────────────
function MTPanel({ children, style = {}, hi = false, onClick, pressable }) {
  const [press, setPress] = React.useState(false);
  return (
    <div
      onClick={onClick}
      onPointerDown={pressable ? () => setPress(true) : undefined}
      onPointerUp={pressable ? () => setPress(false) : undefined}
      onPointerLeave={pressable ? () => setPress(false) : undefined}
      style={{
        background: hi ? MT_COLORS.panelHi : MT_COLORS.panel,
        border: `0.75px solid ${MT_COLORS.stroke}`,
        borderRadius: 22,
        backdropFilter: 'blur(14px)', WebkitBackdropFilter: 'blur(14px)',
        boxShadow: 'inset 0 1px 0 rgba(255,255,255,0.04)',
        transition: 'transform .18s ease, background .2s ease',
        transform: press ? 'scale(0.98)' : 'scale(1)',
        cursor: onClick ? 'pointer' : 'default',
        ...style,
      }}>
      {children}
    </div>
  );
}

function MTChip({ label, active, color, onClick, sub }) {
  const c = color || MT_COLORS.teal;
  return (
    <button onClick={onClick} style={{
      appearance: 'none', cursor: 'pointer', font: 'inherit',
      display: 'flex', alignItems: 'center', gap: 8,
      padding: sub ? '9px 13px' : '10px 15px', borderRadius: 999,
      background: active ? `${c}22` : 'rgba(255,255,255,0.025)',
      border: `1px solid ${active ? c : MT_COLORS.inkGhost}`,
      color: active ? MT_COLORS.ink : MT_COLORS.inkDim,
      transition: 'all .16s ease', whiteSpace: 'nowrap',
    }}>
      {color && <span style={{
        width: 9, height: 9, borderRadius: 9, background: c,
        boxShadow: active ? `0 0 10px ${c}` : 'none', flexShrink: 0,
      }} />}
      <span style={{ fontSize: 14, fontWeight: active ? 600 : 500, letterSpacing: 0.1 }}>{label}</span>
    </button>
  );
}

// Primary glowing CTA
function MTButton({ children, onClick, full, tone = 'teal', size = 'md', style = {} }) {
  const [press, setPress] = React.useState(false);
  const c = tone === 'teal' ? MT_COLORS.teal : tone === 'ghost' ? 'transparent' : tone;
  const ghost = tone === 'ghost';
  const pads = { sm: '11px 18px', md: '15px 22px', lg: '18px 26px' };
  return (
    <button
      onClick={onClick}
      onPointerDown={() => setPress(true)} onPointerUp={() => setPress(false)} onPointerLeave={() => setPress(false)}
      style={{
        appearance: 'none', font: 'inherit', cursor: 'pointer',
        width: full ? '100%' : 'auto', padding: pads[size],
        borderRadius: 999, position: 'relative',
        border: ghost ? `1px solid ${MT_COLORS.tealLine}` : 'none',
        background: ghost ? 'rgba(54,232,210,0.05)'
          : `linear-gradient(180deg, ${MT_COLORS.teal}, #1FBFAC)`,
        color: ghost ? MT_COLORS.teal : '#022019',
        fontSize: size === 'lg' ? 18 : 16, fontWeight: 650, letterSpacing: 0.2,
        boxShadow: ghost ? 'none'
          : `0 0 28px rgba(54,232,210,${press ? 0.25 : 0.42}), inset 0 1px 0 rgba(255,255,255,0.5)`,
        transform: press ? 'scale(0.975)' : 'scale(1)',
        transition: 'transform .14s ease, box-shadow .2s ease',
        display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 9,
        ...style,
      }}>
      {children}
    </button>
  );
}

// section eyebrow label (mono)
function MTEyebrow({ children, color }) {
  return <div style={{
    fontFamily: 'var(--mono)', fontSize: 11, letterSpacing: 2.5,
    textTransform: 'uppercase', color: color || MT_COLORS.inkFaint,
  }}>{children}</div>;
}

// ── persistence ───────────────────────────────────────────────────
const MT_KEY = 'mt_sessions_v1';
function mtLoadSessions() {
  try {
    const raw = localStorage.getItem(MT_KEY);
    // normalize: imported/legacy entries may lack markers
    if (raw) return JSON.parse(raw).map(s => ({ ...s, markers: s.markers || [] }));
  } catch (e) {}
  return [];
}
function mtSaveSessions(arr) {
  try { localStorage.setItem(MT_KEY, JSON.stringify(arr)); } catch (e) {}
}

// ── ambient audio engine (Web Audio, generated) ───────────────────
function useAmbient() {
  const ref = React.useRef(null);
  const ensure = React.useCallback(() => {
    if (ref.current) return ref.current;
    const AC = window.AudioContext || window.webkitAudioContext;
    if (!AC) return null;
    const ctx = new AC();
    const master = ctx.createGain(); master.gain.value = 0; master.connect(ctx.destination);
    const lp = ctx.createBiquadFilter(); lp.type = 'lowpass'; lp.frequency.value = 620; lp.Q.value = 0.6; lp.connect(master);
    // two detuned drones + a fifth
    const freqs = [110, 110.4, 164.8];
    const oscs = freqs.map((f, i) => {
      const o = ctx.createOscillator(); o.type = i === 2 ? 'sine' : 'triangle'; o.frequency.value = f;
      const g = ctx.createGain(); g.gain.value = i === 2 ? 0.12 : 0.5;
      o.connect(g); g.connect(lp); o.start();
      return o;
    });
    // slow breathing LFO on filter
    const lfo = ctx.createOscillator(); lfo.frequency.value = 0.07;
    const lfoG = ctx.createGain(); lfoG.gain.value = 180;
    lfo.connect(lfoG); lfoG.connect(lp.frequency); lfo.start();
    ref.current = { ctx, master, lp };
    return ref.current;
  }, []);

  const fade = React.useCallback((to, t = 1.6) => {
    const a = ensure(); if (!a) return;
    if (a.ctx.state === 'suspended') a.ctx.resume();
    const now = a.ctx.currentTime;
    a.master.gain.cancelScheduledValues(now);
    a.master.gain.setValueAtTime(a.master.gain.value, now);
    a.master.gain.linearRampToValueAtTime(to, now + t);
  }, [ensure]);

  const bell = React.useCallback((freq = 528) => {
    const a = ensure(); if (!a) return;
    if (a.ctx.state === 'suspended') a.ctx.resume();
    const now = a.ctx.currentTime;
    [1, 2.01, 3.02].forEach((m, i) => {
      const o = a.ctx.createOscillator(); o.type = 'sine'; o.frequency.value = freq * m;
      const g = a.ctx.createGain(); g.gain.value = 0;
      o.connect(g); g.connect(a.ctx.destination);
      g.gain.setValueAtTime(0, now);
      g.gain.linearRampToValueAtTime(0.16 / (i + 1), now + 0.02);
      g.gain.exponentialRampToValueAtTime(0.0001, now + 3.4 - i * 0.6);
      o.start(now); o.stop(now + 3.6);
    });
  }, [ensure]);

  // short soft confirmation, distinct from the long bowls
  const pluck = React.useCallback((freq = 740, gain = 0.08) => {
    const a = ensure(); if (!a) return;
    if (a.ctx.state === 'suspended') a.ctx.resume();
    const now = a.ctx.currentTime;
    const o = a.ctx.createOscillator(); o.type = 'sine'; o.frequency.value = freq;
    const g = a.ctx.createGain(); g.gain.value = 0;
    o.connect(g); g.connect(a.ctx.destination);
    g.gain.setValueAtTime(0, now);
    g.gain.linearRampToValueAtTime(gain, now + 0.01);
    g.gain.exponentialRampToValueAtTime(0.0001, now + 0.5);
    o.start(now); o.stop(now + 0.55);
  }, [ensure]);

  // a soft, warm bell — gentler than pluck (slow attack, octave partial,
  // long decay). Used as the optional per-point cue in 61-point relax.
  const chime = React.useCallback((freq = 330, gain = 0.05) => {
    const a = ensure(); if (!a) return;
    if (a.ctx.state === 'suspended') a.ctx.resume();
    const now = a.ctx.currentTime;
    [[freq, gain], [freq * 2, gain * 0.3]].forEach(([f, gg], i) => {
      const o = a.ctx.createOscillator(); o.type = 'sine'; o.frequency.value = f;
      const g = a.ctx.createGain(); g.gain.value = 0;
      o.connect(g); g.connect(a.ctx.destination);
      g.gain.setValueAtTime(0, now);
      g.gain.linearRampToValueAtTime(gg, now + 0.05);
      g.gain.exponentialRampToValueAtTime(0.0001, now + 1.7 - i * 0.5);
      o.start(now); o.stop(now + 1.8);
    });
  }, [ensure]);

  return { fade, bell, pluck, chime };
}

// ── pose preference (standing energy-body vs seated meditation posture) ──
const MTPoseContext = React.createContext('standing');
const MT_POSE_KEY = 'mt_pose_v1';
function mtLoadPose() {
  try { const v = localStorage.getItem(MT_POSE_KEY); if (v === 'seated' || v === 'standing') return v; } catch (e) {}
  return 'standing';
}
function mtSavePose(p) { try { localStorage.setItem(MT_POSE_KEY, p); } catch (e) {} }

// ── voice guidance (Web Speech API) ───────────────────────────────
// pre-recorded guidance (ElevenLabs "Brian", generated once — no runtime
// API calls). speak() plays the recording when the line is known, and
// falls back to browser speech synthesis for any other text.
const MT_VOICE_AUDIO = {
  'Rest attention at the rim of the nostrils.': 'anapana-1',
  'Feel the breath enter — cool. Leave — warm.': 'anapana-2',
  'Just the breath. Nothing to add, nothing to fix.': 'anapana-3',
  'When the mind wanders, gently return to the breath.': 'anapana-4',
  'Sharpen the attention on this small triangle of skin.': 'anapana-5',
  'Move attention slowly through the body, part by part.': 'vipassana-1',
  'Whatever arises — pleasant or unpleasant — simply observe.': 'vipassana-2',
  'Anicca. Every sensation is changing, passing.': 'vipassana-3',
  'No reaction. No craving, no aversion. Only observe.': 'vipassana-4',
  'Stay equanimous, knowing it will change.': 'vipassana-5',
  'Let the body soften, the heart grow warm.': 'metta-1',
  'May I be happy. May I be peaceful. May I be free.': 'metta-2',
  'May all beings be happy. May all beings be free.': 'metta-3',
  'Radiate goodwill outward, in every direction.': 'metta-4',
  'Rest in the warmth, open and unguarded.': 'metta-5',
  'Sit. Know the body as it is.': 'open-1',
  'When a thought arises, note it softly — and let it pass.': 'open-2',
  'Whatever you are doing, be aware of it.': 'open-3',
  'Rest in open awareness. Nothing to chase.': 'open-4',
  'Repeat the Name, gently, with each breath.': 'bhakti-1',
  'Let the Name fill the mind — leave no room for anything else.': 'bhakti-2',
  'When a sensation or feeling arises, offer it to the Lord and return to the Name.': 'bhakti-3',
  'No need to observe. Only to fill, and to surrender.': 'bhakti-4',
  'The ego dissolves where the Name lives.': 'bhakti-5',
  'Place the Name on this part of the body.': 'hybrid-1',
  'Fill each cell with the Name in place of craving.': 'hybrid-2',
  'Move slowly — let the Name saturate the whole body.': 'hybrid-3',
  'Where sensation was, now let the Name be.': 'hybrid-4',
  'Body and Name become one.': 'hybrid-5',
  'Begin with the breath. Ānāpāna.': 'enter-anapana',
  'Now move to the body. Begin the sweep.': 'enter-vipassana',
  'Now, lovingkindness. Let the heart open.': 'enter-metta',
  'Rest in open awareness.': 'enter-open',
  'Gently return your attention to breath.': 'remind-breath',
  'Gently return your attention to body sweep.': 'remind-sweep',
  'Gently return your attention to lovingkindness.': 'remind-metta',
  'Gently return your attention to noting.': 'remind-noting',
  'Gently return your attention to the Name.': 'remind-name',
  'Feel each foot as it lifts, moves, and places.': 'walking-1',
  'Walk a little slower than feels natural.': 'walking-2',
  'When the mind wanders, return to the soles of the feet.': 'walking-3',
  'Lifting. Moving. Placing.': 'walking-4',
  'Begin walking. Attention in the feet.': 'enter-walking',
  'Gently return your attention to the steps.': 'remind-steps',
  'Let the body settle. Let the eyes close.': 'settle-1',
  'Why such a small area? A narrow focus sharpens the mind, like a lens gathering light.': 'anapana-why1',
  'Do not force the breath — only watch it. Long or short, simply know it as it is.': 'anapana-why2',
  'Each time you notice the mind has wandered and return, the attention grows stronger.': 'anapana-why3',
  'Why observe without reacting? Each craving or aversion plants a habit; calm observation dissolves one.': 'vipassana-why1',
  'Move at an even pace, part by part — the faint sensations matter as much as the strong.': 'vipassana-why2',
  'This is the sixty-one point relaxation, from the Himalayan tradition of Swami Rama. Your attention will travel through sixty-one points across the body, resting a breath at each. It calms the nervous system, deepens awareness of the body, and settles the mind for stillness. Lie down, let the breath be easy, and simply follow.': 'relax-intro',
  'Relax the eyebrow center.': 'relax-eyebrow-center',
  'Relax the hollow of the throat.': 'relax-hollow-of-the-throat',
  'Relax the right shoulder.': 'relax-right-shoulder',
  'Relax the right elbow.': 'relax-right-elbow',
  'Relax the right wrist.': 'relax-right-wrist',
  'Relax the right thumb.': 'relax-right-thumb',
  'Relax the right index finger.': 'relax-right-index-finger',
  'Relax the right middle finger.': 'relax-right-middle-finger',
  'Relax the right ring finger.': 'relax-right-ring-finger',
  'Relax the right little finger.': 'relax-right-little-finger',
  'Relax the left shoulder.': 'relax-left-shoulder',
  'Relax the left elbow.': 'relax-left-elbow',
  'Relax the left wrist.': 'relax-left-wrist',
  'Relax the left thumb.': 'relax-left-thumb',
  'Relax the left index finger.': 'relax-left-index-finger',
  'Relax the left middle finger.': 'relax-left-middle-finger',
  'Relax the left ring finger.': 'relax-left-ring-finger',
  'Relax the left little finger.': 'relax-left-little-finger',
  'Relax the center of the heart.': 'relax-center-of-the-heart',
  'Relax the right side of the chest.': 'relax-right-side-of-the-chest',
  'Relax the left side of the chest.': 'relax-left-side-of-the-chest',
  'Relax the solar plexus.': 'relax-solar-plexus',
  'Relax the navel center.': 'relax-navel-center',
  'Relax the right side of the pelvis.': 'relax-right-side-of-the-pelvis',
  'Relax the right knee.': 'relax-right-knee',
  'Relax the right ankle.': 'relax-right-ankle',
  'Relax the right big toe.': 'relax-right-big-toe',
  'Relax the right second toe.': 'relax-right-second-toe',
  'Relax the right middle toe.': 'relax-right-middle-toe',
  'Relax the right fourth toe.': 'relax-right-fourth-toe',
  'Relax the right little toe.': 'relax-right-little-toe',
  'Relax the left side of the pelvis.': 'relax-left-side-of-the-pelvis',
  'Relax the left knee.': 'relax-left-knee',
  'Relax the left ankle.': 'relax-left-ankle',
  'Relax the left big toe.': 'relax-left-big-toe',
  'Relax the left second toe.': 'relax-left-second-toe',
  'Relax the left middle toe.': 'relax-left-middle-toe',
  'Relax the left fourth toe.': 'relax-left-fourth-toe',
  'Relax the left little toe.': 'relax-left-little-toe',
  'Relax the center of the pelvis.': 'relax-center-of-the-pelvis'
};

function useVoice() {
  const synth = (typeof window !== 'undefined') ? window.speechSynthesis : null;
  const voiceRef = React.useRef(null);
  const audioRef = React.useRef(null);
  React.useEffect(() => {
    if (!synth) return;
    const pick = () => {
      const vs = synth.getVoices();
      const pref = ['Samantha', 'Google UK English Female', 'Karen', 'Moira', 'Serena', 'Google US English', 'Microsoft Aria'];
      let v = null;
      for (const name of pref) { v = vs.find(x => x.name === name); if (v) break; }
      if (!v) v = vs.find(x => /en[-_]/i.test(x.lang)) || vs[0];
      voiceRef.current = v || null;
    };
    pick();
    synth.onvoiceschanged = pick;
    return () => { try { synth.onvoiceschanged = null; } catch (e) {} };
  }, [synth]);

  const speak = React.useCallback((text, { rate = 0.82, pitch = 0.95, volume = 1 } = {}) => {
    if (!text) return;
    const fid = MT_VOICE_AUDIO[text];
    if (fid) {
      try {
        if (audioRef.current) { audioRef.current.pause(); audioRef.current = null; }
        const a = new Audio('audio/' + fid + '.mp3');
        a.volume = volume;
        audioRef.current = a;
        a.play().catch(() => {});   // autoplay block → stay silent rather than crash
        return;
      } catch (e) {}
    }
    if (!synth) return;
    try {
      synth.cancel();   // never queue behind a previous utterance
      const u = new SpeechSynthesisUtterance(text);
      if (voiceRef.current) u.voice = voiceRef.current;
      u.rate = rate; u.pitch = pitch; u.volume = volume; u.lang = (voiceRef.current && voiceRef.current.lang) || 'en-US';
      synth.speak(u);
    } catch (e) {}
  }, [synth]);
  const cancel = React.useCallback(() => {
    try { if (audioRef.current) { audioRef.current.pause(); audioRef.current = null; } } catch (e) {}
    try { synth && synth.cancel(); } catch (e) {}
  }, [synth]);
  return { speak, cancel, supported: true };
}

// ── screen wake lock (keep the display on during a sitting) ───────
function useWakeLock(active = true) {
  React.useEffect(() => {
    if (!active || !('wakeLock' in navigator)) return;
    let lock = null, gone = false;
    const acquire = () => {
      navigator.wakeLock.request('screen')
        .then((l) => { if (gone) { try { l.release(); } catch (e) {} } else lock = l; })
        .catch(() => {});
    };
    // the lock is auto-released when the tab is hidden — re-acquire on return
    const onVis = () => { if (document.visibilityState === 'visible') acquire(); };
    acquire();
    document.addEventListener('visibilitychange', onVis);
    return () => {
      gone = true;
      document.removeEventListener('visibilitychange', onVis);
      try { lock && lock.release(); } catch (e) {}
    };
  }, [active]);
}

// ── parked thoughts (the pre-sit "set down your mind" box) ────────
const MT_PARKED_KEY = 'mt_parked_v1';
function mtLoadParked() {
  try { const r = localStorage.getItem(MT_PARKED_KEY); if (r) return JSON.parse(r); } catch (e) {}
  return [];
}
function mtSaveParked(arr) { try { localStorage.setItem(MT_PARKED_KEY, JSON.stringify(arr || [])); } catch (e) {} }
function mtClearParked() { try { localStorage.removeItem(MT_PARKED_KEY); } catch (e) {} }

// ── last-used session config (for Quick Start) ───────────────────
const MT_LASTCFG_KEY = 'mt_lastcfg_v1';
function mtLoadLastCfg() {
  try { const r = localStorage.getItem(MT_LASTCFG_KEY); if (r) return JSON.parse(r); } catch (e) {}
  return null;
}
function mtSaveLastCfg(cfg) {
  try {
    const { parked, ...rest } = cfg || {};   // never persist the parked thoughts into defaults
    localStorage.setItem(MT_LASTCFG_KEY, JSON.stringify(rest));
  } catch (e) {}
}

// ── interrupted-sit recovery (heartbeat written during sessions) ──
const MT_ACTIVE_KEY = 'mt_active_sit_v1';
function mtSaveActiveSit(o) { try { localStorage.setItem(MT_ACTIVE_KEY, JSON.stringify(o)); } catch (e) {} }
function mtLoadActiveSit() {
  try { const r = localStorage.getItem(MT_ACTIVE_KEY); if (r) return JSON.parse(r); } catch (e) {}
  return null;
}
function mtClearActiveSit() { try { localStorage.removeItem(MT_ACTIVE_KEY); } catch (e) {} }

// ── backup: export / import everything Anicca stores ──────────────
// literal key names — MT_LIFE_KEY lives in lifetime.jsx which loads
// after this file, so referencing the consts here would throw (TDZ
// across scripts). Keep in sync with the MT_*_KEY consts.
const MT_BACKUP_KEYS = ['mt_onboarded', 'mt_sessions_v1', 'mt_lastcfg_v1', 'mt_life_v1', 'mt_pose_v1', 'mt_parked_v1'];
function mtExportData() {
  const data = {};
  for (const k of MT_BACKUP_KEYS) { try { const v = localStorage.getItem(k); if (v !== null) data[k] = v; } catch (e) {} }
  const payload = { app: 'anicca', version: 1, exported: new Date().toISOString(), data };
  const blob = new Blob([JSON.stringify(payload, null, 2)], { type: 'application/json' });
  const a = document.createElement('a');
  a.href = URL.createObjectURL(blob);
  a.download = `anicca-backup-${new Date().toISOString().slice(0, 10)}.json`;
  document.body.appendChild(a); a.click(); a.remove();
  setTimeout(() => URL.revokeObjectURL(a.href), 2000);
}
function mtImportData(file, onDone) {
  const reader = new FileReader();
  reader.onload = () => {
    try {
      const parsed = JSON.parse(reader.result);
      if (!parsed || (parsed.app !== 'anicca' && parsed.app !== 'soma') || !parsed.data) { onDone && onDone(false, 'Not an Anicca backup file.'); return; }
      for (const [k, v] of Object.entries(parsed.data)) {
        if (MT_BACKUP_KEYS.includes(k) && typeof v === 'string') {
          try { localStorage.setItem(k, v); } catch (e) {}
        }
      }
      onDone && onDone(true);
    } catch (e) { onDone && onDone(false, 'Could not read that file.'); }
  };
  reader.readAsText(file);
}

// ── viewport ──────────────────────────────────────────────────────
function useViewport() {
  const get = () => ({ w: window.innerWidth, h: window.innerHeight });
  const [vp, setVp] = React.useState(get);
  React.useEffect(() => {
    let t; const on = () => { clearTimeout(t); t = setTimeout(() => setVp(get()), 80); };
    window.addEventListener('resize', on); window.addEventListener('orientationchange', on);
    return () => { window.removeEventListener('resize', on); window.removeEventListener('orientationchange', on); };
  }, []);
  return { ...vp, isPhone: vp.w < 720, isWide: vp.w >= 720, landscape: vp.w >= 980 && vp.w > vp.h * 1.05 };
}

Object.assign(window, {
  MT_COLORS, MT_TRAD, MT_PATHS, MT_DEITIES, MT_SENSATIONS, MT_SENS_MAP, MT_EMOTIONS, MT_INTENSITY, MT_REGION_LABEL,
  MTIcon, MTPanel, MTChip, MTButton, MTEyebrow,
  mtLoadSessions, mtSaveSessions, useAmbient, useViewport,
  MTPoseContext, mtLoadPose, mtSavePose,
  mtLoadParked, mtSaveParked, mtClearParked,
  mtLoadLastCfg, mtSaveLastCfg,
  useVoice,
});
