{"id":963,"date":"2026-02-10T00:39:56","date_gmt":"2026-02-10T03:39:56","guid":{"rendered":"https:\/\/sites.usp.br\/sofiafala\/?page_id=963"},"modified":"2026-02-10T04:00:25","modified_gmt":"2026-02-10T07:00:25","slug":"doe-video","status":"publish","type":"page","link":"https:\/\/sites.usp.br\/sofiafala\/doe-video\/","title":{"rendered":"Doe V\u00eddeo"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-page\" data-elementor-id=\"963\" class=\"elementor elementor-963\" data-elementor-post-type=\"page\">\n\t\t\t\t<div class=\"elementor-element elementor-element-34b4b6d e-flex e-con-boxed e-con e-parent\" data-id=\"34b4b6d\" data-element_type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-d35d224 elementor-widget elementor-widget-shortcode\" data-id=\"d35d224\" data-element_type=\"widget\" data-widget_type=\"shortcode.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<div class=\"elementor-shortcode\"><div class=\"sofia-doe-video sdv-shell\" style=\"max-width:980px;margin:0 auto;padding:24px;\">\r\n\r\n<style>\r\n.sdv-shell{\r\nfont-family: Roboto, system-ui, -apple-system, Segoe UI, Arial, sans-serif;\r\ncolor:#202124;\r\n}\r\n.sdv-shell * { box-sizing: border-box; }\r\n.sdv-shell a{ color:#1a73e8; }\r\n.sdv-shell a:hover{ text-decoration: underline; }\r\n\r\n.sdv-bg{\r\nbackground: #f8f9fa;\r\nborder-radius: 20px;\r\npadding: 18px;\r\nborder: 1px solid rgba(60,64,67,.08);\r\n}\r\n\r\n.sdv-card{\r\nbackground:#fff;\r\nborder-radius: 18px;\r\nborder: 1px solid rgba(60,64,67,.12);\r\nbox-shadow: 0 1px 2px rgba(60,64,67,.08), 0 2px 8px rgba(60,64,67,.08);\r\n}\r\n\r\n.sdv-title{\r\nfont-size: 18px;\r\nfont-weight: 800;\r\ncolor:#202124;\r\n}\r\n\r\n.sdv-btn{\r\nappearance:none;\r\nborder:1px solid rgba(60,64,67,.12);\r\nbackground:#fff;\r\ncolor:#202124;\r\nborder-radius: 999px;\r\npadding: 10px 16px;\r\nfont-weight: 700;\r\ncursor:pointer;\r\ntransition: transform .06s ease, box-shadow .14s ease, background .14s ease, border-color .14s ease, filter .14s ease;\r\n}\r\n.sdv-btn:hover{\r\nbackground:#f8f9fa;\r\nbox-shadow: 0 1px 2px rgba(60,64,67,.08), 0 2px 8px rgba(60,64,67,.12);\r\n}\r\n.sdv-btn:active{ transform: translateY(1px); }\r\n.sdv-btn:focus{\r\noutline:none;\r\nbox-shadow: 0 0 0 4px rgba(26,115,232,.22);\r\nborder-color: rgba(26,115,232,.65);\r\n}\r\n.sdv-btn-disabled{\r\nopacity:.55;\r\ncursor:not-allowed !important;\r\nbox-shadow:none !important;\r\n}\r\n\r\n.sdv-btn-primary{\r\nbackground:#1a73e8;\r\ncolor:#fff;\r\nborder-color: transparent;\r\n}\r\n.sdv-btn-primary:hover{ filter: brightness(.96); background:#1a73e8; }\r\n\r\n.sdv-btn-danger{\r\nbackground:#d93025;\r\ncolor:#fff;\r\nborder-color: transparent;\r\n}\r\n.sdv-btn-danger:hover{ filter: brightness(.96); background:#d93025; }\r\n\r\n.sdv-btn-success{\r\nbackground:#188038;\r\ncolor:#fff;\r\nborder-color: transparent;\r\n}\r\n.sdv-btn-success:hover{ filter: brightness(.96); background:#188038; }\r\n\r\n.sdv-shell input[type=\"email\"],\r\n.sdv-shell input[type=\"date\"],\r\n.sdv-shell select{\r\nwidth: 100%;\r\nborder: 1px solid rgba(60,64,67,.22);\r\nborder-radius: 12px;\r\npadding: 12px 12px;\r\nbackground:#fff;\r\ncolor:#202124;\r\ntransition: box-shadow .14s ease, border-color .14s ease;\r\n}\r\n.sdv-shell input:focus,\r\n.sdv-shell select:focus{\r\noutline:none;\r\nborder-color: rgba(26,115,232,.75);\r\nbox-shadow: 0 0 0 4px rgba(26,115,232,.18);\r\n}\r\n\r\n.sdv-pill{\r\ndisplay:inline-flex; align-items:center; gap:8px;\r\npadding:8px 12px;\r\nborder-radius: 999px;\r\nborder: 1px solid rgba(60,64,67,.14);\r\nbackground:#fff;\r\nbox-shadow: 0 1px 2px rgba(60,64,67,.06);\r\n}\r\n.sdv-rec-dot{\r\nwidth:10px;height:10px;border-radius:50%;\r\nbackground:#d93025;\r\nbox-shadow:0 0 0 rgba(217,48,37,.6);\r\nanimation: sdvPulse 1s infinite;\r\n}\r\n@keyframes sdvPulse { 0%{ box-shadow:0 0 0 0 rgba(217,48,37,.45);} 70%{ box-shadow:0 0 0 10px rgba(217,48,37,0);} 100%{ box-shadow:0 0 0 0 rgba(217,48,37,0);} }\r\n\r\n.sdv-fade-in{ animation: sdvFadeIn .22s ease forwards; }\r\n@keyframes sdvFadeIn { from{opacity:0; transform: translateY(6px);} to{opacity:1; transform: translateY(0);} }\r\n\r\n.sdv-loading{ position:relative; overflow:hidden; }\r\n.sdv-loading:after{\r\ncontent:\"\"; position:absolute; inset:0;\r\nbackground: linear-gradient(90deg, rgba(255,255,255,0), rgba(255,255,255,.35), rgba(255,255,255,0));\r\ntransform: translateX(-120%);\r\nanimation: sdvShimmer 1s infinite;\r\n}\r\n@keyframes sdvShimmer { to { transform: translateX(120%);} }\r\n\r\n.sdv-steps{ display:flex; justify-content:center; gap:14px; align-items:center; margin-bottom:18px; }\r\n.sdv-stepdot{\r\nwidth:34px;height:34px;border-radius:999px;display:grid;place-items:center;\r\nfont-weight:900; letter-spacing:.3px;\r\nborder: 1px solid rgba(60,64,67,.12);\r\nbox-shadow: 0 1px 2px rgba(60,64,67,.06);\r\n}\r\n.sdv-line{ height:3px;width:160px;background:#e8eaed;border-radius:99px; }\r\n.sdv-steplabels{ display:flex;justify-content:center;gap:150px;margin-top:-8px;margin-bottom:22px;font-size:12px;color:#5f6368; }\r\n\r\n.sdv-mode-wrap{ padding:16px; max-width:760px; margin:0 auto 14px; }\r\n.sdv-mode-title{ margin:0 0 12px; text-align:center; font-size:18px; font-weight:900; }\r\n.sdv-mode-btns{ display:flex; gap:12px; justify-content:center; flex-wrap:wrap; margin: 6px 0 10px; }\r\n.sdv-mode-btns button{ min-width:240px; padding:12px 18px; }\r\n.sdv-active{ background:#1a73e8 !important; color:#fff !important; border-color:transparent !important; }\r\n\r\n.sdv-divider{ height:1px;background: rgba(60,64,67,.12); margin:12px 0; }\r\n\r\n.sdv-prompt{ text-align:center; }\r\n.sdv-refresh-wrap{ display:flex; align-items:center; gap:10px; justify-content:center; }\r\n.sdv-refresh{\r\nwidth:48px;\r\nheight:48px;\r\nborder-radius:16px;\r\nborder:1px solid rgba(180,167,255,.28);\r\nbackground:linear-gradient(180deg,#f3efff 0%, #efeafe 100%);\r\ncursor:pointer;\r\ndisplay:grid;\r\nplace-items:center;\r\nbox-shadow:0 1px 2px rgba(60,64,67,.06), 0 6px 16px rgba(167,139,250,.14);\r\ntransition:transform .08s ease, box-shadow .16s ease, background .16s ease;\r\n}\r\n.sdv-refresh:hover{\r\nbackground:linear-gradient(180deg,#ede7ff 0%, #e9e1ff 100%);\r\nbox-shadow:0 1px 2px rgba(60,64,67,.06), 0 10px 20px rgba(167,139,250,.20);\r\n}\r\n.sdv-refresh:active{ transform:scale(.97); }\r\n.sdv-refresh:focus{\r\noutline:none;\r\nbox-shadow:0 0 0 4px rgba(167,139,250,.20), 0 8px 18px rgba(167,139,250,.18);\r\nborder-color:rgba(167,139,250,.45);\r\n}\r\n.sdv-refresh svg{ width:22px;height:22px;opacity:1;color:#7c3aed; }\r\n.sdv-refresh-label{ font-size:14px;color:#6d28d9;font-weight:800; }\r\n\r\n.sdv-prompt .w{ font-size: 34px; font-weight: 900; margin: 10px 0 6px; line-height: 1.14; }\r\n.sdv-prompt .s{ font-size: 16px; color:#5f6368; margin:0; }\r\n.sdv-prompt-actions{ display:flex; gap:10px; justify-content:center; flex-wrap:wrap; margin-top: 12px; }\r\n\r\n.sdv-cta{\r\nmargin:0 0 12px;\r\ntext-align:center;\r\npadding:12px 14px;\r\nborder-radius: 16px;\r\nborder: 1px solid rgba(26,115,232,.18);\r\nbackground: linear-gradient(180deg, rgba(26,115,232,.06), rgba(255,255,255,1));\r\n}\r\n.sdv-cta strong{ display:block; font-size:16px; color:#202124; font-weight:900; }\r\n.sdv-cta span{ display:block; margin-top:6px; color:#5f6368; font-size:14px; }\r\n\r\n.sdv-visor{ width:100%; max-height:360px; border-radius: 16px; background:#000; border: 1px solid rgba(60,64,67,.14); }\r\n\r\n.sdv-underbar{\r\nmargin-top:10px;\r\npadding:10px 12px;\r\nborder:1px solid rgba(60,64,67,.12);\r\nborder-radius:16px;\r\nbackground:#f8f9fa;\r\n}\r\n.sdv-underbar-row{ display:flex; align-items:center; justify-content:space-between; gap:10px; flex-wrap:wrap; }\r\n.sdv-underbar-text{ font-size:14px; color:#202124; font-weight:900; margin:0; flex:1 1 200px; line-height:1.2; }\r\n.sdv-underbar-actions{ display:flex; gap:10px; flex-wrap:wrap; justify-content:flex-end; }\r\n.sdv-underbar-actions button{ padding:10px 14px; min-width:130px; }\r\n.sdv-underbar-sub{ font-size:12px; color:#5f6368; margin:6px 0 0; }\r\n\r\n.sdv-modal-backdrop{\r\nposition:fixed; inset:0; background:rgba(32,33,36,.45);\r\ndisplay:none; align-items:center; justify-content:center;\r\npadding:18px; z-index:999999;\r\nbackdrop-filter: blur(6px);\r\n}\r\n.sdv-modal{\r\nwidth:min(520px, 96vw);\r\nbackground:#fff;\r\nborder-radius: 20px;\r\nborder: 1px solid rgba(60,64,67,.12);\r\nbox-shadow: 0 10px 28px rgba(60,64,67,.20);\r\noverflow:hidden;\r\n}\r\n.sdv-modal-header{\r\npadding:16px 18px 10px;\r\nborder-bottom:1px solid rgba(60,64,67,.08);\r\ndisplay:flex; align-items:center; justify-content:space-between; gap:10px;\r\n}\r\n.sdv-modal-title{ margin:0; font-size:18px; color:#202124; font-weight:900; }\r\n.sdv-modal-body{ padding:18px; }\r\n.sdv-modal-body p{ margin:0 0 14px; color:#3c4043; text-align:center; }\r\n.sdv-modal-actions{ display:flex; flex-direction:column; gap:10px; }\r\n.sdv-modal-actions button{\r\nwidth:100%;\r\npadding:13px 14px;\r\nborder-radius:16px;\r\nfont-size:15px;\r\nfont-weight:800;\r\n}\r\n\r\n.sdv-next-word{ background:#e8f0fe; color:#174ea6; border-color:#d2e3fc; }\r\n.sdv-next-phrase{ background:#f3e8ff; color:#6b21a8; border-color:#e9d5ff; }\r\n.sdv-stop{ background:#f1f3f4; color:#202124; border-color:#dadce0; }\r\n\r\n.sdv-thanks{\r\ndisplay:none;\r\nmax-width:760px;\r\nmargin:0 auto;\r\npadding:22px 18px;\r\nborder-radius: 20px;\r\nborder: 1px solid rgba(60,64,67,.12);\r\nbackground:#fff;\r\nbox-shadow: 0 1px 2px rgba(60,64,67,.08), 0 6px 22px rgba(60,64,67,.10);\r\ntext-align:center;\r\n}\r\n.sdv-thanks h2{ margin:0 0 10px; font-size:26px; font-weight: 900; }\r\n.sdv-thanks p{ margin:0 0 16px; color:#3c4043; font-size:16px; line-height:1.35; }\r\n\r\n.sdv-intro{\r\nmax-width:920px;\r\nmargin:0 auto 18px;\r\npadding:22px 22px;\r\nborder-radius: 20px;\r\nborder: 1px solid rgba(60,64,67,.12);\r\nbackground:#fff;\r\nbox-shadow: 0 1px 2px rgba(60,64,67,.08), 0 6px 22px rgba(60,64,67,.10);\r\ncolor:#202124;\r\n}\r\n.sdv-intro h1,\r\n.sdv-bg .sdv-intro h1,\r\nh1.sdv-video-main-title{\r\nmargin:0 0 14px;\r\nfont-size:28px;\r\nline-height:1.15;\r\nfont-weight:900;\r\ntext-align:center;\r\ncolor:#f28c28 !important;\r\n-webkit-text-fill-color:#f28c28 !important;\r\n}\r\n.sdv-intro p{\r\nmargin:0 0 14px;\r\nfont-size:16px;\r\nline-height:1.55;\r\ncolor:#3c4043;\r\n}\r\n.sdv-intro ol{\r\nmargin:8px 0 14px 22px;\r\npadding:0;\r\nfont-size:16px;\r\nline-height:1.55;\r\ncolor:#3c4043;\r\n}\r\n.sdv-intro li{ margin:0 0 6px; }\r\n.sdv-intro .sdv-count{\r\nfont-size:18px;\r\nfont-weight:800;\r\ncolor:#3c4043;\r\n}\r\n\r\n\r\n.sdv-termo-link{\r\nfont-weight:800;\r\ncolor:#f28c28 !important;\r\ntext-decoration:underline;\r\n}\r\n\r\n#msgCadastro, #msgVideo{ font-weight: 700; }\r\n<\/style>\r\n\r\n<div class=\"sdv-bg\">\r\n\r\n<div class=\"sdv-intro\">\r\n<h1 class=\"sdv-video-main-title\" style=\"color:#f28c28 !important;-webkit-text-fill-color:#f28c28 !important;\">Bem-vindo(a) ao Projeto SofiaFala - Coleta Participativa de V\u00eddeo<\/h1>\r\n<p>O SofiaFala \u00e9 um projeto de pesquisa que pretende ajudar pessoas com dist\u00farbios de fala, promovendo a inclus\u00e3o e a conscientiza\u00e7\u00e3o sobre esses desafios, para que todas as vozes possam ser ouvidas.<\/p>\r\n<p>A coleta de dados ser\u00e1 feita por meio da grava\u00e7\u00e3o de <b>v\u00eddeos de palavras e frases<\/b> pelos participantes. Essas grava\u00e7\u00f5es ser\u00e3o armazenadas em um banco de dados digital, permitindo seu uso para pesquisas cient\u00edficas.<\/p>\r\n<p><b>A participa\u00e7\u00e3o \u00e9 simples e envolve duas etapas:<\/b><\/p>\r\n<ol>\r\n<li>Cadastro de dados b\u00e1sicos, aceite do Termo de Consentimento Livre e Esclarecido (TCLE) e aceite do Termo de Consentimento de Uso de Imagem, Som e Voz (TCUISV).<\/li>\r\n<li>Grava\u00e7\u00e3o dos v\u00eddeos com palavras e\/ou frases.<\/li>\r\n<\/ol>\r\n<p>Este projeto \u00e9 uma colabora\u00e7\u00e3o entre a Profa. Dra. Alessandra Alaniz Macedo, da FFCLRP-USP, e a Profa. Dra. Patr\u00edcia Pupin Mandr\u00e1, da FMRP-USP. Sua participa\u00e7\u00e3o pode impactar positivamente a inclus\u00e3o e a conscientiza\u00e7\u00e3o sobre os desafios de pessoas com dist\u00farbios de fala. Contamos com a sua colabora\u00e7\u00e3o!<\/p>\r\n<p class=\"sdv-count\">Junte-se \u00e0s outras pessoas e doe voz.<\/p>\r\n<\/div>\r\n\r\n<div class=\"sdv-steps\">\r\n<div id=\"stepDot1\" class=\"sdv-stepdot\" style=\"background:#1a73e8;color:#fff;border-color:transparent;\">1<\/div>\r\n<div class=\"sdv-line\"><\/div>\r\n<div id=\"stepDot2\" class=\"sdv-stepdot\" style=\"background:#fff;color:#1f2937;\">2<\/div>\r\n<\/div>\r\n\r\n<div class=\"sdv-steplabels\">\r\n<div>Cadastro do Participante<\/div>\r\n<div>Doa\u00e7\u00e3o de V\u00eddeo<\/div>\r\n<\/div>\r\n\r\n<div id=\"etapaCadastro\" class=\"sdv-card\" style=\"padding:18px;\">\r\n<h2 class=\"sdv-title\" style=\"margin:0 0 14px;text-align:center;\">Cadastro do Participante<\/h2>\r\n\r\n<form id=\"formCadastro\" style=\"display:grid;gap:12px;max-width:620px;margin:0 auto;\">\r\n<label style=\"display:grid;gap:6px;\">\r\n<span style=\"font-size:12px;color:#5f6368;font-weight:700;\">E-mail<\/span>\r\n<input name=\"email\" type=\"email\" placeholder=\"E-mail\" required>\r\n<\/label>\r\n\r\n<label style=\"display:grid;gap:6px;\">\r\n<span style=\"font-size:12px;color:#5f6368;font-weight:700;\">Data de nascimento<\/span>\r\n<input name=\"data_nascimento\" id=\"data_nascimento\" type=\"date\" required>\r\n<\/label>\r\n\r\n<label style=\"display:grid;gap:6px;\">\r\n<span style=\"font-size:12px;color:#5f6368;font-weight:700;\">G\u00eanero<\/span>\r\n<select name=\"genero\" id=\"genero\" required>\r\n<option value=\"\" selected disabled>Selecione<\/option>\r\n<option value=\"Feminino\">Feminino<\/option>\r\n<option value=\"Masculino\">Masculino<\/option>\r\n<option value=\"N\u00e3o-bin\u00e1rio\">N\u00e3o-bin\u00e1rio<\/option>\r\n<option value=\"Prefiro n\u00e3o informar\">Prefiro n\u00e3o informar<\/option>\r\n<option value=\"Outro\">Outro<\/option>\r\n<\/select>\r\n<\/label>\r\n\r\n<label style=\"display:grid;gap:6px;\">\r\n<span style=\"font-size:12px;color:#5f6368;font-weight:700;\">Origem do dist\u00farbio<\/span>\r\n<select name=\"origem_disturbio\" id=\"origem_disturbio\" required>\r\n<option value=\"\" selected disabled>Selecione<\/option>\r\n<option value=\"Altera\u00e7\u00e3o de fala em crian\u00e7a\/articula\u00e7\u00e3o\/apraxia\/disartria\">Altera\u00e7\u00e3o de fala em crian\u00e7a\/articula\u00e7\u00e3o\/apraxia\/disartria<\/option>\r\n<option value=\"S\u00edndrome de Down (T21)\">S\u00edndrome de Down (T21)<\/option>\r\n<option value=\"Transtorno do Espectro Autista (TEA)\">Transtorno do Espectro Autista (TEA)<\/option>\r\n<option value=\"Acidente Vascular Cerebral (AVC)\">Acidente Vascular Cerebral (AVC)<\/option>\r\n<option value=\"Defici\u00eancia Auditiva\">Defici\u00eancia Auditiva<\/option>\r\n<option value=\"Defici\u00eancia Intelectual\">Defici\u00eancia Intelectual<\/option>\r\n<option value=\"Defici\u00eancia Visual\">Defici\u00eancia Visual<\/option>\r\n<option value=\"Outro\">Outro<\/option>\r\n<\/select>\r\n<\/label>\r\n\r\n<label style=\"display:flex;gap:10px;align-items:flex-start;padding:10px 12px;border:1px solid rgba(60,64,67,.12);border-radius:14px;background:#fff;\">\r\n<input name=\"apenas_palavras\" type=\"checkbox\" value=\"1\" style=\"margin-top:3px;\">\r\n<span style=\"font-size:12px;color:#3c4043;line-height:1.3;\">\r\nDesejo contribuir apenas com palavras <b>(op\u00e7\u00e3o para pessoas que n\u00e3o conseguem falar frases)<\/b>.\r\n<\/span>\r\n<\/label>\r\n\r\n<label style=\"display:flex;gap:10px;align-items:flex-start;padding:10px 12px;border:1px solid rgba(60,64,67,.12);border-radius:14px;background:#fff;\">\r\n<input name=\"aceite_termos\" type=\"checkbox\" value=\"1\" required style=\"margin-top:3px;\">\r\n<span style=\"font-size:12px;color:#3c4043;line-height:1.3;\">\r\nDeclaro que li e aceito o <a class=\"sdv-termo-link\" href=\"https:\/\/sites.usp.br\/sofiafala\/wp-content\/uploads\/sites\/1551\/2026\/05\/TCLE_e_TCUISV_corrigido.pdf.pdf\" target=\"_blank\" rel=\"noopener noreferrer\">TCLE e Termo de Consentimento de Uso de Imagem, Som e Voz<\/a>.\r\n<\/span>\r\n<\/label>\r\n\r\n<div style=\"display:flex;justify-content:center;gap:10px;margin-top:8px;flex-wrap:wrap;\">\r\n<button type=\"button\" id=\"btnVoltarHome\" class=\"sdv-btn\">\r\nVoltar\r\n<\/button>\r\n\r\n<button type=\"submit\" id=\"btnContinuar\"\r\nclass=\"sdv-btn sdv-btn-primary sdv-btn-disabled\"\r\nstyle=\"min-width:160px;\"\r\ndisabled>\r\nContinuar\r\n<\/button>\r\n<\/div>\r\n\r\n<div id=\"msgCadastro\" style=\"min-height:22px;text-align:center;\"><\/div>\r\n<\/form>\r\n<\/div>\r\n\r\n<div id=\"etapaVideo\" style=\"display:none;margin-top:16px;\">\r\n\r\n<div id=\"thanksScreen\" class=\"sdv-thanks\">\r\n<h2>Obrigado!<\/h2>\r\n<p>Sua doa\u00e7\u00e3o foi muito importante para o projeto SofiaFala.<br>Se quiser, voc\u00ea pode voltar para a p\u00e1gina inicial.<\/p>\r\n<div style=\"display:flex;justify-content:center;gap:10px;flex-wrap:wrap;\">\r\n<button type=\"button\" id=\"btnThanksHome\" class=\"sdv-btn sdv-btn-primary\"\r\nstyle=\"padding:12px 18px;border-radius:999px;cursor:pointer;min-width:260px;\">\r\nVoltar para a p\u00e1gina inicial\r\n<\/button>\r\n<\/div>\r\n<\/div>\r\n\r\n<div id=\"mainDonationFlow\">\r\n\r\n<div class=\"sdv-mode-wrap sdv-card\">\r\n<h3 class=\"sdv-mode-title\">Escolha o que ser\u00e1 gravado<\/h3>\r\n<div class=\"sdv-mode-btns\">\r\n<button type=\"button\" id=\"btnModePalavra\" class=\"sdv-btn\">Palavra<\/button>\r\n<button type=\"button\" id=\"btnModeFrase\" class=\"sdv-btn\">Frase<\/button>\r\n<\/div>\r\n\r\n<div class=\"sdv-divider\"><\/div>\r\n\r\n<div class=\"sdv-prompt\">\r\n<div class=\"sdv-refresh-wrap\">\r\n<button type=\"button\" id=\"btnRefreshItem\" class=\"sdv-refresh\" title=\"Trocar palavra\/frase\">\r\n<svg viewBox=\"0 0 24 24\" fill=\"none\" aria-hidden=\"true\">\r\n<path d=\"M20 12a8 8 0 1 1-2.34-5.66\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\"\/>\r\n<path d=\"M20 4v6h-6\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"\/>\r\n<\/svg>\r\n<\/button>\r\n<span class=\"sdv-refresh-label\">Trocar palavra\/frase<\/span>\r\n<\/div>\r\n\r\n<div id=\"promptTitle\" class=\"w\" style=\"display:none;\"><\/div>\r\n\r\n<div style=\"display:flex;justify-content:center;margin:12px 0 8px;\">\r\n<img decoding=\"async\" id=\"promptImage\" src=\"\" alt=\"\" style=\"display:none;max-width:100%;width:100%;max-width:420px;max-height:240px;object-fit:cover;border-radius:18px;border:1px solid rgba(60,64,67,.12);box-shadow:0 1px 2px rgba(60,64,67,.08), 0 2px 8px rgba(60,64,67,.08);\">\r\n<\/div>\r\n\r\n<p id=\"promptSub\" class=\"s\" style=\"display:none;\">Repita em voz alta e grave o v\u00eddeo.<\/p>\r\n<p id=\"promptHint\" class=\"s\" style=\"color:#5f6368;margin-top:8px;\">\r\nSelecione <b>Palavra<\/b> ou <b>Frase<\/b> para aparecer o texto a ser gravado.\r\n<\/p>\r\n\r\n<div class=\"sdv-prompt-actions\">\r\n<button type=\"button\" id=\"btnSpeakTop\" class=\"sdv-btn sdv-btn-primary\" style=\"min-width:240px;\">\r\n\u25b6 Ouvir\r\n<\/button>\r\n<\/div>\r\n\r\n<p id=\"ttsHintTop\" class=\"s\" style=\"color:#5f6368;margin-top:8px;display:none;\">\r\nSe n\u00e3o tocar automaticamente, toque uma vez em <b>Ouvir<\/b> (alguns celulares exigem intera\u00e7\u00e3o).\r\n<\/p>\r\n<\/div>\r\n<\/div>\r\n\r\n<div id=\"painelCamera\" class=\"sdv-card\" style=\"padding:16px;max-width:760px;margin:0 auto;\">\r\n<div id=\"ctaBeforeCam\" class=\"sdv-cta\">\r\n<strong>Primeiro, ative a c\u00e2mera para come\u00e7ar<\/strong>\r\n<span>Depois voc\u00ea repete a palavra\/frase e grava o v\u00eddeo.<\/span>\r\n<\/div>\r\n\r\n<video id=\"srcVideo\" playsinline autoplay muted\r\nstyle=\"position:absolute;left:-9999px;top:-9999px;width:1px;height:1px;opacity:0;\"><\/video>\r\n\r\n<div id=\"preCameraStage\" class=\"sdv-fade-in\">\r\n<div style=\"display:flex;justify-content:center;\">\r\n<button type=\"button\" id=\"btnAtivarCam\"\r\nclass=\"sdv-btn sdv-btn-primary\"\r\nstyle=\"min-width:280px;font-size:16px;padding:12px 18px;\">\r\nAtivar c\u00e2mera\r\n<\/button>\r\n<\/div>\r\n<\/div>\r\n\r\n<div id=\"cameraStage\" style=\"display:none;\" class=\"sdv-fade-in\">\r\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:10px;gap:10px;flex-wrap:wrap;\">\r\n<div id=\"recPill\" class=\"sdv-pill\" style=\"display:none;\">\r\n<div class=\"sdv-rec-dot\"><\/div>\r\n<strong style=\"letter-spacing:.6px;\">REC<\/strong>\r\n<span id=\"recTime\" style=\"font-variant-numeric: tabular-nums;\">00:00<\/span>\r\n<\/div>\r\n\r\n<div id=\"hintPill\" class=\"sdv-pill\">\r\n<span style=\"color:#202124;font-weight:800;\">Dica:<\/span>\r\n<span style=\"color:#5f6368;font-weight:700;\">posicione a crian\u00e7a no centro e grave em ambiente iluminado.<\/span>\r\n<\/div>\r\n<\/div>\r\n\r\n<canvas id=\"maskCanvas\" class=\"sdv-visor\"><\/canvas>\r\n\r\n<div id=\"underBar\" class=\"sdv-underbar\" style=\"display:none;\">\r\n<div class=\"sdv-underbar-row\">\r\n<p id=\"underText\" class=\"sdv-underbar-text\"><\/p>\r\n<div class=\"sdv-underbar-actions\">\r\n<button type=\"button\" id=\"btnSpeak\" class=\"sdv-btn sdv-btn-primary\">\u25b6 Ouvir<\/button>\r\n<button type=\"button\" id=\"btnSkip\" class=\"sdv-btn\">Trocar<\/button>\r\n<\/div>\r\n<\/div>\r\n<p class=\"sdv-underbar-sub\">Se n\u00e3o tocar automaticamente, toque em \u201cOuvir\u201d (alguns celulares exigem intera\u00e7\u00e3o).<\/p>\r\n<\/div>\r\n\r\n<div style=\"display:flex;gap:10px;flex-wrap:wrap;margin-top:12px;justify-content:center;\">\r\n<button type=\"button\" id=\"btnRecStart\"\r\nclass=\"sdv-btn sdv-btn-danger\"\r\nstyle=\"min-width:190px;border-radius:999px;\">\r\n\u25cf Iniciar grava\u00e7\u00e3o\r\n<\/button>\r\n\r\n<button type=\"button\" id=\"btnRecStop\"\r\nclass=\"sdv-btn\"\r\nstyle=\"min-width:190px;border-radius:999px;background:#202124;color:#fff;border-color:transparent;display:none;\">\r\nParar grava\u00e7\u00e3o\r\n<\/button>\r\n<\/div>\r\n<\/div>\r\n\r\n<div id=\"postStage\" style=\"display:none;margin-top:12px;\" class=\"sdv-fade-in\">\r\n<h4 style=\"margin:10px 0 8px;text-align:center;font-weight:900;color:#202124;\">Rever sua grava\u00e7\u00e3o<\/h4>\r\n<video id=\"playback\" controls class=\"sdv-visor\" style=\"max-height:360px;\"><\/video>\r\n\r\n<div style=\"display:flex;gap:10px;flex-wrap:wrap;margin-top:12px;justify-content:center;\">\r\n<button type=\"button\" id=\"btnRetry\" class=\"sdv-btn\" style=\"min-width:200px;\">\r\nTentar novamente\r\n<\/button>\r\n\r\n<button type=\"button\" id=\"btnEnviarGravacao\" class=\"sdv-btn sdv-btn-success\" style=\"min-width:200px;\">\r\nEnviar v\u00eddeo\r\n<\/button>\r\n<\/div>\r\n<\/div>\r\n<\/div>\r\n\r\n<div id=\"msgVideo\" style=\"min-height:22px;margin-top:12px;text-align:center;\"><\/div>\r\n\r\n<div style=\"display:flex;justify-content:center;margin-top:12px;\">\r\n<button type=\"button\" id=\"btnVoltarCadastro\" class=\"sdv-btn\">\r\nVoltar para cadastro\r\n<\/button>\r\n<\/div>\r\n\r\n<\/div>\r\n\r\n<input type=\"hidden\" id=\"nonce\" value=\"26bc4d910d\">\r\n<input type=\"hidden\" id=\"ajax\" value=\"https:\/\/sites.usp.br\/sofiafala\/wp-admin\/admin-ajax.php\">\r\n<input type=\"hidden\" id=\"homeUrl\" value=\"https:\/\/sites.usp.br\/sofiafala\/\">\r\n<\/div>\r\n\r\n<div id=\"sdvModalBackdrop\" class=\"sdv-modal-backdrop\" aria-hidden=\"true\">\r\n<div class=\"sdv-modal\" role=\"dialog\" aria-modal=\"true\">\r\n<div class=\"sdv-modal-header\">\r\n<h3 class=\"sdv-modal-title\">V\u00eddeo enviado<\/h3>\r\n<button type=\"button\" id=\"btnModalClose\" class=\"sdv-btn\" style=\"padding:8px 12px;\">Fechar<\/button>\r\n<\/div>\r\n<div class=\"sdv-modal-body\">\r\n<p id=\"modalMsg\">Pronto! O que voc\u00ea quer gravar agora?<\/p>\r\n<div class=\"sdv-modal-actions\">\r\n<button type=\"button\" id=\"btnNextPalavra\" class=\"sdv-btn sdv-next-word\">Pr\u00f3xima palavra<\/button>\r\n<button type=\"button\" id=\"btnNextFrase\" class=\"sdv-btn sdv-next-phrase\">Pr\u00f3xima frase<\/button>\r\n<button type=\"button\" id=\"btnStopDonation\" class=\"sdv-btn sdv-stop\">Parar doa\u00e7\u00e3o<\/button>\r\n<\/div>\r\n<\/div>\r\n<\/div>\r\n<\/div>\r\n\r\n<\/div>\r\n<\/div>\r\n\r\n<script src=\"https:\/\/cdn.jsdelivr.net\/npm\/@mediapipe\/face_mesh\/face_mesh.js\"><\/script>\r\n<script src=\"https:\/\/cdn.jsdelivr.net\/npm\/@mediapipe\/selfie_segmentation\/selfie_segmentation.js\"><\/script>\r\n\r\n<script>\r\n(function () {\r\nconst ajax = document.getElementById(\"ajax\").value;\r\nconst nonce = document.getElementById(\"nonce\").value;\r\nconst homeUrl = document.getElementById(\"homeUrl\").value;\r\n\r\nconst etapaCadastro = document.getElementById(\"etapaCadastro\");\r\nconst etapaVideo = document.getElementById(\"etapaVideo\");\r\nconst stepDot1 = document.getElementById(\"stepDot1\");\r\nconst stepDot2 = document.getElementById(\"stepDot2\");\r\n\r\nconst mainDonationFlow = document.getElementById(\"mainDonationFlow\");\r\nconst thanksScreen = document.getElementById(\"thanksScreen\");\r\nconst btnThanksHome = document.getElementById(\"btnThanksHome\");\r\n\r\nconst msgCadastro = document.getElementById(\"msgCadastro\");\r\nconst msgVideo = document.getElementById(\"msgVideo\");\r\n\r\nconst palavras = {\"1\":\"Abelha\",\"2\":\"Agulha\",\"3\":\"Alho\",\"4\":\"Amarelo\",\"5\":\"Amora\",\"6\":\"Bacia\",\"7\":\"Bailarina\",\"8\":\"Bala\",\"9\":\"Balan\u00e7o\",\"10\":\"Bal\u00e3o\",\"11\":\"Cachorro\",\"12\":\"Cadeado\",\"13\":\"Cadeira\",\"14\":\"Caf\u00e9\",\"15\":\"Cafeteira\",\"16\":\"Dedo\",\"17\":\"Degrau\",\"18\":\"Dentadura\",\"19\":\"Dente\",\"20\":\"Dentista\",\"21\":\"Deserto\",\"22\":\"Ervilha\",\"23\":\"Espelho\",\"24\":\"Faca\",\"25\":\"Fama\",\"26\":\"Fam\u00edlia\",\"27\":\"Fantasma\",\"28\":\"Farinha\",\"29\":\"Gado\",\"30\":\"Gafanhoto\",\"31\":\"Gaiola\",\"32\":\"Galho\",\"33\":\"Galinha\",\"34\":\"Ilha\",\"35\":\"Jabuticaba\",\"36\":\"Jaca\",\"37\":\"Jacar\u00e9\",\"38\":\"Jaleco\",\"39\":\"Janela\",\"40\":\"Lagartixa\",\"41\":\"Lagarto\",\"42\":\"Lago\",\"43\":\"Lagosta\",\"44\":\"Lama\",\"45\":\"Maca\",\"46\":\"Macaco\",\"47\":\"Macarr\u00e3o\",\"48\":\"Madeira\",\"49\":\"M\u00e3e\",\"50\":\"Nadador\",\"51\":\"Namora\",\"52\":\"N\u00e3o\",\"53\":\"Nariz\",\"54\":\"Nascer\",\"55\":\"Pa\u00e7oca\",\"56\":\"Pai\",\"57\":\"Palha\",\"58\":\"Palha\u00e7o\",\"59\":\"Pamonha\",\"60\":\"R\u00e1dio\",\"61\":\"Rainha\",\"62\":\"Raio\",\"63\":\"Ralo\",\"64\":\"Raposa\",\"65\":\"Sab\u00e3o\",\"66\":\"Sabonete\",\"67\":\"Saci\",\"68\":\"Saco\",\"69\":\"Saia\",\"70\":\"Ta\u00e7a\",\"71\":\"Tambor\",\"72\":\"Tapete\",\"73\":\"Tartaruga\",\"74\":\"Tatu\",\"75\":\"Unha\",\"76\":\"Urubu\",\"77\":\"Vaca\",\"78\":\"Vagalume\",\"79\":\"Vag\u00e3o\",\"80\":\"Vale\",\"81\":\"Vara\",\"82\":\"Xadrez\",\"83\":\"Xale\",\"84\":\"Xampu\",\"85\":\"Xarope\",\"86\":\"Xaxim\",\"87\":\"Zang\u00e3o\",\"88\":\"Zebra\",\"89\":\"Zebu\",\"90\":\"Zelador\",\"91\":\"Zero\",\"92\":\"Z\u00edper\",\"93\":\"\u00c2ncora\",\"94\":\"Baleia\",\"95\":\"Cabra\",\"96\":\"Damasco\",\"97\":\"Farofa\",\"98\":\"Garrafa\",\"99\":\"Jesus\",\"100\":\"Molho\"};\r\nconst frases = {\"1\":\"Gosto de jogar peteca com minha irm\u00e3\",\"2\":\"O palha\u00e7o tem nariz vermelho\",\"3\":\"Jo\u00e3o caminhou na praia calmamente\",\"4\":\"O problema \u00e9 que estou com fraqueza\",\"5\":\"Zeca, corra bem r\u00e1pido pra igreja\",\"6\":\"A pesca \u00e9 proibida nesse canto\",\"7\":\"O casar\u00e3o foi vendido sem pressa\",\"8\":\"A chupeta da menina \u00e9 amarela\",\"9\":\"O travesseiro \u00e9 fofo e leve\",\"10\":\"N\u00e3o gosto de frutas vermelhas\",\"11\":\"O elefante correu atr\u00e1s da lebre\",\"12\":\"Voc\u00ea gosta de sorvete de abacaxi?\",\"13\":\"Esses s\u00e3o nossos bebezinhos\",\"14\":\"Jo\u00e3o deu dinheiro pro seu pai comprar um jogo\",\"15\":\"Vi Z\u00e9 fazer essas viagens seis vezes\",\"16\":\"A pesca \u00e9 proibida\",\"17\":\"Analfabetismo \u00e9 um problema chato\",\"18\":\"Agindo sem pressa acertamos mais\",\"19\":\"Recebi meu pai pra almo\u00e7ar\",\"20\":\"Trabalho \u00e9 a vida do povo\",\"21\":\"Isso se resolver\u00e1 de maneira tranquila\",\"22\":\"Os pesquisadores n\u00e3o acreditam nessa hist\u00f3ria\",\"23\":\"Nosso telefone est\u00e1 mudo\",\"24\":\"Desculpe se te chamo de velho\",\"25\":\"Ela n\u00e3o tem fome quando sai de casa\",\"26\":\"Preciso preservar a flora porque a natureza \u00e9 linda!\",\"27\":\"Neste caso, a gente fica mais tranquilo\",\"28\":\"Foi muito dif\u00edcil entender a can\u00e7\u00e3o de natal\",\"29\":\"Ainda n\u00e3o se sabe o dia da prova\",\"30\":\"A escurid\u00e3o do quarto assustou a crian\u00e7a\",\"31\":\"Minha m\u00e3e n\u00e3o quer ir pro shopping\",\"32\":\"O gramado est\u00e1 florido\",\"33\":\"Ser\u00e1 que hoje tem arroz com bife?\",\"34\":\"Ainda faltam seis minutos\",\"35\":\"Ela seguia discretamente\",\"36\":\"Hoje, eu n\u00e3o pude fazer minha gin\u00e1stica\",\"37\":\"\u00c9 poss\u00edvel que ele j\u00e1 esteja fora de perigo\",\"38\":\"Depois do almo\u00e7o te encontro pro ch\u00e1\",\"39\":\"Quero te ver bem quando ele voltar l\u00e1\",\"40\":\"Tenho muito orgulho do nosso gerente\",\"41\":\"O inspetor faz a vistoria completa\",\"42\":\"Ser\u00e1 muito dif\u00edcil conseguir que voltem\",\"43\":\"Voc\u00ea quer me dizer a data?\",\"44\":\"Desculpe, mas me atrasei no casamento\",\"45\":\"Faz um desvio em dire\u00e7\u00e3o ao mar\",\"46\":\"O velho tigre ainda aceita combate\",\"47\":\"\u00c9 hora do homem se humanizar mais\",\"48\":\"Ela ficou na fazenda por uma hora\",\"49\":\"Hoje irei precisar de voc\u00ea\",\"50\":\"Em ele o tempo flui num ritmo suave\"};\r\nconst distMap = {\"Altera\u00e7\u00e3o de fala em crian\u00e7a\\\/articula\u00e7\u00e3o\\\/apraxia\\\/disartria\":\"01\",\"S\u00edndrome de Down (T21)\":\"02\",\"Transtorno do Espectro Autista (TEA)\":\"03\",\"Acidente Vascular Cerebral (AVC)\":\"04\",\"Defici\u00eancia Auditiva\":\"05\",\"Defici\u00eancia Intelectual\":\"06\",\"Defici\u00eancia Visual\":\"07\",\"Outro\":\"08\"};\r\nconst buscaPalavras = {\"1\":\"bee insect\",\"2\":\"sewing needle\",\"3\":\"garlic bulb\",\"4\":\"yellow object\",\"5\":\"blackberry fruit\",\"6\":\"wash basin\",\"7\":\"ballerina dancer\",\"8\":\"candy sweet\",\"9\":\"playground swing\",\"10\":\"balloon\",\"11\":\"dog\",\"12\":\"padlock lock\",\"13\":\"chair\",\"14\":\"coffee cup\",\"15\":\"coffee pot\",\"16\":\"finger hand\",\"17\":\"stair step\",\"18\":\"dentures\",\"19\":\"tooth\",\"20\":\"dentist\",\"21\":\"desert landscape\",\"22\":\"peas vegetable\",\"23\":\"mirror\",\"24\":\"knife\",\"25\":\"famous celebrity\",\"26\":\"family\",\"27\":\"ghost costume\",\"28\":\"flour baking\",\"29\":\"cattle cow\",\"30\":\"grasshopper insect\",\"31\":\"bird cage\",\"32\":\"tree branch\",\"33\":\"chicken hen\",\"34\":\"island\",\"35\":\"jabuticaba fruit\",\"36\":\"jackfruit\",\"37\":\"alligator crocodile\",\"38\":\"lab coat\",\"39\":\"window\",\"40\":\"gecko lizard\",\"41\":\"lizard\",\"42\":\"lake\",\"43\":\"lobster\",\"44\":\"mud\",\"45\":\"hospital stretcher\",\"46\":\"monkey\",\"47\":\"pasta macaroni\",\"48\":\"wood plank\",\"49\":\"mother woman\",\"50\":\"swimmer\",\"51\":\"romantic couple\",\"52\":\"no sign\",\"53\":\"nose\",\"54\":\"newborn baby\",\"55\":\"peanut candy\",\"56\":\"father man\",\"57\":\"straw hay\",\"58\":\"clown\",\"59\":\"corn food\",\"60\":\"radio device\",\"61\":\"queen crown\",\"62\":\"lightning\",\"63\":\"sink drain\",\"64\":\"fox\",\"65\":\"soap bar\",\"66\":\"soap bar\",\"67\":\"brazilian folklore character\",\"68\":\"bag sack\",\"69\":\"skirt clothing\",\"70\":\"cup trophy\",\"71\":\"drum instrument\",\"72\":\"carpet rug\",\"73\":\"turtle\",\"74\":\"armadillo\",\"75\":\"fingernail\",\"76\":\"vulture bird\",\"77\":\"cow\",\"78\":\"firefly insect\",\"79\":\"train wagon\",\"80\":\"valley landscape\",\"81\":\"wooden stick\",\"82\":\"chess board pieces\",\"83\":\"shawl clothing\",\"84\":\"shampoo bottle\",\"85\":\"syrup bottle\",\"86\":\"fern plant\",\"87\":\"drone bee insect\",\"88\":\"zebra\",\"89\":\"zebu cattle\",\"90\":\"janitor cleaning\",\"91\":\"number zero\",\"92\":\"zipper closeup\",\"93\":\"anchor\",\"94\":\"whale\",\"95\":\"goat\",\"96\":\"apricot fruit\",\"97\":\"farofa food\",\"98\":\"bottle\",\"99\":\"jesus painting\",\"100\":\"sauce gravy\"};\r\nconst buscaFrases = {\"1\":\"children playing shuttlecock\",\"2\":\"clown red nose\",\"3\":\"man walking on beach\",\"4\":\"weak tired person\",\"5\":\"running to church\",\"6\":\"no fishing sign\",\"7\":\"old mansion house\",\"8\":\"girl with yellow pacifier\",\"9\":\"soft pillow bed\",\"10\":\"red fruits\",\"11\":\"elephant and hare\",\"12\":\"pineapple ice cream\",\"13\":\"babies\",\"14\":\"father son money video game\",\"15\":\"travel road trip\",\"16\":\"no fishing sign\",\"17\":\"illiteracy school reading\",\"18\":\"careful calm planning\",\"19\":\"family lunch father\",\"20\":\"people working\",\"21\":\"peaceful solution calm\",\"22\":\"scientists researchers\",\"23\":\"telephone\",\"24\":\"old man portrait\",\"25\":\"woman leaving home\",\"26\":\"forest nature flora\",\"27\":\"calm relaxed people\",\"28\":\"christmas song choir\",\"29\":\"exam date calendar\",\"30\":\"dark room scared child\",\"31\":\"mother shopping mall\",\"32\":\"flowering lawn garden\",\"33\":\"rice steak meal\",\"34\":\"clock six minutes\",\"35\":\"walking discreetly person\",\"36\":\"gym exercise\",\"37\":\"hospital recovery patient\",\"38\":\"tea after lunch\",\"39\":\"waiting for return home\",\"40\":\"office manager portrait\",\"41\":\"inspector inspection\",\"42\":\"people returning home\",\"43\":\"calendar date\",\"44\":\"late wedding couple\",\"45\":\"road detour sea\",\"46\":\"old tiger\",\"47\":\"human empathy people\",\"48\":\"farm countryside hour\",\"49\":\"help support friend\",\"50\":\"time flowing calm concept\"};\r\n\r\nconst MAX_P = 100;\r\nconst MAX_F = 50;\r\n\r\nlet cadastro = null;\r\nlet mode = null;\r\nlet idxP = 1;\r\nlet idxF = 1;\r\nlet individuo = null;\r\nlet videoNo = 1;\r\nlet lastUploadOk = false;\r\n\r\nfunction setMsg(el, text, ok){\r\nel.textContent = text || \"\";\r\nel.style.color = ok ? \"#188038\" : \"#d93025\";\r\n}\r\nfunction pad2(n){ return String(n).padStart(2,'0'); }\r\nfunction pad6(n){ return String(n).padStart(6,'0'); }\r\n\r\nfunction getOrCreateIndividuo(){\r\nconst key = \"sofia_sdv_individuo\";\r\nlet v = localStorage.getItem(key);\r\nif (!v || !\/^\\d{6}$\/.test(v)){\r\nv = pad6(Math.floor(1 + Math.random()*999999));\r\nlocalStorage.setItem(key, v);\r\n}\r\nreturn v;\r\n}\r\nfunction getOrCreateVideoNo(){\r\nconst key = \"sofia_sdv_video_no\";\r\nlet v = parseInt(localStorage.getItem(key) || \"1\", 10);\r\nif (!Number.isFinite(v) || v < 1) v = 1;\r\nreturn v;\r\n}\r\nfunction setVideoNo(v){ localStorage.setItem(\"sofia_sdv_video_no\", String(v)); }\r\n\r\nindividuo = getOrCreateIndividuo();\r\nvideoNo = getOrCreateVideoNo();\r\n\r\nfunction sentKey(which){ return \"sofia_sdv_sent_\" + which + \"_\" + individuo; }\r\nfunction loadSent(which){\r\ntry{\r\nconst raw = localStorage.getItem(sentKey(which));\r\nif (!raw) return {};\r\nconst obj = JSON.parse(raw);\r\nreturn (obj && typeof obj === \"object\") ? obj : {};\r\n}catch(e){ return {}; }\r\n}\r\nfunction saveSent(which, obj){\r\ntry{ localStorage.setItem(sentKey(which), JSON.stringify(obj || {})); }catch(e){}\r\n}\r\nfunction markSent(which, idx){\r\nconst s = loadSent(which);\r\ns[String(idx)] = 1;\r\nsaveSent(which, s);\r\n}\r\nfunction isSent(which, idx){\r\nconst s = loadSent(which);\r\nreturn !!s[String(idx)];\r\n}\r\nfunction getUnsentList(which){\r\nconst max = (which === \"P\") ? MAX_P : MAX_F;\r\nconst out = [];\r\nfor (let i = 1; i <= max; i++) {\r\nif (!isSent(which, i)) out.push(i);\r\n}\r\nreturn out;\r\n}\r\nfunction getRandomFromArray(arr){\r\nif (!arr || !arr.length) return null;\r\nreturn arr[Math.floor(Math.random() * arr.length)];\r\n}\r\nfunction getRandomUnsent(which){\r\nconst list = getUnsentList(which);\r\nreturn getRandomFromArray(list);\r\n}\r\nfunction getRandomUnsentExcludingCurrent(which, current){\r\nconst list = getUnsentList(which).filter(n => n !== current);\r\nif (!list.length) {\r\nif (current && !isSent(which, current)) return current;\r\nreturn null;\r\n}\r\nreturn getRandomFromArray(list);\r\n}\r\n\r\nconst ctaBeforeCam = document.getElementById(\"ctaBeforeCam\");\r\nconst preCameraStage = document.getElementById(\"preCameraStage\");\r\nconst cameraStage = document.getElementById(\"cameraStage\");\r\nconst postStage = document.getElementById(\"postStage\");\r\n\r\nconst srcVideo = document.getElementById(\"srcVideo\");\r\nconst canvas = document.getElementById(\"maskCanvas\");\r\nconst ctx = canvas.getContext(\"2d\");\r\n\r\nconst playback = document.getElementById(\"playback\");\r\n\r\nconst btnAtivarCam = document.getElementById(\"btnAtivarCam\");\r\nconst btnRecStart = document.getElementById(\"btnRecStart\");\r\nconst btnRecStop = document.getElementById(\"btnRecStop\");\r\nconst btnEnviarGravacao = document.getElementById(\"btnEnviarGravacao\");\r\nconst btnRetry = document.getElementById(\"btnRetry\");\r\n\r\nconst underBar = document.getElementById(\"underBar\");\r\nconst underText = document.getElementById(\"underText\");\r\nconst btnSpeak = document.getElementById(\"btnSpeak\");\r\nconst btnSkip = document.getElementById(\"btnSkip\");\r\n\r\nconst recPill = document.getElementById(\"recPill\");\r\nconst recTime = document.getElementById(\"recTime\");\r\nconst hintPill = document.getElementById(\"hintPill\");\r\n\r\nconst btnModePalavra = document.getElementById(\"btnModePalavra\");\r\nconst btnModeFrase = document.getElementById(\"btnModeFrase\");\r\nconst promptTitle = document.getElementById(\"promptTitle\");\r\nconst promptSub = document.getElementById(\"promptSub\");\r\nconst promptHint = document.getElementById(\"promptHint\");\r\nconst btnRefreshItem = document.getElementById(\"btnRefreshItem\");\r\nconst btnSpeakTop = document.getElementById(\"btnSpeakTop\");\r\nconst ttsHintTop = document.getElementById(\"ttsHintTop\");\r\nconst promptImage = document.getElementById(\"promptImage\");\r\n\r\nfunction getPromptText(){\r\nif (!mode) return \"\";\r\nif (mode === \"P\") return String(palavras[idxP] || (\"Palavra \" + idxP));\r\nif (mode === \"F\") return String(frases[idxF] || (\"Frase \" + idxF));\r\nreturn \"\";\r\n}\r\n\r\nfunction getPromptSearchQuery(){\r\nif (!mode) return \"\";\r\nif (mode === \"P\") return String(buscaPalavras[idxP] || getPromptText());\r\nif (mode === \"F\") return String(buscaFrases[idxF] || getPromptText());\r\nreturn \"\";\r\n}\r\n\r\nlet preferredVoice = null;\r\nfunction ttsAvailable(){ return !!(window.speechSynthesis && window.SpeechSynthesisUtterance); }\r\nfunction loadVoices(){\r\nif (!ttsAvailable()) return;\r\nconst vs = window.speechSynthesis.getVoices() || [];\r\nif (!vs.length) return;\r\npreferredVoice = vs.find(v => (v.lang || \"\").toLowerCase() === \"pt-br\")\r\n|| vs.find(v => (v.lang || \"\").toLowerCase().startsWith(\"pt\"))\r\n|| vs[0] || null;\r\n}\r\nif (ttsAvailable()){\r\nloadVoices();\r\nwindow.speechSynthesis.onvoiceschanged = () => loadVoices();\r\n} else {\r\nbtnSpeakTop.style.display = \"none\";\r\nbtnSpeak.style.display = \"none\";\r\nttsHintTop.style.display = \"none\";\r\n}\r\nfunction stopSpeak(){ if (ttsAvailable()) { try{ window.speechSynthesis.cancel(); }catch(e){} } }\r\nfunction speak(text){\r\nif (!ttsAvailable() || !text) return;\r\ntry{\r\nstopSpeak();\r\nconst u = new SpeechSynthesisUtterance(text);\r\nu.rate = 0.95; u.pitch = 1.0; u.volume = 1.0;\r\nif (preferredVoice) u.voice = preferredVoice;\r\nu.lang = (preferredVoice && preferredVoice.lang) ? preferredVoice.lang : \"pt-BR\";\r\nwindow.speechSynthesis.speak(u);\r\n} catch(e){}\r\n}\r\nbtnSpeakTop.onclick = () => speak(getPromptText());\r\nbtnSpeak.onclick = () => speak(getPromptText());\r\n\r\nfunction isApenasPalavras(){\r\nreturn !!(cadastro && String(cadastro.apenas_palavras || \"0\") === \"1\");\r\n}\r\n\r\nfunction applyApenasPalavrasUI(){\r\nconst only = isApenasPalavras();\r\nif (btnModeFrase){\r\nbtnModeFrase.disabled = only;\r\nbtnModeFrase.style.display = only ? \"none\" : \"inline-block\";\r\n}\r\nconst modalNextFrase = document.getElementById(\"btnNextFrase\");\r\nif (modalNextFrase){\r\nmodalNextFrase.style.display = only ? \"none\" : \"block\";\r\n}\r\nconst refreshLabel = document.querySelector(\".sdv-refresh-label\");\r\nif (refreshLabel){\r\nrefreshLabel.textContent = only ? \"Trocar palavra\" : \"Trocar palavra\/frase\";\r\n}\r\nif (ctaBeforeCam){\r\nconst ctaSpan = ctaBeforeCam.querySelector(\"span\");\r\nif (ctaSpan){\r\nctaSpan.textContent = only ? \"Depois voc\u00ea repete a palavra e grava o v\u00eddeo.\" : \"Depois voc\u00ea repete a palavra\/frase e grava o v\u00eddeo.\";\r\n}\r\n}\r\nif (mode === \"F\" && only){\r\nmode = null;\r\n}\r\n}\r\n\r\n\r\nconst imageCache = {};\r\nasync function fetchOpenverseImage(query){\r\nif (!query) return \"\";\r\nif (imageCache[query]) return imageCache[query];\r\n\r\nconst url = \"https:\/\/api.openverse.org\/v1\/images\/?q=\" + encodeURIComponent(query) + \"&page_size=1\";\r\nconst res = await fetch(url);\r\nif (!res.ok) throw new Error(\"Falha ao buscar imagem\");\r\nconst data = await res.json();\r\n\r\nconst img = data && data.results && data.results[0] ? data.results[0] : null;\r\nconst out = img ? (img.thumbnail || img.url || \"\") : \"\";\r\nimageCache[query] = out;\r\nreturn out;\r\n}\r\n\r\nlet promptRenderToken = 0;\r\n\r\nasync function renderPrompt(){\r\nconst token = ++promptRenderToken;\r\n\r\nif (!mode){\r\npromptTitle.style.display = \"none\";\r\npromptSub.style.display = \"none\";\r\npromptHint.style.display = \"block\";\r\nbtnSpeakTop.disabled = true;\r\nttsHintTop.style.display = \"none\";\r\nunderBar.style.display = \"none\";\r\n\r\nif (promptImage){\r\npromptImage.style.display = \"none\";\r\npromptImage.removeAttribute(\"src\");\r\npromptImage.alt = \"\";\r\n}\r\nreturn;\r\n}\r\n\r\nconst txt = getPromptText();\r\nconst query = getPromptSearchQuery();\r\n\r\npromptTitle.textContent = txt;\r\npromptTitle.style.display = \"block\";\r\npromptSub.style.display = \"block\";\r\npromptHint.style.display = \"none\";\r\nbtnSpeakTop.disabled = false;\r\nttsHintTop.style.display = \"block\";\r\nunderText.textContent = txt;\r\n\r\nif (promptImage){\r\npromptImage.style.display = \"none\";\r\npromptImage.removeAttribute(\"src\");\r\npromptImage.alt = txt;\r\n}\r\n\r\ntry{\r\nconst imgUrl = await fetchOpenverseImage(query);\r\nif (token !== promptRenderToken) return;\r\n\r\nif (promptImage && imgUrl){\r\npromptImage.src = imgUrl;\r\npromptImage.alt = txt;\r\npromptImage.style.display = \"block\";\r\n}\r\n} catch(e){\r\nif (token !== promptRenderToken) return;\r\nif (promptImage){\r\npromptImage.style.display = \"none\";\r\npromptImage.removeAttribute(\"src\");\r\n}\r\n}\r\n\r\nif (cameraStage.style.display !== \"none\") underBar.style.display = \"block\";\r\n}\r\n\r\nfunction setMode(newMode){\r\nif (newMode === \"F\" && isApenasPalavras()){\r\nsetMsg(msgVideo, \"Voc\u00ea marcou a op\u00e7\u00e3o de contribuir apenas com palavras.\", false);\r\nreturn;\r\n}\r\n\r\nmode = newMode;\r\napplyApenasPalavrasUI();\r\n\r\nconst first = getRandomUnsent(mode);\r\nif (first == null){\r\nsetMsg(msgVideo, \"Voc\u00ea j\u00e1 enviou todos os itens desse tipo. Obrigado!\", true);\r\nreturn;\r\n}\r\n\r\nif (mode === \"P\") idxP = first; else idxF = first;\r\n\r\nbtnModePalavra.classList.toggle(\"sdv-active\", mode===\"P\");\r\nbtnModeFrase.classList.toggle(\"sdv-active\", mode===\"F\");\r\n\r\nrenderPrompt();\r\nbtnRecStart.disabled = false;\r\nif (cameraStage.style.display !== \"none\") underBar.style.display = \"block\";\r\n}\r\n\r\nbtnModePalavra.onclick = () => setMode(\"P\");\r\nbtnModeFrase.onclick = () => setMode(\"F\");\r\nrenderPrompt();\r\n\r\nfunction canSwapNow(){\r\nif (!mode) return false;\r\nif (recorder && recorder.state && recorder.state !== \"inactive\") return false;\r\nreturn true;\r\n}\r\n\r\nfunction swapItemKeepCamera(){\r\nif (!mode) return setMsg(msgVideo, \"Selecione Palavra ou Frase primeiro.\", false);\r\nif (!canSwapNow()) return setMsg(msgVideo, \"Voc\u00ea n\u00e3o pode trocar enquanto est\u00e1 gravando.\", false);\r\n\r\nstopSpeak();\r\n\r\nconst current = (mode === \"P\") ? idxP : idxF;\r\nconst next = getRandomUnsentExcludingCurrent(mode, current);\r\n\r\nif (next == null){\r\nsetMsg(msgVideo, \"Voc\u00ea j\u00e1 enviou todos os itens desse tipo. Obrigado!\", true);\r\nreturn;\r\n}\r\n\r\nif (mode === \"P\") idxP = next; else idxF = next;\r\n\r\nif (postStage.style.display !== \"none\"){\r\npostStage.style.display = \"none\";\r\ncameraStage.style.display = (stream ? \"block\" : \"none\");\r\npreCameraStage.style.display = (stream ? \"none\" : \"block\");\r\nctaBeforeCam.style.display = (stream ? \"none\" : \"block\");\r\ntry{ playback.pause(); }catch(e){}\r\nplayback.removeAttribute(\"src\");\r\nplayback.load();\r\n}\r\n\r\nrenderPrompt();\r\nunderBar.style.display = (stream && cameraStage.style.display !== \"none\") ? \"block\" : \"none\";\r\nsetMsg(msgVideo, \"Item trocado. Pode continuar normalmente.\", true);\r\n}\r\n\r\nbtnRefreshItem.onclick = swapItemKeepCamera;\r\nbtnSkip.onclick = swapItemKeepCamera;\r\n\r\nconst dn = document.getElementById(\"data_nascimento\");\r\nif (dn){\r\nconst today = new Date();\r\nconst yyyy = today.getFullYear();\r\nconst mm = String(today.getMonth()+1).padStart(2,'0');\r\nconst dd = String(today.getDate()).padStart(2,'0');\r\ndn.max = `${yyyy}-${mm}-${dd}`;\r\n}\r\n\r\nconst formCadastro = document.getElementById(\"formCadastro\");\r\nconst btnContinuar = document.getElementById(\"btnContinuar\");\r\nconst aceite = formCadastro.querySelector('input[name=\"aceite_termos\"]');\r\n\r\nfunction refreshContinuar(){\r\nconst okForm = formCadastro.checkValidity();\r\nconst okTermos = aceite && aceite.checked;\r\nbtnContinuar.disabled = !(okForm && okTermos);\r\nbtnContinuar.classList.toggle(\"sdv-btn-disabled\", btnContinuar.disabled);\r\nbtnContinuar.style.cursor = btnContinuar.disabled ? \"not-allowed\" : \"pointer\";\r\n}\r\nformCadastro.addEventListener(\"input\", refreshContinuar);\r\nformCadastro.addEventListener(\"change\", refreshContinuar);\r\nrefreshContinuar();\r\n\r\ndocument.getElementById(\"btnVoltarHome\").onclick = () => window.location.href = homeUrl;\r\n\r\ndocument.getElementById(\"btnVoltarCadastro\").onclick = () => {\r\nstopSpeak();\r\nstopAllMedia();\r\ncloseModal();\r\nthanksScreen.style.display = \"none\";\r\nmainDonationFlow.style.display = \"block\";\r\n\r\netapaVideo.style.display = \"none\";\r\netapaCadastro.style.display = \"block\";\r\n\r\nstepDot1.style.background = \"#1a73e8\"; stepDot1.style.color=\"#fff\"; stepDot1.style.borderColor=\"transparent\";\r\nstepDot2.style.background = \"#fff\"; stepDot2.style.color=\"#1f2937\";\r\n\r\nsetMsg(msgVideo, \"\", true);\r\n};\r\n\r\nbtnThanksHome.onclick = () => window.location.href = homeUrl;\r\n\r\nformCadastro.addEventListener(\"submit\", (e) => {\r\ne.preventDefault();\r\nsetMsg(msgCadastro, \"\", true);\r\n\r\nif (dn && dn.value){\r\nconst chosen = new Date(dn.value + \"T00:00:00\");\r\nconst now = new Date(); now.setHours(0,0,0,0);\r\nif (chosen > now){\r\nsetMsg(msgCadastro, \"A data de nascimento n\u00e3o pode ser no futuro.\", false);\r\nreturn;\r\n}\r\n}\r\n\r\nconst fd = new FormData(formCadastro);\r\ncadastro = {};\r\nfd.forEach((v,k) => { cadastro[k] = v; });\r\nif (!cadastro.apenas_palavras) cadastro.apenas_palavras = \"0\";\r\n\r\nif (!cadastro.aceite_termos){\r\nsetMsg(msgCadastro, \"Voc\u00ea precisa aceitar os termos.\", false);\r\nreturn;\r\n}\r\n\r\netapaCadastro.style.display = \"none\";\r\netapaVideo.style.display = \"block\";\r\n\r\nstepDot1.style.background = \"#fff\"; stepDot1.style.color=\"#1f2937\"; stepDot1.style.borderColor=\"rgba(60,64,67,.12)\";\r\nstepDot2.style.background = \"#1a73e8\"; stepDot2.style.color=\"#fff\"; stepDot2.style.borderColor=\"transparent\";\r\n\r\nthanksScreen.style.display = \"none\";\r\nmainDonationFlow.style.display = \"block\";\r\n\r\nsetMsg(msgVideo, \"\", true);\r\nresetCameraUIHard();\r\nlastUploadOk = false;\r\ncloseModal();\r\napplyApenasPalavrasUI();\r\nif (isApenasPalavras()){\r\nsetMode(\"P\");\r\n} else {\r\nrenderPrompt();\r\n}\r\n});\r\n\r\nasync function enviarVideo(file){\r\nif (!cadastro) throw new Error(\"Voc\u00ea precisa preencher o cadastro antes.\");\r\nif (!mode) throw new Error(\"Selecione Palavra ou Frase antes de enviar.\");\r\nif (mode === \"F\" && isApenasPalavras()) throw new Error(\"Voc\u00ea marcou a op\u00e7\u00e3o de contribuir apenas com palavras.\");\r\n\r\nconst distLabel = cadastro.origem_disturbio || \"\";\r\nconst distCode = distMap[distLabel] || \"08\";\r\n\r\nconst sexo = (cadastro.genero || \"\").toLowerCase().includes(\"femin\") ? \"F\"\r\n: (cadastro.genero || \"\").toLowerCase().includes(\"mascul\") ? \"M\"\r\n: \"NI\";\r\n\r\nconst birth = new Date((cadastro.data_nascimento || \"\") + \"T00:00:00\");\r\nconst now = new Date();\r\nlet idade = 0;\r\nif (!isNaN(birth.getTime())){\r\nidade = now.getFullYear() - birth.getFullYear();\r\nconst m = now.getMonth() - birth.getMonth();\r\nif (m < 0 || (m === 0 && now.getDate() < birth.getDate())) idade--;\r\nif (idade < 0) idade = 0;\r\nif (idade > 100) idade = 100;\r\n}\r\n\r\nconst dd = String(now.getDate()).padStart(2,'0');\r\nconst mm = String(now.getMonth()+1).padStart(2,'0');\r\nconst yyyy = now.getFullYear();\r\nconst dataColeta = `${dd}.${mm}.${yyyy}`;\r\n\r\nconst noTrans = (mode === \"P\") ? idxP : idxF;\r\nconst transCode = mode + pad2(noTrans);\r\n\r\nconst meta = {\r\nsexo,\r\ndist: distCode,\r\nidade: pad2(idade),\r\ndata: dataColeta,\r\ntrans: mode,\r\nno_trans: pad2(noTrans),\r\ntranscode: transCode,\r\nindividuo: individuo,\r\nvideo_no: pad2(videoNo),\r\n};\r\n\r\nconst fd = new FormData();\r\nfd.append(\"action\", \"sofia_doe_video_upload\");\r\nfd.append(\"nonce\", nonce);\r\nfd.append(\"video\", file);\r\nObject.keys(cadastro).forEach(k => fd.append(\"cadastro[\"+k+\"]\", cadastro[k]));\r\nObject.keys(meta).forEach(k => fd.append(\"meta[\"+k+\"]\", meta[k]));\r\n\r\nconst res = await fetch(ajax, { method:\"POST\", body: fd });\r\nconst data = await res.json();\r\nif (!data || !data.success) throw new Error((data && data.data && data.data.message) ? data.data.message : \"Erro ao enviar.\");\r\nreturn { data, meta };\r\n}\r\n\r\nconst MIRROR_VIDEO = true;\r\nconst flipCanvas = document.createElement(\"canvas\");\r\nconst flipCtx = flipCanvas.getContext(\"2d\");\r\n\r\nconst c1 = document.createElement(\"canvas\"); const x1 = c1.getContext(\"2d\");\r\nconst c2 = document.createElement(\"canvas\"); const x2 = c2.getContext(\"2d\");\r\nconst c3 = document.createElement(\"canvas\"); const x3 = c3.getContext(\"2d\");\r\n\r\nconst segMaskCanvas = document.createElement(\"canvas\"); const segMaskCtx = segMaskCanvas.getContext(\"2d\");\r\nconst personCanvas = document.createElement(\"canvas\"); const personCtx = personCanvas.getContext(\"2d\");\r\nconst segSmall = document.createElement(\"canvas\"); const segSmallCtx = segSmall.getContext(\"2d\");\r\n\r\nlet stream = null;\r\nlet recorder = null;\r\nlet chunks = [];\r\nlet recordedBlob = null;\r\n\r\nlet faceMesh = null, selfieSeg = null;\r\nlet meshReady = false, segReady = false;\r\nlet processingFace = false, processingSeg = false;\r\nlet smoothLandmarks = null;\r\nlet segMaskReady = false;\r\n\r\nlet renderRAF = null;\r\nlet recInterval = null;\r\nlet recStartTs = null;\r\n\r\nfunction stopAllMedia(){\r\ntry{ if (recorder && recorder.state !== \"inactive\") recorder.stop(); } catch(e){}\r\nrecorder = null;\r\n\r\ntry{\r\nif (stream){\r\nstream.getTracks().forEach(t => { try{ t.stop(); }catch(e){} });\r\n}\r\n} catch(e){}\r\nstream = null;\r\n\r\ntry{ srcVideo.srcObject = null; } catch(e){}\r\nif (renderRAF){ cancelAnimationFrame(renderRAF); renderRAF = null; }\r\nstopTimer();\r\n}\r\n\r\nfunction setSmooth(ctx2d){\r\ntry{ ctx2d.imageSmoothingEnabled = true; ctx2d.imageSmoothingQuality = \"high\"; } catch(e){}\r\n}\r\n[ctx,x1,x2,x3,segMaskCtx,personCtx,segSmallCtx,flipCtx].forEach(setSmooth);\r\n\r\nfunction ensureAllCanvasSizes(){\r\nconst w = srcVideo.videoWidth || 1280;\r\nconst h = srcVideo.videoHeight || 720;\r\n\r\nif (canvas.width !== w) canvas.width = w;\r\nif (canvas.height !== h) canvas.height = h;\r\n\r\nif (flipCanvas.width !== w) flipCanvas.width = w;\r\nif (flipCanvas.height !== h) flipCanvas.height = h;\r\n\r\nif (segMaskCanvas.width !== w) segMaskCanvas.width = w;\r\nif (segMaskCanvas.height !== h) segMaskCanvas.height = h;\r\n\r\nif (personCanvas.width !== w) personCanvas.width = w;\r\nif (personCanvas.height !== h) personCanvas.height = h;\r\n\r\nconst w1 = Math.max(160, Math.round(w * 0.45));\r\nconst h1 = Math.max(120, Math.round(h * 0.45));\r\nconst w2 = Math.max(140, Math.round(w * 0.25));\r\nconst h2 = Math.max(110, Math.round(h * 0.25));\r\nconst w3 = Math.max(120, Math.round(w * 0.16));\r\nconst h3 = Math.max(96, Math.round(h * 0.16));\r\n\r\nif (c1.width !== w1) c1.width = w1;\r\nif (c1.height !== h1) c1.height = h1;\r\nif (c2.width !== w2) c2.width = w2;\r\nif (c2.height !== h2) c2.height = h2;\r\nif (c3.width !== w3) c3.width = w3;\r\nif (c3.height !== h3) c3.height = h3;\r\n\r\nconst sw = Math.max(180, Math.round(w * 0.36));\r\nconst sh = Math.max(140, Math.round(h * 0.36));\r\nif (segSmall.width !== sw) segSmall.width = sw;\r\nif (segSmall.height !== sh) segSmall.height = sh;\r\n}\r\n\r\nfunction updateFlipFrame(){\r\nconst W = flipCanvas.width, H = flipCanvas.height;\r\nflipCtx.clearRect(0,0,W,H);\r\nif (MIRROR_VIDEO){\r\nflipCtx.save();\r\nflipCtx.scale(-1, 1);\r\nflipCtx.drawImage(srcVideo, -W, 0, W, H);\r\nflipCtx.restore();\r\n} else {\r\nflipCtx.drawImage(srcVideo, 0, 0, W, H);\r\n}\r\n}\r\n\r\nfunction drawCinematicBlurBackground(){\r\nconst W = canvas.width, H = canvas.height;\r\n\r\nx1.clearRect(0,0,c1.width,c1.height);\r\nx1.drawImage(flipCanvas, 0,0,c1.width,c1.height);\r\n\r\nx2.clearRect(0,0,c2.width,c2.height);\r\nx2.drawImage(c1, 0,0,c2.width,c2.height);\r\n\r\nx3.clearRect(0,0,c3.width,c3.height);\r\nx3.drawImage(c2, 0,0,c3.width,c3.height);\r\n\r\nctx.clearRect(0,0,W,H);\r\nctx.drawImage(c3, 0,0,W,H);\r\n\r\nctx.save();\r\nctx.globalAlpha = 0.22;\r\nctx.drawImage(c3, -6, 0, W+12, H);\r\nctx.drawImage(c3, 6, 0, W+12, H);\r\nctx.drawImage(c3, 0, -6, W, H+12);\r\nctx.drawImage(c3, 0, 6, W, H+12);\r\nctx.restore();\r\n\r\nctx.save();\r\nconst g = ctx.createRadialGradient(W*0.5, H*0.48, Math.min(W,H)*0.20, W*0.5, H*0.52, Math.min(W,H)*0.78);\r\ng.addColorStop(0, \"rgba(0,0,0,0)\");\r\ng.addColorStop(1, \"rgba(0,0,0,0.22)\");\r\nctx.fillStyle = g;\r\nctx.fillRect(0,0,W,H);\r\nctx.restore();\r\n}\r\n\r\nfunction drawPersonFromSegmentation(){\r\nif (!segMaskReady) return false;\r\n\r\nconst W = canvas.width, H = canvas.height;\r\n\r\npersonCtx.clearRect(0,0,W,H);\r\npersonCtx.drawImage(flipCanvas, 0,0,W,H);\r\n\r\nsegSmallCtx.clearRect(0,0,segSmall.width, segSmall.height);\r\nsegSmallCtx.drawImage(segMaskCanvas, 0,0,segSmall.width, segSmall.height);\r\n\r\nsegMaskCtx.clearRect(0,0,W,H);\r\nsegMaskCtx.filter = \"blur(10px)\";\r\nsegMaskCtx.drawImage(segSmall, 0,0,W,H);\r\nsegMaskCtx.filter = \"none\";\r\n\r\npersonCtx.globalCompositeOperation = \"destination-in\";\r\npersonCtx.drawImage(segMaskCanvas, 0,0,W,H);\r\npersonCtx.globalCompositeOperation = \"source-over\";\r\n\r\nctx.drawImage(personCanvas, 0,0,W,H);\r\nreturn true;\r\n}\r\n\r\nfunction rectFromLandmarks(landmarks, idxList, padX=0.12, padY=0.18){\r\nlet minX = 1, minY = 1, maxX = 0, maxY = 0;\r\nidxList.forEach(i=>{\r\nconst p = landmarks[i];\r\nif (!p) return;\r\nminX = Math.min(minX, p.x); minY = Math.min(minY, p.y);\r\nmaxX = Math.max(maxX, p.x); maxY = Math.max(maxY, p.y);\r\n});\r\nconst w = maxX - minX;\r\nconst h = maxY - minY;\r\nminX -= w*padX; maxX += w*padX;\r\nminY -= h*padY; maxY += h*padY;\r\nreturn {minX, minY, maxX, maxY};\r\n}\r\n\r\nfunction drawBars(landmarks){\r\nconst leftEyeIdx = [33,133,159,145,153,154,155,156,157,158,160,161,163,144];\r\nconst rightEyeIdx = [362,263,386,374,380,381,382,383,384,385,387,388,390,373];\r\n\r\nconst le = rectFromLandmarks(landmarks, leftEyeIdx, 0.15, 0.25);\r\nconst re = rectFromLandmarks(landmarks, rightEyeIdx, 0.15, 0.25);\r\n\r\nlet minX = Math.min(le.minX, re.minX);\r\nlet minY = Math.min(le.minY, re.minY);\r\nlet maxX = Math.max(le.maxX, re.maxX);\r\nlet maxY = Math.max(le.maxY, re.maxY);\r\n\r\nconst w = maxX - minX;\r\nconst h = maxY - minY;\r\n\r\nminX -= w * 0.10;\r\nmaxX += w * 0.10;\r\nminY -= h * 0.80;\r\nmaxY += h * 0.80;\r\n\r\nconst W = canvas.width, H = canvas.height;\r\nconst x = Math.max(0, minX) * W;\r\nconst y = Math.max(0, minY) * H;\r\nconst ww = (Math.min(1, maxX) * W) - x;\r\nconst hh = (Math.min(1, maxY) * H) - y;\r\n\r\nctx.save();\r\nctx.fillStyle = \"rgba(0,0,0,1)\";\r\nctx.fillRect(x, y, Math.max(0, ww), Math.max(0, hh));\r\nctx.restore();\r\n}\r\n\r\nfunction renderFrame(){\r\nif (!stream) return;\r\nensureAllCanvasSizes();\r\nupdateFlipFrame();\r\n\r\ndrawCinematicBlurBackground();\r\nconst okPerson = drawPersonFromSegmentation();\r\nif (!okPerson) ctx.drawImage(flipCanvas, 0,0,canvas.width, canvas.height);\r\n\r\nif (smoothLandmarks) drawBars(smoothLandmarks);\r\n\r\nrenderRAF = requestAnimationFrame(renderFrame);\r\n}\r\n\r\nasync function initFaceMesh(){\r\nif (faceMesh) return;\r\nfaceMesh = new FaceMesh({ locateFile: (file) => `https:\/\/cdn.jsdelivr.net\/npm\/@mediapipe\/face_mesh\/${file}` });\r\nfaceMesh.setOptions({ maxNumFaces: 1, refineLandmarks: true, minDetectionConfidence: 0.5, minTrackingConfidence: 0.5 });\r\n\r\nconst alpha = 0.72;\r\nfaceMesh.onResults((results) => {\r\nif (results.multiFaceLandmarks && results.multiFaceLandmarks[0]) {\r\nconst lm = results.multiFaceLandmarks[0];\r\nif (!smoothLandmarks) smoothLandmarks = lm.map(p => ({x:p.x, y:p.y, z:p.z}));\r\nelse {\r\nfor (let i=0;i<lm.length;i++){\r\nconst p = lm[i], s = smoothLandmarks[i];\r\nif (!p || !s) continue;\r\ns.x = alpha*s.x + (1-alpha)*p.x;\r\ns.y = alpha*s.y + (1-alpha)*p.y;\r\ns.z = alpha*s.z + (1-alpha)*p.z;\r\n}\r\n}\r\n} else smoothLandmarks = null;\r\nprocessingFace = false;\r\n});\r\nmeshReady = true;\r\n}\r\n\r\nasync function initSelfieSeg(){\r\nif (selfieSeg) return;\r\nselfieSeg = new SelfieSegmentation({ locateFile: (file) => `https:\/\/cdn.jsdelivr.net\/npm\/@mediapipe\/selfie_segmentation\/${file}` });\r\nselfieSeg.setOptions({ modelSelection: 1 });\r\nselfieSeg.onResults((results) => {\r\nensureAllCanvasSizes();\r\nsegMaskCtx.clearRect(0,0,segMaskCanvas.width, segMaskCanvas.height);\r\nsegMaskCtx.drawImage(results.segmentationMask, 0,0,segMaskCanvas.width, segMaskCanvas.height);\r\nsegMaskReady = true;\r\nprocessingSeg = false;\r\n});\r\nsegReady = true;\r\n}\r\n\r\nasync function loopFace(){\r\nif (!meshReady || !stream) return;\r\nif (processingFace) { requestAnimationFrame(loopFace); return; }\r\nprocessingFace = true;\r\ntry { updateFlipFrame(); await faceMesh.send({ image: flipCanvas }); }\r\ncatch(e){ processingFace = false; }\r\nrequestAnimationFrame(loopFace);\r\n}\r\n\r\nasync function loopSeg(){\r\nif (!segReady || !stream) return;\r\nif (processingSeg) { requestAnimationFrame(loopSeg); return; }\r\nprocessingSeg = true;\r\ntry { updateFlipFrame(); await selfieSeg.send({ image: flipCanvas }); }\r\ncatch(e){ processingSeg = false; }\r\nrequestAnimationFrame(loopSeg);\r\n}\r\n\r\nfunction pickMimeType(){\r\nconst c = [\"video\/webm;codecs=vp9,opus\",\"video\/webm;codecs=vp8,opus\",\"video\/webm\"];\r\nfor (const t of c) if (window.MediaRecorder && MediaRecorder.isTypeSupported && MediaRecorder.isTypeSupported(t)) return t;\r\nreturn \"\";\r\n}\r\n\r\nasync function waitLoadedMetadata(videoEl){\r\nif (videoEl.readyState >= 1 && videoEl.videoWidth > 0) return;\r\nawait new Promise((resolve) => {\r\nconst onMeta = () => { videoEl.removeEventListener('loadedmetadata', onMeta); resolve(); };\r\nvideoEl.addEventListener('loadedmetadata', onMeta, { once:true });\r\n});\r\n}\r\n\r\nfunction stopTimer(){ if (recInterval){ clearInterval(recInterval); recInterval = null; } }\r\nfunction startTimer(){\r\nstopTimer();\r\nrecStartTs = Date.now();\r\nrecTime.textContent = \"00:00\";\r\nrecInterval = setInterval(()=>{\r\nconst ms = Date.now()-recStartTs;\r\nconst s = Math.floor(ms\/1000);\r\nconst mm = String(Math.floor(s\/60)).padStart(2,'0');\r\nconst ss = String(s%60).padStart(2,'0');\r\nrecTime.textContent = `${mm}:${ss}`;\r\n}, 250);\r\n}\r\n\r\nfunction resetCameraUIHard(){\r\nstopAllMedia();\r\ncameraStage.style.display = \"none\";\r\npostStage.style.display = \"none\";\r\npreCameraStage.style.display = \"block\";\r\nctaBeforeCam.style.display = \"block\";\r\n\r\nbtnRecStop.style.display = \"none\";\r\nbtnRecStart.style.display = \"inline-block\";\r\nbtnRecStart.disabled = !mode;\r\n\r\nrecPill.style.display = \"none\";\r\nhintPill.style.display = \"inline-flex\";\r\n\r\nplayback.removeAttribute(\"src\");\r\nplayback.load();\r\n\r\nunderBar.style.display = \"none\";\r\n\r\nrecordedBlob = null;\r\nchunks = [];\r\nsmoothLandmarks = null;\r\nsegMaskReady = false;\r\n\r\nlastUploadOk = false;\r\n}\r\nresetCameraUIHard();\r\n\r\nbtnAtivarCam.onclick = async () => {\r\nsetMsg(msgVideo, \"\", true);\r\n\r\nbtnAtivarCam.classList.add(\"sdv-loading\");\r\nbtnAtivarCam.disabled = true;\r\nbtnAtivarCam.style.opacity = \"0.9\";\r\nbtnAtivarCam.textContent = \"Ativando c\u00e2mera...\";\r\n\r\nrecordedBlob = null;\r\nchunks = [];\r\nsmoothLandmarks = null;\r\nsegMaskReady = false;\r\n\r\ntry{\r\nawait initFaceMesh();\r\nawait initSelfieSeg();\r\n\r\nstream = await navigator.mediaDevices.getUserMedia({ video:true, audio:true });\r\nsrcVideo.srcObject = stream;\r\n\r\nawait waitLoadedMetadata(srcVideo);\r\nawait srcVideo.play();\r\n\r\npreCameraStage.style.display = \"none\";\r\ncameraStage.style.display = \"block\";\r\nctaBeforeCam.style.display = \"none\";\r\n\r\nunderBar.style.display = mode ? \"block\" : \"none\";\r\nrenderPrompt();\r\n\r\nif (renderRAF) cancelAnimationFrame(renderRAF);\r\nrenderFrame();\r\nloopFace();\r\nloopSeg();\r\n\r\nbtnRecStart.disabled = !mode;\r\nsetMsg(msgVideo, mode ? \"C\u00e2mera pronta. Agora repita e clique em iniciar grava\u00e7\u00e3o.\" : \"C\u00e2mera pronta. Agora selecione Palavra ou Frase.\", true);\r\n\r\n} catch(e){\r\nsetMsg(msgVideo, \"N\u00e3o foi poss\u00edvel acessar c\u00e2mera\/microfone.\", false);\r\nstopAllMedia();\r\n} finally {\r\nbtnAtivarCam.classList.remove(\"sdv-loading\");\r\nbtnAtivarCam.disabled = false;\r\nbtnAtivarCam.style.opacity = \"1\";\r\nbtnAtivarCam.textContent = \"Ativar c\u00e2mera\";\r\n}\r\n};\r\n\r\nbtnRecStart.onclick = () => {\r\nif (!mode) return setMsg(msgVideo, \"Selecione Palavra ou Frase antes de gravar.\", false);\r\nif (!stream) return setMsg(msgVideo, \"Ative a c\u00e2mera primeiro.\", false);\r\n\r\nstopSpeak();\r\nlastUploadOk = false;\r\n\r\nbtnRecStart.style.display = \"none\";\r\nbtnRecStop.style.display = \"inline-block\";\r\nbtnRecStop.disabled = false;\r\nbtnAtivarCam.disabled = true;\r\n\r\nrecPill.style.display = \"inline-flex\";\r\nhintPill.style.display = \"none\";\r\nstartTimer();\r\n\r\nconst canvasStream = canvas.captureStream(30);\r\nconst audioTracks = stream.getAudioTracks();\r\nif (audioTracks && audioTracks[0]) canvasStream.addTrack(audioTracks[0]);\r\n\r\nconst mimeType = pickMimeType();\r\ntry{\r\nrecorder = mimeType ? new MediaRecorder(canvasStream, { mimeType }) : new MediaRecorder(canvasStream);\r\n} catch(e){\r\nstopTimer();\r\nrecPill.style.display = \"none\";\r\nhintPill.style.display = \"inline-flex\";\r\nbtnRecStop.style.display = \"none\";\r\nbtnRecStart.style.display = \"inline-block\";\r\nbtnAtivarCam.disabled = false;\r\nsetMsg(msgVideo, \"Seu navegador n\u00e3o suporta grava\u00e7\u00e3o. Tente outro navegador.\", false);\r\nreturn;\r\n}\r\n\r\nchunks = [];\r\nrecorder.ondataavailable = (ev) => { if (ev.data && ev.data.size) chunks.push(ev.data); };\r\nrecorder.onstop = () => {\r\nstopTimer();\r\nrecordedBlob = new Blob(chunks, { type: recorder.mimeType || \"video\/webm\" });\r\nconst url = URL.createObjectURL(recordedBlob);\r\n\r\ncameraStage.style.display = \"none\";\r\npostStage.style.display = \"block\";\r\nplayback.src = url;\r\nplayback.style.display = \"block\";\r\nbtnEnviarGravacao.disabled = false;\r\n\r\nbtnAtivarCam.disabled = false;\r\nunderBar.style.display = \"none\";\r\n\r\nsetMsg(msgVideo, \"Confira o v\u00eddeo. Se estiver bom, clique em \u201cEnviar v\u00eddeo\u201d.\", true);\r\n};\r\n\r\nrecorder.start(250);\r\nsetMsg(msgVideo, \"Gravando... quando terminar clique em parar.\", true);\r\n};\r\n\r\nbtnRecStop.onclick = () => {\r\nbtnRecStop.disabled = true;\r\nif (recorder && recorder.state !== \"inactive\") recorder.stop();\r\nbtnAtivarCam.disabled = false;\r\nbtnRecStop.style.display = \"none\";\r\nbtnRecStart.style.display = \"inline-block\";\r\n};\r\n\r\nbtnRetry.onclick = () => {\r\ncameraStage.style.display = \"block\";\r\npostStage.style.display = \"none\";\r\nbtnRecStart.style.display = \"inline-block\";\r\nbtnRecStop.style.display = \"none\";\r\nrecPill.style.display = \"none\";\r\nhintPill.style.display = \"inline-flex\";\r\nunderBar.style.display = mode ? \"block\" : \"none\";\r\nlastUploadOk = false;\r\nsetMsg(msgVideo, \"\", true);\r\n};\r\n\r\nbtnEnviarGravacao.onclick = async () => {\r\nif (!recordedBlob) return setMsg(msgVideo, \"Nenhuma grava\u00e7\u00e3o pronta para enviar.\", false);\r\n\r\nbtnEnviarGravacao.disabled = true;\r\nsetMsg(msgVideo, \"Enviando v\u00eddeo...\", true);\r\n\r\nconst file = new File([recordedBlob], \"video-anonimizado.webm\", { type: recordedBlob.type || \"video\/webm\" });\r\n\r\ntry{\r\nconst { data, meta } = await enviarVideo(file);\r\n\r\nconst sentIdx = parseInt(meta.no_trans, 10);\r\nmarkSent(mode, sentIdx);\r\n\r\nlastUploadOk = true;\r\nsetMsg(msgVideo, data.data.message, true);\r\n\r\nvideoNo++;\r\nsetVideoNo(videoNo);\r\n\r\nstopAllMedia();\r\nopenModal(\"Pronto! O que voc\u00ea quer gravar agora?\");\r\n\r\n} catch(err){\r\nsetMsg(msgVideo, err.message || \"Falha ao enviar.\", false);\r\n} finally {\r\nbtnEnviarGravacao.disabled = false;\r\n}\r\n};\r\n\r\nconst sdvModalBackdrop = document.getElementById(\"sdvModalBackdrop\");\r\nconst btnModalClose = document.getElementById(\"btnModalClose\");\r\nconst modalMsg = document.getElementById(\"modalMsg\");\r\n\r\nconst btnNextPalavra = document.getElementById(\"btnNextPalavra\");\r\nconst btnNextFrase = document.getElementById(\"btnNextFrase\");\r\nconst btnStopDonation= document.getElementById(\"btnStopDonation\");\r\n\r\nfunction openModal(text){\r\nmodalMsg.textContent = text || \"Pronto!\";\r\nsdvModalBackdrop.style.display = \"flex\";\r\nsdvModalBackdrop.setAttribute(\"aria-hidden\",\"false\");\r\n}\r\nfunction closeModal(){\r\nsdvModalBackdrop.style.display = \"none\";\r\nsdvModalBackdrop.setAttribute(\"aria-hidden\",\"true\");\r\n}\r\nbtnModalClose.onclick = closeModal;\r\nsdvModalBackdrop.addEventListener(\"click\", (e)=>{ if (e.target === sdvModalBackdrop) closeModal(); });\r\n\r\nfunction gotoNext(newMode){\r\nif (!lastUploadOk) return;\r\nif (newMode === \"F\" && isApenasPalavras()){\r\nsetMsg(msgVideo, \"Voc\u00ea marcou a op\u00e7\u00e3o de contribuir apenas com palavras.\", false);\r\nreturn;\r\n}\r\nstopSpeak();\r\n\r\nmode = newMode;\r\nbtnModePalavra.classList.toggle(\"sdv-active\", mode===\"P\");\r\nbtnModeFrase.classList.toggle(\"sdv-active\", mode===\"F\");\r\n\r\nconst next = getRandomUnsent(mode);\r\nif (next == null){\r\ncloseModal();\r\nsetMsg(msgVideo, \"Voc\u00ea j\u00e1 enviou todos os itens desse tipo. Obrigado!\", true);\r\nreturn;\r\n}\r\n\r\nif (mode === \"P\") idxP = next; else idxF = next;\r\n\r\nrenderPrompt();\r\n\r\npreCameraStage.style.display = \"block\";\r\nctaBeforeCam.style.display = \"block\";\r\ncameraStage.style.display = \"none\";\r\npostStage.style.display = \"none\";\r\nunderBar.style.display = \"none\";\r\nlastUploadOk = false;\r\n\r\nplayback.removeAttribute(\"src\");\r\nplayback.load();\r\nrecordedBlob = null;\r\nchunks = [];\r\n\r\ncloseModal();\r\nsetMsg(msgVideo, \"Pronto! Ative a c\u00e2mera e grave o pr\u00f3ximo.\", true);\r\n}\r\n\r\nbtnNextPalavra.onclick = () => gotoNext(\"P\");\r\nbtnNextFrase.onclick = () => gotoNext(\"F\");\r\n\r\nbtnStopDonation.onclick = () => {\r\nstopSpeak();\r\nstopAllMedia();\r\nlastUploadOk = false;\r\ncloseModal();\r\n\r\nmainDonationFlow.style.display = \"none\";\r\nthanksScreen.style.display = \"block\";\r\nsetMsg(msgVideo, \"\", true);\r\ntry{ window.scrollTo({ top: 0, behavior: \"smooth\" }); }catch(e){ window.scrollTo(0,0); }\r\n};\r\n\r\n})();\r\n<\/script>\r\n\r\n<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"","protected":false},"author":24330,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":"","_links_to":"","_links_to_target":""},"class_list":["post-963","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/sites.usp.br\/sofiafala\/wp-json\/wp\/v2\/pages\/963","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/sites.usp.br\/sofiafala\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/sites.usp.br\/sofiafala\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/sites.usp.br\/sofiafala\/wp-json\/wp\/v2\/users\/24330"}],"replies":[{"embeddable":true,"href":"https:\/\/sites.usp.br\/sofiafala\/wp-json\/wp\/v2\/comments?post=963"}],"version-history":[{"count":4,"href":"https:\/\/sites.usp.br\/sofiafala\/wp-json\/wp\/v2\/pages\/963\/revisions"}],"predecessor-version":[{"id":994,"href":"https:\/\/sites.usp.br\/sofiafala\/wp-json\/wp\/v2\/pages\/963\/revisions\/994"}],"wp:attachment":[{"href":"https:\/\/sites.usp.br\/sofiafala\/wp-json\/wp\/v2\/media?parent=963"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}