<!DOCTYPE html>
<html lang="pt-BR">

<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
  <!-- iPad/iOS PWA — Add to Home Screen -->
  <meta name="mobile-web-app-capable" content="yes" />
  <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
  <meta name="apple-mobile-web-app-title" content="" />
  <link rel="apple-touch-icon" sizes="180x180" id="apple-touch-icon" href="" />
  <title></title>
  <meta name="description" content="" />
  <!-- Bing Webmaster Tools Verification -->
  <meta name="msvalidate.01" content="FAC6C6E589657C67185F34C3CE938388" />
  <link id="favicon" rel="icon" type="image/png" href="" />
  <!-- Preconnect — kept under 4 (PSI guideline). Only origins on the critical path. -->
  <!-- api.cattive.com handles 100% of data + storage requests on every page. -->
  <link rel="preconnect" href="https://api.cattive.com" crossorigin />
  <link rel="preconnect" href="https://iefppahyskbnsaogvzem.supabase.co" crossorigin />
  <!-- AgoraTicker external APIs (inmet, open-meteo, espn, brasilapi) were
       previously dns-prefetched. Removed: AgoraBar mounts via
       requestIdleCallback well after FCP, so the DNS lookup happens then
       anyway. Six dns-prefetch entries also exceeded PSI's budget. -->
  <link rel="dns-prefetch" href="https://www.googletagmanager.com" />
  <link rel="dns-prefetch" href="https://www.google-analytics.com" />
  <!-- Self-hosted Inter Variable (latin subset, ~47KB woff2) — inline @font-face +
       preload means the font request fires immediately (parallel with CSS bundle)
       and the swap is non-blocking. Previous `@fontsource-variable/inter` import
       moved the @font-face into the render-blocking CSS chunk (PSI: FCP +600ms). -->
  <link rel="preload" href="/fonts/inter-variable-latin.woff2" as="font" type="font/woff2" crossorigin />
  <style>
    @font-face{
      font-family:'Inter';
      font-style:normal;
      font-weight:100 900;
      font-display:swap;
      src:url(/fonts/inter-variable-latin.woff2) format('woff2-variations');
      unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
    }
  </style>
  <!-- Speculation Rules API — Chrome 121+ pre-renders article-page links when
       the user hovers or scrolls near them. Navigation to an article from the
       home becomes instant (page already rendered in background). W3C spec,
       Google-promoted — NOT cloaking. Eagerness "moderate" balances
       prefetch cost vs hit rate. -->
  <script type="speculationrules">
    {
      "prerender": [{
        "where": {
          "and": [
            { "href_matches": "/noticias/*" },
            { "not": { "href_matches": "/*/admin/*" } }
          ]
        },
        "eagerness": "moderate"
      }]
    }
  </script>

  <!-- AI Discoverability & Agent-Ready -->
  <link rel="manifest" href="/.well-known/ai-plugin.json" />
  <link rel="author" href="/llms.txt" type="text/plain" />
  <link rel="api-catalog" href="/.well-known/api-catalog" type="application/linkset+json" />
  <link rel="service-desc" href="/openapi.yaml" type="application/yaml" />
  <link rel="alternate" type="application/rss+xml" title="RSS Feed" href="/feed.xml" />
  
  <script>
    // Set title, description & favicon BEFORE React boots to prevent flash.
    // Registry mirrors SITE_REGISTRY in src/utils/resolvePortalIdentity.ts.
    // To add a new portal: add ONE entry here AND in resolvePortalIdentity.ts
    // AND in netlify/edge-functions/_shared/strip-inline-registry.ts.
    //
    // ⚠️  PRIVACY / CROSS-TENANT INFO DISCLOSURE
    // In production, the Netlify edge function `seo-meta-injection.ts`
    // rewrites the inline portals registry array below to contain ONLY the
    // matching entry for the request hostname (same for the GA registry).
    // Without that strip, view-source on every apex exposes the full
    // tenant list — fixed in PR addressing 2026-05-17 disclosure report.
    // Localhost/dev keeps the full array (no edge function runs locally).
    // Tests: netlify/edge-functions/_shared/__tests__/strip-inline-registry.test.ts
    //
    // 🚨 Do NOT write the literal token "var sites = [" or "var gaRegistry = {"
    // anywhere except the real declarations below. The edge regex is anchored
    // to line start (^\s*) for defense in depth, but it's still safer to
    // avoid the literals in comments to prevent any future bypass risk.
    (function () {
      var h = location.hostname;
      var p = location.pathname;
      var isLocal = h === 'localhost' || h === '127.0.0.1' || h.indexOf('192.168.') === 0;

      // Registry: [domainMatch[], localPaths[], title, description, favicon, shortName]
      // P9: publicidade-legal.* MUST come FIRST so substring match
      // (`hostname.indexOf(...) !== -1`) catches it before the parent
      // tenant entries (e.g. `jornaldebarueri`). Without this, a hit on
      // `publicidade-legal.jornaldebarueri.com.br` would set the title
      // to "Jornal de Barueri" instead of "Publicidade Legal".
      var sites = [
        [['publicidade-legal.'], ['/publicidade-legal'], 'Publicidade Legal', 'Documentos legais oficiais com certificação digital ICP-Brasil e validade jurídica.', 'https://api.cattive.com/storage/v1/object/public/portal-assets/publegal/favicon.png', 'Publ. Legal'],
        [['cattive.com','cattive.me'], ['/cattive','/login'], 'Cattive', 'Plataforma AI-First para Portais de Notícias', 'https://api.cattive.com/storage/v1/object/public/portal-assets/cattive/favicon.png', 'Cattive'],
        [['publicidade.legal','publicidadelegalbrasil'], ['/publicidade-legal'], 'Publicidade.Legal', 'Homologação Oficial de Publicidade Legal e Atos Societários.', 'https://api.cattive.com/storage/v1/object/public/portal-assets/publegal/favicon.png', 'Pub. Legal'],
        [['jornaldebarueri'], ['/jb'], 'Jornal de Barueri', 'Portal de Notícias de Barueri e região.', 'https://api.cattive.com/storage/v1/object/public/portal-assets/jb/icon.png', 'JB'],
        [['allphaville'], ['/alphaville'], 'Allphaville', 'Portal de Notícias de Alphaville e região.', 'https://api.cattive.com/storage/v1/object/public/portal-assets/cattive/favicon.png', 'Allphaville'],
        [['nossasp'], ['/sp'], 'Nossa SP', 'Portal de Notícias de São Paulo e região.', '/favicon-sp.ico', 'Nossa SP'],
        [['vivaamericana'], ['/americana'], 'Viva Americana', 'Portal de Notícias de Americana e região.', 'https://api.cattive.com/storage/v1/object/public/portal-assets/cattive/favicon.png', 'Americana'],
        [['cbnamazonia'], ['/cbn-amazonia'], 'CBN Amazônia', 'CBN Amazônia - Seu portal regional de notícias com credibilidade.', 'https://api.cattive.com/storage/v1/object/public/portal-assets/cattive/favicon.png', 'CBN Amazônia'],
        [['portalamazonia'], ['/portal-amazonia'], 'Portal Amazônia', 'Portal de Notícias da Amazônia.', 'https://api.cattive.com/storage/v1/object/public/portal-assets/cattive/favicon.png', 'P. Amazônia'],
        [['amanha.com'], ['/grupo-amanha'], 'Grupo Amanhã', 'Portal do Grupo Amanhã.', 'https://api.cattive.com/storage/v1/object/public/portal-assets/cattive/favicon.png', 'Amanhã'],
      ];

      // System routes (admin, console) — use Cattive branding
      var systemPaths = ['/admin', '/console'];

      var matched = null;

      // 1. Production: match by domain
      if (!isLocal) {
        for (var i = 0; i < sites.length; i++) {
          for (var d = 0; d < sites[i][0].length; d++) {
            if (h.indexOf(sites[i][0][d]) !== -1) { matched = sites[i]; break; }
          }
          if (matched) break;
        }
      } else {
        // 2. Localhost: match by path prefix
        for (var i = 0; i < sites.length; i++) {
          for (var lp = 0; lp < sites[i][1].length; lp++) {
            if (p === sites[i][1][lp] || p.indexOf(sites[i][1][lp] + '/') === 0) { matched = sites[i]; break; }
          }
          if (matched) break;
        }
        // 3. Localhost system routes → Cattive branding
        if (!matched) {
          for (var s = 0; s < systemPaths.length; s++) {
            if (p.indexOf(systemPaths[s]) === 0) {
              matched = [[], [], 'Cattive Platform', 'Cattive Platform', 'https://api.cattive.com/storage/v1/object/public/portal-assets/cattive/favicon.png', 'Cattive'];
              break;
            }
          }
        }
      }

      // 4. Fallback: localhost root → Cattive Platform, production unknown → JB
      if (!matched) {
        matched = isLocal
          ? [[], [], 'Cattive Platform', 'Cattive Platform — Ambiente de Desenvolvimento Local', 'https://api.cattive.com/storage/v1/object/public/portal-assets/cattive/favicon.png', 'Cattive']
          : [[], [], 'Cattive', 'Plataforma AI-First para Portais de Notícias', 'https://api.cattive.com/storage/v1/object/public/portal-assets/cattive/favicon.png', 'Cattive'];
      }

      // Apply
      var appleTitle = document.querySelector('meta[name="apple-mobile-web-app-title"]');
      var appleTouchIcon = document.getElementById('apple-touch-icon');
      document.title = matched[2];
      document.querySelector('meta[name="description"]').content = matched[3];
      document.getElementById('favicon').href = matched[4];
      if (appleTitle) appleTitle.content = matched[5];
      if (appleTouchIcon) appleTouchIcon.href = matched[4];

      // ── Google Analytics Boot (with Consent Mode v2) ──
      // GA loads synchronously for Google's verification bot to detect.
      // Consent Mode v2 ensures NO data is collected until user accepts cookies.
      // Multi-tenant: Each portal can have its own GA measurement ID.
      // Admin/console subdomains are always excluded.
      (function() {
        var gaRegistry = {
          'jornaldebarueri': 'G-CCYGRP3XJ3'
          // Add other portals here: 'cbnamazonia': 'G-XXXXXXXXXX'
        };

        // Skip admin/console/auth subdomains
        var sub = h.split('.')[0];
        if (sub === 'admin' || sub === 'console' || sub === 'auth' || sub === 'myaccount') return;

        // Skip localhost
        if (isLocal) return;

        // Find matching GA ID by domain
        var gaId = null;
        for (var key in gaRegistry) {
          if (h.indexOf(key) !== -1) { gaId = gaRegistry[key]; break; }
        }
        if (!gaId) return;

        // Initialize gtag
        window.dataLayer = window.dataLayer || [];
        window.gtag = function() { window.dataLayer.push(arguments); };

        // ── Consent Mode v2 (LGPD-307: opt-in) ──
        // Analytics defaults to DENIED until the user explicitly accepts via
        // PortalCookieBanner → "Aceitar todos". This is the conservative LGPD
        // posture aligned with Art. 8 (specific consent for non-essential
        // tracking). Previously this was opt-out; flipped to opt-in by LGPD-307.
        var priorConsent = null;
        try { priorConsent = localStorage.getItem('portal_cookie_consent'); } catch(e) {}
        var userExplicitlyAccepted = priorConsent === 'all';

        // Set consent defaults BEFORE config (required by Google)
        window.gtag('consent', 'default', {
          analytics_storage: userExplicitlyAccepted ? 'granted' : 'denied',
          ad_storage: userExplicitlyAccepted ? 'granted' : 'denied',
          ad_user_data: userExplicitlyAccepted ? 'granted' : 'denied',
          ad_personalization: userExplicitlyAccepted ? 'granted' : 'denied',
          functionality_storage: userExplicitlyAccepted ? 'granted' : 'denied',
          personalization_storage: userExplicitlyAccepted ? 'granted' : 'denied',
          url_passthrough: true
        });

        window.gtag('js', new Date());
        window.gtag('config', gaId, { send_page_view: userExplicitlyAccepted });

        // Mark as injected for the React hook to detect
        window.__GA_MEASUREMENT_ID = gaId;
        window.__GA_CONSENT_GRANTED = userExplicitlyAccepted;

        var s = document.createElement('script');
        s.async = true;
        s.src = 'https://www.googletagmanager.com/gtag/js?id=' + gaId;
        document.head.appendChild(s);
      })();

      // Generate dynamic Web Manifest for PWA
      var isAdminPage = location.hostname.startsWith('admin.') || location.hostname.startsWith('console.') || location.pathname.startsWith('/admin') || location.pathname.startsWith('/console');
      // Flash subdomain (`flash.<tenant>`) installs as its own PWA with the
      // Flash branding so users see "Flash" on the home screen, not the
      // generic portal name.
      var isFlashSubdomain = location.hostname.startsWith('flash.');
      var portalDisplayName = matched[2];
      var manifestName = isFlashSubdomain ? ('Flash · ' + portalDisplayName) : document.title;
      var manifestShortName = isFlashSubdomain ? 'Flash' : (appleTitle ? appleTitle.content : document.title);
      var manifestDescription = isFlashSubdomain
        ? ('Notícias em tela cheia do ' + portalDisplayName + ': clima, trânsito, cinema, eventos e mais.')
        : document.querySelector('meta[name="description"]').content;
      var logoSrc = document.getElementById('favicon').href;
      var manifest = {
        name: manifestName,
        short_name: manifestShortName,
        description: manifestDescription,
        start_url: isAdminPage ? "/admin" : "/",
        display: "standalone",
        background_color: isFlashSubdomain ? "#000000" : "#ffffff",
        theme_color: isFlashSubdomain
          ? "#000000"
          : (matched[2] === 'Cattive' || matched[2] === 'Cattive Platform') ? "#0f172a"
            : matched[2] === 'Publicidade.Legal' ? "#1e293b"
              : "#2563eb",
        icons: [
          {
            src: logoSrc,
            sizes: "192x192",
            type: "image/png",
            purpose: "any maskable"
          },
          {
            src: logoSrc,
            sizes: "512x512",
            type: "image/png",
            purpose: "any maskable"
          }
        ]
      };

      // Web Share Target API for Admin
      if (isAdminPage) {
        manifest.shortcuts = [
          { name: "Novo Artigo", short_name: "Artigo", url: "/admin/posts/new", icons: [{ src: logoSrc, sizes: "192x192" }] },
          { name: "Nova Imagem (DAM)", short_name: "Mídia", url: "/admin/media", icons: [{ src: logoSrc, sizes: "192x192" }] }
        ];

        manifest.share_target = {
          action: "/admin/media",
          method: "POST",
          enctype: "multipart/form-data",
          params: {
            title: "title",
            text: "text",
            url: "url",
            files: [
              {
                name: "file",
                accept: ["image/jpeg", "image/png", "image/webp", "video/mp4"]
              }
            ]
          }
        };
      }

      // Encode manifest as Data URI to avoid CORS and Blob destruction issues
      var manifestJson = encodeURIComponent(JSON.stringify(manifest));
      var link = document.createElement('link');
      link.rel = 'manifest';
      link.href = 'data:application/manifest+json;charset=utf-8,' + manifestJson;
      document.head.appendChild(link);
    })();
  </script>
  <script type="module" crossorigin src="/assets/index-B8XTF3z6.js"></script>
  <link rel="stylesheet" crossorigin href="/assets/index-dJrRDRDM.css">
</head>

<body class="bg-slate-50 text-slate-900 antialiased selection:bg-blue-100 selection:text-blue-900">
  <!-- #A11 — Skip Navigation Link
       Inline style removed: Tailwind `sr-only` already hides the link until focused,
       and the inline style was overriding `focus:not-sr-only` (PSI: "skip link not focusable"). -->
  <a href="#main-content" class="sr-only focus:not-sr-only focus:fixed focus:top-2 focus:left-2 focus:z-[9999] focus:bg-blue-600 focus:text-white focus:px-4 focus:py-2 focus:rounded-lg focus:text-sm focus:font-medium focus:shadow-lg">Pular para o conteúdo</a>
  <div id="global-admin-preloader-container"></div>
  <div id="root"></div>
  <!-- Crawler / no-JS fallback.
       Bots that don't execute JS (or pause before React mounts) used to see
       "JavaScript Required" here and surface it as the page description in
       Google Alerts / WhatsApp / FB previews. We now render a semantic
       fallback that mirrors the page <title> and <meta description>
       (populated either by the inline boot script above or by the
       seo-meta-injection edge function). Discoverability links point
       crawlers to the structured feeds. The whole block is hidden when JS
       runs (React replaces #root), so end users never see it.
       —2026-05-18 SEO incident fix. -->
  <noscript>
    <article style="max-width:720px;margin:60px auto;padding:24px;font-family:system-ui,-apple-system,Segoe UI,Roboto,sans-serif;line-height:1.5;color:#0f172a">
      <h1 id="ns-title" style="font-size:32px;font-weight:700;margin:0 0 12px;line-height:1.2"></h1>
      <p id="ns-desc" style="font-size:18px;margin:0 0 24px;color:#475569"></p>
      <nav aria-label="Recursos para crawlers">
        <h2 style="font-size:14px;font-weight:600;text-transform:uppercase;letter-spacing:.05em;color:#64748b;margin:0 0 8px">Recursos</h2>
        <ul style="list-style:none;padding:0;margin:0;display:flex;flex-wrap:wrap;gap:12px">
          <li><a href="/feed.xml" style="color:#2563eb;text-decoration:underline">RSS Feed</a></li>
          <li><a href="/sitemap.xml" style="color:#2563eb;text-decoration:underline">Mapa do site</a></li>
          <li><a href="/llms.txt" style="color:#2563eb;text-decoration:underline">AI agents (llms.txt)</a></li>
          <li><a href="/noticias" style="color:#2563eb;text-decoration:underline">Últimas notícias</a></li>
        </ul>
      </nav>
      <p style="margin:32px 0 0;padding-top:16px;border-top:1px solid #e2e8f0;color:#94a3b8;font-size:14px">Para a experiência completa, habilite JavaScript no seu navegador.</p>
    </article>
  </noscript>
  <!-- Platform Health: Blank Screen Auto-Recovery V3
       - Phase 1 (5s): Auto-reload silently (max 2 attempts)
       - Phase 2 (12s): Show diagnostic overlay only if auto-recovery failed
       - Sends beacon to log-incident for every detected incident -->
  <script>
    (function() {
      var errors = [];
      var RELOAD_KEY = '_pf_recovery_count';
      var RELOAD_TS_KEY = '_pf_recovery_ts';
      var MAX_RETRIES = 2;
      var SESSION_WINDOW_MS = 60000; // Reset counter after 60s of no issues

      window.__diag = { errors: errors, phase: 'init' };
      window.__platformHealth = { incidents: [] };

      // Collect all JS errors from page load
      window.addEventListener('error', function(e) {
        errors.push('[ERR] ' + (e.message || '') + ' @ ' + (e.filename || '?').split('/').pop() + ':' + (e.lineno || '?'));
      });
      window.addEventListener('unhandledrejection', function(e) {
        var msg = e.reason && e.reason.message ? e.reason.message : String(e.reason);
        errors.push('[REJ] ' + msg.substring(0, 200));
      });

      // Get reload attempt count (with stale window check)
      function getReloadCount() {
        try {
          var ts = parseInt(sessionStorage.getItem(RELOAD_TS_KEY) || '0', 10);
          if (Date.now() - ts > SESSION_WINDOW_MS) {
            sessionStorage.removeItem(RELOAD_KEY);
            sessionStorage.removeItem(RELOAD_TS_KEY);
            return 0;
          }
          return parseInt(sessionStorage.getItem(RELOAD_KEY) || '0', 10);
        } catch(e) { return 0; }
      }

      function incrementReloadCount() {
        try {
          var count = getReloadCount() + 1;
          sessionStorage.setItem(RELOAD_KEY, count.toString());
          sessionStorage.setItem(RELOAD_TS_KEY, Date.now().toString());
          return count;
        } catch(e) { return 99; }
      }

      function clearReloadCount() {
        try {
          sessionStorage.removeItem(RELOAD_KEY);
          sessionStorage.removeItem(RELOAD_TS_KEY);
        } catch(e) {}
      }

      // DOM visibility check
      function checkBlank() {
        var root = document.getElementById('root');
        if (!root) return { isBlank: true, info: 'NO_ROOT', metrics: {} };
        var h = root.scrollHeight;
        var kids = root.children.length;
        var txt = (root.textContent || '').trim().length;
        var imgs = root.querySelectorAll('img').length;
        var buttons = root.querySelectorAll('button,a').length;
        var visEls = root.querySelectorAll('header,nav,main,article,section,h1,h2,h3,p').length;
        var isBlank = txt < 10 && imgs === 0 && buttons < 2 && visEls < 2;
        return {
          isBlank: isBlank,
          info: 'scrollH=' + h + ', children=' + kids + ', text=' + txt + ', imgs=' + imgs + ', btns=' + buttons + ', semantic=' + visEls,
          metrics: { scrollHeight: h, children: kids, text: txt, imgs: imgs, btns: buttons, semantic: visEls }
        };
      }

      // Walk DOM tree for diagnostics
      function walkDOM(root) {
        try {
          var walk = function(el, depth) {
            if (depth > 4 || !el) return '';
            var tag = el.tagName ? el.tagName.toLowerCase() : '#text';
            var cls = el.className ? (' class="' + String(el.className).substring(0, 60) + '"') : '';
            var s = new Array(depth + 1).join('  ') + '<' + tag + cls + '>\n';
            for (var i = 0; i < Math.min(el.children.length, 5); i++) {
              s += walk(el.children[i], depth + 1);
            }
            return s;
          };
          return walk(root, 0);
        } catch(e) { return 'walk error: ' + e.message; }
      }

      // Send incident to logging edge function via beacon (fire-and-forget)
      function logIncident(type, phase, metrics, autoResolved, resolutionMethod) {
        try {
          var payload = JSON.stringify({
            incident_type: type,
            severity: autoResolved ? 'medium' : 'critical',
            url: location.href,
            path: location.pathname,
            user_agent: navigator.userAgent,
            error_message: errors.length > 0 ? errors[0] : null,
            auto_resolved: autoResolved,
            resolution_method: resolutionMethod,
            metadata: {
              phase: phase,
              metrics: metrics,
              errors: errors.slice(0, 10),
              dom_tree: type === 'blank_screen' ? walkDOM(document.getElementById('root')) : null,
              reload_attempts: getReloadCount(),
              timestamp: new Date().toISOString()
            }
          });
          // Use sendBeacon for reliability (survives page unload/reload)
          if (navigator.sendBeacon) {
            navigator.sendBeacon('/functions/v1/log-incident', payload);
          }
          // Also store locally for the health service to pick up
          window.__platformHealth.incidents.push(JSON.parse(payload));
        } catch(e) { /* silent */ }
      }

      // Phase 1: After 5s — silent auto-recovery
      setTimeout(function() {
        var result = checkBlank();
        if (!result.isBlank) {
          // Page is fine — clear any stale recovery counters
          clearReloadCount();
          return;
        }

        var attempts = getReloadCount();
        if (attempts < MAX_RETRIES) {
          // Log the incident as auto-resolved, then silently reload
          logIncident('blank_screen', '5s', result.metrics, true, 'auto_reload');
          incrementReloadCount();
          // Small delay to let beacon send
          setTimeout(function() { location.reload(); }, 150);
        }
        // If max retries reached, Phase 2 will handle it
      }, 5000);

      // Phase 2: After 12s — final check, show overlay if still broken
      setTimeout(function() {
        var result = checkBlank();
        if (!result.isBlank) {
          clearReloadCount();
          return;
        }

        var attempts = getReloadCount();
        if (attempts < MAX_RETRIES) {
          // Still within retry budget — one more attempt
          logIncident('blank_screen', '12s', result.metrics, true, 'auto_reload');
          incrementReloadCount();
          setTimeout(function() { location.reload(); }, 150);
          return;
        }

        // All retries exhausted — show diagnostic overlay
        logIncident('blank_screen', '12s', result.metrics, false, null);
        showRecoveryOverlay(result);
      }, 12000);

      function showRecoveryOverlay(result) {
        var d = document.getElementById('ios-diag-overlay');
        if (d) return; // Already showing

        d = document.createElement('div');
        d.id = 'ios-diag-overlay';
        d.style.cssText = 'position:fixed;inset:0;z-index:99999;background:#fafafa;padding:0;font-family:Inter,-apple-system,system-ui,sans-serif;overflow:auto;display:flex;flex-direction:column;align-items:center;justify-content:center';
        d.innerHTML = ''
          // Clean, professional recovery UI
          + '<div style="max-width:420px;width:100%;padding:32px 24px;text-align:center">'
          +   '<div style="width:56px;height:56px;border-radius:16px;background:#fee2e2;display:flex;align-items:center;justify-content:center;margin:0 auto 20px">'
          +     '<svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="#dc2626" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>'
          +   '</div>'
          +   '<h2 style="font-size:20px;font-weight:700;color:#0f172a;margin:0 0 8px;letter-spacing:-0.02em">Algo deu errado</h2>'
          +   '<p style="font-size:14px;color:#64748b;margin:0 0 24px;line-height:1.5">A página não carregou corretamente. Tentamos recarregar automaticamente, mas o problema persiste.</p>'
          +   '<button onclick="sessionStorage.removeItem(\'' + RELOAD_KEY + '\');sessionStorage.removeItem(\'' + RELOAD_TS_KEY + '\');location.reload()" style="width:100%;padding:14px;background:#0f172a;color:#fff;border:none;border-radius:12px;font-size:15px;font-weight:600;cursor:pointer;transition:background 0.2s;letter-spacing:-0.01em" onmouseover="this.style.background=\'#1e293b\'" onmouseout="this.style.background=\'#0f172a\'">Recarregar Página</button>'
          +   '<button onclick="location.href=\'/\'" style="width:100%;padding:12px;background:transparent;color:#64748b;border:1px solid #e2e8f0;border-radius:12px;font-size:14px;font-weight:500;cursor:pointer;margin-top:10px;transition:all 0.2s" onmouseover="this.style.borderColor=\'#94a3b8\';this.style.color=\'#334155\'" onmouseout="this.style.borderColor=\'#e2e8f0\';this.style.color=\'#64748b\'">Ir para a página inicial</button>'
          // Collapsible technical details (dev-friendly, user-hidden)
          +   '<details style="margin-top:24px;text-align:left;width:100%">'
          +     '<summary style="font-size:12px;color:#94a3b8;cursor:pointer;font-weight:500;user-select:none">Informações técnicas</summary>'
          +     '<pre style="background:#0f172a;color:#4ade80;padding:14px;border-radius:10px;font-size:10px;overflow:auto;white-space:pre-wrap;word-break:break-all;max-height:200px;margin-top:8px;line-height:1.5">'
          +       result.info
          +       '\n\nErros (' + errors.length + '):\n' + (errors.length ? errors.join('\n') : '(nenhum)')
          +       '\n\nUA: ' + navigator.userAgent
          +       '\n\nURL: ' + location.href
          +       '\n\nTentativas: ' + getReloadCount()
          +     '</pre>'
          +   '</details>'
          + '</div>';
        document.body.appendChild(d);
      }
    })();
  </script>
  <script>
    (function() {
      var h = location.hostname;
      var p = location.pathname;
      var isAdminPage = h.startsWith('admin.') || h.startsWith('console.') || p.startsWith('/admin') || p.startsWith('/console');
      if (isAdminPage) {
        var preloaderContainer = document.getElementById('global-admin-preloader-container');
        if (preloaderContainer) {
          preloaderContainer.innerHTML = '<style>.uni-loader{position:fixed;top:0;left:0;width:100%;height:100%;z-index:99999;background:#fafafa;transition:opacity .4s ease}.uni-loader-bar{position:absolute;top:0;left:0;width:100%;height:2px;overflow:hidden}.uni-loader-bar::after{content:"";position:absolute;top:0;left:-40%;width:40%;height:100%;background:linear-gradient(90deg,transparent,rgba(0,0,0,.12),transparent);animation:uni-shimmer 1.4s ease-in-out infinite}@keyframes uni-shimmer{0%{left:-40%}100%{left:100%}}@media(prefers-color-scheme:dark){.uni-loader{background:#0a0a0a}.uni-loader-bar::after{background:linear-gradient(90deg,transparent,rgba(255,255,255,.08),transparent)}}</style><div id="global-admin-preloader" class="uni-loader"><div class="uni-loader-bar"></div></div>';
        }
      }
    })();
  </script>
  <!-- WebMCP: Expose site tools to AI agents via browser -->
  <script>
    (function() {
      // WebMCP API — navigator.modelContext.provideContext()
      // Spec: https://webmachinelearning.github.io/webmcp/
      // No-op if browser doesn't support it (progressive enhancement)
      if (typeof navigator !== 'undefined' && 'modelContext' in navigator && navigator.modelContext && typeof navigator.modelContext.provideContext === 'function') {
        try {
          navigator.modelContext.provideContext({
            tools: [
              {
                name: 'search_articles',
                description: 'Search published news articles on this portal. Returns headlines, summaries, categories, and direct URLs.',
                inputSchema: {
                  type: 'object',
                  properties: {
                    query: { type: 'string', description: 'Search query text' },
                    category: { type: 'string', description: 'Category filter (politica, educacao, saude, seguranca, cultura, esportes, economia, transporte, meio-ambiente)' },
                    limit: { type: 'number', description: 'Maximum results to return (default: 10)' }
                  },
                  required: ['query']
                }
              },
              {
                name: 'get_portal_info',
                description: 'Get structured information about the current portal including editorial policies, coverage areas, contact details, and citation format.',
                inputSchema: {
                  type: 'object',
                  properties: {
                    format: { type: 'string', enum: ['full', 'summary'], description: 'Response detail level' }
                  }
                }
              },
              {
                name: 'get_latest_news',
                description: 'Get the most recent published news articles from this portal with headlines, summaries, and publication timestamps.',
                inputSchema: {
                  type: 'object',
                  properties: {
                    count: { type: 'number', description: 'Number of articles to return (default: 5, max: 20)' },
                    category: { type: 'string', description: 'Optional category filter' }
                  }
                }
              },
              {
                name: 'get_weather',
                description: 'Get current weather conditions and forecast for the local region.',
                inputSchema: {
                  type: 'object',
                  properties: {
                    days: { type: 'number', description: 'Forecast days (1-7, default: 1)' }
                  }
                }
              }
            ]
          });
        } catch(e) {
          // Silently fail — WebMCP not supported
        }
      }
    })();
  </script>
</body>

</html>