/* FlowZ — shows-app.jsx
   Shell React (sem build, Babel transpila no navegador) do /shows.

   Fase 0 da migração pro padrão "React sem build" (ver
   /root/.claude/plans/humming-mixing-aho.md e CONTEXT.md): prova a mecânica
   do loader e organiza o app num componente React de verdade, mas o corpo
   das 3 abas (Shows/Agenda/Perfil) ainda é a MESMA marcação + lógica de
   antes, injetada tal qual via innerHTML (LegacyAppBridge) — decomposição
   real em componentes entra na Fase 1 (Perfil) e Fase 2 (Agenda). Toda a
   lógica (fetch, drag-reorder, swipe, configurações, etc.) mora em
   /shows-legacy.js, carregado ANTES deste arquivo como script clássico —
   as funções ficam em `window` de propósito, porque a marcação legada
   ainda referencia várias delas via onclick="fn()" inline, e o guard de
   autenticação (redirect pra /login/) já roda sozinho assim que
   shows-legacy.js carrega, sem precisar de nada daqui.
*/

const { useEffect, useRef, useState } = React;

const PRE_APP_HTML = `<div id="page-bg" aria-hidden="true">
  <div class="pg-orb pg-orb1"></div>
  <div class="pg-orb pg-orb2"></div>
  <div class="pg-orb pg-orb3"></div>
  <div class="pg-orb pg-orb4"></div>
</div>

<!-- App notification banner -->
<div id="app-toast" onclick="hideToast()" role="status" aria-live="polite"></div>

<!-- Direct-to-show notification (persistent until dismissed) -->
<div id="direct-notif-banner">
  <span class="dn-icon">⚠️</span>
  <div class="dn-body">
    <div class="dn-title" id="dn-title">Membro foi direto para o show</div>
    <div class="dn-sub" id="dn-sub">Um membro da equipe não vai ao ponto de encontro</div>
  </div>
  <button class="dn-ok" onclick="dismissDirectNotif()">OK</button>
</div>

<!-- Assistente wizard -->
<button class="asst-fab" id="asst-fab" onclick="asstOpen()" aria-label="Assistente" style="display:none">
  <img src="/criar-show/wizard-avatar.png" alt="assistente">
  <span class="asst-badge" id="asst-badge" style="display:none"></span>
</button>
<div class="asst-overlay" id="asst-overlay" style="display:none" onclick="asstClose()">
  <div class="asst-panel" onclick="event.stopPropagation()">
    <div class="asst-panel-handle"></div>
    <div class="asst-panel-head">
      <div class="asst-panel-avatar"><img src="/criar-show/wizard-avatar.png" alt="assistente"></div>
      <div class="asst-panel-info">
        <div class="asst-panel-name">Assistente</div>
        <div class="asst-panel-sub" id="asst-panel-sub">Analisando shows...</div>
      </div>
    </div>
    <div class="asst-panel-body" id="asst-panel-body"></div>
  </div>
</div>

<!-- Quick-create wizard virou <QuickCreateDialog/> (React de verdade,
     Fase 3b) — não é mais injetado aqui via innerHTML. -->

<!-- Modal de verificar logística virou <LogisticsDialog/> (React de
     verdade, Fase 3c) — não é mais injetado aqui via innerHTML. -->

<!-- Day modal -->
<div id="ag-overlay" onclick="agCloseModal()">
  <div id="ag-sheet" onclick="event.stopPropagation()">
    <div class="ag-sheet-grip"></div>
    <div class="ag-sheet-hdr" id="ag-sheet-hdr"></div>
    <div id="ag-sheet-list"></div>
  </div>
</div>

`;

const HEADER_HTML = `  <header class="hdr" id="hdr">
    <div class="hdr-row">
      <div class="hdr-leading">
        <button class="hdr-settings" onclick="setTab('perfil')" aria-label="Configurações">
          <svg width="20" height="20" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.8" stroke-linecap="round">
            <circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v-.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/>
          </svg>
        </button>
      </div>
      <div class="hdr-title-wrap">
        <div class="hdr-title" id="hdr-title">Shows</div>
        <div class="hdr-sub" id="hdr-sub">FlowZ</div>
      </div>
      <div style="display:flex;align-items:center;justify-content:flex-end;gap:8px">
        <div class="hdr-brand" aria-hidden="true">
          <span class="hdr-brand-name">FlowZ</span>
        </div>
        <button class="hdr-quick" id="hdr-quick" onclick="qcOpen()" aria-label="Criar shows rápido">
          <svg width="15" height="15" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M13 2 4.5 13.5H11l-1 8.5 8.5-11.5H12l1-8.5z"/></svg>
          Rápido
        </button>
        <button class="hdr-create" id="hdr-create" onclick="window.location.href='/criar-show/?new=1'" aria-label="Criar show">
          Criar
        </button>
      </div>
    </div>
  </header>
`;

const AFTER_SHOWS_HTML = `  <div id="panel-agenda" class="tab-panel">
    <div id="agenda-content">
      <div class="sk-list" role="status" aria-label="Carregando agenda…">
        <div class="sk-cal" style="animation-delay:.05s"></div>
        <div class="sk-card" style="animation-delay:.15s"><div class="sk-date"></div><div class="sk-body"><div class="sk-line lg sk-w55"></div><div class="sk-line sk-w75"></div></div></div>
        <div class="sk-card" style="animation-delay:.23s"><div class="sk-date"></div><div class="sk-body"><div class="sk-line lg sk-w75"></div><div class="sk-line sk-w55"></div></div></div>
      </div>
    </div>
  </div>

  <!-- ── Panel: Perfil / Configurações ── -->
  <div id="panel-perfil" class="tab-panel">

    <!-- Main settings view -->
    <div id="cfg-main">
      <div class="cfg-page-head fade-up">
        <div class="cfg-page-copy">
          <span class="cfg-page-eyebrow">Workspace</span>
          <div class="cfg-large-title">Configurações</div>
          <p class="cfg-page-subtitle">Gerencie sua conta, equipe, acessos e preferências do FlowZ.</p>
        </div>
      </div>

      <!-- Account hero -->
      <div class="v3-cfg-acct">
        <div class="av" id="cfg-acct-av">⚡</div>
        <div class="info">
          <div class="nm" id="cfg-acct-nm">FlowZ Produtor</div>
          <div class="artist" id="cfg-acct-artist" style="display:none"></div>
          <div class="em" id="cfg-acct-em">—</div>
          <div class="plan">Produtor Geral</div>
        </div>
        <div class="arrow"><svg width="16" height="16" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 18 15 12 9 6"/></svg></div>
      </div>

      <div class="cfg-groups">

      <!-- Notificações -->
      <div class="cfg-group">
      <div class="v3-cfg-group-label">Notificações <span class="ln"></span></div>
      <div class="v3-cfg-list">
        <div class="v3-cfg-row acc-amber" style="cursor:default;opacity:.45">
          <div class="ic"><svg width="15" height="15" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9"/><path d="M13.73 21a2 2 0 0 1-3.46 0"/></svg></div>
          <div class="lbl"><div class="t">Permissões</div><div class="s">Pedir ao sistema</div></div>
          <div class="end"><span class="soon-badge">EM BREVE</span></div>
        </div>
      </div>
      </div>

      <!-- Central da IA -->
      <div class="cfg-group">
      <div class="v3-cfg-group-label">Central da IA <span class="ln"></span></div>
      <div class="v3-cfg-list">
        <div class="v3-cfg-row acc-purple" onclick="cfgAiOpen()" style="cursor:pointer">
          <div class="ic"><svg width="15" height="15" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="11" width="18" height="10" rx="2"/><circle cx="12" cy="5" r="2"/><path d="M12 7v4"/><line x1="8" y1="16" x2="8" y2="16"/><line x1="16" y1="16" x2="16" y2="16"/></svg></div>
          <div class="lbl"><div class="t">Configurar IA</div><div class="s" id="cfg-ai-status-sub">Desativada</div></div>
          <div class="end"><div class="arrow"><svg width="14" height="14" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 18 15 12 9 6"/></svg></div></div>
        </div>
      </div>
      </div>

      <!-- Equipe -->
      <div class="cfg-group">
      <div class="v3-cfg-group-label">Equipe <span class="ln"></span></div>
      <div class="v3-cfg-list">
        <div class="v3-cfg-row acc-sky" onclick="cfgMembrosOpen()" style="cursor:pointer">
          <div class="ic"><svg width="15" height="15" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/></svg></div>
          <div class="lbl"><div class="t">Membros da equipe</div><div class="s" id="cfg-members-sub">Nomes e funções para hotel e voo</div></div>
          <div class="end"><div class="arrow"><svg width="14" height="14" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 18 15 12 9 6"/></svg></div></div>
        </div>
      </div>
      </div>

      <!-- Links -->
      <div class="cfg-group">
      <div class="v3-cfg-group-label">Links <span class="ln"></span></div>
      <div class="v3-cfg-list">
        <div class="v3-cfg-row acc-emerald" onclick="cfgShareLink('equipe.html','Link da equipe')" style="cursor:pointer">
          <div class="ic"><svg width="15" height="15" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></div>
          <div class="lbl"><div class="t">Link da equipe</div><div class="s">Logística, hotel e voo</div></div>
          <div class="end"><div class="arrow"><svg width="14" height="14" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 18 15 12 9 6"/></svg></div></div>
        </div>
        <div class="v3-cfg-row acc-rose" onclick="cfgShareLink('artista.html','Link do artista')" style="cursor:pointer">
          <div class="ic"><svg width="15" height="15" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z"/><path d="M19 10v2a7 7 0 0 1-14 0v-2"/><line x1="12" y1="19" x2="12" y2="23"/><line x1="8" y1="23" x2="16" y2="23"/></svg></div>
          <div class="lbl"><div class="t">Link do artista</div><div class="s">Horários e ponto de encontro</div></div>
          <div class="end"><div class="arrow"><svg width="14" height="14" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 18 15 12 9 6"/></svg></div></div>
        </div>
      </div>
      </div>

      <!-- Roteiro Compartilhado -->
      <div class="cfg-group">
      <div class="v3-cfg-group-label">Roteiro Compartilhado <span class="ln"></span></div>
      <div class="v3-cfg-list">
        <div class="v3-cfg-row acc-purple" onclick="(function(){window.location.href='/acesso.html';})()" style="cursor:pointer">
          <div class="ic"><svg width="15" height="15" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></div>
          <div class="lbl"><div class="t">Gerenciar acessos</div><div class="s">Tokens individuais · device pinning · geo</div></div>
          <div class="end"><div class="arrow"><svg width="14" height="14" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 18 15 12 9 6"/></svg></div></div>
        </div>
      </div>

      <div class="v3-cfg-list">
        <div class="v3-cfg-row danger" onclick="cfgSharedRevoke()" style="cursor:pointer">
          <div class="ic"><svg width="15" height="15" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="4.93" y1="4.93" x2="19.07" y2="19.07"/></svg></div>
          <div class="lbl"><div class="t">Revogar todos os acessos</div><div class="s">Invalida todos os links existentes</div></div>
          <div class="end"><div class="arrow"><svg width="14" height="14" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 18 15 12 9 6"/></svg></div></div>
        </div>
      </div>
      </div>

      <!-- PWA -->
      <div class="cfg-group">
      <div class="v3-cfg-group-label">PWA <span class="ln"></span></div>
      <div class="v3-cfg-list">
        <div class="v3-cfg-row acc-sky" id="cfg-row-update" onclick="cfgRefreshApp()" style="cursor:pointer">
          <div class="ic"><svg width="15" height="15" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="23 4 23 10 17 10"/><polyline points="1 20 1 14 7 14"/><path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15"/></svg></div>
          <div class="lbl"><div class="t" id="cfg-update-title">Buscar atualização</div><div class="s">Forçar download da versão mais recente</div></div>
          <div class="end"><div class="arrow"><svg width="14" height="14" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 18 15 12 9 6"/></svg></div></div>
        </div>
      </div>
      </div>

      <!-- Conta -->
      <div class="cfg-group">
      <div class="v3-cfg-group-label">Conta <span class="ln"></span></div>
      <div class="v3-cfg-list">
        <div class="v3-cfg-row acc-sky" onclick="cfgEditPins()" style="cursor:pointer">
          <div class="ic"><svg width="15" height="15" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="11" width="18" height="11" rx="2" ry="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg></div>
          <div class="lbl"><div class="t">Perfil do produtor</div><div class="s">Nome, PINs e ponto de encontro</div></div>
          <div class="end"><div class="arrow"><svg width="14" height="14" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 18 15 12 9 6"/></svg></div></div>
        </div>
        <div class="v3-cfg-row acc-amber" onclick="cfgResetPassword()" style="cursor:pointer">
          <div class="ic"><svg width="15" height="15" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 2l-2 2m-7.61 7.61a5.5 5.5 0 1 1-7.778 7.778 5.5 5.5 0 0 1 7.777-7.777zm0 0L15.5 7.5m0 0l3 3L22 7l-3-3m-3.5 3.5L19 4"/></svg></div>
          <div class="lbl"><div class="t">Redefinir senha</div><div class="s">Enviar link para seu e-mail</div></div>
          <div class="end"><div class="arrow"><svg width="14" height="14" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 18 15 12 9 6"/></svg></div></div>
        </div>
        <div class="v3-cfg-row danger" onclick="cfgSignOut()" style="cursor:pointer">
          <div class="ic"><svg width="15" height="15" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"/><polyline points="16 17 21 12 16 7"/><line x1="21" y1="12" x2="9" y2="12"/></svg></div>
          <div class="lbl"><div class="t">Sair</div><div class="s">Encerrar sessão neste dispositivo</div></div>
          <div class="end"><div class="arrow"><svg width="14" height="14" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 18 15 12 9 6"/></svg></div></div>
        </div>
      </div>
      </div>

      <!-- Sobre -->
      <div class="cfg-group">
      <div class="v3-cfg-group-label">Sobre <span class="ln"></span></div>
      <div class="v3-cfg-list">
        <div class="v3-cfg-row" style="cursor:default">
          <div class="ic"><svg width="15" height="15" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg></div>
          <div class="lbl"><div class="t">Versão</div><div class="s" id="cfg-version">—</div></div>
        </div>
      </div>
      </div>

      <!-- Dev tools -->
      <div class="cfg-group">
      <div class="v3-cfg-group-label">Desenvolvedor <span class="ln"></span></div>
      <div class="v3-cfg-list">
        <div class="v3-cfg-row acc-purple" onclick="showOnboarding()" style="cursor:pointer">
          <div class="ic"><svg width="15" height="15" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/></svg></div>
          <div class="lbl"><div class="t">Testar onboarding</div><div class="s">Abre o wizard de boas-vindas</div></div>
          <div class="end"><div class="arrow"><svg width="14" height="14" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 18 15 12 9 6"/></svg></div></div>
        </div>
      </div>
      </div>

      </div><!-- /.cfg-groups -->

      <div class="v3-cfg-footer">
        <img src="/voltz-logo.png" style="width:30px;height:30px;border-radius:8px;object-fit:contain;display:block;margin:0 auto 8px">
        <span class="v">FlowZ</span>
        App criado pela VoltZ Company
      </div>
    </div><!-- /#cfg-main -->

  </div>
  <!-- Membros sub-view (full-screen overlay no mobile; diálogo centralizado no desktop — ver html.desktop .cfg-sub-view em shows-app.css) -->
    <div id="cfg-membros" class="cfg-sub-view">
      <div class="cfg-sub-hdr">
        <span class="cfg-sub-back" onclick="cfgMembrosClose()">‹ Voltar</span>
        <span class="cfg-sub-title">Membros da Equipe</span>
        <span class="cfg-sub-add" onclick="cfgMembrosShowForm()">+ Adicionar</span>
      </div>
      <!-- add form -->
      <div class="cfg-add-form" id="cfg-m-form">
        <input class="cfg-add-inp" id="cfg-m-name" placeholder="NOME" autocomplete="off" />
        <input class="cfg-add-inp" id="cfg-m-role" placeholder="Função (ex: Músico, Roadie...)" autocomplete="off" />
        <div class="cfg-add-brow">
          <button onclick="cfgMembrosHideForm()">Cancelar</button>
          <button class="ok" onclick="cfgMembrosSubmit()">Salvar</button>
        </div>
      </div>
      <!-- dynamic list -->
      <div id="cfg-membros-list" style="margin-top:12px"></div>
    </div>

    <!-- Central da IA sub-view (full-screen overlay no mobile; diálogo centralizado no desktop) -->
    <div id="cfg-ai" class="cfg-sub-view">
      <div class="cfg-sub-hdr">
        <span class="cfg-sub-back" onclick="cfgAiClose()">‹ Voltar</span>
        <span class="cfg-sub-title">Configurar IA</span>
        <span style="width:44px"></span>
      </div>

      <div class="v3-cfg-group-label" style="margin-top:16px">Status <span class="ln"></span></div>
      <div class="v3-cfg-list">
        <div class="v3-cfg-row" style="cursor:default">
          <div class="ic"><svg width="15" height="15" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18.36 6.64a9 9 0 1 1-12.73 0"/><line x1="12" y1="2" x2="12" y2="12"/></svg></div>
          <div class="lbl"><div class="t">Central da IA</div><div class="s" id="cfg-ai-status-label">Desativada</div></div>
          <div class="end"><div class="cfg-switch" id="cfg-ai-switch" onclick="cfgAiToggleEnabled()"></div></div>
        </div>
      </div>

      <div class="v3-cfg-group-label">Número de logs <span class="ln"></span></div>
      <div class="cfg-add-form open">
        <input class="cfg-add-inp" id="cfg-ai-logs-input" placeholder="Ex: 21983764623 (DDD + número)" inputmode="numeric" autocomplete="off" />
        <div class="cfg-add-brow">
          <button class="ok" onclick="cfgAiSaveLogsNumber()">Salvar</button>
        </div>
      </div>
      <div style="padding:8px 16px 0;font-size:11px;color:var(--text-3)">Esse número recebe os avisos quando algo dá errado ou os lembretes do sistema.</div>

      <div class="v3-cfg-group-label" style="margin-top:20px">Grupos e números do bot <span class="ln"></span></div>
      <div id="cfg-wa-group-sub" style="padding:0 16px 8px;font-size:11px;color:var(--text-3)">Nenhum grupo ou número selecionado</div>

      <div class="cfg-add-form open">
        <input class="cfg-add-inp" id="cfg-wa-search" placeholder="Buscar grupo…" autocomplete="off" oninput="cfgWaRenderGroups()" />
      </div>
      <div id="cfg-wa-groups-list" class="cfg-wa-list"></div>

      <div class="cfg-add-form open" style="margin-top:10px">
        <input class="cfg-add-inp" id="cfg-wa-number-input" placeholder="Adicionar número (DDD + número)" inputmode="numeric" autocomplete="off" />
        <div class="cfg-add-brow">
          <button class="ok" onclick="cfgWaAddNumber()">Adicionar número</button>
        </div>
      </div>

      <div id="cfg-wa-selected" class="cfg-wa-chips"></div>

      <div style="margin:16px 16px 0">
        <button id="cfg-wa-send-btn" class="cfg-wa-send" onclick="cfgWaSendBroadcast()" disabled>Enviar mensagem de teste</button>
      </div>
      <div id="cfg-wa-send-status" style="padding:8px 16px 0;font-size:11px;color:var(--text-3)"></div>
    </div>
`;

const POST_APP_HTML = `<!-- ── Tab bar ── -->
<div id="ptr-indicator" aria-hidden="true"><div id="ptr-spinner"></div>Atualizando...</div>

<nav class="tabbar">
  <div class="sb-brand">
    <span class="sb-brand-name">FlowZ</span>
    <span class="sb-brand-short">FZ</span>
    <button class="sb-collapse" type="button" onclick="toggleSidebar()" aria-label="Recolher menu" title="Recolher menu">
      <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><polyline points="15 18 9 12 15 6"/></svg>
    </button>
  </div>
  <div class="tab-ind" id="tab-ind" aria-hidden="true"></div>
  <div class="sb-nav-label">Operação</div>
  <a href="#" class="tab active" id="tab-shows" title="Shows" aria-current="page" onclick="event.preventDefault();setTab('shows')">
    <span class="tab-burst" aria-hidden="true"></span>
    <span class="tab-ico"><svg width="24" height="24" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
      <rect class="if" x="9" y="2.5" width="6" height="10.5" rx="3" fill="currentColor" stroke="none"/>
      <rect x="9" y="2.5" width="6" height="10.5" rx="3"/>
      <path d="M5.5 11.5a6.5 6.5 0 0 0 13 0"/>
      <line x1="12" y1="18" x2="12" y2="21"/><line x1="8.5" y1="21" x2="15.5" y2="21"/>
    </svg></span>
    <span class="tab-lbl">Shows</span>
  </a>
  <a href="#" class="tab" id="tab-agenda" title="Agenda" onclick="event.preventDefault();setTab('agenda')">
    <span class="tab-burst" aria-hidden="true"></span>
    <span class="tab-ico"><svg width="24" height="24" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
      <path class="if" d="M7.5 5h9a4 4 0 0 1 4 4v1h-17V9a4 4 0 0 1 4-4z" fill="currentColor" stroke="none"/>
      <circle class="if" cx="8.6" cy="15" r="1.7" fill="currentColor" stroke="none"/>
      <rect x="3.5" y="5" width="17" height="15.5" rx="4"/>
      <line x1="8" y1="2.5" x2="8" y2="6.5"/><line x1="16" y1="2.5" x2="16" y2="6.5"/>
      <line x1="3.5" y1="10" x2="20.5" y2="10"/>
    </svg></span>
    <span class="tab-lbl">Agenda</span>
  </a>
  <div class="sb-nav-label secondary">Gestão</div>
  <a href="#" class="tab sb-tool" id="tab-team" title="Equipe" onclick="event.preventDefault();openSidebarTool('team')">
    <span class="tab-ico"><svg width="24" height="24" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M16 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="8.5" cy="7" r="4"/><path d="M20 8v6M23 11h-6"/></svg></span>
    <span class="tab-lbl">Equipe</span>
  </a>
  <a href="/acesso.html" class="tab sb-tool" id="tab-access" title="Acessos">
    <span class="tab-ico"><svg width="24" height="24" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="8" cy="15" r="4"/><path d="m11 12 8-8M15 4l3 3M14 9l3 3"/></svg></span>
    <span class="tab-lbl">Acessos</span>
  </a>
  <a href="#" class="tab sb-tool" id="tab-ai" title="Assistente IA" onclick="event.preventDefault();openSidebarTool('ai')">
    <span class="tab-ico"><svg width="24" height="24" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="7" width="18" height="13" rx="3"/><path d="M12 3v4M9 3h6"/><circle cx="8.5" cy="13" r="1" fill="currentColor"/><circle cx="15.5" cy="13" r="1" fill="currentColor"/><path d="M8 17h8"/></svg></span>
    <span class="tab-lbl">Assistente IA</span>
  </a>
  <div class="sb-nav-label secondary">Sistema</div>
  <a href="#" class="tab" id="tab-perfil" title="Configurações" onclick="event.preventDefault();setTab('perfil')">
    <span class="tab-burst" aria-hidden="true"></span>
    <span class="tab-ico"><svg width="24" height="24" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09A1.65 1.65 0 0 0 19.4 15Z"/></svg></span>
    <span class="tab-lbl">Configurações</span>
  </a>
  <div class="sb-footer" aria-hidden="true">
    <span class="sb-footer-label">FLOWZ WORKSPACE</span>
    <span class="sb-footer-copy">Produção e logística<br>em um só lugar.</span>
  </div>
</nav>

<div id="update-banner">
  <div><div class="ub-text">Nova versão disponível</div><div class="ub-sub">Recarregue para aplicar</div></div>
  <button class="ub-btn" onclick="location.reload()">Recarregar</button>
</div>
`;

const FLOATING_MODALS_HTML = `
<!-- Onboarding modal -->
<div id="ob-overlay">
  <div class="ob-card" id="ob-card">

    <!-- Step 1: Nomes -->
    <div id="ob-step-1">
      <div class="ob-steps"><div class="ob-step-dot active"></div><div class="ob-step-dot"></div><div class="ob-step-dot"></div></div>
      <div class="ob-icon"><svg width="26" height="26" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z"/><path d="M19 10v2a7 7 0 0 1-14 0v-2"/><line x1="12" y1="19" x2="12" y2="23"/><line x1="8" y1="23" x2="16" y2="23"/></svg></div>
      <div class="ob-title">Bem-vindo ao FlowZ!</div>
      <div class="ob-sub">Vamos começar com o básico. Esses nomes aparecem no app e nas páginas da equipe e do artista.</div>
      <div class="ob-pin-label">NOME DO ARTISTA</div>
      <input class="ob-name-input" id="ob-artist-input" type="text" maxlength="100" placeholder="Ex: Artista Fulano" oninput="obNamesInput()" autocomplete="off">
      <div class="ob-pin-label" style="margin-top:0">SEU NOME (PRODUTOR)</div>
      <input class="ob-name-input" id="ob-name-input" type="text" maxlength="100" placeholder="Ex: Zeca" oninput="obNamesInput()" autocomplete="off">
      <button class="ob-btn ob-btn-primary" id="ob-btn-name" disabled onclick="obSaveNames()">Continuar</button>
    </div>

    <!-- Step 2: Equipe (opcional) -->
    <div id="ob-step-2" style="display:none">
      <div class="ob-steps"><div class="ob-step-dot"></div><div class="ob-step-dot active"></div><div class="ob-step-dot"></div></div>
      <div class="ob-icon"><svg width="26" height="26" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/></svg></div>
      <div class="ob-title">Cadastrar equipe</div>
      <div class="ob-sub">Adicione os primeiros membros. Cada um recebe um link individual de acesso.</div>
      <div id="ob-team-list" style="display:none;max-height:140px;overflow-y:auto;margin-bottom:10px;flex-direction:column;gap:6px"></div>
      <div class="ob-pin-label">NOME DO MEMBRO</div>
      <div style="display:flex;gap:8px;margin-bottom:16px">
        <input class="ob-name-input" id="ob-member-input" type="text" maxlength="100" placeholder="Ex: Carlos (Motorista)" oninput="obMemberInput()" autocomplete="off" style="margin-bottom:0;flex:1">
        <button id="ob-btn-add-member" onclick="obAddMember()" disabled style="padding:0 16px;border-radius:12px;background:#7C3AED;border:none;color:#FFFFFF;font-size:14px;font-weight:700;font-family:inherit;cursor:pointer;white-space:nowrap;transition:opacity .2s;opacity:.4">+ Gerar</button>
      </div>
      <div style="display:flex;gap:8px">
        <button class="ob-btn" style="background:rgba(255,255,255,.06);border:1px solid rgba(255,255,255,.1);color:rgba(255,255,255,.5);flex:1" onclick="obStep(3)">Fazer depois</button>
        <button class="ob-btn ob-btn-primary" style="flex:1" id="ob-btn-finish-team" onclick="obStep(3)">Concluir</button>
      </div>
    </div>

    <!-- Step 3: Pronto -->
    <div id="ob-step-3" style="display:none">
      <div class="ob-steps"><div class="ob-step-dot"></div><div class="ob-step-dot"></div><div class="ob-step-dot active"></div></div>
      <div class="ob-icon" style="background:rgba(52,211,153,.12);color:#34D399"><svg width="26" height="26" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg></div>
      <div class="ob-title">Tudo configurado!</div>
      <div class="ob-sub" id="ob-done-sub">Você já pode criar shows e compartilhar com sua equipe.</div>
      <div class="ob-note">Adicione mais membros a qualquer momento em <b>Acessos</b>. Altere nomes em <b>Configurações → Conta</b>.</div>
      <button class="ob-btn ob-btn-success" onclick="obFinish()">Entrar no FlowZ</button>
    </div>

  </div>
</div>

<!-- Subscription paywall -->
<div id="sub-paywall">
  <div class="sub-card">
    <div id="sub-paywall-icon" class="sub-icon">
      <svg width="26" height="26" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="11" width="18" height="11" rx="2" ry="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg>
    </div>
    <div class="sub-title" id="sub-paywall-title">Assinatura encerrada</div>
    <div class="sub-msg" id="sub-paywall-msg">Sua assinatura foi cancelada. Renove para continuar acessando o FlowZ.</div>
    <button class="sub-btn sub-btn-primary" onclick="window.location.href='/assinatura/'">Renovar assinatura</button>
    <button class="sub-btn sub-btn-secondary" id="sub-manage-btn" onclick="subManageBilling()">Gerenciar cobrança</button>
  </div>
</div>

<!-- PIN editor modal -->
<div id="ep-overlay">
  <div class="ep-card">
    <button class="ep-close" onclick="cfgPinsClose()">&#xd7;</button>
    <div class="ep-title">Configurações do produtor</div>
    <div class="ep-sub">Edite seu nome de exibição, os PINs de acesso e o ponto de encontro padrão.</div>

    <div class="ep-section">
      <div class="ep-section-label">Identificação</div>
      <div class="ep-name-sublabel">Nome do produtor</div>
      <input class="ep-name-input" id="ep-name-input" type="text" maxlength="100" placeholder="Ex: Zeca" oninput="epNamesInput()" autocomplete="off">
      <div class="ep-name-sublabel">Nome do artista</div>
      <input class="ep-name-input" id="ep-artist-input" type="text" maxlength="100" placeholder="Ex: Artista Fulano" oninput="epNamesInput()" autocomplete="off">
      <div class="ep-save-row">
        <button class="ep-save-btn" id="ep-btn-names" disabled onclick="epSaveNames()">Salvar nomes</button>
      </div>
      <div class="ep-status" id="ep-status-names"></div>
    </div>

    <div class="ep-divider"></div>

    <div class="ep-section">
      <div class="ep-section-label">PIN da equipe</div>
      <div class="ep-digits" id="ep-digits-team">
        <input class="ob-digit" id="ep-t0" type="tel" maxlength="1" inputmode="numeric" pattern="[0-9]*" oninput="epDigit('team',0,this.value)" onkeydown="epKey('team',0,event)">
        <input class="ob-digit" id="ep-t1" type="tel" maxlength="1" inputmode="numeric" pattern="[0-9]*" oninput="epDigit('team',1,this.value)" onkeydown="epKey('team',1,event)">
        <input class="ob-digit" id="ep-t2" type="tel" maxlength="1" inputmode="numeric" pattern="[0-9]*" oninput="epDigit('team',2,this.value)" onkeydown="epKey('team',2,event)">
        <input class="ob-digit" id="ep-t3" type="tel" maxlength="1" inputmode="numeric" pattern="[0-9]*" oninput="epDigit('team',3,this.value)" onkeydown="epKey('team',3,event)">
      </div>
      <div class="ep-save-row">
        <button class="ep-save-btn" id="ep-btn-team" disabled onclick="epSave('team')">Salvar PIN da equipe</button>
      </div>
      <div class="ep-status" id="ep-status-team"></div>
    </div>

    <div class="ep-divider"></div>

    <div class="ep-section">
      <div class="ep-section-label">PIN do artista</div>
      <div class="ep-digits" id="ep-digits-artist">
        <input class="ob-digit" id="ep-a0" type="tel" maxlength="1" inputmode="numeric" pattern="[0-9]*" oninput="epDigit('artist',0,this.value)" onkeydown="epKey('artist',0,event)">
        <input class="ob-digit" id="ep-a1" type="tel" maxlength="1" inputmode="numeric" pattern="[0-9]*" oninput="epDigit('artist',1,this.value)" onkeydown="epKey('artist',1,event)">
        <input class="ob-digit" id="ep-a2" type="tel" maxlength="1" inputmode="numeric" pattern="[0-9]*" oninput="epDigit('artist',2,this.value)" onkeydown="epKey('artist',2,event)">
        <input class="ob-digit" id="ep-a3" type="tel" maxlength="1" inputmode="numeric" pattern="[0-9]*" oninput="epDigit('artist',3,this.value)" onkeydown="epKey('artist',3,event)">
      </div>
      <div class="ep-save-row">
        <button class="ep-save-btn" id="ep-btn-artist" disabled onclick="epSave('artist')">Salvar PIN do artista</button>
      </div>
      <div class="ep-status" id="ep-status-artist"></div>
    </div>

    <div class="ep-divider"></div>

    <div class="ep-section">
      <div class="ep-section-label">Ponto de encontro</div>
      <div class="ep-name-sublabel">Endereço padrão usado em novos shows</div>
      <div class="ep-presets">
        <button type="button" class="ep-preset-chip" onclick="epPickMeetingPreset('Rua Voluntários da Pátria, 233 - Santana, São Paulo - SP')">Unipare (SP)</button>
        <button type="button" class="ep-preset-chip" onclick="epPickMeetingPreset('Av. dos Democráticos, 1400 - Bonsucesso, Rio de Janeiro - RJ')">Saída 7 (RJ)</button>
      </div>
      <input class="ep-name-input" id="ep-meeting-input" type="text" maxlength="200" placeholder="Ex: Alameda Santos, 2233" oninput="epMeetingInput()" autocomplete="off">
      <div class="ep-save-row">
        <button class="ep-save-btn" id="ep-btn-meeting" disabled onclick="epSaveMeeting()">Salvar ponto de encontro</button>
      </div>
      <div class="ep-status" id="ep-status-meeting"></div>
    </div>
  </div>
</div>
`;

/* ── Fase 3a: aba Shows em React de verdade ──────────────────────────
   Tradução direta de render()/buildCard()/setSeg() (antes em
   shows-legacy.js) pra componentes React. Swipe-to-delete e
   drag-to-reorder (as duas IIFEs em shows-legacy.js) continuam
   INTOCADAS — operam no DOM que este componente renderiza, sem conflito,
   porque o React só re-renderiza a lista quando `shows`/`seg` mudam
   (evento 'flowz:shows-sync' ou ação local), nunca durante um arrasto.
   window._seg é mantido em sincronia pra armLP() (drag-reorder) continuar
   lendo o segmento certo. */

function ShowCard({ show, idx, past, onDelete }) {
  const d = window.parseLocalDate(show.date);
  if (!d && past) return null;

  const dayNum = d ? d.getDate() : '—';
  const month = d ? window.MONTHS[d.getMonth()] : '';
  const weekday = d ? window.DAYS[d.getDay()] : '';
  const delay = Math.min(idx * 0.06 + 0.05, 0.55).toFixed(2);
  const venueDedup = (show.venue && show.venue.trim() !== (show.name || '').trim()) ? show.venue : null;
  const meta = [venueDedup, show.city].filter(Boolean).join(' · ');
  const remDone = (show.reminders || []).filter((r) => r.done).length;
  const matDone = (show.materials || []).filter((m) => m.checked).length;
  const done = remDone + matDone;
  const total = (show.reminders || []).length + (show.materials || []).length;
  const progress = total > 0 ? done / total : 0;
  const progColor = progress >= 1 ? '#34D399' : 'var(--purple)';
  const meetingChip = !past && show.departureTimeMeetingShow;
  const showWx = !past && (show.city || show.venueAddress) && show.date;
  const pending = !show.logisticsFinalized && !past;

  return (
    <div className="show-card-wrap" data-id={String(show.id)} data-date={show.date || ''}>
      <div
        className="show-del-area"
        onClick={(e) => { e.stopPropagation(); onDelete(show.id); }}
      >
        <svg width="16" height="16" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
          <polyline points="3 6 5 6 21 6" />
          <path d="M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6" />
          <path d="M10 11v6M14 11v6" />
          <path d="M9 6V4a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v2" />
        </svg>
        Apagar
      </div>
      <a
        className={'show-card' + (past ? ' past' : '')}
        href={'show.html?id=' + encodeURIComponent(show.id)}
        style={{ animationDelay: delay + 's' }}
      >
        <div className="card-inner">
          <div className="date-col">
            <div className="date-day">{dayNum}</div>
            <div className="date-month">{month}</div>
            <div className="date-week">{weekday}</div>
          </div>
          <div className="card-body">
            <div className="card-top-row">
              <div style={{ flex: 1, minWidth: 0 }}>
                <div className="card-name">{show.name}</div>
                {meta ? <div className="card-venue">{meta}</div> : null}
              </div>
              {show.logisticsFinalized ? (
                <span className="card-status ok" title="Logística finalizada">
                  <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="#fff" strokeWidth="3.2" strokeLinecap="round" strokeLinejoin="round">
                    <polyline points="20 6 9 17 4 12" />
                  </svg>
                </span>
              ) : null}
            </div>
            {show.time ? (
              <div className="card-time-row"><div className="card-time-main"><div className="card-time">{show.time}</div></div></div>
            ) : !past ? (
              <div className="card-time-row"><div className="card-time-main"><div className="card-time-tbd">A definir horário do show</div></div></div>
            ) : null}
            {meetingChip ? (
              <div className="card-footer">
                <div className="meeting-chip">
                  <div className="meeting-dot" />
                  Encontro {show.departureTimeMeetingShow}
                </div>
              </div>
            ) : null}
            {total > 0 ? (
              <div className="progress-row">
                <div className="progress-track">
                  <div className="progress-fill" style={{ width: Math.round(progress * 100) + '%', background: progColor }} />
                </div>
                <div className="progress-count">{done}/{total}</div>
              </div>
            ) : null}
            {showWx ? <div className="show-wx" id={'swx-' + String(show.id)} /> : null}
          </div>
          {pending ? (
            <div className="card-pending-col">
              <span className="card-pending" title="Aguardando logística">
                <span className="card-spin" />
                <span className="card-pending-txt">Preparando logística</span>
              </span>
            </div>
          ) : null}
        </div>
      </a>
      <div className="card-actions">
        <button
          className="ca-btn" title="Editar show" aria-label="Editar show"
          onClick={(e) => { e.preventDefault(); e.stopPropagation(); window.editShow(String(show.id)); }}
        >
          <svg width="13" height="13" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
            <path d="M17 3a2.85 2.83 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5Z" />
          </svg>
        </button>
        <button
          className="ca-btn ca-danger" title="Apagar show" aria-label="Apagar show"
          onClick={(e) => { e.preventDefault(); e.stopPropagation(); onDelete(show.id); }}
        >
          <svg width="13" height="13" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
            <polyline points="3 6 5 6 21 6" />
            <path d="M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6" />
            <path d="M10 11v6M14 11v6" />
            <path d="M9 6V4a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v2" />
          </svg>
        </button>
      </div>
    </div>
  );
}

function ShowsSkeleton() {
  const delays = [0.05, 0.13, 0.21, 0.29];
  return (
    <div className="sk-list" role="status" aria-label="Carregando shows…">
      {delays.map((d, i) => (
        <div className="sk-card" style={{ animationDelay: d + 's' }} key={i}>
          <div className="sk-date" />
          <div className="sk-body">
            <div className="sk-line lg sk-w55" />
            <div className="sk-line sk-w75" />
            <div className="sk-line sk-w35" />
          </div>
        </div>
      ))}
    </div>
  );
}

function ShowsEmpty({ isPast }) {
  return (
    <div className="empty fade-up">
      <div className="empty-icon">
        <svg width="36" height="36" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round">
          <rect x="9" y="2" width="6" height="11" rx="3" />
          <path d="M5 10a7 7 0 0 0 14 0" />
          <line x1="12" y1="17" x2="12" y2="21" />
          <line x1="9" y1="21" x2="15" y2="21" />
        </svg>
      </div>
      <div className="empty-title">{isPast ? 'Nenhum show realizado' : 'Nenhum show agendado'}</div>
      <div className="empty-sub">{isPast ? 'Shows concluídos aparecem aqui.' : 'Adicione o primeiro show da agenda.'}</div>
      {!isPast ? (
        <button className="empty-cta" onClick={() => { window.location.href = '/criar-show/'; }}>
          <svg width="16" height="16" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round">
            <line x1="12" y1="5" x2="12" y2="19" />
            <line x1="5" y1="12" x2="19" y2="12" />
          </svg>
          Criar show
        </button>
      ) : null}
    </div>
  );
}

function ShowsDownBanner() {
  const html = window.svcDownBannerHtml ? window.svcDownBannerHtml() : '';
  return <div dangerouslySetInnerHTML={{ __html: html }} />;
}

function ShowsScreen() {
  const [shows, setShows] = useState(null); // null = ainda não carregou (skeleton)
  const [seg, setSegState] = useState('upcoming');
  const [svcDown, setSvcDown] = useState(false);

  useEffect(() => {
    function onSync(e) {
      if (e.detail && e.detail.ok === false) {
        setSvcDown(true);
        return;
      }
      setSvcDown(false);
      setShows((window._allShows || []).slice());
    }
    window.addEventListener('flowz:shows-sync', onSync);
    if (window._allShows && window._allShows.length) setShows(window._allShows.slice());
    return () => window.removeEventListener('flowz:shows-sync', onSync);
  }, []);

  function setSeg(next) {
    window._seg = next; // drag-reorder (armLP em shows-legacy.js) lê esse global
    setSegState(next);
  }

  // qcSave() (quick-create, ainda legado até a Fase 3b) troca pra "Próximos"
  // depois de criar shows — expõe o setter pra ele conseguir chamar.
  useEffect(() => {
    window.setSeg = setSeg;
    return () => { delete window.setSeg; };
  });

  // Recalculado a cada render (sem useMemo de propósito): o drag-reorder
  // legado muta show.sortIndex nos MESMOS objetos que `shows` referencia,
  // sem trocar a referência do array (é assim que ele evita brigar com o
  // React durante o arrasto — ver Fase 3 do plano de migração). Um
  // useMemo com dependência [shows] ficaria com a ordenação em cache
  // desatualizada depois de um drag, e o próximo re-render por qualquer
  // outro motivo (ex: trocar de segmento) devolvia a lista pra ordem
  // antiga — o React reconciliava o DOM de volta, desfazendo o arrasto
  // visualmente mesmo com o servidor já persistido na ordem nova. Sem
  // memo, cada render já lê o sortIndex atual. Lista não tem
  // virtualização (não passa de ~100 itens hoje), custo é desprezível.
  const all = shows || [];
  const upcoming = all
    .filter((s) => !s.date || !window._showIsPast(s))
    .sort((a, b) => {
      const da = a.date || '9999', db = b.date || '9999';
      if (da !== db) return da < db ? -1 : 1;
      const sa = window._sortIdx(a), sb = window._sortIdx(b);
      if (sa !== sb) return sa - sb;
      return window._timeSortVal(a.time) - window._timeSortVal(b.time);
    });
  const past = all
    .filter((s) => s.date && window._showIsPast(s))
    .sort((a, b) => {
      if (a.date !== b.date) return a.date < b.date ? 1 : -1;
      return window._timeSortVal(b.time) - window._timeSortVal(a.time);
    });

  const isPast = seg === 'past';
  const list = isPast ? past : upcoming;

  useEffect(() => {
    const totalEl = document.getElementById('title-meta');
    if (totalEl && shows) totalEl.textContent = shows.length + ' shows · ' + upcoming.length + ' agendados';
  }, [shows, upcoming.length]);

  useEffect(() => {
    if (!isPast && list.length) window.loadAllWeather(list, 'swx-');
    // eslint-disable-next-line
  }, [list, isPast]);

  async function handleDelete(id) {
    if (!window.confirm('Apagar este show?')) return;
    const token = window.getAuthToken();
    const res = await fetch(window.SUPABASE_URL + '/rest/v1/shows?id=eq.' + id, {
      method: 'DELETE',
      headers: { apikey: window.SUPABASE_ANON, Authorization: 'Bearer ' + token },
    });
    if (res.ok) {
      const filtered = (window._allShows || []).filter((s) => s.id !== id);
      window._allShows = filtered;
      setShows(filtered.slice());
    } else {
      window.showToast('Erro ao apagar show', 'danger');
    }
  }

  let groups = null;
  if (!isPast) {
    let currentMonth = null;
    groups = [];
    list.forEach((s, i) => {
      const d = window.parseLocalDate(s.date);
      if (d) {
        const mKey = d.getFullYear() + '-' + d.getMonth();
        if (mKey !== currentMonth) {
          currentMonth = mKey;
          groups.push({ type: 'hdr', key: 'hdr-' + mKey, label: window.MONTHS_FULL[d.getMonth()] + ' ' + d.getFullYear() });
        }
      }
      groups.push({ type: 'card', key: String(s.id), show: s, idx: i });
    });
  }

  return (
    <div id="panel-shows" className="tab-panel active">
      <section className="title-block fade-up" style={{ animationDelay: '.05s' }}>
        <div className="title-head">
          <span className="eyebrow" id="shows-eyebrow">Pré-produção</span>
          <h1 className="title-h1">Pré-produção.</h1>
          <div className="title-meta" id="title-meta">Carregando…</div>
        </div>
        <div className="title-actions">
          <button className="sync-btn logi-primary" id="logi-check-btn" onClick={() => window.logiOpen()} title="Verificar logística">
            <svg width="13" height="13" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
              <circle cx="6" cy="19" r="3" /><circle cx="18" cy="5" r="3" /><path d="M9 19h6a4 4 0 0 0 0-8h-4a4 4 0 0 1 0-8h4" />
            </svg>
            Verificar logística
          </button>
          <button className="sync-btn" id="sync-btn" onClick={() => window.syncShows()} title="Sincronizar">
            <svg width="13" height="13" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round">
              <polyline points="23 4 23 10 17 10" /><polyline points="1 20 1 14 7 14" /><path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15" />
            </svg>
            Sincronizar
          </button>
        </div>
      </section>

      <div className="seg-wrap fade-up" style={{ animationDelay: '.12s' }} role="group" aria-label="Filtrar shows">
        <button className={'seg-btn' + (!isPast ? ' active' : '')} id="seg-upcoming" aria-pressed={!isPast} onClick={() => setSeg('upcoming')}>Próximos</button>
        <button className={'seg-btn' + (isPast ? ' active' : '')} id="seg-past" aria-pressed={isPast} onClick={() => setSeg('past')}>Realizados</button>
      </div>

      <div id="content">
        {svcDown ? (
          <ShowsDownBanner />
        ) : shows === null ? (
          <ShowsSkeleton />
        ) : list.length === 0 ? (
          <ShowsEmpty isPast={isPast} />
        ) : (
          <div className="list">
            {isPast ? (
              <React.Fragment>
                <div className="section-hdr">Realizados</div>
                {list.map((s, i) => <ShowCard key={String(s.id)} show={s} idx={i} past onDelete={handleDelete} />)}
              </React.Fragment>
            ) : (
              groups.map((g) => g.type === 'hdr'
                ? <div className="section-hdr" key={g.key}>{g.label}</div>
                : <ShowCard key={g.key} show={g.show} idx={g.idx} past={false} onDelete={handleDelete} />
              )
            )}
          </div>
        )}
      </div>
    </div>
  );
}

/* ── Fase 3b: quick-create wizard em React de verdade ────────────────
   Tradução de qcOpen/qcClose/qcNav/qcRenderCal/qcToggleDay/qcMaskTime/
   qcSync/qcSave (removidos de shows-legacy.js) pra estado local. Sem
   geometria/gesto — forma pura, risco baixo. Helpers puros
   (qcUUID/qcYMD/qcHasShow/qcBuildShowData/qcFallbackName) continuam em
   shows-legacy.js, chamados via window.*. */

function QuickCreateDialog() {
  const [open, setOpen] = useState(false);
  const [month, setMonth] = useState(() => { const d = new Date(); return new Date(d.getFullYear(), d.getMonth(), 1); });
  const [sel, setSel] = useState(() => new Set());
  const [name, setName] = useState('');
  const [time, setTime] = useState('');
  const [saving, setSaving] = useState(false);
  const nameRef = useRef(null);

  useEffect(() => {
    window.qcOpen = function () {
      const now = new Date();
      setMonth(new Date(now.getFullYear(), now.getMonth(), 1));
      setSel(new Set());
      setName('');
      setTime('');
      setSaving(false);
      setOpen(true);
      document.body.style.overflow = 'hidden';
      setTimeout(() => { if (nameRef.current) nameRef.current.focus(); }, 340);
    };
    return () => { delete window.qcOpen; };
  });

  function close() {
    setOpen(false);
    document.body.style.overflow = '';
  }

  function nav(delta) {
    const next = new Date(month.getFullYear(), month.getMonth() + delta, 1);
    const floor = new Date(); floor.setDate(1); floor.setHours(0, 0, 0, 0);
    if (next < floor) return;
    setMonth(next);
  }

  function toggleDay(ymd) {
    setSel((prev) => {
      const next = new Set(prev);
      if (next.has(ymd)) next.delete(ymd); else next.add(ymd);
      return next;
    });
  }

  function maskTime(raw) {
    let v = raw.replace(/\D/g, '').slice(0, 4);
    if (v.length >= 3) v = v.slice(0, 2) + ':' + v.slice(2);
    setTime(v);
  }

  async function save() {
    if (saving) return;
    const dates = Array.from(sel).sort();
    if (!dates.length) return;
    const timeVal = /^\d{1,2}:\d{2}$/.test(time.trim()) ? time.trim() : '';
    const userId = window.getUserId();
    if (!userId) { window.showToast('Sessão expirada. Faça login novamente.', 'danger'); return; }
    setSaving(true);
    try {
      const token = (await window.getAuthTokenFresh()) || window.getAuthToken();
      const now = new Date().toISOString();
      const rows = dates.map((date) => {
        const id = window.qcUUID();
        return {
          id: id, user_id: userId,
          data: Object.assign(window.qcBuildShowData(name.trim() || window.qcFallbackName(date), date, timeVal), { id: id, createdAt: now, updatedAt: now }),
        };
      });
      const res = await fetch(window.SUPABASE_URL + '/rest/v1/shows', {
        method: 'POST',
        headers: { apikey: window.SUPABASE_ANON, Authorization: 'Bearer ' + token, 'Content-Type': 'application/json', Prefer: 'return=minimal' },
        body: JSON.stringify(rows),
      });
      if (!res.ok) {
        let t = ''; try { t = await res.text(); } catch (e2) {}
        throw new Error('HTTP ' + res.status + (t ? ' — ' + t : ''));
      }
      close();
      window.setSeg('upcoming');
      await window.load();
      window.showToast(rows.length > 1 ? rows.length + ' shows criados' : 'Show criado', 'success', name.trim());
    } catch (e) {
      window.showToast('Erro ao criar', 'danger', e.message);
    } finally {
      setSaving(false);
    }
  }

  const y = month.getFullYear(), m = month.getMonth();
  const startDow = new Date(y, m, 1).getDay();
  const daysIn = new Date(y, m + 1, 0).getDate();
  const today = new Date(); today.setHours(0, 0, 0, 0);
  const cells = [];
  for (let i = 0; i < startDow; i++) cells.push(<div className="qc-day empty" key={'e' + i} />);
  for (let d = 1; d <= daysIn; d++) {
    const ymd = window.qcYMD(y, m, d);
    const dt = new Date(y, m, d);
    const isPast = dt < today;
    const isToday = dt.getTime() === today.getTime();
    const hasShow = window.qcHasShow(ymd);
    const isSel = sel.has(ymd);
    let cls = 'qc-day';
    if (isPast) cls += ' past';
    if (isToday) cls += ' today';
    if (hasShow) cls += ' has';
    if (isSel) cls += ' sel';
    cells.push(<div className={cls} key={ymd} onClick={isPast ? undefined : () => toggleDay(ymd)}>{d}</div>);
  }

  const n = sel.size;
  const saveLabel = n > 1 ? 'Criar ' + n + ' shows' : 'Criar show';

  if (!open) return null;

  return (
    <div className="qc-overlay" id="qc-overlay" style={{ display: 'block' }} onClick={close}>
      <div className="qc-sheet" onClick={(e) => e.stopPropagation()} role="dialog" aria-modal="true" aria-label="Criar shows rápido">
        <button className="qc-close" onClick={close} aria-label="Fechar">
          <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.4" strokeLinecap="round" aria-hidden="true">
            <line x1="18" y1="6" x2="6" y2="18" /><line x1="6" y1="6" x2="18" y2="18" />
          </svg>
        </button>
        <div className="qc-grip" />
        <div className="qc-head">
          <div className="qc-eyebrow">
            <svg width="12" height="12" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M13 2 4.5 13.5H11l-1 8.5 8.5-11.5H12l1-8.5z" /></svg>
            Criação rápida
          </div>
          <div className="qc-title">Novos shows</div>
        </div>
        <div className="qc-body">
          <div className="qc-label"><span className="n">1</span>Nome do show</div>
          <input className="qc-input" id="qc-name" ref={nameRef} type="text" placeholder="Ex: Henrique & Juliano" autoComplete="off" value={name} onChange={(e) => setName(e.target.value)} />

          <div className="qc-label"><span className="n">2</span>Datas <span id="qc-count" style={{ marginLeft: 'auto', fontFamily: 'var(--font-mono)', fontSize: 10, color: 'var(--text-3)' }}>{n ? n + (n > 1 ? ' datas' : ' data') : ''}</span></div>
          <div className="qc-cal">
            <div className="qc-cal-bar">
              <button className="qc-cal-nav" onClick={() => nav(-1)} aria-label="Mês anterior">
                <svg width="14" height="14" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2.4" strokeLinecap="round" strokeLinejoin="round"><polyline points="15 18 9 12 15 6" /></svg>
              </button>
              <div className="qc-cal-mon" id="qc-cal-mon">{window.MONTHS_FULL[m] + ' ' + y}</div>
              <button className="qc-cal-nav" onClick={() => nav(1)} aria-label="Próximo mês">
                <svg width="14" height="14" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2.4" strokeLinecap="round" strokeLinejoin="round"><polyline points="9 18 15 12 9 6" /></svg>
              </button>
            </div>
            <div className="qc-cal-wd"><span>Dom</span><span>Seg</span><span>Ter</span><span>Qua</span><span>Qui</span><span>Sex</span><span>Sáb</span></div>
            <div className="qc-cal-grid" id="qc-cal-grid">{cells}</div>
          </div>

          <div className="qc-label"><span className="n">3</span>Horário</div>
          <div className="qc-time-row">
            <div className="qc-time-info">
              <div className="qc-time-t">A definir</div>
              <div className="qc-time-s">Deixe em branco ou informe o horário de todos os shows.</div>
            </div>
            <input className="qc-time-input" id="qc-time" type="text" inputMode="numeric" maxLength={5} placeholder="--:--" value={time} onChange={(e) => maskTime(e.target.value)} />
          </div>
        </div>
        <div className="qc-foot">
          <button className="qc-save" id="qc-save" onClick={save} disabled={!(n > 0) || saving}>
            {saving ? <span><span className="qc-spin" /> Criando...</span> : <span id="qc-save-label">{saveLabel}</span>}
          </button>
        </div>
      </div>
    </div>
  );
}

/* ── Fase 3c: modal de verificar logística em React de verdade ──────
   Tradução de logiOpen/logiClose/logiFilter/logiPick/logiChange/
   logiSetType/logiCheckReady/logiOpenRoute/_logiState/_logiAddr
   (removidos de shows-legacy.js) pra estado local. Sem geometria/
   gesto — forma pura, mesmo risco baixo da Fase 3b. _logiGeocodeCheck
   continua em shows-legacy.js (helper puro reusado via window.*). */

function logiAddr(entry) {
  const show = entry.show;
  if (entry.type === 'hotel') {
    return { full: show.hotelAddress || show.hotelName || '', fallback: (show.hotelName || '') + (show.city ? ', ' + show.city : '') };
  }
  return {
    full: show.venueAddress || ((show.venue || '') + (show.city ? ', ' + show.city : '')),
    fallback: (show.venue || '') + (show.city ? ', ' + show.city : ''),
  };
}

function LogiSlot({ n, label, state, query, touched, onQuery, onFocus, onPick, onChange, onSetType }) {
  const matches = React.useMemo(() => {
    const all = window._allShows || [];
    const q = (query || '').trim().toLowerCase();
    const pool = q
      ? all.filter((s) => { if (!s.date) return false; const hay = [s.name, s.city, s.venue].filter(Boolean).join(' ').toLowerCase(); return hay.indexOf(q) !== -1; })
      : all.filter((s) => !!s.date);
    return pool.sort((a, b) => (a.date < b.date ? -1 : 1)).slice(0, q ? 8 : 20);
  }, [query, state.show]);

  if (state.show) {
    const show = state.show;
    const d = window.parseLocalDate(show.date);
    const dLabel = d ? (d.getDate() + ' ' + window.MONTHS[d.getMonth()]) : '';
    const hasHotel = !!(show.hasHotel && (show.hotelAddress || show.hotelName));
    return (
      <div className="logi-selected">
        <div className="logi-selected-info">
          <div className="logi-selected-name">{(show.name || 'Show') + (dLabel ? ' · ' + dLabel : '')}</div>
          <button className="logi-selected-change" onClick={onChange}>Trocar</button>
        </div>
        <div className="logi-toggle">
          <button className={'logi-toggle-btn' + (state.type === 'venue' ? ' active' : '')} onClick={() => onSetType('venue')}>Local do show</button>
          <button className={'logi-toggle-btn' + (state.type === 'hotel' ? ' active' : '')} disabled={!hasHotel} onClick={() => onSetType('hotel')}>Hotel</button>
        </div>
      </div>
    );
  }

  return (
    <div className="logi-picker">
      <input
        className="qc-input" type="text" placeholder="Buscar show por nome, cidade ou casa…"
        aria-label={label} autoComplete="off" value={query}
        onChange={(e) => onQuery(e.target.value)} onFocus={onFocus}
      />
      {touched && (
        <div className="logi-list" role="listbox" aria-label="Resultados da busca" aria-live="polite">
          {matches.length
            ? matches.map((s) => {
                const d = window.parseLocalDate(s.date);
                const dLabel = d ? (d.getDate() + ' ' + window.MONTHS[d.getMonth()]) : '';
                const sub = [s.venue, s.city].filter(Boolean).join(' · ');
                return (
                  <button type="button" className="logi-item" role="option" key={s.id} onClick={() => onPick(s)}>
                    <span className="logi-item-date">{dLabel}</span>
                    <span className="logi-item-info">
                      <div className="logi-item-name">{s.name || 'Show'}</div>
                      {sub ? <div className="logi-item-sub">{sub}</div> : null}
                    </span>
                  </button>
                );
              })
            : <div className="logi-empty">Nenhum show encontrado</div>}
        </div>
      )}
    </div>
  );
}

function LogisticsDialog() {
  const [open, setOpen] = useState(false);
  const [slots, setSlots] = useState({ 1: { show: null, type: 'venue' }, 2: { show: null, type: 'venue' } });
  const [queries, setQueries] = useState({ 1: '', 2: '' });
  const [touched, setTouched] = useState({ 1: false, 2: false });
  const [checking, setChecking] = useState(false);

  useEffect(() => {
    window.logiOpen = function () {
      setSlots({ 1: { show: null, type: 'venue' }, 2: { show: null, type: 'venue' } });
      setQueries({ 1: '', 2: '' });
      setTouched({ 1: false, 2: false });
      setChecking(false);
      setOpen(true);
      document.body.style.overflow = 'hidden';
    };
    return () => { delete window.logiOpen; };
  });

  function close() {
    setOpen(false);
    document.body.style.overflow = '';
  }

  function pick(n, show) {
    const hasHotel = !!(show.hasHotel && (show.hotelAddress || show.hotelName));
    setSlots((prev) => ({ ...prev, [n]: { show, type: hasHotel ? prev[n].type : 'venue' } }));
  }

  function change(n) {
    setSlots((prev) => ({ ...prev, [n]: { show: null, type: 'venue' } }));
    setQueries((prev) => ({ ...prev, [n]: '' }));
    setTouched((prev) => ({ ...prev, [n]: false }));
  }

  function setType(n, type) {
    setSlots((prev) => ({ ...prev, [n]: { ...prev[n], type } }));
  }

  async function openRoute() {
    if (!slots[1].show || !slots[2].show || checking) return;
    setChecking(true);
    const a = logiAddr(slots[1]);
    const b = logiAddr(slots[2]);
    let origin = a.full, destination = b.full;
    try {
      if (a.full && a.fallback && a.full !== a.fallback) {
        const okA = await window._logiGeocodeCheck(a.full);
        if (!okA) origin = a.fallback;
      }
      if (b.full && b.fallback && b.full !== b.fallback) {
        const okB = await window._logiGeocodeCheck(b.full);
        if (!okB) destination = b.fallback;
      }
    } catch (e) {}
    setChecking(false);
    if (!origin || !destination) { window.showToast('Endereço não encontrado pra um dos pontos', 'danger'); return; }
    const url = 'https://www.google.com/maps/dir/?api=1&origin=' + encodeURIComponent(origin) + '&destination=' + encodeURIComponent(destination) + '&travelmode=driving';
    window.open(url, '_blank');
    close();
  }

  if (!open) return null;

  const ready = !!(slots[1].show && slots[2].show);

  return (
    <div className="qc-overlay" id="logi-overlay" style={{ display: 'block' }} onClick={close}>
      <div className="qc-sheet" onClick={(e) => e.stopPropagation()} role="dialog" aria-modal="true" aria-label="Verificar logística">
        <button className="qc-close" onClick={close} aria-label="Fechar">
          <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.4" strokeLinecap="round" aria-hidden="true">
            <line x1="18" y1="6" x2="6" y2="18" /><line x1="6" y1="6" x2="18" y2="18" />
          </svg>
        </button>
        <div className="qc-grip" />
        <div className="qc-head">
          <div className="qc-eyebrow">
            <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.4" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
              <circle cx="6" cy="19" r="3" /><circle cx="18" cy="5" r="3" /><path d="M9 19h6a4 4 0 0 0 0-8h-4a4 4 0 0 1 0-8h4" />
            </svg>
            Logística
          </div>
          <div className="qc-title">Verificar rota entre shows</div>
        </div>
        <div className="qc-body">
          <div className="qc-label"><span className="n">1</span>Ponto de partida</div>
          <LogiSlot
            n={1} label="Buscar show do ponto de partida" state={slots[1]} query={queries[1]} touched={touched[1]}
            onQuery={(v) => setQueries((p) => ({ ...p, 1: v }))}
            onFocus={() => setTouched((p) => ({ ...p, 1: true }))}
            onPick={(s) => pick(1, s)} onChange={() => change(1)} onSetType={(t) => setType(1, t)}
          />

          <div className="qc-label" style={{ marginTop: 18 }}><span className="n">2</span>Destino</div>
          <LogiSlot
            n={2} label="Buscar show do destino" state={slots[2]} query={queries[2]} touched={touched[2]}
            onQuery={(v) => setQueries((p) => ({ ...p, 2: v }))}
            onFocus={() => setTouched((p) => ({ ...p, 2: true }))}
            onPick={(s) => pick(2, s)} onChange={() => change(2)} onSetType={(t) => setType(2, t)}
          />
        </div>
        <div className="qc-foot">
          <button className="qc-save" onClick={openRoute} disabled={!ready || checking}>
            {checking ? 'Verificando endereços…' : 'Ver rota no Google Maps'}
          </button>
        </div>
      </div>
    </div>
  );
}

function LegacyAppBridge() {
  const preAppRef = useRef(null);
  const headerRef = useRef(null);
  const afterShowsRef = useRef(null);
  const postAppRef = useRef(null);
  const modalsRef = useRef(null);
  const bootedRef = useRef(false);

  useEffect(() => {
    if (bootedRef.current) return; // StrictMode/dev double-invoke guard
    bootedRef.current = true;

    preAppRef.current.innerHTML = PRE_APP_HTML;
    headerRef.current.innerHTML = HEADER_HTML;
    afterShowsRef.current.innerHTML = AFTER_SHOWS_HTML;
    postAppRef.current.innerHTML = POST_APP_HTML;
    modalsRef.current.innerHTML = FLOATING_MODALS_HTML;

    if (document.documentElement.classList.contains('sidebar-collapsed')) {
      var collapseBtn = document.querySelector('.sb-collapse');
      if (collapseBtn) {
        collapseBtn.setAttribute('aria-label', 'Expandir menu');
        collapseBtn.setAttribute('title', 'Expandir menu');
      }
    }

    // Sequência de bootstrap que antes rodava no fim do <script> monolítico
    // (shows.html linhas 4851-4862) — adiada pra cá porque depende do DOM
    // acima já estar montado (load() escreve em #content, #agenda-content
    // etc.).
    window.load();
    window._initDirectNotifSubscription();
    window.checkSubscriptionStatus();

    var onVisible = function () {
      if (document.visibilityState === 'visible') window.load();
    };
    var onPageShow = function (e) {
      document.documentElement.classList.remove('page-out');
      if (e.persisted) window.load();
    };
    document.addEventListener('visibilitychange', onVisible);
    window.addEventListener('pageshow', onPageShow);
    return function () {
      document.removeEventListener('visibilitychange', onVisible);
      window.removeEventListener('pageshow', onPageShow);
    };
  }, []);

  return (
    <>
      <div ref={preAppRef} />
      <div className="app">
        <div ref={headerRef} />
        <ShowsScreen />
        <div ref={afterShowsRef} />
      </div>
      <div ref={postAppRef} />
      <div ref={modalsRef} />
      <QuickCreateDialog />
      <LogisticsDialog />
    </>
  );
}

function App() {
  return <LegacyAppBridge />;
}

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