import { useCallback, useEffect, useRef, useState } from "react";

import "./chessClock.css";

/* ══ HELPERS ══ */
const fmt = s => Math.floor(Math.abs(s)/60).toString().padStart(2,"0")+":"+Math.floor(Math.abs(s)%60).toString().padStart(2,"0");
const fmtMs = ms => Math.floor(ms/1000)+"."+(Math.floor((ms%1000)/10)).toString().padStart(2,"0");
const fmtDate = ts => { const d=new Date(ts); return d.getDate()+"/"+(d.getMonth()+1)+"/"+d.getFullYear()+"  "+d.getHours().toString().padStart(2,"0")+"h"+d.getMinutes().toString().padStart(2,"0"); };
const buildPreview = (m,s,i) => { let t=m>0?m+" min":""; if(m>0&&s>0)t+=" "; if(s>0)t+=s+" sec"; if(!t)t="0 sec"; if(i>0)t+=" + "+i+"s"; return t; };

/* ══ SCROLL GUARD ══
   Returns pointer handlers that cancel the action if the finger moves > THRESHOLD px.
   Usage: const {onPD, onPU, onPC, onPM} = useScrollGuard(onDown, onUp, player)
*/
const SCROLL_THRESHOLD = 10;
function useScrollGuard(onDown, onUp, arg){
  const startY = useRef(null);
  const startX = useRef(null);
  const cancelled = useRef(false);

  const onPD = useCallback((e) => {
    e.stopPropagation();
    startY.current = e.clientY;
    startX.current = e.clientX;
    cancelled.current = false;
    if(arg !== undefined) onDown(arg);
    else onDown();
  }, [onDown, arg]);

  const onPM = useCallback((e) => {
    if(cancelled.current) return;
    if(startY.current === null) return;
    const dy = Math.abs(e.clientY - startY.current);
    const dx = Math.abs(e.clientX - startX.current);
    if(dy > SCROLL_THRESHOLD || dx > SCROLL_THRESHOLD){
      cancelled.current = true;
      if(arg !== undefined) onUp(arg);
      else onUp();
    }
  }, [onUp, arg]);

  const onPU = useCallback((e) => {
    e.stopPropagation();
    startY.current = null;
    if(cancelled.current){ cancelled.current = false; return; }
    if(arg !== undefined) onUp(arg);
    else onUp();
  }, [onUp, arg]);

  const onPC = useCallback((e) => {
    e.stopPropagation();
    startY.current = null;
    cancelled.current = false;
    if(arg !== undefined) onUp(arg);
    else onUp();
  }, [onUp, arg]);

  return { onPD, onPM, onPU, onPC };
}

/* ══ HAPTIC ══ */
const haptic = pat => {
  try {
    if(navigator.vibrate){
      navigator.vibrate(typeof pat==="number"?Math.max(50,pat):pat);
    }
  } catch(e){}
};

/* ══ AUDIO ══ */
let _ac=null;
const getAC=()=>{ if(!_ac) _ac=new (window.AudioContext||window.webkitAudioContext)(); return _ac; };
const beep=(freq,dur,type,vol,delay)=>{ try{ const c=getAC(),o=c.createOscillator(),g=c.createGain(); o.connect(g);g.connect(c.destination); o.type=type||"sine"; o.frequency.value=freq; const t=c.currentTime+(delay||0); g.gain.setValueAtTime(vol||0.14,t); g.gain.exponentialRampToValueAtTime(0.001,t+dur); o.start(t); o.stop(t+dur+0.05); }catch(e){} };
const playTick=()=>beep(900,0.04,"square",0.12);
const playTock=()=>beep(600,0.04,"square",0.10);
const playSwoop=()=>{ try{ const c=getAC(),o=c.createOscillator(),g=c.createGain(); o.connect(g);g.connect(c.destination); o.frequency.setValueAtTime(520,c.currentTime); o.frequency.exponentialRampToValueAtTime(180,c.currentTime+0.2); g.gain.setValueAtTime(0.15,c.currentTime); g.gain.exponentialRampToValueAtTime(0.001,c.currentTime+0.2); o.start(); o.stop(c.currentTime+0.22); }catch(e){} };
const playFanfare=()=>{ [523,659,784,1047].forEach((f,i)=>beep(f,0.22,"sine",0.16,i*0.11)); };
const playWarn=()=>{ beep(220,0.07,"sawtooth",0.12,0); beep(220,0.07,"sawtooth",0.12,0.14); };

/* ══ ELO ══ */
const calcElo=(rA,rB,won)=>{ const K=32,ea=1/(1+Math.pow(10,(rB-rA)/400)); return Math.round(K*(won-ea)); };
const tryLoad=(key,def)=>{ try{ return JSON.parse(localStorage.getItem(key)||"null")||def; }catch(e){ return def; } };
const trySave=(key,val)=>{ try{ localStorage.setItem(key,JSON.stringify(val)); }catch(e){} };

/* ══ SCRAMBLE ══ */
const SFACES=["U","D","F","B","L","R"], SMODS=["","'","2"];
const genScramble=(n)=>{ const m=[]; let last=-1; for(let i=0;i<(n||20);i++){ let f; do{f=Math.floor(Math.random()*6);}while(f===last); last=f; m.push(SFACES[f]+SMODS[Math.floor(Math.random()*3)]); } return m; };

/* ══ CONSTANTS ══ */
const PRESETS = [
  {base:60,  inc:0, tag:"BULLET", lbl:"1 min"},
  {base:60,  inc:1, tag:"BULLET", lbl:"1 min + 1s"},
  {base:120, inc:1, tag:"BULLET", lbl:"2 min + 1s"},
  {base:180, inc:0, tag:"BLITZ",  lbl:"3 min"},
  {base:180, inc:2, tag:"BLITZ",  lbl:"3 min + 2s"},
  {base:300, inc:0, tag:"BLITZ",  lbl:"5 min"},
  {base:300, inc:3, tag:"BLITZ",  lbl:"5 min + 3s"},
  {base:300, inc:5, tag:"BLITZ",  lbl:"5 min + 5s"},
  {base:600, inc:0, tag:"RAPID",  lbl:"10 min"},
  {base:600, inc:5, tag:"RAPID",  lbl:"10 min + 5s"},
  {base:900, inc:10,tag:"RAPID",  lbl:"15 min + 10s"},
  {base:1200,inc:5, tag:"RAPID",  lbl:"20 min + 5s"},
  {base:1800,inc:0, tag:"CLASSIC",lbl:"30 min"},
  {base:1800,inc:20,tag:"CLASSIC",lbl:"30 min + 20s"},
  {base:3600,inc:30,tag:"CLASSIC",lbl:"60 min + 30s"},
];
const TAG_COLORS = {BULLET:"#f04040",BLITZ:"#e8b84b",RAPID:"#38e878",CLASSIC:"#4b9ee8"};
const P1C = ["p1c0","p1c1","p1c2","p1c3","p1c4","p1c5","p1c6","p1c7","p1c8"];
const P2C = ["p2c0","p2c1","p2c2","p2c3","p2c4","p2c5","p2c6","p2c7","p2c8"];
const AVATARS=["♟","♞","♜","♛","♔","🦁","🐯","⚡","🔥","💎","👑","🎯","🦊","🐉","🌙","⚔"];
const genId=()=>"u"+Math.random().toString(36).slice(2,8);
const DEF_USERS=[
  {id:"u_default0",name:"Joueur 1",avatar:"♟",elo:1200,streak:0,wins:0,games:0},
  {id:"u_default1",name:"Joueur 2",avatar:"♞",elo:1200,streak:0,wins:0,games:0},
];

/* ══ RUBIK'S CUBE ══ */
function RubiksCube({player,size="md"}){
  const colors=player===0?P1C:P2C;
  return <div className={"rcube "+size}>{colors.map((c,i)=><div key={i} className={"rc "+c}/>)}</div>;
}

/* ══ CUSTOM TIME MODAL ══ */
function CustomModal({initMin,initSec,initInc,onConfirm,onCancel}){
  const [mins,setMins]=useState(initMin);
  const [secs,setSecs]=useState(initSec);
  const [inc,setInc]=useState(initInc);
  const sp=(set,d,mn,mx)=>set(v=>Math.max(mn,Math.min(mx,v+d)));
  const total=mins*60+secs;
  return(
    <div className="modal-bg" onPointerDown={onCancel}>
      <div className="modal" onPointerDown={e=>e.stopPropagation()}>
        <div className="modal-handle"/>
        <div className="modal-title">Temps Personnalisé</div>
        <div className="modal-sub">Définissez votre contrôle de temps</div>
        <div className="modal-fields">
          {[{lbl:"Minutes",val:mins,set:setMins,d:1,mn:0,mx:180,u:"min"},
            {lbl:"Secondes",val:secs,set:setSecs,d:5,mn:0,mx:55,u:"sec (x5)"},
            {lbl:"Incrément",val:inc,set:setInc,d:1,mn:0,mx:60,u:"+sec/coup"}
          ].map(f=>(
            <div key={f.lbl} className="modal-field">
              <div className="modal-f-lbl">{f.lbl}</div>
              <div className="modal-spin">
                <div className="modal-sb" onPointerDown={()=>sp(f.set,-f.d,f.mn,f.mx)}>−</div>
                <div className="modal-sv">{f.val}</div>
                <div className="modal-sb" onPointerDown={()=>sp(f.set,+f.d,f.mn,f.mx)}>+</div>
              </div>
              <div className="modal-su">{f.u}</div>
            </div>
          ))}
        </div>
        <div className="modal-prev">
          <span className="modal-prev-lbl">Aperçu</span>
          <span className="modal-prev-val">{buildPreview(mins,secs,inc)}</span>
        </div>
        <div className="modal-actions">
          <button className="modal-ok" style={{opacity:total===0?.4:1}} onPointerDown={()=>{if(total>0)onConfirm(total,inc);}}>Confirmer</button>
          <button className="modal-cancel" onPointerDown={onCancel}>Annuler</button>
        </div>
      </div>
    </div>
  );
}

/* ══ TIME CHART ══ */
function TimeChart({snapshots,initTime}){
  if(!snapshots||snapshots.length<2) return null;
  const W=300,H=65,P=4;
  const maxM=snapshots[snapshots.length-1].move||1;
  const pts0=snapshots.map(s=>(P+((s.move/maxM)*(W-P*2)))+","+(P+(1-(s.t0/initTime))*(H-P*2)));
  const pts1=snapshots.map(s=>(P+((s.move/maxM)*(W-P*2)))+","+(P+(1-(s.t1/initTime))*(H-P*2)));
  return(
    <div className="chart-wrap">
      <div className="chart-ttl">Temps restant par coup</div>
      <svg width="100%" viewBox={"0 0 "+W+" "+H} preserveAspectRatio="none">
        <polyline points={pts0.join(" ")} fill="none" stroke="var(--gold)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" opacity=".9"/>
        <polyline points={pts1.join(" ")} fill="none" stroke="var(--blu)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" opacity=".9"/>
      </svg>
      <div className="chart-leg">
        <div className="chart-li"><div className="chart-ld" style={{background:"var(--gold)"}}/>J1</div>
        <div className="chart-li"><div className="chart-ld" style={{background:"var(--blu)"}}/>J2</div>
      </div>
    </div>
  );
}

/* ══ USER MANAGER SCREEN ══ */
function UserManagerScreen({users,onSave,onClose}){
  const [list,setList]=useState(users.map(u=>({...u})));
  const [editId,setEditId]=useState(null);
  const [showAvFor,setShowAvFor]=useState(null);
  const edit=(id,k,v)=>setList(prev=>prev.map(u=>u.id===id?{...u,[k]:v}:u));
  const addUser=()=>{
    const nu={id:genId(),name:"Nouveau",avatar:"♟",elo:1200,streak:0,wins:0,games:0};
    setList(prev=>[...prev,nu]);
    setEditId(nu.id);
  };
  const delUser=(id)=>{
    if(list.length<=2)return;
    setList(prev=>prev.filter(u=>u.id!==id));
    if(editId===id)setEditId(null);
  };
  const saveUser=()=>{ setEditId(null); setShowAvFor(null); };
  return(
    <div className="um">
      <div className="um-hd">
        <div className="um-title">Joueurs</div>
        <button className="um-add-btn" onPointerDown={addUser}>+ Ajouter</button>
        <div className="um-close" onPointerDown={()=>{onSave(list);onClose();}}>✕</div>
      </div>
      <div className="um-body">
        {list.map(u=>{
          const isEdit=editId===u.id;
          return(
            <div key={u.id} className={"um-card"+(isEdit?" editing":"")}>
              <div className="um-row">
                <div className={"um-av"+(showAvFor===u.id?" open":"")}
                  onPointerDown={()=>isEdit&&setShowAvFor(showAvFor===u.id?null:u.id)}>
                  {u.avatar}
                </div>
                <div className="um-info">
                  {isEdit
                    ?<input className="um-name-input" defaultValue={u.name} maxLength={14}
                        onChange={e=>edit(u.id,"name",e.target.value||"Joueur")}
                        onPointerDown={e=>e.stopPropagation()} autoFocus/>
                    :<div className="um-name">{u.name}</div>
                  }
                  <div className="um-meta">
                    <span className="um-elo">{"ELO "+u.elo}</span>
                    {u.streak>=2&&<span className="um-streak">{"🔥 "+u.streak}</span>}
                    <span className="um-wins">{u.wins+" victoires"}</span>
                  </div>
                </div>
                <div className="um-actions">
                  {isEdit
                    ?(null)
                    :<div className="um-btn edit" onPointerDown={()=>{setEditId(u.id);setShowAvFor(null);}}>✏</div>
                  }
                  {list.length>2&&<div className="um-btn del" onPointerDown={()=>delUser(u.id)}>🗑</div>}
                </div>
              </div>
              {isEdit&&showAvFor===u.id&&(
                <div className="um-av-grid">
                  {AVATARS.map(av=>(
                    <div key={av} className={"um-av-item"+(u.avatar===av?" sel":"")}
                      onPointerDown={()=>{edit(u.id,"avatar",av);setShowAvFor(null);}}>
                      {av}
                    </div>
                  ))}
                </div>
              )}
              {isEdit&&(
                <div className="um-save-row">
                  <button className="um-save-btn" onPointerDown={saveUser}>Confirmer</button>
                  <button className="um-cancel-btn" onPointerDown={()=>{setEditId(null);setShowAvFor(null);}}>Annuler</button>
                </div>
              )}
            </div>
          );
        })}
      </div>
    </div>
  );
}

/* ══ PLAYER SELECT SCREEN ══ */
function PlayerSelectScreen({users,onConfirm,onClose}){
  const [sel0,setSel0]=useState(users[0]?.id||null);
  const [sel1,setSel1]=useState(users[1]?.id||null);
  const ready=sel0&&sel1&&sel0!==sel1;
  const u0=users.find(u=>u.id===sel0);
  const u1=users.find(u=>u.id===sel1);
  return(
    <div className="ps">
      {/* J2 panel — top, rotated */}
      <div className={"ps-half flip"+(u1?" on1":"")}>
        <div className="ps-label">Joueur 2 — Haut de l'écran</div>
        <div className="ps-sel-display">
          {u1
            ?<><div className="ps-sel-av">{u1.avatar}</div><div className={"ps-sel-name blue"}>{u1.name}</div></>
            :<div className="ps-sel-empty">Choisissez un joueur</div>
          }
        </div>
        <div className="ps-grid">
          {users.map(u=>{
            let _sy1=null;
            return(
            <div key={u.id}
              className={"ps-chip"+(sel1===u.id?" sel1":"")+(sel0===u.id?" other-taken":"")}
              onPointerDown={e=>{_sy1=e.clientY;}}
              onPointerUp={e=>{if(_sy1!==null&&Math.abs(e.clientY-_sy1)<10){setSel1(u.id);}_sy1=null;}}>
              <div className="ps-chip-av">{u.avatar}</div>
              <div style={{display:"flex",flexDirection:"column",gap:1}}>
                <div className="ps-chip-name">{u.name}</div>
                <div className="ps-chip-elo">{"ELO "+u.elo}</div>
              </div>
            </div>
            );
          })}
        </div>
      </div>

      {/* Divider */}
      <div className="ps-div">
        <div className="ps-vs">VS</div>
      </div>

      {/* J1 panel — bottom */}
      <div className={"ps-half"+(u0?" on0":"")}>
        <div className="ps-label">Joueur 1 — Bas de l'écran</div>
        <div className="ps-sel-display">
          {u0
            ?<><div className="ps-sel-av">{u0.avatar}</div><div className="ps-sel-name">{u0.name}</div></>
            :<div className="ps-sel-empty">Choisissez un joueur</div>
          }
        </div>
        <div className="ps-grid">
          {users.map(u=>{
            let _sy0=null;
            return(
            <div key={u.id}
              className={"ps-chip"+(sel0===u.id?" sel0":"")+(sel1===u.id?" other-taken":"")}
              onPointerDown={e=>{_sy0=e.clientY;}}
              onPointerUp={e=>{if(_sy0!==null&&Math.abs(e.clientY-_sy0)<10){setSel0(u.id);}_sy0=null;}}>
              <div className="ps-chip-av">{u.avatar}</div>
              <div style={{display:"flex",flexDirection:"column",gap:1}}>
                <div className="ps-chip-name">{u.name}</div>
                <div className="ps-chip-elo">{"ELO "+u.elo}</div>
              </div>
            </div>
            );
          })}
        </div>
      </div>

      {/* Footer buttons */}
      <div className="ps-footer">
        <button className="ps-back" onPointerDown={onClose}>← Retour</button>
        <button className={"ps-go"+(ready?" ready":" wait")}
          onPointerDown={()=>ready&&onConfirm(sel0,sel1)}>
          {ready?"Jouer !":"Sélectionnez 2 joueurs"}
        </button>
      </div>
    </div>
  );
}

/* ══ CUBE PREP SCREEN ══ */
function CubePrepScreen({p0,p1,onReady}){
  const [countdown,setCountdown]=useState(30);
  const [scrambles]=useState([genScramble(18),genScramble(18)]);
  const timerRef=useRef(null);
  useEffect(()=>{
    timerRef.current=setInterval(()=>{
      setCountdown(c=>{ if(c<=1){clearInterval(timerRef.current);onReady();return 0;} return c-1; });
    },1000);
    return()=>clearInterval(timerRef.current);
  },[]);
  const go=()=>{ clearInterval(timerRef.current); onReady(); };
  return(
    <div className="prep">
      <div className="prep-title">Mémorisez !</div>
      <div className="prep-sub">Chaque joueur a son propre mélange</div>
      <div className="prep-players">
        {[p0,p1].map((u,pi)=>(
          <div key={pi} className="prep-p-card">
            <div style={{fontSize:22}}>{u.avatar}</div>
            <div className="prep-p-name">{u.name}</div>
            <RubiksCube player={pi} size="md"/>
            <div className="prep-scramble">
              {scrambles[pi].map((m,i)=><div key={i} className="prep-move">{m}</div>)}
            </div>
          </div>
        ))}
      </div>
      <div className="prep-countdown">{countdown}</div>
      <button className="prep-ready-btn" onPointerDown={go}>On est prêts !</button>
      <div className="prep-skip" onPointerDown={go}>Passer</div>
    </div>
  );
}

/* ══ SOLO CS TIMER ══ */
const HOLD_MS=900;
function SoloCsTimerPanel({player,phase,elapsed,progress,onDown,onUp,user,isDone,isWinner}){
  const {onPD,onPM,onPU,onPC}=useScrollGuard(onDown,onUp,player);
  const CIRC=264;
  const prog=Math.min(1,progress||0);
  const offset=CIRC*(1-prog);
  const ph=isDone?(isWinner?"win":"lose"):phase;
  const bgCls="scs-panel"+(player===1?" flip":"")+" "+(ph==="ready"?"hold":ph)+"-bg";

  let stateLbl,stateClr,timeLbl,hint,showRing=false;
  if(ph==="win"){stateLbl="VICTOIRE !";stateClr="gold";timeLbl=fmtMs(elapsed);hint=""}
  else if(ph==="lose"){stateLbl="PERDU";stateClr="dim";timeLbl=fmtMs(elapsed);hint=""}
  else if(phase==="idle"){stateLbl="CS TIMER";stateClr="blu";timeLbl="00.00";hint="Maintenez appuyé"}
  else if(phase==="hold"){stateLbl="CHARGEZ…";stateClr="grn";timeLbl=Math.round(prog*100)+"%";hint="Ne relâchez pas !";showRing=true;}
  else if(phase==="ready"){stateLbl="RELÂCHEZ !";stateClr="grn";timeLbl="GO";hint="Relâchez pour démarrer";showRing=true;}
  else if(phase==="run"){stateLbl="⏱ EN COURS";stateClr="red";timeLbl=fmtMs(elapsed);hint="Appuyez pour stopper";}
  else{stateLbl="STOPPÉ";stateClr="dim";timeLbl=fmtMs(elapsed);hint="En attente…";}

  return(
    <div className={bgCls}
      onPointerDown={onPD}
      onPointerMove={onPM}
      onPointerUp={onPU}
      onPointerCancel={onPC}>
      <div className={"scs-name"}>
        <div className="scs-av">{user.avatar}</div>
        <div className="scs-plbl">{user.name}</div>
      </div>
      <div className={"scs-state "+stateClr}>{stateLbl}</div>
      {showRing?(
        <div className="scs-ring" style={{width:100,height:100}}>
          <svg viewBox="0 0 100 100" width="100" height="100" style={{position:"absolute",top:0,left:0,overflow:"visible"}}>
            <circle cx="50" cy="50" r="42" fill="none" stroke="rgba(255,255,255,.10)" strokeWidth="5"/>
            <circle cx="50" cy="50" r="42" fill="none"
              stroke={phase==="ready"?"#ffffff":"#7affc0"}
              strokeWidth="7" strokeLinecap="round"
              strokeDasharray={""+CIRC}
              strokeDashoffset={phase==="ready"?"0":""+offset}
              transform="rotate(-90 50 50)"
              style={phase==="ready"?{animation:"wbreathe .4s ease-in-out infinite alternate"}:{}}/>
          </svg>
          <div className={"scs-time "+ph} style={{position:"relative",zIndex:1}}>{timeLbl}</div>
        </div>
      ):(phase==="run"&&!isDone)?(
        <div className="scs-ring" style={{width:100,height:100}}>
          <svg viewBox="0 0 100 100" width="100" height="100" style={{position:"absolute",top:0,left:0,overflow:"visible"}}>
            <circle cx="50" cy="50" r="42" fill="none" stroke="rgba(255,255,255,.08)" strokeWidth="5"/>
            <circle cx="50" cy="50" r="42" fill="none" stroke="#80ffbe" strokeWidth="5" strokeLinecap="round"
              strokeDasharray="60 204" transform="rotate(-90 50 50)"
              style={{animation:"rspin .7s linear infinite"}}/>
            <circle cx="50" cy="50" r="38" fill="none" stroke="rgba(80,255,160,.2)" strokeWidth="3" strokeLinecap="round"
              strokeDasharray="30 208" transform="rotate(-90 50 50)"
              style={{animation:"rspin2 1.4s linear infinite reverse"}}/>
          </svg>
          <div className={"scs-time "+ph} style={{position:"relative",zIndex:1}}>{timeLbl}</div>
        </div>
      ):(
        <div className={"scs-time "+ph}>{timeLbl}</div>
      )}
      {ph==="win"&&<div className="scs-win-lbl">♛ Gagné !</div>}
      {hint&&<div className="scs-hint">{hint}</div>}
    </div>
  );
}

/* ══ SOLO CS TIMER — one player ══ */
function SoloCsTimerSolo({user}){
  const [phase,setPhase]=useState("idle");
  const [elapsed,setElapsed]=useState(0);
  const [progress,setProgress]=useState(0);
  const [history,setHistory]=useState([]);

  const phaseRef=useRef("idle");
  const startRef=useRef(null);
  const holdStartRef=useRef(null);
  const holdFrameRef=useRef(null);
  const frameRef=useRef(null);

  useEffect(()=>{ phaseRef.current=phase; },[phase]);

  // RAF for run
  useEffect(()=>{
    if(phase!=="run"){cancelAnimationFrame(frameRef.current);return;}
    const loop=()=>{
      setElapsed(performance.now()-startRef.current);
      frameRef.current=requestAnimationFrame(loop);
    };
    frameRef.current=requestAnimationFrame(loop);
    return()=>cancelAnimationFrame(frameRef.current);
  },[phase]);

  const onDown=useCallback(()=>{
    const ph=phaseRef.current;
    if(ph==="idle"||ph==="stop"){
      // Reset elapsed if coming from stop
      if(ph==="stop"){setElapsed(0);}
      holdStartRef.current=performance.now();
      setPhase("hold");
      const loop=()=>{
        if(!holdStartRef.current)return;
        const prog=Math.min(1,(performance.now()-holdStartRef.current)/HOLD_MS);
        setProgress(prog);
        if(prog<1){
          holdFrameRef.current=requestAnimationFrame(loop);
        } else {
          holdStartRef.current=null;
          haptic(50);
          setPhase("ready");
        }
      };
      holdFrameRef.current=requestAnimationFrame(loop);
    } else if(ph==="run"){
      // Stop the timer
      const el=performance.now()-startRef.current;
      cancelAnimationFrame(frameRef.current);
      setElapsed(el);
      setHistory(prev=>[el,...prev].slice(0,10));
      setPhase("stop");
      haptic([60,40,100]);
    }
  },[]);

  const onUp=useCallback(()=>{
    const ph=phaseRef.current;
    if(ph==="ready"){
      startRef.current=performance.now();
      setPhase("run");
    } else if(ph==="hold"){
      cancelAnimationFrame(holdFrameRef.current);
      holdStartRef.current=null;
      setProgress(0);
      setPhase("idle");
    }
  },[]);

  const reset=()=>{
    cancelAnimationFrame(frameRef.current);
    cancelAnimationFrame(holdFrameRef.current);
    holdStartRef.current=null;
    startRef.current=null;
    phaseRef.current="idle";
    setPhase("idle");
    setElapsed(0);
    setProgress(0);
  };

  const CIRC=264;
  const prog=Math.min(1,progress);
  const offset=CIRC*(1-prog);
  const best=history.length>0?Math.min(...history):null;

  let stateLbl,stateClr,timeDisplay,hint;
  if(phase==="idle"){stateLbl="CS TIMER";stateClr="blu";timeDisplay=user.avatar;hint="Maintenez appuyé";}
  else if(phase==="hold"){stateLbl="CHARGEZ…";stateClr="grn";timeDisplay=Math.round(prog*100)+"%";hint="Ne relâchez pas !";}
  else if(phase==="ready"){stateLbl="RELÂCHEZ !";stateClr="wht";timeDisplay="GO";hint="Relâchez pour démarrer";}
  else if(phase==="run"){stateLbl="⏱ EN COURS";stateClr="red";timeDisplay=fmtMs(elapsed);hint="Appuyez pour stopper";}
  else{stateLbl="✓ TEMPS";stateClr="gold";timeDisplay=fmtMs(elapsed);hint="Utilisez ▶ Rejouer en bas";}

  const bgStyle=phase==="idle"?"scs-solo-panel idle-bg":phase==="hold"||phase==="ready"?"scs-solo-panel hold-bg":phase==="run"?"scs-solo-panel run-bg":"scs-solo-panel stop-bg";

  const {onPD,onPM,onPU,onPC}=useScrollGuard(onDown,onUp);

  const isStop = phase==="stop";

  return(
    <div className={bgStyle}
      onPointerDown={isStop?undefined:onPD}
      onPointerMove={isStop?undefined:onPM}
      onPointerUp={isStop?undefined:onPU}
      onPointerCancel={isStop?undefined:onPC}>

      <div style={{display:"flex",alignItems:"center",gap:8,position:"relative",zIndex:1}}>
        <div style={{fontSize:20}}>{user.avatar}</div>
        <div className="scs-plbl">{user.name}</div>
      </div>

      <div className={"scs-solo-state "+stateClr}>{stateLbl}</div>

      {(phase==="hold"||phase==="ready")?(
        <div className="scs-ring" style={{width:120,height:120}}>
          <svg viewBox="0 0 120 120" width="120" height="120" style={{position:"absolute",top:0,left:0,overflow:"visible"}}>
            <circle cx="60" cy="60" r="52" fill="none" stroke="rgba(255,255,255,.10)" strokeWidth="6"/>
            <circle cx="60" cy="60" r="52" fill="none"
              stroke={phase==="ready"?"#ffffff":"#7affc0"}
              strokeWidth="8" strokeLinecap="round"
              strokeDasharray={""+Math.round(2*Math.PI*52)}
              strokeDashoffset={phase==="ready"?"0":""+Math.round(2*Math.PI*52*(1-prog))}
              transform="rotate(-90 60 60)"
              style={phase==="ready"?{animation:"wbreathe .4s ease-in-out infinite alternate"}:{}}/>
          </svg>
          <div className={"scs-solo-time "+(phase==="ready"?"ready":"hold")} style={{position:"relative",zIndex:1,fontSize:"clamp(36px,10vw,52px)"}}>
            {timeDisplay}
          </div>
        </div>
      ):(
        <div className={"scs-solo-time "+phase}>{timeDisplay}</div>
      )}

      <div className={"scs-solo-hint"}>{hint}</div>

      {best!==null&&phase!=="hold"&&phase!=="ready"&&(
        <div className="scs-solo-best" onPointerDown={e=>e.stopPropagation()}>
          <div className="scs-solo-best-lbl">Meilleur</div>
          <div className="scs-solo-best-val">{fmtMs(best)}</div>
          {history.length>1&&(
            <>
              <div className="scs-solo-best-lbl" style={{marginLeft:10}}>Moy.</div>
              <div className="scs-solo-best-val" style={{color:"var(--gold)"}}>
                {fmtMs(history.reduce((a,b)=>a+b,0)/history.length)}
              </div>
            </>
          )}
        </div>
      )}

      {history.length>0&&phase==="stop"&&(
        <div className="scs-solo-history"
          style={{touchAction:"pan-y",overflowY:"auto",maxHeight:"38vh"}}
          onPointerDown={e=>e.stopPropagation()}
          onPointerMove={e=>e.stopPropagation()}
          onPointerUp={e=>e.stopPropagation()}>
          {history.slice(0,10).map((t,i)=>(
            <div key={i} className="scs-solo-hist-row">
              <div className="scs-solo-hist-n">#{i+1}</div>
              <div className={"scs-solo-hist-t"+(t===best?" best":"")}>{fmtMs(t)}</div>
              {t===best&&<div style={{fontSize:9,color:"#80ffbe",letterSpacing:2}}>BEST</div>}
            </div>
          ))}
        </div>
      )}

      <div style={{position:"absolute",bottom:0,left:0,right:0,padding:"6px 14px clamp(8px,2vh,18px)",background:"linear-gradient(to top,rgba(6,10,14,.98) 55%,transparent)",display:"flex",justifyContent:"center",gap:10,zIndex:30}}
        onPointerDown={e=>e.stopPropagation()}>
        {phase==="stop"&&(
          <button className="scs-reset" style={{background:"linear-gradient(135deg,var(--g2),var(--gold))",color:"var(--bg)",border:"none",letterSpacing:4,fontSize:12,padding:"9px 22px"}}
            onPointerDown={e=>{e.stopPropagation();onDown();}}>
            ▶ Rejouer
          </button>
        )}
        <button className="scs-reset" onPointerDown={reset}>↺ Reset</button>
        {history.length>0&&<button className="scs-reset" onPointerDown={()=>setHistory([])}>🗑</button>}
      </div>
    </div>
  );
}

function SoloCsTimer({p0,p1,onClose}){
  const [mode,setMode]=useState("solo");
  const [phases,setPhases]=useState(["idle","idle"]);
  const [elapsed,setElapsed]=useState([0,0]);
  const [progress,setProgress]=useState([0,0]);
  const [done,setDone]=useState(false);
  const [winner,setWinner]=useState(null);

  const phaseRef=useRef(["idle","idle"]);
  const startRef=useRef([null,null]);
  const holdStartRef=useRef([null,null]);
  const holdFrameRef=useRef([null,null]);
  const elRef=useRef([0,0]);
  const doneRef=useRef(false);
  const frameRef=useRef(null);

  useEffect(()=>{ phaseRef.current=phases; },[phases]);

  useEffect(()=>{
    if(done){cancelAnimationFrame(frameRef.current);return;}
    const loop=()=>{
      const now=performance.now();
      setElapsed(prev=>{
        const n=[...prev];
        for(let p=0;p<2;p++)
          if(phaseRef.current[p]==="run"&&startRef.current[p]!==null)
            n[p]=now-startRef.current[p];
        return n;
      });
      frameRef.current=requestAnimationFrame(loop);
    };
    frameRef.current=requestAnimationFrame(loop);
    return()=>cancelAnimationFrame(frameRef.current);
  },[done]);

  const finalize=useCallback((e0,e1)=>{
    if(doneRef.current)return;
    doneRef.current=true;
    cancelAnimationFrame(frameRef.current);
    const w=e0<=e1?0:1;
    setWinner(w);setDone(true);
    setPhases(prev=>{const n=[...prev];n[w]="win";n[w===0?1:0]="lose";return n;});
  },[]);

  const onDown=useCallback((player)=>{
    if(doneRef.current)return;
    const ph=phaseRef.current[player];
    if(ph==="idle"){
      holdStartRef.current[player]=performance.now();
      setPhases(prev=>{const n=[...prev];n[player]="hold";return n;});
      const loop=()=>{
        if(!holdStartRef.current[player])return;
        const prog=Math.min(1,(performance.now()-holdStartRef.current[player])/HOLD_MS);
        setProgress(prev=>{const n=[...prev];n[player]=prog;return n;});
        if(prog<1){
          holdFrameRef.current[player]=requestAnimationFrame(loop);
        } else {
          holdStartRef.current[player]=null;
          haptic(50);
          setPhases(prev=>{const n=[...prev];n[player]="ready";return n;});
        }
      };
      holdFrameRef.current[player]=requestAnimationFrame(loop);
    } else if(ph==="run"){
      const el=performance.now()-startRef.current[player];
      startRef.current[player]=null;
      elRef.current[player]=el;
      setElapsed(prev=>{const n=[...prev];n[player]=el;return n;});
      const other=player===0?1:0;
      const otherPh=phaseRef.current[other];
      setPhases(prev=>{const n=[...prev];n[player]="stop";return n;});
      if(otherPh==="stop"){
        finalize(player===0?el:elRef.current[0],player===1?el:elRef.current[1]);
      }
    }
  },[finalize]);

  const onUp=useCallback((player)=>{
    const ph=phaseRef.current[player];
    if(ph==="ready"){
      startRef.current[player]=performance.now();
      setPhases(prev=>{const n=[...prev];n[player]="run";return n;});
    } else if(ph==="hold"){
      cancelAnimationFrame(holdFrameRef.current[player]);
      holdStartRef.current[player]=null;
      setProgress(prev=>{const n=[...prev];n[player]=0;return n;});
      setPhases(prev=>{const n=[...prev];n[player]="idle";return n;});
    }
  },[]);

  const reset=()=>{
    cancelAnimationFrame(frameRef.current);
    [0,1].forEach(p=>{
      cancelAnimationFrame(holdFrameRef.current[p]);
      holdStartRef.current[p]=null;
      startRef.current[p]=null;
    });
    doneRef.current=false;
    phaseRef.current=["idle","idle"];
    elRef.current=[0,0];
    setPhases(["idle","idle"]);
    setElapsed([0,0]);
    setProgress([0,0]);
    setDone(false);
    setWinner(null);
  };

  return(
    <div className="scs">
      {/* Mode toggle header */}
      <div style={{position:"absolute",top:0,left:0,right:0,zIndex:50,display:"flex",justifyContent:"center",padding:"10px 0",pointerEvents:"none"}}>
        <div className="scs-mode-toggle" style={{pointerEvents:"all"}} onPointerDown={e=>e.stopPropagation()}>
          <div className={"scs-mode-btn"+(mode==="solo"?" active":"")} onPointerDown={()=>{setMode("solo");reset();}}>Solo</div>
          <div className={"scs-mode-btn"+(mode==="duel"?" active":"")} onPointerDown={()=>{setMode("duel");reset();}}>Duel</div>
        </div>
      </div>

      {mode==="solo"?(
        <SoloCsTimerSolo user={p0}/>
      ):(
        <>
          <SoloCsTimerPanel player={1} phase={phases[1]} elapsed={elapsed[1]} progress={progress[1]}
            onDown={onDown} onUp={onUp} user={p1} isDone={done} isWinner={winner===1}/>
          <div className="scs-div"><div className="scs-vs">VS</div></div>
          <SoloCsTimerPanel player={0} phase={phases[0]} elapsed={elapsed[0]} progress={progress[0]}
            onDown={onDown} onUp={onUp} user={p0} isDone={done} isWinner={winner===0}/>
          <div className="scs-footer" onPointerDown={e=>e.stopPropagation()}>
            <button className="scs-reset" onPointerDown={reset}>↺ Reset</button>
            <button className="scs-close" onPointerDown={onClose}>✕ Fermer</button>
          </div>
        </>
      )}

      {/* Close button always visible in solo mode */}
      {mode==="solo"&&(
        <div style={{position:"absolute",top:10,right:14,zIndex:60}} onPointerDown={e=>e.stopPropagation()}>
          <button className="scs-close" onPointerDown={onClose}>✕</button>
        </div>
      )}
    </div>
  );
}

/* ══ TOURNAMENT ══ */
function buildRound(players){
  return players.reduce((acc,_,i)=>i%2===0?[...acc,{p1:players[i],p2:players[i+1]||null,winner:null}]:acc,[]);
}
function TournamentScreen({onClose,onStartMatch}){
  const [size,setSize]=useState(4);
  const DEFAULT_NAMES=["Joueur 1","Joueur 2","Joueur 3","Joueur 4","Joueur 5","Joueur 6","Joueur 7","Joueur 8"];
  const [names,setNames]=useState(DEFAULT_NAMES);
  const [editIdx,setEditIdx]=useState(null);
  const [bracket,setBracket]=useState(null);
  const [phase,setPhase]=useState("setup");
  const setName=(i,v)=>setNames(prev=>{const n=[...prev];n[i]=v||DEFAULT_NAMES[i];return n;});
  const start=()=>{
    setEditIdx(null);
    const players=names.slice(0,size).map((n,i)=>({name:n||DEFAULT_NAMES[i],id:i}));
    setBracket({rounds:[buildRound(players)],currentRound:0,champion:null});
    setPhase("bracket");
  };
  const recordWin=(ri,mi,bracketWinnerId)=>{
    setBracket(prev=>{
      const b=JSON.parse(JSON.stringify(prev));
      b.rounds[ri][mi].winner=bracketWinnerId;
      const round=b.rounds[ri];
      if(round.every(m=>m.winner!==null)){
        const winners=round.map(m=>m.p1&&m.p1.id===m.winner?m.p1:m.p2);
        if(winners.length>1){b.rounds.push(buildRound(winners));b.currentRound=ri+1;}
        else{b.champion=winners[0];}
      }
      return b;
    });
  };
  const champion=bracket&&bracket.champion;
  const totalRounds=Math.log2(size);
  const getRoundName=(ri)=>{
    const rem=totalRounds-ri;
    if(rem===1)return"Finale";
    if(rem===2)return"Demi-finales";
    if(rem===3)return"Quarts de finale";
    return"Tour "+(ri+1);
  };
  return(
    <div className="trn">
      <div className="trn-hd">
        <div className="trn-title">Tournoi</div>
        <div className="trn-close" onPointerDown={onClose}>✕</div>
      </div>
      <div className="trn-body">
        {phase==="setup"&&(
          <div className="trn-setup">
            <div>
              <div className="cfg-section">Nombre de joueurs</div>
              <div className="trn-size-row">
                {[4,8].map(s=>(
                  <div key={s} className={"trn-size-btn"+(size===s?" sel":"")} onPointerDown={()=>setSize(s)}>
                    {s+" joueurs"}
                  </div>
                ))}
              </div>
            </div>
            <div>
              <div className="cfg-section">Joueurs — appuyez pour renommer</div>
              <div className="trn-players-grid">
                {names.slice(0,size).map((n,i)=>(
                  <div key={i} className={"trn-player-slot"+(editIdx===i?" trn-p-slot-edit":"")}
                    onPointerDown={()=>setEditIdx(i)}>
                    <div className="trn-p-num">{i+1}</div>
                    <RubiksCube player={i%2} size="sm"/>
                    {editIdx===i
                      ?<input className="trn-p-input" autoFocus
                          defaultValue={n} maxLength={12}
                          onChange={e=>setName(i,e.target.value)}
                          onBlur={()=>setEditIdx(null)}
                          onPointerDown={e=>e.stopPropagation()}/>
                      :<div className="trn-p-name">{n}</div>
                    }
                  </div>
                ))}
              </div>
            </div>
            <button className="trn-start-btn" onPointerDown={start}>Démarrer le tournoi</button>
          </div>
        )}
        {phase==="bracket"&&bracket&&(
          <div className="trn-bracket">
            {champion&&(
              <div className="trn-winner-banner">
                <div className="trn-w-ico">🏆</div>
                <div className="trn-w-title">{"Champion : "+champion.name}</div>
                <div className="trn-w-sub">Tournoi terminé !</div>
                <button className="trn-new-btn" onPointerDown={()=>{setBracket(null);setPhase("setup");}}>Nouveau tournoi</button>
              </div>
            )}
            {bracket.rounds.map((round,ri)=>(
              <div key={ri}>
                <div className="trn-round-title">{getRoundName(ri)}</div>
                {round.map((match,mi)=>{
                  const isDone=match.winner!==null;
                  const isActive=ri===bracket.currentRound&&!isDone&&!champion;
                  return(
                    <div key={mi} className={"trn-match"+(isActive?" active":isDone?" done":"")}>
                      {[match.p1,match.p2].map((pl,pi)=>pl?(
                        <div key={pi} className={"trn-m-row"+(match.winner===pl.id?" won":"")}>
                          <div className="trn-m-name">{pl.name}</div>
                          {match.winner===pl.id&&<span style={{fontSize:12,marginRight:4}}>♛</span>}
                          <div className="trn-m-score">{match.winner===pl.id?"1":isDone?"0":"-"}</div>
                        </div>
                      ):(
                        <div key={pi} className="trn-m-row" style={{opacity:.4}}>
                          <div className="trn-m-name">En attente…</div>
                          <div className="trn-m-score">-</div>
                        </div>
                      ))}
                      {isActive&&match.p1&&match.p2&&(
                        <div className="trn-m-play" onPointerDown={()=>{
                          onStartMatch(match,(localW)=>recordWin(ri,mi,localW===0?match.p1.id:match.p2.id));
                        }}>▶ Jouer ce match</div>
                      )}
                      {isActive&&(!match.p1||!match.p2)&&(
                        <div className="trn-m-tbd">En attente des matchs précédents</div>
                      )}
                    </div>
                  );
                })}
              </div>
            ))}
          </div>
        )}
      </div>
    </div>
  );
}

/* ══ HISTORY ══ */
function HistoryScreen({history,onClose,onClear}){
  return(
    <div className="hist">
      <div className="hist-hd">
        <div className="hist-title">Historique</div>
        <div className="hist-close" onPointerDown={onClose}>✕</div>
      </div>
      <div className="hist-body">
        {history.length===0?(
          <div className="hist-empty">
            <div className="hist-empty-ico">🕐</div>
            <div className="hist-empty-lbl">Aucune partie</div>
          </div>
        ):(
          <>
            {[...history].reverse().map((g,idx)=>(
              <div key={g.id} className={"hist-entry w"+g.winner} style={{animationDelay:(idx*0.05)+"s"}}>
                <div className="hist-row1">
                  <div className="hist-date">{fmtDate(g.ts)}</div>
                  <div className={"hist-badge b"+g.winner}>{"J"+(g.winner+1)+" Gagne"}</div>
                </div>
                <div className="hist-players">
                  {[0,1].map(p=>(
                    <div key={p} className={"hist-player"+(g.winner===p?" winner":"")}>
                      <div className="hist-p-top">
                        <RubiksCube player={p} size="sm"/>
                        <div className="hist-p-name">{"J"+(p+1)}</div>
                        {g.winner===p&&<span style={{fontSize:11}}>♛</span>}
                      </div>
                      <div className="hist-p-time">{fmt(g.times[p])}</div>
                      <div className="hist-p-meta">{"Cube x"+g.cubeWins[p]+(g.penaltyTotal&&g.penaltyTotal[p]>0?"  •  -"+g.penaltyTotal[p]+"s pénalité":"")}</div>
                    </div>
                  ))}
                </div>
                <div className="hist-footer">
                  <div className="hist-meta">{g.moves+" coups  •  "+g.csCount+" CS"}</div>
                  <div className="hist-meta">{g.timeLabel+"  •  "+g.why}</div>
                </div>
              </div>
            ))}
            <div style={{display:"flex",justifyContent:"center",paddingTop:8}}>
              <button className="hist-clear" onPointerDown={onClear}>Effacer l'historique</button>
            </div>
          </>
        )}
      </div>
    </div>
  );
}

/* ══ CONFIG SCREEN ══ */
function ConfigScreen({onStart,history,onShowHistory,onShowTournament,onShowUsers,onShowSoloCsTimer,rules,onRulesChange,users,selIds}){
  const [sel,setSel]=useState(2);
  const [sct,setSct]=useState(7);
  const [showModal,setShowModal]=useState(false);
  const [cBase,setCBase]=useState(300);
  const [cInc,setCInc]=useState(0);
  const sp=(set,d,mn,mx)=>set(v=>Math.max(mn,Math.min(mx,v+d)));
  const isCustom=sel===-1;
  const activeBase=isCustom?cBase:PRESETS[sel].base;
  const activeInc=isCustom?cInc:PRESETS[sel].inc;
  const cMins=Math.floor(cBase/60);
  const cSecs=cBase%60;
  const tog=(k)=>onRulesChange({...rules,[k]:!rules[k]});
  const u0=users.find(u=>u.id===selIds[0])||users[0];
  const u1=users.find(u=>u.id===selIds[1])||users[1];
  return(
    <div className="cfg">
      <div className="cfg-hd">
        <div className="cfg-logo">CHESSCUBING CLOCK</div>
        <div style={{display:"flex",alignItems:"center",justifyContent:"center",gap:8,marginTop:4}}><img src={"data:image/png;base64,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"} style={{width:32,height:32,borderRadius:7,flexShrink:0}} alt="logo"/><div className="cfg-sub" style={{margin:0}}>Speed Challenge Edition</div></div>
        <div className="cfg-hd-row">
          <div style={{display:"flex",alignItems:"center",gap:5}}>
            <div style={{fontSize:18}}>{u0.avatar}</div>
            <span style={{fontSize:8,letterSpacing:3,color:"var(--dim)",textTransform:"uppercase"}}>{u0.name}</span>
          </div>
          <div className="icon-btn" onPointerDown={onShowUsers}>
            <span style={{fontSize:12}}>👥</span>
            <span className="icon-btn-lbl">Joueurs</span>
          </div>
          <div className="icon-btn" onPointerDown={onShowHistory}>
            <span style={{fontSize:12}}>📋</span>
            <span className="icon-btn-lbl">{"("+history.length+")"}</span>
          </div>
          <div className="icon-btn" onPointerDown={onShowTournament}>
            <span style={{fontSize:12}}>🏆</span>
            <span className="icon-btn-lbl">Tournoi</span>
          </div>
          <div className="icon-btn" onPointerDown={onShowSoloCsTimer}>
            <span style={{fontSize:12}}>⚡</span>
            <span className="icon-btn-lbl">CS Timer</span>
          </div>
          <div style={{display:"flex",alignItems:"center",gap:5}}>
            <span style={{fontSize:8,letterSpacing:3,color:"var(--dim)",textTransform:"uppercase"}}>{u1.name}</span>
            <div style={{fontSize:18}}>{u1.avatar}</div>
          </div>
        </div>
      </div>
      <div className="cfg-body">
        <div className="cfg-section">CS Timer — tous les</div>
        <div className="cfg-card">
          <div className="toggle-row">
            <div className="toggle-lbl">
              <div className="toggle-name">⚡ CS Timer activé</div>
              <div className="toggle-desc">Résolvez un cube Rubik's tous les N coups pour gagner x2</div>
            </div>
            <div className={"toggle"+(rules.csEnabled?" on":"")} onPointerDown={()=>tog("csEnabled")}><div className="toggle-knob"/></div>
          </div>
          {rules.csEnabled&&(
          <div className="cfg-stepper">
            <div className="cfg-s-lbl">Coups avant CS Timer</div>
            <div style={{display:"flex",alignItems:"center",gap:5}}>
              <div className="cfg-btns"><div className="cfg-btn" onPointerDown={()=>sp(setSct,-1,2,20)}>−</div></div>
              <div className="cfg-s-val">{sct}</div>
              <div className="cfg-btns"><div className="cfg-btn" onPointerDown={()=>sp(setSct,+1,2,20)}>+</div></div>
            </div>
          </div>
          )}
        </div>
        <div className="cfg-section">Règles de gameplay</div>
        <div className="cfg-card">
          <div className="toggle-row">
            <div className="toggle-lbl">
              <div className="toggle-name">⚔ Coups interdits</div>
              <div className="toggle-desc">Double coup : prise de dame interdite</div>
            </div>
            <div className={"toggle"+(rules.forbidCapture?" on":"")} onPointerDown={()=>tog("forbidCapture")}><div className="toggle-knob"/></div>
          </div>
          <div className="toggle-row">
            <div className="toggle-lbl">
              <div className="toggle-name">{"⏳ Malus de temps ("+rules.moveLimitSec+"s / -"+rules.penaltySec+"s)"}</div>
              <div className="toggle-desc">Dépasser la limite par coup = pénalité</div>
            </div>
            <div className={"toggle"+(rules.penaltyEnabled?" on":"")} onPointerDown={()=>tog("penaltyEnabled")}><div className="toggle-knob"/></div>
          </div>
          {rules.penaltyEnabled&&(
            <div style={{display:"flex",gap:0}}>
              <div className="cfg-stepper" style={{flex:1,borderRight:"1px solid rgba(255,255,255,.04)"}}>
                <div className="cfg-s-lbl" style={{fontSize:10}}>Limite/coup</div>
                <div style={{display:"flex",alignItems:"center",gap:3}}>
                  <div className="cfg-btns"><div className="cfg-btn" style={{width:27,height:27,fontSize:15}} onPointerDown={()=>onRulesChange({...rules,moveLimitSec:Math.max(5,rules.moveLimitSec-5)})}>−</div></div>
                  <div className="cfg-s-val" style={{fontSize:18,minWidth:28}}>{rules.moveLimitSec+"s"}</div>
                  <div className="cfg-btns"><div className="cfg-btn" style={{width:27,height:27,fontSize:15}} onPointerDown={()=>onRulesChange({...rules,moveLimitSec:Math.min(60,rules.moveLimitSec+5)})}>+</div></div>
                </div>
              </div>
              <div className="cfg-stepper" style={{flex:1}}>
                <div className="cfg-s-lbl" style={{fontSize:10}}>Pénalité</div>
                <div style={{display:"flex",alignItems:"center",gap:3}}>
                  <div className="cfg-btns"><div className="cfg-btn" style={{width:27,height:27,fontSize:15}} onPointerDown={()=>onRulesChange({...rules,penaltySec:Math.max(5,rules.penaltySec-5)})}>−</div></div>
                  <div className="cfg-s-val" style={{fontSize:18,minWidth:28}}>{rules.penaltySec+"s"}</div>
                  <div className="cfg-btns"><div className="cfg-btn" style={{width:27,height:27,fontSize:15}} onPointerDown={()=>onRulesChange({...rules,penaltySec:Math.min(60,rules.penaltySec+5)})}>+</div></div>
                </div>
              </div>
            </div>
          )}
          {rules.csEnabled&&(
          <div className="toggle-row">
            <div className="toggle-lbl">
              <div className="toggle-name">🎲 Mode Chaos</div>
              <div className="toggle-desc">Seuil CS Timer aléatoire à chaque cycle</div>
            </div>
            <div className={"toggle chaos"+(rules.chaosMode?" on":"")} onPointerDown={()=>tog("chaosMode")}><div className="toggle-knob"/></div>
          </div>
          )}
          {rules.csEnabled&&(
          <div className="toggle-row">
            <div className="toggle-lbl">
              <div className="toggle-name">🧩 Préparation Rubik's</div>
              <div className="toggle-desc">Mélange officiel à mémoriser avant la partie</div>
            </div>
            <div className={"toggle"+(rules.cubePrepEnabled?" on":"")} onPointerDown={()=>tog("cubePrepEnabled")}><div className="toggle-knob"/></div>
          </div>
          )}
        </div>
        <div className="cfg-section">Expérience</div>
        <div className="cfg-card">
          <div className="toggle-row">
            <div className="toggle-lbl">
              <div className="toggle-name">🔊 Sons</div>
              <div className="toggle-desc">Tic-tac, swoosh CS Timer, fanfare victoire</div>
            </div>
            <div className={"toggle"+(rules.soundEnabled?" on":"")} onPointerDown={()=>tog("soundEnabled")}><div className="toggle-knob"/></div>
          </div>
          <div className="toggle-row">
            <div className="toggle-lbl">
              <div className="toggle-name">📳 Vibrations</div>
              <div className="toggle-desc">Retour haptique sur chaque action</div>
            </div>
            <div className={"toggle"+(rules.hapticEnabled?" on":"")} onPointerDown={()=>tog("hapticEnabled")}><div className="toggle-knob"/></div>
          </div>
        </div>
        <div className="cfg-section">Temps de jeu</div>
        <div className={"cfg-custom"+(isCustom?" c-on":"")} onPointerDown={()=>setShowModal(true)}>
          <div>
            <div className="cfg-c-main">{isCustom?buildPreview(cMins,cSecs,cInc):"✦  Temps personnalisé"}</div>
            {isCustom&&<div className="cfg-c-detail">{cInc>0?"+ "+cInc+" sec/coup":"Sans incrément"}{"  ·  Perso"}</div>}
          </div>
          <span className="cfg-c-arrow">{isCustom?"✏":"›"}</span>
        </div>
        {["BULLET","BLITZ","RAPID","CLASSIC"].map(tag=>(
          <div key={tag} style={{marginBottom:8}}>
            <div style={{fontSize:9,letterSpacing:4,color:TAG_COLORS[tag],textTransform:"uppercase",padding:"0 3px 5px",fontWeight:700}}>{tag}</div>
            <div className="cfg-card">
              {PRESETS.filter(p=>p.tag===tag).map(p=>{
                const i=PRESETS.indexOf(p);
                let _sy=null;
                return(
                  <div key={i} className={"cfg-row"+(!isCustom&&sel===i?" sel":"")}
                    onPointerDown={e=>{_sy=e.clientY;}}
                    onPointerUp={e=>{if(_sy!==null&&Math.abs(e.clientY-_sy)<10){setSel(i);}_sy=null;}}>
                    <div style={{display:"flex",flexDirection:"column",gap:2}}>
                      <span className="cfg-row-lbl">{p.base<60?p.base+"s":Math.floor(p.base/60)+" min"}</span>
                      {p.inc>0&&<span style={{fontSize:9,color:"var(--dim)"}}>{"+ "+p.inc+" sec/coup"}</span>}
                    </div>
                    <span className="cfg-chk">✓</span>
                  </div>
                );
              })}
            </div>
          </div>
        ))}
        <div style={{padding:"5px 0 3px",fontSize:9,letterSpacing:2,color:"var(--dim)",textAlign:"center",textTransform:"uppercase"}}>
          {"⚡ Après "+sct+" coups — CS Timer — le gagnant joue x2"}
        </div>
      </div>
      <div className="cfg-ft">
        <button className="start-btn" onPointerDown={()=>onStart(activeBase,activeInc,sct,isCustom?buildPreview(cMins,cSecs,cInc):PRESETS[sel].lbl)}>
          Démarrer la Partie
        </button>
      </div>
      {showModal&&(
        <CustomModal initMin={cMins} initSec={cSecs} initInc={cInc}
          onConfirm={(base,inc)=>{setCBase(base);setCInc(inc);setSel(-1);setShowModal(false);}}
          onCancel={()=>setShowModal(false)}/>
      )}
    </div>
  );
}

/* ══ MOVE DOTS ══ */
function Dots({moves,sct}){
  const inC=moves===0?0:((moves-1)%sct)+1;
  const onT=moves>0&&moves%sct===0;
  return(
    <div className="dots">
      {Array.from({length:sct},(_,i)=>{
        const filled=i<(onT?sct:inC);
        return <div key={i} className={"dot"+(filled?" f":"")+(i===sct-1?" t":"")}/>;
      })}
    </div>
  );
}

/* ══ CS OVERLAY ══ */
function CSOverlay({phase,elapsed,isDone,isWinner,onDown,onUp,player,holdProgress}){
  const {onPD,onPM,onPU,onPC}=useScrollGuard(onDown,onUp,player);
  const CIRC=264; // circumference for r=42 circle
  const prog=Math.min(1,holdProgress||0);
  const offset=CIRC*(1-prog);

  let ts,tc,ls,lc,hint;
  if(isDone){ts=fmtMs(elapsed);tc=isWinner?"win":"lose";ls=isWinner?"Victoire !":"Éliminé";lc=isWinner?"grn":"dim";hint=isWinner?"2 coups consécutifs !":"";}
  else if(phase==="idle"){ts="0.00";tc="idle";ls="CS TIMER";lc="blu";hint="Maintenez appuyé";}
  else if(phase==="hold"){ts="0.00";tc="hold";ls="CHARGEZ…";lc="grn";hint="Ne relâchez pas !";}
  else if(phase==="ready"){ts="GO";tc="hold";ls="RELÂCHEZ !";lc="grn";hint="Relâchez pour démarrer";}
  else if(phase==="run"){ts=fmtMs(elapsed);tc="run";ls="⏱";lc="red";hint="Appuyez pour stopper";}
  else{ts=fmtMs(elapsed);tc="stop";ls="Stoppé";lc="dim";hint="En attente…";}
  const bgc=isDone?(isWinner?"win":"lose"):phase==="ready"?"hold":phase;

  return(
    <div className="cso"
      onPointerDown={onPD}
      onPointerMove={onPM}
      onPointerUp={onPU}
      onPointerCancel={onPC}>
      <div className={"cso-bg "+bgc}/>
      <div className={"cso-lbl "+lc}>{ls}</div>

      {(phase==="hold"||phase==="ready")&&!isDone&&(
        <div className="cso-ring" style={{width:100,height:100}}>
          <svg viewBox="0 0 100 100" width="100" height="100" style={{position:"absolute",top:0,left:0,overflow:"visible"}}>
            <circle cx="50" cy="50" r="42" fill="none" stroke="rgba(255,255,255,.10)" strokeWidth="5"/>
            <circle cx="50" cy="50" r="42" fill="none"
              stroke={phase==="ready"?"#ffffff":"#7affc0"}
              strokeWidth="7"
              strokeLinecap="round"
              strokeDasharray={""+CIRC}
              strokeDashoffset={phase==="ready"?"0":""+offset}
              transform="rotate(-90 50 50)"
              style={phase==="ready"?{animation:"wbreathe .4s ease-in-out infinite alternate"}:{}}/>
          </svg>
          <div className={"cso-t "+tc} style={{position:"relative",zIndex:1}}>
            {phase==="ready"?"GO":Math.round(prog*100)+"%"}
          </div>
        </div>
      )}

      {phase==="run"&&!isDone&&(
        <div className="cso-ring" style={{width:100,height:100}}>
          <svg viewBox="0 0 100 100" width="100" height="100" style={{position:"absolute",top:0,left:0,overflow:"visible"}}>
            <circle cx="50" cy="50" r="42" fill="none" stroke="rgba(255,255,255,.08)" strokeWidth="5"/>
            <circle cx="50" cy="50" r="42" fill="none"
              stroke="#80ffbe" strokeWidth="5" strokeLinecap="round"
              strokeDasharray="60 204"
              transform="rotate(-90 50 50)"
              style={{animation:"rspin .7s linear infinite"}}/>
            <circle cx="50" cy="50" r="38" fill="none"
              stroke="rgba(80,255,160,.2)" strokeWidth="3" strokeLinecap="round"
              strokeDasharray="30 208"
              transform="rotate(-90 50 50)"
              style={{animation:"rspin2 1.4s linear infinite reverse"}}/>
          </svg>
          <div className={"cso-t "+tc} style={{position:"relative",zIndex:1}}>{ts}</div>
        </div>
      )}

      {phase!=="hold"&&phase!=="ready"&&phase!=="run"&&(
        <div className={"cso-t "+tc}>{ts}</div>
      )}

      {isDone&&isWinner?<div className="cso-win">{hint}</div>:hint?<div className="cso-hint">{hint}</div>:null}
    </div>
  );
}

/* ══ DOUBLE MOVE OVERLAY ══ */
function DblOverlay({isWinner,movesLeft,forbidCapture,showChallenge}){
  return(
    <div className="dbl">
      {isWinner?<div className="dbl-bw"/>:<div className="dbl-bl"/>}
      {isWinner?(
        <div className="dbl-card win-card">
          <div className="dbl-icon">⚡</div>
          <div className="dbl-title">Double Coup !</div>
          {forbidCapture&&<div className="dbl-sub">⚔ Prise de dame interdite</div>}
          <div className="dbl-pips">
            {[0,1].map(i=><div key={i} className={"dbl-pip"+(i>=movesLeft?" used":"")}/>)}
          </div>
          <div className="dbl-hint">Appuyez pour jouer</div>
        </div>
      ):(
        <div className="dbl-card lose-card">
          <div className="dbl-wait-ico">⏳</div>
          <div className="dbl-wait-title">Adversaire joue 2 coups…</div>
          <div className="dbl-wait-sub">Attendez votre tour</div>
          {forbidCapture&&showChallenge&&(
            <div className="dbl-challenge">⚔ Appuyez pour contester une prise</div>
          )}
        </div>
      )}
    </div>
  );
}

/* ══ GAME SCREEN ══ */
function GameScreen({initTime,inc,sct,timeLabel,onBack,onGameEnd,rules,playerNames,tournamentCb,profiles}){
  const [times,setTimes]=useState([initTime,initTime]);
  const [active,setActive]=useState(null);
  const [moves,setMoves]=useState(0);
  const [paused,setPaused]=useState(false);
  const [scOn,setScOn]=useState(false);
  const [csPhase,setCsPhase]=useState(["idle","idle"]);
  const [csEl,setCsEl]=useState([0,0]);
  const [scDone,setScDone]=useState(false);
  const [scWin,setScWin]=useState(null);
  const [dbl,setDbl]=useState(false);
  const [dblP,setDblP]=useState(null);
  const [dblL,setDblL]=useState(2);
  const [over,setOver]=useState(false);
  const [winner,setWinner]=useState(null);
  const [why,setWhy]=useState("");
  const [ripple,setRipple]=useState([null,null]);
  const [cubeWins,setCubeWins]=useState([0,0]);
  const [pendingWin,setPendingWin]=useState(null);
  const [penaltyFlash,setPenaltyFlash]=useState(null);
  const [totalPenalty,setTotalPenalty]=useState([0,0]);
  const [moveTimer,setMoveTimer]=useState(0);
  const [showForbidden,setShowForbidden]=useState(null);
  const [showChallenge,setShowChallenge]=useState(false);
  const [snapshots,setSnapshots]=useState([]);
  const [currentSct,setCurrentSct]=useState(sct);
  const [eloDelta,setEloDelta]=useState([0,0]);

  const clockRef=useRef(null),frameRef=useRef(null),startRef=useRef([null,null]);
  const doneRef=useRef(false),phaseRef=useRef(["idle","idle"]),elRef=useRef([0,0]);
  const movesRef=useRef(0),cubeWinsRef=useRef([0,0]),csCountRef=useRef(0);
  const penaltyRef=useRef([0,0]),pendingTimerRef=useRef(null);
  const moveStartRef=useRef(null),moveFrameRef=useRef(null);
  const timesRef=useRef([initTime,initTime]);
  const currentSctRef=useRef(sct);
  const holdStartRef=useRef([null,null]);
  const holdFrameRef=useRef([null,null]);

  const HOLD_DURATION=900; // ms to fill the circle

  const [holdProgress,setHoldProgress]=useState([0,0]);

  useEffect(()=>{phaseRef.current=csPhase;},[csPhase]);
  useEffect(()=>{elRef.current=csEl;},[csEl]);
  useEffect(()=>{doneRef.current=scDone;},[scDone]);
  useEffect(()=>{movesRef.current=moves;},[moves]);
  useEffect(()=>{cubeWinsRef.current=cubeWins;},[cubeWins]);
  useEffect(()=>{csCountRef.current=Math.floor(moves/currentSct);},[moves,currentSct]);
  useEffect(()=>{penaltyRef.current=totalPenalty;},[totalPenalty]);
  useEffect(()=>{timesRef.current=times;},[times]);
  useEffect(()=>{currentSctRef.current=currentSct;},[currentSct]);

  // Challenge hint
  useEffect(()=>{
    if(dbl&&rules.forbidCapture){
      const t=setTimeout(()=>setShowChallenge(true),400);
      return()=>clearTimeout(t);
    } else { setShowChallenge(false); }
  },[dbl,rules.forbidCapture]);

  // Tick-tock sounds
  useEffect(()=>{
    if(!rules.soundEnabled||active===null||paused||scOn||dbl||over)return;
    const id=setInterval(()=>{ if(active===0)playTick(); else playTock(); },1000);
    return()=>clearInterval(id);
  },[active,paused,scOn,dbl,over,rules.soundEnabled]);

  // Chess clock
  useEffect(()=>{
    if(active===null||paused||scOn||dbl||over){clearInterval(clockRef.current);return;}
    clockRef.current=setInterval(()=>{
      setTimes(prev=>{
        const n=[...prev];
        n[active]=Math.max(0,n[active]-0.1);
        if(n[active]<=0){
          const w=active===0?1:0;
          const d=[calcElo(profiles.p0.elo,profiles.p1.elo,w===0?1:0),calcElo(profiles.p1.elo,profiles.p0.elo,w===1?1:0)];
          setEloDelta(d);
          setOver(true);setWinner(w);setWhy("Temps écoulé");
          if(rules.soundEnabled)playFanfare();
          if(rules.hapticEnabled)haptic([50,50,150]);
          if(onGameEnd)onGameEnd({winner:w,times:n,moves:movesRef.current,csCount:csCountRef.current,cubeWins:cubeWinsRef.current,timeLabel,ts:Date.now(),penaltyTotal:penaltyRef.current,why:"Temps écoulé",snapshots,eloDelta:d,names:[profiles.p0.name,profiles.p1.name],avatars:[profiles.p0.avatar,profiles.p1.avatar]});
          if(tournamentCb)tournamentCb(w);
        }
        return n;
      });
    },100);
    return()=>clearInterval(clockRef.current);
  },[active,paused,scOn,dbl,over]);

  // Move timer bar
  useEffect(()=>{
    if(!rules.penaltyEnabled||active===null||paused||scOn||dbl||over){cancelAnimationFrame(moveFrameRef.current);return;}
    moveStartRef.current=performance.now();
    const loop=()=>{setMoveTimer((performance.now()-moveStartRef.current)/1000);moveFrameRef.current=requestAnimationFrame(loop);};
    moveFrameRef.current=requestAnimationFrame(loop);
    return()=>cancelAnimationFrame(moveFrameRef.current);
  },[active,paused,scOn,dbl,over,rules.penaltyEnabled]);

  // CS Timer RAF
  useEffect(()=>{
    if(!scOn||scDone){cancelAnimationFrame(frameRef.current);return;}
    const loop=()=>{
      const now=performance.now();
      setCsEl(prev=>{const n=[...prev];for(let p=0;p<2;p++)if(phaseRef.current[p]==="run"&&startRef.current[p]!==null)n[p]=now-startRef.current[p];return n;});
      frameRef.current=requestAnimationFrame(loop);
    };
    frameRef.current=requestAnimationFrame(loop);
    return()=>cancelAnimationFrame(frameRef.current);
  },[scOn,scDone]);

  const finalize=useCallback((e0,e1)=>{
    if(doneRef.current)return;
    doneRef.current=true;
    const w=e0<=e1?0:1;
    setScDone(true);setScWin(w);
    cancelAnimationFrame(frameRef.current);
    setCubeWins(prev=>{const n=[...prev];n[w]++;return n;});
    if(rules.soundEnabled)playSwoop();
    if(rules.hapticEnabled)haptic([30,20,80]);
    const nextSct=rules.chaosMode?Math.max(2,sct+Math.floor(Math.random()*5)-1):sct;
    setTimeout(()=>{
      setScOn(false);setCsPhase(["idle","idle"]);setCsEl([0,0]);
      startRef.current=[null,null];setScDone(false);doneRef.current=false;setScWin(null);
      setCurrentSct(nextSct);
      setDbl(true);setDblP(w);setDblL(2);setActive(w);
    },1200);
  },[rules,sct]);

  const csDown=useCallback((player)=>{
    if(!scOn||doneRef.current)return;
    const ph=phaseRef.current[player];
    if(ph==="idle"){
      holdStartRef.current[player]=performance.now();
      setCsPhase(prev=>{const n=[...prev];n[player]="hold";return n;});
      const loop=()=>{
        if(!holdStartRef.current[player])return;
        const prog=Math.min(1,(performance.now()-holdStartRef.current[player])/900);
        setHoldProgress(prev=>{const n=[...prev];n[player]=prog;return n;});
        if(prog<1){
          holdFrameRef.current[player]=requestAnimationFrame(loop);
        } else {
          // Circle full → ready to launch on release
          holdStartRef.current[player]=null;
          if(rules.hapticEnabled)haptic([60,40,60]);
          setCsPhase(prev=>{const n=[...prev];n[player]="ready";return n;});
        }
      };
      holdFrameRef.current[player]=requestAnimationFrame(loop);
    }
    else if(ph==="run"){
      const el=performance.now()-startRef.current[player];
      startRef.current[player]=null;
      setCsEl(prev=>{const n=[...prev];n[player]=el;return n;});
      setCsPhase(prev=>{const n=[...prev];n[player]="stop";const ot=player===0?1:0;if(n[ot]==="stop")finalize(player===0?el:elRef.current[0],player===1?el:elRef.current[1]);return n;});
    }
  },[scOn,finalize,rules.hapticEnabled]);

  const csUp=useCallback((player)=>{
    if(!scOn||doneRef.current)return;
    const ph=phaseRef.current[player];
    if(ph==="ready"){
      // Released after full → start timer now
      startRef.current[player]=performance.now();
      setCsPhase(prev=>{const n=[...prev];n[player]="run";return n;});
    } else if(ph==="hold"){
      // Released before full → cancel
      cancelAnimationFrame(holdFrameRef.current[player]);
      holdStartRef.current[player]=null;
      setHoldProgress(prev=>{const n=[...prev];n[player]=0;return n;});
      setCsPhase(prev=>{const n=[...prev];n[player]="idle";return n;});
    }
  },[scOn]);

  const fireRipple=(p)=>setRipple(prev=>{const n=[...prev];n[p]=Date.now();return n;});

  const applyPenalty=useCallback((player)=>{
    const pen=rules.penaltySec;
    setTimes(prev=>{const n=[...prev];n[player]=Math.max(0,n[player]-pen);return n;});
    setTotalPenalty(prev=>{const n=[...prev];n[player]+=pen;return n;});
    setPenaltyFlash(player);
    if(rules.soundEnabled)playWarn();
    if(rules.hapticEnabled)haptic([50,30,50,30,80]);
    setTimeout(()=>setPenaltyFlash(null),800);
  },[rules]);

  const handlePress=useCallback((player)=>{
    if(over||scOn)return;
    if(rules.hapticEnabled)haptic(50);
    fireRipple(player);
    if(active===null){setActive(player===0?1:0);setMoves(1);return;}
    if(dbl&&dblP!==null){
      if(player!==dblP){
        if(rules.forbidCapture){
          setShowChallenge(false);
          setShowForbidden(player);
          if(rules.hapticEnabled)haptic([80,40,80]);
          setTimeout(()=>setShowForbidden(null),2000);
          setDbl(false);setDblP(null);setActive(player);
        }
        return;
      }
      if(active!==player)return;
      const left=dblL-1;setDblL(left);
      if(left===0){setDbl(false);setDblP(null);setActive(player===0?1:0);}
      return;
    }
    if(active!==player)return;
    if(rules.penaltyEnabled&&moveStartRef.current!==null){
      const elapsed=(performance.now()-moveStartRef.current)/1000;
      if(elapsed>rules.moveLimitSec)applyPenalty(player);
    }
    cancelAnimationFrame(moveFrameRef.current);setMoveTimer(0);
    const nm=moves+1;setMoves(nm);
    setSnapshots(prev=>[...prev,{move:nm,t0:timesRef.current[0],t1:timesRef.current[1]}]);
    if(inc>0)setTimes(prev=>{const n=[...prev];n[player]+=inc;return n;});
    if(rules.soundEnabled){if(player===0)playTick();else playTock();}
    setActive(player===0?1:0);
    if(rules.csEnabled&&nm%currentSctRef.current===0){
      doneRef.current=false;startRef.current=[null,null];
      setScOn(true);setCsPhase(["idle","idle"]);setCsEl([0,0]);setScDone(false);setScWin(null);
      if(rules.soundEnabled)playSwoop();
      if(rules.hapticEnabled)haptic([50,40,50,40,50]);
    }
  },[active,over,scOn,dbl,dblP,dblL,moves,inc,rules,applyPenalty]);

  const declareWinner=useCallback((player)=>{
    if(over||scOn)return;
    if(pendingWin===player){
      clearTimeout(pendingTimerRef.current);setPendingWin(null);
      clearInterval(clockRef.current);
      setOver(true);setWinner(player);setWhy("Échec et mat");
      const d=[calcElo(profiles.p0.elo,profiles.p1.elo,player===0?1:0),calcElo(profiles.p1.elo,profiles.p0.elo,player===1?1:0)];
      setEloDelta(d);
      if(rules.soundEnabled)playFanfare();
      if(rules.hapticEnabled)haptic([50,50,150]);
      if(onGameEnd)onGameEnd({winner:player,times,moves:movesRef.current,csCount:csCountRef.current,cubeWins:cubeWinsRef.current,timeLabel,ts:Date.now(),penaltyTotal:penaltyRef.current,why:"Échec et mat",snapshots,eloDelta:d,names:[profiles.p0.name,profiles.p1.name],avatars:[profiles.p0.avatar,profiles.p1.avatar]});
      if(tournamentCb)tournamentCb(player);
    } else {
      clearTimeout(pendingTimerRef.current);setPendingWin(player);
      pendingTimerRef.current=setTimeout(()=>setPendingWin(null),3000);
    }
  },[over,scOn,pendingWin,times,timeLabel,onGameEnd,tournamentCb,rules,profiles,snapshots]);

  const reset=useCallback(()=>{
    clearInterval(clockRef.current);cancelAnimationFrame(frameRef.current);
    cancelAnimationFrame(moveFrameRef.current);clearTimeout(pendingTimerRef.current);
    cancelAnimationFrame(holdFrameRef.current[0]);cancelAnimationFrame(holdFrameRef.current[1]);
    holdStartRef.current=[null,null];holdFrameRef.current=[null,null];
    startRef.current=[null,null];doneRef.current=false;
    setTimes([initTime,initTime]);timesRef.current=[initTime,initTime];
    setActive(null);setMoves(0);setPaused(false);
    setScOn(false);setCsPhase(["idle","idle"]);setCsEl([0,0]);setScDone(false);setScWin(null);
    setDbl(false);setDblP(null);setDblL(2);setCurrentSct(sct);
    setOver(false);setWinner(null);setWhy("");setRipple([null,null]);
    setCubeWins([0,0]);setPendingWin(null);setPenaltyFlash(null);
    setTotalPenalty([0,0]);setMoveTimer(0);setShowForbidden(null);setShowChallenge(false);
    setSnapshots([]);setEloDelta([0,0]);setHoldProgress([0,0]);
  },[initTime,sct]);

  const [t0,t1]=times;
  const p0on=active===0&&!scOn&&!dbl;
  const p1on=active===1&&!scOn&&!dbl;
  const divLabel=over?"FIN":paused?"PAUSE":scOn?"CS TIMER":dbl?"x2":active===null?"APPUYEZ":"J"+(active+1)+" JOUE";
  const pName=playerNames||(profiles?[profiles.p0.name,profiles.p1.name]:["Joueur 1","Joueur 2"]);
  const pAv=profiles?[profiles.p0.avatar,profiles.p1.avatar]:["♟","♞"];
  const pStr=profiles?[profiles.p0.streak||0,profiles.p1.streak||0]:[0,0];
  const mtPct=rules.penaltyEnabled&&active!==null&&!scOn&&!dbl?Math.min(100,(moveTimer/rules.moveLimitSec)*100):0;
  const mtCls=mtPct>=100?"crit":mtPct>=75?"warn":"";

  return(
    <div className="game">
      {/* Player 2 — top, flipped */}
      <div className={"panel flip "+(p1on?"on":"off")+(t1<30&&p1on?" dng":"")+(penaltyFlash===1?" pf":"")}
        onPointerDown={()=>{if(!scOn)handlePress(1);}}>        {ripple[1]&&<div key={ripple[1]} className="p-ripple" style={{top:"50%",left:"50%",marginLeft:-100,marginTop:-100}}/>}
        {scOn&&<CSOverlay phase={csPhase[1]} elapsed={csEl[1]} isDone={scDone} isWinner={scWin===1} onDown={csDown} onUp={csUp} player={1} holdProgress={holdProgress[1]}/>}
        {dbl&&<DblOverlay isWinner={dblP===1} movesLeft={dblL} forbidCapture={rules.forbidCapture} showChallenge={showChallenge}/>}
        {showForbidden===1&&(
          <div className="trn-challenge">
            <div className="trn-ch-ico">⚔</div>
            <div className="trn-ch-title">Contestation !</div>
            <div className="trn-ch-sub">Double coup annulé — prise de dame</div>
          </div>
        )}
        <div className={"clock"+(t1<30?" dng":"")}>{fmt(t1)}</div>
        {rules.penaltyEnabled&&p1on&&<div className="mt-wrap" style={{transform:"rotate(180deg)"}}><div className={"mt-bar "+mtCls} style={{width:mtPct+"%"}}/></div>}
        {rules.csEnabled&&!scOn&&!dbl&&<Dots moves={moves} sct={currentSct}/>}
        {rules.chaosMode&&!scOn&&!dbl&&<div className="chaos-lbl">🎲 Chaos</div>}
        {p1on&&<div className="sonar"/>}
        {totalPenalty[1]>0&&<div className="pen-badge">{"-"+totalPenalty[1]+"s"}</div>}
        <div style={{display:"flex",alignItems:"center",gap:7}}>
          <RubiksCube player={1} size="sm"/>
          <div className="p-av">{pAv[1]}</div>
          <div className="p-label">{pName[1]}</div>
          {pStr[1]>=2&&<div className="streak-badge">{"🔥 "+pStr[1]}</div>}
          <span style={{fontSize:9,color:"var(--dim)"}}>{"x"+cubeWins[1]}</span>
        </div>
        {penaltyFlash===1&&<div className="pen-bar"/>}
      </div>

      {/* Divider + Win buttons */}
      <div className="div">
        {!over&&(
          <div className={"win-btn wl flip2"+(pendingWin===1?" pnd":"")}
            onPointerDown={e=>{e.stopPropagation();declareWinner(1);}}>
            <div className="win-btn-inner">
              <div className="win-btn-ico">♛</div>
              <div className="win-btn-lbl">{pendingWin===1?"Confirmer":pName[1]+" ♛"}</div>
              {pendingWin===1&&<div style={{fontSize:7,letterSpacing:1,color:"var(--g2)"}}>Retaper ✓</div>}
            </div>
          </div>
        )}
        <div className="div-c">
          <div className="div-badge">{moves===0?"PRÊT":"COUP "+moves}</div>
          <div className="div-sub">{divLabel}</div>
        </div>
        {!over&&(
          <div className={"win-btn wr"+(pendingWin===0?" pnd":"")}
            onPointerDown={e=>{e.stopPropagation();declareWinner(0);}}>
            <div className="win-btn-inner">
              <div className="win-btn-ico">♛</div>
              <div className="win-btn-lbl">{pendingWin===0?"Confirmer":pName[0]+" ♛"}</div>
              {pendingWin===0&&<div style={{fontSize:7,letterSpacing:1,color:"var(--g2)"}}>Retaper ✓</div>}
            </div>
          </div>
        )}
      </div>

      {/* Player 1 — bottom */}
      <div className={"panel "+(p0on?"on":"off")+(t0<30&&p0on?" dng":"")+(penaltyFlash===0?" pf":"")}
        onPointerDown={()=>{if(!scOn)handlePress(0);}}>
        {ripple[0]&&<div key={ripple[0]} className="p-ripple" style={{top:"50%",left:"50%",marginLeft:-100,marginTop:-100}}/>}
        {scOn&&<CSOverlay phase={csPhase[0]} elapsed={csEl[0]} isDone={scDone} isWinner={scWin===0} onDown={csDown} onUp={csUp} player={0} holdProgress={holdProgress[0]}/>}
        {dbl&&<DblOverlay isWinner={dblP===0} movesLeft={dblL} forbidCapture={rules.forbidCapture} showChallenge={showChallenge}/>}
        {showForbidden===0&&(
          <div className="trn-challenge">
            <div className="trn-ch-ico">⚔</div>
            <div className="trn-ch-title">Contestation !</div>
            <div className="trn-ch-sub">Double coup annulé — prise de dame</div>
          </div>
        )}
        {p0on&&<div className="sonar"/>}
        <div className={"clock"+(t0<30?" dng":"")}>{fmt(t0)}</div>
        {rules.penaltyEnabled&&p0on&&<div className="mt-wrap"><div className={"mt-bar "+mtCls} style={{width:mtPct+"%"}}/></div>}
        {rules.csEnabled&&!scOn&&!dbl&&<Dots moves={moves} sct={currentSct}/>}
        {rules.chaosMode&&!scOn&&!dbl&&<div className="chaos-lbl">🎲 Chaos</div>}
        {totalPenalty[0]>0&&<div className="pen-badge">{"-"+totalPenalty[0]+"s"}</div>}
        <div style={{display:"flex",alignItems:"center",gap:7}}>
          <span style={{fontSize:9,color:"var(--dim)"}}>{"x"+cubeWins[0]}</span>
          {pStr[0]>=2&&<div className="streak-badge">{"🔥 "+pStr[0]}</div>}
          <div className="p-label">{pName[0]}</div>
          <div className="p-av">{pAv[0]}</div>
          <RubiksCube player={0} size="sm"/>
        </div>
        {penaltyFlash===0&&<div className="pen-bar"/>}
      </div>

      {/* Controls */}
      {!over&&(
        <div className="ctrls">
          <button className="cbtn" onClick={()=>setPaused(p=>!p)}>{paused?"▶ Reprendre":"⏸ Pause"}</button>
          <button className="cbtn" onClick={reset}>↺ Reset</button>
          <button className="cbtn" onClick={onBack}>⚙</button>
        </div>
      )}

      {/* End */}
      {over&&(
        <div className="end">
          <div className="end-ico">♛</div>
          <div className="end-title">{pName[winner||0]+" Gagne !"}</div>
          <div className="end-cubes">
            {[0,1].map(p=>(
              <div key={p} className={"end-cube-card"+(p===winner?" winner":"")}>
                <div style={{fontSize:26}}>{pAv[p]}</div>
                <RubiksCube player={p} size="lg"/>
                <div className="end-cube-lbl">{p===winner?"♛ Victoire":pName[p]}</div>
                <div className="end-cube-sub">{"Cube x"+cubeWins[p]}</div>
                {totalPenalty[p]>0&&<div className="end-cube-sub" style={{color:"var(--pur)"}}>{"−"+totalPenalty[p]+"s pén."}</div>}
                <div className={"end-elo "+(eloDelta[p]>=0?"pos":"neg")}>{(eloDelta[p]>=0?"+":"")+eloDelta[p]+" ELO"}</div>
                {pStr[p]>=2&&<div style={{fontSize:10,color:"var(--red)"}}>{"🔥 Streak "+pStr[p]}</div>}
              </div>
            ))}
          </div>
          <div className="end-reason">{why}</div>
          <TimeChart snapshots={snapshots} initTime={initTime}/>
          <div className="end-stats">
            <div className="stat"><div className="stat-v">{moves}</div><div className="stat-l">Coups</div></div>
            <div className="stat"><div className="stat-v">{Math.floor(moves/currentSct)||0}</div><div className="stat-l">CS Timer</div></div>
            <div className="stat"><div className="stat-v">{fmt(times[0])}</div><div className="stat-l">J1 Restant</div></div>
            <div className="stat"><div className="stat-v">{fmt(times[1])}</div><div className="stat-l">J2 Restant</div></div>
          </div>
          <div className="end-btns">
            <button className="btn1" onClick={reset}>Rejouer</button>
            <button className="btn2" onClick={onBack}>⚙ Réglages</button>
          </div>
        </div>
      )}
    </div>
  );
}

/* ══ ROOT ══ */
export default function ChessClockApp(){

  // Set favicon
  useEffect(()=>{
    const link=document.querySelector("link[rel*='icon']")||document.createElement("link");
    link.type="image/png";link.rel="shortcut icon";
    link.href="data:image/png;base64, ";
    document.getElementsByTagName("head")[0].appendChild(link);
    document.title="ChessCubing Clock";
  },[]);

  const [screen,setScreen]=useState("config");
  const [gTime,setGTime]=useState(180);
  const [gInc,setGInc]=useState(2);
  const [gSct,setGSct]=useState(7);
  const [gLabel,setGLabel]=useState("3 min");
  const [showHist,setShowHist]=useState(false);
  const [showTrn,setShowTrn]=useState(false);
  const [showUsers,setShowUsers]=useState(false);
  const [showSelect,setShowSelect]=useState(false);
  const [showPrep,setShowPrep]=useState(false);
  const [showSoloCs,setShowSoloCs]=useState(false);
  const [history,setHistory]=useState([]);
  const [trnCb,setTrnCb]=useState(null);
  const [trnIds,setTrnIds]=useState(null); // [id0, id1] for tournament matches
  const [users,setUsers]=useState(()=>tryLoad("chess_users",DEF_USERS));
  const [selIds,setSelIds]=useState(()=>{
    const u=tryLoad("chess_users",DEF_USERS);
    return [u[0]?.id||DEF_USERS[0].id, u[1]?.id||DEF_USERS[1].id];
  });
  const [rules,setRules]=useState({
    forbidCapture:false,penaltyEnabled:false,moveLimitSec:20,penaltySec:10,
    chaosMode:false,cubePrepEnabled:false,soundEnabled:true,hapticEnabled:true,
    csEnabled:true
  });

  const saveUsers=(list)=>{ setUsers(list); trySave("chess_users",list); };

  // Derive profile objects for game
  const getUser=(id)=>users.find(u=>u.id===id)||users[0];
  const p0=getUser(selIds[0]);
  const p1=getUser(selIds[1]);
  const profiles={p0,p1};

  const updateElo=(entry)=>{
    setUsers(prev=>{
      const next=prev.map(u=>{
        const idx=selIds.indexOf(u.id); // 0=J1, 1=J2, -1=not playing
        if(idx===-1)return u;
        const isWinner=entry.winner===idx;
        const delta=entry.eloDelta?entry.eloDelta[idx]:0;
        return{...u,
          elo:Math.max(100,(u.elo||1200)+delta),
          wins:(u.wins||0)+(isWinner?1:0),
          games:(u.games||0)+1,
          streak:isWinner?(u.streak||0)+1:0,
        };
      });
      trySave("chess_users",next);
      return next;
    });
  };

  const addGame=(entry)=>{ setHistory(prev=>[...prev,{id:Date.now(),...entry}]); updateElo(entry); };

  const startTournamentMatch=(match,cb)=>{
    setTrnCb(()=>(lw)=>cb(lw));
    setTrnIds([match.p1.userId||selIds[0], match.p2.userId||selIds[1]]);
    setScreen("game");setShowTrn(false);
  };

  // Config → PlayerSelect → (CubePrepScreen) → Game
  const onConfigStart=(base,inc,sct,label)=>{
    setGTime(base);setGInc(inc);setGSct(sct);setGLabel(label);
    setTrnCb(null);setTrnIds(null);
    setShowSelect(true);
  };

  const onPlayersConfirmed=(id0,id1)=>{
    setSelIds([id0,id1]);
    setShowSelect(false);
    if(rules.cubePrepEnabled){ setShowPrep(true); }
    else{ setScreen("game"); }
  };

  const activeSelIds=trnIds||selIds;
  const ap0=getUser(activeSelIds[0]);
  const ap1=getUser(activeSelIds[1]);
  const activeProfiles={p0:ap0,p1:ap1};

  return(
    <div className="app">
      {showUsers&&<UserManagerScreen users={users} onSave={saveUsers} onClose={()=>setShowUsers(false)}/>}
      {showHist&&<HistoryScreen history={history} onClose={()=>setShowHist(false)} onClear={()=>setHistory([])}/>}
      {showTrn&&<TournamentScreen onClose={()=>setShowTrn(false)} onStartMatch={startTournamentMatch}/>}
      {showSelect&&<PlayerSelectScreen users={users} onConfirm={onPlayersConfirmed} onClose={()=>setShowSelect(false)}/>}
      {showPrep&&<CubePrepScreen p0={ap0} p1={ap1} onReady={()=>{ setShowPrep(false); setScreen("game"); }}/>}
      {showSoloCs&&<SoloCsTimer p0={ap0} p1={ap1} onClose={()=>setShowSoloCs(false)}/>}
      {screen==="config"
        ?<ConfigScreen
            history={history}
            users={users}
            selIds={selIds}
            onShowHistory={()=>setShowHist(true)}
            onShowTournament={()=>setShowTrn(true)}
            onShowUsers={()=>setShowUsers(true)}
            onShowSoloCsTimer={()=>setShowSoloCs(true)}
            rules={rules}
            onRulesChange={setRules}
            onStart={onConfigStart}/>
        :<GameScreen
            initTime={gTime} inc={gInc} sct={gSct} timeLabel={gLabel}
            rules={rules}
            profiles={activeProfiles}
            playerNames={null}
            tournamentCb={trnCb}
            onBack={()=>{setScreen("config");if(trnCb){setShowTrn(true);}setTrnCb(null);setTrnIds(null);}}
            onGameEnd={addGame}/>
      }
    </div>
  );
}
