1<!DOCTYPE html> 2<html lang="pt-BR"> 3 4<head> 5 <meta charset="UTF-8"> 6 <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover"> 7 <title>Nativa FM Bauru - A Nativa é tudo e muito mais! â Nativa FM Bauru</title> 8 <meta name="description" content="A Nativa é tudo e muito mais!"> 9 <meta name="keywords" content="radio, online, musica, streaming"> 10 <meta name="robots" content="index, follow"> 11 12 <link rel="canonical" href="https://nativafmbauru.com.br/"> 13 14 <!-- Open Graph (WhatsApp, Facebook, Telegram, LinkedIn, Discord, Teams, iMessage) --> 15 <meta property="og:type" content="website"> 16 <meta property="og:title" content="Nativa FM Bauru - A Nativa é tudo e muito mais!"> 17 <meta property="og:description" content="A Nativa é tudo e muito mais!"> 18 <meta property="og:url" content="https://nativafmbauru.com.br/"> 19 <meta property="og:site_name" content="Nativa FM Bauru"> 20 <meta property="og:locale" content="pt_BR"> 21 <meta property="og:image" content="https://nativafmbauru.com.br/uploads/media/6a18a5b4f2efe_1780000180.webp"> 22 <meta property="og:image:secure_url" content="https://nativafmbauru.com.br/uploads/media/6a18a5b4f2efe_1780000180.webp"> 23 <meta property="og:image:alt" content="Nativa FM Bauru - A Nativa é tudo e muito mais!"> 24 <meta property="og:image:width" content="192"> 25 <meta property="og:image:height" content="192"> 26 <meta property="og:image:type" content="image/webp"> 27 28 <!-- Twitter / X --> 29 <meta name="twitter:card" content="summary_large_image"> 30 <meta name="twitter:title" content="Nativa FM Bauru - A Nativa é tudo e muito mais!"> 31 <meta name="twitter:description" content="A Nativa é tudo e muito mais!"> 32 <meta name="twitter:image" content="https://nativafmbauru.com.br/uploads/media/6a18a5b4f2efe_1780000180.webp"> 33 <meta name="twitter:image:alt" content="Nativa FM Bauru - A Nativa é tudo e muito mais!"> 34 35 <!-- LCP Preload (Logo) com WebP fallback --> 36 <link rel="preload" as="image" href="https://nativafmbauru.com.br/uploads/media/6a18a5b4f2efe_1780000180.webp"> 37 38 <link rel="stylesheet" href="https://nativafmbauru.com.br/themes/neon/style.css?v=1790900780"> 39 40 41 <!-- Custom CSS (Admin) --> 42 43 <!-- External Fonts (Google Fonts) --> 44 <link rel="preconnect" href="https://fonts.googleapis.com"> 45 <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> 46 <link 47 href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Outfit:wght@400;500;700&family=Roboto:ital,wght@0,300;0,400;0,500;0,700;1,400&family=DM+Sans:ital,opsz,wght@0,9..40,300;0,9..40,400;0,9..40,500;0,9..40,700;1,9..40,400&display=swap" 48 rel="stylesheet"> 49 <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet"> 50 51 <!-- Lucide Icons (Ajuste 8 â Ãcones modernos) --> 52
52<script src="https://unpkg.com/lucide@latest/dist/umd/lucide.min.js" defer></script>
52 53 54 <!-- Global CSS â Seções e Cookie Banner (Ajustes 6 e 3) --> 55 <link rel="stylesheet" href="https://nativafmbauru.com.br/assets/css/section-header.css?v=1790900780"> 56 <link rel="stylesheet" href="https://nativafmbauru.com.br/assets/css/cookie-banner.css?v=1790900780"> 57 <!-- Global Slider CSS â carregado para todos os temas --> 58 <link rel="stylesheet" href="https://nativafmbauru.com.br/assets/css/slider.css?v=1784297539"> 59 <!-- Top Músicas: marquee de tÃtulo/artista. Depois do CSS de tema de 60 propósito â precisa vencer o `text-overflow: ellipsis` dos temas. --> 61 <link rel="stylesheet" href="https://nativafmbauru.com.br/assets/css/chart-marquee.css?v=1790785599"> 62 <!-- App Rádio 3.0: camada de segurança escopada em html.radio30-app. Carregada 63 sempre, porque a classe também é injetada pelo próprio app â cobre o HTML 64 servido sem a detecção no servidor (cache, service worker). --> 65 <link rel="stylesheet" href="https://nativafmbauru.com.br/assets/css/radio30-app.css?v=1790785599"> 66 67 <!-- Favicon --> 68 <link rel="icon" type="image/png" sizes="32x32" href="https://nativafmbauru.com.br/uploads/media/6a18a5b4f2efe_1780000180.webp"> 69 <link rel="shortcut icon" href="https://nativafmbauru.com.br/uploads/media/6a18a5b4f2efe_1780000180.webp"> 70 71 <!-- PWA Meta Tags --> 72 <link rel="manifest" href="/?manifest=1"> 73 <meta name="theme-color" content="#ffffff" media="(prefers-color-scheme: light)"> 74 <meta name="theme-color" content="#000000" media="(prefers-color-scheme: dark)"> 75 <meta name="theme-color" content="#ffffff"> 76 77 <meta name="mobile-web-app-capable" content="yes"> 78 <meta name="apple-mobile-web-app-capable" content="yes"> 79 <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"> 80 <meta name="apple-mobile-web-app-title" content="Nativa FM Bauru"> 81 82 <!-- Apple Touch Icons â usa o Ãcone de Configurações Gerais; PWA como fallback --> 83 <link rel="apple-touch-icon" href="https://nativafmbauru.com.br/uploads/media/6a18a5b4f2efe_1780000180.webp"> 84 <link rel="apple-touch-icon" sizes="152x152" href="https://nativafmbauru.com.br/uploads/media/6a18a5b4f2efe_1780000180.webp"> 85 <link rel="apple-touch-icon" sizes="180x180" href="https://nativafmbauru.com.br/uploads/media/6a18a5b4f2efe_1780000180.webp"> 86 <link rel="apple-touch-icon" sizes="167x167" href="https://nativafmbauru.com.br/uploads/media/6a18a5b4f2efe_1780000180.webp"> 87 88
88<script> 89 const SITE_URL = "https://nativafmbauru.com.br"; 90 const STREAM_URL = ""; /* carregado via /api/stream-config.php */ 91 const SITE_NAME = "Nativa FM Bauru"; 92 const PLAYER_DEFAULT_IMAGE = "https://nativafmbauru.com.br/uploads/media/6a18a5b4f2efe_1780000180.webp"; 93</script>
93 94 95<!-- Font Awesome --> 96<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> 97<!-- Material Icons + Symbols (Stitch uses Material Symbols Outlined) --> 98<link href="https://fonts.googleapis.com/icon?family=Material+Icons+Round" rel="stylesheet"> 99<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,[email protected],0..1&display=swap" rel="stylesheet"> 100<!-- Space Grotesk â Fonte principal do design Stitch NEON --> 101<link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300;400;500;600;700&display=swap" rel="stylesheet"> 102 103<link rel="preconnect" href="https://fonts.googleapis.com"> 104<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> 105<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&family=Poppins:wght@300;400;500;600;700;800&family=Space+Grotesk:wght@300;400;500;600;700;800&display=swap" rel="stylesheet"> 106 <!-- Dynamic Theme CSS â carregado APÃS o head.php do tema para garantir que o admin sempre prevaleça --> 107 <style> 108 @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap'); 109 110 :root { 111 --primary-color: #7911b0; 112 --secondary-color: #903ff3; 113 --tertiary-color: #e100ff; 114 --accent-color: #ff00ea; 115 --primary-rgb: 121, 17, 176; 116 --secondary-rgb: 144, 63, 243; 117 --tertiary-rgb: 225, 0, 255; 118 --accent-rgb: 255, 0, 234; 119 /* Aliases semânticos */ 120 --color-primary: #7911b0; 121 --color-secondary: #903ff3; 122 --color-tertiary: #e100ff; 123 } 124 125 :root { 126 /* Light Theme - Background Colors */ 127 --bg-primary: #ffffff; 128 --bg-primary-rgb: 255, 255, 255; 129 --bg-secondary: #f5f5f7; 130 --bg-secondary-rgb: 245, 245, 247; 131 --bg-tertiary: #e9ecef; 132 --bg-card: #ffffff; 133 --bg-card-rgb: 255, 255, 255; 134 --bg-card-hover: #f8f9fa; 135 --bg-input: #ffffff; 136 137 /* === Header/Nav background (sincronizado com theme_color do PWA) === */ 138 --site-header-bg: #ffffff; 139 --header-bg: var(--site-header-bg); 140 141 --glass-bg: rgba(255, 255, 255, 0.95); 142 --glass-border: rgba(0, 0, 0, 0.08); 143 --glass-shadow: 0 8px 32px rgba(0, 0, 0, 0.08); 144 145 --text-primary: #1a1a2e; 146 --text-primary-rgb: 26, 26, 46; 147 --text-secondary: #4a4a5a; 148 --text-muted: #6c757d; 149 150 --border-color: rgba(0, 0, 0, 0.08); 151 --border-light: rgba(0, 0, 0, 0.05); 152 153 --shadow-sm: 0 2px 8px rgba(0, 0, 0, 0.06); 154 --shadow-md: 0 4px 16px rgba(0, 0, 0, 0.08); 155 --shadow-lg: 0 8px 32px rgba(0, 0, 0, 0.1); 156 --shadow-glow: 0 0 30px rgba(121, 17, 176, 0.12); 157 158 --gradient-dark: linear-gradient(180deg, #ffffff 0%, #f5f5f7 100%); 159 160 /* === WAVE Brutalism â Borda/Sombra (Light) === */ 161 --brut-border-color: #000000; 162 --brut-border-light: #333333; 163 --brut-shadow-color: #000000; 164 --brut-shadow-hover: #000000; 165 } 166 167 :root { 168 --nav-font-family: 'Inter', sans-serif; 169 --nav-font-size: 14px; 170 --nav-font-weight: normal; 171 --nav-font-style: normal; 172 --nav-color: #111111; 173 } 174 175 .nav, .nav-link, .header nav, .header .nav-link, nav a, 176 #mainNav a, #mainNav a.nav-link { 177 font-family: var(--nav-font-family); 178 font-size: var(--nav-font-size); 179 font-weight: var(--nav-font-weight); 180 font-style: var(--nav-font-style); 181 color: var(--nav-color); 182 } 183 184 :root { 185 --page-title-font-family: 'Inter', sans-serif;
186 --page-title-font-weight: bold; 187 --page-title-font-style: normal; 188 --page-title-color: #1a1a1a; 189 --page-title-font-size-base: 39px; 190 191 /* Aliases legados â mantém compatibilidade com head.php dos temas */ 192 --title-font-family: 'Inter', sans-serif; 193 --title-font-weight: bold; 194 --title-font-style: normal; 195 --title-color: #1a1a1a; 196 --title-font-size-base: 39px; 197 } 198 199 /* === FONTE DOS TÃTULOS DAS PÃGINAS (somente front-end) === */ 200 body h1, body h2, body h3, body h4, body h5, body h6, 201 body .section-title, body .page-title, body .pd-page-hero__title, 202 /* Single pages â tÃtulos principais de página */ 203 body .ns-title, 204 body .pr-title, 205 body .ep-title, 206 body .on-air-title, 207 body .page-hero__title { 208 font-family: var(--page-title-font-family) !important; 209 font-weight: var(--page-title-font-weight) !important; 210 font-style: var(--page-title-font-style) !important; 211 color: var(--page-title-color) !important; 212 } 213 body h1, body .ns-title, body .pr-title, body .ep-title, body .on-air-title, body .page-hero__title { font-size: var(--page-title-font-size-base) !important; } 214 body h2 { font-size: calc(var(--page-title-font-size-base) * 0.85) !important; } 215 body h3 { font-size: calc(var(--page-title-font-size-base) * 0.7) !important; } 216 body h4, body h5, body h6 { font-size: calc(var(--page-title-font-size-base) * 0.6) !important; } 217 218 :root { 219 --card-title-font-family: 'Inter', sans-serif; 220 --card-title-font-weight: bold; 221 --card-title-font-style: normal; 222 --card-title-color: #222222; 223 --card-title-font-size: 20px; 224 } 225 226 /* === FONTE DOS CARDS (home + páginas internas + single pages) (somente front-end) === */ 227 /* ââ NotÃcias ââ */ 228 body .hn-card__title, body .hn-hero__title, body .d5-news-card__title, 229 body .d5-news-featured__title, body .s-news-card__title, body .news-title, 230 /* ââ Sidebar de notÃcia single ââ */ 231 body .ns-sidebar-card-title, body .ns-sidebar-title, 232 body .pulse-sidebar-card-title, body .pulse-sidebar-title, 233 /* ââ Eventos ââ */ 234 body .d5-event-card__title, body .s-event-card__title, body .event-title, 235 /* ââ Promoções ââ */ 236 body .d5-promo-card__title, body .s-promo-card__title, body .promo-title, 237 /* ââ Podcasts / Episódios ââ */ 238 body .pod-card__title, body .sp-title, body .ep-sidebar-title, body .ep-more-title, body .podcast-title, 239 /* ââ Programação / Shows ââ */ 240 body .d5-prog-card__name, body .schedule-name, body .on-air-name, body .spsc-name, body .s-show-card__name, 241 /* ââ Equipe ââ */ 242 body .team-name, body .team-member-name, 243 /* ââ Listagens ââ */ 244 body .s-section-title, 245 /* ââ Genéricos ââ */ 246 body .card-title, body .font-display { 247 font-family: var(--card-title-font-family) !important; 248 font-weight: var(--card-title-font-weight) !important; 249 font-style: var(--card-title-font-style) !important; 250 color: var(--card-title-color) !important; 251 font-size: var(--card-title-font-size) !important; 252 } 253 254 :root { 255 --body-font-family: 'Poppins', sans-serif; 256 --body-font-weight: normal; 257 --body-font-style: normal; 258 --body-font-color: #333333; 259 --body-font-size: 15px; 260 } 261 262 /* ââ Parágrafos e listas genéricas (somente front-end) ââ */ 263 p:not(.font-preview), li { 264 font-family: var(--body-font-family) !important; 265 font-weight: var(--body-font-weight) !important; 266 font-style: var(--body-font-style) !important; 267 font-size: var(--body-font-size) !important; 268 color: var(--body-font-color) !important; 269 } 270 271 /* ââ Single de NotÃcia (ns-*) ââ */ 272 .ns-body-content, .ns-body-content p, .ns-body-content li, .ns-lead { 273 font-family: var(--body-font-family) !important; 274 font-weight: var(--body-font-weight) !important; 275 font-style: var(--body-font-style) !important; 276 font-size: var(--body-font-size) !important; 277 color: var(--body-font-color) !important; 278 } 279 280 /* ââ Single de Evento (ev-*) ââ */ 281 .ev-description, .ev-description p, .ev-description li { 282 font-family: var(--body-font-family) !important; 283 font-weight: var(--body-font-weight) !important; 284 font-style: var(--body-font-style) !important; 285 font-size: var(--body-font-size) !important; 286 color: var(--body-font-color) !important; 287 } 288 289 /* ââ Single de Promoção (pr-*) ââ */ 290 .pr-description, .pr-description p, .pr-description li, 291 .pr-rules-body, .pr-rules-body p, .pr-rules-body li { 292 font-family: var(--body-font-family) !important; 293 font-weight: var(--body-font-weight) !important; 294 font-style: var(--body-font-style) !important; 295 font-size: var(--body-font-size) !important; 296 color: var(--body-font-color) !important; 297 } 298 299 /* ââ Single de Podcast (ep-*) ââ */ 300 .ep-desc-content, .ep-desc-content p, .ep-desc-content li { 301 font-family: var(--body-font-family) !important; 302 font-weight: var(--body-font-weight) !important; 303 font-style: var(--body-font-style) !important; 304 font-size: var(--body-font-size) !important; 305 color: var(--body-font-color) !important; 306 } 307 308 /* ââ Page Builder / Páginas dinâmicas ââ */ 309 .bloco-texto, .bloco-texto p, .bloco-texto li, 310 .pd-compat-text, .pd-compat-rich, .pd-compat-rich p, .pd-compat-rich li, 311 .pd-page-content p, .pd-page-content li { 312 font-family: var(--body-font-family) !important; 313 font-weight: var(--body-font-weight) !important; 314 font-style: var(--body-font-style) !important; 315 font-size: var(--body-font-size) !important; 316 color: var(--body-font-color) !important; 317 } 318 319 /* ââ Cards e seções da Home ââ */ 320 .card-description, .card-text, .card-excerpt, 321 .news-excerpt, .news-description, 322 .event-description, .event-excerpt, 323 .team-description, .team-bio, 324 .promo-description, .promotion-description, 325 .podcast-description, .podcast-excerpt, 326 .section-description, .section-text, 327 .about-text, .about-description, 328 .hero-description, .hero-text, 329 .slider-description, .slide-text { 330 font-family: var(--body-font-family) !important; 331 font-weight: var(--body-font-weight) !important; 332 font-style: var(--body-font-style) !important; 333 font-size: var(--body-font-size) !important; 334 color: var(--body-font-color) !important; 335 } 336 337 :root { 338 --player-bg: linear-gradient(135deg, #31004c 0%, #7b15b2 100%); 339 --player-text-color: #ffffff; 340 } 341 342 /* ========================================================= 343 GLOBAL PLAYER CONTROLS (SOLID ROUND BUTTONS) 344 ========================================================= */ 345 /* Garante herança da cor base do texto no container */ 346 #player, .d5-player, .neon-player { 347 color: var(--player-text-color, #ffffff) !important; 348 } 349 350 /* Textos padronizados */ 351 #playerArtist, #playerTitle, #playerStatusText, .live-text, .neon-player__title, .neon-player__artist, 352 .d5-player-title, .d5-player-artist { 353 color: var(--player-text-color, #ffffff) !important; 354 -webkit-text-stroke: 0 !important; 355 text-shadow: none !important; 356 } 357 .neon-player__artist, .d5-player-artist { 358 opacity: 0.8 !important; 359 } 360 361 /* 362 BOTÃES SÃLIDOS (Exemplo Anexo) 363 O fundo do botão herda a Cor dos Elementos. 364 O Ãcone corta a cor, usando a cor de fundo original do player (ou escala de cinza/preta). 365 */ 366 #playBtn, #liveBtn, #videoBtn, #volumeBtn, 367 .d5-play-btn, .neon-player__play-btn, .neon-player__live-btn, .neon-player__vol-btn { 368 background-color: var(--player-text-color, #ffffff) !important; 369 border: none !important; 370 box-shadow: 0 4px 10px rgba(0,0,0,0.15) !important; 371 display: flex !important; 372 align-items: center !important; 373 justify-content: center !important; 374 border-radius: 50% !important; /* Sempre redondo */ 375 } 376 377 /* Ajuste de Preenchimento para garantir que todos os botões fiquem proporcionais */ 378 #liveBtn, #videoBtn, #volumeBtn, .neon-player__live-btn, .neon-player__vol-btn { 379 width: 36px !important; 380 height: 36px !important; 381 min-width: 36px !important; 382 } 383 #playBtn, .d5-play-btn, .neon-player__play-btn { 384 width: 48px !important; 385 height: 48px !important; 386 } 387 388 /* Ãcones dentro dos botões (Cor contrastante) */ 389 #playBtn i, #liveBtn i, #volumeBtn i, #videoBtn i, .d5-vol-icon, 390 #playBtn svg, #liveBtn svg, #volumeBtn svg, #videoBtn svg, 391 #svgPlay, #svgPause, 392 .d5-play-btn i, .d5-play-btn svg, .d5-vol-icon svg, 393 .neon-player__play-btn svg, .neon-player__controls button svg, .neon-player__vol-btn svg, 394 .neon-player__controls button i { 395 color: var(--player-bg, #222) !important; 396 fill: var(--player-bg, #222) !important; 397 filter: none !important; 398 -webkit-text-stroke: 0 !important; 399 text-shadow: none !important; 400 /* Adicionando um mixin de preto para garantir contraste na inversão */ 401 color: color-mix(in srgb, var(--player-bg, #222) 80%, black) !important; 402 fill: color-mix(in srgb, var(--player-bg, #222) 80%, black) !important; 403 } 404 /* Exceção para o spinner de loading preservar stroke e não ter fill */ 405 #svgLoading { 406 color: color-mix(in srgb, var(--player-bg, #222) 80%, black) !important; 407 fill: none !important; 408 } 409 410 /* Remove margens estranhas dos Ãcones centralizados que alguns SVGs tem por padrão */ 411 .neon-player__play-btn svg, .d5-play-btn i { 412 margin: 0 !important; 413 transform: translateX(2px); /* Ajuste visual do triângulo de play ficar centralizado visualmente */ 414 } 415 .neon-player__controls button svg { 416 transform: none; 417 } 418 419 /* Trilho do Slider de Volume */ 420 .d5-volume-slider, .neon-player__vol-slider { 421 background: color-mix(in srgb, var(--player-text-color, #ffffff) 20%, transparent) !important; 422 } 423 424 /* Controle de Volume: Destaque na bolinha (Thumb) combinando com o botão sólido */ 425 #volumeSlider::-webkit-slider-thumb, 426 .d5-volume-slider::-webkit-slider-thumb, 427 .neon-player__vol-slider::-webkit-slider-thumb { 428 background: var(--player-text-color, #ffffff) !important; 429 box-shadow: 0 2px 5px rgba(0,0,0,0.3) !important; 430 border: none !important; 431 } 432 #volumeSlider::-moz-range-thumb, 433 .d5-volume-slider::-moz-range-thumb, 434 .neon-player__vol-slider::-moz-range-thumb { 435 background: var(--player-text-color, #ffffff) !important; 436 box-shadow: 0 2px 5px rgba(0,0,0,0.3) !important; 437 border: none !important; 438 } 439 440 /* Elementos secundários (Badges informativos) */ 441 #playerArtwork, .d5-player-artwork { 442 background-color: color-mix(in srgb, var(--player-text-color, #ffffff) 10%, transparent) !important; 443 border: 1px solid color-mix(in srgb, var(--player-text-color, #ffffff) 15%, transparent) !important; 444 border-radius: 8px !important; 445 } 446 .live-badge { 447 background-color: color-mix(in srgb, var(--player-text-color, #ffffff) 15%, transparent) !important; 448 border: 1px solid color-mix(in srgb, var(--player-text-color, #ffffff) 30%, transparent) !important; 449 color: var(--player-text-color, #ffffff) !important; 450 } 451 .live-dot, .neon-player__live-dot { 452 background-color: var(--player-text-color, #ffffff) !important; 453 } 454 455 /* ========================================================= 456 PADRONIZAÃÃO TIPOGRÃFICA MOBILE (FIXED SIZES) 457 As definições abaixo forçam tamanhos fixos no mobile, 458 ignorando os tamanhos definidos pelo painel para desktop. 459 Escala baseada em boas práticas para UI Mobile. 460 ========================================================= */ 461 @media (max-width: 768px) { 462 :root { 463 --page-title-font-size-base: 24px !important; 464 --card-title-font-size: 18px !important; 465 --body-font-size: 14px !important; 466 --nav-font-size: 16px !important; 467 } 468 469 /* TÃtulo Principal (H1) */ 470 body h1, body .ns-title, body .pr-title, body .ep-title, body .on-air-title, body .page-hero__title { 471 font-size: 24px !important; 472 line-height: 1.4 !important; 473 } 474 475 /* TÃtulo Secundário (H2) */ 476 body h2, body .section-title { 477 font-size: 20px !important; 478 line-height: 1.4 !important; 479 } 480 481 /* TÃtulo Terciário (H3) / Cards Principais */ 482 body h3, 483 body .hn-card__title, body .hn-hero__title, body .d5-news-card__title, 484 body .d5-news-featured__title, body .s-news-card__title, body .news-title, 485 body .ns-sidebar-card-title, body .ns-sidebar-title, 486 body .pulse-sidebar-card-title, body .pulse-sidebar-title, 487 body .d5-event-card__title, body .s-event-card__title, body .event-title, 488 body .d5-promo-card__title, body .s-promo-card__title, body .promo-title, 489 body .pod-card__title, body .sp-title, body .ep-sidebar-title, body .ep-more-title, body .podcast-title, 490 body .d5-prog-card__name, body .schedule-name, body .on-air-name, body .spsc-name, body .s-show-card__name, 491 body .tea
491m-name, body .team-member-name, 492 body .s-section-title, 493 body .card-title, body .font-display, 494 body .neon-news-header__title { 495 font-size: 18px !important; 496 line-height: 1.4 !important; 497 } 498 499 /* SubtÃtulo (H4-H6 / Nav) */ 500 body h4, body h5, body h6, 501 body .nav, body .nav-link, body .header nav, body .header .nav-link, body nav a, 502 body #mainNav a, body #mainNav a.nav-link { 503 font-size: 16px !important; 504 line-height: 1.4 !important; 505 } 506 507 /* Corpo do Texto (Body) */ 508 body p:not(.font-preview), body li, 509 body .ns-body-content, body .ns-body-content p, body .ns-body-content li, body .ns-lead, 510 body .ev-description, body .ev-description p, body .ev-description li, 511 body .pr-description, body .pr-description p, body .pr-description li, 512 body .pr-rules-body, body .pr-rules-body p, body .pr-rules-body li, 513 body .ep-desc-content, body .ep-desc-content p, body .ep-desc-content li, 514 body .bloco-texto, body .bloco-texto p, body .bloco-texto li, 515 body .pd-compat-text, body .pd-compat-rich, body .pd-compat-rich p, body .pd-compat-rich li, 516 body .pd-page-content p, body .pd-page-content li { 517 font-size: 14px !important; 518 line-height: 1.6 !important; 519 } 520 521 /* Descrições / Texto Auxiliar */ 522 body .card-description, body .card-text, body .card-excerpt, 523 body .news-excerpt, body .news-description, 524 body .event-description, body .event-excerpt, 525 body .team-description, body .team-bio, 526 body .promo-description, body .promotion-description, 527 body .podcast-description, body .podcast-excerpt, 528 body .section-description, body .section-text, 529 body .about-text, body .about-description, 530 body .hero-description, body .hero-text, 531 body .slider-description, body .slide-text, 532 body .neon-slide__desc { 533 font-size: 12px !important; 534 line-height: 1.5 !important; 535 } 536
537 /* Legendas / Caption */ 538 body figcaption, body .caption, body .date-badge, body .d5-news-date, body .category-badge, 539 body .neon-news-header__label span, body .neon-news-header__label { 540 font-size: 11px !important; 541 line-height: 1.4 !important; 542 } 543 } 544 545/* === CONTROLE DE TAMANHO DO LOGOTIPO === */ 546@media (min-width: 769px) { 547 .site-logo img, .navbar-brand img, .navbar-logo img, header .logo img, nav .logo img, header img[src*='uploads/media'], header img[src*='uploads/logo'], header a[href='./'] > img, .wave-header__logo img, .pulse-header__logo img, .neon-header__logo img, .header-logo img { 548 width: 120px !important; 549 max-width: 100% !important; 550 height: auto !important; 551 object-fit: contain !important; 552 display: block !important; 553 transition: width 0.2s, height 0.2s !important; 554 } 555 header, .site-header, nav.navbar, .navbar, .navbar-inner, .header-inner, .wave-header, .pulse-header, .neon-header { 556 height: auto !important; 557 min-height: 68px !important; 558 padding-top: 16px !important; 559 padding-bottom: 16px !important; 560 display: flex !important; 561 align-items: center !important; 562 box-sizing: border-box !important; 563 } 564} 565@media (max-width: 768px) { 566 .site-logo img, .navbar-brand img, .navbar-logo img, header .logo img, nav .logo img, header img[src*='uploads/media'], header img[src*='uploads/logo'], header a[href='./'] > img, .wave-header__logo img, .pulse-header__logo img, .neon-header__logo img, .header-logo img, #mobileNav img[src*='uploads/media'], #mobileNav img[src*='uploads/logo'], #mobileNav a[href='./'] > img, [data-ag-drawer] img[src*='uploads/media'], [data-ag-drawer] img[src*='uploads/logo'], [data-ag-drawer] a[href='./'] > img, .wave-mobile__logo img, .pulse-mobile__logo img, .neon-mobile__logo img, .mobile-logo img { 567 width: 50px !important; 568 max-width: 100% !important; 569 height: auto !important; 570 object-fit: contain !important; 571 display: block !important; 572 transition: width 0.2s, height 0.2s !important; 573 } 574 header, .site-header, nav.navbar, .navbar, .navbar-inner, .header-inner, .wave-header, .pulse-header, .neon-header { 575 height: auto !important; 576 min-height: 39px !important; 577 padding-top: 12px !important; 578 padding-bottom: 12px !important; 579 } 580} 581.navbar-brand, .site-logo, nav .logo, .wave-header__logo, .pulse-header__logo, .neon-header__logo, .header-logo { 582 display: flex !important; 583 align-items: center !important; 584 overflow: visible !important; 585 flex-shrink: 0 !important; 586 height: auto !important; 587} 588 </style> 589 590 <!-- Google Analytics --> 591 592 <!-- Google Search Console --> 593 594 <!-- Código Personalizado â <head> (raw, escopo do tenant; ver /?page=integrations) --> 595 </head> 596 597<body class="theme-light page-home"> 598 599 600 <!-- Código Personalizado â inÃcio do <body> (raw, escopo do tenant) --> 601 602 603<header class="neon-header" id="header"> 604 <div class="neon-header__inner"> 605 <!-- Logo --> 606 <a href="./" class="neon-header__logo"> 607 <img src="https://nativafmbauru.com.br/uploads/media/6a2974fa436ab_1781101818.png" 608 alt="Nativa FM Bauru"> 609 </a> 610 611 <!-- Desktop Nav --> 612 <nav class="ag-eic neon-nav ag-eic--neon" id="mainNav" aria-label="Menu principal"> 613 <ul class="ag-eic__list"> 614 <li class="ag-eic__item is-active"> 615 <a 616 class="ag-eic__link" 617 href="https://nativafmbauru.com.br/" 618 aria-current="page" aria-expanded="false" 619 > 620 <span class="ag-eic__icon"><svg class="ag-eic__icon-svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false">
620<path d="M4 11 12 4l8 7"/><path d="M6 10v9a1 1 0 0 0 1 1h3v-6h4v6h3a1 1 0 0 0 1-1v-9"/></svg></span> 621 <span class="ag-eic__label-wrap"><span class="ag-eic__label">Home</span></span> 622 </a> 623 </li> 624 <li class="ag-eic__item"> 625 <a 626 class="ag-eic__link" 627 href="noticias" 628 aria-expanded="false" 629 > 630 <span class="ag-eic__icon"><svg class="ag-eic__icon-svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M7 3h7l4 4v13a1 1 0 0 1-1 1H7a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1z"/><path d="M14 3v4h4"/><line x1="8.5" y1="12" x2="15.5" y2="12"/><line x1="8.5" y1="15.5" x2="15.5" y2="15.5"/></svg></span> 631 <span class="ag-eic__label-wrap"><span class="ag-eic__label">NotÃcias</span></span> 632 </a> 633 </li> 634 <li class="ag-eic__item"> 635 <a 636 class="ag-eic__link" 637 href="equipe" 638 aria-expanded="false" 639 > 640 <span class="ag-eic__icon"><svg class="ag-eic__icon-svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><circle cx="9" cy="8" r="3.5"/><path d="M2.5 20a6.5 6.5 0 0 1 13 0"/><circle cx="17" cy="9" r="3"/><path d="M15.5 13.5c2.9.3 5 2.5 5.5 6.3"/></svg></span> 641 <span class="ag-eic__label-wrap"><span class="ag-eic__label">Equipe</span></span> 642 </a> 643 </li> 644 <li class="ag-eic__item"> 645 <a 646 class="ag-eic__link" 647 href="promocoes" 648 aria-expanded="false" 649 > 650 <span class="ag-eic__icon"><svg class="ag-eic__icon-svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><rect x="3" y="8.5" width="18" height="4" rx="1"/><path d="M5 12.5V20a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-7.5"/><line x1="12" y1="8.5" x2="12" y2="21"/><path d="M12 8.5S10.8 3.5 8.4 3.5a2.2 2.2 0 0 0 0 5zM12 8.5s1.2-5 3.6-5a2.2 2.2 0 0 1 0 5z"/></svg></span> 651 <span class="ag-eic__label-wrap"><span class="ag-eic__label">Promoções</span></span> 652 </a> 653 </li> 654 <li class="ag-eic__item"> 655 <a 656 class="ag-eic__link" 657 href="programacao" 658 aria-expanded="false" 659 > 660 <span class="ag-eic__icon"><svg class="ag-eic__icon-svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="9"/><path d="M12 7v5.2l3.4 2"/></svg></span> 661 <span class="ag-eic__label-wrap"><span class="ag-eic__label">Programação</span></span> 662 </a> 663 </li> 664 <li class="ag-eic__item"> 665 <a 666 class="ag-eic__link" 667 href="contato" 668 aria-expanded="false" 669 > 670 <span class="ag-eic__icon"><svg class="ag-eic__icon-svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><rect x="3" y="5" width="18" height="14" rx="2"/><path d="M3 7l9 6 9-6"/></svg></span> 671 <span class="ag-eic__label-wrap"><span class="ag-eic__label">Contato</span></span> 672 </a> 673 </li> 674 </ul> 675</nav> 676 677<style> 678/* Menu Horizontal ExpansÃvel com Ãcones â estilos globais (emitidos uma única vez por página) */ 679.ag-eic { 680 --ag-eic-radius: 14px; 681 --ag-eic-height: 44px; 682 --ag-eic-gap: 8px; 683 --ag-eic-pad: 14px; 684 --ag-eic-font-size: var(--nav-font-size, 14px); 685 --ag-eic-bg: var(--bg-secondary, #eef0f3); 686 --ag-eic-bg-hover: var(--bg-hover, var(--bg-tertiary, #e2e5ea)); 687 --ag-eic-text: var(--text-secondary, #52525b); 688 --ag-eic-text-hover: var(--text-primary, #18181b); 689 --ag-eic-accent: var(--color-primary, var(--primary-color, #2563eb)); 690 --ag-eic-bg-active: rgba(37, 99, 235, .12); 691 --ag-eic-bg-active: color-mix(in srgb, var(--ag-eic-accent) 14%, transparent); 692 --ag-eic-border: 0 solid transparent; 693 --ag-eic-shadow: none; 694 max-width: 100%; 695 overflow-x: auto; 696 scrollbar-width: none; 697 -ms-overflow-style: none; 698} 699.ag-eic::-webkit-scrollbar { display: none; } 700 701.ag-eic__list { 702 display: flex; 703 align-items: center; 704 flex-wrap: nowrap; 705 gap: var(--ag-eic-gap); 706 margin: 0; 707 padding: 2px; 708 list-style: none; 709} 710 711.ag-eic__item { 712 position: relative; 713 flex: 0 0 auto; 714} 715 716/* O <a> não carrega `color` de propósito â ver "NOTA DE CASCATA" no topo 717 deste arquivo. Quem pinta é .ag-eic__icon / .ag-eic__label. */ 718.ag-eic__link { 719 display: grid; 720 grid-template-columns: auto 0fr;
721 align-items: center; 722 height: var(--ag-eic-height); 723 border: var(--ag-eic-border); 724 border-radius: var(--ag-eic-radius); 725 background: var(--ag-eic-bg); 726 box-shadow: var(--ag-eic-shadow); 727 text-decoration: none; 728 cursor: pointer; 729 -webkit-tap-highlight-color: transparent; 730 transition: grid-template-columns 260ms cubic-bezier(.4, 0, .2, 1), 731 background-color 200ms ease, 732 box-shadow 200ms ease; 733} 734 735.ag-eic__icon { 736 width: calc(var(--ag-eic-height) - 2px); 737 height: 100%; 738 display: flex; 739 align-items: center; 740 justify-content: center; 741 flex-shrink: 0; 742 color: var(--ag-eic-text); 743 transition: color 200ms ease; 744} 745 746.ag-eic__icon-svg { 747 width: 20px; 748 height: 20px; 749} 750 751.ag-eic__label-wrap { 752 min-width: 0; 753 overflow: hidden; 754} 755 756.ag-eic__label { 757 display: block; 758 white-space: nowrap; 759 font-family: var(--nav-font-family, inherit); 760 font-size: var(--ag-eic-font-size); 761 font-weight: 600; 762 line-height: 1; 763 color: var(--ag-eic-text); 764 padding-right: 0; 765 opacity: 0; 766 transform: translateX(-4px); 767 transition: opacity 180ms ease, transform 180ms ease, color 200ms ease, 768 padding-right 260ms cubic-bezier(.4, 0, .2, 1); 769} 770 771/* Expansão no hover â só em dispositivos com mouse/trackpad de fato */ 772@media (hover: hover) and (pointer: fine) { 773 .ag-eic__item:hover .ag-eic__link { 774 grid-template-columns: auto 1fr; 775 background: var(--ag-eic-bg-hover); 776 } 777 .ag-eic__item:hover .ag-eic__icon, 778 .ag-eic__item:hover .ag-eic__label { 779 color: var(--ag-eic-text-hover); 780 } 781 .ag-eic__item:hover .ag-eic__label { 782 opacity: 1; 783 transform: none; 784 padding-right: var(--ag-eic-pad); 785 } 786} 787 788/* Expansão por teclado (foco) ou por toque em mobile (classe .is-expanded via JS) */ 789.ag-eic__item:focus-within .ag-eic__link, 790.ag-eic__item.is-expanded .ag-eic__link { 791 grid-template-columns: auto 1fr; 792 background: var(--ag-eic-bg-hover); 793} 794.ag-eic__item:focus-within .ag-eic__icon, 795.ag-eic__item:focus-within .ag-eic__label, 796.ag-eic__item.is-expanded .ag-eic__icon, 797.ag-eic__item.is-expanded .ag-eic__label { 798 color: var(--ag-eic-text-hover); 799} 800.ag-eic__item:focus-within .ag-eic__label, 801.ag-eic__item.is-expanded .ag-eic__label { 802 opacity: 1; 803 transform: none; 804 padding-right: var(--ag-eic-pad); 805} 806 807/* Item ativo (página atual) */ 808.ag-eic__item.is-active .ag-eic__link { 809 background: var(--ag-eic-bg-active); 810} 811.ag-eic__item.is-active .ag-eic__icon, 812.ag-eic__item.is-active .ag-eic__label { 813 color: var(--ag-eic-accent); 814} 815.ag-eic__item.is-active .ag-eic__link::after { 816 content: ''; 817 position: absolute; 818 left: 10px; 819 right: 10px; 820 bottom: 3px; 821 height: 3px; 822 border-radius: 2px; 823 background: var(--ag-eic-accent); 824} 825 826/* Item desabilitado */ 827.ag-eic__item.is-disabled .ag-eic__link { 828 opacity: .45; 829 cursor: not-allowed; 830 pointer-events: none; 831} 832 833/* Foco visÃvel no teclado */ 834.ag-eic__link:focus-visible { 835 outline: 2px solid var(--ag-eic-accent); 836 outline-offset: 2px; 837} 838 839@media (max-width: 768px) { 840 .ag-eic { 841 --ag-eic-height: 40px; 842 --ag-eic-gap: 6px; 843 --ag-eic-pad: 12px; 844 } 845 .ag-eic__icon-svg { 846 width: 18px; 847 height: 18px; 848 } 849} 850 851@media (prefers-reduced-motion: reduce) { 852 .ag-eic__link, 853 .ag-eic__label, 854 .ag-eic__icon { 855 transition: none !important; 856 } 857} 858</style>
859<script> 860(function () { 861 // Comportamento mÃnimo: em telas sem hover (touch), o primeiro toque 862 // expande o item e o segundo navega. No desktop tudo é CSS. 863 function hasHover() { 864 return window.matchMedia('(hover: hover) and (pointer: fine)').matches; 865 } 866 867 function collapseAll(except) { 868 document.querySelectorAll('.ag-eic__item.is-expanded').forEach(function (el) { 869 if (el === except) return; 870 el.classList.remove('is-expanded'); 871 const link = el.querySelector('.ag-eic__link'); 872 if (link) link.setAttribute('aria-expanded', 'false'); 873 }); 874 } 875 876 document.addEventListener('click', function (e) { 877 const link = e.target.closest('.ag-eic__link'); 878 if (link && !hasHover()) { 879 const item = link.closest('.ag-eic__item'); 880 if (item && !item.classList.contains('is-expanded')) { 881 e.preventDefault(); 882 collapseAll(item); 883 item.classList.add('is-expanded'); 884 link.setAttribute('aria-expanded', 'true'); 885 return; 886 } 887 } 888 if (!e.target.closest('.ag-eic')) collapseAll(null); 889 }); 890 891 document.addEventListener('keydown', function (e) { 892 if (e.key === 'Escape') collapseAll(null); 893 }); 894 895 document.addEventListener('focusin', function (e) { 896 const link = e.target.closest('.ag-eic__link'); 897 if (link) link.setAttribute('aria-expanded', 'true'); 898 }); 899 900 document.addEventListener('focusout', function (e) { 901 const link = e.target.closest('.ag-eic__link'); 902 const item = link ? link.closest('.ag-eic__item') : null; 903 if (link && item && !item.classList.contains('is-expanded')) { 904 link.setAttribute('aria-expanded', 'false'); 905 } 906 }); 907 908 /** 909 * Re-sincroniza o item ativo no cliente. Os headers dos temas já marcam 910 * o ativo no PHP; isto cobre bfcache / service worker cache / popstate, 911 * substituindo o que as funções sync*NavActive() faziam com os links de 912 * texto antigos. 913 */ 914 window.agEicSyncActive = function () { 915 // NFD decompoe os acentos e o filtro [^a-z0-9-] abaixo ja descarta as 916 // marcas combinantes resultantes -- por isso nao ha replace dedicado 917 // a elas (evita caracteres invisiveis no fonte). 918 const norm = (s) => s.toLowerCase() 919 .normalize('NFD') 920 .replace(/[^a-z0-9-]/g, ''); 921 922 const slugFromHref = (href) => { 923 try { 924 const url = new URL(href, window.location.origin); 925 const sp = url.searchParams.get('page'); 926 if (sp) return sp; 927 const p = url.pathname.replace(/^\//, '').replace(/\/$/, ''); 928 return p ? p.split('/').pop() : 'home'; 929 } catch (e) { 930 const s = href.replace(/^\//, '').replace(/\/$/, ''); 931 return s || 'home'; 932 } 933 }; 934 935 const current = norm(window.location.pathname.replace(/^\//, '').replace(/\/$/, '') || 'home'); 936 937 document.querySelectorAll('.ag-eic__link[href]').forEach(function (link) { 938 const on = norm(slugFromHref(link.getAttribute('href') || '')) === current; 939 const item = link.closest('.ag-eic__item'); 940 if (item) item.classList.toggle('is-active', on); 941 if (on) { 942 link.setAttribute('aria-current', 'page'); 943 } else { 944 link.removeAttribute('aria-current'); 945 } 946 }); 947 }; 948 949 window.agEicSyncActive(); 950 window.addEventListener('pageshow', function (e) { if (e.persisted) window.agEicSyncActive(); }); 951 window.addEventListener('popstate', function () { window.agEicSyncActive(); }); 952})(); 953</script>
953 954 955 <!-- Right Actions --> 956 <div class="neon-header__actions"> 957 <!-- Seletor de Praça (multi-praça; inerte com <2 praças) --> 958 959 <!-- On Air Widget --> 960 961 <!-- Search --> 962 <form action="https://nativafmbauru.com.br/" method="GET" class="neon-search" id="neonDesktopSearchForm"> 963 <input type="hidden" name="page" value="busca"> 964 <button type="submit" class="neon-search__btn"> 965 <!-- Lucide: search --> 966 <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/></svg> 967 </button> 968 <input type="text" name="q" placeholder="Buscar..." class="neon-search__input" id="neonDesktopSearchInput" autocomplete="off"> 969 <div class="neon-search-spinner" style="display: none;"> 970 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="spin"><path d="M21 12a9 9 0 1 1-6.219-8.56"/></svg> 971 </div> 972 <!-- Resultado Desktop --> 973 <div class="neon-live-search-results" id="neonDesktopSearchDropdown"></div> 974 </form> 975 976 </div> 977 978 <!-- NEW: Mobile Actions (App Style Spotify) --> 979 <div class="neon-header__mobile-actions"> 980 <!-- Mobile Toggle (drawer) --> 981 <button type="button" class="neon-header__mobile-btn neon-header__mobile-action" id="neonMobileBtn" data-ag-drawer-toggle aria-label="Abrir menu" aria-expanded="false" aria-controls="neonMobile"> 982 <!-- Lucide: menu --> 983 <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="4" x2="20" y1="12" y2="12"/><line x1="4" x2="20" y1="6" y2="6"/><line x1="4" x2="20" y1="18" y2="18"/></svg> 984 </button> 985 <a href="https://wa.me/5514997350454" target="_blank" rel="noopener" class="neon-header__mobile-action header-icon-whatsapp" aria-label="WhatsApp" style="display: flex; align-items: center;"> 986 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" style="width: 22px; height: 22px; min-width: 22px; min-height: 22px;"> 987 <path d="M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 005.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 00-3.48-8.413z"/> 988 </svg> 989 </a> 990 <button type="button" class="neon-header__mobile-action" onclick="NeonMobileSearch.open()" aria-label="Buscar" style="display: flex; align-items: center;"> 991 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="width: 22px; height: 22px; min-width: 22px; min-height: 22px;"><circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/></svg> 992 </button> 993 </div> 994 </div> 995</header> 996 997<!-- Mobile Expandable Search --> 998<div class="neon-mobile-search-overlay" id="neonMobileSearchOverlay"> 999 <div class="neon-mobile-search-dialog"> 1000 <div class="neon-mobile-search-topbar"> 1001 <h3 class="neon-mobile-search-title">Pesquisar</h3> 1002 <button type="button" class="neon-mobile-search-close" onclick="NeonMobileSearch.close()" aria-label="Fechar Busca"> 1003 <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg> 1004 </button> 1005 </div> 1006 <form action="https://nativafmbauru.com.br/" method="GET" class="neon-mobile-search-form" id="neonMobileSearchForm"> 1007 <input type="hidden" name="page" value="busca"> 1008 <button type="submit" class="neon-mobile-search-submit"> 1009 <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/></svg> 1010 </button> 1011 <input type="text" name="q" placeholder="O que você quer ouvir?" class="neon-mobile-search-input" id="neonMobileSearchInput" autocomplete="off"> 1012 <div class="neon-search-spinner" id="neonMobileSearchSpinner" style="display: none;"> 1013 <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="spin"><path d="M21 12a9 9 0 1 1-6.219-8.56"/></svg> 1014 </div> 1015 </form> 1016 <!-- Resultado Mobile --> 1017 <div class="neon-mobile-live-results" id="neonMobileSearchDropdown"></div> 1018 </div> 1019</div> 1020 1021<!-- Menu Mobile Drawer (partial compartilhado â markup+JS únicos) --> 1022 1023<!-- Backdrop / Overlay do Drawer --> 1024<div class="neon-mobile-overlay" id="neonOverlay" data-ag-drawer-overlay></div> 1025 1026<!-- Drawer / Painel Lateral --> 1027<aside class="neon-mobile" id="neonMobile" data-ag-drawer aria-hidden="true"> 1028 <div class="neon-mobile__header"> 1029 <div class="neon-mobile__logo"> 1030 <img src="https://nativafmbauru.com.br/uploads/media/6a2974fa436ab_1781101818.png" 1031 alt="Nativa FM Bauru"> 1032 </div> 1033 <button type="button" class="neon-mobile__close" data-ag-drawer-close aria-label="Fechar menu"> 1034 <!-- Lucide: x --> 1035 <svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg> 1036 </button> 1037 </div> 1038 1039 1040 1041 <nav class="neon-mobile__nav"> 1042 <a href="https://nativafmbauru.com.br/" data-ag-drawer-link 1043 class="neon-mobile__link neon-mobile__link--active"> 1044 Home <!-- Lucide: chevron-right --> 1045 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewB
1045ox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="m9 18 6-6-6-6"/></svg> 1046 </a> 1047 <a href="noticias" data-ag-drawer-link 1048 class="neon-mobile__link "> 1049 NotÃcias <!-- Lucide: chevron-right --> 1050 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="m9 18 6-6-6-6"/></svg> 1051 </a> 1052 <a href="equipe" data-ag-drawer-link 1053 class="neon-mobile__link "> 1054 Equipe <!-- Lucide: chevron-right --> 1055 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="m9 18 6-6-6-6"/></svg> 1056 </a> 1057 <a href="promocoes" data-ag-drawer-link 1058 class="neon-mobile__link "> 1059 Promoções <!-- Lucide: chevron-right --> 1060 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="m9 18 6-6-6-6"/></svg> 1061 </a> 1062 <a href="programacao" data-ag-drawer-link 1063 class="neon-mobile__link "> 1064 Programação <!-- Lucide: chevron-right --> 1065 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="m9 18 6-6-6-6"/></svg> 1066 </a> 1067 <a href="contato" data-ag-drawer-link 1068 class="neon-mobile__link "> 1069 Contato <!-- Lucide: chevron-right --> 1070 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="m9 18 6-6-6-6"/></svg> 1071 </a> 1072 </nav> 1073 1074 <div class="neon-mobile__footer"> 1075 <p>Nativa FM Bauru</p> 1076 </div> 1077</aside> 1078
1079<script> 1080/* Controlador ÃNICO do drawer mobile (compartilhado por Pulse/Wave/Neon/Glow). 1081 Como só um tema renderiza por página, há um único [data-ag-drawer]. */ 1082(function () { 1083 if (window.AgDrawer) return; 1084 1085 const panel = document.querySelector('[data-ag-drawer]'); 1086 if (!panel) return; 1087 const overlay = document.querySelector('[data-ag-drawer-overlay]'); 1088 const toggles = document.querySelectorAll('[data-ag-drawer-toggle]'); 1089 let lastFocus = null; 1090 1091 const AgDrawer = { 1092 open() { 1093 panel.classList.add('is-open'); 1094 if (overlay) overlay.classList.add('is-open'); 1095 document.body.style.overflow = 'hidden'; 1096 panel.setAttribute('aria-hidden', 'false'); 1097 toggles.forEach(t => t.setAttribute('aria-expanded', 'true')); 1098 // Acessibilidade: guarda o foco anterior e move para o botão de fechar. 1099 lastFocus = document.activeElement; 1100 const closeBtn = panel.querySelector('[data-ag-drawer-close]'); 1101 if (closeBtn) closeBtn.focus(); 1102 }, 1103 close() { 1104 panel.classList.remove('is-open'); 1105 if (overlay) overlay.classList.remove('is-open'); 1106 document.body.style.overflow = ''; 1107 panel.setAttribute('aria-hidden', 'true'); 1108 toggles.forEach(t => t.setAttribute('aria-expanded', 'false')); 1109 // Devolve o foco a quem abriu o drawer. 1110 if (lastFocus && typeof lastFocus.focus === 'function') lastFocus.focus(); 1111 }, 1112 toggle() { 1113 panel.classList.contains('is-open') ? this.close() : this.open(); 1114 } 1115 }; 1116 window.AgDrawer = AgDrawer; 1117 1118 toggles.forEach(t => { 1119 t.setAttribute('aria-expanded', 'false'); 1120 t.addEventListener('click', (e) => { e.preventDefault(); AgDrawer.toggle(); }); 1121 }); 1122 if (overlay) overlay.addEventListener('click', () => AgDrawer.close()); 1123 panel.querySelectorAll('[data-ag-drawer-close]').forEach(b => b.addEventListener('click', () => AgDrawer.close())); 1124 panel.querySelectorAll('[data-ag-drawer-link]').forEach(a => a.addEventListener('click', () => AgDrawer.close())); 1125 document.addEventListener('keydown', (e) => { 1126 if (e.key === 'Escape' && panel.classList.contains('is-open')) AgDrawer.close(); 1127 }); 1128})(); 1129</script>
1129 1130 1131<!-- Header spacer removido: #mainContent já tem padding-top:72px via style.css --> 1132
1133<script> 1134// ââ Active nav state sync (JS) ââââââââââââââââââââââââââââââââââââââââââ 1135function syncNeonNavActive() { 1136 const raw = window.location.pathname.replace(/^\//, '').replace(/\/$/, ''); 1137 const currentPage = raw || 'home'; 1138 const normalizeSlug = (s) => s.toLowerCase().normalize('NFD').replace(/[\u0300-\u036f]/g, '').replace(/[^a-z0-9-]/g, ''); 1139 const getSlug = (href) => { 1140 try { 1141 const url = new URL(href, window.location.origin); 1142 const sp = url.searchParams.get('page'); 1143 if (sp) return sp; 1144 const p = url.pathname.replace(/^\//, '').replace(/\/$/, ''); 1145 return p ? p.split('/').pop() : 'home'; 1146 } catch(e) { return href.replace(/^\//, '').replace(/\/$/, '') || 'home'; } 1147 }; 1148 const pn = normalizeSlug(currentPage); 1149 // Menu de Ãcones: o componente mantém o próprio sync (.is-active no <li> + 1150 // aria-current no link). Menu de texto: a lista abaixo fica vazia quando o 1151 // estilo de Ãcones está ativo, então as duas linhas convivem. 1152 if (typeof window.agEicSyncActive === 'function') window.agEicSyncActive(); 1153 document.querySelectorAll('.neon-nav__link').forEach(l => l.classList.toggle('neon-nav__link--active', normalizeSlug(getSlug(l.getAttribute('href')||'')) === pn)); 1154 document.querySelectorAll('.neon-mobile__link').forEach(l => l.classList.toggle('neon-mobile__link--active', normalizeSlug(getSlug(l.getAttribute('href')||'')) === pn)); 1155} 1156syncNeonNavActive(); 1157window.addEventListener('pageshow', (e) => { if (e.persisted) syncNeonNavActive(); }); 1158window.addEventListener('popstate', syncNeonNavActive); 1159// ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ 1160 1161// ESC fecha a busca mobile. O drawer é controlado pelo AgDrawer (partial compartilhado). 1162document.addEventListener('keydown', e => { 1163 if (e.key === 'Escape' && typeof NeonMobileSearch !== 'undefined') NeonMobileSearch.close(); 1164}); 1165 1166const NeonMobileSearch = { 1167 open() { 1168 document.getElementById('neonMobileSearchOverlay').classList.add('is-active'); 1169 document.body.style.overflow = 'hidden'; 1170 setTimeout(() => { 1171 const input = document.getElementById('neonMobileSearchInput'); 1172 if(input) input.focus(); 1173 }, 300); 1174 }, 1175 close() { 1176 document.getElementById('neonMobileSearchOverlay').classList.remove('is-active'); 1177 document.body.style.overflow = ''; 1178 }, 1179 toggle() { 1180 document.getElementById('neonMobileSearchOverlay').classList.contains('is-active') ? this.close() : this.open(); 1181 } 1182}; 1183</script>
1183 1184 <!-- Page Content --> 1185 <div id="mainContent"> 1186 1187<!-- âââââââââââ NEON HERO SLIDER âââââââââââ --> 1188<section class="neon-slider neon-slider--contained neon-slider--rounded" 1189 style="margin-top:20px;"> 1190 <div class="neon-slider__container" style="height:500px;min-height:260px;border-radius:var(--neon-radius-lg, 24px);overflow:hidden;position:relative;"> 1191 1192 <div id="neon-hero-slider" class="neon-slider__track slider-transition-vertical slider-align-left" 1193 style="height:100%;width:100%;border-radius:var(--neon-radius-lg, 24px);"> 1194 1195 <div class="neon-slider__carousel"> 1196 <div class="neon-slide active" 1197 style="opacity:1; "> 1198 1199 <!-- Imagem de fundo --> 1200 <img alt="" 1201 class="neon-slide__img" 1202 src="https://nativafmbauru.com.br/uploads/sliders/6a18a61ad4146_1780000282.webp" 1203 loading="eager"> 1204 1205 <!-- Overlay gradiente --> 1206 1207 <!-- Conteúdo textual --> 1208 <div class="neon-slide__content" style="padding-bottom:5rem;"> 1209 1210 1211 </div> 1212 </div> 1213 <div class="neon-slide " 1214 style="opacity:0; cursor: pointer;" data-slide-link="noticia/radio-liga-sozinho-e-toca-rick-renner-apos-morte-do-cantor-bruno-se-surpreende-nao-tem-explicacao" data-slide-target="_self"> 1215 1216 <!-- Imagem de fundo --> 1217 <img alt="Rádio liga sozinho e toca Rick & Renner após morte do cantor; Bruno se surpreende: âNão tem explicaçãoâ" 1218 class="neon-slide__img" 1219 src="https://nativafmbauru.com.br/uploads/rss_6abd3945bc294.png" 1220 loading="lazy"> 1221 1222 <!-- Overlay gradiente --> 1223 <div class="neon-slide__overlay" style="--ov-r: 0; --ov-g: 0; --ov-b: 0; --ov-a: 0.5; background:linear-gradient(to right, rgba(0,0,0,0.83) 0%, rgba(0,0,0,0.65) 35%, rgba(0,0,0,0.30) 55%, rgba(0,0,0,0) 100%);"></div> 1224 1225 <!-- Conteúdo textual --> 1226 <div class="neon-slide__content" style="padding-bottom:5rem;"> 1227 <h1 style="--sl-title-fs:clamp(1.8rem, 3.5vw, 2.8rem);font-size:clamp(1.8rem, 3.5vw, 2.8rem);color:#ffffff !important;line-height:1.2;font-weight:bold;" class="neon-slide__title"> 1228 Rádio liga sozinho e toca Rick & Renner após morte do cantor; Bruno se surpreende: âNão tem explicaçãoâ </h1> 1229 1230 <p style="--sl-desc-fs:clamp(0.9rem, 1.4vw, 1.1rem);font-size:clamp(0.9rem, 1.4vw, 1.1rem);color:#ffffff !important;line-height:1.6;" class="neon-slide__desc"> 1231 Sertanejo contou que aparelho começou a tocar música da dupla sem que ninguém o acionasse e interpretou o episódio como⦠</p> 1232 1233 </div> 1234 </div> 1235 <div class="neon-slide " 1236 style="opacity:0; "> 1237 1238 <!-- Imagem de fundo --> 1239 <img alt="" 1240 class="neon-slide__img" 1241 src="https://nativafmbauru.com.br/uploads/sliders/6a18a620ee2ff_1780000288.webp" 1242 loading="lazy"> 1243 1244 <!-- Overlay gradiente --> 1245 1246 <!-- Conteúdo textual --> 1247 <div class="neon-slide__content" style="padding-bottom:5rem;"> 1248 1249 1250 </div> 1251 </div> 1252 <div class="neon-slide " 1253 style="opacity:0; cursor: pointer;
1253" data-slide-link="promocao/musica-da-semana" data-slide-target="_self"> 1254 1255 <!-- Imagem de fundo --> 1256 <img alt="Música da Semana" 1257 class="neon-slide__img" 1258 src="https://nativafmbauru.com.br/uploads/media/6a18a95f5c211_1780001119.png" 1259 loading="lazy"> 1260 1261 <!-- Overlay gradiente --> 1262 1263 <!-- Conteúdo textual --> 1264 <div class="neon-slide__content" style="padding-bottom:5rem;"> 1265 1266 1267 </div> 1268 </div> 1269 <div class="neon-slide " 1270 style="opacity:0; cursor: pointer;" data-slide-link="promocao/pix-surpresa-da-nativa-1780000428" data-slide-target="_self"> 1271 1272 <!-- Imagem de fundo --> 1273 <img alt="PIX surpresa da Nativa" 1274 class="neon-slide__img" 1275 src="https://nativafmbauru.com.br/uploads/media/6a18a945650f2_1780001093.png" 1276 loading="lazy"> 1277 1278 <!-- Overlay gradiente --> 1279 1280 <!-- Conteúdo textual --> 1281 <div class="neon-slide__content" style="padding-bottom:5rem;"> 1282 1283 1284 </div> 1285 </div> 1286 </div> 1287 1288 <!-- Dots --> 1289 <div class="neon-slider__dots"> 1290 <button onclick="neonGoToSlide(0)" 1291 class="neon-slider__dot active" 1292 data-slide="0" 1293 aria-label="Ir para slide 1"></button> 1294 <button onclick="neonGoToSlide(1)" 1295 class="neon-slider__dot " 1296 data-slide="1" 1297 aria-label="Ir para slide 2"></button> 1298 <button onclick="neonGoToSlide(2)" 1299 class="neon-slider__dot " 1300 data-slide="2" 1301 aria-label="Ir para slide 3"></button> 1302 <button onclick="neonGoToSlide(3)" 1303 class="neon-slider__dot " 1304 data-slide="3" 1305 aria-label="Ir para slide 4"></button> 1306 <button onclick="neonGoToSlide(4)" 1307 class="neon-slider__dot " 1308 data-slide="4" 1309 aria-label="Ir para slide 5"></button> 1310 </div> 1311 1312 <!-- Arrows --> 1313 <div class="neon-slider__arrows"> 1314 <button class="neon-slider__arrow neon-slider__arrow--prev" onclick="neonPrevSlide()" aria-label="Slide anterior"> 1315 <!-- Lucide: chevron-left --> 1316 <svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="m15 18-6-6 6-6"/></svg> 1317 </button> 1318 <button class="neon-slider__arrow neon-slider__arrow--next" onclick="neonNextSlide()" aria-label="Próximo slide"> 1319 <!-- Lucide: chevron-right --> 1320 <svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="m9 18 6-6-6-6"/></svg> 1321 </button> 1322 </div> 1323 1324 </div> 1325 1326 </div><!-- /.neon-slider__container --> 1327 </section> 1328 1329<!-- âââââââââââ NEON SLIDER STYLES âââââââââââ --> 1330<style> 1331/* ââ Container ââ */ 1332.neon-slider { 1333 position : relative; 1334 width : 100%; 1335 overflow : hidden; 1336 background : var(--neon-bg-deep, #0e0c20); 1337 margin-top : 20px; /* respiro entre o header e o slider */ 1338 margin-bottom: 0; 1339} 1340 1341.neon-slider--contained { 1342 max-width : var(--container-width, 1280px); 1343 margin : 20px auto 0; 1344} 1345 1346.neon-slider--rounded, 1347.neon-slider--contained .neon-slider__container { 1348 border-radius: var(--neon-radius-lg, 24px); 1349 overflow: hidden; 1350} 1351 1352.neon-slider__track { 1353 position: relative; 1354 width: 100%; 1355 overflow: hidden; 1356 background: var(--neon-bg-deep, #0e0c20); 1357} 1358 1359.neon-slider__carousel { 1360 position: relative; 1361 width: 100%; 1362 height: 100%; 1363} 1364 1365/* ââ Slides ââ */ 1366.neon-slide { 1367 position: absolute; 1368 inset: 0; 1369 width: 100%; 1370 height: 100%; 1371 transition: opacity 0.8s ease, visibility 0.8s ease; 1372 visibility: hidden; 1373} 1374 1375.neon-slide.active { 1376 opacity: 1 !important; 1377 visibility: visible !important; 1378 z-index: 2; 1379} 1380 1381.neon-slide__img { 1382 position: absolute; 1383 inset: 0; 1384 width: 100%; 1385 height: 100%; 1386 object-fit: cover; 1387 object-position: center; 1388} 1389 1390.neon-slide__overlay { 1391 position: absolute; 1392 inset: 0; 1393 z-index: 1; 1394} 1395 1396/* ââ Alinhamento Global de Conteúdo ââ */ 1397/* Torna o slide um flex-row para poder posicionar o bloco de conteúdo */ 1398.slider-align-left .neon-slide, 1399.slider-align-center .neon-slide, 1400.slider-align-right .neon-slide { 1401 display : flex; 1402 flex-direction : row; 1403 align-items : stretch; /* conteúdo estica 100% da altura */ 1404} 1405.slider-align-left .neon-slide { justify-content: flex-start; } 1406.slider-align-center .neon-slide { justify-content: center; } 1407.slider-align-right .neon-slide { justify-content: flex-end; } 1408 1409/* Ajustes de texto e espaçamento por alinhamento */ 1410.slider-align-left .neon-slide__content {
1411 align-items : flex-start; 1412 text-align : left; 1413} 1414.slider-align-center .neon-slide__content { 1415 align-items : center; 1416 text-align : center; 1417 max-width : 70%; 1418} 1419.slider-align-right .neon-slide__content { 1420 align-items : flex-end; 1421 text-align : right; 1422 padding-left : 0; 1423 padding-right: 5rem; 1424} 1425 1426/* ââ Content ââ */ 1427.neon-slide__content { 1428 position : relative; 1429 z-index : 3; 1430 display : flex; 1431 flex-direction: column; 1432 justify-content: center; 1433 height : 100%; 1434 padding : 3rem 5rem 8rem !important; /* Maior respiro no bottom (8rem) e laterais (5rem) */ 1435 max-width : 55%; 1436 box-sizing : border-box; 1437} 1438 1439.neon-slide__title { 1440 font-family: var(--font-family, sans-serif); 1441 font-weight: 700; 1442 margin: 0 0 1rem; 1443 line-height: 1.2; 1444 letter-spacing: -0.01em; 1445} 1446 1447.neon-slide__desc { 1448 font-family: var(--font-family, sans-serif); 1449 font-weight: 400; 1450 margin: 0 0 1.5rem; 1451 max-width: 500px; 1452 opacity: 0.9; 1453} 1454 1455/* ââ Tamanho de tÃtulo/descrição vindos do painel (Aparência Global) ââ 1456 Somente desktop (â¥769px). O mobile mantém os tamanhos fixos definidos 1457 nos blocos @media (max-width: 767px/768px) e não é afetado aqui. 1458 Especificidade elevada de propósito: o CSS dinâmico de models/Settings.php 1459 gera `body h1 { font-size: ... !important }` (0,0,2) e 1460 `p:not(.font-preview) { font-size: ... !important }` (0,1,1), que venceriam 1461 `.neon-slide__title` (0,1,0) e o font-size inline. */ 1462@media (min-width: 769px) { 1463 .neon-slide__content .neon-slide__title { 1464 font-size: var(--sl-title-fs) !important; 1465 } 1466 .neon-slide__content p.neon-slide__desc { 1467 font-size: var(--sl-desc-fs) !important; 1468 } 1469} 1470 1471.neon-slide__cta-wrap { 1472 display: flex; 1473} 1474 1475.neon-slide__cta { 1476 display: inline-flex; 1477 align-items: center; 1478 gap: 8px; 1479 padding: 12px 32px; 1480 background: var(--neon-pink, #ff7cf5); 1481 color: #fff; 1482 font-family: var(--font-family, sans-serif); 1483 font-size: 0.9rem; 1484 font-weight: 600; 1485 text-decoration: none; 1486 border-radius: var(--neon-radius-pill, 9999px); 1487 border: none; 1488 cursor: pointer; 1489 transition: all 0.3s ease; 1490 box-shadow: 0 0 20px rgba(var(--neon-pink-rgb, 255, 124, 245), 0.4); 1491 letter-spacing: 0.02em; 1492} 1493 1494.neon-slide__cta:hover { 1495 background: var(--neon-cyan, #00e3fd); 1496 color: #fff; 1497 transform: translateY(-2px); 1498 box-shadow: 0 0 30px rgba(var(--neon-cyan-rgb, 0, 227, 253), 0.5); 1499} 1500 1501/* ââ Dots ââ */ 1502.neon-slider__dots { 1503 position : absolute; 1504 bottom : 2rem; /* Mais próximo da base do slider e afastado do texto */ 1505 left : 50%; 1506 transform: translateX(-50%); 1507 display : flex; 1508 gap : 12px; /* Aumentando levemente o gap para um look mais sofisticado */ 1509 z-index : 10; 1510} 1511 1512.neon-slider__dot { 1513 width: 10px; 1514 height: 10px; 1515 border-radius: 50%; 1516 background: rgba(255, 255, 255, 0.3); 1517 border: none; 1518 cursor: pointer; 1519 transition: all 0.3s ease; 1520 padding: 0; 1521} 1522 1523.neon-slider__dot:hover { 1524 background: rgba(255, 255, 255, 0.6); 1525} 1526 1527.neon-slider__dot.active { 1528 background: var(--neon-pink, #ff7cf5); 1529 width: 28px; 1530 border-radius: 5px; 1531 box-shadow: 0 0 12px rgba(var(--neon-pink-rgb, 255, 124, 245), 0.6); 1532} 1533 1534/* ââ Arrows ââ */ 1535.neon-slider__arrows { 1536 position: absolute; 1537 top: 50%; 1538 transform: translateY(-50%); 1539 width: 100%; 1540 display: flex; 1541 justify-content: space-between; 1542 padding: 0 1rem; 1543 pointer-events: none; 1544 z-index: 10; 1545} 1546 1547.neon-slider__arrow { 1548 width: 48px; 1549 height: 48px; 1550 border-radius: 50%; 1551 background: rgba(var(--neon-pink-rgb, 255, 124, 245), 0.15); 1552 backdrop-filter: blur(12px); 1553 -webkit-backdrop-filter: blur(12px); 1554 border: 1px solid rgba(var(--neon-pink-rgb, 255, 124, 245), 0.3); 1555 color: #fff; 1556 font-size: 1rem; 1557 cursor: pointer; 1558 transition: all 0.3s ease; 1559 pointer-events: auto; 1560 display: flex; 1561 align-items: center; 1562 justify-content: center; 1563} 1564 1565.neon-slider__arrow:hover { 1566 background: var(--neon-pink, #ff7cf5); 1567 border-color: var(--neon-pink, #ff7cf5); 1568 box-shadow: 0 0 20px rgba(var(--neon-pink-rgb, 255, 124, 245), 0.5); 1569} 1570 1571/* ââ Empty fallback ââ */ 1572.neon-slide__empty { 1573 display: flex; 1574 align-items: center; 1575 justify-content: center; 1576 background: radial-gradient(ellipse at 30% 50%, 1577 rgba(var(--neon-pink-rgb, 255, 124, 245), 0.12) 0%, transparent 60%), 1578 var(--neon-bg-deep, #0e0c20); 1579 height: 100%; 1580 min-height: 400px; 1581} 1582 1583/* ââ Mobile ââ */ 1584@media (max-width: 767px) { 1585/* Removido o override fixo .neon-slider, usando .slider-fullscreen / .neon-slider--contained do slider.css global */ 1586 1587 /* Centralização vertical correta â garante que a cadeia de altura funcione mesmo quando 1588 o global slider.css resolve o carousel via position:absolute */ 1589 .neon-slide__content { 1590 position: absolute !important; 1591 top: 0 !important; 1592 bottom: 0 !important; 1593 left: 0 !important; 1594 right: 0 !important; 1595 height: 100% !important; 1596 max-width: 100% !important; 1597 display: flex !important; 1598 flex-direction: column !important; 1599 justify-content: center !important; 1600 align-items: center !important; 1601 text-align: center !important; 1602 padding: 16px !important; 1603 box-sizing: border-box !important; 1604 } 1605 1606 /* Preservar alinhamento global configurado no painel */ 1607 .slider-align-left .neon-slide__content { align-items: flex-start !important; text-align: left !important; } 1608 .slider-align-center .neon-slide__content { align-items: center !important; text-align: center !important; } 1609 .slider-align-right .neon-slide__content { align-items: flex-end !important; text-align: right !important; padding-right: 1.5rem !important; } 1610 1611 .neon-slide__desc { 1612 display: none !important; 1613 } 1614 1615 .neon-slide__cta-wrap { 1616 display: none !important; 1617 } 1618 1619 .neon-slide__title { 1620 font-size: 1.1rem !important; 1621 line-height: 1.3 !important; 1622 } 1623 1624 .neon-slider__arrows { 1625 display: none; 1626 } 1627 1628 .neon-slider__dots { 1629 bottom: 12px; 1630 } 1631 1632 .neon-slider__dot { 1633 width: 8px; 1634 height: 8px; 1635 } 1636 1637 .neon-slider__dot.active { 1638 width: 22px; 1639 } 1640} 1641</style> 1642 1643<!-- âââââââââââ NEON SLIDER SCRIPT âââââââââââ -->
1644<script> 1645(function () { 1646 'use strict'; 1647 1648 var NEON_SLIDER = { 1649 currentSlide: 0, 1650 slides: [], 1651 dots: [], 1652 interval: null, 1653 autoplay: true, 1654 speed: 5000, 1655 isPaused: false, 1656 swipedAt: 0, 1657 1658 init: function () { 1659 this.slides = document.querySelectorAll('.neon-slide'); 1660 this.dots = document.querySelectorAll('.neon-slider__dot'); 1661 1662 // Antes do early return: a área clicável do slide existe mesmo 1663 // quando há um slide só e não há navegação entre slides. 1664 this.bindSlideLinks(); 1665 1666 if (this.slides.length <= 1) return; 1667 1668 var self = this; 1669 1670 // Hover pause 1671 var track = document.getElementById('neon-hero-slider'); 1672 if (track) { 1673 track.addEventListener('mouseenter', function () { self.isPaused = true; }); 1674 track.addEventListener('mouseleave', function () { self.isPaused = false; }); 1675 } 1676 1677 // Touch/swipe 1678 var touchStartX = 0; 1679 if (track) { 1680 track.addEventListener('touchstart', function (e) { 1681 touchStartX = e.changedTouches[0].screenX; 1682 }, { passive: true }); 1683 track.addEventListener('touchend', function (e) { 1684 var diff = touchStartX - e.changedTouches[0].screenX; 1685 if (Math.abs(diff) > 50) { 1686 // Arrastar troca de slide e NÃO conta como clique no slide 1687 // (o toque ainda gera um 'click' logo depois do 'touchend'). 1688 self.swipedAt = Date.now(); 1689 diff > 0 ? self.next() : self.prev(); 1690 } 1691 }, { passive: true }); 1692 } 1693 1694 // Autoplay 1695 if (this.autoplay) { 1696 this.startAutoplay(); 1697 } 1698 }, 1699 1700 /** 1701 * Clique na área do slide (fora de <a> e <button>) navega pela SPA. 1702 * Navegação dura recarregaria o documento e pararia o player ao vivo. 1703 * Delegado no track, que é recriado a cada render â sem listener órfão. 1704 */ 1705 bindSlideLinks: function () { 1706 var self = this; 1707 var track = document.getElementById('neon-hero-slider'); 1708 if (!track || track.getAttribute('data-slide-links-bound') === '1') return; 1709 track.setAttribute('data-slide-links-bound', '1'); 1710 1711 track.addEventListener('click', function (e) { 1712 if (e.target.closest('a') || e.target.closest('button')) return; 1713 1714 var slide = e.target.closest('.neon-slide[data-slide-link]'); 1715 if (!slide) return; 1716 1717 // Fim de um arraste não é clique. 1718 if (self.swipedAt && Date.now() - self.swipedAt < 500) return; 1719 1720 var url = slide.getAttribute('data-slide-link'); 1721 if (!url) return; 1722 1723 var target = slide.getAttribute('data-slide-target'); 1724 e.preventDefault(); 1725 1726 if (typeof window.spaNavigate === 'function') { 1727 window.spaNavigate(url, target); 1728 } else if (target === '_blank') { 1729 window.open(url, '_blank', 'noopener,noreferrer'); 1730 } else { 1731 window.location.href = url; 1732 } 1733 }); 1734 }, 1735 1736 show: function (index) { 1737 var self = this; 1738 var track = document.getElementById('neon-hero-slider'); 1739 var isVertical = track && track.classList.contains('slider-transition-vertical'); 1740 var oldSlide = this.currentSlide; 1741 1742 if (isVertical && index !== oldSlide) { 1743 var current = this.slides[oldSlide]; 1744 var next = this.slides[index]; 1745 1746 // PASSO 1 - Prepara 1747 next.style.transition = 'none'; 1748 next.style.transform = 'translateY(100%)'; 1749 next.style.opacity = '0'; 1750 next.style.visibility = 'visible'; 1751 next.style.zIndex = '3'; 1752 1753 current.style.visibility = 'visible'; 1754 current.style.zIndex = '2'; 1755 1756 // Classes puramente de estado 1757 current.classList.add('is-leaving'); 1758 current.classList.remove('active'); 1759 next.classList.add('active'); 1760 next.classList.remove('is-leaving'); 1761 1762 // PASSO 2 - Reflow 1763 next.getBoundingClientRect(); 1764 1765 // PASSO 3 - Religar transitioes 1766 next.style.transition = 'opacity 600ms ease-in-out, transform 600ms ease-in-out'; 1767 current.style.transition = 'opacity 600ms ease-in-out, transform 600ms ease-in-out'; 1768 1769 // PASSO 4 - Despachar simultaneamente 1770 requestAnimationFrame(function() { 1771 next.style.transform = 'translateY(0)'; 1772 next.style.opacity = '1'; 1773 current.style.transform = 'translateY(-100%)'; 1774 current.style.opacity = '0'; 1775 }); 1776 1777 // PASSO 5 - Cleanup 1778 setTimeout(function() {
1779 current.style.transition = 'none'; 1780 current.style.transform = 'translateY(100%)'; 1781 current.style.opacity = '0'; 1782 current.style.zIndex = ''; 1783 current.style.visibility = ''; 1784 next.style.zIndex = ''; 1785 next.style.visibility = ''; 1786 current.classList.remove('is-leaving'); 1787 }, 620); 1788 } else { 1789 this.slides.forEach(function (s) { 1790 s.classList.remove('active'); 1791 s.style.opacity = '0'; 1792 }); 1793 this.slides[index].style.opacity = '1'; 1794 this.slides[index].classList.add('active'); 1795 } 1796 1797 this.dots.forEach(function (d, i) { 1798 if (i === index) { 1799 d.classList.add('active'); 1800 } else { 1801 d.classList.remove('active'); 1802 } 1803 }); 1804 1805 this.currentSlide = index; 1806 }, 1807 1808 next: function () { 1809 this.goTo((this.currentSlide + 1) % this.slides.length); 1810 }, 1811 1812 prev: function () { 1813 this.goTo((this.currentSlide - 1 + this.slides.length) % this.slides.length); 1814 }, 1815 1816 goTo: function (index) { 1817 this.show(index); 1818 if (this.autoplay) { 1819 this.stopAutoplay(); 1820 this.startAutoplay(); 1821 } 1822 }, 1823 1824 startAutoplay: function () { 1825 if (!this.autoplay) return; 1826 this.stopAutoplay(); 1827 var self = this; 1828 this.interval = setInterval(function () { 1829 if (!self.isPaused) { 1830 self.show((self.currentSlide + 1) % self.slides.length); 1831 } 1832 }, this.speed); 1833 }, 1834 1835 stopAutoplay: function () { 1836 if (this.interval) { 1837 clearInterval(this.interval); 1838 this.interval = null; 1839 } 1840 } 1841 }; 1842 1843 // Global functions for onclick 1844 window.neonGoToSlide = function (i) { NEON_SLIDER.goTo(i); }; 1845 window.neonNextSlide = function () { NEON_SLIDER.next(); }; 1846 window.neonPrevSlide = function () { NEON_SLIDER.prev(); }; 1847 1848 if (document.readyState === 'loading') { 1849 document.addEventListener('DOMContentLoaded', function () { NEON_SLIDER.init(); }); 1850 } else { 1851 NEON_SLIDER.init(); 1852 } 1853})(); 1854</script>
1854 1855 1856 1857<section class="section neon-promo-section "> 1858 <div class="container"> 1859 <div class="neon-news-header"> 1860 <div class="neon-news-header__bar"></div> 1861 <div class="neon-news-header__text"> 1862 <div class="neon-news-header__label"> 1863 <!-- Lucide: gift --> 1864 <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 12 20 22 4 22 4 12"/><rect width="22" height="5" x="1" y="7"/><line x1="12" x2="12" y1="22" y2="7"/><path d="M12 7H7.5a2.5 2.5 0 0 1 0-5C11 2 12 7 12 7z"/><path d="M12 7h4.5a2.5 2.5 0 0 0 0-5C13 2 12 7 12 7z"/></svg> 1865 <span>Do seu jeito!</span> 1866 </div> 1867 <h2 class="neon-news-header__title">Promoções</h2> 1868 </div> 1869 </div> 1870 1871 <div class="neon-promo-layout-wrapper"> 1872 <div class="neon-promo-grid shelf-row shelf-82"> 1873 1874 <div class="neon-promo-card"> 1875 <!-- Image --> 1876 <div class="neon-promo-card__img"> 1877 <img src="https://nativafmbauru.com.br/uploads/media/6a18a945650f2_1780001093.png" 1878 alt="PIX surpresa da Nativa" loading="lazy"> 1879 1880 </div> 1881 1882 <!-- Body --> 1883 <div class="neon-promo-card__body"> 1884 <h4 class="neon-promo-card__title">PIX surpresa da Nativa</h4> 1885 1886 <p class="neon-promo-card__desc">Promoção PIX SURPRESA da Nativa 1887 1888O ouvinte deverá mandar uma mensagem de texto para o whatsapp da Promoção da Nativa (...</p> 1889 1890 <!-- Footer: linha separadora + CTA --> 1891 <hr class="neon-promo-card__divider"> 1892 <div class="neon-promo-card__footer"> 1893 <a href="https://nativafmbauru.com.br/promocao/pix-surpresa-da-nativa-1780000428" 1894 class="neon-promo-card__cta neon-promo-card__cta--primary"> 1895 Participar 1896 <!-- Lucide: arrow-right --> 1897 <svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14"/><path d="m12 5 7 7-7 7"/></svg> 1898 </a> 1899 </div> 1900 </div> 1901 </div> 1902 1903 <div class="neon-promo-card"> 1904 <!-- Image --> 1905 <div class="neon-promo-card__img"> 1906 <img src="https://nativafmbauru.com.br/uploads/media/6a18a95f5c211_1780001119.png" 1907 alt="Música da Semana" loading="lazy"> 1908 1909 </div> 1910 1911 <!-- Body --> 1912 <div class="neon-promo-card__body"> 1913 <h4 class="neon-promo-card__title">Música da Semana</h4> 1914 1915 <p class="neon-promo-card__desc">Toda semana com um sucesso que vai te dar R$ 500,00, até sexta-feira no programa âA Nativa entrou no grupoâ. Envie seu n...</p> 1916 1917 <!-- Footer: linha separadora + CTA --> 1918 <hr class="neon-promo-card__divider"> 1919 <div class="neon-promo-card__footer"> 1920 <a href="https://nativafmbauru.com.br/promocao/musica-da-semana" 1921 class="neon-promo-card__cta neon-promo-card__cta--primary"> 1922 Participar 1923 <!-- Lucide: arrow-right --> 1924 <svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14"/><path d="m12 5 7 7-7 7"/></svg> 1925 </a> 1926 </div> 1927 </div> 1928 </div> 1929 </div> 1930 1931 </div> 1932 1933 <!-- Shelf pagination dots (apenas mobile) -->
1934 <div class="shelf-dots"></div> 1935 </div> 1936</section> 1937 1938<!-- Ãltimas NotÃcias â Neon Theme --> 1939<section class="neon-news-section"> 1940 <div class="container"> 1941 <!-- Header Stitch-style --> 1942 <div class="neon-news-header"> 1943 <div class="neon-news-header__bar"></div> 1944 <div class="neon-news-header__text"> 1945 <div class="neon-news-header__label"> 1946 <!-- Lucide: newspaper --> 1947 <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 22h16a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2H8a2 2 0 0 0-2 2v16a2 2 0 0 1-2 2Zm0 0a2 2 0 0 1-2-2v-9c0-1.1.9-2 2-2h2"/><path d="M18 14h-8"/><path d="M15 18h-5"/><path d="M10 6h8v4h-8V6Z"/></svg> 1948 <span>Em destaque</span> 1949 </div> 1950 <h2 class="neon-news-header__title">Ãltimas NotÃcias</h2> 1951 </div> 1952 </div> 1953 1954 <!-- Tabs de categorias --> 1955 <div class="neon-news-tabs" role="tablist" data-news-tabs="neon"> 1956 <button class="neon-news-tab active" data-category="0" role="tab" aria-selected="true">Todas</button> 1957 <button class="neon-news-tab" data-category="4" role="tab" aria-selected="false"> 1958 NotÃcias </button> 1959 </div> 1960 1961 1962 <!-- Layout Wrapper (grid + banner lateral) --> 1963 <div class="neon-news-layout-wrapper"> 1964 1965 <!-- News Grid --> 1966 <div id="neon-home-news-grid" class="neon-news-grid shelf-row shelf-72"> 1967 <div class="neon-promo-card neon-news-card-item"> 1968 <!-- Imagem com badge sobrepost no canto superior esquerdo --> 1969 <div class="neon-promo-card__img"> 1970 <img src="uploads/rss_6abd3945bc294.png" 1971 alt="Rádio liga sozinho e toca Rick & Renner após morte do cantor; Bruno se surpreende: âNão tem explicaçãoâ" 1972 onerror="this.parentElement.classList.add('no-thumb'); this.remove();" loading="lazy"> 1973 <div class="neon-promo-badge neon-promo-badge--primary neon-news-badge"> 1974 <span>NotÃcias</span> 1975 </div> 1976 </div> 1977 1978 <!-- Corpo --> 1979 <div class="neon-promo-card__body"> 1980 <h4 class="neon-promo-card__title">Rádio liga sozinho e toca Rick & Renner após morte do cantor; Bruno se surpreende: âNão tem explicaçãoâ</h4> 1981 <p class="neon-promo-card__desc">Sertanejo contou que aparelho começou a tocar música da dupla sem que ninguém o acionasse e interpretou o episódio como...</p> 1982 1983 <hr class="neon-promo-card__divider"> 1984 <div class="neon-promo-card__footer neon-news-card__footer"> 1985 <time class="neon-news-card__date" datetime="2026-09-28 16:06:33"> 1986 28/09/2026 </time> 1987 <a href="noticia/radio-liga-sozinho-e-toca-rick-renner-apos-morte-do-cantor-bruno-se-surpreende-nao-tem-explicacao" 1988 class="neon-promo-card__cta neon-promo-card__cta--primary"> 1989 Saiba Mais 1990 <!-- Lucide: arrow-right --> 1991 <svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14"/><path d="m12 5 7 7-7 7"/></svg> 1992 </a> 1993 </div> 1994 </div> 1995 </div> 1996 1997 <div class="neon-promo-card neon-news-card-item"> 1998 <!-- Imagem com badge sobrepost no canto superior esquerdo --> 1999 <div class="neon-promo-card__img"> 2000 <img src="uploads/rss_6abd3945c0b48.png" 2001 alt="Rick, da dupla Rick & Renner, morre aos 59 anos em acidente de helicóptero em Santa Catarina" 2002 onerror="this.parentElement.classList.add('no-thumb'); this.remove();" loading="lazy"> 2003 <div class="neon-promo-badge neon-promo-badge--primary neon-news-badge">
2004 <span>NotÃcias</span> 2005 </div> 2006 </div> 2007 2008 <!-- Corpo --> 2009 <div class="neon-promo-card__body"> 2010 <h4 class="neon-promo-card__title">Rick, da dupla Rick & Renner, morre aos 59 anos em acidente de helicóptero em Santa Catarina</h4> 2011 <p class="neon-promo-card__desc">Cantor sertanejo estava entre as cinco pessoas que viajavam na aeronave; destroços foram localizados nesta terça-feira...</p> 2012 2013 <hr class="neon-promo-card__divider"> 2014 <div class="neon-promo-card__footer neon-news-card__footer"> 2015 <time class="neon-news-card__date" datetime="2026-09-22 15:49:26"> 2016 22/09/2026 </time> 2017 <a href="noticia/rick-da-dupla-rick-renner-morre-aos-59-anos-em-acidente-de-helicoptero-em-santa-catarina" 2018 class="neon-promo-card__cta neon-promo-card__cta--primary"> 2019 Saiba Mais 2020 <!-- Lucide: arrow-right --> 2021 <svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14"/><path d="m12 5 7 7-7 7"/></svg> 2022 </a> 2023 </div> 2024 </div> 2025 </div> 2026 2027 <div class="neon-promo-card neon-news-card-item"> 2028 <!-- Imagem com badge sobrepost no canto superior esquerdo --> 2029 <div class="neon-promo-card__img"> 2030 <img src="uploads/rss_6abd3945c50f1.png" 2031 alt="âSó vejo essa menina com roupa de 50 reaisâ: filha de Neymar, Helena é alvo de comentário polêmico sobre pensão e Amanda Kimberlly rebate. âAté a etiquetaâ¦â" 2032 onerror="this.parentElement.classList.add('no-thumb'); this.remove();" loading="lazy"> 2033 <div class="neon-promo-badge neon-promo-badge--primary neon-news-badge"> 2034 <span>NotÃcias</span> 2035 </div> 2036 </div> 2037 2038 <!-- Corpo --> 2039 <div class="neon-promo-card__body"> 2040 <h4 class="neon-promo-card__title">âSó vejo essa menina com roupa de 50 reaisâ: filha de Neymar, Helena é alvo de comentário polêmico sobre pensão e Amanda Kimberlly rebate. âAté a etiquetaâ¦â</h4> 2041 <p class="neon-promo-card__desc">Influenciadora usou o bom humor para responder seguidora que questionou os looks e a pensão da pequena Helena. Amanda...</p> 2042 2043 <hr class="neon-promo-card__divider"> 2044 <div class="neon-promo-card__footer neon-news-card__footer"> 2045 <time class="neon-news-card__date" datetime="2026-08-25 15:45:43"> 2046 25/08/2026 </time> 2047 <a href="noticia/so-vejo-essa-menina-com-roupa-de-50-reais-filha-de-neymar-helena-e-alvo-de-comentario-polemico-sobre-pensao-e-amanda-kimberlly-rebate-ate-a-etiqueta" 2048 class="neon-promo-card__cta neon-promo-card__cta--primary"> 2049 Saiba Mais 2050 <!-- Lucide: arrow-right --> 2051 <svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14"/><path d="m12 5 7 7-7 7"/></svg> 2052 </a> 2053 </div> 2054 </div> 2055 </div> 2056 2057 </div> 2058 2059 </div><!-- /.neon-news-layout-wrapper --> 2060 2061 <div class="neon-news-more"> 2062 <a href="noticias" class="neon-news-more__btn"> 2063 <i class="fas fa-newspaper"></i> 2064 Ver outras notÃcias 2065 </a> 2066 </div> 2067
2068 <div class="shelf-dots"></div> 2069 </div> 2070</section> 2071
2072<script> 2073(function () { 2074 const grid = document.getElementById('neon-home-news-grid'); 2075 const tabs = document.querySelectorAll('[data-news-tabs="neon"] .neon-news-tab'); 2076 const limit = 3; 2077 2078 if (!grid || !tabs.length) return; 2079 2080 function esc(str) { 2081 if (!str) return ''; 2082 const d = document.createElement('div'); 2083 d.textContent = str; 2084 return d.innerHTML; 2085 } 2086 2087 function truncate(str, max) { 2088 if (!str) return ''; 2089 str = str.replace(/<[^>]*>/g, ''); 2090 return str.length > max ? str.slice(0, max) + '...' : str; 2091 } 2092 2093 function fmtDate(dateStr) { 2094 if (!dateStr) return ''; 2095 return new Date(dateStr).toLocaleDateString('pt-BR'); 2096 } 2097 2098 const svgArrow = '<svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14"/><path d="m12 5 7 7-7 7"/></svg>'; 2099 2100 function buildCard(news, idx) { 2101 const excerpt = esc(truncate(news.summary || news.content, 120)); 2102 const imgSrc = news.featured_image ? SITE_URL + '/uploads/' + news.featured_image : ''; 2103 const slug = esc(news.slug || String(news.id)); 2104 2105 return `<div class="neon-promo-card neon-news-card-item"> 2106 <div class="neon-promo-card__img"> 2107 ${imgSrc ? `<img src="${esc(imgSrc)}" alt="${esc(news.title)}" onerror="this.parentElement.classList.add('no-thumb');this.remove();" loading="lazy">` : ''} 2108 ${news.category_name ? `<div class="neon-promo-badge neon-promo-badge--primary neon-news-badge"><span>${esc(news.category_name)}</span></div>` : ''} 2109 </div> 2110 <div class="neon-promo-card__body"> 2111 <h4 class="neon-promo-card__title">${esc(news.title)}</h4> 2112 ${excerpt ? `<p class="neon-promo-card__desc">${excerpt}</p>` : ''} 2113 <hr class="neon-promo-card__divider"> 2114 <div class="neon-promo-card__footer neon-news-card__footer"> 2115 ${news.published_at ? `<time class="neon-news-card__date" datetime="${esc(news.published_at)}">${fmtDate(news.published_at)}</time>` : ''} 2116 <a href="noticia/${slug}" class="neon-promo-card__cta neon-promo-card__cta--primary">Saiba Mais ${svgArrow}</a> 2117 </div> 2118 </div> 2119 </div>`; 2120 } 2121
2122 tabs.forEach(function (tab) { 2123 tab.addEventListener('click', function () { 2124 const categoryId = parseInt(this.dataset.category) || 0; 2125 2126 tabs.forEach(function (t) { 2127 t.classList.remove('active'); 2128 t.setAttribute('aria-selected', 'false'); 2129 }); 2130 this.classList.add('active'); 2131 this.setAttribute('aria-selected', 'true'); 2132 2133 grid.classList.add('neon-news-grid--loading'); 2134 2135 let url = SITE_URL + '/api/news.php?limit=' + limit + '&page=1'; 2136 if (categoryId > 0) url += '&category=' + categoryId; 2137 2138 fetch(url) 2139 .then(function (r) { return r.json(); }) 2140 .then(function (data) { 2141 grid.classList.remove('neon-news-grid--loading'); 2142 grid.innerHTML = ''; 2143 if (data.news && data.news.length > 0) { 2144 data.news.forEach(function (item, idx) { 2145 grid.insertAdjacentHTML('beforeend', buildCard(item, idx)); 2146 }); 2147 } else { 2148 grid.innerHTML = '<p class="neon-news-empty">Nenhuma notÃcia encontrada nesta categoria.</p>'; 2149 } 2150 }) 2151 .catch(function () { 2152 grid.classList.remove('neon-news-grid--loading'); 2153 }); 2154 }); 2155 }); 2156})(); 2157</script>
2157 2158 2159 2160<!-- Top Músicas â Neon Theme --> 2161<section class="neon-chart-section"> 2162 <div class="container"> 2163 <!-- Header: Stitch-style (gradient bar + fire icon) --> 2164 <div class="neon-chart-header" style="display: flex; justify-content: space-between; align-items: flex-end; margin-bottom: 2rem;"> 2165 <div class="neon-news-header" style="margin-bottom: 0;"> 2166 <div class="neon-news-header__bar"></div> 2167 <div class="neon-news-header__text"> 2168 <div class="neon-news-header__label"> 2169 <span class="material-symbols-outlined" style="font-size:14px; font-variation-settings: 'FILL' 1">local_fire_department</span> 2170 <span>As mais tocadas </span> 2171 </div> 2172 <h2 class="neon-news-header__title">Top Músicas</h2> 2173 </div> 2174 </div> 2175 <a href="paradas" class="neon-chart-header__cta"> 2176 Ver Todas â <span class="material-symbols-outlined" style="font-size:16px">arrow_forward</span> 2177 </a> 2178 </div> 2179 2180 <!-- Grid 2 colunas + banner lateral --> 2181 <div class="neon-chart-layout-wrapper"> 2182 <div class="neon-chart-grid" id="chart-list"> 2183 <div class="neon-chart-track neon-chart-track--pink" id="track-0" 2184 data-track-id="28" 2185 onclick="toggleChartTrack(0)"> 2186 2187 <!-- Row: Rank + Cover + Info + Votes --> 2188 <div class="neon-chart-track__row"> 2189 <!-- Rank number --> 2190 <span class="neon-chart-track__rank">01</span> 2191 2192 <!-- Cover art --> 2193 <div class="neon-chart-track__cover" 2194 > 2195 <img class="neon-chart-track__cover-img" id="img-0" 2196 src="https://is1-ssl.mzstatic.com/image/thumb/Music211/v4/3b/d8/a6/3bd8a697-f495-6018-689f-e9b505278bf5/196874116920.jpg/600x600bb.jpg" 2197 alt="Retrovisor" 2198 onerror="this.src='https://nativafmbauru.com.br/assets/img/default-cover.svg'"> 2199 <button class="neon-chart-track__play-overlay" id="play-btn-0" 2200 data-url="https://audio-ssl.itunes.apple.com/itunes-assets/AudioPreview221/v4/8b/38/00/8b3800d0-e962-9f5b-a806-dc2588e54da6/mzaf_576454498965197282.plus.aac.p.m4a" 2201 onclick="event.stopPropagation(); playChartTrack(0)"> 2202 <span class="material-symbols-outlined" id="play-icon-0" style="font-size:22px; font-variation-settings:'FILL' 1">play_arrow</span> 2203 </button> 2204 </div> 2205 2206 <!-- Title + Artist --> 2207 <div class="neon-chart-track__info"> 2208 <p class="neon-chart-track__title">Retrovisor</p> 2209 <p class="neon-chart-track__artist">Gusttavo Lima</p> 2210 </div> 2211 2212 <!-- Vote buttons --> 2213 <div class="neon-chart-track__votes"> 2214 <button class="neon-vote-btn neon-vote-up" id="like-0" 2215 onclick="event.stopPropagation(); vote(0, 'like')" title="Curtir"> 2216 <span class="material-symbols-outlined" style="font-size:18px">thumb_up</span> 2217 </button> 2218 <span class="neon-vote-count" id="vote-count-0"> 2219 36 </span> 2220 <button class="neon-vote-btn neon-vote-down" id="dislike-0" 2221 onclick="event.stopPropagation(); vote(0, 'dislike')" title="Não curtir"> 2222 <span class="material-symbols-outlined" style="font-size:18px">thumb_down</span> 2223 </button> 2224 </div> 2225 </div><!-- /.neon-chart-track__row --> 2226 2227 <!-- Inline player (hidden, shown on click) --> 2228 <div class="neon-inline-player" id="player-ui-0" 2229 data-url="https://audio-ssl.itunes.apple.com/itunes-assets/AudioPreview221/v4/8b/38/00/8b3800d0-e962-9f5b-a806-dc2588e54da6/mzaf_576454498965197282.plus.aac.p.m4a" 2230 data-title="Retrovisor"
2231 data-artist="Gusttavo Lima" 2232 data-cover="https://is1-ssl.mzstatic.com/image/thumb/Music211/v4/3b/d8/a6/3bd8a697-f495-6018-689f-e9b505278bf5/196874116920.jpg/600x600bb.jpg" 2233 style="display:none;"> 2234 <button class="neon-inline-player__btn" id="pplay-0" 2235 data-url="https://audio-ssl.itunes.apple.com/itunes-assets/AudioPreview221/v4/8b/38/00/8b3800d0-e962-9f5b-a806-dc2588e54da6/mzaf_576454498965197282.plus.aac.p.m4a" 2236 onclick="event.stopPropagation(); playChartTrack(0)"> 2237 <span class="material-symbols-outlined" style="font-size:18px; font-variation-settings:'FILL' 1">play_arrow</span> 2238 </button> 2239 <div style="flex:1; min-width:0;"> 2240 <div class="neon-inline-player__bar" onclick="seekTrack(event,0)"> 2241 <div class="neon-inline-player__progress" id="progress-bar-0"></div> 2242 </div> 2243 <div class="neon-inline-player__times"> 2244 <span id="current-time-0">0:00</span> 2245 <span id="total-time-0">--:--</span> 2246 </div> 2247 </div> 2248 </div><!-- /.neon-inline-player --> 2249 2250 </div><!-- /.neon-chart-track --> 2251 <div class="neon-chart-track neon-chart-track--cyan" id="track-1" 2252 data-track-id="30" 2253 onclick="toggleChartTrack(1)"> 2254 2255 <!-- Row: Rank + Cover + Info + Votes --> 2256 <div class="neon-chart-track__row"> 2257 <!-- Rank number --> 2258 <span class="neon-chart-track__rank">02</span> 2259 2260 <!-- Cover art --> 2261 <div class="neon-chart-track__cover" 2262 > 2263 <img class="neon-chart-track__cover-img" id="img-1" 2264 src="https://is1-ssl.mzstatic.com/image/thumb/Music211/v4/3d/06/16/3d0616e9-7841-e64f-01f0-a60a98ce11c7/25UMGIM33948.rgb.jpg/600x600bb.jpg" 2265 alt="Saudade Proibida (Ao Vivo)" 2266 onerror="this.src='https://nativafmbauru.com.br/assets/img/default-cover.svg'"> 2267 <button class="neon-chart-track__play-overlay" id="play-btn-1" 2268 data-url="https://audio-ssl.itunes.apple.com/itunes-assets/AudioPreview221/v4/27/81/07/2781075e-c6a3-1008-e078-14d68f5b02a9/mzaf_2490608400725389767.plus.aac.p.m4a" 2269 onclick="event.stopPropagation(); playChartTrack(1)"> 2270 <span class="material-symbols-outlined" id="play-icon-1" style="font-size:22px; font-variation-settings:'FILL' 1">play_arrow</span> 2271 </button> 2272 </div> 2273 2274 <!-- Title + Artist --> 2275 <div class="neon-chart-track__info"> 2276 <p class="neon-chart-track__title">Saudade Proibida (Ao Vivo)</p> 2277 <p class="neon-chart-track__artist">Simone Mendes</p> 2278 </div> 2279 2280 <!-- Vote buttons --> 2281 <div class="neon-chart-track__votes"> 2282 <button class="neon-vote-btn neon-vote-up" id="like-1" 2283 onclick="event.stopPropagation(); vote(1, 'like')" title="Curtir"> 2284 <span class="material-symbols-outlined" style="font-size:18px">thumb_up</span> 2285 </button> 2286 <span class="neon-vote-count" id="vote-count-1"> 2287 29 </span> 2288 <button class="neon-vote-btn neon-vote-down" id="dislike-1" 2289 onclick="event.stopPropagation(); vote(1, 'dislike')" title="Não curtir"> 2290 <span class="material-symbols-outlined" style="font-size:18px">thumb_down</span> 2291 </button> 2292 </div> 2293 </div><!-- /.neon-chart-track__row --> 2294 2295 <!-- Inline player (hidden, shown on click) --> 2296 <div class="neon-inline-player" id="player-ui-1" 2297 data-url="https://audio-ssl.itunes.apple.com/itunes-assets/AudioPreview221/v4/27/81/07/2781075e-c6a3-1008-e078-14d68f5b02a9/mzaf_2490608400725389767.plus.aac.p.m4a" 2298 data-title="Saudade Proibida (Ao Vivo)" 2299 data-artist="Simone Mendes"
2300 data-cover="https://is1-ssl.mzstatic.com/image/thumb/Music211/v4/3d/06/16/3d0616e9-7841-e64f-01f0-a60a98ce11c7/25UMGIM33948.rgb.jpg/600x600bb.jpg" 2301 style="display:none;"> 2302 <button class="neon-inline-player__btn" id="pplay-1" 2303 data-url="https://audio-ssl.itunes.apple.com/itunes-assets/AudioPreview221/v4/27/81/07/2781075e-c6a3-1008-e078-14d68f5b02a9/mzaf_2490608400725389767.plus.aac.p.m4a" 2304 onclick="event.stopPropagation(); playChartTrack(1)"> 2305 <span class="material-symbols-outlined" style="font-size:18px; font-variation-settings:'FILL' 1">play_arrow</span> 2306 </button> 2307 <div style="flex:1; min-width:0;"> 2308 <div class="neon-inline-player__bar" onclick="seekTrack(event,1)"> 2309 <div class="neon-inline-player__progress" id="progress-bar-1"></div> 2310 </div> 2311 <div class="neon-inline-player__times"> 2312 <span id="current-time-1">0:00</span> 2313 <span id="total-time-1">--:--</span> 2314 </div> 2315 </div> 2316 </div><!-- /.neon-inline-player --> 2317 2318 </div><!-- /.neon-chart-track --> 2319 <div class="neon-chart-track neon-chart-track--pink" id="track-2" 2320 data-track-id="29" 2321 onclick="toggleChartTrack(2)"> 2322 2323 <!-- Row: Rank + Cover + Info + Votes --> 2324 <div class="neon-chart-track__row"> 2325 <!-- Rank number --> 2326 <span class="neon-chart-track__rank">03</span> 2327 2328 <!-- Cover art --> 2329 <div class="neon-chart-track__cover" 2330 > 2331 <img class="neon-chart-track__cover-img" id="img-2" 2332 src="https://is1-ssl.mzstatic.com/image/thumb/Music221/v4/f4/74/7b/f4747b8e-2913-e3eb-fe21-7b1f2823c52f/196874366028.jpg/600x600bb.jpg" 2333 alt="Cadeira Cativa (Ao Vivo)" 2334 onerror="this.src='https://nativafmbauru.com.br/assets/img/default-cover.svg'"> 2335 <button class="neon-chart-track__play-overlay" id="play-btn-2" 2336 data-url="https://audio-ssl.itunes.apple.com/itunes-assets/AudioPreview211/v4/27/05/4b/27054b7a-c17f-b0c6-c6fc-c4417dfba626/mzaf_9835988559387151635.plus.aac.p.m4a" 2337 onclick="event.stopPropagation(); playChartTrack(2)"> 2338 <span class="material-symbols-outlined" id="play-icon-2" style="font-size:22px; font-variation-settings:'FILL' 1">play_arrow</span> 2339 </button> 2340 </div> 2341 2342 <!-- Title + Artist --> 2343 <div class="neon-chart-track__info"> 2344 <p class="neon-chart-track__title">Cadeira Cativa (Ao Vivo)</p> 2345 <p class="neon-chart-track__artist">Zé Neto & Cristiano</p> 2346 </div> 2347 2348 <!-- Vote buttons --> 2349 <div class="neon-chart-track__votes"> 2350 <button class="neon-vote-btn neon-vote-up" id="like-2" 2351 onclick="event.stopPropagation(); vote(2, 'like')" title="Curtir"> 2352 <span class="material-symbols-outlined" style="font-size:18px">thumb_up</span> 2353 </button> 2354 <span class="neon-vote-count" id="vote-count-2"> 2355 21 </span> 2356 <button class="neon-vote-btn neon-vote-down" id="dislike-2" 2357 onclick="event.stopPropagation(); vote(2, 'dislike')" title="Não curtir"> 2358 <span class="material-symbols-outlined" style="font-size:18px">thumb_down</span> 2359 </button> 2360 </div> 2361 </div><!-- /.neon-chart-track__row --> 2362 2363 <!-- Inline player (hidden, shown on click) --> 2364 <div class="neon-inline-player" id="player-ui-2" 2365 data-url="https://audio-ssl.itunes.apple.com/itunes-assets/AudioPreview211/v4/27/05/4b/27054b7a-c17f-b0c6-c6fc-c4417dfba626/mzaf_9835988559387151635.plus.aac.p.m4a" 2366 data-title="Cadeira Cativa (Ao Vivo)" 2367 data-artist="Zé Neto & Cristiano"
2368 data-cover="https://is1-ssl.mzstatic.com/image/thumb/Music221/v4/f4/74/7b/f4747b8e-2913-e3eb-fe21-7b1f2823c52f/196874366028.jpg/600x600bb.jpg" 2369 style="display:none;"> 2370 <button class="neon-inline-player__btn" id="pplay-2" 2371 data-url="https://audio-ssl.itunes.apple.com/itunes-assets/AudioPreview211/v4/27/05/4b/27054b7a-c17f-b0c6-c6fc-c4417dfba626/mzaf_9835988559387151635.plus.aac.p.m4a" 2372 onclick="event.stopPropagation(); playChartTrack(2)"> 2373 <span class="material-symbols-outlined" style="font-size:18px; font-variation-settings:'FILL' 1">play_arrow</span> 2374 </button> 2375 <div style="flex:1; min-width:0;"> 2376 <div class="neon-inline-player__bar" onclick="seekTrack(event,2)"> 2377 <div class="neon-inline-player__progress" id="progress-bar-2"></div> 2378 </div> 2379 <div class="neon-inline-player__times"> 2380 <span id="current-time-2">0:00</span> 2381 <span id="total-time-2">--:--</span> 2382 </div> 2383 </div> 2384 </div><!-- /.neon-inline-player --> 2385 2386 </div><!-- /.neon-chart-track --> 2387 <div class="neon-chart-track neon-chart-track--cyan" id="track-3" 2388 data-track-id="31" 2389 onclick="toggleChartTrack(3)"> 2390 2391 <!-- Row: Rank + Cover + Info + Votes --> 2392 <div class="neon-chart-track__row"> 2393 <!-- Rank number --> 2394 <span class="neon-chart-track__rank">04</span> 2395 2396 <!-- Cover art --> 2397 <div class="neon-chart-track__cover" 2398 > 2399 <img class="neon-chart-track__cover-img" id="img-3" 2400 src="https://is1-ssl.mzstatic.com/image/thumb/Music211/v4/54/20/ff/5420ff9a-e8d3-4546-fc1a-99d8cae88062/26UMGIM45423.rgb.jpg/600x600bb.jpg" 2401 alt="Estranho De Novo (Ao Vivo)" 2402 onerror="this.src='https://nativafmbauru.com.br/assets/img/default-cover.svg'"> 2403 <button class="neon-chart-track__play-overlay" id="play-btn-3" 2404 data-url="https://audio-ssl.itunes.apple.com/itunes-assets/AudioPreview211/v4/07/1e/c3/071ec3f0-40ee-3947-9e5f-64aa8786c6ca/mzaf_9100846059423630688.plus.aac.p.m4a" 2405 onclick="event.stopPropagation(); playChartTrack(3)"> 2406 <span class="material-symbols-outlined" id="play-icon-3" style="font-size:22px; font-variation-settings:'FILL' 1">play_arrow</span> 2407 </button> 2408 </div> 2409 2410 <!-- Title + Artist --> 2411 <div class="neon-chart-track__info"> 2412 <p class="neon-chart-track__title">Estranho De Novo (Ao Vivo)</p> 2413 <p class="neon-chart-track__artist">Felipe Araújo</p> 2414 </div> 2415 2416 <!-- Vote buttons --> 2417 <div class="neon-chart-track__votes"> 2418 <button class="neon-vote-btn neon-vote-up" id="like-3" 2419 onclick="event.stopPropagation(); vote(3, 'like')" title="Curtir"> 2420 <span class="material-symbols-outlined" style="font-size:18px">thumb_up</span> 2421 </button> 2422 <span class="neon-vote-count" id="vote-count-3"> 2423 11 </span> 2424 <button class="neon-vote-btn neon-vote-down" id="dislike-3" 2425 onclick="event.stopPropagation(); vote(3, 'dislike')" title="Não curtir"> 2426 <span class="material-symbols-outlined" style="font-size:18px">thumb_down</span> 2427 </button> 2428 </div> 2429 </div><!-- /.neon-chart-track__row --> 2430 2431 <!-- Inline player (hidden, shown on click) --> 2432 <div class="neon-inline-player" id="player-ui-3" 2433 data-url="https://audio-ssl.itunes.apple.com/itunes-assets/AudioPreview211/v4/07/1e/c3/071ec3f0-40ee-3947-9e5f-64aa8786c6ca/mzaf_9100846059423630688.plus.aac.p.m4a" 2434 data-title="Estranho De Novo (Ao Vivo)" 2435 data-artist="Felipe Araújo"
2436 data-cover="https://is1-ssl.mzstatic.com/image/thumb/Music211/v4/54/20/ff/5420ff9a-e8d3-4546-fc1a-99d8cae88062/26UMGIM45423.rgb.jpg/600x600bb.jpg" 2437 style="display:none;"> 2438 <button class="neon-inline-player__btn" id="pplay-3" 2439 data-url="https://audio-ssl.itunes.apple.com/itunes-assets/AudioPreview211/v4/07/1e/c3/071ec3f0-40ee-3947-9e5f-64aa8786c6ca/mzaf_9100846059423630688.plus.aac.p.m4a" 2440 onclick="event.stopPropagation(); playChartTrack(3)"> 2441 <span class="material-symbols-outlined" style="font-size:18px; font-variation-settings:'FILL' 1">play_arrow</span> 2442 </button> 2443 <div style="flex:1; min-width:0;"> 2444 <div class="neon-inline-player__bar" onclick="seekTrack(event,3)"> 2445 <div class="neon-inline-player__progress" id="progress-bar-3"></div> 2446 </div> 2447 <div class="neon-inline-player__times"> 2448 <span id="current-time-3">0:00</span> 2449 <span id="total-time-3">--:--</span> 2450 </div> 2451 </div> 2452 </div><!-- /.neon-inline-player --> 2453 2454 </div><!-- /.neon-chart-track --> 2455 <div class="neon-chart-track neon-chart-track--pink" id="track-4" 2456 data-track-id="32" 2457 onclick="toggleChartTrack(4)"> 2458 2459 <!-- Row: Rank + Cover + Info + Votes --> 2460 <div class="neon-chart-track__row"> 2461 <!-- Rank number --> 2462 <span class="neon-chart-track__rank">05</span> 2463 2464 <!-- Cover art --> 2465 <div class="neon-chart-track__cover" 2466 > 2467 <img class="neon-chart-track__cover-img" id="img-4" 2468 src="https://is1-ssl.mzstatic.com/image/thumb/Music211/v4/b3/cf/da/b3cfdac4-2fc7-31da-4d5e-f716cc978868/196873612935.jpg/600x600bb.jpg" 2469 alt="OLHO MARROM - Ao Vivo em Lisboa" 2470 onerror="this.src='https://nativafmbauru.com.br/assets/img/default-cover.svg'"> 2471 <button class="neon-chart-track__play-overlay" id="play-btn-4" 2472 data-url="https://audio-ssl.itunes.apple.com/itunes-assets/AudioPreview211/v4/c2/61/fd/c261fd07-f12a-270c-49c9-8978c85926f5/mzaf_17332012605388868844.plus.aac.p.m4a" 2473 onclick="event.stopPropagation(); playChartTrack(4)"> 2474 <span class="material-symbols-outlined" id="play-icon-4" style="font-size:22px; font-variation-settings:'FILL' 1">play_arrow</span> 2475 </button> 2476 </div> 2477 2478 <!-- Title + Artist --> 2479 <div class="neon-chart-track__info"> 2480 <p class="neon-chart-track__title">OLHO MARROM - Ao Vivo em Lisboa</p> 2481 <p class="neon-chart-track__artist">Luan Santana</p> 2482 </div> 2483 2484 <!-- Vote buttons --> 2485 <div class="neon-chart-track__votes"> 2486 <button class="neon-vote-btn neon-vote-up" id="like-4" 2487 onclick="event.stopPropagation(); vote(4, 'like')" title="Curtir"> 2488 <span class="material-symbols-outlined" style="font-size:18px">thumb_up</span> 2489 </button> 2490 <span class="neon-vote-count" id="vote-count-4"> 2491 25 </span> 2492 <button class="neon-vote-btn neon-vote-down" id="dislike-4" 2493 onclick="event.stopPropagation(); vote(4, 'dislike')" title="Não curtir"> 2494 <span class="material-symbols-outlined" style="font-size:18px">thumb_down</span> 2495 </button> 2496 </div> 2497 </div><!-- /.neon-chart-track__row --> 2498 2499 <!-- Inline player (hidden, shown on click) --> 2500 <div class="neon-inline-player" id="player-ui-4" 2501 data-url="https://audio-ssl.itunes.apple.com/itunes-assets/AudioPreview211/v4/c2/61/fd/c261fd07-f12a-270c-49c9-8978c85926f5/mzaf_17332012605388868844.plus.aac.p.m4a" 2502 data-title="OLHO MARROM - Ao Vivo em Lisboa" 2503 data-artist="Luan Santana"
2504 data-cover="https://is1-ssl.mzstatic.com/image/thumb/Music211/v4/b3/cf/da/b3cfdac4-2fc7-31da-4d5e-f716cc978868/196873612935.jpg/600x600bb.jpg" 2505 style="display:none;"> 2506 <button class="neon-inline-player__btn" id="pplay-4" 2507 data-url="https://audio-ssl.itunes.apple.com/itunes-assets/AudioPreview211/v4/c2/61/fd/c261fd07-f12a-270c-49c9-8978c85926f5/mzaf_17332012605388868844.plus.aac.p.m4a" 2508 onclick="event.stopPropagation(); playChartTrack(4)"> 2509 <span class="material-symbols-outlined" style="font-size:18px; font-variation-settings:'FILL' 1">play_arrow</span> 2510 </button> 2511 <div style="flex:1; min-width:0;"> 2512 <div class="neon-inline-player__bar" onclick="seekTrack(event,4)"> 2513 <div class="neon-inline-player__progress" id="progress-bar-4"></div> 2514 </div> 2515 <div class="neon-inline-player__times"> 2516 <span id="current-time-4">0:00</span> 2517 <span id="total-time-4">--:--</span> 2518 </div> 2519 </div> 2520 </div><!-- /.neon-inline-player --> 2521 2522 </div><!-- /.neon-chart-track --> 2523 <div class="neon-chart-track neon-chart-track--cyan" id="track-5" 2524 data-track-id="27" 2525 onclick="toggleChartTrack(5)"> 2526 2527 <!-- Row: Rank + Cover + Info + Votes --> 2528 <div class="neon-chart-track__row"> 2529 <!-- Rank number --> 2530 <span class="neon-chart-track__rank">06</span> 2531 2532 <!-- Cover art --> 2533 <div class="neon-chart-track__cover" 2534 > 2535 <img class="neon-chart-track__cover-img" id="img-5" 2536 src="https://is1-ssl.mzstatic.com/image/thumb/Music211/v4/0d/c2/23/0dc223e8-0f7e-b188-1f8a-f2b4e576b0dc/dj.esvmgkxr.jpg/600x600bb.jpg" 2537 alt="Vagabundo" 2538 onerror="this.src='https://nativafmbauru.com.br/assets/img/default-cover.svg'"> 2539 <button class="neon-chart-track__play-overlay" id="play-btn-5" 2540 data-url="https://audio-ssl.itunes.apple.com/itunes-assets/AudioPreview221/v4/32/0e/48/320e481f-2331-266f-de6f-71c4f5707519/mzaf_13393668534680992445.plus.aac.p.m4a" 2541 onclick="event.stopPropagation(); playChartTrack(5)"> 2542 <span class="material-symbols-outlined" id="play-icon-5" style="font-size:22px; font-variation-settings:'FILL' 1">play_arrow</span> 2543 </button> 2544 </div> 2545 2546 <!-- Title + Artist --> 2547 <div class="neon-chart-track__info"> 2548 <p class="neon-chart-track__title">Vagabundo</p> 2549 <p class="neon-chart-track__artist">Gusttavo Lima & Luis Fonsi</p> 2550 </div> 2551 2552 <!-- Vote buttons --> 2553 <div class="neon-chart-track__votes"> 2554 <button class="neon-vote-btn neon-vote-up" id="like-5" 2555 onclick="event.stopPropagation(); vote(5, 'like')" title="Curtir"> 2556 <span class="material-symbols-outlined" style="font-size:18px">thumb_up</span> 2557 </button> 2558 <span class="neon-vote-count" id="vote-count-5"> 2559 16 </span> 2560 <button class="neon-vote-btn neon-vote-down" id="dislike-5" 2561 onclick="event.stopPropagation(); vote(5, 'dislike')" title="Não curtir"> 2562 <span class="material-symbols-outlined" style="font-size:18px">thumb_down</span> 2563 </button> 2564 </div> 2565 </div><!-- /.neon-chart-track__row --> 2566 2567 <!-- Inline player (hidden, shown on click) --> 2568 <div class="neon-inline-player" id="player-ui-5" 2569 data-url="https://audio-ssl.itunes.apple.com/itunes-assets/AudioPreview221/v4/32/0e/48/320e481f-2331-266f-de6f-71c4f5707519/mzaf_13393668534680992445.plus.aac.p.m4a" 2570 data-title="Vagabundo"
2571 data-artist="Gusttavo Lima & Luis Fonsi" 2572 data-cover="https://is1-ssl.mzstatic.com/image/thumb/Music211/v4/0d/c2/23/0dc223e8-0f7e-b188-1f8a-f2b4e576b0dc/dj.esvmgkxr.jpg/600x600bb.jpg" 2573 style="display:none;"> 2574 <button class="neon-inline-player__btn" id="pplay-5" 2575 data-url="https://audio-ssl.itunes.apple.com/itunes-assets/AudioPreview221/v4/32/0e/48/320e481f-2331-266f-de6f-71c4f5707519/mzaf_13393668534680992445.plus.aac.p.m4a" 2576 onclick="event.stopPropagation(); playChartTrack(5)"> 2577 <span class="material-symbols-outlined" style="font-size:18px; font-variation-settings:'FILL' 1">play_arrow</span> 2578 </button> 2579 <div style="flex:1; min-width:0;"> 2580 <div class="neon-inline-player__bar" onclick="seekTrack(event,5)"> 2581 <div class="neon-inline-player__progress" id="progress-bar-5"></div> 2582 </div> 2583 <div class="neon-inline-player__times"> 2584 <span id="current-time-5">0:00</span> 2585 <span id="total-time-5">--:--</span> 2586 </div> 2587 </div> 2588 </div><!-- /.neon-inline-player --> 2589 2590 </div><!-- /.neon-chart-track --> 2591 </div><!-- /.neon-chart-grid --> 2592 2593 </div><!-- /.neon-chart-layout-wrapper --> 2594 </div> 2595</section> 2596
2597<script> 2598(function () { 2599 'use strict'; 2600 2601 /* ââ Estado ââ */ 2602 var _activeIdx = -1; 2603 var _isPlaying = false; 2604 var _rpAudio = null; 2605 var _progressBound = false; 2606 var _updateInterval = null; 2607 2608 /* ââ Cookie helpers para persistir votos ââ */ 2609 var VOTE_COOKIE_KEY = 'chart_votes'; 2610 var VOTE_COOKIE_DAYS = 30; 2611 2612 function getVoteCookie() { 2613 var match = document.cookie.match(new RegExp('(?:^|; )' + VOTE_COOKIE_KEY + '=([^;]*)')); 2614 if (!match) return {}; 2615 try { return JSON.parse(decodeURIComponent(match[1])); } catch(e) { return {}; } 2616 } 2617 function setVoteCookie(hash, voteType) { 2618 var data = getVoteCookie(); 2619 if (voteType === null) { delete data[hash]; } else { data[hash] = voteType; } 2620 var expires = new Date(Date.now() + VOTE_COOKIE_DAYS * 864e5).toUTCString(); 2621 document.cookie = VOTE_COOKIE_KEY + '=' + encodeURIComponent(JSON.stringify(data)) 2622 + '; expires=' + expires + '; path=/; SameSite=Lax'; 2623 } 2624 2625 /* ââ Track data (injected from PHP) ââ */ 2626 var trackData = {}; 2627 var hashToIndex = {}; 2628 2629 trackData[0] = { 2630 likes: 32, 2631 dislikes: 4, 2632 voted: null 2633 }; 2634 trackData[1] = { 2635 likes: 27, 2636 dislikes: 2, 2637 voted: null 2638 }; 2639 trackData[2] = { 2640 likes: 18, 2641 dislikes: 3, 2642 voted: null 2643 }; 2644 trackData[3] = { 2645 likes: 11, 2646 dislikes: 0, 2647 voted: null 2648 }; 2649 trackData[4] = { 2650 likes: 17, 2651 dislikes: 8, 2652 voted: null 2653 }; 2654 trackData[5] = { 2655 likes: 12, 2656 dislikes: 4, 2657 voted: null 2658 }; 2659 2660 /* Restaurar votos do cookie */ 2661 (function restoreVotesFromCookie() { 2662 var saved = getVoteCookie(); 2663 Object.keys(saved).forEach(function(hash) { 2664 var idx = hashToIndex[hash]; 2665 if (idx === undefined || !trackData[idx]) return; 2666 trackData[idx].voted = saved[hash]; 2667 updateVoteUI(idx); 2668 }); 2669 })(); 2670 2671 var activeChartId = '1'; 2672
2673 /* ââ Toggle card (expand/collapse inline player) ââ */ 2674 window.toggleChartTrack = function (idx) { 2675 var playerUI = document.getElementById('player-ui-' + idx); 2676 var trackItem = document.getElementById('track-' + idx); 2677 if (!playerUI || !trackItem) return; 2678 2679 var isActive = trackItem.classList.contains('neon-chart-active'); 2680 2681 /* Close all cards */ 2682 document.querySelectorAll('.neon-chart-track').forEach(function(el) { 2683 el.classList.remove('neon-chart-active'); 2684 var p = el.querySelector('.neon-inline-player'); 2685 if (p) p.style.display = 'none'; 2686 }); 2687 2688 if (!isActive) { 2689 trackItem.classList.add('neon-chart-active'); 2690 playerUI.style.display = 'flex'; 2691 playChartTrack(idx); 2692 } else { 2693 _activeIdx = -1; 2694 _isPlaying = false; 2695 if (window.radioPlayer) { 2696 if (window.radioPlayer.stopPlayback) window.radioPlayer.stopPlayback(); 2697 else if (window.radioPlayer.audio) window.radioPlayer.audio.pause(); 2698 } 2699 _resetIcons(); 2700 /* Resume live after 500ms */ 2701 setTimeout(function() { 2702 if (window.radioPlayer) { 2703 if (typeof window.radioPlayer.returnToLive === 'function') window.radioPlayer.returnToLive(); 2704 else if (typeof window.radioPlayer.startPlayback === 'function') window.radioPlayer.startPlayback(); 2705 } 2706 }, 500); 2707 } 2708 }; 2709 2710 /* ââ Play chart track via radioPlayer ââ */ 2711 window.playChartTrack = async function (idx) { 2712 var playerUI = document.getElementById('player-ui-' + idx); 2713 var extBtn = document.getElementById('play-btn-' + idx); 2714 var dataSource = playerUI || extBtn; 2715 if (!dataSource) return; 2716 2717 var url = playerUI ? playerUI.dataset.url : (extBtn ? extBtn.dataset.url : ''); 2718 var title = playerUI ? playerUI.dataset.title : (extBtn ? extBtn.dataset.title : ''); 2719 var artist = playerUI ? playerUI.dataset.artist : (extBtn ? extBtn.dataset.artist : ''); 2720 var imgTag = document.getElementById('img-' + idx); 2721 var cover = (imgTag ? imgTag.src : '') || (playerUI ? playerUI.dataset.cover : ''); 2722 var needPreview = playerUI ? playerUI.dataset.needPreview === 'true' : false; 2723 var pplayBtn = document.getElementById('pplay-' + idx); 2724 2725 if (_activeIdx === idx) { _stopAndResume(idx); return; } 2726 2727 /* Fetch preview if needed */ 2728 if (!url && needPreview) { 2729 if (pplayBtn) { 2730 var origIcon = pplayBtn.innerHTML; 2731 pplayBtn.innerHTML = '<span class="material-symbols-outlined" style="font-size:18px;animation:spin 1s linear infinite">refresh</span>'; 2732 try { 2733 var res = await fetch('https://nativafmbauru.com.br/api/track_info.php?artist=' + encodeURIComponent(artist) + '&title=' + encodeURIComponent(title)); 2734 var data = await res.json(); 2735 if (data.success && data.preview_url) { 2736 url = data.preview_url; 2737 if (playerUI) { playerUI.dataset.url = url; playerUI.dataset.needPreview = 'false'; } 2738 if (extBtn) extBtn.dataset.url = url; 2739 if (pplayBtn) pplayBtn.dataset.url = url; 2740 if (data.artwork) { cover = data.artwork; if (imgTag) imgTag.src = data.artwork; } 2741 } else { pplayBtn.innerHTML = origIcon; return; } 2742 } catch(e) { pplayBtn.innerHTML = origIcon; return; } 2743 pplayBtn.innerHTML = origIcon; 2744 } 2745 } else if (!url) { return; } 2746 2747 /* Close previous */ 2748 if (_activeIdx >= 0 && _activeIdx !== idx) { 2749 _setIcon(_activeIdx, 'play_arrow'); 2750 var prevItem = document.getElementById('track-' + _activeIdx); 2751 if (prevItem) { 2752 prevItem.classList.remove('neon-chart-active'); 2753 var prevPlayer = prevItem.querySelector('.neon-inline-player'); 2754 if (prevPlayer) prevPlayer.style.display = 'none'; 2755 } 2756 } 2757 2758 _activeIdx = idx; 2759 _resetIcons(); 2760 _setIcon(idx, 'pause'); 2761 2762 var trackItem = document.getElementById('track-' + idx); 2763 if (trackItem) { 2764 trackItem.classList.add('neon-chart-active'); 2765 var playerEl = trackItem.querySelector('.neon-inline-player'); 2766 if (playerEl) playerEl.style.display = 'flex'; 2767 } 2768 2769 /* Play via radioPlayer */ 2770 if (window.radioPlayer) { 2771 if (typeof window.radioPlayer.playTrack === 'function') { 2772 window.radioPlayer.playTrack(url, { title: title, artist: artist, artwork: cover }); 2773 } else if (window.radioPlayer.audio) { 2774 window.radioPlayer.audio.src = url; 2775 window.radioPlayer.audio.play(); 2776 } 2777 _startProgressUpdate(idx); 2778 } 2779 2780 _isPlaying = true; 2781 }; 2782 2783 /* ââ Seek ââ */ 2784 window.seekTrack = function (e, idx) { 2785 if (_activeIdx !== idx || !window.radioPlayer || !window.radioPlayer.audio) return; 2786 e.stopPropagation(); 2787 var bar = e.currentTarget; 2788 var pct = e.offsetX / bar.clientWidth; 2789 var audio = window.radioPlayer.audio; 2790 if (!isNaN(audio.duration)) audio.currentTime = audio.duration * pct; 2791 }; 2792 2793 /* ââ Votação ââ */ 2794 window.vote = function (idx, type) { 2795 if (!activeChartId) return; 2796 var t = trackData[idx]; 2797 if (!t) return; 2798 var trackEl = document.getElementById('track-' + idx); 2799 if (!trackEl) return; 2800 var trackId = trackEl.dataset.trackId; 2801 if (!trackId) return; 2802 2803 var oldState = { likes: t.likes, dislikes: t.dislikes, voted: t.voted }; 2804 2805 /* Optimistic toggle */ 2806 if (t.voted === type) { 2807 t.voted = null; 2808 type === 'like' ? t.likes-- : t.dislikes--; 2809 } else { 2810 if (t.voted) { t.voted === 'like' ? t.likes-- : t.dislikes--; } 2811 t.voted = type; 2812 type === 'like' ? t.likes++ : t.dislikes++; 2813 } 2814 updateVoteUI(idx); 2815 2816 var fd = new FormData(); 2817 fd.append('action', 'vote'); 2818 fd.append('chart_id', activeChartId); 2819 fd.append('track_id', trackId); 2820 fd.append('type', type === 'like' ? 'up' : 'down'); 2821 2822 fetch('https://nativafmbauru.com.br/api/charts.php', { method: 'POST', body: fd }) 2823 .then(function(r) { return r.json(); }) 2824 .then(function(data) { 2825 if (data.success) { 2826 t.likes = parseInt(data.counts.votes_up); 2827 t.dislikes = parseInt(data.counts.votes_down); 2828 updateVoteUI(idx); 2829 setVoteCookie(trackId, t.voted); 2830 if (data.ranked_tracks && data.ranked_tracks.length > 0) _reorderChart(data.ranked_tracks); 2831 } else { 2832 Object.assign(t, oldState); updateVoteUI(idx); 2833 } 2834 }) 2835 .catch(function() { Object.assign(t, oldState); updateVoteUI(idx); }); 2836 }; 2837 2838 function updateVoteUI(idx) { 2839 var t = trackData[idx]; 2840 var lb = document.getElementById('like-' + idx); 2841 var db = document.getElementById('dislike-' + idx); 2842 var ce = document.getElementById('vote-count-' + idx); 2843 if (lb) lb.classList.toggle('voted', t.voted === 'like'); 2844 if (db) db.classList.toggle('voted', t.voted === 'dislike'); 2845 if (ce) { 2846 var total = t.likes + t.dislikes; 2847 var fmt = function(n) { return n >= 1000 ? (n/1000).toFixed(1).replace('.0','')+'K' : String(n); }; 2848 ce.textContent = total > 0 ? fmt(total) : ''; 2849 } 2850 } 2851 2852 function _reorderChart(rankedTracks) { 2853 var list = document.getElementById('chart-list'); 2854 if (!list) return; 2855 var posMap = {}; 2856 rankedTracks.forEach(function(rt) { posMap[rt.track_hash] = rt.position; }); 2857 var items = Array.from(list.querySelectorAll('.neon-chart-track')); 2858 items.sort(function(a,b) { return (posMap[a.dataset.trackId]||999) - (posMap[b.dataset.trackId]||999); }); 2859 list.style.transition = 'opacity 0.25s ease'; 2860 list.style.opacity = '0.5'; 2861 setTimeout(function() {
2862 items.forEach(function(el, i) { 2863 var rs = el.querySelector('.neon-chart-track__rank'); 2864 if (rs) rs.textContent = String(i+1).padStart(2,'0'); 2865 list.appendChild(el); 2866 }); 2867 list.style.opacity = '1'; 2868 }, 260); 2869 } 2870 2871 /* ââ Progress update ââ */ 2872 function _startProgressUpdate(idx) { 2873 if (_updateInterval) clearInterval(_updateInterval); 2874 if (!window.radioPlayer || !window.radioPlayer.audio) return; 2875 var audio = window.radioPlayer.audio; 2876 2877 function onTimeUpdate() { 2878 if (_activeIdx !== idx) return; 2879 var pb = document.getElementById('progress-bar-' + idx); 2880 var ct = document.getElementById('current-time-' + idx); 2881 var tt = document.getElementById('total-time-' + idx); 2882 if (pb && audio.duration) pb.style.width = (audio.currentTime / audio.duration * 100) + '%'; 2883 if (ct) ct.textContent = _fmt(audio.currentTime); 2884 if (tt && audio.duration) tt.textContent = _fmt(audio.duration); 2885 if (audio.ended) _stopAndResume(idx); 2886 } 2887 function onPlay() { _setIcon(idx, 'pause'); } 2888 function onPause() { _setIcon(idx, 'play_arrow'); } 2889 2890 audio.removeEventListener('timeupdate', audio._neonTimeUpdate); 2891 audio.removeEventListener('play', audio._neonPlay); 2892 audio.removeEventListener('pause', audio._neonPause); 2893 audio._neonTimeUpdate = onTimeUpdate; 2894 audio._neonPlay = onPlay; 2895 audio._neonPause = onPause; 2896 audio.addEventListener('timeupdate', onTimeUpdate); 2897 audio.addEventListener('play', onPlay); 2898 audio.addEventListener('pause', onPause); 2899 2900 _updateInterval = setInterval(function() { 2901 if (_activeIdx !== idx || !audio || audio.paused) return; 2902 onTimeUpdate(); 2903 }, 250); 2904 } 2905 2906 function _stopAndResume(idx) { 2907 _setIcon(idx, 'play_arrow'); 2908 if (_updateInterval) clearInterval(_updateInterval); 2909 _activeIdx = -1; 2910 _isPlaying = false; 2911 var trackItem = document.getElementById('track-' + idx); 2912 if (trackItem) { 2913 trackItem.classList.remove('neon-chart-active'); 2914 var p = trackItem.querySelector('.neon-inline-player'); 2915 if (p) p.style.display = 'none'; 2916 } 2917 if (window.radioPlayer) { 2918 if (typeof window.radioPlayer.returnToLive === 'function') window.radioPlayer.returnToLive(); 2919 else { setTimeout(function() { if (typeof window.radioPlayer.startPlayback === 'function') window.radioPlayer.startPlayback(); }, 300); } 2920 } 2921 } 2922 2923 function _setIcon(idx, name) { 2924 var overlay = document.getElementById('play-icon-' + idx); 2925 if (overlay) overlay.textContent = name; 2926 var pplay = document.getElementById('pplay-' + idx); 2927 if (pplay) { 2928 var ic = pplay.querySelector('.material-symbols-outlined'); 2929 if (ic) ic.textContent = name; 2930 } 2931 } 2932 2933 function _resetIcons() { 2934 document.querySelectorAll('.neon-inline-player__btn .material-symbols-outlined').forEach(function(icon) { 2935 icon.textContent = 'play_arrow'; 2936 }); 2937 } 2938 2939 function _fmt(s) { 2940 s = Math.floor(s || 0); 2941 var m = Math.floor(s / 60), sec = s % 60; 2942 return m + ':' + (sec < 10 ? '0' : '') + sec; 2943 } 2944 2945 /* ââ Auto-fetch artwork for tracks without cover ââ */ 2946 (function loadMissingArtwork() { 2947 var items = document.querySelectorAll('.neon-chart-track__cover[data-need-art="true"]'); 2948 items.forEach(function(item) { 2949 var artist = item.dataset.trackArtist; 2950 var title = item.dataset.trackTitle; 2951 var idx = item.dataset.trackIndex; 2952 fetch('https://nativafmbauru.com.br/api/track_info.php?artist=' + encodeURIComponent(artist) + '&title=' + encodeURIComponent(title)) 2953 .then(function(r) { return r.json(); }) 2954 .then(function(data) { 2955 if (data.success) { 2956 if (data.artwork) { 2957 var img = document.getElementById('img-' + idx); 2958 if (img) img.src = data.artwork; 2959 } 2960 if (data.preview_url) { 2961 var pui = document.getElementById('player-ui-' + idx); 2962 var btn = document.getElementById('play-btn-' + idx); 2963 if (pui) { pui.dataset.url = data.preview_url; pui.dataset.needPreview = 'false'; } 2964 if (btn) { btn.dataset.url = data.preview_url; btn.dataset.needPreview = 'false'; } 2965 } 2966 } 2967 }) 2968 .catch(function(e) { console.error('Auto artwork fetch error', e); }); 2969 }); 2970 })(); 2971 2972})(); 2973</script>
2973 2974 2975<!-- Equipe â Neon Theme --> 2976<section class="neon-team-section" style="overflow:visible!important;"> 2977 <div class="container" style="overflow:visible!important;"> 2978 <!-- Header Stitch-style --> 2979 <!-- Header Stitch-style with custom buttons --> 2980 <div style="display:flex; justify-content: space-between; align-items: flex-end; margin-bottom: 32px; flex-wrap: wrap; gap: 16px;"> 2981 <div class="neon-news-header" style="margin-bottom: 0;"> 2982 <div class="neon-news-header__bar"></div> 2983 <div class="neon-news-header__text"> 2984 <div class="neon-news-header__label"> 2985 <!-- Lucide: users --> 2986 <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M22 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/></svg> 2987 <span></span> 2988 </div> 2989 <h2 class="neon-news-header__title">Equipe</h2> 2990 </div> 2991 </div> 2992 <div style="display:flex;gap:10px;"> 2993 <button class="team-carousel-prev" aria-label="Anterior" 2994 style="width:44px;height:44px;border-radius:50%;border:2px solid var(--color-primary);background:transparent;color:var(--color-primary);cursor:pointer;display:flex;align-items:center;justify-content:center;transition:all 0.25s;"> 2995 <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m15 18-6-6 6-6"/></svg> 2996 </button> 2997 <button class="team-carousel-next" aria-label="Próximo" 2998 style="width:44px;height:44px;border-radius:50%;border:none;background:var(--color-primary);color:#fff;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:all 0.25s;"> 2999 <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m9 18 6-6-6-6"/></svg> 3000 </button> 3001 </div> 3002 </div> 3003 3004 <!-- Team Grid + banner lateral --> 3005 <div class="neon-team-layout-wrapper"> 3006 <div class="team-carousel-wrapper" style="overflow:hidden; position:relative;"> 3007 <div class="team-carousel-inner shelf-72" style="display:flex; gap:24px;"> 3008 <div class="team-card neon-team-card neon-team-card--var-1" 3009 data-nome="André" 3010 data-cargo="Locutor" 3011 data-descricao="O André faz parte da programação da Nativa, levando boa música, alto astral e muita interação para os ouvintes. Com seu jeito único, acompanha o público e deixa o dia ainda mais animado." 3012 data-foto="https://nativafmbauru.com.br/uploads/media/6a18a3318ddae_1779999537.webp" 3013 data-facebook="" 3014 data-instagram="https://www.instagram.com/andreluizcosta88/" 3015 data-twitter="" 3016 data-tiktok=""> 3017 3018 <!-- Avatar com glow --> 3019 <div class="neon-team-card__avatar-wrap"> 3020 <div class="neon-team-card__avatar-glow"></div> 3021 <img class="neon-team-card__avatar" 3022 src="https://nativafmbauru.com.br/uploads/media/6a18a3318ddae_1779999537.webp" 3023 alt="André" loading="lazy"> 3024 </div> 3025 3026 <!-- Info --> 3027 <div class="neon-team-card__info"> 3028 <h3 class="neon-team-card__name">André</h3> 3029 3030 <p class="neon-team-card__role" style="color: var(--color-secondary);"> 3031 Locutor </p> 3032 3033 <p class="neon-team-card__bio"> 3034 O André faz parte da programação da Nativa, levando boa música, alto astral e muita interação para os ouvintes. Com seu... </p> 3035 3036 <!-- Social Links --> 3037 <div class="neon-team-card__socials"> 3038 <a href="https://www.instagram.com/andreluizcosta88/" target="_blank" rel="noopener" class="neon-team-social-btn" title="Instagram"> 3039 <i class="fab fa-instagram"></i> 3040 </a> 3041 </div> 3042 </div> 3043 </div> 3044 <div class="team-card neon-team-card neon-team-card--var-2" 3045 data-nome="Cleiton" 3046 data-cargo="Coordenador ArtÃstico" 3047 data-descricao="à frente da coordenação artÃstica da Nativa, o Cleiton trabalha para que a programação esteja sempre em sintonia com os ouvintes. Com dedicação e criatividade, contribui para levar música, entretenimento e conteúdo de qualidade para o ar todos os dias." 3048 data-foto="https://nativafmbauru.com.br/uploads/media/6a18a330d75c7_1779999536.webp" 3049 data-facebook="" 3050 data-instagram="https://www.instagram.com/cleiton.carioca/" 3051 data-twitter="" 3052 data-tiktok=""> 3053 3054 <!-- Avatar com glow --> 3055 <div class="neon-team-card__avatar-wrap"> 3056 <div class="neon-team-card__avatar-glow"></div> 3057 <img class="neon-team-card__avatar" 3058 src="https://nativafmbauru.com.br/uploads/media/6a18a330d75c7_1779999536.webp" 3059 alt="Cleiton" loading="lazy"> 3060 </div> 3061 3062 <!-- Info --> 3063 <div class="neon-team-card__info"> 3064 <h3 class="neon-team-card__name">Cleiton</h3> 3065 3066 <p class="neon-team-card__role" style="color: var(--color-primary);"> 3067 Coordenador ArtÃstico </p> 3068 3069 <p class="neon-team-card__bio"> 3070 à frente da coordenação artÃstica da Nativa, o Cleiton trabalha para que a programação esteja sempre em sintonia com os... </p> 3071 3072 <!-- Social Links --> 3073 <div class="neon-team-card__socials"> 3074 <a href="https://www.instagram.com/cleiton.carioca/" target="_blank" rel="noopener" class="neon-team-social-btn" title="Instagram"> 3075 <i class="fab fa-instagram"></i> 3076 </a> 3077 </div> 3078 </div> 3079 </div> 3080 <div class="team-card neon-team-card neon-team-card--var-3" 3081 data-nome="Day Quarenta" 3082 data-cargo="Apresentadora" 3083 data-descricao="Diariamente a Day leva muita alegria e alto astral com o programa âA Nativa entrou no grupoâ Vem que tem alegria, vem que tem Nativa!" 3084 data-foto="https://nativafmbauru.com.br/uploads/media/6a18a33033f04_1779999536.webp" 3085 data-facebook="" 3086 data-instagram="" 3087 data-twitter="" 3088 data-tiktok=""> 3089 3090 <!-- Avatar com glow --> 3091 <div class="neon-team-card__avatar-wrap"> 3092 <div class="neon-team-card__avatar-glow"></div> 3093 <img class="neon-team-card__avatar" 3094 src="https://nativafmbauru.com.br/uploads/media/6a18a33033f04_1779999536.webp" 3095 alt="Day Quarenta" loading="lazy"> 3096 </div> 3097 3098 <!-- Info --> 3099 <div class="neon-team-card__info"> 3100 <h3 class="neon-team-card__name">Day Quarenta</h3> 3101 3102 <p class="neon-team-card__role" style="color: var(--color-secondary);"> 3103 Apresentadora </p> 3104 3105 <p class="neon-team-card__bio"> 3106 Diariamente a Day leva muita alegria e alto astral com o programa âA Nativa entrou no grupoâ Vem que tem alegria, vem... </p> 3107 3108 <!-- Social Links --> 3109 </div> 3110 </div> 3111 </div> 3112 </div> 3113 3114 </div><!-- /.neon-team-layout-wrapper --> 3115 3116 <div class="team-carousel-dots" style="display:flex;justify-content:center;gap:8px;margin-top:20px;"></div> 3117 3118 <!-- Ver Toda a Equipe --> 3119 <div class="neon-team-viewall"> 3120 <a href="https://nativafmbauru.com.br/equipe" class="neon-team-viewall__btn"> 3121 <!-- Lucide: users-2 --> 3122 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewB
3122ox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14 19a6 6 0 0 0-12 0"/><circle cx="8" cy="9" r="4"/><path d="M22 19a6 6 0 0 0-6-6 4 4 0 0 0 0-8"/></svg> 3123 Ver Toda a Equipe </a> 3124 </div> 3125 </div> 3126</section>
3127<script src="https://nativafmbauru.com.br/assets/js/team-module.js?v=1790900781"></script>
3127 3128 3129
3130<script> 3131 // ââ Podcast Player Integration ââââââââââââââââââââââââââââââ 3132 // Delega ao radioPlayer.playPodcast() â método nativo que seta currentSong, 3133 // chama updateSongInfo() e dispara o MutationObserver do mini player mobile. 3134 function playPodcastEpisode(audioUrl, title, coverUrl, artist) { 3135 if (!audioUrl) { 3136 alert('Este episódio não possui áudio disponÃvel.'); 3137 return; 3138 } 3139 var rp = window.radioPlayer; 3140 if (!rp) { 3141 window.open(audioUrl, '_blank'); 3142 return; 3143 } 3144 3145 // Usar o método nativo playPodcast() que já configura currentSong, 3146 // chama updateSongInfo() e dispara radioPlayerStateChange corretamente. 3147 if (typeof rp.playPodcast === 'function') { 3148 rp.playPodcast( 3149 audioUrl, 3150 title || 'Podcast', 3151 artist || '', 3152 coverUrl || rp.defaultArtwork || '' 3153 ); 3154 return; 3155 } 3156 3157 // Fallback legado caso playPodcast não exista 3158 rp.audio.pause(); 3159 rp.audio.src = ''; 3160 rp.isStream = false; 3161 rp.userIntendedPlay = true; 3162 if (rp.playerTitle) rp.playerTitle.textContent = title || 'Podcast'; 3163 if (rp.playerArtist) rp.playerArtist.textContent = artist || ''; 3164 if (coverUrl && rp.playerArtwork) { 3165 rp.playerArtwork.classList.add('has-image'); 3166 var img = rp.playerArtwork.querySelector('img'); 3167 if (!img) { img = document.createElement('img'); rp.playerArtwork.appendChild(img); } 3168 img.src = coverUrl; 3169 img.alt = title || 'Capa do Podcast'; 3170 } 3171 rp.audio.src = audioUrl; 3172 rp.audio.load(); 3173 rp.audio.play().catch(function (e) { 3174 console.warn('Autoplay blocked:', e); 3175 rp.setState && rp.setState('connecting'); 3176 }); 3177 rp.setState && rp.setState('transmitting'); 3178 } 3179 3180 // Global Audio Handling: Mutex (Stop others) + UI Sync 3181 3182 document.addEventListener('play', function (e) { 3183 // 1. Stop all other audios 3184 var audios = document.getElementsByTagName('audio'); 3185 for (var i = 0, len = audios.length; i < len; i++) { 3186 if (audios[i] != e.target) { 3187 audios[i].pause(); 3188 audios[i].currentTime = 0; // Reset others 3189 } 3190 } 3191 3192 // 2. Update UI for the playing audio (if it's a chart player) 3193 if (e.target.classList.contains('chart-audio-player')) { 3194 const container = e.target.closest('.chart-track-player'); 3195 if (container) { 3196 const icon = container.querySelector('.player-control-icon i'); 3197 if (icon) { 3198 icon.classList.remove('fa-play'); 3199 icon.classList.add('fa-pause'); 3200 } 3201 } 3202 } 3203 }, true); 3204 3205 document.addEventListener('pause', function (e) { 3206 // Update UI when paused 3207 if (e.target.classList.contains('chart-audio-player')) { 3208 const container = e.target.closest('.chart-track-player'); 3209 if (container) { 3210 const icon = container.querySelector('.player-control-icon i'); 3211 if (icon) { 3212 icon.classList.remove('fa-pause'); 3213 icon.classList.add('fa-play'); 3214 } 3215 } 3216 } 3217 }, true); 3218 3219 function toggleChartPlayer(element) { 3220 // Find the parent chart-track (supports generic + neon theme) 3221 const trackCard = element.closest('.chart-track, .neon-chart-track'); 3222 if (!trackCard) return; 3223 3224 // Check if this card is currently active 3225 const isActive = trackCard.classList.contains('active'); 3226 3227 // Close ALL other tracks first (Accordion effect) 3228 document.querySelectorAll('.chart-track.active, .neon-chart-track.active').forEach(card => { 3229 card.classList.remove('active'); 3230 const audio = card.querySelector('audio'); 3231 if (audio) { 3232 audio.pause(); 3233 audio.currentTime = 0; 3234 } 3235 }); 3236 3237 // If it wasn't active, open it now 3238 if (!isActive) { 3239 // STOP MAIN RADIO when opening a preview 3240 if (window.radioPlayer && typeof window.radioPlayer.stopPlayback === 'function') { 3241 window.radioPlayer.stopPlayback(); 3242 } 3243 3244 trackCard.classList.add('active'); 3245 const audio = trackCard.querySelector('audio'); 3246 if (audio) { 3247 audio.play().catch(e => console.log("Autoplay blocked usually ok", e)); 3248 } 3249 } 3250 } 3251 3252 // New Function to handle the inner player interaction (Custom Player Click) 3253 function toggleTrackPlayback(element) { 3254 // Element is .custom-player-ui 3255 const playerContainer = element.closest('.chart-track-player'); 3256 if (!playerContainer) return; 3257 3258 const audio = playerContainer.querySelector('audio.chart-audio-player'); 3259 const icon = playerContainer.querySelector('.player-control-icon i'); 3260 3261 if (audio) { 3262 if (audio.paused) { 3263 // Stop main radio 3264 if (window.radioPlayer && typeof window.radioPlayer.stopPlayback === 'function') { 3265 window.radioPlayer.stopPlayback(); 3266 } 3267 3268 // Stop other chart players 3269 document.querySelectorAll('audio.chart-audio-player').forEach(otherAudio => { 3270 if (otherAudio !== audio) { 3271 otherAudio.pause(); 3272 otherAudio.currentTime = 0; 3273 // Reset other icons/bars 3274 const otherContainer = otherAudio.closest('.chart-track-player'); 3275 if (otherContainer) { 3276 const otherIcon = otherContainer.querySelector('.player-control-icon i'); 3277 const otherBar = otherContainer.querySelector('.player-progress-fill'); 3278 if (otherIcon) { 3279 otherIcon.classList.remove('fa-pause'); 3280 otherIcon.classList.add('fa-play'); 3281 } 3282 if (otherBar) otherBar.style.width = '0%'; 3283 } 3284 } 3285 }); 3286 3287 audio.play(); 3288 if (icon) { 3289 icon.classList.remove('fa-play'); 3290 icon.classList.add('fa-pause'); 3291 } 3292 } else { 3293 audio.pause(); 3294 if (icon) { 3295 icon.classList.remove('fa-pause'); 3296 icon.classList.add('fa-play'); 3297 } 3298 } 3299 } 3300 } 3301 3302 // Attach listeners to update Progress Bars 3303 document.addEventListener('DOMContentLoaded', function () { 3304 // Use event delegation or attach to existing audios? 3305 // Since we have multiple, let's attach to all present 3306 const chartAudios = document.querySelectorAll('audio.chart-audio-player'); 3307 chartAudios.forEach(audio => { 3308 3309 // Update Progress Bar 3310 audio.addEventListener('timeupdate', function () { 3311 const container = this.closest('.chart-track-player'); 3312 if (!container) return; 3313 const bar = container.querySelector('.player-progress-fill'); 3314 3315 if (bar && this.duration) { 3316 const percent = (this.currentTime / this.duration) * 100; 3317 bar.style.width = percent + '%'; 3318 } 3319 }); 3320 3321 // Reset on End â and resume main radio stream 3322 audio.addEventListener('ended', function () { 3323 const container = this.closest('.chart-track-player'); 3324 if (!container) return; 3325 3326 const bar = container.querySelector('.player-progress-fill'); 3327 const icon = container.querySelector('.player-control-icon i'); 3328 if (bar) bar.style.width = '0%'; 3329 if (icon) { icon.classList.remove('fa-pause'); icon.classList.add('fa-play'); } 3330 this.currentTime = 0; 3331 3332 // Close the accordion panel (supports generic + neon) 3333 const trackCard = container.closest('.chart-track, .neon-chart-track'); 3334 if (trackCard) trackCard.classList.remove('active'); 3335 3336 // Resume main streaming player 3337 setTimeout(function () { 3338 if (window.radioPlayer && typeof window.radioPlayer.startPlayback === 'function') { 3339 window.radioPlayer.startPlayback(); 3340 } else if (window.radioPlayer && typeof window.radioPlayer.play === 'function') { 3341 window.radioPlayer.play(); 3342 } 3343 }, 400); 3344 }); 3345 }); 3346 }); 3347 3348 3349 3350 async function voteTrack(chartId, trackId, voteType, btn) { 3351 if (btn.disabled) return; 3352 3353 // Get the parent container (supports generic + neon theme) 3354 const voteContainer = btn.closest('.vote-column, .neon-chart-track__votes'); 3355 if (!voteContainer) return; 3356 3357 // Disable both buttons (supports generic + neon btn classes) 3358 const allBtns = voteContainer.querySelectorAll('.vote-mini-btn, .neon-vote-btn'); 3359 allBtns.forEach(b => b.disabled = true); 3360 3361 const formData = new FormData(); 3362 formData.append('action', 'vote'); 3363 formData.append('vote_type', voteType); 3364 3365 // Auto mode: trackId is 0, use track_hash instead 3366 const trackCard = btn.closest('.chart-track, .neon-chart-track, [data-track-hash]'); 3367 const trackHash = trackCard ? trackCard.dataset.trackHash : ''; 3368 3369 if (trackId === 0 && trackHash) { 3370 // Auto mode â send track_hash, no chart_id/track_id 3371 formData.append('track_hash', trackHash); 3372 formData.append('chart_id', ''); 3373 formData.append('track_id', ''); 3374 } else { 3375 // Manual mode â send chart_id + track_id 3376 formData.append('chart_id', chartId); 3377 formData.append('track_id', trackId); 3378 } 3379 3380 try { 3381 const response = await fetch(SITE_URL + '/api/vote.php', { 3382 method: 'POST', 3383 body: formData 3384 }); 3385 const data = await response.json(); 3386 3387 if (data.success) { 3388 voteContainer.classList.add('voted'); 3389 3390 // Update the vote count display in real-time 3391 const voteCountEl = voteContainer.querySelector('.vote-net-count'); 3392 if (voteCountEl) { 3393 let currentCount = parseInt(voteCountEl.textContent) || 0; 3394 if (voteType === 'up') { 3395 currentCount += 1; 3396 } else if (voteType === 'down') { 3397 currentCount -= 1; 3398 } 3399 voteCountEl.textContent = currentCount; 3400 3401 voteCountEl.style.transform = 'scale(1.2)'; 3402 setTimeout(() => { 3403 voteCountEl.style.transform = 'scale(1)'; 3404 }, 200); 3405 } 3406 3407 // Visual feedback on the clicked button 3408 btn.style.opacity = '0.5'; 3409 3410 if (typeof showToast === 'function') { 3411 showToast(data.message || 'Voto registrado!', 'success'); 3412 } 3413 } else { 3414 allBtns.forEach(b => b.disabled = false); 3415 if (typeof showToast === 'function') { 3416 showToast(data.message, 'info'); 3417 } else { 3418 console.log("Voting info: " + data.message); 3419 const msg = document.createElement('div'); 3420 msg.style.cssText = 'position:fixed;bottom:20px;right:20px;background:#333;color:white;padding:10px 20px;border-radius:5px;z-index:9999;animation:fadeIn 0.3s;'; 3421 msg.textContent = data.message; 3422 document.body.appendChild(msg); 3423 setTimeout(() => msg.remove(), 3000); 3424 } 3425 } 3426 } catch (error) { 3427 allBtns.forEach(b => b.disabled = false); 3428 console.error('Vote error:', error); 3429 } 3430 } 3431</script>
3431 3432 </div> 3433 3434 <!-- Persistent Audio Player --> 3435 <!-- Theme: NEON â Glassmorphism + Neon Glow â Audio Player --> 3436<div id="player" class="neon-player"> 3437 <div class="neon-player__inner"> 3438 3439 <!-- ââââ GRUPO ESQUERDO: Artwork + Info + Controles + Volume ââââ --> 3440 <div class="neon-player__left-group"> 3441 3442 <!-- Artwork + Info --> 3443 <div class="neon-player__info"> 3444 <div class="neon-player__artwork" id="playerArtwork"> 3445 <img src="https://nativafmbauru.com.br/uploads/media/6a18a5b4f2efe_1780000180.webp" 3446 alt="Album Art" 3447 onerror="this.src = PLAYER_DEFAULT_IMAGE || 'https://nativafmbauru.com.br/assets/img/default-cover.png'"> 3448 </div> 3449 <div class="neon-player__meta"> 3450 <div class="neon-player__status" data-player-status> 3451 </div> 3452 <div class="neon-player__title" id="playerTitle">Carregando...</div> 3453 <div class="neon-player__artist" id="playerArtist">Nativa FM Bauru</div> 3454 </div> 3455 </div> 3456 3457 <!-- NOVOS CONTROLES (NATIVOS) --> 3458 <div class="zmp-player-controls-wrapper"> 3459 3460 <!-- PLAY / PAUSE --> 3461 <button id="playBtn" class="zmp-btn zmp-play-size" title="Play/Pause"> 3462 <svg id="playIcon" class="zmp-svg zmp-show" xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" style="max-width: 22px; max-height: 22px;"> 3463 <path fill="currentColor" d="M6 3.5a1.5 1.5 0 0 1 2.3-.8l11.5 8a1.5 1.5 0 0 1 0 2.6l-11.5 8A1.5 1.5 0 0 1 6 20.5v-17z"/> 3464 </svg> 3465 </button> 3466 3467 <!-- AO VIVO --> 3468 <button id="zmpLiveBtn" class="zmp-btn zmp-aux-size" title="Voltar ao Vivo" onclick="if(window.radioPlayer) window.radioPlayer.returnToLive()"> 3469 <svg class="zmp-svg zmp-show" xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="currentColor" style="max-width: 18px; max-height: 18px;"> 3470 <circle cx="12" cy="12" r="2.5" /> 3471 <path d="M7.74 16.26a6 6 0 0 1 0-8.52l1.42 1.42a4 4 0 0 0 0 5.68z" /> 3472 <path d="M16.26 16.26a6 6 0 0 0 0-8.52l-1.42 1.42a4 4 0 0 1 0 5.68z" /> 3473 <path d="M4.91 19.09a10 10 0 0 1 0-14.18l1.42 1.42a8 8 0 0 0 0 11.34z" /> 3474 <path d="M19.09 19.09a10 10 0 0 0 0-14.18l-1.42 1.42a8 8 0 0 1 0 11.34z" /> 3475 </svg> 3476 </button> 3477 3478 <!-- VOLUME --> 3479 <button id="volumeBtn" class="zmp-btn zmp-aux-size" title="Volume"> 3480 <svg id="volumeIcon" class="zmp-svg zmp-show" xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24"> 3481 <path fill="currentColor" d="M3 9v6h4l5 5V4L7 9H3zm13.5 3c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02zM14 3.23v2.06c2.89.86 5 3.54 5 6.71s-2.11 5.85-5 6.71v2.06c4.01-.91 7-4.49 7-8.77s-2.99-7.86-7-8.77z"/> 3482 </svg> 3483 </button> 3484 <input type="range" id="volumeSlider" class="zmp-volume-slider" min="0" max="100" value="90" /> 3485 3486 </div> <!-- /zmp-player-controls-wrapper --> 3487 3488 <!-- CSS BLINDADO DOS CONTROLES --> 3489 <style> 3490 .zmp-player-controls-wrapper { 3491 display: flex; 3492 align-items: center; 3493 gap: 16px; 3494 margin-left: 20px; 3495 } 3496 .zmp-btn { 3497 appearance: none !important; 3498 background: transparent !important; 3499 color: var(--player-text-color, #ffffff); 3500 border: none !important; 3501 border-radius: 50% !important; 3502 display: flex !important; 3503 align-items: center !important; 3504 justify-content: center !important; 3505 cursor: pointer; 3506 box-shadow: none !important; 3507 transition: opacity 0.2s ease, transform 0.15s ease; 3508 padding: 0 !important; 3509 } 3510 .zmp-btn:hover { 3511 opacity: 0.7; 3512 transform: scale(1.08); 3513 } 3514 .zmp-play-size { 3515 width: 48px !important; 3516 height: 48px !important; 3517 min-width: 48px !important; 3518 } 3519 .zmp-aux-size { 3520 width: 36px !important; 3521 height: 36px !important; 3522 min-width: 36px !important; 3523 } 3524 /* ââ BLINDAGEM MÃXIMA PARA SVG E DESIGN NEON ââ 3525 Garante que os controles respondam à "COR DOS ELEMENTOS" do painel, 3526 independentemente do fundo, restaurando o estilo Neon sem fills hardcoded. */ 3527 3528 /* 1. Cores e Fills dos Ãcones (SVGs e FontAwesome) */ 3529 html body #player #playBtn svg, 3530 html body #player #zmpLiveBtn svg, 3531 html body #player #volumeBtn svg, 3532 html body #player .zmp-svg, 3533 html body #player .zmp-btn i { 3534 display: block; 3535 color: var(--player-text-color, #ffffff) !important; 3536 fill: var(--player-text-color, #ffffff) !important; 3537 stroke: none !important; 3538 margin: 0 auto !important; 3539 pointer-events: none;
3540 width: 20px !important; 3541 height: auto !important; 3542 filter: none !important; 3543 } 3544 3545 /* Ajuste de tamanho especÃfico para Live e Volume */ 3546 html body #player #zmpLiveBtn svg, 3547 html body #player #volumeBtn svg, 3548 html body #player #volumeBtn i, 3549 html body #player #zmpLiveBtn i { 3550 width: 18px !important; 3551 } 3552 3553 /* Textos padronizados de AO VIVO */ 3554 html body #player .neon-player__live-text, 3555 html body #player .neon-watch-label { 3556 color: var(--player-text-color, #ffffff) !important; 3557 } 3558 html body #player .neon-player__live-dot { 3559 background: var(--player-text-color, #ffffff) !important; 3560 box-shadow: 0 0 6px color-mix(in srgb, var(--player-text-color, #ffffff) 60%, transparent) !important; 3561 } 3562 3563 html body #player #zmpIconLoad { 3564 fill: none !important; 3565 stroke: currentColor !important; 3566 } 3567 3568 /* 2. Formato e Glow dos Botões Principais (Restaurando o Neon) */ 3569 html body #player, html body .neon-player { 3570 background: var(--player-bg, rgba(20, 16, 33, 0.95)) !important; 3571 } 3572 3573 html body #player #playBtn, 3574 html body #player #zmpLiveBtn, 3575 html body #player #volumeBtn, 3576 html body #player .zmp-btn { 3577 background-color: transparent !important; 3578 box-shadow: none !important; 3579 display: flex; 3580 align-items: center; 3581 justify-content: center; 3582 cursor: pointer; 3583 transition: all 0.3s ease; 3584 border: none !important; /* Limpa bordas extras e heranças do themes/neon/style.css */ 3585 } 3586 3587 /* Play Button - Anel Neon Principal */ 3588 html body #player #playBtn { 3589 width: 48px !important; 3590 height: 48px !important; 3591 border-radius: 50% !important; 3592 border: 1.5px solid color-mix(in srgb, var(--player-text-color, #ffffff) 50%, transparent) !important; 3593 background: color-mix(in srgb, var(--player-text-color, #ffffff) 5%, transparent) !important; 3594 } 3595 html body #player #playBtn:hover { 3596 background: color-mix(in srgb, var(--player-text-color, #ffffff) 15%, transparent) !important; 3597 border-color: var(--player-text-color, #ffffff) !important; 3598 transform: scale(1.05); 3599 box-shadow: 0 0 15px color-mix(in srgb, var(--player-text-color, #ffffff) 30%, transparent) !important; 3600 } 3601 3602 /* Correção visual do play center gap (o triângulo engana o olho) */ 3603 html body #player #playBtn svg { 3604 transform: translateX(1.5px); 3605 } 3606 /* Quando está pausado, o SVG muda para pause/spinner, então removemos o shift */ 3607 html body #player #playBtn svg.animate-spin, 3608 html body #player #playBtn svg[class*="fa-pause"] { 3609 transform: translateX(0); 3610 } 3611 3612 /* Live/Volume Buttons - Anéis Menores */ 3613 html body #player #zmpLiveBtn, 3614 html body #player #volumeBtn { 3615 width: 36px !important; 3616 height: 36px !important; 3617 border-radius: 50% !important; 3618 border: 1.5px solid color-mix(in srgb, var(--player-text-color, #ffffff) 30%, transparent) !important; 3619 background: transparent !important; 3620 } 3621 html body #player #zmpLiveBtn:hover, 3622 html body #player #volumeBtn:hover { 3623 border-color: color-mix(in srgb, var(--player-text-color, #ffffff) 80%, transparent) !important; 3624 background: color-mix(in srgb, var(--player-text-color, #ffffff) 10%, transparent) !important; 3625 } 3626 3627 /* Slider de Volume */ 3628 .zmp-volume-slider { 3629 width: 80px; 3630 height: 4px; 3631 border-radius: 4px; 3632 appearance: none; 3633 background: color-mix(in srgb, var(--player-text-color, #ffffff) 20%, transparent); 3634 outline: none; 3635 cursor: pointer; 3636 } 3637 .zmp-volume-slider::-webkit-slider-thumb { 3638 appearance: none; 3639 width: 12px; 3640 height: 12px; 3641 border-radius: 50%; 3642 background: var(--player-text-color, #ffffff); 3643 cursor: pointer; 3644 box-shadow: 0 1px 4px rgba(0,0,0,0.3); 3645 } 3646 3647 /* Responsive Hiding se a tela for mto pequena pro volume (inclui celular em paisagem) */ 3648 @media (max-width: 1024px), (pointer: coarse) and (max-width: 1366px) { 3649 #zmpVolBtn, .zmp-volume-slider { display: none !important; }
3650 .zmp-player-controls-wrapper { margin-left: auto; gap: 12px; } 3651 } 3652 </style> 3653 3654 3655 </div><!-- /.neon-player__left-group --> 3656 3657 <!-- ââââ GRUPO DIREITO: Botão ASSISTIR AO VIVO ââââ --> 3658 <!-- Aparece apenas quando o widget de vÃdeo existe no DOM (JS controla) --> 3659 <div class="neon-player__video-btn-wrap" id="neonVideoWatchBtn" style="display:none;"> 3660 <button class="neon-player__watch-btn" id="btnAssistirAoVivo" title="Assistir transmissão ao vivo"> 3661 <span class="neon-watch-dot"></span> 3662 <span class="neon-watch-label">ASSISTIR AO VIVO</span> 3663 </button> 3664 </div> 3665 3666 </div><!-- /.neon-player__inner --> 3667 <div id="visualizer" style="display:none;"></div> 3668</div> 3669 3670<style> 3671/* ââââââââââââââââââââââââââââââââââââââââââââââââ 3672 NEON PLAYER â Layout: Left-group + Right-button 3673 ââââââââââââââââââââââââââââââââââââââââââââââââ */ 3674 3675/* O inner agora é: left-group flex-1 | btn-wrap flex-shrink-0 */ 3676.neon-player__inner { 3677 display : flex; 3678 align-items : center; 3679 justify-content: space-between; 3680 max-width : 1440px; 3681 margin : 0 auto; 3682 padding : 12px 32px; 3683 gap : 24px; 3684} 3685 3686/* Grupo esquerdo: agrupa artwork, controles e volume numa fileira */ 3687.neon-player__left-group { 3688 display : flex; 3689 align-items: center; 3690 gap : 24px; 3691 flex : 1; 3692 min-width : 0; 3693} 3694 3695/* Fix: info não cresce mais (ocupa apenas o que precisa) */ 3696.neon-player__info { 3697 display : flex; 3698 align-items: center; 3699 gap : 14px; 3700 min-width : 0; 3701 /* Remove o flex:1 antigo â agora o left-group controla o crescimento */ 3702} 3703 3704/* ââ Botão ASSISTIR AO VIVO (direita) ââ */ 3705.neon-player__video-btn-wrap { 3706 flex-shrink: 0; 3707 margin-left: auto; /* empurra para a extrema direita */ 3708} 3709 3710.neon-player__watch-btn { 3711 display : flex; 3712 align-items : center; 3713 gap : 8px; 3714 background : transparent; 3715 color : var(--player-text-color, #ffffff); 3716 border : 1px solid color-mix(in srgb, var(--player-text-color, #ffffff) 40%, transparent); 3717 font-size : 11px; 3718 font-weight : 800; 3719 letter-spacing : 0.8px; 3720 text-transform : uppercase; 3721 padding : 9px 20px; 3722 border-radius : 999px; 3723 cursor : pointer; 3724 white-space : nowrap; 3725 transition : all 0.2s ease; 3726 font-family : 'Space Grotesk', 'Inter', sans-serif; 3727 box-shadow : none; 3728} 3729 3730.neon-player__watch-btn:hover { 3731 background: color-mix(in srgb, var(--player-text-color, #ffffff) 10%, transparent); 3732 transform: scale(1.02); 3733} 3734 3735.neon-watch-dot { 3736 width : 7px; 3737 height : 7px; 3738 border-radius: 50%; 3739 background : var(--player-text-color, #ffffff); 3740 flex-shrink : 0; 3741 animation : neon-watch-pulse 1.5s ease-in-out infinite; 3742} 3743 3744@keyframes neon-watch-pulse { 3745 0%, 100% { opacity: 1; transform: scale(1); } 3746 50% { opacity: 0.3; transform: scale(0.85); } 3747} 3748 3749/* Estado: vÃdeo aberto â botão muda para "FECHAR VÃDEO" */ 3750.neon-player__watch-btn.is-open { 3751 background : color-mix(in srgb, var(--player-text-color, #ffffff) 15%, transparent); 3752 color : var(--player-text-color, #ffffff); 3753 border : 1px solid color-mix(in srgb, var(--player-text-color, #ffffff) 40%, transparent); 3754 box-shadow : none; 3755} 3756 3757.neon-player__watch-btn.is-open .neon-watch-dot { 3758 animation: none; 3759 opacity : 1; 3760} 3761 3762/* Mobile: ocultar botão de vÃdeo (não aplicável) â inclui celular em paisagem */ 3763@media (max-width: 1024px), (pointer: coarse) and (max-width: 1366px) { 3764 .neon-player__video-btn-wrap { display: none !important; } 3765 .neon-player__inner { padding: 10px 16px; gap: 12px; } 3766 .neon-player__left-group { gap: 12px; } 3767} 3768</style> 3769
3770<script> 3771(function() { 3772 function initWatchBtn() { 3773 var btn = document.getElementById('btnAssistirAoVivo'); 3774 var btnWrap = document.getElementById('neonVideoWatchBtn'); 3775 var widget = document.getElementById('vmpWidget'); 3776 var label = btn ? btn.querySelector('.neon-watch-label') : null; 3777 3778 // Só exibe o botão se o widget de vÃdeo existir no DOM 3779 if (!widget || !btn || !label) return; 3780 btnWrap.style.display = ''; 3781 3782 function syncLabel() { 3783 var isOpen = widget.style.display !== 'none'; 3784 btn.classList.toggle('is-open', isOpen); 3785 label.textContent = isOpen ? 'FECHAR VÃDEO' : 'ASSISTIR AO VIVO'; 3786 } 3787 3788 btn.addEventListener('click', function() { 3789 var isOpen = widget.style.display !== 'none'; 3790 widget.style.display = isOpen ? 'none' : 'block'; 3791 syncLabel(); 3792 }); 3793 3794 // Sincronizar quando o botão à interno do mini player for clicado 3795 var closeBtn = document.getElementById('vmpCloseBtn'); 3796 if (closeBtn) { 3797 closeBtn.addEventListener('click', function() { 3798 setTimeout(syncLabel, 50); 3799 }); 3800 } 3801 3802 syncLabel(); // estado inicial 3803 } 3804 3805 if (document.readyState === 'loading') { 3806 document.addEventListener('DOMContentLoaded', initWatchBtn); 3807 } else { 3808 setTimeout(initWatchBtn, 200); 3809 } 3810 3811})(); 3812</script>
3812 3813 <!-- Video Player Global: movido para dentro do #mainContent (topo) â Fix 3 --> 3814 <!-- O singleton define('VIDEO_PLAYER_GLOBAL_RENDERED') previne dupla renderização --> 3815 3816 3817<footer class="neon-footer"> 3818 <div class="neon-footer__accent-line"></div> 3819 <div class="neon-footer__inner"> 3820 3821 <!-- Col 1: Marca / About --> 3822 <div class="neon-footer__col"> 3823 <a href="home" class="neon-footer__logo"> 3824 <img src="https://nativafmbauru.com.br/uploads/media/6a2974fa436ab_1781101818.png" 3825 alt="Nativa FM Bauru"> 3826 </a> 3827 <p class="neon-footer__site-name">Nativa FM Bauru</p> 3828 <p class="neon-footer__desc">A Nativa é tudo e muito mais!</p> 3829 <div class="neon-footer__social"> 3830 <a href="https://www.instagram.com/nativafmbauru/" target="_blank" rel="noopener" class="neon-footer__social-btn" title="Instagram"> 3831 <i class="fab fa-instagram"></i> 3832 </a> 3833 <a href="https://www.facebook.com/nativafmbauru" target="_blank" rel="noopener" class="neon-footer__social-btn" title="Facebook"> 3834 <i class="fab fa-facebook-f"></i> 3835 </a> 3836 <a href="https://www.youtube.com/@nativafm_bauru" target="_blank" rel="noopener" class="neon-footer__social-btn" title="YouTube"> 3837 <i class="fab fa-youtube"></i> 3838 </a> 3839 <a href="https://play.google.com/store/apps/details?id=br.com.nativafmbauru.twa&hl=pt_BR" target="_blank" rel="noopener" class="neon-footer__social-btn" title="Android"> 3840 <i class="fab fa-android"></i> 3841 </a> 3842 <a href="https://apps.apple.com/us/app/nativa-fm-bauru/id6467184660" target="_blank" rel="noopener" class="neon-footer__social-btn" title="iOS"> 3843 <i class="fab fa-apple"></i> 3844 </a> 3845 <a href="https://wa.me/5514997350454" target="_blank" rel="noopener" class="neon-footer__social-btn" title="WhatsApp"> 3846 <i class="fab fa-whatsapp"></i> 3847 </a> 3848 </div> 3849 </div> 3850 3851 <!-- Col 2 e 3: Navegação (2 colunas) --> 3852 <div class="neon-footer__col neon-footer__col--nav"> 3853 <h4 class="neon-footer__heading">Navegação</h4> 3854 <ul class="neon-footer__links neon-footer__links--two-cols"> 3855 <li><a href="https://nativafmbauru.com.br/s">Home</a></li> 3856 <li><a href="promocoes">Promoções</a></li> 3857 <li><a href="programacao">Programação</a></li> 3858 <li><a href="noticias">NotÃcias</a></li> 3859 <li><a href="equipe">Equipe</a></li> 3860 <li><a href="contato">Contato</a></li> 3861 </ul> 3862 </div> 3863 3864 <!-- Col 4: Contato --> 3865 <div class="neon-footer__col"> 3866 <h4 class="neon-footer__heading">Contato</h4> 3867 <ul class="neon-footer__contact"> 3868 <li> 3869 <!-- WhatsApp (mantido FA Brands) --> 3870 <i class="fab fa-whatsapp"></i> 3871 <a href="https://wa.me/5514997350454" target="_blank" rel="noopener"> 3872 (14) 997350454 </a> 3873 </li> 3874 <li> 3875 <!-- Lucide: phone --> 3876 <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07A19.5 19.5 0 0 1 4.69 12a19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 3.56 1.2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z"/></svg>
3877 <span>(14) 3232-3572</span> 3878 </li> 3879 </ul> 3880 </div> 3881 </div> 3882 3883 <!-- Barra de Copyright --> 3884 <div class="neon-footer__bottom"> 3885 <div class="neon-footer__bottom-inner"> 3886 <div class="neon-footer__b-left"> 3887 <p class="neon-footer__copyright"> 3888 Todos os Direito Reservados - uHost · <a href="politica-de-privacidade" class="neon-footer__privacy-link">PolÃtica de Privacidade</a> 3889 </p> 3890 </div> 3891 <div class="neon-footer__b-right"> 3892 <a href="https://uhost.com.br/" target="_blank" rel="noopener" class="neon-footer__dev-link"> 3893 <img src="https://nativafmbauru.com.br/uploads/media/69c33a45ac364_1774402117.png" 3894 alt="Site e app para rádio - UHOST" 3895 class="neon-footer__dev-logo" 3896 onerror="this.closest('.neon-footer__dev-link').style.display='none'"> 3897 </a> 3898 </div> 3899 </div> 3900 </div> 3901</footer> 3902
3903<script> 3904document.addEventListener('DOMContentLoaded', () => { 3905 const handleShelves = () => { 3906 if (window.innerWidth > 768) { 3907 document.querySelectorAll('.shelf-dots').forEach(d => d.style.display = 'none'); 3908 return; 3909 } else { 3910 document.querySelectorAll('.shelf-dots').forEach(d => d.style.display = 'flex'); 3911 } 3912 3913 const shelves = document.querySelectorAll('.shelf-row'); 3914 shelves.forEach(shelf => { 3915 // Touch handler aplicado SEMPRE â independente de haver dots 3916 let _tx = 0, _tl = 0; 3917 shelf.addEventListener('touchstart', e => { 3918 _tx = e.touches[0].clientX; 3919 _tl = shelf.scrollLeft; 3920 }, { passive: true }); 3921 shelf.addEventListener('touchmove', e => { 3922 shelf.scrollLeft = _tl + (_tx - e.touches[0].clientX); 3923 }, { passive: true }); 3924 3925 // Encontra o container dos dots (pode estar fora do layout-wrapper, dentro do .container) 3926 const dotContainer = shelf.closest('.container')?.querySelector('.shelf-dots') ?? null; 3927 3928 if (!dotContainer) return; 3929 3930 const cards = Array.from(shelf.children); 3931 if (cards.length === 0) return; 3932 3933 // Evitar duplicações 3934 if (dotContainer.children.length === cards.length) return; 3935 3936 // Criar dots 3937 dotContainer.innerHTML = ''; 3938 cards.forEach((_, i) => { 3939 const dot = document.createElement('div'); 3940 dot.classList.add('dot'); 3941 if (i === 0) dot.classList.add('active'); 3942 dotContainer.appendChild(dot); 3943 }); 3944 3945 const dots = Array.from(dotContainer.children); 3946 3947 // Observer para atualizar estado ativo 3948 const observer = new IntersectionObserver((entries) => { 3949 entries.forEach(entry => { 3950 if (entry.isIntersecting) { 3951 const index = cards.indexOf(entry.target); 3952 if (index !== -1 && dots[index]) { 3953 dots.forEach(d => d.classList.remove('active')); 3954 dots[index].classList.add('active'); 3955 } 3956 } 3957 }); 3958 }, { 3959 root: shelf, 3960 threshold: 0.6 // pelo menos 60% visÃvel para ativar 3961 }); 3962 3963 cards.forEach(card => observer.observe(card)); 3964 }); 3965 }; 3966 3967 handleShelves(); 3968 window.addEventListener('resize', handleShelves); 3969}); 3970</script>
3970 3971 3972 3973 <!-- ===== WHATSAPP WIDGET (Global â todos os temas) ===== --> 3974 <!-- Oculto automaticamente se nenhum número estiver configurado --> 3975 <!-- Oculto em mobile via CSS (max-width: 768px) --> 3976 <link rel="stylesheet" href="https://nativafmbauru.com.br/assets/css/whatsapp-widget.css?v=1779829714"> 3977
3977<script src="https://cdnjs.cloudflare.com/ajax/libs/qrcodejs/1.0.0/qrcode.min.js" defer></script>
3977 3978
3978<script src="https://nativafmbauru.com.br/assets/js/whatsapp-widget.js" defer></script>
3978 3979 3980<!-- ===== WHATSAPP WIDGET (Global) ===== --> 3981 3982<!-- Botão Flutuante --> 3983<button id="wa-fab" 3984 aria-label="Fale conosco pelo WhatsApp" 3985 title="Fale conosco pelo WhatsApp"> 3986 <svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"> 3987 <path d="M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 005.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 00-3.48-8.413z"/> 3988 </svg> 3989</button> 3990 3991<!-- Overlay --> 3992<div id="wa-overlay" aria-hidden="true"></div> 3993 3994<!-- Painel lateral (Drawer) --> 3995<aside id="wa-panel" role="dialog" aria-modal="true" aria-label="WhatsApp"> 3996 3997 <!-- Cabeçalho --> 3998 <div id="wa-panel-header"> 3999 <p class="wa-ph-title"> 4000 <svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"> 4001 <path d="M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 005.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 00-3.48-8.413z"/> 4002 </svg> 4003 WhatsApp 4004 </p> 4005 <button id="wa-close-btn" aria-label="Fechar">✕</button> 4006 </div> 4007 4008 <!-- Corpo --> 4009 <div id="wa-panel-body"> 4010 4011 <p class="wa-body-title">Escaneie o QR Code e fale conosco pelo WhatsApp</p> 4012 4013 <!-- QR Code gerado via whatsapp-widget.js --> 4014 <div id="wa-qr-wrap" aria-label="QR Code WhatsApp"></div> 4015 4016 <p class="wa-body-hint"> 4017 Aponte a câmera do celular para o código acima 4018 </p> 4019 4020 </div> 4021</aside> 4022 4023<!-- Variáveis injetadas para o JS -->
4024<script> 4025var WA_NUMBER = "5514997350454"; 4026var WA_BTN_POS = "bottom-left"; 4027</script>
4027 4028 4029 <!-- Cookie Banner Global (Ajuste 3) --> 4030 <!-- ===== COOKIE BANNER â Bottom Sheet Nativo ===== --> 4031<div 4032 id="cookieBanner" 4033 class="cookie-banner" 4034 role="alertdialog" 4035 aria-live="polite" 4036 aria-label="Aviso de privacidade" 4037 aria-describedby="cookieBannerDesc" 4038 style="display:none;" 4039> 4040 <!-- Handle pill (drag indicator nativo) --> 4041 <div class="cookie-banner__handle" aria-hidden="true"></div> 4042 4043 <!-- Cabeçalho estilo app nativo --> 4044 <div class="cookie-banner__header"> 4045 <div class="cookie-banner__app-icon" aria-hidden="true"> 4046 <img src="https://nativafmbauru.com.br/uploads/media/6a18a5b4f2efe_1780000180.webp" alt="" width="46" height="46" loading="lazy"> 4047 </div> 4048 <div class="cookie-banner__app-info"> 4049 <p class="cookie-banner__app-name">Sua privacidade</p> 4050 <p class="cookie-banner__app-host">Nativa FM Bauru · nativafmbauru.com.br</p> 4051 </div> 4052 </div> 4053 4054 <!-- Separador --> 4055 <div class="cookie-banner__divider" aria-hidden="true"></div> 4056 4057 <!-- Texto explicativo --> 4058 <p class="cookie-banner__desc" id="cookieBannerDesc"> 4059 Usamos cookies para manter o app funcionando e melhorar sua experiência. Nenhum dado é vendido a terceiros. 4060 <a href="https://nativafmbauru.com.br/?page=politica-de-privacidade" target="_blank" rel="noopener" class="cookie-banner__privacy-link">PolÃtica de privacidade</a> 4061 </p> 4062 4063 <!-- Ações empilhadas (estilo nativo) --> 4064 <div class="cookie-banner__actions"> 4065 <button 4066 id="cookieBannerAccept" 4067 class="cookie-banner__btn cookie-banner__btn--primary" 4068 type="button" 4069 aria-label="Aceitar todos os cookies" 4070 > 4071 Aceitar todos 4072 </button> 4073 <button 4074 id="cookieBannerDecline" 4075 class="cookie-banner__btn cookie-banner__btn--secondary" 4076 type="button" 4077 aria-label="Aceitar apenas cookies essenciais" 4078 > 4079 Apenas essenciais 4080 </button> 4081 </div> 4082</div> 4083
4084<script> 4085/* ââ Cookie Banner JS (IIFE) ââ */ 4086(function () { 4087 'use strict'; 4088 4089 var STORAGE_KEY = 'cookie_consent'; 4090 var banner = document.getElementById('cookieBanner'); 4091 if (!banner) return; 4092 4093 /* Se o usuário já escolheu, não mostrar novamente */ 4094 try { 4095 if (localStorage.getItem(STORAGE_KEY)) return; 4096 } catch (e) { 4097 return; 4098 } 4099 4100 /* ââ Animação de entrada (slide-up) ââ */ 4101 function showBanner() { 4102 banner.style.display = 'flex'; 4103 void banner.offsetHeight; 4104 banner.classList.add('cookie-banner--visible'); 4105 } 4106 4107 function hideBanner(callback) { 4108 banner.classList.remove('cookie-banner--visible'); 4109 banner.classList.add('cookie-banner--hiding'); 4110 setTimeout(function () { 4111 banner.style.display = 'none'; 4112 banner.classList.remove('cookie-banner--hiding'); 4113 if (typeof callback === 'function') callback(); 4114 }, 400); 4115 } 4116 4117 function saveChoice(choice) { 4118 try { localStorage.setItem(STORAGE_KEY, choice); } catch (e) {} 4119 } 4120 4121 /* ââ Mostrar após 1.2s ââ */ 4122 setTimeout(showBanner, 1200); 4123 4124 /* ââ Botão Aceitar todos ââ */ 4125 var acceptBtn = document.getElementById('cookieBannerAccept'); 4126 if (acceptBtn) { 4127 acceptBtn.addEventListener('click', function () { 4128 saveChoice('accepted'); 4129 hideBanner(function () { 4130 document.dispatchEvent(new CustomEvent('cookie:accepted')); 4131 }); 4132 }); 4133 } 4134 4135 /* ââ Botão Apenas essenciais ââ */ 4136 var declineBtn = document.getElementById('cookieBannerDecline'); 4137 if (declineBtn) { 4138 declineBtn.addEventListener('click', function () { 4139 saveChoice('essential'); 4140 hideBanner(function () { 4141 document.dispatchEvent(new CustomEvent('cookie:declined')); 4142 }); 4143 }); 4144 } 4145 4146 /* ââ Fechar com Escape ââ */ 4147 document.addEventListener('keydown', function (e) { 4148 if (e.key === 'Escape' && banner.classList.contains('cookie-banner--visible')) { 4149 saveChoice('essential'); 4150 hideBanner(); 4151 } 4152 }); 4153})(); 4154</script>
4154 4155 4156 <!-- Smart App Install Banner (global â CTA de loja, prompt PWA ou instruções iOS). 4157 Dentro do app Rádio 3.0 não faz sentido convidar a instalar o app. --> 4158 4159 <!-- Popup de Abertura (global â campanha cadastrada em /?page=banners). 4160 Sem campanha ativa não emite CSS, JS nem markup. --> 4161 4162 <!-- Menu Mobile Global (Apenas Mobile via CSS). Também traz o estilo de mini 4163 player e o player expandido â nada disso existe dentro do app Rádio 3.0. --> 4164 4165<nav class="mobile-bottom-nav"> 4166 <!-- Item 1: fixo (Página Inicial) --> 4167 <a class="nav-item" href="https://nativafmbauru.com.br"> 4168 <div class="nav-icon-box"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 9.5L12 3l9 6.5V20a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V9.5z"/><path d="M9 21V12h6v9"/></svg></div> 4169 </a> 4170 4171 <!-- Itens 2-5: dinâmicos --> 4172 <a class="nav-item" href="/promocoes"> 4173 <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 12 20 22 4 22 4 12"/><rect x="2" y="7" width="20" height="5"/><line x1="12" y1="22" x2="12" y2="7"/><path d="M12 7H7.5a2.5 2.5 0 0 1 0-5C11 2 12 7 12 7z"/><path d="M12 7h4.5a2.5 2.5 0 0 0 0-5C13 2 12 7 12 7z"/></svg> <span>Promoções</span> 4174 </a> 4175 <a class="nav-item" href="/noticias"> 4176 <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="8" y1="6" x2="21" y2="6"/><line x1="8" y1="12" x2="21" y2="12"/><line x1="8" y1="18" x2="21" y2="18"/><circle cx="3" cy="6" r="1"/><circle cx="3" cy="12" r="1"/><circle cx="3" cy="18" r="1"/></svg> <span>NotÃcias</span> 4177 </a> 4178 <a class="nav-item" href="/programacao"> 4179 <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 18V5l12-2v13"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="16" r="3"/></svg> <span>Programação</span> 4180 </a> 4181 <a class="nav-item" href="/contato"> 4182 <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"/><polyline points="22,6 12,13 2,6"/></svg> <span>Contato</span> 4183 </a> 4184 </nav> 4185 4186<style> 4187.mobile-bottom-nav { 4188 display: none; 4189} 4190@media (max-width: 1024px), (pointer: coarse) and (max-width: 1366px) { 4191 .mobile-bottom-nav { 4192 position: fixed; 4193 bottom: 0; left: 0; right: 0; 4194 background: var(--bg-card, #ffffff); 4195 border-top: 1px solid var(--border-color, #e0e0e0); 4196 display: flex; 4197 justify-content: space-around; 4198 align-items: flex-start; 4199 padding: 12px 0 calc(12px + env(safe-area-inset-bottom)); 4200 z-index: 9999; 4201 } 4202} 4203 4204html[data-theme="dark"] .mobile-bottom-nav, 4205body.dark-mode .mobile-bottom-nav { 4206 background: var(--bg-card, #121214); 4207 border-top: 1px solid var(--border-color, rgba(255, 255, 255, 0.08)); 4208} 4209 4210.mobile-bottom-nav .nav-item { 4211 all: unset; 4212 display: flex !important; 4213 flex-direction: column !important; 4214 align-items: center !important; 4215 gap: 5px !important; 4216 cursor: pointer !important; 4217 padding: 4px 10px !important; 4218 text-decoration: none !important; 4219 box-sizing: border-box !important; 4220} 4221 4222.mobile-bottom-nav .nav-item svg { stroke: #9e9e9e; width: 24px; height: 24px; transition: all 0.2s; } 4223.mobile-bottom-nav .nav-item span { font-size: 11px; color: #9e9e9e; font-weight: 500; transition: all 0.2s; } 4224 4225/* Hover â feedback visual ao toque */ 4226.mobile-bottom-nav .nav-item:hover svg, 4227.mobile-bottom-nav .nav-item:focus svg { stroke: var(--primary-color, #1B1464); opacity: 0.7; } 4228.mobile-bottom-nav .nav-item:hover span, 4229.mobile-bottom-nav .nav-item:focus span { color: var(--primary-color, #1B1464); opacity: 0.7; } 4230 4231/* Ativo â página atual */ 4232.mobile-bottom-nav .nav-item.active svg { stroke: var(--primary-color, #1B1464); opacity: 1; } 4233.mobile-bottom-nav .nav-item.active span { color: var(--primary-color, #1B1464); font-weight: 500; opacity: 1; } 4234 4235.mobile-bottom-nav .nav-icon-box { 4236 width: 48px; height: 48px; 4237 border-radius: 14px; 4238 background: var(--primary-color, #1B1464); 4239 display: flex; align-items: center; justify-content: center; 4240 margin-top: -6px; /* Para alinhar opticamente a caixa maior com os outros Ãcones */ 4241 transition: all 0.2s; 4242} 4243 4244/* Ãcone box do item 1 quando ativo */ 4245.mobile-bottom-nav .nav-item.active .nav-icon-box { background: var(--primary-color, #1B1464); } 4246 4247/* Ãcone box do item 1 quando inativo */ 4248.mobile-bottom-nav .nav-item:not(.active) .nav-icon-box { background: var(--border-color, #e0e0e0); } 4249.mobile-bottom-nav .nav-item:not(.active) .nav-icon-box svg { stroke: #9e9e9e !important; opacity: 1; } 4250 4251/* Home icon should be white inside the active solid box */ 4252.mobile-bottom-nav .nav-item.active .nav-icon-box svg { stroke: #ffffff !important; } 4253 4254/* Prevent overrides from global player svg rule modifying this one if any */ 4255
4256/* Para não sobrepor o footer em sites mobile, adicione padding bottom global body via classe */ 4257@media (max-width: 1024px), (pointer: coarse) and (max-width: 1366px) { 4258 body { 4259 padding-bottom: calc(148px + env(safe-area-inset-bottom)) !important; 4260 } 4261 4262 /* ========================================= 4263 REESTILIZAÃÃO GLOBAL DO PLAYER MOBILE 4264 ESTILO DEEZER (PÃLULA FLUTUANTE LIMPA) 4265 ========================================= */ 4266 #player, .radio-player, .neon-player, .d5-player, .app-player, .player-container, .global-player { 4267 position: fixed !important; 4268 bottom: calc(85px + env(safe-area-inset-bottom)) !important; 4269 left: 12px !important; 4270 right: 12px !important; 4271 width: auto !important; 4272 height: 64px !important; 4273 min-height: 64px !important; 4274 max-height: 64px !important; 4275 box-sizing: border-box !important; 4276 align-items: center !important; 4277 overflow: hidden !important; /* garante que nada vaze para fora */ 4278 border-radius: 12px !important; 4279 background: var(--player-bg, #181818) !important; 4280 box-shadow: 0 8px 25px rgba(0,0,0,0.4) !important; 4281 border: 1px solid var(--border-color, rgba(255,255,255,0.06)) !important; 4282 padding: 0 12px !important; 4283 z-index: 9998 !important; 4284 } 4285 4286 /* Container global - forçar flex row */ 4287 #player > div, 4288 .neon-player__inner, 4289 .d5-player-inner { 4290 display: flex !important; 4291 flex-direction: row !important; 4292 align-items: center !important; 4293 justify-content: flex-start !important; 4294 padding: 0 !important; 4295 height: 100% !important; 4296 gap: 10px !important; 4297 width: 100% !important; 4298 border: none !important; 4299 } 4300 4301 /* Ocultar elementos desnecessários (Artwork e Status Badge agora são visÃveis) */ 4302 .neon-player__video-btn-wrap, 4303 .wave-player__video-btn-wrap, 4304 .pulse-player__video-btn-wrap, 4305 .glow-player__video-btn-wrap, 4306 .d5-volume-ctrl, 4307 .zmp-volume-slider, 4308 #volumeBtn, 4309 #liveBtn, 4310 #zmpLiveBtn, 4311 #videoBtn, 4312 .d5-play-ring, 4313 #visualizer, 4314 .neon-player__watch-btn, 4315 .wave-player__watch-btn, 4316 .pulse-player__watch-btn, 4317 .glow-player__watch-btn { 4318 display: none !important; 4319 } 4320 4321 /* ==== Ajuste: Alinhamento exato da Capa e Botão Play (Tamanho fixo 48x48) ==== 4322 Cada tema pode redefinir o tamanho da capa com especificidade maior 4323 (ex.: WAVE usa 52px no brutalism_override.css). O que importa aqui é que 4324 o slot NUNCA saia do fluxo e não mude de tamanho entre estados. */ 4325 .neon-player__artwork, 4326 .d5-player-artwork, 4327 .player-artwork, 4328 #playerArtwork, 4329 .wave-player__artwork, 4330 .pulse-player__artwork, 4331 .glow-player__artwork, 4332 .play-btn, 4333 .neon-player__play-btn, 4334 .d5-play-btn, 4335 #playBtn, 4336 .global-play-btn, 4337 .wave-player__play-btn { 4338 width: 48px !important; 4339 height: 48px !important; 4340 min-width: 48px !important; 4341 max-width: 48px !important; 4342 flex-shrink: 0 !important; 4343 align-self: center !important; 4344 display: flex !important; 4345 align-items: center !important; 4346 justify-content: center !important; 4347 box-sizing: border-box !important; 4348 margin: 0 !important; 4349 padding: 0 !important; 4350 } 4351 4352 .neon-player__artwork, 4353 .d5-player-artwork, 4354 .player-artwork, 4355 #playerArtwork, 4356 .wave-player__artwork, 4357 .pulse-player__artwork, 4358 .glow-player__artwork { 4359 border-radius: 6px !important; /* Capa quadrada com cantos suaves no mobile */ 4360 overflow: hidden !important; 4361 display: block !important; 4362 } 4363 4364 .neon-player__artwork img, 4365 .d5-player-artwork img, 4366 .player-artwork img, 4367 #playerArtwork img, 4368 .wave-player__artwork img, 4369 .pulse-player__artwork img, 4370 .glow-player__artwork img { 4371 width: 48px !important; 4372 height: 48px !important; 4373 object-fit: cover !important; 4374 display: block !important; 4375 } 4376 4377 /* ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ 4378 ESQUELETO ÃNICO DO MINI PLAYER (NEON / WAVE / PULSE / GLOW) 4379 ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ 4380 Regra de ouro: o layout NÃO depende do conteúdo. A ordem e a 4381 distribuição são as mesmas com ou sem metadados â só o texto e a 4382 imagem mudam. Ordem fixa: 4383 capa â badge â tÃtulo â artista â play (colado na direita) 4384 IMPORTANTE: usamos #player como prefixo para ter especificidade 4385 maior que as regras inline no @media do player.php. --- */ 4386 #player .neon-player__left-group, 4387 #player .wave-player__left-group, 4388 #player .pulse-player__left-group, 4389 #player .glow-player__left-group { 4390 display: flex !important; 4391 flex-direction: row !important; 4392 align-items: center !important; 4393 justify-content: flex-start !important; /* sobrescreve qualquer space-between herdado */ 4394 gap: 10px !important; 4395 flex: 1 1 0 !important; 4396 width: 100% !important; 4397 min-width: 0 !important; 4398 overflow: hidden !important; 4399 } 4400 4401 /* Bloco capa + texto: ocupa TODA a sobra, sempre. à esse flex:1 1 0 que 4402 impede o botão play de escorregar para o meio quando o texto é curto. */ 4403 #player .neon-player__info, 4404 #player .wave-player__info, 4405 #player .pulse-player__info, 4406 #player .glow-player__info { 4407 display: flex !important; 4408 flex-direction: row !important; 4409 align-items: center !important; 4410 justify-content: flex-start !important; 4411 flex: 1 1 0 !important; 4412 min-width: 0 !important; 4413 gap: 10px !important; 4414 order: 1 !important; /* capa + texto primeiro */ 4415 overflow: hidden !important; 4416 } 4417 4418 /* Coluna de texto: min-width:0 é obrigatório para o ellipsis funcionar 4419 dentro de um flex item (sem ele o texto empurra o container). */ 4420 #player .wave-player__meta, 4421 #player .neon-player__meta, 4422 #player .pulse-player__meta, 4423 #player .glow-player__meta, 4424 #player .d5-player-meta, 4425 #player .player-meta, 4426 #player .nmp-meta-wrap { 4427 display: flex !important; 4428 flex-direction: column !important; 4429 justify-content: center !important; 4430 gap: 0 !important; 4431 line-height: 1 !important; 4432 overflow: hidden !important; 4433 min-width: 0 !important; 4434 flex: 1 1 0 !important; 4435 } 4436 4437 /* Play ancorado na borda direita em TODOS os estados. 4438 margin-left:auto + order:2 = sempre o último, sempre colado à direita.
4439 (o margin-left:20px do player.php perde: 0,2,0 vs 0,1,0) */ 4440 #player .zmp-player-controls-wrapper { 4441 margin: 0 0 0 auto !important; 4442 padding: 0 !important; 4443 order: 2 !important; 4444 flex: 0 0 auto !important; 4445 gap: 0 !important; 4446 width: auto !important; 4447 } 4448 4449 /* ---- LÃGICA DEMO 05 ---- */ 4450 .d5-player-inner > div:nth-child(2) { 4451 order: -1 !important; /* Bloco do Play vai para a esquerda */ 4452 margin: 0 !important; 4453 margin-right: -4px !important; 4454 flex: 0 0 auto !important; 4455 width: auto !important; 4456 } 4457 .d5-player-left { 4458 order: 2 !important; /* Bloco de Info vai para a direita do Play */ 4459 flex: 1 !important; 4460 width: auto !important; 4461 gap: 0 !important; 4462 } 4463 .d5-player-inner > div:nth-child(3) { 4464 display: none !important; /* Esconde botões extras estendidos */ 4465 } 4466 .d5-player-meta { 4467 justify-content: center !important; 4468 min-height: 0 !important; 4469 gap: 0 !important; 4470 } 4471 4472 /* ---- TIPOGRAFIA COMUM (TITULO / ARTISTA) ---- 4473 As três linhas têm ALTURA RESERVADA (badge 10px, tÃtulo 16px, 4474 artista 12px). Linha vazia continua ocupando o mesmo espaço, então 4475 trocar de estado não causa reflow nem salto de altura. */ 4476 .player-status-badge, 4477 .neon-player__status, 4478 .wave-player__status, 4479 .pulse-player__status, 4480 .glow-player__status, 4481 .live-badge, 4482 .wave-player__live-text { 4483 display: block !important; 4484 font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif !important; 4485 font-size: 10px !important; 4486 font-weight: 700 !important; 4487 text-transform: uppercase !important; 4488 letter-spacing: 0.08em !important; 4489 margin-bottom: 3px !important; 4490 line-height: 1 !important; 4491 height: 10px !important; 4492 flex: 0 0 10px !important; 4493 color: var(--player-text-color, #ffffff) !important; 4494 } 4495 4496 .neon-player__title, 4497 .d5-player-title, 4498 .wave-player__title, 4499 .pulse-player__title, 4500 .glow-player__title, 4501 .player-title { 4502 font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif !important; 4503 font-size: 13px !important; 4504 font-weight: 800 !important; 4505 color: var(--player-text-color, #ffffff) !important; 4506 text-transform: uppercase !important; 4507 width: 100% !important; 4508 text-shadow: none !important; 4509 -webkit-text-stroke: 0 !important; 4510 line-height: 16px !important; 4511 height: 16px !important; 4512 flex: 0 0 16px !important; 4513 display: block; /* sem !important: o JS do marquee precisa poder ocultar */ 4514 padding: 0 !important; 4515 margin: 0 0 2px 0 !important; 4516 white-space: nowrap !important; 4517 overflow: hidden !important; 4518 text-overflow: ellipsis !important; 4519 } 4520 4521 /* Oculta os elementos originais quando o marquee está ativo â usa !important 4522 para sobrescrever regras de tema (ex: wave-player__title tem display:block !important) */ 4523 #player .nmp-src-hidden { 4524 display: none !important; 4525 } 4526 4527 .neon-player__artist, 4528 .d5-player-artist, 4529 .wave-player__artist, 4530 .pulse-player__artist, 4531 .glow-player__artist, 4532 .player-artist { 4533 font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif !important; 4534 font-size: 11px !important; 4535 font-weight: 400 !important; 4536 color: var(--player-text-color, #ffffff) !important; 4537 opacity: 0.8 !important; 4538 text-transform: uppercase !important; 4539 white-space: nowrap !important; 4540 overflow: hidden !important; 4541 text-overflow: ellipsis !important; 4542 width: 100% !important; 4543 line-height: 12px !important; 4544 height: 12px !important; 4545 flex: 0 0 12px !important; 4546 display: block; 4547 padding: 0 !important; 4548 margin: 0 !important; 4549 } 4550 4551 /* ---- AJUSTE 3: ANIMAÃÃO MARQUEE ---- */ 4552 --marquee-duration: 10s; 4553 4554 /* Wrapper de texto do mini player mobile. 4555 Nenhum tema gera .nmp-meta-wrap hoje; mantido para compatibilidade. 4556 order:1 para acompanhar o esqueleto (capa+texto antes do play). */ 4557 .nmp-meta-wrap { 4558 flex: 1 1 0 !important; 4559 min-width: 0 !important; 4560 overflow: hidden !important; 4561 display: flex !important; 4562 flex-direction: column !important; 4563 justify-content: center !important; 4564 gap: 0 !important; 4565 line-height: 1 !important; 4566 order: 1 !important; 4567 } 4568 4569 /* O antigo bloco .nmp-fallback (logo + nome do site) foi removido: ele 4570 trocava a subárvore inteira do mini player quando não havia metadados, 4571 com markup, tamanhos e ordem próprios â a causa do layout embaralhado. 4572 Agora o esqueleto é sempre o mesmo e só o texto muda. */ 4573 4574 /* Linha de texto com suporte a marquee. 4575 O <span> só vira inline-block quando o marquee está ativo. Enquanto for 4576 inline, o text-overflow do pai consegue aplicar o ellipsis â um filho 4577 inline-block seria cortado a seco, sem reticências. */ 4578 .mini-player-text { 4579 white-space: nowrap !important; 4580 overflow: hidden !important; 4581 text-overflow: ellipsis !important; 4582 display: block !important; 4583 width: 100% !important; 4584 position: relative !important; 4585 } 4586 .mini-player-text span { 4587 display: inline; 4588 white-space: nowrap !important; /* Impede que o texto duplicado (marquee) quebre linha */ 4589 padding-right: 0; 4590 } 4591 /* Estado rolando: o span passa a conter DUAS cópias idênticas (.nmp-run), 4592 cada uma com o intervalo já embutido no próprio padding-right. Assim 4593 metade da largura total é exatamente uma cópia + intervalo, e o 4594 translateX(-50%) emenda o fim no começo sem salto. Se o intervalo 4595 ficasse solto entre as cópias (ou no padding do span), 50% cairia no 4596 meio do vão e a volta daria um pulo visÃvel. */ 4597 .mini-player-text span.scrolling { 4598 display: inline-block; 4599 padding-right: 0; 4600 will-change: transform; 4601 animation: nmp-marquee-scroll 12s linear infinite; /* duração real vem do JS */ 4602 } 4603 .mini-player-text span.scrolling .nmp-run { 4604 display: inline-block; 4605 white-space: nowrap; 4606 padding-right: 48px; /* intervalo entre o fim de uma cópia e o inÃcio da outra */ 4607 font-style: normal; 4608 }
4609 @keyframes nmp-marquee-scroll { 4610 0% { transform: translateX(0); } 4611 100% { transform: translateX(-50%); } 4612 } 4613 /* Respeita quem pediu menos animação no sistema: em vez de rolar, volta ao 4614 texto estático com reticências â a segunda cópia sai de cena para não 4615 aparecer texto repetido cortado no meio. */ 4616 @media (prefers-reduced-motion: reduce) { 4617 .mini-player-text span.scrolling { 4618 display: inline; 4619 animation: none !important; 4620 transform: none !important; 4621 } 4622 .mini-player-text span.scrolling .nmp-run { 4623 padding-right: 0 !important; 4624 } 4625 .mini-player-text span.scrolling .nmp-run + .nmp-run { 4626 display: none !important; 4627 } 4628 #player.nmp-one-line #nmpDisplayTitle { 4629 text-overflow: ellipsis !important; 4630 } 4631 } 4632 4633 /* ââââââââââââââââââââââââââââââââââââââââââââââââââââââââ 4634 LAYOUT GLOBAL â Mini Player Mobile (TODOS OS TEMAS) 4635 Abordagem: seletores de CLASSE e nth-child apenas. 4636 SEM :has() â compatÃvel com qualquer browser. 4637 ââââââââââââââââââââââââââââââââââââââââââââââââââââââââ */ 4638 4639 /* --- Container direto do #player: força flex-start em TUDO --- */ 4640 #player > div, 4641 #player > .neon-player__inner, 4642 #player > .wave-player__inner, 4643 #player > .pulse-player__inner, 4644 #player > .glow-player__inner, 4645 #player > .d5-player-inner { 4646 flex-wrap: nowrap !important; 4647 gap: 10px !important; 4648 padding: 0 !important; 4649 overflow: hidden !important; 4650 justify-content: flex-start !important; 4651 align-items: center !important; 4652 } 4653 4654 /* Nota: as regras de #player .neon-player__left-group, .neon-player__info e 4655 .zmp-player-controls-wrapper com prefixo #player estão na seção LÃGICA FLEX acima. */ 4656 4657 /* ââââââââââââââââââââââââââââââââââââââââââââââââââââââââ 4658 DEMO 01 â Inner: .max-w-screen-2xl 4659 Estrutura: [1:Left=info] [2:Center=play] [3:Right=extras] 4660 ââââââââââââââââââââââââââââââââââââââââââââââââââââââââ */ 4661 /* Centro (playBtn) â vai para a ESQUERDA */ 4662 #player > div.max-w-screen-2xl > div:nth-child(2) { 4663 order: 1 !important; 4664 flex: 0 0 auto !important; 4665 width: auto !important; 4666 margin: 0 !important; 4667 gap: 0 !important; 4668 align-items: center !important; 4669 } 4670 /* Esquerda (artwork + info) â expande para preencher */ 4671 #player > div.max-w-screen-2xl > div:nth-child(1) { 4672 order: 2 !important; 4673 flex: 1 1 0 !important; 4674 min-width: 0 !important; 4675 overflow: hidden !important; 4676 width: auto !important; 4677 } 4678 /* Direita (extras/volume) â oculto */ 4679 #player > div.max-w-screen-2xl > div:nth-child(3) { 4680 display: none !important; 4681 } 4682 /* Container de texto dentro do bloco de info do Demo01 */ 4683 #player > div.max-w-screen-2xl > div:nth-child(1) > div:last-child { 4684 flex: 1 1 0 !important; 4685 min-width: 0 !important; 4686 overflow: hidden !important; 4687 } 4688 4689 /* --- Containers de meta-info internos --- */ 4690 .neon-player__info, 4691 .wave-player__info, 4692 .pulse-player__info, 4693 .glow-player__info, 4694 .d5-player-meta { 4695 flex: 1 1 0 !important; 4696 min-width: 0 !important; 4697 overflow: hidden !important; 4698 } 4699 4700 /* --- TÃtulo e Artista: sempre truncados com ellipsis --- 4701 IMPORTANTE: NÃO adicionar display:block !important aqui â 4702 o JS do marquee precisa conseguir ocultar esses elementos 4703 via element.style.display = 'none' para mostrar os 4704 substitutos #nmpDisplayTitle / #nmpDisplayArtist no lugar. --- */ 4705 #player #playerTitle, 4706 #player #playerArtist, 4707 #player .neon-player__title, 4708 #player .wave-player__title, 4709 #player .pulse-player__title, 4710 #player .glow-player__title, 4711 #player .d5-player-title, 4712 #player .player-title, 4713 #player .neon-player__artist, 4714 #player .wave-player__artist, 4715 #player .pulse-player__artist, 4716 #player .glow-player__artist, 4717 #player .d5-player-artist, 4718 #player .player-artist { 4719 max-width: 100% !important; 4720 overflow: hidden !important; 4721 text-overflow: ellipsis !important; 4722 white-space: nowrap !important; 4723 /* display intencionalmente ausente â controlado pelo JS do marquee */ 4724 } 4725 4726 /* Garante que playerTitle/Artist aparecem (desfaz 'hidden' do Tailwind/temas) 4727 SEM !important para não bloquear o display:none que o marquee-JS coloca */ 4728 #player #playerTitle { display: block; } 4729 #player #playerArtist { display: block; } 4730 4731 /* Elementos de display do marquee (substitutos). 4732 Tipografia e altura reservada IDÃNTICAS à s do tÃtulo/artista originais â 4733 o fallback é troca de string, nunca troca de estilo. */ 4734 #nmpDisplayTitle { 4735 font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif !important; 4736 font-size: 13px !important; 4737 font-weight: 800 !important; 4738 color: var(--player-text-color, #ffffff) !important; 4739 text-transform: uppercase !important; 4740 letter-spacing: 0.02em !important; 4741 line-height: 16px !important; 4742 height: 16px !important; 4743 flex: 0 0 16px !important; 4744 margin: 0 0 2px 0 !important; 4745 } 4746 #nmpDisplayArtist { 4747 font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif !important; 4748 font-size: 11px !important; 4749 font-weight: 400 !important; 4750 color: var(--player-text-color, #ffffff) !important; 4751 opacity: 0.8 !important; 4752 text-transform: uppercase !important; 4753 line-height: 12px !important; 4754 height: 12px !important; 4755 flex: 0 0 12px !important; 4756 } 4757 4758 /* âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ 4759 ESTADO COM METADADOS â LINHA ÃNICA (classe .nmp-one-line) 4760 âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ 4761 Com faixa tocando, música e artista deixam de ocupar duas linhas 4762 estreitas e passam a formar UMA linha só: MÃSICA ⢠ARTISTA. 4763 A coluna de texto do mini player tem ~150px; dividir isso em duas 4764 linhas de 13px/11px espremia os dois textos e cortava os dois. 4765 Em uma linha só, o texto ganha o dobro de largura útil e o que não 4766 couber rola em marquee contÃnuo (nunca reticências, nunca fonte menor). 4767 4768 O slot do artista continua existindo no DOM â apenas fica vazio e sai 4769 do fluxo â para o esqueleto (capa â badge â texto â play) não mudar. 4770 âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ */ 4771 4772 /* Linha vazia (o slot do artista) sai do fluxo: nada de 12px em branco. */ 4773 #player.nmp-one-line .nmp-empty { 4774 display: none !important; 4775 } 4776 4777 /* Bloco de texto opticamente centrado com a capa de 48px. */ 4778 #player.nmp-one-line .neon-player__meta, 4779 #player.nmp-one-line .wave-player__meta, 4780 #player.nmp-one-line .pulse-player__meta, 4781 #player.nmp-one-line .glow-player__meta, 4782 #player.nmp-one-line .d5-player-meta, 4783 #player.nmp-one-line .player-meta, 4784 #player.nmp-one-line .nmp-meta-wrap { 4785 justify-content: center !important; 4786 gap: 0 !important; 4787 } 4788 4789 /* A linha única. Mesmo corpo de fonte do tÃtulo antigo (13px) â o gan
4789ho de 4790 leitura vem da largura, não de encolher a tipografia. 4791 text-overflow: clip (e não ellipsis) porque o overflow aqui é tratado 4792 pelo marquee; reticências só voltam em prefers-reduced-motion. */ 4793 #player.nmp-one-line #nmpDisplayTitle { 4794 font-size: 13px !important; 4795 font-weight: 700 !important; 4796 letter-spacing: 0.01em !important; 4797 line-height: 18px !important; 4798 height: 18px !important; 4799 flex: 0 0 18px !important; 4800 margin: 0 !important; 4801 overflow: hidden !important; 4802 text-overflow: clip !important; 4803 } 4804 4805 /* Nome da música em destaque; separador e artista recuam em peso/opacidade 4806 para a linha ter hierarquia mesmo sendo uma só. */ 4807 #player.nmp-one-line #nmpDisplayTitle .nmp-track { 4808 font-weight: 800 !important; 4809 } 4810 #player.nmp-one-line #nmpDisplayTitle .nmp-sep { 4811 font-weight: 400 !important; 4812 opacity: 0.55 !important; 4813 padding: 0 2px !important; 4814 } 4815 #player.nmp-one-line #nmpDisplayTitle .nmp-artist { 4816 font-weight: 400 !important; 4817 opacity: 0.8 !important; 4818 } 4819 4820 /* âââââââââââââââââââââââââââââââââââââââââââââââ 4821 BADGE "â AO VIVO" â Mini Player Mobile Integrado 4822 âââââââââââââââââââââââââââââââââââââââââââââââ */ 4823 .wave-player__meta [data-player-status], 4824 .neon-player__meta [data-player-status], 4825 .pulse-player__meta [data-player-status], 4826 .glow-player__meta [data-player-status], 4827 .d5-player-meta [data-player-status], 4828 .player-meta [data-player-status], 4829 .nmp-meta-wrap [data-player-status] { 4830 display: block !important; 4831 font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif !important; 4832 font-size: 10px !important; 4833 font-weight: 700 !important; 4834 text-transform: uppercase !important; 4835 letter-spacing: 0.08em !important; 4836 white-space: nowrap !important; 4837 overflow: hidden !important; 4838 text-overflow: ellipsis !important; 4839 line-height: 1 !important; 4840 margin-bottom: 2px !important; 4841 } 4842 4843 /* âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ 4844 STATUS DO MINI PLAYER â apenas "Ao Vivo", sem avisos offline 4845 O estado de conexão é responsabilidade exclusiva da pÃlula 4846 flutuante (connection-status.php). Aqui sempre mostramos "Ao Vivo". 4847 Especificidade #player + attr > classe + attr â sobrescreve o bloco acima. 4848 âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ */ 4849 4850 /* Zera o texto dinâmico injetado pelo player.js */ 4851 #player [data-player-status] { 4852 font-size: 0 !important; 4853 letter-spacing: 0 !important; 4854 color: transparent !important; 4855 margin-bottom: 3px !important; 4856 } 4857 4858 /* Injeta "â Ao Vivo" fixo via pseudo-elemento */ 4859 #player [data-player-status]::before { 4860 content: "â Ao Vivo"; 4861 font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif !important; 4862 font-size: 9px !important; 4863 font-weight: 500 !important; 4864 color: var(--player-text-color, #ffffff) !important; 4865 opacity: 0.7 !important; 4866 text-transform: none !important; 4867 letter-spacing: normal !important; 4868 line-height: 1 !important; 4869 } 4870 4871 /* Quando em modo podcast/música, oculta "Ao Vivo" também */ 4872 #player [data-player-status][data-is-stream="false"]::before { 4873 content: "" !important; 4874 } 4875 4876 /* âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ 4877 ESTADO FALLBACK â streaming SEM metadados (classe .nmp-no-track) 4878 âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ 4879 Estado próprio, com design fechado: não existe faixa para anunciar, 4880 então a hierarquia passa a ser 4881 [selo AO VIVO] â [nome da emissora] â [praça que está tocando] 4882 em um bloco de texto ÃNICO e compacto (entrelinhas apertadas), em vez 4883 de linhas soltas com altura reservada em branco. 4884 4885 O esqueleto NÃO muda (capa â texto â play, mesma ordem, mesmos slots) â 4886 apenas as alturas reservadas das linhas vazias são liberadas e a 4887 tipografia é redistribuÃda. Ver o histórico em assets/css/style.css: 4888 o fallback antigo tirava a capa do fluxo e sangrava o texto. 4889 âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ */ 4890 4891 /* Linha sem conteúdo sai do fluxo â nada de 12/16px vazios entre os textos. 4892 Vale Sà no fallback; com metadados o esqueleto de altura fixa é mantido. */ 4893 #player.nmp-no-track .nmp-empty { 4894 display: none !important; 4895 } 4896 4897 /* Coluna de texto: bloco coeso, opticamente centrado com a capa de 48px. */ 4898 #player.nmp-no-track .neon-player__meta, 4899 #player.nmp-no-track .wave-player__meta, 4900 #player.nmp-no-track .pulse-player__meta, 4901 #player.nmp-no-track .glow-player__meta, 4902 #player.nmp-no-track .d5-player-meta, 4903 #player.nmp-no-track .player-meta, 4904 #player.nmp-no-track .nmp-meta-wrap { 4905 justify-content: center !important; 4906 gap: 0 !important; 4907 } 4908 4909 /* Selo "AO VIVO" â chip translúcido que ancora o topo do bloco. 4910 align-self: flex-start é obrigatório: sem ele o chip esticaria por toda a 4911 largura da coluna (align-items: stretch do flex) e o fundo viraria faixa. 4912 Cor derivada de --player-text-color â acompanha o painel de cores. */ 4913 #player.nmp-no-track [data-player-status] { 4914 display: inline-flex !important; 4915 align-items: center !important; 4916 gap: 5px !important; 4917 align-self: flex-start !important; 4918 width: auto !important; 4919 max-width: 100% !important; 4920 height: auto !important; 4921 flex: 0 0 auto !important; 4922 padding: 3px 8px 3px 7px !important; 4923 margin: 0 0 5px 0 !important; 4924 border-radius: 999px !important; 4925 background: rgba(255, 255, 255, 0.16) !important; 4926 background: color-mix(in srgb, var(--player-text-color, #ffffff) 18%, transparent) !important; 4927 color: var(--player-text-color, #ffffff) !important; 4928 font-size: 0 !important; /* silencia o texto dinâmico do player.js */ 4929 line-height: 1 !important; 4930 overflow: visible !important; 4931 } 4932 4933 #player.nmp-no-track [data-player-status]::before { 4934 content: "AO VIVO" !important; 4935 font-size: 9px !important; 4936 font-weight: 700 !important; 4937 letter-spacing: 0.1em !important; 4938 line-height: 1 !important; 4939 color: inherit !important; 4940 opacity: 1 !important; 4941 text-transform: uppercase !important; 4942 } 4943 4944 /* Ponto do "ao vivo" com pulso â order:-1 coloca o pseudo depois no código 4945 à ESQUERDA do texto, sem precisar de elemento extra no DOM. */ 4946 #player.nmp-no-track [data-player-status]::after { 4947 content: "" !important; 4948 order: -1 !important; 4949 width: 5px !important; 4950 height: 5px !important; 4951 flex: 0 0 5px !important; 4952 border-radius: 50% !important; 4953 background: currentColor !important; 4954 animation: nmp-live-pulse 1.9s ease-in-out infinite !important; 4955 } 4956 4957 /* Podcast/música sob demanda não é "ao vivo" â chip inteiro sai. */ 4958 #player.nmp-no-track [data-player-status][data-is-stream="false"] { 4959 display: none !important; 4960 } 4961
4962 @keyframes nmp-live-pulse { 4963 0%, 100% { opacity: 1; transform: scale(1); } 4964 50% { opacity: 0.45; transform: scale(0.8); } 4965 } 4966 4967 /* Nome da emissora â linha dominante do estado. Caixa natural (não força 4968 maiúsculas): respeita como o nome foi cadastrado no painel. */ 4969 #player.nmp-no-track #nmpDisplayTitle { 4970 font-size: 14px !important; 4971 font-weight: 700 !important; 4972 letter-spacing: 0 !important; 4973 text-transform: none !important; 4974 line-height: 17px !important; 4975 height: 17px !important; 4976 flex: 0 0 17px !important; 4977 margin: 0 !important; 4978 opacity: 1 !important; 4979 } 4980 4981 /* Praça em transmissão ("Você está ouvindo X") â linha de apoio, colada ao 4982 nome da emissora. Reaproveita o slot do artista, então herda o marquee 4983 quando o nome da praça não cabe. */ 4984 #player.nmp-no-track #nmpDisplayArtist { 4985 font-size: 11px !important; 4986 font-weight: 500 !important; 4987 letter-spacing: 0 !important; 4988 text-transform: none !important; 4989 line-height: 13px !important; 4990 height: 13px !important; 4991 flex: 0 0 13px !important; 4992 margin: 1px 0 0 0 !important; 4993 opacity: 0.72 !important; 4994 } 4995 4996 /* O elemento do seletor de praças vira redundante no fallback: seu texto já 4997 está na linha de apoio acima (com marquee). Só aqui â no desktop e no 4998 estado com metadados ele continua intacto. */ 4999 #player.nmp-no-track #agNowPlaying { 5000 display: none !important; 5001 } 5002 5003 /* Instalação sem nome de emissora configurado: a praça assume o papel de 5004 linha principal em vez de sobrar uma linha pequena e solta. */ 5005 #player.nmp-no-track.nmp-no-name #nmpDisplayArtist { 5006 font-size: 13px !important; 5007 font-weight: 600 !important; 5008 line-height: 16px !important; 5009 height: 16px !important; 5010 flex: 0 0 16px !important; 5011 margin: 0 !important; 5012 opacity: 0.92 !important; 5013 } 5014 5015 /* LÃGICA DO BOTÃO VOLTAR AO VIVO NO MOBILE (Quando toca Podcast) */ 5016 #player.is-playing-ext #zmpLiveBtn { 5017 display: flex !important; 5018 position: absolute !important; 5019 right: 12px !important; 5020 top: 50% !important; 5021 transform: translateY(-50%) !important; 5022 width: 40px !important; 5023 height: 40px !important; 5024 background: var(--color-primary) !important; 5025 border: 2px solid var(--border-color, transparent) !important; 5026 border-radius: 0 !important; /* Estilo Brutalista Quadrado */ 5027 color: var(--player-text-color, #ffffff) !important; 5028 align-items: center !important; 5029 justify-content: center !important; 5030 z-index: 99 !important; 5031 cursor: pointer !important; 5032 box-sizing: border-box !important; 5033 padding: 0 !important; 5034 } 5035 #player.is-playing-ext #zmpLiveBtn svg { 5036 width: 18px !important; 5037 height: 18px !important; 5038 margin: 0 !important; 5039 display: block !important; 5040 } 5041 #player.is-playing-ext .neon-player__info, 5042 #player.is-playing-ext .wave-player__info, 5043 #player.is-playing-ext .pulse-player__info, 5044 #player.is-playing-ext .glow-player__info { 5045 padding-right: 48px !important; /* Evitar que o texto fique debaixo do botão */ 5046 } 5047 5048 /* ---- ESTILO DO BOTÃO DE PLAY ---- */ 5049 #playBtn, .zmp-btn, .d5-play-btn, .neon-player__play-btn { 5050 background: transparent !important; 5051 border: none !important; 5052 box-shadow: none !important; 5053 width: auto !important; 5054 height: auto !important; 5055 padding: 0 !important; 5056 display: flex !important; 5057 align-items: center !important; 5058 justify-content: center !important; 5059 border-radius: 0 !important; 5060 transform: none !important; 5061 pointer-events: auto !important; 5062 cursor: pointer !important; 5063 z-index: 10 !important; 5064 } 5065 5066 #playBtn svg, .zmp-svg, .d5-play-btn i, .neon-player__play-btn svg { 5067 width: 28px !important; 5068 height: 28px !important; 5069 fill: var(--player-text-color, #ffffff) !important; 5070 color: var(--player-text-color, #ffffff) !important; 5071 filter: none !important; 5072 } 5073 5074 /* Outros widgets fixos de rodapé (WhatsApp / Video aberto) sobem para escapar da pÃlula */ 5075 .vmp-widget, #vmpWidget, #waWidget, .wa-widget { 5076 bottom: calc(145px + env(safe-area-inset-bottom)) !important; 5077 z-index: 9998 !important; 5078 } 5079 5080 /* Garantir que o player__inner não clippe os elementos filhos. 5081 O recorte final é do #player (overflow:hidden na pÃlula). */ 5082 .neon-player__inner, 5083 .wave-player__inner, 5084 .pulse-player__inner, 5085 .glow-player__inner { 5086 overflow: visible !important; 5087 } 5088} 5089</style> 5090 5091
5092<script src="https://cdnjs.cloudflare.com/ajax/libs/color-thief/2.3.0/color-thief.umd.js"></script>
vendor: 1 bytes, line 5092
5092
5093<script> 5094document.addEventListener('DOMContentLoaded', function () { 5095 const items = document.querySelectorAll('.mobile-bottom-nav .nav-item'); 5096 const currentPath = window.location.pathname; 5097 5098 items.forEach(item => { 5099 const href = item.getAttribute('href'); 5100 if (!href) return; 5101 5102 try { 5103 // Parse full URLs perfectly by using the current origin as base 5104 const urlObj = new URL(href, window.location.origin); 5105 const itemPath = urlObj.pathname; 5106 5107 // Match if exact path, or if current starts with itemPath (except for root '/') 5108 if (itemPath === currentPath || (currentPath.startsWith(itemPath) && itemPath !== '/')) { 5109 item.classList.add('active'); 5110 } 5111 } catch (e) { 5112 console.warn("Invalid Mobile Nav URL: ", href); 5113 } 5114 }); 5115 5116 // Special case: Ensure Home acts correctly when at exact root 5117 const homeItems = document.querySelectorAll('.mobile-bottom-nav .nav-item'); 5118 homeItems.forEach(item => { 5119 const href = item.getAttribute('href'); 5120 if (href) { 5121 try { 5122 const urlObj = new URL(href, window.location.origin); 5123 if (urlObj.pathname === '/' && currentPath === '/') { 5124 item.classList.add('active'); 5125 } else if (urlObj.pathname === '/') { 5126 item.classList.remove('active'); 5127 } 5128 } catch(e){} 5129 } 5130 }); 5131 5132 // ========================================= 5133 // LOGIC FOR EXPANDED PLAYER 5134 // ========================================= 5135 const miniPlayers = document.querySelectorAll('#player, .radio-player, .neon-player, .d5-player, .app-player, .player-container, .global-player'); 5136 const epCard = document.getElementById('expandedPlayerCard'); 5137 const epHandle = document.getElementById('epHandle'); 5138 const epPlayBtn = document.getElementById('epPlayBtn'); 5139 5140 // Synchronizing the UI 5141 let observerActivated = false; 5142 5143 // Waveform logic 5144 const epWaveform = document.getElementById('epWaveform'); 5145 const waveCtx = epWaveform ? epWaveform.getContext('2d') : null; 5146 let waveAnimId; 5147 let waveBars = []; 5148 const NUM_BARS = 18; 5149 const BAR_WIDTH = 3; 5150 const BAR_GAP = 3; 5151 let isPlayingAudio = false; 5152 5153 if (waveCtx) { 5154 for(let i=0; i<NUM_BARS; i++) { 5155 waveBars.push({ height: 2, phase: Math.random() * Math.PI * 2, speed: 0.05 + Math.random() * 0.06 }); 5156 } 5157 } 5158 5159 function renderWaveform() { 5160 if(!waveCtx) return; 5161 waveCtx.clearRect(0, 0, epWaveform.width, epWaveform.height); 5162 const isCardOpen = epCard && epCard.classList.contains('active'); 5163 let allSettled = true; 5164 const centerY = epWaveform.height; // Bars from bottom up 5165 5166 for(let i=0; i<NUM_BARS; i++) { 5167 const bar = waveBars[i]; 5168 let targetHeight = 2; // Idle state 5169 5170 if(isPlayingAudio && isCardOpen) { 5171 bar.phase += bar.speed; 5172 targetHeight = 4 + Math.abs(Math.sin(bar.phase)) * (epWaveform.height - 6); 5173 allSettled = false; 5174 } 5175 5176 bar.height += (targetHeight - bar.height) * 0.2; 5177 if(Math.abs(bar.height - targetHeight) > 0.5) { 5178 allSettled = false; 5179 } 5180 5181 const isLight = document.body.classList.contains('theme-light'); 5182 waveCtx.fillStyle = isLight ? 'rgba(26,23,48,0.7)' : 'rgba(255,255,255,0.7)'; 5183 const startX = (epWaveform.width / 2) - ((NUM_BARS * (BAR_WIDTH + BAR_GAP)) / 2) + i * (BAR_WIDTH + BAR_GAP); 5184 waveCtx.fillRect(startX, Math.max(0, centerY - bar.height), BAR_WIDTH, bar.height); 5185 } 5186 5187 if(!allSettled || (isPlayingAudio && isCardOpen)) { 5188 if (waveAnimId) cancelAnimationFrame(waveAnimId); 5189 waveAnimId = requestAnimationFrame(renderWaveform); 5190 } 5191 } 5192 5193 // Background ColorLogic 5194 const epBgLayer1 = document.getElementById('epBgLayer1'); 5195 const epBgLayer2 = document.getElementById('epBgLayer2'); 5196 let currentBgLayer = 1; 5197 let lastArtworkSrc = ''; 5198 let colorThief = null; 5199 try { colorThief = new ColorThief(); } catch(e) {} 5200 5201 function applyColors(imageUrl) { 5202 if (!colorThief || !imageUrl || imageUrl === lastArtworkSrc) return; 5203 lastArtworkSrc = imageUrl; 5204 5205 const img = new Image(); 5206 img.crossOrigin = 'Anonymous'; 5207 img.src = imageUrl; 5208 img.onload = () => { 5209 let palette = null; 5210 try { palette = colorThief.getPalette(img, 3); } catch(e) { return; } 5211 if(palette && palette.length >= 2) { 5212 const c1 = `rgb(${palette[0][0]}, ${palette[0][1]}, ${palette[0][2]})`; 5213 const c2 = `rgb(${palette[1][0]}, ${palette[1][1]}, ${palette[1][2]})`; 5214 const gradient = `linear-gradient(135deg, ${c1} 0%, ${c2} 100%)`; 5215 5216 if(currentBgLayer === 1 && epBgLayer2) { 5217 epBgLayer2.style.backgroundImage = gradient; 5218 epBgLayer2.style.opacity = '1'; 5219 if(epBgLayer1) epBgLayer1.style.opacity = '0'; 5220 currentBgLayer = 2; 5221 } else if (currentBgLayer === 2 && epBgLayer1) { 5222 epBgLayer1.style.backgroundImage = gradient; 5223 epBgLayer1.style.opacity = '1'; 5224 if(epBgLayer2) epBgLayer2.style.opacity = '0'; 5225 currentBgLayer = 1; 5226 } 5227 } 5228 }; 5229 } 5230 5231 window.syncAllPlayerUI = function() { 5232 const epTitle = document.getElementById('epTitle'); 5233 const epArtist = document.getElementById('epArtist'); 5234 const epArtworkImg = document.getElementById('epArtworkImg'); 5235 const epPlayIcon = document.getElementById('epPlayIcon'); 5236 5237 const pTitle = document.getElementById('playerTitle') || document.querySelector('.player-title'); 5238 const pArtist = document.getElementById('playerArtist') || document.querySelector('.player-artist'); 5239 const pArtwork = document.getElementById('playerArtwork') || document.querySelector('.player-artwork'); 5240 const pPlayIcon = document.getElementById('playIcon') || document.querySelector('.play-icon, #playBtn svg, .global-play-btn svg'); 5241 5242 const doSync = () => { 5243 if(pTitle && epTitle) epTitle.textContent = pTitle.textContent; 5244 if(pArtist && epArtist) epArtist.textContent = pArtist.textContent; 5245 5246 if(pArtwork && epArtworkImg) { 5247 const img = pArtwork.querySelector('img'); 5248 if(img && img.src) { 5249 epArtworkImg.removeAttribute('crossorigin'); 5250 epArtworkImg.src = img.src; 5251 applyColors(img.src); 5252 } else if (pArtwork.tagName === 'IMG') { 5253 epArtworkImg.removeAttribute('crossorigin'); 5254 epArtworkImg.src = pArtwork.src; 5255 applyColors(pArtwork.src); 5256 } 5257 } 5258 5259 let wasPlaying = isPlayingAudio; 5260 if(pPlayIcon && epPlayIcon) { 5261 const htmlStr = pPlayIcon.tagName.toLowerCase() === 'svg' ? pPlayIcon.outerHTML : pPlayIcon.innerHTML; 5262 // Remove inner IDs to avoid DOM conflicts 5263 const cleanHtmlStr = htmlStr.replace(/id="[^"]*"/g, ''); 5264 epPlayIcon.innerHTML = cleanHtmlStr; 5265 5266 if (htmlStr.includes('M7 ') || htmlStr.includes('M7,')) { 5267 isPlayingAudio = true; 5268 } else if (htmlStr.includes('M6 3.5') || htmlStr.includes('M6,')) { 5269 isPlayingAudio = false;
5270 } else { 5271 isPlayingAudio = window.radioPlayer && window.radioPlayer.state === 'transmitting'; 5272 } 5273 } 5274 if (wasPlaying !== isPlayingAudio) { 5275 renderWaveform(); 5276 } 5277 }; 5278 5279 doSync(); 5280 5281 if(!observerActivated) { 5282 observerActivated = true; 5283 const observer = new MutationObserver(() => doSync()); 5284 if(pTitle) observer.observe(pTitle, { childList: true, characterData: true, subtree: true }); 5285 if(pArtist) observer.observe(pArtist, { childList: true, characterData: true, subtree: true }); 5286 if(pArtwork) observer.observe(pArtwork, { childList: true, attributes: true, subtree: true, attributeFilter: ['src'] }); 5287 if(pPlayIcon) observer.observe(pPlayIcon, { childList: true, subtree: true, attributes: true }); 5288 } 5289 }; 5290 5291 // Listen to global changes from RadioPlayer 5292 document.addEventListener('radioPlayerStateChange', window.syncAllPlayerUI); 5293 5294 // Bind Open/Toggle actions explicitly 5295 miniPlayers.forEach(p => { 5296 p.addEventListener('click', (e) => { 5297 // Card expandido é exclusivo do mobile (inclui celular em paisagem) â ignorar em desktop/tablet 5298 if (!window.matchMedia('(max-width: 1024px), (pointer: coarse) and (max-width: 1366px)').matches) return; 5299 5300 const isPlayBtn = e.target.closest('#playBtn') || e.target.closest('.d5-play-btn') || 5301 e.target.closest('.neon-player__play-btn') || e.target.closest('.global-btn') || 5302 e.target.closest('.global-play') || e.target.closest('#volumeBtn') || 5303 e.target.closest('#zmpLiveBtn') || e.target.closest('#liveBtn') || 5304 e.target.closest('.zmp-volume-slider') || e.target.closest('.zmp-player-controls-wrapper') || 5305 e.target.closest('#btnAssistirAoVivo') || e.target.closest('.neon-player__video-btn-wrap'); 5306 5307 if (isPlayBtn) { 5308 e.stopPropagation(); 5309 return; 5310 } 5311 5312 if (epCard) { 5313 epCard.style.display = 'flex'; 5314 void epCard.offsetWidth; // Force Reflow 5315 epCard.classList.add('active'); 5316 document.body.style.overflow = 'hidden'; 5317 window.syncAllPlayerUI(); 5318 renderWaveform(); 5319 } 5320 }); 5321 }); 5322 5323 // Expanded Play Btn 5324 if(epPlayBtn) { 5325 epPlayBtn.addEventListener('click', (e) => { 5326 e.stopPropagation(); 5327 e.preventDefault(); 5328 if (window.radioPlayer && typeof window.radioPlayer.togglePlay === 'function') { 5329 window.radioPlayer.togglePlay(); 5330 } else { 5331 // Fallback 5332 const nativePlayBtn = document.getElementById('playBtn') || document.querySelector('.neon-player__play-btn, .d5-play-btn, .global-play'); 5333 if(nativePlayBtn) nativePlayBtn.click(); 5334 } 5335 setTimeout(window.syncAllPlayerUI, 50); 5336 }); 5337 } 5338 5339 // Swipe capabilities 5340 if(epCard && epHandle) { 5341 function closeExpandedPlayer() { 5342 epCard.classList.remove('active'); 5343 epCard.style.transform = ''; 5344 document.body.style.overflow = ''; 5345 renderWaveform(); // Jump start fade out 5346 setTimeout(() => { 5347 if(!epCard.classList.contains('active')) { 5348 epCard.style.display = 'none'; 5349 } 5350 }, 450); 5351 } 5352 5353 let startY = 0; 5354 let currentY = 0; 5355 let isDragging = false; 5356 5357 // Click to close 5358 epHandle.addEventListener('click', (e) => { 5359 e.stopPropagation(); 5360 closeExpandedPlayer(); 5361 }); 5362 epHandle.addEventListener('touchstart', (e) => { 5363 e.stopPropagation(); 5364 }, {passive: true}); 5365 epHandle.addEventListener('touchend', (e) => { 5366 e.stopPropagation(); 5367 e.preventDefault(); 5368 closeExpandedPlayer(); 5369 }, {passive: false}); 5370 5371 epCard.addEventListener('touchstart', (e) => { 5372 startY = e.touches[0].clientY; 5373 isDragging = true; 5374 epCard.style.transition = 'none'; 5375 }, {passive: true}); 5376 5377 epCard.addEventListener('touchmove', (e) => { 5378 if(!isDragging) return; 5379 currentY = e.touches[0].clientY; 5380 const diff = currentY - startY; 5381 if(diff > 0) { 5382 epCard.style.transform = `translateY(${diff}px)`; 5383 } 5384 }, {passive: true}); 5385 5386 epCard.addEventListener('touchend', (e) => { 5387 if(!isDragging) return; 5388 isDragging = false;
5389 const diff = currentY - startY; 5390 epCard.style.transition = 'transform 0.4s cubic-bezier(0.32, 0.72, 0, 1)'; 5391 5392 if(diff > 150) { 5393 closeExpandedPlayer(); 5394 } else { 5395 epCard.style.transform = ''; 5396 } 5397 }); 5398 } 5399 5400 5401 // ====================================================== 5402 // Filtro de Metadados + Marquee do mini player mobile 5403 // 5404 // ESQUELETO ÃNICO: a estrutura, a ordem e a distribuição são as mesmas em 5405 // todos os estados. Sem metadados, só o TEXTO muda â nada é removido do DOM 5406 // e nada troca de lugar. Por isso não existe mais bloco de fallback próprio. 5407 // CORREÃÃO: flag de reentrância para evitar loop infinito 5408 // ====================================================== 5409 (function initMetadataFilterAndMarquee() { 5410 if (!window.matchMedia('(max-width: 1024px), (pointer: coarse) and (max-width: 1366px)').matches) return; // Apenas mobile (inclui celular em paisagem) 5411 5412 // Palavras que indicam player em modo não-música. 'live' foi removido 5413 // para não bloquear podcasts como "Live Sessions" â 'ao vivo'/'aovivo' bastam. 5414 var BLOCKLIST = ['vinheta','trilha','break','off','locu\u00e7\u00e3o','locutor','intervalo','comercial','patroc\u00ednio','jingle','spot','ao vivo','aovivo']; 5415 var FALLBACK_NAME = "Nativa FM Bauru"; 5416 // Deploy em que o include roda fora do escopo de $siteName: cai na constante 5417 // que o head.php do tema publica, em vez de deixar a linha do nome vazia. 5418 if (!FALLBACK_NAME && typeof SITE_NAME !== 'undefined') FALLBACK_NAME = SITE_NAME || ''; 5419 5420 // O texto de "carregando" só faz sentido nos primeiros segundos. Passada a 5421 // carência, se ainda não chegou metadado, a linha de tÃtulo passa a exibir o 5422 // nome da emissora (configuração do tenant) em vez de mentir "carregando". 5423 var LOADING_GRACE_MS = 3000; 5424 var _startedAt = Date.now(); 5425 5426 // FLAG: evitar loop infinito (observer -> DOM change -> observer...) 5427 var _busy = false; 5428 5429 function isMusicMetadata(title, artist) { 5430 var str = (title + ' ' + artist).toLowerCase(); 5431 return !BLOCKLIST.some(function(w){ return str.indexOf(w) !== -1; }); 5432 } 5433 5434 // TÃtulo que não representa uma faixa: vazio ou placeholder de carregamento 5435 // já fora da janela de carência. 5436 function isPlaceholderTitle(title) { 5437 if (!title) return true; 5438 return /^carregando/i.test(title) && (Date.now() - _startedAt) > LOADING_GRACE_MS; 5439 } 5440 5441 // Cria elementos de EXIBIÃÃO dedicados para o marquee. 5442 // Os elementos originais (#playerTitle/#playerArtist) NÃO são tocados â 5443 // apenas ocultados. Assim o MutationObserver não entra em loop. 5444 function getOrCreateDisplayEl(sourceEl, displayId) { 5445 var existing = document.getElementById(displayId); 5446 if (existing) return existing; 5447 var d = document.createElement('div'); 5448 d.id = displayId; 5449 d.className = 'mini-player-text'; 5450 d.appendChild(document.createElement('span')); 5451 sourceEl.parentNode.insertBefore(d, sourceEl.nextSibling); 5452 return d; 5453 } 5454 5455 // Velocidade do marquee em px/s. Duração fixa fazia texto curto se arrastar 5456 // e texto longo passar voando; com velocidade constante a leitura tem sempre 5457 // o mesmo ritmo â só o tempo de volta muda. 5458 var MARQUEE_SPEED = 45; 5459 var MARQUEE_MIN_S = 8; 5460 var MARQUEE_MAX_S = 45; 5461 5462 // Monta uma "passada" do texto. `parts` é uma lista de trechos {text, cls} â 5463 // é o que permite música, separador e artista terem pesos diferentes dentro 5464 // da MESMA linha. wrapAsRun envolve tudo em .nmp-run (usado só no estado 5465 // rolando, onde existem duas cópias iguais). 5466 function buildRun(parts, wrapAsRun) { 5467 var frag = document.createDocumentFragment(); 5468 var host = frag; 5469 if (wrapAsRun) { 5470 host = document.createElement('i'); 5471 host.className = 'nmp-run'; 5472 frag.appendChild(host); 5473 } 5474 for (var i = 0; i < parts.length; i++) { 5475 var p = parts[i]; 5476 if (!p.text) continue; 5477 if (p.cls) { 5478 var s = document.createElement('span'); 5479 s.className = p.cls; 5480 s.textContent = p.text; // textContent: metadado do streaming não é markup 5481 host.appendChild(s); 5482 } else { 5483 host.appendChild(document.createTextNode(p.text)); 5484 } 5485 } 5486 return frag; 5487 } 5488 5489 // Ativa o marquee Sà quando o texto realmente estoura o container. 5490 // A medição é SÃNCRONA: ler clientWidth já força o cálculo de layout, então 5491 // não dependemos de requestAnimationFrame â que fica suspenso quando a aba 5492 // está em segundo plano. Era essa dependência (mais a medição num único 5493 // frame, quando o elemento ainda podia ter largura 0) que deixava tÃtulo 5494 // longo cortado sem nunca rolar. O retry usa setTimeout pelo mesmo motivo. 5495 function applyMarqueeOnDisplay(displayEl, parts) { 5496 if (!displayEl) return;
5497 var span = displayEl.querySelector('span'); 5498 if (!span) return; 5499 5500 span.classList.remove('scrolling'); 5501 span.style.animationDuration = ''; 5502 span.textContent = ''; 5503 span.appendChild(buildRun(parts, false)); 5504 5505 var tries = 0; 5506 function decide() { 5507 // Container ainda sem largura medÃvel (acabou de entrar no DOM, ou a 5508 // pÃlula ainda não foi posicionada) â tenta de novo em 100ms. 5509 if (displayEl.clientWidth === 0 && tries++ < 20) { 5510 setTimeout(decide, 100); 5511 return; 5512 } 5513 // Medir no CONTAINER, não no <span>: fora do estado de rolagem o span é 5514 // inline (para o ellipsis do pai funcionar) e inline não expõe scrollWidth. 5515 if (displayEl.scrollWidth <= displayEl.clientWidth + 1) return; // cabe: fica parado 5516 5517 // Duas cópias idênticas, cada uma com o intervalo embutido no próprio 5518 // padding â metade da largura total vira exatamente uma cópia, então o 5519 // translateX(-50%) emenda o fim no começo sem salto. 5520 span.textContent = ''; 5521 span.appendChild(buildRun(parts, true)); 5522 span.appendChild(buildRun(parts, true)); 5523 span.classList.add('scrolling'); 5524 5525 // A distância percorrida por ciclo é UMA cópia (texto + intervalo) â 5526 // é ela que define a duração, não a largura total do span. 5527 var run = span.querySelector('.nmp-run'); 5528 var dist = run ? run.offsetWidth : 0; 5529 if (dist > 0) { 5530 var secs = Math.min(MARQUEE_MAX_S, Math.max(MARQUEE_MIN_S, dist / MARQUEE_SPEED)); 5531 span.style.animationDuration = secs.toFixed(1) + 's'; 5532 } 5533 } 5534 decide(); 5535 } 5536 5537 // Texto da praça em transmissão ("Você está ouvindo X"), injetado pelo 5538 // seletor de praças (Modo Rede). No estado fallback ele passa a ser a linha 5539 // de apoio do bloco de texto â o elemento original é ocultado por CSS para 5540 // não duplicar a informação. Fora do Modo Rede o elemento não existe e o 5541 // fallback fica com duas linhas (selo + nome da emissora). 5542 function getCityLine() { 5543 var el = document.getElementById('agNowPlaying'); 5544 if (!el || el.style.display === 'none') return ''; 5545 return (el.textContent || '').trim(); 5546 } 5547 5548 // Localiza o bloco capa+texto em qualquer um dos quatro temas. 5549 function findInfoEl(playerEl, titleEl) { 5550 var themed = playerEl.querySelector( 5551 '.neon-player__info, .wave-player__info, .pulse-player__info, .glow-player__info' 5552 ); 5553 if (themed) return themed; 5554 return (titleEl.parentNode && titleEl.parentNode !== playerEl) ? titleEl.parentNode : null; 5555 } 5556 5557 function applyMetadataFilter() { 5558 if (_busy) return; // Evitar reentrada 5559 5560 var playerEl = document.getElementById('player') || 5561 document.querySelector('.neon-player, .radio-player'); 5562 if (!playerEl) return; 5563 5564 var titleEl = document.getElementById('playerTitle'); 5565 var artistEl = document.getElementById('playerArtist'); 5566 if (!titleEl || !artistEl) return; 5567 5568 var infoEl = findInfoEl(playerEl, titleEl); 5569 if (!infoEl) return; 5570 5571 var title = (titleEl.textContent || '').trim(); 5572 var artist = (artistEl.textContent || '').trim(); 5573 5574 // Sem faixa exibÃvel â ESTADO FALLBACK: a linha de tÃtulo recebe o nome 5575 // da emissora e a de apoio recebe a praça em transmissão. A classe 5576 // .nmp-no-track no player liga o design próprio desse estado (bloco de 5577 // texto compacto + selo "AO VIVO"); o esqueleto continua o mesmo. 5578 var hasTrack = !isPlaceholderTitle(title) && isMusicMetadata(title, artist); 5579 var showTitle = hasTrack ? title : FALLBACK_NAME; 5580 var showArtist = hasTrack ? artist : getCityLine(); 5581 5582 // COM FAIXA â LINHA ÃNICA "MÃSICA ⢠ARTISTA". 5583 // Duas linhas de ~150px espremiam os dois textos; em uma linha só o texto 5584 // tem o dobro da largura útil e o excedente rola em marquee. O slot do 5585 // artista continua no DOM, apenas vazio (.nmp-empty) â o esqueleto do 5586 // mini player não muda. Sem faixa, o fallback segue com as duas linhas 5587 // (nome da emissora + praça), cada uma com seu próprio marquee. 5588 var titleParts, artistParts; 5589 if (hasTrack) { 5590 titleParts = [{ text: showTitle, cls: 'nmp-track' }]; 5591 if (showArtist) { 5592 titleParts.push({ text: ' ⢠', cls: 'nmp-sep' }); 5593 titleParts.push({ text: showArtist, cls: 'nmp-artist' }); 5594 } 5595 artistParts = []; 5596 showArtist = ''; // o slot do artista fica vazio â sai do fluxo 5597 } else { 5598 titleParts = [{ text: showTitle }
5598]; 5599 artistParts = [{ text: showArtist }]; 5600 } 5601 5602 _busy = true; 5603 try { 5604 // Classes de estado no #player â não são observadas pelo 5605 // MutationObserver (que só olha o texto de title/artist), então não há 5606 // risco de reentrância aqui. 5607 playerEl.classList.toggle('nmp-no-track', !hasTrack); 5608 playerEl.classList.toggle('nmp-no-name', !hasTrack && !showTitle); 5609 playerEl.classList.toggle('nmp-one-line', hasTrack); 5610 5611 // O bloco capa+texto NUNCA é ocultado â o esqueleto é sempre o mesmo. 5612 infoEl.style.display = ''; 5613 5614 // Exibição dedicada para marquee (não toca nos originais observados) 5615 var displayTitle = getOrCreateDisplayEl(titleEl, 'nmpDisplayTitle'); 5616 var displayArtist = getOrCreateDisplayEl(artistEl, 'nmpDisplayArtist'); 5617 5618 applyMarqueeOnDisplay(displayTitle, titleParts); 5619 applyMarqueeOnDisplay(displayArtist, artistParts); 5620 5621 // Linha vazia é retirada do fluxo no fallback e na linha única (regras 5622 // CSS #player.nmp-no-track .nmp-empty / #player.nmp-one-line .nmp-empty) 5623 // â evita o vão vertical em branco entre o selo e o texto. 5624 displayTitle.classList.toggle('nmp-empty', !showTitle); 5625 displayArtist.classList.toggle('nmp-empty', !showArtist); 5626 5627 // Usa classe CSS com !important para sobrescrever regras de tema (ex: wave-player__title) 5628 titleEl.classList.add('nmp-src-hidden'); 5629 artistEl.classList.add('nmp-src-hidden'); 5630 displayTitle.classList.remove('nmp-src-hidden'); 5631 displayArtist.classList.remove('nmp-src-hidden'); 5632 displayTitle.style.display = ''; 5633 displayArtist.style.display = ''; 5634 } finally { 5635 _busy = false; 5636 } 5637 } 5638 5639 // ---------------------------------------------------------------- 5640 // Observer nos dois elementos originais. 5641 // CRITICAL: usar characterData:true + subtree:true para detectar 5642 // quando player.js faz `element.textContent = "..."` (muda text node) 5643 // O flag _busy já previne o loop de reintrância. 5644 // ---------------------------------------------------------------- 5645 var titleEl = document.getElementById('playerTitle'); 5646 var artistEl = document.getElementById('playerArtist'); 5647 var mo = new MutationObserver(function() { 5648 if (_busy) return; 5649 applyMetadataFilter(); 5650 }); 5651 var obsOpts = { childList: true, characterData: true, subtree: true }; 5652 if (titleEl) mo.observe(titleEl, obsOpts); 5653 if (artistEl) mo.observe(artistEl, obsOpts); 5654 5655 // Também acionar quando o próprio radioPlayer dispara changestate 5656 setTimeout(applyMetadataFilter, 800); 5657 // Passada extra ao fim da carência: troca "Carregando..." pelo nome da 5658 // emissora caso o streaming não tenha mandado metadado nenhum. 5659 setTimeout(applyMetadataFilter, LOADING_GRACE_MS + 200); 5660 document.addEventListener('radioPlayerStateChange', function() { 5661 if (_busy) return; 5662 // Pequeno delay para o DOM ja ter sido atualizado 5663 setTimeout(applyMetadataFilter, 50); 5664 }); 5665 5666 // Rotação de tela / mudança de largura muda a decisão do marquee. 5667 var _rzTimer; 5668 window.addEventListener('resize', function() { 5669 clearTimeout(_rzTimer); 5670 _rzTimer = setTimeout(applyMetadataFilter, 200); 5671 }); 5672 5673 // Expor para reavaliação externa (ex.: troca de praça no Modo Rede) 5674 window.checkMiniPlayerOverflow = applyMetadataFilter; 5675 })(); 5676 5677}); 5678</script>
5678 5679 5680<!-- EXPANDED MOBILE PLAYER CARD --> 5681<div class="expanded-player-card" id="expandedPlayerCard"> 5682 <div class="ep-bg-layer" id="epBgLayer1" style="opacity: 1;"></div> 5683 <div class="ep-bg-layer" id="epBgLayer2" style="opacity: 0;"></div> 5684 <div class="ep-bg-overlay"></div> 5685 <button class="ep-handle-btn" id="epHandle" aria-label="Minimize"> 5686 <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M6 9l6 6 6-6"/></svg> 5687 </button> 5688 <div class="ep-content"> 5689 <div class="ep-artwork has-image"> 5690 <img src="" alt="Album Art" id="epArtworkImg"> 5691 </div> 5692 <div class="ep-metadata"> 5693 <h2 class="ep-title" id="epTitle">...</h2> 5694 <p class="ep-artist" id="epArtist">...</p> 5695 <canvas id="epWaveform" class="ep-waveform" width="120" height="30"></canvas> 5696 </div> 5697 <div class="ep-controls"> 5698 <button class="ep-play-btn" id="epPlayBtn" aria-label="Play/Pause"> 5699 <div class="ep-play-icon" id="epPlayIcon"> 5700 <!-- Ãcone injetado dinamicamente --> 5701 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M6 3.5a1.5 1.5 0 0 1 2.3-.8l11.5 8a1.5 1.5 0 0 1 0 2.6l-11.5 8A1.5 1.5 0 0 1 6 20.5v-17z" fill="currentColor"/></svg> 5702 </div> 5703 </button> 5704 </div> 5705 </div> 5706</div> 5707 5708<style> 5709/* Oculto em Desktop, exibido em Mobile */ 5710.expanded-player-card { 5711 display: none; 5712} 5713 5714@media (max-width: 1024px), (pointer: coarse) and (max-width: 1366px) { 5715 .expanded-player-card { 5716 display: flex; 5717 flex-direction: column; 5718 position: fixed; 5719 bottom: calc(85px + env(safe-area-inset-bottom)); 5720 left: 12px; 5721 width: calc(100% - 24px); 5722 height: 60px; 5723 z-index: 99999; 5724 background-color: var(--neon-bg-deep, var(--bg-color, #121212)); 5725 color: var(--neon-text, var(--text-color, #ffffff)); 5726 border-radius: 12px; 5727 opacity: 0; 5728 pointer-events: none; 5729 transition: all 0.42s cubic-bezier(0.32, 0.72, 0, 1); 5730 overflow: hidden; 5731 box-sizing: border-box; 5732 } 5733 5734 .expanded-player-card.active { 5735 bottom: 0; 5736 left: 0; 5737 width: 100%; 5738 height: 100vh; 5739 height: 100dvh; 5740 border-radius: 0; 5741 opacity: 1; 5742 pointer-events: auto; 5743 } 5744 5745 .ep-bg-layer { 5746 position: absolute; 5747 top: 0; left: 0; right: 0; bottom: 0; 5748 z-index: 0; 5749 transition: opacity 1.5s ease; 5750 background-size: cover; 5751 background-position: center; 5752 background-image: linear-gradient(135deg, var(--neon-bg-deep, var(--bg-color, #121212)) 0%, rgba(0,0,0,0.9) 100%); 5753 } 5754 5755 body.theme-light .ep-bg-layer { 5756 background-image: linear-gradient(135deg, var(--neon-bg-deep, var(--bg-color, #f0eef5)) 0%, rgba(255,255,255,0.9) 100%); 5757 } 5758 5759 .ep-bg-overlay { 5760 position: absolute; 5761 top: 0; left: 0; right: 0; bottom: 0; 5762 z-index: 1; 5763 background: linear-gradient(to bottom, rgba(0,0,0,0.4) 0%, var(--neon-bg-deep, var(--bg-color, #121212)) 100%); 5764 pointer-events: none; 5765 } 5766 5767 body.theme-light .ep-bg-overlay { 5768 background: linear-gradient(to bottom, rgba(255,255,255,0.2) 0%, var(--neon-bg-deep, var(--bg-color, #f0eef5)) 100%); 5769 } 5770 5771 .ep-handle-btn { 5772 position: absolute; 5773 top: calc(16px + env(safe-area-inset-top)); 5774 left: 16px; 5775 width: 44px; 5776 height: 44px; 5777 border-radius: 50%; 5778 background-color: var(--glass-border, rgba(255,255,255,0.1)); 5779 border: none; 5780 display: flex; 5781 justify-content: center; 5782 align-items: center; 5783 cursor: pointer; 5784 color: var(--neon-text, var(--text-color, #fff)); 5785 transition: transform 0.1s, background-color 0.2s; 5786 z-index: 99; 5787 padding: 0; 5788 pointer-events: auto; 5789 } 5790 5791 .ep-handle-btn:active { 5792 transform: scale(0.9); 5793 background-color: var(--neon-surface-hover, rgba(255,255,255,0.2)); 5794 } 5795 5796 .ep-content { 5797 flex: 1; 5798 display: flex; 5799 flex-direction: column; 5800 align-items: center; 5801 justify-content: center; 5802 width: 100%; 5803 padding: 0 24px; 5804 box-sizing: border-box; 5805 opacity: 0; 5806 transition: opacity 0.2s ease; 5807 position: relative; 5808 z-index: 2; 5809 } 5810 .expanded-player-card.active .ep-content { 5811 opacity: 1; 5812 transition-delay: 0.15s; 5813 } 5814 5815 .ep-artwork { 5816 width: 85%; 5817 aspect-ratio: 1 / 1; 5818 border-radius: 16px; 5819 background-color: var(--glass-border, rgba(255,255,255,0.1)); 5820 box-shadow: var(--shadow-lg, 0 16px 40px rgba(0,0,0,0.5)); 5821 margin-bottom: 6vh; 5822 overflow: hidden; 5823 display: flex; 5824 align-items: center; 5825 justify-content: center; 5826 } 5827 5828 .ep-artwork img { 5829 width: 100%; 5830 height: 100%; 5831 object-fit: cover; 5832 } 5833 5834 .ep-metadata { 5835 width: 100%; 5836 text-align: center; 5837 margin-bottom: 6vh; 5838 } 5839 5840 .ep-title { 5841 font-family: var(--font-primary, sans-serif); 5842 font-size: 24px; 5843 font-weight: 700; 5844 margin: 0 0 8px 0; 5845 white-space: nowrap; 5846 overflow: hidden; 5847 text-overflow: ellipsis; 5848 color: var(--neon-text, var(--primary-color, var(--text-color, #fff))); 5849 } 5850 5851 .ep-artist { 5852 font-family: var(--font-secondary, var(--font-primary, sans-serif)); 5853 font-size: 16px; 5854 font-weight: 400; 5855 margin: 0; 5856 color: var(--neon-text-muted, var(--text-color, #ccc)); 5857 opacity: 0.8; 5858 white-space: nowrap; 5859 overflow: hidden; 5860 text-overflow: ellipsis; 5861 } 5862 5863 .ep-waveform { 5864 display: block; 5865 margin: 16px auto 0 auto; 5866 opacity: 0.8; 5867 } 5868 5869 .ep-controls { 5870 width: 100%; 5871 display: flex; 5872 justify-content: center; 5873 align-items: center; 5874 } 5875 5876 .ep-play-btn { 5877 width: 72px; 5878 height: 72px; 5879 border-radius: 50%; 5880 background-color: var(--primary-color, #1B1464); 5881 border: none; 5882 display: flex; 5883 justify-content: center; 5884 align-items: center; 5885 cursor: pointer; 5886 padding: 0; 5887 box-shadow: 0 8px 16px rgba(0,0,0,0.2); 5888 transition: transform 0.2s, background-color 0.2s; 5889 color: #ffffff !important; 5890 } 5891 5892 .ep-play-btn:active { 5893 transform: scale(0.95); 5894 } 5895 5896 .ep-play-icon { 5897 width: 28px; 5898 height: 28px; 5899 display: flex; 5900 justify-content: center; 5901 align-items: center; 5902 } 5903 .ep-play-icon svg { 5904 width: 100%; 5905 height: 100%; 5906 color: #ffffff; 5907 fill: currentColor; 5908 } 5909} 5910</style> 5911 5912 <!-- Barra de Status de Conexão Global (Apenas Mobile via CSS) --> 5913 5914<div id="connectionStatusBar" role="alert" aria-live="assertive" aria-atomic="true"> 5915 <span id="connectionStatusIcon"></span> 5916 <span id="connectionStatusMsg"></span> 5917</div> 5918 5919<style> 5920/* Oculto em desktop */ 5921#connectionStatusBar { 5922 display: none; 5923} 5924 5925@media (max-width: 768px) { 5926 #connectionStatusBar { 5927 position: fixed; 5928 top: calc(env(safe-area-inset-top) + 12px); 5929 left: 16px; 5930 right: 16px; 5931 z-index: 100000; 5932 display: flex; 5933 align-items: center; 5934 gap: 10px; 5935 padding: 12px 20px; 5936 border-radius: 50px; 5937 color: #ffffff; 5938 font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; 5939 font-size: 14px; 5940 font-weight: 500; 5941 line-height: 1.3; 5942 box-sizing: border-box; 5943 box-shadow: 0 4px 16px rgba(0, 0, 0, 0.35); 5944 /* Estado padrão: acima da viewport com fade */ 5945 transform: translateY(-80px); 5946 opacity: 0; 5947 pointer-events: none; 5948 transition: transform 0.3s cubic-bezier(0.32, 0.72, 0, 1), 5949 opacity 0.3s ease, 5950 background-color 0.25s ease; 5951 will-change: transform, opacity; 5952 } 5953 5954 #connectionStatusBar.is-visible { 5955 transform: translateY(0); 5956 opacity: 1; 5957 pointer-events: auto; 5958 } 5959 5960 #connectionStatusBar.state-offline { 5961 background-color: #111111; 5962 } 5963 5964 #connectionStatusBar.state-online { 5965 background-color: #2e7d32; 5966 } 5967 5968 #connectionStatusIcon { 5969 flex-shrink: 0;
5970 width: 20px; 5971 height: 20px; 5972 display: flex; 5973 align-items: center; 5974 justify-content: center; 5975 } 5976 5977 #connectionStatusIcon svg { 5978 width: 20px; 5979 height: 20px; 5980 display: block; 5981 } 5982 5983 #connectionStatusMsg { 5984 flex: 1; 5985 min-width: 0; 5986 white-space: nowrap; 5987 overflow: hidden; 5988 text-overflow: ellipsis; 5989 } 5990} 5991</style> 5992
5993<script> 5994(function () { 5995 /* Ãcone Wi-Fi com X â estilo Happn */ 5996 var ICON_OFFLINE = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="#ffffff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M1 6C4.27 3.47 8.46 2 12 2s7.73 1.47 11 4"/><path d="M5 10a10.16 10.16 0 0 1 7-2.82A10.16 10.16 0 0 1 19 10"/><path d="M8.53 14A5.14 5.14 0 0 1 12 12.85"/><line x1="15" y1="15" x2="21" y2="21"/><line x1="21" y1="15" x2="15" y2="21"/></svg>'; 5997 var ICON_ONLINE = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="#ffffff" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/><polyline points="22 4 12 14.01 9 11.01"/></svg>'; 5998 5999 var bar = document.getElementById('connectionStatusBar'); 6000 var iconEl = document.getElementById('connectionStatusIcon'); 6001 var msgEl = document.getElementById('connectionStatusMsg'); 6002 var dismissTimer = null; 6003 6004 function showBar(type) { 6005 if (!bar) return; 6006 6007 if (dismissTimer) { 6008 clearTimeout(dismissTimer); 6009 dismissTimer = null; 6010 } 6011 6012 // Remove estados anteriores e força reflow para reiniciar a transição 6013 bar.classList.remove('state-offline', 'state-online', 'is-visible'); 6014 void bar.offsetWidth; 6015 6016 if (type === 'offline') { 6017 iconEl.innerHTML = ICON_OFFLINE; 6018 msgEl.textContent = 'Sem conexão à internet'; 6019 bar.classList.add('state-offline', 'is-visible'); 6020 6021 // Vibração háptica â iOS não suporta navigator.vibrate 6022 if (navigator.vibrate) { 6023 navigator.vibrate([200, 100, 200]); 6024 } 6025 } else { 6026 iconEl.innerHTML = ICON_ONLINE; 6027 msgEl.textContent = 'Conexão restabelecida'; 6028 bar.classList.add('state-online', 'is-visible'); 6029 6030 dismissTimer = setTimeout(function () { 6031 bar.classList.remove('is-visible'); 6032 dismissTimer = null; 6033 }, 3000); 6034 } 6035 } 6036 6037 window.addEventListener('offline', function () { showBar('offline'); }); 6038 window.addEventListener('online', function () { showBar('online'); }); 6039})(); 6040</script>
6040 6041 6042 <!-- Audio Player Script â não carregado dentro do app Rádio 3.0: sem o markup 6043 do player ele quebraria no bindEvents, e lá o site não deve tocar áudio nem 6044 disputar a Media Session com o player nativo. Quem usa window.radioPlayer 6045 já confere se ele existe. --> 6046
6046<script src="https://nativafmbauru.com.br/assets/js/player.js?v=1790900781"></script>
6046 6047
6047<script src="https://nativafmbauru.com.br/assets/js/app.js?v=1790900781" defer></script>
6047 6048 6049 <!-- PWA Service Worker Registration --> 6050
6050<script src="https://nativafmbauru.com.br/sw-init.js" defer></script>
6050 6051 6052 <!-- Analytics Tracker --> 6053
6053<script src="https://nativafmbauru.com.br/assets/js/tracker.js" defer></script>
6053 6054 6055 <!-- Top Músicas: tÃtulo/artista que não cabe no card desliza em vez de cortar --> 6056
6056<script src="https://nativafmbauru.com.br/assets/js/chart-marquee.js?v=1790785599" defer></script>
6056 6057 6058 <!-- Banner Tracking (impressões e cliques) --> 6059 <!-- Não redeclarar: o head.php do tema já define `const SITE_URL`. Usar 6060 window.SITE_URL evita "Identifier 'SITE_URL' has already been declared" 6061 (que quebrava o tracking de banner e scripts seguintes). --> 6062
6062<script>window.SITE_URL = window.SITE_URL || 'https://nativafmbauru.com.br';</script>
6062 6063
6063<script>const ACTIVE_CITY_ID = null;</script>
6063 6064
6064<script src="https://nativafmbauru.com.br/assets/js/banner-tracking.js?v=1784297539" defer></script>
6064 6065 6066 6067 <!-- JSON-LD para SEO --> 6068
6068<script type="application/ld+json"> 6069 { 6070 "@context": "https://schema.org", 6071 "@type": "RadioStation", 6072 "name": "Nativa FM Bauru", 6073 "url": "https://nativafmbauru.com.br", 6074 "logo": "https://nativafmbauru.com.br/uploads/media/6a18a5b4f2efe_1780000180.webp", 6075 "description": "A Nativa é tudo e muito mais!" 6076 } 6077 </script>
6077 6078 6079 <!-- Código Personalizado â fim do <body> (raw, escopo do tenant) --> 6080
6080<script type="module" src="https://static.cloudflareinsights.com/beacon.min.js/v31edd6df95cf4e85bb4c19e7a9bdbcba1788362987495" integrity="sha512-iIg7k2xntmwu6/uSb5tpc/hySgZc4eoL31yB29W6tJFo2akwjPWcEqnCEdJvGexCL0KEQwVYv5BlowfhVz26hg==" data-cf-beacon='{"version":"2024.11.0","token":"04e69c4ac2a5417fa45cc4543cb77976","r":1,"spa":2}' crossorigin="anonymous"></script>
6080 6081</body> 6082</html>
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.