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

// ─────────────────────────────────────────────────────────────
// MOCK DATA — TODO: replace with /api/trellus/leaderboard fetch
// ─────────────────────────────────────────────────────────────
const DEALERSHIP = "RIVERSIDE FORD — NORTH LOT";
const TEAM_DAILY_GOAL = 50; // total appointments target for the lot today

const SEED_REPS = [
  { id: 1, name: "Marcus Vega",       initials: "MV", color: "#F5B800",
    dials_made: 184, dials_connected: 47, talk_time_seconds: 7820, appointments_set: 11,
    last_call_at: 12, status: "ON_FIRE",
    dispositions: { connected: 47, no_answer: 92, voicemail: 31, wrong_number: 5, stumped: 23, demo_booked: 11, callback_requested: 8 } },
  { id: 2, name: "Tanya Brooks",      initials: "TB", color: "#E26A4F",
    dials_made: 142, dials_connected: 33, talk_time_seconds: 5410, appointments_set: 7,
    last_call_at: 38, status: "ON_FIRE",
    dispositions: { connected: 33, no_answer: 80, voicemail: 22, wrong_number: 2, stumped: 14, demo_booked: 7, callback_requested: 6 } },
  { id: 3, name: "Devin Park",        initials: "DP", color: "#7CB1F0",
    dials_made: 128, dials_connected: 28, talk_time_seconds: 4220, appointments_set: 6,
    last_call_at: 91, status: "ON_FIRE",
    dispositions: { connected: 28, no_answer: 72, voicemail: 24, wrong_number: 4, stumped: 12, demo_booked: 6, callback_requested: 5 } },
  { id: 4, name: "Rosa Klein",        initials: "RK", color: "#9C7BD9",
    dials_made: 117, dials_connected: 24, talk_time_seconds: 3905, appointments_set: 5,
    last_call_at: 174, status: "ACTIVE",
    dispositions: { connected: 24, no_answer: 65, voicemail: 21, wrong_number: 3, stumped: 11, demo_booked: 5, callback_requested: 4 } },
  { id: 5, name: "Jamal Atwater",     initials: "JA", color: "#5BB58A",
    dials_made: 103, dials_connected: 19, talk_time_seconds: 3120, appointments_set: 4,
    last_call_at: 63, status: "ACTIVE",
    dispositions: { connected: 19, no_answer: 61, voicemail: 18, wrong_number: 5, stumped: 9, demo_booked: 4, callback_requested: 3 } },
  { id: 6, name: "Priya Sandoval",    initials: "PS", color: "#D89C5B",
    dials_made: 88,  dials_connected: 14, talk_time_seconds: 2010, appointments_set: 3,
    last_call_at: 6, status: "ACTIVE",
    dispositions: { connected: 14, no_answer: 54, voicemail: 16, wrong_number: 4, stumped: 7, demo_booked: 3, callback_requested: 2 } },
  { id: 7, name: "Cole Heffernan",    initials: "CH", color: "#6F7AA8",
    dials_made: 61,  dials_connected: 9,  talk_time_seconds: 1240, appointments_set: 2,
    last_call_at: 1421, status: "IDLE",
    dispositions: { connected: 9, no_answer: 40, voicemail: 10, wrong_number: 2, stumped: 5, demo_booked: 2, callback_requested: 1 } },
  { id: 8, name: "Beth Calloway",     initials: "BC", color: "#C268A2",
    dials_made: 44,  dials_connected: 6,  talk_time_seconds: 720, appointments_set: 1,
    last_call_at: 2207, status: "IDLE",
    dispositions: { connected: 6, no_answer: 30, voicemail: 7, wrong_number: 1, stumped: 2, demo_booked: 1, callback_requested: 1 } },
  { id: 9, name: "Avery Quintero",    initials: "AQ", color: "#4FB3B5",
    dials_made: 156, dials_connected: 38, talk_time_seconds: 6210, appointments_set: 8,
    last_call_at: 22, status: "ON_FIRE",
    dispositions: { connected: 38, no_answer: 82, voicemail: 26, wrong_number: 3, stumped: 19, demo_booked: 8, callback_requested: 6 } },
  { id: 10, name: "Sami Doherty",     initials: "SD", color: "#F08A6E",
    dials_made: 134, dials_connected: 29, talk_time_seconds: 4880, appointments_set: 6,
    last_call_at: 47, status: "ACTIVE",
    dispositions: { connected: 29, no_answer: 74, voicemail: 22, wrong_number: 3, stumped: 15, demo_booked: 6, callback_requested: 4 } },
  { id: 11, name: "Khalid Osman",     initials: "KO", color: "#8ECD68",
    dials_made: 121, dials_connected: 26, talk_time_seconds: 4205, appointments_set: 5,
    last_call_at: 14, status: "ON_FIRE",
    dispositions: { connected: 26, no_answer: 70, voicemail: 19, wrong_number: 2, stumped: 13, demo_booked: 5, callback_requested: 4 } },
  { id: 12, name: "Lana Ruiz",        initials: "LR", color: "#E2A4D1",
    dials_made: 109, dials_connected: 22, talk_time_seconds: 3540, appointments_set: 4,
    last_call_at: 134, status: "ACTIVE",
    dispositions: { connected: 22, no_answer: 64, voicemail: 17, wrong_number: 3, stumped: 11, demo_booked: 4, callback_requested: 3 } },
  { id: 13, name: "Eddie Marchetti",  initials: "EM", color: "#C2A35B",
    dials_made: 96,  dials_connected: 17, talk_time_seconds: 2740, appointments_set: 4,
    last_call_at: 81, status: "ACTIVE",
    dispositions: { connected: 17, no_answer: 58, voicemail: 16, wrong_number: 2, stumped: 10, demo_booked: 4, callback_requested: 2 } },
  { id: 14, name: "Noor Bashir",      initials: "NB", color: "#9D6BB5",
    dials_made: 92,  dials_connected: 16, talk_time_seconds: 2380, appointments_set: 3,
    last_call_at: 53, status: "ACTIVE",
    dispositions: { connected: 16, no_answer: 56, voicemail: 14, wrong_number: 3, stumped: 9, demo_booked: 3, callback_requested: 3 } },
  { id: 15, name: "Trevor Lin",       initials: "TL", color: "#5C9DD8",
    dials_made: 78,  dials_connected: 13, talk_time_seconds: 1980, appointments_set: 3,
    last_call_at: 110, status: "ACTIVE",
    dispositions: { connected: 13, no_answer: 50, voicemail: 12, wrong_number: 2, stumped: 7, demo_booked: 3, callback_requested: 1 } },
  { id: 16, name: "Maya Reinholt",    initials: "MR", color: "#EEAA55",
    dials_made: 70,  dials_connected: 11, talk_time_seconds: 1610, appointments_set: 2,
    last_call_at: 220, status: "ACTIVE",
    dispositions: { connected: 11, no_answer: 45, voicemail: 11, wrong_number: 2, stumped: 6, demo_booked: 2, callback_requested: 2 } },
  { id: 17, name: "Garrett Mosley",   initials: "GM", color: "#7090B0",
    dials_made: 58,  dials_connected: 8,  talk_time_seconds: 1110, appointments_set: 2,
    last_call_at: 980, status: "IDLE",
    dispositions: { connected: 8, no_answer: 38, voicemail: 9, wrong_number: 2, stumped: 5, demo_booked: 2, callback_requested: 1 } },
  { id: 18, name: "Ines Vasquez",     initials: "IV", color: "#D87CA0",
    dials_made: 36,  dials_connected: 4,  talk_time_seconds: 560,  appointments_set: 1,
    last_call_at: 2680, status: "IDLE",
    dispositions: { connected: 4, no_answer: 24, voicemail: 6, wrong_number: 1, stumped: 1, demo_booked: 1, callback_requested: 0 } },
];

const OUTCOMES = [
  { key: "connected",          label: "CONNECTED",          tone: "good",  weight: 18 },
  { key: "no_answer",          label: "NO ANSWER",          tone: "muted", weight: 42 },
  { key: "voicemail",          label: "VOICEMAIL",          tone: "muted", weight: 20 },
  { key: "wrong_number",       label: "WRONG NUMBER",       tone: "warn",  weight: 4 },
  { key: "stumped",            label: "STUMPED",             tone: "warn",  weight: 9 },
  { key: "demo_booked",        label: "DEMO BOOKED",        tone: "fire",  weight: 4 },
  { key: "callback_requested", label: "CALLBACK",           tone: "good",  weight: 5 },
];

const COMMENTARY = {
  demo_booked: [
    { emoji: "👑", text: "sounded like an 850 credit score · white new balances for sure" },
    { emoji: "👑", text: "didn't even ask the price" },
    { emoji: "🤯", text: "OMG he booked himself basically" },
    { emoji: "💰", text: "this one's ready to sign on the hood" },
    { emoji: "⚡", text: "told me his trade was a peach" },
    { emoji: "👑", text: "king behavior. pulling up Saturday" },
  ],
  connected: [
    { emoji: "👌", text: "warm one · actually picked up" },
    { emoji: "🎙️", text: "got him talking about the new Tahoe" },
    { emoji: "🔥", text: "locked in. running the pitch" },
    { emoji: "☕", text: "he had time today thank god" },
  ],
  callback_requested: [
    { emoji: "📞", text: "says he'll call back fr fr" },
    { emoji: "⏳", text: "thinking it over · keep him warm" },
    { emoji: "📅", text: "asked us to ring back at 3" },
  ],
  no_answer: [
    { emoji: "👻", text: "ghost city" },
    { emoji: "📵", text: "crickets" },
    { emoji: "😶", text: "nobody home" },
  ],
  voicemail: [
    { emoji: "📼", text: "left a smooth one" },
    { emoji: "🎤", text: "tape city. dropped the script" },
    { emoji: "📩", text: "voicemail · he'll hear it" },
  ],
  gatekeeper: [],
  wrong_number: [
    { emoji: "🙃", text: "this number is a barber shop now" },
    { emoji: "🔀", text: "data quality issue · wrong guy" },
    { emoji: "❓", text: "asked for Steve, got Stephanie" },
  ],
  stumped: [
    { emoji: "💀", text: "keep shooting your shot king" },
    { emoji: "😂", text: "guy said he had to talk to his wife. ok pal" },
    { emoji: "😂", text: "that guy was in a bad mood anyways" },
    { emoji: "💀", text: "rough one · next dial" },
    { emoji: "😮‍💨", text: "got hung up on. shake it off" },
    { emoji: "💀", text: "told me to lose his number lol" },
    { emoji: "💪", text: "stay locked in. on to the next" },
  ],
};
const pickCommentary = (key) => {
  const arr = COMMENTARY[key]; if (!arr) return null;
  return arr[Math.floor(Math.random()*arr.length)];
};

// ─────────────────────────────────────────────────────────────
// CHAT ROOM — fake users + seeded backlog + idle banter
// ─────────────────────────────────────────────────────────────
const CHAT_USERS = [
  { id: 1, handle: "M.VEGA",      color: "#F5B800", role: "rep" },
  { id: 2, handle: "T.BROOKS",    color: "#E26A4F", role: "rep" },
  { id: 3, handle: "D.PARK",      color: "#7CB1F0", role: "rep" },
  { id: 4, handle: "R.KLEIN",     color: "#9C7BD9", role: "rep" },
  { id: 5, handle: "J.ATWATER",   color: "#5BB58A", role: "rep" },
  { id: 6, handle: "P.SANDOVAL",  color: "#D89C5B", role: "rep" },
  { id: 7, handle: "C.HEFFERNAN", color: "#6F7AA8", role: "rep" },
  { id: 8, handle: "B.CALLOWAY",  color: "#C268A2", role: "rep" },
  { id: 9, handle: "M.RIVERA",    color: "#FFFFFF", role: "gsm" },
];
const userById = (id) => CHAT_USERS.find(u => u.id === id) || CHAT_USERS[0];

// Seeded backlog — appears as if the chat has been going all morning
const CHAT_BACKLOG = [
  { from: 9, text: "$50 BOUNTY UP — first 3 demos wins. GO." },
  { from: 1, text: "say less" },
  { from: 2, text: "i got u" },
  { from: 5, text: "🫡" },
  { from: 1, text: "just booked one. dude is pulling up sat" },
  { from: 9, text: "🔥🔥🔥 @M.VEGA" },
  { from: 5, text: "let him cook fr" },
  { from: 7, text: "..." },
  { from: 9, text: "@C.HEFFERNAN you good?" },
  { from: 7, text: "yeah was in BR" },
  { from: 3, text: "lol" },
  { from: 4, text: "got hung up on twice already today 💀" },
  { from: 6, text: "skill issue 😂" },
  { from: 4, text: "@P.SANDOVAL ill remember that" },
  { from: 2, text: "yall the white new balances guy from yest just rebooked" },
  { from: 1, text: "850 credit score for sure" },
  { from: 9, text: "next spiff hits at 100 dials. KEEP DIALING" },
];

// ─────────────────────────────────────────────────────────────
// SALES FLOOR — fictional monthly car sales data
// ─────────────────────────────────────────────────────────────
const SALES_MONTH = "MAY · MONTH-TO-DATE";
const SALES_REPS = [
  { id: 1, name: "Marcus Vega",      initials: "MV", color: "#F5B800",
    units: 24, front_gross: 41200, back_gross: 22800, top_sale: { vehicle: "'25 Tahoe Z71", price: 71500 }, csi: 96, last_sale: "today" },
  { id: 2, name: "Tanya Brooks",     initials: "TB", color: "#E26A4F",
    units: 21, front_gross: 36700, back_gross: 19400, top_sale: { vehicle: "'25 Mustang GT", price: 58200 }, csi: 94, last_sale: "today" },
  { id: 3, name: "Devin Park",       initials: "DP", color: "#7CB1F0",
    units: 18, front_gross: 33500, back_gross: 17100, top_sale: { vehicle: "'24 F-150 Lariat", price: 64800 }, csi: 92, last_sale: "yest" },
  { id: 4, name: "Rosa Klein",       initials: "RK", color: "#9C7BD9",
    units: 16, front_gross: 28200, back_gross: 14300, top_sale: { vehicle: "'25 Bronco Sport", price: 42100 }, csi: 95, last_sale: "today" },
  { id: 5, name: "Jamal Atwater",    initials: "JA", color: "#5BB58A",
    units: 14, front_gross: 25600, back_gross: 12800, top_sale: { vehicle: "'25 Explorer ST", price: 56400 }, csi: 90, last_sale: "yest" },
  { id: 6, name: "Priya Sandoval",   initials: "PS", color: "#D89C5B",
    units: 13, front_gross: 22900, back_gross: 11400, top_sale: { vehicle: "'24 Escape Hybrid", price: 38200 }, csi: 93, last_sale: "today" },
  { id: 7, name: "Avery Quintero",   initials: "AQ", color: "#4FB3B5",
    units: 12, front_gross: 20100, back_gross: 9800,  top_sale: { vehicle: "'25 Edge Titanium", price: 48700 }, csi: 91, last_sale: "today" },
  { id: 8, name: "Sami Doherty",     initials: "SD", color: "#F08A6E",
    units: 11, front_gross: 18800, back_gross: 8600,  top_sale: { vehicle: "'24 Maverick XLT", price: 32400 }, csi: 89, last_sale: "yest" },
  { id: 9, name: "Khalid Osman",     initials: "KO", color: "#8ECD68",
    units: 10, front_gross: 16400, back_gross: 7900,  top_sale: { vehicle: "'25 Ranger Lariat", price: 44900 }, csi: 88, last_sale: "yest" },
  { id: 10, name: "Lana Ruiz",       initials: "LR", color: "#E2A4D1",
    units: 9,  front_gross: 14700, back_gross: 7100,  top_sale: { vehicle: "'24 Escape ST-Line", price: 36800 }, csi: 92, last_sale: "3 days" },
  { id: 11, name: "Eddie Marchetti", initials: "EM", color: "#C2A35B",
    units: 8,  front_gross: 12800, back_gross: 6200,  top_sale: { vehicle: "'25 Bronco Heritage", price: 52300 }, csi: 87, last_sale: "yest" },
  { id: 12, name: "Cole Heffernan",  initials: "CH", color: "#6F7AA8",
    units: 6,  front_gross: 9400,  back_gross: 4400,  top_sale: { vehicle: "'24 Edge SEL", price: 41200 }, csi: 84, last_sale: "4 days" },
  { id: 13, name: "Beth Calloway",   initials: "BC", color: "#C268A2",
    units: 4,  front_gross: 6200,  back_gross: 2900,  top_sale: { vehicle: "'24 EcoSport SES", price: 28400 }, csi: 86, last_sale: "5 days" },
];

const RECENT_DELIVERIES = [
  { repId: 1, vehicle: "'25 Tahoe Z71",        buyer: "T. NGUYEN",  price: 71500, time: "14m ago" },
  { repId: 4, vehicle: "'25 Bronco Sport BL",  buyer: "L. ANDREWS", price: 42100, time: "1h ago"  },
  { repId: 2, vehicle: "'25 Mustang GT Coupe", buyer: "R. PATEL",   price: 58200, time: "2h ago"  },
  { repId: 6, vehicle: "'24 Escape Hybrid",    buyer: "D. KIM",     price: 38200, time: "3h ago"  },
  { repId: 1, vehicle: "'25 Expedition Max",   buyer: "M. CHOI",    price: 78400, time: "yest"    },
  { repId: 7, vehicle: "'25 Edge Titanium",    buyer: "S. JACKSON", price: 48700, time: "yest"    },
  { repId: 3, vehicle: "'24 F-150 Lariat 4WD", buyer: "B. SHARMA",  price: 64800, time: "yest"    },
  { repId: 5, vehicle: "'25 Explorer ST",      buyer: "P. ROMERO",  price: 56400, time: "2 days"  },
];
const SALES_GOAL_UNITS = 200; // dealership monthly target

const fmtMoney = (n) => "$" + Math.round(n).toLocaleString();
const fmtMoneyK = (n) => "$" + (n/1000).toFixed(n >= 100000 ? 0 : 1) + "K";

// Pool of fictional vehicles + buyers for the live sales sim
const VEHICLE_POOL = [
  "'25 F-150 Lariat 4WD", "'25 Mustang GT Coupe", "'25 Bronco Sport BL", "'24 Edge Titanium",
  "'25 Explorer ST", "'24 Escape Hybrid SE", "'25 Ranger Lariat", "'25 Maverick XLT Hybrid",
  "'25 Expedition Max", "'25 Tahoe Z71", "'24 Bronco Heritage", "'25 Edge SEL AWD",
  "'24 F-250 Platinum", "'25 Mustang Mach-E", "'25 Transit Connect", "'25 Bronco Wildtrak",
  "'25 F-150 Raptor", "'24 Mustang EcoBoost", "'25 Maverick Tremor",
];
const BUYER_INITIALS = [
  "A. CHEN","B. ALONSO","C. MURPHY","D. SHARMA","E. PATEL","F. JOHNSON","G. KIM","H. PARKER",
  "I. LEE","J. ROMERO","K. NGUYEN","L. SMITH","M. ROSS","N. WALKER","O. BLAKE","P. TAYLOR",
  "Q. ESPINOZA","R. BUTLER","S. DELGADO","T. HOWARD","U. KAUR","V. FOSTER",
];

// Live sales simulator — generates a new sale every 5–11s, mutates units +
// gross on the seller's row, and pushes an event into the feed.
function useSalesSim() {
  const [reps, setReps] = useState(SALES_REPS);
  const [events, setEvents] = useState([]); // newest first
  const idRef = useRef(0);
  const repsRef = useRef(reps);
  useEffect(() => { repsRef.current = reps; }, [reps]);

  useEffect(() => {
    let to;
    const tick = () => {
      const current = repsRef.current;
      // weight by current units (success breeds success), with floor so cold
      // sellers still have a chance.
      const totalW = current.reduce((s, r) => s + r.units + 4, 0);
      let r = Math.random() * totalW;
      let chosen = current[0];
      for (const rep of current) { r -= rep.units + 4; if (r <= 0) { chosen = rep; break; } }
      const vehicle    = VEHICLE_POOL[Math.floor(Math.random() * VEHICLE_POOL.length)];
      const buyer      = BUYER_INITIALS[Math.floor(Math.random() * BUYER_INITIALS.length)];
      const price      = 28000 + Math.floor(Math.random() * 52000);
      const frontGross = 700 + Math.floor(Math.random() * 2800);
      const backGross  = 350 + Math.floor(Math.random() * 1800);

      setReps((prev) => prev.map((rp) => rp.id === chosen.id ? {
        ...rp,
        units: rp.units + 1,
        front_gross: rp.front_gross + frontGross,
        back_gross:  rp.back_gross  + backGross,
        last_sale:   "just now",
      } : rp));

      const id = ++idRef.current;
      setEvents((prev) => [{
        id, rep: chosen, vehicle, buyer, price,
        time: new Date(), frontGross, backGross,
      }, ...prev].slice(0, 14));

      to = setTimeout(tick, 5000 + Math.random() * 6000);
    };
    to = setTimeout(tick, 3500);
    return () => clearTimeout(to);
  }, []);

  return { reps, events };
}

// Drips in over time
const IDLE_BANTER = [
  "anyone got tums",
  "this guy fr",
  "wd",
  "let him cook",
  "🔥",
  "smash",
  "next dial fellas",
  "brb · gotta hit the head",
  "send help",
  "im locked in",
  "going crazy on the dialer rn",
  "👀",
  "got one warm",
  "tell me why he asked for the price first thing 💀",
  "lol",
  "lmao",
  "💀💀💀",
  "skill issue",
  "voicemail city today",
  "stop ghosting me chad",
  "ringer dude",
  "@everyone hydrate",
  "got a callback fr",
  "im built different",
  "save my soul",
];

function pickOutcome() {
  const total = OUTCOMES.reduce((s, o) => s + o.weight, 0);
  let r = Math.random() * total;
  for (const o of OUTCOMES) { r -= o.weight; if (r <= 0) return o; }
  return OUTCOMES[0];
}

// ─────────────────────────────────────────────────────────────
// ANIMATED NUMBER — smooth tween between values
// Defensive: any NaN / Infinity / absurdly-large input is coerced to a safe
// finite number before being tweened or rendered.
// ─────────────────────────────────────────────────────────────
const TICK_HARD_MAX = 1_000_000; // anything past this is corruption — clamp.
function safeNum(n, fallback = 0) {
  if (typeof n !== "number" || !Number.isFinite(n)) return fallback;
  if (Math.abs(n) > TICK_HARD_MAX) return Math.sign(n) * TICK_HARD_MAX;
  return n;
}
function useTween(value, ms = 700) {
  const safeValue = safeNum(value);
  const [display, setDisplay] = useState(safeValue);
  const fromRef = useRef(safeValue);
  const startRef = useRef(performance.now());
  const targetRef = useRef(safeValue);

  useEffect(() => {
    if (safeValue === targetRef.current) return;
    fromRef.current = safeNum(display, safeValue);
    targetRef.current = safeValue;
    startRef.current = performance.now();
    let raf;
    const tick = (t) => {
      const k = Math.min(1, (t - startRef.current) / ms);
      const ease = 1 - Math.pow(1 - k, 3);
      const v = fromRef.current + (safeValue - fromRef.current) * ease;
      setDisplay(safeNum(v, safeValue));
      if (k < 1) raf = requestAnimationFrame(tick);
    };
    raf = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf);
  }, [safeValue]);

  return display;
}

function Tick({ value, fmt = (n) => Math.round(n).toLocaleString(), className = "" }) {
  const v = useTween(value);
  return <span className={"tabular-nums " + className}>{fmt(safeNum(v))}</span>;
}

function fmtTime(s) {
  const h = Math.floor(s / 3600);
  const m = Math.floor((s % 3600) / 60);
  const sec = Math.floor(s % 60);
  if (h > 0) return `${h}H ${String(m).padStart(2,"0")}M`;
  return `${m}:${String(sec).padStart(2,"0")}`;
}
function fmtIdle(s) {
  if (s < 60) return `${s}S`;
  const m = Math.floor(s / 60);
  if (m < 60) return `${m} MIN`;
  return `${Math.floor(m/60)}H ${m%60}M`;
}

// ─────────────────────────────────────────────────────────────
// TOP BAR
// ─────────────────────────────────────────────────────────────
function TopBar({ period, setPeriod, sound, setSound, now, chatOpen, setChatOpen, theme, setTheme, view, setView }) {
  const periods = ["TODAY", "THIS WEEK", "THIS MONTH"];
  const views = [
    { id: "calls", label: "CALL FLOOR" },
    { id: "sales", label: "SALES FLOOR" },
  ];
  return (
    <header className="flex flex-wrap items-center justify-between gap-3 border-b border-amber-500/20 bg-[#100E08] px-5 py-3">
      <div className="flex items-center gap-4">
        <div className="flex items-center gap-2.5">
          <span className="grid h-9 w-9 place-items-center text-amber-300" aria-hidden="true">
            <svg viewBox="0 0 100 100" width="36" height="36">
              <g fill="currentColor">
                <polygon points="20,18 32,18 32,21 25,21 23,23 23,76 25,78 32,78 32,82 20,82" />
                <polygon points="80,18 68,18 68,21 75,21 77,23 77,76 75,78 68,78 68,82 80,82" />
                <rect x="35" y="32" width="30" height="4" />
                <rect x="35" y="43" width="22" height="4" />
                <rect x="35" y="54" width="14" height="4" />
                <rect x="35" y="67" width="12" height="3" />
              </g>
            </svg>
          </span>
          <div className="leading-[1.05] whitespace-nowrap">
            <div className="font-display text-[19px] font-extrabold tracking-tight text-amber-50">WAR MACHINE</div>
            <div className="font-mono text-[10px] tracking-[0.28em] text-amber-400/80">/ {view === "sales" ? "SALES BOARD" : "LEADERBOARD"}</div>
          </div>
        </div>
        <div className="ml-3 hidden h-7 w-px bg-white/10 md:block" />
        <div className="hidden whitespace-nowrap font-mono text-[10.5px] tracking-[0.22em] text-white/40 lg:block">
          {DEALERSHIP}
        </div>
        <div className="flex shrink-0 overflow-hidden rounded-sm border border-amber-400/40 bg-black/40 font-mono text-[10.5px] tracking-[0.2em]">
          {views.map((v) => (
            <button key={v.id} onClick={() => setView(v.id)}
              className={`whitespace-nowrap px-3 py-1.5 transition ${view === v.id ? "bg-amber-400 text-[#0A0A08] font-bold" : "text-white/65 hover:text-white"}`}>
              {v.label}
            </button>
          ))}
        </div>
      </div>

      <div className="flex items-center gap-3">
        <div className="flex shrink-0 overflow-hidden rounded-sm border border-white/10 bg-black/40 font-mono text-[10.5px] tracking-[0.2em]">
          {periods.map((p) => (
            <button key={p} onClick={() => setPeriod(p)}
              className={`whitespace-nowrap px-3 py-1.5 transition ${period === p ? "bg-amber-400 text-[#0A0A08] font-bold" : "text-white/60 hover:text-white"}`}>
              {p}
            </button>
          ))}
        </div>

        <div className="flex shrink-0 items-center gap-2 whitespace-nowrap rounded-sm border border-white/10 bg-black/40 px-2.5 py-1.5 font-mono text-[10.5px] tracking-[0.18em] text-white/70">
          <span className="h-1.5 w-1.5 animate-pulse rounded-full bg-emerald-400 shadow-[0_0_8px_2px_rgba(52,211,153,0.6)]"></span>
          LIVE · {now.toLocaleTimeString([], { hour12:false })}
        </div>

        <button
          onClick={() => setChatOpen((v) => !v)}
          title="Pop out the team chat window"
          className={`inline-flex shrink-0 items-center gap-1.5 whitespace-nowrap rounded-sm border px-2.5 py-1.5 font-mono text-[10.5px] font-bold tracking-[0.2em] transition ${chatOpen ? "border-amber-400/60 bg-amber-400 text-[#0A0A08]" : "border-amber-400/40 bg-amber-400/10 text-amber-300 hover:bg-amber-400/20"}`}>
          <span>💬</span>
          <span>TEAM CHAT</span>
        </button>

        <button
          onClick={() => setTheme(theme === "dark" ? "light" : "dark")}
          title={theme === "dark" ? "Switch to light mode" : "Switch to dark mode"}
          className={`grid h-8 w-8 place-items-center rounded-sm border transition ${theme === "dark" ? "border-white/10 bg-black/40 text-white/70 hover:text-amber-300" : "border-amber-400/50 bg-amber-400/15 text-amber-300"}`}>
          <span className="text-[14px] leading-none">{theme === "dark" ? "☀️" : "🌙"}</span>
        </button>

        <button onClick={() => setSound((s) => !s)} title={sound ? "Mute sound effects" : "Unmute sound effects (cha-ching on sales, ding on demos)"}
          className={`grid h-8 w-8 place-items-center rounded-sm border ${sound ? "border-amber-400/50 bg-amber-400/10 text-amber-300" : "border-white/10 bg-black/40 text-white/40"}`}>
          <SoundIcon on={sound} />
        </button>
      </div>
    </header>
  );
}

const SoundIcon = ({ on }) => (
  <svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="square">
    <path d="M4 9v6h4l5 4V5L8 9H4z" />
    {on ? <path d="M16 8c1.5 1.2 1.5 6.8 0 8M19 5c3 2.5 3 11.5 0 14" /> : <path d="M16 9l6 6M22 9l-6 6" />}
  </svg>
);

// ─────────────────────────────────────────────────────────────
// SPIFF HERO
// ─────────────────────────────────────────────────────────────
function SpiffHero({ teamAppts: liveAppts, goal, apptOverride, setApptOverride, goalLabel = "TEAM DAILY APPT GOAL" }) {
  // Effective count: when scrubbing, the override wins; otherwise we use the
  // live simulated count from the call ticker.
  const teamAppts = apptOverride != null ? apptOverride : liveAppts;
  const pct = Math.min(999, (teamAppts / goal) * 100);
  const barPct = Math.min(100, pct);
  const remaining = Math.max(0, goal - teamAppts);
  const overGoal = teamAppts >= goal;
  const scrubbing = apptOverride != null;

  const [celebrate, setCelebrate] = useState(false);
  const prevOverGoal = useRef(overGoal);
  useEffect(() => {
    // Fire confetti every time we *cross* the goal threshold (so scrubbing
    // up across it always triggers, but staying above it doesn't loop).
    if (overGoal && !prevOverGoal.current) {
      setCelebrate(true);
      const t = setTimeout(() => setCelebrate(false), 4200);
      prevOverGoal.current = overGoal;
      return () => clearTimeout(t);
    }
    prevOverGoal.current = overGoal;
  }, [overGoal]);

  // Drag-to-scrub on the progress bar
  const barRef = useRef(null);
  const [dragging, setDragging] = useState(false);
  const SCRUB_MAX = Math.round(goal * 1.4); // 140% so we can demo over-goal celebration
  const updateFromClientX = (clientX) => {
    const el = barRef.current; if (!el) return;
    const rect = el.getBoundingClientRect();
    const ratio = Math.min(1, Math.max(0, (clientX - rect.left) / rect.width));
    setApptOverride(Math.round(ratio * SCRUB_MAX));
  };
  useEffect(() => {
    if (!dragging) return;
    const onMove = (e) => updateFromClientX(e.clientX ?? e.touches?.[0]?.clientX ?? 0);
    const onUp = () => setDragging(false);
    window.addEventListener("mousemove", onMove);
    window.addEventListener("mouseup", onUp);
    window.addEventListener("touchmove", onMove, { passive: false });
    window.addEventListener("touchend", onUp);
    return () => {
      window.removeEventListener("mousemove", onMove);
      window.removeEventListener("mouseup", onUp);
      window.removeEventListener("touchmove", onMove);
      window.removeEventListener("touchend", onUp);
    };
  }, [dragging]);

  let mood;
  if (overGoal)        mood = { label: "GOAL MET · KEEP COOKING",     color: "text-emerald-300", emoji: "🏆", emojiAccent: "💚" };
  else if (pct < 15)   mood = { label: "LOT IS DEAD",                 color: "text-rose-400",    emoji: "💀", emojiAccent: "🪦" };
  else if (pct < 30)   mood = { label: "LOT IS KINDA QUIET",          color: "text-orange-300",  emoji: "😶", emojiAccent: "🤐" };
  else if (pct < 45)   mood = { label: "LOT IS HEATING UP",           color: "text-amber-300",   emoji: "🌡️", emojiAccent: "♨️" };
  else if (pct < 60)   mood = { label: "LOT IS CRACKALACKIN",         color: "text-amber-200",   emoji: "🔥", emojiAccent: "💥" };
  else if (pct < 75)   mood = { label: "LOT IS BUSSIN!",              color: "text-amber-200",   emoji: "🔥", emojiAccent: "⚡" };
  else if (pct < 90)   mood = { label: "LOT IS ON FIRE",              color: "text-amber-300",   emoji: "🔥", emojiAccent: "🚒" };
  else                 mood = { label: "LOT IS WILDIN OUT FORREAL!!", color: "text-orange-200",  emoji: "🚨", emojiAccent: "🔥" };

  return (
    <section className={`relative overflow-hidden border bg-gradient-to-br from-amber-400/[0.08] via-[#16140F] to-[#0F0E0A] ${overGoal ? "border-emerald-400/40" : "border-amber-400/30"}`}>
      <div className="absolute inset-0 opacity-[0.06]" style={{
        backgroundImage:"repeating-linear-gradient(45deg, #F5B800 0 1px, transparent 1px 14px)"
      }} />
      <div className="absolute -right-12 -top-10 h-44 w-44 rounded-full bg-amber-400/10 blur-3xl" />
      {celebrate && <Confetti />}

      <div className="relative grid grid-cols-12 items-center gap-3 p-3">
        {/* TEAM GOAL (left) */}
        <div className="col-span-12 md:col-span-4">
          <div className="whitespace-nowrap font-mono text-[11px] font-bold tracking-[0.28em] text-white/65">/ {goalLabel}</div>
          <div className="mt-0.5 flex items-baseline gap-2">
            <span className="font-figure text-[48px] leading-none text-amber-50"><Tick value={teamAppts} /></span>
            <span className="font-display text-[24px] font-black leading-none text-white/35">/ {goal}</span>
            <span className="ml-1 inline-flex items-center gap-1 text-[20px] leading-none">
              <span>{mood.emoji}</span>
              <span className="text-[16px] opacity-80">{mood.emojiAccent}</span>
            </span>
          </div>
        </div>

        {/* BOUNTY (middle) */}
        <div className="col-span-12 md:col-span-5 md:col-start-5 flex items-center gap-3">
          <div className="relative grid h-[56px] w-[56px] shrink-0 place-items-center bg-amber-400 text-[#0A0A08]"
               style={{clipPath:"polygon(50% 0, 100% 25%, 100% 75%, 50% 100%, 0 75%, 0 25%)"}}>
            <span className="font-figure text-[28px] leading-none">$</span>
            <span className="absolute inset-0 animate-[shimmer_2.6s_linear_infinite] bg-[linear-gradient(90deg,transparent,rgba(255,255,255,0.5),transparent)] bg-[length:200%_100%]"
                  style={{clipPath:"polygon(50% 0, 100% 25%, 100% 75%, 50% 100%, 0 75%, 0 25%)"}}></span>
          </div>
          <div className="min-w-0">
            <div className="whitespace-nowrap font-mono text-[10px] font-bold tracking-[0.3em] text-amber-300/90">/ TODAY&apos;S SPIFF</div>
            <div className="font-figure text-[38px] leading-[0.95] text-amber-50" style={{letterSpacing:"-0.02em"}}>
              $50<span className="font-display text-[22px] font-black not-italic ml-2 align-middle">BOUNTY</span>
            </div>
            <div className="mt-0.5 whitespace-nowrap font-mono text-[10px] tracking-[0.22em] text-white/45">SET BY M. RIVERA · 09:14 · WINNER TAKES ALL</div>
          </div>
        </div>

        {/* MOOD (top right) — text + emoji combo */}
        <div className="col-span-12 md:col-span-3 md:col-start-10 flex items-center md:justify-end">
          <div className="md:text-right">
            <div className="whitespace-nowrap font-mono text-[10px] font-bold tracking-[0.28em] text-white/45">/ FLOOR MOOD</div>
            <div className={`mt-0.5 inline-flex items-center gap-1.5 font-display text-[17px] md:text-[18px] font-black leading-tight tracking-[0.04em] ${mood.color}`}
                 style={{ textShadow: mood.color.includes("amber") || mood.color.includes("orange") ? "0 0 14px rgba(245,184,0,0.4)" : "none" }}>
              <span className="text-[20px] leading-none">{mood.emoji}</span>
              <span className="whitespace-nowrap">{mood.label}</span>
              <span className="text-[18px] leading-none opacity-85">{mood.emojiAccent}</span>
            </div>
          </div>
        </div>

        {/* full width progress bar — drag to scrub the appt count for demo */}
        <div className="col-span-12">
          <div className="mb-1 flex items-center justify-between gap-2 font-mono text-[9px] tracking-[0.22em] text-white/35">
            <span>← DRAG TO PREVIEW</span>
            {scrubbing && (
              <button
                onClick={() => setApptOverride(null)}
                className="rounded-sm border border-amber-400/40 bg-amber-400/15 px-2 py-0.5 font-mono text-[9px] font-bold tracking-[0.22em] text-amber-300 hover:bg-amber-400/25">
                RESET TO LIVE
              </button>
            )}
          </div>
          <div
            ref={barRef}
            onMouseDown={(e) => { setDragging(true); updateFromClientX(e.clientX); }}
            onTouchStart={(e) => { setDragging(true); updateFromClientX(e.touches[0].clientX); }}
            className={`relative h-5 rounded-sm bg-white/[0.06] ring-1 ring-white/5 ${dragging ? "cursor-grabbing" : "cursor-grab"} select-none`}
            style={{ userSelect: "none" }}>
            {[25,50,75].map((m) => (
              <div key={m} className="absolute inset-y-0 w-px bg-white/10" style={{ left: m+"%" }} />
            ))}
            <div className={`absolute inset-y-0 left-0 overflow-hidden rounded-sm transition-[width] duration-700 ${overGoal ? "bg-gradient-to-r from-emerald-500 via-amber-300 to-amber-200" : "bg-gradient-to-r from-amber-500 to-amber-300"}`}
                 style={{ width: barPct + "%", boxShadow: overGoal ? "0 0 22px rgba(52,211,153,0.55), 0 0 18px rgba(245,184,0,0.45)" : "0 0 16px rgba(245,184,0,0.55)" }}>
              <div className="absolute inset-0 animate-[shimmer_2.2s_linear_infinite] bg-[linear-gradient(90deg,transparent,rgba(255,255,255,0.55),transparent)] bg-[length:200%_100%]"></div>
            </div>
            {/* riding torch */}
            {!overGoal && (
              <div className="pointer-events-none absolute top-1/2 -translate-y-1/2 transition-[left] duration-700"
                   style={{ left: `clamp(0%, ${barPct}%, 100%)` }}>
                <div className={`relative ${barPct > 88 ? "-translate-x-full" : barPct < 12 ? "" : "-translate-x-1/2"}`}>
                  {pct >= 50 && (
                    <div className="pointer-events-none absolute left-1/2 top-0 -translate-x-1/2 -translate-y-2">
                      <span className="smoke smoke-a" />
                      <span className="smoke smoke-b" />
                      {pct >= 75 && <span className="smoke smoke-c" />}
                    </div>
                  )}
                  <div className={`relative inline-flex items-center gap-1 whitespace-nowrap rounded-sm px-2.5 py-1 font-display text-[18px] font-black tabular-nums text-[#0A0A08] ${pct >= 50 ? "bg-amber-300" : "bg-amber-400"}`}
                       style={{ boxShadow: pct >= 75 ? "0 0 22px rgba(245,184,0,0.95), 0 0 6px rgba(255,200,80,1)" : pct >= 50 ? "0 0 14px rgba(245,184,0,0.7)" : "0 0 6px rgba(245,184,0,0.4)" }}>
                    {pct >= 50 && <span className="flame text-[16px] leading-none">🔥</span>}
                    <Tick value={pct} fmt={(n)=>n.toFixed(0)+"%"} />
                    {pct >= 75 && <span className="flame text-[16px] leading-none">🔥</span>}
                  </div>
                </div>
              </div>
            )}
            {/* settled badge once goal cleared */}
            {overGoal && (
              <div className="pointer-events-none absolute right-3 top-1/2 -translate-y-1/2 inline-flex items-center whitespace-nowrap rounded-sm bg-emerald-300 px-2.5 py-1 font-display text-[18px] font-black tabular-nums text-[#0A0A08]"
                   style={{ boxShadow:"0 0 18px rgba(52,211,153,0.7)" }}>
                <Tick value={pct} fmt={(n)=>n.toFixed(0)+"%"} />
              </div>
            )}
          </div>
          <div className="mt-1.5 flex items-center justify-between gap-3 whitespace-nowrap font-mono text-[10.5px] font-bold tracking-[0.22em] text-white/55">
            <span>{remaining > 0 ? <><span className="text-amber-300">{remaining}</span> APPTS TO HIT GOAL</> : <span className="text-emerald-300">+{teamAppts - goal} OVER GOAL · KEEP GOING</span>}</span>
          </div>
        </div>
      </div>
    </section>
  );
}

function Confetti() {
  const pieces = useMemo(() => Array.from({length: 36}, (_, i) => ({
    id: i,
    left: Math.random() * 100,
    delay: Math.random() * 0.4,
    dur: 1.6 + Math.random() * 1.4,
    color: ["#F5B800","#FFD86B","#5BB58A","#FFFFFF","#E26A4F"][i % 5],
    size: 6 + Math.random() * 6,
    rot: Math.random() * 720,
  })), []);
  return (
    <div className="pointer-events-none absolute inset-0 z-20 overflow-hidden">
      <div className="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 font-display text-[64px] font-black text-amber-300 boom"
           style={{ textShadow:"0 0 40px rgba(245,184,0,0.9), 0 0 14px #fff" }}>
        GOAL CRUSHED
      </div>
      {pieces.map(p => (
        <span key={p.id} className="confetti"
          style={{
            left: p.left+"%",
            background: p.color,
            width: p.size, height: p.size*0.4,
            animationDelay: p.delay+"s",
            animationDuration: p.dur+"s",
            transform: `rotate(${p.rot}deg)`,
          }} />
      ))}
    </div>
  );
}

const Stat = ({k, v, hot}) => (
  <div>
    <div className="text-white/35">{k}</div>
    <div className={"font-display text-[16px] font-bold tabular-nums " + (hot ? "text-amber-300" : "text-white/90")}>
      <Tick value={v} />
    </div>
  </div>
);

// ─────────────────────────────────────────────────────────────
// LEADERBOARD
// ─────────────────────────────────────────────────────────────
function Avatar({ rep, size = 36, fire = false }) {
  return (
    <div className="relative shrink-0">
      <div className="grid place-items-center font-display font-extrabold text-[#0A0A08]"
        style={{ width:size, height:size, background:rep.color, borderRadius:4, fontSize:size*0.42 }}>
        {rep.initials}
      </div>
      {fire && (
        <div className="absolute -right-1 -top-1 grid h-5 w-5 place-items-center rounded-full bg-[#0A0A08] text-[12px]">
          <Flame />
        </div>
      )}
    </div>
  );
}

const Flame = () => (
  <span className="flame inline-block leading-none">🔥</span>
);

const Medal = ({ rank }) => {
  const palettes = {
    1: { a:"#FFD86B", b:"#F5B800", c:"#7A5A00", glow:"rgba(245,184,0,0.85)", label:"1ST" },
    2: { a:"#F2F4F8", b:"#C0C5CC", c:"#5C6066", glow:"rgba(220,225,232,0.5)",  label:"2ND" },
    3: { a:"#E8B582", b:"#C58A4F", c:"#6A3E1A", glow:"rgba(197,138,79,0.55)",   label:"3RD" },
  };
  if (rank > 3) {
    return (
      <span className="font-display text-[15px] font-bold tabular-nums text-white/25">{String(rank).padStart(2,"0")}</span>
    );
  }
  const p = palettes[rank];
  const size = rank === 1 ? 36 : 30;
  return (
    <div className="relative">
      {rank === 1 && <span className="absolute inset-0 -m-1 rounded-full medal-pulse" style={{ background: p.glow }} />}
      <div className={"relative grid place-items-center font-display font-black text-[#0A0A08] " + (rank === 1 ? "medal-shine" : "")}
        style={{
          width: size, height: size,
          background: `radial-gradient(circle at 30% 25%, ${p.a} 0%, ${p.b} 55%, ${p.c} 100%)`,
          clipPath:"polygon(50% 0, 95% 25%, 95% 75%, 50% 100%, 5% 75%, 5% 25%)",
          boxShadow: rank === 1 ? `0 0 18px ${p.glow}, inset 0 0 8px rgba(255,255,255,0.35)` : `0 0 10px ${p.glow}, inset 0 0 6px rgba(255,255,255,0.25)`,
        }}>
        <span className="font-display font-black leading-none" style={{ fontSize: rank===1 ? 12 : 10, letterSpacing: "0.04em" }}>{p.label}</span>
      </div>
    </div>
  );
};

function StatusPill({ rep }) {
  if (rep.status === "ON_FIRE")
    return (
      <span className="inline-flex shrink-0 items-center gap-1 whitespace-nowrap rounded-sm bg-amber-400/15 px-1.5 py-0.5 font-mono text-[9.5px] font-bold tracking-[0.2em] text-amber-300">
        <Flame /> ON FIRE
      </span>
    );
  if (rep.status === "ACTIVE")
    return (
      <span className="inline-flex shrink-0 items-center gap-1.5 whitespace-nowrap rounded-sm bg-emerald-400/10 px-1.5 py-0.5 font-mono text-[9.5px] font-bold tracking-[0.2em] text-emerald-300">
        <span className="h-1.5 w-1.5 animate-pulse rounded-full bg-emerald-400 shadow-[0_0_6px_rgba(52,211,153,0.8)]" />
        DIALING
      </span>
    );
  return (
    <span className="inline-flex shrink-0 items-center gap-1.5 whitespace-nowrap rounded-sm bg-rose-500/10 px-1.5 py-0.5 font-mono text-[9.5px] font-bold tracking-[0.2em] text-rose-300">
      <span className="h-1.5 w-1.5 rounded-full bg-rose-400" />
      IDLE {fmtIdle(rep.last_call_at)}
    </span>
  );
}

function Leaderboard({ reps, topDials, recentlyDialedId }) {
  return (
    <section className="flex flex-col border border-white/5 bg-[#100E08]" style={{maxHeight: 720}}>
      <header className="flex items-center justify-between gap-3 whitespace-nowrap border-b border-white/5 px-4 py-2.5">
        <div className="flex items-center gap-2">
          <span className="h-2 w-2 bg-amber-400" />
          <h2 className="font-mono text-[13px] font-bold tracking-[0.28em] text-white/70">/ LEADERBOARD · {reps.length} REPS</h2>
        </div>
        <div className="font-mono text-[10px] tracking-[0.2em] text-white/35">
          DIALS · CONN% · TALK · APPTS
        </div>
      </header>

      <ol className="flex flex-col overflow-y-auto">
        {reps.map((rep, i) => {
          const rank = i + 1;
          const connRate = rep.dials_made ? Math.min(100, Math.max(0, (rep.dials_connected / rep.dials_made) * 100)) : 0;
          const barPct = (rep.dials_made / topDials) * 100;
          const isFire = rep.status === "ON_FIRE";
          const isIdle = rep.status === "IDLE";
          const justDialed = rep.id === recentlyDialedId;

          return (
            <li key={rep.id}
              className={`relative grid items-center gap-3 border-b border-white/5 transition-colors
                ${rank === 1 ? "grid-cols-[44px_44px_minmax(0,1fr)_auto] px-4 py-3.5" : rank <= 3 ? "grid-cols-[40px_40px_minmax(0,1fr)_auto] px-4 py-3" : "grid-cols-[28px_36px_minmax(0,1fr)_auto] px-4 py-2.5"}
                ${rank === 1 ? "bg-gradient-to-r from-amber-400/[0.13] via-amber-400/[0.05] to-transparent" : rank === 2 ? "bg-gradient-to-r from-white/[0.05] to-transparent" : rank === 3 ? "bg-gradient-to-r from-orange-300/[0.04] to-transparent" : ""}
                ${isFire && rank > 3 ? "bg-gradient-to-r from-amber-500/[0.04] to-transparent" : ""}
                ${isIdle ? "bg-rose-500/[0.025]" : ""}
                ${justDialed ? "ring-1 ring-inset ring-amber-300/40" : ""}`}>
              {rank === 1 && <span className="absolute inset-y-0 left-0 w-[3px] bg-gradient-to-b from-amber-300 via-amber-400 to-amber-500" style={{boxShadow:"0 0 14px rgba(245,184,0,0.7)"}} />}
              {rank === 2 && <span className="absolute inset-y-0 left-0 w-[2px] bg-white/60" />}
              {rank === 3 && <span className="absolute inset-y-0 left-0 w-[2px] bg-[#C58A4F]" />}
              {isIdle && rank > 3 && <span className="absolute inset-y-0 left-0 w-[2px] bg-rose-500/60" />}
              {isFire && rank > 3 && <span className="absolute inset-y-0 left-0 w-[2px] bg-amber-400" />}

              <div className="flex items-center justify-center">
                <Medal rank={rank} />
              </div>

              <Avatar rep={rep} size={rank === 1 ? 44 : rank <= 3 ? 40 : 36} fire={isFire} />

              <div className="min-w-0">
                <div className="flex min-w-0 items-center gap-2">
                  <span className={`min-w-0 truncate font-display font-extrabold leading-none ${rank === 1 ? "text-[22px] text-amber-50" : rank <= 3 ? "text-[20px] text-white" : "text-[18px] text-white/85 font-bold"}`}>{rep.name}</span>
                  {rank === 1 && <span className="shrink-0 text-[22px] leading-none" style={{filter: "drop-shadow(0 0 8px rgba(245,184,0,0.7))"}} title="LEADER">👑</span>}
                  <StatusPill rep={rep} />
                </div>
                <div className="mt-1.5 flex items-center gap-2">
                  <div className={`relative flex-1 overflow-hidden rounded-sm bg-white/5 ${rank === 1 ? "h-[8px]" : "h-[6px]"}`}>
                    <div className={`absolute inset-y-0 left-0 transition-[width] duration-700 ${rank === 1 ? "bg-gradient-to-r from-amber-500 via-amber-300 to-amber-200" : isFire ? "bg-gradient-to-r from-amber-500 to-amber-300" : rank <= 3 ? "bg-white/55" : "bg-white/30"}`}
                         style={{ width: barPct + "%", boxShadow: rank === 1 ? "0 0 10px rgba(245,184,0,0.55)" : "none" }} />
                    {(isFire || rank === 1) && (
                      <div className="absolute inset-0 opacity-60 animate-[shimmer_2.4s_linear_infinite] bg-[linear-gradient(90deg,transparent,rgba(245,184,0,0.7),transparent)] bg-[length:200%_100%]" />
                    )}
                  </div>
                  <span className="whitespace-nowrap font-mono text-[9.5px] tracking-[0.16em] text-white/40">{rep.dials_made} DIALS</span>
                </div>
              </div>

              <div className={`flex shrink-0 items-center gap-5 whitespace-nowrap pl-2 font-mono text-[10px] tracking-[0.12em] ${rank > 3 ? "text-white/45" : "text-white/65"}`}>
                <Cell label="CONN" value={<><Tick value={rep.dials_connected} /></>} width={42} dim={rank > 3} />
                <Cell label="RATE" value={<><Tick value={connRate} fmt={(n)=>n.toFixed(1)+"%"} /></>} width={56} dim={rank > 3} />
                <Cell label="TALK" value={fmtTime(rep.talk_time_seconds)} mono width={64} dim={rank > 3} />
                <Cell label="APPTS" value={<Tick value={rep.appointments_set} />} hot={rank === 1 || isFire} big width={56} crown={rank === 1} />
              </div>
            </li>
          );
        })}
      </ol>
    </section>
  );
}

const Cell = ({ label, value, hot, big, mono, width, dim, crown }) => (
  <div className="shrink-0 text-right" style={{ minWidth: width }}>
    <div className={`text-[9px] tracking-[0.22em] ${dim ? "text-white/25" : "text-white/40"}`}>/ {label}</div>
    <div className={`relative font-display tabular-nums ${big ? "text-[20px] font-black" : "text-[14px] font-bold"} ${hot ? "text-amber-300" : dim ? "text-white/65" : "text-white"} ${mono ? "font-mono text-[12px] tracking-tight font-bold" : ""}`}
      style={{ textShadow: hot && big ? "0 0 10px rgba(245,184,0,0.45)" : "none" }}>
      {value}{crown && <span className="ml-1 text-amber-300">★</span>}
    </div>
  </div>
);

// ─────────────────────────────────────────────────────────────
// LIVE CALL FEED
// ─────────────────────────────────────────────────────────────
function LiveFeed({ events, pulse, funMode, setFunMode }) {
  // Watch for a brand-new demo_booked event so we can fire the celebration
  // (banner + screen flash + sparkle burst). Trigger keys off the event id
  // and auto-clears so it fires every booking, not just the first.
  const [celebration, setCelebration] = useState(null);
  const lastSeenIdRef = useRef(null);
  useEffect(() => {
    const newest = events[0];
    if (!newest || newest.outcome.key !== "demo_booked") return;
    if (lastSeenIdRef.current === newest.id) return;
    lastSeenIdRef.current = newest.id;
    setCelebration({ id: newest.id, rep: newest.rep });
    const t = setTimeout(() => setCelebration(null), 4200);
    return () => clearTimeout(t);
  }, [events]);

  // Sparkle burst — fly outward from the avatar of the booking rep.
  const sparkles = useMemo(() => {
    if (!celebration) return [];
    return Array.from({ length: 10 }, (_, i) => {
      const angle = (i / 10) * Math.PI * 2;
      const dist = 40 + Math.random() * 36;
      return {
        id: i,
        glyph: ["✨","⭐","💥","🔥","💰","👑"][i % 6],
        dx: Math.cos(angle) * dist,
        dy: Math.sin(angle) * dist - 10,
        delay: Math.random() * 0.18,
      };
    });
  }, [celebration?.id]);

  return (
    <aside className="relative flex flex-col border border-white/5 bg-[#100E08]">
      {/* full-screen gold flash whenever someone books */}
      {celebration && <div key={"flash-" + celebration.id} className="screen-flash" />}

      {/* slide-in banner above the feed list */}
      {celebration && (
        <div key={"banner-" + celebration.id} className="booked-banner pointer-events-none absolute left-0 right-0 top-0 z-30 overflow-hidden">
          <div className="flex items-center justify-center gap-2 bg-gradient-to-r from-amber-500 via-amber-300 to-amber-500 px-3 py-2 shadow-[0_0_40px_rgba(245,184,0,0.65)]">
            <span className="text-[18px]">🎉</span>
            <span className="font-display text-[15px] font-black tracking-[0.08em] text-[#0A0A08]">
              {celebration.rep.name.toUpperCase()} BOOKED A DEMO
            </span>
            <span className="text-[18px]">👑</span>
          </div>
        </div>
      )}

      <header className="flex items-center justify-between gap-2 border-b border-white/5 px-4 py-3">
        <div className="flex items-center gap-2">
          <span className={`h-2 w-2 rounded-full bg-emerald-400 ${pulse ? "animate-ping-fast" : ""}`}
                style={{ boxShadow: "0 0 10px 2px rgba(52,211,153,0.5)" }} />
          <h2 className="whitespace-nowrap font-mono text-[15px] font-bold tracking-[0.28em] text-white/80">/ LIVE CALL FEED</h2>
        </div>
        <button
          onClick={() => setFunMode(v => !v)}
          title={funMode ? "Hide commentary" : "Show commentary"}
          className={`group inline-flex items-center gap-1.5 whitespace-nowrap rounded-sm border px-2.5 py-1.5 font-mono text-[12px] font-bold tracking-[0.2em] transition-colors ${funMode ? "border-amber-400/40 bg-amber-400/10 text-amber-300" : "border-white/10 bg-white/[0.03] text-white/40 hover:text-white/70"}`}>
          <span>{funMode ? "🔥" : "💤"}</span>
          <span>HOT TAKES · {funMode ? "ON" : "OFF"}</span>
        </button>
      </header>
      <ul className="relative">
        {events.map((e, i) => {
          const isBooked = e.outcome.key === "demo_booked";
          return (
            <li key={e.id}
                className={`feed-row relative flex items-start gap-3 border-b border-white/[0.04] px-4 py-3 ${isBooked ? "booked-row overflow-visible" : ""}`}
                style={{ opacity: Math.max(0.3, 1 - i*0.06) }}>
              <div className={`relative ${isBooked ? "booked-avatar" : ""}`}>
                <Avatar rep={e.rep} size={36} />
                {/* sparkles fly out only on the most recent booking */}
                {isBooked && celebration?.id === e.id && sparkles.map((s) => (
                  <span
                    key={s.id}
                    className="booked-sparkle"
                    style={{
                      left: 18, top: 18,
                      "--dx": s.dx + "px",
                      "--dy": s.dy + "px",
                      animationDelay: s.delay + "s",
                    }}>
                    {s.glyph}
                  </span>
                ))}
              </div>
              <div className="min-w-0 flex-1">
                <div className="flex items-center justify-between gap-2">
                  <div className={`truncate font-display text-[18px] font-bold leading-none ${isBooked ? "text-amber-100" : "text-white"}`}>
                    {e.rep.name}
                    {isBooked && <span className="ml-2 text-[20px]">👑</span>}
                  </div>
                  <span className={isBooked ? "booked-badge" : ""}>
                    <OutcomeBadge outcome={e.outcome} />
                  </span>
                </div>
                <div className="mt-1.5 font-mono text-[12px] tracking-[0.18em] text-white/45">
                  {e.timeLabel} · DIAL #{e.dialNum}
                </div>
                {funMode && e.commentary && (
                  <div className={`mt-1.5 flex items-start gap-2 font-display text-[15px] font-medium italic leading-snug ${e.outcome.tone === "fire" ? "text-amber-200" : e.outcome.tone === "good" ? "text-emerald-200/90" : e.outcome.tone === "warn" ? "text-rose-200/85" : "text-white/65"}`}>
                    <span className="shrink-0 not-italic text-[18px]">{e.commentary.emoji}</span>
                    <span className="min-w-0">“{e.commentary.text}”</span>
                  </div>
                )}
              </div>
            </li>
          );
        })}
      </ul>
    </aside>
  );
}

const OutcomeBadge = ({ outcome }) => {
  const tones = {
    good:  "bg-emerald-400/10 text-emerald-300 border-emerald-400/20",
    fire:  "bg-amber-400/15 text-amber-300 border-amber-400/30",
    warn:  "bg-orange-500/10 text-orange-300 border-orange-500/20",
    muted: "bg-white/5 text-white/45 border-white/10",
  };
  return (
    <span className={`shrink-0 whitespace-nowrap rounded-sm border px-2 py-1 font-mono text-[11px] font-bold tracking-[0.18em] ${tones[outcome.tone]}`}>
      {outcome.tone === "fire" && <span className="mr-1">🔥</span>}
      {outcome.label}
    </span>
  );
};

// ─────────────────────────────────────────────────────────────
// AGGREGATE FOOTER
// ─────────────────────────────────────────────────────────────
function AggregateFooter({ reps }) {
  const totals = useMemo(() => {
    const safe = (n) => (typeof n === "number" && Number.isFinite(n) ? n : 0);
    const dials = reps.reduce((s,r)=>s+safe(r.dials_made),0);
    const conn  = reps.reduce((s,r)=>s+safe(r.dials_connected),0);
    const talk  = reps.reduce((s,r)=>s+safe(r.talk_time_seconds),0);
    const appts = reps.reduce((s,r)=>s+safe(r.appointments_set),0);
    const rate  = dials > 0 ? Math.min(100, Math.max(0, (conn/dials)*100)) : 0;
    return { dials, conn, talk, appts, rate };
  }, [reps]);

  const cards = [
    { k: "TEAM DIALS",       v: <Tick value={totals.dials} /> },
    { k: "TEAM CONNECT RATE",v: <Tick value={totals.rate} fmt={(n)=>n.toFixed(1)+"%"} /> },
    { k: "TEAM TALK TIME",   v: fmtTime(totals.talk), mono:true },
    { k: "APPTS BOOKED",     v: <Tick value={totals.appts} />, hot:true },
  ];

  return (
    <footer className="grid grid-cols-2 gap-px overflow-hidden border border-white/5 bg-white/5 md:grid-cols-4">
      {cards.map((c, i) => (
        <div key={c.k} className="relative bg-[#100E08] px-4 py-3">
          <div className="flex items-center gap-1.5 font-mono text-[11px] tracking-[0.28em] text-white/40">
            <span>/</span>{c.k}
          </div>
          <div className={`mt-1 font-display tabular-nums ${c.hot ? "text-amber-300" : "text-white"} ${c.mono ? "font-mono text-[30px] tracking-tight" : "text-[36px] font-extrabold"}`}>
            {c.v}
          </div>
          {i === 3 && <div className="absolute right-3 top-3 text-[16px]"><Flame /></div>}
        </div>
      ))}
    </footer>
  );
}

// ─────────────────────────────────────────────────────────────
// TEAM CHAT — single shared state, rendered by both the always-visible
// bottom strip (TrollBox) and the optional floating popout (FloatingChat).
// ─────────────────────────────────────────────────────────────
const fmtChatTime = (d) => {
  let h = d.getHours();
  const m = String(d.getMinutes()).padStart(2,"0");
  const ampm = h >= 12 ? "p" : "a";
  h = h % 12 || 12;
  return `${h}:${m}${ampm}`;
};

// Shared hook: anyone consuming this gets the same backlog + ticker, so the
// bottom strip and the floating window never diverge.
function useChatRoom() {
  const [messages, setMessages] = useState(() => {
    const start = Date.now() - CHAT_BACKLOG.length * 42_000; // ~12 min of "history"
    return CHAT_BACKLOG.map((l, i) => ({
      id: i,
      user: userById(l.from),
      text: l.text,
      time: new Date(start + i * 42_000),
    }));
  });
  const [input, setInput] = useState("");
  const [typing, setTyping] = useState(null);
  const idRef = useRef(CHAT_BACKLOG.length);
  const lastUserRef = useRef(null);

  useEffect(() => {
    let to1, to2;
    const cycle = () => {
      let u;
      for (let i = 0; i < 6; i++) {
        u = CHAT_USERS[Math.floor(Math.random() * CHAT_USERS.length)];
        if (u.id !== lastUserRef.current) break;
      }
      setTyping(u);
      to1 = setTimeout(() => {
        setTyping(null);
        const text = IDLE_BANTER[Math.floor(Math.random() * IDLE_BANTER.length)];
        const id = ++idRef.current;
        lastUserRef.current = u.id;
        setMessages((m) => [...m, { id, user: u, text, time: new Date() }].slice(-80));
      }, 700 + Math.random() * 800);
      to2 = setTimeout(cycle, 3800 + Math.random() * 5200);
    };
    to2 = setTimeout(cycle, 2400);
    return () => { clearTimeout(to1); clearTimeout(to2); };
  }, []);

  const send = () => {
    const trimmed = input.trim();
    if (!trimmed) return;
    const id = ++idRef.current;
    setMessages((m) => [...m, {
      id,
      user: { handle: "YOU", color: "#FAFAF7", role: "demo" },
      text: trimmed,
      time: new Date(),
    }].slice(-80));
    setInput("");
  };

  return { messages, input, setInput, typing, send };
}

// Tiny shared sub-components so both views render identical chat rows.
function ChatBody({ messages, typing, scrollRef }) {
  return (
    <ul ref={scrollRef} className="flex-1 overflow-y-auto px-3.5 py-2 font-mono text-[12px] leading-snug">
      {messages.map((m) => (
        <li key={m.id} className="mb-0.5 break-words">
          <span className="mr-1.5 tabular-nums text-white/30">{fmtChatTime(m.time)}</span>
          <span className="font-bold" style={{ color: m.user.color }}>&lt;{m.user.handle}&gt;</span>
          <span className="ml-1.5 text-white/85">{m.text}</span>
        </li>
      ))}
      {typing && (
        <li className="italic text-white/35">
          <span className="mr-1.5 tabular-nums text-white/20">{fmtChatTime(new Date())}</span>
          <span className="font-bold" style={{ color: typing.color }}>{typing.handle}</span>
          <span className="ml-1.5">is typing<span className="animate-pulse">...</span></span>
        </li>
      )}
    </ul>
  );
}

function ChatInputRow({ input, setInput, send }) {
  return (
    <footer className="flex items-center gap-2 border-t border-white/10 bg-black/30 px-3 py-1.5">
      <span className="whitespace-nowrap font-mono text-[10.5px] font-bold tracking-[0.18em] text-amber-300/80">&lt;YOU&gt;</span>
      <input
        value={input}
        onChange={(e) => setInput(e.target.value)}
        onKeyDown={(e) => { if (e.key === "Enter") send(); }}
        maxLength={140}
        placeholder="say something..."
        className="min-w-0 flex-1 bg-transparent font-mono text-[12px] text-white placeholder:text-white/25 outline-none"
      />
      <button
        onClick={send}
        className="whitespace-nowrap rounded-sm bg-amber-400 px-2.5 py-1 font-mono text-[10px] font-black tracking-[0.22em] text-[#0A0A08] hover:bg-amber-300">
        SEND
      </button>
    </footer>
  );
}

function TrollBox({ chat }) {
  const { messages, input, setInput, typing, send } = chat;
  const listRef = useRef(null);
  useEffect(() => {
    if (listRef.current) listRef.current.scrollTop = listRef.current.scrollHeight;
  }, [messages, typing]);

  return (
    <section className="flex flex-col border border-amber-400/25 bg-[#0E0B05]" style={{height: 220}}>
      <header className="flex items-center justify-between gap-3 border-b border-amber-400/30 bg-gradient-to-r from-amber-400/[0.22] via-amber-400/[0.08] to-transparent px-3.5 py-2">
        <div className="flex items-center gap-2.5">
          <span className="inline-flex h-2 w-2 bg-amber-400" style={{boxShadow:"0 0 10px rgba(245,184,0,0.7)"}} />
          <h2 className="font-mono text-[12.5px] font-bold tracking-[0.28em] text-amber-200">/ CHAT ROOM · #riverside-north</h2>
          <span className="hidden md:inline font-mono text-[10px] tracking-[0.22em] text-white/35">all reps · log persists for 24h</span>
        </div>
        <div className="flex items-center gap-3 font-mono text-[10px] tracking-[0.22em] text-emerald-300/85">
          <span className="inline-flex items-center gap-1.5">
            <span className="h-1.5 w-1.5 animate-pulse rounded-full bg-emerald-400 shadow-[0_0_6px_rgba(52,211,153,0.7)]" />
            {CHAT_USERS.length} ONLINE
          </span>
        </div>
      </header>
      <ChatBody messages={messages} typing={typing} scrollRef={listRef} />
      <ChatInputRow input={input} setInput={setInput} send={send} />
    </section>
  );
}

// ─────────────────────────────────────────────────────────────
// FLOATING CHAT — popup window, draggable by its title bar, with X to close.
// Shares state with the bottom TrollBox via the same `chat` prop.
// ─────────────────────────────────────────────────────────────
function FloatingChat({ chat, onClose }) {
  const { messages, input, setInput, typing, send } = chat;
  const WIDTH = 420;
  const HEIGHT = 480;
  const [pos, setPos] = useState(() => ({
    x: Math.max(20, (typeof window !== "undefined" ? window.innerWidth : 1200) / 2 - WIDTH / 2),
    y: 84,
  }));
  const [dragOffset, setDragOffset] = useState(null);
  const dragging = dragOffset != null;

  const onHeaderDown = (e) => {
    // ignore drag if X button captured the click
    if (e.target.closest("[data-no-drag]")) return;
    setDragOffset({ x: e.clientX - pos.x, y: e.clientY - pos.y });
  };
  useEffect(() => {
    if (!dragging) return;
    const onMove = (e) => {
      const w = window.innerWidth, h = window.innerHeight;
      setPos({
        x: Math.max(0, Math.min(w - WIDTH, e.clientX - dragOffset.x)),
        y: Math.max(0, Math.min(h - 80, e.clientY - dragOffset.y)),
      });
    };
    const onUp = () => setDragOffset(null);
    window.addEventListener("mousemove", onMove);
    window.addEventListener("mouseup", onUp);
    return () => {
      window.removeEventListener("mousemove", onMove);
      window.removeEventListener("mouseup", onUp);
    };
  }, [dragging, dragOffset]);

  const listRef = useRef(null);
  useEffect(() => {
    if (listRef.current) listRef.current.scrollTop = listRef.current.scrollHeight;
  }, [messages, typing]);

  return (
    <div
      className="fixed z-50 flex flex-col border-2 border-amber-400/60 bg-[#0E0B05] shadow-[0_50px_120px_-20px_rgba(0,0,0,0.85)]"
      style={{ left: pos.x, top: pos.y, width: WIDTH, height: HEIGHT }}
      role="dialog" aria-label="Team chat">
      {/* AOL-style title bar (draggable) */}
      <header
        onMouseDown={onHeaderDown}
        className={`flex items-center justify-between gap-3 border-b border-amber-400/40 bg-gradient-to-r from-amber-400/[0.35] via-amber-400/[0.15] to-amber-400/[0.05] px-3 py-2 ${dragging ? "cursor-grabbing" : "cursor-grab"} select-none`}
        style={{ userSelect: "none" }}>
        <div className="flex items-center gap-2.5">
          <span className="inline-flex h-2 w-2 bg-amber-400" style={{boxShadow:"0 0 10px rgba(245,184,0,0.8)"}} />
          <h2 className="font-mono text-[12.5px] font-bold tracking-[0.28em] text-amber-100">/ TEAM CHAT</h2>
          <span className="hidden sm:inline font-mono text-[10px] tracking-[0.22em] text-white/40">#riverside-north</span>
        </div>
        <div className="flex items-center gap-2">
          <span className="hidden md:inline font-mono text-[9px] tracking-[0.22em] text-emerald-300/85">{CHAT_USERS.length} ONLINE</span>
          <button
            data-no-drag
            onClick={onClose}
            className="grid h-6 w-6 place-items-center rounded-sm border border-white/15 bg-black/40 font-mono text-[14px] font-bold leading-none text-white/70 hover:border-rose-400/60 hover:bg-rose-400/15 hover:text-rose-200"
            aria-label="Close chat">
            ✕
          </button>
        </div>
      </header>
      <ChatBody messages={messages} typing={typing} scrollRef={listRef} />
      <ChatInputRow input={input} setInput={setInput} send={send} />
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// SALES FLOOR VIEW
// ─────────────────────────────────────────────────────────────
function SalesHero({ reps, unitOverride, setUnitOverride, goal = SALES_GOAL_UNITS, periodLabel = "MONTH-TO-DATE" }) {
  const totals = useMemo(() => {
    const units = reps.reduce((s,r)=>s+r.units, 0);
    const front = reps.reduce((s,r)=>s+r.front_gross, 0);
    const back  = reps.reduce((s,r)=>s+r.back_gross, 0);
    const total = front + back;
    const avg   = units ? total / units : 0;
    const top   = [...reps].sort((a,b)=>b.units-a.units)[0];
    return { units, front, back, total, avg, top };
  }, [reps]);
  // Scrub override wins when set
  const displayUnits = unitOverride != null ? unitOverride : totals.units;
  const pct = Math.min(999, (displayUnits / goal) * 100);
  const barPct = Math.min(100, pct);
  const overGoal = displayUnits >= goal;
  const scrubbing = unitOverride != null;

  // Drag to scrub
  const barRef = useRef(null);
  const [dragging, setDragging] = useState(false);
  const SCRUB_MAX = Math.round(goal * 1.4);
  const updateFromClientX = (clientX) => {
    const el = barRef.current; if (!el) return;
    const rect = el.getBoundingClientRect();
    const ratio = Math.min(1, Math.max(0, (clientX - rect.left) / rect.width));
    setUnitOverride(Math.round(ratio * SCRUB_MAX));
  };
  useEffect(() => {
    if (!dragging) return;
    const onMove = (e) => updateFromClientX(e.clientX ?? e.touches?.[0]?.clientX ?? 0);
    const onUp = () => setDragging(false);
    window.addEventListener("mousemove", onMove);
    window.addEventListener("mouseup", onUp);
    window.addEventListener("touchmove", onMove, { passive: false });
    window.addEventListener("touchend", onUp);
    return () => {
      window.removeEventListener("mousemove", onMove);
      window.removeEventListener("mouseup", onUp);
      window.removeEventListener("touchmove", onMove);
      window.removeEventListener("touchend", onUp);
    };
  }, [dragging]);

  // Confetti when crossing goal during scrub
  const [celebrate, setCelebrate] = useState(false);
  const prevOver = useRef(overGoal);
  useEffect(() => {
    if (overGoal && !prevOver.current) {
      setCelebrate(true);
      const t = setTimeout(() => setCelebrate(false), 4200);
      prevOver.current = overGoal;
      return () => clearTimeout(t);
    }
    prevOver.current = overGoal;
  }, [overGoal]);

  let mood;
  if (overGoal)        mood = { color: "text-emerald-300", emoji: "🏆", accent: "💚" };
  else if (pct < 15)   mood = { color: "text-rose-400",    emoji: "💀", accent: "🪦" };
  else if (pct < 30)   mood = { color: "text-orange-300",  emoji: "😶", accent: "🤐" };
  else if (pct < 45)   mood = { color: "text-amber-300",   emoji: "🌡️", accent: "♨️" };
  else if (pct < 60)   mood = { color: "text-amber-200",   emoji: "🔥", accent: "💥" };
  else if (pct < 75)   mood = { color: "text-amber-200",   emoji: "🔥", accent: "⚡" };
  else if (pct < 90)   mood = { color: "text-amber-300",   emoji: "🔥", accent: "🚒" };
  else                 mood = { color: "text-orange-200",  emoji: "🚨", accent: "🔥" };

  return (
    <section className={`relative overflow-hidden border bg-gradient-to-br from-amber-400/[0.08] via-[#16140F] to-[#0F0E0A] ${overGoal ? "border-emerald-400/40" : "border-amber-400/30"}`}>
      <div className="absolute inset-0 opacity-[0.06]" style={{
        backgroundImage:"repeating-linear-gradient(45deg, #F5B800 0 1px, transparent 1px 14px)"
      }} />
      {celebrate && <Confetti />}
      <div className="relative grid grid-cols-12 items-center gap-3 p-3">
        <div className="col-span-12 md:col-span-4">
          <div className="whitespace-nowrap font-mono text-[11px] font-bold tracking-[0.28em] text-white/65">/ MAY · {periodLabel}</div>
          <div className="mt-0.5 flex items-baseline gap-2">
            <span className="font-figure text-[48px] leading-none text-amber-50"><Tick value={displayUnits} /></span>
            <span className="font-display text-[24px] font-black leading-none text-white/35">/ {goal} UNITS</span>
            <span className="ml-1 inline-flex items-center gap-1 text-[20px] leading-none">
              <span>{mood.emoji}</span>
              <span className="text-[16px] opacity-80">{mood.accent}</span>
            </span>
          </div>
        </div>

        <div className="col-span-12 md:col-span-4 md:col-start-5 flex items-center gap-3">
          <div className="relative grid h-[56px] w-[56px] shrink-0 place-items-center bg-amber-400 text-[#0A0A08]"
               style={{clipPath:"polygon(50% 0, 100% 25%, 100% 75%, 50% 100%, 0 75%, 0 25%)"}}>
            <span className="font-figure text-[26px] leading-none">$</span>
            <span className="absolute inset-0 animate-[shimmer_2.6s_linear_infinite] bg-[linear-gradient(90deg,transparent,rgba(255,255,255,0.5),transparent)] bg-[length:200%_100%]"
                  style={{clipPath:"polygon(50% 0, 100% 25%, 100% 75%, 50% 100%, 0 75%, 0 25%)"}}></span>
          </div>
          <div className="min-w-0">
            <div className="whitespace-nowrap font-mono text-[10px] font-bold tracking-[0.3em] text-amber-300/90">/ TOTAL GROSS</div>
            <div className="font-figure text-[38px] leading-[0.95] text-amber-50">{fmtMoneyK(totals.total)}</div>
            <div className="mt-0.5 whitespace-nowrap font-mono text-[10px] tracking-[0.22em] text-white/45">
              FRONT {fmtMoneyK(totals.front)} · BACK {fmtMoneyK(totals.back)}
            </div>
          </div>
        </div>

        <div className="col-span-12 md:col-span-3 md:col-start-10 flex items-center md:justify-end">
          <div className="md:text-right">
            <div className="whitespace-nowrap font-mono text-[10px] font-bold tracking-[0.28em] text-white/45">/ MONTH LEADER</div>
            <div className="mt-0.5 inline-flex items-center gap-1.5 font-display text-[17px] md:text-[18px] font-black leading-tight tracking-[0.04em] text-amber-200">
              <span className="text-[20px] leading-none">👑</span>
              <span className="whitespace-nowrap">{totals.top.name.toUpperCase()}</span>
            </div>
            <div className="mt-0.5 font-mono text-[10px] tracking-[0.22em] text-white/45">{totals.top.units} UNITS · {fmtMoneyK(totals.top.front_gross + totals.top.back_gross)}</div>
          </div>
        </div>

        {/* Scrubable goal bar */}
        <div className="col-span-12">
          <div className="mb-1 flex items-center justify-between gap-2 font-mono text-[9px] tracking-[0.22em] text-white/35">
            <span>← DRAG TO PREVIEW MONTHLY PROGRESS</span>
            {scrubbing && (
              <button
                onClick={() => setUnitOverride(null)}
                className="rounded-sm border border-amber-400/40 bg-amber-400/15 px-2 py-0.5 font-mono text-[9px] font-bold tracking-[0.22em] text-amber-300 hover:bg-amber-400/25">
                RESET TO LIVE
              </button>
            )}
          </div>
          <div
            ref={barRef}
            onMouseDown={(e) => { setDragging(true); updateFromClientX(e.clientX); }}
            onTouchStart={(e) => { setDragging(true); updateFromClientX(e.touches[0].clientX); }}
            className={`relative h-5 rounded-sm bg-white/[0.06] ring-1 ring-white/5 ${dragging ? "cursor-grabbing" : "cursor-grab"} select-none`}
            style={{ userSelect: "none" }}>
            {[25,50,75].map((m) => (
              <div key={m} className="absolute inset-y-0 w-px bg-white/10" style={{ left: m+"%" }} />
            ))}
            <div className={`absolute inset-y-0 left-0 overflow-hidden rounded-sm transition-[width] duration-300 ${overGoal ? "bg-gradient-to-r from-emerald-500 via-amber-300 to-amber-200" : "bg-gradient-to-r from-amber-500 to-amber-300"}`}
                 style={{ width: barPct + "%", boxShadow: overGoal ? "0 0 22px rgba(52,211,153,0.55), 0 0 18px rgba(245,184,0,0.45)" : "0 0 16px rgba(245,184,0,0.55)" }}>
              <div className="absolute inset-0 animate-[shimmer_2.2s_linear_infinite] bg-[linear-gradient(90deg,transparent,rgba(255,255,255,0.55),transparent)] bg-[length:200%_100%]"></div>
            </div>
            {!overGoal && (
              <div className="pointer-events-none absolute top-1/2 -translate-y-1/2 transition-[left] duration-300"
                   style={{ left: `clamp(0%, ${barPct}%, 100%)` }}>
                <div className={`relative ${barPct > 88 ? "-translate-x-full" : barPct < 12 ? "" : "-translate-x-1/2"}`}>
                  <div className={`relative inline-flex items-center gap-1 whitespace-nowrap rounded-sm px-2 py-0.5 font-display text-[15px] font-black tabular-nums text-[#0A0A08] ${pct >= 50 ? "bg-amber-300" : "bg-amber-400"}`}
                       style={{ boxShadow: pct >= 75 ? "0 0 22px rgba(245,184,0,0.95)" : pct >= 50 ? "0 0 14px rgba(245,184,0,0.7)" : "0 0 6px rgba(245,184,0,0.4)" }}>
                    {pct >= 50 && <span className="flame text-[14px] leading-none">🔥</span>}
                    <Tick value={pct} fmt={(n)=>n.toFixed(0)+"%"} />
                  </div>
                </div>
              </div>
            )}
            {overGoal && (
              <div className="pointer-events-none absolute right-3 top-1/2 -translate-y-1/2 inline-flex items-center whitespace-nowrap rounded-sm bg-emerald-300 px-2 py-0.5 font-display text-[15px] font-black tabular-nums text-[#0A0A08]"
                   style={{ boxShadow:"0 0 18px rgba(52,211,153,0.7)" }}>
                <Tick value={pct} fmt={(n)=>n.toFixed(0)+"%"} />
              </div>
            )}
          </div>
          <div className="mt-1.5 flex items-center justify-between gap-3 whitespace-nowrap font-mono text-[10.5px] font-bold tracking-[0.22em] text-white/55">
            <span>{!overGoal ? <><span className="text-amber-300">{Math.max(0, goal - displayUnits)}</span> UNITS TO GOAL</> : <span className="text-emerald-300">+{displayUnits - goal} OVER GOAL · KEEP GOING</span>}</span>
          </div>
        </div>
      </div>
    </section>
  );
}

function SalesAggregates({ reps }) {
  const totals = useMemo(() => {
    const units = reps.reduce((s,r)=>s+r.units, 0);
    const total = reps.reduce((s,r)=>s+r.front_gross+r.back_gross, 0);
    const avg = units ? total/units : 0;
    const csi = Math.round(reps.reduce((s,r)=>s+r.csi, 0) / reps.length);
    return { units, total, avg, csi };
  }, [reps]);
  const cards = [
    { k: "UNITS SOLD",       v: totals.units },
    { k: "TOTAL GROSS",      v: fmtMoneyK(totals.total) },
    { k: "AVG GROSS / UNIT", v: fmtMoneyK(totals.avg), mono:true },
    { k: "TEAM CSI",         v: totals.csi + "%", hot:true },
  ];
  return (
    <footer className="grid grid-cols-2 gap-px overflow-hidden border border-white/5 bg-white/5 md:grid-cols-4">
      {cards.map((c, i) => (
        <div key={c.k} className="relative bg-[#100E08] px-4 py-3">
          <div className="flex items-center gap-1.5 font-mono text-[11px] tracking-[0.28em] text-white/40">
            <span>/</span>{c.k}
          </div>
          <div className={`mt-1 font-display tabular-nums ${c.hot ? "text-amber-300" : "text-white"} ${c.mono ? "font-mono text-[30px] tracking-tight" : "text-[36px] font-extrabold"}`}>
            {c.v}
          </div>
          {i === 3 && <div className="absolute right-3 top-3 text-[16px]">🏆</div>}
        </div>
      ))}
    </footer>
  );
}

function SalesLeaderboard({ reps }) {
  const topUnits = Math.max(...reps.map(r=>r.units), 1);
  return (
    <section className="flex flex-col border border-white/5 bg-[#100E08]" style={{maxHeight: 720}}>
      <header className="flex items-center justify-between gap-3 whitespace-nowrap border-b border-white/5 px-4 py-2.5">
        <div className="flex items-center gap-2">
          <span className="h-2 w-2 bg-amber-400" />
          <h2 className="font-mono text-[13px] font-bold tracking-[0.28em] text-white/70">/ SALES LEADERBOARD · {reps.length} SALESPEOPLE</h2>
        </div>
        <div className="font-mono text-[10px] tracking-[0.2em] text-white/35">
          UNITS · FRONT · BACK · TOTAL · CSI
        </div>
      </header>
      <ol className="flex flex-col overflow-y-auto">
        {reps.map((rep, i) => {
          const rank = i + 1;
          const total = rep.front_gross + rep.back_gross;
          const barPct = (rep.units / topUnits) * 100;
          return (
            <li key={rep.id}
              className={`relative grid items-center gap-3 border-b border-white/5
                ${rank === 1 ? "grid-cols-[44px_44px_minmax(0,1fr)_auto] px-4 py-3.5" : rank <= 3 ? "grid-cols-[40px_40px_minmax(0,1fr)_auto] px-4 py-3" : "grid-cols-[28px_36px_minmax(0,1fr)_auto] px-4 py-2.5"}
                ${rank === 1 ? "bg-gradient-to-r from-amber-400/[0.13] via-amber-400/[0.05] to-transparent" : rank === 2 ? "bg-gradient-to-r from-white/[0.05] to-transparent" : rank === 3 ? "bg-gradient-to-r from-orange-300/[0.04] to-transparent" : ""}`}>
              {rank === 1 && <span className="absolute inset-y-0 left-0 w-[3px] bg-gradient-to-b from-amber-300 via-amber-400 to-amber-500" style={{boxShadow:"0 0 14px rgba(245,184,0,0.7)"}} />}
              {rank === 2 && <span className="absolute inset-y-0 left-0 w-[2px] bg-white/60" />}
              {rank === 3 && <span className="absolute inset-y-0 left-0 w-[2px] bg-[#C58A4F]" />}

              <div className="flex items-center justify-center">
                <Medal rank={rank} />
              </div>
              <Avatar rep={rep} size={rank === 1 ? 44 : rank <= 3 ? 40 : 36} />

              <div className="min-w-0">
                <div className="flex min-w-0 items-center gap-2">
                  <span className={`min-w-0 truncate font-display font-extrabold leading-none ${rank === 1 ? "text-[22px] text-amber-50" : rank <= 3 ? "text-[20px] text-white" : "text-[18px] text-white/85 font-bold"}`}>{rep.name}</span>
                  {rank === 1 && <span className="shrink-0 text-[22px] leading-none" style={{filter:"drop-shadow(0 0 8px rgba(245,184,0,0.7))"}}>👑</span>}
                </div>
                <div className="mt-1.5 flex items-center gap-2">
                  <div className={`relative flex-1 overflow-hidden rounded-sm bg-white/5 ${rank === 1 ? "h-[8px]" : "h-[6px]"}`}>
                    <div className={`absolute inset-y-0 left-0 transition-[width] duration-700 ${rank === 1 ? "bg-gradient-to-r from-amber-500 via-amber-300 to-amber-200" : rank <= 3 ? "bg-white/55" : "bg-white/30"}`}
                         style={{ width: barPct + "%", boxShadow: rank === 1 ? "0 0 10px rgba(245,184,0,0.55)" : "none" }} />
                  </div>
                  <span className="whitespace-nowrap font-mono text-[9.5px] tracking-[0.16em] text-white/40">{rep.units} UNITS · LAST {rep.last_sale.toUpperCase()}</span>
                </div>
              </div>

              <div className={`flex shrink-0 items-center gap-5 whitespace-nowrap pl-2 font-mono text-[10px] tracking-[0.12em] ${rank > 3 ? "text-white/45" : "text-white/65"}`}>
                <Cell label="UNITS"  value={rep.units} width={42} hot={rank === 1} big={rank === 1} crown={rank === 1} dim={rank > 3} />
                <Cell label="FRONT"  value={fmtMoneyK(rep.front_gross)} mono width={56} dim={rank > 3} />
                <Cell label="BACK"   value={fmtMoneyK(rep.back_gross)} mono width={52} dim={rank > 3} />
                <Cell label="TOTAL"  value={fmtMoneyK(rep.front_gross + rep.back_gross)} mono width={62} hot={rank === 1} dim={rank > 3} />
                <Cell label="CSI"    value={rep.csi + "%"} width={42} dim={rank > 3} />
              </div>
            </li>
          );
        })}
      </ol>
    </section>
  );
}

// Live sales feed — every car sold triggers an over-the-top celebration
// (gold flash + banner + row pulse + sparkles), even bigger than the call
// floor's demo_booked treatment.
function SalesFeed({ events }) {
  const [celebration, setCelebration] = useState(null);
  const lastSeenIdRef = useRef(null);
  useEffect(() => {
    const newest = events[0];
    if (!newest) return;
    if (lastSeenIdRef.current === newest.id) return;
    lastSeenIdRef.current = newest.id;
    setCelebration({ id: newest.id, rep: newest.rep, vehicle: newest.vehicle, price: newest.price });
    const t = setTimeout(() => setCelebration(null), 4400);
    return () => clearTimeout(t);
  }, [events]);

  const sparkles = useMemo(() => {
    if (!celebration) return [];
    return Array.from({ length: 14 }, (_, i) => {
      const angle = (i / 14) * Math.PI * 2;
      const dist = 44 + Math.random() * 50;
      return {
        id: i,
        glyph: ["✨","⭐","💥","🔥","💰","👑","🎉","💸"][i % 8],
        dx: Math.cos(angle) * dist,
        dy: Math.sin(angle) * dist - 12,
        delay: Math.random() * 0.22,
      };
    });
  }, [celebration?.id]);

  return (
    <aside className="relative flex flex-col border border-white/5 bg-[#100E08]">
      {celebration && <div key={"flash-" + celebration.id} className="screen-flash" />}
      {celebration && (
        <div key={"banner-" + celebration.id} className="booked-banner pointer-events-none absolute left-0 right-0 top-0 z-30 overflow-hidden">
          <div className="flex items-center justify-center gap-2 bg-gradient-to-r from-amber-500 via-amber-300 to-amber-500 px-3 py-2 shadow-[0_0_40px_rgba(245,184,0,0.65)]">
            <span className="text-[18px]">🎉</span>
            <span className="font-display text-[14px] font-black tracking-[0.06em] text-[#0A0A08]">
              {celebration.rep.name.toUpperCase()} JUST SOLD A {celebration.vehicle.replace(/^['"]/, "").toUpperCase()} · {fmtMoneyK(celebration.price)}
            </span>
            <span className="text-[18px]">🚗</span>
          </div>
        </div>
      )}

      <header className="flex items-center justify-between gap-2 border-b border-white/5 px-4 py-3">
        <div className="flex items-center gap-2">
          <span className="h-2 w-2 rounded-full bg-emerald-400" style={{ boxShadow: "0 0 10px 2px rgba(52,211,153,0.5)" }} />
          <h2 className="whitespace-nowrap font-mono text-[15px] font-bold tracking-[0.28em] text-white/80">/ LIVE SALES FEED</h2>
        </div>
        <span className="font-mono text-[10px] tracking-[0.22em] text-white/40">CARS SOLD · TODAY</span>
      </header>
      <ul className="relative">
        {events.length === 0 && (
          <li className="px-4 py-6 text-center font-mono text-[11px] tracking-[0.18em] text-white/35">waiting for the next sale…</li>
        )}
        {events.map((e, i) => {
          const isLatest = i === 0 && celebration?.id === e.id;
          return (
            <li key={e.id}
                className={`feed-row relative flex items-start gap-3 border-b border-white/[0.04] px-4 py-3 ${isLatest ? "booked-row overflow-visible" : ""}`}
                style={{ opacity: Math.max(0.35, 1 - i*0.05) }}>
              <div className={`relative ${isLatest ? "booked-avatar" : ""}`}>
                <Avatar rep={e.rep} size={36} />
                {isLatest && sparkles.map((s) => (
                  <span key={s.id} className="booked-sparkle"
                    style={{
                      left: 18, top: 18,
                      "--dx": s.dx + "px",
                      "--dy": s.dy + "px",
                      animationDelay: s.delay + "s",
                    }}>{s.glyph}</span>
                ))}
              </div>
              <div className="min-w-0 flex-1">
                <div className="flex items-center justify-between gap-2">
                  <div className={`truncate font-display text-[18px] font-bold leading-none ${isLatest ? "text-amber-100" : "text-white"}`}>
                    {e.rep.name}
                    {isLatest && <span className="ml-2 text-[20px]">👑</span>}
                  </div>
                  <span className={`shrink-0 whitespace-nowrap rounded-sm border border-amber-400/40 bg-amber-400/15 px-2 py-1 font-mono text-[11px] font-bold tracking-[0.18em] text-amber-300 ${isLatest ? "booked-badge" : ""}`}>
                    🚗 SOLD
                  </span>
                </div>
                <div className="mt-1.5 truncate font-display text-[16px] font-bold leading-tight text-white/90">{e.vehicle}</div>
                <div className="mt-1 flex items-center justify-between gap-2 font-mono text-[12px] tracking-[0.16em] text-white/45">
                  <span>→ {e.buyer}</span>
                  <span className="font-display text-[16px] font-black tabular-nums text-amber-300" style={{textShadow:"0 0 8px rgba(245,184,0,0.45)"}}>{fmtMoneyK(e.price)}</span>
                </div>
              </div>
            </li>
          );
        })}
      </ul>
    </aside>
  );
}

function RecentDeliveries({ reps, liveEvents = [] }) {
  // Merge live events (newest first) with the seeded RECENT_DELIVERIES so the
  // panel always reflects fresh sales. Cap at 10 rows.
  const merged = useMemo(() => {
    const liveRows = liveEvents.map((e) => ({
      key: "live-" + e.id,
      rep: e.rep,
      vehicle: e.vehicle,
      buyer: e.buyer,
      price: e.price,
      time: "just now",
      isNew: true,
      id: e.id,
    }));
    const seeded = RECENT_DELIVERIES.map((d, i) => ({
      key: "seed-" + i,
      rep: reps.find((r) => r.id === d.repId),
      vehicle: d.vehicle,
      buyer: d.buyer,
      price: d.price,
      time: d.time,
      isNew: false,
    }));
    return [...liveRows, ...seeded].slice(0, 10);
  }, [liveEvents, reps]);

  // Celebrate the newest live row briefly
  const [celebrateId, setCelebrateId] = useState(null);
  const lastSeenRef = useRef(null);
  useEffect(() => {
    const newest = liveEvents[0];
    if (!newest || lastSeenRef.current === newest.id) return;
    lastSeenRef.current = newest.id;
    setCelebrateId(newest.id);
    const t = setTimeout(() => setCelebrateId(null), 3400);
    return () => clearTimeout(t);
  }, [liveEvents]);

  return (
    <aside className="flex flex-col border border-white/5 bg-[#100E08]">
      <header className="flex items-center gap-2 border-b border-white/5 px-4 py-3">
        <span className="h-2 w-2 bg-amber-400" />
        <h2 className="whitespace-nowrap font-mono text-[15px] font-bold tracking-[0.28em] text-white/80">/ RECENT DELIVERIES</h2>
      </header>
      <ul className="flex flex-col">
        {merged.map((d) => {
          const isCelebrating = d.id != null && d.id === celebrateId;
          return (
            <li key={d.key}
                className={`feed-row relative flex items-center gap-3 border-b border-white/[0.04] px-4 py-3 ${isCelebrating ? "booked-row overflow-visible" : ""}`}>
              <div className={isCelebrating ? "booked-avatar" : ""}>
                {d.rep && <Avatar rep={d.rep} size={32} />}
              </div>
              <div className="min-w-0 flex-1">
                <div className="truncate font-display text-[16px] font-bold leading-tight text-white">{d.vehicle}</div>
                <div className="font-mono text-[11px] tracking-[0.16em] text-white/45">
                  {d.rep ? d.rep.name.toUpperCase() : "—"} → {d.buyer}
                </div>
              </div>
              <div className="shrink-0 text-right">
                <div className={`font-display text-[15px] font-black tabular-nums text-amber-300 ${isCelebrating ? "booked-badge" : ""}`}
                     style={{textShadow:"0 0 8px rgba(245,184,0,0.35)"}}>{fmtMoneyK(d.price)}</div>
                <div className="font-mono text-[10px] tracking-[0.18em] text-white/40">{d.time.toUpperCase()}</div>
              </div>
            </li>
          );
        })}
      </ul>
    </aside>
  );
}

// ─────────────────────────────────────────────────────────────
// APP
// ─────────────────────────────────────────────────────────────
function App() {
  const [period, setPeriod] = useState("TODAY");
  const [sound, setSound] = useState(false);
  const [funMode, setFunMode] = useState(true);
  const [now, setNow] = useState(new Date());
  const [reps, setReps] = useState(SEED_REPS);
  const [events, setEvents] = useState([]);
  const [pulse, setPulse] = useState(false);
  const [lastDialed, setLastDialed] = useState(null);
  // Manual scrub override for the team appt count — null = follow live data.
  const [apptOverride, setApptOverride] = useState(null);
  // Floating chat window toggle.
  const [chatOpen, setChatOpen] = useState(false);
  // Shared chat state — bottom strip + floating popout consume the same hook.
  const chat = useChatRoom();
  // Light/dark theme — persisted across page refreshes.
  const [theme, setTheme] = useState(() => {
    try { return localStorage.getItem("wm_theme") || "dark"; } catch { return "dark"; }
  });
  useEffect(() => {
    try { localStorage.setItem("wm_theme", theme); } catch {}
  }, [theme]);
  // View toggle: "calls" (live dial board) or "sales" (monthly car sales).
  const [view, setView] = useState("calls");
  // Live sales sim — runs in the background regardless of which view is shown.
  const sales = useSalesSim();
  // Re-sort whenever sales.reps mutates (new sales rerank).
  const salesRanked = useMemo(() => [...sales.reps].sort((a,b) => {
    if (b.units !== a.units) return b.units - a.units;
    return (b.front_gross + b.back_gross) - (a.front_gross + a.back_gross);
  }), [sales.reps]);
  // Scrubable unit override for the sales goal bar
  const [unitOverride, setUnitOverride] = useState(null);
  // Drop any scrub overrides when the period changes so the new period's
  // live numbers show up immediately (otherwise the stale override looks broken).
  useEffect(() => { setApptOverride(null); setUnitOverride(null); }, [period]);

  const eventIdRef = useRef(0);
  // Live mirror of reps so the tick closure always sees the latest state
  // instead of the snapshot captured when the effect mounted.
  const repsRef = useRef(SEED_REPS);
  useEffect(() => { repsRef.current = reps; }, [reps]);

  // clock
  useEffect(() => {
    const t = setInterval(() => setNow(new Date()), 1000);
    return () => clearInterval(t);
  }, []);

  // idle timers tick up
  useEffect(() => {
    const t = setInterval(() => {
      setReps((rs) => rs.map((r) => r.status === "IDLE" ? { ...r, last_call_at: r.last_call_at + 1 } : r));
    }, 1000);
    return () => clearInterval(t);
  }, []);

  // simulated call ticks — capped at multiple levels so the totals can
  // never spiral into junk:
  //   1. each rep is capped at REP_DIAL_LIMIT individually
  //   2. team total is capped at TEAM_DIAL_CEILING (resets to seed)
  //   3. the cap check is also re-run inside setReps in case of races
  useEffect(() => {
    let timeoutId;
    const TEAM_DIAL_CEILING = 3200;
    const REP_DIAL_LIMIT = 260;
    const tick = () => {
      const current = repsRef.current;
      // hard reset if we've overshot — read current ref, not closure
      const teamDials = current.reduce((s,r)=>s+(r.dials_made||0),0);
      if (teamDials >= TEAM_DIAL_CEILING) {
        setReps(SEED_REPS);
        setEvents([]);
        timeoutId = setTimeout(tick, 2500);
        return;
      }

      // pick a non-idle rep (weight by dials), using current state
      const active = current.filter((r) => r.status !== "IDLE" && (r.dials_made||0) < REP_DIAL_LIMIT);
      if (active.length === 0) {
        setReps(SEED_REPS);
        setEvents([]);
        timeoutId = setTimeout(tick, 2500);
        return;
      }
      const total = active.reduce((s,r)=>s+(r.dials_made||0)+5,0);
      let r = Math.random() * total;
      let chosen = active[0];
      for (const rep of active) { r -= ((rep.dials_made||0) + 5); if (r <= 0) { chosen = rep; break; } }

      const outcome = pickOutcome();

      setReps((prev) => {
        // double-check inside the functional updater in case of races
        const live = prev.reduce((s,r)=>s+(r.dials_made||0),0);
        if (live >= TEAM_DIAL_CEILING) return SEED_REPS;
        return prev.map((rep) => {
          if (rep.id !== chosen.id) return rep;
          // per-rep hard cap — silently skip the increment if at ceiling
          if ((rep.dials_made||0) >= REP_DIAL_LIMIT) return rep;
          const dispKey = outcome.key;
          const dispNow = (rep.dispositions && rep.dispositions[dispKey]) || 0;
          const next = { ...rep,
            dials_made: (rep.dials_made||0) + 1,
            last_call_at: 0,
            dispositions: { ...(rep.dispositions || {}), [dispKey]: dispNow + 1 },
          };
          if (dispKey === "connected" || dispKey === "demo_booked" || dispKey === "callback_requested") {
            next.dials_connected = (rep.dials_connected||0) + 1;
            next.talk_time_seconds = (rep.talk_time_seconds||0) + 30 + Math.floor(Math.random()*180);
          }
          if (dispKey === "demo_booked") {
            next.appointments_set = (rep.appointments_set||0) + 1;
          }
          return next;
        });
      });

      setLastDialed(chosen.id);
      setPulse(true); setTimeout(() => setPulse(false), 600);

      setEvents((evts) => {
        const id = ++eventIdRef.current;
        const newEvt = {
          id,
          rep: chosen,
          outcome,
          commentary: pickCommentary(outcome.key),
          dialNum: chosen.dials_made + 1,
          timeLabel: new Date().toLocaleTimeString([], { hour12:false }),
        };
        return [newEvt, ...evts].slice(0, 8);
      });

      // slower cadence so totals breathe and nothing balloons mid-shift
      timeoutId = setTimeout(tick, 2200 + Math.random() * 2800);
    };
    timeoutId = setTimeout(tick, 1500);
    return () => clearTimeout(timeoutId);
  }, []);

  const ranked = useMemo(() => {
    return [...reps].sort((a,b) => {
      // primary: appointments, secondary: dials_connected, tertiary: dials_made
      if (b.appointments_set !== a.appointments_set) return b.appointments_set - a.appointments_set;
      if (b.dials_connected !== a.dials_connected) return b.dials_connected - a.dials_connected;
      return b.dials_made - a.dials_made;
    });
  }, [reps]);

  const topDials = Math.max(...reps.map((r) => r.dials_made), 1);

  // ─── PERIOD SCALING ───────────────────────────────────────────
  // Sims only tick "today" values. Switching the period selector
  // multiplies the displayed numbers up (for calls) or down (for
  // sales — since SALES_REPS is already month-to-date) so the
  // selector means something in both views.
  const callMult  = period === "THIS MONTH" ? 22 : period === "THIS WEEK" ? 5 : 1;
  const salesMult = period === "THIS MONTH" ? 1 : period === "THIS WEEK" ? 0.25 : 0.08;

  const callRepsScaled = useMemo(() => ranked.map((r) => ({
    ...r,
    dials_made:        Math.round(r.dials_made        * callMult),
    dials_connected:   Math.round(r.dials_connected   * callMult),
    talk_time_seconds: Math.round(r.talk_time_seconds * callMult),
    appointments_set:  Math.round(r.appointments_set  * callMult),
  })), [ranked, callMult]);
  const callGoal      = Math.round(TEAM_DAILY_GOAL * callMult);
  const callTeamAppts = callRepsScaled.reduce((s, r) => s + r.appointments_set, 0);

  const salesRepsScaled = useMemo(() => salesRanked.map((r) => ({
    ...r,
    units:       Math.round(r.units       * salesMult),
    front_gross: Math.round(r.front_gross * salesMult),
    back_gross:  Math.round(r.back_gross  * salesMult),
    // csi stays — quality %, not a count
  })), [salesRanked, salesMult]);
  const salesGoalScaled = Math.round(SALES_GOAL_UNITS * salesMult);
  const periodLabel = period === "THIS MONTH" ? "MONTH-TO-DATE"
                     : period === "THIS WEEK" ? "WEEK-TO-DATE"
                     : "TODAY";
  const callGoalLabel = period === "THIS MONTH" ? "TEAM MONTHLY APPT GOAL"
                      : period === "THIS WEEK" ? "TEAM WEEKLY APPT GOAL"
                      : "TEAM DAILY APPT GOAL";

  return (
    <div data-theme={theme} className="flex min-h-screen flex-col gap-2 bg-[#0A0A08] p-2 text-white">
      <TopBar period={period} setPeriod={setPeriod} sound={sound} setSound={setSound} now={now}
              chatOpen={chatOpen} setChatOpen={setChatOpen} theme={theme} setTheme={setTheme}
              view={view} setView={setView} />

      {view === "calls" ? (
        <>
          <SpiffHero
            teamAppts={callTeamAppts}
            goal={callGoal}
            apptOverride={apptOverride}
            setApptOverride={setApptOverride}
            goalLabel={callGoalLabel}
          />
          <AggregateFooter reps={callRepsScaled} />
          <div className="grid grid-cols-12 gap-2">
            <div className="col-span-12 flex flex-col lg:col-span-8">
              <Leaderboard reps={callRepsScaled} topDials={Math.max(...callRepsScaled.map((r) => r.dials_made), 1)} recentlyDialedId={lastDialed} />
            </div>
            <div className="col-span-12 flex flex-col lg:col-span-4">
              <LiveFeed events={events} pulse={pulse} funMode={funMode} setFunMode={setFunMode} />
            </div>
          </div>
          <TrollBox chat={chat} />
          {chatOpen && <FloatingChat chat={chat} onClose={() => setChatOpen(false)} />}
        </>
      ) : (
        <>
          <SalesHero reps={salesRepsScaled} unitOverride={unitOverride} setUnitOverride={setUnitOverride} goal={salesGoalScaled} periodLabel={periodLabel} />
          <SalesAggregates reps={salesRepsScaled} />
          <div className="grid grid-cols-12 gap-2">
            <div className="col-span-12 flex flex-col lg:col-span-8">
              <SalesLeaderboard reps={salesRepsScaled} />
            </div>
            <div className="col-span-12 flex flex-col gap-2 lg:col-span-4">
              <SalesFeed events={sales.events} />
              <RecentDeliveries reps={salesRanked} liveEvents={sales.events} />
            </div>
          </div>
          <TrollBox chat={chat} />
          {chatOpen && <FloatingChat chat={chat} onClose={() => setChatOpen(false)} />}
        </>
      )}
    </div>
  );
}

ReactDOM.createRoot(document.getElementById("root")).render(<App />);
