      /* =====================================================================
         FORMULÁRIO EM TELA CHEIA (Onda 2) — bloco final, de propósito.
         .modal/.modalcard têm ~15 declarações espalhadas pelo arquivo, uma
         por breakpoint de responsividade acumulado ao longo do tempo. Em
         vez de caçar e editar cada uma (risco real de esquecer alguma —
         já aconteceu antes com o recolher da sidebar), esse bloco fica
         DE PROPÓSITO por último no arquivo, com a MESMA especificidade
         (ou igual à mais alta encontrada, #modal .modalcard) — por regra
         de cascata do CSS, um seletor de especificidade igual escrito
         depois sempre vence, em qualquer viewport, sem precisar tocar
         nas regras antigas. Nenhuma lógica de abrir/fechar/detectar
         alteração não salva mudou — só a aparência.
         ===================================================================== */
      /* top fixo (não é 0): o formulário NUNCA pode cobrir o cabeçalho da
         página (título do módulo + descrição, dentro de .top) — regra
         permanente. Já tentamos manter isso com JS medindo a altura de
         .top (frágil: dependia da posição de rolagem no momento exato da
         medição) e com position:sticky + margens negativas (quebrava o
         respiro/padding do topo da página) — as duas causaram bugs visuais
         em cascata. Esta versão usa um valor fixo generoso em CSS puro: sem
         JS, sem sticky, sem depender de rolagem. Pode sobrar um pouco mais
         de respiro do que o estritamente necessário, mas NUNCA cobre o
         cabeçalho, em qualquer cenário. Ajustado por breakpoint porque
         .top muda de tamanho (empilha em telas estreitas). */
      #modal.modal {
        position: fixed;
        top: 88px;
        right: 0;
        bottom: 0;
        left: var(--side-w, 280px);
        padding: 0;
        background: var(--surf-0);
        /* Borda + sombra no topo: sem isso, com o mesmo fundo do
           cabeçalho/página, o respiro acima do formulário e o formulário em
           si pareciam um bloco só, sem separação visual nenhuma. */
        border-top: 1px solid var(--line);
        box-shadow: 0 -10px 24px rgba(0, 0, 0, 0.1);
        display: block;
      }
      /* .top empilha (título, descrição e botões um embaixo do outro)
         abaixo de 900px — fica bem mais alto, então o formulário precisa
         de mais respiro no topo pra não cobrir nada dela. Fica DEPOIS da
         regra de cima (mesma especificidade #modal.modal) de propósito:
         em CSS, entre regras empatadas, a que vem depois no arquivo vence
         — colocar isso antes faria a regra de cima sempre ganhar, mesmo
         dentro da media query. */
      @media (max-width: 900px) {
        #modal.modal {
          top: 210px;
        }
      }
      #modal .modalcard {
        width: 100%;
        max-width: none;
        height: 100%;
        max-height: none;
        border-radius: 0;
        border: none;
        box-shadow: none;
        padding: 0;
        display: flex;
        flex-direction: column;
      }
      /* No Calendário em tela cheia (body.calendar-fullscreen-mode) não
         existe ".top"/menu lateral pra proteger, e o formulário em tela
         cheia cobrindo tudo fica estranho por cima da agenda em fullscreen
         real do navegador — volta pro formato antigo de popup centralizado
         com fundo escurecido/blur, só nesse cenário específico. Precisa de
         especificidade MAIOR que #modal.modal/#modal .modalcard acima
         (que já usam ID) pra vencer, por isso o prefixo "body.calendar-
         fullscreen-mode" na frente. */
      body.calendar-fullscreen-mode #modal.modal {
        position: fixed;
        inset: 0;
        top: 0;
        left: 0;
        background: var(--overlay);
        backdrop-filter: blur(7px);
        -webkit-backdrop-filter: blur(7px);
        display: grid;
        place-items: center;
        padding: 16px;
        border-top: none;
        box-shadow: none;
      }
      body.calendar-fullscreen-mode #modal .modalcard {
        width: min(980px, calc(100vw - 32px));
        max-width: 980px;
        height: auto;
        max-height: calc(100dvh - 32px);
        overflow: auto;
        background: var(--surf-2);
        border: 1px solid var(--line);
        border-radius: 22px;
        box-shadow: var(--shadow);
        padding: 0;
      }
      /* #confirmDialog reaproveita as mesmas classes .modal/.modalcard do
         formulário em tela cheia, mas PRECISA continuar sendo um diálogo
         pequeno centralizado (Confirmar/Cancelar) — nunca tela cheia. As
         regras acima usam o seletor #modal (não .modal solto) exatamente
         por isso: pra não vazar pra cá. Esse bloco, com especificidade de
         ID, garante a aparência de diálogo pequeno independente de onde
         mais no arquivo `.modal`/`.modalcard` (soltas) apareçam. */
      #confirmDialog.modal {
        position: fixed;
        inset: 0;
        left: 0;
        display: flex;
        align-items: center;
        justify-content: center;
        padding: 16px;
        background: var(--overlay);
      }
      #confirmDialog .modalcard {
        width: min(420px, calc(100vw - 32px));
        max-width: min(420px, calc(100vw - 32px));
        height: auto;
        max-height: 90vh;
        overflow: auto;
        border-radius: var(--radius);
        border: 1px solid var(--line);
        box-shadow: 0 24px 60px rgba(0, 0, 0, 0.35);
        padding: 28px 24px 22px;
        display: block;
      }
      /* Cabeçalho (voltar + título/subtítulo + Cancelar/Salvar) fica fixo
         durante a rolagem de um formulário longo — comum em telas cheias,
         sem isso o usuário perderia o botão Salvar de vista ao rolar. O
         padding que antes ficava em .modalcard todo migra pra cá + pro
         #modalBody, pra não sobrar respiro estranho acima do cabeçalho
         fixo (sticky respeita o padding do ancestral com scroll).
         Usa o prefixo #modal pra empatar (e, por vir depois, vencer) a
         especificidade das regras antigas "#modal .modalhead..." feitas
         só pro modal de alocações (linhas ~3500-3760) — sem isso, aquelas
         regras (padding/gap/border-bottom diferentes) continuariam
         ganhando por terem um seletor de ID. */
      #modal .modalhead,
      .modalhead {
        flex: 0 0 auto;
        display: flex;
        justify-content: space-between;
        align-items: center;
        gap: 14px;
        padding: 13px 32px;
        margin-bottom: 0;
        border-bottom: 1px solid var(--line);
        background: var(--surf-0);
      }
      #modal .modalhead h3,
      .modalTitles h3 {
        margin: 0;
        font-size: 17px;
        font-weight: 900;
        line-height: 1.25;
        letter-spacing: normal;
      }
      #modalBody {
        flex: 1 1 auto;
        overflow-y: auto;
        padding: 24px 32px;
        scrollbar-width: thin;
      }
      #modalBody::-webkit-scrollbar {
        width: 8px;
      }
      #modalBody::-webkit-scrollbar-thumb {
        background: var(--line);
        border-radius: 20px;
      }
      /* Enquanto recarrega, o ícone gira para dar retorno visual. */
      .syncStatus.isRefreshing {
        pointer-events: none;
        opacity: 0.75;
      }
      .syncStatus.isRefreshing i {
        animation: syncSpin 0.8s linear infinite;
      }
      @keyframes syncSpin {
        to {
          transform: rotate(360deg);
        }
      }
      @media (max-width: 720px) {
        /* Em telas estreitas mostra só o ícone, para não competir com o
           botão de nova alocação. */
        .syncStatus span {
          display: none;
        }
      }
