{"id":11963,"date":"2026-06-22T09:27:01","date_gmt":"2026-06-22T07:27:01","guid":{"rendered":"https:\/\/vincesconsulting.com\/tecnologia\/fren\/"},"modified":"2026-09-04T12:19:32","modified_gmt":"2026-09-04T10:19:32","slug":"fren","status":"publish","type":"page","link":"https:\/\/vincesconsulting.com\/pt-pt\/tecnologia\/fren\/","title":{"rendered":"Fren"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-page\" data-elementor-id=\"11963\" class=\"elementor elementor-11963 elementor-11011\" data-elementor-post-type=\"page\">\n\t\t\t\t<div class=\"elementor-element elementor-element-fb775a4 e-con-full e-flex e-con e-parent\" data-id=\"fb775a4\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-5d28f2b elementor-widget elementor-widget-html\" data-id=\"5d28f2b\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<div>\n\n<!--\n  Dashboard Vinces \u00b7 FREN \u00b7 p\u00e1gina standalone (versi\u00f3n redise\u00f1ada para WP)\n  Endpoint API: https:\/\/vision360.vincesconsulting.com\/api\/dashboard-publico\/fren\/\n  Refresco cliente: 30 min \u00b7 Cach\u00e9 backend: 1h.\n-->\n\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n\n<title>FREN: Di\u00e1rio das Sess\u00f5es, vota\u00e7\u00f5es do Congresso e pergunta do dia \u00b7 Intelig\u00eancia regulat\u00f3ria com IA \u00b7 Vinces<\/title>\n<meta name=\"description\" content=\"FREN: assistente de IA para Rela\u00e7\u00f5es P\u00fablicas em Espanha. 5 m\u00f3dulos (Leis, Decisores, Vota\u00e7\u00f5es, Di\u00e1rios de Sess\u00f5es, Not\u00edcias), 15 dias gr\u00e1tis, RGPD da UE. Consulta o \u00faltimo Di\u00e1rio das Sess\u00f5es do Congresso, o hemiciclo da \u00faltima vota\u00e7\u00e3o em plen\u00e1rio e a pergunta do dia respondida com IA e fontes oficiais.\">\n<meta name=\"keywords\" content=\"FREN, ata das sess\u00f5es, \u00faltima ata das sess\u00f5es, Congresso, Senado, parlamentos regionais, hemiciclo, vota\u00e7\u00e3o em plen\u00e1rio, voto do deputado, assistente regulat\u00f3rio de IA, assistente de IA para a pol\u00edtica, Vinces Consulting\">\n<meta name=\"author\" content=\"Vinces Consulting\">\n<meta name=\"robots\" content=\"index,follow,max-image-preview:large,max-snippet:-1\">\n<link rel=\"canonical\" href=\"https:\/\/fren.democrata.es\/\">\n\n<meta property=\"og:type\" content=\"site\">\n<meta property=\"og:site_name\" content=\"Vinces Consulting\">\n<meta property=\"og:title\" content=\"FREN \u00b7 Assistente de IA para assuntos regulamentares \u00b7 Vinces\">\n<meta property=\"og:description\" content=\"Assistente de IA para Rela\u00e7\u00f5es P\u00fablicas em Espanha. 5 m\u00f3dulos (Leis, Decisores, Vota\u00e7\u00f5es, Atas das Sess\u00f5es, Not\u00edcias). 15 dias gr\u00e1tis, sem cart\u00e3o de cr\u00e9dito. RGPD \u00b7 UE.\">\n<meta property=\"og:locale\" content=\"es_ES\">\n<meta property=\"og:url\" content=\"https:\/\/fren.democrata.es\/\">\n\n<link rel=\"preconnect\" href=\"https:\/\/fonts.googleapis.com\">\n<link rel=\"preconnect\" href=\"https:\/\/fonts.gstatic.com\" crossorigin=\"\">\n<link rel=\"stylesheet\" href=\"https:\/\/fonts.googleapis.com\/css2?family=Libre+Franklin:wght@400;500;600;700;800&family=Lato:wght@400;700&display=swap\">\n<script defer src=\"https:\/\/cdn.jsdelivr.net\/npm\/chart.js@4.4.1\/dist\/chart.umd.min.js\"><\/script>\n\n<style>\n\/* =========================================================\n   Vinces \u00b7 Dashboards p\u00fablicos \u2014 capa visual redesign\n   Mantiene todas las clases del HTML\/JS original e\n   incorpora la identidad de vincesconsulting.com (hero\n   navy, kicker naranja, tipograf\u00eda display, CTAs p\u00edldora).\n   ========================================================= *\/\n:root{\n  --navy:#1F2547;\n  --navy-deep:#161A36;\n  --navy-light:#2A3158;\n  --navy-soft:#E9ECF3;\n  --orange:#F3A53A;\n  --orange-soft:#FFF1DA;\n  --green:#1FA886;\n  --bg:#EEF1F3;\n  --bg-alt:#F6F8FA;\n  --card:#FFFFFF;\n  --ink:#1F2547;\n  --ink-soft:#5A6076;\n  --muted:#8A90A3;\n  --line:#E2E6EE;\n  --line-soft:#EDF0F5;\n  --good:#1FA886;\n  --warn:#E5A040;\n  --bad:#C0392B;\n\n  \/* Aliases para mantener compatibilidad con el CSS original *\/\n  --vinces-primary:var(--navy);\n  --vinces-secondary:var(--orange);\n  --vinces-dark:var(--navy-deep);\n  --panel:var(--card);\n  --panel-soft:var(--bg-alt);\n  --brand:var(--navy);\n  --brand-soft:var(--navy-soft);\n  --brand-light:var(--navy-light);\n  --accent:var(--orange);\n  --accent-soft:var(--orange-soft);\n  --accent-dark:#D88E25;\n\n  --radius:18px;\n  --radius-sm:10px;\n  --radius-pill:999px;\n  --shadow:0 1px 2px rgba(31,37,71,.04), 0 8px 24px rgba(31,37,71,.06);\n  --shadow-lg:0 4px 12px rgba(31,37,71,.06), 0 24px 60px rgba(31,37,71,.12);\n\n  --hm-0:#F1F3F7;--hm-1:#DDE2EE;--hm-2:#B8C2D9;\n  --hm-3:#7889B0;--hm-4:#42507A;--hm-5:#1F2547;\n\n  --font-display:\"Libre Franklin\",-apple-system,BlinkMacSystemFont,sans-serif;\n  --font-body:\"Lato\",\"Libre Franklin\",-apple-system,BlinkMacSystemFont,sans-serif;\n}\n\n*{box-sizing:border-box}\nhtml,body{margin:0;padding:0}\nbody{\n  font-family:var(--font-body);\n  background:var(--bg);\n  color:var(--ink);\n  line-height:1.65;\n  -webkit-font-smoothing:antialiased;\n  text-rendering:optimizeLegibility;\n}\n\n\/* =========================================================\n   HERO full-bleed (estilo Vinces)\n   ========================================================= *\/\n.vc-hero{\n  position:relative;\n  background:var(--navy);\n  color:#fff;\n  padding:96px 24px 88px;\n  overflow:hidden;\n}\n.vc-hero::before{\n  content:\"\";\n  position:absolute;inset:0;\n  background:\n    radial-gradient(circle at 88% 18%, rgba(243,165,58,.10), transparent 45%),\n    radial-gradient(circle at 8% 95%, rgba(31,168,134,.07), transparent 50%);\n  pointer-events:none;\n}\n.vc-hero::after{\n  content:\"\";\n  position:absolute;left:0;right:0;bottom:0;height:1px;\n  background:linear-gradient(90deg, transparent, rgba(243,165,58,.45), transparent);\n}\n.vc-hero-inner{\n  position:relative;\n  max-width:1240px;margin:0 auto;\n  display:grid;grid-template-columns:1fr;gap:28px;\n}\n@media(min-width:880px){\n  .vc-hero-inner{grid-template-columns:minmax(0,1fr) auto;align-items:end;gap:48px}\n}\n.vc-kicker{\n  display:inline-block;\n  color:var(--orange);\n  font-family:var(--font-display);\n  font-weight:700;font-size:.78rem;\n  letter-spacing:.18em;text-transform:uppercase;\n  margin:0 0 22px;line-height:1.2;\n}\n.vc-kicker::before{content:\"\/\/ \"}\n.vc-hero h1{\n  font-family:var(--font-display);\n  font-size:clamp(2.4rem,5.6vw,4.8rem);\n  font-weight:800;\n  letter-spacing:-.035em;\n  line-height:.98;\n  margin:0 0 24px;\n  color:#fff;\n  text-wrap:balance;\n}\n.vc-hero-lead{\n  font-size:clamp(1rem,1.25vw,1.15rem);\n  color:rgba(255,255,255,.78);\n  max-width:680px;\n  line-height:1.55;\n  margin:0 0 28px;\n}\n.vc-hero-lead strong{color:#fff;font-weight:600}\n.vc-hero-meta{\n  display:inline-flex;align-items:center;gap:10px;\n  background:rgba(255,255,255,.05);\n  border:1px solid rgba(255,255,255,.14);\n  padding:9px 18px;\n  border-radius:999px;\n  font-size:.8rem;\n  color:rgba(255,255,255,.85);\n  backdrop-filter:blur(6px);\n}\n.vc-hero-meta .dot{\n  width:8px;height:8px;border-radius:50%;\n  background:#4ADE80;\n  box-shadow:0 0 0 4px rgba(74,222,128,.18);\n}\n.vc-hero-meta.err .dot{background:#FCA5A5;box-shadow:0 0 0 4px rgba(252,165,165,.18)}\n.vc-hero-meta.err{color:#FCA5A5;border-color:rgba(252,165,165,.25)}\n\n.vc-hero-cta{\n  display:inline-flex;align-items:center;gap:14px;\n  background:#fff;color:var(--navy);\n  padding:14px 16px 14px 26px;\n  border-radius:999px;\n  text-decoration:none;\n  font-family:var(--font-display);\n  font-weight:700;font-size:1.45rem;\n  transition:transform .15s ease, box-shadow .2s ease;\n  align-self:start;\n}\n.vc-hero-cta:hover{transform:translateY(-2px);box-shadow:0 10px 24px rgba(0,0,0,.25)}\n.vc-hero-cta .ico{\n  width:30px;height:30px;border-radius:50%;\n  background:var(--navy);color:#fff;\n  display:inline-flex;align-items:center;justify-content:center;\n  font-size:1.45rem;font-weight:400;\n  transition:transform .2s ease;\n}\n.vc-hero-cta:hover .ico{transform:rotate(-12deg)}\n\n\/* =========================================================\n   Layout principal (sustituye al .wrap inline)\n   ========================================================= *\/\n.wrap{max-width:1240px;margin:0 auto;padding:56px 24px 96px}\n@media(max-width:768px){.wrap{padding:40px 18px 64px}}\n\n\/* Cabecera vieja: la ocultamos porque ahora vive en el hero *\/\nheader.page{display:none}\n\nnoscript .nojs{\n  background:#FFF7ED;border:1px solid #FED7AA;color:#9A3412;\n  padding:16px 20px;border-radius:var(--radius-sm);margin-bottom:24px;font-size:.9rem;\n}\n\n\/* =========================================================\n   PRODUCT SECTION \u2014 card grande con dos columnas\n   ========================================================= *\/\n.product-section{\n  margin:0 0 40px;\n  background:var(--card);\n  border:1px solid var(--line);\n  border-radius:var(--radius);\n  box-shadow:var(--shadow);\n  overflow:hidden;\n  position:relative;\n}\n.product-section::before{\n  content:\"\";position:absolute;top:0;left:0;\n  width:160px;height:4px;\n  background:linear-gradient(90deg,var(--navy) 0%,var(--orange) 100%);\n}\n.product-grid{display:grid;grid-template-columns:1fr;gap:0}\n@media(min-width:1020px){\n  .product-grid{grid-template-columns:360px 1fr}\n  .product-grid.reverse{grid-template-columns:1fr 360px}\n}\n.product-info{\n  padding:48px 38px;\n  background:linear-gradient(180deg,#FAFBFC 0%, #F0F3F7 100%);\n  border-right:1px solid var(--line);\n  display:flex;flex-direction:column;gap:18px;\n}\n.product-grid.reverse .product-info{\n  border-right:0;border-left:1px solid var(--line);order:2;\n}\n@media(max-width:1019px){\n  .product-info{padding:32px 24px;border-right:0;border-left:0;border-bottom:1px solid var(--line)}\n  .product-grid.reverse .product-info{order:0;border-left:0;border-bottom:1px solid var(--line)}\n}\n\n.product-badge{\n  display:inline-block;\n  color:var(--orange);\n  font-family:var(--font-display);\n  font-weight:700;font-size:.72rem;\n  letter-spacing:.16em;text-transform:uppercase;\n  background:transparent;padding:0;border:0;\n  align-self:flex-start;line-height:1.2;\n}\n.product-badge::before{content:\"\/\/ \"}\n.product-badge.brand{color:var(--navy)}\n\n.product-name{\n  font-family:var(--font-display);\n  font-size:clamp(1.7rem,2.4vw,2.2rem);\n  font-weight:800;color:var(--navy);\n  margin:0;letter-spacing:-.025em;line-height:1.05;\n  text-wrap:balance;\n}\n.product-tagline{\n  font-size:1rem;color:var(--ink-soft);\n  margin:0;line-height:1.7;\n}\n.product-tagline strong{color:var(--ink);font-weight:600}\n\n.product-content{padding:42px 38px;min-width:0}\n@media(max-width:1019px){.product-content{padding:30px 24px}}\n.product-content-header{\n  display:flex;align-items:flex-start;justify-content:space-between;\n  gap:16px;flex-wrap:wrap;margin-bottom:22px;\n}\n.product-content-header h3{\n  margin:0;\n  font-family:var(--font-display);\n  font-size:clamp(1.25rem,1.6vw,1.55rem);\n  font-weight:700;color:var(--navy);\n  letter-spacing:-.02em;line-height:1.2;\n}\n.product-content-header .sub{\n  font-size:1.45rem;color:var(--ink-soft);\n  margin:8px 0 0;line-height:1.55;max-width:62ch;\n}\n\n\/* =========================================================\n   CTA p\u00edldora \u2014 el patr\u00f3n Vinces \"Contacta con nosotros \u2197\"\n   ========================================================= *\/\n.pane-cta,\n.product-cta,\n.dl-btn{\n  display:inline-flex;align-items:center;gap:12px;\n  background:var(--navy);color:#fff;\n  padding:13px 18px 13px 26px;\n  border-radius:999px;\n  text-decoration:none;\n  font-family:var(--font-display);\n  font-weight:700;font-size:.88rem;\n  transition:transform .15s ease, box-shadow .2s ease, background .2s ease;\n  border:0;cursor:pointer;line-height:1;\n  white-space:nowrap;\n}\n.pane-cta::after,\n.product-cta::after{content:none}\n.pane-cta::before,\n.product-cta::before,\n.dl-btn::before{\n  order:2;\n  content:\"\\2197\";\n  width:26px;height:26px;border-radius:50%;\n  background:rgba(255,255,255,.16);\n  display:inline-flex;align-items:center;justify-content:center;\n  font-size:1.25rem;font-weight:500;\n  transition:transform .25s ease;\n}\n.pane-cta:hover,\n.product-cta:hover,\n.dl-btn:hover{\n  background:var(--navy-light);\n  transform:translateY(-2px);\n  box-shadow:0 10px 24px rgba(31,37,71,.18);\n  color:#fff;\n}\n.pane-cta:hover::before,\n.product-cta:hover::before{transform:translate(2px,-2px) rotate(-8deg)}\n\n.pane-cta-row{\n  margin-top:28px;padding:22px 24px;\n  background:var(--bg-alt);\n  border:1px solid var(--line-soft);\n  border-radius:var(--radius-sm);\n  display:flex;flex-wrap:wrap;align-items:center;gap:18px;\n}\n.pane-cta-row .pane-cta-text{\n  flex:1;min-width:240px;\n  font-size:1.45rem;color:var(--ink-soft);\n  margin:0;line-height:1.6;\n}\n.pane-cta-row .pane-cta-text strong{color:var(--ink);font-weight:700}\n.content-cta-row{\n  margin-top:32px;padding:24px 26px;\n  background:linear-gradient(135deg, var(--navy) 0%, var(--navy-deep) 100%);\n  color:#fff;\n  border-radius:var(--radius-sm);\n  display:flex;flex-wrap:wrap;align-items:center;gap:20px;\n}\n.content-cta-row .pane-cta-text{\n  flex:1;min-width:240px;\n  font-size:1.45rem;color:rgba(255,255,255,.78);\n  margin:0;line-height:1.6;\n}\n.content-cta-row .pane-cta-text strong{color:#fff;font-weight:700}\n.content-cta-row .pane-cta{\n  background:#fff;color:var(--navy);\n}\n.content-cta-row .pane-cta::before{background:var(--navy);color:#fff}\n.content-cta-row .pane-cta:hover{background:var(--orange);color:var(--navy)}\n.content-cta-row .pane-cta:hover::before{background:var(--navy);color:#fff}\n\n\/* Updated pill compatible con c\u00f3digo original (queda oculto en hero, pero el JS a\u00fan escribe en \u00e9l) *\/\n.updated{\n  font-size:.8rem;color:var(--ink-soft);\n  background:var(--card);border:1px solid var(--line);\n  padding:8px 16px;border-radius:999px;\n  display:inline-flex;align-items:center;gap:8px;\n}\n.updated .dot{width:8px;height:8px;border-radius:50%;background:var(--good);box-shadow:0 0 0 4px rgba(31,168,134,.15)}\n.updated.err .dot{background:var(--bad);box-shadow:0 0 0 4px rgba(192,57,43,.15)}\n.updated.err{color:var(--bad);border-color:#FECACA}\n\n\/* =========================================================\n   Carrusel de tabs (PolicyAlert)\n   ========================================================= *\/\n.car-tabs{\n  display:flex;gap:6px;margin:-8px 0 28px;\n  padding:6px;background:var(--bg-alt);\n  border:1px solid var(--line-soft);border-radius:999px;\n  flex-wrap:wrap;width:fit-content;max-width:100%;\n}\n.car-tab{\n  background:transparent;border:0;\n  padding:10px 20px;font-weight:600;font-size:1.25rem;\n  color:var(--ink-soft);cursor:pointer;\n  font-family:var(--font-display);\n  border-radius:999px;\n  transition:all .15s ease;\n  line-height:1.2;\n}\n.car-tab:hover{color:var(--navy)}\n.car-tab.active{\n  background:var(--navy);color:#fff;\n  box-shadow:0 2px 8px rgba(31,37,71,.18);\n}\n.car-pane{display:none}\n.car-pane.active{display:block;animation:vc-fade .35s cubic-bezier(.16,1,.3,1)}\n@keyframes vc-fade{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}\n\n\/* =========================================================\n   Nombramientos (Poder Digital)\n   ========================================================= *\/\n.nomb-list{list-style:none;padding:0;margin:0;display:flex;flex-direction:column;gap:12px}\n.nomb-list-grid{display:grid;grid-template-columns:1fr;gap:14px}\n@media(min-width:780px){.nomb-list-grid{grid-template-columns:1fr 1fr}}\n.nomb-item{\n  display:flex;align-items:flex-start;gap:16px;\n  padding:22px;background:#fff;\n  border:1px solid var(--line);border-radius:var(--radius-sm);\n  transition:all .18s ease;\n  position:relative;\n}\n.nomb-item::before{\n  content:\"\";position:absolute;left:0;top:22px;bottom:22px;width:3px;\n  background:var(--orange);border-radius:3px;opacity:0;transition:opacity .18s ease;\n}\n.nomb-item:hover{\n  border-color:var(--navy);\n  box-shadow:0 8px 24px rgba(31,37,71,.08);\n  transform:translateY(-2px);\n}\n.nomb-item:hover::before{opacity:1}\n.nomb-item .badge{\n  flex:0 0 auto;width:48px;height:48px;border-radius:50%;\n  background:linear-gradient(135deg, var(--navy) 0%, var(--navy-light) 100%);\n  color:#fff;\n  display:flex;align-items:center;justify-content:center;\n  font-weight:700;font-size:.9rem;\n  font-family:var(--font-display);\n  box-shadow:0 4px 10px rgba(31,37,71,.18);\n}\n.nomb-item .body{flex:1;min-width:0}\n.nomb-item .name{\n  font-family:var(--font-display);\n  font-weight:700;font-size:1rem;\n  margin:0 0 6px;color:var(--navy);line-height:1.25;\n  letter-spacing:-.01em;\n}\n.nomb-item .cargo{font-size:.88rem;color:var(--ink-soft);margin:0;line-height:1.5}\n.nomb-item time{\n  font-size:.72rem;color:var(--muted);\n  display:inline-block;margin-top:10px;\n  text-transform:uppercase;letter-spacing:.06em;font-weight:600;\n}\n.nomb-item a{\n  display:inline-block;margin-top:8px;\n  color:var(--navy);text-decoration:none;\n  font-size:.78rem;font-weight:600;\n}\n.nomb-item a:hover{color:var(--orange)}\n\n\/* =========================================================\n   Leyes \/ stepper (PolicyAlert)\n   ========================================================= *\/\n.ley{\n  padding:24px 26px;margin-bottom:14px;\n  border:1px solid var(--line);border-radius:var(--radius-sm);\n  background:#fff;transition:all .18s ease;\n}\n.ley:last-child{margin-bottom:0}\n.ley:hover{\n  border-color:var(--navy);\n  box-shadow:0 8px 24px rgba(31,37,71,.08);\n  transform:translateY(-2px);\n}\n.ley .ley-title{\n  font-family:var(--font-display);\n  font-weight:700;font-size:1.05rem;\n  color:var(--navy);display:block;margin-bottom:8px;\n  letter-spacing:-.015em;line-height:1.35;\n  text-decoration:none;\n}\n.ley .ley-meta{font-size:1.1rem;color:var(--ink-soft);margin:0 0 18px;line-height:1.5}\n.ley .ley-meta strong{color:var(--navy);font-weight:700}\n.stepper{display:flex;flex-wrap:wrap;align-items:flex-start;width:100%;gap:2px 0}\n.stepper .step{\n  flex:1 1 auto;min-width:60px;text-align:center;position:relative;\n  font-size:.64rem;color:var(--muted);padding:0 4px;\n  text-transform:uppercase;letter-spacing:.04em;font-weight:600;\n}\n.stepper .step .dot{\n  width:12px;height:12px;border-radius:50%;\n  background:var(--line);border:2px solid #fff;\n  margin:0 auto 6px;position:relative;z-index:1;\n  box-shadow:0 0 0 1px var(--line);\n}\n.stepper .step.done .dot{background:var(--good);box-shadow:0 0 0 1px var(--good)}\n.stepper .step.current .dot{\n  background:var(--orange);\n  box-shadow:0 0 0 1px var(--orange), 0 0 0 4px rgba(243,165,58,.25);\n  width:14px;height:14px;\n}\n.stepper .step.done,.stepper .step.current{color:var(--ink)}\n.stepper .step.current{font-weight:700;color:var(--navy)}\n.stepper .step::before{content:\"\";position:absolute;top:5px;left:0;right:50%;height:2px;background:var(--line);z-index:0}\n.stepper .step::after{content:\"\";position:absolute;top:5px;left:50%;right:0;height:2px;background:var(--line);z-index:0}\n.stepper .step.done::before,.stepper .step.done::after{background:var(--good)}\n.stepper .step.current::before{background:var(--good)}\n.stepper .step:first-child::before{display:none}\n.stepper .step:last-child::after{display:none}\n\n\/* =========================================================\n   KPIs (PolicyAlert)\n   ========================================================= *\/\n.kpi-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:16px;margin:8px 0 0}\n@media(min-width:760px){.kpi-grid{grid-template-columns:repeat(4,1fr)}}\n.kpi-card{\n  padding:24px 22px;background:#fff;\n  border:1px solid var(--line);border-radius:var(--radius-sm);\n  display:flex;flex-direction:column;gap:6px;\n  position:relative;overflow:hidden;\n  transition:all .18s ease;\n}\n.kpi-card::before{\n  content:\"\";position:absolute;top:0;left:0;right:0;height:3px;\n  background:var(--navy);\n}\n.kpi-card.accent::before{background:var(--orange)}\n.kpi-card.green::before{background:var(--good)}\n.kpi-card.purple::before{background:#7C3AED}\n.kpi-card:hover{box-shadow:0 12px 28px rgba(31,37,71,.08);transform:translateY(-2px)}\n.kpi-label{\n  font-size:.7rem;color:var(--muted);\n  text-transform:uppercase;letter-spacing:.08em;font-weight:700;margin:0;\n}\n.kpi-value{\n  font-family:var(--font-display);\n  font-size:2.4rem;font-weight:800;\n  color:var(--navy);line-height:1;margin:6px 0 2px;\n  letter-spacing:-.03em;font-variant-numeric:tabular-nums;\n}\n.kpi-card.accent .kpi-value{color:var(--orange)}\n.kpi-card.green .kpi-value{color:var(--good)}\n.kpi-card.purple .kpi-value{color:#7C3AED}\n.kpi-sub{font-size:.8rem;color:var(--ink-soft);margin:0;line-height:1.4}\n\n\/* =========================================================\n   Temas conversaci\u00f3n (WATS): filtros, leyenda, chart\n   ========================================================= *\/\n.tc-meta{\n  font-size:1.25rem;color:var(--muted);margin:8px 0 0;\n  font-weight:500;\n}\n.tc-filters{\n  display:flex;flex-wrap:wrap;gap:6px;\n  margin:20px 0 24px;\n  padding:0 0 18px;border-bottom:1px solid var(--line);\n}\n.tc-filters button{\n  border:1px solid var(--line);background:#fff;\n  color:var(--ink-soft);\n  padding:8px 16px;border-radius:999px;\n  cursor:pointer;font-size:1.1rem;font-weight:600;\n  transition:all .15s ease;line-height:1.2;\n  font-family:var(--font-display);\n}\n.tc-filters button:hover{border-color:var(--navy);color:var(--navy)}\n.tc-filters button.active{\n  background:var(--navy);color:#fff;border-color:var(--navy);\n  box-shadow:0 2px 8px rgba(31,37,71,.16);\n}\n.tc-filters button[disabled]{opacity:.35;cursor:not-allowed}\n.tc-chart-wrap{position:relative;min-height:380px;margin-bottom:16px}\n.tc-legend{\n  display:flex;flex-wrap:wrap;gap:18px;align-items:center;\n  padding:14px 18px;background:var(--bg-alt);\n  border:1px solid var(--line-soft);\n  border-radius:var(--radius-sm);\n  font-size:.8rem;color:var(--ink-soft);\n}\n.tc-legend .lg{display:inline-flex;align-items:center;gap:8px;font-weight:500}\n.tc-legend .sw{width:12px;height:12px;border-radius:3px;display:inline-block}\n\n\/* =========================================================\n   Temas activos (PolicyAlert)\n   ========================================================= *\/\n.temas-act-wrap{position:relative;height:340px;margin:14px 0 14px}\n.temas-act-summary{\n  display:flex;flex-wrap:wrap;gap:10px;align-items:center;\n  margin-bottom:14px;font-size:.88rem;color:var(--ink-soft);\n}\n.temas-act-summary .pill{\n  background:var(--orange);color:var(--navy);\n  padding:6px 14px;border-radius:999px;\n  font-weight:700;font-size:.78rem;\n  font-family:var(--font-display);letter-spacing:.01em;\n}\n.temas-act-legend{\n  display:flex;flex-wrap:wrap;gap:8px;\n  margin-top:14px;padding-top:18px;border-top:1px solid var(--line);\n}\n.temas-act-legend .ta-tag{\n  display:inline-flex;align-items:center;gap:7px;\n  padding:7px 14px;\n  border:1px solid var(--line);border-radius:999px;\n  background:#fff;cursor:pointer;\n  font-family:var(--font-display);\n  font-size:.78rem;font-weight:600;color:var(--ink);\n  transition:all .14s ease;user-select:none;line-height:1.2;\n}\n.temas-act-legend .ta-tag:hover{border-color:var(--navy)}\n.temas-act-legend .ta-tag .sw{width:10px;height:10px;border-radius:50%;display:inline-block;flex-shrink:0;border:1.5px solid transparent}\n.temas-act-legend .ta-tag.off{opacity:.45;background:var(--bg-alt);text-decoration:line-through;color:var(--muted)}\n.temas-act-legend .ta-tag.off .sw{border-color:var(--muted);background:transparent !important}\n.temas-act-legend .ta-actions{display:inline-flex;gap:8px;margin-left:auto;align-items:center;font-size:.78rem}\n.temas-act-legend .ta-actions a{color:var(--navy);font-weight:700;cursor:pointer;text-decoration:none;font-family:var(--font-display)}\n.temas-act-legend .ta-actions a:hover{color:var(--orange)}\n.temas-act-legend .ta-actions span{color:var(--muted)}\n\n\/* =========================================================\n   FAQ\n   ========================================================= *\/\n.faq-section{\n  margin:0 0 40px;padding:56px 48px;\n  background:var(--card);border:1px solid var(--line);\n  border-radius:var(--radius);box-shadow:var(--shadow);\n}\n@media(max-width:768px){.faq-section{padding:36px 24px}}\n.faq-section > h2{\n  font-family:var(--font-display);\n  font-size:clamp(1.8rem,2.6vw,2.3rem);color:var(--navy);\n  font-weight:800;margin:0 0 14px;letter-spacing:-.025em;line-height:1.1;\n  text-wrap:balance;\n}\n.faq-intro{font-size:1.05rem;color:var(--ink-soft);margin:0 0 36px;line-height:1.6;max-width:62ch}\n.faq-block{margin-bottom:36px;padding-top:32px;border-top:1px solid var(--line);scroll-margin-top:24px}\n.faq-block:first-of-type{border-top:0;padding-top:0}\n.faq-block-title{\n  font-family:var(--font-display);\n  font-size:1.35rem;color:var(--navy);\n  font-weight:800;margin:0 0 22px;letter-spacing:-.015em;\n  display:flex;align-items:center;gap:14px;flex-wrap:wrap;\n}\n.faq-badge{\n  display:inline-block;\n  background:var(--navy);color:#fff;\n  font-family:var(--font-display);\n  font-size:.68rem;font-weight:700;letter-spacing:.12em;text-transform:uppercase;\n  padding:5px 12px;border-radius:999px;\n}\n.faq-badge.brand{background:var(--orange);color:var(--navy)}\n.faq-list{display:grid;grid-template-columns:1fr;gap:10px}\n@media(min-width:1100px){.faq-list{grid-template-columns:1fr 1fr;gap:10px 24px}}\n.faq-list details{\n  border:1px solid var(--line);border-radius:var(--radius-sm);\n  background:#fff;transition:all .18s ease;overflow:hidden;\n}\n.faq-list details:hover{border-color:var(--navy-light);box-shadow:0 4px 14px rgba(31,37,71,.06)}\n.faq-list details[open]{border-color:var(--navy);box-shadow:0 8px 24px rgba(31,37,71,.10)}\n.faq-list details summary{\n  padding:16px 22px;cursor:pointer;font-weight:600;\n  color:var(--ink);font-size:1.45rem;list-style:none;line-height:1.45;\n}\n.faq-list details summary::after{\n  content:\"+\";float:right;font-weight:300;color:var(--orange);\n  font-size:1.6rem;line-height:.7;margin-left:8px;transition:transform .2s ease;\n}\n.faq-list details[open] summary::after{content:\"\\2212\";color:var(--navy)}\n.faq-list details p{padding:0 22px 18px;margin:0;font-size:.9rem;color:var(--ink-soft);line-height:1.7}\n.faq-list details p a{color:var(--navy);font-weight:700}\n\n\/* =========================================================\n   SEO block \u2014 texto largo indexable\n   ========================================================= *\/\n.seo-block{\n  margin:0 0 32px;padding:56px 48px;\n  background:var(--card);border:1px solid var(--line);\n  border-radius:var(--radius);box-shadow:var(--shadow);\n}\n@media(max-width:768px){.seo-block{padding:36px 24px}}\n.seo-block h2{\n  font-family:var(--font-display);\n  font-size:clamp(1.7rem,2.4vw,2.1rem);color:var(--navy);\n  font-weight:800;margin:0 0 32px;letter-spacing:-.025em;\n  padding-bottom:18px;border-bottom:3px solid var(--orange);\n  line-height:1.15;display:inline-block;\n}\n.seo-grid{display:grid;grid-template-columns:1fr;gap:40px;margin-top:0}\n@media(min-width:960px){.seo-grid{grid-template-columns:1fr 1fr;gap:48px}}\n.seo-item h3{\n  font-family:var(--font-display);\n  font-size:1.25rem;color:var(--navy);font-weight:800;\n  margin:0 0 14px;line-height:1.25;letter-spacing:-.015em;\n}\n.seo-item h4{\n  font-family:var(--font-display);\n  font-size:.78rem;color:var(--orange);font-weight:700;\n  margin:24px 0 12px;text-transform:uppercase;letter-spacing:.12em;\n}\n.seo-item h4::before{content:\"\/\/ \"}\n.seo-item p{font-size:1rem;color:var(--ink-soft);margin:0 0 14px;line-height:1.75}\n.seo-item p strong{color:var(--ink);font-weight:600}\n.seo-item a{color:var(--navy);font-weight:600;text-decoration:none;border-bottom:1px solid currentColor}\n.seo-item a:hover{color:var(--orange)}\n.seo-table{\n  width:100%;border-collapse:collapse;font-size:.86rem;margin-top:12px;\n  background:#fff;border:1px solid var(--line);border-radius:var(--radius-sm);overflow:hidden;\n}\n.seo-table caption{\n  text-align:left;padding:14px 16px;background:var(--navy);color:#fff;\n  font-family:var(--font-display);font-weight:700;font-size:1.25rem;\n  letter-spacing:-.005em;\n}\n.seo-table th,.seo-table td{padding:12px 16px;text-align:left;border-bottom:1px solid var(--line)}\n.seo-table th{\n  background:var(--bg-alt);color:var(--ink);\n  font-family:var(--font-display);font-weight:700;\n  font-size:.76rem;text-transform:uppercase;letter-spacing:.06em;\n}\n.seo-table tr:last-child td{border-bottom:0}\n.seo-table tr:nth-child(even){background:#FAFBFC}\n.seo-table .muted-cell{color:var(--muted);font-style:italic;text-align:center;padding:20px}\n\n\/* =========================================================\n   Utilidades + estados\n   ========================================================= *\/\n.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}\n.skeleton{background:linear-gradient(90deg,#F1F5F9 25%,#E2E8F0 50%,#F1F5F9 75%);background-size:200% 100%;animation:sk 1.4s infinite;border-radius:6px;color:transparent}\n@keyframes sk{0%{background-position:200% 0}100%{background-position:-200% 0}}\n.error{\n  background:#FEF2F2;border:1px solid #FECACA;color:#991B1B;\n  padding:14px 18px;border-radius:var(--radius-sm);font-size:.92rem;line-height:1.55;\n}\n.empty{color:var(--muted);font-size:.9rem;font-style:italic}\n\n\/* Di\u00e1logos (snippets) *\/\ndialog.snippets{border:none;border-radius:var(--radius);padding:0;max-width:560px;width:90%;box-shadow:var(--shadow-lg)}\ndialog.snippets::backdrop{background:rgba(22,26,54,.55)}\ndialog.snippets .head{padding:20px 24px;border-bottom:1px solid var(--line);display:flex;align-items:center;justify-content:space-between;gap:12px}\ndialog.snippets .head h3{margin:0;font-size:1.05rem;color:var(--navy);font-family:var(--font-display);font-weight:800}\ndialog.snippets .head button{border:0;background:transparent;font-size:1.5rem;cursor:pointer;color:var(--ink-soft)}\ndialog.snippets .body{padding:20px 24px;max-height:50vh;overflow:auto}\ndialog.snippets blockquote{margin:0 0 14px;padding:14px 18px;border-left:3px solid var(--orange);background:var(--bg-alt);border-radius:6px;font-size:.92rem;color:var(--ink-soft)}\n\n\/* Heatmap (por si lo activan) *\/\n.hm-meta{display:flex;flex-wrap:wrap;gap:10px;align-items:center;font-size:.84rem;color:var(--ink-soft);margin-bottom:16px}\n.hm-meta .pill{background:var(--navy);color:#fff;padding:5px 14px;border-radius:999px;font-weight:600;font-size:.74rem;font-family:var(--font-display)}\n.hm-meta .pill.pill-id{background:var(--navy-soft);color:var(--navy)}\n.hm-meta .pill.pill-fallback{background:var(--orange);color:var(--navy)}\n.hm-scroll{overflow-x:auto;overflow-y:hidden;-webkit-overflow-scrolling:touch;max-width:100%}\ntable.heatmap{border-collapse:separate;border-spacing:3px;width:max-content;min-width:100%;font-size:1.1rem}\ntable.heatmap th, table.heatmap td{padding:0}\ntable.heatmap thead th{font-weight:700;color:var(--ink-soft);text-align:center;padding:8px 6px;writing-mode:horizontal-tb;white-space:nowrap;font-family:var(--font-display);font-size:.74rem;text-transform:uppercase;letter-spacing:.04em}\ntable.heatmap tbody th{text-align:left;padding:8px 14px 8px 0;color:var(--ink);font-weight:500;white-space:nowrap;max-width:280px;overflow:hidden;text-overflow:ellipsis}\ntable.heatmap tbody th.person-cell .person-info{display:flex;align-items:center;gap:10px}\ntable.heatmap tbody th .avatar{width:36px !important;height:36px !important;border-radius:50%;object-fit:cover;flex:0 0 36px;border:2px solid var(--line)}\ntable.heatmap tbody th .avatar-placeholder{width:36px;height:36px;border-radius:50%;background:var(--navy-soft);color:var(--navy);display:flex;align-items:center;justify-content:center;font-weight:700;font-size:.72rem;flex:0 0 36px;border:2px solid var(--line);font-family:var(--font-display)}\ntable.heatmap tbody th .person-text{display:flex;flex-direction:column;min-width:0}\ntable.heatmap tbody th .person-name{font-weight:600;color:var(--navy);overflow:hidden;text-overflow:ellipsis;font-family:var(--font-display);letter-spacing:-.005em}\ntable.heatmap tbody th .grupo{display:flex;align-items:center;gap:5px;font-size:.7rem;color:var(--muted);font-weight:500;overflow:hidden;text-overflow:ellipsis;margin-top:2px}\ntable.heatmap tbody th .group-logo{width:14px !important;height:14px !important;object-fit:contain;flex:0 0 14px}\ntable.heatmap td.cell{width:46px;height:36px;border-radius:6px;text-align:center;color:#0F172A;cursor:pointer;transition:transform .12s ease;font-variant-numeric:tabular-nums;font-size:.72rem;font-weight:600}\ntable.heatmap td.cell:hover{transform:scale(1.08);outline:2px solid var(--navy)}\ntable.heatmap td.cell[data-level=\"0\"]{background:var(--hm-0);color:var(--muted)}\ntable.heatmap td.cell[data-level=\"1\"]{background:var(--hm-1)}\ntable.heatmap td.cell[data-level=\"2\"]{background:var(--hm-2)}\ntable.heatmap td.cell[data-level=\"3\"]{background:var(--hm-3);color:#fff}\ntable.heatmap td.cell[data-level=\"4\"]{background:var(--hm-4);color:#fff}\ntable.heatmap td.cell[data-level=\"5\"]{background:var(--hm-5);color:#fff}\n.hm-legend{display:flex;align-items:center;gap:8px;margin-top:14px;font-size:.75rem;color:var(--ink-soft)}\n.hm-legend .scale{display:flex;border-radius:4px;overflow:hidden;border:1px solid var(--line)}\n.hm-legend .scale span{width:24px;height:12px;display:block}\n\n\/* Hemiciclo groups (pills bajo el SVG) *\/\n.hemi-groups{display:flex;flex-wrap:wrap;gap:8px;margin-top:18px}\n.hemi-group{display:inline-flex;align-items:center;gap:7px;font-size:.78rem;padding:7px 12px;background:#fff;border:1px solid var(--line);border-radius:999px;color:var(--ink);transition:border-color .12s ease;line-height:1.2}\n.hemi-group:hover{border-color:var(--navy)}\n.hemi-group .logo{width:18px !important;height:18px !important;object-fit:contain;flex:0 0 18px;border-radius:50%;background:transparent}\n.hemi-group .dot{width:10px;height:10px;border-radius:50%;display:inline-block;flex:0 0 10px}\n.hemi-group .nm{font-weight:600;font-family:var(--font-display)}\n.hemi-group .ct{color:var(--muted);margin-left:2px;font-weight:600;font-variant-numeric:tabular-nums}\n.hemi-wrap{position:relative;width:100%;max-width:580px;margin:0 auto}\n.hemi-wrap svg{width:100%;height:auto;display:block}\n.hemi-wrap .seat{transition:stroke-width .12s ease, filter .12s ease;cursor:pointer}\n.hemi-wrap .seat:hover{stroke:var(--navy);stroke-width:1.5;filter:brightness(1.15) drop-shadow(0 1px 2px rgba(0,0,0,.25))}\n.hemi-tooltip{position:absolute;pointer-events:none;background:rgba(31,37,71,.97);color:#fff;padding:11px 13px;border-radius:8px;font-size:.78rem;line-height:1.4;z-index:10;opacity:0;transition:opacity .1s;box-shadow:0 8px 20px rgba(0,0,0,.25);font-family:var(--font-display);max-width:260px}\n.hemi-tooltip.visible{opacity:1}\n.hemi-tooltip .ttl{font-weight:700;margin-bottom:4px;line-height:1.25}\n.hemi-tooltip .grp{display:flex;align-items:center;gap:6px;opacity:.95;font-size:.72rem;margin-bottom:6px}\n.hemi-tooltip .grp img{width:16px !important;height:16px !important;object-fit:contain;background:#fff;border-radius:50%;padding:1px;flex:0 0 16px}\n.hemi-tooltip .vt{display:inline-block;padding:3px 9px;border-radius:999px;font-weight:700;font-size:.7rem}\n.hemi-tooltip .vt.yes{background:#22C55E;color:#fff}\n.hemi-tooltip .vt.no{background:#EF4444;color:#fff}\n.hemi-tooltip .vt.abstention{background:#F59E0B;color:#fff}\n.hemi-tooltip .vt.no_vote{background:#111827;color:#fff}\n.hemi-meta .pill.aprobada{background:#16A34A}\n.hemi-meta .pill.rechazada{background:#DC2626}\n\n\/* Hemiciclo *\/\n.hemi-wrap{position:relative;width:100%;max-width:580px;margin:0 auto}\n.hemi-wrap svg{width:100%;height:auto;display:block}\n.hemi-totals{display:grid;grid-template-columns:repeat(4,1fr);gap:12px;margin:16px 0 16px}\n.hemi-total{padding:14px 12px;border-radius:var(--radius-sm);background:#fff;border:1px solid var(--line);text-align:center}\n.hemi-total .lbl{font-size:.68rem;color:var(--muted);text-transform:uppercase;letter-spacing:.06em;font-weight:700}\n.hemi-total .val{font-family:var(--font-display);font-size:1.4rem;font-weight:800;display:block;margin-top:4px;color:var(--navy);letter-spacing:-.02em}\n.hemi-total.yes .val{color:#16A34A}\n.hemi-total.no .val{color:#DC2626}\n.hemi-total.abs .val{color:var(--orange)}\n\n\/* Pregunta del d\u00eda *\/\n.pregunta-card{\n  padding:26px 28px;background:#fff;\n  border:1px solid var(--line);border-radius:var(--radius-sm);\n  border-top:4px solid var(--orange);\n}\n.pregunta-meta{font-size:.72rem;color:var(--muted);margin-bottom:10px;text-transform:uppercase;letter-spacing:.08em;font-weight:700;font-family:var(--font-display)}\n.pregunta-q{\n  font-family:var(--font-display);font-size:1.2rem;font-weight:800;\n  color:var(--navy);margin:0 0 14px;line-height:1.3;letter-spacing:-.015em;\n}\n.pregunta-a{font-size:1.45rem;color:var(--ink);line-height:1.7;border-left:3px solid var(--navy);padding:4px 0 4px 18px;margin-top:6px}\n\n\n\n\/* ==========================================================\n   AJUSTES UX (compact hero \u00b7 loading pill a la derecha \u00b7\n   sin aside repetido) \u2014 aplicado a todos los productos\n   ========================================================== *\/\n.vc-hero{\n  padding:42px 24px 34px !important;\n}\n.vc-hero::before{opacity:.85}\n.vc-hero-inner{\n  gap:18px;\n  align-items:center !important;\n}\n@media(min-width:880px){\n  .vc-hero-inner{\n    grid-template-columns:minmax(0,1fr) auto !important;\n    align-items:center !important;\n    gap:32px;\n  }\n}\n.vc-kicker{\n  margin:0 0 10px !important;\n  font-size:.72rem !important;\n  letter-spacing:.16em !important;\n}\n.vc-hero h1{\n  font-size:clamp(1.65rem,3.2vw,2.4rem) !important;\n  margin:0 0 10px !important;\n  line-height:1.08 !important;\n  letter-spacing:-.02em !important;\n}\n.vc-hero-lead{\n  font-size:clamp(.92rem,1.05vw,1rem) !important;\n  margin:0 !important;\n  max-width:72ch;\n  line-height:1.5 !important;\n}\n\n\/* Columna derecha: pill arriba, CTA debajo *\/\n.vc-hero-right{\n  display:flex;flex-direction:column;align-items:flex-end;gap:12px;\n}\n.vc-hero-cta{\n  padding:11px 14px 11px 22px !important;\n  font-size:.88rem !important;\n  align-self:flex-end !important;\n}\n.vc-hero-cta .ico{width:26px;height:26px;font-size:1.25rem}\n\n\/* Loading \/ \"Actualizado\u2026\" pill \u2014 sin posici\u00f3n absoluta *\/\n.vc-hero #updated-pill{\n  position:static !important;\n  display:inline-flex;align-items:center;gap:8px;\n  background:rgba(255,255,255,.06) !important;\n  border:1px solid rgba(255,255,255,.16) !important;\n  color:rgba(255,255,255,.82) !important;\n  padding:5px 12px;border-radius:999px;\n  font-size:1.1rem;letter-spacing:.04em;\n  margin:0 !important;\n  max-width:min(80vw,360px);\n  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;\n  align-self:flex-end;\n}\n.vc-hero #updated-pill .dot{\n  width:7px;height:7px;border-radius:50%;\n  background:#4ADE80;\n  box-shadow:0 0 0 3px rgba(74,222,128,.16);\n  flex-shrink:0;\n}\n.vc-hero #updated-pill.err{\n  background:rgba(252,165,165,.08) !important;\n  border-color:rgba(252,165,165,.28) !important;\n  color:#FCA5A5 !important;\n}\n.vc-hero #updated-pill.err .dot{\n  background:#FCA5A5;\n  box-shadow:0 0 0 3px rgba(252,165,165,.18);\n}\n@media(max-width:879px){\n  .vc-hero{padding:32px 18px 26px !important;}\n  .vc-hero-right{flex-direction:row;flex-wrap:wrap;align-items:center;gap:10px;align-self:flex-start}\n  .vc-hero #updated-pill{align-self:auto}\n}\n\n\/* Quitar la aside \"product-info\" que repite los textos del hero \u00b7 grid a 1 columna *\/\n.product-grid .product-info,\n.product-grid.reverse .product-info{\n  display:none !important;\n}\n.product-grid,\n.product-grid.reverse{\n  grid-template-columns:1fr !important;\n}\n.product-grid > .product-content{\n  order:1 !important;\n  border:0 !important;\n}\n\n\/* Acercar los gr\u00e1ficos al header *\/\n.wrap{padding-top:32px !important;}\n@media(max-width:768px){.wrap{padding-top:22px !important}}\n\n\/* =========================================================\n   FREN \u00b7 Sankey temas\u2192partidos + Afinidad de voto (Vinces)\n   ========================================================= *\/\n.tc-filters{display:flex;flex-wrap:wrap;gap:7px;margin:16px 0 20px;padding-bottom:18px;border-bottom:1px solid var(--line)}\n.tc-btn{border:1px solid var(--line);background:#fff;color:var(--ink-soft);border-radius:999px;padding:6px 15px;font-size:.8rem;cursor:pointer;font-family:var(--font-display);font-weight:600;transition:all .15s;line-height:1.2}\n.tc-btn:hover{border-color:var(--navy);color:var(--navy)}\n.tc-btn.active{background:var(--navy);border-color:var(--navy);color:#fff}\n.sankey-wrap{position:relative;width:100%;min-height:360px}\n.sk-svg{width:100%;height:auto;display:block}\n.sk-label{font:600 11px var(--font-display),sans-serif;fill:var(--ink-soft)}\n.sk-node{cursor:pointer}\n.sk-link{transition:stroke-opacity .12s;cursor:pointer}\n.sk-link:hover{stroke-opacity:.72}\n.sk-tema:hover .sk-label{fill:var(--ink)}\n.afinidad-wrap{position:relative;min-height:520px;width:100%}\n.afi-svg{width:100%;height:auto;display:block}\n.afi-label{font:600 11px var(--font-display),sans-serif;fill:var(--ink-soft);transition:opacity .2s}\n.afi-link{cursor:pointer;transition:stroke-opacity .2s,stroke-width .2s,stroke .2s}\n.afi-tooltip{position:absolute;pointer-events:none;background:var(--navy);color:#fff;padding:9px 12px;border-radius:9px;font-size:.78rem;line-height:1.4;max-width:240px;opacity:0;transition:opacity .12s;z-index:5;box-shadow:0 8px 24px rgba(31,37,71,.28)}\n.afi-tooltip.visible{opacity:1}\n.afi-tooltip .ttl{font-weight:700;margin-bottom:2px;font-family:var(--font-display)}\n.afi-legend{display:flex;flex-wrap:wrap;gap:18px;font-size:.78rem;color:var(--ink-soft);margin-top:14px}\n.afi-legend .dash{display:inline-block;width:22px;border-top:3px solid var(--muted);vertical-align:middle;margin-right:4px}\n.tema-hint{font-size:1.1rem;color:var(--muted);margin:12px 0 0}\n.tema-detail{margin-top:16px;border:1px solid var(--line);border-radius:14px;padding:18px 20px;background:var(--bg-alt)}\n.tema-detail .td-head{display:flex;align-items:center;gap:10px;margin-bottom:12px}\n.tema-detail .td-dot{width:14px;height:14px;border-radius:4px;display:inline-block}\n.tema-detail h4{margin:0;font-size:1.05rem;font-family:var(--font-display);color:var(--navy)}\n\/* Bot\u00f3n \"Saber m\u00e1s\" en cabeceras de detalle + modal de contacto *\/\n.saber-mas{margin-left:auto;display:inline-flex;align-items:center;gap:5px;border:1.5px solid var(--orange);background:var(--orange-soft);color:var(--accent-dark);font-family:var(--font-display);font-weight:700;font-size:.72rem;line-height:1;padding:5px 12px;border-radius:999px;cursor:pointer;white-space:nowrap;transition:background .15s,color .15s,transform .15s}\n.saber-mas:hover{background:var(--orange);color:var(--navy);transform:translateY(-1px)}\n.vc-cmodal{position:fixed;inset:0;z-index:9999;display:none;align-items:center;justify-content:center;background:rgba(22,26,54,.55);backdrop-filter:blur(3px);padding:20px}\n.vc-cmodal.open{display:flex}\n.vc-cmodal .box{background:#fff;border-radius:18px;max-width:430px;width:100%;padding:30px 30px 26px;box-shadow:0 24px 60px rgba(31,37,71,.3)}\n.vc-cmodal h4{font-family:var(--font-display);font-weight:800;font-size:1.3rem;color:var(--navy);margin:0 0 10px;letter-spacing:-.02em}\n.vc-cmodal p{font-family:var(--font-body);font-size:1.45rem;color:var(--ink-soft);line-height:1.55;margin:0 0 22px}\n.vc-cmodal .acts{display:flex;gap:8px;align-items:center;flex-wrap:wrap}\n.vc-cmodal .cta{display:inline-flex;align-items:center;gap:9px;background:var(--orange);color:var(--navy);font-family:var(--font-display);font-weight:700;font-size:1.45rem;padding:12px 24px;border-radius:999px;text-decoration:none;border:0;cursor:pointer;transition:transform .15s,background .2s;box-shadow:0 6px 18px rgba(243,165,58,.28)}\n.vc-cmodal .cta:hover{transform:translateY(-1px);background:#f7b35a}\n.vc-cmodal .x{background:none;border:0;cursor:pointer;font-family:var(--font-display);font-weight:600;font-size:.92rem;color:var(--ink-soft);padding:10px 8px;margin-left:auto}\n.vc-cmodal .x:hover{color:var(--navy)}\n.tema-detail h5{margin:0 0 10px;font-size:.7rem;text-transform:uppercase;letter-spacing:.06em;color:var(--muted);font-family:var(--font-display);font-weight:700}\n.td-cols{display:flex;gap:28px;flex-wrap:wrap}\n.td-col{flex:1 1 240px;min-width:220px}\n.td-bar-row{display:flex;align-items:center;gap:10px;margin-bottom:8px;font-size:.84rem}\n.td-bar-lbl{flex:0 0 120px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n.td-bar{flex:1;height:10px;background:var(--line);border-radius:5px;overflow:hidden}\n.td-bar-fill{display:block;height:100%;border-radius:5px}\n.td-bar-val{flex:0 0 auto;color:var(--muted);font-variant-numeric:tabular-nums}\n.td-iv{display:flex;align-items:center;gap:11px;margin-bottom:10px}\n.td-rank{flex:0 0 18px;text-align:center;font-weight:700;color:var(--muted);font-size:.8rem}\n.td-avatar{width:36px;height:36px;border-radius:50%;object-fit:cover;flex:0 0 36px}\n.td-avatar-ph{display:flex;align-items:center;justify-content:center;background:var(--navy);color:#fff;font-size:.72rem;font-weight:700}\n.td-iv-text{display:flex;flex-direction:column;min-width:0;flex:1}\n.td-iv-name{font-weight:600;font-size:.86rem;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n.td-iv-group{font-size:.75rem;color:var(--muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n.afinidad-layout{display:flex;gap:20px;flex-wrap:wrap;align-items:flex-start}\n.afinidad-layout .afinidad-wrap{flex:1 1 420px;min-width:300px}\n.afinidad-detail{flex:0 0 290px;border:1px solid var(--line);border-radius:14px;padding:18px 20px;background:var(--bg-alt);align-self:stretch}\n.afi-detail-hint{font-size:.84rem;color:var(--muted);margin:0}\n.afinidad-detail h4{margin:0;font-size:1.02rem;font-family:var(--font-display);color:var(--navy)}\n.afinidad-detail h5{margin:16px 0 10px;font-size:.7rem;text-transform:uppercase;letter-spacing:.06em;color:var(--muted);font-family:var(--font-display);font-weight:700}\n.ad-head{display:flex;align-items:center;gap:11px}\n.ad-logo{width:40px;height:40px;border-radius:50%;object-fit:contain;background:#fff;flex:0 0 40px;border:1px solid var(--line)}\n.ad-sub{font-size:.75rem;color:var(--muted)}\n.ad-vote,.ad-coes{display:flex;align-items:center;gap:9px;margin-bottom:7px;font-size:.8rem}\n.ad-vote-lbl,.ad-coes-lbl{flex:0 0 92px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n.ad-vote-bar,.ad-coes-bar{flex:1;height:9px;background:var(--line);border-radius:5px;overflow:hidden}\n.ad-vote-bar>span,.ad-coes-bar>span{display:block;height:100%;border-radius:5px;background:var(--navy)}\n.ad-vote.favor .ad-vote-bar>span{background:#22C55E}\n.ad-vote.contra .ad-vote-bar>span{background:#EF4444}\n.ad-vote.abs .ad-vote-bar>span{background:#F59E0B}\n.ad-vote.nv .ad-vote-bar>span{background:#111827}\n.ad-vote-val,.ad-coes-val{flex:0 0 auto;color:var(--muted);font-variant-numeric:tabular-nums}\n.afi-node{cursor:pointer;transition:opacity .2s}\n.muted-cell{color:var(--muted);font-style:italic}\n\n.temas-act-wrap,\n.tc-chart-wrap{width:100% !important;}\n.temas-act-wrap canvas,\n.tc-chart-wrap canvas{\n  width:100% !important;\n  max-width:100% !important;\n}\n\n\/* FREN \u2014 Reparto tem\u00e1tico global como barras horizontales (sustituye al donut) *\/\n#fren-summary{display:block !important}\n#fren-summary .donut-mini{display:none !important}\n#fren-top-temas{\n  display:block;\n  margin:8px 0 18px;\n}\n#fren-top-temas h4{\n  font-family:var(--font-display);\n  font-size:.78rem;letter-spacing:.08em;text-transform:uppercase;\n  color:var(--muted);font-weight:700;\n  margin:0 0 12px;\n}\n.tema-bar-row{\n  display:grid;\n  grid-template-columns:minmax(140px,180px) 1fr 52px;\n  align-items:center;gap:14px;\n  padding:7px 0;\n  border-bottom:1px solid rgba(0,0,0,.05);\n  font-size:.88rem;\n}\n.tema-bar-row:last-child{border-bottom:0}\n.tema-bar-row .nm{\n  color:var(--ink);font-weight:600;\n  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;\n}\n.tema-bar-row .bar{\n  position:relative;height:10px;\n  background:rgba(0,0,0,.05);\n  border-radius:999px;overflow:hidden;\n}\n.tema-bar-row .bar .fill{\n  display:block;height:100%;\n  border-radius:999px;\n  transition:width .6s cubic-bezier(.2,.7,.2,1);\n}\n.tema-bar-row .pct{\n  font-variant-numeric:tabular-nums;\n  font-weight:700;font-family:var(--font-display);\n  color:var(--navy);text-align:right;\n  font-size:1.1rem;\n}\n@media(max-width:640px){\n  .tema-bar-row{grid-template-columns:1fr 44px;gap:8px;row-gap:4px}\n  .tema-bar-row .nm{grid-column:1\/-1;font-size:1.1rem}\n  .tema-bar-row .bar{grid-column:1\/2}\n  .tema-bar-row .pct{grid-column:2\/3;font-size:.78rem}\n}\n\n\/* ==========================================================\n   HERO IMPACTO \u2014 titular grande, LIVE pulsante, malla + glow,\n   chips de alcance. Sobrescribe los ajustes \"compact\".\n   ========================================================== *\/\n.vc-hero{\n  padding:46px 24px 40px !important;\n  background:\n    radial-gradient(120% 140% at 85% -10%, var(--navy-light) 0%, var(--navy) 42%, var(--navy-deep) 100%) !important;\n}\n\/* Malla de puntos sutil sobre el navy *\/\n.vc-hero::before{\n  background:\n    radial-gradient(circle at 88% 12%, rgba(243,165,58,.16), transparent 42%),\n    radial-gradient(circle at 4% 100%, rgba(31,168,134,.10), transparent 52%),\n    radial-gradient(rgba(255,255,255,.05) 1px, transparent 1px) !important;\n  background-size:auto, auto, 22px 22px !important;\n  opacity:1 !important;\n}\n.vc-hero::after{\n  height:2px !important;\n  background:linear-gradient(90deg, transparent, var(--orange), transparent) !important;\n  opacity:.6;\n}\n.vc-hero-inner{\n  align-items:center !important;\n  gap:28px !important;\n}\n@media(min-width:880px){\n  .vc-hero-inner{\n    grid-template-columns:minmax(0,1fr) auto !important;\n    align-items:center !important;\n    gap:56px !important;\n  }\n}\n\n\/* Kicker con punto LIVE pulsante *\/\n.vc-kicker{\n  display:inline-flex !important;align-items:center;gap:9px;\n  margin:0 0 13px !important;\n  font-size:.72rem !important;\n  letter-spacing:.18em !important;\n  padding:6px 14px 6px 11px;\n  border:1px solid rgba(243,165,58,.32);\n  border-radius:999px;\n  background:rgba(243,165,58,.08);\n  color:var(--orange);\n}\n.vc-kicker::before{content:none !important}\n.vc-live-dot{\n  position:relative;width:8px;height:8px;border-radius:50%;\n  background:#4ADE80;flex-shrink:0;\n}\n.vc-live-dot::after{\n  content:\"\";position:absolute;inset:0;border-radius:50%;\n  background:#4ADE80;\n}\n@media(prefers-reduced-motion:no-preference){\n  .vc-live-dot::after{animation:vcLivePulse 1.8s ease-out infinite}\n}\n@keyframes vcLivePulse{\n  0%{transform:scale(1);opacity:.7}\n  70%{transform:scale(3);opacity:0}\n  100%{transform:scale(3);opacity:0}\n}\n\n\/* Titular grande con segunda l\u00ednea destacada *\/\n.vc-hero h1{\n  font-size:clamp(1.7rem,3.3vw,2.7rem) !important;\n  font-weight:800 !important;\n  line-height:1 !important;\n  letter-spacing:-.035em !important;\n  margin:0 0 14px !important;\n  white-space:nowrap;\n}\n.vc-hero h1 .hl{\n  position:relative;\n  color:var(--orange);\n  white-space:nowrap;\n}\n.vc-hero h1 .hl::after{\n  content:\"\";position:absolute;left:0;right:0;bottom:.04em;height:.09em;\n  background:linear-gradient(90deg,var(--orange),rgba(243,165,58,.15));\n  border-radius:999px;\n}\n\n.vc-hero-lead{\n  font-size:clamp(.9rem,1vw,1.02rem) !important;\n  color:rgba(255,255,255,.82) !important;\n  max-width:60ch !important;\n  line-height:1.58 !important;\n  margin:0 0 20px !important;\n}\n\n\/* Fila de chips de alcance *\/\n.vc-hero-chips{\n  display:flex;flex-wrap:wrap;gap:10px;margin:0;padding:0;list-style:none;\n}\n.vc-hero-chips li{\n  display:inline-flex;align-items:center;gap:8px;\n  font-family:var(--font-display);\n  font-size:1.1rem;font-weight:600;\n  color:rgba(255,255,255,.9);\n  background:rgba(255,255,255,.06);\n  border:1px solid rgba(255,255,255,.14);\n  padding:8px 14px;border-radius:999px;\n  backdrop-filter:blur(6px);\n  transition:transform .15s ease, border-color .15s ease, background .15s ease;\n}\n.vc-hero-chips li:hover{\n  transform:translateY(-2px);\n  border-color:rgba(243,165,58,.4);\n  background:rgba(243,165,58,.1);\n}\n.vc-hero-chips .chip-ico{\n  color:var(--orange);display:inline-flex;flex-shrink:0;\n}\n@media(prefers-reduced-motion:reduce){\n  .vc-hero-chips li:hover{transform:none}\n}\n\n\/* CTA m\u00e1s presente *\/\n.vc-hero-cta{\n  padding:14px 18px 14px 26px !important;\n  font-size:1.45rem !important;\n  box-shadow:0 8px 24px rgba(0,0,0,.22);\n}\n.vc-hero-cta .ico{width:30px;height:30px;font-size:1.45rem}\n\n@media(max-width:879px){\n  .vc-hero{padding:44px 18px 36px !important;}\n  .vc-hero h1{font-size:clamp(1.7rem,7vw,2.6rem) !important;white-space:normal}\n  .vc-hero h1 .hl{white-space:normal}\n}\n\n\/* ==========================================================\n   RUEDA VERTICAL (estilo cr\u00e9ditos) \u2014 rail derecho del hero\n   ========================================================== *\/\n\/* Rail: pill arriba, tarjeta de la rueda en medio, CTA abajo *\/\n.vc-hero-right{\n  gap:18px !important;\n  align-self:center !important;\n}\n\/* Tarjeta que enmarca la rueda *\/\n.vc-hero-rail-card{\n  width:286px;\n  background:rgba(255,255,255,.045);\n  border:1px solid rgba(255,255,255,.12);\n  border-radius:16px;\n  padding:16px 16px 8px;\n  backdrop-filter:blur(6px);\n}\n.vc-wheel-label{\n  display:block;\n  font-family:var(--font-display);\n  font-size:.85rem;font-weight:700;\n  letter-spacing:.18em;text-transform:uppercase;\n  color:var(--orange);\n  margin:0 0 12px 2px;\n}\n.vc-hero-wheel{\n  position:relative;\n  height:184px;\n  overflow:hidden;\n  -webkit-mask-image:linear-gradient(180deg,transparent 0,#000 20%,#000 80%,transparent 100%);\n  mask-image:linear-gradient(180deg,transparent 0,#000 18%,#000 82%,transparent 100%);\n}\n.vc-hero-wheel-track{\n  display:flex;flex-direction:column;\n  will-change:transform;\n}\n@media(prefers-reduced-motion:no-preference){\n  .vc-hero-wheel-track{animation:vcWheelScroll 16s linear infinite}\n}\n.vc-hero-wheel:hover .vc-hero-wheel-track{animation-play-state:paused}\n@keyframes vcWheelScroll{\n  from{transform:translateY(0)}\n  to{transform:translateY(-50%)}\n}\n.vc-wheel-chip{\n  display:flex;align-items:center;gap:10px;\n  margin-bottom:10px;\n  font-family:var(--font-display);\n  font-size:1.1rem;font-weight:600;line-height:1.25;\n  color:rgba(255,255,255,.92);\n  background:rgba(255,255,255,.06);\n  border:1px solid rgba(255,255,255,.14);\n  padding:10px 14px;border-radius:12px;\n  backdrop-filter:blur(6px);\n}\n.vc-wheel-chip .chip-ico{\n  color:var(--orange);display:inline-flex;flex-shrink:0;\n}\n\/* Acciones bajo el texto: bot\u00f3n-logo + badge \"Actualizado\" *\/\n.vc-hero-actions{\n  display:flex;align-items:center;flex-wrap:wrap;\n  gap:16px;margin-top:22px;\n}\n.vc-hero-actions .vc-hero-cta{align-self:auto !important}\n.vc-hero-actions #updated-pill{align-self:auto !important}\n\/* Bot\u00f3n \"Contacta\" \u2014 ocupa el hueco a la derecha de la fila de acciones *\/\n.vc-hero-contact{\n  margin-left:auto;align-self:auto !important;\n  display:inline-flex;align-items:center;gap:9px;\n  padding:11px 22px;border-radius:999px;\n  background:var(--orange);color:var(--navy);\n  font:700 1.45rem var(--font-display),sans-serif;letter-spacing:.01em;\n  text-decoration:none;border:1px solid transparent;white-space:nowrap;\n  transition:transform .15s ease,box-shadow .2s ease,background .2s ease;\n  box-shadow:0 6px 18px rgba(243,165,58,.26);\n}\n.vc-hero-contact:hover{transform:translateY(-1px);background:#f7b35a;box-shadow:0 10px 24px rgba(243,165,58,.36)}\n.vc-hero-contact svg{width:17px;height:17px;display:block}\n@media(max-width:879px){.vc-hero-contact{margin-left:0}}\n\n\/* Bot\u00f3n = logotipo completo de PolicyAlert (sin texto) *\/\n.vc-hero-cta{\n  padding:10px 18px !important;\n  gap:10px !important;\n}\n.vc-cta-logo{display:inline-flex;align-items:center;flex-shrink:0}\n.vc-cta-logo svg{height:30px;width:auto;display:block}\n\/* Icono \"abrir en nueva ventana\": badge circular navy \u2192 se\u00f1ala que es un enlace *\/\n.vc-cta-ext{\n  width:26px;height:26px;border-radius:50%;flex-shrink:0;\n  background:var(--navy);color:#fff;\n  display:inline-flex;align-items:center;justify-content:center;\n  transition:transform .15s ease, background .2s ease;\n}\n.vc-cta-ext svg{width:14px;height:14px;display:block}\n.vc-hero-cta:hover .vc-cta-ext{background:var(--navy-light);transform:translate(1px,-1px)}\n\n@media(max-width:879px){\n  .vc-hero-rail-card{width:100%}\n  .vc-hero-wheel{height:148px}\n  .vc-cta-logo svg{height:30px}\n}\n\n<\/style>\n<style id=\"rubrika-type\">\n\/* === Sistema tipogr\u00e1fico Rubrika + hero padding (jun 2026) ===\n   T\u00edtulos\/Subt\u00edtulos: Libre Franklin \u00b7 Textos\/Botones: Lato *\/\n.vc-hero{ padding:150px 24px 100px !important; }\n@media(max-width:879px){ .vc-hero{ padding:110px 18px 64px !important; } }\n\/* T\u00edtulos \u2014 Libre Franklin 600 \u00b7 48\/58 *\/\n.vc-hero h1{\n  font-family:\"Libre Franklin\",sans-serif !important;\n  font-weight:600 !important; font-size:48px !important;\n  line-height:58px !important; letter-spacing:-.01em !important;\n  white-space:normal !important;\n}\n@media(max-width:879px){ .vc-hero h1{ font-size:34px !important; line-height:42px !important; } }\n\/* Subt\u00edtulos \u2014 Libre Franklin 600 \u00b7 32\/38 *\/\n.product-name, .product-content-header h3, .faq-section > h2, .seo-block h2{\n  font-family:\"Libre Franklin\",sans-serif !important;\n  font-weight:600 !important; font-size:32px !important;\n  line-height:38px !important; letter-spacing:-.01em !important;\n}\n@media(max-width:879px){\n  .product-name, .product-content-header h3, .faq-section > h2, .seo-block h2{\n    font-size:25px !important; line-height:31px !important;\n  }\n}\n\/* Textos \u2014 Lato 400 \u00b7 16\/24 *\/\n.vc-hero-lead, .product-content-header .sub, .faq-intro,\n.faq-list details p, .pane-cta-text, .seo-item p{\n  font-family:\"Lato\",sans-serif !important;\n  font-weight:400 !important; font-size:16px !important; line-height:24px !important;\n}\n\/* Botones \u2014 Lato 700 \u00b7 15\/15 *\/\n.vc-hero-cta, .vc-hero-contact, .pane-cta, .vc-cmodal .cta,\n.wt-cta-btn, .saber-mas, .ley-follow{\n  font-family:\"Lato\",sans-serif !important;\n  font-weight:700 !important; font-size:15px !important; line-height:15px !important;\n}\n<\/style>\n\n\n\n<!-- HERO (estilo Vinces) -->\n<section class=\"vc-hero\" aria-label=\"Cabecera de producto\" data-vc-hero-injected=\"1\">\n  <div class=\"vc-hero-inner\">\n    <div>\n      <span class=\"vc-kicker\"><span class=\"vc-live-dot\"><\/span>FREN \u00b7 IA para Assuntos P\u00fablicos<\/span>\n      <h1>Toda a pol\u00edtica espanhola, numa <span class=\"hl\">pergunta<\/span><\/h1>\n      <p class=\"vc-hero-lead\"><strong>O FREN<\/strong> \u00e9 o assistente de IA especializado em pol\u00edtica, regulamenta\u00e7\u00e3o e assuntos p\u00fablicos. Faz-lhe perguntas em linguagem natural e recebe respostas fundamentadas \u2014 com gr\u00e1ficos, hemiciclos e tabelas \u2014 sempre citando a fonte oficial. <\/p>\n      <div class=\"vc-hero-actions\">\n        <a class=\"vc-hero-cta\" href=\"https:\/\/fren.democrata.es\/\" target=\"_blank\" rel=\"noopener\" aria-label=\"Abrir FREN\">\n          <span class=\"vc-cta-logo\" aria-hidden=\"true\"><svg width=\"1600\" height=\"413\" viewbox=\"0 0 1600 413\" fill=\"none\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\">\n<path d=\"M1323.7 403.902V85.5322H1399.43V403.902H1323.7ZM1399.43 219.176H1375.17C1377.15 187.102 1383.26 160.571 1393.51 139.584C1403.77 118.597 1417.38 102.955 1434.34 92.6598C1451.69 81.9683 1471.41 76.6226 1493.5 76.6226C1514.8 76.6226 1533.34 80.9784 1549.12 89.69C1565.29 98.0056 1577.71 110.677 1586.39 127.704C1595.46 144.732 1600 166.115 1600 191.853V403.902H1524.27V207.297C1524.27 192.645 1522.1 180.37 1517.76 170.47C1513.82 160.175 1507.7 152.453 1499.42 147.305C1491.14 142.158 1480.49 139.584 1467.47 139.584C1457.22 139.584 1447.75 141.762 1439.07 146.117C1430.79 150.077 1423.69 155.819 1417.77 163.343C1411.86 170.47 1407.32 178.984 1404.16 188.884C1401.01 198.387 1399.43 208.485 1399.43 219.176Z\" fill=\"#021666\"><\/path>\n<path d=\"M1259.27 212.642L1215.49 243.529C1215.49 209.871 1209.18 184.132 1196.56 166.313C1183.94 148.097 1165.79 138.99 1142.13 138.99C1118.07 138.99 1099.73 148.097 1087.1 166.313C1074.48 184.528 1068.17 210.861 1068.17 245.311C1068.17 278.969 1074.68 304.906 1087.7 323.121C1101.11 341.337 1120.24 350.444 1145.09 350.444C1162.83 350.444 1177.63 346.286 1189.46 337.971C1201.69 329.655 1210.17 316.984 1214.9 299.956H1294.77C1286.1 336.783 1268.35 364.898 1241.52 384.301C1215.1 403.308 1182.95 412.811 1145.09 412.811C1113.53 412.811 1086.12 406.08 1062.85 392.616C1039.57 379.153 1021.63 359.948 1009.01 335.001C996.778 309.658 990.665 279.761 990.665 245.311C990.665 209.277 996.778 178.786 1009.01 153.839C1021.63 128.496 1039.38 109.291 1062.25 96.2237C1085.13 83.1563 1111.76 76.6226 1142.13 76.6226C1172.89 76.6226 1199.52 83.3543 1222 96.8177C1244.48 110.281 1261.84 129.288 1274.07 153.839C1286.29 178.39 1292.41 207.891 1292.41 242.341V260.16H1022.02V212.642H1259.27Z\" fill=\"#021666\"><\/path>\n<path d=\"M792.156 403.902V85.5322H867.887V403.902H792.156ZM867.887 234.619H844.221C845.799 197.397 851.715 167.302 861.971 144.336C872.62 120.973 886.031 103.945 902.203 93.2538C918.375 82.1663 935.927 76.6226 954.86 76.6226C961.171 76.6226 967.087 77.4146 972.609 78.9985C978.526 80.5824 982.865 82.7603 985.626 85.5322V151.463C980.498 149.879 975.173 148.889 969.651 148.493C964.129 147.701 957.818 147.305 950.718 147.305C936.519 147.305 924.094 149.483 913.444 153.839C903.189 157.799 894.709 163.739 888.003 171.658C881.298 179.182 876.17 188.29 872.62 198.981C869.465 209.277 867.887 221.156 867.887 234.619Z\" fill=\"#021666\"><\/path>\n<path d=\"M491.455 403.902V0H571.328V403.902H491.455ZM549.437 63.5551V0H774.264V63.5551H549.437ZM549.437 241.153V177.598H751.781V241.153H549.437Z\" fill=\"#021666\"><\/path>\n<path fill-rule=\"evenodd\" clip-rule=\"evenodd\" d=\"M158.177 56.8847C161.891 48.5492 171.442 34.9247 191.903 34.9247C212.364 34.9247 221.909 48.5492 225.623 56.8847C276.075 170.119 311.514 238.738 377.368 350.791C395.105 378.863 373.34 408.807 346.341 407.131C305.492 405.094 259.976 380.641 217.245 357.684C208.665 353.075 200.198 348.526 191.903 344.231C183.611 348.525 175.146 353.072 166.569 357.68C123.835 380.637 78.3108 405.094 37.4591 407.131C10.4598 408.807 -11.3052 378.863 6.43224 350.791C72.2859 238.738 107.725 170.119 158.177 56.8847Z\" fill=\"#2069E7\"><\/path>\n<\/path><\/path><\/path><\/path><\/path><\/svg><\/span>\n          <span class=\"vc-cta-ext\" aria-hidden=\"true\"><svg width=\"16\" height=\"16\" viewbox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6\"><\/path><polyline points=\"15 3 21 3 21 9\"><\/polyline><line x1=\"10\" y1=\"14\" x2=\"21\" y2=\"3\"><\/line><\/svg><\/span>\n        <\/a>\n         <span class=\"updated\" id=\"updated-pill\" aria-live=\"polite\" style=\"background:rgba(255,255,255,.05);border-color:rgba(255,255,255,.14);color:rgba(255,255,255,.85)\">\n          <span class=\"dot\"><\/span>\n          <span id=\"updated-text\">A carregar dados\u2026<\/span>\n        <\/span>\n        <a class=\"vc-hero-contact\" href=\"https:\/\/vincesconsulting.com\/pt-pt\/contacto\/\" target=\"_blank\" rel=\"noopener\" aria-label=\"Contacta con Vinces\">\n          <svg viewbox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><path d=\"M4 4h16a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2z\"><\/path><polyline points=\"22,6 12,13 2,6\"><\/polyline><\/svg>\n          <span>Contacta-nos<\/span>\n        <\/a> \n      <\/div>\n    <\/div>\n    <div class=\"vc-hero-rail-card\" id=\"vc-hero-wheel\" role=\"group\" aria-label=\"Qu\u00e9 responde FREN\">\n      <span class=\"vc-wheel-label\">O que \u00e9 que respondes?<\/span>\n      <div class=\"vc-hero-wheel\">\n        <div class=\"vc-hero-wheel-track\">\n          <span class=\"vc-wheel-chip\"><span class=\"chip-ico\" aria-hidden=\"true\"><svg width=\"16\" height=\"16\" viewbox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M3 4h18M7 4v16M3 8h4M17 4v16M17 8h4M3 12h4M17 12h4M3 16h4M17 16h4\"><\/path><\/svg><\/span>Leis e regulamenta\u00e7\u00e3o<\/span>\n          <span class=\"vc-wheel-chip\"><span class=\"chip-ico\" aria-hidden=\"true\"><svg width=\"16\" height=\"16\" viewbox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2\"><\/path><circle cx=\"9\" cy=\"7\" r=\"4\"><\/circle><path d=\"M23 21v-2a4 4 0 0 0-3-3.87\"><\/path><path d=\"M16 3.13a4 4 0 0 1 0 7.75\"><\/path><\/svg><\/span>Decisores e partes interessadas<\/span>\n          <span class=\"vc-wheel-chip\"><span class=\"chip-ico\" aria-hidden=\"true\"><svg width=\"16\" height=\"16\" viewbox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M9 12l2 2 4-4\"><\/path><path d=\"M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0z\"><\/path><\/svg><\/span>Vota\u00e7\u00f5es no Congresso<\/span>\n          <span class=\"vc-wheel-chip\"><span class=\"chip-ico\" aria-hidden=\"true\"><svg width=\"16\" height=\"16\" viewbox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z\"><\/path><path d=\"M14 2v6h6M8 13h8M8 17h8\"><\/path><\/svg><\/span>Atas das Sess\u00f5es<\/span>\n          <span class=\"vc-wheel-chip\"><span class=\"chip-ico\" aria-hidden=\"true\"><svg width=\"16\" height=\"16\" viewbox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.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-9h4\"><\/path><path d=\"M18 14h-8M15 18h-5M10 6h8v4h-8z\"><\/path><\/svg><\/span>Atualidade pol\u00edtica<\/span>\n          <span class=\"vc-wheel-chip\"><span class=\"chip-ico\" aria-hidden=\"true\"><svg width=\"16\" height=\"16\" viewbox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\"><\/path><\/svg><\/span>Respostas com refer\u00eancia \u00e0 fonte<\/span>\n          <span class=\"vc-wheel-chip\"><span class=\"chip-ico\" aria-hidden=\"true\"><svg width=\"16\" height=\"16\" viewbox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M13 2 3 14h9l-1 8 10-12h-9z\"><\/path><\/svg><\/span>Dados oficiais em tempo real<\/span>\n          <!-- duplicado para loop infinito sin salto -->\n          <span class=\"vc-wheel-chip\" aria-hidden=\"true\"><span class=\"chip-ico\"><svg width=\"16\" height=\"16\" viewbox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M3 4h18M7 4v16M3 8h4M17 4v16M17 8h4M3 12h4M17 12h4M3 16h4M17 16h4\"><\/path><\/svg><\/span>Leis e regulamenta\u00e7\u00e3o<\/span>\n          <span class=\"vc-wheel-chip\" aria-hidden=\"true\"><span class=\"chip-ico\"><svg width=\"16\" height=\"16\" viewbox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2\"><\/path><circle cx=\"9\" cy=\"7\" r=\"4\"><\/circle><path d=\"M23 21v-2a4 4 0 0 0-3-3.87\"><\/path><path d=\"M16 3.13a4 4 0 0 1 0 7.75\"><\/path><\/svg><\/span>Decisores e partes interessadas<\/span>\n          <span class=\"vc-wheel-chip\" aria-hidden=\"true\"><span class=\"chip-ico\"><svg width=\"16\" height=\"16\" viewbox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M9 12l2 2 4-4\"><\/path><path d=\"M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0z\"><\/path><\/svg><\/span>Vota\u00e7\u00f5es no Congresso<\/span>\n          <span class=\"vc-wheel-chip\" aria-hidden=\"true\"><span class=\"chip-ico\"><svg width=\"16\" height=\"16\" viewbox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z\"><\/path><path d=\"M14 2v6h6M8 13h8M8 17h8\"><\/path><\/svg><\/span>Atas das sess\u00f5es<\/span>\n          <span class=\"vc-wheel-chip\" aria-hidden=\"true\"><span class=\"chip-ico\"><svg width=\"16\" height=\"16\" viewbox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.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-9h4\"><\/path><path d=\"M18 14h-8M15 18h-5M10 6h8v4h-8z\"><\/path><\/svg><\/span>Atualidade pol\u00edtica<\/span>\n          <span class=\"vc-wheel-chip\" aria-hidden=\"true\"><span class=\"chip-ico\"><svg width=\"16\" height=\"16\" viewbox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\"><\/path><\/svg><\/span>Respostas com refer\u00eancia \u00e0 fonte<\/span>\n          <span class=\"vc-wheel-chip\" aria-hidden=\"true\"><span class=\"chip-ico\"><svg width=\"16\" height=\"16\" viewbox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M13 2 3 14h9l-1 8 10-12h-9z\"><\/path><\/svg><\/span>Dados oficiais em tempo real<\/span>\n        <\/div>\n      <\/div>\n    <\/div>\n  <\/div>\n<\/section>\n\n<div class=\"wrap\">\n\n  <noscript>\n    <div class=\"nojs\">\n  Esta p\u00e1gina usa JavaScript para mostrar gr\u00e1ficos interativos. Se o tiveres desativado, podes consultar os dados brutos em\n <a href=\"\/api\/dashboard-publico\/fren\/\">     \/api\/dashboard-publico\/fren\/.<\/a> \n    <\/div>\n  <\/noscript>\n\n  <section class=\"product-section\" aria-labelledby=\"fren-title\" itemscope=\"\" itemtype=\"https:\/\/schema.org\/Dataset\">\n    <div class=\"product-grid\">\n      <aside class=\"product-info\">\n        <span class=\"product-badge\">FREN \u00b7 Intelig\u00eancia artificial para Assuntos P\u00fablicos<\/span>\n        <h2 class=\"product-name\" id=\"fren-title\" itemprop=\"name\">Toda a pol\u00edtica espanhola, numa pergunta<\/h2>\n        <p class=\"product-tagline\" itemprop=\"description\">\n          <strong>O FREN<\/strong> junta <strong>5 m\u00f3dulos<\/strong> \u2014 Leis, Decisores, Vota\u00e7\u00f5es, Atas das Sess\u00f5es e Atualidade \u2014 para reduzir horas de pesquisa a segundos, citando sempre a fonte oficial.\n        <\/p>\n      <\/aside>\n\n      <div class=\"product-content\" data-carousel=\"\">\n        <nav class=\"car-tabs\" role=\"tablist\" aria-label=\"Vistas FREN\">\n          <button type=\"button\" class=\"car-tab active\" data-pane=\"pane-temas\" role=\"tab\" aria-selected=\"true\">Temas quentes<\/button>\n          <button type=\"button\" class=\"car-tab\" data-pane=\"pane-afinidad\" role=\"tab\" aria-selected=\"false\">Quem vota em quem<\/button>\n          <button type=\"button\" class=\"car-tab\" data-pane=\"pane-pregunta\" role=\"tab\" aria-selected=\"false\">Pergunta do dia<\/button>\n        <\/nav>\n\n        <div class=\"car-pane active\" id=\"pane-temas\" role=\"tabpanel\">\n          <div class=\"product-content-header\">\n            <div>\n              <h3>Temas quentes dos \u00faltimos 3 meses<\/h3>\n              <p class=\"sub\">Os temas mais presentes nas atas das sess\u00f5es dos \u00faltimos 3 meses e quais os partidos que os impulsionam. A espessura de cada linha indica a sua import\u00e2ncia no debate. Filtra por c\u00e2mara ou clica num tema ou partido.  <\/p>\n            <\/div>\n          <\/div>\n          <div class=\"hm-meta\" id=\"temas-meta\"><\/div>\n          <div class=\"tc-filters\" id=\"temas-filters\"><\/div>\n          <div class=\"sankey-wrap\" id=\"temas-wrap\"><p class=\"empty\" style=\"padding:24px 0\">A carregar temas\u2026<\/p><\/div>\n          <p class=\"tema-hint\" id=\"tema-hint\">Clica num tema para veres quais s\u00e3o os partidos que o est\u00e3o a promover e os seus principais intervenientes.<\/p>\n          <div class=\"tema-detail\" id=\"tema-detail\" hidden=\"\"><\/div>\n          <div class=\"pane-cta-row\">\n            <p class=\"pane-cta-text\">\n              <strong>Queres aprofundar a an\u00e1lise das Atas das Sess\u00f5es em rela\u00e7\u00e3o aos teus temas?<\/strong>\n  Pergunta ao FREN: tem todos os jornais oficiais do Congresso, do Senado e dos parlamentos regionais indexados e analisados por tema.\n            <\/p>\n            <a class=\"pane-cta\" href=\"https:\/\/fren.democrata.es\/\" rel=\"noopener\">Explorar temas no FREN<\/a>\n          <\/div>\n        <\/div>\n\n        <div class=\"car-pane\" id=\"pane-afinidad\" role=\"tabpanel\">\n          <div class=\"product-content-header\">\n            <div>\n              <h3>Quem vota em quem<\/h3>\n              <p class=\"sub\">Afinidade entre grupos, com base no n\u00famero de vezes que votam da mesma forma na sess\u00e3o plen\u00e1ria do Congresso (\u00faltimos 3 meses). Quanto mais grossa e curta for a liga\u00e7\u00e3o, maior \u00e9 a coincid\u00eancia. <\/p>\n            <\/div>\n          <\/div>\n          <div class=\"hm-meta\" id=\"afinidad-meta\"><\/div>\n          <div class=\"afinidad-layout\">\n            <div class=\"afinidad-wrap\" id=\"afinidad-wrap\"><p class=\"empty\" style=\"padding:24px 0\">A carregar a afinidade de voto\u2026<\/p><\/div>\n            <aside class=\"afinidad-detail\" id=\"afinidad-detail\"><p class=\"afi-detail-hint\">Clica num grupo para veres os detalhes dos votos e as suas afinidades com os restantes.<\/p><\/aside>\n          <\/div>\n          <div class=\"afi-legend\">\n             <span><span class=\"dash\"><\/span> Espessura = % de coincid\u00eancia de votos<\/span>\n            <span>Tamanho do n\u00f3 = n\u00famero de deputados do grupo<\/span>\n          <\/div>\n          <div class=\"pane-cta-row\">\n            <p class=\"pane-cta-text\">\n              <strong>Queres perceber os padr\u00f5es de voto por temas e antecipar comportamentos futuros?<\/strong>\n  Pergunta ao FREN e descobre as alian\u00e7as, a disciplina de voto e os cen\u00e1rios de maioria em qualquer vota\u00e7\u00e3o no Congresso ou no Senado.\n            <\/p>\n            <a class=\"pane-cta\" href=\"https:\/\/fren.democrata.es\/\" rel=\"noopener\">Explorar vota\u00e7\u00f5es no FREN<\/a>\n          <\/div>\n        <\/div>\n\n        <div class=\"car-pane\" id=\"pane-pregunta\" role=\"tabpanel\">\n          <div class=\"product-content-header\">\n            <div>\n              <h3>Pergunta do dia, respondida pela IA<\/h3>\n              <p class=\"sub\">A FREN escolhe todos os dias uma not\u00edcia relevante e comenta-a, citando fontes oficiais e declara\u00e7\u00f5es de respons\u00e1veis pol\u00edticos.<\/p>\n            <\/div>\n          <\/div>\n          <div id=\"pregunta-content\">\n            <p class=\"empty\" style=\"padding:24px 0\">A carregar a pergunta do dia\u2026<\/p>\n          <\/div>\n          <div class=\"pane-cta-row\">\n            <p class=\"pane-cta-text\">\n              <strong>Tens as tuas pr\u00f3prias perguntas?<\/strong>\n  Come\u00e7a o teu per\u00edodo de teste gratuito de 15 dias no FREN, sem cart\u00e3o de cr\u00e9dito e sem compromisso.\n            <\/p>\n            <a class=\"pane-cta\" href=\"https:\/\/fren.democrata.es\/\" rel=\"noopener\">Experimenta o FREN de gra\u00e7a<\/a>\n          <\/div>\n        <\/div>\n      <\/div>\n    <\/div>\n  <\/section>\n\n  <!-- FAQ -->\n  <section class=\"faq-section\" aria-labelledby=\"faq-title\" id=\"faq\">\n    <h2 id=\"faq-title\">Perguntas frequentes<\/h2>\n    <p class=\"faq-intro\">Tudo o que precisas de saber sobre o FREN, o assistente de IA da Vinces e da Dem\u00f3crata para pol\u00edtica, regulamenta\u00e7\u00e3o e assuntos p\u00fablicos.<\/p>\n    <article class=\"faq-block\">\n      <h3 class=\"faq-block-title\"><span class=\"faq-badge\">FREN<\/span> O assistente de IA para Assuntos P\u00fablicos<\/h3>\n      <div class=\"faq-list\">\n    <details><summary>O que \u00e9 o FREN?<\/summary><p>O assistente de IA especializado e perito em pol\u00edtica, regulamenta\u00e7\u00e3o e assuntos p\u00fablicos. Fazes-lhe perguntas em linguagem natural e ele trabalha, pesquisa e d\u00e1-te as \u00faltimas not\u00edcias sobre estas \u00e1reas, citando sempre a fonte oficial. <\/p><\/details>\n    <details><summary>Para quem \u00e9?<\/summary><p>Para departamentos de Rela\u00e7\u00f5es P\u00fablicas, equipas jur\u00eddicas e de conformidade, empresas de consultoria e escrit\u00f3rios de advogados, associa\u00e7\u00f5es, investigadores, jornalistas e qualquer decisor que precise de acompanhar a atualidade pol\u00edtica com rigor.<\/p><\/details>\n    <details><summary>O que \u00e9 que posso perguntar-te?<\/summary><p>Tudo o que quiseres saber sobre regulamenta\u00e7\u00e3o, decisores, vota\u00e7\u00f5es, atas das sess\u00f5es ou atualidade pol\u00edtica, tal como se perguntasses a um especialista. N\u00e3o precisas de pesquisas exatas nem de filtros. <\/p><\/details>\n    <details><summary>Que m\u00f3dulos tem?<\/summary><p>Cinco: Leis e regulamenta\u00e7\u00e3o, decisores, vota\u00e7\u00f5es, atas das sess\u00f5es e atualidade pol\u00edtica. Cada uma liga-se a fontes oficiais diferentes e podem ser combinadas numa mesma pesquisa. <\/p><\/details>\n    <details><summary>O que faz o m\u00f3dulo de Leis e Regulamenta\u00e7\u00e3o?<\/summary><p>Acompanha iniciativas e legisla\u00e7\u00e3o em tempo real (Congresso, Senado, assembleias regionais, minist\u00e9rios, secretarias regionais e jornais oficiais), identifica o que te diz respeito e antecipa as mudan\u00e7as.<\/p><\/details>\n    <details><summary>E o m\u00f3dulo dos Decisores?<\/summary><p>Identifica e acompanha os decisores p\u00fablicos: estrutura das c\u00e2maras e dos governos, percurso profissional, presen\u00e7a nas redes sociais e posi\u00e7\u00f5es assumidas.<\/p><\/details>\n    <details><summary>E o das vota\u00e7\u00f5es?<\/summary><p>Mostra como fica a assembleia com os votos de cada grupo e deputado, e analisa tend\u00eancias, alian\u00e7as e poss\u00edveis maiorias.<\/p><\/details>\n    <details><summary>E os Di\u00e1rios das Sess\u00f5es?<\/summary><p>Analisa o debate parlamentar na \u00edntegra: quem interveio, sobre que tema e com que intensidade, com cita\u00e7\u00f5es literais e links para a fonte.<\/p><\/details>\n    <details><summary>E quanto \u00e0 atualidade pol\u00edtica?<\/summary><p>Comunicados de imprensa de minist\u00e9rios e organismos, agenda institucional e novidades regulamentares, filtrados por setor.<\/p><\/details>\n    <details><summary>Como \u00e9 que isto funciona?<\/summary><p>Fazes a pergunta em linguagem natural; o FREN recupera informa\u00e7\u00e3o de fontes oficiais em tempo real, cruza dados entre m\u00f3dulos e constr\u00f3i uma resposta fundamentada com texto, gr\u00e1ficos, hemiciclos e tabelas.<\/p><\/details>\n    <details><summary>O que \u00e9 a pesquisa sem\u00e2ntica?<\/summary><p>O FREN n\u00e3o procura palavras exatas, mas sim o significado da tua pesquisa. Se perguntares por \u00abenergia limpa\u00bb, ele tamb\u00e9m encontra \u00abenergias renov\u00e1veis\u00bb, \u00abtransi\u00e7\u00e3o ecol\u00f3gica\u00bb ou \u00abdescarboniza\u00e7\u00e3o\u00bb, mesmo que n\u00e3o uses essas palavras. <\/p><\/details>\n    <details><summary>\u00c9 de confian\u00e7a? Como \u00e9 que evita as alucina\u00e7\u00f5es da IA? <\/summary><p>A FREN come\u00e7a por recolher a informa\u00e7\u00e3o de fontes oficiais e, depois, elabora a resposta com base nesses documentos (t\u00e9cnica RAG), citando a fonte exata. Se n\u00e3o tiver dados suficientes, diz isso, em vez de inventar. <\/p><\/details>\n    <details><summary>O que s\u00e3o os modos Pro e Think?<\/summary><p>Duas formas de responder, dependendo da pergunta: <strong>o \u00abPro\u00bb<\/strong> faz uma an\u00e1lise aprofundada com racioc\u00ednio interm\u00e9dio (~1 min); <strong>o \u00abThink\u00bb<\/strong> investiga de forma exaustiva, verificando v\u00e1rias fontes (v\u00e1rios minutos). A resposta aparece em tempo real enquanto \u00e9 gerada. <\/p><\/details>\n    <details><summary>Como funcionam os cr\u00e9ditos?<\/summary><p>O FREN funciona com um sistema de cr\u00e9ditos que se esgotam a cada consulta: as perguntas simples gastam menos cr\u00e9ditos do que aquelas que cruzam v\u00e1rias fontes, e o modo Pro consome menos do que o Think. Podes come\u00e7ar com o teste gratuito e, depois, comprar o pacote que melhor se adequar ao teu uso. <\/p><\/details>\n    <details><summary>Citas as fontes?<\/summary><p>Sempre. Cada resposta indica a fonte exata (sess\u00e3o parlamentar, URL do documento ou publica\u00e7\u00e3o nas redes sociais) para que possas verific\u00e1-la. Toda a informa\u00e7\u00e3o \u00e9 oficial e comprovada.  <\/p><\/details>\n    <details><summary>Em que \u00e9 que se diferencia do ChatGPT?<\/summary><p>O FREN acede em tempo real \u00e0s fontes oficiais espanholas (BOE, atas das sess\u00f5es, propostas de lei, vota\u00e7\u00f5es) e cita a fonte exata; um chatbot geral n\u00e3o acede a essas fontes.<\/p><\/details>\n    <details><summary>Fazes a cobertura dos parlamentos regionais?<\/summary><p>Sim. As Cortes Gerais e todos os parlamentos e governos aut\u00f4nomos. <\/p><\/details>\n    <details><summary>Existem contas para equipas e empresas?<\/summary><p>Sim. Cada utilizador tem o seu perfil, conversas e hist\u00f3rico privados, enquanto os cr\u00e9ditos s\u00e3o partilhados por toda a organiza\u00e7\u00e3o, sendo geridos de forma centralizada por uma conta de administrador. <\/p><\/details>\n    <details><summary>As minhas consultas s\u00e3o confidenciais e cumprem o RGPD?<\/summary><p>Sim. As tuas consultas s\u00e3o privadas e n\u00e3o s\u00e3o utilizadas para treinar modelos; os dados s\u00e3o armazenados encriptados na Uni\u00e3o Europeia, em conformidade com o RGPD. <\/p><\/details>\n    <details><summary>Como \u00e9 que come\u00e7o?<\/summary><p>Experimenta gratuitamente durante 15 dias, sem cart\u00e3o de cr\u00e9dito e sem compromisso, em <a href=\"https:\/\/fren.democrata.es\/\" rel=\"noopener\">fren.democrata.es<\/a>. Podes cancelar quando quiseres. <\/p><\/details>\n      <\/div>\n    <\/article>\n  <\/section>\n\n<\/div>\n\n<!-- Snippets dialog -->\n<dialog class=\"snippets\" id=\"snippets-dialog\" aria-labelledby=\"snippets-title\">\n  <div class=\"head\">\n    <h3 id=\"snippets-title\">Excertos<\/h3>\n    <button type=\"button\" id=\"snippets-close\" aria-label=\"Cerrar\">\u2715<\/button>\n  <\/div>\n  <div class=\"body\" id=\"snippets-body\"><\/div>\n<\/dialog>\n\n<script defer src=\"https:\/\/cdn.jsdelivr.net\/npm\/d3@7\/dist\/d3.min.js\"><\/script>\n<script defer src=\"https:\/\/cdn.jsdelivr.net\/npm\/d3-sankey@0.12.3\/dist\/d3-sankey.min.js\"><\/script>\n<script>\n\/*\n * Helpers compartidos por todas las p\u00e1ginas de producto (FREN, PolicyAlert,\n * Poder Digital, WATS). Se exponen en `window.VincesDash` para que cada\n * p\u00e1gina pueda invocarlos sin duplicar c\u00f3digo.\n *\n * IMPORTANT: las p\u00e1ginas standalone descargadas por \"Descargar HTML externo\"\n * inlinean este script. Mantenerlo autocontenido (sin imports).\n *\/\n(function () {\n  \"use strict\";\n\n  const LOCALE = \"es-ES\";\n  const REFRESH_MS = 30 * 60 * 1000;\n\n  const $ = (s, r) => (r || document).querySelector(s);\n  const $$ = (s, r) => Array.from((r || document).querySelectorAll(s));\n\n  function fmtDate(iso) {\n    if (!iso) return \"\";\n    try {\n      return new Date(iso).toLocaleDateString(LOCALE, {\n        day: \"2-digit\", month: \"long\", year: \"numeric\",\n      });\n    } catch { return iso; }\n  }\n  function fmtDateTime(iso) {\n    if (!iso) return \"\";\n    try {\n      return new Date(iso).toLocaleString(LOCALE, {\n        day: \"2-digit\", month: \"short\", year: \"numeric\",\n        hour: \"2-digit\", minute: \"2-digit\",\n      });\n    } catch { return iso; }\n  }\n  function escapeHtml(s) {\n    return String(s == null ? \"\" : s)\n      .replace(\/&\/g, \"&amp;\").replace(\/<\/g, \"&lt;\").replace(\/>\/g, \"&gt;\")\n      .replace(\/\"\/g, \"&quot;\").replace(\/'\/g, \"&#39;\");\n  }\n  function initials(name) {\n    return (name || \"?\").trim().split(\/\\s+\/).slice(0, 2).map(p => p[0]).join(\"\").toUpperCase();\n  }\n\n  \/**\n   * Carga est\u00e1ndar de los endpoints p\u00fablicos del dashboard.\n   * - apiUrl: URL absoluta o relativa al endpoint \/api\/dashboard-publico\/...\n   * - onData: callback(data) llamado en \u00e9xito.\n   * - onError: callback(message, kind) llamado en error. kind: \"network\" | \"http\" | \"json\" | \"render\".\n   *\/\n  async function loadDashboardData(apiUrl, onData, onError) {\n    let response;\n    try {\n      response = await fetch(apiUrl, {\n        method: \"GET\",\n        headers: { Accept: \"application\/json\" },\n        mode: \"cors\",\n        cache: \"no-cache\",\n      });\n    } catch (err) {\n      console.error(\"[Dashboard] Network\/CORS error:\", err);\n      const isFileProtocol = window.location.protocol === \"file:\";\n      const msg = isFileProtocol\n        ? `No se pudieron cargar los datos desde <code>${escapeHtml(apiUrl)}<\/code>. <br>Si has abierto este HTML como archivo local, s\u00edrvelo desde un servidor web (no <code>file:\/\/<\/code>) o aseg\u00farate de que el endpoint permite el origen <code>null<\/code>.`\n        : `No se pudieron cargar los datos desde <code>${escapeHtml(apiUrl)}<\/code>. <br>Comprueba la configuraci\u00f3n CORS del backend para el origen actual: <code>${escapeHtml(window.location.origin)}<\/code>.`;\n      onError && onError(msg, \"network\");\n      return;\n    }\n    if (!response.ok) {\n      console.error(\"[Dashboard] HTTP error:\", response.status);\n      onError && onError(`El servidor devolvi\u00f3 HTTP ${response.status} al consultar <code>${escapeHtml(apiUrl)}<\/code>.`, \"http\");\n      return;\n    }\n    let data;\n    try {\n      data = await response.json();\n    } catch (err) {\n      console.error(\"[Dashboard] JSON parse error:\", err);\n      onError && onError(\"La respuesta no es JSON v\u00e1lido.\", \"json\");\n      return;\n    }\n    try {\n      onData && onData(data);\n    } catch (err) {\n      console.error(\"[Dashboard] Render error:\", err);\n      onError && onError(\"Error al renderizar los datos.\", \"render\");\n    }\n  }\n\n  \/**\n   * Pinta el pill de \"Actualizado...\" en la cabecera y gestiona el estado de error.\n   *\/\n  function setUpdatedPill(data, errMessage) {\n    const pill = $(\"#updated-pill\");\n    const txt = $(\"#updated-text\");\n    if (!pill || !txt) return;\n    if (errMessage) {\n      pill.classList.add(\"err\");\n      txt.textContent = errMessage;\n    } else {\n      pill.classList.remove(\"err\");\n      txt.textContent = \"Actualizado \" + fmtDateTime((data && data.generated_at) || new Date().toISOString());\n    }\n  }\n\n  \/**\n   * Bot\u00f3n \"Descargar HTML externo\": clona el DOM, elimina elementos de test,\n   * sustituye la API_URL relativa por una absoluta y descarga como fichero\n   * \u00fanico listo para WordPress.\n   *\/\n  function bindDownloadExternalHtml(absApiUrl) {\n    const btn = $(\"#download-html-btn\");\n    if (!btn) return;\n    btn.addEventListener(\"click\", () => {\n      try {\n        btn.dataset.state = \"generating\";\n        btn.querySelector(\".lbl\").textContent = \"Generando\u2026\";\n\n        const cloned = document.documentElement.cloneNode(true);\n        cloned.querySelectorAll(\".testbar, #download-html-btn\").forEach(el => el.remove());\n\n        cloned.querySelectorAll(\"script\").forEach(s => {\n          const txt = s.textContent || \"\";\n          if (txt.includes(\"DEFAULT_API_URL\")) {\n            s.textContent = txt.replace(\n              \/const\\s+DEFAULT_API_URL\\s*=\\s*[\"'][^\"']*[\"'];\/,\n              `const DEFAULT_API_URL = ${JSON.stringify(absApiUrl)};`\n            );\n          }\n        });\n\n        const banner =\n          \"\\n<!--\\n\" +\n          \"  Dashboard Vinces \u00b7 p\u00e1gina standalone por producto\\n\" +\n          \"  Generado: \" + new Date().toISOString() + \"\\n\" +\n          \"  Endpoint API: \" + absApiUrl + \"\\n\" +\n          \"\\n\" +\n          \"  C\u00f3mo integrarlo en WordPress:\\n\" +\n          \"    1. Editor de la p\u00e1gina \u2192 bloque 'HTML personalizado'.\\n\" +\n          \"    2. Pega el fichero completo (todo, incluyendo <html>, <head>, <body>).\\n\" +\n          \"       En la mayor\u00eda de temas WP basta con pegar a partir de <body>.\\n\" +\n          \"    3. Aseg\u00farate de que el dominio WP est\u00e1 incluido en CORS del backend.\\n\" +\n          \"    4. El cliente refresca cada 30 min; el backend cachea 1h.\\n\" +\n          \"-->\\n\";\n        const html = \"<!DOCTYPE html>\\n\" + cloned.outerHTML.replace(\/^<html\/, banner + \"<html\");\n\n        const blob = new Blob([html], { type: \"text\/html;charset=utf-8\" });\n        const url = URL.createObjectURL(blob);\n        const a = document.createElement(\"a\");\n        a.href = url;\n        const stamp = new Date().toISOString().slice(0, 10);\n        a.download = `dashboard-vinces-${(window.VincesDash && window.VincesDash.product) || \"page\"}-${stamp}.html`;\n        document.body.appendChild(a);\n        a.click();\n        document.body.removeChild(a);\n        setTimeout(() => URL.revokeObjectURL(url), 2000);\n\n        btn.dataset.state = \"done\";\n        btn.querySelector(\".lbl\").textContent = \"\u2714 Descargado\";\n        setTimeout(() => {\n          btn.removeAttribute(\"data-state\");\n          btn.querySelector(\".lbl\").textContent = \"Descargar HTML externo\";\n        }, 2500);\n      } catch (err) {\n        console.error(\"[download-html] error:\", err);\n        btn.removeAttribute(\"data-state\");\n        btn.querySelector(\".lbl\").textContent = \"Error al generar\";\n        setTimeout(() => { btn.querySelector(\".lbl\").textContent = \"Descargar HTML externo\"; }, 2500);\n      }\n    });\n  }\n\n  \/**\n   * Inicializa carruseles tipo tabs sobre cualquier elemento [data-carousel].\n   * Cuando un pane se activa, ejecuta el callback registrado en\n   * window.VincesDash.onPaneActivated[paneId] (si existe).\n   *\/\n  function initCarousels() {\n    document.querySelectorAll(\"[data-carousel]\").forEach(scope => {\n      const tabs = scope.querySelectorAll(\".car-tab\");\n      const panes = scope.querySelectorAll(\".car-pane\");\n      tabs.forEach(btn => {\n        btn.addEventListener(\"click\", () => {\n          const target = btn.getAttribute(\"data-pane\");\n          tabs.forEach(b => {\n            b.classList.toggle(\"active\", b === btn);\n            b.setAttribute(\"aria-selected\", b === btn ? \"true\" : \"false\");\n          });\n          panes.forEach(p => {\n            p.classList.toggle(\"active\", p.id === target);\n          });\n          const cb = window.VincesDash && window.VincesDash.onPaneActivated && window.VincesDash.onPaneActivated[target];\n          if (typeof cb === \"function\") cb();\n        });\n      });\n    });\n  }\n\n  window.VincesDash = Object.assign(window.VincesDash || {}, {\n    LOCALE,\n    REFRESH_MS,\n    $, $$,\n    fmtDate, fmtDateTime, escapeHtml, initials,\n    loadDashboardData,\n    setUpdatedPill,\n    bindDownloadExternalHtml,\n    initCarousels,\n    onPaneActivated: {},\n  });\n})();\n<\/script>\n\n<script>\n(() => {\n  \"use strict\";\n\n  const DEFAULT_API_URL = \"https:\/\/vision360.vincesconsulting.com\/api\/dashboard-publico\/fren\/\";\n  const {\n    $, $$, fmtDate, fmtDateTime, escapeHtml, initials,\n    loadDashboardData, setUpdatedPill, bindDownloadExternalHtml, initCarousels,\n  } = window.VincesDash;\n  window.VincesDash.product = \"fren\";\n\n  function getApiUrl() {\n    const diarioId = ($(\"#diario-id-input\")?.value || \"\").trim();\n    if (diarioId) return DEFAULT_API_URL + \"?diario_id=\" + encodeURIComponent(diarioId);\n    return DEFAULT_API_URL;\n  }\n\n  function levelFor(w) {\n    if (w >= 0.40) return 5;\n    if (w >= 0.25) return 4;\n    if (w >= 0.15) return 3;\n    if (w >= 0.07) return 2;\n    if (w >  0.00) return 1;\n    return 0;\n  }\n\n  \/\/ ===== Estado + helper de pane activo =====\n  const STATE = {};\n  function isPaneActive(id){ const el = document.getElementById(id); return !!(el && el.classList.contains(\"active\")); }\n\n\/\/ ===== Temas calientes (Sankey temas \u2192 partidos) =====\n  let temasChamberKey = \"todos\";\n  let _temasByName = {};   \/\/ tema-nombre -> objeto del tema de la c\u00e1mara actual (para el clic)\n  let _partidosById = {};  \/\/ pid -> {id, name, color, logo_url, temas:[{topic,color,score}]}\n  let _sankeySel = null;   \/\/ selecci\u00f3n activa de resaltado (tema o partido)\n\n  function renderTemasCalientes(tc) {\n    const filters = $(\"#temas-filters\"), meta = $(\"#temas-meta\"), wrap = $(\"#temas-wrap\");\n    const hasData = tc && tc.by_chamber && Array.isArray(tc.by_chamber.todos) && tc.by_chamber.todos.length;\n    if (!hasData) {\n      if (filters) filters.innerHTML = \"\";\n      if (meta) meta.innerHTML = \"\";\n      _resetTemaDetail();\n      if (wrap) wrap.innerHTML = '<p class=\"empty\" style=\"padding:24px 0\">A\u00fan no hay Diarios de Sesiones analizados en los \u00faltimos 3 meses.<\/p>';\n      return;\n    }\n    if (meta) {\n      const v = tc.ventana || {};\n      meta.innerHTML = `\n        <span class=\"pill\">${tc.n_diarios} diarios analizados<\/span>\n        ${v.desde ? `<span>\u00b7 del <time datetime=\"${escapeHtml(v.desde)}\">${fmtDate(v.desde)}<\/time> al <time datetime=\"${escapeHtml(v.hasta || \"\")}\">${fmtDate(v.hasta)}<\/time><\/span>` : \"\"}\n      `;\n    }\n    if (filters) {\n      const chambers = tc.ambitos_chamber || [];\n      const valid = temasChamberKey === \"todos\" || chambers.some(c => String(c.chamber_id) === temasChamberKey);\n      if (!valid) temasChamberKey = \"todos\";\n      filters.innerHTML =\n        `<button type=\"button\" class=\"tc-btn ${temasChamberKey === \"todos\" ? \"active\" : \"\"}\" data-key=\"todos\">Todas las c\u00e1maras<\/button>` +\n        chambers.map(c => `<button type=\"button\" class=\"tc-btn ${temasChamberKey === String(c.chamber_id) ? \"active\" : \"\"}\" data-key=\"${c.chamber_id}\">${escapeHtml(c.chamber)}<\/button>`).join(\"\");\n      filters.querySelectorAll(\".tc-btn\").forEach(b => b.addEventListener(\"click\", () => {\n        temasChamberKey = b.dataset.key;\n        filters.querySelectorAll(\".tc-btn\").forEach(x => x.classList.toggle(\"active\", x === b));\n        drawSankey(tc);\n      }));\n    }\n    drawSankey(tc);\n  }\n\n  function drawSankey(tc) {\n    const wrap = $(\"#temas-wrap\");\n    const list = (tc.by_chamber && tc.by_chamber[temasChamberKey]) || [];\n    _resetTemaDetail();\n    _sankeySel = null;\n    if (!wrap) return;\n    if (!list.length) {\n      wrap.innerHTML = '<p class=\"empty\" style=\"padding:24px 0\">No hay temas registrados para esta c\u00e1mara en los \u00faltimos 3 meses.<\/p>';\n      return;\n    }\n    if (!window.d3 || !window.d3.sankey) {\n      wrap.innerHTML = '<p class=\"empty\" style=\"padding:24px 0\">Cargando librer\u00eda de gr\u00e1ficos\u2026<\/p>';\n      return;\n    }\n    try {\n      const d3 = window.d3;\n      const TOP_PARTIES = 5;   \/\/ por tema, m\u00e1ximo de partidos en el flujo\n      const MIN_SHARE = 0.04;  \/\/ descarta flujos < 4% del tema (anti-saturaci\u00f3n)\n\n      _temasByName = {};\n      _partidosById = {};\n      const temaNodes = [], partidoMap = {}, links = [];\n      list.forEach(t => {\n        const tid = \"t:\" + t.topic;\n        _temasByName[t.topic] = t;\n        temaNodes.push({ id: tid, name: t.topic, color: t.color || \"#9aa0a6\", kind: \"tema\", topic: t.topic });\n        const pps = t.por_partido || [];\n        const total = pps.reduce((a, b) => a + (b.score || 0), 0) || 1;\n        pps.slice(0, TOP_PARTIES).forEach(p => {\n          if (!p.score || (p.score \/ total) < MIN_SHARE) return;\n          const pid = \"p:\" + (p.group_id || p.group || \"?\");\n          if (!partidoMap[pid]) partidoMap[pid] = { id: pid, name: p.group || \"\u2014\", color: p.color || \"#9aa0a6\", kind: \"partido\", logo_url: p.logo_url || null };\n          if (!_partidosById[pid]) _partidosById[pid] = { id: pid, name: p.group || \"\u2014\", color: p.color || \"#9aa0a6\", logo_url: p.logo_url || null, temas: [] };\n          _partidosById[pid].temas.push({ topic: t.topic, color: t.color || \"#9aa0a6\", score: p.score });\n          links.push({ source: pid, target: tid, value: p.score, color: p.color || \"#9aa0a6\" });\n        });\n      });\n      const nodes = temaNodes.concat(Object.values(partidoMap));\n      if (!links.length) {\n        wrap.innerHTML = '<p class=\"empty\" style=\"padding:24px 0\">Sin datos de partidos por tema.<\/p>';\n        return;\n      }\n\n      const W = 820, LEFT = 200, RIGHT = 230;\n      const partyCount = Object.keys(partidoMap).length;\n      \/\/ Alto suficiente para que los logos de partido (22px) no se solapen,\n      \/\/ incl. en \"todas las c\u00e1maras\" donde hay m\u00e1s partidos a la derecha.\n      const H = Math.max(380, Math.max(temaNodes.length, partyCount) * 50);\n      const sankey = d3.sankey()\n        .nodeId(d => d.id)\n        .nodeWidth(13)\n        .nodePadding(26)\n        .extent([[LEFT, 18], [W - RIGHT, H - 18]]);\n      const graph = sankey({\n        nodes: nodes.map(d => Object.assign({}, d)),\n        links: links.map(d => Object.assign({}, d)),\n      });\n\n      const linkPath = d3.sankeyLinkHorizontal();\n      let linkEls = \"\", nodeEls = \"\";\n      graph.links.forEach(l => {\n        const topic = (l.target && l.target.topic) || \"\";\n        const party = (l.source && l.source.id) || \"\";\n        linkEls += `<path class=\"sk-link\" d=\"${linkPath(l)}\" fill=\"none\" stroke=\"${escapeHtml(l.color)}\" stroke-opacity=\"0.5\" stroke-width=\"${Math.max(1, l.width).toFixed(1)}\" data-topic=\"${escapeHtml(topic)}\" data-party=\"${escapeHtml(party)}\"><title>${escapeHtml(l.target.name)} \u2192 ${escapeHtml(l.source.name)}: ${l.value}<\/title><\/path>`;\n      });\n      graph.nodes.forEach(n => {\n        const h = Math.max(1, n.y1 - n.y0), wdt = (n.x1 - n.x0);\n        const cy = (n.y0 + n.y1) \/ 2;\n        const isTema = n.kind === \"tema\";\n        nodeEls += `<g class=\"sk-node ${isTema ? \"sk-tema\" : \"sk-partido\"}\"${isTema ? ` data-topic=\"${escapeHtml(n.topic)}\"` : ` data-party=\"${escapeHtml(n.id)}\"`}>`;\n        nodeEls += `<rect x=\"${n.x0.toFixed(1)}\" y=\"${n.y0.toFixed(1)}\" width=\"${wdt.toFixed(1)}\" height=\"${h.toFixed(1)}\" rx=\"2\" fill=\"${escapeHtml(n.color)}\"><title>${escapeHtml(n.name)}<\/title><\/rect>`;\n        if (isTema) {\n          \/\/ Tema a la DERECHA: etiqueta a la derecha del nodo.\n          nodeEls += `<text class=\"sk-label\" x=\"${(n.x1 + 8).toFixed(1)}\" y=\"${cy.toFixed(1)}\" dy=\"0.35em\" text-anchor=\"start\">${escapeHtml(n.name)}<\/text>`;\n        } else {\n          \/\/ Partido a la IZQUIERDA (extremo del Sankey): logo + nombre a la izquierda.\n          const sz = 22, lx = n.x0 - 8 - sz;\n          if (n.logo_url) {\n            nodeEls += `<image href=\"${escapeHtml(n.logo_url)}\" x=\"${lx.toFixed(1)}\" y=\"${(cy - sz \/ 2).toFixed(1)}\" width=\"${sz}\" height=\"${sz}\" preserveAspectRatio=\"xMidYMid meet\"><title>${escapeHtml(n.name)}<\/title><\/image>`;\n          } else {\n            nodeEls += `<circle cx=\"${(n.x0 - 8 - 8).toFixed(1)}\" cy=\"${cy.toFixed(1)}\" r=\"8\" fill=\"${escapeHtml(n.color)}\"><\/circle>`;\n          }\n          nodeEls += `<text class=\"sk-label\" x=\"${(lx - 5).toFixed(1)}\" y=\"${cy.toFixed(1)}\" dy=\"0.35em\" text-anchor=\"end\">${escapeHtml(_shortGroup(n.name))}<\/text>`;\n        }\n        nodeEls += `<\/g>`;\n      });\n\n      wrap.innerHTML =\n        `<svg viewBox=\"0 0 ${W} ${H}\" preserveAspectRatio=\"xMidYMid meet\" class=\"sk-svg\" role=\"img\" aria-label=\"Diagrama Sankey de temas a partidos\">` +\n        `<g class=\"sk-links\">${linkEls}<\/g>${nodeEls}<\/svg>`;\n    } catch (err) {\n      console.error(\"[FREN] sankey error:\", err);\n      wrap.innerHTML = '<p class=\"empty\" style=\"padding:24px 0\">No se pudo dibujar el diagrama de temas.<\/p>';\n    }\n  }\n\n  \/\/ Resalta solo los flujos del tema\/partido seleccionado (aten\u00faa el resto).\n  function _sankeyHighlight(attr, val) {\n    const svg = $(\"#temas-wrap .sk-svg\");\n    if (!svg || !val) return;\n    const sel = attr + \"=\" + val;\n    if (_sankeySel === sel) { _sankeyClearHighlight(); return; }   \/\/ re-clic = quitar\n    _sankeySel = sel;\n    svg.querySelectorAll(\"path.sk-link\").forEach(l => {\n      l.style.strokeOpacity = (l.getAttribute(attr) === val) ? \"0.9\" : \"0.05\";\n    });\n  }\n  function _sankeyClearHighlight() {\n    _sankeySel = null;\n    const svg = $(\"#temas-wrap .sk-svg\");\n    if (!svg) return;\n    svg.querySelectorAll(\"path.sk-link\").forEach(l => { l.style.strokeOpacity = \"\"; });\n  }\n\n  function _resetTemaDetail() {\n    const box = $(\"#tema-detail\"), hint = $(\"#tema-hint\");\n    if (box) { box.hidden = true; box.innerHTML = \"\"; }\n    if (hint) hint.hidden = false;\n  }\n\n  function renderTemaDetail(tema) {\n    const box = $(\"#tema-detail\"), hint = $(\"#tema-hint\");\n    if (!box || !tema) return;\n    const ivs = tema.top_intervinientes || [];\n    const pp = tema.por_partido || [];\n    const maxP = Math.max(...pp.map(p => p.score || 0), 0.0001);\n    box.innerHTML = `\n      <div class=\"td-head\">\n        <span class=\"td-dot\" style=\"background:${escapeHtml(tema.color || '#9aa0a6')}\"><\/span>\n        <h4>${escapeHtml(tema.topic)}<\/h4>\n        <button type=\"button\" class=\"saber-mas\" data-vc-contact=\"${escapeHtml(tema.topic)}\">Saber m\u00e1s \u2197<\/button>\n      <\/div>\n      <div class=\"td-cols\">\n        <div class=\"td-col\">\n          <h5>Qu\u00e9 partidos lo mueven<\/h5>\n          ${pp.length ? pp.map(p => `\n            <div class=\"td-bar-row\">\n              <span class=\"td-bar-lbl\" title=\"${escapeHtml(p.group || '\u2014')}\">${escapeHtml(_shortGroup(p.group || '\u2014'))}<\/span>\n              <span class=\"td-bar\"><span class=\"td-bar-fill\" style=\"width:${Math.round((p.score \/ maxP) * 100)}%;background:${escapeHtml(p.color || '#9aa0a6')}\"><\/span><\/span>\n            <\/div>`).join(\"\") : '<p class=\"muted-cell\">Sin datos.<\/p>'}\n        <\/div>\n        <div class=\"td-col\">\n          <h5>Principales intervinientes<\/h5>\n          ${ivs.length ? ivs.map((p, i) => `\n            <div class=\"td-iv\">\n              <span class=\"td-rank\">${i + 1}<\/span>\n              ${p.photo_url\n                ? `<img decoding=\"async\" class=\"td-avatar\" src=\"${escapeHtml(p.photo_url)}\" alt=\"\" loading=\"lazy\">`\n                : `<span class=\"td-avatar td-avatar-ph\">${escapeHtml(initials(p.name || '?'))}<\/span>`}\n              <span class=\"td-iv-text\">\n                <span class=\"td-iv-name\">${escapeHtml(p.name || '\u2014')}<\/span>\n                ${p.group ? `<span class=\"td-iv-group\">${escapeHtml(p.group)}<\/span>` : \"\"}\n              <\/span>\n            <\/div>`).join(\"\") : '<p class=\"muted-cell\">Sin datos.<\/p>'}\n        <\/div>\n      <\/div>`;\n    box.hidden = false;\n    if (hint) hint.hidden = true;\n  }\n\n  function renderPartidoDetail(pid) {\n    const box = $(\"#tema-detail\"), hint = $(\"#tema-hint\");\n    const pd = _partidosById[pid];\n    if (!box || !pd) return;\n    const temas = (pd.temas || []).slice().sort((a, b) => (b.score || 0) - (a.score || 0));\n    const maxS = Math.max(...temas.map(t => t.score || 0), 0.0001);\n    box.innerHTML = `\n      <div class=\"td-head\">\n        ${pd.logo_url\n          ? `<img decoding=\"async\" src=\"${escapeHtml(pd.logo_url)}\" alt=\"\" style=\"width:26px;height:26px;object-fit:contain\">`\n          : `<span class=\"td-dot\" style=\"background:${escapeHtml(pd.color || '#9aa0a6')}\"><\/span>`}\n        <h4>${escapeHtml(_shortGroup(pd.name))}<\/h4>\n        <button type=\"button\" class=\"saber-mas\" data-vc-contact=\"${escapeHtml(pd.name)}\">Saber m\u00e1s \u2197<\/button>\n      <\/div>\n      <div class=\"td-cols\">\n        <div class=\"td-col\" style=\"flex-basis:100%\">\n          <h5>Temas que m\u00e1s mueve<\/h5>\n          ${temas.length ? temas.map(t => `\n            <div class=\"td-bar-row\">\n              <span class=\"td-bar-lbl\" title=\"${escapeHtml(t.topic)}\">${escapeHtml(t.topic)}<\/span>\n              <span class=\"td-bar\"><span class=\"td-bar-fill\" style=\"width:${Math.round((t.score \/ maxS) * 100)}%;background:${escapeHtml(t.color || '#9aa0a6')}\"><\/span><\/span>\n            <\/div>`).join(\"\") : '<p class=\"muted-cell\">Sin datos.<\/p>'}\n        <\/div>\n      <\/div>`;\n    box.hidden = false;\n    if (hint) hint.hidden = true;\n  }\n\n  \/\/ ===== Afinidad de voto (grafo de bloques, d3-force) =====\n  function _shortGroup(label) {\n    return (label || \"\").replace(\/Grupo Parlamentario\/gi, \"GP\").replace(\/\\s+\/g, \" \").trim();\n  }\n  function _nodeRadius(size, maxSize) {\n    const MIN = 16, MAX = 42;\n    const s = Math.sqrt(Math.max(size || 1, 1)) \/ Math.sqrt(Math.max(maxSize || 1, 1));\n    return MIN + (MAX - MIN) * s;\n  }\n\n  function renderAfinidad(af) {\n    const wrap = $(\"#afinidad-wrap\"), meta = $(\"#afinidad-meta\");\n    if (!wrap) return;\n    const nodes0 = (af && af.nodes) || [], edges0 = (af && af.edges) || [];\n    if (meta) {\n      meta.innerHTML = (af && af.n_votaciones)\n        ? `<span class=\"pill\">${af.n_votaciones} votaciones nominales<\/span><span>\u00b7 \u00faltimos 3 meses \u00b7 % de coincidencia de voto entre grupos<\/span>`\n        : \"\";\n    }\n    if (!window.d3) { wrap.innerHTML = '<p class=\"empty\" style=\"padding:24px 0\">Cargando librer\u00eda de gr\u00e1ficos\u2026<\/p>'; return; }\n    if (!nodes0.length) {\n      wrap.innerHTML = '<p class=\"empty\" style=\"padding:24px 0\">No hay suficientes votaciones nominales en el periodo para calcular afinidades entre grupos.<\/p>';\n      return;\n    }\n    try {\n      const d3 = window.d3;\n      _afiSel = null;\n      const W = Math.max(wrap.clientWidth || 640, 320), H = 540;\n      const maxSize = Math.max(...nodes0.map(n => n.size || 1), 1);\n      const nodes = nodes0.map(n => ({ ...n, r: _nodeRadius(n.size, maxSize) }));\n      const links = edges0.map(e => ({ source: e.a, target: e.b, w: e.w, shared: e.shared, agree: e.agree }));\n\n      const sim = d3.forceSimulation(nodes)\n        .force(\"link\", d3.forceLink(links).id(d => d.id).distance(l => 115 + (1 - l.w) * 215).strength(l => 0.08 + l.w * 0.5))\n        .force(\"charge\", d3.forceManyBody().strength(-980))\n        .force(\"center\", d3.forceCenter(W \/ 2, H \/ 2))\n        .force(\"collide\", d3.forceCollide(d => d.r + 26))\n        .stop();\n      for (let i = 0; i < 400; i++) sim.tick();\n      nodes.forEach(n => {\n        n.x = Math.max(n.r + 4, Math.min(W - n.r - 4, n.x));\n        n.y = Math.max(n.r + 4, Math.min(H - n.r - 16, n.y));\n      });\n      const byId = {}; nodes.forEach(n => { byId[n.id] = n; });\n\n      const linkEls = links.map(l => {\n        const a = byId[(l.source && l.source.id) || l.source], b = byId[(l.target && l.target.id) || l.target];\n        if (!a || !b) return \"\";\n        const sw = (1 + l.w * 7).toFixed(2), op = (0.12 + l.w * 0.5).toFixed(2);\n        return `<line x1=\"${a.x.toFixed(1)}\" y1=\"${a.y.toFixed(1)}\" x2=\"${b.x.toFixed(1)}\" y2=\"${b.y.toFixed(1)}\" stroke=\"#94a3b8\" stroke-width=\"${sw}\" stroke-opacity=\"${op}\" class=\"afi-link\" data-a=\"${escapeHtml(_shortGroup(a.label))}\" data-b=\"${escapeHtml(_shortGroup(b.label))}\" data-w=\"${Math.round(l.w * 100)}\" data-shared=\"${l.shared}\" data-src=\"${escapeHtml((l.source && l.source.id) || l.source)}\" data-tgt=\"${escapeHtml((l.target && l.target.id) || l.target)}\"><\/line>`;\n      }).join(\"\");\n\n      let defs = \"\", nodeEls = \"\";\n      nodes.forEach((n, i) => {\n        const cid = `afclip${i}`, ri = (n.r - 2).toFixed(1);\n        defs += `<clipPath id=\"${cid}\"><circle cx=\"${n.x.toFixed(1)}\" cy=\"${n.y.toFixed(1)}\" r=\"${ri}\"><\/circle><\/clipPath>`;\n        const dash = n.heterogeneo ? ` stroke-dasharray=\"4 3\"` : \"\";\n        nodeEls += `<g class=\"afi-node\" data-id=\"${escapeHtml(n.id)}\">`;\n        nodeEls += `<circle cx=\"${n.x.toFixed(1)}\" cy=\"${n.y.toFixed(1)}\" r=\"${n.r.toFixed(1)}\" fill=\"${escapeHtml(n.color || \"#64748b\")}\" stroke=\"#fff\" stroke-width=\"2\"${dash}><\/circle>`;\n        if (n.logo_url) {\n          const d2 = ((n.r - 2) * 2).toFixed(1);\n          nodeEls += `<image href=\"${escapeHtml(n.logo_url)}\" x=\"${(n.x - (n.r - 2)).toFixed(1)}\" y=\"${(n.y - (n.r - 2)).toFixed(1)}\" width=\"${d2}\" height=\"${d2}\" clip-path=\"url(#${cid})\" preserveAspectRatio=\"xMidYMid slice\"><\/image>`;\n        }\n        nodeEls += `<text x=\"${n.x.toFixed(1)}\" y=\"${(n.y + n.r + 13).toFixed(1)}\" text-anchor=\"middle\" class=\"afi-label\">${escapeHtml(_shortGroup(n.label))}<\/text>`;\n        nodeEls += `<\/g>`;\n      });\n\n      wrap.innerHTML =\n        `<svg viewBox=\"0 0 ${W} ${H}\" preserveAspectRatio=\"xMidYMid meet\" class=\"afi-svg\" role=\"img\" aria-label=\"Grafo de afinidad de voto entre grupos parlamentarios\">` +\n        `<defs>${defs}<\/defs><g class=\"afi-links\">${linkEls}<\/g>${nodeEls}<\/svg>` +\n        `<div class=\"afi-tooltip\" id=\"afi-tooltip\" role=\"tooltip\"><\/div>`;\n\n      const tip = $(\"#afi-tooltip\");\n      wrap.addEventListener(\"mousemove\", e => {\n        const ln = e.target.closest && e.target.closest(\"line.afi-link\");\n        if (!ln || !tip) { if (tip) tip.classList.remove(\"visible\"); return; }\n        tip.innerHTML = `<div class=\"ttl\">${ln.getAttribute(\"data-a\")} \u2194 ${ln.getAttribute(\"data-b\")}<\/div><span class=\"vt\">${ln.getAttribute(\"data-w\")}% coinciden \u00b7 ${ln.getAttribute(\"data-shared\")} votaciones<\/span>`;\n        const rect = wrap.getBoundingClientRect();\n        let left = e.clientX - rect.left + 14, top = e.clientY - rect.top - 10;\n        if (left + 230 > rect.width) left = e.clientX - rect.left - 230;\n        tip.style.left = left + \"px\"; tip.style.top = Math.max(0, top) + \"px\";\n        tip.classList.add(\"visible\");\n      });\n      wrap.addEventListener(\"mouseleave\", () => { if (tip) tip.classList.remove(\"visible\"); });\n\n      wrap.addEventListener(\"click\", e => {\n        const g = e.target.closest && e.target.closest(\"g.afi-node\");\n        if (g) {\n          const id = g.getAttribute(\"data-id\");\n          if (_afiSel === id) { _afiClearHighlight(); _resetAfinidadDetail(); }\n          else { _afiHighlight(id); renderAfinidadDetail(id, af); }\n        } else { _afiClearHighlight(); _resetAfinidadDetail(); }\n      });\n      _resetAfinidadDetail();\n    } catch (err) {\n      console.error(\"[FREN] afinidad error:\", err);\n      wrap.innerHTML = '<p class=\"empty\" style=\"padding:24px 0\">No se pudo dibujar el grafo de afinidad.<\/p>';\n    }\n  }\n\n  \/\/ Resalta el nodo seleccionado, sus aristas y sus vecinos; aten\u00faa el resto.\n  let _afiSel = null;\n  function _afiHighlight(id) {\n    const svg = $(\"#afinidad-wrap .afi-svg\");\n    if (!svg || !id) return;\n    _afiSel = id;\n    const neighbors = new Set([id]);\n    svg.querySelectorAll(\"line.afi-link\").forEach(l => {\n      const on = l.getAttribute(\"data-src\") === id || l.getAttribute(\"data-tgt\") === id;\n      if (on) { neighbors.add(l.getAttribute(\"data-src\")); neighbors.add(l.getAttribute(\"data-tgt\")); }\n      const base = parseFloat(l.getAttribute(\"stroke-width\")) || 1.5;\n      l.style.stroke = on ? \"var(--orange)\" : \"#cbd5e1\";\n      l.style.strokeOpacity = on ? \"0.95\" : \"0.05\";\n      l.style.strokeWidth = on ? (base + 1.6).toFixed(2) : base.toFixed(2);\n    });\n    svg.querySelectorAll(\"g.afi-node\").forEach(g => {\n      g.style.opacity = neighbors.has(g.getAttribute(\"data-id\")) ? \"1\" : \"0.2\";\n    });\n  }\n  function _afiClearHighlight() {\n    _afiSel = null;\n    const svg = $(\"#afinidad-wrap .afi-svg\");\n    if (!svg) return;\n    svg.querySelectorAll(\"line.afi-link\").forEach(l => { l.style.stroke = \"\"; l.style.strokeOpacity = \"\"; l.style.strokeWidth = \"\"; });\n    svg.querySelectorAll(\"g.afi-node\").forEach(g => { g.style.opacity = \"\"; });\n  }\n  function _resetAfinidadDetail() {\n    const box = $(\"#afinidad-detail\");\n    if (box) box.innerHTML = '<p class=\"afi-detail-hint\">Haz clic en un grupo para ver su detalle de votos y sus afinidades con el resto.<\/p>';\n  }\n\n  function renderAfinidadDetail(id, af) {\n    const box = $(\"#afinidad-detail\");\n    if (!box || !af || !id) return;\n    const node = (af.nodes || []).find(n => n.id === id);\n    if (!node) return;\n    const labelOf = {};\n    (af.nodes || []).forEach(n => { labelOf[n.id] = n.label; });\n    const coes = (af.edges || [])\n      .filter(e => e.a === id || e.b === id)\n      .map(e => ({ other: e.a === id ? e.b : e.a, w: e.w, shared: e.shared }))\n      .sort((a, b) => b.w - a.w);\n    const v = node.votes || { favor: 0, contra: 0, abstencion: 0, no_voto: 0 };\n    const totalV = (v.favor + v.contra + v.abstencion + v.no_voto) || 1;\n    const voteRow = (lbl, val, cls) =>\n      `<div class=\"ad-vote ${cls}\"><span class=\"ad-vote-lbl\">${lbl}<\/span><span class=\"ad-vote-bar\"><span style=\"width:${Math.round(val \/ totalV * 100)}%\"><\/span><\/span><span class=\"ad-vote-val\">${val}<\/span><\/div>`;\n    box.innerHTML = `\n      <div class=\"ad-head\">\n        ${node.logo_url\n          ? `<img decoding=\"async\" class=\"ad-logo\" src=\"${escapeHtml(node.logo_url)}\" alt=\"\">`\n          : `<span class=\"ad-logo\" style=\"background:${escapeHtml(node.color || '#64748b')}\"><\/span>`}\n        <div>\n          <h4>${escapeHtml(node.label)}<\/h4>\n          <span class=\"ad-sub\">${node.size || 0} diputados \u00b7 ${node.n_votaciones || totalV} votaciones<\/span>\n        <\/div>\n        <button type=\"button\" class=\"saber-mas\" data-vc-contact=\"${escapeHtml(node.label)}\">Saber m\u00e1s \u2197<\/button>\n      <\/div>\n      <h5>Sentido de su voto (mayor\u00eda del grupo)<\/h5>\n      ${voteRow(\"A favor\", v.favor, \"favor\")}\n      ${voteRow(\"En contra\", v.contra, \"contra\")}\n      ${voteRow(\"Abstenci\u00f3n\", v.abstencion, \"abs\")}\n      ${voteRow(\"No vot\u00f3\", v.no_voto, \"nv\")}\n      <h5>Vota igual que\u2026<\/h5>\n      ${coes.length ? coes.map(c => `\n        <div class=\"ad-coes\">\n          <span class=\"ad-coes-lbl\" title=\"${escapeHtml(labelOf[c.other] || c.other)}\">${escapeHtml(_shortGroup(labelOf[c.other] || c.other))}<\/span>\n          <span class=\"ad-coes-bar\"><span style=\"width:${Math.round(c.w * 100)}%\"><\/span><\/span>\n          <span class=\"ad-coes-val\">${Math.round(c.w * 100)}%<\/span>\n        <\/div>`).join(\"\") : '<p class=\"muted-cell\">Sin coincidencias suficientes.<\/p>'}\n    `;\n  }\n\n  \/\/ Clic en un tema (nodo o flujo del Sankey) \u2192 detalle de intervinientes.\n  $(\"#temas-wrap\")?.addEventListener(\"click\", e => {\n    if (!e.target.closest) return;\n    const partido = e.target.closest(\"g.sk-partido\");\n    if (partido) { const pid = partido.getAttribute(\"data-party\"); _sankeyHighlight(\"data-party\", pid); renderPartidoDetail(pid); return; }\n    const el = e.target.closest(\"[data-topic]\");\n    if (el) {\n      const topic = el.getAttribute(\"data-topic\");\n      _sankeyHighlight(\"data-topic\", topic);\n      let t = _temasByName[topic];\n      if (!t && STATE.temas && STATE.temas.by_chamber) {\n        t = (STATE.temas.by_chamber[temasChamberKey] || STATE.temas.by_chamber.todos || []).find(x => x.topic === topic);\n      }\n      if (t) renderTemaDetail(t);\n      return;\n    }\n    _sankeyClearHighlight();\n  });\n\n  \/\/ ===== Modal de contacto (botones \"Saber m\u00e1s\") =====\n  function vcContact(label){\n    let m=document.getElementById(\"vcContactModal\");\n    if(!m){\n      m=document.createElement(\"div\"); m.className=\"vc-cmodal\"; m.id=\"vcContactModal\";\n      m.setAttribute(\"role\",\"dialog\"); m.setAttribute(\"aria-modal\",\"true\");\n      m.innerHTML='<div class=\"box\"><h4>Descubre FREN<\/h4><p id=\"vcContactMsg\"><\/p><div class=\"acts\"><a class=\"cta\" href=\"https:\/\/fren.democrata.es\/\" target=\"_blank\" rel=\"noopener\">Probar FREN<\/a><button class=\"x\" type=\"button\">Cerrar<\/button><\/div><\/div>';\n      document.body.appendChild(m);\n      m.addEventListener(\"click\",ev=>{ if(ev.target===m||ev.target.classList.contains(\"x\")){ m.classList.remove(\"open\"); m.setAttribute(\"aria-hidden\",\"true\"); } });\n      document.addEventListener(\"keydown\",ev=>{ if(ev.key===\"Escape\"){ m.classList.remove(\"open\"); m.setAttribute(\"aria-hidden\",\"true\"); } });\n    }\n    m.querySelector(\"#vcContactMsg\").textContent = label\n      ? '\u00bfQuieres el an\u00e1lisis completo sobre \u201c'+label+'\u201d? Solicita una demo de FREN y accede al detalle.'\n      : 'Solicita una demo de FREN y accede al an\u00e1lisis completo.';\n    m.classList.add(\"open\"); m.setAttribute(\"aria-hidden\",\"false\");\n  }\n  document.addEventListener(\"click\", e=>{\n    const b = e.target.closest && e.target.closest(\"[data-vc-contact]\");\n    if(b){ e.preventDefault(); e.stopPropagation(); vcContact(b.getAttribute(\"data-vc-contact\")); }\n  });\n\n  \/\/ ===== Heatmap =====\n  function renderHeatmap(diario) {\n    if (!diario) {\n      $(\"#hm-scroll\").innerHTML = '<p class=\"empty\">No hay diario de sesiones disponible.<\/p>';\n      $(\"#hm-meta\").innerHTML = \"\";\n      return;\n    }\n    if (diario.analysis_pending || !diario.intervinientes?.length) {\n      const meta = $(\"#hm-meta\");\n      meta.innerHTML = `\n        ${diario.chamber ? `<span class=\"pill\">${escapeHtml(diario.chamber)}<\/span>` : \"\"}\n        ${diario.id ? `<span class=\"pill pill-id\">ID: ${diario.id}<\/span>` : \"\"}\n        <span>${escapeHtml(diario.title || \"\")}<\/span>\n        ${diario.comision ? `<span>\u00b7 ${escapeHtml(diario.comision)}<\/span>` : \"\"}\n        ${diario.fecha ? `<span>\u00b7 <time datetime=\"${escapeHtml(diario.fecha)}\">${fmtDate(diario.fecha)}<\/time><\/span>` : \"\"}\n      `;\n      const status = diario.analysis_status || \"pending\";\n      $(\"#hm-scroll\").innerHTML = `\n        <p class=\"empty\">\n          El an\u00e1lisis tem\u00e1tico de este Diario a\u00fan no est\u00e1 disponible (estado: <code>${escapeHtml(status)}<\/code>).\n          Se est\u00e1 calculando en segundo plano. Vuelve a recargar en unos minutos.\n        <\/p>`;\n      return;\n    }\n    const meta = $(\"#hm-meta\");\n    meta.innerHTML = `\n      <span class=\"pill\">${escapeHtml(diario.chamber || \"\")}<\/span>\n      ${diario.id ? `<span class=\"pill pill-id\">ID: ${diario.id}<\/span>` : \"\"}\n      ${diario.is_fallback ? `<span class=\"pill pill-fallback\" title=\"El \u00faltimo Diario todav\u00eda se est\u00e1 procesando; mostramos el \u00faltimo con an\u00e1lisis disponible.\">\u00daltimo disponible<\/span>` : \"\"}\n      <span>${escapeHtml(diario.title || \"\")}<\/span>\n      ${diario.comision ? `<span>\u00b7 ${escapeHtml(diario.comision)}<\/span>` : \"\"}\n      <span>\u00b7 <time datetime=\"${escapeHtml(diario.fecha)}\">${fmtDate(diario.fecha)}<\/time><\/span>\n      ${diario.url_fuente ? `<span>\u00b7 <a href=\"${escapeHtml(diario.url_fuente)}\" rel=\"noopener\" target=\"_blank\">Fuente oficial<\/a><\/span>` : \"\"}\n    `;\n    const allTopics = diario.topics || [];\n    const intervs = diario.intervinientes || [];\n    const topicsWithData = allTopics\n      .map((topic, idx) => ({ topic, idx, hasData: intervs.some(p => (p.weights?.[idx] || 0) > 0) }))\n      .filter(t => t.hasData);\n    if (topicsWithData.length === 0) {\n      $(\"#hm-scroll\").innerHTML = '<p class=\"empty\">No hay datos tem\u00e1ticos para mostrar.<\/p>';\n      return;\n    }\n    let html = '<table class=\"heatmap\"><thead><tr><th scope=\"col\">Interviniente<\/th>';\n    topicsWithData.forEach(t => { html += `<th scope=\"col\" title=\"${escapeHtml(t.topic)}\">${escapeHtml(t.topic)}<\/th>`; });\n    html += \"<\/tr><\/thead><tbody>\";\n    intervs.forEach((p, rowIdx) => {\n      const photoHtml = p.photo_url\n        ? `<img decoding=\"async\" src=\"${escapeHtml(p.photo_url)}\" alt=\"\" class=\"avatar\" loading=\"lazy\">`\n        : `<span class=\"avatar-placeholder\">${escapeHtml(initials(p.name || \"?\"))}<\/span>`;\n      const groupLogoHtml = p.group_photo_url\n        ? `<img decoding=\"async\" src=\"${escapeHtml(p.group_photo_url)}\" alt=\"\" class=\"group-logo\" loading=\"lazy\">`\n        : \"\";\n      html += `<tr><th scope=\"row\" class=\"person-cell\">\n        <div class=\"person-info\">\n          ${photoHtml}\n          <div class=\"person-text\">\n            <span class=\"person-name\">${escapeHtml(p.name || \"\u2014\")}<\/span>\n            ${p.group ? `<span class=\"grupo\">${groupLogoHtml}${escapeHtml(p.group)}<\/span>` : \"\"}\n          <\/div>\n        <\/div>\n      <\/th>`;\n      topicsWithData.forEach(({ topic, idx: colIdx }) => {\n        const w = (p.weights && p.weights[colIdx]) || 0;\n        const lvl = levelFor(w);\n        const pct = Math.round(w * 100);\n        html += `<td class=\"cell\" data-level=\"${lvl}\" data-row=\"${rowIdx}\" data-topic=\"${escapeHtml(topic)}\" data-person=\"${escapeHtml(p.name || \"\")}\" title=\"${escapeHtml(p.name)} \u00b7 ${escapeHtml(topic)}: ${pct}%\" aria-label=\"${escapeHtml(p.name)} habl\u00f3 de ${escapeHtml(topic)} un ${pct} por ciento\">\n                  ${pct > 0 ? pct + \"%\" : \"\"}\n                <\/td>`;\n      });\n      html += \"<\/tr>\";\n    });\n    html += \"<\/tbody><\/table>\";\n    $(\"#hm-scroll\").innerHTML = html;\n    $(\"#hm-legend\").hidden = false;\n\n    $$(\"#hm-scroll td.cell\").forEach(td => {\n      td.addEventListener(\"click\", () => {\n        const row = parseInt(td.dataset.row, 10);\n        const topic = td.dataset.topic;\n        const person = td.dataset.person;\n        const snips = (intervs[row]?.snippets || {})[topic] || [];\n        $(\"#snippets-title\").textContent = `${person} sobre \"${topic}\"`;\n        $(\"#snippets-body\").innerHTML = snips.length\n          ? snips.map(s => `<blockquote>${escapeHtml(s)}<\/blockquote>`).join(\"\")\n          : '<p class=\"empty\">No hay extractos disponibles.<\/p>';\n        $(\"#snippets-dialog\").showModal();\n      });\n    });\n  }\n\n  \/\/ ===== Reparto tem\u00e1tico (bar chart horizontal nativo, sin Chart.js) =====\n  const FREN_DONUT_COLORS = [\"#1F2547\",\"#F3A53A\",\"#42507A\",\"#1FA886\",\"#7889B0\",\"#D88E25\",\"#5A8DC0\",\"#8A6B4A\",\"#6B8A7A\",\"#9B7B5A\",\"#B8C2D9\"];\n  function renderDonut(diario) {\n    const summary = $(\"#fren-summary\");\n    if (!diario?.topics?.length) { if (summary) summary.hidden = true; return; }\n    const allTotals = diario.topics.map((_, i) =>\n      (diario.intervinientes || []).reduce((acc, p) => acc + ((p.weights && p.weights[i]) || 0), 0)\n    );\n    const filtered = diario.topics\n      .map((topic, i) => ({ topic, total: allTotals[i] }))\n      .filter(item => item.total > 0)\n      .sort((a, b) => b.total - a.total);\n    if (filtered.length === 0) { if (summary) summary.hidden = true; return; }\n    if (summary) summary.hidden = false;\n    const total = filtered.reduce((a, b) => a + b.total, 0) || 1;\n    const colors = filtered.map((_, i) => FREN_DONUT_COLORS[i % FREN_DONUT_COLORS.length]);\n    \/\/ Ocultamos el donut antiguo si existe\n    const donutWrap = document.querySelector(\"#fren-summary .donut-mini\");\n    if (donutWrap) donutWrap.style.display = \"none\";\n\n    const list = $(\"#fren-top-temas\");\n    if (list) {\n      const top = filtered.slice(0, 8);\n      const maxPct = (top[0].total \/ total) * 100 || 1;\n      list.innerHTML = '<h4>Reparto tem\u00e1tico global<\/h4>' + top.map((f, i) => {\n        const pct = (f.total \/ total) * 100;\n        const w = (pct \/ maxPct) * 100;\n        return `\n        <div class=\"tema-bar-row\">\n          <span class=\"nm\" title=\"${escapeHtml(f.topic)}\">${escapeHtml(f.topic)}<\/span>\n          <span class=\"bar\"><span class=\"fill\" style=\"width:${w.toFixed(1)}%;background:${colors[i]}\"><\/span><\/span>\n          <span class=\"pct\">${pct.toFixed(1)}%<\/span>\n        <\/div>`;\n      }).join(\"\");\n    }\n  }\n\n  \/\/ ===== Hemiciclo =====\n  const HEMI_ROWS = [\n    { radius: 70,  count: 22 }, { radius: 90,  count: 28 }, { radius: 110, count: 34 },\n    { radius: 130, count: 40 }, { radius: 150, count: 46 }, { radius: 170, count: 52 },\n    { radius: 190, count: 58 }, { radius: 210, count: 62 }, { radius: 230, count: 8  },\n  ];\n  const HEMI_VIEWBOX = \"-10 -10 480 270\";\n  const HEMI_CENTER_X = 235, HEMI_CENTER_Y = 245, HEMI_SEAT_R = 5.2;\n  function _generateHemiSeatPositions() {\n    const positions = [];\n    HEMI_ROWS.forEach((row, rowIdx) => {\n      const rowPositions = [];\n      for (let i = 0; i < row.count; i++) {\n        const t = (i + 0.5) \/ row.count;\n        const angle = Math.PI - t * Math.PI;\n        const x = HEMI_CENTER_X + row.radius * Math.cos(angle);\n        const y = HEMI_CENTER_Y - row.radius * Math.sin(angle);\n        rowPositions.push({ x, y, angle, rowIdx });\n      }\n      positions.push(rowPositions);\n    });\n    return positions;\n  }\n  const HEMI_POS = _generateHemiSeatPositions();\n  const HEMI_FLAT = (() => {\n    const flat = [];\n    HEMI_POS.forEach((row, rowIdx) => {\n      if (rowIdx === HEMI_POS.length - 1) return;\n      row.forEach((p, i) => flat.push({ ...p, rowIdx, idxInRow: i }));\n    });\n    flat.sort((a, b) => (b.angle - a.angle) || (a.rowIdx - b.rowIdx));\n    return flat;\n  })();\n  const GROUP_ORDER = [\"bildu\",\"erc\",\"junts\",\"pnv\",\"sumar\",\"podemos\",\"psoe\",\"mixto\",\"ciudadanos\",\"pp\",\"vox\",\"otro\"];\n  function _voteColor(v) {\n    return ({ yes: \"#22C55E\", no: \"#EF4444\", abstention: \"#F59E0B\", \"no vote\": \"#111827\", \"no_vote\": \"#111827\" })[v] || \"#D1D5DB\";\n  }\n  function renderHemiciclo(votacion) {\n    const wrap = $(\"#hemi-wrap\"), meta = $(\"#hemi-meta\");\n    const totalsRow = $(\"#hemi-totals\"), groupsBox = $(\"#hemi-groups\");\n    if (!wrap) return;\n    if (!votacion) {\n      wrap.innerHTML = '<p class=\"empty\" style=\"padding:20px 0\">No hay votaciones recientes con detalle disponible.<\/p>';\n      meta.innerHTML = \"\"; totalsRow.hidden = true; groupsBox.innerHTML = \"\"; return;\n    }\n    const fecha = votacion.fecha ? fmtDate(votacion.fecha) : \"\";\n    const resultClass = votacion.result === \"aprobada\" ? \"aprobada\" : \"rechazada\";\n    const resultLabel = votacion.result === \"aprobada\" ? \"Aprobada\" : \"Rechazada\";\n    meta.innerHTML = `\n      <span class=\"pill ${resultClass}\">${resultLabel}<\/span>\n      <span class=\"pill\">Sesi\u00f3n ${votacion.session}, votaci\u00f3n n\u00ba ${votacion.num_voting}<\/span>\n      <span>\u00b7 <time datetime=\"${escapeHtml(votacion.fecha || '')}\">${escapeHtml(fecha)}<\/time><\/span>\n      ${votacion.legislature ? `<span>\u00b7 ${escapeHtml(votacion.legislature)} legislatura<\/span>` : \"\"}\n    `;\n    const subt = $(\"#hemi-subtitle\");\n    if (subt) {\n      const t = votacion.title || (votacion.initiative_title || \"\");\n      subt.textContent = t ? (t.length > 200 ? t.slice(0, 197) + \"\u2026\" : t) : \"Votaci\u00f3n m\u00e1s reciente del Pleno del Congreso.\";\n    }\n    totalsRow.hidden = false;\n    [\"yes\",\"no\",\"abstention\",\"no_vote\"].forEach(k => {\n      const el = totalsRow.querySelector(`[data-k=\"${k}\"]`);\n      if (el) el.textContent = (votacion.totals && votacion.totals[k] != null) ? votacion.totals[k] : 0;\n    });\n\n    const votes = (votacion.votes || []).filter(v => v && v.vote);\n    const buckets = {};\n    GROUP_ORDER.forEach(s => buckets[s] = []);\n    votes.forEach(v => {\n      const slug = v.group_slug || \"otro\";\n      if (!buckets[slug]) buckets[slug] = [];\n      buckets[slug].push(v);\n    });\n    Object.keys(buckets).forEach(s => buckets[s].sort((a,b) => (a.author_name || \"\").localeCompare(b.author_name || \"\")));\n    const orderedVotes = [];\n    GROUP_ORDER.forEach(s => { (buckets[s] || []).forEach(v => orderedVotes.push(v)); });\n    Object.keys(buckets).forEach(s => {\n      if (!GROUP_ORDER.includes(s)) buckets[s].forEach(v => orderedVotes.push(v));\n    });\n    const seats = HEMI_FLAT.map((pos, idx) => ({ pos, vote: orderedVotes[idx] || null }));\n\n    const svgParts = [];\n    svgParts.push(`<svg viewBox=\"${HEMI_VIEWBOX}\" preserveAspectRatio=\"xMidYMid meet\" role=\"img\" aria-labelledby=\"hemi-title\">`);\n    svgParts.push(`<title>Hemiciclo del Congreso \u2013 \u00faltima votaci\u00f3n<\/title>`);\n    seats.forEach(({ pos, vote }) => {\n      const color = vote ? _voteColor(vote.vote) : \"#D1D5DB\";\n      const dataAttrs = vote\n        ? `data-name=\"${escapeHtml(vote.author_name || '')}\" data-group=\"${escapeHtml(vote.group_name || '')}\" data-vote=\"${escapeHtml(vote.vote)}\" data-logo=\"${escapeHtml(vote.group_logo_url || '')}\"`\n        : \"\";\n      svgParts.push(`<circle class=\"seat\" cx=\"${pos.x.toFixed(2)}\" cy=\"${pos.y.toFixed(2)}\" r=\"${HEMI_SEAT_R}\" fill=\"${color}\" stroke=\"#fff\" stroke-width=\".5\" ${dataAttrs}\/>`);\n    });\n    svgParts.push(`<\/svg>`);\n    svgParts.push(`<div class=\"hemi-tooltip\" id=\"hemi-tooltip\" role=\"tooltip\"><\/div>`);\n    wrap.innerHTML = svgParts.join(\"\");\n\n    const tip = $(\"#hemi-tooltip\");\n    let _hovered = null;\n    wrap.addEventListener(\"mouseover\", e => {\n      const c = e.target.closest(\"circle.seat\");\n      if (!c || c === _hovered) return;\n      _hovered = c;\n      const name = c.getAttribute(\"data-name\");\n      if (!name) { tip.classList.remove(\"visible\"); return; }\n      const group = c.getAttribute(\"data-group\") || \"\";\n      const logo = c.getAttribute(\"data-logo\") || \"\";\n      const vote = c.getAttribute(\"data-vote\") || \"\";\n      const voteCls = (vote.replace(\" \", \"_\")) || \"\";\n      const voteLabel = { yes:\"A favor\", no:\"En contra\", abstention:\"Abstenci\u00f3n\", \"no vote\":\"No vot\u00f3\", \"no_vote\":\"No vot\u00f3\" }[vote] || vote;\n      tip.innerHTML = `\n        <div class=\"ttl\">${escapeHtml(name)}<\/div>\n        ${group ? `<div class=\"grp\">${logo ? `<img decoding=\"async\" src=\"${escapeHtml(logo)}\" alt=\"\">` : \"\"}<span>${escapeHtml(group)}<\/span><\/div>` : \"\"}\n        <span class=\"vt ${voteCls}\">${escapeHtml(voteLabel)}<\/span>\n      `;\n      tip.classList.add(\"visible\");\n    });\n    wrap.addEventListener(\"mousemove\", e => {\n      if (!tip.classList.contains(\"visible\")) return;\n      const wrapRect = wrap.getBoundingClientRect();\n      const x = e.clientX - wrapRect.left, y = e.clientY - wrapRect.top;\n      const w = tip.offsetWidth || 240, h = tip.offsetHeight || 80;\n      let left = x + 14, top = y - h - 8;\n      if (left + w > wrapRect.width) left = x - w - 14;\n      if (top < 0) top = y + 14;\n      tip.style.left = left + \"px\"; tip.style.top = top + \"px\";\n    });\n    wrap.addEventListener(\"mouseout\", e => {\n      const to = e.relatedTarget;\n      if (!to || !to.closest || !to.closest(\".hemi-wrap\")) { _hovered = null; tip.classList.remove(\"visible\"); }\n      else if (!to.closest(\"circle.seat\")) { _hovered = null; tip.classList.remove(\"visible\"); }\n    });\n\n    groupsBox.innerHTML = (votacion.groups_breakdown || []).map(g => {\n      const majMap = { favor: \"\u2713 A favor\", contra: \"\u2717 En contra\", abstencion: \"\u25cb Abstenci\u00f3n\", no_voto: \"\u2014 No vot\u00f3\", mixto: \"Mixto\" };\n      const maj = majMap[g.majority_vote] || \"\";\n      const logo = g.logo_url\n        ? `<img decoding=\"async\" class=\"logo\" src=\"${escapeHtml(g.logo_url)}\" alt=\"${escapeHtml(g.group_name)}\" loading=\"lazy\">`\n        : `<span class=\"dot\" style=\"background:${escapeHtml(g.color || '#9aa0a6')}\"><\/span>`;\n      return `<span class=\"hemi-group\" title=\"${escapeHtml(g.group_name)} \u00b7 ${maj}\">\n        ${logo}\n        <span class=\"nm\">${escapeHtml(g.group_name)}<\/span>\n        <span class=\"ct\">(${g.total_members})<\/span>\n      <\/span>`;\n    }).join(\"\");\n  }\n\n  \/\/ ===== Pregunta del d\u00eda =====\n  function _extractPlainAnswer(html, maxLen) {\n    const tmp = document.createElement(\"div\");\n    tmp.innerHTML = html || \"\";\n    const txt = (tmp.textContent || \"\").trim().replace(\/\\s+\/g, \" \");\n    if (txt.length <= maxLen) return { preview: txt, isLong: false };\n    return { preview: txt.slice(0, maxLen).trim() + \"\u2026\", isLong: true };\n  }\n\n  function renderPreguntaDelDia(qa) {\n    const cont = $(\"#pregunta-content\");\n    if (!cont) return;\n    if (!qa || !qa.question) {\n      cont.innerHTML = '<p class=\"empty\" style=\"padding:24px 0\">Hoy no hay pregunta destacada disponible.<\/p>';\n      return;\n    }\n    const fechaNoticia = qa.noticia_date ? fmtDate(qa.noticia_date) : \"\";\n    const fuente = [];\n    if (qa.noticia_source) fuente.push(escapeHtml(qa.noticia_source));\n    if (fechaNoticia) fuente.push(`<time datetime=\"${escapeHtml(qa.noticia_date)}\">${escapeHtml(fechaNoticia)}<\/time>`);\n    const fuenteHtml = fuente.length ? fuente.join(\" \u00b7 \") : \"Noticia reciente\";\n\n    const { preview, isLong } = _extractPlainAnswer(qa.answer_html, 220);\n\n    cont.innerHTML = `\n      <article class=\"pregunta-card\" itemscope itemtype=\"https:\/\/schema.org\/Question\">\n        <div class=\"pregunta-meta\">Inspirada en una noticia de hoy<\/div>\n        <h4 class=\"pregunta-q\" itemprop=\"name\">${escapeHtml(qa.question)}<\/h4>\n        <div class=\"pregunta-a-collapsed\">\n          <p class=\"pregunta-preview\">${escapeHtml(preview)}<\/p>\n          ${isLong ? `\n            <button type=\"button\" class=\"pregunta-toggle\" aria-expanded=\"false\">\n              Ver respuesta completa\n            <\/button>\n            <div class=\"pregunta-a\" itemprop=\"acceptedAnswer\" itemscope itemtype=\"https:\/\/schema.org\/Answer\" hidden>\n              <div itemprop=\"text\">${qa.answer_html}<\/div>\n            <\/div>` : `\n            <div class=\"pregunta-a\" itemprop=\"acceptedAnswer\" itemscope itemtype=\"https:\/\/schema.org\/Answer\" hidden>\n              <meta itemprop=\"text\" content=\"${escapeHtml(preview)}\">\n            <\/div>`}\n        <\/div>\n        <div class=\"pregunta-fuente\">\n          <strong>Fuente:<\/strong>\n          ${qa.noticia_url\n            ? `<a href=\"${escapeHtml(qa.noticia_url)}\" rel=\"noopener\" target=\"_blank\">${escapeHtml(qa.noticia_title || 'Ver noticia')}<\/a> \u00b7 ${fuenteHtml}`\n            : `${escapeHtml(qa.noticia_title || 'Noticia reciente')} \u00b7 ${fuenteHtml}`}\n        <\/div>\n      <\/article>\n    `;\n\n    const toggle = cont.querySelector(\".pregunta-toggle\");\n    if (toggle) {\n      toggle.addEventListener(\"click\", () => {\n        const full = cont.querySelector(\".pregunta-a\");\n        const preview = cont.querySelector(\".pregunta-preview\");\n        const open = toggle.getAttribute(\"aria-expanded\") === \"true\";\n        if (open) {\n          full.hidden = true; preview.hidden = false;\n          toggle.setAttribute(\"aria-expanded\", \"false\");\n          toggle.textContent = \"Ver respuesta completa\";\n        } else {\n          full.hidden = false; preview.hidden = true;\n          toggle.setAttribute(\"aria-expanded\", \"true\");\n          toggle.textContent = \"Ocultar respuesta\";\n        }\n      });\n    }\n  }\n\n  \/\/ ===== Tablas SEO =====\n  function renderSeoTables(data) {\n    const diarioBody = document.querySelector(\"#seo-table-diario tbody\");\n    if (diarioBody) {\n      const d = data.diario_sesiones;\n      if (!d || !(d.intervinientes || []).length) {\n        diarioBody.innerHTML = '<tr><td colspan=\"3\" class=\"muted-cell\">El \u00faltimo Diario de Sesiones a\u00fan se est\u00e1 procesando.<\/td><\/tr>';\n      } else {\n        const topics = d.topics || [];\n        diarioBody.innerHTML = (d.intervinientes || []).map(p => {\n          const tags = topics\n            .map((t, i) => ({ t, w: (p.weights || [])[i] || 0 }))\n            .filter(x => x.w > 0)\n            .sort((a, b) => b.w - a.w)\n            .map(x => `${escapeHtml(x.t)} (${Math.round(x.w * 100)}%)`)\n            .join(\", \");\n          return `<tr itemscope itemtype=\"https:\/\/schema.org\/Person\">\n            <td itemprop=\"name\">${escapeHtml(p.name || \"\u2014\")}<\/td>\n            <td itemprop=\"memberOf\">${escapeHtml(p.group || \"\u2014\")}<\/td>\n            <td>${tags || '<span class=\"muted-cell\">\u2014<\/span>'}<\/td>\n          <\/tr>`;\n        }).join(\"\");\n      }\n    }\n    const votBody = document.querySelector(\"#seo-table-votacion tbody\");\n    if (votBody) {\n      const v = data.ultima_votacion;\n      const groups = v && v.groups_breakdown || [];\n      if (!groups.length) {\n        votBody.innerHTML = '<tr><td colspan=\"7\" class=\"muted-cell\">No hay votaci\u00f3n reciente con detalle individual disponible.<\/td><\/tr>';\n      } else {\n        const majMap = { favor: \"A favor\", contra: \"En contra\", abstencion: \"Abstenci\u00f3n\", no_voto: \"No vot\u00f3\", mixto: \"Mixto\" };\n        votBody.innerHTML = groups.map(g => `\n          <tr>\n            <td><strong>${escapeHtml(g.group_name || \"\u2014\")}<\/strong><\/td>\n            <td>${(g.votes && g.votes.yes) || 0}<\/td>\n            <td>${(g.votes && g.votes.no) || 0}<\/td>\n            <td>${(g.votes && g.votes.abstention) || 0}<\/td>\n            <td>${(g.votes && g.votes.no_vote) || 0}<\/td>\n            <td>${g.total_members || 0}<\/td>\n            <td>${escapeHtml(majMap[g.majority_vote] || g.majority_vote || \"\u2014\")}<\/td>\n          <\/tr>`).join(\"\");\n      }\n    }\n  }\n\n  \/\/ ===== Load =====\n  function load() {\n    const apiUrl = getApiUrl();\n    loadDashboardData(apiUrl, data => {\n      STATE.temas = data.temas_calientes_diarios;\n      STATE.afinidad = data.afinidad_votos;\n      renderTemasCalientes(STATE.temas);\n      if (isPaneActive(\"pane-afinidad\")) renderAfinidad(STATE.afinidad);\n      renderPreguntaDelDia(data.pregunta_del_dia);\n      renderSeoTables(data);\n      setUpdatedPill(data, null);\n    }, (msg, kind) => {\n      setUpdatedPill(null, kind === \"network\" ? \"Error de conexi\u00f3n\" : kind === \"http\" ? \"Error HTTP\" : \"Error\");\n      const w = $(\"#temas-wrap\"); if (w) w.innerHTML = `<p class=\"error\">${msg}<\/p>`;\n    });\n  }\n\n  $(\"#snippets-close\").addEventListener(\"click\", () => $(\"#snippets-dialog\").close());\n  $(\"#snippets-dialog\").addEventListener(\"click\", e => {\n    if (e.target === $(\"#snippets-dialog\")) $(\"#snippets-dialog\").close();\n  });\n  $(\"#reload-btn\")?.addEventListener(\"click\", load);\n  $(\"#diario-id-input\")?.addEventListener(\"keypress\", e => {\n    if (e.key === \"Enter\") { e.preventDefault(); load(); }\n  });\n\n  window.VincesDash.onPaneActivated = window.VincesDash.onPaneActivated || {};\n  window.VincesDash.onPaneActivated[\"pane-temas\"] = () => renderTemasCalientes(STATE.temas);\n  window.VincesDash.onPaneActivated[\"pane-afinidad\"] = () => renderAfinidad(STATE.afinidad);\n\n  initCarousels();\n  const absUrl = `${window.location.protocol}\/\/${window.location.host}\/api\/dashboard-publico\/fren\/`;\n  bindDownloadExternalHtml(absUrl);\n\n  load();\n  setInterval(load, window.VincesDash.REFRESH_MS);\n})();\n<\/script>\n\n\n<script>\n(function(){\n  function wrapHeroRight(){\n    return; \/* hero ya estructurado con .vc-hero-actions + rueda *\/\n    var pill = document.getElementById('updated-pill');\n    var cta = document.querySelector('.vc-hero-cta');\n    if (!pill || !cta || cta.parentNode.classList.contains('vc-hero-right')) return;\n    var wrap = document.createElement('div');\n    wrap.className = 'vc-hero-right';\n    cta.parentNode.insertBefore(wrap, cta);\n    wrap.appendChild(pill);\n    wrap.appendChild(cta);\n  }\n  if (document.readyState === 'loading') {\n    document.addEventListener('DOMContentLoaded', wrapHeroRight);\n  } else {\n    wrapHeroRight();\n  }\n})();\n<\/script>\n\n\n<\/div>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>FREN: Di\u00e1rio das Sess\u00f5es, vota\u00e7\u00f5es do Congresso e pergunta do dia \u00b7 Intelig\u00eancia regulat\u00f3ria com IA \u00b7 Vinces FREN \u00b7 IA para Assuntos P\u00fablicos Toda a pol\u00edtica espanhola, numa pergunta O FREN \u00e9 o assistente de IA especializado em pol\u00edtica, regulamenta\u00e7\u00e3o e assuntos p\u00fablicos. Faz-lhe perguntas em linguagem natural e recebe respostas fundamentadas \u2014 com [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":4956,"parent":11884,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"_acf_changed":false,"footnotes":""},"class_list":["post-11963","page","type-page","status-publish","has-post-thumbnail","hentry"],"acf":[],"_links":{"self":[{"href":"https:\/\/vincesconsulting.com\/pt-pt\/wp-json\/wp\/v2\/pages\/11963","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/vincesconsulting.com\/pt-pt\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/vincesconsulting.com\/pt-pt\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/vincesconsulting.com\/pt-pt\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/vincesconsulting.com\/pt-pt\/wp-json\/wp\/v2\/comments?post=11963"}],"version-history":[{"count":0,"href":"https:\/\/vincesconsulting.com\/pt-pt\/wp-json\/wp\/v2\/pages\/11963\/revisions"}],"up":[{"embeddable":true,"href":"https:\/\/vincesconsulting.com\/pt-pt\/wp-json\/wp\/v2\/pages\/11884"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/vincesconsulting.com\/pt-pt\/wp-json\/wp\/v2\/media\/4956"}],"wp:attachment":[{"href":"https:\/\/vincesconsulting.com\/pt-pt\/wp-json\/wp\/v2\/media?parent=11963"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}