leonardo 1 місяць тому
батько
коміт
b97f4b524d

+ 1 - 2
index.html

@@ -2,8 +2,7 @@
 <html lang="pt-BR">
   <head>
     <meta charset="UTF-8" />
-    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1" />
+    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
     <meta name="description" content="Assistente interno com base de conhecimento — busca em documentos e atendimentos." />
     <meta name="theme-color" content="#1e2d4b" />
     <meta property="og:title" content="ORÁCULO" />

+ 1 - 0
src/components/BotaoAlterarTema.vue

@@ -11,6 +11,7 @@ const { darkMode } = useTheme();
     type="button"
     class="inline-flex items-center justify-center rounded-md !p-2 !bg-none !bg-transparent !border-0 !text-current hover:!bg-black/10 dark:hover:!bg-white/10 motion-safe:transition-colors"
     aria-label="Alternar tema"
+    :aria-pressed="darkMode"
     @click="darkMode = !darkMode"
   >
     <Transition name="tema-icon" mode="out-in">

+ 8 - 6
src/components/ChatWindow.vue

@@ -2,6 +2,8 @@
   <div class="flex h-full min-h-[520px] w-full flex-col gap-4">
     <div
       ref="chatEl"
+      role="log"
+      aria-live="polite"
       class="min-h-0 flex-1 overflow-auto rounded-2xl border border-gray-200 bg-background/60 p-4 dark:border-gray-700 dark:bg-black/20"
     >
       <div v-if="!messages.length" class="grid h-full place-items-center">
@@ -22,19 +24,19 @@
           <div class="mb-0.5 flex items-center gap-1.5" :class="m.role === 'user' ? 'flex-row-reverse' : ''">
             <div
               class="flex h-5 w-5 shrink-0 items-center justify-center rounded-full text-[9px] font-bold text-white"
-              :class="m.role === 'user' ? 'bg-primary' : 'bg-gray-400 dark:bg-gray-600'"
+              :class="m.role === 'user' ? 'bg-primary' : 'bg-gray-600 dark:bg-gray-600'"
             >
               {{ m.role === 'user' ? 'V' : 'O' }}
             </div>
             <span class="text-xs font-medium text-muted-foreground">
               {{ m.role === 'user' ? 'Você' : 'Oráculo' }}
             </span>
-            <span v-if="m.hora" class="text-[10px] text-gray-300 dark:text-gray-600">
+            <span v-if="m.hora" class="text-[10px] text-gray-500 dark:text-gray-400">
               {{ m.hora }}
             </span>
             <button
               type="button"
-              class="copy-btn flex items-center gap-1 rounded-md border border-gray-200 bg-white px-1.5 py-0.5 text-[10px] font-medium text-gray-500 opacity-0 shadow-sm transition-opacity group-hover:opacity-100 hover:text-gray-700 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-400 dark:hover:text-gray-200"
+              class="copy-btn flex items-center gap-1 rounded-md border border-gray-200 bg-white px-1.5 py-0.5 text-[10px] font-medium text-gray-600 opacity-0 shadow-sm transition-opacity group-hover:opacity-100 group-focus-within:opacity-100 focus-visible:opacity-100 max-whatsapp:opacity-100 hover:text-gray-700 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-400 dark:hover:text-gray-200"
               :aria-label="`Copiar mensagem ${m.role === 'user' ? 'sua' : 'do Oráculo'}`"
               @click="copiarMensagem(m.content, idx)"
             >
@@ -86,7 +88,7 @@
 
         <div v-if="loading && !isStreaming" class="flex flex-col items-start gap-0.5">
           <div class="mb-0.5 flex items-center gap-1.5">
-            <div class="flex h-5 w-5 shrink-0 items-center justify-center rounded-full bg-gray-400 text-[9px] font-bold text-white dark:bg-gray-600">O</div>
+            <div class="flex h-5 w-5 shrink-0 items-center justify-center rounded-full bg-gray-600 text-[9px] font-bold text-white dark:bg-gray-600">O</div>
             <span class="text-xs font-medium text-muted-foreground">Oráculo</span>
           </div>
           <div class="rounded-2xl border border-gray-200 bg-white/50 px-4 py-3 dark:border-gray-700 dark:bg-gray-800/60">
@@ -106,8 +108,8 @@
         v-model="draft"
         rows="2"
         placeholder="Digite sua pergunta..."
+        aria-label="Digite sua pergunta"
         class="resize-none"
-        style="resize: none"
         @keydown.enter.exact.prevent="onSend"
       />
       <BaseButton
@@ -120,7 +122,7 @@
       </BaseButton>
     </div>
 
-    <div v-if="error" class="flex items-center justify-between gap-2 rounded-xl border border-red-200 bg-red-50 px-3 py-2 text-sm text-red-600 dark:border-red-500/30 dark:bg-red-500/10 dark:text-red-300">
+    <div v-if="error" role="alert" class="flex items-center justify-between gap-2 rounded-xl border border-red-200 bg-red-50 px-3 py-2 text-sm text-red-600 dark:border-red-500/30 dark:bg-red-500/10 dark:text-red-300">
       <span>Erro: {{ error }}</span>
       <button
         type="button"

+ 5 - 1
src/components/ChunkErrorBanner.vue

@@ -1,5 +1,9 @@
 <script setup>
 import { chunkLoadError } from "../composables/useRouteLoading.js";
+
+function recarregar() {
+  window.location.reload();
+}
 </script>
 
 <template>
@@ -9,7 +13,7 @@ import { chunkLoadError } from "../composables/useRouteLoading.js";
     role="alert"
   >
     <span>Uma nova versão do sistema está disponível.</span>
-    <button type="button" class="underline underline-offset-2" @click="() => window.location.reload()">
+    <button type="button" class="underline underline-offset-2" @click="recarregar">
       Recarregar agora
     </button>
   </div>

+ 3 - 1
src/components/DocumentList.vue

@@ -163,8 +163,10 @@ function fileType(source) {
       >
         <button
           v-if="source"
-          class="absolute right-1 top-1 rounded-lg border border-transparent p-1.5 text-gray-400 opacity-0 transition-opacity hover:border-red-200 hover:bg-red-50 hover:text-red-600 group-hover:opacity-100 dark:hover:border-red-900/50 dark:hover:bg-red-950/30 dark:hover:text-red-400"
+          type="button"
+          class="absolute right-1 top-1 rounded-lg border border-transparent p-1.5 text-gray-500 opacity-0 transition-opacity hover:border-red-200 hover:bg-red-50 hover:text-red-600 group-hover:opacity-100 group-focus-within:opacity-100 focus-visible:opacity-100 max-whatsapp:opacity-100 dark:hover:border-red-900/50 dark:hover:bg-red-950/30 dark:hover:text-red-400"
           :title="`Excluir '${source}'`"
+          :aria-label="`Excluir '${source}'`"
           @click="confirmingSource = source"
         >
           <BaseIcon :icon="Trash2" class="h-4 w-4" />

+ 1 - 0
src/components/DocumentUpload.vue

@@ -145,6 +145,7 @@ const canSubmit = computed(() => {
         <button
           type="button"
           class="shrink-0 rounded-lg border border-transparent p-1.5 text-gray-400 transition-colors hover:border-gray-200 hover:bg-gray-100 dark:hover:border-gray-700 dark:hover:bg-white/5"
+          aria-label="Remover arquivo"
           @click="removeFile"
         >
           <BaseIcon :icon="X" class="h-4 w-4" />

+ 3 - 0
src/components/ModalMidia.vue

@@ -79,6 +79,7 @@ onUnmounted(() => window.removeEventListener("keydown", aoTeclado));
           type="button"
           class="absolute right-4 top-4 z-10 flex h-9 w-9 items-center justify-center rounded-full bg-white/10 text-white hover:bg-white/20"
           title="Fechar"
+          aria-label="Fechar"
           @click="emit('close')"
         >
           <BaseIcon :icon="X" class="h-4 w-4" />
@@ -118,6 +119,7 @@ onUnmounted(() => window.removeEventListener("keydown", aoTeclado));
             type="button"
             class="flex h-8 w-8 items-center justify-center rounded-full text-white hover:bg-white/20 disabled:opacity-30"
             title="Diminuir zoom"
+            aria-label="Diminuir zoom"
             :disabled="zoom <= 1"
             @click="aplicarZoom(-0.25)"
           >
@@ -128,6 +130,7 @@ onUnmounted(() => window.removeEventListener("keydown", aoTeclado));
             type="button"
             class="flex h-8 w-8 items-center justify-center rounded-full text-white hover:bg-white/20 disabled:opacity-30"
             title="Aumentar zoom"
+            aria-label="Aumentar zoom"
             :disabled="zoom >= 4"
             @click="aplicarZoom(0.25)"
           >

+ 1 - 1
src/components/SearchBox.vue

@@ -2,7 +2,7 @@
   <section class="rounded-2xl border border-gray-200 bg-gray-100/50 p-4 shadow-sm backdrop-blur-md dark:border-gray-700 dark:bg-secondary/50">
     <h2 class="text-lg font-semibold text-foreground">Busca</h2>
     <div class="mt-3 grid grid-cols-1 gap-2 compact:grid-cols-[1fr_120px]">
-      <input v-model="query" placeholder="Buscar na base..." @keydown.enter="onSearch" />
+      <input v-model="query" placeholder="Buscar na base..." aria-label="Buscar na base" @keydown.enter="onSearch" />
       <BaseButton :disabled="loading || !query.trim()" @click="onSearch">
         Buscar
       </BaseButton>

+ 2 - 0
src/components/base/CampoBusca.vue

@@ -25,6 +25,7 @@ function aoLimpar() {
       :value="modelValue"
       type="search"
       :placeholder="placeholder"
+      :aria-label="placeholder"
       class="w-full rounded-lg border border-gray-200 bg-background py-1.5 pl-9 pr-8 text-sm text-gray-700 placeholder:text-gray-400 focus:outline-none focus:ring-2 focus:ring-primary/30 dark:border-gray-700 dark:text-gray-200 dark:placeholder:text-gray-500"
       @input="emit('update:modelValue', $event.target.value); emit('input')"
       @keyup.enter="emit('enter')"
@@ -34,6 +35,7 @@ function aoLimpar() {
       type="button"
       class="absolute right-2 top-1/2 -translate-y-1/2 rounded bg-transparent p-0.5 text-gray-400 hover:text-muted-foreground dark:hover:text-gray-300"
       title="Limpar busca"
+      aria-label="Limpar busca"
       @click="aoLimpar"
     >
       <BaseIcon :icon="X" class="h-4 w-4" />

+ 1 - 0
src/components/base/ListItemCard.vue

@@ -18,6 +18,7 @@ defineEmits(["toggle"]);
     <button
       v-if="clickable"
       type="button"
+      :aria-expanded="expanded"
       class="flex w-full flex-wrap items-center gap-2 rounded-2xl bg-transparent px-4 py-3.5 text-left"
       @click="$emit('toggle')"
     >

+ 1 - 1
src/components/base/StatCard.vue

@@ -9,7 +9,7 @@
       <div class="text-xs text-muted-foreground">{{ label }}</div>
     </div>
     <div v-if="value !== null" class="mt-2 text-2xl font-semibold text-foreground">
-      {{ value }}<span v-if="suffix" class="text-sm font-normal text-gray-400">{{ suffix }}</span>
+      {{ value }}<span v-if="suffix" class="text-sm font-normal text-gray-500">{{ suffix }}</span>
     </div>
     <div v-if="$slots.default" class="mt-1 text-xs text-muted-foreground" :class="{ 'mt-2': value === null }">
       <slot />

+ 1 - 1
src/layout/HeaderSistema.vue

@@ -17,7 +17,7 @@ const { menuUsuarioAberto, menuUsuarioRef, alternarMenuUsuario, fecharMenuUsuari
 
 const logoutLoading = ref(false);
 const rotaAtiva = computed(() => String(route.name ?? ""));
-const usuarioNome = computed(() => user.value?.Nome || user.value?.Login || "Usuario");
+const usuarioNome = computed(() => user.value?.Nome || user.value?.Login || "Usuário");
 const usuarioSetor = computed(() => user.value?.Setor || user.value?.Nivel || "");
 const avatarIniciais = computed(() => _avatarIniciais(usuarioNome.value));
 const avatarCor = computed(() => _avatarCor(usuarioNome.value));

+ 5 - 4
src/layout/ListaConversas.vue

@@ -50,7 +50,7 @@ async function abrirConversa(id) {
       {{ conversationsError }}
     </div>
     <template v-for="grupo in conversacoesAgrupadas" :key="grupo.label">
-      <div class="px-3 pt-2 pb-0.5 text-[10px] font-medium text-gray-400 dark:text-white/30 select-none">
+      <div class="px-3 pt-2 pb-0.5 text-[10px] font-medium text-gray-500 dark:text-white/50 select-none">
         {{ grupo.label }}
       </div>
       <div class="grid gap-1">
@@ -59,9 +59,10 @@ async function abrirConversa(id) {
         :key="c.id"
         role="button"
         tabindex="0"
+        :aria-current="String(activeConversationId) === c.id ? 'true' : undefined"
         class="group relative w-full flex items-center gap-3 rounded-xl px-3 py-2.5 text-left text-sm transition-colors overflow-hidden cursor-pointer focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background"
         :class="String(activeConversationId) === c.id
-          ? 'text-gray-900 hover:bg-gray-100/80 dark:text-white dark:hover:bg-white/10'
+          ? 'bg-gray-100 text-gray-900 hover:bg-gray-100/80 dark:bg-white/10 dark:text-white dark:hover:bg-white/10'
           : 'text-gray-600 hover:text-gray-900 hover:bg-gray-100/80 dark:text-white/70 dark:hover:text-white dark:hover:bg-white/10'"
         @click="editingConversaId !== c.id && abrirConversa(c.id)"
         @keydown.enter.prevent="editingConversaId !== c.id && abrirConversa(c.id)"
@@ -130,7 +131,7 @@ async function abrirConversa(id) {
     </template>
     <div
       v-if="!conversationsLoading && conversacoesAgrupadas.length === 0"
-      class="px-3 py-2 text-xs text-gray-400 dark:text-white/30 italic"
+      class="px-3 py-2 text-xs text-gray-500 dark:text-white/50 italic"
     >
       Nenhuma conversa ainda
     </div>
@@ -138,7 +139,7 @@ async function abrirConversa(id) {
     <button
       v-if="conversationsHasMore"
       type="button"
-      class="mt-1 w-full rounded-xl px-3 py-2 text-left text-xs text-gray-400 transition-colors hover:bg-gray-100/80 hover:text-gray-700 dark:text-white/30 dark:hover:bg-white/10 dark:hover:text-white/70"
+      class="mt-1 w-full rounded-xl px-3 py-2 text-left text-xs text-gray-500 transition-colors hover:bg-gray-100/80 hover:text-gray-700 dark:text-white/50 dark:hover:bg-white/10 dark:hover:text-white/70"
       :disabled="conversationsLoading"
       @click="loadMoreConversations"
     >

+ 5 - 3
src/layout/SidebarSistema.vue

@@ -13,6 +13,7 @@ import {
   TriangleAlert,
   SlidersHorizontal,
   Trophy,
+  ClipboardCheck,
 } from "lucide-vue-next";
 import ListaConversas from "./ListaConversas.vue";
 import BaseIcon from "../components/base/BaseIcon.vue";
@@ -46,6 +47,7 @@ const itensBiblioteca = [
   { rota: "avaliacoes", icon: Star, label: "Avaliações" },
   { rota: "ranking-atendentes", icon: Trophy, label: "Ranking de atendentes" },
   { rota: "atendimentos-nao-resolvidos", icon: TriangleAlert, label: "Não resolvidos" },
+  { rota: "golden-set", icon: ClipboardCheck, label: "Golden set" },
 ];
 
 function irPara(nome) {
@@ -88,7 +90,7 @@ async function novaConversa() {
 
     <div
       v-if="!sidebarRecolhida"
-      class="px-2 pt-1 pb-0.5 text-[10px] font-semibold uppercase tracking-widest text-gray-400 dark:text-white/30 select-none"
+      class="px-2 pt-1 pb-0.5 text-[10px] font-semibold uppercase tracking-widest text-gray-500 dark:text-white/50 select-none"
     >
       Chat
     </div>
@@ -129,7 +131,7 @@ async function novaConversa() {
       <template v-if="isAdmin">
         <div
           v-if="!sidebarRecolhida"
-          class="px-2 pb-0.5 text-[10px] font-semibold uppercase tracking-widest text-gray-400 dark:text-white/30 select-none"
+          class="px-2 pb-0.5 text-[10px] font-semibold uppercase tracking-widest text-gray-500 dark:text-white/50 select-none"
         >
           Biblioteca
         </div>
@@ -151,7 +153,7 @@ async function novaConversa() {
       </template>
       <div
         v-if="!sidebarRecolhida"
-        class="px-2 pb-0.5 text-[10px] font-semibold uppercase tracking-widest text-gray-400 dark:text-white/30 select-none"
+        class="px-2 pb-0.5 text-[10px] font-semibold uppercase tracking-widest text-gray-500 dark:text-white/50 select-none"
       >
         Sistema
       </div>

+ 8 - 4
src/styles/highlight-theme.css

@@ -7,14 +7,18 @@
   .hljs-number, .hljs-literal, .hljs-type, .hljs-class,
   .hljs-symbol, .hljs-bullet, .hljs-link { color: var(--chart-2); }
   .hljs-title, .hljs-function, .hljs-attribute { color: var(--chart-3); font-weight: 600; }
-  .hljs-variable, .hljs-template-variable { color: var(--chart-4); }
-  .hljs-tag, .hljs-name { color: var(--chart-1); font-weight: 600; }
+  .hljs-variable, .hljs-template-variable { color: var(--warning-fg); }
+  .hljs-tag, .hljs-name { color: var(--success-fg); font-weight: 600; }
   .hljs-deletion {
     color: var(--destructive);
     background-color: color-mix(in oklab, var(--destructive) 12%, transparent);
   }
   .hljs-addition {
-    color: var(--chart-1);
-    background-color: color-mix(in oklab, var(--chart-1) 12%, transparent);
+    color: var(--success-fg);
+    background-color: color-mix(in oklab, var(--success-fg) 12%, transparent);
+  }
+  .dark .hljs-keyword, .dark .hljs-selector-tag, .dark .hljs-built_in,
+  .dark .hljs-deletion {
+    color: color-mix(in oklab, var(--destructive) 55%, white);
   }
 }

+ 17 - 2
src/styles/tailwind.css

@@ -28,6 +28,8 @@
   --chart-2: oklch(0.6231 0.188 259.8145);
   --chart-3: oklch(0.6056 0.2189 292.7172);
   --chart-4: oklch(0.7686 0.1647 70.0804);
+  --success-fg: oklch(0.45 0.13 160);
+  --warning-fg: oklch(0.48 0.12 65);
   --font-sans: Inter, ui-sans-serif, sans-serif, system-ui;
   --font-serif: ui-serif, Georgia, Cambria, "Times New Roman", Times, serif;
   --font-mono: JetBrains Mono, ui-monospace, monospace;
@@ -74,6 +76,8 @@
   --chart-2: oklch(0.7137 0.1434 254.624);
   --chart-3: oklch(0.709 0.1592 293.5412);
   --chart-4: oklch(0.8369 0.1644 84.4286);
+  --success-fg: oklch(0.8003 0.1821 151.711);
+  --warning-fg: oklch(0.8369 0.1644 84.4286);
   --font-sans: Inter, ui-sans-serif, sans-serif, system-ui;
   --font-serif: ui-serif, Georgia, Cambria, "Times New Roman", Times, serif;
   --font-mono: JetBrains Mono, ui-monospace, monospace;
@@ -372,8 +376,8 @@ body {
     transform: none;
   }
   .code-copy-btn.copied {
-    color: #22c55e;
-    border-color: #22c55e44;
+    color: var(--success-fg);
+    border-color: color-mix(in oklab, var(--success-fg) 30%, transparent);
   }
   .code-copy-btn svg {
     width: 11px;
@@ -434,3 +438,14 @@ body {
     background: rgba(255, 255, 255, 0.22);
   }
 }
+
+@media (prefers-reduced-motion: reduce) {
+  *,
+  *::before,
+  *::after {
+    animation-duration: 0.01ms !important;
+    animation-iteration-count: 1 !important;
+    transition-duration: 0.01ms !important;
+    scroll-behavior: auto !important;
+  }
+}

+ 6 - 6
src/styles/toast-theme.css

@@ -17,9 +17,9 @@
   }
 
   .Vue-Toastification__toast--success {
-    background-color: color-mix(in oklab, var(--chart-1) 10%, var(--background)) !important;
-    color: var(--chart-1) !important;
-    border: 1px solid color-mix(in oklab, var(--chart-1) 30%, transparent) !important;
+    background-color: color-mix(in oklab, var(--success-fg) 10%, var(--background)) !important;
+    color: var(--success-fg) !important;
+    border: 1px solid color-mix(in oklab, var(--success-fg) 30%, transparent) !important;
   }
 
   .Vue-Toastification__toast--error {
@@ -35,9 +35,9 @@
   }
 
   .Vue-Toastification__toast--warning {
-    background-color: color-mix(in oklab, var(--chart-4) 10%, var(--background)) !important;
-    color: var(--chart-4) !important;
-    border: 1px solid color-mix(in oklab, var(--chart-4) 30%, transparent) !important;
+    background-color: color-mix(in oklab, var(--warning-fg) 10%, var(--background)) !important;
+    color: var(--warning-fg) !important;
+    border: 1px solid color-mix(in oklab, var(--warning-fg) 30%, transparent) !important;
   }
 
   .dark .Vue-Toastification__toast--success,

+ 1 - 0
src/views/atendimentos/AtendimentoView.vue

@@ -237,6 +237,7 @@ watch(() => route.params.id, carregar, { immediate: true });
               type="button"
               class="mt-0.5 flex h-9 w-9 shrink-0 items-center justify-center rounded-xl border border-gray-300 text-gray-600 hover:bg-black/[0.03] dark:border-gray-600 dark:text-gray-300 dark:hover:bg-white/[0.04]"
               title="Voltar"
+              aria-label="Voltar"
               @click="voltar"
             >
               <BaseIcon :icon="ArrowLeft" class="h-4 w-4" />

+ 2 - 2
src/views/auth/LoginView.vue

@@ -139,14 +139,14 @@ async function onSubmit() {
           <div>
             <div class="text-2xl font-extrabold tracking-tight">Entrar</div>
             <div class="text-sm text-muted-foreground">
-              Informe seu usuario ou email e sua senha para acessar o sistema.
+              Informe seu usuário ou e-mail e sua senha para acessar o sistema.
             </div>
           </div>
         </div>
 
         <form class="mt-6 grid gap-4" @submit.prevent="onSubmit">
           <label class="grid gap-1.5">
-            <span class="text-sm font-medium">Usuario ou email</span>
+            <span class="text-sm font-medium">Usuário ou e-mail</span>
             <input
               ref="loginInputRef"
               v-model="form.login"

+ 4 - 3
src/views/conversas/ConversasWhatsappView.vue

@@ -321,6 +321,7 @@ onUnmounted(() => {
               type="button"
               class="hidden h-8 w-8 shrink-0 items-center justify-center rounded-lg text-gray-500 hover:bg-black/[0.03] max-whatsapp:inline-flex dark:text-gray-400 dark:hover:bg-white/[0.04]"
               title="Voltar para a lista"
+              aria-label="Voltar para a lista"
               @click="fecharConversa"
             >
               <BaseIcon :icon="ArrowLeft" class="h-4 w-4" />
@@ -369,7 +370,7 @@ onUnmounted(() => {
                     <button
                       v-else-if="midiaErros[m.Id]"
                       type="button"
-                      class="mt-1 text-xs font-medium text-red-500 underline"
+                      class="mt-1 text-xs font-medium text-red-600 underline dark:text-red-400"
                       @click="resolverMidia(m)"
                     >
                       Falha ao carregar áudio — tentar novamente
@@ -390,7 +391,7 @@ onUnmounted(() => {
                     <button
                       v-else-if="midiaErros[m.Id]"
                       type="button"
-                      class="text-xs font-medium text-red-500 underline"
+                      class="text-xs font-medium text-red-600 underline dark:text-red-400"
                       @click="resolverMidia(m)"
                     >
                       Falha ao carregar imagem — tentar novamente
@@ -415,7 +416,7 @@ onUnmounted(() => {
                     <button
                       v-else-if="midiaErros[m.Id]"
                       type="button"
-                      class="text-xs font-medium text-red-500 underline"
+                      class="text-xs font-medium text-red-600 underline dark:text-red-400"
                       @click="resolverMidia(m)"
                     >
                       Falha ao carregar vídeo — tentar novamente

+ 1 - 1
src/views/usuarios/UsuariosView.vue

@@ -162,7 +162,7 @@ onMounted(async () => {
           <div
             class="rounded-xl border border-primary/15 bg-primary/10 px-3 py-2 text-sm font-medium text-primary dark:border-primary/20 dark:bg-primary/15"
           >
-            {{ totalUsuarios }} usuario{{ totalUsuarios === 1 ? "" : "s" }}
+            {{ totalUsuarios }} usuário{{ totalUsuarios === 1 ? "" : "s" }}
           </div>
           <BaseButton @click="abrirNovoUsuario">
             <BaseIcon :icon="Plus" class="h-4 w-4" />