// Practice screen — core answering loop.
// Handles 4 task types: word-formation, grammar, multiple-choice, irregular.
// MC items render full-width option tiles; everything else uses the typed input.
// Globals: React, VOCAB, CATEGORY_META, FAMILY_META, checkAnswer, formatDuration, makeBeeper.

const { useState: pUseState, useEffect: pUseEffect, useRef: pUseRef, useCallback: pUseCallback } = React;

// Force the practice run onto a dark focused surface (like Live); restore on exit.
function useForceDark() {
  pUseEffect(() => {
    const root = document.documentElement;
    const prev = root.dataset.theme;
    root.dataset.theme = "dark";
    return () => { root.dataset.theme = prev; };
  }, []);
}

// A faint, slow drifting motif behind the stat strip (mirrors trainer.css .t-qbg).
function PMShape({ type, col, size, dur, delay, dx, dy, dr, top, left, right, bottom }) {
  const inner = { tri: <path d="M50 7 94 90 6 90Z" />, cir: <circle cx="50" cy="50" r="43" />, sqr: <rect x="9" y="9" width="82" height="82" rx="12" />, dia: <path d="M50 4 96 50 50 96 4 50Z" /> }[type];
  return <span className="t-qshape" style={{ width: size, height: size, color: col, top, left, right, bottom, "--dx": `${dx}px`, "--dy": `${dy}px`, "--dr": `${dr}deg`, animationDuration: `${dur}s`, animationDelay: `${delay}s` }}><svg viewBox="0 0 100 100" fill="none" stroke="currentColor" strokeWidth="5" strokeLinejoin="round">{inner}</svg></span>;
}
// A fuller field of drifting shapes (was 4 — too sparse to notice). Computed once
// at load with deterministic spread so they cover the whole run, not just corners.
const PM_SHAPES = (() => {
  const COLORS = ["#19b39f", "#5aa6e6", "#e6b24c", "#a98fe0", "#46c7b4"];
  const TYPES = ["tri", "cir", "sqr", "dia"];
  const out = [];
  const N = 20;
  for (let i = 0; i < N; i++) {
    const dir = i % 2 ? 1 : -1;
    out.push({
      type: TYPES[(i * 3) % TYPES.length],
      col: COLORS[i % COLORS.length],
      size: 44 + ((i * 41) % 112),                 // 44 .. 156
      dur: 24 + ((i * 7) % 22),                     // 24 .. 46
      delay: -((i * 5) % 28),
      dx: dir * (12 + ((i * 11) % 26)),
      dy: (i % 3 ? 1 : -1) * (14 + ((i * 9) % 24)),
      dr: dir * (16 + ((i * 13) % 30)),
      top: `${((i * 53) % 116) - 10}%`,             // -10 .. 106
      left: `${((i * 71) % 118) - 10}%`,            // -10 .. 108
    });
  }
  return out;
})();
function PracticeMotif() {
  return (
    <span className="t-qbg" aria-hidden="true">
      {PM_SHAPES.map((s, i) => (
        <PMShape key={i} type={s.type} col={s.col} size={s.size} dur={s.dur} delay={s.delay} dx={s.dx} dy={s.dy} dr={s.dr} top={s.top} left={s.left} />
      ))}
    </span>
  );
}

function PracticeScreen({
  queue,
  endless,
  soundOn,
  autoAdvance,
  reduceMotion,
  onFinish,
  onExit,
  recordAnswer,
  sourceLabel = null,
}) {
  const [idx, setIdx] = pUseState(0);
  const [input, setInput] = pUseState("");
  const [picked, setPicked] = pUseState(null);
  const [feedback, setFeedback] = pUseState(null);
  const [score, setScore] = pUseState(0);
  const [streak, setStreak] = pUseState(0);
  const [bestStreak, setBestStreak] = pUseState(0);
  const [correctCount, setCorrectCount] = pUseState(0);   // correct WORDS (gaps), not items
  const [answeredGaps, setAnsweredGaps] = pUseState(0);   // words answered (passage = its gap count)
  const [wrong, setWrong] = pUseState([]);
  const [answers, setAnswers] = pUseState([]);   // every answer this session: {id, ua, c}
  const [questionStart, setQuestionStart] = pUseState(() => Date.now());
  const [elapsed, setElapsed] = pUseState(0);
  const [sessionStart] = pUseState(() => Date.now());
  const inputRef = pUseRef(null);
  const beeper = pUseRef(null);

  if (!beeper.current) beeper.current = makeBeeper();
  useForceDark();

  const total = queue.length;
  // Grade is by WORDS (gaps): a passage is its number of gaps, a single question
  // is 1. So a 7/9 passage scores 7 of 9, not 0 of 1.
  const gapTotal = queue.reduce((n, it) => n + ((it.gaps && it.gaps.length) || 1), 0);
  const item = queue[idx % total];
  const isMC = item.type === "multiple-choice";
  const isPassage = !!(item.gaps && item.gaps.length);   // OGE whole-text task

  pUseEffect(() => {
    const t = setInterval(() => setElapsed(Date.now() - questionStart), 250);
    return () => clearInterval(t);
  }, [questionStart]);

  pUseEffect(() => {
    if (!isMC && !feedback) {
      const t = setTimeout(() => inputRef.current?.focus(), 30);
      return () => clearTimeout(t);
    }
  }, [idx, feedback, isMC]);

  const submit = pUseCallback((rawAnswer) => {
    if (feedback) return;
    const res = checkAnswer(rawAnswer, item);
    const timeBonus = Math.max(0, 30 - Math.floor((Date.now() - questionStart) / 1000));
    const base = res.ok ? (res.exact ? 10 : 7) : 0;
    const streakBonus = res.ok ? Math.min(streak, 5) : 0;
    const gained = base + (res.ok ? Math.floor(timeBonus / 6) : 0) + streakBonus;

    setFeedback({ ok: res.ok, exact: res.exact, gained, shown: item.answer, userShown: rawAnswer });
    setScore(s => s + gained);
    if (res.ok) {
      setCorrectCount(c => c + 1);
      setStreak(s => {
        const ns = s + 1;
        setBestStreak(b => Math.max(b, ns));
        return ns;
      });
      if (soundOn) beeper.current.correct();
      if (window.haptic) window.haptic((streak + 1) % 5 === 0 ? "celebrate" : "success");
    } else {
      setStreak(0);
      setWrong(w => [...w, { item, userAnswer: rawAnswer || "(skipped)" }]);
      if (soundOn) beeper.current.wrong();
      if (window.haptic) window.haptic("error");
    }
    setAnswers(a => [...a, { id: item.id, ua: rawAnswer || "", c: res.ok ? 1 : 0 }]);
    setAnsweredGaps(g => g + 1);
    recordAnswer(item, res.ok);
  }, [feedback, item, streak, questionStart, soundOn, recordAnswer]);

  // A passage (OGE) is one queue item with many gaps; score by gaps, record the
  // passage as correct only if every gap is right.
  const handlePassageCheck = pUseCallback((result) => {
    setScore(s => s + result.correctGaps * 10);
    const allOk = result.correctGaps === result.total;
    // Grade by words: this passage adds its correct gaps to the running total,
    // out of its gap count — a 7/9 passage is 7 right of 9, not 0 of 1.
    setCorrectCount(c => c + result.correctGaps);
    setAnsweredGaps(g => g + result.total);
    if (!allOk) setWrong(w => [...w, { item, userAnswer: `${result.correctGaps}/${result.total} gaps correct` }]);
    setAnswers(a => [...a, { id: item.id, ua: `${result.correctGaps}/${result.total}`, c: allOk ? 1 : 0 }]);
    recordAnswer(item, allOk, { correct: result.correctGaps, total: result.total });
    if (window.haptic) window.haptic(allOk ? "celebrate" : "success");
  }, [item, recordAnswer]);

  const advance = pUseCallback(() => {
    const isLast = !endless && idx + 1 >= total;
    if (isLast) {
      onFinish({
        score, total: gapTotal, correct: correctCount,
        bestStreak,
        durationMs: Date.now() - sessionStart,
        wrong,
        questions: answers,
        startedAt: sessionStart,
      });
      return;
    }
    setIdx(i => i + 1);
    setInput("");
    setPicked(null);
    setFeedback(null);
    setQuestionStart(Date.now());
    setElapsed(0);
  }, [endless, idx, total, score, correctCount, bestStreak, sessionStart, wrong, answers, onFinish]);

  // Endless has no natural end, so "Finish" wraps it up into the Results screen
  // (a real summary), counting the questions actually answered. Nothing answered
  // yet → just leave.
  const finishEndless = pUseCallback(() => {
    if (answeredGaps === 0) { onExit(); return; }
    if (window.haptic) window.haptic("celebrate");
    onFinish({ score, total: answeredGaps, correct: correctCount, bestStreak, durationMs: Date.now() - sessionStart, wrong, questions: answers, startedAt: sessionStart });
  }, [answeredGaps, score, correctCount, bestStreak, sessionStart, wrong, answers, onFinish, onExit]);

  // Auto-advance after correct (opt-in via setting)
  pUseEffect(() => {
    if (!feedback || !feedback.ok || !autoAdvance) return;
    const t = setTimeout(advance, 380);
    return () => clearTimeout(t);
  }, [feedback, autoAdvance, advance]);

  // Keyboard: Esc to exit, Enter to advance after feedback, 1–4 for MC
  pUseEffect(() => {
    const onKey = (e) => {
      if (e.key === "Escape") { onExit(); return; }
      if (feedback && (e.key === "Enter" || e.key === " ")) {
        e.preventDefault(); advance(); return;
      }
      if (!feedback && isMC && /^[1-4]$/.test(e.key)) {
        const i = Number(e.key) - 1;
        if (item.choices?.[i]) {
          setPicked(item.choices[i]);
          submit(item.choices[i]);
        }
      }
    };
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, [feedback, advance, onExit, isMC, item, submit]);

  const answeredSoFar = idx + (feedback ? 1 : 0);     // items answered — for the "n / N" passage progress
  const accuracy = answeredGaps === 0 ? 0 : (correctCount / Math.max(1, answeredGaps)) * 100;   // by words
  const progressPct = (answeredSoFar / total) * 100;

  return (
    <div className="t-run" data-rm={reduceMotion ? "1" : "0"}>
      <PracticeMotif />
      <div className="t-run-body">
        <div className="t-run-shell t-prac-shell" data-passage={isPassage ? "1" : undefined}>
          <div className="t-prac-top">
            <button className="t-prac-end" onClick={endless ? finishEndless : onExit} aria-label={endless ? "Finish session" : "Exit session"}>
              ← {endless && answeredSoFar > 0 ? "Finish" : "End"}
            </button>
            <span className="t-prac-track"><span style={{ width: `${endless ? accuracy : progressPct}%` }} /></span>
            <span className="t-prac-count">{endless ? `${answeredSoFar} · ${Math.round(accuracy)}%` : `${idx + 1} / ${total}`}</span>
          </div>

          <main className="qcard" data-feedback={feedback ? (feedback.ok ? "ok" : "no") : ""} data-task={item.type}>
            {isPassage ? (
            <PassageView key={item.id} item={item} onCheck={handlePassageCheck} onContinue={advance} isLast={!endless && idx + 1 >= total} />
            ) : (
            <>
            <div className="qcard-eyebrow">
              <span className="task-tag" data-task={item.type}>{FAMILY_META[item.type]?.label}</span>
              {sourceLabel && <><span className="dot-sep">·</span><span className="eyebrow-source">{sourceLabel}</span></>}
              {item.base && <span className="base-chip" style={{ marginLeft: "auto" }}>{item.base}</span>}
            </div>

            <h1 className="qprompt">{renderSentence(item.sentence, feedback, isMC)}</h1>

            {isMC ? (
              <MCOptions
                item={item}
                picked={picked}
                feedback={feedback}
                onPick={(c) => { if (!feedback) { setPicked(c); submit(c); } }}
              />
            ) : (
              <form
                className="answer-form"
                onSubmit={(e) => {
                  e.preventDefault();
                  if (feedback) { advance(); return; }
                  submit(input);
                }}
              >
                <input
                  ref={inputRef}
                  className="answer-input"
                  value={input}
                  onChange={e => setInput(e.target.value)}
                  placeholder={placeholderFor(item.type)}
                  disabled={!!feedback}
                  type="text"
                  autoComplete="off"
                  autoCorrect="off"
                  autoCapitalize="off"
                  spellCheck={false}
                  aria-label="Your answer"
                  onFocus={() => {
                    const bring = () => { const el = document.querySelector(".qprompt"); if (el && el.scrollIntoView) el.scrollIntoView({ block: "start", behavior: "auto" }); };
                    setTimeout(bring, 100); setTimeout(bring, 350); setTimeout(bring, 650);
                  }}
                />
              </form>
            )}

            <FeedbackBar feedback={feedback} />
            </>
            )}
          </main>

          {!isPassage && (
            <div className="t-prac-foot">
              <div className="t-foot-content">
                <div className="t-statstrip">
                  <div className="t-statcell is-accent"><span className="t-stat-v">{score}</span><span className="t-stat-l">Score</span></div>
                  <div className="t-statcell"><span className="t-stat-v">{streak}</span><span className="t-stat-l">Streak</span></div>
                  <div className="t-statcell"><span className="t-stat-v">{Math.round(accuracy)}%</span><span className="t-stat-l">Accuracy</span></div>
                  <div className="t-statcell"><span className="t-stat-v">{formatDuration(elapsed)}</span><span className="t-stat-l">Time</span></div>
                </div>
                <ReportControl key={item.id} item={item}
                  userAnswer={isMC ? (picked != null && item.choices ? item.choices[picked] : "") : input} />
              </div>
            </div>
          )}
        </div>
      </div>

      {!isPassage && (
      <div className="t-run-actions" data-feedback={feedback ? "1" : "0"}>
        {!feedback ? (
          <>
            <button className="link-btn" onClick={() => submit(isMC ? null : "")}>I don't know</button>
            {!isMC && (
              <button className="primary-btn" onClick={() => submit(input)} disabled={!input.trim()}>
                Check<span className="kbd-hint">↵</span>
              </button>
            )}
          </>
        ) : (
          <>
            <span className="action-summary">
              {feedback.ok ? "Nice" : "Keep going"}
            </span>
            <button className="primary-btn" onClick={(e) => { if (window.tapFeedback) window.tapFeedback("medium", e); advance(); }}>
              {(!endless && idx + 1 >= total) ? "See results" : "Next"}
              <span className="kbd-hint">↵</span>
            </button>
          </>
        )}
      </div>
      )}
    </div>
  );
}

// ---------- Multiple-Choice options ----------
function MCOptions({ item, picked, feedback, onPick }) {
  return (
    <div className="mc-options" role="radiogroup" aria-label="Answer choices">
      {item.choices.map((c, i) => {
        const isPicked = picked === c;
        const isAnswer = feedback && checkAnswer(c, item).ok;
        const isUserWrong = feedback && isPicked && !feedback.ok;
        let cls = "mc-option";
        if (feedback) {
          if (isAnswer) cls += " is-correct";
          else if (isUserWrong) cls += " is-wrong";
          else cls += " is-faded";
        } else if (isPicked) {
          cls += " is-picked";
        }
        return (
          <button
            key={c}
            className={cls}
            onClick={() => onPick(c)}
            disabled={!!feedback}
            role="radio"
            aria-checked={isPicked}
          >
            <span className="mc-index" aria-hidden="true">{i + 1}</span>
            <span className="mc-text">{c}</span>
            {feedback && isAnswer && <span className="mc-mark" aria-hidden="true">✓</span>}
            {feedback && isUserWrong && <span className="mc-mark" aria-hidden="true">×</span>}
          </button>
        );
      })}
    </div>
  );
}

// ---------- Feedback bar (in-card; the action bar handles primary CTA on mobile) ----------
function FeedbackBar({ feedback }) {
  return (
    <div className={`feedback-bar ${feedback ? "is-shown" : ""} ${feedback?.ok ? "is-ok" : "is-no"}`}>
      {feedback && (
        <>
          <div className="feedback-text">
            <div className="feedback-line">
              {feedback.ok
                ? (feedback.exact
                    ? <b>Correct.</b>
                    : <span><b>Almost — </b>watch the spelling.</span>)
                : <b>Not quite.</b>}
            </div>
            <div className="feedback-answer">{feedback.shown}</div>
          </div>
          {feedback.ok && <div className="feedback-gain" aria-label={`gained ${feedback.gained} points`}>+{feedback.gained}</div>}
        </>
      )}
    </div>
  );
}

function StatChip({ label, value, sub, mono, accent }) {
  return (
    <div className={`stat-chip ${accent ? "is-accent" : ""}`}>
      <div className="stat-chip-label">{label}</div>
      <div className={`stat-chip-value ${mono ? "is-mono" : ""}`}>{value}</div>
      {sub && <div className="stat-chip-sub">{sub}</div>}
    </div>
  );
}

function placeholderFor(type) {
  if (type === "grammar") return "Type the correct form…";
  if (type === "irregular") return "Type the irregular form…";
  return "Type the transformed word…";
}

function shortCategoryLabel(label) {
  if (!label) return "";
  // Strip leading "Test N — " for compact rail display
  return label.replace(/^Test \d+ — /, "");
}

// Render the prompt sentence with a styled blank where ___ sits.
// After the user answers, the blank is replaced by:
//   - MC: the user's pick in serif italic (their selection)
//   - typed: the canonical answer
function renderSentence(sentence, feedback, isMC) {
  const parts = sentence.split(/_{2,}/);
  let blank;
  if (feedback) {
    const shown = isMC ? (feedback.userShown ?? feedback.shown) : feedback.shown;
    const cls = "blank is-filled" + (feedback.ok ? "" : " is-wrong-fill");
    blank = <span className={cls}>{shown}</span>;
  } else {
    blank = <span className="blank" aria-label="blank">&nbsp;</span>;
  }
  return (
    <>
      {parts.map((p, i) => (
        <React.Fragment key={i}>
          <span>{p}</span>
          {i < parts.length - 1 && blank}
        </React.Fragment>
      ))}
    </>
  );
}

// ---------- OGE passage: fill every gap in the whole text, then check all ----------
function PassageView({ item, onCheck, onContinue, isLast }) {
  const gaps = item.gaps || [];
  const [inputs, setInputs] = pUseState(() => gaps.map(() => ""));
  const [result, setResult] = pUseState(null);
  const gapRefs = pUseRef([]);
  // Enter in a gap jumps to the next gap; Enter in the last gap checks the passage.
  const onGapEnter = (i) => {
    if (result) return;
    if (i + 1 < gaps.length) gapRefs.current[i + 1] && gapRefs.current[i + 1].focus();
    else if (inputs.some(x => x.trim())) check();
  };

  const segs = [];
  const parts = String(item.text).split(/⟦(\d+)⟧/);
  for (let i = 0; i < parts.length; i++) segs.push(i % 2 === 0 ? { text: parts[i] } : { gap: parseInt(parts[i], 10) - 1 });

  const setInput = (i, v) => setInputs(arr => arr.map((x, k) => (k === i ? v : x)));
  const check = () => {
    if (result) return;
    const r = gaps.map((g, i) => ({ ok: checkAnswer(inputs[i], { answer: g.answer, alts: g.alts }).ok, ua: inputs[i], answer: g.answer }));
    setResult(r);
    onCheck({ correctGaps: r.filter(x => x.ok).length, total: gaps.length, perGap: r });
  };
  const correctN = result ? result.filter(x => x.ok).length : 0;

  const filledN = inputs.filter(x => x.trim()).length;
  const toReview = result ? gaps.length - correctN : 0;
  const isWF = item.type === "word-formation" || item.category === "oge_wf";

  return (
    <div className="passage">
      <div className="passage-head">
        <span className="task-tag passage-tag" data-task={isWF ? "word-formation" : "grammar"}>{isWF ? "ОГЭ · Word Formation" : "ОГЭ · Grammar"}</span>
        <span className="passage-sub">Open cloze · {gaps.length} gap{gaps.length === 1 ? "" : "s"}</span>
      </div>
      <p className="passage-instr">Read the text below and fill in each gap. Use the word in <b>CAPITALS</b> at the top of the gap to form a word that fits — full forms only, never contractions.</p>
      <div className="passage-text">
        {segs.map((s, i) => (s.text != null
          ? <span key={i}>{s.text}</span>
          : <PassageGap key={i} n={s.gap + 1} cue={gaps[s.gap].base} value={inputs[s.gap]} onChange={v => setInput(s.gap, v)} res={result ? result[s.gap] : null} locked={!!result} inputRef={el => { gapRefs.current[s.gap] = el; }} onEnter={() => onGapEnter(s.gap)} />))}
      </div>
      <div className="passage-actions">
        {!result ? (
          <>
            <span className="passage-counter">{filledN} of {gaps.length} filled</span>
            <span className="passage-action-btns">
              <button className="link-btn passage-idk" onClick={check}>I don't know</button>
              <button className="primary-btn" onClick={check} disabled={filledN === 0}>Check answers<span className="passage-tick" aria-hidden="true">✓</span></button>
            </span>
          </>
        ) : (
          <>
            <span className={`passage-counter ${correctN === gaps.length ? "is-perfect" : ""}`}>{correctN} / {gaps.length} correct{toReview > 0 ? ` · ${toReview} to review` : ""}</span>
            <button className="primary-btn" onClick={onContinue}>{isLast ? "See results" : "Next passage"}<span className="kbd-hint">→</span></button>
          </>
        )}
      </div>
      <ReportControl key={item.id} item={item} />
    </div>
  );
}
function PassageGap({ n, cue, value, onChange, res, locked, inputRef, onEnter }) {
  const filled = (value || "").trim().length > 0;
  const cls = "passage-gap" + (res ? (res.ok ? " is-ok" : " is-no") : (filled ? " is-filled" : ""));
  return (
    <span className={cls}>
      <span className="passage-cue">
        <span className="passage-num">{n}</span>
        <span className="passage-cueword">{cue}</span>
        {res ? <span className={`passage-mark ${res.ok ? "is-ok" : "is-no"}`} aria-hidden="true">{res.ok ? "✓" : "✕"}</span> : null}
      </span>
      <input className="passage-input" value={value} onChange={e => onChange(e.target.value)} disabled={locked}
        ref={inputRef} onKeyDown={e => { if (e.key === "Enter") { e.preventDefault(); onEnter && onEnter(); } }}
        type="text" autoComplete="off" autoCorrect="off" autoCapitalize="off" spellCheck={false}
        size={Math.max(7, (value || "").length + 1)} aria-label={"Gap " + cue} />
      {res && !res.ok ? <span className="passage-correct">→ {res.answer}</span> : null}
    </span>
  );
}

// Inline "report a problem" control under each question. Posts to /api/report
// (works for guests too). Collapses by default; remounts per item via key.
function ReportControl({ item, userAnswer }) {
  const [open, setOpen] = pUseState(false);
  const [sent, setSent] = pUseState(false);
  const [reason, setReason] = pUseState("");
  const [note, setNote] = pUseState("");
  const [busy, setBusy] = pUseState(false);

  const send = async () => {
    if (!reason || busy) return;
    setBusy(true);
    let token = null; try { token = localStorage.getItem(window.TOKEN_KEY || "vp.token.v1"); } catch (e) {}
    const examMode = (window.CATEGORY_META && window.CATEGORY_META[item.category] && window.CATEGORY_META[item.category].exam) || "ege";
    try {
      await fetch("/api/report", {
        method: "POST",
        headers: { "content-type": "application/json", ...(token ? { Authorization: `Bearer ${token}` } : {}) },
        body: JSON.stringify({
          itemId: item.id, category: item.category, examMode,
          sentence: item.sentence || item.text || "", base: item.base || "",
          answer: item.answer || (Array.isArray(item.gaps) ? item.gaps.map(g => g.answer).join(" / ") : ""),
          userAnswer: userAnswer || "", reason, note,
        }),
      });
    } catch (e) { /* swallow — best-effort */ }
    setBusy(false); setSent(true);
  };

  if (sent) return <div className="report-control"><div className="report-thanks">✓ Thanks — we'll review it.</div></div>;
  return (
    <div className="report-control">
      {!open ? (
        <button type="button" className="report-link" onClick={() => setOpen(true)}>⚑ Report a problem</button>
      ) : (
        <div className="report-panel">
          <div className="report-title">What's wrong with this question?</div>
          <div className="report-reasons">
            {[["wrong_answer", "Answer looks wrong"], ["unclear", "Unclear / ambiguous"], ["typo", "Typo"], ["other", "Other"]].map(([v, l]) => (
              <button type="button" key={v} className={`report-chip ${reason === v ? "is-on" : ""}`} onClick={() => setReason(v)}>{l}</button>
            ))}
          </div>
          <input className="report-note" value={note} onChange={e => setNote(e.target.value)} placeholder="Add a detail (optional)" maxLength={300} />
          <div className="report-actions">
            <button type="button" className="report-cancel" onClick={() => setOpen(false)}>Cancel</button>
            <button type="button" className="report-send" onClick={send} disabled={!reason || busy}>{busy ? "…" : "Send report"}</button>
          </div>
        </div>
      )}
    </div>
  );
}

Object.assign(window, { PracticeScreen });
