/* ============================================================
   EDUCARE — Tarefas de Fluência Verbal (TFV)
   Linguagem + Funções Executivas. 3 tarefas, blocos de 30s, percentil por âncora.
   ============================================================ */
(function () {
  const { useState, useEffect, useRef } = React;
  const Icon = window.Icon;

  const TFV_KEY = "educare-tfv-config";
  const NORMS_KEY = "educare-tfv-norms";
  const NORM_PCT = [95, 75, 50, 25, 5];
  const NORM_AGES = [6, 7, 8, 9, 10, 11, 12];

  const DEFAULT_TASKS = [
    { key: "FVL", name: "Fluência Verbal Livre", short: "fluência verbal livre", blocks: 5, totalSec: 150,
      instruction: "Você deve dizer o maior número possível de palavras em dois minutos e meio, sempre com os olhos fechados, sem dizer nomes próprios, de pessoas, cidades, países, nem números. Entendeu bem? Podemos começar?" },
    { key: "FVF", name: "Fluência Verbal Fonêmica — letra P", short: "fluência verbal fonêmica", blocks: 4, totalSec: 120,
      instruction: "Você deve dizer o maior número possível de palavras que começam com a letra P, em dois minutos. Não pode dizer nomes próprios (de pessoas, cidades, países)." },
    { key: "FVS", name: "Fluência Verbal Semântica — roupas/vestimentas", short: "fluência verbal semântica", blocks: 4, totalSec: 120,
      instruction: "Você deve dizer o maior número de palavras que sejam roupas / vestimentas em dois minutos." },
  ];

  // Normas embutidas (fornecidas/conferidas pelo profissional). Cada bloco/total = [P95, P75, P50, P25, P5]
  const RAW_NORMS = {
    "6_privada": { fvl: { b1: [13, 10, 8, 6, 1], b2: [10, 6, 5, 2, 1], b3: [10, 6, 4, 3, 1], b4: [14, 7, 4, 2, 0], b5: [13, 6, 3, 2, 0], total: [46, 31, 23, 18, 7] }, fvf: { b1: [7, 5, 4, 3, 1], b2: [5, 3, 2, 1, 0], b3: [4, 2, 1, 1, 0], b4: [5, 2, 1, 0, 0], total: [18, 10, 8, 6, 4] }, fvs: { b1: [11, 8, 6, 5, 3], b2: [5, 3, 2, 2, 0], b3: [4, 2, 1, 0, 0], b4: [5, 2, 1, 0, 0], total: [18, 13, 11, 10, 7] } },
    "6_publica": { fvl: { b1: [13, 10, 7, 3, 1], b2: [12, 8, 5, 2, 0], b3: [13, 7, 4, 2, 0], b4: [11, 6, 4, 2, 0], b5: [7, 6, 4, 1, 0], total: [43, 35, 23, 14, 9] }, fvf: { b1: [7, 4, 4, 3, 1], b2: [4, 3, 1, 0, 0], b3: [5, 2, 1, 0, 0], b4: [4, 1, 1, 0, 0], total: [17, 10, 7, 5, 3] }, fvs: { b1: [10, 8, 7, 5, 2], b2: [4, 3, 2, 1, 0], b3: [3, 3, 1, 0, 0], b4: [4, 1, 0, 0, 0], total: [16, 13, 10, 9, 7] } },
    "7_privada": { fvl: { b1: [21, 11, 10, 6, 1], b2: [14, 10, 7, 4, 3], b3: [14, 11, 7, 4, 1], b4: [14, 9, 6, 4, 0], b5: [12, 10, 6, 4, 1], total: [66, 44, 37, 30, 11] }, fvf: { b1: [8, 7, 6, 4, 3], b2: [5, 4, 2, 1, 0], b3: [6, 3, 2, 1, 0], b4: [6, 3, 1, 1, 0], total: [17, 15, 12, 8, 7] }, fvs: { b1: [12, 10, 8, 7, 4], b2: [7, 3, 2, 2, 1], b3: [4, 2, 2, 1, 0], b4: [4, 2, 1, 0, 0], total: [22, 16, 13, 11, 8] } },
    "7_publica": { fvl: { b1: [16, 11, 7, 6, 2], b2: [10, 7, 6, 4, 2], b3: [10, 6, 4, 3, 0], b4: [15, 7, 5, 3, 1], b5: [13, 7, 5, 2, 0], total: [55, 37, 26, 18, 7] }, fvf: { b1: [10, 6, 4, 3, 2], b2: [6, 3, 2, 1, 0], b3: [6, 2, 1, 0, 0], b4: [4, 2, 1, 0, 0], total: [22, 11, 8, 5, 4] }, fvs: { b1: [12, 8, 6, 4, 4], b2: [6, 3, 1, 0, 0], b3: [4, 2, 1, 0, 0], b4: [5, 2, 0, 0, 0], total: [21, 11, 10, 8, 5] } },
    "8_privada": { fvl: { b1: [15, 12, 10, 7, 4], b2: [13, 9, 8, 5, 1], b3: [15, 10, 8, 4, 1], b4: [15, 9, 6, 3, 1], b5: [12, 9, 6, 3, 0], total: [62, 45, 41, 27, 15] }, fvf: { b1: [9, 7, 5, 4, 2], b2: [5, 4, 2, 1, 0], b3: [6, 2, 1, 1, 0], b4: [4, 3, 1, 1, 0], total: [18, 15, 13, 8, 5] }, fvs: { b1: [14, 11, 9, 7, 5], b2: [6, 4, 2, 1, 0], b3: [5, 3, 1, 1, 0], b4: [4, 2, 1, 0, 0], total: [21, 17, 15, 12, 9] } },
    "8_publica": { fvl: { b1: [17, 12, 8, 5, 3], b2: [16, 9, 7, 3, 2], b3: [11, 8, 5, 3, 2], b4: [12, 7, 5, 3, 0], b5: [9, 7, 5, 3, 0], total: [53, 39, 32, 19, 13] }, fvf: { b1: [10, 6, 5, 4, 1], b2: [5, 3, 3, 1, 0], b3: [5, 3, 2, 1, 0], b4: [5, 3, 2, 1, 0], total: [19, 14, 12, 9, 5] }, fvs: { b1: [12, 8, 8, 6, 4], b2: [6, 4, 2, 1, 0], b3: [5, 3, 1, 0, 0], b4: [6, 2, 1, 0, 0], total: [21, 15, 13, 11, 7] } },
    "9_privada": { fvl: { b1: [23, 17, 12, 8, 2], b2: [16, 12, 9, 6, 2], b3: [14, 12, 8, 5, 2], b4: [15, 10, 7, 4, 1], b5: [13, 9, 6, 4, 2], total: [75, 57, 42, 28, 17] }, fvf: { b1: [11, 8, 6, 4, 2], b2: [7, 4, 3, 2, 1], b3: [6, 4, 2, 2, 1], b4: [6, 3, 2, 1, 0], total: [26, 17, 13, 10, 8] }, fvs: { b1: [15, 11, 9, 7, 5], b2: [7, 4, 3, 2, 1], b3: [5, 4, 2, 1, 0], b4: [5, 3, 1, 0, 0], total: [25, 20, 16, 10, 8] } },
    "9_publica": { fvl: { b1: [18, 14, 11, 8, 3], b2: [15, 12, 9, 6, 1], b3: [14, 10, 8, 5, 1], b4: [17, 10, 7, 3, 1], b5: [14, 9, 6, 4, 1], total: [63, 50, 41, 31, 18] }, fvf: { b1: [12, 8, 6, 4, 2], b2: [5, 4, 3, 2, 1], b3: [6, 3, 2, 1, 0], b4: [5, 3, 2, 1, 0], total: [24, 18, 13, 10, 6] }, fvs: { b1: [14, 9, 8, 5, 1], b2: [6, 3, 2, 1, 0], b3: [4, 3, 2, 1, 0], b4: [4, 3, 1, 0, 0], total: [23, 16, 14, 11, 4] } },
    "10_privada": { fvl: { b1: [23, 18, 15, 11, 4], b2: [19, 13, 10, 7, 1], b3: [15, 13, 10, 6, 2], b4: [14, 11, 9, 5, 2], b5: [16, 11, 6, 5, 2], total: [79, 65, 50, 41, 15] }, fvf: { b1: [12, 8, 7, 6, 3], b2: [7, 4, 4, 3, 1], b3: [6, 5, 3, 2, 1], b4: [5, 4, 3, 2, 1], total: [26, 20, 16, 12, 8] }, fvs: { b1: [15, 12, 9, 7, 5], b2: [8, 4, 4, 3, 1], b3: [7, 3, 1, 1, 0], b4: [5, 3, 2, 1, 0], total: [25, 21, 18, 13, 11] } },
    "10_publica": { fvl: { b1: [23, 16, 12, 10, 5], b2: [15, 12, 10, 7, 3], b3: [14, 11, 9, 5, 2], b4: [13, 9, 7, 6, 4], b5: [12, 10, 8, 5, 2], total: [68, 55, 45, 40, 23] }, fvf: { b1: [11, 7, 6, 4, 4], b2: [6, 4, 3, 2, 1], b3: [6, 3, 2, 1, 0], b4: [6, 3, 2, 1, 0], total: [23, 17, 14, 10, 8] }, fvs: { b1: [13, 12, 10, 8, 4], b2: [7, 5, 3, 2, 0], b3: [6, 3, 1, 1, 0], b4: [4, 3, 1, 0, 0], total: [24, 19, 16, 14, 8] } },
    "11_privada": { fvl: { b1: [29, 22, 16, 12, 6], b2: [25, 15, 11, 8, 3], b3: [20, 12, 9, 7, 4], b4: [18, 13, 10, 7, 4], b5: [17, 13, 9, 7, 4], total: [103, 68, 55, 47, 31] }, fvf: { b1: [12, 10, 8, 6, 3], b2: [7, 6, 4, 3, 1], b3: [7, 4, 3, 2, 1], b4: [7, 4, 3, 2, 0], total: [29, 22, 17, 14, 8] }, fvs: { b1: [16, 13, 10, 8, 4], b2: [11, 4, 3, 2, 0], b3: [8, 4, 3, 2, 0], b4: [5, 4, 2, 0, 0], total: [33, 24, 18, 15, 12] } },
    "11_publica": { fvl: { b1: [27, 18, 15, 11, 4], b2: [19, 13, 10, 7, 2], b3: [14, 11, 9, 6, 3], b4: [16, 10, 7, 5, 1], b5: [18, 13, 8, 6, 2], total: [86, 60, 51, 39, 14] }, fvf: { b1: [11, 9, 6, 5, 3], b2: [6, 5, 3, 2, 1], b3: [6, 5, 3, 1, 1], b4: [6, 3, 2, 2, 0], total: [28, 20, 15, 13, 6] }, fvs: { b1: [17, 11, 9, 8, 5], b2: [7, 4, 3, 2, 1], b3: [6, 3, 2, 1, 0], b4: [5, 2, 1, 0, 0], total: [28, 20, 16, 11, 8] } },
    "12_privada": { fvl: { b1: [25, 21, 17, 14, 6], b2: [24, 15, 12, 8, 2], b3: [22, 13, 9, 7, 4], b4: [21, 14, 11, 6, 2], b5: [17, 10, 8, 4, 0], total: [97, 67, 57, 43, 19] }, fvf: { b1: [11, 10, 8, 6, 3], b2: [8, 4, 3, 2, 1], b3: [8, 3, 3, 2, 0], b4: [7, 5, 2, 1, 1], total: [28, 20, 15, 12, 8] }, fvs: { b1: [17, 12, 10, 9, 6], b2: [10, 7, 5, 3, 1], b3: [8, 5, 3, 2, 1], b4: [6, 4, 3, 1, 0], total: [36, 26, 22, 17, 12] } },
    "12_publica": { fvl: { b1: [25, 18, 15, 14, 8], b2: [18, 13, 11, 9, 3], b3: [17, 12, 9, 7, 3], b4: [18, 10, 8, 6, 1], b5: [17, 12, 8, 4, 2], total: [85, 62, 51, 44, 25] }, fvf: { b1: [10, 9, 7, 5, 3], b2: [8, 4, 3, 3, 2], b3: [6, 4, 3, 2, 1], b4: [6, 4, 3, 2, 0], total: [24, 20, 17, 13, 9] }, fvs: { b1: [15, 13, 11, 9, 5], b2: [8, 5, 4, 3, 0], b3: [7, 4, 4, 1, 0], b4: [6, 3, 2, 0, 0], total: [29, 23, 20, 18, 10] } },
  };
  function blocksOf(t, n) { const b = []; for (let i = 1; i <= n; i++) b.push(t["b" + i]); return { blocks: b, total: t.total }; }
  const DEFAULT_NORMS = (function () {
    const out = {};
    for (const k in RAW_NORMS) { const r = RAW_NORMS[k]; out[k] = { FVL: blocksOf(r.fvl, 5), FVF: blocksOf(r.fvf, 4), FVS: blocksOf(r.fvs, 4) }; }
    return out;
  })();

  function loadConfig() {
    try { const s = JSON.parse(localStorage.getItem(TFV_KEY) || "null"); if (s && Array.isArray(s.tasks) && s.tasks.length === 3) return s; } catch (e) { /* ignora */ }
    return { tasks: JSON.parse(JSON.stringify(DEFAULT_TASKS)) };
  }
  function saveConfig(cfg) { try { localStorage.setItem(TFV_KEY, JSON.stringify(cfg)); } catch (e) { /* indisponível */ } }
  function loadNorms() {
    let saved = {};
    try { const o = JSON.parse(localStorage.getItem(NORMS_KEY) || "null"); if (o && typeof o === "object" && !Array.isArray(o)) saved = o; } catch (e) { /* ignora */ }
    return Object.assign(JSON.parse(JSON.stringify(DEFAULT_NORMS)), saved); // edições salvas sobrescrevem os padrões por faixa
  }
  function saveNorms(o) { try { localStorage.setItem(NORMS_KEY, JSON.stringify(o)); } catch (e) { /* indisponível */ } }

  function lookupAnchor(anchors, value) {
    if (!Array.isArray(anchors) || anchors.length !== 5) return null;
    const v = Number(value); let bd = Infinity, bp = null, ba = null;
    for (let i = 0; i < 5; i++) { const d = Math.abs(v - Number(anchors[i])); if (d < bd || (d === bd && NORM_PCT[i] < bp)) { bd = d; bp = NORM_PCT[i]; ba = Number(anchors[i]); } }
    return { percentile: bp, anchor: ba };
  }
  function classify(p) {
    if (p == null || isNaN(p)) return null;
    if (p > 98) return "Excepcionalmente Alta";
    if (p >= 91) return "Acima da Média";
    if (p >= 75) return "Média Superior";
    if (p >= 25) return "Média";
    if (p >= 9) return "Média Inferior";
    if (p >= 2) return "Abaixo da Média";
    return "Excepcionalmente Baixa";
  }
  function anchorRow(norms, ageKey, taskKey, idx) {
    const t = norms[ageKey] && norms[ageKey][taskKey];
    if (!t) return null;
    if (idx === "total") return Array.isArray(t.total) && t.total.length === 5 ? t.total : null;
    return t.blocks && t.blocks[idx] && t.blocks[idx].length === 5 ? t.blocks[idx] : null;
  }
  const blkLabel = (i) => `Bloco ${i + 1} (${i * 30}–${(i + 1) * 30}s)`;
  const fmtTime = (s) => { s = Math.floor(s); return Math.floor(s / 60) + ":" + String(s % 60).padStart(2, "0"); };
  function esc(s) { return String(s == null ? "" : s).replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;"); }

  /* ---------------- Pontuação assistida (IA com fallback em regras locais) ----------------
     As regras completas de pontuação vivem no servidor, em
     supabase/functions/ia/tasks.ts (tarefa "tfv-pontuar"). */
  const tokenize = (t) => String(t || "").trim().split(/\s+/).filter(Boolean);
  const normWord = (w) => w.toLowerCase().replace(/[.,;:!?"]/g, "").trim();

  // Pré-pontuação local (regras determinísticas seguras). Perseveração considera a tarefa inteira.
  function localScoreTask(taskKey, textsArr) {
    const seen = new Set();
    const out = {};
    textsArr.forEach((txt, bi) => {
      const items = tokenize(txt).map((w) => {
        const k = normWord(w);
        let pontos = 1, motivo = "palavra válida";
        if (!k) { pontos = 0; motivo = "vazio"; }
        else if (seen.has(k)) { pontos = 0; motivo = "perseveração (repetida)"; }
        else if (taskKey === "FVF" && !/^p/i.test(k)) { pontos = 0; motivo = "não começa com P"; }
        else if (taskKey === "FVL" && /^\d+$/.test(k)) { pontos = 0; motivo = "número"; }
        if (k) seen.add(k);
        return { palavra: w, pontos, motivo };
      });
      out[bi] = { items, total: items.reduce((s, x) => s + x.pontos, 0) };
    });
    return out;
  }

  const wordCount = (s) => { const t = String(s || "").trim(); return t ? t.split(/\s+/).length : 0; };

  /* ---------------- Etapa de uma tarefa (cronômetro + contadores + transcrição) ---------------- */
  function TaskStep({ task, counts, setCounts, texts, setTexts, scored, onScore, scoring, onSetPts, hasAi, iaErro }) {
    const [running, setRunning] = useState(false);
    const [elapsed, setElapsed] = useState(0);
    const startRef = useRef(0);
    const elapsedRef = useRef(0);
    const [rec, setRec] = useState(null);
    const [listening, setListening] = useState(false);
    const [audioUrl, setAudioUrl] = useState("");
    const recogRef = useRef(null);
    const recRef = useRef(null);
    const activeRef = useRef(false);
    const assignedRef = useRef(0); // nº de palavras já atribuídas na sessão atual de reconhecimento
    const textsRef = useRef(texts); textsRef.current = texts;
    const countsRef = useRef(counts); countsRef.current = counts;
    elapsedRef.current = elapsed;

    useEffect(() => {
      if (!running) return;
      startRef.current = Date.now() - elapsed * 1000;
      const id = setInterval(() => {
        const e = (Date.now() - startRef.current) / 1000;
        if (e >= task.totalSec) { setElapsed(task.totalSec); elapsedRef.current = task.totalSec; setRunning(false); stopCapture(); }
        else { setElapsed(e); elapsedRef.current = e; }
      }, 200);
      return () => clearInterval(id);
    }, [running]);

    // Ao trocar de tarefa (desmontar), encerra microfone e reconhecimento.
    useEffect(() => () => {
      activeRef.current = false;
      if (recogRef.current) { try { recogRef.current.stop(); } catch (e) { /* */ } }
      if (recRef.current) { try { recRef.current.stop(); } catch (e) { /* */ } }
    }, []);

    const curBlock = Math.min(task.blocks - 1, Math.floor(elapsed / 30));
    const total = counts.reduce((s, x) => s + (Number(x) || 0), 0);
    const inc = () => setCounts(counts.map((c, i) => (i === curBlock ? (Number(c) || 0) + 1 : c)));
    const setBlk = (i, v) => setCounts(counts.map((c, idx) => (idx === i ? (v === "" ? "" : Math.max(0, parseInt(v, 10) || 0)) : c)));
    function setText(i, val) {
      const nt = textsRef.current.map((t, idx) => (idx === i ? val : t));
      setTexts(nt);
      setCounts(countsRef.current.map((c, idx) => (idx === i ? wordCount(val) : c)));
    }
    function appendText(i, chunk) {
      const cur = textsRef.current[i] || "";
      setText(i, (cur ? cur + " " : "") + chunk);
    }
    function reset() { setRunning(false); setElapsed(0); elapsedRef.current = 0; }

    function startRecognition() {
      const SR = window.SpeechRecognition || window.webkitSpeechRecognition;
      if (!SR) return false;
      const r = new SR();
      r.lang = "pt-BR"; r.continuous = true; r.interimResults = true;
      r.onstart = () => { assignedRef.current = 0; };
      r.onresult = (e) => {
        // Atribui as palavras ao bloco em que foram ditas (em tempo quase real),
        // sem esperar o "final" — que só chega depois da pausa e cairia no bloco seguinte.
        let full = "";
        for (let i = 0; i < e.results.length; i++) full += e.results[i][0].transcript + " ";
        const words = full.trim().split(/\s+/).filter(Boolean);
        const lastFinal = e.results.length && e.results[e.results.length - 1].isFinal;
        const stable = lastFinal ? words.length : Math.max(0, words.length - 1); // segura a última palavra parcial
        if (stable > assignedRef.current) {
          const blk = Math.min(task.blocks - 1, Math.floor((elapsedRef.current || 0) / 30));
          appendText(blk, words.slice(assignedRef.current, stable).join(" "));
          assignedRef.current = stable;
        }
      };
      r.onend = () => { if (activeRef.current) { try { r.start(); } catch (e) { /* */ } } };
      r.onerror = () => { /* ignora; onend reinicia */ };
      try { r.start(); recogRef.current = r; return true; } catch (e) { return false; }
    }

    function stopCapture() {
      activeRef.current = false;
      if (recogRef.current) { try { recogRef.current.stop(); } catch (e) { /* */ } recogRef.current = null; }
      if (recRef.current) { try { recRef.current.stop(); } catch (e) { /* */ } recRef.current = null; }
      setRec(null); setListening(false);
    }
    async function toggleRec() {
      if (rec || listening) { stopCapture(); setRunning(false); return; }
      activeRef.current = true;
      const ok = startRecognition();
      setListening(ok);
      if (elapsed < task.totalSec) setRunning(true); // inicia o cronômetro junto
      if (!ok) alert("Transcrição automática não disponível neste navegador (use o Chrome). O áudio será gravado mesmo assim.");
      try {
        const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
        const mr = new MediaRecorder(stream); const chunks = [];
        mr.ondataavailable = (e) => chunks.push(e.data);
        mr.onstop = () => { setAudioUrl(URL.createObjectURL(new Blob(chunks, { type: "audio/webm" }))); stream.getTracks().forEach((t) => t.stop()); };
        mr.start(); recRef.current = mr; setRec(mr);
      } catch (e) { if (!ok) { stopCapture(); setRunning(false); alert("Não foi possível acessar o microfone."); } }
    }

    const active = !!(rec || listening);

    return (
      <div>
        <div className="hay-instruction"><Icon name="help" size={18} /> {task.instruction}</div>

        <div className="tfv-timer">
          <div className="tfv-clock"><b>{fmtTime(elapsed)}</b><span>/ {fmtTime(task.totalSec)}</span></div>
          <div className="tfv-ctrls">
            <button type="button" className={"btn btn-sm " + (running ? "btn-ghost" : "btn-primary")} onClick={() => setRunning((r) => !r)}>{running ? "Pausar" : (elapsed > 0 ? "Continuar" : "Iniciar")}</button>
            <button type="button" className="btn btn-ghost btn-sm" onClick={reset}>Zerar tempo</button>
            <button type="button" className={"btn btn-sm " + (active ? "btn-coral" : "btn-ghost")} onClick={toggleRec}>{active ? "■ Parar gravação" : "● Gravar e transcrever"}</button>
          </div>
        </div>

        {listening && <p className="help-text" style={{ marginTop: 0 }}>🎙️ Transcrevendo no <b>bloco {curBlock + 1}</b>… a contagem é preenchida automaticamente (você pode corrigir o texto de cada bloco).</p>}

        <button type="button" className="tfv-inc" onClick={inc}>+1 palavra <span>(bloco atual: {curBlock + 1})</span></button>

        <div className="tfv-blocks">
          {counts.map((c, i) => (
            <div className={"tfv-block" + (running && i === curBlock ? " on" : "")} key={i}>
              <span className="tb-label">{blkLabel(i)}</span>
              <input className="ctrl" type="number" min="0" value={c} onChange={(e) => setBlk(i, e.target.value)} />
              <textarea className="ctrl tfv-txt" rows={2} value={texts[i] || ""} onChange={(e) => setText(i, e.target.value)} placeholder="transcrição do bloco..."></textarea>
            </div>
          ))}
          <div className="tfv-block total"><span className="tb-label">Total</span><div className="tb-total">{total}</div></div>
        </div>

        <div className="tfv-score-bar">
          <button type="button" className="btn btn-primary btn-sm" onClick={onScore} disabled={scoring}>
            <Icon name="sparkles" size={15} /> {scoring ? "Pontuando…" : "Pontuar com IA"}
          </button>
          <span className="help-text" style={{ margin: 0 }}>{hasAi ? "A Educare IA aplica os critérios do teste; revise e ajuste cada palavra." : "Sem IA — usa regras locais (perseveração, FVF sem P, números). Ajuste cada palavra na mão."}</span>
        </div>

        {iaErro && (
          <p className="form-err" role="alert" style={{ display: "flex", alignItems: "center", gap: 7, color: "#EF4444", fontWeight: 700, fontSize: 13, margin: "8px 0 0" }}>
            <Icon name="x" size={14} /> {iaErro}
          </p>
        )}

        {scored && Object.keys(scored).length > 0 && (
          <div className="tfv-breakdown">
            {counts.map((c, bi) => (scored[bi] && scored[bi].items.length ? (
              <div className="tfv-bd-block" key={bi}>
                <b>{blkLabel(bi)} — {scored[bi].total} pts</b>
                <div className="tfv-bd-items">
                  {scored[bi].items.map((it, ii) => (
                    <span className={"tfv-word" + (it.pontos === 0 ? " zero" : "")} key={ii} title={it.motivo}>
                      {it.palavra}
                      <input type="number" min="0" max="9" value={it.pontos} onChange={(e) => onSetPts(bi, ii, Math.max(0, parseInt(e.target.value, 10) || 0))} />
                    </span>
                  ))}
                </div>
              </div>
            ) : null))}
          </div>
        )}

        {audioUrl && (
          <div className="fld" style={{ marginTop: 12, marginBottom: 0 }}>
            <label>Gravação</label>
            <audio controls src={audioUrl} style={{ width: "100%" }}></audio>
            <a className="link" href={audioUrl} download={"tfv-" + task.key + ".webm"}>Baixar áudio</a>
          </div>
        )}
      </div>
    );
  }

  /* ---------------- Editor de tabelas normativas ---------------- */
  function NormsEditor({ config, norms, onSave, onClose }) {
    const [n, setN] = useState(() => JSON.parse(JSON.stringify(norms || {})));
    const [age, setAge] = useState("8");
    const [escola, setEscola] = useState("privada");
    const key = age + "_" + escola;

    const setVal = (taskKey, rowIdx, col, val) => setN((prev) => {
      const a = JSON.parse(JSON.stringify(prev));
      if (!a[key]) a[key] = {};
      if (!a[key][taskKey]) a[key][taskKey] = { blocks: [], total: [0, 0, 0, 0, 0] };
      const t = a[key][taskKey];
      const num = parseFloat(String(val).replace(",", ".")) || 0;
      if (rowIdx === "total") { if (!Array.isArray(t.total) || t.total.length !== 5) t.total = [0, 0, 0, 0, 0]; t.total[col] = num; }
      else { if (!t.blocks[rowIdx] || t.blocks[rowIdx].length !== 5) t.blocks[rowIdx] = [0, 0, 0, 0, 0]; t.blocks[rowIdx][col] = num; }
      return a;
    });
    const getVal = (taskKey, rowIdx, col) => {
      const t = n[key] && n[key][taskKey]; if (!t) return "";
      const arr = rowIdx === "total" ? t.total : (t.blocks && t.blocks[rowIdx]);
      return arr && arr[col] != null ? arr[col] : "";
    };

    return (
      <div className="form-wrap">
        <button className="pt-back" onClick={onClose}><Icon name="chevL" size={16} /> Voltar</button>
        <div className="page-head"><div><h1>Tabelas normativas — TFV</h1><p className="sub">5 âncoras por linha, na ordem [P95, P75, P50, P25, P5]. Cadastre/confira os valores do livro (Anexo C) antes do uso clínico. Linhas em branco aparecem como “— (norma não cadastrada)”.</p></div></div>
        <div className="form-card">
          <div className="grid-2">
            <div className="fld" style={{ marginBottom: 0 }}><label>Idade</label><select className="ctrl" value={age} onChange={(e) => setAge(e.target.value)}>{NORM_AGES.map((a) => <option key={a} value={String(a)}>{a} anos</option>)}</select></div>
            <div className="fld" style={{ marginBottom: 0 }}><label>Tipo de escola</label><select className="ctrl" value={escola} onChange={(e) => setEscola(e.target.value)}><option value="privada">Particular</option><option value="publica">Pública</option></select></div>
          </div>
        </div>
        {config.tasks.map((task) => (
          <div className="form-card" key={task.key}>
            <div className="sec-head">{task.name}</div>
            <div className="anchor-grid anchor-head"><span>Linha</span><span>P95</span><span>P75</span><span>P50</span><span>P25</span><span>P5</span></div>
            {Array.from({ length: task.blocks }).map((_, i) => (
              <div className="anchor-grid" key={i}>
                <span className="an-label">Bloco {i + 1}</span>
                {[0, 1, 2, 3, 4].map((col) => <input key={col} className="ctrl" type="number" step="any" value={getVal(task.key, i, col)} onChange={(e) => setVal(task.key, i, col, e.target.value)} />)}
              </div>
            ))}
            <div className="anchor-grid">
              <span className="an-label"><b>Total</b></span>
              {[0, 1, 2, 3, 4].map((col) => <input key={col} className="ctrl" type="number" step="any" value={getVal(task.key, "total", col)} onChange={(e) => setVal(task.key, "total", col, e.target.value)} />)}
            </div>
          </div>
        ))}
        <div className="save-bar"><button className="btn btn-primary" onClick={() => onSave(n)}><Icon name="clipboardCheck" size={18} /> Salvar tabelas</button></div>
      </div>
    );
  }

  /* ---------------- Editor de instruções ---------------- */
  function ConfigEditor({ config, onSave, onClose }) {
    const [c, setC] = useState(() => JSON.parse(JSON.stringify(config)));
    const upd = (i, field, val) => setC((prev) => ({ ...prev, tasks: prev.tasks.map((t, idx) => (idx === i ? { ...t, [field]: val } : t)) }));
    return (
      <div className="form-wrap">
        <button className="pt-back" onClick={onClose}><Icon name="chevL" size={16} /> Voltar</button>
        <div className="page-head"><div><h1>Gerenciar teste — TFV</h1><p className="sub">Edite as instruções de cada tarefa. Fica salvo neste dispositivo.</p></div></div>
        {c.tasks.map((t, i) => (
          <div className="form-card" key={t.key}>
            <div className="sec-head">{t.name}</div>
            <div className="fld" style={{ marginBottom: 0 }}><label>Instrução</label><textarea className="ctrl" value={t.instruction} onChange={(e) => upd(i, "instruction", e.target.value)}></textarea></div>
          </div>
        ))}
        <div className="save-bar"><button className="btn btn-primary" onClick={() => onSave(c)}><Icon name="clipboardCheck" size={18} /> Salvar</button></div>
        <div style={{ textAlign: "center", marginTop: 8 }}><button className="text-link" onClick={() => setC({ tasks: JSON.parse(JSON.stringify(DEFAULT_TASKS)) })}>Restaurar padrão</button></div>
      </div>
    );
  }

  /* ---------------- Wizard ---------------- */
  function TfvTest({ onBack, onOpenPatient }) {
    const [config, setConfig] = useState(loadConfig);
    const [norms, setNorms] = useState(loadNorms);
    const [editing, setEditing] = useState(false);
    const [editingNorms, setEditingNorms] = useState(false);
    const [step, setStep] = useState(1); // 1=ident, 2..4=tarefas, 5=resultado
    const [pid, setPid] = useState("");
    const [date, setDate] = useState(window.todayISO());
    const [idade, setIdade] = useState("");
    const [escola, setEscola] = useState("");
    const [data, setData] = useState(() => ({ FVL: [0, 0, 0, 0, 0], FVF: [0, 0, 0, 0], FVS: [0, 0, 0, 0] }));
    const [textData, setTextData] = useState(() => ({ FVL: ["", "", "", "", ""], FVF: ["", "", "", ""], FVS: ["", "", "", ""] }));
    const [err, setErr] = useState("");
    const [saved, setSaved] = useState(false);
    const [avalId, setAvalId] = useState(null);
    const [copied, setCopied] = useState(false);
    const [scores, setScores] = useState({}); // { taskKey: { blockIdx: {items,total} } }
    const [scoring, setScoring] = useState("");
    const [ia, setIa] = useState(null);
    const [iaBusy, setIaBusy] = useState(false);
    const [iaErro, setIaErro] = useState("");   // erro do parecer (etapa Resultado)
    const [pontErro, setPontErro] = useState(""); // erro da pontuação (etapas FVL/FVF/FVS)

    if (editing) return <ConfigEditor config={config} onClose={() => setEditing(false)} onSave={(c) => { saveConfig(c); setConfig(c); setEditing(false); }} />;
    if (editingNorms) return <NormsEditor config={config} norms={norms} onClose={() => setEditingNorms(false)} onSave={(o) => { saveNorms(o); setNorms(o); setEditingNorms(false); }} />;

    const patient = (window.PATIENTS || []).find((p) => p.id === pid);
    const escolaLabel = escola === "publica" ? "Pública" : escola === "privada" ? "Particular" : "—";
    const ageNum = parseInt(idade, 10);
    const ageKey = ageNum + "_" + escola;
    const missingIdent = !escola || isNaN(ageNum);
    const normLabel = missingIdent ? "—" : (norms[ageKey] ? (ageNum + " anos · " + escolaLabel) : ("não cadastrada (" + ageNum + " anos · " + escolaLabel + ")"));
    const STEPS = ["Identificação", "FVL", "FVF", "FVS", "Resultado"];

    function taskRows(task) {
      const counts = data[task.key];
      const rows = [];
      for (let i = 0; i < task.blocks; i++) {
        const raw = Number(counts[i]) || 0;
        const a = anchorRow(norms, ageKey, task.key, i);
        const r = a ? lookupAnchor(a, raw) : null;
        rows.push({ label: blkLabel(i), raw, p: r ? r.percentile : null, anchor: r ? r.anchor : null, cls: classify(r ? r.percentile : null) });
      }
      const total = counts.reduce((s, x) => s + (Number(x) || 0), 0);
      const at = anchorRow(norms, ageKey, task.key, "total");
      const rt = at ? lookupAnchor(at, total) : null;
      rows.push({ label: "Total", raw: total, p: rt ? rt.percentile : null, anchor: rt ? rt.anchor : null, cls: classify(rt ? rt.percentile : null), isTotal: true });
      return rows;
    }
    const results = config.tasks.map((t) => ({ key: t.key, name: t.name, short: t.short, rows: taskRows(t) }));
    const totalCls = (k) => { const r = results.find((x) => x.key === k); const tr = r && r.rows[r.rows.length - 1]; return tr && tr.cls ? tr.cls : "não classificada"; };

    function parecer() {
      return `Foi aplicado o Teste de Tarefas de Fluência Verbal, que tem o objetivo de avaliar Linguagem e Funções Executivas. O paciente obteve escore total com classificação ${totalCls("FVL")} na fluência verbal livre, classificação ${totalCls("FVF")} na fluência verbal fonêmica e classificação ${totalCls("FVS")} na fluência verbal semântica.`;
    }

    /* Payload da IA — escores e percentis já calculados aqui, mais as
       transcrições. Só o primeiro nome. */
    function payloadIA() {
      return {
        primeiro_nome: patient ? String(patient.name).split(" ")[0] : "",
        idade: idade || null,
        tipo_de_escola: escolaLabel,
        data: date,
        norma_aplicada: normLabel,
        tarefas: results.map((r) => ({
          sigla: r.key,
          nome: r.name,
          linhas: r.rows.map((x) => ({
            bloco_ou_total: x.label,
            escore_bruto: x.raw,
            percentil: x.p,
            classificacao: x.cls || null,
          })),
          transcricao_por_bloco: (textData[r.key] || []).map((t, i) => ({
            bloco: i + 1, palavras: t || "",
          })),
        })),
      };
    }
    async function gerarIA() {
      setIaBusy(true); setIaErro("");
      try { setIa(await window.EducareIA.gerar("tfv", payloadIA())); }
      catch (e) { setIaErro(e.message || "Falha ao gerar o parecer."); }
      finally { setIaBusy(false); }
    }
    const parecerFinal = window.EducareIA.texto(ia, parecer());

    function goTop() { const el = document.querySelector(".main-scroll"); if (el) el.scrollTop = 0; }
    function next() { if (step === 1 && !pid) { setErr("Selecione o paciente."); return; } setErr(""); setStep((s) => Math.min(5, s + 1)); goTop(); }
    function prev() { if (step === 1) { onBack(); return; } setStep((s) => s - 1); goTop(); }
    const setCounts = (taskKey, arr) => setData((d) => ({ ...d, [taskKey]: arr }));
    const setTexts = (taskKey, arr) => setTextData((d) => ({ ...d, [taskKey]: arr }));

    async function scoreTask(task) {
      setScoring(task.key);
      setPontErro("");
      let result = null;
      if (window.EducareIA.configurada()) {
        try {
          result = {};
          const anteriores = []; // perseveração é avaliada na tarefa inteira
          for (let bi = 0; bi < task.blocks; bi++) {
            const words = tokenize(textData[task.key][bi]);
            if (!words.length) { result[bi] = { items: [], total: 0 }; continue; }
            const parsed = await window.EducareIA.gerar("tfv-pontuar", {
              tarefa: task.key,
              nome_da_tarefa: task.name,
              bloco: bi + 1,
              palavras_dos_blocos_anteriores: anteriores.slice(),
              palavras: words,
            });
            const items = (parsed.itens || []).map((x) => ({
              palavra: x.palavra, pontos: Number(x.pontos) || 0, motivo: x.motivo || "",
            }));
            result[bi] = { items, total: items.reduce((s, x) => s + x.pontos, 0) };
            anteriores.push(...words);
          }
        } catch (e) {
          result = null;
          setPontErro((e.message || "Falha na IA.") + " Pontuação feita pelas regras locais — revise cada palavra.");
        }
      }
      if (!result) result = localScoreTask(task.key, textData[task.key]);
      setScores((s) => ({ ...s, [task.key]: result }));
      setData((d) => ({ ...d, [task.key]: d[task.key].map((c, i) => (result[i] ? result[i].total : c)) }));
      setScoring("");
    }
    function setItemPts(taskKey, bi, ii, pts) {
      const t = Object.assign({}, scores[taskKey] || {});
      const blk = t[bi]; if (!blk) return;
      const items = blk.items.map((x, idx) => (idx === ii ? Object.assign({}, x, { pontos: pts }) : x));
      const total = items.reduce((a, x) => a + x.pontos, 0);
      t[bi] = { items, total };
      setScores((s) => ({ ...s, [taskKey]: t }));
      setData((d) => ({ ...d, [taskKey]: d[taskKey].map((c, k) => (k === bi ? total : c)) }));
    }

    /* Conteúdo gravado no prontuário — usado ao salvar e ao ressincronizar
       depois que a IA responde. */
    function registro() {
      return {
        result: `FVL ${totalCls("FVL")} · FVF ${totalCls("FVF")} · FVS ${totalCls("FVS")}`,
        note: parecerFinal,
        sheet: { kind: "tfv", idade: idade || "—", escola: escolaLabel, normLabel, tasks: results, transcripts: textData, parecer: parecerFinal, ia },
      };
    }

    function save() {
      const rec = window.addAvaliacao({ pid, name: "Tarefas de Fluência Verbal (TFV)", date, ...registro() });
      setAvalId(rec ? rec.id : null);
      setSaved(true);
    }

    /* Parecer gerado depois de salvar reescreve o registro já gravado. */
    useEffect(() => {
      if (!avalId || !ia) return;
      window.atualizarAvaliacao(avalId, registro());
    }, [ia, avalId]);
    function exportPDF() {
      const tbl = (r) => `<h2>${esc(r.name)}</h2><table>${"<tr><th>Avaliação quantitativa</th><th>Escore bruto</th><th>Percentil</th><th>Classificação</th></tr>"}${r.rows.map((x) => `<tr${x.isTotal ? ' style="font-weight:bold;background:#F1F5F4"' : ""}><td>${esc(x.label)}</td><td class="c">${x.raw}</td><td class="c">${x.p == null ? "—" : x.p + (x.anchor != null ? " <span style='color:#888;font-size:10px'>(≈ " + x.anchor + ")</span>" : "")}</td><td>${esc(x.cls || "— (norma não cadastrada)")}</td></tr>`).join("")}</table>`;
      const html = `<!DOCTYPE html><html lang="pt-BR"><head><meta charset="UTF-8"><title>TFV — ${esc(patient ? patient.name : "")}</title>
        <style>body{font-family:Arial,Helvetica,sans-serif;color:#142826;padding:24px;font-size:12px}h1{font-size:16px;text-align:center;margin:0 0 4px}h2{font-size:13px;background:#E9F0EE;padding:6px 8px;border-radius:6px;margin:16px 0 4px}.meta{margin:8px 0}table{width:100%;border-collapse:collapse;margin-top:4px}th,td{border:1px solid #B9C9C5;padding:6px 8px;text-align:left}th{background:#D8E5E2}td.c{text-align:center}.an{margin-top:16px;line-height:1.5}</style></head><body>
        <h1>TAREFAS DE FLUÊNCIA VERBAL (TFV)</h1>
        <div class="meta"><b>Paciente:</b> ${esc(patient ? patient.name : "—")} &nbsp; <b>Idade:</b> ${esc(idade) || "—"}${idade ? " anos" : ""} &nbsp; <b>Escola:</b> ${esc(escolaLabel)} &nbsp; <b>Data:</b> ${esc(date)}<br/><b>Norma aplicada:</b> ${esc(normLabel)}</div>
        ${results.map(tbl).join("")}
        ${config.tasks.map((t) => { const arr = textData[t.key] || []; if (!arr.some((x) => x && x.trim())) return ""; return `<h2>${esc(t.name)} — transcrição</h2>` + arr.map((x, i) => (x && x.trim() ? `<p style="margin:2px 0"><b>Bloco ${i + 1}:</b> ${esc(x)}</p>` : "")).join(""); }).join("")}
        <p class="an"><b>Parecer:</b> ${esc(parecerFinal)}</p>
        <p style="margin-top:10px;font-size:10px;color:#666">Interpretação automática de apoio — não substitui o julgamento clínico.</p>
        </body></html>`;
      const w = window.open("", "_blank"); if (!w) { alert("Permita pop-ups para exportar o PDF."); return; }
      w.document.write(html); w.document.close(); w.focus(); setTimeout(() => { try { w.print(); } catch (e) { /* manual */ } }, 300);
    }

    const taskIdx = step - 2;
    const task = config.tasks[taskIdx];

    return (
      <div className="form-wrap">
        <div className="hay-top">
          <button className="pt-back" onClick={onBack}><Icon name="chevL" size={16} /> Voltar para avaliações</button>
          {step === 1 && (
            <span style={{ display: "flex", gap: 8, flexWrap: "wrap" }}>
              <button className="btn btn-ghost btn-xs" onClick={() => setEditingNorms(true)}><Icon name="chart" size={14} /> Tabelas normativas</button>
              <button className="btn btn-ghost btn-xs" onClick={() => setEditing(true)}><Icon name="fileText" size={14} /> Gerenciar teste</button>
            </span>
          )}
        </div>

        <div className="page-head" style={{ marginBottom: 14 }}>
          <div><h1><Icon name="clipboardList" size={25} /> Tarefas de Fluência Verbal (TFV)</h1><p className="sub">Linguagem e funções executivas — fluência livre, fonêmica (P) e semântica (roupas).</p></div>
        </div>

        <div className="hay-stepper">
          {STEPS.map((s, i) => (
            <button type="button" key={i} className={"hs" + (i + 1 === step ? " on" : "") + (i + 1 < step ? " done" : "")} onClick={() => { setStep(i + 1); goTop(); }}>
              <span className="hs-n">{i + 1 < step ? <Icon name="clipboardCheck" size={14} stroke={3} /> : i + 1}</span>{s}
            </button>
          ))}
        </div>

        {step === 1 && (
          <div className="form-card">
            <div className="sec-head"><span className="si"><Icon name="users" size={18} /></span> Identificação</div>
            <div className="fld"><label>Paciente <span className="req">*</span></label><window.PatientPicker value={pid} onChange={(id) => { setPid(id); const p = (window.PATIENTS || []).find((x) => x.id === id); if (p && p.age != null) setIdade(String(p.age)); if (p && p.escola) setEscola(p.escola); }} /></div>
            <div className="grid-2">
              <div className="fld"><label>Idade da criança</label><input className="ctrl" type="number" min="0" max="18" value={idade} onChange={(e) => setIdade(e.target.value)} placeholder="anos" /></div>
              <div className="fld"><label>Tipo de escola</label><select className="ctrl" value={escola} onChange={(e) => setEscola(e.target.value)}><option value="">Selecione...</option><option value="publica">Pública</option><option value="privada">Particular</option></select></div>
            </div>
            <div className="fld" style={{ marginBottom: 0 }}><label>Data</label><input className="ctrl" type="date" value={date} onChange={(e) => setDate(e.target.value)} /></div>
          </div>
        )}

        {step >= 2 && step <= 4 && task && (
          <div className="form-card">
            <div className="sec-head"><span className="si"><Icon name="activity" size={18} /></span> {task.name}</div>
            <TaskStep key={task.key} task={task} counts={data[task.key]} setCounts={(arr) => setCounts(task.key, arr)} texts={textData[task.key]} setTexts={(arr) => setTexts(task.key, arr)} scored={scores[task.key] || {}} onScore={() => scoreTask(task)} scoring={scoring === task.key} onSetPts={(bi, ii, pts) => setItemPts(task.key, bi, ii, pts)} hasAi={window.EducareIA.configurada()} iaErro={pontErro} />
          </div>
        )}

        {step === 5 && (
          <>
            <div className="hay-sheet-id">
              <span><b>Paciente:</b> {patient ? patient.name : "—"}</span>
              <span><b>Idade:</b> {idade || "—"}{idade ? " anos" : ""}</span>
              <span><b>Escola:</b> {escolaLabel}</span>
              <span><b>Data:</b> {date}</span>
              <span><b>Norma aplicada:</b> {normLabel}</span>
            </div>
            {results.map((r) => (
              <div className="form-card" key={r.key} style={{ paddingBottom: 8 }}>
                <div className="sec-head">{r.name}</div>
                <table className="hay-sheet">
                  <thead><tr><th>Avaliação quantitativa</th><th>Escore bruto</th><th>Percentil</th><th>Classificação</th></tr></thead>
                  <tbody>
                    {r.rows.map((x, j) => (
                      <tr key={j} style={x.isTotal ? { fontWeight: 700 } : null}>
                        <td>{x.label}</td>
                        <td className="c">{x.raw}</td>
                        <td className="c">{x.p == null ? "—" : <span>{x.p}{x.anchor != null && <span className="anchor-ref">≈ {x.anchor}</span>}</span>}</td>
                        <td>{x.cls || <span className="muted-cell">— (norma não cadastrada)</span>}</td>
                      </tr>
                    ))}
                  </tbody>
                </table>
                {(textData[r.key] || []).some((t) => t && t.trim()) && (
                  <div className="abc-note" style={{ marginTop: 10 }}><b>Transcrição</b><p style={{ whiteSpace: "pre-line" }}>{(textData[r.key] || []).map((t, i) => (t && t.trim() ? `Bloco ${i + 1}: ${t}` : null)).filter(Boolean).join("\n")}</p></div>
                )}
              </div>
            ))}

            <window.IaBloco
              titulo="PARECER CLÍNICO"
              report={ia} fallback={parecer()}
              busy={iaBusy} erro={iaErro} onGerar={gerarIA}
            />
            <div style={{ textAlign: "right", marginTop: 6 }}>
              <button className="btn btn-ghost btn-xs" onClick={() => { try { navigator.clipboard.writeText(parecerFinal); setCopied(true); } catch (e) { /* */ } }}>{copied ? "Copiado!" : "Copiar parecer"}</button>
            </div>

            {saved && (
              <div className="save-ok" style={{ marginTop: 14 }}><span className="so-ic"><Icon name="clipboardCheck" size={18} stroke={2.6} /></span><div><b>Avaliação salva!</b><span>Vinculada ao prontuário{patient ? " de " + patient.name : ""}.</span></div></div>
            )}

            <div className="save-bar" style={{ gap: 10, display: "flex", flexWrap: "wrap" }}>
              {!saved
                ? <button className="btn btn-primary" onClick={save}><Icon name="clipboardCheck" size={18} /> Salvar no prontuário</button>
                : <button className="btn btn-primary" onClick={() => onOpenPatient && pid && onOpenPatient(pid)}><Icon name="users" size={18} /> Ver no prontuário</button>}
              <button className="btn btn-ghost" onClick={exportPDF}><Icon name="download" size={18} /> Exportar PDF da folha</button>
            </div>
          </>
        )}

        {err && step === 1 && <p className="form-err" style={{ display: "flex", alignItems: "center", gap: 7, color: "#EF4444", fontWeight: 700, fontSize: 13.5, margin: "12px 0 0" }}><Icon name="x" size={15} /> {err}</p>}

        {step < 5 && (
          <div className="hay-nav">
            <button className="btn btn-ghost btn-sm" onClick={prev}><Icon name="chevL" size={16} /> {step === 1 ? "Cancelar" : "Voltar"}</button>
            <button className="btn btn-primary btn-sm" onClick={next}>{step === 4 ? "Ver resultado" : "Continuar"} <Icon name="arrowRight" size={16} /></button>
          </div>
        )}

      </div>
    );
  }

  window.TfvTest = TfvTest;
})();
